summaryrefslogtreecommitdiff
path: root/Remote/Encrypted.hs
blob: 0ff2833b375c1811f782032362d5ac30b01e5341 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
{- common functions for encrypted remotes
 -
 - Copyright 2011 Joey Hess <joey@kitenet.net>
 -
 - Licensed under the GNU GPL version 3 or higher.
 -}

module Remote.Encrypted where

import qualified Data.Map as M
import Control.Monad.State (liftIO)

import Types
import RemoteClass
import Crypto
import qualified Annex
import Messages

{- 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"
		(Just "none", Nothing) -> return c
		(Just "none", Just _) -> error "Cannot change encryption type of existing remote."
		(Nothing, Just _) -> return c
		(Just _, Nothing) -> use $ genCipher c
		(Just _, Just v) -> use $ updateCipher c v
	where
		use a = do
			cipher <- liftIO a
			return $ M.delete "encryption" $ storeCipher c cipher

{- Helpers that can be applied to a Remote's normal actions to
 - add crypto support. -}
storeKeyEncrypted :: Maybe RemoteConfig -> (Key -> Maybe (Cipher, Key) -> Annex a) -> Key -> Annex a
storeKeyEncrypted c a k = a k =<< cipherKey c k
retrieveKeyFileEncrypted :: Maybe RemoteConfig -> (Key -> FilePath -> Maybe (Cipher, Key) -> Annex a) -> Key -> FilePath -> Annex a
retrieveKeyFileEncrypted c a k f = a k f =<< cipherKey c k
removeKeyEncrypted :: Maybe RemoteConfig -> (Key -> Annex a) -> Key -> Annex a
removeKeyEncrypted = withEncryptedKey
hasKeyEncrypted :: Maybe RemoteConfig -> (Key -> Annex a) -> Key -> Annex a
hasKeyEncrypted = withEncryptedKey

{- Gets encryption Cipher, and encrypted version of Key. 
 -
 - The decrypted Cipher is cached in the Annex state. -}
cipherKey :: Maybe RemoteConfig -> Key -> Annex (Maybe (Cipher, Key))
cipherKey Nothing _ = return Nothing
cipherKey (Just c) k = do
	cache <- Annex.getState Annex.cipher
	case cache of
		Just cipher -> ret cipher
		Nothing -> case extractCipher c of
			Nothing -> return Nothing
			Just encipher -> do
				showNote "getting encryption key"
				cipher <- liftIO $ decryptCipher c encipher
				Annex.changeState (\s -> s { Annex.cipher = Just cipher })
				ret cipher
	where
		ret cipher = do
			k' <- liftIO $ encryptKey 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'