enabling rsync.net gcrypt repos

Still need to detect when the user is trying to create a repo
that already exists, and jump to the enabling code.
This commit is contained in:
Joey Hess 2013-09-26 23:28:25 -04:00
parent 538910a6f9
commit 1550759220
8 changed files with 71 additions and 38 deletions

View file

@ -47,10 +47,10 @@ makeSshRemote forcersync sshdata mcost = do
{- Generates a ssh or rsync url from a SshData. -} {- Generates a ssh or rsync url from a SshData. -}
sshUrl :: Bool -> SshData -> String sshUrl :: Bool -> SshData -> String
sshUrl forcersync sshdata = T.unpack $ T.concat $ sshUrl forcersync sshdata = addtrailingslash $ T.unpack $ T.concat $
if (forcersync || rsyncOnly sshdata) if (forcersync || rsyncOnly sshdata)
then [u, h, T.pack ":", sshDirectory sshdata, T.pack "/"] then [u, h, T.pack ":", sshDirectory sshdata]
else [T.pack "ssh://", u, h, d, T.pack "/"] else [T.pack "ssh://", u, h, d]
where where
u = maybe (T.pack "") (\v -> T.concat [v, T.pack "@"]) $ sshUserName sshdata u = maybe (T.pack "") (\v -> T.concat [v, T.pack "@"]) $ sshUserName sshdata
h = sshHostName sshdata h = sshHostName sshdata
@ -58,6 +58,9 @@ sshUrl forcersync sshdata = T.unpack $ T.concat $
| T.pack "/" `T.isPrefixOf` sshDirectory sshdata = sshDirectory sshdata | T.pack "/" `T.isPrefixOf` sshDirectory sshdata = sshDirectory sshdata
| T.pack "~/" `T.isPrefixOf` sshDirectory sshdata = T.concat [T.pack "/", sshDirectory sshdata] | T.pack "~/" `T.isPrefixOf` sshDirectory sshdata = T.concat [T.pack "/", sshDirectory sshdata]
| otherwise = T.concat [T.pack "/~/", sshDirectory sshdata] | otherwise = T.concat [T.pack "/~/", sshDirectory sshdata]
addtrailingslash s
| "/" `isSuffixOf` s = s
| otherwise = s ++ "/"
{- Runs an action that returns a name of the remote, and finishes adding it. -} {- Runs an action that returns a name of the remote, and finishes adding it. -}
addRemote :: Annex RemoteName -> Annex Remote addRemote :: Annex RemoteName -> Annex Remote

View file

