Compare commits
1 Commits
e54465ac9f
...
issue-312-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61e0cad31f |
@@ -160,9 +160,15 @@
|
|||||||
Two things stop that: the three wordings in
|
Two things stop that: the three wordings in
|
||||||
PASSWORD_HINTS are kept within a couple of
|
PASSWORD_HINTS are kept within a couple of
|
||||||
characters of each other in length, and this floor
|
characters of each other in length, and this floor
|
||||||
is above what the longest of them needs. -->
|
matches what each of them needs. All three measure
|
||||||
|
48px -- 3 lines at the 16px line height, at the
|
||||||
|
368px width this box has in the 396px popup body.
|
||||||
|
Do not raise it: the reserve is unused height on
|
||||||
|
every tab, and at 6rem it pushed
|
||||||
|
#btn-add-wallet-confirm to bottom=628px in a 600px
|
||||||
|
viewport, below the fold. -->
|
||||||
<p
|
<p
|
||||||
class="text-xs text-muted mb-1 min-h-[6rem]"
|
class="text-xs text-muted mb-1 min-h-[3rem]"
|
||||||
id="add-wallet-password-hint"
|
id="add-wallet-password-hint"
|
||||||
>
|
>
|
||||||
This password encrypts your recovery phrase on this
|
This password encrypts your recovery phrase on this
|
||||||
|
|||||||
@@ -26,6 +26,17 @@ function displayName(walletIdx) {
|
|||||||
return (wallet && wallet.name) || "Wallet " + (walletIdx + 1);
|
return (wallet && wallet.name) || "Wallet " + (walletIdx + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// What the typed confirmation and the wallet name are compared as. HTML
|
||||||
|
// collapses runs of whitespace when it renders the name, so a wallet named
|
||||||
|
// "My Wallet" with two spaces DISPLAYS as "My Wallet": the user cannot
|
||||||
|
// see the second space and cannot type a string that matches the stored
|
||||||
|
// name. Comparing collapsed on both sides is what keeps the confirmation
|
||||||
|
// satisfiable, on the one screen whose whole purpose is unwedging a user
|
||||||
|
// who is already stuck. Case and surrounding space go the same way.
|
||||||
|
function confirmKey(name) {
|
||||||
|
return name.trim().replace(/\s+/g, " ").toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
// Drop the password from the DOM and the wallet selection from the
|
// Drop the password from the DOM and the wallet selection from the
|
||||||
// closure. Registered as the view-leave handler as well as run on entry,
|
// closure. Registered as the view-leave handler as well as run on entry,
|
||||||
// so the typed password does not sit in the hidden view after the user
|
// so the typed password does not sit in the hidden view after the user
|
||||||
@@ -156,13 +167,14 @@ function init(_ctx) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case and surrounding spaces are not part of the confirmation.
|
// Case, surrounding spaces and repeated inner spaces are not part
|
||||||
// This asks whether the user knows which wallet they are on; it is
|
// of the confirmation; see confirmKey(). This asks whether the
|
||||||
// not a secret, and refusing "wallet 2" for "Wallet 2" would only
|
// user knows which wallet they are on; it is not a secret, and
|
||||||
// teach the user to distrust the control.
|
// refusing "wallet 2" for "Wallet 2" would only teach the user to
|
||||||
const typed = $("delete-wallet-lost-name-input").value.trim();
|
// distrust the control.
|
||||||
|
const typed = $("delete-wallet-lost-name-input").value;
|
||||||
const expected = displayName(lostPasswordIndex);
|
const expected = displayName(lostPasswordIndex);
|
||||||
if (typed.toLowerCase() !== expected.toLowerCase()) {
|
if (confirmKey(typed) !== confirmKey(expected)) {
|
||||||
$("delete-wallet-lost-flash").textContent =
|
$("delete-wallet-lost-flash").textContent =
|
||||||
"That is not the name of this wallet. Type " +
|
"That is not the name of this wallet. Type " +
|
||||||
expected +
|
expected +
|
||||||
|
|||||||
@@ -326,6 +326,33 @@ describe("the typed confirmation", () => {
|
|||||||
]);
|
]);
|
||||||
expect(await persistedWallets(storage)).toHaveLength(2);
|
expect(await persistedWallets(storage)).toHaveLength(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// A name with a doubled inner space RENDERS with one — HTML collapses
|
||||||
|
// runs of whitespace — so the string the user can see and type is not
|
||||||
|
// the string the name is stored as. Comparing the two raw would make
|
||||||
|
// this wallet's confirmation impossible to satisfy by any typing at
|
||||||
|
// all, wedging the one screen that exists to unwedge people.
|
||||||
|
test("a doubled space inside the name is typed back as one", async () => {
|
||||||
|
const { deleteWallet, state, storage } = load();
|
||||||
|
state.wallets[1].name = "My Wallet";
|
||||||
|
await openLostPassword(deleteWallet, 1);
|
||||||
|
|
||||||
|
// What the DOM was handed still has both spaces; what the user
|
||||||
|
// reads off the screen, and therefore types, has one.
|
||||||
|
expect(node("delete-wallet-lost-name").textContent).toBe("My Wallet");
|
||||||
|
node("delete-wallet-lost-name-input").value = "My Wallet";
|
||||||
|
await click("btn-delete-wallet-lost-confirm");
|
||||||
|
|
||||||
|
expect(state.wallets.map((w) => w.name)).toEqual([
|
||||||
|
"Wallet 1",
|
||||||
|
"Wallet 3",
|
||||||
|
]);
|
||||||
|
const persisted = await persistedWallets(storage);
|
||||||
|
expect(persisted.map((w) => w.encryptedSecret)).toEqual([
|
||||||
|
"secret-one",
|
||||||
|
"secret-three",
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("deleting without the password", () => {
|
describe("deleting without the password", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user