Skip to content

Commit

Permalink
Sign app on macOS
Browse files Browse the repository at this point in the history
- Update package-client to sign the macos dmg artifact using `codesign`
  (integrated in `electron-builder`)
- Rename `libparsec/index.node` to `libparsec.node`
- Open devtools on startup with `OPEN_DEV_TOOLS` env var.

Closes #7724, closes #7874
  • Loading branch information
FirelightFlagboy committed Nov 4, 2024
1 parent 9ec782d commit f9e6baa
Show file tree
Hide file tree
Showing 14 changed files with 98 additions and 33 deletions.
58 changes: 50 additions & 8 deletions .github/workflows/package-client.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ on:
secrets:
SENTRY_AUTH_TOKEN:
required: true
MACOS_CI_KEYCHAIN_PASSWD:
required: true
MACOS_CERT_PASSWD:
required: true
MACOS_CERT:
required: true
MACOS_CERT_COMMON_NAME:
required: true
MACOS_NOTARIZATION_TEAM_ID:
required: true
MACOS_NOTARIZATION_APPLE_ID:
required: true
MACOS_NOTARIZATION_PASSWD:
required: true
workflow_dispatch:
inputs:
version:
Expand Down Expand Up @@ -326,20 +340,47 @@ jobs:
working-directory: client
timeout-minutes: 1

- name: Prepare codesign
shell: bash -o pipefail -eux {0}
if: matrix.platform == 'macos'
run: |
printenv MACOS_CERT | base64 --decode > certificate.p12
security create-keychain -p "${{ secrets.MACOS_CI_KEYCHAIN_PASSWD }}" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "${{ secrets.MACOS_CI_KEYCHAIN_PASSWD }}" build.keychain
security import certificate.p12 -k build.keychain -P "${{ secrets.MACOS_CERT_PASSWD }}" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${{ secrets.MACOS_CI_KEYCHAIN_PASSWD }}" build.keychain
env:
MACOS_CERT: ${{ secrets.MACOS_CERT }}
timeout-minutes: 2

- name: Build Electron apps
# What's about the extra `--` in `-- --nightly`?
# The reason is for npm to pass the flag `--nightly` to the underlying npm script.
# But since the base npm script `npm run electron:release` call another npm script,
# we need to escape the flag another time by adding another `--`.
run: >-
npm run electron:release
${{ (matrix.platform == 'linux' || inputs.nightly_build) && '--' || '' }}
${{ matrix.platform == 'linux' && 'appimage' || '' }}
${{ inputs.nightly_build && '--nightly' || '' }}
shell: bash -eux -o pipefail {0}
run: |
if ${{ matrix.platform == 'macos' }}; then
export CSC_LINK='${{ secrets.MACOS_CERT }}'
export CSC_KEY_PASSWORD='${{ secrets.MACOS_CERT_PASSWD }}'
export CSC_NAME='${{ secrets.MACOS_CERT_COMMON_NAME }}'
export CSC_IDENTITY_AUTO_DISCOVERY=true
export CSC_KEYCHAIN=build.keychain
export APPLE_TEAM_ID='${{ secrets.MACOS_NOTARIZATION_TEAM_ID }}'
export APPLE_ID='${{ secrets.MACOS_NOTARIZATION_APPLE_ID }}'
export APPLE_APP_SPECIFIC_PASSWORD='${{ secrets.MACOS_NOTARIZATION_PASSWD }}'
fi
npm run electron:release \
${{ (matrix.platform == 'linux' || inputs.nightly_build || matrix.platform == 'macos') && '--' || '' }} \
${{ matrix.platform == 'linux' && 'appimage' || '' }} \
${{ inputs.nightly_build && '--nightly' || '' }} \
${{ matrix.platform == 'macos' && '--sign' || ''}}
env:
PARSEC_APP_SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
working-directory: client/electron
timeout-minutes: 5
timeout-minutes: 10

- name: Upload client electron sourcemaps
run: npm run sentry:sourcemaps
Expand All @@ -365,7 +406,7 @@ jobs:
shell: bash
run: |
arch=$(uname -m)
app_file="Parsec_${{ steps.version.outputs.full }}_${{ matrix.os_alias }}_${arch}${{ matrix.platform == 'linux' && '' || '.unsigned'}}.${{ matrix.extension }}"
app_file="Parsec_${{ steps.version.outputs.full }}_${{ matrix.os_alias }}_${arch}${{ (matrix.platform == 'windows' || matrix.platform == 'linux') && '.unsigned' || '' }}.${{ matrix.extension }}"
latest_file="latest-${{ matrix.os_alias }}-${arch}.yml"
cat << EOF | tee -a $GITHUB_OUTPUT
Expand All @@ -380,9 +421,10 @@ jobs:
working-directory: client/electron/dist

