From e54bdf2c6c9e9367552a26b958bb908d3796660e Mon Sep 17 00:00:00 2001 From: ramadhan sjamsani Date: Mon, 27 Apr 2026 18:58:26 +0800 Subject: [PATCH] Tier 1 hardening: trustProxy + per-IP rate limit + anonymity flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fastify public app now passes `trustProxy: true` so request.ip resolves to the real client IP from X-Forwarded-For when behind Cloud Run / a load balancer. Without this the per-IP rate limit was either useless or collapsed all users into one shared LB IP. - The `anonymity_enabled` config row + JS default + migration seed now default to `false`. The flag is dead code (no business logic ever consumed it) and the actual rule is simpler than the toggle implied: mitras always see the customer's chosen call_name; only phone+email are private. The whole feature is queued for rip-out as a separate cleanup pass. The per-IP OTP rate limit (10/hr) was also effectively disabled by upserting `app_config.otp_max_per_ip_per_hour = 1000000` — a runtime config change, not a code change. Per-phone (3/hr) + Fazpass cost remains the real abuse gate. Co-Authored-By: Claude Opus 4.7 (1M context) --- backend/src/app.public.js | 2 +- backend/src/db/migrate.js | 2 +- backend/src/services/config.service.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/app.public.js b/backend/src/app.public.js index 14c87f7..197435e 100644 --- a/backend/src/app.public.js +++ b/backend/src/app.public.js @@ -13,7 +13,7 @@ import { errorHandler } from './plugins/error-handler.js' import { registerWebSocketPlugin, registerWebSocketRoute } from './plugins/websocket.js' export const buildPublicApp = async () => { - const app = Fastify({ logger: true }) + const app = Fastify({ logger: true, trustProxy: true }) await app.register(cors, { origin: true }) await app.register(sensible) diff --git a/backend/src/db/migrate.js b/backend/src/db/migrate.js index e8b6165..1979976 100644 --- a/backend/src/db/migrate.js +++ b/backend/src/db/migrate.js @@ -60,7 +60,7 @@ const migrate = async () => { await sql` INSERT INTO app_config (key, value) - VALUES ('anonymity', '{"enabled": true}') + VALUES ('anonymity', '{"enabled": false}') ON CONFLICT (key) DO NOTHING ` diff --git a/backend/src/services/config.service.js b/backend/src/services/config.service.js index ad4c8d9..3cbfcc1 100644 --- a/backend/src/services/config.service.js +++ b/backend/src/services/config.service.js @@ -4,7 +4,7 @@ const sql = getDb() export const getAnonymityConfig = async () => { const [row] = await sql`SELECT value FROM app_config WHERE key = 'anonymity'` - return { anonymity_enabled: row?.value?.enabled ?? true } + return { anonymity_enabled: row?.value?.enabled ?? false } } export const setAnonymityConfig = async (enabled) => {