[object Object]

← back to Dw Photo Capture

Add bounded public /marketing/ static route (images only, traversal-safe) + color-coordinate demo GIF for email hosting

ba0e274160d6095578e16e3783388ecfe3a2e7d2 · 2026-07-29 07:37:50 -0700 · Steve Abrams

Files touched

Diff

commit ba0e274160d6095578e16e3783388ecfe3a2e7d2
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Jul 29 07:37:50 2026 -0700

    Add bounded public /marketing/ static route (images only, traversal-safe) + color-coordinate demo GIF for email hosting
---
 public-marketing/color-coordinate-wm.gif | Bin 0 -> 1197618 bytes
 server.js                                |  30 +++++++++++++++++++++++++++++-
 2 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/public-marketing/color-coordinate-wm.gif b/public-marketing/color-coordinate-wm.gif
new file mode 100644
index 0000000..0a5a24c
Binary files /dev/null and b/public-marketing/color-coordinate-wm.gif differ
diff --git a/server.js b/server.js
index 06839cd..4c68f5e 100644
--- a/server.js
+++ b/server.js
@@ -918,7 +918,7 @@ const appHandler = (req, res) => {
   // public (no-auth) paths: health + the home-screen-install assets iOS fetches without creds
   const PUBLIC = ['/healthz', '/icon-180.png', '/icon-512.png', '/apple-touch-icon.png', '/manifest.webmanifest', '/apps/similar', '/apps/color-index', '/apps/color-widen', '/apps/color-dots'];
   const _p = req.url.split('?')[0];
-  if (!PUBLIC.includes(_p) && !checkAuth(req)) {
+  if (!PUBLIC.includes(_p) && !_p.startsWith('/marketing/') && !checkAuth(req)) {
     res.writeHead(401, { 'WWW-Authenticate': 'Basic realm="DW Photo Capture"' });
     return res.end('Auth required');
   }
@@ -926,6 +926,34 @@ const appHandler = (req, res) => {
 
   if (u.pathname === '/healthz') return send(res, 200, { ok: true });
 
+  // ── Public marketing assets (email images) — TIGHTLY bounded static serve ──
+  // No auth (allowed in the PUBLIC gate above). NOT a generic file server:
+  //  · Fixed dir public-marketing/ — never user-controlled.
+  //  · Basename-only + strict regex allowlist (images only); rejects any '..' / slash.
+  //  · Resolved path must stay inside the dir (path-traversal guard).
+  if (_p.startsWith('/marketing/')) {
+    const name = _p.slice('/marketing/'.length);
+    if (name.includes('/') || name.includes('..') ||
+        !/^[A-Za-z0-9._-]+\.(gif|png|jpe?g|webp)$/.test(name)) {
+      return send(res, 404, { err: 'not found' });
+    }
+    const MDIR = path.join(ROOT, 'public-marketing');
+    const fp = path.join(MDIR, name);
+    if (!fp.startsWith(MDIR + path.sep)) return send(res, 404, { err: 'not found' });
+    return fs.readFile(fp, (e, buf) => {
+      if (e) return send(res, 404, { err: 'not found' });
+      const ext = name.split('.').pop().toLowerCase();
+      const ct = { gif: 'image/gif', png: 'image/png', jpg: 'image/jpeg',
+                   jpeg: 'image/jpeg', webp: 'image/webp' }[ext] || 'application/octet-stream';
+      res.writeHead(200, {
+        'Content-Type': ct,
+        'Cache-Control': 'public, max-age=604800',
+        'Access-Control-Allow-Origin': '*'
+      });
+      res.end(buf);
+    });
+  }
+
   // ── PDP CLIP "More like this" proxy (GATED-STEP-1, shipped) ─────────────────
   // Public (no basic-auth) but TIGHTLY bounded: NOT a generic proxy.
   //  · SSRF guard: fixed upstream host+path 127.0.0.1:9914/similar — never user-controlled.

← d204283 auto-save: 2026-07-29T04:35:46 (1 files) — data/color-dots.j  ·  back to Dw Photo Capture  ·  chore: v1.6.0 — public /marketing static route for email ass 3116235 →