feat: an "Allow weak passwords" setting lets a new wallet have a short password (closes #674)
Settings has a new "Allow weak passwords" checkbox, off in a new profile. While it is off, AddWallet refuses a password shorter than 12 characters, as before. While it is on, AddWallet accepts any password that is not empty. Key derivation is unchanged: one Argon2id derivation at libsodium's interactive setting. README's Key Decisions now states those parameters and why one light derivation is enough: the password's length is what protects the stored secret. The screens say "password", as README's wording rules require, so the setting is "Allow weak passwords". Model: opus-5-5
This commit was merged in pull request #677.
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
// "Allow weak passwords" in Settings is off until the user ticks it. While it
|
||||
// is off, AddWallet refuses a password shorter than 12 characters. While it is
|
||||
// on, AddWallet accepts any password that is not empty
|
||||
// (https://git.eeqj.de/sneak/AutistMask/issues/674). These boot the real popup,
|
||||
// set the checkbox in Settings as the user does, and then add a wallet.
|
||||
|
||||
jest.mock("../src/shared/vault", () => ({
|
||||
decryptWithPassword: jest.fn(),
|
||||
encryptWithPassword: jest.fn(async () => ({
|
||||
salt: "salt",
|
||||
nonce: "nonce",
|
||||
ciphertext: "ciphertext",
|
||||
})),
|
||||
}));
|
||||
|
||||
const {
|
||||
bootPopup,
|
||||
cleanupPopup,
|
||||
unversionedValidProfile,
|
||||
} = require("./support/popupBoot");
|
||||
|
||||
const CHECKBOX = "settings-allow-weak-passwords";
|
||||
const ERROR = "add-wallet-password-error";
|
||||
|
||||
afterEach(() => {
|
||||
cleanupPopup();
|
||||
});
|
||||
|
||||
// Boots a popup that holds one wallet and opens Settings, where the checkbox
|
||||
// starts unticked. Ticks it when `allow` is true. Then opens AddWallet and
|
||||
// presses the die for a recovery phrase.
|
||||
async function openAddWallet(allow) {
|
||||
const page = await bootPopup(unversionedValidProfile());
|
||||
await page.click("btn-settings");
|
||||
const checkbox = page.node(CHECKBOX);
|
||||
expect(checkbox.checked).toBe(false);
|
||||
if (allow) {
|
||||
checkbox.checked = true;
|
||||
for (const fn of checkbox.listeners.change) await fn();
|
||||
expect(page.storage.read("autistmask").allowWeakPasswords).toBe(true);
|
||||
}
|
||||
await page.click("btn-main-add-wallet");
|
||||
await page.click("btn-generate-phrase");
|
||||
return page;
|
||||
}
|
||||
|
||||
// Types `password` into both password fields and presses Import.
|
||||
async function importWith(page, password) {
|
||||
page.node("add-wallet-password").value = password;
|
||||
page.node("add-wallet-password-confirm").value = password;
|
||||
await page.click("btn-add-wallet-confirm");
|
||||
}
|
||||
|
||||
function storedWalletCount(page) {
|
||||
return page.storage.read("autistmask").wallets.length;
|
||||
}
|
||||
|
||||
describe("Allow weak passwords", () => {
|
||||
test("unticked: a password shorter than 12 characters is refused", async () => {
|
||||
const page = await openAddWallet(false);
|
||||
await importWith(page, "short");
|
||||
expect(page.text(ERROR)).toBe(
|
||||
"Password must be at least 12 characters.",
|
||||
);
|
||||
expect(storedWalletCount(page)).toBe(1);
|
||||
expect(page.visibleViews()).toEqual(["add-wallet"]);
|
||||
});
|
||||
|
||||
test("ticked: a password shorter than 12 characters is accepted", async () => {
|
||||
const page = await openAddWallet(true);
|
||||
await importWith(page, "short");
|
||||
expect(page.text(ERROR)).toBe("");
|
||||
expect(storedWalletCount(page)).toBe(2);
|
||||
expect(page.visibleViews()).toEqual(["main"]);
|
||||
});
|
||||
|
||||
test.each([false, true])(
|
||||
"an empty password is refused (ticked: %s)",
|
||||
async (allow) => {
|
||||
const page = await openAddWallet(allow);
|
||||
await importWith(page, "");
|
||||
expect(page.text(ERROR)).toBe("Please choose a password.");
|
||||
expect(storedWalletCount(page)).toBe(1);
|
||||
expect(page.visibleViews()).toEqual(["add-wallet"]);
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -629,8 +629,15 @@ const CONTRACT = [
|
||||
// the falsy answer is also the DEFAULT_STATE default.
|
||||
falsy: [0],
|
||||
})),
|
||||
// Each lets a request reach another service, so anything but true is off.
|
||||
...["useBlockscout", "checkRecipientsOnEtherscan"].map((field) => ({
|
||||
// Anything but true is off for these three settings:
|
||||
// - useBlockscout and checkRecipientsOnEtherscan let a request reach
|
||||
// another service.
|
||||
// - allowWeakPasswords lets AddWallet accept a short password.
|
||||
...[
|
||||
"useBlockscout",
|
||||
"checkRecipientsOnEtherscan",
|
||||
"allowWeakPasswords",
|
||||
].map((field) => ({
|
||||
field,
|
||||
kind: KIND.SCALAR,
|
||||
hostile: [42, "notabool", { a: 1 }],
|
||||
|
||||
Reference in New Issue
Block a user