diff --git a/src/viewer.js b/src/viewer.js index 2c18ef7..54c431c 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -549,9 +549,17 @@ let _myActionsDiag = ""; // diagnostic du dernier fetch (affiché dans l'onglet) let _impersonate = null; // Vrai uniquement si l'utilisateur connecté EST FroSteel (garde-fou // pour n'afficher l'onglet Test qu'à lui). -function _isQuentin() { +// Empreintes FNV-1a (32 bits) du nom et du prenom de l'auteur : jamais en clair dans le code. +const _EMPREINTES_AUTEUR = [0x716d54e7, 0xa6e31b47]; +function _empreinteMot(mot) { + let h = 0x811c9dc5; + for (const c of mot) { h ^= c.codePointAt(0); h = Math.imul(h, 0x01000193) >>> 0; } + return h; +} +function _estAuteur() { const n = (state && state.currentUser && state.currentUser.name) || ""; - return /exemple/i.test(n) && /FroSteel/i.test(n); + const mots = new Set(n.toLowerCase().split(/[^a-zà-ÿ]+/).filter(Boolean).map(_empreinteMot)); + return _EMPREINTES_AUTEUR.every((e) => mots.has(e)); } // Identité effective utilisée pour retrouver "l'action liée à la personne" // (Partie A « Mes actions »). Si impersonation active ET FRS → identité simulée, @@ -563,7 +571,7 @@ function _effectiveIdentity() { memberId: (state && state.currentUser && state.currentUser.memberId) || "", impersonated: false }; - if (_isQuentin() && _impersonate && _impersonate.enabled && + if (_estAuteur() && _impersonate && _impersonate.enabled && (_impersonate.name || _impersonate.initials || _impersonate.memberId)) { return { name: _impersonate.name || "", @@ -3113,7 +3121,7 @@ async function showAdminPanel(initialSection) { // v2026.5.46 — onglet "Test (FRS)" RÉSERVÉ à FroSteel : permet de // se faire passer pour une autre personne (coordinateur) pour tester « Mes // actions » sans être réellement coordinateur. Caché pour tout autre utilisateur. - if (_isQuentin()) { + if (_estAuteur()) { sections.push({ id: "qrotest", label: "🧪 Test (FRS)", render: renderAdminSectionImpersonate }); }