Files
WRNexusJS/packages/captcha/src/helpers.ts
T
Clintchiz 586a6db8ff
Quality / quality (ubuntu-latest) (push) Failing after 21s
Quality / quality (windows-latest) (push) Canceled after 0s
release: WRNexusJS 0.8.0
2026-08-02 23:18:51 +05:30

91 lines
3.1 KiB
TypeScript

import type { Context } from "@wrnexus/core";
import type {
CaptchaEngine,
CaptchaProvider,
CaptchaVerificationResult,
VerifyCaptchaInput,
} from "./types.ts";
import { selfHostedProvider } from "./providers/self-hosted.ts";
export function captchaTokenFrom(
value: Request | Headers | FormData | URLSearchParams | Record<string, unknown>,
field = "wrn-captcha-response",
): Promise<string | undefined> | string | undefined {
if (value instanceof Request) {
const header = value.headers.get("x-wrn-captcha-token");
if (header) return header;
return value
.clone()
.formData()
.then((form) => {
const token = form.get(field) ?? form.get("captchaToken") ?? form.get("responseToken");
return typeof token === "string" ? token : undefined;
})
.catch(async () => {
try {
const body = (await value.clone().json()) as Record<string, unknown>;
const token = body[field] ?? body.captchaToken ?? body.responseToken;
return token === undefined ? undefined : String(token);
} catch {
return undefined;
}
});
}
if (value instanceof Headers) {
return value.get("x-wrn-captcha-token") ?? value.get("x-captcha-token") ?? undefined;
}
if (value instanceof FormData || value instanceof URLSearchParams) {
const token = value.get(field) ?? value.get("captchaToken") ?? value.get("responseToken");
return typeof token === "string" ? token : undefined;
}
const token = value[field] ?? value.captchaToken ?? value.responseToken;
return token === undefined ? undefined : String(token);
}
export function captchaHeaders(token: string): HeadersInit {
return { "x-wrn-captcha-token": token };
}
export function captchaFields(
token: string,
field = "wrn-captcha-response",
): Record<string, string> {
return { [field]: token };
}
export async function verifyCaptcha(
providerOrEngine: CaptchaProvider | CaptchaEngine,
input: VerifyCaptchaInput,
): Promise<CaptchaVerificationResult> {
const provider: CaptchaProvider =
"client" in providerOrEngine
? (providerOrEngine as CaptchaProvider)
: selfHostedProvider(providerOrEngine as CaptchaEngine);
return provider.verify(input);
}
export async function verifyCaptchaOrThrow(
providerOrEngine: CaptchaProvider | CaptchaEngine,
input: VerifyCaptchaInput,
): Promise<CaptchaVerificationResult> {
const result = await verifyCaptcha(providerOrEngine, input);
if (!result.success) {
throw new Error(
`WRN-CAPTCHA-${String(result.code ?? "FAILED").toUpperCase()}: ${result.message ?? "CAPTCHA verification failed"}`,
);
}
return result;
}
export function captchaResultResponse(result: CaptchaVerificationResult): Response {
return Response.json(result, {
status: result.success ? 200 : 403,
headers: { "cache-control": "no-store", "x-content-type-options": "nosniff" },
});
}
export function captchaContext(ctx: Context): CaptchaVerificationResult | null {
const result = ctx.locals.captcha;
return result && typeof result === "object" ? (result as CaptchaVerificationResult) : null;
}