From 84cacb81c206070ac0982db01ef91c3e67482210 Mon Sep 17 00:00:00 2001 From: giancarlo Date: Sat, 27 Apr 2024 19:13:11 +0700 Subject: [PATCH] Refactor CAPTCHA setup verification Eliminated constant verification of CAPTCHA setup across different modules and refactored the CAPTCHA token verification process. This commit relies on config parameters to decide whether to verify CAPTCHA or not, instead of environment variables. It also reforms the token submission to CAPTCHA service for consistency and clarity. --- .../src/captcha/server/verify-captcha.tsx | 16 +++++-- packages/next/src/actions/index.ts | 47 +++++++++---------- packages/next/src/routes/index.ts | 9 +--- 3 files changed, 35 insertions(+), 37 deletions(-) diff --git a/packages/features/auth/src/captcha/server/verify-captcha.tsx b/packages/features/auth/src/captcha/server/verify-captcha.tsx index 21cb27b21..bf306612c 100644 --- a/packages/features/auth/src/captcha/server/verify-captcha.tsx +++ b/packages/features/auth/src/captcha/server/verify-captcha.tsx @@ -3,20 +3,26 @@ import 'server-only'; const verifyEndpoint = 'https://challenges.cloudflare.com/turnstile/v0/siteverify'; -const secret = process.env.CAPTCHA_SECRET_TOKEN; +const CAPTCHA_SECRET_TOKEN = process.env.CAPTCHA_SECRET_TOKEN; /** - * Verify the CAPTCHA token with the CAPTCHA service - * @param token + * @name verifyCaptchaToken + * @description Verify the CAPTCHA token with the CAPTCHA service + * @param token - The CAPTCHA token to verify */ export async function verifyCaptchaToken(token: string) { - if (!secret) { + if (!CAPTCHA_SECRET_TOKEN) { throw new Error('CAPTCHA_SECRET_TOKEN is not set'); } + const formData = new FormData(); + + formData.append('secret', CAPTCHA_SECRET_TOKEN); + formData.append('response', token); + const res = await fetch(verifyEndpoint, { method: 'POST', - body: `secret=${encodeURIComponent(secret)}&response=${encodeURIComponent(token)}`, + body: formData, headers: { 'content-type': 'application/x-www-form-urlencoded', }, diff --git a/packages/next/src/actions/index.ts b/packages/next/src/actions/index.ts index 1b2a8b5a6..c71e13e0d 100644 --- a/packages/next/src/actions/index.ts +++ b/packages/next/src/actions/index.ts @@ -13,13 +13,6 @@ import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-clie import { captureException, zodParseFactory } from '../utils'; /** - * @name IS_CAPTCHA_SETUP - * @description Check if the CAPTCHA is setup - */ -const IS_CAPTCHA_SETUP = !!process.env.CAPTCHA_SECRET_TOKEN; - -/** - * * @name enhanceAction * @description Enhance an action with captcha, schema and auth checks */ @@ -48,9 +41,25 @@ export function enhanceAction< type UserParam = Config['auth'] extends false ? undefined : User; const requireAuth = config.auth ?? true; - let user: UserParam = undefined as UserParam; + // validate the schema passed in the config if it exists + const data = config.schema + ? zodParseFactory(config.schema)(params) + : params; + + // by default, the CAPTCHA token is not required + const verifyCaptcha = config.captcha ?? false; + + // verify the CAPTCHA token. It will throw an error if the token is invalid. + if (verifyCaptcha) { + const token = (data as Args & { captchaToken: string }).captchaToken; + + // Verify the CAPTCHA token. It will throw an error if the token is invalid. + await verifyCaptchaToken(token); + } + + // verify the user is authenticated if required if (requireAuth) { // verify the user is authenticated if required const auth = await requireUser(getSupabaseServerActionClient()); @@ -63,35 +72,23 @@ export function enhanceAction< user = auth.data as UserParam; } - // validate the schema - const data = config.schema - ? zodParseFactory(config.schema)(params) - : params; - - // verify captcha unless it's explicitly disabled - // verify the captcha token if required - const verifyCaptcha = config.captcha ?? IS_CAPTCHA_SETUP; - - if (verifyCaptcha) { - const token = (data as Args & { captchaToken: string }).captchaToken; - - // Verify the CAPTCHA token. It will throw an error if the token is invalid. - await verifyCaptchaToken(token); - } - // capture exceptions if required const shouldCaptureException = config.captureException ?? true; + // if the action should capture exceptions, wrap the action in a try/catch block if (shouldCaptureException) { try { + // pass the data to the action return await fn(data, user); } catch (error) { + // capture the exception await captureException(error); + // re-throw the error throw error; } } else { - // pass the data to the action + // no need to capture exceptions, just pass the data to the action return fn(data, user); } }; diff --git a/packages/next/src/routes/index.ts b/packages/next/src/routes/index.ts index 0a6744f95..c2bee0830 100644 --- a/packages/next/src/routes/index.ts +++ b/packages/next/src/routes/index.ts @@ -19,12 +19,6 @@ interface HandlerParams { body: Body; } -/** - * @name IS_CAPTCHA_SETUP - * @description Check if the CAPTCHA is setup - */ -const IS_CAPTCHA_SETUP = !!process.env.CAPTCHA_SECRET_TOKEN; - /** * Enhanced route handler function. * @@ -69,7 +63,8 @@ export const enhanceRouteHandler = < * This function takes a request object as an argument and returns a response object. */ return async function routeHandler(request: NextRequest) { - const shouldVerifyCaptcha = params?.captcha ?? IS_CAPTCHA_SETUP; + // Check if the captcha token should be verified + const shouldVerifyCaptcha = params?.captcha ?? false; // Verify the captcha token if required and setup if (shouldVerifyCaptcha) {