From a2f72b80afdf153b36394596e149cf3b344fdce0 Mon Sep 17 00:00:00 2001 From: snekxs <26660858+snekxs@users.noreply.github.com> Date: Wed, 23 Sep 2026 01:31:11 -0600 Subject: [PATCH 1/2] Drop the full-screen developer tools warning The window-vs-viewport check fired on Firefox forks with vertical tabs, sidebars or tall toolbars, blocking the control panel with no developer tools open. Keep only the console "Stop!" warning. --- src/control.css | 53 --------------- src/security-headers.test.ts | 6 -- src/self-xss-guard.ts | 121 +++-------------------------------- 3 files changed, 8 insertions(+), 172 deletions(-) diff --git a/src/control.css b/src/control.css index ac12e637..12c96537 100644 --- a/src/control.css +++ b/src/control.css @@ -4076,56 +4076,3 @@ body { height: 100vh; overflow: hidden; } grid-template-columns: repeat(2, minmax(0, 1fr)); } } - -/* Self-XSS guard (src/self-xss-guard.ts). Shown only in production builds while - developer tools appear to be open; the copy steers the user away from pasting - unfamiliar code. */ -#selfxss-notice { - position: fixed; - inset: 0; - z-index: 2147483000; - display: grid; - place-items: center; - padding: 1.5rem; - background: rgb(8 9 10 / 88%); - backdrop-filter: blur(4px); -} -.selfxss-panel { - max-width: 34rem; - padding: 1.75rem 1.9rem; - border: 1px solid var(--destructive); - border-radius: 14px; - background: var(--card); - box-shadow: 0 24px 60px rgb(0 0 0 / 55%); - text-align: center; -} -.selfxss-panel h2 { - margin: 0 0 0.75rem; - font-size: 2rem; - font-weight: 800; - letter-spacing: 0.04em; - text-transform: uppercase; - color: var(--destructive); -} -.selfxss-panel p { - margin: 0 0 1rem; - color: var(--dim); - line-height: 1.6; -} -.selfxss-hint { - font-weight: 600; - color: var(--text); -} -.selfxss-dismiss { - margin-top: 0.5rem; - padding: 0.6rem 1.1rem; - border: 1px solid var(--line-strong); - border-radius: 8px; - background: var(--raised); - color: var(--text-soft); - font-size: 0.78rem; -} -.selfxss-dismiss:hover { - background: var(--hover); - color: var(--text); -} diff --git a/src/security-headers.test.ts b/src/security-headers.test.ts index 85f4a6b4..b9b494db 100644 --- a/src/security-headers.test.ts +++ b/src/security-headers.test.ts @@ -6,7 +6,6 @@ import { PERMISSIONS_POLICY, SECURITY_HEADERS, } from "../functions/_lib/security-headers.js"; -import { devtoolsLikelyOpen } from "./self-xss-guard.ts"; import { TRUSTED_TYPES_POLICY, setSanitizedHtml } from "./trusted-types.ts"; const headersFile = readFileSync(new URL("../public/_headers", import.meta.url), "utf8"); @@ -121,8 +120,3 @@ test("the page ships no inline scripts for the CSP to block", () => { assert.match(indexHtml, /]*src="\/theme-init\.js"/); }); -test("the developer-tools heuristic only fires on a wide window/viewport gap", () => { - assert.equal(devtoolsLikelyOpen(1200, 1200, 800, 800), false); - assert.equal(devtoolsLikelyOpen(1600, 1200, 800, 800), true, "docked to the right"); - assert.equal(devtoolsLikelyOpen(1200, 1200, 1000, 800), true, "docked to the bottom"); -}); diff --git a/src/self-xss-guard.ts b/src/self-xss-guard.ts index 28bf0d0a..8bafaed5 100644 --- a/src/self-xss-guard.ts +++ b/src/self-xss-guard.ts @@ -3,13 +3,13 @@ * * A web page cannot stop someone from running code in their own developer * tools — the browser exposes no such control — so this is deterrence, not a - * security boundary. It prints the familiar "do not paste code here" banner, - * and while developer tools appear to be open it shows a blocking notice. + * security boundary. It prints the familiar "do not paste code here" banner + * to the console. * - * It deliberately avoids `debugger` loops and console overrides: those are - * trivially bypassed, break legitimate debugging, and can trap users. The - * developer-tools check is a heuristic (window vs. viewport size) and can be - * wrong (e.g. extreme browser zoom), so the notice can be dismissed. + * It deliberately avoids `debugger` loops, console overrides and detecting + * open developer tools: those are trivially bypassed, break legitimate + * debugging, and misfire on browsers with wide chrome (e.g. Firefox forks + * with vertical tabs or sidebars). * * Call only on production builds (see control.tsx). */ @@ -19,117 +19,12 @@ const WARNING_BODY = "This console is meant for developers. If someone told you to copy and paste " + "code here, it is a scam: pasting it can hand over your connected mouse and " + "your OpenMouse settings. Never paste code you do not fully understand."; -const NOTICE_HINT = "Developer tools detected. Close them to continue."; -const DISMISS_LABEL = "I understand the risk — continue"; -const DETECT_THRESHOLD_PX = 160; -const CHECK_INTERVAL_MS = 1000; -const DISMISS_KEY = "openmouse.selfxss.dismissed"; - -let notice: HTMLElement | null = null; -let dismissed = false; - -/** - * Heuristic: when developer tools are docked, the outer window is much larger - * than the viewport. Pure so it can be unit tested. - */ -export function devtoolsLikelyOpen( - outerWidth: number, - innerWidth: number, - outerHeight: number, - innerHeight: number, - threshold: number = DETECT_THRESHOLD_PX, -): boolean { - return outerWidth - innerWidth > threshold || outerHeight - innerHeight > threshold; -} - -function warn(): void { +/** Prints the production-only console warning. Call once. */ +export function startSelfXssGuard(): void { console.log( `%c${WARNING_TITLE}`, "color:#fff;background:#b3261e;font-size:24px;font-weight:800;padding:6px 14px;border-radius:6px;", ); console.log(`%c${WARNING_BODY}`, "color:inherit;font-size:15px;line-height:1.5;"); } - -function showNotice(): void { - if (notice) return; - - const root = document.createElement("div"); - root.id = "selfxss-notice"; - root.setAttribute("role", "alertdialog"); - root.setAttribute("aria-modal", "true"); - root.setAttribute("aria-label", WARNING_TITLE); - - const panel = document.createElement("div"); - panel.className = "selfxss-panel"; - - const title = document.createElement("h2"); - title.textContent = WARNING_TITLE; - - const body = document.createElement("p"); - body.textContent = WARNING_BODY; - - const hint = document.createElement("p"); - hint.className = "selfxss-hint"; - hint.textContent = NOTICE_HINT; - - const dismiss = document.createElement("button"); - dismiss.type = "button"; - dismiss.className = "selfxss-dismiss"; - dismiss.textContent = DISMISS_LABEL; - dismiss.addEventListener("click", () => { - dismissed = true; - try { - sessionStorage.setItem(DISMISS_KEY, "1"); - } catch { - /* storage unavailable — the dismissal simply does not persist */ - } - hideNotice(); - }); - - panel.append(title, body, hint, dismiss); - root.append(panel); - document.body.append(root); - notice = root; -} - -function hideNotice(): void { - notice?.remove(); - notice = null; -} - -function storedDismissed(): boolean { - try { - return sessionStorage.getItem(DISMISS_KEY) === "1"; - } catch { - return false; - } -} - -/** Starts the production-only console/DevTools deterrence. Call once. */ -export function startSelfXssGuard(): void { - if (typeof window === "undefined" || typeof document === "undefined") return; - dismissed = storedDismissed(); - warn(); - - const check = (): void => { - if (dismissed) return; - if ( - devtoolsLikelyOpen( - window.outerWidth, - window.innerWidth, - window.outerHeight, - window.innerHeight, - ) - ) { - showNotice(); - } else { - hideNotice(); - } - }; - - check(); - window.setInterval(check, CHECK_INTERVAL_MS); - window.addEventListener("focus", check); - window.addEventListener("resize", check); -} From 814d7808c7ddb88ec6882f0a35d4ab5d4876ba09 Mon Sep 17 00:00:00 2001 From: snekxs <26660858+snekxs@users.noreply.github.com> Date: Wed, 23 Sep 2026 14:31:00 -0600 Subject: [PATCH 2/2] Announce OpenMouse Bridge in the news banner Replace the Chrome 153 Razer known-issue alert with an info notice linking to the Bridge launch post. --- public/news.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/public/news.json b/public/news.json index fd4247c1..0947b060 100644 --- a/public/news.json +++ b/public/news.json @@ -1,6 +1,6 @@ { - "id": "2026-09-razer-chrome-153", - "level": "critical", - "message": "Using a Razer mouse? A recent Chrome update can stop it from being detected. This is a known issue we're tracking - open the workaround guide.", - "url": "https://openmouse.app/blog-razer-windows-chrome-153" + "id": "2026-09-openmouse-bridge", + "level": "info", + "message": "OpenMouse Bridge is here: Razer mice work on Windows again, plus game profiles, low-battery alerts and Firefox support. Read the announcement.", + "url": "https://openmouse.app/blog-openmouse-bridge" }