From 118a42745c822f3d95536f31c4fb2c2feea11200 Mon Sep 17 00:00:00 2001 From: "Gustavo \"Guz\" L. de Mello" Date: Sat, 13 Jan 2024 18:58:54 -0300 Subject: [PATCH] feat: librewolf configuration --- flake.lock | 39 ++ flake.nix | 5 + hosts/desktop/default/home.nix | 1 + hosts/desktop/shared-home.nix | 26 +- hosts/desktop/work/home.nix | 19 + .../programs/librewolf/default.nix | 415 ++++++++++++++++++ .../programs/librewolf/search.json.mozlz4 | Bin 0 -> 2164 bytes 7 files changed, 504 insertions(+), 1 deletion(-) create mode 100644 modules/home-manager/programs/librewolf/default.nix create mode 100644 modules/home-manager/programs/librewolf/search.json.mozlz4 diff --git a/flake.lock b/flake.lock index d9c9cad..7560644 100644 --- a/flake.lock +++ b/flake.lock @@ -16,6 +16,44 @@ "type": "github" } }, + "firefox-addons": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "dir": "pkgs/firefox-addons", + "lastModified": 1705103913, + "narHash": "sha256-PX6zS6uni5IXZMUQB2DUbhj+oV7QyAfwEEenOb/DstU=", + "owner": "rycee", + "repo": "nur-expressions", + "rev": "c8e94a42015531a061a4518aff7aee03d5a4f215", + "type": "gitlab" + }, + "original": { + "dir": "pkgs/firefox-addons", + "owner": "rycee", + "repo": "nur-expressions", + "type": "gitlab" + } + }, + "flake-utils": { + "locked": { + "lastModified": 1629284811, + "narHash": "sha256-JHgasjPR0/J1J3DRm4KxM4zTyAj4IOJY8vIl75v/kPI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c5d161cc0af116a2e17f54316f0bf43f0819785c", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "flatpaks": { "locked": { "lastModified": 1704403850, @@ -139,6 +177,7 @@ }, "root": { "inputs": { + "firefox-addons": "firefox-addons", "flatpaks": "flatpaks", "home-manager": "home-manager", "nix-colors": "nix-colors", diff --git a/flake.nix b/flake.nix index d10c97f..04171e0 100644 --- a/flake.nix +++ b/flake.nix @@ -26,6 +26,11 @@ # Used for theming the OS, see modules/home-manager/theme.nix nix-colors.url = "github:misterio77/nix-colors"; + firefox-addons = { + url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + # Necessary for modules/home-manager/programs/tmux.nix tmux-plugin-manager = { url = "github:tmux-plugins/tpm"; diff --git a/hosts/desktop/default/home.nix b/hosts/desktop/default/home.nix index 59b3492..a91aa14 100644 --- a/hosts/desktop/default/home.nix +++ b/hosts/desktop/default/home.nix @@ -4,4 +4,5 @@ imports = [ ../shared-home.nix ]; + librewolf.profiles.guz.isDefault = true; } diff --git a/hosts/desktop/shared-home.nix b/hosts/desktop/shared-home.nix index 456496a..b85456e 100644 --- a/hosts/desktop/shared-home.nix +++ b/hosts/desktop/shared-home.nix @@ -4,6 +4,7 @@ imports = [ ../../modules/home-manager/theme.nix ../../modules/home-manager/config/terminal.nix + ../../modules/home-manager/programs/librewolf ./wm.nix ./keybinds.nix ]; @@ -15,9 +16,32 @@ ''; }; + librewolf = { + enable = true; + profiles = { + guz = { + id = 0; + settings = { + "webgl.disabled" = false; + "browser.startup.homepage" = "https://search.brave.com"; + "privacy.clearOnShutdown.history" = false; + "privacy.clearOnShutdown.downloads" = false; + "extensions.activeThemeID" = "firefox-compact-dark@mozilla.org"; + "privacy.clearOnShutdown.cookies" = false; + }; + extensions = with inputs.firefox-addons.packages."x86_64-linux"; [ + darkreader + canvasblocker + smart-referer + ]; + }; + }; + }; + services.flatpak.packages = [ "nz.mega.MEGAsync" "md.obsidian.Obsidian" + "dev.vencord.Vesktop" ]; # services.flatpak.overrides = { }; @@ -25,7 +49,7 @@ nixpkgs.config.allowUnfreePredicate = _: true; home.packages = with pkgs; [ ## Programs - firefox + # firefox # (pkgs.writeShellScriptBin "my-hello" '' # echo "Hello, ${config.home.username}!" diff --git a/hosts/desktop/work/home.nix b/hosts/desktop/work/home.nix index f96f3cf..7e01a6d 100644 --- a/hosts/desktop/work/home.nix +++ b/hosts/desktop/work/home.nix @@ -7,4 +7,23 @@ theme.accent = "94e2d5"; wm.wallpaper = ../../../static/guz-wallpaper-work.webp; + librewolf.profiles.work = { + isDefault = true; + id = 1; + settings = { + "webgl.disabled" = false; + "browser.startup.homepage" = "https://github.com"; + "privacy.clearOnShutdown.history" = false; + "privacy.clearOnShutdown.downloads" = false; + "extensions.activeThemeID" = "firefox-compact-dark@mozilla.org"; + "privacy.clearOnShutdown.cookies" = false; + }; + extensions = with inputs.firefox-addons.packages."x86_64-linux"; [ + darkreader + canvasblocker + smart-referer + github-file-icons + ]; + }; + } diff --git a/modules/home-manager/programs/librewolf/default.nix b/modules/home-manager/programs/librewolf/default.nix new file mode 100644 index 0000000..721068f --- /dev/null +++ b/modules/home-manager/programs/librewolf/default.nix @@ -0,0 +1,415 @@ +/* + THIS FILE ISN'T LICENSED UNDER THE WTFPL LICENSE. + + This file is copied from Home-manager's GitHub and was modified to suit my + (Gustavo "Guz" L. de Mello) personal needs. The original file can be found + here: https://github.com/nix-community/home-manager/blob/master/modules/programs/firefox.nix + + Said file is licensed under the MIT License, which a copy is written below: + + MIT License + + Copyright (c) 2017-2023 Home Manager contributors + Copyright (c) 2023-present Gustavo "Guz" L. de Mello + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +{ inputs, config, lib, pkgs, ... }: + +with lib; +let + cfg = config.librewolf; + + jsonFormat = pkgs.formats.json { }; + + firefoxConfigPath = ".librewolf"; + profilesPath = firefoxConfigPath; + + # The extensions path shared by all profiles; will not be supported + # by future Firefox versions. + extensionPath = "extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"; + + profiles = flip mapAttrs' cfg.profiles + (_: profile: + nameValuePair "Profile${toString profile.id}" { + Name = profile.name; + Path = profile.path; + IsRelative = 1; + Default = if profile.isDefault then 1 else 0; + }) // { + General = { StartWithLastProfile = 1; }; + }; + + profilesIni = generators.toINI { } profiles; + + userPrefValue = pref: + builtins.toJSON (if isBool pref || isInt pref || isString pref then + pref + else + builtins.toJSON pref); + + mkUserJs = prefs: extraPrefs: bookmarks: + let + prefs' = lib.optionalAttrs ([ ] != bookmarks) + { + "browser.bookmarks.file" = toString (firefoxBookmarksFile bookmarks); + "browser.places.importBookmarksHTML" = true; + } // prefs; + in + '' + // Generated by Home Manager. + + ${concatStrings (mapAttrsToList (name: value: '' + user_pref("${name}", ${userPrefValue value}); + '') prefs')} + + ${extraPrefs} + ''; + + mkContainersJson = containers: + let + containerToIdentity = _: container: { + userContextId = container.id; + name = container.name; + icon = container.icon; + color = container.color; + public = true; + }; + in + '' + ${builtins.toJSON { + version = 4; + lastUserContextId = + elemAt (mapAttrsToList (_: container: container.id) containers) 0; + identities = mapAttrsToList containerToIdentity containers; + }} + ''; + + firefoxBookmarksFile = bookmarks: + let + indent = level: + lib.concatStringsSep "" (map (lib.const " ") (lib.range 1 level)); + + bookmarkToHTML = indentLevel: bookmark: + '' + ${indent indentLevel}
${escapeXML bookmark.name}''; + + directoryToHTML = indentLevel: directory: '' + ${indent indentLevel}
${ + if directory.toolbar then + '' +

Bookmarks Toolbar'' + else + ''

${escapeXML directory.name}'' + }

+ ${indent indentLevel}

+ ${allItemsToHTML (indentLevel + 1) directory.bookmarks} + ${indent indentLevel}

''; + + itemToHTMLOrRecurse = indentLevel: item: + if item ? "url" then + bookmarkToHTML indentLevel item + else + directoryToHTML indentLevel item; + + allItemsToHTML = indentLevel: bookmarks: + lib.concatStringsSep "\n" + (map (itemToHTMLOrRecurse indentLevel) bookmarks); + + bookmarkEntries = allItemsToHTML 1 bookmarks; + in + pkgs.writeText "firefox-bookmarks.html" '' + + + + Bookmarks +

Bookmarks Menu

+

+ ${bookmarkEntries} +

+ ''; + + mkNoDuplicateAssertion = entities: entityKind: + ( + let + # Return an attribute set with entity IDs as keys and a list of + # entity names with corresponding ID as value. An ID is present in + # the result only if more than one entity has it. The argument + # entities is a list of AttrSet of one id/name pair. + findDuplicateIds = entities: + filterAttrs (_entityId: entityNames: length entityNames != 1) + (zipAttrs entities); + + duplicates = findDuplicateIds (mapAttrsToList + (entityName: entity: { "${toString entity.id}" = entityName; }) + entities); + + mkMsg = entityId: entityNames: + " - ID ${entityId} is used by " + concatStringsSep ", " entityNames; + in + { + assertion = duplicates == { }; + message = '' + Must not have a Firefox ${entityKind} with an existing ID but + '' + concatStringsSep "\n" (mapAttrsToList mkMsg duplicates); + } + ); +in +{ + options.librewolf = with lib; with lib.types; { + enable = mkEnableOption "Enable module"; + overrides = mkOption { + default = { }; + type = attrsOf (either bool (either int str)); + }; + profiles = mkOption { + type = attrsOf (submodule ({ config, name, ... }: { + options = { + name = mkOption { + type = str; + default = name; + }; + id = mkOption { + type = ints.unsigned; + default = 0; + }; + settings = mkOption { + type = attrsOf (jsonFormat.type // { + description = ""; + }); + default = { }; + }; + extraConfig = mkOption { + type = lines; + default = ""; + }; + userChrome = mkOption { + type = lines; + default = ""; + }; + userContent = mkOption { + type = lines; + default = ""; + }; + bookmarks = mkOption + { + type = + let + bookmarkSubmodule = submodule + ({ config, name, ... }: { + options = { + name = mkOption { + type = str; + default = name; + }; + tags = mkOption { + type = listOf str; + default = [ ]; + }; + keyword = mkOption { + type = nullOr str; + default = null; + }; + url = mkOption { + type = str; + }; + }; + }); + bookmarkType = addCheck bookmarkSubmodule (x: x ? "url"); + + directoryType = submodule ({ config, name, ... }: { + options = { + name = mkOption { + type = str; + default = name; + }; + bookmarks = mkOption { + type = listOf nodeType; + default = [ ]; + }; + toolbar = mkOption { + type = bool; + default = false; + }; + }; + }); + + nodeType = either bookmarkType directoryType; + in + with types; + coercedTo (attrsOf nodeType) attrValues (listOf nodeType); + default = [ ]; + }; + path = mkOption { + type = str; + default = name; + }; + isDefault = mkOption { + type = bool; + default = config.id == 0; + }; + # For some reason Librewolf isn't working with the generated file, so + # a static one is passed as a temp fix. + search.file = mkOption { + type = path; + default = ./search.json.mozlz4; + }; + /* + search = { + force = mkOption { + type = bool; + default = false; + }; + default = mkOption { + type = nullOr str; + default = null; + }; + privateDefault = mkOption { + type = nullOr str; + default = null; + }; + order = mkOption { + type = uniq (listOf str); + default = [ ]; + }; + engines = mkOption { + type = attrsOf (attrsOf jsonFormat.type); + default = { }; + }; + }; + */ + containers = mkOption { + type = attrsOf + (submodule ({ name, ... }: { + options = { + name = mkOption { + type = str; + default = name; + }; + id = mkOption { + type = ints.unsigned; + default = 0; + }; + color = mkOption { + type = enum [ + "blue" + "turquoise" + "green" + "yellow" + "orange" + "red" + "pink" + "purple" + "toolbar" + ]; + default = "pink"; + }; + icon = mkOption { + type = enum [ + "briefcase" + "cart" + "circle" + "dollar" + "fence" + "fingerprint" + "gift" + "vacation" + "food" + "fruit" + "pet" + "tree" + "chill" + ]; + default = "fruit"; + }; + }; + })); + default = { }; + }; + extensions = mkOption { + type = listOf package; + default = [ ]; + }; + }; + })); + default = { }; + }; + }; + config = lib.mkIf cfg.enable { + programs.librewolf.enable = true; + programs.librewolf.settings = cfg.overrides; + + home.file = mkMerge ([{ + "${firefoxConfigPath}/profiles.ini" = + mkIf (cfg.profiles != { }) { text = profilesIni; force = true; }; + }] ++ flip mapAttrsToList cfg.profiles (_: profile: { + "${profilesPath}/${profile.path}/.keep".text = ""; + + "${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 != "" || profile.bookmarks != [ ]) + { + text = + mkUserJs profile.settings profile.extraConfig profile.bookmarks; + }; + + "${profilesPath}/${profile.path}/containers.json" = + mkIf (profile.containers != { }) { + text = mkContainersJson profile.containers; + }; + + "${profilesPath}/${profile.path}/search.json.mozlz4" = { + force = true; + source = ./search.json.mozlz4; # Use static file, because for some reason this isn't working with Librewolf. + }; + + "${profilesPath}/${profile.path}/extensions" = + mkIf (profile.extensions != [ ]) { + source = + let + extensionsEnvPkg = pkgs.buildEnv { + name = "hm-firefox-extensions"; + paths = profile.extensions; + }; + in + "${extensionsEnvPkg}/share/mozilla/${extensionPath}"; + recursive = true; + force = true; + }; + })); + + }; +} diff --git a/modules/home-manager/programs/librewolf/search.json.mozlz4 b/modules/home-manager/programs/librewolf/search.json.mozlz4 new file mode 100644 index 0000000000000000000000000000000000000000..f050ceee119bff137a2560bf2024a1c0a61912df GIT binary patch literal 2164 zcmd1JukxufF<`jQ&%p4-zFMg)wWv5VKTpZZQb#E@FFi9awOGk2x>_kSMafF3JTp79 zAT=d3(V;jsu_!r1FE_s`GbbleFTW@~B{eOvG^a#KM=3rpF*jAoN-12AAwWSRHBVEL z;j?yTv136&Kv8~KW=d*`l2u7jX{wG=d~Rwv9TgT8xyIfHOYMrKM%YThIU=2iwV!wQCig8ZD! zMj9=vna?-uibBc^JBU1b`vr0@{ilSUH5?#Zc_07x;Q_aH6 z%1To7eY6X+tIBPawlK(>X)^MBWHd=nEzwI(RM1FHEGS9NNc_aaY|O|n!@$Hcje%d0 zNmk6rmhro2ieYk+frX`ouA#A^k*-OSiGgmCk%ft_S*oFtg|Vrzsew`2E=EVEqQtU9 zMviKR1sNqJ1;w$+DS3KvOb*EzdP!;wL3+vgx%ylT4=ZwWlysC*Qj3#|G7Cy%S(v;S z1QcqRKJX`JSSb_~WtJtDr0OVS=B1<-q~@ih=9TCukF3k~v7vQkP( zEJ?J=%uP&B)i20Pw@ykdPBk;p$qaMy4=OkCc2CcDbaZs|3l7b24NZ4+badutc;J}s z?C9(0=;-8H;92A@#PA_7&&|m<%r(p-*|j{vDc#Z7B``9aF&aH zScrK=M2N9zVvdhlijj{+rbm)VPJV=GzG<3yv3G<)xw)}^m2Z-PL9xERp|82ANvVgq znRb<-ML>wLWm=lPWm<@Zc3G9azP_bdo|9S81BMThZV^GjAvwN|j^zeXUM@kN;qGBZ z+1|mW<;gxFhN;G7+WO_$`ME)XqKqH@|JTjW&T$P43o^ z2+c_>4o!D3v~BL3yab> zb_(;)tV#`WH!N^3D@zIrD9tHN3Cz_mi!##I&kGF8D6{nRb%`*m$aT%O2+A_9EUAo$ zNY2X)i7@f^DAYD9swyrmiYzED_3|<=&ouDJcMNlM^+-uB_izjgGjI%dG!jF*DQ-GE6Zk^eXU3&y4ae^vk#K&CfC@ zig2x}%qUAQaqueNOG*#& z%t><%@D5J5(9cbAG%&4*^hgV|)DE%m%QZCg)OO1v33c)G_bgAZa!)Hv(>C$+$u2AjHt}`NkID&6 za|tUfjtorlat?M3j0p9p4Dj?b@pmgOH1`WBb@neZh)6BTG6>A@Dt9$;%FxduTCiZH0K)b}^?GROcTm7bn%`s&;0-Y|4GudG2AR)*_qimKgeX8 zo25tQMS7SP`S>OJrWjZxxfDcb`xX|J<^+40C+21QmZqf|XM_b>rc1Lh>vIWMgfSSE z7UhWX1Qa9|CFXK71jgzp6{U(YJdD**DoM>P$Vn^#)grMRwpRN3(Hu;I3{Liiw$)q= z^FvaLa*Jz~YIQ;xH1{SJWa<}}rl+SCmqalH=qQy`7EER+NGvGG$xKc>$ziNtp{vjE zks&ibuUI>)I6qIRHdaR|{w>2-PLIsI5+$p=(wrO}rTCK6oYdUZlA=n_6cGlew9K5; zN8HS+3=Ju%X_Dk{A2Rs6tF!O9OlYvx^E- z{Q`YOnI@GMrv@jMrKb3A=ViLc8<3NqoS2ivn2?&M8yc)6#iWp)d5%F$NrkU6IU_MI zFEvMmp(wSYAhjqncMbzX5!VNX%;J)wd`}l8E2X^5iu__>2BuU#LD!jl3|)-;Ox&W( zRSYba49v{TA7rA^i;ByGU4sfdJ^hjjN|IdzoZTv%Qv8flJqq;QBYoT)Q@l$&f{aqq p9N#f8Kj)HnX=PC5cVJ-V?_p53Pb?_tU|`^v=VuSdDN(Ae1ppI)se1qb literal 0 HcmV?d00001