-This set of bash scripts allows one to clone/fetch/pull git repositories using gnunet, specifically the GNS and the GNUnet VPN.
+This set of bash scripts allows one to use remote git repositories via gnunet, specifically the GNS, GNUnet VPN, and gnunet-identity.
In the interest of demonstrating that it works, all the repos on my server are available at
`gnunet://git.serv.amelia.gnunet.gns.alt/<repo>.git` (see gitweb for the specific URIs).
Try cloning them ! (And do tell me if it fails, or if it works.)
Usage:
Client:
You must add the repo folder to the GIT_EXEC_PATH (for example by prepending
- `GIT_EXEC_PATH=$GIT_EXEC_PATH:<path-to-git-over-gnunet-repo>` before every git command that uses remotes).
- The URL to give to git is `gnunet://<gns location of the repo>/<name of the repo>`.
+ `GIT_EXEC_PATH=$GIT_EXEC_PATH:/path/to/git/over/gnunet/repo` before every git command that uses remotes).
+ The URL to give to git is `gnunet://[gnunet-identity@]gns.location.of.the.repo[/path/to/the/repo]`.
Server:
- To serve repos, you have to setup a gnunet-vpn exit service.
```
- You should also add a gns VPN record containing the required information to connect to the exit service.
`gnunet-namestore -a -t VPN -e 1d -n <gns-name> -V '1 <peer-id> <gns-name>' -z <ego> -p`
- Next, you need to run the daemon: it needs to run `handle-request.sh` in the parent folder of all the repos every time someone connects to it.
- For example, with socat: `socat tcp4-listen:9418,bind=169.254.86.1,fork exec:'/path/to/handle-request.sh /path/to/repos'`
- - This will open the repos for pulling on the url `gnunet://<gns-record-name>/<repo-name>`.
+ For example, with socat: `socat tcp4-listen:9418,bind=169.254.86.1,fork exec:'/path/to/handle-request.sh /path/to/repos /path/to/list/of/pkeys'`
+ - This will open the repos for pulling on the url `gnunet://[gnunet-identity@]gns-name.public-key[/path/to/the/repo]`.
+ - Additionally, any owner of a public key listed in /path/to/list/of/pkeys (each line should be a pkey on its own) will be allowed push access
+ (by specifying the corresponding identity before the @).
Features:
- Clone repo !
- Fetch repo !
- Pull repo !
+ - Authenticated push to repo !
TODO:
- - Pushing, and a gnunet-identity verification system ?
- Pulling from anyone using a commit hash ?
- DHT to figure out who has what commits ?
- Question of trust for pulling from peers ?
How it works:
Client:
- Uses a git remote helper to give git the ability to interpet the gnunet:// scheme.
- - Gets the VPN record associated with the GNS name given in gnunet://<gns-name>/<repo-path>.
- - Connects to the exit service, give it the name of the repo and the command required (e.g. `git-upload-pack`).
+ - Gets the VPN record associated with the GNS name given in the scheme.
+ - Connects to the exit service, give it the name of the repo and the command required
+ (e.g. `git-upload-pack`) (and the public key if an identity was specified).
Server:
- Reads the path and the command.
- - Checks that the command is git-upload-pack and the path isn't malicious.
+ - Checks that the the path isn't malicious.
+ - Checks that the command is git-upload-pack, or that the client is authenticated and the command is git-receive-pack.
- Executes the command and connects it to the client.
+Authentication (also done when pulling):
+ - The server receives the public key.
+ - It checks the key is allowed.
+ - It sends a randomly-generated passphrase to the client, encrypted to the public key.
+ - The client decyphers and hashes the passphrase, and sends the hash back.
+ - This avoids the request by a malicious server of decyphering of arbitrary strings.
+ - The server checks the correctness of the hash.
#!/usr/bin/env bash
-if test -z $1 || ! test -z $2; then
- echo >&2 "Usage: $0 /base/path"
+if test -z "$1" || test -z "$2" || ! test -z "$3"; then
+ echo >&2 "Usage: $0 /base/path /file/containing/list/of/allowed/pkeys"
exit 1
fi
base_path="$1"
+pkeys="$2"
read -r path || { echo "No path specified." | tee /dev/stderr; exit 1; }
read -r comm || { echo "No command specified." | tee /dev/stderr; exit 1; }
;;
esac
+if test "" != "$pkey"; then
+ pkey="$(grep -xm1 -- "$pkey" < "$pkeys")" || { echo "Unknown public key." | tee /dev/stderr; exit 1; }
+ keyphrase="$(</dev/random base64 2> /dev/null | head -c 64)"
+ hashed="$(printf '%s\n' "$keyphrase" | sha256sum)"
+ encrypted="$(gnunet-identity -k "$pkey" -W "$keyphrase")"
+ printf '%s\n' "$encrypted"
+ read -r returned_hash
+ case "$returned_hash" in
+ "$hashed")
+ ;;
+ *)
+ echo "Incorrect passphrase decryption." | tee /dev/stderr
+ exit 1
+ ;;
+ esac
+fi
+
case "$comm" in
git-upload-pack)
- # No pkey checking.
+ # Unidentified pull is allowed.
;;
git-receive-pack)
- # Accept any valid pkey. FIXME
- echo "Command \`$comm' not supported yet." | tee /dev/stderr
- exit 1
+ if test "" = "$pkey"; then
+ echo "Unidentified push is not allowed." | tee /dev/stderr
+ exit 1
+ fi
;;
*)
echo "Unknown command: \`$comm'." | tee /dev/stderr