This commit is contained in:
2026-10-19 12:16:49 -04:00
parent d7ecab6494
commit 6d3f470922
10446 changed files with 1626249 additions and 2216 deletions
+41
View File
@@ -0,0 +1,41 @@
export type Wallet = { privateKey: CryptoKey; publicKey: string; address: string };
const encode = (bytes: ArrayBuffer) => btoa(String.fromCharCode(...new Uint8Array(bytes)));
async function loadOrCreate(): Promise<Wallet> {
const db = await new Promise<IDBDatabase>((resolve, reject) => {
const request = indexedDB.open('wikideck-wallet', 1);
request.onupgradeneeded = () => request.result.createObjectStore('keys');
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(new Error('Enable browser storage to create your local wallet.'));
});
try {
const saved = await new Promise<Wallet | undefined>((resolve, reject) => {
const req = db.transaction('keys').objectStore('keys').get('identity');
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
if (saved) return saved;
const keys = await crypto.subtle.generateKey({ name: 'ECDSA', namedCurve: 'P-256' }, false, ['sign', 'verify']);
const spki = await crypto.subtle.exportKey('spki', keys.publicKey);
const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', spki));
const wallet = { privateKey: keys.privateKey, publicKey: encode(spki),
address: Array.from(digest, b => b.toString(16).padStart(2, '0')).join('') };
await new Promise<void>((resolve, reject) => {
const tx = db.transaction('keys', 'readwrite');
tx.objectStore('keys').put(wallet, 'identity');
tx.oncomplete = () => resolve();
tx.onerror = () => reject(tx.error);
});
return wallet;
} finally { db.close(); }
}
let pending: Promise<Wallet> | undefined;
export function getWallet(): Promise<Wallet> {
return pending ??= (async () => {
if (navigator.locks) return await navigator.locks.request('wikideck-wallet-init', loadOrCreate);
return loadOrCreate();
})().catch(error => { pending = undefined; throw error; });
}
export async function sign(wallet: Wallet, message: string): Promise<string> {
return encode(await crypto.subtle.sign({ name: 'ECDSA', hash: 'SHA-256' }, wallet.privateKey, new TextEncoder().encode(message)));
}