b0VIM 7.4baJU:/joeydarkstar~joey/src/git-annex/Assistant/WebApp/Configurators/Ssh.hs 3210#"! Utpv^wdc9Va>Sad%vTPOwfC0" q _ N /  m N 8 ( ' c B #  J .   l U %  _F/ 6XP@X&wuPA&t`-,I return $ case mapMaybe addrCanonName <$> r of r <- catchMaybeIO $ getAddrInfo canonname (Just h) Nothing let canonname = Just $ defaultHints { addrFlags = [AI_CANONNAME] } let h = T.unpack t checkdns t = do check_hostname = checkM (liftIO . checkdns) hostnamefield bad_hostname = "cannot resolve host name" :: Text#ifndef __ANDROID__ bad_username = "bad user name" :: Text bad_username textField check_username = checkBool (all (`notElem` "/:@ \t") . T.unpack) ] , ("existing ssh key", ExistingSshKey) [ ("password", Password) authmethods = authmethods :: [(Text, AuthMethod)] <*> areq intField (bfs "Port") (Just $ inputPort d) <*> aopt textField (bfs "Directory") (Just $ Just $ fromMaybe (T.pack gitAnnexAssistantDefaultDir) $ inputDirectory d) <*> aopt passwordField (bfs "Password") Nothing <*> areq (selectFieldList authmethods) (bfs "Authenticate with") (Just $ inputAuthMethod d) <*> aopt check_username (bfs "User name") (Just $ inputUsername d) <$> aopt check_hostname (bfs "Host name") (Just $ inputHostname d) gen = SshInput wheresshInputAForm hostnamefield d = normalize <$> gensshInputAForm :: Field Handler Text -> SshInput -> AForm Handler SshInput } , inputPort = sshPort s , inputDirectory = Just $ sshDirectory s , inputPassword = Nothing , inputAuthMethod = if needsPubKey s then CachedPassword else ExistingSshKey , inputUsername = sshUserName s { inputHostname = Just $ sshHostName smkSshInput s = SshInputmkSshInput :: SshData -> SshInput } , sshCapabilities = [] -- untested , needsPubKey = False , sshPort = inputPort s (maybe "" T.unpack $ inputDirectory s) (T.unpack $ fromJust $ inputHostname s) , sshRepoName = genSshRepoName , sshDirectory = fromMaybe "" $ inputDirectory s , sshUserName = inputUsername s { sshHostName = fromMaybe "" $ inputHostname smkSshData s = SshData mkSshData :: SshInput -> SshData - the result of such a form into a SshData. -}{- SshInput is only used for applicative form prompting, this convertsdata RepoStatus = NewRepo | ExistingRepo-- and is just being added.-- Is a repository a new one that's being created, or did it already exist deriving (Eq, Show) | ExistingSshKey | CachedPassword = Passworddata AuthMethod } , inputPort :: Int , inputDirectory :: Maybe Text , inputPassword :: Maybe Text , inputAuthMethod :: AuthMethod , inputUsername :: Maybe Text { inputHostname :: Maybe Textdata SshInput = SshInputsshConfigurator = page "Add a remote server" (Just Configuration)sshConfigurator :: Widget -> Handler Htmlimport Data.Ordimport Network.Socketimport qualified Data.Map as Mimport qualified Data.Text as Timport Utility.Envimport Utility.ThreadSchedulerimport Utility.FileModeimport Utility.Tmpimport Annex.Pathimport Assistant.CredPairCacheimport Types.Credsimport Assistant.RemoteControlimport Logs.UUIDimport Annex.UUIDimport qualified Remote.GCrypt as GCryptimport Git.Types (RemoteName)import Types.Remote (RemoteConfig)import Utility.Gpgimport Utility.UserInfoimport Types.StandardGroupsimport Remoteimport Logs.Remoteimport Assistant.WebApp.MakeRemoteimport Annex.Sshimport Assistant.Sshimport Assistant.WebApp.Gpgimport Assistant.WebApp.Commonmodule Assistant.WebApp.Configurators.Ssh where{-# LANGUAGE CPP #-}{-# LANGUAGE QuasiQuotes, TemplateHaskell, OverloadedStrings #-} -} - Licensed under the GNU AGPL version 3 or higher. - - Copyright 2012-2014 Joey Hess -{- git-annex assistant webapp configurator for ssh-based remotesad>TR+# j F Q  _ > = o /   M , @Z5!98isRsyncNet (Just host) = ".rsync.net" `T.isSuffixOf` T.toLower hostisRsyncNet Nothing = FalseisRsyncNet :: Maybe Text -> Bool sshSetup sshinput (torsyncnet remotecommand) (Just $ sshPubKey keypair) (a sshdata) ] , "mkdir -p " ++ T.unpack (sshDirectory sshdata) , "dd of=.ssh/authorized_keys oflag=append conv=notrunc" , "touch .ssh/authorized_keys" [ "mkdir -p .ssh" let remotecommand = intercalate ";" - rsync.net's shell does not support that. -} {- I'd prefer to separate commands with && , but ] , cmd , sshhost [ if knownhost then "" else sshOpt "StrictHostKeyChecking" "no" let torsyncnet cmd = filter (not . null) let sshhost = genSshHost (sshHostName sshdata) (sshUserName sshdata) } , sshCapabilities = [RsyncCapable] , needsPubKey = True { sshRepoName = reponame (mkSshData sshinput) sshdata <- liftIO $ setupSshKeyPair keypair $ keypair <- liftIO genSshKeyPair knownhost <- liftIO $ maybe (return False) knownHost (inputHostname sshinput)prepRsyncNet sshinput reponame a = doprepRsyncNet :: SshInput -> String -> (SshData -> Handler Html) -> Handler Html -} - in to ssh over stdin. - documentation recommends a dd methodd, where the line is fed - To append the ssh key to rsync.net's authorized_keys, their - - used on rsync.net. If successful, runs an action with its SshData.{- Prepares rsync.net ssh key and creates the directory that will be notinstalled = error "internal" notencrypted = error "Unexpectedly found a non-encrypted git repository, instead of the expected encrypted git repository." where enableGCrypt sshdata reponame checkGCryptRepoEncryption (genSshUrl sshdata) notencrypted notinstalled $ prepRsyncNet sshinput reponame $ \sshdata -> whenGcryptInstalled $enableRsyncNetGCrypt sshinput reponame = enableRsyncNetGCrypt :: SshInput -> RemoteName -> Handler Html prepRsyncNet sshinput reponame $ makeSshRepo ExistingRepo . rsyncOnlyenableRsyncNet sshinput reponame = enableRsyncNet :: SshInput -> String -> Handler Html gitinit = "git init --bare " ++ T.unpack (sshDirectory sshdata) sshhost = genSshHost (sshHostName sshdata) (sshUserName sshdata) where makeGCryptRepo NewRepo keyid sshdata sshSetup (mkSshInput sshdata) [sshhost, gitinit] Nothing $getMakeRsyncNetGCryptR sshdata (RepoKey keyid) = whenGcryptInstalled $ withNewSecretKey $ getMakeRsyncNetGCryptR sshdata . RepoKeygetMakeRsyncNetGCryptR sshdata NoRepoKey = whenGcryptInstalled $getMakeRsyncNetGCryptR :: SshData -> RepoKey -> Handler Html{- Make a new gcrypt special remote on rsync.net. -}getMakeRsyncNetSharedR = makeSshRepo NewRepo . rsyncOnly