feat(auth): Integrate Cloudflare Turnstile bot protection and enhance swarm tracking
- Add Cloudflare Turnstile integration for login and registration forms - Create turnstile verification utility with server-side token validation - Add turnstile_site_key and turnstile_secret_key fields to nodes table - Implement admin panel UI for configuring Turnstile keys in settings - Update login and register API routes to verify Turnstile tokens - Expose turnstile_site_key via GET /api/node endpoint for frontend - Add admin endpoint to save and update Turnstile configuration - Create remote_likes and remote_reposts tables for federated interaction tracking - Add swarm reply metadata fields (swarm_reply_to_id, swarm_reply_to_content, swarm_reply_to_author) to posts table - Add comprehensive TURNSTILE_SETUP.md documentation with setup instructions and security notes - Create database migration 0007 with schema updates and indexes - Protects against bot registrations and automated attacks on federated nodes
This commit is contained in:
@@ -72,6 +72,8 @@ export default function AdminPage() {
|
||||
faviconUrl: '',
|
||||
accentColor: '#FFFFFF',
|
||||
isNsfw: false,
|
||||
turnstileSiteKey: '',
|
||||
turnstileSecretKey: '',
|
||||
});
|
||||
const [savingSettings, setSavingSettings] = useState(false);
|
||||
const [isUploadingBanner, setIsUploadingBanner] = useState(false);
|
||||
@@ -142,6 +144,8 @@ export default function AdminPage() {
|
||||
faviconUrl: data.faviconUrl || '',
|
||||
accentColor: data.accentColor || '#FFFFFF',
|
||||
isNsfw: data.isNsfw || false,
|
||||
turnstileSiteKey: data.turnstileSiteKey || '',
|
||||
turnstileSecretKey: data.turnstileSecretKey || '',
|
||||
});
|
||||
} catch {
|
||||
// error
|
||||
@@ -809,6 +813,71 @@ export default function AdminPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
padding: '16px',
|
||||
background: 'var(--background-secondary)',
|
||||
borderRadius: '8px',
|
||||
border: '1px solid var(--border)',
|
||||
}}>
|
||||
<div style={{ marginBottom: '16px' }}>
|
||||
<label style={{ fontSize: '13px', fontWeight: 600, marginBottom: '4px', display: 'block' }}>
|
||||
Cloudflare Turnstile (Bot Protection)
|
||||
</label>
|
||||
<p style={{ fontSize: '12px', color: 'var(--foreground-secondary)', marginBottom: '12px' }}>
|
||||
Add Cloudflare Turnstile to protect registration and login from bots. Get your keys from the{' '}
|
||||
<a href="https://dash.cloudflare.com/?to=/:account/turnstile" target="_blank" rel="noopener noreferrer" style={{ color: 'var(--accent)' }}>
|
||||
Cloudflare Dashboard
|
||||
</a>.
|
||||
</p>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gap: '12px' }}>
|
||||
<div>
|
||||
<label style={{ fontSize: '12px', fontWeight: 500, marginBottom: '4px', display: 'block' }}>
|
||||
Site Key
|
||||
</label>
|
||||
<input
|
||||
className="input"
|
||||
type="text"
|
||||
value={nodeSettings.turnstileSiteKey}
|
||||
onChange={e => setNodeSettings({ ...nodeSettings, turnstileSiteKey: e.target.value })}
|
||||
placeholder="0x4AAAAAAA..."
|
||||
style={{ fontFamily: 'monospace', fontSize: '13px' }}
|
||||
/>
|
||||
<p style={{ fontSize: '11px', color: 'var(--foreground-tertiary)', marginTop: '4px' }}>
|
||||
Public key shown to users
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<label style={{ fontSize: '12px', fontWeight: 500, marginBottom: '4px', display: 'block' }}>
|
||||
Secret Key
|
||||
</label>
|
||||
<input
|
||||
className="input"
|
||||
type="password"
|
||||
value={nodeSettings.turnstileSecretKey}
|
||||
onChange={e => setNodeSettings({ ...nodeSettings, turnstileSecretKey: e.target.value })}
|
||||
placeholder="0x4AAAAAAA..."
|
||||
style={{ fontFamily: 'monospace', fontSize: '13px' }}
|
||||
/>
|
||||
<p style={{ fontSize: '11px', color: 'var(--foreground-tertiary)', marginTop: '4px' }}>
|
||||
Secret key for server-side verification
|
||||
</p>
|
||||
</div>
|
||||
{nodeSettings.turnstileSiteKey && nodeSettings.turnstileSecretKey && (
|
||||
<div style={{
|
||||
padding: '8px 12px',
|
||||
background: 'rgba(34, 197, 94, 0.1)',
|
||||
border: '1px solid rgba(34, 197, 94, 0.3)',
|
||||
borderRadius: '6px',
|
||||
fontSize: '12px',
|
||||
color: 'rgb(34, 197, 94)',
|
||||
}}>
|
||||
✓ Turnstile is enabled and will be shown on login/registration
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ paddingTop: '8px' }}>
|
||||
<button className="btn btn-primary" onClick={() => handleSaveSettings()} disabled={savingSettings}>
|
||||
{savingSettings ? 'Saving...' : 'Save Settings'}
|
||||
|
||||
Reference in New Issue
Block a user