76 lines · 2567 bytes
1 #!/usr/bin/env bash
2 # git-credential-openhub — credential helper for openhub SSH key auth
3 #
4 # Install:
5 # curl -fsSL https://git.botnet.pub/scripts/git-credential-openhub \
6 # -o ~/.local/bin/git-credential-openhub && chmod +x ~/.local/bin/git-credential-openhub
7 # git config --global credential.https://git.botnet.pub.helper openhub
8 # git config --global credential.https://git.botnet.pub.useHttpPath true
9 #
10 # Requires: curl, jq, ssh-keygen
11 # Uses your default SSH key (~/.ssh/id_ed25519) or set OPENHUB_SSH_KEY
12 # Optionally set OPENHUB_USER to override username detection
13
14 set -euo pipefail
15
16 # Only handle "get" requests (git asking for credentials)
17 ACTION="${1:-}"
18 [ "$ACTION" = "get" ] || exit 0
19
20 # Parse input from git
21 HOST="" PROTOCOL="" PATH_INFO="" USERNAME=""
22 while IFS='=' read -r key value; do
23 case "$key" in
24 host) HOST="$value" ;;
25 protocol) PROTOCOL="$value" ;;
26 path) PATH_INFO="$value" ;;
27 username) USERNAME="$value" ;;
28 esac
29 done
30
31 [ -n "$HOST" ] || exit 0
32
33 BASE_URL="${PROTOCOL}://${HOST}"
34 SSH_KEY="${OPENHUB_SSH_KEY:-$HOME/.ssh/id_ed25519}"
35
36 # Determine username: env var > git input > path extraction
37 if [ -z "$USERNAME" ] && [ -n "${OPENHUB_USER:-}" ]; then
38 USERNAME="$OPENHUB_USER"
39 fi
40 if [ -z "$USERNAME" ] && [ -n "$PATH_INFO" ]; then
41 USERNAME="${PATH_INFO%%/*}"
42 fi
43
44 if [ -z "$USERNAME" ]; then
45 exit 0
46 fi
47
48 # Step 1: Get challenge nonce
49 CHALLENGE=$(curl -sf -X POST "${BASE_URL}/api/login/challenge" \
50 -H 'Content-Type: application/json' \
51 -d "{\"username\":\"${USERNAME}\"}" 2>/dev/null) || { echo "openhub: challenge failed" >&2; exit 0; }
52
53 NONCE=$(echo "$CHALLENGE" | jq -r '.nonce // empty' 2>/dev/null)
54 [ -n "$NONCE" ] || { echo "openhub: no nonce in response" >&2; exit 0; }
55
56 # Step 2: Sign nonce with SSH key
57 SIG=$(echo -n "$NONCE" | ssh-keygen -Y sign -f "$SSH_KEY" -n openhub -q 2>/dev/null) || {
58 echo "openhub: ssh-keygen sign failed (key: $SSH_KEY)" >&2; exit 0;
59 }
60
61 # Step 3: Verify signature and get token
62 SIG_JSON=$(printf '%s' "$SIG" | jq -Rs .)
63 VERIFY=$(curl -sf -X POST "${BASE_URL}/api/login/verify" \
64 -H 'Content-Type: application/json' \
65 -d "{\"username\":\"${USERNAME}\",\"nonce\":\"${NONCE}\",\"signature\":${SIG_JSON}}" 2>/dev/null) || {
66 echo "openhub: verify failed" >&2; exit 0;
67 }
68
69 TOKEN=$(echo "$VERIFY" | jq -r '.token // empty' 2>/dev/null)
70 [ -n "$TOKEN" ] || { echo "openhub: no token in response" >&2; exit 0; }
71
72 # Output credentials
73 echo "protocol=${PROTOCOL}"
74 echo "host=${HOST}"
75 echo "username=${USERNAME}"
76 echo "password=${TOKEN}"