From c80b2a543a6463468e6872f87bcea78773dba3fa Mon Sep 17 00:00:00 2001 From: defiQUG Date: Mon, 13 Apr 2026 21:35:02 -0700 Subject: [PATCH] Support configurable trust proxy hop count --- .env.example | 4 ++++ src/integration/api-gateway/app.ts | 13 +++++++++++-- src/shared/config/env-validator.ts | 11 +++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 6393ed8..2ffc118 100644 --- a/.env.example +++ b/.env.example @@ -25,6 +25,10 @@ CRYPTO_COM_API_SECRET= # ---------------------------------------------------------------------------- # API behind reverse proxy (rate limits, logging) # TRUST_PROXY=1 +# TRUST_PROXY_HOPS=1 +# When TRUST_PROXY=1, Express uses this hop count (default 1, max 10). Usually **1**: Node sees +# one reverse proxy peer (NPM or the Phoenix API hub). Raise only if another proxy terminates +# TCP in series before dbis_core (rare); validate client IP / rate limits after changing. # ---------------------------------------------------------------------------- # IRU marketplace — rate limits (optional; sensible defaults in code) diff --git a/src/integration/api-gateway/app.ts b/src/integration/api-gateway/app.ts index 1bc015f..76282a2 100644 --- a/src/integration/api-gateway/app.ts +++ b/src/integration/api-gateway/app.ts @@ -147,9 +147,18 @@ import ilcRoutes from '@/core/ledger/ilc/ilc.routes'; const app: Express = express(); -// Behind NPM / load balancer: set TRUST_PROXY=1 so rate limits and req.ip use the client address +// Behind NPM / API hub: set TRUST_PROXY=1 so rate limits and req.ip use the client address. +// TRUST_PROXY_HOPS = Express "trust proxy" hop count (default 1). Typically 1: Node's TCP peer +// is one reverse proxy (NPM or hub), even if X-Forwarded-For lists a longer browser→edge chain. if (process.env.TRUST_PROXY === '1' || process.env.TRUST_PROXY === 'true') { - app.set('trust proxy', 1); + const hopsRaw = process.env.TRUST_PROXY_HOPS; + const hopsParsed = hopsRaw !== undefined && hopsRaw !== '' ? parseInt(hopsRaw, 10) : 1; + const hops = + Number.isFinite(hopsParsed) && hopsParsed >= 1 && hopsParsed <= 10 ? hopsParsed : 1; + if (hopsRaw !== undefined && hopsRaw !== '' && hops !== hopsParsed) { + logger.warn('TRUST_PROXY_HOPS invalid; using 1', { TRUST_PROXY_HOPS: hopsRaw }); + } + app.set('trust proxy', hops); } // Security middleware diff --git a/src/shared/config/env-validator.ts b/src/shared/config/env-validator.ts index 8ad8d67..176ed1e 100644 --- a/src/shared/config/env-validator.ts +++ b/src/shared/config/env-validator.ts @@ -43,6 +43,17 @@ const envConfig: EnvConfig = { errorMessage: 'PORT must be a valid port number (1-65535)', }, + TRUST_PROXY_HOPS: { + required: false, + description: + 'When TRUST_PROXY=1, Express trust proxy hop count (1-10). Default 1: one reverse proxy terminates TCP to Node.', + validator: (value) => { + const n = parseInt(value, 10); + return !isNaN(n) && n >= 1 && n <= 10; + }, + errorMessage: 'TRUST_PROXY_HOPS must be an integer from 1 to 10', + }, + ALLOWED_ORIGINS: { required: process.env.NODE_ENV === 'production', description: 'Comma-separated list of allowed CORS origins',