Browser pairing, notifications, element hiding; drop the top bar

Pairing decrypts a Chromium browser's cookie store (PBKDF2-HMAC-SHA1
against its Keychain key, then AES-128-CBC) and injects the result into
WKHTTPCookieStore. Only the configured apps' hosts and their sign-in
hosts survive the filter. Browsers are offered most-recently-used first,
since the first entry becomes the default and someone with four
Chromium browsers installed wants the one they actually browse in.

WKWebView defines window.Notification but it does nothing: constructing
one throws no error and shows no banner, so a page believes it notified
you. Measured on the machine as `api=function shim=no` before the shim
was made unconditional; `from page: Odoo - Test notification -> raised`
after.

Anything on a page can be right-clicked away. The rule is re-asserted on
every navigation, because the injected script only carries a snapshot
from when the view was built and a selector added since would otherwise
come back on reload.

The top bar is gone. Navigation lives beside the cog, the nav carries
the traffic lights, and two-finger swipe goes back and forward.

The seed is now the real app list, scoped to exact hosts so a Drive link
inside Gmail switches rather than being swallowed.
This commit is contained in:
2026-09-01 12:17:31 +02:00
parent e369c82774
commit ff4a0c6bc4
44 changed files with 2492 additions and 419 deletions
+29 -2
View File
@@ -42,6 +42,29 @@ through `accounts.google.com`.
tool once. Every app also claims a real Chrome user agent by default, because Google
refuses logins from anything it identifies as an embedded webview.
**Pairing imports a browser's cookies.** Settings lists the browsers installed, most
recently used first, and pairing decrypts that browser's cookie store — PBKDF2-HMAC-SHA1
against its Keychain key, then AES-128-CBC — and injects the result into WebKit's shared
jar. Only cookies for the apps on your list and their sign-in hosts are read; everything
else is dropped before anything is written. macOS asks for Keychain permission the first
time, which is the consent gate and cannot be skipped.
Google and Microsoft increasingly tie a session to the browser that created it, so those
may still ask you to sign in once. After that the persistent jar keeps it.
**Notifications work, with one gap.** WKWebView *defines* `window.Notification` but it is
inert: constructing one throws nothing and shows nothing, so a page believes it notified
you and you never hear about it. It is replaced with a shim that forwards to a real macOS
notification carrying the app's name. Service-worker push in the background is not
covered — only notifications a page raises while it is open.
**Anything on a page can be hidden.** Right-click it and choose *Hide this element*, or
use the eye button in the nav to point at one (arrow-up widens the selection to the
parent, Escape cancels). Selectors are stored per app, listed in Settings, editable, and
reversible. The rule is re-asserted on every navigation and re-added if a single-page app
rewrites `<head>`, and cached in the page's own storage so a reload hides it before the
first paint rather than after it has flashed on screen.
## Apps and groups
An app owns the **exact host** of its URL — `mail.google.com`, not `google.com` — or Gmail
@@ -51,8 +74,12 @@ Extra hosts can be added per app.
Groups are for the nav only. Deleting one keeps its apps, ungrouped: deleting a folder
should never be a way to lose the things inside it.
The nav collapses to a 52px icon rail that is still clickable, so switching apps never
requires expanding it first.
The nav collapses to a 72px icon rail that is still clickable, so switching apps never
requires expanding it first. It is that wide because the macOS traffic lights have to fit
inside it: there is no title bar and no toolbar, so the nav carries the drag strip.
Back, forward, reload and hide-an-element sit next to the cog at the top of the nav.
There is no toolbar — two-finger swipe goes back and forward.
## Running it