ncantu 5689693507 UserWallet: Multiple feature implementations and updates
**Motivations:**
- Implement BIP39 mnemonic import for identity creation
- Add password-based key protection for enhanced security
- Improve pairing workflow with QR code and URL display
- Migrate hash cache from LocalStorage to IndexedDB for better scalability
- Update signet-dashboard and mempool components

**Root causes:**
- N/A (feature implementations)

**Correctifs:**
- N/A (no bug fixes in this commit)

**Evolutions:**
- BIP39 mnemonic import: Support for 12/24 word English mnemonics with BIP32 derivation path m/44'/0'/0'/0/0
- Key protection: Password-based encryption of private keys at rest with unlock/lock functionality
- Pairing workflow: QR code and URL display for device pairing, form-based word exchange between devices
- IndexedDB migration: Hash cache moved from LocalStorage to IndexedDB to avoid size limitations
- Global action bar: URL parameter support for navigation
- Pairing connection: Enhanced pairing status management

**Pages affectées:**
- userwallet/src/utils/identity.ts
- userwallet/src/utils/keyProtection.ts
- userwallet/src/utils/sessionUnlockedKey.ts
- userwallet/src/utils/indexedDbStorage.ts
- userwallet/src/utils/cache.ts
- userwallet/src/utils/pairing.ts
- userwallet/src/components/UnlockScreen.tsx
- userwallet/src/components/PairingDisplayScreen.tsx
- userwallet/src/components/PairingSetupBlock.tsx
- userwallet/src/components/GlobalActionBar.tsx
- userwallet/src/components/HomeScreen.tsx
- userwallet/src/components/ImportIdentityScreen.tsx
- userwallet/src/components/DataExportImportScreen.tsx
- userwallet/src/hooks/useIdentity.ts
- userwallet/src/hooks/usePairingConnected.ts
- userwallet/src/services/syncService.ts
- userwallet/src/services/pairingConfirm.ts
- userwallet/src/App.tsx
- userwallet/package.json
- userwallet/docs/specs.md
- userwallet/docs/storage.md
- userwallet/docs/synthese.md
- signet-dashboard/public/*.html
- signet-dashboard/public/app.js
- signet-dashboard/public/styles.css
- mempool (submodule updates)
- hash_list.txt, hash_list_cache.txt, utxo_list.txt, utxo_list_cache.txt, fees_list.txt
- features/*.md (documentation files)
2026-01-26 10:23:34 +01:00

6.1 KiB
Raw Blame History

Stockage des données - UserWallet

Author: Équipe 4NK Date: 2026-01-26

Synthèse

  • Relais (api-relay) : Stockage hybride (mémoire + ./data/messages.json). Messages, seenHashes, signatures et clés persistés. Sauvegarde à larrêt (SIGINT/SIGTERM) et périodique (configurable via SAVE_INTERVAL_SECONDS).
  • Front (userwallet) : LocalStorage (userwallet_identity, userwallet_relays, userwallet_pairs, userwallet_hash_cache ; legacy : userwallet_keypair, userwallet_services). IndexedDB : hash_cache, userwallet_pairing_confirm. Graphe contractuel en mémoire uniquement (GraphResolver).

Stockage sur le relais (api-relay)

Architecture

Le relais utilise un stockage hybride : mémoire + persistance sur disque.

Structure de stockage

En mémoire :

  • messages: Map<string, StoredMessage> - Messages chiffrés indexés par hash
  • signatures: Map<string, StoredSignature[]> - Signatures indexées par hash de message
  • keys: Map<string, StoredKey[]> - Clés de déchiffrement indexées par hash de message
  • seenHashes: Set<string> - Hash vus pour déduplication

Sur disque :

  • Fichier {STORAGE_PATH}/messages.json contenant :
    • messages: Array de [hash, StoredMessage]
    • seenHashes: Array de hash (string[])
    • signatures: Array de [hash, StoredSignature[]]
    • keys: Array de [hash, StoredKey[]]

Persistance

  • Chargement : Au démarrage, charge messages.json si présent (ENOENT = premier run, démarrage à vide).
  • Sauvegarde : À larrêt (SIGINT/SIGTERM) et périodiquement si SAVE_INTERVAL_SECONDS > 0 (défaut 300 s).

Format de données

StoredMessage :

{
  msg: {
    hash: string,
    message_chiffre: string,
    datajson_public: {
      services_uuid: string[],
      types_uuid: string[],
      timestamp?: number,
      ...
    }
  },
  received_at: number,
  relayed: boolean
}

StoredSignature :

{
  msg: {
    signature: {
      hash: string,
      cle_publique: string,
      signature: string,
      nonce: string,
      materiel?: object
    },
    hash_cible?: string
  },
  received_at: number,
  relayed: boolean
}

StoredKey :

{
  msg: {
    hash_message: string,
    cle_de_chiffrement_message: {
      algo: string,
      params: object,
      cle_chiffree?: string
    },
    df_ecdh_scannable: string
  },
  received_at: number,
  relayed: boolean
}

Configuration

  • STORAGE_PATH : Chemin du répertoire de stockage (défaut: ./data)
  • SAVE_INTERVAL_SECONDS : Intervalle de sauvegarde périodique en secondes (défaut: 300). Mettre à 0 pour désactiver.

Limitations actuelles

  • Pas de base de données (SQLite/PostgreSQL recommandé en production)
  • Pas de compression des données

Stockage sur le front (userwallet)

Architecture

Le front utilise LocalStorage du navigateur pour toutes les données locales.

Structure de stockage

Clés utilisées :

  1. userwallet_identity : Identité locale

    {
      uuid: string,
      privateKey: string,
      publicKey: string,
      name?: string,
      t0_anniversaire: number,
      version: string
    }
    
  2. userwallet_relays : Configuration des relais

    Array<{
      endpoint: string,
      priority: number,
      enabled: boolean,
      last_sync?: number
    }>
    
  3. userwallet_pairs : Configuration des pairs

    Array<{
      uuid: string,
      membres_parents_uuid: string[],
      is_local: boolean,
      can_sign: boolean,
      publicKey?: string  // clé publique identité de l'autre device (ECDH pairing)
    }>
    
  4. userwallet_hash_cache : Cache des hash vus (IndexedDB, store kv)

    string[] // Array de hash
    
  5. userwallet_pairing_confirm : Confirmations de pairing (IndexedDB, store kv)

    Array<{ pairLocal: string, pairRemote: string, hash: string, version: number }>
    
  6. userwallet_keypair : (Legacy) Paire de clés

  7. userwallet_services : (Legacy) Services configurés

Données en mémoire (non persistées)

  • Graphe contractuel : Résolu dynamiquement depuis les messages synchronisés
    • Services, Contrats, Champs, Actions, Membres, Pairs
    • Stocké dans GraphResolver.cache (Map)
    • Perdu au rechargement de page

Limitations

  • Taille limitée : LocalStorage a une limite (~5-10MB selon navigateur)
  • Pas de synchronisation : Données locales uniquement
  • Sécurité : Clés privées stockées en clair (à chiffrer avec mot de passe)

Export / Import

  • Export : Écran « Export / Import données » (/data). Télécharge un JSON (identité, relais, pairs, hash_cache, pairing_confirm, keypair, services). hash_cache et pairing_confirm lus depuis IndexedDB.
  • Import : Même écran, bouton « Choisir un fichier ». Remplace les données locales (hash_cache, pairing_confirm écrits en IndexedDB si présents dans lexport) puis recharge la page.

Protection par mot de passe

  • Activation : Écran « Export / Import données » → section « Protection par mot de passe ». Mot de passe + confirmation (min. 8 caractères). Chiffrement AES-GCM (clé dérivée PBKDF2-HMAC-SHA256, 100k itérations).
  • Déverrouillage : Si protection activée, écran « Déverrouiller » affiché tant que la session nest pas ouverte. Mot de passe → clé en session, puis accès aux écrans normaux.
  • Verrouillage : Bouton « Verrouiller » (accueil ou /data). Vide la session uniquement ; stockage chiffré inchangé.
  • Désactivation : /data → « Désactiver la protection » (mot de passe actuel). Déchiffrement et réécriture de lidentité avec clé en clair.

IndexedDB

  • Base : userwallet, store kv (key/value).
  • Utilisation : hash_cache, userwallet_pairing_confirm (confirmations de pairing). utils/indexedDbStorage expose idbGet, idbSet, idbRemove.
  • Migration : Au premier HashCache.init(), si IndexedDB vide et localStorage contient userwallet_hash_cache, copie vers IndexedDB puis suppression du localStorage.

Pas de synchronisation cloud (hors scope, jamais).