1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-21 11:53:34 +00:00

Enable cross-compilation and packaging of Windows Appx from macOS (#17976)

* Enable cross-compilation and packaging of Windows Appx from macOS

* Consolidate cargo build execution into a single function in native build script

* Install cargo-xwin when needed

* Install Appx tools when needed

* Consolidate command execution into a single function in native build script

* Only include the native node modules for the appropriate platform

electron-builder's globs interact strangely, so we can't
exclude all the .node files in the global config and then
include the platform-specific files in the platform
configuration.

* Always copy Rust binaries to dist folder

* Log source and destination when copying files

* Update copyright

* Match Electron version in Beta build
This commit is contained in:
Isaiah Inuwa
2026-01-09 14:18:17 -06:00
committed by GitHub
parent 92190d734c
commit 881afacded
8 changed files with 474 additions and 55 deletions

View File

@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="utf-8"?>
<!--suppress XmlUnusedNamespaceDeclaration -->
<!-- <Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"> -->
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
IgnorableNamespaces="uap rescap com uap10 build"
xmlns:build="http://schemas.microsoft.com/developer/appx/2015/build">
<!-- use single quotes to avoid double quotes escaping in the publisher value -->
<Identity Name="${applicationId}"
ProcessorArchitecture="${arch}"
Publisher='${publisher}'
Version="${version}" />
<Properties>
<DisplayName>${displayName}</DisplayName>
<PublisherDisplayName>${publisherDisplayName}</PublisherDisplayName>
<Description>A secure and free password manager for all of your devices.</Description>
<Logo>assets\StoreLogo.png</Logo>
</Properties>
<Resources>
<Resource Language="en-US" />
<Resource Language="af" />
<Resource Language="ar" />
<Resource Language="az-latn" />
<Resource Language="be" />
<Resource Language="bg" />
<Resource Language="bn" />
<Resource Language="bs" />
<Resource Language="ca" />
<Resource Language="cs" />
<Resource Language="cy" />
<Resource Language="da" />
<Resource Language="de" />
<Resource Language="el" />
<Resource Language="en-gb" />
<Resource Language="en-in" />
<Resource Language="es" />
<Resource Language="et" />
<Resource Language="eu" />
<Resource Language="fa" />
<Resource Language="fi" />
<Resource Language="fil" />
<Resource Language="fr" />
<Resource Language="gl" />
<Resource Language="he" />
<Resource Language="hi" />
<Resource Language="hr" />
<Resource Language="hu" />
<Resource Language="id" />
<Resource Language="it" />
<Resource Language="ja" />
<Resource Language="ka" />
<Resource Language="km" />
<Resource Language="kn" />
<Resource Language="ko" />
<Resource Language="lt" />
<Resource Language="lv" />
<Resource Language="ml" />
<Resource Language="mr" />
<Resource Language="nb" />
<Resource Language="ne" />
<Resource Language="nl" />
<Resource Language="nn" />
<Resource Language="or" />
<Resource Language="pl" />
<Resource Language="pt-br" />
<Resource Language="pt-pt" />
<Resource Language="ro" />
<Resource Language="ru" />
<Resource Language="si" />
<Resource Language="sk" />
<Resource Language="sl" />
<Resource Language="sr-cyrl" />
<Resource Language="sv" />
<Resource Language="te" />
<Resource Language="th" />
<Resource Language="tr" />
<Resource Language="uk" />
<Resource Language="vi" />
<Resource Language="zh-cn" />
<Resource Language="zh-tw" />
</Resources>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.26200.7019"
MaxVersionTested="10.0.26200.7171" />
</Dependencies>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
</Capabilities>
<Applications>
<Application Id="bitwardendesktop" Executable="${executable}"
EntryPoint="Windows.FullTrustApplication">
<uap:VisualElements
BackgroundColor="#175DDC"
DisplayName="${displayName}"
Square150x150Logo="assets\Square150x150Logo.png"
Square44x44Logo="assets\Square44x44Logo.png"
Description="A secure and free password manager for all of your devices.">
<uap:LockScreen Notification="badgeAndTileText" BadgeLogo="assets\BadgeLogo.png" />
<uap:DefaultTile Wide310x150Logo="assets\Wide310x150Logo.png" />
<uap:SplashScreen Image="assets\SplashScreen.png" />
</uap:VisualElements>
</Application>
</Applications>
</Package>

View File

@@ -20,47 +20,79 @@ fs.mkdirSync(path.join(__dirname, "dist"), { recursive: true });
const args = process.argv.slice(2); // Get arguments passed to the script
const mode = args.includes("--release") ? "release" : "debug";
const isRelease = mode === "release";
const targetArg = args.find(arg => arg.startsWith("--target="));
const target = targetArg ? targetArg.split("=")[1] : null;
let crossPlatform = process.argv.length > 2 && process.argv[2] === "cross-platform";
/**
* Execute a command.
* @param {string} bin Executable to run.
* @param {string[]} args Arguments for executable.
* @param {string} [workingDirectory] Path to working directory, relative to the script directory. Defaults to the script directory.
* @param {string} [useShell] Whether to use a shell to execute the command. Defaults to false.
*/
function runCommand(bin, args, workingDirectory = "", useShell = false) {
const options = { stdio: 'inherit', cwd: path.resolve(__dirname, workingDirectory), shell: useShell }
console.debug("Running command:", bin, args, options)
child_process.execFileSync(bin, args, options)
}
function buildNapiModule(target, release = true) {
const targetArg = target ? `--target ${target}` : "";
const targetArg = target ? `--target=${target}` : "";
const releaseArg = release ? "--release" : "";
child_process.execSync(`npm run build -- ${releaseArg} ${targetArg}`, { stdio: 'inherit', cwd: path.join(__dirname, "napi") });
const crossCompileArg = effectivePlatform(target) !== process.platform ? "--cross-compile" : "";
runCommand("npm", ["run", "build", "--", crossCompileArg, releaseArg, targetArg].filter(s => s != ''), "./napi", true);
}
/**
* Build a Rust binary with Cargo.
*
* If {@link target} is specified, cross-compilation helpers are used to build if necessary, and the resulting
* binary is copied to the `dist` folder.
* @param {string} bin Name of cargo binary package in `desktop_native` workspace.
* @param {string?} target Rust compiler target, e.g. `aarch64-pc-windows-msvc`.
* @param {boolean} release Whether to build in release mode.
*/
function cargoBuild(bin, target, release) {
const targetArg = target ? `--target=${target}` : "";
const releaseArg = release ? "--release" : "";
const args = ["build", "--bin", bin, releaseArg, targetArg]
// Use cross-compilation helper if necessary
if (effectivePlatform(target) === "win32" && process.platform !== "win32") {
args.unshift("xwin")
}
runCommand("cargo", args.filter(s => s != ''))
// Infer the architecture and platform if not passed explicitly
let nodeArch, platform;
if (target) {
nodeArch = rustTargetsMap[target].nodeArch;
platform = rustTargetsMap[target].platform;
}
else {
nodeArch = process.arch;
platform = process.platform;
}
// Copy the resulting binary to the dist folder
const profileFolder = isRelease ? "release" : "debug";
const ext = platform === "win32" ? ".exe" : "";
const src = path.join(__dirname, "target", target ? target : "", profileFolder, `${bin}${ext}`)
const dst = path.join(__dirname, "dist", `${bin}.${platform}-${nodeArch}${ext}`)
console.log(`Copying ${src} to ${dst}`);
fs.copyFileSync(src, dst);
}
function buildProxyBin(target, release = true) {
const targetArg = target ? `--target ${target}` : "";
const releaseArg = release ? "--release" : "";
child_process.execSync(`cargo build --bin desktop_proxy ${releaseArg} ${targetArg}`, {stdio: 'inherit', cwd: path.join(__dirname, "proxy")});
if (target) {
// Copy the resulting binary to the dist folder
const targetFolder = release ? "release" : "debug";
const ext = process.platform === "win32" ? ".exe" : "";
const nodeArch = rustTargetsMap[target].nodeArch;
fs.copyFileSync(path.join(__dirname, "target", target, targetFolder, `desktop_proxy${ext}`), path.join(__dirname, "dist", `desktop_proxy.${process.platform}-${nodeArch}${ext}`));
}
cargoBuild("desktop_proxy", target, release)
}
function buildImporterBinaries(target, release = true) {
// These binaries are only built for Windows, so we can skip them on other platforms
if (process.platform !== "win32") {
return;
}
const bin = "bitwarden_chromium_import_helper";
const targetArg = target ? `--target ${target}` : "";
const releaseArg = release ? "--release" : "";
child_process.execSync(`cargo build --bin ${bin} ${releaseArg} ${targetArg}`);
if (target) {
// Copy the resulting binary to the dist folder
const targetFolder = release ? "release" : "debug";
const nodeArch = rustTargetsMap[target].nodeArch;
fs.copyFileSync(path.join(__dirname, "target", target, targetFolder, `${bin}.exe`), path.join(__dirname, "dist", `${bin}.${process.platform}-${nodeArch}.exe`));
if (effectivePlatform(target) == "win32") {
cargoBuild("bitwarden_chromium_import_helper", target, release)
}
}
@@ -69,17 +101,29 @@ function buildProcessIsolation() {
return;
}
child_process.execSync(`cargo build --release`, {
stdio: 'inherit',
cwd: path.join(__dirname, "process_isolation")
});
runCommand("cargo", ["build", "--package", "process_isolation", "--release"]);
console.log("Copying process isolation library to dist folder");
fs.copyFileSync(path.join(__dirname, "target", "release", "libprocess_isolation.so"), path.join(__dirname, "dist", `libprocess_isolation.so`));
}
function installTarget(target) {
child_process.execSync(`rustup target add ${target}`, { stdio: 'inherit', cwd: __dirname });
runCommand("rustup", ["target", "add", target]);
// Install cargo-xwin for cross-platform builds targeting Windows
if (target.includes('windows') && process.platform !== 'win32') {
runCommand("cargo", ["install", "--version", "0.20.2", "--locked", "cargo-xwin"]);
// install tools needed for packaging Appx, only supported on macOS for now.
if (process.platform === "darwin") {
runCommand("brew", ["install", "iinuwa/msix-packaging-tap/msix-packaging", "osslsigncode"]);
}
}
}
function effectivePlatform(target) {
if (target) {
return rustTargetsMap[target].platform
}
return process.platform
}
if (!crossPlatform && !target) {
@@ -94,9 +138,9 @@ if (!crossPlatform && !target) {
if (target) {
console.log(`Building for target: ${target} in ${mode} mode`);
installTarget(target);
buildNapiModule(target, mode === "release");
buildProxyBin(target, mode === "release");
buildImporterBinaries(false, mode === "release");
buildNapiModule(target, isRelease);
buildProxyBin(target, isRelease);
buildImporterBinaries(target, isRelease);
buildProcessIsolation();
return;
}
@@ -113,8 +157,8 @@ if (process.platform === "linux") {
platformTargets.forEach(([target, _]) => {
installTarget(target);
buildNapiModule(target, mode === "release");
buildProxyBin(target, mode === "release");
buildImporterBinaries(target, mode === "release");
buildNapiModule(target, isRelease);
buildProxyBin(target, isRelease);
buildImporterBinaries(target, isRelease);
buildProcessIsolation();
});

View File

@@ -13,14 +13,15 @@
},
"afterSign": "scripts/after-sign.js",
"afterPack": "scripts/after-pack.js",
"asarUnpack": ["**/*.node"],
"beforePack": "scripts/before-pack.js",
"files": [
"**/*",
"!**/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/scripts",
"!node_modules/@bitwarden/desktop-napi/src",
"!node_modules/@bitwarden/desktop-napi/Cargo.toml",
"!node_modules/@bitwarden/desktop-napi/build.rs",
"!node_modules/@bitwarden/desktop-napi/package.json"
],
"electronVersion": "36.8.1",
"electronVersion": "37.7.0",
"generateUpdatesFilesForAllChannels": true,
"publish": {
"provider": "generic",
@@ -34,11 +35,11 @@
},
"extraFiles": [
{
"from": "desktop_native/dist/desktop_proxy.${platform}-${arch}.exe",
"from": "desktop_native/dist/desktop_proxy.win32-${arch}.exe",
"to": "desktop_proxy.exe"
},
{
"from": "desktop_native/dist/bitwarden_chromium_import_helper.${platform}-${arch}.exe",
"from": "desktop_native/dist/bitwarden_chromium_import_helper.win32-${arch}.exe",
"to": "bitwarden_chromium_import_helper.exe"
}
]
@@ -58,6 +59,7 @@
"appx": {
"artifactName": "Bitwarden-Beta-${version}-${arch}.${ext}",
"backgroundColor": "#175DDC",
"customManifestPath": "./custom-appx-manifest.xml",
"applicationId": "BitwardenBeta",
"identityName": "8bitSolutionsLLC.BitwardenBeta",
"publisher": "CN=14D52771-DE3C-4886-B8BF-825BA7690418",

View File

@@ -13,12 +13,13 @@
},
"afterSign": "scripts/after-sign.js",
"afterPack": "scripts/after-pack.js",
"asarUnpack": ["**/*.node"],
"beforePack": "scripts/before-pack.js",
"files": [
"**/*",
"!**/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/scripts",
"!node_modules/@bitwarden/desktop-napi/src",
"!node_modules/@bitwarden/desktop-napi/Cargo.toml",
"!node_modules/@bitwarden/desktop-napi/build.rs",
"!node_modules/@bitwarden/desktop-napi/package.json"
],
"electronVersion": "39.2.6",
"generateUpdatesFilesForAllChannels": true,
@@ -94,11 +95,11 @@
},
"extraFiles": [
{
"from": "desktop_native/dist/desktop_proxy.${platform}-${arch}.exe",
"from": "desktop_native/dist/desktop_proxy.win32-${arch}.exe",
"to": "desktop_proxy.exe"
},
{
"from": "desktop_native/dist/bitwarden_chromium_import_helper.${platform}-${arch}.exe",
"from": "desktop_native/dist/bitwarden_chromium_import_helper.win32-${arch}.exe",
"to": "bitwarden_chromium_import_helper.exe"
}
]
@@ -172,6 +173,7 @@
"appx": {
"artifactName": "${productName}-${version}-${arch}.${ext}",
"backgroundColor": "#175DDC",
"customManifestPath": "./custom-appx-manifest.xml",
"applicationId": "bitwardendesktop",
"identityName": "8bitSolutionsLLC.bitwardendesktop",
"publisher": "CN=14D52771-DE3C-4886-B8BF-825BA7690418",

View File

@@ -29,7 +29,7 @@
"build:macos-extension:mas": "./desktop_native/macos_provider/build.sh && node scripts/build-macos-extension.js mas",
"build:macos-extension:masdev": "./desktop_native/macos_provider/build.sh && node scripts/build-macos-extension.js mas-dev",
"build:main": "cross-env NODE_ENV=production webpack --config webpack.config.js --config-name main",
"build:main:dev": "npm run build-native && cross-env NODE_ENV=development webpack --config webpack.config.js --config-name main",
"build:main:dev": "cross-env NODE_ENV=development webpack --config webpack.config.js --config-name main",
"build:main:watch": "npm run build-native && cross-env NODE_ENV=development webpack --config webpack.config.js --config-name main --watch",
"build:renderer": "cross-env NODE_ENV=production webpack --config webpack.config.js --config-name renderer",
"build:renderer:dev": "cross-env NODE_ENV=development webpack --config webpack.config.js --config-name renderer",

View File

@@ -6,9 +6,12 @@ const path = require("path");
const { flipFuses, FuseVersion, FuseV1Options } = require("@electron/fuses");
const builder = require("electron-builder");
const fse = require("fs-extra");
exports.default = run;
/**
*
* @param {builder.AfterPackContext} context
*/
async function run(context) {
console.log("## After pack");
// console.log(context);

View File

@@ -0,0 +1,226 @@
#!/usr/bin/env pwsh
<#
.SYNOPSIS
Script to build, package and sign the Bitwarden desktop client as a Windows Appx
package.
.DESCRIPTION
This script provides cross-platform support for packaging and signing the
Bitwarden desktop client as a Windows Appx package.
Currently, only macOS -> Windows Appx is supported, but Linux -> Windows Appx
could be added in the future by providing Linux binaries for the msix-packaging
project.
.NOTES
The reason this script exists is because electron-builder does not currently
support cross-platform Appx packaging without proprietary tools (Parallels
Windows VM). This script uses third-party tools (makemsix from msix-packaging
and osslsigncode) to package and sign the Appx.
The signing certificate must have the same subject as the publisher name. This
can be generated on the Windows target using PowerShell 5.1 and copied to the
host, or directly on the host with OpenSSL.
Using Windows PowerShell 5.1:
```powershell
$publisher = "CN=Bitwarden Inc., O=Bitwarden Inc., L=Santa Barbara, S=California, C=US, SERIALNUMBER=7654941, OID.2.5.4.15=Private Organization, OID.1.3.6.1.4.1.311.60.2.1.2=Delaware, OID.1.3.6.1.4.1.311.60.2.1.3=US"
$certificate = New-SelfSignedCertificate -Type Custom -KeyUsage DigitalSignature -CertStoreLocation "Cert:\CurrentUser\My" -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.3", "2.5.29.19={text}") -Subject $publisher -FriendlyName "Bitwarden Developer Signing Certificate"
$password = Read-Host -AsSecureString
Export-PfxCertificate -cert "Cert:\CurrentUser\My\${$certificate.Thumbprint}" -FilePath "C:\path/to/pfx" -Password $password
```
Using OpenSSL:
```sh
subject="jurisdictionCountryName=US/jurisdictionStateOrProvinceName=Delaware/businessCategory=Private Organization/serialNumber=7654941, C=US, ST=California, L=Santa Barbara, O=Bitwarden Inc., CN=Bitwarden Inc."
keyfile="/tmp/mysigning.rsa.pem"
certfile="/tmp/mysigning.cert.pem"
p12file="/tmp/mysigning.p12"
openssl req -x509 -keyout "$keyfile" -out "$certfile" -subj "$subject" \
-newkey rsa:2048 -days 3650 -nodes \
-addext 'keyUsage=critical,digitalSignature' \
-addext 'extendedKeyUsage=critical,codeSigning' \
-addext 'basicConstraints=critical,CA:FALSE'
openssl pkcs12 -inkey "$keyfile" -in "$certfile" -export -out "$p12file"
rm $keyfile
```
.EXAMPLE
./scripts/cross-build.ps1 -Architecture arm64 -CertificatePath ~/Development/code-signing.pfx -CertificatePassword (Read-Host -AsSecureString) -Release -Beta
Reads the signing certificate password from user input, then builds, packages
and signs the Appx.
Alternatively, you can specify the CERTIFICATE_PASSWORD environment variable.
#>
param(
[Parameter(Mandatory=$true)]
[ValidateSet("X64", "ARM64")]$Architecture,
[string]
# Path to PKCS12 certificate file. If not specified, the Appx will not be signed.
$CertificatePath,
[SecureString]
# Password for PKCS12 certificate. Alternatively, may be specified in
# CERTIFICATE_PASSWORD environment variable. If not specified, the Appx will
# not be signed.
$CertificatePassword,
[Switch]
# Whether to build the Beta version of the app.
$Beta=$false,
[Switch]
# Whether to build in release mode.
$Release=$false
)
$ErrorActionPreference = "Stop"
$PSNativeCommandUseErrorActionPreference = $true
$startTime = Get-Date
$originalLocation = Get-Location
if (!(Get-Command makemsix -ErrorAction SilentlyContinue)) {
Write-Error "The `makemsix` tool from the msix-packaging project is required to construct Appx package."
Write-Error "On macOS, you can install with Homebrew:"
Write-Error " brew install iinuwa/msix-packaging-tap/msix-packaging"
Exit 1
}
if (!(Get-Command osslsigncode -ErrorAction SilentlyContinue)) {
Write-Error "The `osslsigncode` tool is required to sign the Appx package."
Write-Error "On macOS, you can install with Homebrew:"
Write-Error " brew install osslsigncode"
Exit 1
}
if (!(Get-Command cargo-xwin -ErrorAction SilentlyContinue)) {
Write-Error "The `cargo-xwin` tool is required to cross-compile Windows native code."
Write-Error "You can install with cargo:"
Write-Error " cargo install --version 0.20.2 --locked cargo-xwin"
Exit 1
}
try {
# Resolve certificate file before we change directories.
$CertificateFile = Get-Item $CertificatePath -ErrorAction SilentlyContinue
cd $PSScriptRoot/..
if ($Beta) {
$electronConfigFile = Get-Item "./electron-builder.beta.json"
}
else {
$electronConfigFile = Get-Item "./electron-builder.json"
}
$builderConfig = Get-Content $electronConfigFile | ConvertFrom-Json
$packageConfig = Get-Content package.json | ConvertFrom-Json
$manifestTemplate = Get-Content $builderConfig.appx.customManifestPath
$srcDir = Get-Location
$assetsDir = Get-Item $builderConfig.directories.buildResources
$buildDir = Get-Item $builderConfig.directories.app
$outDir = Join-Path (Get-Location) ($builderConfig.directories.output ?? "dist")
if ($Release) {
$buildConfiguration = "--release"
}
$arch = "$Architecture".ToLower()
$ext = "appx"
$version = Get-Date -Format "yyyy.M.d.1HHmm"
$productName = $builderConfig.productName
$artifactName = "${productName}-$($packageConfig.version)-${arch}.$ext"
Write-Host "Building native code"
$rustTarget = switch ($arch) {
x64 { "x86_64-pc-windows-msvc" }
arm64 { "aarch64-pc-windows-msvc" }
default {
Write-Error "Unsupported architecture: $Architecture. Supported architectures are x64 and arm64"
Exit(1)
}
}
npm run build-native -- cross-platform $buildConfiguration "--target=$rustTarget"
Write-Host "Building Javascript code"
if ($Release) {
npm run build
}
else {
npm run build:dev
}
Write-Host "Cleaning output folder"
Remove-Item -Recurse -Force $outDir -ErrorAction Ignore
Write-Host "Packaging Electron executable"
& npx electron-builder --config $electronConfigFile --publish never --dir --win --$arch
cd $outDir
New-Item -Type Directory (Join-Path $outDir "appx")
Write-Host "Building Appx directory structure"
$appxDir = (Join-Path $outDir appx/app)
if ($arch -eq "x64") {
Move-Item (Join-Path $outDir "win-unpacked") $appxDir
}
else {
Move-Item (Join-Path $outDir "win-${arch}-unpacked") $appxDir
}
Write-Host "Copying Assets"
New-Item -Type Directory (Join-Path $outDir appx/assets)
Copy-Item $srcDir/resources/appx/* $outDir/appx/assets/
Write-Host "Building Appx manifest"
$translationMap = @{
'arch' = $arch
'applicationId' = $builderConfig.appx.applicationId
'displayName' = $productName
'executable' = "app\${productName}.exe"
'publisher' = $builderConfig.appx.publisher
'publisherDisplayName' = $builderConfig.appx.publisherDisplayName
'version' = $version
}
$manifest = $manifestTemplate
$translationMap.Keys | ForEach-Object {
$manifest = $manifest.Replace("`${$_}", $translationMap[$_])
}
$manifest | Out-File appx/AppxManifest.xml
$unsignedArtifactpath = [System.IO.Path]::GetFileNameWithoutExtension($artifactName) + "-unsigned.$ext"
Write-Host "Creating unsigned Appx"
makemsix pack -d appx -p $unsignedArtifactpath
$outfile = Join-Path $outDir $unsignedArtifactPath
if ($null -eq $CertificatePath) {
Write-Warning "No Certificate specified. Not signing Appx."
}
elseif ($null -eq $CertificatePassword -and $null -eq $env:CERTIFICATE_PASSWORD) {
Write-Warning "No certificate password specified in CertificatePassword argument nor CERTIFICATE_PASSWORD environment variable. Not signing Appx."
}
else {
$cert = $CertificateFile
$pw = $null
if ($null -ne $CertificatePassword) {
$pw = ConvertFrom-SecureString -SecureString $CertificatePassword -AsPlainText
} else {
$pw = $env:CERTIFICATE_PASSWORD
}
$unsigned = $outfile
$outfile = (Join-Path $outDir $artifactName)
Write-Host "Signing $artifactName with $cert"
osslsigncode sign `
-pkcs12 "$cert" `
-pass "$pw" `
-in $unsigned `
-out $outfile
Remove-Item $unsigned
}
$endTime = Get-Date
$elapsed = $endTime - $startTime
Write-Host "Successfully packaged $(Get-Item $outfile)"
Write-Host ("Finished at $($endTime.ToString('HH:mm:ss')) in $($elapsed.ToString('mm')) minutes and $($elapsed.ToString('ss')).$($elapsed.ToString('fff')) seconds")
}
finally {
Set-Location -Path $originalLocation
}

View File

@@ -0,0 +1,31 @@
/* eslint-disable no-console */
/** @import { BeforePackContext } from 'app-builder-lib' */
exports.default = run;
/**
* @param {BeforePackContext} context
*/
async function run(context) {
console.log("## before pack");
console.log("Stripping .node files that don't belong to this platform...");
removeExtraNodeFiles(context);
}
/**
* Removes Node files for platforms besides the current platform being packaged.
*
* @param {BeforePackContext} context
*/
function removeExtraNodeFiles(context) {
// When doing cross-platform builds, due to electron-builder limitiations,
// .node files for other platforms may be generated and unpacked, so we
// remove them manually here before signing and distributing.
const packagerPlatform = context.packager.platform.nodeName;
const platforms = ["darwin", "linux", "win32"];
const fileFilter = context.packager.info._configuration.files[0].filter;
for (const platform of platforms) {
if (platform != packagerPlatform) {
fileFilter.push(`!node_modules/@bitwarden/desktop-napi/desktop_napi.${platform}-*.node`);
}
}
}