This repository has been archived on 2026-05-25. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
zen-browser-flake/package.nix
Xin Huang 21a72764b6 fix(darwin): use stable app path to prevent installs.ini accumulation (#150)
* fix: Add policies.json support for macOS (Darwin)

Previously, policies.json was only installed for Linux builds,
causing browser policies (including ExtensionSettings) to be
ignored on macOS. This resulted in extensions not being automatically
installed on macOS systems.

This fix adds the policies.json installation to the Darwin install
phase, mirroring the Linux behavior and ensuring policy enforcement
works correctly on macOS.

Fixes extension auto-installation and other policy-based features on macOS.

* fix(darwin): use stable app path to prevent installs.ini accumulation

Problem:
- Zen Browser creates install IDs based on the application path
- Wrapper script uses Nix store path which changes on every rebuild
- Each new path creates a new install ID entry in installs.ini
- Results in: multiple Dock icons, empty profiles, data loss

Solution:
- Use the stable Home Manager symlink path (~/.../Home Manager Apps/...)
- This path remains constant across Nix rebuilds
- Zen Browser sees the same path every time, reuses existing install ID
- Falls back to store path if symlink doesn't exist yet

Benefits:
- No activation scripts or workarounds needed
- Fixes root cause instead of symptoms
- Maintains profile continuity naturally
- Clean, elegant solution

* fix: force WAL checkpoint after updating places.sqlite

Problem:
- SQLite WAL mode writes changes to .sqlite-wal file first
- Changes aren't visible until WAL is checkpointed to main file
- Zen Browser reads stale data from main file on startup
- User needs to wait or manually trigger checkpoint to see updates

Solution:
- Execute PRAGMA wal_checkpoint(FULL) after all updates
- Forces immediate merge of WAL changes to main database file
- Ensures spaces/pins updates are visible on next Zen startup

This fixes the delay between home-manager rebuild and seeing
configuration changes in Zen Browser.

* fix(darwin): preserve correct bundle identifier in code signature

Problem:
- AdGuard recognizes apps by code signing identifier, not CFBundleIdentifier
- Nix's adhoc re-signing changes identifier from 'app.zen-browser.zen' to 'zen'
- This breaks AdGuard's app filtering for Nix-built Zen Browser

Solution:
- Explicitly set --identifier flag when re-signing with codesign
- Maintains 'app.zen-browser.zen' identifier for AdGuard compatibility
- Ensures proper ad-blocking and app recognition

This allows AdGuard and other security tools to correctly identify
Zen Browser even when built through Nix.
2025-11-05 06:14:41 -05:00

250 lines
7.1 KiB
Nix

{
name,
variant,
policies ? {},
lib,
stdenv,
config,
wrapGAppsHook3,
autoPatchelfHook,
ffmpeg,
alsa-lib,
curl,
dbus-glib,
gtk3,
libXtst,
libva,
libGL,
pciutils,
pipewire,
adwaita-icon-theme,
undmg,
writeText,
fetchurl,
fetchzip,
makeDesktopItem,
copyDesktopItems,
patchelfUnstable, # have to use patchelfUnstable to support --no-clobber-old-sections
applicationName ?
"Zen Browser"
+ (
if name == "beta"
then " (Beta)"
else if name == "twilight"
then " (Twilight)"
else if name == "twilight-official"
then " (Twilight)"
else ""
),
}: let
binaryName = "zen-${name}";
libName = "zen-bin-${variant.version}";
mozillaPlatforms = {
x86_64-linux = "linux-x86_64";
aarch64-linux = "linux-aarch64";
aarch64-darwin = "darwin-aarch64";
};
firefoxPolicies =
(config.firefox.policies or {})
// policies;
policiesJson = writeText "firefox-policies.json" (builtins.toJSON {policies = firefoxPolicies;});
pname = "zen-${name}-bin-unwrapped";
desktopIconName =
if name == "beta"
then "zen-browser"
else binaryName;
installDarwin = ''
runHook preInstall
mkdir -p "$out/Applications" "$out/bin"
cp -r *.app "$out/Applications/${applicationName}.app"
ln -s zen "$out/Applications/${applicationName}.app/Contents/MacOS/${binaryName}"
# Install policies.json for macOS
mkdir -p "$out/Applications/${applicationName}.app/Contents/Resources/distribution"
ln -s ${policiesJson} "$out/Applications/${applicationName}.app/Contents/Resources/distribution/policies.json"
# Re-sign with correct identifier to maintain AdGuard compatibility
# AdGuard uses code signing identifier (not CFBundleIdentifier) to recognize apps
/usr/bin/codesign --force --deep --sign - \
--identifier "app.zen-browser.zen" \
"$out/Applications/${applicationName}.app"
# Use symlink path to avoid installs.ini accumulation on Nix rebuilds
# The symlink is created by home-manager and remains stable across rebuilds
cat > "$out/bin/${binaryName}" << EOF
#!/bin/bash
# Use stable path from home-manager to avoid creating new install IDs
STABLE_PATH="\$HOME/Applications/Home Manager Apps/${applicationName}.app"
if [[ -e "\$STABLE_PATH" ]]; then
exec /usr/bin/open -na "\$STABLE_PATH" --args "\$@"
else
# Fallback to nix store path if symlink doesn't exist yet
exec /usr/bin/open -na "$out/Applications/${applicationName}.app" --args "\$@"
fi
EOF
chmod +x "$out/bin/${binaryName}"
ln -s "$out/bin/${binaryName}" "$out/bin/zen"
runHook postInstall
'';
installLinux = ''
runHook preInstall
# Linux tarball installation
mkdir -p "$prefix/lib/${libName}"
cp -r "$src"/* "$prefix/lib/${libName}"
mkdir -p "$out/bin"
ln -s "$prefix/lib/${libName}/zen" "$out/bin/${binaryName}"
ln -s "$out/bin/${binaryName}" "$out/bin/zen"
mkdir -p "$out/lib/${libName}/distribution"
ln -s ${policiesJson} "$out/lib/${libName}/distribution/policies.json"
install -D $src/browser/chrome/icons/default/default16.png $out/share/icons/hicolor/16x16/apps/${desktopIconName}.png
install -D $src/browser/chrome/icons/default/default32.png $out/share/icons/hicolor/32x32/apps/${desktopIconName}.png
install -D $src/browser/chrome/icons/default/default48.png $out/share/icons/hicolor/48x48/apps/${desktopIconName}.png
install -D $src/browser/chrome/icons/default/default64.png $out/share/icons/hicolor/64x64/apps/${desktopIconName}.png
install -D $src/browser/chrome/icons/default/default128.png $out/share/icons/hicolor/128x128/apps/${desktopIconName}.png
runHook postInstall
'';
in
stdenv.mkDerivation {
inherit pname;
inherit (variant) version;
src =
if stdenv.hostPlatform.isDarwin
then
fetchurl {
inherit (variant) url;
hash = variant.sha256;
}
else
fetchzip {
inherit (variant) url;
hash = variant.sha256;
};
sourceRoot = lib.optionalString stdenv.hostPlatform.isDarwin ".";
desktopItems = [
(makeDesktopItem {
name = binaryName;
desktopName = "Zen Browser${lib.optionalString (name == "twilight") " Twilight"}";
exec = "${binaryName} %u";
icon = desktopIconName;
type = "Application";
mimeTypes = [
"text/html"
"text/xml"
"application/xhtml+xml"
"x-scheme-handler/http"
"x-scheme-handler/https"
"application/x-xpinstall"
"application/pdf"
"application/json"
];
startupWMClass = binaryName;
categories = ["Network" "WebBrowser"];
startupNotify = true;
terminal = false;
keywords = ["Internet" "WWW" "Browser" "Web" "Explorer"];
extraConfig.X-MultipleArgs = "false";
actions = {
new-windows = {
name = "Open a New Window";
exec = "${binaryName} %u";
};
new-private-window = {
name = "Open a New Private Window";
exec = "${binaryName} --private-window %u";
};
profilemanager = {
name = "Open the Profile Manager";
exec = "${binaryName} --ProfileManager %u";
};
};
})
];
nativeBuildInputs =
lib.optionals stdenv.hostPlatform.isLinux [
wrapGAppsHook3
autoPatchelfHook
patchelfUnstable
copyDesktopItems
]
++ lib.optionals stdenv.hostPlatform.isDarwin [
undmg
];
buildInputs = lib.optionals stdenv.hostPlatform.isLinux [
gtk3
adwaita-icon-theme
alsa-lib
dbus-glib
libXtst
ffmpeg
];
runtimeDependencies = lib.optionals stdenv.hostPlatform.isLinux [
curl
libva.out
pciutils
libGL
];
appendRunpaths = lib.optionals stdenv.hostPlatform.isLinux [
"${libGL}/lib"
"${pipewire}/lib"
];
# Firefox uses "relrhack" to manually process relocations from a fixed offset
patchelfFlags = ["--no-clobber-old-sections"];
preFixup = ''
gappsWrapperArgs+=(
--prefix LD_LIBRARY_PATH : "${lib.makeLibraryPath [ffmpeg]}"
--add-flags "--name=''${MOZ_APP_LAUNCHER:-${binaryName}}"
--add-flags "--class=''${MOZ_APP_LAUNCHER:-${binaryName}}"
)
'';
installPhase =
if stdenv.hostPlatform.isDarwin
then installDarwin
else installLinux;
passthru = {
inherit applicationName binaryName libName;
ffmpegSupport = true;
gssSupport = true;
gtk3 = gtk3;
};
meta = {
description = "Experience tranquillity while browsing the web without people tracking you!";
homepage = "https://zen-browser.app";
downloadPage = "https://zen-browser.app/download/";
changelog = "https://github.com/zen-browser/desktop/releases";
sourceProvenance = with lib.sourceTypes; [binaryNativeCode];
platforms = builtins.attrNames mozillaPlatforms;
hydraPlatforms = [];
mainProgram = binaryName;
desktopFileName = "${binaryName}.desktop";
};
}