mirror of
https://github.com/siyuan-note/siyuan.git
synced 2026-07-03 14:09:06 +02:00
116 lines
3.5 KiB
JavaScript
116 lines
3.5 KiB
JavaScript
/**
|
|
* macOS 开发环境:为 node_modules 中的 Electron.app 代码签名。
|
|
*
|
|
* 背景:Electron 42+ 在 macOS 上使用 UNNotification,要求应用具备有效代码签名;
|
|
* 刚安装的 Electron.app 仅有 linker-signed 占位签名,开发时通知会静默失败。
|
|
*
|
|
* 用法(在 app 目录下):
|
|
* pnpm run install:electron # 安装 / 更新 Electron 二进制
|
|
* pnpm run sign:dev # macOS 开发者手动签名,供本地通知等功能使用
|
|
*
|
|
* 非 macOS 平台直接跳过。无可用证书时仅打印提示并以退出码 0 结束。
|
|
* 可通过环境变量 SIYUAN_DEV_SIGN_IDENTITY 或 CSC_NAME 指定证书名称。
|
|
*/
|
|
const {execFileSync} = require("child_process");
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
|
|
const PREFERRED_IDENTITY_PATTERNS = [
|
|
/^Apple Development:/,
|
|
/^Developer ID Application:/,
|
|
/^Mac Developer:/,
|
|
];
|
|
|
|
function resolveElectronApp() {
|
|
let electronPkg;
|
|
try {
|
|
electronPkg = require.resolve("electron/package.json");
|
|
} catch {
|
|
return null;
|
|
}
|
|
const appPath = path.join(path.dirname(electronPkg), "dist", "Electron.app");
|
|
return fs.existsSync(appPath) ? appPath : null;
|
|
}
|
|
|
|
function listCodeSignIdentities() {
|
|
let output;
|
|
try {
|
|
output = execFileSync("security", ["find-identity", "-v", "-p", "codesigning"], {
|
|
encoding: "utf8",
|
|
});
|
|
} catch {
|
|
return [];
|
|
}
|
|
const identities = [];
|
|
for (const line of output.split("\n")) {
|
|
// 1) ABCD1234 "Apple Development: name (TEAMID)"
|
|
const match = line.match(/^\s*\d+\)\s+[0-9A-F]+\s+"(.+)"\s*$/);
|
|
if (match) {
|
|
identities.push(match[1]);
|
|
}
|
|
}
|
|
return identities;
|
|
}
|
|
|
|
function pickIdentity(identities) {
|
|
const envIdentity = process.env.SIYUAN_DEV_SIGN_IDENTITY || process.env.CSC_NAME;
|
|
if (envIdentity) {
|
|
if (identities.includes(envIdentity)) {
|
|
return envIdentity;
|
|
}
|
|
console.warn(`sign:dev: identity not found: ${envIdentity}, auto-selecting`);
|
|
}
|
|
for (const pattern of PREFERRED_IDENTITY_PATTERNS) {
|
|
const found = identities.find((name) => pattern.test(name));
|
|
if (found) {
|
|
return found;
|
|
}
|
|
}
|
|
return identities[0] || null;
|
|
}
|
|
|
|
function getCodesignInfo(appPath) {
|
|
try {
|
|
const result = require("child_process").spawnSync("codesign", ["-dvv", appPath], {encoding: "utf8"});
|
|
return (result.stdout || "") + (result.stderr || "");
|
|
} catch {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
function isAlreadySigned(appPath) {
|
|
const output = getCodesignInfo(appPath);
|
|
return !/linker-signed/.test(output) && /Authority=/.test(output);
|
|
}
|
|
|
|
function main() {
|
|
if (process.platform !== "darwin") {
|
|
return;
|
|
}
|
|
|
|
const appPath = resolveElectronApp();
|
|
if (!appPath) {
|
|
console.warn("sign:dev: Electron.app not found, run install:electron first");
|
|
return;
|
|
}
|
|
|
|
const identities = listCodeSignIdentities();
|
|
const identity = pickIdentity(identities);
|
|
if (!identity) {
|
|
console.warn("sign:dev: no codesigning identity (macOS notifications may not work)");
|
|
console.warn("sign:dev: sign in with Apple ID in Xcode, or set SIYUAN_DEV_SIGN_IDENTITY");
|
|
return;
|
|
}
|
|
|
|
if (isAlreadySigned(appPath)) {
|
|
console.log(`sign:dev: already signed (${identity})`);
|
|
return;
|
|
}
|
|
|
|
console.log(`sign:dev: signing with ${identity}`);
|
|
execFileSync("codesign", ["--force", "--deep", "--sign", identity, appPath], {stdio: "inherit"});
|
|
console.log("sign:dev: done");
|
|
}
|
|
|
|
main();
|