Files
Synapsis/src/lib/turnstile.ts
T
Christomatt 5b0269af34 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
2026-01-26 18:10:48 +01:00

52 lines
1.7 KiB
TypeScript

import { db, nodes } from '@/db';
import { eq } from 'drizzle-orm';
export async function verifyTurnstileToken(token: string, ip?: string): Promise<boolean> {
try {
// Get node settings to check if Turnstile is enabled
const domain = process.env.NEXT_PUBLIC_NODE_DOMAIN || 'localhost:3000';
const node = await db.query.nodes.findFirst({
where: eq(nodes.domain, domain),
});
// If no secret key is configured, skip verification (Turnstile is disabled)
if (!node?.turnstileSecretKey) {
return true;
}
// Verify the token with Cloudflare
const formData = new FormData();
formData.append('secret', node.turnstileSecretKey);
formData.append('response', token);
if (ip) {
formData.append('remoteip', ip);
}
const response = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', {
method: 'POST',
body: formData,
});
const data = await response.json();
return data.success === true;
} catch (error) {
console.error('Turnstile verification error:', error);
// On error, fail closed (reject the request)
return false;
}
}
export async function getTurnstileSiteKey(): Promise<string | null> {
try {
const domain = process.env.NEXT_PUBLIC_NODE_DOMAIN || 'localhost:3000';
const node = await db.query.nodes.findFirst({
where: eq(nodes.domain, domain),
});
return node?.turnstileSiteKey || null;
} catch (error) {
console.error('Error fetching Turnstile site key:', error);
return null;
}
}