1{ pkgs, config, lib, ... }:
2
3let
4 cfg = config.programs.firefox;
5
6 policyFormat = pkgs.formats.json { };
7
8 organisationInfo = ''
9 When this option is in use, Firefox will inform you that "your browser
10 is managed by your organisation". That message appears because NixOS
11 installs what you have declared here such that it cannot be overridden
12 through the user interface. It does not mean that someone else has been
13 given control of your browser, unless of course they also control your
14 NixOS configuration.
15 '';
16
17 # deprecated per-native-messaging-host options
18 nmhOptions = {
19 browserpass = {
20 name = "Browserpass";
21 package = pkgs.browserpass;
22 };
23 bukubrow = {
24 name = "Bukubrow";
25 package = pkgs.bukubrow;
26 };
27 euwebid = {
28 name = "Web eID";
29 package = pkgs.web-eid-app;
30 };
31 ff2mpv = {
32 name = "ff2mpv";
33 package = pkgs.ff2mpv;
34 };
35 fxCast = {
36 name = "fx_cast";
37 package = pkgs.fx-cast-bridge;
38 };
39 gsconnect = {
40 name = "GSConnect";
41 package = pkgs.gnomeExtensions.gsconnect;
42 };
43 jabref = {
44 name = "JabRef";
45 package = pkgs.jabref;
46 };
47 passff = {
48 name = "PassFF";
49 package = pkgs.passff-host;
50 };
51 tridactyl = {
52 name = "Tridactyl";
53 package = pkgs.tridactyl-native;
54 };
55 ugetIntegrator = {
56 name = "Uget Integrator";
57 package = pkgs.uget-integrator;
58 };
59 };
60in
61{
62 options.programs.firefox = {
63 enable = lib.mkEnableOption "the Firefox web browser";
64
65 package = lib.mkOption {
66 type = lib.types.package;
67 default = pkgs.firefox;
68 description = "Firefox package to use.";
69 defaultText = lib.literalExpression "pkgs.firefox";
70 relatedPackages = [
71 "firefox"
72 "firefox-beta-bin"
73 "firefox-bin"
74 "firefox-devedition-bin"
75 "firefox-esr"
76 ];
77 };
78
79 wrapperConfig = lib.mkOption {
80 type = lib.types.attrs;
81 default = {};
82 description = "Arguments to pass to Firefox wrapper";
83 };
84
85 policies = lib.mkOption {
86 type = policyFormat.type;
87 default = { };
88 description = ''
89 Group policies to install.
90
91 See [Mozilla's documentation](https://mozilla.github.io/policy-templates/)
92 for a list of available options.
93
94 This can be used to install extensions declaratively! Check out the
95 documentation of the `ExtensionSettings` policy for details.
96
97 ${organisationInfo}
98 '';
99 };
100
101 preferences = lib.mkOption {
102 type = with lib.types; attrsOf (oneOf [ bool int str ]);
103 default = { };
104 description = ''
105 Preferences to set from `about:config`.
106
107 Some of these might be able to be configured more ergonomically
108 using policies.
109
110 ${organisationInfo}
111 '';
112 };
113
114 preferencesStatus = lib.mkOption {
115 type = lib.types.enum [ "default" "locked" "user" "clear" ];
116 default = "locked";
117 description = ''
118 The status of `firefox.preferences`.
119
120 `status` can assume the following values:
121 - `"default"`: Preferences appear as default.
122 - `"locked"`: Preferences appear as default and can't be changed.
123 - `"user"`: Preferences appear as changed.
124 - `"clear"`: Value has no effect. Resets to factory defaults on each startup.
125 '';
126 };
127
128 languagePacks = lib.mkOption {
129 # Available languages can be found in https://releases.mozilla.org/pub/firefox/releases/${cfg.package.version}/linux-x86_64/xpi/
130 type = lib.types.listOf (lib.types.enum ([
131 "ach"
132 "af"
133 "an"
134 "ar"
135 "ast"
136 "az"
137 "be"
138 "bg"
139 "bn"
140 "br"
141 "bs"
142 "ca-valencia"
143 "ca"
144 "cak"
145 "cs"
146 "cy"
147 "da"
148 "de"
149 "dsb"
150 "el"
151 "en-CA"
152 "en-GB"
153 "en-US"
154 "eo"
155 "es-AR"
156 "es-CL"
157 "es-ES"
158 "es-MX"
159 "et"
160 "eu"
161 "fa"
162 "ff"
163 "fi"
164 "fr"
165 "fy-NL"
166 "ga-IE"
167 "gd"
168 "gl"
169 "gn"
170 "gu-IN"
171 "he"
172 "hi-IN"
173 "hr"
174 "hsb"
175 "hu"
176 "hy-AM"
177 "ia"
178 "id"
179 "is"
180 "it"
181 "ja"
182 "ka"
183 "kab"
184 "kk"
185 "km"
186 "kn"
187 "ko"
188 "lij"
189 "lt"
190 "lv"
191 "mk"
192 "mr"
193 "ms"
194 "my"
195 "nb-NO"
196 "ne-NP"
197 "nl"
198 "nn-NO"
199 "oc"
200 "pa-IN"
201 "pl"
202 "pt-BR"
203 "pt-PT"
204 "rm"
205 "ro"
206 "ru"
207 "sco"
208 "si"
209 "sk"
210 "sl"
211 "son"
212 "sq"
213 "sr"
214 "sv-SE"
215 "szl"
216 "ta"
217 "te"
218 "th"
219 "tl"
220 "tr"
221 "trs"
222 "uk"
223 "ur"
224 "uz"
225 "vi"
226 "xh"
227 "zh-CN"
228 "zh-TW"
229 ]));
230 default = [ ];
231 description = ''
232 The language packs to install.
233 '';
234 };
235
236 autoConfig = lib.mkOption {
237 type = lib.types.lines;
238 default = "";
239 description = ''
240 AutoConfig files can be used to set and lock preferences that are not covered
241 by the policies.json for Mac and Linux. This method can be used to automatically
242 change user preferences or prevent the end user from modifiying specific
243 preferences by locking them. More info can be found in https://support.mozilla.org/en-US/kb/customizing-firefox-using-autoconfig.
244 '';
245 };
246
247 nativeMessagingHosts = ({
248 packages = lib.mkOption {
249 type = lib.types.listOf lib.types.package;
250 default = [];
251 description = ''
252 Additional packages containing native messaging hosts that should be made available to Firefox extensions.
253 '';
254 };
255 }) // (builtins.mapAttrs (k: v: lib.mkEnableOption "${v.name} support") nmhOptions);
256 };
257
258 config = let
259 forEachEnabledNmh = fn: lib.flatten (lib.mapAttrsToList (k: v: lib.optional cfg.nativeMessagingHosts.${k} (fn k v)) nmhOptions);
260 in lib.mkIf cfg.enable {
261 warnings = forEachEnabledNmh (k: v:
262 "The `programs.firefox.nativeMessagingHosts.${k}` option is deprecated, " +
263 "please add `${v.package.pname}` to `programs.firefox.nativeMessagingHosts.packages` instead."
264 );
265 programs.firefox.nativeMessagingHosts.packages = forEachEnabledNmh (_: v: v.package);
266
267 environment.systemPackages = [
268 (cfg.package.override (old: {
269 extraPrefsFiles = old.extraPrefsFiles or [] ++ [(pkgs.writeText "firefox-autoconfig.js" cfg.autoConfig)];
270 nativeMessagingHosts = old.nativeMessagingHosts or [] ++ cfg.nativeMessagingHosts.packages;
271 cfg = (old.cfg or {}) // cfg.wrapperConfig;
272 }))
273 ];
274
275 environment.etc =
276 let
277 policiesJSON = policyFormat.generate "firefox-policies.json" { inherit (cfg) policies; };
278 in
279 lib.mkIf (cfg.policies != { }) {
280 "firefox/policies/policies.json".source = "${policiesJSON}";
281 };
282
283 # Preferences are converted into a policy
284 programs.firefox.policies = {
285 DisableAppUpdate = true;
286 Preferences = (builtins.mapAttrs
287 (_: value: { Value = value; Status = cfg.preferencesStatus; })
288 cfg.preferences);
289 ExtensionSettings = builtins.listToAttrs (builtins.map
290 (lang: lib.attrsets.nameValuePair
291 "langpack-${lang}@firefox.mozilla.org"
292 {
293 installation_mode = "normal_installed";
294 install_url = "https://releases.mozilla.org/pub/firefox/releases/${cfg.package.version}/linux-x86_64/xpi/${lang}.xpi";
295 }
296 )
297 cfg.languagePacks);
298 };
299 };
300
301 meta.maintainers = with lib.maintainers; [ danth ];
302}