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-name>.
+ - 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`).
Server:
- Reads the path and the command.
else
echo "$2"
fi | awk '
-match($0, /(([^@]*)@)?([^/]*)(\/(.*))?/, a) { printf "%s\n%s\n%s\n", a[2], a[3], a[5] }
+match($0, /(([^@]*)@)?([^/]*)(\/.*)?/, a) { printf "%s\n%s\n%s\n", a[2], a[3], a[4] }
' | { read -r username && read -r gnsname && read -r path && ! grep '.'; }
if test "$?" != "0"; then
echo >&2 "Invalid address: \`$2'."
- echo >&2 "URI format: \`[gnunet://][user@]gns.name/path/to/repo'."
+ echo >&2 "URI format: \`[gnunet://][user@]gns.name[/path/to/repo]'."
exit 1
fi
echo >&2 "Usage: $0 /base/path"
exit 1
fi
-base_path="$1/"
+base_path="$1"
read -r path || { echo "No path specified." | tee /dev/stderr; exit 1; }
read -r comm || { echo "No command specified." | tee /dev/stderr; exit 1; }
-if echo "$path" | grep -q '/'; then
- echo "Path \`$path' contains a '/'." | tee /dev/stderr
- exit 1
-fi
-if test "$path" = '..'; then
- echo "Path cannot be \`..'." | tee /dev/stderr
- exit 1
-fi
+full_path="$(realpath -sm "$base_path$path")"
+case "$full_path" in
+ "$base_path") ;;
+ "$base_path/"*) ;;
+ *) echo "Invalid path: \`$full_path'." | tee /dev/stderr
+ exit 1
+ ;;
+esac
if test "$comm" != "git-upload-pack"; then
echo "Command \`$comm' has to be git-upload-pack." | tee /dev/stderr
exit 1
fi
-git -C "$base_path$path" rev-parse --git-dir >/dev/null 2>/dev/null || { echo "Not a git repository." | tee /dev/stderr; exit 1; }
+git_dir="$(git -C "$full_path" rev-parse --path-format=absolute --git-dir)" || { echo "Not a git repository: \`$full_path'." | tee /dev/stderr; exit 1; }
echo ''
-exec "$comm" "$base_path$path"
+exec "$comm" "$git_dir"