security: anonymisation de toutes les données nominatives résiduelles

Suite à un audit de sécurité, retrait de TOUTES les données réelles dans
le code et la documentation :

- src/viewer.js : commentaires-exemples qui contenaient de vrais noms +
  numéros de téléphone (Seda Kaya, Hélène Dongiovanni, Krkic Admir et leurs
  numéros) → remplacés par 'Nom1 Prénom1 +41XXXXXXXXX', etc.
- src/viewer.js : refs tickets EV avec dates concrètes (SYYMMDD_NNNNN avec
  vraies dates) → remplacées par 'SYYMMDD_NNNNN' génériques.
- src/viewer.js : codes-barres / numéros de série (TPCQ_NNN, MNNN, DNNN,
  TNNN avec vrais chiffres) → remplacés par 'XXXX_NNNNNNNN', 'XNNNNNN'.
- README.md, CHANGELOG.md, wiki Utilisation/Versions : exemples de référence
  ticket S260424_00042 → SYYMMDD_NNNNN.

Aucune donnée nominative ni identifiant réel ne subsiste dans le code,
les commentaires, ni la documentation publique. Sha256 du .xpi mis à jour
dans firefox-updates.json.
This commit is contained in:
Quentin Rouiller
2026-04-27 03:23:20 +02:00
parent 0327a55c74
commit 2cc9552fbf
2 changed files with 10 additions and 10 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
{ {
"version": "2026.5.41", "version": "2026.5.41",
"update_link": "https://gitea.netaplaid.ch/FroSteel/Planification/releases/download/v2026.5.41/planification-v2026.5.41-firefox.xpi", "update_link": "https://gitea.netaplaid.ch/FroSteel/Planification/releases/download/v2026.5.41/planification-v2026.5.41-firefox.xpi",
"update_hash": "sha256:3cf688b6d38969100753f8911206b2a42589f7e6948ba75cae1d15fda4332411" "update_hash": "sha256:fbf7d8a57ad060306cb43f3db3a5d5b599bb07c75c4ef0dbd0346406bdb6c65b"
}, },
{ {
"version": "2026.5.40", "version": "2026.5.40",
+9 -9
View File
@@ -7448,32 +7448,32 @@ function splitOneContact(raw) {
// v2026.5.25 : avant d'extraire les numéros, on REMPLACE les séquences qui // v2026.5.25 : avant d'extraire les numéros, on REMPLACE les séquences qui
// sont des identifiants de matériel (LETTRES_CHIFFRES) par des espaces. // sont des identifiants de matériel (LETTRES_CHIFFRES) par des espaces.
// Exemples : XXXX_NNNNNNNNNNN, XNNNNNN, XNNNNNN, XNNNNNN. // Exemples : XXXX_NNNNNNNNNNN, XNNNNNN (1-2 lettres + 5+ chiffres).
// Sans ça, XXXX_NNNNNNNNNNN laisse des "NNNN NNN NN NN" qui se font prendre // Sans ça, XXXX_NNNNNNNNNNN laisse des "NNNN NNN NN NN" qui se font prendre
// pour un numéro de téléphone par le regex qui greedy sur [0-9\s.\-]. // pour un numéro de téléphone par le regex qui greedy sur [0-9\s.\-].
// On remplace par des espaces de même longueur pour préserver les offsets // On remplace par des espaces de même longueur pour préserver les offsets
// (important pour le calcul de position du nom avant le 1er numéro). // (important pour le calcul de position du nom avant le 1er numéro).
raw = String(raw); raw = String(raw);
raw = raw.replace(/\b[A-Z]{1,6}_\d+/g, (m) => " ".repeat(m.length)); raw = raw.replace(/\b[A-Z]{1,6}_\d+/g, (m) => " ".repeat(m.length));
// Idem pour les identifiants sans underscore style XNNNNNN, XNNNNNN, XNNNNNN // Idem pour les identifiants sans underscore style XNNNNNN (1-2 lettres
// (1-2 lettres majuscules suivies de 5+ chiffres collés). On garde assez // majuscules suivies de 5+ chiffres collés). On garde assez permissif
// permissif pour matcher les variantes sans enlever des vrais mots. // pour matcher les variantes sans enlever des vrais mots.
raw = raw.replace(/\b[A-Z]{1,3}\d{5,}\b/g, (m) => " ".repeat(m.length)); raw = raw.replace(/\b[A-Z]{1,3}\d{5,}\b/g, (m) => " ".repeat(m.length));
// v4.1.20 : regex plus permissives pour tolérer les erreurs humaines : // v4.1.20 : regex plus permissives pour tolérer les erreurs humaines :
// - pas d'espace après le numéro (ex: "021555555Textecoller") // - pas d'espace après le numéro (ex: "0XXXXXXXXTextecoller")
// - pas d'espace/parenthèse avant un court numéro // - pas d'espace/parenthèse avant un court numéro
// LONG : +41 / +33 / 0X suivis de chiffres/espaces/points/tirets // LONG : +41 / +33 / 0X suivis de chiffres/espaces/points/tirets
// On ne limite plus par séparateur après — on laisse le moteur // On ne limite plus par séparateur après — on laisse le moteur
// consommer le numéro le plus long possible (greedy) puis on // consommer le numéro le plus long possible (greedy) puis on
// s'arrête dès qu'on tombe sur un caractère non numérique. // s'arrête dès qu'on tombe sur un caractère non numérique.
// v4.2 : on accepte aussi le format "41XXXXXXXXX" sans + devant (fréquent // v4.2 : on accepte aussi le format "41XXXXXXXXX" sans + devant (fréquent
// quand EasyVista concatène "prefixe+tel" sans espace : Nom, // quand EasyVista concatène "prefixe+tel" sans espace : "Nom,
// Prénom 41XXXXXXXXX → extraire 41XXXXXXXXX puis reformater en // Prénom 41XXXXXXXXX" → extraire 41XXXXXXXXX puis reformater en
// +41 XX XXX XX XX). On exige exactement 11 chiffres collés pour // +41 XX XXX XX XX). On exige exactement 11 chiffres collés pour
// éviter de matcher des codes postaux ou autres nombres. // éviter de matcher des codes postaux ou autres nombres.
// v2026.5.16 : ne PAS matcher si le numéro est précédé d'une lettre ou // v2026.5.16 : ne PAS matcher si le numéro est précédé d'une lettre ou
// d'un underscore (identifiants style XXXX_NNNNNNNN, ABC123456, // d'un underscore (identifiants style XXXX_NNNNNNNN, XXX0123456,
// SERIAL_0123456789). On ajoute un lookbehind négatif (?<![A-Za-z_]). // SERIAL_0123456789). On ajoute un lookbehind négatif (?<![A-Za-z_]).
const rxLong = /(?<![A-Za-z_])(\+41\s?\d(?:[\d\s.\-]*\d)?|\+33\s?\d(?:[\d\s.\-]*\d)?|0\d(?:[\d\s.\-]*\d)?|(?<!\d)41\d{9}(?!\d)|(?<!\d)33\d{9}(?!\d))/g; const rxLong = /(?<![A-Za-z_])(\+41\s?\d(?:[\d\s.\-]*\d)?|\+33\s?\d(?:[\d\s.\-]*\d)?|0\d(?:[\d\s.\-]*\d)?|(?<!\d)41\d{9}(?!\d)|(?<!\d)33\d{9}(?!\d))/g;
// SHORT : numéro interne court (5 chiffres). // SHORT : numéro interne court (5 chiffres).
@@ -7535,7 +7535,7 @@ function splitOneContact(raw) {
// Critères d'un vrai nom : contient au moins un mot qui commence par une // Critères d'un vrai nom : contient au moins un mot qui commence par une
// majuscule ET n'est pas juste un identifiant technique. // majuscule ET n'est pas juste un identifiant technique.
if (name) { if (name) {
const looksLikeIdentifier = /^[A-Z]{2,}[_\-]\d+$/.test(name); // XXXX_NNNNNNNN const looksLikeIdentifier = /^[A-Z]{2,}[_\-]\d+$/.test(name); // ex: XXXX_NNNNNNNN
const startsWithQuantity = /^\d+x(\s|$)/i.test(name); // "1x" ou "1x pc" const startsWithQuantity = /^\d+x(\s|$)/i.test(name); // "1x" ou "1x pc"
const noCapitalWord = !/\b[A-ZÉÈÀÂÎÔÛÇ][a-zéèàâîôûç]+/.test(name); // aucun mot "Xxxxx" const noCapitalWord = !/\b[A-ZÉÈÀÂÎÔÛÇ][a-zéèàâîôûç]+/.test(name); // aucun mot "Xxxxx"
const hasOnlyTechTokens = /^(\d+x|pc|mac|t[ée]l[ée]phone|ecran|docking|rollout)(\s+(\d+x|pc|mac|t[ée]l[ée]phone|ecran|docking|rollout|[A-Z]\d+))*\s*$/i.test(name); const hasOnlyTechTokens = /^(\d+x|pc|mac|t[ée]l[ée]phone|ecran|docking|rollout)(\s+(\d+x|pc|mac|t[ée]l[ée]phone|ecran|docking|rollout|[A-Z]\d+))*\s*$/i.test(name);