This commit is contained in:
Joey Hess 2011-04-16 21:41:14 -04:00
parent 98e3817466
commit 991efddfa1
2 changed files with 86 additions and 65 deletions

View file

@ -42,17 +42,20 @@ gen :: Git.Repo -> UUID -> Maybe RemoteConfig -> Annex (Remote Annex)
gen r u c = do gen r u c = do
dir <- getConfig r "directory" (error "missing directory") dir <- getConfig r "directory" (error "missing directory")
cst <- remoteCost r cheapRemoteCost cst <- remoteCost r cheapRemoteCost
return $ Remote { return $ encryptedRemote c
uuid = u, (storeEncrypted dir)
cost = cst, (retrieveEncrypted dir)
name = Git.repoDescribe r, Remote {
storeKey = storeKeyEncrypted c $ store dir, uuid = u,
retrieveKeyFile = retrieveKeyFileEncrypted c $ retrieve dir, cost = cst,
removeKey = removeKeyEncrypted c $ remove dir, name = Git.repoDescribe r,
hasKey = hasKeyEncrypted c $ checkPresent dir, storeKey = store dir,
hasKeyCheap = True, retrieveKeyFile = retrieve dir,
config = Nothing removeKey = remove dir,
} hasKey = checkPresent dir,
hasKeyCheap = True,
config = Nothing
}
directorySetup :: UUID -> RemoteConfig -> Annex RemoteConfig directorySetup :: UUID -> RemoteConfig -> Annex RemoteConfig
directorySetup u c = do directorySetup u c = do
@ -74,43 +77,47 @@ dirKey d k = d </> hashDirMixed k </> f </> f
where where
f = keyFile k f = keyFile k
store :: FilePath -> Key -> Maybe (Cipher, Key) -> Annex Bool store :: FilePath -> Key -> Annex Bool
store d k c = do store d k = do
g <- Annex.gitRepo g <- Annex.gitRepo
let src = gitAnnexLocation g k let src = gitAnnexLocation g k
liftIO $ catch (copy src) (const $ return False) let dest = dirKey d k
where liftIO $ catch (storeHelper dest $ copyFile src dest) (const $ return False)
copy src = case c of
Just (cipher, enckey) -> do
content <- L.readFile src
let dest = dirKey d enckey
prep dest
withEncryptedContent cipher content $ \s -> do
L.writeFile dest s
cleanup True dest
_ -> do
let dest = dirKey d k
prep dest
ok <- copyFile src dest
cleanup ok dest
prep dest = liftIO $ do
let dir = parentDir dest
createDirectoryIfMissing True dir
allowWrite dir
cleanup ok dest = do
when ok $ do
let dir = parentDir dest
preventWrite dest
preventWrite dir
return ok
retrieve :: FilePath -> Key -> FilePath -> Maybe (Cipher, Key) -> Annex Bool storeEncrypted :: FilePath -> (Cipher, Key) -> Key -> Annex Bool
retrieve d k f Nothing = liftIO $ copyFile (dirKey d k) f storeEncrypted d (cipher, enck) k = do
retrieve d k f (Just (cipher, enckey)) = g <- Annex.gitRepo
liftIO $ flip catch (const $ return False) $ do let src = gitAnnexLocation g k
content <- L.readFile (dirKey d enckey) let dest = dirKey d enck
withDecryptedContent cipher content $ L.writeFile f liftIO $ catch (storeHelper dest $ encrypt src dest) (const $ return False)
return True where
encrypt src dest = do
content <- L.readFile src
withEncryptedContent cipher content $ L.writeFile dest
return True
storeHelper :: FilePath -> IO Bool -> IO Bool
storeHelper dest a = do
let dir = parentDir dest
createDirectoryIfMissing True dir
allowWrite dir
ok <- a
when ok $ do
preventWrite dest
preventWrite dir
return ok
retrieve :: FilePath -> Key -> FilePath -> Annex Bool
retrieve d k f = liftIO $ copyFile (dirKey d k) f
retrieveEncrypted :: FilePath -> (Cipher, Key) -> FilePath -> Annex Bool
retrieveEncrypted d (cipher, enck) f =
liftIO $ catch decrypt (const $ return False)
where
decrypt = do
content <- L.readFile (dirKey d enck)
withDecryptedContent cipher content $ L.writeFile f
return True
remove :: FilePath -> Key -> Annex Bool remove :: FilePath -> Key -> Annex Bool
remove d k = liftIO $ catch del (const $ return False) remove d k = liftIO $ catch del (const $ return False)

View file

@ -33,16 +33,39 @@ encryptionSetup c =
cipher <- liftIO a cipher <- liftIO a
return $ M.delete "encryption" $ storeCipher c cipher return $ M.delete "encryption" $ storeCipher c cipher
{- Helpers that can be applied to a Remote's normal actions to {- Modifies a Remote to support encryption.
- add crypto support. -} -
storeKeyEncrypted :: Maybe RemoteConfig -> (Key -> Maybe (Cipher, Key) -> Annex a) -> Key -> Annex a - Two additional functions must be provided by the remote,
storeKeyEncrypted c a k = a k =<< cipherKey c k - to support storing and retrieving encrypted content. -}
retrieveKeyFileEncrypted :: Maybe RemoteConfig -> (Key -> FilePath -> Maybe (Cipher, Key) -> Annex a) -> Key -> FilePath -> Annex a encryptedRemote
retrieveKeyFileEncrypted c a k f = a k f =<< cipherKey c k :: Maybe RemoteConfig
removeKeyEncrypted :: Maybe RemoteConfig -> (Key -> Annex a) -> Key -> Annex a -> ((Cipher, Key) -> Key -> Annex Bool)
removeKeyEncrypted = withEncryptedKey -> ((Cipher, Key) -> FilePath -> Annex Bool)
hasKeyEncrypted :: Maybe RemoteConfig -> (Key -> Annex a) -> Key -> Annex a -> Remote Annex
hasKeyEncrypted = withEncryptedKey -> Remote Annex
encryptedRemote c storeKeyEncrypted retrieveKeyFileEncrypted r =
r {
storeKey = store,
retrieveKeyFile = retrieve,
removeKey = withkey $ removeKey r,
hasKey = withkey $ hasKey r
}
where
store k = do
v <- cipherKey c k
case v of
Nothing -> (storeKey r) k
Just x -> storeKeyEncrypted x k
retrieve k f = do
v <- cipherKey c k
case v of
Nothing -> (retrieveKeyFile r) k f
Just x -> retrieveKeyFileEncrypted x f
withkey a k = do
v <- cipherKey c k
case v of
Nothing -> a k
Just (_, k') -> a k'
{- Gets encryption Cipher, and encrypted version of Key. {- Gets encryption Cipher, and encrypted version of Key.
- -
@ -64,12 +87,3 @@ cipherKey (Just c) k = do
ret cipher = do ret cipher = do
k' <- liftIO $ encryptKey cipher k k' <- liftIO $ encryptKey cipher k
return $ Just (cipher, k') return $ Just (cipher, k')
{- Passes the encrypted version of the key to the action when encryption
- is enabled, and the non-encrypted version otherwise. -}
withEncryptedKey :: Maybe RemoteConfig -> (Key -> Annex a) -> Key -> Annex a
withEncryptedKey c a k = do
v <- cipherKey c k
case v of
Nothing -> a k
Just (_, k') -> a k'