diff options
| author | Adam Soltys <[email protected]> | 2026-08-17 06:45:56 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-08-17 06:45:56 -0700 |
| commit | be93ce6e37a6304d295b5ecc2f95db52964b0074 (patch) | |
| tree | 9812774de23c6a02c1e268854571a6f0b04c2f43 /tools | |
| parent | 16f513da8d319a8f940c713ddc8358399cd2e434 (diff) | |
| download | coinosv3-be93ce6e37a6304d295b5ecc2f95db52964b0074.tar.gz coinosv3-be93ce6e37a6304d295b5ecc2f95db52964b0074.zip | |
A blank-password vault stops masquerading as a locked one: new wallets auto-save through it again, setting a real password re-encrypts every saved wallet instead of dropping the absent ones, and the save-first lock prompt finally names the password it wants
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JtaatFfAbx91Nh3xqKVqKz
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/padlock-flow-test.js | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/tools/padlock-flow-test.js b/tools/padlock-flow-test.js index be4cdf9..ce37f1a 100644 --- a/tools/padlock-flow-test.js +++ b/tools/padlock-flow-test.js @@ -86,6 +86,102 @@ try { await sleep(600); txt = await body(); check('unlock needs the password', /password/i.test(txt), txt.slice(0, 120).replace(/\n+/g, ' | ')); + + // ---- a second wallet meets the vault (fresh device) ---------------------- + const ctx2 = await browser.createBrowserContext(); + const p2 = await ctx2.newPage(); + await p2.setViewport({ width: 420, height: 880 }); + const click2 = (t) => p2.evaluate((x) => { const e = [...document.querySelectorAll('button')].find((n) => n.textContent.trim().toLowerCase().includes(x.toLowerCase())); if (e) { e.click(); return true; } return false; }, t); + const clickTitle2 = (t) => p2.evaluate((x) => { const b = [...document.querySelectorAll('button')].find((n) => n.title === x); if (b) { b.click(); return true; } return false; }, t); + const body2 = () => p2.evaluate(() => document.body.innerText); + const waitText2 = async (x, ms = 20000) => { for (let i = 0; i < ms / 250; i++) { if ((await body2()).toLowerCase().includes(x.toLowerCase())) return true; await sleep(250); } return false; }; + const importWallet = async () => { + await click2('Import existing'); + await sleep(400); + await p2.waitForSelector('textarea'); + await p2.type('textarea', generateMnemonic(wordlist)); + await click2('Open wallet'); + return waitText2('receive'); + }; + const addWallet = async () => { + await click2('Wallets'); await sleep(600); + await click2('Add wallet'); await sleep(400); + await click2('Savings'); await sleep(200); + await click2('Continue'); await sleep(600); + return importWallet(); + }; + const savingsRows = () => p2.evaluate(() => [...document.querySelectorAll('button')].map((e) => e.textContent.trim()).filter((x) => /^[●○] Savings/.test(x)).length); + + console.log('\n[a wallet created after a reload still auto-saves]'); + await p2.goto('http://localhost:5236/', { waitUntil: 'domcontentloaded' }); + await p2.evaluate(() => localStorage.setItem('btc-wallet-network', 'regtest')); + await p2.reload({ waitUntil: 'domcontentloaded' }); + await sleep(400); + await click2('Get started'); + await sleep(500); + check('wallet A open', await importWallet()); + await sleep(2000); + await p2.reload({ waitUntil: 'domcontentloaded' }); // session restore: vault untouched this session + check('back after reload', await waitText2('receive')); + await sleep(1000); + check('wallet B open', await addWallet()); + await sleep(2000); + await clickTitle2('Lock wallet'); + await sleep(600); + txt = await body2(); + check('padlock offers to SET a password (B is saved, vault is passwordless)', + /protect this device/i.test(txt) && !/already saved on this device/i.test(txt), txt.slice(0, 140).replace(/\n+/g, ' | ')); + let f2 = await p2.$$('input[type=password]'); + await f2[0].type('hunter22'); + await f2[1].type('hunter22'); + await click2('Save'); + await sleep(1200); + check('locked in place', await waitText2('receive')); + + console.log('\n[setting the password kept every saved wallet]'); + await p2.reload({ waitUntil: 'domcontentloaded' }); + check('reload keeps the locked view on screen', await waitText2('receive')); + await clickTitle2('Unlock'); + await sleep(600); + check('re-entry asks for the password', /unlock saved wallets|enter your password/i.test(await body2())); + await (await p2.$('input[type=password]')).type('hunter22'); + await click2('Unlock'); + check('password opens it', await waitText2('receive')); + await sleep(1000); + await click2('Wallets'); await sleep(600); + check('both wallets survived the re-encrypt', (await savingsRows()) === 2, `${await savingsRows()} row(s)`); + await click2('Back'); await sleep(500); + + console.log('\n[a new wallet against a passworded vault: the ask explains itself]'); + await p2.reload({ waitUntil: 'domcontentloaded' }); // session restore again: vault password not in memory + check('back after reload', await waitText2('receive')); + await sleep(1000); + check('wallet C open', await addWallet()); + await sleep(2000); + await clickTitle2('Lock wallet'); + await sleep(600); + txt = await body2(); + check('it says WHICH password it wants', /already saved on this device/i.test(txt), txt.slice(0, 160).replace(/\n+/g, ' | ')); + await (await p2.$('input[type=password]')).type('wrong-guess'); + await click2('Lock'); + await sleep(600); + check('a wrong password is refused', /wrong password/i.test(await body2())); + await p2.evaluate(() => { const i = document.querySelector('input[type=password]'); i.value = ''; i.dispatchEvent(new Event('input', { bubbles: true })); }); + await (await p2.$('input[type=password]')).type('hunter22'); + await click2('Lock'); + await sleep(1500); + check('the right one saves C and locks in place', await waitText2('receive')); + await p2.reload({ waitUntil: 'domcontentloaded' }); + check('locked view survives the reload', await waitText2('receive')); + await clickTitle2('Unlock'); + await sleep(600); + await (await p2.$('input[type=password]')).type('hunter22'); + await click2('Unlock'); + check('unlocked once more', await waitText2('receive')); + await sleep(1000); + await click2('Wallets'); await sleep(600); + check('all three wallets are in the vault', (await savingsRows()) === 3, `${await savingsRows()} row(s)`); + await ctx2.close(); } catch (e) { check('run completed', false, e.message); } finally { |