- name: Sanity check that "latest" file contain the correct application file
shell: bash
run: |
cat "${{ steps.build-info.outputs.latest_file }}"
grep -e "${{ steps.build-info.outputs.app_file }}" "${{ steps.build-info.outputs.latest_file }}"
grep -q -e "${{ steps.build-info.outputs.app_file }}" "${{ steps.build-info.outputs.latest_file }}"
working-directory: client/electron/dist

- uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # pin v4.4.3
Expand Down
9 changes: 8 additions & 1 deletion .github/workflows/releaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ jobs:
nightly_build: ${{ github.event_name == 'schedule' || github.ref == 'refs/tags/nightly' }}
secrets:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
MACOS_CI_KEYCHAIN_PASSWD: ${{ secrets.MACOS_CI_KEYCHAIN_PASSWD }}
MACOS_CERT_PASSWD: ${{ secrets.MACOS_CERT_PASSWD }}
MACOS_CERT: ${{ secrets.MACOS_CERT }}
MACOS_CERT_COMMON_NAME: ${{ secrets.MACOS_CERT_COMMON_NAME }}
MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.MACOS_NOTARIZATION_TEAM_ID }}
MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.MACOS_NOTARIZATION_APPLE_ID }}
MACOS_NOTARIZATION_PASSWD: ${{ secrets.MACOS_NOTARIZATION_PASSWD }}

package-parsec-cli:
needs: version
Expand Down Expand Up @@ -116,7 +123,7 @@ jobs:
cp ${CP_ARGS} artifacts/linux-appimage-X64-electron/latest-linux-*.yml release-files
# DMG & ZIP
cp ${CP_ARGS} artifacts/macos-dmg-X64-electron/Parsec_${{ needs.version.outputs.full }}_mac_*.unsigned{.dmg,.zip}{,.blockmap} release-files
cp ${CP_ARGS} artifacts/macos-dmg-X64-electron/Parsec_${{ needs.version.outputs.full }}_mac_*.{dmg,zip}{,.blockmap} release-files
cp ${CP_ARGS} artifacts/macos-dmg-X64-electron/latest-mac-*.yml release-files
# TODO: Currently, Windows electron client is not signed by the CI, thus
Expand Down
4 changes: 2 additions & 2 deletions bindings/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ Install electron dependencies and build:
```bash
# In /bindings/electron
npm install
npm run build # Generate index.node (basically a .so that node can load)
npm run build # Generate libparsec.node (basically a .so that node can load)
```

> *Note: `../client/electron` project automatically does `npm build` and copy `index.node` where needed.*
> *Note: `../client/electron` project automatically does `npm build` and copy `libparsec.node` where needed.*
## 2. Android

Expand Down
2 changes: 1 addition & 1 deletion bindings/electron/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "libparsec_bindings_electron"
exclude = ["index.node"]
exclude = ["libparsec.node"]
publish.workspace = true
authors.workspace = true
edition.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion bindings/electron/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Basically `make.py` wraps the following commands:

```shell
npm install
# (re)generate index.node
# (re)generate dist/libparsec.node
npm run build:dev
# Or for release
npm run build:release
Expand Down
2 changes: 1 addition & 1 deletion bindings/electron/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "libparsec_bindings_electron",
"version": "3.1.1-a.0+dev",
"description": "",
"main": "index.node",
"main": "dist/libparsec.node",
"scripts": {
"build:ci": "node scripts/build.js ci",
"build:dev": "node scripts/build.js dev",
Expand Down
4 changes: 2 additions & 2 deletions bindings/electron/scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ function build_electron_bindings(cargo_flags) {
"cargo-cp-artifact",
"--npm",
"cdylib",
"dist/libparsec/index.node",
"dist/libparsec.node",
"--",
"cargo",
"build",
Expand Down Expand Up @@ -100,4 +100,4 @@ build_electron_bindings(cargo_flags);


// Finally, copy the typing info
fs.copyFileSync('src/index.d.ts', 'dist/libparsec/index.d.ts');
fs.copyFileSync('src/index.d.ts', 'dist/libparsec.d.ts');
2 changes: 1 addition & 1 deletion bindings/web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Basically `make.py` wraps the following commands:

```shell
npm install
# (re)generate index.node
# (re)generate dist/libparsec.node
npm run build:dev
# Or for release
npm run build:release
Expand Down
2 changes: 1 addition & 1 deletion client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ npm run electron:dist -- -- --dir # To debug the generated payload
npm run electron:dist -- -- --linux snap # To generate a subset (see `npx electron-builder build --help`)
```

> The `index.node` will be automatically copied by electron on build (see
> The `libparsec.node` will be automatically copied by electron on build (see
> `libparsec` script defined in `client/electron/package.json`)
## Android dev
Expand Down
7 changes: 7 additions & 0 deletions client/electron/macOS/entitlements.plist
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,12 @@
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<!--
We disable the validation for loaded dylib to be signed.
This is required because we need to load the dylib of macFUSE which is already installed on the system
and is not signed by the same team.
-->
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
19 changes: 17 additions & 2 deletions client/electron/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,23 @@ const fs = require('node:fs');
fs.mkdirSync('build/assets', { recursive: true });
fs.writeFileSync('build/assets/publishConfig.json', JSON.stringify(publishConfig));

const SIGN_OPTIONS = {
/**
* @type {Partial<import('app-builder-lib').WindowsConfiguration>}
*/
const WIN_SIGN_OPTIONS = {
certificateSubjectName: 'Scille',
certificateSha1: '9EB59B224218EE4B9C436CBD327BE60940592013',
};

/**
* @type {Partial<import('app-builder-lib').MacConfiguration>}
*/
const MACOS_SIGN_OPTIONS = {
notarize: {
teamId: process.env.APPLE_TEAM_ID,
},
};

const UNSIGNED_ARTIFACT_NAME =
OPTS.sign || OPTS.platform === 'linux'
? 'Parsec_${buildVersion}_${os}_${env.BUILD_MACHINE_ARCH}.${ext}'
Expand Down Expand Up @@ -138,7 +150,7 @@ const options = {

win: {
target: 'nsis',
...(OPTS.sign ? SIGN_OPTIONS : {}),
...(OPTS.sign ? WIN_SIGN_OPTIONS : {}),
extraResources: [
{
from: 'node_modules/regedit/vbs',
Expand All @@ -164,6 +176,9 @@ const options = {
hardenedRuntime: true,
entitlements: './macOS/entitlements.plist',
entitlementsInherit: './macOS/entitlements.plist',
...(OPTS.sign ? MACOS_SIGN_OPTIONS : {}),
// https://www.electron.build/mac#binaries
binaries: ['build/src/libparsec.node'],
},

linux: {
Expand Down
14 changes: 4 additions & 10 deletions client/electron/scripts/copy_bindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const fs = require('fs');
const path = require('path');

const WORKDIR = path.join(__dirname, '..');
const SRCDIR = path.join(WORKDIR, '../../bindings/electron/dist/libparsec');
const SRCDIR = path.join(WORKDIR, '../../bindings/electron/dist/');
const DSTDIR = path.join(WORKDIR, 'build');

function copy(src, dst) {
Expand All @@ -15,16 +15,10 @@ function copy(src, dst) {

const dstParent = path.dirname(dst);
console.log(`>>> mkdir -p ${path.relative(WORKDIR, dstParent)}`);
fs.mkdirSync(dstParent, {recursive: true});
fs.mkdirSync(dstParent, { recursive: true });
console.log(`>>> cp ${path.relative(WORKDIR, src)} ${path.relative(WORKDIR, dst)}`);
fs.copyFileSync(src, dst);
}

copy(
path.join(SRCDIR, 'index.node'),
path.join(DSTDIR, 'src/libparsec/index.node'),
);
copy(
path.join(SRCDIR, 'index.d.ts'),
path.join(DSTDIR, 'generated-ts/src/libparsec.d.ts'),
);
copy(path.join(SRCDIR, 'libparsec.node'), path.join(DSTDIR, 'src/libparsec.node'));
copy(path.join(SRCDIR, 'libparsec.d.ts'), path.join(DSTDIR, 'generated-ts/src/libparsec.d.ts'));
4 changes: 2 additions & 2 deletions client/electron/snap/snapcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ parts:
npm clean-install
npm run build:release
cp -va dist/libparsec/index.node "$CRAFT_PART_INSTALL/libparsec.node"
cp -va dist/libparsec/index.d.ts "$CRAFT_PART_INSTALL/libparsec.d.ts"
cp -va dist/libparsec.node "$CRAFT_PART_INSTALL/libparsec.node"
cp -va dist/libparsec.d.ts "$CRAFT_PART_INSTALL/libparsec.d.ts"
# We pre-package `megashark-lib` to workaround a permission issue during it's `prepare` step when installed as a 3rd dependencies from `client-vite`.
megashark-lib:
Expand Down
2 changes: 1 addition & 1 deletion client/electron/src/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ export class ElectronCapacitorApp {
this.MainWindow.show();
}
setTimeout(() => {
if (electronIsDev) {
if (electronIsDev || process.env.OPEN_DEV_TOOLS == 'true') {
this.MainWindow.webContents.openDevTools();
}
CapElectronEventEmitter.emit('CAPELECTRON_DeeplinkListenerInitialized', '');
Expand Down

0 comments on commit f9e6baa

Please sign in to comment.