Skip to content

feat: add space-scoped privacy protections#243

Merged
yonaries merged 4 commits intomainfrom
feat/space-privacy-protections
Apr 5, 2026
Merged

feat: add space-scoped privacy protections#243
yonaries merged 4 commits intomainfrom
feat/space-privacy-protections

Conversation

@yonaries
Copy link
Copy Markdown
Contributor

@yonaries yonaries commented Apr 5, 2026

Major changes

  • add an AdGuard-backed WebKit content blocking pipeline with per-space filter selection, caching, compilation, and refresh
  • wire space-scoped privacy settings into browser page creation and refresh so tracker blocking, ad blocking, cookie policy, and fingerprinting protection apply per space

Minor changes

  • move privacy controls under Space Settings and disable the top-level Privacy tab until browser-wide options are added
  • strengthen fingerprinting protection with a deterministic balanced profile and default new spaces to fingerprinting on with cookies allowed
  • add regression coverage for per-space persistence, ad-block updates, and fingerprinting behavior

@yonaries yonaries marked this pull request as ready for review April 5, 2026 15:59
@yonaries yonaries requested a review from kenenisa as a code owner April 5, 2026 15:59
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 5, 2026

Greptile Summary

This PR adds a full space-scoped privacy pipeline: an AdGuard-backed WebKit content-blocking system with per-space filter selection, on-disk shard caching, incremental refresh, and scheduling; fingerprinting protection via a deterministic JS profile; and cookie-policy enforcement. Privacy settings are wired into BrowserPage creation (deferring navigation until rule lists are registered) and refreshed live when space settings change via a NotificationCenter-based pipeline.

  • Critical: resolveFilterSource in AdBlockService has an inverted guard — when allowNetworkFetch: false and no cached text is available, the else branch silently makes a live network request instead of throwing missingCachedList. This defeats the parameter's purpose and causes unexpected network calls during settings-change refreshes.
  • Critical: The tracker-domain regex uses \\\\ in the Swift source, which produces two literal backslashes at the regex level instead of the intended subdomain-separator \., causing tracker requests from subdomains (e.g. static.hotjar.com, cdn.segment.com) to bypass the third-party tracker block entirely.
  • Warning: The background-refresh scheduler uses try? await Task.sleep(...) which silently swallows CancellationError, causing one spurious refreshScheduledSpaces() call each time a settings change resets the scheduler task.
  • Minor: ContentBlockerArtifactStore identifier parsing splits on . and silently returns nil if a list ID ever contains a dot, making the corresponding shard unloadable without any diagnostic.

Confidence Score: 2/5

Not safe to merge: the inverted guard in resolveFilterSource causes unauthorized network fetches when ad-block settings change with no cache present, and the double-escaped regex silently narrows the scope of third-party tracker blocking.

Two bugs with direct behavioral impact (unintended network I/O in resolveFilterSource, broken subdomain regex in regexForDomain) and one correctness issue in the cancellation path lower confidence significantly despite solid overall architecture and good test coverage.

ora/Features/Privacy/Services/AdBlockService.swift (resolveFilterSource logic and cancellation handling), ora/Features/Privacy/Services/BrowserPrivacyService.swift (regexForDomain backslash escaping)

Important Files Changed

