aboutsummaryrefslogtreecommitdiff
path: root/home-manager/modules/programs/firefox.nix
diff options
context:
space:
mode:
Diffstat (limited to 'home-manager/modules/programs/firefox.nix')
-rw-r--r--home-manager/modules/programs/firefox.nix319
1 files changed, 319 insertions, 0 deletions
diff --git a/home-manager/modules/programs/firefox.nix b/home-manager/modules/programs/firefox.nix
new file mode 100644
index 00000000000..d5003f59edc
--- /dev/null
+++ b/home-manager/modules/programs/firefox.nix
@@ -0,0 +1,319 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+ inherit (pkgs.stdenv.hostPlatform) isDarwin;
+
+ cfg = config.programs.firefox;
+
+ mozillaConfigPath =
+ if isDarwin
+ then "Library/Application Support/Mozilla"
+ else ".mozilla";
+
+ firefoxConfigPath =
+ if isDarwin
+ then "Library/Application Support/Firefox"
+ else "${mozillaConfigPath}/firefox";
+
+ profilesPath =
+ if isDarwin
+ then "${firefoxConfigPath}/Profiles"
+ else firefoxConfigPath;
+
+ # The extensions path shared by all profiles; will not be supported
+ # by future Firefox versions.
+ extensionPath = "extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}";
+
+ extensionsEnvPkg = pkgs.buildEnv {
+ name = "hm-firefox-extensions";
+ paths = cfg.extensions;
+ };
+
+ profiles =
+ flip mapAttrs' cfg.profiles (_: profile:
+ nameValuePair "Profile${toString profile.id}" {
+ Name = profile.name;
+ Path =
+ if isDarwin
+ then "Profiles/${profile.path}"
+ else profile.path;
+ IsRelative = 1;
+ Default = if profile.isDefault then 1 else 0;
+ }
+ ) // {
+ General = {
+ StartWithLastProfile = 1;
+ };
+ };
+
+ profilesIni = generators.toINI {} profiles;
+
+ mkUserJs = prefs: extraPrefs: ''
+ // Generated by Home Manager.
+
+ ${concatStrings (mapAttrsToList (name: value: ''
+ user_pref("${name}", ${builtins.toJSON value});
+ '') prefs)}
+
+ ${extraPrefs}
+ '';
+
+in
+
+{
+ meta.maintainers = [ maintainers.rycee ];
+
+ imports = [
+ (mkRemovedOptionModule ["programs" "firefox" "enableGoogleTalk"]
+ "Support for this option has been removed.")
+ (mkRemovedOptionModule ["programs" "firefox" "enableIcedTea"]
+ "Support for this option has been removed.")
+ ];
+
+ options = {
+ programs.firefox = {
+ enable = mkEnableOption "Firefox";
+
+ package = mkOption {
+ type = types.package;
+ default =
+ if versionAtLeast config.home.stateVersion "19.09"
+ then pkgs.firefox
+ else pkgs.firefox-unwrapped;
+ defaultText = literalExample "pkgs.firefox";
+ description = ''
+ The Firefox package to use. If state versionĀ ā‰„Ā 19.09 then
+ this should be a wrapped Firefox package. For earlier state
+ versions it should be an unwrapped Firefox package.
+ '';
+ };
+
+ extensions = mkOption {
+ type = types.listOf types.package;
+ default = [];
+ example = literalExample ''
+ with pkgs.nur.repos.rycee.firefox-addons; [
+ https-everywhere
+ privacy-badger
+ ]
+ '';
+ description = ''
+ List of Firefox add-on packages to install. Some
+ pre-packaged add-ons are accessible from NUR,
+ <link xlink:href="https://github.com/nix-community/NUR"/>.
+ Once you have NUR installed run
+
+ <screen language="console">
+ <prompt>$</prompt> <userinput>nix-env -f '&lt;nixpkgs&gt;' -qaP -A nur.repos.rycee.firefox-addons</userinput>
+ </screen>
+
+ to list the available Firefox add-ons.
+
+ </para><para>
+
+ Note that it is necessary to manually enable these
+ extensions inside Firefox after the first installation.
+
+ </para><para>
+
+ Extensions listed here will only be available in Firefox
+ profiles managed through the
+ <link linkend="opt-programs.firefox.profiles">programs.firefox.profiles</link>
+ option. This is due to recent changes in the way Firefox
+ handles extension side-loading.
+ '';
+ };
+
+ profiles = mkOption {
+ type = types.attrsOf (types.submodule ({config, name, ...}: {
+ options = {
+ name = mkOption {
+ type = types.str;
+ default = name;
+ description = "Profile name.";
+ };
+
+ id = mkOption {
+ type = types.ints.unsigned;
+ default = 0;
+ description = ''
+ Profile ID. This should be set to a unique number per profile.
+ '';
+ };
+
+ settings = mkOption {
+ type = with types; attrsOf (either bool (either int str));
+ default = {};
+ example = literalExample ''
+ {
+ "browser.startup.homepage" = "https://nixos.org";
+ "browser.search.region" = "GB";
+ "browser.search.isUS" = false;
+ "distribution.searchplugins.defaultLocale" = "en-GB";
+ "general.useragent.locale" = "en-GB";
+ "browser.bookmarks.showMobileBookmarks" = true;
+ }
+ '';
+ description = "Attribute set of Firefox preferences.";
+ };
+
+ extraConfig = mkOption {
+ type = types.lines;
+ default = "";
+ description = ''
+ Extra preferences to add to <filename>user.js</filename>.
+ '';
+ };
+
+ userChrome = mkOption {
+ type = types.lines;
+ default = "";
+ description = "Custom Firefox user chrome CSS.";
+ example = ''
+ /* Hide tab bar in FF Quantum */
+ @-moz-document url("chrome://browser/content/browser.xul") {
+ #TabsToolbar {
+ visibility: collapse !important;
+ margin-bottom: 21px !important;
+ }
+
+ #sidebar-box[sidebarcommand="treestyletab_piro_sakura_ne_jp-sidebar-action"] #sidebar-header {
+ visibility: collapse !important;
+ }
+ }
+ '';
+ };
+
+ userContent = mkOption {
+ type = types.lines;
+ default = "";
+ description = "Custom Firefox user content CSS.";
+ example = ''
+ /* Hide scrollbar in FF Quantum */
+ *{scrollbar-width:none !important}
+ '';
+ };
+
+ path = mkOption {
+ type = types.str;
+ default = name;
+ description = "Profile path.";
+ };
+
+ isDefault = mkOption {
+ type = types.bool;
+ default = config.id == 0;
+ defaultText = "true if profile ID is 0";
+ description = "Whether this is a default profile.";
+ };
+ };
+ }));
+ default = {};
+ description = "Attribute set of Firefox profiles.";
+ };
+
+ enableAdobeFlash = mkOption {
+ type = types.bool;
+ default = false;
+ description = "Whether to enable the unfree Adobe Flash plugin.";
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ assertions = [
+ (
+ let
+ defaults =
+ catAttrs "name" (filter (a: a.isDefault) (attrValues cfg.profiles));
+ in {
+ assertion = cfg.profiles == {} || length defaults == 1;
+ message =
+ "Must have exactly one default Firefox profile but found "
+ + toString (length defaults)
+ + optionalString (length defaults > 1)
+ (", namely " + concatStringsSep ", " defaults);
+ }
+ )
+
+ (
+ let
+ duplicates =
+ filterAttrs (_: v: length v != 1)
+ (zipAttrs
+ (mapAttrsToList (n: v: { "${toString v.id}" = n; })
+ (cfg.profiles)));
+
+ mkMsg = n: v: " - ID ${n} is used by ${concatStringsSep ", " v}";
+ in {
+ assertion = duplicates == {};
+ message =
+ "Must not have Firefox profiles with duplicate IDs but\n"
+ + concatStringsSep "\n" (mapAttrsToList mkMsg duplicates);
+ }
+ )
+ ];
+
+ home.packages =
+ let
+ # The configuration expected by the Firefox wrapper.
+ fcfg = {
+ enableAdobeFlash = cfg.enableAdobeFlash;
+ };
+
+ # A bit of hackery to force a config into the wrapper.
+ browserName = cfg.package.browserName
+ or (builtins.parseDrvName cfg.package.name).name;
+
+ # The configuration expected by the Firefox wrapper builder.
+ bcfg = setAttrByPath [browserName] fcfg;
+
+ package =
+ if isDarwin then
+ cfg.package
+ else if versionAtLeast config.home.stateVersion "19.09" then
+ cfg.package.override { cfg = fcfg; }
+ else
+ (pkgs.wrapFirefox.override { config = bcfg; }) cfg.package { };
+ in
+ [ package ];
+
+ home.file = mkMerge (
+ [{
+ "${mozillaConfigPath}/${extensionPath}" = mkIf (cfg.extensions != []) {
+ source = "${extensionsEnvPkg}/share/mozilla/${extensionPath}";
+ recursive = true;
+ };
+
+ "${firefoxConfigPath}/profiles.ini" = mkIf (cfg.profiles != {}) {
+ text = profilesIni;
+ };
+ }]
+ ++ flip mapAttrsToList cfg.profiles (_: profile: {
+ "${profilesPath}/${profile.path}/chrome/userChrome.css" =
+ mkIf (profile.userChrome != "") {
+ text = profile.userChrome;
+ };
+
+ "${profilesPath}/${profile.path}/chrome/userContent.css" =
+ mkIf (profile.userContent != "") {
+ text = profile.userContent;
+ };
+
+ "${profilesPath}/${profile.path}/user.js" =
+ mkIf (profile.settings != {} || profile.extraConfig != "") {
+ text = mkUserJs profile.settings profile.extraConfig;
+ };
+
+ "${profilesPath}/${profile.path}/extensions" = mkIf (cfg.extensions != []) {
+ source = "${extensionsEnvPkg}/share/mozilla/${extensionPath}";
+ recursive = true;
+ force = true;
+ };
+ })
+ );
+ };
+}