Allow dev CORS from LAN IPs; add submission deletion

The dev-only CORS bypass in app.ts only ever matched
http://localhost:<port>, never the LAN IP a phone actually connects
through over WiFi - so testing the feedback form from a real device
against a local dev API had its submissions silently rejected by CORS.
Extended the bypass to also allow private LAN ranges (192.168.x.x,
10.x.x.x, 172.16-31.x.x), dev-only as before.

Also adds DELETE /feedback/admin/submissions/:submissionId (cascades
to the submission's answers, guest book entry, and newsletter signup
in explicit dependency order, single-path by submission_id) so an
admin can remove an individual abusive/inappropriate entry - decided
in IMPLEMENTATION_PLAN.md §7 item 8. getGuestBookEntries now also
returns submissionId so the admin UI can target the delete call.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Patrick Müller
2026-08-06 22:55:32 +02:00
parent 7488ac673f
commit 56074d4441
3 changed files with 95 additions and 5 deletions
+8 -3
View File
@@ -40,15 +40,20 @@ let allowedHosts = [
];
const isDev = process.env.NODE_ENV !== 'production';
const localhostRegex = /^http:\/\/localhost:\d+$/;
// Matches http://<private-LAN-IPv4>:<port> - needed so the feedback form can
// be reached from a real phone over WiFi during dev (the phone's Origin is
// the dev machine's LAN IP, never "localhost"). Dev-only, same as above.
const lanIpRegex = /^http:\/\/(192\.168\.\d{1,3}\.\d{1,3}|10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}):\d+$/;
app.use(cors({
allowedHeaders: ['Content-Type', 'X-Session-Id', 'X-Session-Key'],
origin: function (origin: any, callback: any) {
// Allow requests with no origin
if (!origin) return callback(null, true);
// Any localhost port is fine outside production - dev servers pick
// whatever port is free (Next.js falls back from 3000 if it's taken).
if (isDev && localhostRegex.test(origin)) {
// Any localhost port, or a private-LAN IP, is fine outside production -
// dev servers pick whatever port is free (Next.js falls back from 3000
// if it's taken), and real-device testing hits the dev machine by IP.
if (isDev && (localhostRegex.test(origin) || lanIpRegex.test(origin))) {
return callback(null, true);
}