mirror of
https://github.com/ksyasuda/dotfiles.git
synced 2026-03-21 18:11:27 -07:00
update skills
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
# Configuration
|
||||
|
||||
## Script Loading
|
||||
|
||||
### Basic (Implicit Rendering)
|
||||
```html
|
||||
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
|
||||
```
|
||||
Automatically renders widgets with `class="cf-turnstile"` on page load.
|
||||
|
||||
### Explicit Rendering
|
||||
```html
|
||||
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"></script>
|
||||
```
|
||||
Manual control over when/where widgets render via `window.turnstile.render()`.
|
||||
|
||||
### With Load Callback
|
||||
```html
|
||||
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?onload=myCallback"></script>
|
||||
<script>
|
||||
function myCallback() {
|
||||
// API ready
|
||||
window.turnstile.render('#container', { sitekey: 'YOUR_SITE_KEY' });
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### Compatibility Mode
|
||||
```html
|
||||
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?compat=recaptcha"></script>
|
||||
```
|
||||
Provides `grecaptcha` API for Google reCAPTCHA drop-in replacement.
|
||||
|
||||
## Widget Configuration
|
||||
|
||||
### Complete Options Object
|
||||
|
||||
```javascript
|
||||
{
|
||||
// Required
|
||||
sitekey: 'YOUR_SITE_KEY', // Widget sitekey from dashboard
|
||||
|
||||
// Callbacks
|
||||
callback: (token) => {}, // Success - token ready
|
||||
'error-callback': (code) => {}, // Error occurred
|
||||
'expired-callback': () => {}, // Token expired (>5min)
|
||||
'timeout-callback': () => {}, // Challenge timeout
|
||||
'before-interactive-callback': () => {}, // Before showing checkbox
|
||||
'after-interactive-callback': () => {}, // After user interacts
|
||||
'unsupported-callback': () => {}, // Browser doesn't support Turnstile
|
||||
|
||||
// Appearance
|
||||
theme: 'auto', // 'light' | 'dark' | 'auto'
|
||||
size: 'normal', // 'normal' | 'compact' | 'flexible'
|
||||
tabindex: 0, // Tab order (accessibility)
|
||||
language: 'auto', // ISO 639-1 code or 'auto'
|
||||
|
||||
// Behavior
|
||||
execution: 'render', // 'render' (auto) | 'execute' (manual)
|
||||
appearance: 'always', // 'always' | 'execute' | 'interaction-only'
|
||||
retry: 'auto', // 'auto' | 'never'
|
||||
'retry-interval': 8000, // Retry interval (ms), default 8000
|
||||
'refresh-expired': 'auto', // 'auto' | 'manual' | 'never'
|
||||
|
||||
// Form Integration
|
||||
'response-field': true, // Add hidden input (default: true)
|
||||
'response-field-name': 'cf-turnstile-response', // Hidden input name
|
||||
|
||||
// Analytics & Data
|
||||
action: 'login', // Action name (for analytics)
|
||||
cData: 'user-session-123', // Custom data (returned in siteverify)
|
||||
}
|
||||
```
|
||||
|
||||
### Key Options Explained
|
||||
|
||||
**`execution`:**
|
||||
- `'render'` (default): Challenge starts immediately on render
|
||||
- `'execute'`: Wait for `turnstile.execute()` call
|
||||
|
||||
**`appearance`:**
|
||||
- `'always'` (default): Widget always visible
|
||||
- `'execute'`: Hidden until `execute()` called
|
||||
- `'interaction-only'`: Hidden until user interaction needed
|
||||
|
||||
**`refresh-expired`:**
|
||||
- `'auto'` (default): Auto-refresh expired tokens
|
||||
- `'manual'`: App must call `reset()` after expiry
|
||||
- `'never'`: No refresh, expired-callback triggered
|
||||
|
||||
**`retry`:**
|
||||
- `'auto'` (default): Auto-retry failed challenges
|
||||
- `'never'`: Don't retry, trigger error-callback
|
||||
|
||||
## HTML Data Attributes
|
||||
|
||||
For implicit rendering, use data attributes on `<div class="cf-turnstile">`:
|
||||
|
||||
| JavaScript Property | HTML Data Attribute | Example |
|
||||
|---------------------|---------------------|---------|
|
||||
| `sitekey` | `data-sitekey` | `data-sitekey="YOUR_KEY"` |
|
||||
| `action` | `data-action` | `data-action="login"` |
|
||||
| `cData` | `data-cdata` | `data-cdata="session-123"` |
|
||||
| `callback` | `data-callback` | `data-callback="onSuccess"` |
|
||||
| `error-callback` | `data-error-callback` | `data-error-callback="onError"` |
|
||||
| `expired-callback` | `data-expired-callback` | `data-expired-callback="onExpired"` |
|
||||
| `timeout-callback` | `data-timeout-callback` | `data-timeout-callback="onTimeout"` |
|
||||
| `theme` | `data-theme` | `data-theme="dark"` |
|
||||
| `size` | `data-size` | `data-size="compact"` |
|
||||
| `tabindex` | `data-tabindex` | `data-tabindex="0"` |
|
||||
| `response-field` | `data-response-field` | `data-response-field="false"` |
|
||||
| `response-field-name` | `data-response-field-name` | `data-response-field-name="token"` |
|
||||
| `retry` | `data-retry` | `data-retry="never"` |
|
||||
| `retry-interval` | `data-retry-interval` | `data-retry-interval="5000"` |
|
||||
| `language` | `data-language` | `data-language="en"` |
|
||||
| `execution` | `data-execution` | `data-execution="execute"` |
|
||||
| `appearance` | `data-appearance` | `data-appearance="interaction-only"` |
|
||||
| `refresh-expired` | `data-refresh-expired` | `data-refresh-expired="manual"` |
|
||||
|
||||
**Example:**
|
||||
```html
|
||||
<div class="cf-turnstile"
|
||||
data-sitekey="YOUR_SITE_KEY"
|
||||
data-theme="dark"
|
||||
data-callback="onTurnstileSuccess"
|
||||
data-error-callback="onTurnstileError"></div>
|
||||
```
|
||||
|
||||
## Content Security Policy
|
||||
|
||||
Add these directives to CSP header/meta tag:
|
||||
|
||||
```
|
||||
script-src https://challenges.cloudflare.com;
|
||||
frame-src https://challenges.cloudflare.com;
|
||||
```
|
||||
|
||||
**Full Example:**
|
||||
```html
|
||||
<meta http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self';
|
||||
script-src 'self' https://challenges.cloudflare.com;
|
||||
frame-src https://challenges.cloudflare.com;">
|
||||
```
|
||||
|
||||
## Framework-Specific Setup
|
||||
|
||||
### React
|
||||
```bash
|
||||
npm install @marsidev/react-turnstile
|
||||
```
|
||||
```jsx
|
||||
import Turnstile from '@marsidev/react-turnstile';
|
||||
|
||||
<Turnstile
|
||||
siteKey="YOUR_SITE_KEY"
|
||||
onSuccess={(token) => console.log(token)}
|
||||
/>
|
||||
```
|
||||
|
||||
### Vue
|
||||
```bash
|
||||
npm install vue-turnstile
|
||||
```
|
||||
```vue
|
||||
<template>
|
||||
<VueTurnstile site-key="YOUR_SITE_KEY" @success="onSuccess" />
|
||||
</template>
|
||||
<script setup>
|
||||
import VueTurnstile from 'vue-turnstile';
|
||||
</script>
|
||||
```
|
||||
|
||||
### Svelte
|
||||
```bash
|
||||
npm install svelte-turnstile
|
||||
```
|
||||
```svelte
|
||||
<script>
|
||||
import Turnstile from 'svelte-turnstile';
|
||||
</script>
|
||||
<Turnstile siteKey="YOUR_SITE_KEY" on:turnstile-callback={handleToken} />
|
||||
```
|
||||
|
||||
### Next.js (App Router)
|
||||
```tsx
|
||||
// app/components/TurnstileWidget.tsx
|
||||
'use client';
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
export default function TurnstileWidget({ sitekey, onSuccess }) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (ref.current && window.turnstile) {
|
||||
const widgetId = window.turnstile.render(ref.current, {
|
||||
sitekey,
|
||||
callback: onSuccess
|
||||
});
|
||||
return () => window.turnstile.remove(widgetId);
|
||||
}
|
||||
}, [sitekey, onSuccess]);
|
||||
|
||||
return <div ref={ref} />;
|
||||
}
|
||||
```
|
||||
|
||||
## Cloudflare Pages Plugin
|
||||
|
||||
```bash
|
||||
npm install @cloudflare/pages-plugin-turnstile
|
||||
```
|
||||
|
||||
```typescript
|
||||
// functions/_middleware.ts
|
||||
import turnstilePlugin from '@cloudflare/pages-plugin-turnstile';
|
||||
|
||||
export const onRequest = turnstilePlugin({
|
||||
secret: 'YOUR_SECRET_KEY',
|
||||
onError: () => new Response('CAPTCHA failed', { status: 403 })
|
||||
});
|
||||
```
|
||||
Reference in New Issue
Block a user