Filename Overview
ora/Features/Privacy/Services/AdBlockService.swift Core ad-block orchestrator; logic inversion in resolveFilterSource makes unauthorized network requests when allowNetworkFetch=false, and cancelled Task.sleep triggers a spurious extra refresh
ora/Features/Privacy/Services/BrowserPrivacyService.swift Privacy configuration service; fingerprinting script and content-rule wiring are correct, but the tracker domain regex has a double-escaped backslash that breaks subdomain matching
ora/Core/BrowserEngine/BrowserPage.swift Adds pending-navigation queue to defer load/reload until content blockers are registered; thread-safe given WKWebView's main-thread requirement
ora/Features/Privacy/Services/ContentBlockerArtifactStore.swift Correct shard storage, retrieval, and revision cleanup, but identifier parsing silently fails for list IDs containing dots
ora/Features/Privacy/Services/ContentBlockerCompileService.swift Recursive shard splitting is bounded and correct; coverage accounting looks accurate
ora/Features/Privacy/Models/SpacePrivacySettings.swift Well-structured per-space settings model with backward-compatible Codable migration for the adBlock field
ora/Features/Privacy/Models/AdBlockModels.swift Clean value types; normalized() correctly deduplicates list IDs
ora/Features/Privacy/Services/FilterListCatalogService.swift Catalog merging and custom-record sorting look correct
ora/Features/Privacy/Services/FilterListUpdateService.swift HTTP conditional-fetch with ETag/Last-Modified is implemented correctly
ora/Core/Utilities/SettingsStore.swift Adds per-container privacy persistence and notification helpers; legacy fallback via legacyPrivacySettings is correct
ora/App/OraRoot.swift Wires AdBlockService startup and privacy-change observer at app root; consistent with existing codebase observer pattern
ora/Features/Settings/Sections/SpacesSettingsView.swift Privacy bindings correctly chain through applyAdBlockSettingsChange to refreshSpace; non-adblock changes post the notification directly
ora/Features/Tabs/State/TabManager.swift refreshPrivacySettings iterates loaded tabs and triggers page refresh correctly
oraTests/oraTests.swift Good regression coverage for per-space persistence, ad-block updates, and fingerprinting behavior
ora/Core/BrowserEngine/BrowserEngine.swift BrowserPageConfiguration now carries privacySettings; factory method updated correctly
ora/Core/Constants/AppEvents.swift Adds spacePrivacySettingsChanged notification name

Sequence Diagram

sequenceDiagram
    participant UI as SpacesSettingsView
    participant SS as SettingsStore
    participant ABS as AdBlockService (actor)
    participant FUS as FilterListUpdateService
    participant CCS as ContentBlockerCompileService
    participant CAS as ContentBlockerArtifactStore
    participant NC as NotificationCenter
    participant TM as TabManager
    participant BP as BrowserPage
    participant BPS as BrowserPrivacyService

    UI->>SS: setPrivacySettings(for: containerID)
    UI->>ABS: refreshSpace(containerId:, reason: .settingsChanged)
    ABS->>SS: privacySettings(for: containerID)
    ABS->>FUS: fetchLatest(for: record) [if allowNetworkFetch]
    FUS-->>ABS: FilterListFetchResult
    ABS->>CCS: compile(record:, rawText:)
    CCS-->>ABS: CompiledFilterArtifacts
    ABS->>CAS: storeCompiledArtifacts(...)
    ABS->>SS: notifySpacePrivacySettingsChanged(for: containerID)
    SS->>NC: post(.spacePrivacySettingsChanged)
    NC->>TM: refreshPrivacySettings(for: containerID)
    TM->>BP: refreshBrowserPageForPrivacySettings()
    BP->>BPS: prepareConfiguration(_:spaceID:completion:)
    BPS->>CAS: ruleListIdentifiers(for:revision:)
    BPS-->>BP: completion() - isReadyForNavigation = true
    BP->>BP: flushPendingNavigationIfNeeded()
Loading

Reviews (1): Last reviewed commit: "feat(privacy): wire space protections in..." | Re-trigger Greptile

Comment thread ora/Features/Privacy/Services/AdBlockService.swift
Comment thread ora/Features/Privacy/Services/AdBlockService.swift
Comment thread ora/Features/Privacy/Services/BrowserPrivacyService.swift Outdated
Comment thread ora/Features/Privacy/Services/ContentBlockerArtifactStore.swift
@yonaries yonaries merged commit 106f796 into main Apr 5, 2026
2 checks passed
@yonaries yonaries deleted the feat/space-privacy-protections branch April 5, 2026 21:01
@tembo tembo Bot added the feature feature request label Apr 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature feature request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant