allow making encrypted rsync special remotes
wow, that was easy!
This commit is contained in:
parent
5228ba9314
commit
014974a7da
6 changed files with 105 additions and 64 deletions
|
@ -195,25 +195,37 @@ getAddDriveR = bootstrap (Just Config) $ do
|
|||
hostname <- maybe "host" id <$> liftIO getHostname
|
||||
hostlocation <- fromRepo Git.repoLocation
|
||||
liftIO $ inDir dir $
|
||||
void $ addRemote' hostname hostlocation
|
||||
addRemote name dir
|
||||
void $ makeGitRemote hostname hostlocation
|
||||
addRemote $ makeGitRemote name dir
|
||||
|
||||
{- Adds a remote, if there is not already one with the same location. -}
|
||||
addRemote :: String -> String -> Annex Remote
|
||||
addRemote name location = do
|
||||
name' <- addRemote' name location
|
||||
{- Runs an action that returns a name of the remote, and finishes adding it. -}
|
||||
addRemote :: Annex String -> Annex Remote
|
||||
addRemote a = do
|
||||
name <- a
|
||||
void $ remoteListRefresh
|
||||
maybe (error "failed to add remote") return =<< Remote.byName (Just name')
|
||||
maybe (error "failed to add remote") return =<< Remote.byName (Just name)
|
||||
|
||||
addRemote' :: String -> String -> Annex String
|
||||
addRemote' name location = inRepo $ \r ->
|
||||
{- Returns the name of the git remote it created. If there's already a
|
||||
- remote at the location, returns its name. -}
|
||||
makeGitRemote :: String -> String -> Annex String
|
||||
makeGitRemote basename location = makeRemote basename location $ \name ->
|
||||
void $ inRepo $
|
||||
Git.Command.runBool "remote"
|
||||
[Param "add", Param name, Param location]
|
||||
|
||||
{- If there's not already a remote at the location, adds it using the
|
||||
- action, which is passed the name of the remote to make.
|
||||
-
|
||||
- Returns the name of the remote. -}
|
||||
makeRemote :: String -> String -> (String -> Annex ()) -> Annex String
|
||||
makeRemote basename location a = do
|
||||
r <- fromRepo id
|
||||
if (null $ filter samelocation $ Git.remotes r)
|
||||
then do
|
||||
let name' = uniqueRemoteName r name 0
|
||||
void $ Git.Command.runBool "remote"
|
||||
[Param "add", Param name', Param location] r
|
||||
return name'
|
||||
else return name
|
||||
let name = uniqueRemoteName r basename 0
|
||||
a name
|
||||
return name
|
||||
else return basename
|
||||
where
|
||||
samelocation x = Git.repoLocation x == location
|
||||
|
||||
|
|
|
@ -15,10 +15,16 @@ import Assistant.WebApp.Types
|
|||
import Assistant.WebApp.SideBar
|
||||
import Utility.Yesod
|
||||
import Assistant.WebApp.Configurators.Local
|
||||
import qualified Types.Remote as R
|
||||
import qualified Remote.Rsync as Rsync
|
||||
import qualified Command.InitRemote
|
||||
import Logs.UUID
|
||||
import Logs.Remote
|
||||
|
||||
import Yesod
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Map as M
|
||||
import Network.BSD
|
||||
import System.Posix.User
|
||||
import System.Process (CreateProcess(..))
|
||||
|
@ -156,16 +162,6 @@ testServer sshserver = do
|
|||
report r = "echo " ++ token r
|
||||
sshopt k v = concat ["-o", k, "=", v]
|
||||
|
||||
{- ssh://user@host/path -}
|
||||
genSshUrl :: SshData -> Text
|
||||
genSshUrl s = T.concat ["ssh://", u, h, d, "/"]
|
||||
where
|
||||
u = maybe "" (\v -> T.concat [v, "@"]) $ sshUserName s
|
||||
h = sshHostName s
|
||||
d
|
||||
| "/" `T.isPrefixOf` sshDirectory s = d
|
||||
| otherwise = T.concat ["/~/", sshDirectory s]
|
||||
|
||||
{- user@host or host -}
|
||||
genSshHost :: Text -> Maybe Text -> String
|
||||
genSshHost host user = maybe "" (\v -> T.unpack v ++ "@") user ++ T.unpack host
|
||||
|
@ -239,52 +235,75 @@ getConfirmSshR sshdata = sshConfigurator $ do
|
|||
let haspubkey = isJust $ pubKey sshdata
|
||||
$(widgetFile "configurators/confirmssh")
|
||||
|
||||
{- Creates the repository on the remote. Does any necessary ssh key setup.
|
||||
-
|
||||
- This is a one-sided remote setup; the remote server probably does not
|
||||
- have a route to the client here.
|
||||
-}
|
||||
getMakeSshR :: SshData -> Handler RepHtml
|
||||
getMakeSshR sshdata = do
|
||||
getMakeSshGitR :: SshData -> Handler RepHtml
|
||||
getMakeSshGitR = makeSsh False
|
||||
|
||||
getMakeSshRsyncR :: SshData -> Handler RepHtml
|
||||
getMakeSshRsyncR = makeSsh True
|
||||
|
||||
makeSsh :: Bool -> SshData -> Handler RepHtml
|
||||
makeSsh rsync sshdata = do
|
||||
(transcript, ok) <- liftIO $ sshTranscript [sshhost, remoteCommand]
|
||||
if ok
|
||||
then do
|
||||
r <- runAnnex undefined $
|
||||
addRemote (sshRepoName sshdata) sshurl
|
||||
r <- runAnnex undefined makerepo
|
||||
syncRemote r
|
||||
redirect RepositoriesR
|
||||
else showerr transcript
|
||||
where
|
||||
sshhost = genSshHost (sshHostName sshdata) (sshUserName sshdata)
|
||||
authline = authorizedKeysLine sshdata
|
||||
remotedir = T.unpack $ sshDirectory sshdata
|
||||
sshurl = T.unpack $ genSshUrl sshdata
|
||||
remoteCommand = join "&&" $ catMaybes
|
||||
[ Just $ "mkdir -p " ++ shellEscape remotedir
|
||||
, Just $ "cd " ++ shellEscape remotedir
|
||||
, Just $ join "&&" makerepo
|
||||
, if null authline
|
||||
then Nothing
|
||||
else Just $ join "&&" makeAuthorizedKeys
|
||||
]
|
||||
makerepo
|
||||
| rsyncOnly sshdata = []
|
||||
| otherwise =
|
||||
[ "git init --bare --shared"
|
||||
, "git annex init"
|
||||
]
|
||||
makeAuthorizedKeys =
|
||||
[ "mkdir -p ~/.ssh"
|
||||
, "touch ~/.ssh/authorized_keys"
|
||||
, "chmod 600 ~/.ssh/authorized_keys"
|
||||
, unwords
|
||||
[ "echo"
|
||||
, shellEscape authline
|
||||
, ">>~/.ssh/authorized_keys"
|
||||
]
|
||||
, if rsync then Nothing else Just $ "git init --bare --shared"
|
||||
, if rsync then Nothing else Just $ "git annex init"
|
||||
, makeAuthorizedKeys sshdata
|
||||
]
|
||||
showerr msg = sshConfigurator $
|
||||
$(widgetFile "configurators/makessherror")
|
||||
{- This is a one-sided remote setup; the remote server
|
||||
- probably does not have a route to the client here. -}
|
||||
makerepo = addRemote $
|
||||
(if rsync then makeRsyncRemote else makeGitRemote)
|
||||
(sshRepoName sshdata) sshurl
|
||||
sshurl = T.unpack $ T.concat $ if rsync
|
||||
then [u, h, ":", sshDirectory sshdata, "/"]
|
||||
else ["ssh://", u, h, d, "/"]
|
||||
where
|
||||
u = maybe "" (\v -> T.concat [v, "@"]) $ sshUserName sshdata
|
||||
h = sshHostName sshdata
|
||||
d
|
||||
| "/" `T.isPrefixOf` sshDirectory sshdata = d
|
||||
| otherwise = T.concat ["/~/", sshDirectory sshdata]
|
||||
|
||||
{- Inits a rsync special remote, and returns the name of the remote. -}
|
||||
makeRsyncRemote :: String -> String -> Annex String
|
||||
makeRsyncRemote name location = makeRemote name location $ const $ do
|
||||
(u, c) <- Command.InitRemote.findByName name
|
||||
c' <- R.setup Rsync.remote u $ M.union config c
|
||||
describeUUID u name
|
||||
configSet u c'
|
||||
where
|
||||
config = M.fromList
|
||||
[ ("encryption", "shared")
|
||||
, ("rsyncurl", location)
|
||||
, ("type", "rsync")
|
||||
]
|
||||
|
||||
makeAuthorizedKeys :: SshData -> Maybe String
|
||||
makeAuthorizedKeys sshdata
|
||||
| pubKey sshdata == Nothing = Nothing
|
||||
| otherwise = Just $ join "&&" $
|
||||
[ "mkdir -p ~/.ssh"
|
||||
, "touch ~/.ssh/authorized_keys"
|
||||
, "chmod 600 ~/.ssh/authorized_keys"
|
||||
, unwords
|
||||
[ "echo"
|
||||
, shellEscape $ authorizedKeysLine sshdata
|
||||
, ">>~/.ssh/authorized_keys"
|
||||
]
|
||||
]
|
||||
|
||||
authorizedKeysLine :: SshData -> String
|
||||
authorizedKeysLine sshdata@(SshData { pubKey = Just pubkey })
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
/config/repository/add/drive AddDriveR GET
|
||||
/config/repository/add/ssh AddSshR GET
|
||||
/config/repository/add/ssh/confirm/#SshData ConfirmSshR GET
|
||||
/config/repository/add/ssh/make/#SshData MakeSshR GET
|
||||
/config/repository/add/ssh/make/git/#SshData MakeSshGitR GET
|
||||
/config/repository/add/ssh/make/rsync/#SshData MakeSshRsyncR GET
|
||||
/config/repository/first FirstRepositoryR GET
|
||||
|
||||
/transfers/#NotificationId TransfersR GET
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
<div .span9 .hero-unit>
|
||||
<h2>
|
||||
Adding a remote server using ssh
|
||||
<p>
|
||||
Clone this repository to a ssh server. Your data will be #
|
||||
uploaded to the server. If you set up other devices to use the same #
|
||||
server, they will all be kept in sync, using the server as a central #
|
||||
hub.
|
||||
<p>
|
||||
You can use nearly any server that has ssh and rsync. For example, you #
|
||||
could use a <a href="http://linode.com/">Linode</a> or another VPS, or #
|
||||
|
|
|
@ -5,9 +5,23 @@
|
|||
<div .span8>
|
||||
<p>
|
||||
The server has been verified to be usable.
|
||||
$if not (rsyncOnly sshdata)
|
||||
<p>
|
||||
You have two options for how to use the server.
|
||||
<p>
|
||||
<a .btn .btn-primary href="@{MakeSshGitR sshdata}" onclick="$('#setupmodal').modal('show');">
|
||||
Use a git repository on the server
|
||||
<br>
|
||||
All your data will be uploaded to the server. If you set up other #
|
||||
devices to use the same server, they will all be kept in sync, #
|
||||
using the server as a central hub. #
|
||||
<p>
|
||||
<a .btn .btn-primary href="@{MakeSshR sshdata}" onclick="$('#setupmodal').modal('show');">
|
||||
Clone this repository to the remote server
|
||||
<a .btn .btn-primary href="@{MakeSshRsyncR sshdata}" onclick="$('#setupmodal').modal('show');">
|
||||
Use an encrypted rsync repository on the server
|
||||
<br>
|
||||
The contents of your files will be stored, fully encrypted, on the #
|
||||
server. The server will not store other information about your #
|
||||
git repository.
|
||||
<div .span4>
|
||||
$if haspubkey
|
||||
<div .alert .alert-info>
|
||||
|
|
|
@ -6,5 +6,5 @@
|
|||
<p>
|
||||
Transcript: #{msg}
|
||||
<p>
|
||||
<a .btn .btn-primary href="@{MakeSshR sshdata}">
|
||||
<a .btn .btn-primary href="#">
|
||||
Retry
|
||||
|
|
Loading…
Add table
Reference in a new issue