/** * TASK-0107 §6(c) — the reCAPTCHA verification HOOK POINT (stub). * * Phase 10 ships the seam, not the integration: `verifyRecaptcha` returns * `{ skipped: true }` while the provider is unconfigured (the real Google * verification lands in Phase 13+ against `RECAPTCHA_SECRET`). The public * page renders the placeholder widget div and the submit payload carries * the `recaptchaToken` slot when `config.recaptcha.enabled` — both flow * through this function so the Phase-13 swap is a single-file change. */ import { loadEnv } from "../../config/env.js"; import { logger } from "../../common/logger.js"; export interface RecaptchaResult { /** True when no verification ran (provider unconfigured / disabled). */ skipped: boolean; /** The verified end-user IP (set by the real provider in Phase 13+). */ success: boolean; ip?: string; } /** * Verify a reCAPTCHA token. STUB behavior (documented): * - provider not configured (`RECAPTCHA_SECRET` empty) → `{ skipped: true, success: true }` * + a one-per-request WARN log ("recaptcha verification skipped (stub)"); * - provider configured → the Phase-13 implementation site (throws * `RECAPTCHA_NOT_CONFIGURED` for now so a half-configured deployment * fails LOUD instead of silently open). */ export async function verifyRecaptcha(_token: string | undefined, _ip: string): Promise { const env = loadEnv(); if (!env.RECAPTCHA_SECRET) { logger.warn("recaptcha verification skipped (stub — RECAPTCHA_SECRET not configured)"); return { skipped: true, success: true }; } // Phase 13: POST https://www.google.com/recaptcha/api/siteverify throw new Error("recaptcha provider not implemented (Phase 13)"); }