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