Skip to content

fix(detector): T-221/T-223 M7 Google challenge-pwd + LinkedIn AJAX#187

Merged
antonyblain merged 1 commit intodevelopfrom
feature/p5-tache-221-223-m7-google-linkedin
Apr 28, 2026
Merged

fix(detector): T-221/T-223 M7 Google challenge-pwd + LinkedIn AJAX#187
antonyblain merged 1 commit intodevelopfrom
feature/p5-tache-221-223-m7-google-linkedin

Conversation

@antonyblain
Copy link
Copy Markdown
Owner

Contexte

Sprint correctif P0 post-recette manuelle MEP v1 (verdict BLOQUÉE, 2026-04-24).
Deux bugs P0 reproduits bloquaient la mise en production :

  • INC-001 / TACHE-221 : Google /challenge/pwd — M7 ne capte pas la soumission password
  • INC-006 / TACHE-223 : LinkedIn /login — M7 ne capte pas le submit AJAX

Hypothèses validées / réfutées

TACHE-221 — Google /challenge/pwd

Hypothèse Verdict Explication
(a) autocomplete="new-password" sur le champ Google déclenche isNewPasswordField() → M7 filtré (faux-positif connexion) CONFIRMÉE isNewPasswordField() retournait true sur le champ Google qui utilise autocomplete="new-password" à tort sur son écran de connexion. Le filtre M7 sautait la capture.
(b) Bouton "Suivant" (type="button", texte FR) ignoré par la regex looksLikeSubmit CONFIRMÉE La regex ne contenait que des termes EN — "suivant", "next", "weiter", etc. absents → Strategy S1/S2 ignoraient le bouton.

TACHE-223 — LinkedIn /login

Hypothèse Verdict Explication
LinkedIn utilise AJAX fetch() + event.preventDefault() → event submit DOM jamais déclenché CONFIRMÉE LinkedIn intercepte la soumission en JS avant que le DOM form submit se propage. Seul l'event click sur le bouton était observable.
Le filtre !f.form dans le listener orphan-click excluait les champs in-form CONFIRMÉE Strategy S2 couvrait seulement les champs sans <form> parent. Le champ LinkedIn est dans un <form>.

Corrections apportées

Stratégie avant/après

Composant Avant Après
Filtre M7 autocomplete="new-password" isNewPasswordField(field) → skip M7 (trop large) isSignInContext() bypass le filtre si URL connexion détectée
autocomplete="current-password" Pas de traitement dédié fieldIsCurrentPassword=true → M7 toujours actif
Regex looksLikeSubmit EN uniquement (submit|login|sign\s*in...) Étendue : suivant|next|weiter|siguiente|continuer|proceed|anmelden|accedi|ingresar
Strategy S3 click Couvre uniquement les champs orphelins (!f.form) Couvre tous les champs password (orphans ET in-form)
Valeur password au submit pwdField.value uniquement pwdField.value || _snPasswordLastValue.get(pwdField) || ''
Snapshot valeur Absent attachPasswordValueSnapshots() — écoute input/blur en capture

Nouvelles fonctions / exports

  • isSignInContext() : détection URL-based des pages de connexion (/login, /signin, /challenge, /auth, /session, /identify, /identifier, /servicelogin)
  • attachPasswordValueSnapshots() : stocke la valeur password dans _snPasswordLastValue (WeakMap) avant reset AJAX
  • _snPasswordLastValue : WeakMap exporté pour les tests

Tests ajoutés

22 nouveaux tests dans tests/unit/content-scripts/password-detector-t221-t223-m7-google-linkedin.test.ts :

TACHE-221 — isSignInContext() regex :

  • T-221-00 : jsdom /false (base)
  • T-221-01 : /challenge/pwdtrue
  • T-221-02 : /login, /account/logintrue
  • T-221-03 : /signin, /sign-in, /sign_intrue
  • T-221-04 : /false
  • T-221-05 : /register, /signupfalse

TACHE-221 — regex looksLikeSubmit multi-langue :

  • T-221-06 : "Suivant" → true
  • T-221-07 : "Next" → true
  • T-221-08 : "Weiter" → true
  • T-221-09 : "Cancel" → false
  • T-221-10 : "Close" → false

