import { Resend } from 'resend' import { escapeHtml } from '../helpers.js' import { getResendFromAddress, getResendInboxAddress, sendResendEmailWithRetry } from '../email.js' // A visitor who finished the /salvation page can tell us they prayed to receive Christ. // Nothing is stored on the server: the response is emailed once to the site inbox and that is all. const hits = new Map() function rateLimit(req, res, next) { const ip = req.ip ?? 'unknown' const now = Date.now() const windowMs = 10 * 60 * 1000 const entry = hits.get(ip) ?? { count: 0, start: now } if (now - entry.start > windowMs) { entry.count = 0; entry.start = now } entry.count += 1 hits.set(ip, entry) if (hits.size > 2000) { for (const [k, v] of hits) { if (now - v.start > windowMs) hits.delete(k) } } if (entry.count > 3) { res.status(429).json({ message: 'Please wait a few minutes before trying again.' }) return } next() } function clean(value, max) { return typeof value === 'string' ? value.trim().replace(/\s+/g, ' ').slice(0, max) : '' } export function register(app) { app.post('/api/salvation-response', rateLimit, async (req, res) => { const { name, email, message, _honey } = req.body ?? {} if (_honey) { res.json({ ok: true }); return } const safeName = clean(name, 100) const safeEmail = clean(email, 200) const safeMessage = typeof message === 'string' ? message.trim().slice(0, 2000) : '' if (safeEmail && !/^[a-zA-Z0-9._%+\-]{1,64}@[a-zA-Z0-9.\-]{1,253}\.[a-zA-Z]{2,}$/.test(safeEmail)) { res.status(400).json({ message: 'That email address does not look right. You can also leave it blank.' }) return } if (!process.env.RESEND_API_KEY) { console.error('[salvation] RESEND_API_KEY env var not set') res.status(503).json({ message: 'We could not send this right now.' }) return } const when = new Date().toLocaleString('en-US', { dateStyle: 'medium', timeStyle: 'short' }) const nameLine = safeName || 'Name not given' const emailLine = safeEmail || 'Email not given' const text = [ 'Someone responded to the gospel on the /salvation page (the courtroom presentation) and says they pleaded guilty, accepted the pardon, and prayed to receive Jesus as Savior.', '', `Name: ${nameLine}`, `Email: ${emailLine}`, `When: ${when}`, '', safeMessage ? `Their message:\n${safeMessage}` : 'They did not leave a message.', '', safeEmail ? 'You can reply directly to this email to reach them.' : 'They did not leave an email address, so there is no way to reply.', ].join('\n') const html = `

Someone responded to the gospel on the /salvation page and says they prayed to receive Jesus as Savior.

Name: ${escapeHtml(nameLine)}
Email: ${escapeHtml(emailLine)}
When: ${escapeHtml(when)}

${safeMessage ? `

Their message:

${escapeHtml(safeMessage).replace(/\n/g, '
')}
` : '

They did not leave a message.

'}

${safeEmail ? 'You can reply directly to this email to reach them.' : 'They did not leave an email address, so there is no way to reply.'}

` try { const resend = new Resend(process.env.RESEND_API_KEY) await sendResendEmailWithRetry({ resend, context: 'salvation-response', payload: { from: getResendFromAddress(), to: [getResendInboxAddress()], ...(safeEmail ? { replyTo: safeEmail } : {}), subject: 'Someone prayed to receive Christ on your salvation page', tags: [{ name: 'flow', value: 'salvation-response' }], text, html, }, }) res.json({ ok: true }) } catch (err) { console.error('[salvation] email failed:', err?.message ?? err) res.status(502).json({ message: 'We could not send this right now.' }) } }) }