foxygit / foxygit Log in
A tiny read-only git web frontend — browse bare repos with just PHP and git, no database, no framework.
commits tags

/server/git-http-backend-auth · 2 KB

raw
#!/bin/sh
# CGI wrapper around git-http-backend, installed by setup-http-push.sh in
# place of calling git-http-backend directly (see the /repos/* block in the
# git.kristoffersson.info Caddyfile). Invoked by fcgiwrap-git, as the `git`
# user, once per HTTP request to /repos/*.
#
# Clone/fetch (anonymous, read-only) is untouched -- it execs straight into
# git-http-backend exactly like before. A push (git-receive-pack) additionally
# requires HTTP Basic Auth whose password is a valid foxygit API key (created
# at https://<host>/?a=account); the username is not checked, same as GitHub's
# "any username, a PAT as the password" convention -- the key alone identifies
# the account. Wrong/missing credentials get a 401 instead of ever reaching
# git-http-backend.
#
# Installed to /usr/local/lib/foxygit/git-http-backend-auth, root:root 0755 --
# root-owned so a bug in the (git-user-owned) web app can't rewrite its own
# auth gate. verify-api-key.php lives alongside it.

set -eu

GIT_HTTP_BACKEND="/usr/lib/git-core/git-http-backend"
VERIFY_SCRIPT="$(dirname "$0")/verify-api-key.php"

is_push=0
case "${PATH_INFO:-}" in
	*/git-receive-pack) is_push=1 ;;
esac
case "${QUERY_STRING:-}" in
	*service=git-receive-pack*) is_push=1 ;;
esac

if [ "$is_push" -eq 1 ]; then
	# Caddy's fastcgi transport forwards request headers as HTTP_* env vars;
	# some setups instead deliver it as REDIRECT_HTTP_AUTHORIZATION.
	auth="${HTTP_AUTHORIZATION:-${REDIRECT_HTTP_AUTHORIZATION:-}}"
	cred=""
	case "$auth" in
		"Basic "*)
			b64="${auth#Basic }"
			cred=$(printf '%s' "$b64" | base64 -d 2>/dev/null || true)
			;;
	esac
	pass="${cred#*:}"

	if [ -z "$auth" ] || [ "$cred" = "$pass" ] || ! printf '%s' "$pass" | php "$VERIFY_SCRIPT"; then
		printf 'Status: 401 Unauthorized\r\nWWW-Authenticate: Basic realm="foxygit push"\r\nContent-Type: text/plain\r\n\r\nAuthentication required to push. Create an API key at https://%s/?a=account and use it as the password (any username works).\n' "${HTTP_HOST:-this host}"
		exit 0
	fi
fi

exec "$GIT_HTTP_BACKEND"