[object Object]

← back to Apartmentwallpaper

Ideas rail: route through safeImg()+escAttr() (XSS hygiene parity with grid); clarify safeImg comment (redact middleware rewrites images in all modes, not just PG-admin)

9c0a8ae5cadf66d6ecbfea91dbb988c67069bc74 · 2026-06-16 18:22:06 -0700 · Steve Abrams

Files touched

Diff

commit 9c0a8ae5cadf66d6ecbfea91dbb988c67069bc74
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Jun 16 18:22:06 2026 -0700

    Ideas rail: route through safeImg()+escAttr() (XSS hygiene parity with grid); clarify safeImg comment (redact middleware rewrites images in all modes, not just PG-admin)
---
 public/index.html | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/public/index.html b/public/index.html
index 2079fd3..99a6528 100644
--- a/public/index.html
+++ b/public/index.html
@@ -537,7 +537,8 @@ const LABELS = {"self-adhesive":"Self adhesive"};
 function escAttr(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, c => ({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;' }[c])); }
 // Image-URL allowlist (defends against XSS via crafted products.json):
 //  • DW Shopify CDN + designerwallcoverings.com (static-mode absolute URLs)
-//  • same-origin /img/<hash> proxy paths (PG-admin mode rewrites images to these)
+//  • same-origin /img/<hash> proxy paths (the api-vendor-redact middleware rewrites
+//    all product images to these in every mode — static AND PG-admin)
 function safeImg(u) { return /^https:\/\/(?:cdn\.shopify\.com|designerwallcoverings\.com)\//.test(u || '') || /^\/img\/[A-Za-z0-9._-]+$/.test(u || '') ? u : '/hero-bg.jpg'; }
 function cardHTML(p) {
   const eager = state.page === 1;
@@ -1116,11 +1117,11 @@ loadGridPage();
     // Curated = deterministic offset slice (every 5th item starting at idx 3) for variety
     const curated = items.filter((_, i) => i % 5 === 3).slice(0, 12);
     function card(p) {
-      const url = (p.image_url || '').replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4');
+      const url = safeImg((p.image_url || '').replace(/(_\d+x\d*)(\.(jpg|jpeg|png|webp|gif))(\?|$)/i, '$2$4'));
       return '<a class="rail-card" href="/sample/' + encodeURIComponent(p.handle_display || p.handle || p.sku) + '">' +
-        '<img src="' + url + '" alt="' + (p.title || '').replace(/"/g, '&quot;') + '" loading="lazy">' +
-        '<div class="rc-title">' + ((p.title || '').split('|')[0] || '').trim() + '</div>' +
-        '<div class="rc-meta">' + (p.vendor || '') + '</div>' +
+        '<img src="' + escAttr(url) + '" alt="' + escAttr(p.title) + '" loading="lazy">' +
+        '<div class="rc-title">' + escAttr(((p.title || '').split('|')[0] || '').trim()) + '</div>' +
+        '<div class="rc-meta">' + escAttr(p.vendor) + '</div>' +
       '</a>';
     }
     const r1 = document.getElementById('railNewest');

← 395eb10 Fix repeated hero image: allow same-origin /img/<hash> proxy  ·  back to Apartmentwallpaper  ·  Pre-warm /img token map at boot (close cold-start 404 window f2ab8c8 →