From da2a5c42e7389cc3351940a673e402fdcacc0645 Mon Sep 17 00:00:00 2001 From: mandalore Date: Tue, 22 Sep 2026 19:14:12 -0500 Subject: [PATCH] Hash the 40k hidden-players list and drop the old PayPal block Hidden players are now matched by a hash of their full name or nickname (src/hide.js) so the names aren't readable in the source or bundle. Also removes the commented-out PayPal section from the Kingmaker sign-up page. Co-Authored-By: Claude Opus 5.5 --- sites/40k-rankings/README.md | 8 ++++++-- sites/40k-rankings/src/hide.js | 27 +++++++++++++++++++++++++++ sites/40k-rankings/src/main.js | 21 ++++++++++++--------- sites/kingmaker/README.md | 3 +-- sites/kingmaker/signups.html | 13 ------------- 5 files changed, 46 insertions(+), 26 deletions(-) create mode 100644 sites/40k-rankings/src/hide.js diff --git a/sites/40k-rankings/README.md b/sites/40k-rankings/README.md index 1c588c2..931e4e3 100644 --- a/sites/40k-rankings/README.md +++ b/sites/40k-rankings/README.md @@ -53,8 +53,11 @@ Everything you'd normally change is in the `CONFIG` block at the top of - `teamId`: the BCP team whose members are shown - `leagueId` / `regionId`: which ITC league and region to rank against - `lmcLeagueId`: the Lord Marshal Conference league used for the LMC columns -- `blacklistNames`: players to hide from the board (full name or nickname, - case-insensitive) +- `hiddenNameHashes`: players to hide from the board, stored as hashes of + their full name or nickname so the names aren't readable in the source. The + comment at the top of `src/hide.js` has a one-line command to hash a name. + This only obfuscates: the roster is public, so anyone could hash every + member's name to find who's hidden. - `memberIds`: fallback roster, used if the team endpoint ever stops returning members without auth - `useSample`: set to `true` to render placeholder rows with no network calls @@ -62,6 +65,7 @@ Everything you'd normally change is in the `CONFIG` block at the top of ## Files - `index.html`, `src/main.js`, `src/style.css`: the page +- `src/hide.js`: name hashing for `hiddenNameHashes` - `nav.html`: this site's header nav entries (see the root README) - `public/elo-data.json`: generated ELO data. Don't edit it by hand; the weekly sync overwrites it. diff --git a/sites/40k-rankings/src/hide.js b/sites/40k-rankings/src/hide.js new file mode 100644 index 0000000..80cadb1 --- /dev/null +++ b/sites/40k-rankings/src/hide.js @@ -0,0 +1,27 @@ +/* Hashing for CONFIG.hiddenNameHashes, so hidden players' names aren't + readable in the source or the deployed bundle. This is obfuscation, not + secrecy: the team roster is public, so anyone could hash every member's + name and find a match. + + Get the hash for a name (full name or nickname) from sites/40k-rankings: + node --input-type=module -e "import { nameHash } from './src/hide.js'; console.log(nameHash('First Last'))" +*/ + +// cyrb53: small, fast, synchronous 53-bit string hash. +function cyrb53(str, seed = 0) { + let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed; + for (let i = 0; i < str.length; i++) { + const ch = str.charCodeAt(i); + h1 = Math.imul(h1 ^ ch, 2654435761); + h2 = Math.imul(h2 ^ ch, 1597334677); + } + h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909); + h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909); + return 4294967296 * (2097151 & h2) + (h1 >>> 0); +} + +// Case- and whitespace-insensitive, so "jane DOE " matches "Jane Doe". +export function nameHash(name) { + const norm = String(name || "").trim().replace(/\s+/g, " ").toLowerCase(); + return norm ? cyrb53(norm).toString(16) : ""; +} diff --git a/sites/40k-rankings/src/main.js b/sites/40k-rankings/src/main.js index 9d64135..7123177 100644 --- a/sites/40k-rankings/src/main.js +++ b/sites/40k-rankings/src/main.js @@ -1,3 +1,5 @@ +import { nameHash } from './hide.js'; + /* ---- Shared: header / footer ---- */ function loadHTML(file, elementId, callback) { fetch(file) @@ -48,19 +50,20 @@ const CONFIG = { // Fallback roster if the team endpoint requires auth. memberIds: [], - // Names to hide from the leaderboard entirely (case-insensitive). - // Match on full name ("First Last") or nickname, whichever the player goes by. - blacklistNames: ["Hidden Player"], + // Players to hide from the leaderboard entirely, as nameHash() values of + // their full name ("First Last") or nickname — see src/hide.js for how to + // generate one. Hashed so the names aren't readable in the source. + hiddenNameHashes: ["5b64057a31512"], // Flip to true to preview the layout with placeholder rows (no network). useSample: false, }; -const BLACKLIST = new Set(CONFIG.blacklistNames.map(n => n.trim().toLowerCase())); -function isBlacklisted(u = {}) { - const full = fullName(u).toLowerCase(); - const nick = String(u.nickname || "").trim().toLowerCase(); - return (full && BLACKLIST.has(full)) || (nick && BLACKLIST.has(nick)); +const HIDDEN = new Set(CONFIG.hiddenNameHashes); +function isHidden(u = {}) { + const full = nameHash(fullName(u)); + const nick = nameHash(u.nickname); + return (full && HIDDEN.has(full)) || (nick && HIDDEN.has(nick)); } const API = "https://newprod-api.bestcoastpairings.com/v1"; @@ -290,7 +293,7 @@ function build(rows, ids) { const kept = []; for (const rec of rows) { const uid = rec.userId || (rec.user && rec.user.id); - if (uid && ids.has(uid) && !isBlacklisted(rec.user || {})) kept.push(rec); + if (uid && ids.has(uid) && !isHidden(rec.user || {})) kept.push(rec); } kept.sort((a, b) => Number(b.ITCPoints || 0) - Number(a.ITCPoints || 0)); return kept; diff --git a/sites/kingmaker/README.md b/sites/kingmaker/README.md index ec03f27..e7f4a1d 100644 --- a/sites/kingmaker/README.md +++ b/sites/kingmaker/README.md @@ -29,8 +29,7 @@ different form or sheet, replace the iframe `src` in the relevant HTML file. ## Updating each season Season name, dates and sign-up status are hardcoded in `index.html`. The entry -fee note is in `signups.html`. There's also a commented-out PayPal block there -that can be re-enabled if fees move back to PayPal. +fee note is in `signups.html`. ## Files diff --git a/sites/kingmaker/signups.html b/sites/kingmaker/signups.html index 313050b..2da2098 100644 --- a/sites/kingmaker/signups.html +++ b/sites/kingmaker/signups.html @@ -18,19 +18,6 @@
- - -