# Components

This page summarizes the main components and how to extend the system safely.

The implementation is split across three layers:

- `toolkit/components/ipprotection` — platform-independent core (state machine,
  proxy/network stack, core helpers).
- `browser/components/ipprotection` — desktop-specific UI layer (panel, toolbar
  button, alert/infobar managers, and onboarding helpers).
- `mobile/shared/modules/geckoview/` — Android GeckoView entry point.

## Component Diagram

A diagram of all the main components is the following:

```{mermaid}
:align: center
:caption: IP Protection architecture

---
config:
  flowchart:
    defaultRenderer: "elk"
---
flowchart LR

  %% browser/components/ipprotection
  subgraph Browser["browser/components/ipprotection (UI layer)"]
    IPProtection
    IPProtectionPanel

    subgraph BrowserHelpers["Browser Helpers"]
      UIHelper["UI Helper"]
      IPPOnboardingMessage["Onboarding Message"]
      IPPOptOutHelper["Opt-Out Helper"]
      IPPUsageHelper["Usage Helper"]
      IPProtectionAlertManager["Alert Manager"]
      IPProtectionInfobarManager["Infobar Manager"]
    end
  end

  %% toolkit/components/ipprotection
  subgraph Toolkit["toolkit/components/ipprotection (core)"]
    IPProtectionService
    IPProtectionActivator

    subgraph CoreHelpers["Core Helpers"]
      IPPStartupCache["Startup Cache Helper"]
      IPProtectionServerlist
      IPPProxyManager
      IPPAutoStart["Auto-Start Helper"]
      IPPAutoRestoreHelper["Auto-Restore Helper"]
      IPPNimbusHelper["Nimbus Eligibility Helper"]
      IPPSessionPrefManager["Session Pref Manager"]
      IPPExceptionsManager
    end

    subgraph FxaAuth["FxA Authentication (fxa/)"]
      IPPAuthProvider
      IPPFxaActivateAuthProvider["Activate Auth Provider"]
      IPPSignInWatcher["Sign-in Observer"]
      GuardianClient
    end

    subgraph Proxy["Proxy stack"]
      IPPChannelFilter
      IPPNetworkErrorObserver
    end
  end

  %% Android layer
  subgraph Android["Android Glue"]
    GeckoViewIPProtection

    subgraph AndroidAuth["Android Authentication"]
      IPPAndroidAuthProvider["Android FxA Auth Provider"]
      IPPGpiAuthProvider["GPI Auth Provider"]
      IPPAndroidSignInWatcher["Android Sign-in Observer"]
    end
  end

  %% Activator wiring
  BrowserHelpers -- "addHelpers()" --> IPProtectionActivator
  IPProtectionActivator --> IPProtectionService
  IPProtectionActivator --> CoreHelpers
  IPProtectionActivator -- "setAuthProvider()" --> IPPFxaActivateAuthProvider
  GeckoViewIPProtection -- "setAuthProvider()" --> IPProtectionActivator

  %% Service wiring
  IPProtectionService --> CoreHelpers
  IPProtectionService -- "authProvider" --> IPPAuthProvider

  %% FxA auth wiring
  IPPFxaActivateAuthProvider -->|extends| IPPAuthProvider
  IPPFxaActivateAuthProvider --> IPPSignInWatcher
  IPPFxaActivateAuthProvider --> GuardianClient

  %% Android auth wiring
  IPPAndroidAuthProvider -->|extends| IPPFxaActivateAuthProvider
  IPPAndroidAuthProvider --> IPPAndroidSignInWatcher
  IPPGpiAuthProvider -->|extends| IPPAuthProvider

  %% UI wiring
  IPProtection --> IPProtectionPanel
  IPProtection --> IPProtectionService

  %% Proxy wiring
  IPPProxyManager --> IPPChannelFilter
  IPPProxyManager --> IPPNetworkErrorObserver
  IPPNetworkErrorObserver -- "error events (401)" --> IPPProxyManager
```

## Toolkit components (`toolkit/components/ipprotection`)

GuardianClient

: HTTP client for the Guardian backend. Manages communication with Guardian to
  retrieve account information, obtain proxy tokens, and run the FxA enrollment
  flow.

IPPChannelFilter

: Main network component. It processes network requests and decides which ones
  should go through the proxy.

IPPProxyManager

: Implements the proxy activation/deactivation and exposes the current status.

IPProtectionService

: The main service. It is initialized during browser startup, initializes helpers
  and other components, and implements the state machine that drives the feature.

IPProtectionActivator

: Entry point that assembles the full helper list and initialises
  `IPProtectionService`. It owns the ordered list of core helpers and exposes
  `addHelpers()` so that the browser layer can register additional,
  browser-specific helpers before `init()` is called. It also exposes
  `setAuthProvider()` to set the active authentication provider.

IPPExceptionsManager

: Manages the exceptions logic (for example, domain exclusions) in coordination
  with the panel and preferences.

### Additional proxy/telemetry components

IPProtectionServerlist

: Provides the available proxy endpoints (server list) to the proxy manager.

IPPNetworkErrorObserver

: Observes network errors related to the proxy and notifies the proxy manager
  (for example, authentication or connectivity failures).

### Core helpers

The core helper list is defined in `IPProtectionActivator.sys.mjs` (toolkit).

IPPAutoStart

: Activates the proxy at startup time when auto-start is enabled.

IPPAutoRestoreHelper

: Restores the proxy state after a crash or restart when auto-restore is enabled.

IPPStartupCache

