#!/usr/bin/env bash
# .git/hooks/pre-commit — Cryptographic Triangles
#
# Auto-runs scripts/validate_onion_seeds.py against any staged file that
# contains .onion addresses. Blocks the commit if any address fails v3
# onion checksum validation.
#
# This is the primary defense against the "1-character .onion transposition
# bug" that caused 4,842 Tor "No more HSDir" errors during the 2026-06-21
# from-zero sync test. See scripts/validate_onion_seeds.py for the validator
# and references/sync-security-audit-2026-06-21.md for the full story.
#
# The hook scans staged files for two patterns:
#   1. Filename matches: triangles.conf, *.onion
#   2. Content contains addnode= entries with .onion addresses
#
# To install:
#   cp scripts/pre-commit .git/hooks/pre-commit
#   chmod +x .git/hooks/pre-commit
#
# To bypass (in emergencies only — NEVER do this for normal commits):
#   git commit --no-verify

set -e

REPO_ROOT="$(git rev-parse --show-toplevel)"
VALIDATOR="${REPO_ROOT}/scripts/validate_onion_seeds.py"

# Find the validator
if [[ ! -x "$VALIDATOR" ]]; then
    echo "pre-commit: WARNING: $VALIDATOR not found or not executable" >&2
    echo "pre-commit: skipping v3 onion validation" >&2
    echo "pre-commit: install with: chmod +x $VALIDATOR" >&2
    exit 0
fi

# Two-pass detection:
#   Pass 1: filename-based — files named triangles.conf or *.onion
#   Pass 2: content-based — any file containing "addnode=" + .onion address

STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR)

# Pass 1: filename-based
NAME_MATCHES=$(echo "$STAGED_FILES" | grep -E '(triangles\.conf$|\.onion$)' || true)

# Pass 2: content-based — find staged files containing addnode= with .onion addresses
CONTENT_MATCHES=""
for f in $STAGED_FILES; do
    if [[ -f "$f" ]] && grep -qE '^[[:space:]]*addnode=[a-z2-7]{56}\.onion' "$f" 2>/dev/null; then
        CONTENT_MATCHES="$CONTENT_MATCHES $f"
    fi
done

# Combine and dedupe
ALL_MATCHES=$(printf "%s\n%s\n" "$NAME_MATCHES" "$CONTENT_MATCHES" | sort -u | grep -v '^$' || true)

if [[ -z "$ALL_MATCHES" ]]; then
    # Nothing to validate
    exit 0
fi

# Filter to only files that exist (skip deletions)
EXISTING_CONFIGS=""
for f in $ALL_MATCHES; do
    if [[ -f "$f" ]]; then
        EXISTING_CONFIGS="$EXISTING_CONFIGS $f"
    fi
done

if [[ -z "$EXISTING_CONFIGS" ]]; then
    exit 0
fi

COUNT=$(echo $EXISTING_CONFIGS | wc -w)
echo "pre-commit: validating $COUNT staged file(s) with .onion addresses..."

# Build the validator command
CMD="python3 \"$VALIDATOR\" --no-color --ci"
if [[ -f "${REPO_ROOT}/src/onionseed.h" ]]; then
    CMD="$CMD --against \"${REPO_ROOT}/src/onionseed.h\""
fi

# Run the validator
if eval $CMD $EXISTING_CONFIGS; then
    echo "pre-commit: v3 onion validation PASSED"
    exit 0
else
    EXIT_CODE=$?
    echo "" >&2
    echo "pre-commit: v3 onion validation FAILED (exit $EXIT_CODE)" >&2
    echo "" >&2
    echo "  The commit was blocked because one or more .onion addresses failed" >&2
    echo "  v3 hidden service checksum validation. This means the .onion address" >&2
    echo "  has a typo or character transposition that Tor will reject at runtime" >&2
    echo "  with 'ed25519 validation failed' / 'No more HSDir available to query'." >&2
    echo "" >&2
    echo "  Fix the .onion address in the affected file, then re-stage and commit." >&2
    echo "" >&2
    echo "  To inspect the failure in detail, run manually:" >&2
    echo "    python3 $VALIDATOR --against ${REPO_ROOT}/src/onionseed.h \\" >&2
    echo "      $EXISTING_CONFIGS" >&2
    echo "" >&2
    echo "  To bypass this check (DO NOT do this for normal commits):" >&2
    echo "    git commit --no-verify" >&2
    exit 1
fi
