#!/bin/bash # Git OpenTimestamp Post-Commit Hook # Self-contained - no external dependencies # Generates cryptographic proof for each commit using OpenTimestamp set -e # Configuration OUTPUT_DIR=".ots" OUTPUT_FILE="$OUTPUT_DIR/proof.ots" # Ensure output directory exists mkdir -p "$OUTPUT_DIR" # Get the current commit hash COMMIT_HASH=$(git rev-parse HEAD) # Function to generate proof using ots CLI generate_with_ots_cli() { local hash="$1" local output="$2" # Create a temporary file with the hash (convert hex to binary) local temp_file=$(mktemp) local temp_ots="${temp_file}.ots" # Use python3 for hex to binary conversion (more portable than xxd) python3 -c "import sys; sys.stdout.buffer.write(bytes.fromhex('$hash'))" > "$temp_file" # Generate timestamp - ots creates .ots file alongside the original ots stamp "$temp_file" 2>/dev/null # Move the generated .ots file to the desired location if [ -f "$temp_ots" ]; then mv "$temp_ots" "$output" rm -f "$temp_file" return 0 else rm -f "$temp_file" return 1 fi } # Function to generate proof using nodejs fallback generate_with_node() { local hash="$1" local output="$2" node -e " const ots = require('@opentimestamps/ots'); const fs = require('fs'); const hash = '$hash'; const output = '$output'; const hashBuffer = Buffer.from(hash, 'hex'); ots.Timestamp.hash(hashBuffer).then(timestamp => { const proof = { hash: hash, timestamp: new Date().toISOString(), status: 'pending' }; fs.writeFileSync(output, JSON.stringify(proof, null, 2)); console.log('Generated local proof (nodejs fallback)'); }).catch(err => { console.error('Error:', err); process.exit(1); }); " } # Check for available tools and generate proof if command -v ots &> /dev/null; then if generate_with_ots_cli "$COMMIT_HASH" "$OUTPUT_FILE"; then echo "[ots] Generated proof with ots CLI: ${COMMIT_HASH:0:8}" else echo "[ots] Warning: ots CLI failed" >&2 exit 0 fi elif command -v node &> /dev/null && node -e "require('@opentimestamps/ots')" &> /dev/null 2>&1; then generate_with_node "$COMMIT_HASH" "$OUTPUT_FILE" echo "[ots] Generated proof with nodejs fallback: ${COMMIT_HASH:0:8}" else echo "[ots] Warning: Neither ots CLI nor @opentimestamps/ots found, skipping proof" >&2 exit 0 fi # Save previous commit hash for chaining PREV_COMMIT=$(git rev-parse HEAD^1 2>/dev/null || echo "") if [ -n "$PREV_COMMIT" ]; then echo "$PREV_COMMIT" > "$OUTPUT_DIR/prev-commit.txt" fi # Create individual proof file for this commit INDIVIDUAL_PROOF="$OUTPUT_DIR/${COMMIT_HASH}.ots" if [ -f "$OUTPUT_FILE" ]; then cp "$OUTPUT_FILE" "$INDIVIDUAL_PROOF" fi echo "[ots] Proof generated successfully"