hylonix/modules/home-manager/gecko-browser/gecko-lib/extensions.nix
hylodon 0f0c4c7727 Added a module to configure browser based on the gecko engine, such as Firefox.
This module should provide similar functionality to the firefox module in
home-manager. Some notable differences between the two include:

* home-manager configures a single browser. This means that any configuration
  that cannot be done on a per-profile basis is shared between all
  profiles. This module configures a new copy of the browser for every profile,
  ensuring that *all* configuration can be on a per-profile basis.

  This might be seen as insanity in a regular distro, but in NixOS this is
  trivial to do and requires no extra storage space.

* home-manager modifies files in the user's directory to configure things such
  as extensions and search engines. This module avoids that when possible by
  pushing configuration into policies and preferences at a browser level.
  This is much nicer for impermanence-based systems.
2026-02-22 19:57:42 +00:00

157 lines
4.9 KiB
Nix

{
pkgs,
lib,
info,
...
}:
let
submodule =
{ name, ... }:
{
options = {
packages = lib.mkOption {
type =
lib.types.listOf
<| lib.types.either lib.types.package
<| lib.types.submodule {
options = {
name = lib.mkOption {
type = lib.types.str;
default = name;
example = "ublock-origin";
description = "The short name of the extension. To find the short name look at the extension's download link.";
};
guid = lib.mkOption {
type = lib.types.str;
example = "uBlock0@raymondhill.net";
description = "The guid of the extension. To find the guid go to https://addons.mozilla.org/api/v5/addons/addon/\${shortName}/";
};
};
};
default = [ ];
description = ''
Extensions to install for this profile. Takes either a package or a description of an extension.
* If a package is given, the extension will be preinstalled.
* If a description is given then ${info.name} will download the extension on startup.
'';
};
settings = lib.mkOption {
type =
let
jsonFormat = pkgs.formats.json { };
in
lib.types.attrsOf jsonFormat.type;
default = { };
description = "Settings for this extension, accessible by the managed storage API. The extension must be referenced by id.";
};
};
};
# (Package -> a) -> ({ name, guid } -> a) -> Extension -> a
withExtension =
f: g: x:
if lib.isDerivation x then f x else g x;
# ublock-origin wants its settings as a string, which is annoying
# to merge. For convenience, you can keep ublock-origin's config
# as a set and this function will turn it into a string at the
# last minute. As a bonus, we can also do other magic for other
# extensions if need be.
magicInfo = {
"uBlock0@raymondhill.net" =
x:
x
// lib.optionalAttrs (x ? adminSettings) {
adminSettings =
builtins.toJSON
<| (
y:
y
// lib.optionalAttrs (y ? userFilters) {
userFilters = builtins.concatStringsSep "\n" y.userFilters;
}
)
<| (
y:
y
// lib.optionalAttrs (y ? urlFilteringString) {
urlFilteringString = builtins.concatStringsSep "\n" y.urlFilteringString;
}
)
<| (
y:
y
// lib.optionalAttrs (y ? hostnameSwitchesString) {
hostnameSwitchesString = builtins.concatStringsSep "\n" y.hostnameSwitchesString;
}
)
<| (
y:
y
// lib.optionalAttrs (y ? dynamicFilteringString) {
dynamicFilteringString = builtins.concatStringsSep "\n" y.dynamicFilteringString;
}
)
<| x.adminSettings;
};
};
magic = guid: magicInfo.${guid} or lib.trivial.id;
in
{
options = {
extensions = lib.mkOption {
type = lib.types.submodule submodule;
default = { };
# example = {
# packages = [
# nur.repos.rycee.firefox-addons.ublock-origin
# { name = "decentraleyes"; guid = "jid1-BoFifL9Vbdl2zQ@jetpack"; }
# ];
# settings."uBlock0@raymondhill.net" = {
# whitelist = [ "example.org" ];
# };
# };
description = "The extensions to install.";
};
};
process =
{ extensions, ... }:
{
policies = {
"3rdparty".Extensions = extensions.settings;
ExtensionSettings =
builtins.listToAttrs
<| builtins.map (
withExtension
(x: {
name = x.addonId;
value = {
installation_mode = "force_installed";
private_browsing = true;
install_url = "file://${x}/share/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}/${x.addonId}.xpi";
};
})
(x: {
name = x.guid;
value = {
installation_mode = "force_installed";
private_browsing = true;
install_url = "https://addons.mozilla.org/firefox/downloads/latest/${x.name}/latest.xpi";
};
})
)
<| extensions.packages;
};
prefs."extensions.autoDisableScopes" = 0;
};
postprocess =
{ policies, ... }:
lib.optionalAttrs (policies ? "3rdparty".Extensions) {
policies."3rdparty".Extensions = builtins.mapAttrs magic <| policies."3rdparty".Extensions or { };
};
}