feat(firefox): add the desktop Firefox browser module (task 0032)
Add Firefox as a single-purpose desktop Module configured entirely through home-manager's programs.firefox, and fan it out from the desktop aggregator so any Host with the desktop enabled brings the browser up. Ship stock mainline Firefox, hardened and de-monetized through locked enterprise policies (telemetry, studies, Pocket, offer-to-save-logins, the default-browser check, Firefox accounts and sync, and the sponsored new-tab surfaces all off). Force-install three extensions by policy, keyed by their verified add-on ids: uBlock Origin, Proton Pass, and SponsorBlock. Default search to DuckDuckGo over a lean list: the general-purpose commercial engines are hidden with metaData.hidden so Firefox does not reconcile them back in, leaving DuckDuckGo and Wikipedia. Theme the browser Nord from the shared Stylix scheme against the one profile, and register it as the default handler for the web-link schemes and HTML. Record the stock-Firefox-plus-policy-extensions decision as ADR 0005.
This commit is contained in:
34
.claude/adr/0005-stock-firefox-policy-extensions.md
Normal file
34
.claude/adr/0005-stock-firefox-policy-extensions.md
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
status: accepted
|
||||
---
|
||||
|
||||
# Stock Firefox with policy-installed extensions
|
||||
|
||||
The browser Module ships **stock mainline Firefox** (`pkgs.firefox`, the release train), and installs its three extensions — an ad and content blocker, the operator's password manager, and a video sponsor-skipper — through Mozilla's enterprise `ExtensionSettings` policy, keyed by add-on id with an install URL and `installation_mode = "force_installed"`.
|
||||
Firefox fetches each signed add-on from Mozilla's add-on site at runtime and enables it automatically.
|
||||
|
||||
We chose this over an ESR, unbranded, or Developer Edition build carrying hash-pinned add-on packages from the Nix store.
|
||||
Stock mainline Firefox refuses to load unsigned locally-built add-ons, so the pinned-package path forces the browser variant: it works only on a build that relaxes signature enforcement, which the mainline release does not.
|
||||
Pairing the variant to the extension mechanism makes this the pivotal, hard-to-reverse decision — the choice of build dictates the whole extension story — so it is recorded here rather than left implicit in the Module.
|
||||
|
||||
The trade-off is deliberate.
|
||||
The policy path gives up build-time reproducibility of the extension binaries, and needs network on first launch to populate them, in exchange for staying on current mainline Firefox with add-ons that are actually enabled and no new flake input.
|
||||
|
||||
## Considered Options
|
||||
|
||||
- **Stock mainline Firefox with policy-installed extensions** (chosen).
|
||||
Current release train, no signature-enforcement caveat, no extra flake input.
|
||||
The extension binaries are fetched signed at runtime rather than pinned, so their exact versions are not reproducible from the flake and first launch needs network.
|
||||
- **ESR or unbranded Firefox with hash-pinned add-on packages** (e.g. via a NUR add-ons input).
|
||||
Rejected: it buys reproducible extension binaries but drags in an older or unusual browser variant to satisfy the signature check the mainline build enforces, plus a new flake input to maintain, for a browser the operator wants on the mainline feature and security cadence.
|
||||
- **Stock Firefox with extensions installed by hand.**
|
||||
Rejected: the state would live outside the flake, would not survive a reimage, and defeats the point of declaring the browser at all.
|
||||
|
||||
## Consequences
|
||||
|
||||
- The Module needs no new flake input and no add-on package set.
|
||||
The extension list is three id/URL pairs under the enterprise policy.
|
||||
- Extension versions are whatever Mozilla currently serves, not a pinned hash, so the browser tracks upstream add-on updates automatically and the flake does not gate them.
|
||||
- First launch after a fresh build requires network to fetch the add-ons.
|
||||
An offline first boot comes up with the extensions not yet present, populating them once online.
|
||||
- Moving to a pinned-package posture later would mean changing the browser variant as well, since the two are coupled — the reason this is captured as a decision rather than a detail.
|
||||
122
.claude/spec/firefox.md
Normal file
122
.claude/spec/firefox.md
Normal file
@@ -0,0 +1,122 @@
|
||||
## Problem Statement
|
||||
|
||||
Neogaia now boots into the keyboard-driven Hyprland desktop, but the session ships no web browser.
|
||||
The operator lives in this desktop daily and needs a browser, yet a stock browser install would arrive un-themed, telemetry-on, cluttered with sponsored surfaces, and requiring a round of manual clicking to reach a usable state.
|
||||
That manual state would also be invisible to the flake and would not survive a reimage or transfer to the future desktop Host.
|
||||
|
||||
The operator wants the browser configured the same way as the rest of the system: declared once, hardened and themed by default, and reproduced automatically on any Host that runs the desktop.
|
||||
|
||||
## Solution
|
||||
|
||||
Add Firefox as a new single-purpose desktop Module, configured entirely through home-manager's `programs.firefox`, and fold it into the desktop aggregator so the browser is part of the daily-drivable session rather than a separate opt-in.
|
||||
|
||||
Ship stock mainline Firefox, hardened and de-monetized through locked enterprise policies, with a small fixed set of extensions force-installed by policy from Mozilla's add-on site.
|
||||
Default search to DuckDuckGo over a lean, pruned engine list.
|
||||
Theme the browser Nord from the same single Stylix source that themes the rest of the graphical layer, with no hand-maintained browser CSS.
|
||||
Register Firefox as the system default handler for web links.
|
||||
|
||||
Leave the most personal, frequently-changing state — bookmarks and container tabs — to Firefox's own runtime management rather than declaring it, keeping the Module lean and avoiding the destructive overwrite those declarative options impose.
|
||||
|
||||
Because the Module joins the aggregator, it comes up on any Host with the desktop enabled: neogaia now, and the future desktop Host for free, with no per-Host browser flag.
|
||||
|
||||
## User Stories
|
||||
|
||||
1. As the operator, I want a web browser present the moment the desktop comes up, so that a daily-drivable session includes browsing without a separate install step.
|
||||
2. As the operator, I want the browser expressed as one more enable in the desktop aggregator, so that any Host running the desktop inherits it and the future desktop Host adopts it without rework.
|
||||
3. As the operator, I want the browser configured declaratively alongside every other Module, so that it is reproduced identically on reimage and never depends on manual post-install clicking.
|
||||
4. As the operator, I want to stay on current mainline Firefox rather than an older release train, so that I get up-to-date browser features and security without maintaining an unusual package variant.
|
||||
5. As the operator, I want a fixed set of extensions installed and actually enabled automatically, so that ad-blocking, password management, and sponsor-skipping work on first launch with no add-on hunting.
|
||||
6. As the operator, I want ad and content blocking, so that pages are lighter and less hostile.
|
||||
7. As the operator, I want my password manager available in the browser, so that credentials autofill without me reaching for another app.
|
||||
8. As the operator, I want sponsor segments skipped in videos, so that watching is uninterrupted.
|
||||
9. As the operator, I want telemetry, studies, the read-it-later widget, and the sponsored surfaces on the new-tab and address bar turned off and kept off, so that the browser is quiet, private, and un-monetized without me policing settings.
|
||||
10. As the operator, I want the browser to stop offering to save logins and to stop nagging about being the default, so that it does not fight the password manager or interrupt me.
|
||||
11. As the operator, I want Firefox accounts and sync disabled, so that no account surface appears for a feature I do not use.
|
||||
12. As the operator, I want DuckDuckGo as the default search with only a lean set of engines present, so that search is private and uncluttered.
|
||||
13. As the operator, I want the browser themed Nord from the same source as the rest of the desktop, so that it coheres with the bar, launcher, and lock screen without me hand-theming it.
|
||||
14. As the operator, I want the browser registered as the system default for web links, so that links opened from the bar, notifications, the launcher, or the terminal land in it.
|
||||
15. As the operator, I want bookmarks and container tabs left to the browser itself, so that the things I add in the moment are never wiped by a rebuild.
|
||||
16. As the operator, I want the whole Host to still build green under the existing check, so that I gain confidence before switching a live machine.
|
||||
|
||||
## Implementation Decisions
|
||||
|
||||
**Module and placement**
|
||||
|
||||
- A new single-purpose Module is added under the desktop group, namespaced to mirror its location per the Namespace convention, exposing one `enable` option guarded by the Enable convention.
|
||||
- The Module is configured entirely through the primary user's home-manager `programs.firefox`, matching every other user-facing Module in the repo; no NixOS-level Firefox program integration and no manual package override are used.
|
||||
- The desktop aggregator turns the Module on at default priority alongside the terminal and the other session pieces, so a single desktop flag brings the browser up while a Host retains the ability to override it.
|
||||
The browser is treated as an essential application of the session rather than optional plumbing, following the precedent that the aggregator already enables the terminal.
|
||||
|
||||
**Package variant and extension mechanism**
|
||||
|
||||
- The package is stock mainline Firefox, not ESR, unbranded, or Developer Edition.
|
||||
- Extensions are installed through Mozilla's enterprise policy `force_installed`, keyed by add-on id with an install URL, so the browser fetches the signed add-on from Mozilla's add-on site and enables it automatically.
|
||||
- Nix-built or hash-pinned add-on packages are not used, because stock Firefox refuses unsigned locally-built add-ons; the trade-off — losing build-time reproducibility of the extension binaries in exchange for current mainline Firefox with add-ons that are actually enabled and no new flake input — is accepted deliberately.
|
||||
This decision is the pivotal, hard-to-reverse one and is called out for an ADR in Further Notes.
|
||||
|
||||
**Extensions**
|
||||
|
||||
- Three extensions are force-installed: an ad and content blocker, the operator's password manager, and a video sponsor-skipper.
|
||||
- All three are self-contained web extensions, so no native messaging host is wired.
|
||||
|
||||
**Hardening**
|
||||
|
||||
- Hardening is split across two mechanisms by intent: things with a corresponding enterprise policy are set as locked policies so they cannot be toggled back in the UI, and the remainder are set as ordinary profile preferences.
|
||||
- Locked policies turn off telemetry and studies and data reporting, turn off the read-it-later widget, stop the browser offering to save logins, stop the default-browser check, strip the sponsored shortcuts, sponsored stories, and snippets from the new-tab page, and disable Firefox accounts and sync.
|
||||
- Profile preferences turn off sponsored address-bar suggestions and tidy the new-tab surface.
|
||||
- Fingerprinting resistance is deliberately left off, because it breaks enough everyday browsing to be a deliberate per-need choice rather than a baseline.
|
||||
|
||||
**Search**
|
||||
|
||||
- A single profile is declared, named as the default profile.
|
||||
- The default engine is DuckDuckGo, and the engine list is pruned to a lean set with the general-purpose commercial engines removed; the removed engines remain reachable through DuckDuckGo's bang syntax.
|
||||
- Declaring search requires the module's authoritative-overwrite acknowledgement, so engines added later through the UI are not preserved across a rebuild; this is accepted as the point of declaring search.
|
||||
|
||||
**Theming**
|
||||
|
||||
- The browser is themed by enabling the Stylix Firefox target against the declared profile, driven from the same single Nord scheme that themes the rest of the graphical layer.
|
||||
- No hand-written browser chrome CSS is shipped; a small chrome-CSS layer remains a later addition on top of Stylix if deeper chrome restyling is ever wanted.
|
||||
- The Firefox Stylix target is enabled from within the browser Module, mirroring how the theming Module already sets per-Module Stylix targets, so the target only takes effect when the browser is enabled.
|
||||
|
||||
**Default browser**
|
||||
|
||||
- Firefox is registered as the default handler for the web-link schemes and HTML through the primary user's home-manager mime-association config, placed in the browser Module.
|
||||
|
||||
**Existing conventions already satisfied**
|
||||
|
||||
- The Waybar workspace indicator already carries a window-rewrite icon mapping for Firefox, so the graphical-application icon convention needs no change.
|
||||
|
||||
## Testing Decisions
|
||||
|
||||
- A good test asserts externally-observable evaluation and build success of the whole Host, not the internals of the Module.
|
||||
This mirrors the desktop and laptop-MVI stance, where the config-merge model makes the whole-Host build the meaningful unit and the highest available seam.
|
||||
- Primary seam, required and existing: the neogaia Host evaluates and its system toplevel builds under the flake check.
|
||||
Building the toplevel drives the Auto-loader discovering the new Module, the aggregator fan-out, home-manager wrapping the Firefox package with the policies, extensions, search, and preferences baked in, the Stylix Firefox target wiring, and the default-handler association, surfacing nearly all config-authoring errors short of launching the browser.
|
||||
- Cheap targeted checks: evaluate specific configuration paths to confirm the aggregator fans the browser enable out, the rendered policies carry the three force-installed extensions, the default search engine resolves to DuckDuckGo, and the Stylix Firefox target is on, reusing the repo's existing lightweight eval-probe pattern.
|
||||
- No Module-level unit tests are added; there is no seam below the whole-Host build worth testing here, and the prior art is the desktop and laptop-MVI build-the-toplevel checks.
|
||||
- The genuine end-to-end confirmation is manual and irreducible: switch the configuration on neogaia, launch the browser, and confirm the three extensions are present and enabled, the Nord theme is applied, DuckDuckGo is the default search, and a link opened from another application lands in the browser.
|
||||
A browser cannot self-test headless, but unlike a reimage this is reversible, so verification is done by living in it with a safety net of a generation rollback or the desktop flag.
|
||||
- The build validates that the policy document is well-formed and baked into the package, but not that Firefox accepts every policy key semantically, since the policy document is only text until the browser loads it; that last mile is part of the manual confirmation.
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- ESR, unbranded, and Developer Edition Firefox variants, and the nix-built or hash-pinned add-on path they would enable; the reproducibility trade-off was weighed and declined.
|
||||
- Native messaging hosts of any kind, including a password-manager native connector and desktop browser-integration bridges; none of the chosen extensions need one.
|
||||
- Declarative bookmarks and declarative container tabs, both deliberately left to the browser's own runtime state.
|
||||
- The Multi-Account Containers extension and the contextual-identity preference it relies on.
|
||||
- Multiple Firefox profiles; a single default profile carries everything.
|
||||
- Custom or Nix-oriented search engines beyond the lean pruned set.
|
||||
- Hand-written browser chrome CSS and any deep chrome-layout restyling such as compact tabs or a hidden title bar.
|
||||
- Fingerprinting resistance and any harder privacy posture that routinely breaks everyday browsing.
|
||||
- Firefox accounts and sync.
|
||||
- Any second browser, and any per-Host browser divergence; the future desktop Host inherits this same Module unchanged.
|
||||
- Any Skeleton, Auto-loader, or secret-wiring change; the Module uses the existing plumbing unchanged.
|
||||
|
||||
## Further Notes
|
||||
|
||||
- The stock-Firefox-plus-policy-extensions decision is hard to reverse — the variant dictates the entire extension mechanism — surprising without context, since a Nix-purist default would expect hash-pinned add-on packages, and the product of a real trade-off between reproducibility and current mainline Firefox with working extensions.
|
||||
It should be recorded as an ADR.
|
||||
- Home-manager's `programs.firefox` was confirmed to expose a top-level policies option that merges into the wrapper's enterprise policies, which is what lets the whole Module, hardening included, live under home-manager rather than needing the NixOS-level program integration.
|
||||
- The declarative search, bookmarks, and containers options all share one authoritative-overwrite model: the browser owns those files at runtime, so declaring them means home-manager overwrites them wholesale and runtime-added entries do not survive a rebuild.
|
||||
This is why bookmarks and containers are left out and why declaring search is an explicit acknowledgement.
|
||||
- The extension set fetches signed add-ons from Mozilla's add-on site at runtime rather than from the Nix store, so first launch after a fresh build needs network to populate the extensions; this is inherent to the policy-based path chosen over the pinned-package path.
|
||||
60
.claude/tasks/0032-firefox-browser.md
Normal file
60
.claude/tasks/0032-firefox-browser.md
Normal file
@@ -0,0 +1,60 @@
|
||||
---
|
||||
spec: firefox
|
||||
---
|
||||
|
||||
## What to build
|
||||
|
||||
Add Firefox as a new single-purpose Module under the desktop group, configured entirely through the primary user's home-manager `programs.firefox`, and fold it into the desktop aggregator so the browser comes up as part of the daily-drivable session on any Host that enables the desktop.
|
||||
|
||||
The browser is stock mainline Firefox, hardened and de-monetized through locked enterprise policies, carrying a small fixed set of extensions force-installed by policy from Mozilla's add-on site.
|
||||
Search defaults to DuckDuckGo over a lean, pruned engine list.
|
||||
The browser is themed Nord from the same single Stylix source as the rest of the graphical layer, and registered as the system default handler for web links.
|
||||
Bookmarks and container tabs are deliberately not declared, leaving that state to the browser's own runtime management.
|
||||
|
||||
The end-to-end result: a Host with the desktop enabled boots into a session where the browser is present, launchable, themed to match, telemetry-quiet, has its extensions installed and enabled on first launch, uses DuckDuckGo, and receives links opened from other applications.
|
||||
|
||||
Scope details, all following the domain conventions (Namespace convention, Enable convention, aggregator fan-out):
|
||||
|
||||
- **Module and placement.** One `enable` option namespaced to mirror the file's location under the desktop group, guarded by the Enable convention. Configured only through home-manager `programs.firefox`; no NixOS-level Firefox program integration and no manual package override. The desktop aggregator turns it on at default priority alongside the terminal, so the single desktop flag brings it up while a Host can still override it.
|
||||
- **Package and extensions.** Stock mainline Firefox, not ESR/unbranded/Developer Edition. The three extensions — an ad and content blocker, the operator's password manager, and a video sponsor-skipper — are installed through the enterprise `force_installed` policy keyed by add-on id with an install URL, so Firefox fetches the signed add-on and enables it automatically. No Nix-built or hash-pinned add-on packages, and no native messaging host.
|
||||
- **Hardening.** Split by intent: policy-backed items are set as locked policies (telemetry, studies, and data reporting off; read-it-later widget off; offer-to-save-logins off; default-browser check off; sponsored shortcuts, stories, and snippets stripped from the new-tab page; Firefox accounts and sync disabled), and the rest as ordinary profile preferences (sponsored address-bar suggestions off, new-tab surface tidied). Fingerprinting resistance stays off.
|
||||
- **Search.** A single profile, named the default. DuckDuckGo as the default engine, the engine list pruned to a lean set with the general-purpose commercial engines removed, using the module's authoritative-overwrite acknowledgement.
|
||||
- **Theming.** Enable the Stylix Firefox target against the declared profile, driven from the shared Nord scheme, set from within this Module (mirroring how the theming Module already sets per-Module Stylix targets). No hand-written browser chrome CSS.
|
||||
- **Default browser.** Register Firefox as the default handler for the web-link schemes and HTML through the user's home-manager mime-association config, placed in this Module.
|
||||
|
||||
Record the pivotal, hard-to-reverse decision — stock Firefox plus policy-installed extensions over an ESR/unbranded build with hash-pinned add-on packages — as an ADR, following the ADR format and the next ADR number.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [x] A new Firefox Module exists under the desktop group with a single `enable` option, namespaced to mirror its directory per the Namespace convention and guarded per the Enable convention; `modules.desktop.firefox.enable` resolves.
|
||||
- [x] The Module is configured only through the primary user's home-manager `programs.firefox`; there is no NixOS-level Firefox program integration and no manual package override.
|
||||
- [x] The desktop aggregator enables the Module at default priority, so `modules.desktop.enable` brings the browser up and a Host can still override the single flag; neogaia carries it through the desktop flag with no per-Host browser line.
|
||||
- [x] The package is stock mainline Firefox (not ESR, unbranded, or Developer Edition).
|
||||
- [x] The three extensions are force-installed via enterprise policy keyed by add-on id with an install URL: the ad and content blocker, the password manager, and the video sponsor-skipper; no native messaging host is declared.
|
||||
- [x] Locked policies turn off telemetry, studies, and data reporting; turn off the read-it-later widget; stop offer-to-save-logins; stop the default-browser check; strip sponsored shortcuts, stories, and snippets from the new-tab page; and disable Firefox accounts and sync.
|
||||
- [x] Profile preferences turn off sponsored address-bar suggestions and tidy the new-tab surface; fingerprinting resistance is left off.
|
||||
- [x] A single default profile is declared with DuckDuckGo as the default search engine and the engine list pruned to a lean set (general-purpose commercial engines removed), using the search authoritative-overwrite acknowledgement.
|
||||
- [x] The Stylix Firefox target is enabled against the declared profile from within this Module, driven from the shared Nord scheme; no hand-written browser chrome CSS is shipped.
|
||||
- [x] Firefox is registered as the default handler for the web-link schemes and HTML through the user's home-manager mime-association config.
|
||||
- [x] An ADR (next number) records the stock-Firefox-plus-policy-extensions decision over an ESR/unbranded build with hash-pinned add-on packages, following the ADR format.
|
||||
- [x] `nix flake check` builds `checks.x86_64-linux.neogaia` green, with the new file staged so evaluation sees it.
|
||||
- [-] Manual confirmation on neogaia: after switching, the browser launches with the three extensions present and enabled, the Nord theme applied, DuckDuckGo as default search, and a link opened from another application lands in it.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The module lives at `modules/desktop/firefox.nix`, declares `modules.desktop.firefox.enable`, and is fanned out by the desktop aggregator at `lib.mkDefault true`.
|
||||
Everything is configured through `home-manager.users.<user>.programs.firefox`, with no NixOS-level program integration and no `package` override, so it stays on stock `pkgs.firefox` (built as `firefox-152.0.6`, the mainline release train).
|
||||
|
||||
The three force-installed extensions are keyed by their real add-on ids, verified against Mozilla's AMO API rather than guessed: uBlock Origin (`uBlock0@raymondhill.net`), Proton Pass (`78272b6fa58f4a1abaac99321d503a20@proton.me`), and SponsorBlock (`sponsorBlocker@ajay.app`).
|
||||
Proton Pass is the operator's password manager, per ADR 0002 and the sops spec.
|
||||
|
||||
Search pruning deviated from a first pass that merely omitted the commercial engines.
|
||||
Omission does not remove them: home-manager's search module writes `search.json.mozlz4`, but Firefox reconciles its locale's app-provided engines back in for any not present in the file, so the general-purpose commercial engines would reappear.
|
||||
The lean set is instead reached by explicitly hiding them with `<engine>.metaData.hidden = true` (the module's documented builtin-hiding idiom), confirmed by decoding the built `search.json.mozlz4`: it carries `_metaData.hidden` on google, bing, ebay, and amazon, with `defaultEngineId = "ddg"`.
|
||||
DuckDuckGo and Wikipedia remain visible; the hidden engines stay reachable through DuckDuckGo bangs.
|
||||
Engines are referenced by their current id form (`ddg`, `google`, …), which the module maps from the old display names — `default = "ddg"` is correct, not `"DuckDuckGo"`.
|
||||
|
||||
The decision to ship stock Firefox with policy-installed extensions over an ESR/unbranded build with hash-pinned add-ons is recorded as ADR 0005.
|
||||
|
||||
The final acceptance criterion is marked `[-]` rather than `[x]`: it is the irreducible manual confirmation the spec calls out (a browser cannot self-test headless), deferred to the operator on the live machine after switching, not dropped work.
|
||||
Every automatable check — the whole-Host toplevel build, and eval probes for the aggregator fan-out, the three force-installed ids, the DuckDuckGo default, the hidden commercial engines, the Stylix Firefox target, and the mime handlers — passes.
|
||||
@@ -10,6 +10,7 @@ in
|
||||
# any one of them while the single flag above enables the whole desktop.
|
||||
config = lib.mkIf cfg.enable {
|
||||
modules.desktop.clipboard.enable = lib.mkDefault true;
|
||||
modules.desktop.firefox.enable = lib.mkDefault true;
|
||||
modules.desktop.hyprland.enable = lib.mkDefault true;
|
||||
modules.desktop.hyprland.hyprlock.enable = lib.mkDefault true;
|
||||
modules.desktop.hyprland.hypridle.enable = lib.mkDefault true;
|
||||
|
||||
95
modules/desktop/firefox.nix
Normal file
95
modules/desktop/firefox.nix
Normal file
@@ -0,0 +1,95 @@
|
||||
{ config, lib, ... }:
|
||||
# Firefox as the desktop browser: stock mainline, hardened and de-monetized by policy.
|
||||
let
|
||||
cfg = config.modules.desktop.firefox;
|
||||
user = config.user.name;
|
||||
|
||||
# A force-installed extension, keyed at the call site by the add-on's own id.
|
||||
# Firefox fetches the signed add-on from Mozilla's site and enables it automatically.
|
||||
forceInstalled = slug: {
|
||||
install_url = "https://addons.mozilla.org/firefox/downloads/latest/${slug}/latest.xpi";
|
||||
installation_mode = "force_installed";
|
||||
};
|
||||
in
|
||||
{
|
||||
options.modules.desktop.firefox.enable = lib.mkEnableOption "Firefox as the desktop browser";
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
home-manager.users.${user} = {
|
||||
programs.firefox = {
|
||||
enable = true;
|
||||
|
||||
# Enterprise policies: enforced and unchangeable from the browser UI.
|
||||
policies = {
|
||||
DisableTelemetry = true;
|
||||
DisableFirefoxStudies = true;
|
||||
DisablePocket = true;
|
||||
OfferToSaveLogins = false;
|
||||
DontCheckDefaultBrowser = true;
|
||||
DisableFirefoxAccounts = true;
|
||||
|
||||
# Strip the monetized surfaces from the new-tab page.
|
||||
FirefoxHome = {
|
||||
SponsoredTopSites = false;
|
||||
SponsoredPocket = false;
|
||||
Snippets = false;
|
||||
};
|
||||
|
||||
# An ad and content blocker, the operator's password manager, and a
|
||||
# video sponsor-skipper. All three are self-contained web extensions.
|
||||
ExtensionSettings = {
|
||||
"uBlock0@raymondhill.net" = forceInstalled "ublock-origin";
|
||||
"78272b6fa58f4a1abaac99321d503a20@proton.me" = forceInstalled "proton-pass";
|
||||
"sponsorBlocker@ajay.app" = forceInstalled "sponsorblock";
|
||||
};
|
||||
};
|
||||
|
||||
profiles.default = {
|
||||
isDefault = true;
|
||||
|
||||
settings = {
|
||||
# Sponsored surfaces the policies above do not reach.
|
||||
"browser.urlbar.suggest.quicksuggest.sponsored" = false;
|
||||
"browser.newtabpage.activity-stream.showSponsored" = false;
|
||||
"browser.newtabpage.activity-stream.showSponsoredTopSites" = false;
|
||||
};
|
||||
|
||||
search = {
|
||||
# Declaring search overwrites Firefox's own engine list wholesale,
|
||||
# so engines added later in the UI do not survive a rebuild.
|
||||
force = true;
|
||||
default = "ddg";
|
||||
|
||||
# The general-purpose commercial engines, hidden to leave a lean
|
||||
# DuckDuckGo-and-Wikipedia list. They stay reachable through bangs.
|
||||
# An engine carrying only metaData is treated as a builtin.
|
||||
engines = {
|
||||
google.metaData.hidden = true;
|
||||
bing.metaData.hidden = true;
|
||||
ebay.metaData.hidden = true;
|
||||
"amazondotcom-us".metaData.hidden = true;
|
||||
};
|
||||
order = [ "ddg" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Nord chrome from the shared Stylix scheme, against the one profile.
|
||||
stylix.targets.firefox = {
|
||||
enable = true;
|
||||
profileNames = [ "default" ];
|
||||
};
|
||||
|
||||
# Links opened from other applications land in Firefox.
|
||||
xdg.mimeApps = {
|
||||
enable = true;
|
||||
defaultApplications = {
|
||||
"text/html" = "firefox.desktop";
|
||||
"application/xhtml+xml" = "firefox.desktop";
|
||||
"x-scheme-handler/http" = "firefox.desktop";
|
||||
"x-scheme-handler/https" = "firefox.desktop";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user