# Correctifs UserWallet et API Relay **Auteur:** Équipe 4NK **Date:** 2026-01-26 ## Motivations - Corriger la condition de relais dans POST /messages (api-relay) : les messages n’étaient jamais relayés. - Supprimer la duplication du type `MessageBase` dans SyncService et utiliser les types partagés. - Supprimer les fallbacks (retour de `[]` ou `false` en erreur) dans relay.ts et remonter les erreurs. - Implémenter une vraie dérivation clé publique depuis la clé privée à l’import d’identité, et documenter la limite (pas de mnemonic/seed). ## Root causes - **Relais** : On appelait `storage.storeMessage()` puis `if (!storage.hasSeenHash())` pour relayer. Or `storeMessage` marque le hash comme vu, donc la condition était toujours fausse et le relais jamais exécuté. - **MessageBase** : SyncService définissait une interface locale `MessageBase` avec `hash?: string`, alors que le code utilisait `msg.hash.hash_value` (type `Hash`). Incohérence de typage et duplication. - **relay.ts** : Les GET renvoyaient `[]` et les POST `false` en cas d’erreur, ce qui masquait les échecs (fallback interdit). - **importIdentity** : On générait une nouvelle paire, puis on écrasait `privateKey` par la seed fournie tout en gardant la `publicKey` de la paire générée. Aucune dérivation depuis la clé importée. ## Correctifs ### 1. api-relay – POST /messages (relay condition) **Fichier:** `api-relay/src/routes/messages.ts` - Calculer `alreadySeen = storage.hasSeenHash(msg.hash)` **avant** `storage.storeMessage(stored)`. - Appeler `storage.storeMessage(stored)`. - Relayer seulement si `!alreadySeen` : `await relay.relayMessage(msg)` et `stored.relayed = true`. ### 2. userwallet – SyncService MessageBase **Fichier:** `userwallet/src/services/syncService.ts` - Importer `MessageBase` depuis `../types/message`. - Supprimer l’interface locale `MessageBase` en fin de fichier. - Utiliser le type partagé pour `validateMessage` et `updateGraph`. ### 3. userwallet – relay.ts (remonter les erreurs) **Fichier:** `userwallet/src/utils/relay.ts` - **GET** (`getMessagesChiffres`, `getSignatures`, `getKeys`) : ne plus retourner `[]` en erreur ; `throw new Error(...)` en cas de `!response.ok` ou d’échec fetch, avec message incluant statut et URL du relais. - **POST** (`postMessageChiffre`, `postSignature`, `postKey`) : ne plus retourner `false` ; `throw new Error(...)` en cas d’échec. Types de retour passés à `Promise`. **Fichier:** `userwallet/src/components/LoginScreen.tsx` - Adapter la boucle de publication : `await postMessageChiffre` / `await postSignature` sans vérifier de booléen ; en cas de throw, le `catch` existant pousse `{ relay, success: false }` et on continue. ### 4. userwallet – importIdentity (dérivation + limite) **Fichiers:** `userwallet/src/utils/crypto.ts`, `userwallet/src/utils/identity.ts` - **crypto.ts** : Ajouter `publicKeyFromPrivateKey(privateKeyHex: string): string` qui dérive la clé publique secp256k1 (compressée, hex) depuis la clé privée hex. - **identity.ts** : - Valider que l’entrée est 64 caractères hexadécimaux (32 octets), après trim et suppression d’un préfixe `0x` éventuel. - Utiliser `publicKeyFromPrivateKey(raw)` pour la clé publique. - Stocker `raw` comme `privateKey` et la clé dérivée comme `publicKey`. - Documenter en JSDoc : seul l’import d’une clé privée hex brute est supporté ; mnemonic (BIP39) et dérivation depuis seed ne sont pas implémentés. ## Évolutions - Aucune évolution fonctionnelle au-delà des correctifs ci‑dessus. ## Pages affectées - `api-relay/src/routes/messages.ts` - `userwallet/src/services/syncService.ts` - `userwallet/src/utils/relay.ts` - `userwallet/src/utils/crypto.ts` - `userwallet/src/utils/identity.ts` - `userwallet/src/components/LoginScreen.tsx` ## Modalités de déploiement - **api-relay** : Redémarrer le serveur après déploiement. - **userwallet** : Rebuild du frontend et déploiement des assets. Les appelants de `relay.ts` (SyncService, LoginScreen) gèrent déjà les erreurs (try/catch) ; les throws sont remontés jusqu’à eux. ## Modalités d’analyse - **Relais** : Poster un message sur un relais avec pairs configurés ; vérifier qu’il est bien relayé vers les pairs (logs, GET sur un pair). - **SyncService** : Vérifier que le type-check et le lint passent ; lancer une sync et s’assurer qu’aucune régression sur la résolution du graphe. - **relay.ts** : En cas de relais injoignable ou réponse non ok, vérifier que l’erreur est bien levée (et non masquée par `[]` / `false`). - **importIdentity** : Importer une clé privée hex valide (64 caractères), vérifier que la clé publique stockée correspond à la dérivation secp256k1. Tester un format invalide (ex. mnemonic) et vérifier le retour `null` et le message en console.