@ -22,6 +22,10 @@ import Types.StandardGroups
import Utility.UserInfo import Utility.UserInfo
import Utility.Gpg import Utility.Gpg
import Assistant.Sync import Assistant.Sync
import qualified Remote.GCrypt as GCrypt
import qualified Git.GCrypt
import Types.Remote (RemoteConfigKey)
import Git.Remote
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Map as M import qualified Data.Map as M
@ -131,39 +135,48 @@ postAddSshR = sshConfigurator $ do
sshTestModal :: Widget sshTestModal :: Widget
sshTestModal = $(widgetFile "configurators/ssh/testmodal") sshTestModal = $(widgetFile "configurators/ssh/testmodal")
{- This only handles gcrypt repositories that are located on ssh servers; {- Note that there's no EnableSshR because ssh remotes are not special
- ones on local drives are handled via another part of the UI. -}
getEnableGCryptR :: UUID -> Handler Html
getEnableGCryptR = postEnableGCryptR
postEnableGCryptR :: UUID -> Handler Html
postEnableGCryptR u = error "TODO"
{- To enable an existing rsync special remote, parse the SshInput from
- its rsyncurl, and display a form whose only real purpose is to check
- if ssh public keys need to be set up. From there, we can proceed with
- the usual repo setup; all that code is idempotent.
-
- Note that there's no EnableSshR because ssh remotes are not special
- remotes, and so their configuration is not shared between repositories. - remotes, and so their configuration is not shared between repositories.
-} -}
getEnableRsyncR :: UUID -> Handler Html getEnableRsyncR :: UUID -> Handler Html
getEnableRsyncR = postEnableRsyncR getEnableRsyncR = postEnableRsyncR
postEnableRsyncR :: UUID -> Handler Html postEnableRsyncR :: UUID -> Handler Html
postEnableRsyncR u = do postEnableRsyncR = enableSpecialSshRemote "rsyncurl" enableRsyncNet enablersync
where
enablersync sshdata = redirect $ ConfirmSshR $
sshdata { rsyncOnly = True }
{- This only handles gcrypt repositories that are located on ssh servers;
- ones on local drives are handled via another part of the UI. -}
getEnableGCryptR :: UUID -> Handler Html
getEnableGCryptR = postEnableGCryptR
postEnableGCryptR :: UUID -> Handler Html
postEnableGCryptR u = whenGcryptInstalled $
enableSpecialSshRemote "gitrepo" enableRsyncNetGCrypt enablersync u
where
enablersync sshdata = error "TODO enable ssh gcrypt remote"
{- To enable an special remote that uses ssh as its transport,
- parse a config key to get its url, and display a form whose
- only real purpose is to check if ssh public keys need to be
- set up.
-}
enableSpecialSshRemote :: RemoteConfigKey -> (SshInput -> RemoteName -> Handler Html) -> (SshData -> Handler ()) -> UUID -> Handler Html
enableSpecialSshRemote urlkey rsyncnetsetup genericsetup u = do
m <- fromMaybe M.empty . M.lookup u <$> liftAnnex readRemoteLog m <- fromMaybe M.empty . M.lookup u <$> liftAnnex readRemoteLog
case (parseSshRsyncUrl =<< M.lookup "rsyncurl" m, M.lookup "name" m) of case (parseSshRsyncUrl =<< M.lookup urlkey m, M.lookup "name" m) of
(Just sshinput, Just reponame) -> sshConfigurator $ do (Just sshinput, Just reponame) -> sshConfigurator $ do
((result, form), enctype) <- liftH $ ((result, form), enctype) <- liftH $
runFormPost $ renderBootstrap $ sshInputAForm textField sshinput runFormPost $ renderBootstrap $ sshInputAForm textField sshinput
case result of case result of
FormSuccess sshinput' FormSuccess sshinput'
| isRsyncNet (inputHostname sshinput') -> | isRsyncNet (inputHostname sshinput') ->
void $ liftH $ enableRsyncNet sshinput' reponame (const noop) void $ liftH $ rsyncnetsetup sshinput' reponame
| otherwise -> do | otherwise -> do
s <- liftIO $ testServer sshinput' s <- liftIO $ testServer sshinput'
case s of case s of
Left status -> showform form enctype status Left status -> showform form enctype status
Right sshdata -> enable sshdata Right sshdata -> liftH $ genericsetup sshdata
{ sshRepoName = reponame } { sshRepoName = reponame }
_ -> showform form enctype UntestedServer _ -> showform form enctype UntestedServer
_ -> redirect AddSshR _ -> redirect AddSshR
@ -171,8 +184,6 @@ postEnableRsyncR u = do
showform form enctype status = do showform form enctype status = do
description <- liftAnnex $ T.pack <$> prettyUUID u description <- liftAnnex $ T.pack <$> prettyUUID u
$(widgetFile "configurators/ssh/enable") $(widgetFile "configurators/ssh/enable")
enable sshdata = liftH $ redirect $ ConfirmSshR $
sshdata { rsyncOnly = True }
{- Converts a rsyncurl value to a SshInput. But only if it's a ssh rsync {- Converts a rsyncurl value to a SshInput. But only if it's a ssh rsync
- url; rsync:// urls or bare path names are not supported. - url; rsync:// urls or bare path names are not supported.
@ -377,10 +388,28 @@ getMakeRsyncNetGCryptR sshdata (RepoKey keyid) = whenGcryptInstalled $ do
sshhost = genSshHost (sshHostName sshdata) (sshUserName sshdata) sshhost = genSshHost (sshHostName sshdata) (sshUserName sshdata)
gitinit = "git init --bare " ++ T.unpack (sshDirectory sshdata) gitinit = "git init --bare " ++ T.unpack (sshDirectory sshdata)
enableRsyncNet :: SshInput -> String -> (Remote -> Handler ()) -> Handler Html enableRsyncNet :: SshInput -> String -> Handler Html
enableRsyncNet sshinput reponame setup = enableRsyncNet sshinput reponame =
prepRsyncNet sshinput reponame $ \sshdata -> prepRsyncNet sshinput reponame $ \sshdata ->
makeSshRepo True setup sshdata makeSshRepo True (const noop) sshdata
enableRsyncNetGCrypt :: SshInput -> String -> Handler Html
enableRsyncNetGCrypt sshinput reponame =
prepRsyncNet sshinput reponame $ \sshdata -> do
let repourl = sshUrl True sshdata
pr <- liftAnnex $ inRepo $ Git.GCrypt.probeRepo repourl
case pr of
Git.GCrypt.Decryptable -> do
r <- liftAnnex $ addRemote $
enableSpecialRemote reponame GCrypt.remote $ M.fromList
[("gitrepo", repourl)]
setupGroup r
liftAssistant $ syncRemote r
redirect $ EditNewCloudRepositoryR $ Remote.uuid r
Git.GCrypt.NotDecryptable ->
error "The drive contains a git repository that is encrypted with a GnuPG key that you do not have."
Git.GCrypt.NotEncrypted ->
error "Unexpectedly found a non-encrypted git repository, instead of the expected encrypted git repository."
{- Prepares rsync.net ssh key, and if successful, runs an action with {- Prepares rsync.net ssh key, and if successful, runs an action with
- its SshData. -} - its SshData. -}

View file

@ -22,6 +22,7 @@ import Logs.UUID
import Annex.UUID import Annex.UUID
import qualified Option import qualified Option
import qualified Annex import qualified Annex
import Git.Remote
def :: [Command] def :: [Command]
def = [noCommit $ withOptions [allrepos] $ command "list" paramPaths seek def = [noCommit $ withOptions [allrepos] $ command "list" paramPaths seek
@ -68,7 +69,6 @@ start l file (key, _) = do
liftIO $ putStrLn $ format (map (\(u, _, t) -> (t, S.member u ls)) l) file liftIO $ putStrLn $ format (map (\(u, _, t) -> (t, S.member u ls)) l) file
stop stop
type RemoteName = String
type Present = Bool type Present = Bool
header :: [(RemoteName, TrustLevel)] -> String header :: [(RemoteName, TrustLevel)] -> String

View file

@ -15,6 +15,7 @@ import Git.Construct
import qualified Git.Config as Config import qualified Git.Config as Config
import qualified Git.Command as Command import qualified Git.Command as Command
import Utility.Gpg import Utility.Gpg
import Git.Remote
urlPrefix :: String urlPrefix :: String
urlPrefix = "gcrypt::" urlPrefix = "gcrypt::"
@ -66,7 +67,6 @@ probeRepo loc baserepo = do
ExitFailure 1 -> NotDecryptable ExitFailure 1 -> NotDecryptable
ExitFailure _ -> NotEncrypted ExitFailure _ -> NotEncrypted
type RemoteName = String
type GCryptId = String type GCryptId = String
{- gcrypt gives each encrypted repository a uique gcrypt-id, {- gcrypt gives each encrypted repository a uique gcrypt-id,

View file

@ -56,6 +56,7 @@ import Logs.Trust
import Logs.Location hiding (logStatus) import Logs.Location hiding (logStatus)
import Remote.List import Remote.List
import Config import Config
import Git.Remote
{- Map from UUIDs of Remotes to a calculated value. -} {- Map from UUIDs of Remotes to a calculated value. -}
remoteMap :: (Remote -> a) -> Annex (M.Map UUID a) remoteMap :: (Remote -> a) -> Annex (M.Map UUID a)
@ -68,7 +69,7 @@ remoteMap c = M.fromList . map (\r -> (uuid r, c r)) .
uuidDescriptions :: Annex (M.Map UUID String) uuidDescriptions :: Annex (M.Map UUID String)
uuidDescriptions = M.unionWith addName <$> uuidMap <*> remoteMap name uuidDescriptions = M.unionWith addName <$> uuidMap <*> remoteMap name
addName :: String -> String -> String addName :: String -> RemoteName -> String
addName desc n addName desc n
| desc == n = desc | desc == n = desc
| null desc = n | null desc = n
@ -76,12 +77,12 @@ addName desc n
{- When a name is specified, looks up the remote matching that name. {- When a name is specified, looks up the remote matching that name.
- (Or it can be a UUID.) -} - (Or it can be a UUID.) -}
byName :: Maybe String -> Annex (Maybe Remote) byName :: Maybe RemoteName -> Annex (Maybe Remote)
byName Nothing = return Nothing byName Nothing = return Nothing
byName (Just n) = either error Just <$> byName' n byName (Just n) = either error Just <$> byName' n
{- Like byName, but the remote must have a configured UUID. -} {- Like byName, but the remote must have a configured UUID. -}
byNameWithUUID :: Maybe String -> Annex (Maybe Remote) byNameWithUUID :: Maybe RemoteName -> Annex (Maybe Remote)
byNameWithUUID = checkuuid <=< byName byNameWithUUID = checkuuid <=< byName
where where
checkuuid Nothing = return Nothing checkuuid Nothing = return Nothing
@ -93,7 +94,7 @@ byNameWithUUID = checkuuid <=< byName
else error e else error e
| otherwise = return $ Just r | otherwise = return $ Just r
byName' :: String -> Annex (Either String Remote) byName' :: RemoteName -> Annex (Either String Remote)
byName' "" = return $ Left "no remote specified" byName' "" = return $ Left "no remote specified"
byName' n = handle . filter matching <$> remoteList byName' n = handle . filter matching <$> remoteList
where where
@ -104,7 +105,7 @@ byName' n = handle . filter matching <$> remoteList
{- Looks up a remote by name (or by UUID, or even by description), {- Looks up a remote by name (or by UUID, or even by description),
- and returns its UUID. Finds even remotes that are not configured in - and returns its UUID. Finds even remotes that are not configured in
- .git/config. -} - .git/config. -}
nameToUUID :: String -> Annex UUID nameToUUID :: RemoteName -> Annex UUID
nameToUUID "." = getUUID -- special case for current repo nameToUUID "." = getUUID -- special case for current repo
nameToUUID "here" = getUUID nameToUUID "here" = getUUID
nameToUUID "" = error "no remote specified" nameToUUID "" = error "no remote specified"

View file

@ -18,6 +18,7 @@ import Types.UUID
import Types.GitConfig import Types.GitConfig
import Config.Cost import Config.Cost
import Utility.Metered import Utility.Metered
import Git.Remote
type RemoteConfigKey = String type RemoteConfigKey = String
type RemoteConfig = M.Map RemoteConfigKey String type RemoteConfig = M.Map RemoteConfigKey String
@ -42,7 +43,7 @@ data RemoteA a = Remote {
-- each Remote has a unique uuid -- each Remote has a unique uuid
uuid :: UUID, uuid :: UUID,
-- each Remote has a human visible name -- each Remote has a human visible name
name :: String, name :: RemoteName,
-- Remotes have a use cost; higher is more expensive -- Remotes have a use cost; higher is more expensive
cost :: Cost, cost :: Cost,
-- Transfers a key to the remote. -- Transfers a key to the remote.

View file

@ -1,7 +1,7 @@
<div .span9 .hero-unit> <div .span9 .hero-unit>
<h2> <h2>
$if new $if new
Repository created Setup complete
$else $else
Editing repository Editing repository
$if new $if new

View file

@ -2,9 +2,8 @@
<h2> <h2>
Enabling #{description} Enabling #{description}
<p> <p>
Another repository uses this server, but the server is not # To enable this repository, you first need to check that its ssh server #
yet enabled for use here. The first step to enable it is to check if it's # is usable from here.
usable here.
<p> <p>
<p> <p>
<form method="post" .form-horizontal enctype=#{enctype}> <form method="post" .form-horizontal enctype=#{enctype}>