UI for making encrypted ssh remotes with gcrypt
Improved probing the remote server, so it gathers a list of the capabilities it has. From that list, we can determine which types of remotes are supported, and display an appropriate UI. The new buttons for making gcrypt repos don't work yet, but the old buttons for unencrypted git repo and encrypted rsync repo have been adapted to the new data types and are working. This commit was sponsored by David Schmitt.
This commit is contained in:
parent
2f75512188
commit
d83a244986
10 changed files with 141 additions and 105 deletions
|
@ -205,7 +205,8 @@ enableAWSRemote _ _ = error "S3 not supported by this build"
|
|||
makeAWSRemote :: SpecialRemoteMaker -> RemoteType -> StandardGroup -> AWSCreds -> RemoteName -> RemoteConfig -> Handler ()
|
||||
makeAWSRemote maker remotetype defaultgroup (AWSCreds ak sk) name config = do
|
||||
liftIO $ AWS.setCredsEnv (T.unpack ak, T.unpack sk)
|
||||
setupCloudRemote defaultgroup $ maker hostname remotetype config
|
||||
setupCloudRemote defaultgroup Nothing $
|
||||
maker hostname remotetype config
|
||||
where
|
||||
{- AWS services use the remote name as the basis for a host
|
||||
- name, so filter it to contain valid characters. -}
|
||||
|
|
|
@ -17,7 +17,6 @@ import Assistant.MakeRemote
|
|||
import Utility.Rsync (rsyncUrlIsShell)
|
||||
import Logs.Remote
|
||||
import Remote
|
||||
import Logs.PreferredContent
|
||||
import Types.StandardGroups
|
||||
import Utility.UserInfo
|
||||
import Utility.Gpg
|
||||
|
@ -54,7 +53,7 @@ mkSshData s = SshData
|
|||
(maybe "" T.unpack $ inputDirectory s)
|
||||
, sshPort = inputPort s
|
||||
, needsPubKey = False
|
||||
, rsyncOnly = False
|
||||
, sshCapabilities = [] -- untested
|
||||
}
|
||||
|
||||
mkSshInput :: SshData -> SshInput
|
||||
|
@ -103,15 +102,12 @@ sshInputAForm hostnamefield def = SshInput
|
|||
data ServerStatus
|
||||
= UntestedServer
|
||||
| UnusableServer Text -- reason why it's not usable
|
||||
| UsableRsyncServer
|
||||
| UsableSshInput
|
||||
| UsableServer [SshServerCapability]
|
||||
deriving (Eq)
|
||||
|
||||
usable :: ServerStatus -> Bool
|
||||
usable UntestedServer = False
|
||||
usable (UnusableServer _) = False
|
||||
usable UsableRsyncServer = True
|
||||
usable UsableSshInput = True
|
||||
capabilities :: ServerStatus -> [SshServerCapability]
|
||||
capabilities (UsableServer cs) = cs
|
||||
capabilities _ = []
|
||||
|
||||
getAddSshR :: Handler Html
|
||||
getAddSshR = postAddSshR
|
||||
|
@ -143,7 +139,7 @@ postEnableRsyncR :: UUID -> Handler Html
|
|||
postEnableRsyncR = enableSpecialSshRemote "rsyncurl" enableRsyncNet enablersync
|
||||
where
|
||||
enablersync sshdata = redirect $ ConfirmSshR $
|
||||
sshdata { rsyncOnly = True }
|
||||
sshdata { sshCapabilities = [RsyncCapable] }
|
||||
|
||||
{- This only handles gcrypt repositories that are located on ssh servers;
|
||||
- ones on local drives are handled via another part of the UI. -}
|
||||
|
@ -214,8 +210,9 @@ parseSshRsyncUrl u
|
|||
- passwordless login is already enabled, use it. Otherwise,
|
||||
- a special ssh key will need to be generated just for this server.
|
||||
-
|
||||
- Once logged into the server, probe to see if git-annex-shell is
|
||||
- available, or rsync. Note that, ~/.ssh/git-annex-shell may be
|
||||
- Once logged into the server, probe to see if git-annex-shell,
|
||||
- git, and rsync are available.
|
||||
- Note that, ~/.ssh/git-annex-shell may be
|
||||
- present, while git-annex-shell is not in PATH.
|
||||
-}
|
||||
testServer :: SshInput -> IO (Either ServerStatus SshData)
|
||||
|
@ -223,22 +220,23 @@ testServer (SshInput { inputHostname = Nothing }) = return $
|
|||
Left $ UnusableServer "Please enter a host name."
|
||||
testServer sshinput@(SshInput { inputHostname = Just hn }) = do
|
||||
status <- probe [sshOpt "NumberOfPasswordPrompts" "0"]
|
||||
if usable status
|
||||
then ret status False
|
||||
else do
|
||||
case capabilities status of
|
||||
[] -> do
|
||||
status' <- probe []
|
||||
if usable status'
|
||||
then ret status' True
|
||||
else return $ Left status'
|
||||
case capabilities status' of
|
||||
[] -> return $ Left status'
|
||||
cs -> ret cs True
|
||||
cs -> ret cs False
|
||||
where
|
||||
ret status needspubkey = return $ Right $ (mkSshData sshinput)
|
||||
ret cs needspubkey = return $ Right $ (mkSshData sshinput)
|
||||
{ needsPubKey = needspubkey
|
||||
, rsyncOnly = status == UsableRsyncServer
|
||||
, sshCapabilities = cs
|
||||
}
|
||||
probe extraopts = do
|
||||
let remotecommand = shellWrap $ intercalate ";"
|
||||
[ report "loggedin"
|
||||
, checkcommand "git-annex-shell"
|
||||
, checkcommand "git"
|
||||
, checkcommand "rsync"
|
||||
, checkcommand shim
|
||||
]
|
||||
|
@ -256,14 +254,19 @@ testServer sshinput@(SshInput { inputHostname = Just hn }) = do
|
|||
, remotecommand
|
||||
]
|
||||
parsetranscript . fst <$> sshTranscript sshopts Nothing
|
||||
parsetranscript s
|
||||
| reported "git-annex-shell" = UsableSshInput
|
||||
| reported shim = UsableSshInput
|
||||
| reported "rsync" = UsableRsyncServer
|
||||
| reported "loggedin" = UnusableServer
|
||||
"Neither rsync nor git-annex are installed on the server. Perhaps you should go install them?"
|
||||
| otherwise = UnusableServer $ T.pack $
|
||||
"Failed to ssh to the server. Transcript: " ++ s
|
||||
parsetranscript s =
|
||||
let cs = map snd $ filter (reported . fst)
|
||||
[ ("git-annex-shell", GitAnnexShellCapable)
|
||||
, (shim, GitAnnexShellCapable)
|
||||
, ("git", GitCapable)
|
||||
, ("rsync", RsyncCapable)
|
||||
]
|
||||
in if null cs
|
||||
then if reported "loggedin"
|
||||
then UnusableServer "Neither rsync nor git-annex are installed on the server. Perhaps you should go install them?"
|
||||
else UnusableServer $ T.pack $
|
||||
"Failed to ssh to the server. Transcript: " ++ s
|
||||
else UsableServer cs
|
||||
where
|
||||
reported r = token r `isInfixOf` s
|
||||
|
||||
|
@ -286,7 +289,9 @@ showSshErr msg = sshConfigurator $
|
|||
$(widgetFile "configurators/ssh/error")
|
||||
|
||||
getConfirmSshR :: SshData -> Handler Html
|
||||
getConfirmSshR sshdata = sshConfigurator $
|
||||
getConfirmSshR sshdata = sshConfigurator $ do
|
||||
secretkeys <- sortBy (comparing snd) . M.toList
|
||||
<$> liftIO secretKeys
|
||||
$(widgetFile "configurators/ssh/confirm")
|
||||
|
||||
getRetrySshR :: SshData -> Handler ()
|
||||
|
@ -300,6 +305,9 @@ getMakeSshGitR = makeSsh False
|
|||
getMakeSshRsyncR :: SshData -> Handler Html
|
||||
getMakeSshRsyncR = makeSsh True
|
||||
|
||||
getMakeSshGCryptR :: SshData -> RepoKey -> Handler Html
|
||||
getMakeSshGCryptR sshdata repokey = error "TODO"
|
||||
|
||||
makeSsh :: Bool -> SshData -> Handler Html
|
||||
makeSsh rsync sshdata
|
||||
| needsPubKey sshdata = do
|
||||
|
@ -312,27 +320,25 @@ makeSsh rsync sshdata
|
|||
| otherwise = makeSsh' rsync sshdata sshdata Nothing
|
||||
|
||||
makeSsh' :: Bool -> SshData -> SshData -> Maybe SshKeyPair -> Handler Html
|
||||
makeSsh' rsync origsshdata sshdata keypair = do
|
||||
makeSsh' rsynconly origsshdata sshdata keypair = do
|
||||
sshSetup ["-p", show (sshPort origsshdata), sshhost, remoteCommand] "" $
|
||||
makeSshRepo rsync sshdata
|
||||
makeSshRepo rsynconly sshdata
|
||||
where
|
||||
sshhost = genSshHost (sshHostName origsshdata) (sshUserName origsshdata)
|
||||
remotedir = T.unpack $ sshDirectory sshdata
|
||||
remoteCommand = shellWrap $ intercalate "&&" $ catMaybes
|
||||
[ Just $ "mkdir -p " ++ shellEscape remotedir
|
||||
, Just $ "cd " ++ shellEscape remotedir
|
||||
, if rsync then Nothing else Just "if [ ! -d .git ]; then git init --bare --shared; fi"
|
||||
, if rsync then Nothing else Just "git annex init"
|
||||
, if rsynconly then Nothing else Just "if [ ! -d .git ]; then git init --bare --shared; fi"
|
||||
, if rsynconly then Nothing else Just "git annex init"
|
||||
, if needsPubKey sshdata
|
||||
then addAuthorizedKeysCommand (rsync || rsyncOnly sshdata) remotedir . sshPubKey <$> keypair
|
||||
then addAuthorizedKeysCommand rsynconly remotedir . sshPubKey <$> keypair
|
||||
else Nothing
|
||||
]
|
||||
|
||||
makeSshRepo :: Bool -> SshData -> Handler Html
|
||||
makeSshRepo forcersync sshdata = do
|
||||
r <- liftAssistant $ makeSshRemote forcersync sshdata Nothing
|
||||
liftAnnex $ setStandardGroup (Remote.uuid r) TransferGroup
|
||||
redirect $ EditNewCloudRepositoryR $ Remote.uuid r
|
||||
makeSshRepo forcersync sshdata = setupCloudRemote TransferGroup Nothing $
|
||||
makeSshRemote forcersync sshdata
|
||||
|
||||
getAddRsyncNetR :: Handler Html
|
||||
getAddRsyncNetR = postAddRsyncNetR
|
||||
|
@ -394,7 +400,7 @@ getMakeRsyncNetGCryptR sshdata NoRepoKey = whenGcryptInstalled $
|
|||
withNewSecretKey $ getMakeRsyncNetGCryptR sshdata . RepoKey
|
||||
getMakeRsyncNetGCryptR sshdata (RepoKey keyid) = whenGcryptInstalled $ do
|
||||
sshSetup [sshhost, gitinit] [] $
|
||||
setupCloudRemote TransferGroup $
|
||||
setupCloudRemote TransferGroup Nothing $
|
||||
makeGCryptRemote (sshRepoName sshdata) (sshUrl True sshdata) keyid
|
||||
where
|
||||
sshhost = genSshHost (sshHostName sshdata) (sshUserName sshdata)
|
||||
|
@ -413,7 +419,7 @@ enableRsyncNetGCrypt sshinput reponame =
|
|||
notencrypted = error "Unexpectedly found a non-encrypted git repository, instead of the expected encrypted git repository."
|
||||
enableRsyncNetGCrypt' :: SshData -> RemoteName -> Handler Html
|
||||
enableRsyncNetGCrypt' sshdata reponame =
|
||||
setupCloudRemote TransferGroup $
|
||||
setupCloudRemote TransferGroup Nothing $
|
||||
enableSpecialRemote reponame GCrypt.remote $ M.fromList
|
||||
[("gitrepo", sshUrl True sshdata)]
|
||||
|
||||
|
@ -427,7 +433,7 @@ prepRsyncNet sshinput reponame a = do
|
|||
(mkSshData sshinput)
|
||||
{ sshRepoName = reponame
|
||||
, needsPubKey = True
|
||||
, rsyncOnly = True
|
||||
, sshCapabilities = [RsyncCapable]
|
||||
}
|
||||
{- I'd prefer to separate commands with && , but
|
||||
- rsync.net's shell does not support that.
|
||||
|
|
|
@ -126,7 +126,8 @@ postEnableWebDAVR _ = error "WebDAV not supported by this build"
|
|||
makeWebDavRemote :: SpecialRemoteMaker -> RemoteName -> CredPair -> RemoteConfig -> Handler ()
|
||||
makeWebDavRemote maker name creds config = do
|
||||
liftIO $ WebDAV.setCredsEnv creds
|
||||
setupCloudRemote TransferGroup $ maker name WebDAV.remote config
|
||||
setupCloudRemote TransferGroup Nothing $
|
||||
maker name WebDAV.remote config
|
||||
|
||||
{- Only returns creds previously used for the same hostname. -}
|
||||
previouslyUsedWebDAVCreds :: String -> Annex (Maybe CredPair)
|
||||
|
|
|
@ -20,6 +20,7 @@ import qualified Remote.List as Remote
|
|||
import qualified Assistant.Threads.Transferrer as Transferrer
|
||||
import Logs.Transfer
|
||||
import qualified Config
|
||||
import Config.Cost
|
||||
import Config.Files
|
||||
import Git.Config
|
||||
import Assistant.Threads.Watcher
|
||||
|
@ -125,12 +126,13 @@ getCurrentTransfers :: Handler TransferMap
|
|||
getCurrentTransfers = currentTransfers <$> liftAssistant getDaemonStatus
|
||||
|
||||
{- Runs an action that creates or enables a cloud remote,
|
||||
- and finishes setting it up; adding it to a group if it's not already in
|
||||
- one, starts syncing with it, and finishes by displaying the page to edit
|
||||
- it. -}
|
||||
setupCloudRemote :: StandardGroup -> Annex RemoteName -> Handler a
|
||||
setupCloudRemote defaultgroup maker = do
|
||||
- and finishes setting it up, then starts syncing with it,
|
||||
- and finishes by displaying the page to edit it. -}
|
||||
setupCloudRemote :: StandardGroup -> Maybe Cost -> Annex RemoteName -> Handler a
|
||||
setupCloudRemote defaultgroup mcost maker = do
|
||||
r <- liftAnnex $ addRemote maker
|
||||
liftAnnex $ setStandardGroup (Remote.uuid r) defaultgroup
|
||||
liftAnnex $ do
|
||||
setStandardGroup (Remote.uuid r) defaultgroup
|
||||
maybe noop (Config.setRemoteCost r) mcost
|
||||
liftAssistant $ syncRemote r
|
||||
redirect $ EditNewCloudRepositoryR $ Remote.uuid r
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
/config/repository/add/ssh/retry/#SshData RetrySshR GET
|
||||
/config/repository/add/ssh/make/git/#SshData MakeSshGitR GET
|
||||
/config/repository/add/ssh/make/rsync/#SshData MakeSshRsyncR GET
|
||||
/config/repository/add/ssh/make/gcrypt/#SshData/#RepoKey MakeSshGCryptR GET
|
||||
/config/repository/add/cloud/rsync.net AddRsyncNetR GET POST
|
||||
/config/repository/add/cloud/rsync.net/shared/#SshData MakeRsyncNetSharedR GET
|
||||
/config/repository/add/cloud/rsync.net/gcrypt/#SshData/#RepoKey MakeRsyncNetGCryptR GET
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue