mirror of
https://github.com/supabase/supabase.git
synced 2026-10-07 02:15:05 +03:00
Merge pull request #10835 from supabase/thor/add-cloudflare-turnstile-example
feat: add cloudflare turnstile example.
This commit is contained in:
3 files changed
+87
-1
No files matched your search
@@ -1,4 +1,4 @@
|
||||
export const corsHeaders = {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey',
|
||||
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
# Cloudflare Turnstile
|
||||
|
||||
Turnstile is Cloudflare's CAPTCHA alternative: https://developers.cloudflare.com/turnstile/get-started/
|
||||
|
||||
## Setup
|
||||
|
||||
- Follow these steps to set up a new site: https://developers.cloudflare.com/turnstile/get-started/
|
||||
- Add the Cloudflare Turnstile widget to your site: https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/
|
||||
|
||||
## Deploy the server-side validation Edge Functions
|
||||
|
||||
- https://developers.cloudflare.com/turnstile/get-started/server-side-validation/
|
||||
|
||||
```bash
|
||||
supabase functions deploy cloudflare-turnstile
|
||||
supabase secrets set CLOUDFLARE_TURNSTILE_SECRET_KEY=your_secret_key
|
||||
```
|
||||
|
||||
## Invoke the function from your site
|
||||
|
||||
```js
|
||||
const { data, error } = await supabase.functions.invoke('cloudflare-turnstile', {
|
||||
body: { token },
|
||||
})
|
||||
```
|
||||
@@ -0,0 +1,61 @@
|
||||
// Follow this setup guide to integrate the Deno language server with your editor:
|
||||
// https://deno.land/manual/getting_started/setup_your_environment
|
||||
// This enables autocomplete, go to definition, etc.
|
||||
|
||||
import { serve } from 'https://deno.land/std@0.131.0/http/server.ts'
|
||||
import { corsHeaders } from '../_shared/cors.ts'
|
||||
|
||||
console.log(`Function "cloudflare-turnstile" up and running!`)
|
||||
|
||||
function ips(req: Request) {
|
||||
return req.headers.get('x-forwarded-for')?.split(/\s*,\s*/)
|
||||
}
|
||||
|
||||
serve(async (req) => {
|
||||
// This is needed if you're planning to invoke your function from a browser.
|
||||
if (req.method === 'OPTIONS') {
|
||||
return new Response('ok', { headers: corsHeaders })
|
||||
}
|
||||
|
||||
try {
|
||||
const { token } = await req.json()
|
||||
if (!token) throw new Error('Missing token!')
|
||||
|
||||
const clientIps = ips(req) || ['']
|
||||
|
||||
// Validate the token by calling the
|
||||
// "/siteverify" API endpoint.
|
||||
const formData = new FormData()
|
||||
formData.append('secret', Deno.env.get('CLOUDFLARE_TURNSTILE_SECRET_KEY') ?? '')
|
||||
formData.append('response', token)
|
||||
formData.append('remoteip', clientIps[0])
|
||||
|
||||
const url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify'
|
||||
const result = await fetch(url, {
|
||||
body: formData,
|
||||
method: 'POST',
|
||||
})
|
||||
|
||||
const outcome = await result.json()
|
||||
console.log(outcome)
|
||||
if (outcome.success) {
|
||||
return new Response(JSON.stringify(outcome), {
|
||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
||||
status: 200,
|
||||
})
|
||||
}
|
||||
|
||||
throw new Error('Turnstile validation failed!')
|
||||
} catch (error) {
|
||||
return new Response(JSON.stringify({ error: error.message }), {
|
||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
||||
status: 400,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// To invoke:
|
||||
// curl -i --location --request POST 'http://localhost:54321/functions/v1/' \
|
||||
// --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0' \
|
||||
// --header 'Content-Type: application/json' \
|
||||
// --data '{"token":"cf-turnstile-response"}'
|
||||
Reference in new issue
Block a user