TACHE-221 — handleFormSubmit bypass filtre :

  • T-221-11 : password sans autocomplete + URL connexion (jsdom /) → M7 ACTIF
  • T-221-12 : new-password + URL non-connexion (jsdom /) → M7 ignoré
  • T-221-13 : current-password → M7 ACTIF

TACHE-223 — snapshot _snPasswordLastValue :

  • T-223-01 : événement input → snapshot stocké
  • T-223-02 : événement blur → snapshot stocké
  • T-223-03 : champ UC-05 (type=text) dans _snPasswordInputs → snapshot capturé
  • T-223-04 : pwdField.value vide + snapshot → M7 utilise snapshot
  • T-223-05 (edge) : vide + pas de snapshot → M7 ignoré

TACHE-223 — Stratégie S3 champ in-form :

  • T-223-06 : champ dans <form> avec valeur → M7 déclenché
  • T-223-07 : champ dans <form> vide + snapshot → M7 déclenché via snapshot
  • T-223-08 (edge) : form création (2 champs, URL /) → M7 ignoré (isCreationForm Signal 2)

Checklist pré-commit

  • npm run format:check — clean
  • npm run lint — 0 warnings
  • npm run build — success
  • npm run test — 1155/1155 passed (66 test files)
  • Aucun secret en dur
  • .gitignore mis à jour : scripts/edit_*.py exclus (feedback_agents_no_patch_scripts.md)

Fichiers modifiés

  • src/content-scripts/detectors/password-detector.ts — +200 lignes (isSignInContext, attachPasswordValueSnapshots, _snPasswordLastValue, filtres M7, Strategy S3)
  • tests/unit/content-scripts/password-detector-t221-t223-m7-google-linkedin.test.ts — NEW (22 tests)
  • .gitignorescripts/edit_*.py ajouté

Refs : TACHE-221, TACHE-223, INC-001, INC-006, P-017, PV recette 2026-04-24, ARB-UC02-01

🤖 Generated with Claude Code

TACHE-221 — Google /challenge/pwd : M7 restait inactif après soumission password.
- Cause (a) : autocomplete="new-password" sur le champ Google déclenchait le filtre
  isNewPasswordField — faux-positif sur une page de CONNEXION.
  Fix : isSignInContext() détecte les URL /challenge, /signin, /login, /auth, etc.
  et bypass le filtre isNewPasswordField quand la page est identifiée comme connexion.
- Cause (b) : bouton "Suivant" (type="button", FR) ignoré par la regex looksLikeSubmit.
  Fix : regex étendue — suivant|next|weiter|siguiente|continuer|proceed|anmelden...
- Cause (c) : fieldIsCurrentPassword ajouté comme court-circuit inconditionnel —
  autocomplete="current-password" est toujours un champ de connexion.

TACHE-223 — LinkedIn /login : M7 ne captait pas le submit AJAX.
- Cause : LinkedIn utilise fetch() + event.preventDefault() — l'event submit DOM
  ne se déclenche jamais. Le filtre orphan-only (!f.form) était trop restrictif.
  Fix S3 : le listener click couvre désormais TOUS les champs password (orphans ET
  in-form), avec appel direct à handleFormSubmit(event, pwdField).
- Fix snapshot : _snPasswordLastValue stocke la valeur via input/blur (capture)
  avant que l'AJAX la vide. handleFormSubmit utilise la valeur || snapshot || ''.

Tests : +22 tests (T-221-00 à T-221-13, T-223-01 à T-223-08).
Suite complète : 1155/1155 passed. format:check + lint + build : OK.
.gitignore : scripts/edit_*.py ajoutés (feedback_agents_no_patch_scripts.md).

Refs : TACHE-221, TACHE-223, INC-001, INC-006, P-017, PV recette 2026-04-24.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@antonyblain antonyblain merged commit 396f4e1 into develop Apr 28, 2026
6 checks passed
@antonyblain antonyblain deleted the feature/p5-tache-221-223-m7-google-linkedin branch April 28, 2026 09:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant