fix: the delete wallet screens name the wallet's own key material (closes #529) #590
@@ -2036,7 +2036,9 @@ view would leave a wallet one click from deletion.
|
|||||||
- **Elements**:
|
- **Elements**:
|
||||||
- "Back" button, "Delete Wallet" heading
|
- "Back" button, "Delete Wallet" heading
|
||||||
- Warning naming the wallet and stating that deletion is permanent and any
|
- Warning naming the wallet and stating that deletion is permanent and any
|
||||||
funds are unrecoverable without the recovery phrase
|
funds are unrecoverable without the recovery phrase, the private key or
|
||||||
|
the extended private key, according to the wallet's kind
|
||||||
|
(`keyMaterialName()` in `src/popup/views/helpers.js`)
|
||||||
- Password input
|
- Password input
|
||||||
- Error line
|
- Error line
|
||||||
- "Confirm Delete" button
|
- "Confirm Delete" button
|
||||||
@@ -2077,9 +2079,10 @@ view would leave a wallet one click from deletion.
|
|||||||
cannot be unlocked again, and that no password is needed to delete it
|
cannot be unlocked again, and that no password is needed to delete it
|
||||||
- What deletion does and does not do: it erases the copy of the key stored
|
- What deletion does and does not do: it erases the copy of the key stored
|
||||||
on this device; nothing on chain changes and no money is moved
|
on this device; nothing on chain changes and no money is moved
|
||||||
- The route back — adding the wallet again with the recovery phrase and a
|
- The route back — adding the wallet again, with a new password, from a kept
|
||||||
new password — and, in bold, that without that phrase written down the
|
copy of its recovery phrase, private key or extended private key (named as
|
||||||
deletion loses everything the wallet holds, forever
|
on DeleteWallet) — and, in bold, that without that copy the deletion loses
|
||||||
|
everything the wallet holds, forever
|
||||||
- That the other wallets are not touched
|
- That the other wallets are not touched
|
||||||
- The wallet's name, and a text input asking for it to be typed back. A name
|
- The wallet's name, and a text input asking for it to be typed back. A name
|
||||||
that shows nothing at all (only spaces, or only characters that paint
|
that shows nothing at all (only spaces, or only characters that paint
|
||||||
@@ -2137,8 +2140,9 @@ view would leave a wallet one click from deletion.
|
|||||||
the address **only if it has on-chain activity**. An address that was
|
the address **only if it has on-chain activity**. An address that was
|
||||||
never used is not found by that scan. The text is written by
|
never used is not found by that scan. The text is written by
|
||||||
`recoveryPathText()` rather than sitting in `index.html`, so it can name
|
`recoveryPathText()` rather than sitting in `index.html`, so it can name
|
||||||
the wallet's own kind of key material: an xprv wallet has no recovery
|
the wallet's own kind of key material through `keyMaterialName()`, as
|
||||||
phrase to re-import.
|
DeleteWallet and DeleteWalletLostPassword do: an xprv wallet has no
|
||||||
|
recovery phrase to re-import.
|
||||||
- A warning when the address holds anything, ETH or any tracked ERC-20,
|
- A warning when the address holds anything, ETH or any tracked ERC-20,
|
||||||
followed by the holdings themselves via `balanceLinesForAddress()` and the
|
followed by the holdings themselves via `balanceLinesForAddress()` and the
|
||||||
USD total via `formatAddressTotal()` (see
|
USD total via `formatAddressTotal()` (see
|
||||||
|
|||||||
@@ -1123,7 +1123,8 @@
|
|||||||
<p class="text-xs mb-3">
|
<p class="text-xs mb-3">
|
||||||
Deleting
|
Deleting
|
||||||
<strong id="delete-wallet-name"></strong> is permanent. Any
|
<strong id="delete-wallet-name"></strong> is permanent. Any
|
||||||
funds will be unrecoverable without your recovery phrase.
|
funds will be unrecoverable without your
|
||||||
|
<span id="delete-wallet-key-material"></span>.
|
||||||
</p>
|
</p>
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<label class="block mb-1">Password</label>
|
<label class="block mb-1">Password</label>
|
||||||
@@ -1174,13 +1175,13 @@
|
|||||||
money at its addresses is not moved or destroyed.
|
money at its addresses is not moved or destroyed.
|
||||||
</p>
|
</p>
|
||||||
<p class="text-xs mb-2">
|
<p class="text-xs mb-2">
|
||||||
If you have the recovery phrase for this wallet written
|
If you have kept a copy of this wallet's
|
||||||
down, add the wallet again afterwards with a new password
|
<span id="delete-wallet-lost-key-material"></span>, add the
|
||||||
and you will have it back.
|
wallet again afterwards with a new password and you will
|
||||||
|
have it back.
|
||||||
<strong
|
<strong
|
||||||
>If you do not have it written down, deleting this
|
>If you have not, deleting this wallet means losing
|
||||||
wallet means losing everything it holds,
|
everything it holds, forever.</strong
|
||||||
forever.</strong
|
|
||||||
>
|
>
|
||||||
</p>
|
</p>
|
||||||
<p class="text-xs mb-3">Your other wallets are not touched.</p>
|
<p class="text-xs mb-3">Your other wallets are not touched.</p>
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ const {
|
|||||||
attachCopyHandlers,
|
attachCopyHandlers,
|
||||||
addressHoldsFunds,
|
addressHoldsFunds,
|
||||||
balanceLinesForAddress,
|
balanceLinesForAddress,
|
||||||
|
keyMaterialName,
|
||||||
} = require("./helpers");
|
} = require("./helpers");
|
||||||
const { formatAddressTotal, getAddressValue } = require("../../shared/prices");
|
const { formatAddressTotal, getAddressValue } = require("../../shared/prices");
|
||||||
const { walletHasRecoveryPhrase } = require("../../shared/wallet");
|
|
||||||
const { state, saveState } = require("../../shared/state");
|
const { state, saveState } = require("../../shared/state");
|
||||||
const {
|
const {
|
||||||
canRemoveAddress,
|
canRemoveAddress,
|
||||||
@@ -54,9 +54,7 @@ function setFlash(msg) {
|
|||||||
// The noun follows the wallet: an xprv wallet holds no recovery phrase, and
|
// The noun follows the wallet: an xprv wallet holds no recovery phrase, and
|
||||||
// this screen is offered on xprv wallets too.
|
// this screen is offered on xprv wallets too.
|
||||||
function recoveryPathText(wallet) {
|
function recoveryPathText(wallet) {
|
||||||
const secret = walletHasRecoveryPhrase(wallet)
|
const secret = keyMaterialName(wallet);
|
||||||
? "recovery phrase"
|
|
||||||
: "extended private key";
|
|
||||||
return (
|
return (
|
||||||
"Getting the address back into this list is not easy, so be sure. " +
|
"Getting the address back into this list is not easy, so be sure. " +
|
||||||
"Adding an address derives the next unused one, not this one, and " +
|
"Adding an address derives the next unused one, not this one, and " +
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const {
|
|||||||
goBack,
|
goBack,
|
||||||
clearViewStack,
|
clearViewStack,
|
||||||
onViewLeave,
|
onViewLeave,
|
||||||
|
keyMaterialName,
|
||||||
} = require("./helpers");
|
} = require("./helpers");
|
||||||
const { state, saveState } = require("../../shared/state");
|
const { state, saveState } = require("../../shared/state");
|
||||||
const { decryptWithPassword } = require("../../shared/vault");
|
const { decryptWithPassword } = require("../../shared/vault");
|
||||||
@@ -75,6 +76,9 @@ function show(walletIdx) {
|
|||||||
clear();
|
clear();
|
||||||
deleteWalletIndex = walletIdx;
|
deleteWalletIndex = walletIdx;
|
||||||
$("delete-wallet-name").textContent = displayName(walletIdx);
|
$("delete-wallet-name").textContent = displayName(walletIdx);
|
||||||
|
$("delete-wallet-key-material").textContent = keyMaterialName(
|
||||||
|
state.wallets[walletIdx],
|
||||||
|
);
|
||||||
showView("delete-wallet-confirm");
|
showView("delete-wallet-confirm");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,6 +98,9 @@ function showLostPassword() {
|
|||||||
clearLostPassword();
|
clearLostPassword();
|
||||||
$("delete-wallet-lost-name").textContent = name;
|
$("delete-wallet-lost-name").textContent = name;
|
||||||
$("delete-wallet-lost-name-echo").textContent = name;
|
$("delete-wallet-lost-name-echo").textContent = name;
|
||||||
|
$("delete-wallet-lost-key-material").textContent = keyMaterialName(
|
||||||
|
state.wallets[walletIdx],
|
||||||
|
);
|
||||||
// showView() runs the leave hook of delete-wallet-confirm, which nulls
|
// showView() runs the leave hook of delete-wallet-confirm, which nulls
|
||||||
// deleteWalletIndex, so this screen's own selection is recorded after
|
// deleteWalletIndex, so this screen's own selection is recorded after
|
||||||
// it and not before.
|
// it and not before.
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ const { isDebug } = require("../../shared/log");
|
|||||||
const { formatUsd, getPrice } = require("../../shared/prices");
|
const { formatUsd, getPrice } = require("../../shared/prices");
|
||||||
const { state, saveState, currentNetwork } = require("../../shared/state");
|
const { state, saveState, currentNetwork } = require("../../shared/state");
|
||||||
const { displaySymbol } = require("../../shared/symbolDisplay");
|
const { displaySymbol } = require("../../shared/symbolDisplay");
|
||||||
|
const { walletHasRecoveryPhrase } = require("../../shared/wallet");
|
||||||
const { markViewRendered } = require("../viewRouter");
|
const { markViewRendered } = require("../viewRouter");
|
||||||
|
|
||||||
// When views are added, removed, or transitions between them change,
|
// When views are added, removed, or transitions between them change,
|
||||||
@@ -418,6 +419,16 @@ function addressHoldsFunds(addr) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The name of a wallet's key material, which is also its only backup: the
|
||||||
|
// recovery phrase of an HD wallet, the private key of a key wallet, the
|
||||||
|
// extended private key of an xprv wallet. DeleteWallet,
|
||||||
|
// DeleteWalletLostPassword and DeleteAddress name the backup with it.
|
||||||
|
function keyMaterialName(wallet) {
|
||||||
|
if (walletHasRecoveryPhrase(wallet)) return "recovery phrase";
|
||||||
|
if (wallet.type === "key") return "private key";
|
||||||
|
return "extended private key";
|
||||||
|
}
|
||||||
|
|
||||||
// The fewest characters of an address any caller may ask to display. The
|
// The fewest characters of an address any caller may ask to display. The
|
||||||
// 10-character cap inside truncateMiddle() is the other half of the same
|
// 10-character cap inside truncateMiddle() is the other half of the same
|
||||||
// guarantee; this is the half that used to be spelled out at each call
|
// guarantee; this is the half that used to be spelled out at each call
|
||||||
@@ -725,6 +736,7 @@ module.exports = {
|
|||||||
balanceLine,
|
balanceLine,
|
||||||
balanceLinesForAddress,
|
balanceLinesForAddress,
|
||||||
addressHoldsFunds,
|
addressHoldsFunds,
|
||||||
|
keyMaterialName,
|
||||||
unknownableAmount,
|
unknownableAmount,
|
||||||
nativeCurrency,
|
nativeCurrency,
|
||||||
tokenLabel,
|
tokenLabel,
|
||||||
|
|||||||
@@ -259,6 +259,36 @@ describe("reaching the screen", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Both screens tell the user what they need to get the wallet back, and a
|
||||||
|
// key or xprv wallet has no recovery phrase: telling its owner to rely on
|
||||||
|
// one sends them looking for words that do not exist
|
||||||
|
// (https://git.eeqj.de/sneak/AutistMask/issues/529).
|
||||||
|
describe("what the screens say the wallet's backup is", () => {
|
||||||
|
test.each([
|
||||||
|
["hd", "recovery phrase"],
|
||||||
|
["key", "private key"],
|
||||||
|
["xprv", "extended private key"],
|
||||||
|
])(
|
||||||
|
"a wallet of type %s is told about its %s",
|
||||||
|
async (type, keyMaterial) => {
|
||||||
|
const { deleteWallet, state } = load();
|
||||||
|
state.wallets[1].type = type;
|
||||||
|
|
||||||
|
deleteWallet.show(1);
|
||||||
|
expect(state.currentView).toBe("delete-wallet-confirm");
|
||||||
|
expect(node("delete-wallet-key-material").textContent).toBe(
|
||||||
|
keyMaterial,
|
||||||
|
);
|
||||||
|
|
||||||
|
await click("btn-delete-wallet-lost-password");
|
||||||
|
expect(state.currentView).toBe(VIEW);
|
||||||
|
expect(node("delete-wallet-lost-key-material").textContent).toBe(
|
||||||
|
keyMaterial,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
describe("the typed confirmation", () => {
|
describe("the typed confirmation", () => {
|
||||||
test("a name that is not the wallet's deletes nothing", async () => {
|
test("a name that is not the wallet's deletes nothing", async () => {
|
||||||
const { deleteWallet, state, storage } = load();
|
const { deleteWallet, state, storage } = load();
|
||||||
|
|||||||
Reference in New Issue
Block a user