2011-04-17 04:40:23 +00:00
|
|
|
{- common functions for encryptable remotes
|
2011-04-16 17:25:27 +00:00
|
|
|
-
|
|
|
|
- Copyright 2011 Joey Hess <joey@kitenet.net>
|
|
|
|
-
|
|
|
|
- Licensed under the GNU GPL version 3 or higher.
|
|
|
|
-}
|
|
|
|
|
2011-04-17 04:40:23 +00:00
|
|
|
module Remote.Encryptable where
|
2011-04-16 17:25:27 +00:00
|
|
|
|
|
|
|
import qualified Data.Map as M
|
|
|
|
import Control.Monad.State (liftIO)
|
|
|
|
|
|
|
|
import Types
|
|
|
|
import RemoteClass
|
|
|
|
import Crypto
|
2011-04-16 22:22:52 +00:00
|
|
|
import qualified Annex
|
|
|
|
import Messages
|
2011-04-17 05:13:21 +00:00
|
|
|
import Config
|
2011-04-16 17:25:27 +00:00
|
|
|
|
|
|
|
{- Encryption setup for a remote. The user must specify whether to use
|
|
|
|
- an encryption key, or not encrypt. An encrypted cipher is created, or is
|
|
|
|
- updated to be accessible to an additional encryption key. -}
|
|
|
|
encryptionSetup :: RemoteConfig -> Annex RemoteConfig
|
|
|
|
encryptionSetup c =
|
|
|
|
case (M.lookup "encryption" c, extractCipher c) of
|
|
|
|
(Nothing, Nothing) -> error "Specify encryption=key or encryption=none"
|
2011-04-16 23:45:59 +00:00
|
|
|
(Just "none", Nothing) -> return c
|
|
|
|
(Just "none", Just _) -> error "Cannot change encryption type of existing remote."
|
2011-04-16 17:25:27 +00:00
|
|
|
(Nothing, Just _) -> return c
|
2011-04-17 22:18:27 +00:00
|
|
|
(Just _, Nothing) -> use "encryption setup" $ genCipher c
|
|
|
|
(Just _, Just v) -> use "encryption updated" $ updateCipher c v
|
2011-04-16 17:25:27 +00:00
|
|
|
where
|
2011-04-17 22:18:27 +00:00
|
|
|
use m a = do
|
2011-04-16 17:25:27 +00:00
|
|
|
cipher <- liftIO a
|
2011-04-17 22:18:27 +00:00
|
|
|
showNote $ m ++ " " ++ describeCipher cipher
|
2011-04-16 17:25:27 +00:00
|
|
|
return $ M.delete "encryption" $ storeCipher c cipher
|
2011-04-16 22:22:52 +00:00
|
|
|
|
2011-04-17 01:41:14 +00:00
|
|
|
{- Modifies a Remote to support encryption.
|
|
|
|
-
|
|
|
|
- Two additional functions must be provided by the remote,
|
|
|
|
- to support storing and retrieving encrypted content. -}
|
2011-04-17 04:40:23 +00:00
|
|
|
encryptableRemote
|
2011-04-17 01:41:14 +00:00
|
|
|
:: Maybe RemoteConfig
|
|
|
|
-> ((Cipher, Key) -> Key -> Annex Bool)
|
|
|
|
-> ((Cipher, Key) -> FilePath -> Annex Bool)
|
|
|
|
-> Remote Annex
|
|
|
|
-> Remote Annex
|
2011-04-17 04:40:23 +00:00
|
|
|
encryptableRemote c storeKeyEncrypted retrieveKeyFileEncrypted r =
|
2011-04-17 01:41:14 +00:00
|
|
|
r {
|
|
|
|
storeKey = store,
|
|
|
|
retrieveKeyFile = retrieve,
|
|
|
|
removeKey = withkey $ removeKey r,
|
2011-04-17 05:13:21 +00:00
|
|
|
hasKey = withkey $ hasKey r,
|
|
|
|
cost = cost r + encryptedRemoteCostAdj
|
2011-04-17 01:41:14 +00:00
|
|
|
}
|
|
|
|
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'
|
2011-04-16 22:22:52 +00:00
|
|
|
|
2011-05-01 18:05:10 +00:00
|
|
|
{- Gets encryption Cipher. The decrypted Cipher is cached in the Annex
|
|
|
|
- state. -}
|
|
|
|
remoteCipher :: RemoteConfig -> Annex (Maybe Cipher)
|
|
|
|
remoteCipher c = do
|
2011-04-16 22:22:52 +00:00
|
|
|
cache <- Annex.getState Annex.cipher
|
|
|
|
case cache of
|
2011-05-01 18:05:10 +00:00
|
|
|
Just cipher -> return $ Just cipher
|
2011-04-16 22:22:52 +00:00
|
|
|
Nothing -> case extractCipher c of
|
|
|
|
Nothing -> return Nothing
|
|
|
|
Just encipher -> do
|
2011-05-01 19:13:54 +00:00
|
|
|
showNote "gpg"
|
2011-04-16 22:22:52 +00:00
|
|
|
cipher <- liftIO $ decryptCipher c encipher
|
|
|
|
Annex.changeState (\s -> s { Annex.cipher = Just cipher })
|
2011-05-01 18:05:10 +00:00
|
|
|
return $ Just cipher
|
|
|
|
|
|
|
|
{- Gets encryption Cipher, and encrypted version of Key. -}
|
|
|
|
cipherKey :: Maybe RemoteConfig -> Key -> Annex (Maybe (Cipher, Key))
|
|
|
|
cipherKey Nothing _ = return Nothing
|
|
|
|
cipherKey (Just c) k = do
|
|
|
|
cipher <- remoteCipher c
|
|
|
|
case cipher of
|
|
|
|
Just ciphertext -> do
|
|
|
|
k' <- liftIO $ encryptKey ciphertext k
|
|
|
|
return $ Just (ciphertext, k')
|
|
|
|
Nothing -> return Nothing
|