Skip to content

Commit 268fa30

Browse files
feat: allow notarization on macOS versions down to 10.15 (#201)
* notarytoolPath option * Removed NotaryToolOptions interface * Update README.md Co-authored-by: Erick Zhao <[email protected]> * Removed unnecessary typeof uses --------- Co-authored-by: Erick Zhao <[email protected]>
1 parent 4ac5fba commit 268fa30

File tree

4 files changed

+31
-7
lines changed

4 files changed

+31
-7
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,18 @@ For notarization, you need the following things:
4040
> If you are using Electron 11 or below, you must add the `com.apple.security.cs.allow-unsigned-executable-memory` entitlement too.
4141
> When using version 12+, this entitlement should not be applied as it increases your app's attack surface.
4242
43+
### Notarization on older macOS versions
44+
45+
Xcode 13 is available from macOS 11.3, but notarization can be performed on systems down to macOS 10.15
46+
(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).
47+
48+
To achieve this, you can copy notarytool binary from a newer macOS version and provide its path as `notarytoolPath` option.
49+
4350
## API
4451

4552
`@electron/notarize` exposes a single `notarize` function that accepts the following parameters:
4653
* `appPath` — the absolute path to your codesigned and packaged Electron application.
54+
* `notarytoolPath` - String (optional) - Path of the notarytool binary ([more details](#notarization-on-older-macos-versions))
4755
* additional options required for authenticating your Apple ID (see below)
4856

4957
The method returns a void Promise once app notarization is complete. Please note that notarization may take

src/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ async function notarize({ appPath, ...otherOptions }: NotarizeOptions) {
4545

4646
d('notarizing using notarytool');
4747
if (!(await isNotaryToolAvailable())) {
48-
throw new Error('notarytool is not available, you must be on at least Xcode 13');
48+
throw new Error(
49+
'notarytool is not available, you must be on at least Xcode 13 or provide notarytoolPath',
50+
);
4951
}
5052

5153
await notarizeAndWaitForNotaryTool({

src/notarytool.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ import { NotaryToolCredentials, NotaryToolStartOptions } from './types';
1212

1313
const d = debug('electron-notarize:notarytool');
1414

15+
function runNotaryTool(args: string[], notarytoolPath?: string) {
16+
const useXcrun = notarytoolPath === undefined;
17+
const cmd = useXcrun ? 'xcrun' : notarytoolPath;
18+
return spawn(cmd, useXcrun ? ['notarytool', ...args] : args);
19+
}
20+
1521
function authorizationArgs(rawOpts: NotaryToolCredentials): string[] {
1622
const opts = validateNotaryToolAuthorizationArgs(rawOpts);
1723
if (isNotaryToolPasswordCredentials(opts)) {
@@ -43,17 +49,25 @@ function authorizationArgs(rawOpts: NotaryToolCredentials): string[] {
4349

4450
async function getNotarizationLogs(opts: NotaryToolStartOptions, id: string) {
4551
try {
46-
const logResult = await spawn('xcrun', ['notarytool', 'log', id, ...authorizationArgs(opts)]);
52+
const logResult = await runNotaryTool(
53+
['log', id, ...authorizationArgs(opts)],
54+
opts.notarytoolPath,
55+
);
4756
d('notarization log', logResult.output);
4857
return logResult.output;
4958
} catch (e) {
5059
d('failed to pull notarization logs', e);
5160
}
5261
}
5362

54-
export async function isNotaryToolAvailable() {
55-
const result = await spawn('xcrun', ['--find', 'notarytool']);
56-
return result.code === 0;
63+
export async function isNotaryToolAvailable(notarytoolPath?: string) {
64+
if (notarytoolPath !== undefined) {
65+
const result = await spawn(notarytoolPath, ['--version']);
66+
return result.code === 0;
67+
} else {
68+
const result = await spawn('xcrun', ['--find', 'notarytool']);
69+
return result.code === 0;
70+
}
5771
}
5872

5973
export async function notarizeAndWaitForNotaryTool(opts: NotaryToolStartOptions) {
@@ -83,7 +97,6 @@ export async function notarizeAndWaitForNotaryTool(opts: NotaryToolStartOptions)
8397
}
8498

8599
const notarizeArgs = [
86-
'notarytool',
87100
'submit',
88101
filePath,
89102
...authorizationArgs(opts),
@@ -92,7 +105,7 @@ export async function notarizeAndWaitForNotaryTool(opts: NotaryToolStartOptions)
92105
'json',
93106
];
94107

95-
const result = await spawn('xcrun', notarizeArgs);
108+
const result = await runNotaryTool(notarizeArgs, opts.notarytoolPath);
96109
const rawOut = result.output.trim();
97110

98111
let parsed: any;

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ export interface NotaryToolNotarizeAppOptions {
129129
* Absolute path to your packaged and codesigned Electron application.
130130
*/
131131
appPath: string;
132+
notarytoolPath?: string;
132133
}
133134

134135
/**

0 commit comments

Comments
 (0)