From de8dee46fa75f19d25e4ca9957aef0ce54aaae72 Mon Sep 17 00:00:00 2001 From: TheRON Date: Fri, 12 Jun 2026 09:39:11 -0400 Subject: [PATCH] Updated --- hubzilla/addon/g1wallet/view/js/g1wallet.js | 67 +++++++++++++++------ 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/hubzilla/addon/g1wallet/view/js/g1wallet.js b/hubzilla/addon/g1wallet/view/js/g1wallet.js index cdddc21..9999b5d 100644 --- a/hubzilla/addon/g1wallet/view/js/g1wallet.js +++ b/hubzilla/addon/g1wallet/view/js/g1wallet.js @@ -5,11 +5,24 @@ * - The g1wallet namespace and session object are declared. * - The unlock button is wired — it intercepts the click but does NOT derive keys yet. * - The event API stubs are in place for cry01 and poll01 to listen to. - * - scrypt-js is loaded (vendor/scrypt-js-3.0.1.min.js) but not yet called. + * - bip39 is loaded (vendor/bip39-3.1.0.min.js, English wordlist only) for + * mnemonic validation and entropy extraction, but full key derivation is + * not yet called. + * + * DERIVATION (not yet implemented — see RFC 0015): + * Per Duniter HD Wallet RFC 0015 (Dubp_HD_Wallet, git.duniter.org/documents/rfcs), + * the wallet's keypair is derived from a 12-word BIP39 mnemonic (English + * wordlist). The mnemonic's ENTROPY (16 bytes for 12 words) — not a PBKDF2 + * seed — is the input to a BIP32-Ed25519 derivation (Khovratovich/Law + * construction, same family as Cardano's HD wallets). + * + * The exact BIP32-Ed25519 derivation path used by Ğecko/Cesium2 has not yet + * been confirmed against RFC 0015 and MUST be verified before this stub is + * replaced with real derivation code. Do not implement against assumptions. * * CRITICAL RULES (never relax these): * - The private key NEVER leaves the browser. - * - The pseudo and password NEVER leave the browser. + * - The mnemonic NEVER leaves the browser. * - No key material in localStorage, sessionStorage, or cookies. * - The private key object is marked non-extractable in WebCrypto. * - One document, one confirmation, one click — no batch signing. @@ -68,7 +81,8 @@ })); return; } - // TODO: implement signing via SubtleCrypto.sign() with Ed25519. + // TODO: implement signing via SubtleCrypto.sign() with Ed25519, + // using the key derived per RFC 0015 (BIP32-Ed25519 over mnemonic entropy). // The signed bytes are base64-encoded and dispatched via the callback event. console.warn('[g1wallet] requestSignature: signing not yet implemented.'); } @@ -125,20 +139,41 @@ if (!unlockBtn) return; // Not on the wallet page. unlockBtn.addEventListener('click', function () { - var pseudo = (document.getElementById('g1wallet-pseudo') || {}).value || ''; - var password = (document.getElementById('g1wallet-password') || {}).value || ''; + var mnemonicEl = document.getElementById('g1wallet-mnemonic'); + var mnemonic = (mnemonicEl || {}).value || ''; + + // Normalize whitespace: collapse multiple spaces/newlines to single spaces, trim. + mnemonic = mnemonic.trim().replace(/\s+/g, ' ').toLowerCase(); _clearError(); - if (!pseudo || !password) { - _showError('Both pseudo and password are required.'); + if (!mnemonic) { + _showError('Mnemonic phrase is required.'); return; } - // TODO: call scrypt derivation here. - // scrypt(pseudo, password, N=4096, r=16, p=1) → 32-byte seed → Ed25519 keypair - // For now: log and show a placeholder message. - console.log('[g1wallet] Unlock clicked. Derivation not yet implemented.'); + var words = mnemonic.split(' '); + if (words.length !== 12) { + _showError('Mnemonic phrase must be exactly 12 words. You entered ' + words.length + '.'); + return; + } + + // Validate against the BIP39 English wordlist and checksum. + if (window.bip39 && typeof window.bip39.validateMnemonic === 'function') { + if (!window.bip39.validateMnemonic(mnemonic)) { + _showError('Invalid mnemonic phrase. Check the words and try again.'); + return; + } + } else { + _showError('Mnemonic validation library not available. Please reload the page.'); + return; + } + + // TODO: derive keypair from mnemonic entropy per RFC 0015 (BIP32-Ed25519). + // var entropy = window.bip39.mnemonicToEntropy(mnemonic); + // ... BIP32-Ed25519 derivation (path TBD, pending RFC 0015 confirmation) ... + // ... resulting Ed25519 keypair imported as non-extractable CryptoKey ... + console.log('[g1wallet] Unlock clicked. Mnemonic validated. Derivation not yet implemented.'); if (spinner) spinner.style.display = 'inline'; unlockBtn.disabled = true; @@ -147,7 +182,7 @@ setTimeout(function () { if (spinner) spinner.style.display = 'none'; unlockBtn.disabled = false; - _showError('Key derivation not yet implemented. This is a skeleton build.'); + _showError('Mnemonic is valid. Key derivation not yet implemented. This is a skeleton build.'); }, 500); }); @@ -156,11 +191,9 @@ _lockWallet(); if (lockedView) lockedView.style.display = ''; if (unlockedView) unlockedView.style.display = 'none'; - // Clear credential fields. - var pseudoEl = document.getElementById('g1wallet-pseudo'); - var passwordEl = document.getElementById('g1wallet-password'); - if (pseudoEl) pseudoEl.value = ''; - if (passwordEl) passwordEl.value = ''; + // Clear the mnemonic field. + var mnemonicEl = document.getElementById('g1wallet-mnemonic'); + if (mnemonicEl) mnemonicEl.value = ''; }); }