From fefd4cb9972c07a01684df8f3ef2d0f6cdbc4fef Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 6 Jun 2024 20:36:07 +0200 Subject: [PATCH] notarytoolPath option --- README.md | 7 +++++++ src/index.ts | 4 +++- src/notarytool.ts | 25 ++++++++++++++++--------- src/types.ts | 8 +++++++- 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index aa62268..ab4d214 100644 --- a/README.md +++ b/README.md @@ -39,12 +39,19 @@ For notarization, you need the following things: If you are using Electron 11 or below, you must add the `com.apple.security.cs.allow-unsigned-executable-memory` entitlement too. When using version 12+, this entitlement should not be applied as it increases your app's attack surface. +### Notarization on older macOS versions + +Xcode 13 is available from macOS 11.3, but notarization can be performed on systems down to macOS 10.5 ([source](https://developer.apple.com/documentation/technotes/tn3147-migrating-to-the-latest-notarization-tool#Enable-notarization-on-an-older-version-of-macOS)). + +To achieve this, you can copy notarytool binary from a newer macOS version and provide its path as `notarytoolPath` option. + ## API ### Method: `notarize(opts): Promise` * `options` Object * `tool` String - The notarization tool to use, default is `notarytool`. Previously, the value `legacy` used `altool`, which [**stopped working** on November 1st 2023](https://developer.apple.com/news/?id=y5mjxqmn). + * `notarytoolPath` - String (optional) - Path of the notarytool binary ([more details](#notarization-on-older-macos-versions)) * `appPath` String - The absolute path to your `.app` file * There are three authentication methods available: * user name with password: diff --git a/src/index.ts b/src/index.ts index ac45c13..a334979 100644 --- a/src/index.ts +++ b/src/index.ts @@ -32,7 +32,9 @@ async function notarize({ appPath, ...otherOptions }: NotarizeOptions) { d('notarizing using notarytool'); if (!(await isNotaryToolAvailable())) { - throw new Error('notarytool is not available, you must be on at least Xcode 13'); + throw new Error( + 'notarytool is not available, you must be on at least Xcode 13 or provide notarytoolPath', + ); } await notarizeAndWaitForNotaryTool({ diff --git a/src/notarytool.ts b/src/notarytool.ts index 51ef7d7..038a4ec 100644 --- a/src/notarytool.ts +++ b/src/notarytool.ts @@ -12,6 +12,12 @@ import { NotaryToolCredentials, NotaryToolStartOptions } from './types'; const d = debug('electron-notarize:notarytool'); +function runNotaryTool(args: string[], notarytoolPath?: string) { + const useXcrun = typeof notarytoolPath === 'undefined'; + const cmd = useXcrun ? 'xcrun' : notarytoolPath; + return spawn(cmd, useXcrun ? ['notarytool', ...args] : args); +} + function authorizationArgs(rawOpts: NotaryToolCredentials): string[] { const opts = validateNotaryToolAuthorizationArgs(rawOpts); if (isNotaryToolPasswordCredentials(opts)) { @@ -41,7 +47,11 @@ function authorizationArgs(rawOpts: NotaryToolCredentials): string[] { } } -export async function isNotaryToolAvailable() { +export async function isNotaryToolAvailable(notarytoolPath?: string) { + if (typeof notarytoolPath !== 'undefined') { + const result = await spawn(notarytoolPath, ['--version']); + return result.code === 0; + } const result = await spawn('xcrun', ['--find', 'notarytool']); return result.code === 0; } @@ -73,7 +83,6 @@ export async function notarizeAndWaitForNotaryTool(opts: NotaryToolStartOptions) } const notarizeArgs = [ - 'notarytool', 'submit', filePath, ...authorizationArgs(opts), @@ -82,7 +91,7 @@ export async function notarizeAndWaitForNotaryTool(opts: NotaryToolStartOptions) 'json', ]; - const result = await spawn('xcrun', notarizeArgs); + const result = await runNotaryTool(notarizeArgs, opts.notarytoolPath); const rawOut = result.output.trim(); let parsed: any; @@ -102,12 +111,10 @@ export async function notarizeAndWaitForNotaryTool(opts: NotaryToolStartOptions) let logOutput: undefined | string; if (parsed.id) { try { - const logResult = await spawn('xcrun', [ - 'notarytool', - 'log', - parsed.id, - ...authorizationArgs(opts), - ]); + const logResult = await runNotaryTool( + ['log', parsed.id, ...authorizationArgs(opts)], + opts.notarytoolPath, + ); d('notarization log', logResult.output); logOutput = logResult.output; } catch (e) { diff --git a/src/types.ts b/src/types.ts index a360cba..df57579 100644 --- a/src/types.ts +++ b/src/types.ts @@ -47,6 +47,10 @@ export interface NotaryToolNotarizeAppOptions { appPath: string; } +export interface NotaryToolOptions { + notarytoolPath?: string; +} + export interface TransporterOptions { ascProvider?: string; } @@ -59,7 +63,9 @@ export interface NotarizeResult { export type LegacyNotarizeStartOptions = LegacyNotarizeAppOptions & LegacyNotarizeCredentials & TransporterOptions; -export type NotaryToolStartOptions = NotaryToolNotarizeAppOptions & NotaryToolCredentials; +export type NotaryToolStartOptions = NotaryToolNotarizeAppOptions & + NotaryToolOptions & + NotaryToolCredentials; /** @deprecated */ export type LegacyNotarizeWaitOptions = NotarizeResult & LegacyNotarizeCredentials; export type NotarizeStapleOptions = Pick;