From de0b5d91b29e015c1fb34e575beb7724061f159a Mon Sep 17 00:00:00 2001 From: TomaSajt <62384384+TomaSajt@users.noreply.github.com> Date: Mon, 24 Feb 2025 20:04:12 +0100 Subject: [PATCH] bitwarden-desktop: add darwin support and do minor refactor --- .../dont-use-platform-triple.patch | 55 ++++++ pkgs/by-name/bi/bitwarden-desktop/package.nix | 166 ++++++++++-------- .../skip-afterpack-and-aftersign.patch | 28 +++ .../bi/bitwarden-desktop/skip-afterpack.diff | 39 ---- 4 files changed, 180 insertions(+), 108 deletions(-) create mode 100644 pkgs/by-name/bi/bitwarden-desktop/dont-use-platform-triple.patch create mode 100644 pkgs/by-name/bi/bitwarden-desktop/skip-afterpack-and-aftersign.patch delete mode 100644 pkgs/by-name/bi/bitwarden-desktop/skip-afterpack.diff diff --git a/pkgs/by-name/bi/bitwarden-desktop/dont-use-platform-triple.patch b/pkgs/by-name/bi/bitwarden-desktop/dont-use-platform-triple.patch new file mode 100644 index 000000000000..0b39a187e39d --- /dev/null +++ b/pkgs/by-name/bi/bitwarden-desktop/dont-use-platform-triple.patch @@ -0,0 +1,55 @@ +diff --git a/apps/desktop/desktop_native/napi/index.js b/apps/desktop/desktop_native/napi/index.js +index acfd0df..31a0c6a 100644 +--- a/apps/desktop/desktop_native/napi/index.js ++++ b/apps/desktop/desktop_native/napi/index.js +@@ -17,6 +17,7 @@ function loadFirstAvailable(localFiles, nodeModule) { + require(nodeModule); + } + ++/* + switch (platform) { + case "android": + switch (arch) { +@@ -121,6 +122,8 @@ switch (platform) { + default: + throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`); + } ++*/ ++nativeBinding = require('./desktop_napi.node') + + if (!nativeBinding) { + if (loadError) { +diff --git a/apps/desktop/desktop_native/napi/package.json b/apps/desktop/desktop_native/napi/package.json +index d557ccf..2e47c79 100644 +--- a/apps/desktop/desktop_native/napi/package.json ++++ b/apps/desktop/desktop_native/napi/package.json +@@ -3,7 +3,7 @@ + "version": "0.1.0", + "description": "", + "scripts": { +- "build": "napi build --platform --js false", ++ "build": "napi build --js false", + "test": "cargo test" + }, + "author": "", +diff --git a/apps/desktop/electron-builder.json b/apps/desktop/electron-builder.json +index 2922035..6497a38 100644 +--- a/apps/desktop/electron-builder.json ++++ b/apps/desktop/electron-builder.json +@@ -18,7 +18,7 @@ + "**/*", + "!**/node_modules/@bitwarden/desktop-napi/**/*", + "**/node_modules/@bitwarden/desktop-napi/index.js", +- "**/node_modules/@bitwarden/desktop-napi/desktop_napi.${platform}-${arch}*.node" ++ "**/node_modules/@bitwarden/desktop-napi/desktop_napi.node" + ], + "electronVersion": "34.0.0", + "generateUpdatesFilesForAllChannels": true, +@@ -67,7 +67,6 @@ + ], + "CFBundleDevelopmentRegion": "en" + }, +- "singleArchFiles": "node_modules/@bitwarden/desktop-napi/desktop_napi.darwin-*.node", + "extraFiles": [ + { + "from": "desktop_native/dist/desktop_proxy.${platform}-${arch}", diff --git a/pkgs/by-name/bi/bitwarden-desktop/package.nix b/pkgs/by-name/bi/bitwarden-desktop/package.nix index ab168b804a28..44f33663d5cd 100644 --- a/pkgs/by-name/bi/bitwarden-desktop/package.nix +++ b/pkgs/by-name/bi/bitwarden-desktop/package.nix @@ -1,23 +1,25 @@ { lib, + apple-sdk_14, buildNpmPackage, cargo, copyDesktopItems, + darwin, electron_34, fetchFromGitHub, gnome-keyring, jq, + llvmPackages_18, makeDesktopItem, makeWrapper, napi-rs-cli, nix-update-script, nodejs_20, - patchutils_0_4_2, pkg-config, - runCommand, rustc, rustPlatform, stdenv, + xcbuild, }: let @@ -25,16 +27,12 @@ let icon = "bitwarden"; electron = electron_34; - bitwardenDesktopNativeArch = - { - aarch64 = "arm64"; - x86_64 = "x64"; - } - .${stdenv.hostPlatform.parsed.cpu.name} - or (throw "bitwarden-desktop: unsupported CPU family ${stdenv.hostPlatform.parsed.cpu.name}"); - + # argon2 npm dependency is using `std::basic_string`, which is no longer allowed in LLVM 19 + buildNpmPackage' = buildNpmPackage.override { + stdenv = if stdenv.hostPlatform.isDarwin then llvmPackages_18.stdenv else stdenv; + }; in -buildNpmPackage rec { +buildNpmPackage' rec { pname = "bitwarden-desktop"; version = "2025.2.0"; @@ -49,7 +47,8 @@ buildNpmPackage rec { ./electron-builder-package-lock.patch ./dont-auto-setup-biometrics.patch ./set-exe-path.patch # ensures `app.getPath("exe")` returns our wrapper, not ${electron}/bin/electron - ./skip-afterpack.diff # this modifies bin/electron etc., but we wrap read-only bin/electron ourselves + ./skip-afterpack-and-aftersign.patch # on linux: don't flip fuses, don't create wrapper script, on darwin: don't try copying safari extensions, don't try re-signing app + ./dont-use-platform-triple.patch # since out arch doesn't match upstream, we'll generate and use desktop_napi.node instead of desktop_napi.${platform}-${arch}.node ]; postPatch = '' @@ -57,6 +56,11 @@ buildNpmPackage rec { rm -r bitwarden_license substituteInPlace apps/desktop/src/main.ts --replace-fail '%%exePath%%' "$out/bin/bitwarden" + + # force canUpdate to false + # will open releases page instead of trying to update files + substituteInPlace apps/desktop/src/main/updater.main.ts \ + --replace-fail 'this.canUpdate =' 'this.canUpdate = false; let _dummy =' ''; nodejs = nodejs_20; @@ -75,31 +79,43 @@ buildNpmPackage rec { npmDepsHash = "sha256-fYZJA6qV3mqxO2g+yxD0MWWQc9QYmdWJ7O7Vf88Qpbs="; cargoDeps = rustPlatform.fetchCargoVendor { - inherit pname version src; - patches = map ( - patch: - runCommand (builtins.baseNameOf patch) { nativeBuildInputs = [ patchutils_0_4_2 ]; } '' - < ${patch} filterdiff -p1 --include=${lib.escapeShellArg cargoRoot}'/*' > $out - '' - ) patches; - patchFlags = [ "-p4" ]; - sourceRoot = "${src.name}/${cargoRoot}"; + inherit + pname + version + src + cargoRoot + patches + ; hash = "sha256-OldVFMI+rcGAbpDg7pHu/Lqbw5I6/+oXULteQ9mXiFc="; }; cargoRoot = "apps/desktop/desktop_native"; env.ELECTRON_SKIP_BINARY_DOWNLOAD = "1"; - nativeBuildInputs = [ - cargo - copyDesktopItems - jq - makeWrapper - napi-rs-cli - pkg-config - rustc - rustPlatform.cargoCheckHook - rustPlatform.cargoSetupHook + # make electron-builder not attempt to codesign the app on darwin + env.CSC_IDENTITY_AUTO_DISCOVERY = "false"; + + nativeBuildInputs = + [ + cargo + jq + makeWrapper + napi-rs-cli + pkg-config + rustc + rustPlatform.cargoCheckHook + rustPlatform.cargoSetupHook + ] + ++ lib.optionals stdenv.hostPlatform.isLinux [ + copyDesktopItems + ] + ++ lib.optionals stdenv.hostPlatform.isDarwin [ + xcbuild + darwin.autoSignDarwinBinariesHook + ]; + + buildInputs = lib.optionals stdenv.hostPlatform.isDarwin [ + apple-sdk_14 ]; preBuild = '' @@ -116,26 +132,32 @@ buildNpmPackage rec { postBuild = '' pushd apps/desktop - # desktop_native/index.js loads a file of that name regardless of the libc being used - mv desktop_native/napi/desktop_napi.* desktop_native/napi/desktop_napi.linux-${bitwardenDesktopNativeArch}-musl.node + # electron-dist needs to be writable on darwin or when using fuses + cp -r ${electron.dist} electron-dist + chmod -R u+w electron-dist npm exec electron-builder -- \ --dir \ - -c.electronDist=${electron.dist} \ + -c.electronDist=electron-dist \ -c.electronVersion=${electron.version} popd ''; - doCheck = true; + # there seem to be issues with missing libs on darwin when running tests + doCheck = !stdenv.hostPlatform.isDarwin; - nativeCheckInputs = [ + nativeCheckInputs = lib.optionals stdenv.hostPlatform.isLinux [ (gnome-keyring.override { useWrappedDaemon = false; }) ]; - checkFlags = [ - "--skip=password::password::tests::test" - ]; + checkFlags = + [ + "--skip=password::password::tests::test" + ] + ++ lib.optionals stdenv.hostPlatform.isDarwin [ + "--skip=clipboard::tests::test_write_read" + ]; preCheck = '' pushd ${cargoRoot} @@ -147,39 +169,43 @@ buildNpmPackage rec { popd ''; - installPhase = '' - runHook preInstall + installPhase = + '' + runHook preInstall + '' + + lib.optionalString stdenv.hostPlatform.isDarwin '' + mkdir -p $out/Applications + cp -r apps/desktop/dist/mac*/Bitwarden.app $out/Applications + makeWrapper $out/Applications/Bitwarden.app/Contents/MacOS/Bitwarden $out/bin/bitwarden + '' + + lib.optionalString stdenv.hostPlatform.isLinux '' + mkdir -p $out/opt/Bitwarden + cp -r apps/desktop/dist/linux-*unpacked/{locales,resources{,.pak}} $out/opt/Bitwarden - mkdir $out + makeWrapper '${lib.getExe electron}' "$out/bin/bitwarden" \ + --add-flags $out/opt/Bitwarden/resources/app.asar \ + --add-flags "\''${NIXOS_OZONE_WL:+\''${WAYLAND_DISPLAY:+--ozone-platform-hint=auto --enable-features=WaylandWindowDecorations --enable-wayland-ime=true}}" \ + --set-default ELECTRON_IS_DEV 0 \ + --inherit-argv0 - pushd apps/desktop/dist/linux-${lib.optionalString stdenv.hostPlatform.isAarch64 "arm64-"}unpacked - mkdir -p $out/opt/Bitwarden - cp -r locales resources{,.pak} $out/opt/Bitwarden - popd + # Extract the polkit policy file from the multiline string in the source code. + # This may break in the future but its better than copy-pasting it manually. + mkdir -p $out/share/polkit-1/actions/ + pushd apps/desktop/src/key-management/biometrics + awk '/const polkitPolicy = `/{gsub(/^.*`/, ""); print; str=1; next} str{if (/`;/) str=0; gsub(/`;/, ""); print}' os-biometrics-linux.service.ts > $out/share/polkit-1/actions/com.bitwarden.Bitwarden.policy + popd - makeWrapper '${lib.getExe electron}' "$out/bin/bitwarden" \ - --add-flags $out/opt/Bitwarden/resources/app.asar \ - --add-flags "\''${NIXOS_OZONE_WL:+\''${WAYLAND_DISPLAY:+--ozone-platform-hint=auto --enable-features=WaylandWindowDecorations --enable-wayland-ime=true}}" \ - --set-default ELECTRON_IS_DEV 0 \ - --inherit-argv0 - - # Extract the polkit policy file from the multiline string in the source code. - # This may break in the future but its better than copy-pasting it manually. - mkdir -p $out/share/polkit-1/actions/ - pushd apps/desktop/src/key-management/biometrics - awk '/const polkitPolicy = `/{gsub(/^.*`/, ""); print; str=1; next} str{if (/`;/) str=0; gsub(/`;/, ""); print}' os-biometrics-linux.service.ts > $out/share/polkit-1/actions/com.bitwarden.Bitwarden.policy - popd - - pushd apps/desktop/resources/icons - for icon in *.png; do - dir=$out/share/icons/hicolor/"''${icon%.png}"/apps - mkdir -p "$dir" - cp "$icon" "$dir"/${icon}.png - done - popd - - runHook postInstall - ''; + pushd apps/desktop/resources/icons + for icon in *.png; do + dir=$out/share/icons/hicolor/"''${icon%.png}"/apps + mkdir -p "$dir" + cp "$icon" "$dir"/${icon}.png + done + popd + '' + + '' + runHook postInstall + ''; desktopItems = [ (makeDesktopItem { @@ -212,6 +238,8 @@ buildNpmPackage rec { platforms = [ "x86_64-linux" "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" ]; mainProgram = "bitwarden"; }; diff --git a/pkgs/by-name/bi/bitwarden-desktop/skip-afterpack-and-aftersign.patch b/pkgs/by-name/bi/bitwarden-desktop/skip-afterpack-and-aftersign.patch new file mode 100644 index 000000000000..695009fb15e7 --- /dev/null +++ b/pkgs/by-name/bi/bitwarden-desktop/skip-afterpack-and-aftersign.patch @@ -0,0 +1,28 @@ +diff --git a/apps/desktop/scripts/after-pack.js b/apps/desktop/scripts/after-pack.js +index 45b79c0..65a6fd5 100644 +--- a/apps/desktop/scripts/after-pack.js ++++ b/apps/desktop/scripts/after-pack.js +@@ -13,6 +13,9 @@ async function run(context) { + console.log("## After pack"); + // console.log(context); + ++ // skip after-pack ++ return; ++ + if (context.packager.platform.nodeName !== "darwin" || context.arch === builder.Arch.universal) { + await addElectronFuses(context); + } +diff --git a/apps/desktop/scripts/after-sign.js b/apps/desktop/scripts/after-sign.js +index 20c24c8..acaf867 100644 +--- a/apps/desktop/scripts/after-sign.js ++++ b/apps/desktop/scripts/after-sign.js +@@ -12,6 +12,9 @@ async function run(context) { + console.log("## After sign"); + // console.log(context); + ++ // skip after-sign ++ return; ++ + const appName = context.packager.appInfo.productFilename; + const appPath = `${context.appOutDir}/${appName}.app`; + const macBuild = context.electronPlatformName === "darwin"; diff --git a/pkgs/by-name/bi/bitwarden-desktop/skip-afterpack.diff b/pkgs/by-name/bi/bitwarden-desktop/skip-afterpack.diff deleted file mode 100644 index 563ed31ffc09..000000000000 --- a/pkgs/by-name/bi/bitwarden-desktop/skip-afterpack.diff +++ /dev/null @@ -1,39 +0,0 @@ -diff --git a/apps/desktop/scripts/after-pack.js b/apps/desktop/scripts/after-pack.js -index fd16cd5ffb..05a2325ee1 100644 ---- a/apps/desktop/scripts/after-pack.js -+++ b/apps/desktop/scripts/after-pack.js -@@ -13,25 +13,6 @@ async function run(context) { - console.log("## After pack"); - // console.log(context); - -- if (context.packager.platform.nodeName !== "darwin" || context.arch === builder.Arch.universal) { -- await addElectronFuses(context); -- } -- -- if (context.electronPlatformName === "linux") { -- console.log("Creating memory-protection wrapper script"); -- const appOutDir = context.appOutDir; -- const oldBin = path.join(appOutDir, context.packager.executableName); -- const newBin = path.join(appOutDir, "bitwarden-app"); -- fse.moveSync(oldBin, newBin); -- console.log("Moved binary to bitwarden-app"); -- -- const wrapperScript = path.join(__dirname, "../resources/memory-dump-wrapper.sh"); -- const wrapperBin = path.join(appOutDir, context.packager.executableName); -- fse.copyFileSync(wrapperScript, wrapperBin); -- fse.chmodSync(wrapperBin, "755"); -- console.log("Copied memory-protection wrapper script"); -- } -- - if (["darwin", "mas"].includes(context.electronPlatformName)) { - const is_mas = context.electronPlatformName === "mas"; - const is_mas_dev = context.targets.some((e) => e.name === "mas-dev"); -@@ -140,6 +121,8 @@ function getIdentities() { - * @param {import("electron-builder").AfterPackContext} context - */ - async function addElectronFuses(context) { -+ return; -+ - const platform = context.packager.platform.nodeName; - - const ext = {