**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)
91 lines
2.1 KiB
TypeScript
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));
|
|
}
|
|
}
|