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
88 lines
3.0 KiB
JavaScript
88 lines
3.0 KiB
JavaScript
// "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"]);
|
|
},
|
|
);
|
|
});
|