]> git.ameliathe1st.gay Git - git-over-gnunet.git/commitdiff
Authenticated pushing via the identity service
authorAmélia Coutard-Sander <git@ameliathe1st.gay>
Thu, 5 Dec 2024 09:21:12 +0000 (10:21 +0100)
committerAmélia Coutard-Sander <git@ameliathe1st.gay>
Thu, 5 Dec 2024 09:21:12 +0000 (10:21 +0100)
README.txt
git-remote-gnunet
handle-request.sh

index 12ba42296b2cc9f54a0849fe6dce573c375dab70..9ca31aa4274295d67d4f9344657901091ec31569 100644 (file)
@@ -1,4 +1,4 @@
-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.)
@@ -6,8 +6,8 @@ In the interest of demonstrating that it works, all the repos on my server are a
 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.
          ```
@@ -20,16 +20,18 @@ Server:
        - 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 ?
@@ -37,9 +39,18 @@ TODO:
 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.
index edccd4952a7e870433bfcc53edc5deb36906b48b..b01e65ac1180230a7055e9c8b08fad0b76010c82 100755 (executable)
@@ -43,4 +43,19 @@ echo >&2 "Trying service \`$service' on peer \`$peer'."
 ip="$(gnunet-vpn -s "$service" -p "$peer" -t)"
 echo >&2 "Using tunnel ip \`$ip'."
 
-{ printf '%s\n' "$path" "$arg" "$pkey"; cat; } | socat stdio tcp4:"$ip":9418
+case "$username" in
+"")
+       { printf '%s\n' "$path" "$arg" "$pkey"; cat; } | socat stdio tcp4:"$ip":9418
+       ;;
+*)
+       fifo="$(mktemp -u)"
+       mkfifo "$fifo" || { echo 2>&1 "Failed to create the fifo."; exit 1; }
+       { printf '%s\n' "$path" "$arg" "$pkey"; head -n1 "$fifo"; cat; } \
+               | socat stdio tcp4:"$ip":9418 \
+               | { head -n 1 \
+                       | { xargs gnunet-identity -e "$username" -R || { echo >&2 'Error !'; exit 1; }; } \
+                       | sha256sum > "$fifo";
+                       cat; }
+       rm "$fifo"
+       ;;
+esac
index 4894910df6850e236f9a05529e8fe1067c5f7ecb..e47975b01599d49a17fce6f4bf967ca20f867dfd 100755 (executable)
@@ -1,10 +1,11 @@
 #!/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; }
@@ -19,14 +20,32 @@ case "$full_path" in
        ;;
 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