# Côté service – Acceptation de session et politique anti-rejeu (3.7) **Author:** Équipe 4NK **Date:** 2026-01-26 ## Explication ### Rôle du « service » Le **service** est l’application **parente** qui embarque UserWallet en iframe. C’est elle qui **consomme** le login : elle reçoit la preuve de login (`login-proof`) via `postMessage`, doit l’**accepter ou refuser** pour ouvrir une session, **sans serveur central**. - UserWallet (iframe) envoie `{ type: 'login-proof', payload: LoginProof }` au parent. - Le parent écoute `window.addEventListener('message', ...)`, filtre `event.data?.type === 'login-proof'`, puis **vérifie** la preuve avant d’accepter la session. ### Acceptation de session Le service doit **vérifier la preuve** en s’appuyant uniquement sur **contrats + signatures** : 1. **Graphe contractuel** : le service dispose du contrat (et contrats fils) du service, fourni par channel message ou contrat par défaut. Il peut en déduire l’action login, les membres, les validateurs. 2. **Clés autorisées** : à partir des validateurs de l’action login (`membres_du_role[].signatures_obligatoires[].cle_publique`), construire l’ensemble des `cle_publique` autorisées à signer. (Résolution `pair_uuid` → clé non utilisée côté service si seules les `cle_publique` explicites sont présentes.) 3. **Vérification crypto** : pour chaque signature de la preuve, vérifier qu’elle signe bien `hash-nonce` (hash du challenge + nonce) avec la `cle_publique` indiquée (secp256k1). 4. **Conformité validateurs** : toutes les signatures doivent provenir de clés autorisées ; au moins une signature valide est requise. 5. **Anti-rejeu** : nonce unique (cache `nonce_vus`), fenêtre temporelle sur le `timestamp` du challenge. Aucune autorité centrale : la décision d’accepter ou refuser la session repose uniquement sur ces vérifications locales. ### Politique anti-rejeu - **Nonce unique** : chaque preuve utilise un nonce. Le service maintient un cache des nonces déjà vus (ex. `NonceCache`). Si un nonce est rejoué dans la fenêtre TTL, la preuve est refusée (`X_NONCE_REUSED`). - **Fenêtre timestamp** : le `timestamp` du challenge doit être dans une fenêtre acceptable (ex. ±5 min). Sinon refus (`X_TIMESTAMP_OUT_OF_WINDOW`). - **Cache `nonce_vus`** : persistance optionnelle (mémoire, IndexedDB, Redis, etc.). Le package fournit un cache en mémoire avec TTL configurable ; le service peut le remplacer par un stockage adapté. ### Implémentation Le package **`service-login-verify`** fournit : - `verifyLoginProof(proof, context)` : vérification complète (crypto, clés autorisées, timestamp, nonce). - `NonceCache` : cache anti-rejeu en mémoire (TTL configurable). - `buildAllowedPubkeysFromValidateurs(validateurs)` : extraction des `cle_publique` depuis les validateurs de l’action login. Le service (parent) : 1. Reçoit contrat + contrats fils (channel ou défaut). 2. Extrait l’action login et ses validateurs, construit `allowedPubkeys` via `buildAllowedPubkeysFromValidateurs`. 3. Maintient une `NonceCache` (ou équivalent). 4. À réception de `login-proof`, appelle `verifyLoginProof(proof, { allowedPubkeys, nonceCache, timestampWindowMs })`. 5. Si `accept: true` → ouvrir la session ; sinon → refuser et optionnellement informer l’utilisateur (ex. via `postMessage` vers l’iframe). ### Limites - Validateurs **sans** `cle_publique` (uniquement `pair_uuid`) : le service ne peut pas vérifier les clés autorisées. Il faut au moins une `cle_publique` dans `signatures_obligatoires` pour une vérification stricte côté service. - Le service ne déchiffre pas le challenge ; il vérifie uniquement les signatures et l’anti-rejeu. ## Utilisation ```ts import { verifyLoginProof, NonceCache, buildAllowedPubkeysFromValidateurs, } from 'service-login-verify'; const nonceCache = new NonceCache(3600000); const allowedPubkeys = buildAllowedPubkeysFromValidateurs(actionLogin.validateurs_action); window.addEventListener('message', (event) => { if (event.data?.type !== 'login-proof') return; const result = verifyLoginProof(event.data.payload, { allowedPubkeys, nonceCache, timestampWindowMs: 300000, }); if (result.accept) { // ouvrir session } else { // refuser (result.reason) } }); ``` ## Références - `features/userwallet-contrat-login-reste-a-faire.md` (§ 3.7) - `userwallet/docs/specs.md` (graphe, validateurs, anti-rejeu) - `service-login-verify/` : implémentation (package à la racine du dépôt). - `website-skeleton/` : squelette de site qui intègre l’iframe et vérifie les preuves.