: Exposes cached information to keep the state machine responsive during startup
  (last known state and entitlement JSON object).

IPPNimbusHelper

: Monitors the Nimbus feature (`NimbusFeatures.ipProtection`) and triggers a
  state recomputation on updates.

### FxA authentication (`toolkit/components/ipprotection/fxa`)

Authentication is abstracted behind `IPPAuthProvider`, which lives in the
toolkit root. `IPProtectionService` always interacts with the provider through
this interface, so all FxA dependencies are fully contained in the `fxa/`
sub-directory. On desktop, the concrete provider and its helpers are registered
from `IPProtectionHelpers.sys.mjs` in the browser layer. On Android, the
selection is done by `GeckoViewIPProtection` at initialisation time (see below).

IPPAuthProvider

: Base class that defines the authentication interface used by
  `IPProtectionService`. The default implementation is a no-op that keeps
  the service in an unauthenticated/inactive state.

IPPFxaActivateAuthProvider

: Concrete FxA implementation of `IPPAuthProvider`. It obtains short-lived
  OAuth tokens from `fxAccounts` via `getToken()`, passes them to
  `GuardianClient` for all Guardian HTTP calls, and enrolls the user by sending
  the FxA Bearer token directly to Guardian's activate endpoint, without using a
  hidden tab or window.

IPPSignInWatcher

: Observes user authentication state. It informs the state machine when the
  user signs in or out.

IPPSessionPrefManager

: Sets session-scoped preferences while the
  proxy is active and resets them when it deactivates, preserving any
  user-set values.

### Android authentication

On Android, two concrete `IPPAuthProvider` implementations are available and
selected at initialisation time by `GeckoViewIPProtection` based on the FxA
sign-in state stored in `toolkit.ipProtection.android.authProvider`.

IPPAndroidAuthProvider

: Android variant of the FxA provider. Extends `IPPFxaActivateAuthProvider`
  and uses `IPPAndroidSignInWatcher` to track the FxA sign-in state.

IPPGpiAuthProvider

: Google Play Integrity implementation of `IPPAuthProvider`. Used when the
  user is not signed into FxA. Obtains a short-lived GPI token from the Android
  layer via `EventDispatcher` and exchanges it for an Auth JWT with Guardian.
  The JWT is cached in `browser.ipProtection.gpi.authJwt` so that subsequent
  proxy starts require no network requests.

IPPAndroidSignInWatcher

: Monitors the FxA sign-in state on Android by listening to
  `IPP:AuthStateChanged` events from the Android layer. Exposes `isSignedIn`
  and dispatches `IPPSignInWatcher:StateChanged` when the state changes.

## Android GeckoView entry point

GeckoViewIPProtection

: GeckoView module that owns the IP Protection lifecycle on Android. On
  `GeckoView:IPProtection:Init` it reads the `toolkit.ipProtection.android.authProvider`
  preference to determine which auth provider to activate: `IPPAndroidAuthProvider`
  (with its FxA helpers) when the user is signed in, or `IPPGpiAuthProvider`
  otherwise. When the FxA sign-in state changes the Android layer clears the
  preference and calls `Uninit` followed by `Init` so that the correct
  provider is selected again.

## Browser components (`browser/components/ipprotection`)

IPProtection

: Manages the UI integration and interactions with the panel.

IPProtectionPanel

: Controls the feature's panel UI.

IPProtectionHelpers

: Registers browser-specific helpers with `IPProtectionActivator` via
  `addHelpers()`: `UIHelper`, `IPPOnboardingMessage`, `IPPOptOutHelper`,
  `IPPUsageHelper`, `IPProtectionAlertManager`, and `IPProtectionInfobarManager`.
  It also registers `IPPFxaActivateAuthProvider` (and its FxA helpers) via
  `setAuthProvider()` and `addHelpers()`.

UIHelper

: Shows and hides the UI based on the current state machine state.

IPPOptOutHelper

: Handles the user opt-out flow and clears stored state accordingly.

IPPOnboardingMessage

: Handles the onboarding message flow for new users.

IPPUsageHelper

: Tracks bandwidth usage warning state and fires state-change events when
  usage crosses the 75% or 90% thresholds.

IPProtectionAlertManager

: Manages alert notifications related to IP Protection.

IPProtectionInfobarManager

: Manages infobar notifications displayed to the user.

## How to implement new components

Do not modify the state machine. New functionality should be added via helper
classes to keep the core simple and robust.

Recommended steps:

1. Decide whether the helper belongs in the **toolkit** layer (no UI, no chrome
   dependency) or the **browser** layer (UI or chrome integration required).

2. Create a helper class with the methods `init()`, `initOnStartupCompleted()`
   and `uninit()` as appropriate for lifecycle needs.

3. If your helper reacts to state changes, listen to the
   `IPProtectionService:StateChanged` event.

4. Register your helper:

   - **Toolkit helpers**: add it to the `coreHelpers` array in
     `toolkit/components/ipprotection/IPProtectionActivator.sys.mjs`.
   - **Browser helpers**: call `IPProtectionActivator.addHelpers([...])` in
     `browser/components/ipprotection/IPProtectionHelpers.sys.mjs`.

   Be mindful of ordering if your helper depends on others. For example,
   `IPPNimbusHelper` is registered last to avoid premature state updates
   triggered by Nimbus' immediate callback.

5. If your component needs to recompute the service state, call
   `IPProtectionService.updateState()` after updating the helper data it
   relies on; the recomputation is synchronous.
