# UserWallet – Anti-rejeu, états visibles, Bloom **Author:** Équipe 4NK **Date:** 2026-01-26 ## Objectif Implémenter les éléments « reste à faire » contrat/login (3.3, 3.4, 3.6) : anti-rejeu (nonce, timestamp), états visibles (indéchiffrable, non validé, statut relais), API Bloom. ## Impacts - **Login** : vérification timestamp et nonce avant publication ; erreurs `X_NONCE_REUSED`, `X_TIMESTAMP_OUT_OF_WINDOW` ; persistance des nonces utilisés (IndexedDB). - **Sync** : compteurs `indechiffrable`, `nonValide`, statut par relais (ok / indisponible) ; affichage dans SyncScreen. - **Relais** : `getBloom(relay)` pour consommation optionnelle du Bloom filter. ## Modifications **Fichiers ajoutés** : `utils/nonceStore.ts`, `services/syncLoop.ts`. **3.4 Anti-rejeu** - `utils/nonceStore.ts` : `init()`, `hasUsed(nonce)`, `markUsed(nonce, timestamp)`. IndexedDB `userwallet_nonce_cache`, TTL 1 h. - `LoginScreen` : avant publish, `verifyTimestamp(proof.challenge.timestamp)` → sinon `X_TIMESTAMP_OUT_OF_WINDOW` ; `nonceStore.init()` puis `hasUsed(nonce)` → sinon `X_NONCE_REUSED` ; après publish réussi, `markUsed(nonce, timestamp)`. **3.3 États visibles** - `SyncService.sync()` : retourne en plus `indechiffrable` (nouveaux messages sans clé), `nonValide` (déchiffrés mais non validés), `relayStatus` (endpoint + ok par relais). Refactor : `processNewMessage`, `processMessageBatch`, `syncOneRelay`, `runSyncLoop` (dans `syncLoop.ts`) pour respecter max-lines / max-params. - `SyncScreen` : affiche « Indéchiffrables (clé manquante) », « Non validés (ex. signature manquante) », « Statut relais » (OK / indisponible par relais). **3.6 Bloom** - `utils/relay.ts` : `getBloom(relay)` → `GET /bloom`, retourne le JSON. Pas d’usage dans le sync pour l’instant (optionnel). ## Modalités de déploiement Déploiement classique du front userwallet. Aucune migration IndexedDB imposée : `userwallet_nonce_cache` est créé au premier `init()`. ## Modalités d’analyse - **Anti-rejeu** : construire un challenge, publier, puis tenter de republier la même preuve → `X_NONCE_REUSED`. Construire un challenge, attendre > 5 min, publier → `X_TIMESTAMP_OUT_OF_WINDOW` si fenêtre par défaut. - **États visibles** : lancer une sync avec relais mixte (OK / KO) et messages éventuels non déchiffrables ou non validés → vérifier les compteurs et le statut relais dans SyncScreen. - **Bloom** : `getBloom(endpoint)` sur un relais avec `/bloom` → objet JSON. ## Références - `features/userwallet-contrat-login-reste-a-faire.md` - `userwallet/docs/specs.md` (anti-rejeu, états)