/**
 * Server-side CAPTCHA verification for reCAPTCHA v3 and Cloudflare Turnstile.
 * Both providers share the same verify interface — only the secret key and
 * verification URL differ.
 */
const VERIFY_URLS = {
    recaptcha: 'https://www.google.com/recaptcha/api/siteverify',
    turnstile: 'https://challenges.cloudflare.com/turnstile/v0/siteverify',
};
/**
 * Verifies a CAPTCHA token server-side.
 * Works for both reCAPTCHA v3 and Cloudflare Turnstile.
 */
export async function verifyCaptcha(token, config, remoteIp) {
    if (config.provider === 'none') {
        return { success: true };
    }
    if (!token) {
        return { success: false, errorCodes: ['missing-input-response'] };
    }
    const verifyUrl = VERIFY_URLS[config.provider];
    if (!verifyUrl) {
        return { success: false, errorCodes: [`unknown-provider:${config.provider}`] };
    }
    const params = new URLSearchParams({
        secret: config.secretKey,
        response: token,
    });
    if (remoteIp) {
        params.set('remoteip', remoteIp);
    }
    try {
        const res = await fetch(verifyUrl, {
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            body: params.toString(),
        });
        if (!res.ok) {
            return { success: false, errorCodes: [`http-error:${res.status}`] };
        }
        const data = (await res.json());
        if (!data.success) {
            return {
                success: false,
                score: data.score,
                action: data.action,
                errorCodes: data['error-codes'] ?? [],
            };
        }
        // reCAPTCHA v3 returns a score; enforce the threshold
        if (config.provider === 'recaptcha' && typeof data.score === 'number') {
            const threshold = config.scoreThreshold ?? 0.5;
            if (data.score < threshold) {
                return {
                    success: false,
                    score: data.score,
                    action: data.action,
                    errorCodes: ['score-below-threshold'],
                };
            }
        }
        return {
            success: true,
            score: data.score,
            action: data.action,
        };
    }
    catch (err) {
        return {
            success: false,
            errorCodes: ['network-error'],
        };
    }
}
/**
 * Resolves CAPTCHA config from environment variables.
 * Returns { provider: 'none' } if no keys are configured.
 */
export function getCaptchaConfig() {
    const recaptchaSiteKey = process.env.RECAPTCHA_SITE_KEY;
    const recaptchaSecret = process.env.RECAPTCHA_SECRET_KEY;
    if (recaptchaSiteKey && recaptchaSecret) {
        return {
            provider: 'recaptcha',
            siteKey: recaptchaSiteKey,
            secretKey: recaptchaSecret,
            scoreThreshold: parseFloat(process.env.RECAPTCHA_SCORE_THRESHOLD ?? '0.5'),
        };
    }
    const turnstileSiteKey = process.env.TURNSTILE_SITE_KEY;
    const turnstileSecret = process.env.TURNSTILE_SECRET_KEY;
    if (turnstileSiteKey && turnstileSecret) {
        return {
            provider: 'turnstile',
            siteKey: turnstileSiteKey,
            secretKey: turnstileSecret,
        };
    }
    return { provider: 'none', siteKey: '', secretKey: '' };
}
//# sourceMappingURL=captcha.js.map