From f406bf76ec51c6bb753a6cefbe52f80455f3d0bc Mon Sep 17 00:00:00 2001 From: samialabri Date: Tue, 20 Oct 2026 01:30:05 +0900 Subject: [PATCH] Fix: server URL and password fields ignored typing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Enter-key handlers were expression-bodied arrows assigned to DOM on… properties: `(e) => e.key === "Enter" && submit()` returns false for every other key, and an on… handler returning false cancels the event, so the server URL ("Use my phone") and both master-password fields accepted no input. Use block bodies, and add scripts/check-handlers.mjs (run by npm run build) to fail the build on handlers that can return false. Co-Authored-By: Claude Opus 5.5 --- package.json | 2 +- scripts/check-handlers.mjs | 32 ++++++++++++++++++++++++++++++++ src/main.ts | 13 ++++++++++--- 3 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 scripts/check-handlers.mjs diff --git a/package.json b/package.json index 7ff3ce8..c9a9e3a 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "type": "module", "scripts": { "dev": "vite", - "build": "tsc --noEmit && vite build", + "build": "node scripts/check-handlers.mjs && tsc --noEmit && vite build", "tauri": "tauri" }, "dependencies": { diff --git a/scripts/check-handlers.mjs b/scripts/check-handlers.mjs new file mode 100644 index 0000000..8fd16f3 --- /dev/null +++ b/scripts/check-handlers.mjs @@ -0,0 +1,32 @@ +// Fails the build if a DOM `on…` handler property is assigned an expression-bodied arrow function, e.g. +// input.onkeydown = (e) => e.key === "Enter" && submit(); +// Such a handler returns `false` for every other key, and a DOM `on…` handler that returns `false` cancels the +// event, so the field silently stops accepting typing. Use a block body: `(e) => { if (…) submit(); }`. +import { readFileSync, readdirSync, statSync } from "node:fs"; +import { join } from "node:path"; + +// An `on…` handler property assigned an arrow with an expression body (not `{`) that can evaluate to false. +const handler = /\.on[a-z]+\s*=\s*(?:async\s*)?\([^)]*\)\s*=>(?!\s*\{)(.*)$/; +const canBeFalse = /&&|\|\||[=!]==?|[<>]=?/; +const files = []; +(function walk(dir) { + for (const name of readdirSync(dir)) { + const p = join(dir, name); + if (statSync(p).isDirectory()) walk(p); + else if (p.endsWith(".ts")) files.push(p); + } +})("src"); + +let failed = false; +for (const file of files) { + readFileSync(file, "utf8") + .split("\n") + .forEach((line, i) => { + const m = handler.exec(line); + if (m && canBeFalse.test(m[1])) { + console.error(`${file}:${i + 1}: on… handler needs a block body (a returned false cancels the event)\n ${line.trim()}`); + failed = true; + } + }); +} +if (failed) process.exit(1); diff --git a/src/main.ts b/src/main.ts index bbfc148..b769caa 100644 --- a/src/main.ts +++ b/src/main.ts @@ -122,7 +122,10 @@ function phonePanel(body: HTMLElement, status: SyncStatus) { start.disabled = false; } }; - url.onkeydown = (e) => e.key === "Enter" && start.click(); + // Block body on purpose: a DOM `on…` handler that returns `false` cancels the event, which would block typing. + url.onkeydown = (e) => { + if (e.key === "Enter") start.click(); + }; if (!url.value) url.focus(); } @@ -255,7 +258,9 @@ function finishSetup(body: HTMLElement, view: SetupView) { btn.disabled = false; }; btn.onclick = submit; - pw.onkeydown = (e) => e.key === "Enter" && void submit(); + pw.onkeydown = (e) => { + if (e.key === "Enter") void submit(); + }; body.replaceChildren( el("p", {}, "Signing in to ", el("strong", { textContent: view.server_host }), "."), el("p", { className: "muted", textContent: view.preapproved ? "This computer is pre-approved." : "Another device will need to approve this computer." }), @@ -339,7 +344,9 @@ function renderUnlock(state: AppState) { } }; btn.onclick = submit; - pw.onkeydown = (e) => e.key === "Enter" && void submit(); + pw.onkeydown = (e) => { + if (e.key === "Enter") void submit(); + }; const card = el("div", { className: "card" }, el("h2", { textContent: "Kestrove is locked" }), pw); if (!state.remembers_secret_key) card.append(sk); card.append(btn, err);