[object Object]

← back to Rentv

rentv: harden Desk backend proxies (contrarian fixes)

c674d281087b32ac813ee65ceab438e3eab11447 · 2026-07-29 09:52:50 -0700 · Steve Abrams

Cody the Contrarian (FIX FIRST) — 3 reproduced, all fixed:
- backendGet + usreProxy: Cache-Control public -> private (admin PII must not be
  storable by shared caches/CDN). backendGet uses private,no-store.
- Replace wildcard /api/homes/* and /api/cre/* with an explicit ALLOWLIST of only
  the 3 paths the Desk calls (homes/search, cre/brokers/all, cre/crcp/stats) —
  mirrors usreProxy; a new upstream endpoint is no longer auto-relayed.
Verified via loopback: allowed=200, off-allowlist=404, header=private,no-store.
(Deferred: lazy-load the 2.5k broker payload — noted as follow-up.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit c674d281087b32ac813ee65ceab438e3eab11447
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Jul 29 09:52:50 2026 -0700

    rentv: harden Desk backend proxies (contrarian fixes)
    
    Cody the Contrarian (FIX FIRST) — 3 reproduced, all fixed:
    - backendGet + usreProxy: Cache-Control public -> private (admin PII must not be
      storable by shared caches/CDN). backendGet uses private,no-store.
    - Replace wildcard /api/homes/* and /api/cre/* with an explicit ALLOWLIST of only
      the 3 paths the Desk calls (homes/search, cre/brokers/all, cre/crcp/stats) —
      mirrors usreProxy; a new upstream endpoint is no longer auto-relayed.
    Verified via loopback: allowed=200, off-allowlist=404, header=private,no-store.
    (Deferred: lazy-load the 2.5k broker payload — noted as follow-up.)
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 server.js | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/server.js b/server.js
index fdd14948..83ca24a6 100644
--- a/server.js
+++ b/server.js
@@ -338,7 +338,7 @@ async function usreProxy(upstream, req, res) {
     if (!qs.get('limit')) qs.set('limit', '500');
     const r = await fetch(`${USRE}${upstream}?${qs}`, { headers: { Authorization: USRE_AUTH }, signal: AbortSignal.timeout(12000) });
     if (!r.ok) return res.status(502).json({ rows: [], total: 0, error: 'upstream ' + r.status });
-    res.set('Cache-Control', 'public, max-age=300');
+    res.set('Cache-Control', 'private, max-age=60');
     res.json(await r.json());
   } catch (e) { res.status(502).json({ rows: [], total: 0, error: 'registry unavailable' }); }
 }
@@ -387,14 +387,15 @@ async function backendGet(base, auth, prefix, req, res) {
     const url = `${base}/api${sub}${qs ? '?' + qs : ''}`;
     const r = await fetch(url, { headers: auth ? { Authorization: auth } : {}, signal: AbortSignal.timeout(12000) });
     const body = await r.text();
-    res.status(r.status).set('Cache-Control', 'public, max-age=120')
+    res.status(r.status).set('Cache-Control', 'private, no-store')
        .type(r.headers.get('content-type') || 'application/json').send(body);
   } catch (e) { res.status(502).json({ error: 'backend unavailable' }); }
 }
-// rentv /api/homes/* → homesonspec :9975 /api/*   (e.g. /api/homes/search, /api/homes/facets)
-app.get('/api/homes/*', adminOnly, (req, res) => backendGet(HOS, null, '/api/homes', req, res));
-// rentv /api/cre/* → crcp :9911 /api/*   (prefix 'cre' avoids colliding with crcp's own /api/crcp/*)
-app.get('/api/cre/*', adminOnly, (req, res) => backendGet(CRCP, CRCP_AUTH, '/api/cre', req, res));
+// ALLOWLIST (not a wildcard): only the exact upstream paths the Desk calls are proxied,
+// mirroring usreProxy's hardcoded routes — a new upstream endpoint is NOT auto-exposed.
+app.get('/api/homes/search', adminOnly, (req, res) => backendGet(HOS, null, '/api/homes', req, res));
+app.get('/api/cre/brokers/all', adminOnly, (req, res) => backendGet(CRCP, CRCP_AUTH, '/api/cre', req, res));
+app.get('/api/cre/crcp/stats', adminOnly, (req, res) => backendGet(CRCP, CRCP_AUTH, '/api/cre', req, res));
 
 // ── AUDIENCE / CRM (/audience): unify the two real contact streams RENTV owns —
 //    newsletter subscribers (subscribers.jsonl) + sublease listing brokers

← a32a5225 rentv Desk: fuller default loads for New Homes + Commercial  ·  back to Rentv  ·  Add 6 RENTV News deal-wire videos (latest rentv.com stories, 5dd7950a →