Compare commits
2
Commits
383a1a20f5
...
a186372877
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a186372877 | ||
|
|
e14f6e9eb5 |
@@ -218,7 +218,9 @@ development workflow, and the Makefile targets are thin shims that call them. We
|
||||
provide:
|
||||
|
||||
- `script/bootstrap` — install all dependencies (pinned node via nvm if needed,
|
||||
yarn via corepack, `yarn install --frozen-lockfile`)
|
||||
yarn via corepack, `yarn install --frozen-lockfile`), then fail, naming the
|
||||
package, if node cannot find a package listed in `dependencies` or
|
||||
`devDependencies` of `package.json`
|
||||
- `script/setup` — make a fresh clone ready for development: bootstrap plus the
|
||||
git pre-commit hook
|
||||
- `script/projectname` — print the project name (used for the Docker image tag)
|
||||
@@ -1836,6 +1838,9 @@ view would leave a wallet one click from deletion.
|
||||
try again." on the error line, nothing deleted
|
||||
- "I have lost my password" → **DeleteWalletLostPassword**
|
||||
- "Back" → previous screen (Settings)
|
||||
- Settings gear → **Settings**, whose "Back" never lands back on this
|
||||
screen: leaving drops the wallet the screen was showing, so it also takes
|
||||
the screen off the Back stack
|
||||
|
||||
#### DeleteWalletLostPassword (`delete-wallet-lost-password`)
|
||||
|
||||
@@ -1874,6 +1879,9 @@ view would leave a wallet one click from deletion.
|
||||
selection comes back with it. The two delete screens are siblings rather
|
||||
than parent and child: nothing is pushed on the way here, so both have
|
||||
Settings as their Back target.
|
||||
- Settings gear → **Settings**, whose "Back" never lands back on this
|
||||
screen: leaving drops the wallet the screen was showing, so it also takes
|
||||
the screen off the Back stack
|
||||
- **Deliberately not password-gated.** A password in front of _discarding_ a
|
||||
secret protects nobody: an attacker at the popup who wants the wallet gone can
|
||||
uninstall the extension, so the only person such a gate stops is the owner who
|
||||
|
||||
@@ -45,6 +45,24 @@ but the review is broader than any of them.
|
||||
|
||||
# Completed Steps
|
||||
|
||||
- 2026-10-06: Back from Settings no longer lands on the delete wallet or
|
||||
lost-password screen after either was left by the settings gear
|
||||
([#480](https://git.eeqj.de/sneak/AutistMask/issues/480)), the defect
|
||||
[#461](https://git.eeqj.de/sneak/AutistMask/issues/461) fixed for the two
|
||||
secret screens. Leaving drops the screen's wallet selection, so its leave
|
||||
handler now also takes it off the Back stack, as a reopened popup already
|
||||
does. `tests/deleteWalletLostPassword.test.js` drives the gear and then Back
|
||||
on both screens.
|
||||
|
||||
- 2026-10-06: `script/bootstrap` no longer reports success while node cannot
|
||||
find a package listed in `dependencies` or `devDependencies` of `package.json`
|
||||
([#263](https://git.eeqj.de/sneak/AutistMask/issues/263)). After the install
|
||||
it asks node for each one's `package.json`, and fails naming the missing
|
||||
package and the fix. yarn skips the install whenever
|
||||
`node_modules/.yarn-integrity` matches `yarn.lock`, so a package deleted from
|
||||
`node_modules` stayed deleted while bootstrap said it was complete. The
|
||||
fresh-clone failure the issue reports did not reproduce.
|
||||
|
||||
- 2026-10-06: Back from Settings no longer lands on the private key export or
|
||||
recovery phrase screen after either was left by the settings gear
|
||||
([#461](https://git.eeqj.de/sneak/AutistMask/issues/461)). Leaving drops the
|
||||
|
||||
@@ -127,6 +127,40 @@ install_js_deps() {
|
||||
fi
|
||||
}
|
||||
|
||||
# run_node: run node from the repo root, through nvm when node is not on PATH;
|
||||
# the script comes on stdin
|
||||
run_node() {
|
||||
if missing node && [ -s "$HOME/.nvm/nvm.sh" ]; then
|
||||
nvm_sh "nvm use $NODE_VERSION >/dev/null && cd \"$ROOT\" && node"
|
||||
else
|
||||
node
|
||||
fi
|
||||
}
|
||||
|
||||
# yarn install exits 0 without touching node_modules once
|
||||
# node_modules/.yarn-integrity matches yarn.lock, so a package deleted from
|
||||
# node_modules stays deleted. Fail unless node finds every package listed in
|
||||
# dependencies and devDependencies of package.json, by its package.json. When a
|
||||
# package's exports does not list that file, node throws
|
||||
# ERR_PACKAGE_PATH_NOT_EXPORTED, which it can only do once it has found the
|
||||
# package, so that error counts as found.
|
||||
check_js_deps() {
|
||||
run_node <<'EOF'
|
||||
const { dependencies, devDependencies } = require("./package.json");
|
||||
for (const name of Object.keys({ ...dependencies, ...devDependencies })) {
|
||||
try {
|
||||
require.resolve(name + "/package.json");
|
||||
} catch (e) {
|
||||
if (e.code !== "ERR_PACKAGE_PATH_NOT_EXPORTED") {
|
||||
console.error(`bootstrap: node cannot find ${name} after yarn install`);
|
||||
console.error(" fix: rm -rf node_modules && make bootstrap");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
main() {
|
||||
cd "$ROOT"
|
||||
|
||||
@@ -136,6 +170,7 @@ main() {
|
||||
ensure_node
|
||||
ensure_yarn
|
||||
install_js_deps
|
||||
check_js_deps
|
||||
|
||||
echo "bootstrap complete"
|
||||
}
|
||||
|
||||
@@ -49,9 +49,9 @@ function confirmKey(name) {
|
||||
}
|
||||
|
||||
// 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,
|
||||
// so the typed password does not sit in the hidden view after the user
|
||||
// navigates away by any route, including the Settings gear.
|
||||
// closure. Run by the view-leave handler as well as on entry, so the typed
|
||||
// password does not sit in the hidden view after the user navigates away
|
||||
// by any route, including the Settings gear.
|
||||
function clear() {
|
||||
deleteWalletIndex = null;
|
||||
$("delete-wallet-password").value = "";
|
||||
@@ -147,8 +147,25 @@ async function finishDelete(walletIdx) {
|
||||
function init(_ctx) {
|
||||
ctx = _ctx;
|
||||
|
||||
onViewLeave("delete-wallet-confirm", clear);
|
||||
onViewLeave("delete-wallet-lost-password", clearLostPassword);
|
||||
// Leaving drops the wallet selection, so each screen also comes off the
|
||||
// Back stack, where the settings gear has just put it: Back from
|
||||
// Settings must not land on a screen whose button can only answer "No
|
||||
// wallet selected for deletion." A reopened popup drops them from the
|
||||
// stack the same way (https://git.eeqj.de/sneak/AutistMask/issues/480).
|
||||
onViewLeave("delete-wallet-confirm", () => {
|
||||
clear();
|
||||
const stack = state.viewStack;
|
||||
if (stack[stack.length - 1] === "delete-wallet-confirm") {
|
||||
stack.pop();
|
||||
}
|
||||
});
|
||||
onViewLeave("delete-wallet-lost-password", () => {
|
||||
clearLostPassword();
|
||||
const stack = state.viewStack;
|
||||
if (stack[stack.length - 1] === "delete-wallet-lost-password") {
|
||||
stack.pop();
|
||||
}
|
||||
});
|
||||
|
||||
// No wipe here: goBack() routes through showView(), which runs the
|
||||
// leave hook.
|
||||
|
||||
@@ -615,3 +615,44 @@ describe("the password route's confirm button", () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
// https://git.eeqj.de/sneak/AutistMask/issues/480: leaving either delete
|
||||
// screen drops its wallet selection, so Back onto one showed a screen whose
|
||||
// button could only answer "No wallet selected for deletion."
|
||||
describe("Back from Settings after leaving by the settings gear", () => {
|
||||
test("does not land on the delete screen", () => {
|
||||
const { helpers, deleteWallet, state } = load();
|
||||
deleteWallet.show(1);
|
||||
// The settings gear: push the current view, then show Settings.
|
||||
helpers.pushCurrentView();
|
||||
helpers.showView("settings");
|
||||
|
||||
expect(state.viewStack).toEqual(["main", "settings"]);
|
||||
helpers.goBack();
|
||||
expect(state.currentView).not.toBe("delete-wallet-confirm");
|
||||
});
|
||||
|
||||
test("does not land on the lost-password screen", async () => {
|
||||
const { helpers, deleteWallet, state } = load();
|
||||
await openLostPassword(deleteWallet, 1);
|
||||
// The settings gear: push the current view, then show Settings.
|
||||
helpers.pushCurrentView();
|
||||
helpers.showView("settings");
|
||||
|
||||
expect(state.viewStack).toEqual(["main", "settings"]);
|
||||
helpers.goBack();
|
||||
expect(state.currentView).not.toBe(VIEW);
|
||||
});
|
||||
|
||||
// The lost-password screen's own Back is "Back returns to the delete
|
||||
// screen with its wallet still chosen", above.
|
||||
test("the delete screen's own Back leaves the rest of the stack alone", async () => {
|
||||
const { deleteWallet, state } = load();
|
||||
deleteWallet.show(1);
|
||||
|
||||
await click("btn-delete-wallet-back");
|
||||
|
||||
expect(state.currentView).toBe("settings");
|
||||
expect(state.viewStack).toEqual(["main"]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user