bitwarden-desktop: add darwin support and do minor refactor

This commit is contained in:
TomaSajt
2025-03-08 21:42:47 +01:00
committed by Sandro Jäckel
parent b5d0eb125c
commit de0b5d91b2
4 changed files with 180 additions and 108 deletions
@@ -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}",
+97 -69
View File
@@ -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<uint8_t>`, 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";
};
@@ -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";
@@ -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 = {