diff --git a/README.md b/README.md index cea6de6..f07b8cd 100644 --- a/README.md +++ b/README.md @@ -40,10 +40,18 @@ 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.15 +(see [TN3147](https://developer.apple.com/documentation/technotes/tn3147-migrating-to-the-latest-notarization-tool#Enable-notarization-on-an-older-version-of-macOS) for more information). + +To achieve this, you can copy notarytool binary from a newer macOS version and provide its path as `notarytoolPath` option. + ## API `@electron/notarize` exposes a single `notarize` function that accepts the following parameters: * `appPath` — the absolute path to your codesigned and packaged Electron application. +* `notarytoolPath` - String (optional) - Path of the notarytool binary ([more details](#notarization-on-older-macos-versions)) * additional options required for authenticating your Apple ID (see below) The method returns a void Promise once app notarization is complete. Please note that notarization may take diff --git a/src/index.ts b/src/index.ts index f83f951..e47249e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -45,7 +45,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 3e0386b..c31103a 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 = 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)) { @@ -43,7 +49,10 @@ function authorizationArgs(rawOpts: NotaryToolCredentials): string[] { async function getNotarizationLogs(opts: NotaryToolStartOptions, id: string) { try { - const logResult = await spawn('xcrun', ['notarytool', 'log', id, ...authorizationArgs(opts)]); + const logResult = await runNotaryTool( + ['log', id, ...authorizationArgs(opts)], + opts.notarytoolPath, + ); d('notarization log', logResult.output); return logResult.output; } catch (e) { @@ -51,9 +60,14 @@ async function getNotarizationLogs(opts: NotaryToolStartOptions, id: string) { } } -export async function isNotaryToolAvailable() { - const result = await spawn('xcrun', ['--find', 'notarytool']); - return result.code === 0; +export async function isNotaryToolAvailable(notarytoolPath?: string) { + if (notarytoolPath !== undefined) { + const result = await spawn(notarytoolPath, ['--version']); + return result.code === 0; + } else { + const result = await spawn('xcrun', ['--find', 'notarytool']); + return result.code === 0; + } } export async function notarizeAndWaitForNotaryTool(opts: NotaryToolStartOptions) { @@ -83,7 +97,6 @@ export async function notarizeAndWaitForNotaryTool(opts: NotaryToolStartOptions) } const notarizeArgs = [ - 'notarytool', 'submit', filePath, ...authorizationArgs(opts), @@ -92,7 +105,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; diff --git a/src/types.ts b/src/types.ts index e28d39e..03a8bd6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -129,6 +129,7 @@ export interface NotaryToolNotarizeAppOptions { * Absolute path to your packaged and codesigned Electron application. */ appPath: string; + notarytoolPath?: string; } /**