feat: add macOS ad-hoc signing support

- Implemented afterPack script to ensure ad-hoc signature for macOS builds.
- Created macosSignUtils module to handle app path retrieval, signature inspection, and ad-hoc signing.
- Added functions to check if the app is signed and apply ad-hoc signing if necessary.
This commit is contained in:
cita
2026-03-06 19:58:38 +08:00
parent 19125d686e
commit 6c51801e50
8 changed files with 142 additions and 55 deletions
+7
View File
@@ -0,0 +1,7 @@
import { ensureAdHocSignature, getMacAppPath } from './macosSignUtils.mjs';
export default async function afterPack(context) {
if (context.electronPlatformName !== 'darwin') return;
await ensureAdHocSignature(getMacAppPath(context));
}
+8 -24
View File
@@ -1,41 +1,25 @@
import { notarize } from '@electron/notarize';
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
const execFileAsync = promisify(execFile);
async function hasSignature(appPath) {
try {
await execFileAsync('codesign', ['--verify', '--deep', '--strict', appPath]);
return true;
} catch {
return false;
}
}
async function adHocSign(appPath) {
await execFileAsync('codesign', ['--force', '--deep', '--sign', '-', appPath]);
}
import { ensureAdHocSignature, getMacAppPath } from './macosSignUtils.mjs';
export default async function afterSign(context) {
if (context.electronPlatformName !== 'darwin') return;
const appPath = `${context.appOutDir}/${context.packager.appInfo.productFilename}.app`;
const appPath = getMacAppPath(context);
const appleId = process.env.APPLE_ID || process.env.APPLEID;
const appleIdPassword = process.env.APPLE_APP_SPECIFIC_PASSWORD || process.env.APPLEIDPASS;
const teamId = process.env.APPLE_TEAM_ID;
const signed = await hasSignature(appPath);
if (!signed) {
console.log('[metapi-desktop] No macOS signing identity detected, applying ad-hoc signature.');
await adHocSign(appPath);
}
const signature = await ensureAdHocSignature(appPath);
if (!appleId || !appleIdPassword || !teamId) {
console.log('[metapi-desktop] Skipping notarization: APPLE_ID / APPLE_APP_SPECIFIC_PASSWORD / APPLE_TEAM_ID not fully configured.');
return;
}
if (signature.isAdHoc) {
console.log('[metapi-desktop] Skipping notarization: macOS app is only ad-hoc signed. Configure a Developer ID certificate to enable notarization.');
return;
}
console.log('[metapi-desktop] Notarizing macOS build...');
await notarize({
appPath,
+41
View File
@@ -0,0 +1,41 @@
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
const execFileAsync = promisify(execFile);
export function getMacAppPath(context) {
return `${context.appOutDir}/${context.packager.appInfo.productFilename}.app`;
}
export async function inspectSignature(appPath) {
try {
const { stdout, stderr } = await execFileAsync('codesign', ['-dv', '--verbose=4', appPath]);
const output = `${stdout}\n${stderr}`;
return {
signed: true,
isAdHoc: /Signature=adhoc/i.test(output) || !/Authority=/i.test(output),
details: output,
};
} catch {
return {
signed: false,
isAdHoc: false,
details: '',
};
}
}
export async function adHocSign(appPath) {
await execFileAsync('codesign', ['--force', '--deep', '--sign', '-', appPath]);
}
export async function ensureAdHocSignature(appPath) {
const signature = await inspectSignature(appPath);
if (signature.signed) {
return signature;
}
console.log('[metapi-desktop] No macOS signing identity detected, applying ad-hoc signature.');
await adHocSign(appPath);
return inspectSignature(appPath);
}