← back to Dw Domain Fleet
scrubVendor: optional inter-token separator ([^a-z0-9]*) catches no-separator handle spellings (wolfgordon, gpjbaker) + add 'g p j baker' per-initial variant + collapse mid-handle residue. Closes the 936 wolfgordon URL-slug leaks (#3 morning digest). Export scrubVendor for tests
1bdbba0a8cfbedd6d03020ca579c420dd71cd832 · 2026-05-30 08:27:08 -0700 · Steve
Files touched
Diff
commit 1bdbba0a8cfbedd6d03020ca579c420dd71cd832
Author: Steve <steve@designerwallcoverings.com>
Date: Sat May 30 08:27:08 2026 -0700
scrubVendor: optional inter-token separator ([^a-z0-9]*) catches no-separator handle spellings (wolfgordon, gpjbaker) + add 'g p j baker' per-initial variant + collapse mid-handle residue. Closes the 936 wolfgordon URL-slug leaks (#3 morning digest). Export scrubVendor for tests
---
shared/render.js | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/shared/render.js b/shared/render.js
index e222209..d8d02c1 100644
--- a/shared/render.js
+++ b/shared/render.js
@@ -90,21 +90,26 @@ function scrubTags(tags) {
* cleaning the slug never breaks a product link. (2026-05-29 fleet vendor-leak
* audit: slug/handle + visible card-title vector.) */
const _VENDOR_SCRUB = VENDORS_DENYLIST
- .concat(['brunschwig fils', 'lee jofa modern', 'gp j baker',
+ .concat(['brunschwig fils', 'lee jofa modern', 'gp j baker', 'g p j baker',
'cole and son', 'cole son', 'clarke and clarke', 'clarke clarke',
'morris and co', 'morris co', 'caroline cecil textiles', 'caroline cecil'])
.slice().sort((a, b) => b.length - a.length)
- // Split on ANY non-alphanumeric run and drop empties, so each vendor's word
- // tokens join with a flexible separator — matches "Brunschwig & Fils" (title)
- // AND "brunschwig-fils" (slug). (The old \s+ split left an empty token for the
- // "&" → a double-separator regex that failed on single-hyphen handles.)
- .map(v => new RegExp('\\b' + v.split(/[^a-z0-9]+/i).filter(Boolean).join('[^a-z0-9]+') + '\\b', 'ig'));
+ // Split on non-alphanumeric runs, drop empties, join with an OPTIONAL separator
+ // ([^a-z0-9]* — zero-or-more) so each vendor matches BOTH the separated form
+ // ("Brunschwig & Fils", "wolf-gordon") AND the concatenated/no-separator
+ // handle spelling ("wolfgordon", "gpjbaker") — the 936 wolfgordon URL-slug
+ // leaks the 2026-05-30 reaudit found. \b boundaries keep it from over-matching
+ // inside unrelated words. Tokens <2 chars are kept literal-only (no optional
+ // sep on a single letter would over-match), so multi-initial vendors use the
+ // explicit "g p j baker" variant above.
+ .map(v => new RegExp('\\b' + v.split(/[^a-z0-9]+/i).filter(Boolean).join('[^a-z0-9]*') + '\\b', 'ig'));
function scrubVendor(s) {
if (s == null) return s;
let o = String(s);
for (let i = 0; i < _VENDOR_SCRUB.length; i++) o = o.replace(_VENDOR_SCRUB[i], ' ');
return o
.replace(/\s{2,}/g, ' ')
+ .replace(/(\s*-\s*)+/g, '-') // collapse mid-string residue like "x- -1" → "x-1"
.replace(/-{2,}/g, '-')
.replace(/^[\s\-–—|·,&]+|[\s\-–—|·,&]+$/g, '')
.replace(/\s{2,}/g, ' ')
@@ -748,4 +753,4 @@ ${script(cfg)}
</body></html>`;
}
-module.exports = { homePage, catalogPage, aboutPage, infoPage, productPage, clean, esc, productSlug };
+module.exports = { homePage, catalogPage, aboutPage, infoPage, productPage, clean, esc, productSlug, scrubVendor };
← 0ac4d91 render.js productSlug: guard both slug returns with hasVendo
·
back to Dw Domain Fleet
·
Add 2026-05-31 read-only vendor-leak re-verify: slug/chip sc 55a7f0b →