Flake for my NixOS devices
1{
2 lib,
3 pkgs,
4 config,
5 ...
6}: let
7 package = pkgs.firefox-devedition;
8in {
9 options.cow.firefox = {
10 enable =
11 lib.mkEnableOption "Firefox with customizations"
12 // {
13 default = config.cow.gdi.enable;
14 };
15 };
16
17 config = lib.mkIf config.cow.firefox.enable {
18 cow.imperm.keep = [".mozilla"];
19
20 home.packages = with pkgs; [
21 nautilus # Needed for file dialogs?? Why??
22 ];
23
24 programs.firefox = {
25 inherit package;
26 enable = true;
27
28 policies = {
29 DisableTelemetry = true;
30 DisableFirefoxStudies = true;
31 DisableSetDesktopBackground = true;
32 DontCheckDefaultBrowser = true;
33 AppAutoUpdate = false;
34 DNSOverHTTPS.Enabled = true;
35 ShowHomeButton = true;
36 DisplayBookmarksToolbar = "never";
37 DisableProfileImport = true;
38 DisablePocket = true;
39 DisableFirefoxAccounts = true;
40 OfferToSaveLoginsDefault = false;
41 OverrideFirstRunPage = "";
42 NoDefaultBookmarks = true;
43 PasswordManagerEnabled = false;
44 SearchBar = "unified";
45 EncryptedMediaExtensions = true;
46
47 EnableTrackingProtection = {
48 Value = true;
49 Locked = true;
50 Cryptomining = true;
51 Fingerprinting = true;
52 EmailTracking = true;
53 };
54
55 Preferences = let
56 lock = val: {
57 Value = val;
58 Status = "locked";
59 };
60 in {
61 # General
62 "browser.aboutConfig.showWarning" = lock false;
63 "media.eme.enabled" = lock true; # Encrypted Media Extensions (DRM)
64 "layout.css.prefers-color-scheme.content-override" = lock 0;
65 "browser.startup.page" = 3;
66 "toolkit.telemetry.server" = lock "";
67
68 # New Tab
69 "browser.newtabpage.activity-stream.showSponsored" = lock false;
70 "browser.newtabpage.activity-stream.system.showSponsored" = lock false;
71 "browser.newtabpage.activity-stream.feeds.section.topstories" = lock false;
72 "browser.newtabpage.activity-stream.feeds.topsites" = lock false;
73 "browser.newtabpage.activity-stream.showSponsoredTopSites" = lock false;
74 "browser.newtabpage.activity-stream.showWeather" = lock false;
75 "browser.newtabpage.activity-stream.system.showWeather" = lock false;
76 "browser.newtabpage.activity-stream.feeds.weatherfeed" = lock false;
77 "browser.newtabpage.activity-stream.feeds.telemetry" = lock false;
78 "browser.newtabpage.activity-stream.telemetry" = lock false;
79 "browser.newtabpage.activity-stream.telemetry.structuredIngestion.endpoint" = lock "";
80 "browser.newtabpage.pinned" = lock [];
81 "browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts.havePinned" = lock "";
82 "browser.urlbar.suggest.weather" = lock false;
83 "browser.urlbar.quicksuggest.scenario" = lock "offline";
84 "browser.urlbar.suggest.quicksuggest.nonsponsored" = lock false;
85 "browser.urlbar.suggest.quicksuggest.sponsored" = lock false;
86
87 # Devtools
88 "devtools.theme" = lock "dark";
89 "devtools.dom.enabled" = lock true;
90 "devtools.command-button-rulers.enabled" = lock true;
91 "devtools.command-button-measure.enabled" = lock true;
92 "devtools.command-button-screenshot.enabled" = lock true;
93 "devtools.toolbox.host" = lock "right";
94 "devtools.webconsole.persistlog" = lock true;
95 "devtools.webconsole.timestampMessages" = lock true;
96
97 # Privacy
98 "dom.private-attribution.submission.enabled" = lock false;
99 "privacy.globalprivacycontrol.enabled" = lock true;
100
101 # ML
102 "browser.ml.enable" = lock false;
103 "browser.ml.linkPreview.enabled" = lock false;
104 "browser.ml.pageAssist.enabled" = lock false;
105 "browser.ml.chat.enabled" = lock false;
106 "browser.ml.chat.menu" = lock false;
107 "browser.ml.chat.page" = lock false;
108 "browser.ml.chat.shortcuts" = lock false;
109 "browser.ml.chat.sidebar" = lock false;
110 };
111
112 Extensions.Install =
113 map (x: "https://addons.mozilla.org/firefox/downloads/latest/${x}/latest.xpi")
114 (
115 [
116 # Appearance
117 "firefox-color"
118 "material-icons-for-github"
119
120 # Security / Privacy
121 "facebook-container"
122
123 ## Ads / Youtube
124 "ublock-origin"
125 "consent-o-matic"
126 "sponsorblock"
127
128 # Information
129 "flagfox"
130 "awesome-rss"
131 "identfavicon-quantum"
132
133 # Devtools
134 "react-devtools"
135 "open-graph-preview-and-debug"
136 "wave-accessibility-tool"
137 "style-us"
138 ]
139 ++ (lib.optional config.cow.keepassxc.enable "keepassxc-browser")
140 );
141
142 ExtensionSettings."*" = {
143 default_area = "menupanel";
144 };
145 };
146 profiles.dev-edition-default = {
147 extensions = {
148 force = true;
149 settings = {
150 "sponsorBlocker@ajay.app".settings.alreadyInstalled = true;
151 "uBlock0@raymondhill.net".settings.selectedFilterLists = [
152 "ublock-filters"
153 "ublock-badware"
154 "ublock-privacy"
155 "ublock-unbreak"
156 "ublock-quick-fixes"
157 "easylist"
158 "easyprivacy"
159 "urlhaus-1"
160 "plowe-0"
161 "adguard-spyware-url"
162 "fanboy-cookiemonster"
163 "ublock-cookies-easylist"
164 "easylist-annoyances"
165 "easylist-chat"
166 "easylist-newsletters"
167 "easylist-notifications"
168 "ublock-annoyances"
169 "IDN-0"
170 ];
171 # TODO: Stylus
172 # "{7a7a4a92-a2a0-41d1-9fd7-1e92480d612d}".force = true;
173 # "{7a7a4a92-a2a0-41d1-9fd7-1e92480d612d}".settings = let
174 # # Catppuccin-stylus import.json
175 # importJson = lib.importJSON inputs.cat-stylus.outPath;
176 #
177 # # Gen the path to update a given user style config value
178 # updateVar = var: val: {
179 # path = [
180 # "usercssData"
181 # "vars"
182 # var
183 # "value"
184 # ];
185 # update = old: val;
186 # };
187 #
188 # # Create function for setting user style options according to catppuccin config
189 # cat = config.catppuccin;
190 # configureStyle = lib.updateManyAttrsByPath [
191 # (updateVar "lightFlavor" cat.flavor)
192 # (updateVar "darkFlavor" cat.flavor)
193 # (updateVar "accentColor" cat.accent)
194 # ];
195 #
196 # # No
197 # md5ToUuidThisIsVeryBad = md5: let
198 # first = builtins.substring 0 8 md5;
199 # second = builtins.substring 8 4 md5;
200 # third = builtins.substring 12 4 md5;
201 # fourth = builtins.substring 16 4 md5;
202 # fifth = builtins.substring 20 12 md5;
203 # in "${first}-${second}-${third}-${fourth}-${fifth}";
204 #
205 # # Create a Stylus DB entry for a given style using the digest as an identifier
206 # mkStylePair = style: let
207 # id = md5ToUuidThisIsVeryBad style.originalDigest;
208 # in {
209 # name = "style-${id}";
210 # value =
211 # (configureStyle style)
212 # // {
213 # inherit id;
214 # _id = id;
215 # # Stylus code says Date.now() for rev, we'll just set it to 0?
216 # _rev = 0;
217 # };
218 # };
219 #
220 # # The first elem of the import.json is settings for Stylus, we'll set those ourselves
221 # generatedStyles = builtins.listToAttrs (builtins.map mkStylePair (builtins.tail importJson));
222 #
223 # # Setting we need to set manually
224 # extensionDb =
225 # generatedStyles
226 # // {
227 # lastUpdateTime = 0;
228 # dbInChromeStorage = true;
229 # settings = {
230 # patchCsp = true;
231 # updateInterval = 0;
232 # updateOnlyEnabled = true;
233 # styleViaXhr = true;
234 # };
235 # };
236 # in
237 # extensionDb;
238 };
239 };
240 search = {
241 force = true;
242 default = "ddg";
243 privateDefault = "ddg";
244 engines = let
245 mkEngineForceFavicon = aliases: queryUrl: iconUrl: {
246 definedAliases = aliases;
247 icon = iconUrl;
248 urls = [{template = queryUrl;}];
249 };
250 mkEngine = aliases: queryUrl: iconExt: (mkEngineForceFavicon aliases queryUrl (
251 let
252 noPath = lib.strings.concatStrings (
253 lib.strings.intersperse "/" (lib.lists.take 3 (lib.strings.splitString "/" queryUrl))
254 );
255 in "${noPath}/favicon.${iconExt}"
256 ));
257 mkModrinth = aliases: type: mkEngine aliases "https://modrinth.com/discover/${type}?q={searchTerms}" "ico";
258 in {
259 # Dev
260 "GitHub Repos" =
261 mkEngineForceFavicon ["@gh" "@github"]
262 "https://github.com/search?type=repositories&q={searchTerms}"
263 "https://github.githubassets.com/favicons/favicon-dark.svg";
264 "SourceGraph" = mkEngine [
265 "@sg"
266 "@sourcegraph"
267 ] "https://sourcegraph.com/search?q={searchTerms}" "png";
268
269 ## Web
270 "MDN Web Docs" = mkEngine [
271 "@mdn"
272 ] "https://developer.mozilla.org/en-US/search?q={searchTerms}" "ico";
273 "Web.Dev" =
274 mkEngineForceFavicon ["@webdev" "@lighthouse"] "https://web.dev/s/results?q={searchTerms}"
275 "https://www.gstatic.com/devrel-devsite/prod/vc7080045e84cd2ce1faf7f7a3876037748d52d088e5100df2e949d051a784791/web/images/favicon.png";
276 "Can I Use" = mkEngineForceFavicon [
277 "@ciu"
278 "@baseline"
279 ] "https://caniuse.com/?search={searchTerms}" "https://caniuse.com/img/favicon-128.png";
280 "NPM" = mkEngine ["@npm"] "https://www.npmx.dev/search?q={searchTerms}" "ico";
281 "Iconify" = mkEngine [
282 "@iconify"
283 "@icons"
284 ] "https://icon-sets.iconify.design/?query={searchTerms}" "ico";
285 "Astro" = mkEngineForceFavicon [
286 "@astro"
287 ] "https://a.stro.cc/{searchTerms}" "https://docs.astro.build/favicon.svg";
288 "Porkbun" = mkEngine ["@porkbun"] "https://porkbun.com/checkout/search?q={searchTerms}" "ico";
289 "Http.Cat" = mkEngine ["@cat" "@hcat" "@httpcat"] "https://http.cat/{searchTerms}" "ico";
290
291 ## Rust
292 "Crates.io" = mkEngine [
293 "@crates"
294 "@cratesio"
295 "@cargo"
296 ] "https://crates.io/search?q={searchTerms}" "ico";
297 "Rust Docs" =
298 mkEngineForceFavicon ["@rust" "@rustdocs" "@ruststd"]
299 "https://doc.rust-lang.org/std/index.html?search={searchTerms}"
300 "https://doc.rust-lang.org/static.files/favicon-2c020d218678b618.svg";
301 "Docsrs" = mkEngine ["@docsrs"] "https://docs.rs/releases/search?query={searchTerms}" "ico";
302
303 ## Python
304 "PyPI" = mkEngineForceFavicon [
305 "@pypi"
306 "@pip"
307 ] "https://pypi.org/search/?q={searchTerms}" "https://pypi.org/static/images/favicon.35549fe8.ico";
308
309 ## .NET
310 "NuGet" = mkEngine ["@nuget"] "https://www.nuget.org/packages?q={searchTerms}" "ico";
311
312 ## Linux Stuff
313 "Kernel Docs" = mkEngine [
314 "@lnx"
315 "@linux"
316 "@kernel"
317 ] "https://www.kernel.org/doc/html/latest/search.html?q={searchTerms}" "ico";
318 "Arch Wiki" = mkEngine [
319 "@aw"
320 "@arch"
321 ] "https://wiki.archlinux.org/index.php?title=Special%3ASearch&search={searchTerms}" "ico";
322 "Nerd Fonts" =
323 mkEngineForceFavicon ["@nf" "@nerdfonts"] "https://www.nerdfonts.com/cheat-sheet?q={searchTerms}"
324 "https://www.nerdfonts.com/assets/img/favicon.ico";
325
326 ### Haskell
327 "Hoogle Base" = mkEngine [
328 "@h"
329 "@hoogle"
330 ] "https://hoogle.haskell.org/?scope=package%3Abase&hoogle={searchTerms}" "png";
331 "Hoogle All" = mkEngine [
332 "@ha"
333 "@hoogall"
334 ] "https://hoogle.haskell.org/?hoogle={searchTerms}" "png";
335
336 ### Nix
337 "Searchix Combined" = mkEngine [
338 "@n"
339 "@nixall"
340 ] "https://search.nix.ee/?query={searchTerms}" "ico";
341 "Nix Packages" = mkEngine [
342 "@nixpkgs"
343 ] "https://search.nix.ee/packages/nixpkgs/search?query={searchTerms}" "ico";
344 "NixOS Options" = mkEngine [
345 "@nixos"
346 ] "https://search.nix.ee/options/nixos/search?query={searchTerms}" "ico";
347 "NixOS Wiki" = mkEngine ["@nixwiki"] "https://nixos.wiki/index.php?search={searchTerms}" "png";
348 "Home Manager Options" = mkEngine [
349 "@hm"
350 ] "https://search.nix.ee/options/home-manager/search?query={searchTerms}" "ico";
351 "Noogle" = mkEngine [
352 "@noogle"
353 "@nixlib"
354 ] "https://docs.nix.ee/q/?term={searchTerms}" "png";
355 "SourceGraph Nix" =
356 mkEngine ["@sgn" "@yoink"]
357 "https://sourcegraph.com/search?q=lang:Nix+-repo:NixOS/*+-repo:nix-community/*+{searchTerms}"
358 "png";
359 "Nixpkgs Issues" =
360 mkEngineForceFavicon ["@nixissues"]
361 "https://github.com/NixOS/nixpkgs/issues?q=sort%3Aupdated-desc+is%3Aissue+is%3Aopen+{searchTerms}"
362 "https://github.githubassets.com/favicons/favicon-dark.svg";
363 "NixVim Options" =
364 mkEngineForceFavicon ["@nixvim"]
365 "https://nix-community.github.io/nixvim/search/?option_scope=0&query={searchTerms}"
366 "https://nix-community.github.io/nixvim/search/favicon.ico";
367
368 # Media
369 "youtube" = mkEngine ["@yt"] "https://www.youtube.com/results?search_query={searchTerms}" "ico";
370 "Spotify" =
371 mkEngineForceFavicon ["@sp" "@spotify"] "https://open.spotify.com/search/{searchTerms}"
372 "https://open.spotifycdn.com/cdn/images/favicon16.1c487bff.png";
373 "Netflix" = mkEngine ["@nfx"] "https://www.netflix.com/search?q={searchTerms}" "ico";
374 "IMDb" = mkEngine ["@imdb"] "https://www.imdb.com/find?q={searchTerms}" "ico";
375
376 # Minecraft
377 "Modrinth" = mkModrinth ["@mr"] "mods";
378 "Modrinth Resource Packs" = mkModrinth ["@mrr"] "resourcepacks";
379 "Modrinth Data Packs" = mkModrinth ["@mrd"] "datapacks";
380
381 # Misc
382 "Firefox Add-ons" = mkEngine [
383 "@addons"
384 ] "https://addons.mozilla.org/en-US/firefox/search/?q={searchTerms}" "ico";
385 "Urban Dictionary" = mkEngine [
386 "@ud"
387 "@urban"
388 ] "https://www.urbandictionary.com/define.php?term={searchTerms}" "ico";
389 "Google Translate" = mkEngine [
390 "@translate"
391 ] "https://translate.google.com/?sl=auto&tl=en&text={searchTerms}&op=translate" "ico";
392
393 # Overrides
394 "History".metaData.alias = "@h";
395 "Bookmarks".metaData.alias = "@b";
396 "Tabs".metaData.alias = "@t";
397 "bing".metaData.hidden = true;
398 "amazondotcom-us".metaData.alias = "@amz";
399 "google".metaData.alias = "@g";
400 "wikipedia".metaData.alias = "@w";
401 "ddg".metaData.alias = "@ddg";
402 };
403 };
404 };
405 };
406 };
407}