Skip to content

PRIVACY UPDATE - #6

Merged
CanPixel merged 5 commits into
masterfrom
privacy-overhaul
Jul 31, 2026
Merged

PRIVACY UPDATE#6
CanPixel merged 5 commits into
masterfrom
privacy-overhaul

Conversation

@CanPixel

Copy link
Copy Markdown
Owner

Privacy overhaul: tracker blocking, browsing data control, and store integrity

Closes the gap between what ÆTHER claims about privacy and what it enforces. Adds real request filtering on all three desktop platforms, gives the user a way to clear what sites leave behind, removes the last outbound request from the privileged window, and fixes several ways the library could leak or lose data.

Tracker blocking

New per-platform request filtering, driven by one shared rule file (src-tauri/resources/content-blocking-rules.json).

Platform Mechanism Third-party cookies
macOS WKContentRuleList blocked
Linux WebKitUserContentFilterStore (same JSON) blocked
Windows WebResourceRequested host matching not blocked

WebKit evaluates rules inside the network path, so a blocked request is never made rather than made and discarded. Windows is the odd one out: WebView2 has no rule-list concept, so it re-derives a host list from the same file and matches per request across the COM boundary. It also has no equivalent of the block-cookies rule — a tracker not on the host list can still set third-party cookies there.

Two constraints on the rule file are silent failures — one bad rule rejects the entire list at runtime with nothing visible to say so — so cargo run --example verify_content_rules compiles the rules through real WebKit, and unit tests cover the alternation and extra-key traps.

Browsing data

Clear browsing data in Settings wipes cookies, caches, local storage and the rest of the shared webview store, leaving collections, captures and conversations untouched. Scope is deliberately the shared default store — a private tab's store is discarded with its webview anyway.

Favicons off the privileged window

Tab favicons used to be <img src="https://host/favicon.ico"> inside the window that holds the IPC bridge, which meant that window made a direct request to every host visited, and forced img-src to allow https: and http:.

They now resolve in Rust on the shared client and reach the renderer as data: URIs. The privileged window makes no outbound requests at all, and the CSP is down to 'self' data: blob:. The cache is memory-only on purpose — a favicon cache on disk is a list of visited hosts by another name.

Honest reporting in Settings

A new Tracker blocking panel states what the running build actually does — engine, domain count, and whether third-party cookies are covered. This is reported by the backend rather than hardcoded in the renderer, because the platforms genuinely differ and a fixed string would keep claiming cookie blocking on Windows long after anyone remembered it wasn't true. Tests assert the per-platform claim: a build that stops blocking cookies while still saying it does is worse than one that never claimed to.

Capture quality

The snapshot script's cleaning previously had no effect — it stripped nav/footer/script from a clone, then sent untouched innerText anyway, so navigation and consent banners were what got embedded. Cleaned text now wins, extraction skips non-content subtrees, and five named consent-manager containers are removed (named roots only; a wrong match silently deletes real article text). A thin page now fails honestly instead of being padded with its own chrome up to the capture threshold.

Store integrity

  • The library is cached and lock-guarded. Every command used to re-read and re-parse library.json; worse, mutations were unsynchronised read-modify-write, so two commands in flight could silently drop one write. with_library_read/with_library_mut fix both. The mutation closure is fallible because callers validate against the library they're about to change, and doing that outside the lock is the race being closed.
  • Delete now means delete. Removing a source physically reclaims its vectors instead of leaving them in the sidecar until compaction thresholds happen to trigger.
  • Delete ordering is crash-safe. Chunks drop before the library entry; capture commits the library entry before chunks. Each direction is chosen so an interrupted operation leaves the harmless orphan — never searchable content the UI can't remove.
  • Startup reconciliation clears orphans left by the previous ordering, for stores that already have them.
  • Capture re-checks for duplicates under the write lock, since embedding is slow enough for the same page to be captured twice in that window.

Performance

  • Five call sites cloned the entire chunk store — every chunk's text and vector — to produce bounded results. They now work inside the read lock or project only what they need.
  • Chat and embedding no longer share one mutex. A generation used to hold it for its full duration, so search, Flow and AiR froze until the answer finished streaming. They're independent models; only the one-time llama.cpp backend init stays serialised.
  • The four large panels are memoized, with handler identities stabilised so the memo actually holds.
  • Address bar draft state moved into the chrome, so typing repaints the address bar instead of the whole application.
  • Settings sections had no spacing rule at all — gaps existed only where a card happened to carry a class that set one. The container now owns the rhythm.

Build and CI

.github/workflows/checks.yml runs clippy and tests on macOS, Linux and Windows for every push, dev-profile and no bundling — a Windows-only compile error used to surface only behind a full release installer build. bun run check:platforms gives the same coverage locally, including a Windows cross type-check that catches WebView2 signature errors from a Mac.

Release profile adds lto = "thin", codegen-units = 1, strip. panic = "abort" is deliberately excluded and documented: every llama.cpp call goes through spawn_blocking and turns a panic into an error message via JoinError. Under abort there is no JoinError — measured, the process takes SIGABRT (exit 134). An abort mid-capture is exactly the orphan state reconciliation exists to clean up.

Docs

docs/SECURITY.md gains sections on content blocking, private tabs, container tabs, what gets captured, and how to verify the platform code.

Verification

103 Rust tests pass on macOS and Linux; Windows type-checks; WebKit accepts all rules; lint, typecheck and renderer build clean.

Known gaps

  • Windows blocking has never been run on real hardware — it compiles and is type-checked, but nobody has watched it block a request.
  • Third-party cookies are unblocked on Windows. Surfaced in Settings; no WebView2 primitive exists to fix it.
  • Private tabs still fetch favicons, which escapes the incognito store and leaves the origin in the session cache until quit.

@CanPixel CanPixel self-assigned this Jul 28, 2026
@CanPixel
CanPixel merged commit 6ac350c into master Jul 31, 2026
14 checks passed
@CanPixel
CanPixel deleted the privacy-overhaul branch July 31, 2026 07:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant