Added new encryption=sharedpubkey mode for special remotes.

This is useful for makking a special remote that anyone with a clone of the
repo and your public keys can upload files to, but only you can decrypt the
files stored in it.
This commit is contained in:
Joey Hess 2016-05-10 16:50:31 -04:00
parent 2d00523609
commit e219289c83
Failed to extract signature
7 changed files with 114 additions and 63 deletions

View file

@ -14,7 +14,6 @@ module Remote.Helper.Encryptable (
remoteCipher',
embedCreds,
cipherKey,
storeCipher,
extractCipher,
describeEncryption,
) where
@ -58,20 +57,18 @@ encryptionSetup c = do
encryption = M.lookup "encryption" c
-- Generate a new cipher, depending on the chosen encryption scheme
genCipher cmd = case encryption of
_ | M.member "cipher" c || M.member "cipherkeys" c -> cannotchange
_ | M.member "cipher" c || M.member "cipherkeys" c || M.member "pubkeys" c -> cannotchange
Just "none" -> return (c, NoEncryption)
Just "shared" -> use "encryption setup" . genSharedCipher cmd
=<< highRandomQuality
Just "shared" -> encsetup $ genSharedCipher cmd
-- hybrid encryption is the default when a keyid is
-- specified but no encryption
_ | maybe (M.member "keyid" c) (== "hybrid") encryption ->
use "encryption setup" . genEncryptedCipher cmd key Hybrid
=<< highRandomQuality
Just "pubkey" -> use "encryption setup" . genEncryptedCipher cmd key PubKey
=<< highRandomQuality
encsetup $ genEncryptedCipher cmd key Hybrid
Just "pubkey" -> encsetup $ genEncryptedCipher cmd key PubKey
Just "sharedpubkey" -> encsetup $ genSharedPubKeyCipher cmd key
_ -> error $ "Specify " ++ intercalate " or "
(map ("encryption=" ++)
["none","shared","hybrid","pubkey"])
["none","shared","hybrid","pubkey", "sharedpubkey"])
++ "."
key = fromMaybe (error "Specifiy keyid=...") $ M.lookup "keyid" c
newkeys = maybe [] (\k -> [(True,k)]) (M.lookup "keyid+" c) ++
@ -82,13 +79,16 @@ encryptionSetup c = do
SharedCipher _ | maybe True (== "shared") encryption -> return (c', EncryptionIsSetup)
EncryptedCipher _ variant _
| maybe True (== if variant == Hybrid then "hybrid" else "pubkey") encryption ->
use "encryption update" $ updateEncryptedCipher cmd newkeys v
use "encryption update" $ updateCipherKeyIds cmd newkeys v
SharedPubKeyCipher _ _ ->
use "encryption update" $ updateCipherKeyIds cmd newkeys v
_ -> cannotchange
encsetup a = use "encryption setup" . a =<< highRandomQuality
use m a = do
showNote m
cipher <- liftIO a
showNote $ describeCipher cipher
return (storeCipher c' cipher, EncryptionIsSetup)
mapM_ showNote (describeCipher cipher)
return (storeCipher cipher c', EncryptionIsSetup)
highRandomQuality =
(&&) (maybe True ( /= "false") $ M.lookup "highRandomQuality" c)
<$> fmap not (Annex.getState Annex.fast)
@ -123,8 +123,8 @@ remoteCipher' c = go $ extractCipher c
- embedcreds=yes allows this, and embedcreds=no prevents it.
-
- If not set, the default is to only store creds when it's surely safe:
- When gpg encryption is used, in which case the creds will be encrypted
- using it. Not when a shared cipher is used.
- When gpg encryption is used and the creds are encrypted using it.
- Not when a shared cipher is used.
-}
embedCreds :: RemoteConfig -> Bool
embedCreds c
@ -141,22 +141,26 @@ cipherKey c = fmap make <$> remoteCipher c
mac = fromMaybe defaultMac $ M.lookup "mac" c >>= readMac
{- Stores an StorableCipher in a remote's configuration. -}
storeCipher :: RemoteConfig -> StorableCipher -> RemoteConfig
storeCipher c (SharedCipher t) = M.insert "cipher" (toB64bs t) c
storeCipher c (EncryptedCipher t _ ks) =
M.insert "cipher" (toB64bs t) $ M.insert "cipherkeys" (showkeys ks) c
storeCipher :: StorableCipher -> RemoteConfig -> RemoteConfig
storeCipher cip = case cip of
(SharedCipher t) -> addcipher t
(EncryptedCipher t _ ks) -> addcipher t . storekeys ks "cipherkeys"
(SharedPubKeyCipher t ks) -> addcipher t . storekeys ks "pubkeys"
where
showkeys (KeyIds l) = intercalate "," l
addcipher t = M.insert "cipher" (toB64bs t)
storekeys (KeyIds l) n = M.insert n (intercalate "," l)
{- Extracts an StorableCipher from a remote's configuration. -}
extractCipher :: RemoteConfig -> Maybe StorableCipher
extractCipher c = case (M.lookup "cipher" c,
M.lookup "cipherkeys" c,
M.lookup "cipherkeys" c <|> M.lookup "pubkeys" c,
M.lookup "encryption" c) of
(Just t, Just ks, encryption) | maybe True (== "hybrid") encryption ->
Just $ EncryptedCipher (fromB64bs t) Hybrid (readkeys ks)
(Just t, Just ks, Just "pubkey") ->
Just $ EncryptedCipher (fromB64bs t) PubKey (readkeys ks)
(Just t, Just ks, Just "sharedpubkey") ->
Just $ SharedPubKeyCipher (fromB64bs t) (readkeys ks)
(Just t, Nothing, encryption) | maybe True (== "shared") encryption ->
Just $ SharedCipher (fromB64bs t)
_ -> Nothing
@ -166,14 +170,25 @@ extractCipher c = case (M.lookup "cipher" c,
describeEncryption :: RemoteConfig -> String
describeEncryption c = case extractCipher c of
Nothing -> "not encrypted"
(Just (SharedCipher _)) -> "encrypted (encryption key stored in git repository)"
(Just (EncryptedCipher _ v (KeyIds { keyIds = ks }))) -> unwords $ catMaybes
[ Just "encrypted (to gpg keys:"
, Just (unwords ks ++ ")")
Just cip -> "encrypted " ++ unwords (map paren (describeCipher cip))
where
paren s = "(" ++ s ++ ")"
describeCipher :: StorableCipher -> [String]
describeCipher c = case c of
(SharedCipher _) -> ["encryption key stored in git repository"]
(EncryptedCipher _ v ks) -> catMaybes
[ Just $ showkeys ks
, case v of
PubKey -> Nothing
Hybrid -> Just "(hybrid mode)"
Hybrid -> Just "hybrid mode"
]
(SharedPubKeyCipher _ ks) ->
[ showkeys ks
, "shared cipher"
]
where
showkeys (KeyIds { keyIds = ks }) = "to gpg keys: " ++ unwords ks
{- Not using Utility.Base64 because these "Strings" are really
- bags of bytes and that would convert to unicode and not round-trip