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

91 lines
2.1 KiB
TypeScript

import { idbGet, idbSet, idbRemove } from './indexedDbStorage';
/**
* Persistent cache for seen hashes (IndexedDB-backed).
* Call init() before use.
*/
export class HashCache {
private cache: Set<string> = new Set();
private storageKey: string;
private initialized = false;
constructor(storageKey: string = 'userwallet_hash_cache') {
this.storageKey = storageKey;
}
/**
* Load cache from IndexedDB. Must be called before hasSeen / markSeen / markSeenBatch.
*/
async init(): Promise<void> {
if (this.initialized) {
return;
}
await this.loadFromStorage();
this.initialized = true;
}
/**
* Check if a hash has been seen.
*/
hasSeen(hash: string): boolean {
return this.cache.has(hash);
}
/**
* Mark a hash as seen (in-memory only). Use markSeenBatch to persist.
*/
markSeen(hash: string): void {
this.cache.add(hash);
}
/**
* Mark multiple hashes as seen and persist to IndexedDB.
*/
async markSeenBatch(hashes: string[]): Promise<void> {
for (const hash of hashes) {
this.cache.add(hash);
}
await this.saveToStorage();
}
/**
* Clear the cache and remove from IndexedDB.
*/
async clear(): Promise<void> {
this.cache.clear();
await idbRemove(this.storageKey);
}
/**
* Get cache size.
*/
size(): number {
return this.cache.size;
}
private async loadFromStorage(): Promise<void> {
let stored = await idbGet(this.storageKey);
if (stored === null && typeof localStorage !== 'undefined') {
const legacy = localStorage.getItem(this.storageKey);
if (legacy !== null) {
await idbSet(this.storageKey, legacy);
localStorage.removeItem(this.storageKey);
stored = legacy;
}
}
if (stored !== null) {
const hashes = JSON.parse(stored) as string[];
this.cache = new Set(hashes);
}
}
private async saveToStorage(): Promise<void> {
let hashes = Array.from(this.cache);
if (hashes.length > 10000) {
hashes = hashes.slice(-10000);
this.cache = new Set(hashes);
}
await idbSet(this.storageKey, JSON.stringify(hashes));
}
}