import { createServer } from 'node:http'; import { readFile } from 'node:fs/promises'; import { fileURLToPath } from 'node:url'; const secret = process.env.CAP_SECRET; if (!secret) throw new Error('Set CAP_SECRET on the server.'); const html = await readFile(fileURLToPath(new URL('./index.html', import.meta.url))); createServer(async (req, res) => { const send = (status, text, type = 'text/plain; charset=utf-8') => { res.writeHead(status, { 'Content-Type': type, 'Cache-Control': 'no-store' }); res.end(text); }; if (req.method === 'GET' && req.url === '/') return send(200, html, 'text/html; charset=utf-8'); if (req.method !== 'POST' || req.url !== '/contact') return send(404, 'Not found'); if (!req.headers['content-type']?.startsWith('application/x-www-form-urlencoded')) return send(415, 'Unsupported form type'); try { const chunks = []; let bytes = 0; for await (const chunk of req) { bytes += chunk.length; if (bytes > 65536) return send(413, 'Form too large'); chunks.push(chunk); } const form = new URLSearchParams(Buffer.concat(chunks).toString('utf8')); const message = form.get('message')?.trim(); if (!message || message.length > 2000) return send(400, '请填写 1–2000 字留言。'); const response = form.get('cap-response'); if (!response) return send(403, '请先完成验证。'); const check = await fetch('https://cap.bug.im/v1/siteverify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ secret, response }), signal: AbortSignal.timeout(8000), }); const result = await check.json(); if (!check.ok || result.success !== true || result.degraded === true) return send(403, '验证未通过,请返回并重新验证。'); // Persist the validated message here, then return success. return send(200, '验证通过。此示例未保存留言。'); } catch { return send(503, '暂时无法校验,请返回并重新验证。'); } }).listen(3000, '127.0.0.1'); console.log('Open http://127.0.0.1:3000');