@@ -26,7 +26,7 @@ const inviteUserSchema = z.object({
2626 'org_admin' ,
2727 'org_super_admin' ,
2828 ] ) ,
29- captcha_token : z . string ( ) . check ( z . minLength ( 1 ) ) ,
29+ captcha_token : z . optional ( z . string ( ) . check ( z . minLength ( 1 ) ) ) ,
3030 first_name : z . string ( ) . check ( z . minLength ( 1 ) ) ,
3131 last_name : z . string ( ) . check ( z . minLength ( 1 ) ) ,
3232} )
@@ -108,7 +108,13 @@ async function validateInvite(c: Context, rawBody: any) {
108108 }
109109
110110 // Verify captcha token with Cloudflare Turnstile
111- await verifyCaptchaToken ( c , body . captcha_token )
111+ const captchaSecret = getEnv ( c , 'CAPTCHA_SECRET_KEY' )
112+ if ( captchaSecret . length > 0 ) {
113+ if ( ! body . captcha_token ) {
114+ throw simpleError ( 'invalid_request' , 'Captcha token is required' )
115+ }
116+ await verifyCaptchaToken ( c , body . captcha_token , captchaSecret )
117+ }
112118
113119 // Use authenticated client - RLS will enforce access based on JWT
114120 const supabase = supabaseClient ( c , authorization )
@@ -236,29 +242,24 @@ app.post('/', middlewareAuth, async (c) => {
236242 invited_first_name : `${ newInvitation ?. first_name ?? body . first_name } ` ,
237243 invited_last_name : `${ newInvitation ?. last_name ?? body . last_name } ` ,
238244 } , 'org:invite_new_capgo_user_to_org' )
239- if ( ! bentoEvent ) {
240- throw simpleError ( 'failed_to_invite_user' , 'Failed to invite user ', { } , 'Failed to track bento event' )
245+ if ( bentoEvent === false ) {
246+ cloudlog ( { requestId : c . get ( 'requestId' ) , context : 'invite_new_user_to_org bento ', message : 'Failed to track bento event' } )
241247 }
242248 return c . json ( BRES )
243249} )
244250
245251// Function to verify Cloudflare Turnstile token
246- async function verifyCaptchaToken ( c : Context , token : string ) {
247- const captchaSecret = getEnv ( c , 'CAPTCHA_SECRET_KEY' )
248- if ( ! captchaSecret ) {
249- throw simpleError ( 'captcha_secret_key_not_set' , 'CAPTCHA_SECRET_KEY not set' )
250- }
251-
252+ async function verifyCaptchaToken ( c : Context , token : string , captchaSecret : string ) {
252253 // "/siteverify" API endpoint.
253254 const url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify'
254255 const result = await fetch ( url , {
255- body : JSON . stringify ( {
256+ body : new URLSearchParams ( {
256257 secret : captchaSecret ,
257258 response : token ,
258259 } ) ,
259260 method : 'POST' ,
260261 headers : {
261- 'Content-Type' : 'application/json ' ,
262+ 'Content-Type' : 'application/x-www-form-urlencoded ' ,
262263 } ,
263264 } )
264265
0 commit comments