summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Annex/UUID.hs22
-rw-r--r--Git/GCrypt.hs73
-rw-r--r--Remote/Git.hs7
-rw-r--r--doc/bugs/Error_creating_encrypted_cloud_repository:___34__internal_server_error__34__.mdwn2
-rw-r--r--doc/design/gcrypt.mdwn8
-rw-r--r--doc/devblog/day_3__gcrypt_uuids.mdwn63
6 files changed, 175 insertions, 0 deletions
diff --git a/Annex/UUID.hs b/Annex/UUID.hs
index c36861bbe..4e274503b 100644
--- a/Annex/UUID.hs
+++ b/Annex/UUID.hs
@@ -17,8 +17,11 @@ module Annex.UUID (
getUncachedUUID,
prepUUID,
genUUID,
+ genUUIDInNameSpace,
+ gCryptNameSpace,
removeRepoUUID,
storeUUID,
+ setUUID,
) where
import Common.Annex
@@ -27,7 +30,9 @@ import qualified Git.Config
import Config
import qualified Data.UUID as U
+import qualified Data.UUID.V5 as U5
import System.Random
+import Data.Bits.Utils
configkey :: ConfigKey
configkey = annexConfig "uuid"
@@ -36,6 +41,17 @@ configkey = annexConfig "uuid"
genUUID :: IO UUID
genUUID = UUID . show <$> (randomIO :: IO U.UUID)
+{- Generates a UUID from a given string, using a namespace.
+ - Given the same namespace, the same string will always result
+ - in the same UUID. -}
+genUUIDInNameSpace :: U.UUID -> String -> UUID
+genUUIDInNameSpace namespace = UUID . show . U5.generateNamed namespace . s2w8
+
+{- Namespace used for UUIDs derived from git-remote-gcrypt ids. -}
+gCryptNameSpace :: U.UUID
+gCryptNameSpace = U5.generateNamed U5.namespaceURL $
+ s2w8 "http://git-annex.branchable.com/design/gcrypt/"
+
{- Get current repository's UUID. -}
getUUID :: Annex UUID
getUUID = getRepoUUID =<< gitRepo
@@ -72,3 +88,9 @@ prepUUID = whenM ((==) NoUUID <$> getUUID) $
storeUUID :: ConfigKey -> UUID -> Annex ()
storeUUID configfield = setConfig configfield . fromUUID
+
+{- Only sets the configkey in the Repo; does not change .git/config -}
+setUUID :: Git.Repo -> UUID -> IO Git.Repo
+setUUID r u = do
+ let s = show configkey ++ "=" ++ fromUUID u
+ Git.Config.store s r
diff --git a/Git/GCrypt.hs b/Git/GCrypt.hs
new file mode 100644
index 000000000..e22bd74a2
--- /dev/null
+++ b/Git/GCrypt.hs
@@ -0,0 +1,73 @@
+{- git-remote-gcrypt support
+ -
+ - https://github.com/blake2-ppc/git-remote-gcrypt
+ -
+ - Copyright 2013 Joey Hess <joey@kitenet.net>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+module Git.GCrypt where
+
+import Common
+import Git.Types
+import Git.Construct
+import qualified Git.Config as Config
+import Utility.Gpg
+
+urlPrefix :: String
+urlPrefix = "gcrypt::"
+
+isEncrypted :: Repo -> Bool
+isEncrypted Repo { location = Url url } = urlPrefix `isPrefixOf` show url
+isEncrypted _ = False
+
+{- The first Repo is the git repository that has the second Repo
+ - as one of its remotes.
+ -
+ - When the remote Repo uses gcrypt, returns the actual underlying
+ - git repository that gcrypt is using to store its data.
+ -
+ - Throws an exception if an url is invalid or the repo does not use
+ - gcrypt.
+ -}
+encryptedRepo :: Repo -> Repo -> IO Repo
+encryptedRepo baserepo = go
+ where
+ go Repo { location = Url url }
+ | urlPrefix `isPrefixOf` u =
+ fromRemoteLocation (drop plen u) baserepo
+ | otherwise = notencrypted
+ where
+ u = show url
+ plen = length urlPrefix
+ go _ = notencrypted
+ notencrypted = error "not a gcrypt encrypted repository"
+
+{- gcrypt gives each encrypted repository a uique gcrypt-id,
+ - which is stored in the repository (in encrypted form)
+ - and cached in a per-remote gcrypt-id configuration setting. -}
+remoteRepoId :: Repo -> Repo -> Maybe String
+remoteRepoId = getRemoteConfig "gcrypt-id"
+
+getRemoteConfig :: String -> Repo -> Repo -> Maybe String
+getRemoteConfig field baserepo remote = do
+ name <- remoteName remote
+ Config.getMaybe (remoteConfigKey field name) baserepo
+
+{- Gpg keys that the remote is encrypted for.
+ - If empty, gcrypt uses --default-recipient-self -}
+particiantList :: Maybe Repo -> Repo -> Repo -> KeyIds
+particiantList globalconfigrepo baserepo remote = KeyIds $ parse $ firstJust
+ [ getRemoteConfig "participants" baserepo remote
+ , Config.getMaybe defaultkey baserepo
+ , Config.getMaybe defaultkey =<< globalconfigrepo
+ ]
+ where
+ defaultkey = "gcrypt.participants"
+ parse (Just "simple") = []
+ parse (Just l) = words l
+ parse Nothing = []
+
+remoteConfigKey :: String -> String -> String
+remoteConfigKey key field = "remote." ++ field ++ "." ++ key
diff --git a/Remote/Git.hs b/Remote/Git.hs
index e269b9ad8..b3f64bfb8 100644
--- a/Remote/Git.hs
+++ b/Remote/Git.hs
@@ -26,6 +26,7 @@ import qualified Git
import qualified Git.Config
import qualified Git.Construct
import qualified Git.Command
+import qualified Git.GCrypt
import qualified Annex
import Logs.Presence
import Logs.Transfer
@@ -152,6 +153,12 @@ tryGitConfigRead r
| Git.repoIsHttp r = do
headers <- getHttpHeaders
store $ geturlconfig headers
+ | Git.GCrypt.isEncrypted r = do
+ g <- gitRepo
+ case Git.GCrypt.remoteRepoId g r of
+ Nothing -> return r
+ Just v -> store $ liftIO $ setUUID r $
+ genUUIDInNameSpace gCryptNameSpace v
| Git.repoIsUrl r = return r
| otherwise = store $ safely $ onLocal r $ do
ensureInitialized
diff --git a/doc/bugs/Error_creating_encrypted_cloud_repository:___34__internal_server_error__34__.mdwn b/doc/bugs/Error_creating_encrypted_cloud_repository:___34__internal_server_error__34__.mdwn
index 251c6aa08..4d04718ab 100644
--- a/doc/bugs/Error_creating_encrypted_cloud_repository:___34__internal_server_error__34__.mdwn
+++ b/doc/bugs/Error_creating_encrypted_cloud_repository:___34__internal_server_error__34__.mdwn
@@ -20,3 +20,5 @@ The operating system is Mac OS X 10.8.4, and the version of git-annex is 4.20130
# End of transcript or log.
"""]]
+
+[[!meta title "OSX bundled gpg does not work with gpg.conf created by MacGPG"]]
diff --git a/doc/design/gcrypt.mdwn b/doc/design/gcrypt.mdwn
new file mode 100644
index 000000000..d5b9c064b
--- /dev/null
+++ b/doc/design/gcrypt.mdwn
@@ -0,0 +1,8 @@
+To integrate with git-remote-gcrypt, a key thing is to have a way to map
+from the gcrypt-id of an encrypted repository to a git-annex repository
+uuid.
+
+To do this, we'll make a v5 UUID, feeding in the gcrypt-id.
+The namespace used is itself a v5 UUID, generated using the URL
+namespace and the URL of this page at the time this scheme was
+developed: "http://git-annex.branchable.com/design/gcrypt/"
diff --git a/doc/devblog/day_3__gcrypt_uuids.mdwn b/doc/devblog/day_3__gcrypt_uuids.mdwn
new file mode 100644
index 000000000..3182aca63
--- /dev/null
+++ b/doc/devblog/day_3__gcrypt_uuids.mdwn
@@ -0,0 +1,63 @@
+Started work on [gcrypt](https://github.com/blake2-ppc/git-remote-gcrypt)
+support.
+
+The first question is, should git-annex leave it up to gcrypt to transport
+the data to the encrypted repository on a push/pull? gcrypt hooks into git
+nicely to make that just work. However, if I go this route, it limits
+the places the encrypted git repositores can be stored to regular git
+remotes (and rsync). The alternative is to somehow use gcrypt to
+generate/consume the data, but use the git-annex special remotes to store
+individual files. Which would allow for a git repo stored on S3, etc.
+For now, I am going with the simple option, but I have not ruled out
+trying to make the latter work. It seems it would need changes to gcrypt
+though.
+
+Next question: Given a remote that uses gcrypt, how do I determine the
+annex.uuid of that repository. I found a nice solutuon to this. gcrypt has
+its own gcrypt-id, and I convert it to a UUID in a
+[[reproducible, and even standards-compliant way|design/gcrypt]]. So
+the same encrypted remote will automatically get the same annex.uuid
+wherever it's used. Nice. Does mean that git-annex cannot find a uuid
+until `git pull` or `git push` has been used, to let gcrypt get the
+gcrypt-id. Implemented that.
+
+The next step is actually making git-annex store data on gcrypt remotes.
+And it needs to store it encrypted of course. It seems best to avoid
+needing a `git annex initremote` for these gcrypt remotes, and just have
+git-annex automatically encrypt data stored on them. But I don't
+know. Without initializing them like a special remote is, I'm limited to
+using the gpg keys that gcrypt is configured to encrypt to, and cannot use
+the regular git-annex hybrid encryption scheme. Also, I need to generate
+and store a nonce anyway to HMAC ecrypt keys. (Or modify gcrypt
+to put enough entropy in gcrypt-id that I can use it?)
+
+Another concern I have is that gcrypt's own encryption scheme is simply
+to use a list of public keys to encrypt to. It would be nicer if the
+full set of git-annex encryption schemes could be used. Then the webapp
+could use shared encryption to avoid needing to make the user set up a gpg
+key, or hybrid encryption could be used to add keys later, etc.
+
+But I see why gcrypt works the way it does. Otherwise, you can't make an
+encrypted repo with a friend set as one of the particpants and have them be
+able to git clone it. Both hybrid and shared encryption store a secret
+inside the repo, which is not accessible if it's encrypted using that
+secret. There are use cases where not being able to blindly clone a gcrypt
+repo would be ok. For example, you use the assistant to pair with a friend
+and then set up an encrypted repo in the cloud for both of you to use.
+
+Anyway, for now, I will need to deal with
+setting up gpg keys etc in the assistant. I don't want to tackle
+full [[design/assistant/gpgkeys]] yet. Instead, I think I will start by
+adding some simple stuff to the assistant:
+
+* When adding a USB drive, offer to encrypt the repository on the drive
+ so that only you can see it.
+* When adding a ssh remote make a similar offer.
+* Add a UI to add an arbitrary git remote with encryption.
+ Let the user paste in the url to an empty remote they have,
+ which could be to eg github. (In most cases this won't be used for
+ annexed content..)
+* When the user has no gpg key, prompt to set one up. (Securely!)
+* Maybe have an interface to add another gpg key that can access the gcrypt
+ repo. Note that this will need to re-encrypt and re-push the whole
+ git history.