← back to Secrets Manager

clipboard-watcher.sh

107 lines

#!/usr/bin/env bash
# Clipboard token watcher — polls pbpaste every 2s, detects token formats,
# pipes them DIRECTLY into cli.js import-paste (no Desktop file middleman —
# launchd can't read ~/Desktop without Full Disk Access).
#
# Steve's only required action: create token at provider → click Copy.
# This catches it within 2s, validates against provider, fans out to all
# .env destinations.
#
# Auto-terminates after 30 min OR when the 4 site-factory tokens are all
# in the master registry, whichever comes first. Safe to run repeatedly.
set -uo pipefail

ROOT=/Users/macstudio3/Projects/secrets-manager
MASTER=$ROOT/.env
LAST=$ROOT/.clipboard-last-hash
LOG=$ROOT/clipboard-watcher.log
START=$(date +%s)
TIMEOUT=$((30 * 60))   # 30 min

TS() { date +%FT%T%z; }

# Already-seen clipboard hash (so we don't re-process the same value)
PREV_HASH=""
[ -f "$LAST" ] && PREV_HASH=$(cat "$LAST")

# Has-token check — read master registry env (which IS readable by launchd)
has_token() {
  [ -f "$MASTER" ] && grep -qE "^$1=[^[:space:]#]+" "$MASTER" 2>/dev/null
}

# Pipe into cli.js — handles validation + fan-out + registry update
ingest_via_cli() {
  local KEY=$1 VAL=$2
  echo "[$(TS)] capturing $KEY (…${VAL: -4}) → cli.js import-paste" >> "$LOG"
  printf '%s=%s\n' "$KEY" "$VAL" | /opt/homebrew/bin/node "$ROOT/cli.js" import-paste >> "$LOG" 2>&1
  /usr/bin/afplay /System/Library/Sounds/Pop.aiff 2>/dev/null &
  /usr/bin/osascript -e "display notification \"$KEY captured & validated\" with title \"Secrets Clipboard\"" 2>/dev/null &
}

# Detect which token type a clipboard value is
classify() {
  local V=$1
  # Strip leading/trailing whitespace
  V=$(echo "$V" | /usr/bin/tr -d '\r\n' | /usr/bin/awk '{gsub(/^ +| +$/, ""); print}')
  [ -z "$V" ] && return 1
  case "$V" in
    sk_live_*|sk_test_*) echo "STRIPE_SECRET_KEY=$V"; return 0 ;;
    rk_live_*|rk_test_*) echo "STRIPE_RESTRICTED_KEY=$V"; return 0 ;;
    pk_live_*|pk_test_*) echo "STRIPE_PUBLISHABLE_KEY=$V"; return 0 ;;
    whsec_*)             echo "STRIPE_WEBHOOK_SECRET=$V"; return 0 ;;
    bb_live_*)           echo "BROWSERBASE_API_KEY=$V"; return 0 ;;
    sk-ant-*)            echo "ANTHROPIC_API_KEY=$V"; return 0 ;;
    sk-*)                echo "OPENAI_API_KEY=$V"; return 0 ;;
    AIza*)               echo "GEMINI_API_KEY=$V"; return 0 ;;
    ghp_*|github_pat_*)  echo "GITHUB_TOKEN=$V"; return 0 ;;
    shpat_*|shpca_*)     echo "SHOPIFY_ADMIN_TOKEN=$V"; return 0 ;;
    re_*)                echo "RESEND_API_KEY=$V"; return 0 ;;
  esac
  # Vercel tokens: 24 alphanumeric chars (no prefix). Detect by length + charset.
  if [[ "$V" =~ ^[A-Za-z0-9]{24}$ ]]; then
    echo "VERCEL_TOKEN=$V"; return 0
  fi
  # Cloudflare API tokens: 40 chars alphanumeric/underscore/dash, starts with letter
  if [[ "$V" =~ ^[A-Za-z][A-Za-z0-9_-]{39}$ ]] && [ ${#V} -eq 40 ]; then
    echo "CLOUDFLARE_API_TOKEN=$V"; return 0
  fi
  # PurelyMail tokens: hex-ish, length 32-64. Lower confidence — only match if length 40+ and pure hex
  if [[ "$V" =~ ^[a-f0-9]{40,}$ ]]; then
    echo "PURELYMAIL_API_TOKEN=$V"; return 0
  fi
  return 1
}

echo "[$(TS)] clipboard-watcher start (timeout ${TIMEOUT}s)" >> "$LOG"

while true; do
  # Timeout
  NOW=$(date +%s)
  if [ $((NOW - START)) -ge $TIMEOUT ]; then
    echo "[$(TS)] timeout reached, exiting" >> "$LOG"
    break
  fi

  # All 4 main tokens captured? Done early.
  if has_token CLOUDFLARE_API_TOKEN && has_token STRIPE_SECRET_KEY && has_token VERCEL_TOKEN && has_token PURELYMAIL_API_TOKEN; then
    echo "[$(TS)] all 4 trigger tokens captured, exiting early" >> "$LOG"
    /usr/bin/afplay /System/Library/Sounds/Glass.aiff 2>/dev/null &
    /usr/bin/osascript -e 'display notification "All 4 site-factory tokens captured" with title "Secrets Clipboard"' 2>/dev/null &
    break
  fi

  CLIP=$(/usr/bin/pbpaste 2>/dev/null || true)
  HASH=$(printf '%s' "$CLIP" | shasum -a 256 | awk '{print $1}')
  if [ "$HASH" != "$PREV_HASH" ] && [ -n "$CLIP" ] && [ ${#CLIP} -lt 500 ]; then
    if MATCH=$(classify "$CLIP"); then
      KEY=${MATCH%%=*}
      VAL=${MATCH#*=}
      ingest_via_cli "$KEY" "$VAL"
    fi
    PREV_HASH=$HASH
    echo "$HASH" > "$LAST"
  fi

  sleep 2
done