130 lines
4.0 KiB
Markdown
130 lines
4.0 KiB
Markdown
# turnstile
|
|
|
|
Cloudflare Turnstile: widget (client) + weryfikacja (server). Klucze z
|
|
SiteIntegrations (panel, nie env). Widget dostaje `siteKey` jako prop; verify
|
|
czyta secret server-side.
|
|
|
|
## Config
|
|
|
|
Brak opcji — pola `turnstileSiteKey` / `turnstileSecretKey` są w
|
|
SiteIntegrations (tab Turnstile). Edytor wpisuje klucze w panelu.
|
|
|
|
## Front — widget (client)
|
|
|
|
Import z `@intecion/ipal-kit/client`. `siteKey` pobierz server-side i przekaż jako prop:
|
|
|
|
```tsx
|
|
// server component — pobiera publiczny siteKey z panelu
|
|
import { getSiteIntegrations } from '@intecion/ipal-kit'
|
|
|
|
const { turnstileSiteKey } = await getSiteIntegrations(payload)
|
|
// przekaż do swojego client-formularza → widget
|
|
```
|
|
|
|
```tsx
|
|
'use client'
|
|
import { Turnstile } from '@intecion/ipal-kit/client'
|
|
import { useState } from 'react'
|
|
|
|
function ContactForm({ siteKey }) {
|
|
const [token, setToken] = useState<string | null>(null)
|
|
return (
|
|
<form>
|
|
{/* pola */}
|
|
<Turnstile siteKey={siteKey} onToken={setToken} theme="auto" />
|
|
<button disabled={!token}>Wyślij</button>
|
|
</form>
|
|
)
|
|
}
|
|
```
|
|
|
|
Widget ładuje skrypt Turnstile sam (bez `next/script`), zwraca token przez
|
|
`onToken` (null przy wygaśnięciu/błędzie).
|
|
|
|
## Front — verify (server)
|
|
|
|
```ts
|
|
import { verifyTurnstile } from '@intecion/ipal-kit/server'
|
|
|
|
const ok = await verifyTurnstile({ token, payload, ip })
|
|
if (!ok) {
|
|
// odrzuć zgłoszenie
|
|
}
|
|
```
|
|
|
|
`verifyTurnstile` czyta secret z SiteIntegrations (Local API), woła Cloudflare.
|
|
Zwraca `false` na każdy problem (brak klucza, sieć, odrzucenie) — traktuj
|
|
`false` jako „nie ufaj temu zgłoszeniu". `server-only` gwarantuje, że nie
|
|
trafi do bundla przeglądarki.
|
|
|
|
> W formularzach zwykle nie wołasz `verifyTurnstile` wprost — robi to
|
|
> `submitForm` (patrz [forms.md](./forms.md)).
|
|
|
|
## Uproszczone wpięcie — TurnstileProvider + useTurnstile (zalecane)
|
|
|
|
Jak CookieBanner: siteKey raz w layoutcie, formularze biorą z kontekstu. Koniec
|
|
przekazywania siteKey do każdego formularza.
|
|
|
|
### 1. Provider w layoutcie (raz, siteKey z serwera)
|
|
|
|
```tsx
|
|
// app/(frontend)/[locale]/layout.tsx (server)
|
|
import { TurnstileProvider } from '@intecion/ipal-kit/client'
|
|
import { getTurnstileSiteKey } from '@/lib/payload' // Twój helper server-side
|
|
|
|
export default async function Layout({ children }) {
|
|
const siteKey = await getTurnstileSiteKey() // z panelu (SiteIntegrations)
|
|
return (
|
|
<html>
|
|
<body>
|
|
<TurnstileProvider siteKey={siteKey}>
|
|
{children}
|
|
</TurnstileProvider>
|
|
</body>
|
|
</html>
|
|
)
|
|
}
|
|
```
|
|
|
|
### 2. Formularz — useTurnstile (zero plumbingu siteKey)
|
|
|
|
```tsx
|
|
'use client'
|
|
import { useTurnstile } from '@intecion/ipal-kit/client'
|
|
|
|
function ContactForm() {
|
|
const { token, TurnstileWidget, reset, enabled } = useTurnstile()
|
|
|
|
async function handleSubmit(data) {
|
|
const result = await submitForm({ ...data, turnstileToken: token })
|
|
if (result.ok) reset() // wyczyść token na następne wysłanie
|
|
}
|
|
|
|
return (
|
|
<form onSubmit={...}>
|
|
{/* pola formularza */}
|
|
<TurnstileWidget /> {/* widget tam, gdzie ma być */}
|
|
<button type="submit">Wyślij</button>
|
|
</form>
|
|
)
|
|
}
|
|
```
|
|
|
|
`token` → do submitForm. `TurnstileWidget` → wstaw gdzie ma być. `reset()` → po
|
|
wysłaniu. `enabled` → false gdy brak klucza (dev bez Turnstile).
|
|
|
|
### Dlaczego Turnstile NIE jest w pełni "wstaw i zapomnij" jak CookieBanner
|
|
|
|
CookieBanner jest samodzielny (renderuje się, zarządza zgodą, zero interakcji).
|
|
Turnstile z natury jest CZĘŚCIĄ formularza — zwraca token, który formularz musi
|
|
wysłać przy submit i zweryfikować server-side. Nie da się go „wstawić
|
|
gdziekolwiek" — musi być w formularzu, przy jego logice wysyłki.
|
|
|
|
Provider+hook to maksimum uproszczenia: siteKey raz (jak CookieBanner), a w
|
|
formularzu tylko `<TurnstileWidget/>` + `token`. Reszta (weryfikacja) dzieje się
|
|
w submitForm automatycznie.
|
|
|
|
### Stary sposób (nadal działa)
|
|
|
|
`<Turnstile siteKey={...} onToken={...} />` bezpośrednio — jeśli potrzebujesz
|
|
pełnej kontroli albo masz nietypowy przypadek. Provider to warstwa wygody nad tym. |