zen.nix (4987B)
1 # modules/home/zen.nix — Zen Browser, the default browser, sharing one 2 # bookmarks file with Floorp. 3 # 4 # This module owns xdg.mimeApps for links and HTML and $BROWSER; the Niri and 5 # Hyprland browser binds launch zen-beta too. Floorp stays installed 6 # (modules/home/floorp.nix); to go back, move those settings to it. 7 # 8 # Zen is not in nixpkgs, so the package comes from the community flake 9 # (inputs.zen-browser, pinned in flake.nix). `packages.default` is the general 10 # release channel — the binary is literally `zen-beta` and versions carry a `b`, 11 # which is how upstream labels its releases; `twilight` is the nightly. 12 # 13 # The profile is written by hand under ~/.zen, for the same reason as Floorp: 14 # Zen's application.ini declares `Profile=zen`, so Gecko reads ~/.zen rather 15 # than anywhere home-manager's Firefox-family modules would look. 16 # 17 # Bookmarks are NOT duplicated. The one encrypted export at 18 # secrets/floorp/bookmarks.html (111 links, 19 folders, matching the live Floorp 19 # profile) is declared here a second time under its own name so this module does 20 # not depend on floorp.nix being imported. Edit it once with 21 # `TMPDIR=/dev/shm sops secrets/floorp/bookmarks.html` and both browsers see it. 22 # 23 # Prefs live in Nix here, not sops, because nothing in them is private yet — 24 # only the start page and the bookmark-file path. If this grows personal prefs, 25 # move it to secrets/zen/user.js and mirror the sops.secrets block floorp.nix 26 # uses. 27 { ... }: 28 { 29 flake.homeModules.zen = 30 { config, lib, pkgs, inputs, ... }: 31 let 32 profile = "daemon"; 33 profileDir = ".zen/${profile}"; 34 zen = inputs.zen-browser.packages.${pkgs.stdenv.hostPlatform.system}.default; 35 bookmarksPath = config.sops.secrets."zen-bookmarks.html".path; 36 in 37 { 38 home.packages = [ zen ]; 39 40 # Zen as the handler for links and HTML. 41 xdg.mimeApps = { 42 enable = true; 43 defaultApplications = lib.genAttrs [ 44 "text/html" 45 "application/xhtml+xml" 46 "x-scheme-handler/http" 47 "x-scheme-handler/https" 48 "x-scheme-handler/about" 49 "x-scheme-handler/unknown" 50 ] (_: [ "zen-beta.desktop" ]); 51 }; 52 53 home.sessionVariables.BROWSER = "zen-beta"; 54 55 # The same encrypted export Floorp imports, under its own secret name so 56 # neither module needs the other. sops-nix is happy for two secrets to come 57 # from one sopsFile; they decrypt to separate runtime paths. 58 sops.secrets."zen-bookmarks.html" = { 59 sopsFile = ../../secrets/floorp/bookmarks.html; 60 format = "binary"; 61 }; 62 63 home.file = { 64 # Written here rather than left to Zen so the Nix-built profile is the 65 # default one. Trade-off, as with Floorp: profile changes made in Zen's 66 # own profile manager are reverted on the next `nh os switch`. 67 ".zen/profiles.ini".text = '' 68 [Profile0] 69 Name=${profile} 70 IsRelative=1 71 Path=${profile} 72 Default=1 73 74 [General] 75 StartWithLastProfile=1 76 Version=2 77 ''; 78 79 # browser.places.importBookmarksHTML is deliberately absent: see the 80 # activation script below for why it cannot live in user.js. 81 "${profileDir}/user.js".text = '' 82 // Managed by modules/home/zen.nix. Zen reads this only at startup. 83 user_pref("browser.bookmarks.file", "${bookmarksPath}"); 84 // Don't let Zen's shipped default bookmarks compete with the import. 85 user_pref("browser.bookmarks.restore_default_bookmarks", false); 86 user_pref("browser.startup.homepage", "https://startpage.daemon-sec.xyz/"); 87 // No first-run tour or import wizard racing the seeded import. 88 user_pref("browser.aboutwelcome.enabled", false); 89 user_pref("browser.startup.firstrunSkipsHomepage", true); 90 user_pref("datareporting.policy.firstRunURL", ""); 91 ''; 92 }; 93 94 # One-time bookmark import, same mechanism floorp.nix documents. 95 # 96 # `browser.places.importBookmarksHTML` is what makes Gecko read 97 # browser.bookmarks.file into the places database. It cannot live in 98 # user.js: the browser consumes it and sets it back to false, but user.js 99 # re-applies every pref at every startup, so the import would run again on 100 # each launch and duplicate all 111 bookmarks. Seeding it into prefs.js 101 # instead, only while the profile has no places.sqlite yet, imports once on 102 # first launch and never again. 103 home.activation.zenSeedBookmarkImport = lib.hm.dag.entryAfter [ "writeBoundary" ] '' 104 zenProfile="$HOME/${profileDir}" 105 zenPrefs="$zenProfile/prefs.js" 106 if [ ! -e "$zenProfile/places.sqlite" ] \ 107 && ! grep -qs 'browser.places.importBookmarksHTML' "$zenPrefs"; then 108 verboseEcho "Zen: seeding the one-time bookmark import in $zenPrefs" 109 if [ -z "''${DRY_RUN:-}" ]; then 110 mkdir -p "$zenProfile" 111 printf '%s\n' 'user_pref("browser.places.importBookmarksHTML", true);' >> "$zenPrefs" 112 fi 113 fi 114 ''; 115 } 116 ; 117 }