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