Compare commits
1 Commits
issue-280-
...
b690e0c8e5
| Author | SHA1 | Date | |
|---|---|---|---|
| b690e0c8e5 |
8
TODO.md
8
TODO.md
@@ -44,6 +44,14 @@ undefined identifiers, which is how
|
||||
|
||||
# Completed Steps
|
||||
|
||||
- 2026-08-12: One wording for a rejected password on every screen that asks for
|
||||
one — the send confirmation and the delete-wallet confirmation no longer say
|
||||
"Wrong password." (a fragment, which `RULES.md` Language & Labeling forbids)
|
||||
and the two reveal screens no longer say "not correct", so all five
|
||||
`decryptWithPassword` call sites now show the sentence the dApp approval paths
|
||||
introduced. Strings only, no behaviour change, and each error container
|
||||
measured at a 360px viewport in the pinned Playwright container
|
||||
([#172](https://git.eeqj.de/sneak/AutistMask/issues/172)).
|
||||
- 2026-08-12: The dust threshold field now explains a rejection instead of
|
||||
snapping back in silence, with the parse in a pure, unit-tested module that
|
||||
accepts plain decimal digits only — hex and exponent notation are refused
|
||||
|
||||
@@ -422,7 +422,10 @@ function init(ctx) {
|
||||
password,
|
||||
);
|
||||
} catch (e) {
|
||||
showError("confirm-tx-password-error", "Wrong password.");
|
||||
showError(
|
||||
"confirm-tx-password-error",
|
||||
"That password is incorrect. Please try again.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,8 @@ function init(_ctx) {
|
||||
try {
|
||||
await decryptWithPassword(wallet.encryptedSecret, pw);
|
||||
} catch (_e) {
|
||||
$("delete-wallet-flash").textContent = "Wrong password.";
|
||||
$("delete-wallet-flash").textContent =
|
||||
"That password is incorrect. Please try again.";
|
||||
$("delete-wallet-flash").style.visibility = "visible";
|
||||
btn.disabled = false;
|
||||
btn.classList.remove("text-muted");
|
||||
|
||||
@@ -144,7 +144,7 @@ async function reveal() {
|
||||
$("export-privkey-flash").style.visibility = "hidden";
|
||||
} catch {
|
||||
if (!isCurrentReveal(generation)) return;
|
||||
fail("That password is not correct. Please try again.");
|
||||
fail("That password is incorrect. Please try again.");
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
btn.classList.remove("text-muted");
|
||||
|
||||
@@ -126,7 +126,7 @@ async function reveal() {
|
||||
if (!isCurrentReveal(generation)) return;
|
||||
// Deliberately not the caught error: the message is fixed so that
|
||||
// nothing derived from the ciphertext or the attempt can surface.
|
||||
fail("That password is not correct. Please try again.");
|
||||
fail("That password is incorrect. Please try again.");
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
btn.classList.remove("text-muted");
|
||||
|
||||
@@ -247,7 +247,7 @@ describe("a reveal that is not interrupted", () => {
|
||||
|
||||
expect(node("export-privkey-value").textContent).toBe("");
|
||||
expect(node("export-privkey-flash").textContent).toBe(
|
||||
"That password is not correct. Please try again.",
|
||||
"That password is incorrect. Please try again.",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
79
tests/passwordMessages.test.js
Normal file
79
tests/passwordMessages.test.js
Normal file
@@ -0,0 +1,79 @@
|
||||
// One wording for one condition (issue #172).
|
||||
//
|
||||
// Every screen that asks for the password decrypts the vault itself, and
|
||||
// each one used to write its own sentence for the same failure: the send
|
||||
// confirmation and the delete-wallet confirmation said "Wrong password."
|
||||
// (a fragment, which RULES.md Language & Labeling forbids), the reveal
|
||||
// screens said "That password is not correct.", and the two dApp approval
|
||||
// paths said "That password is incorrect." A user hitting two of those
|
||||
// minutes apart had no way to tell whether the wallet meant the same
|
||||
// thing.
|
||||
//
|
||||
// This scans the source rather than driving six views, because the
|
||||
// invariant is about the set of call sites and not about any one of them:
|
||||
// a seventh screen that decrypts the vault has to join the set, and a
|
||||
// DOM test per view cannot notice one that was never written.
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const SRC = path.join(__dirname, "..", "src");
|
||||
|
||||
const CANONICAL = "That password is incorrect. Please try again.";
|
||||
|
||||
// Wordings this repo has actually shipped for the same condition. A
|
||||
// literal match, so a new variant is caught by the "only the canonical
|
||||
// sentence appears" assertion below rather than by guessing at phrasing.
|
||||
const SUPERSEDED = [
|
||||
"Wrong password.",
|
||||
"That password is not correct. Please try again.",
|
||||
];
|
||||
|
||||
function jsFilesUnder(dir) {
|
||||
return fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
|
||||
const full = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) return jsFilesUnder(full);
|
||||
return entry.name.endsWith(".js") ? [full] : [];
|
||||
});
|
||||
}
|
||||
|
||||
// The call sites are found, not listed: the file layout moves (the private
|
||||
// key export was in addressDetail.js when #172 was filed and is its own
|
||||
// view now), and a hardcoded list would quietly stop covering a screen it
|
||||
// no longer names.
|
||||
function callSites() {
|
||||
return jsFilesUnder(SRC).filter((file) => {
|
||||
if (file === path.join(SRC, "shared", "vault.js")) return false;
|
||||
return fs.readFileSync(file, "utf8").includes("decryptWithPassword(");
|
||||
});
|
||||
}
|
||||
|
||||
describe("password failure messages", () => {
|
||||
const files = callSites();
|
||||
|
||||
test("the call sites are found where they are expected", () => {
|
||||
const found = files
|
||||
.map((f) => path.relative(SRC, f).split(path.sep).join("/"))
|
||||
.sort();
|
||||
expect(found).toEqual([
|
||||
"popup/views/approval.js",
|
||||
"popup/views/confirmTx.js",
|
||||
"popup/views/deleteWallet.js",
|
||||
"popup/views/exportPrivkey.js",
|
||||
"popup/views/showPhrase.js",
|
||||
]);
|
||||
});
|
||||
|
||||
test("the canonical message is a full sentence", () => {
|
||||
expect(CANONICAL).toMatch(/^[A-Z][^]*\.$/);
|
||||
});
|
||||
|
||||
test.each(files)("%s tells the user the canonical sentence", (f) => {
|
||||
expect(fs.readFileSync(f, "utf8")).toContain(CANONICAL);
|
||||
});
|
||||
|
||||
test.each(files)("%s carries no superseded wording", (f) => {
|
||||
const source = fs.readFileSync(f, "utf8");
|
||||
for (const old of SUPERSEDED) expect(source).not.toContain(old);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user