update
This commit is contained in:
1 parent
66158e222e
commit
67c757f481
314 files changed
+37945
-22962
No files matched your search
@@ -0,0 +1,151 @@
|
||||
import { spawn } from "node:child_process";
|
||||
import { readdir } from "node:fs/promises";
|
||||
import { extname } from "node:path";
|
||||
|
||||
function delay(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function runCommand(command, args, capture = false) {
|
||||
return await new Promise((resolve, reject) => {
|
||||
const child = spawn(command, args, {
|
||||
stdio: capture ? ["ignore", "pipe", "pipe"] : "inherit",
|
||||
});
|
||||
let stdout = "";
|
||||
let stderr = "";
|
||||
|
||||
if (capture) {
|
||||
child.stdout.on("data", (chunk) => {
|
||||
stdout += chunk.toString();
|
||||
});
|
||||
child.stderr.on("data", (chunk) => {
|
||||
stderr += chunk.toString();
|
||||
});
|
||||
}
|
||||
|
||||
child.on("error", reject);
|
||||
child.on("close", (code) => {
|
||||
if (code === 0) {
|
||||
resolve({ stdout, stderr });
|
||||
return;
|
||||
}
|
||||
reject(new Error(stderr || stdout || `${command} failed with exit code ${code ?? 1}`));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function runCodesign(args) {
|
||||
await runCommand("/usr/bin/codesign", args, false);
|
||||
}
|
||||
|
||||
function buildCodesignArgs(targetPath, identity, keychain, fileOptions = {}) {
|
||||
const args = [
|
||||
"--sign", identity,
|
||||
"--force",
|
||||
];
|
||||
|
||||
if (keychain) {
|
||||
args.push("--keychain", keychain);
|
||||
}
|
||||
if (fileOptions.timestamp !== false) {
|
||||
args.push("--timestamp");
|
||||
}
|
||||
if (fileOptions.hardenedRuntime) {
|
||||
args.push("--options", "runtime");
|
||||
}
|
||||
if (fileOptions.entitlements) {
|
||||
args.push("--entitlements", fileOptions.entitlements);
|
||||
}
|
||||
if (Array.isArray(fileOptions.additionalArguments) && fileOptions.additionalArguments.length > 0) {
|
||||
args.push(...fileOptions.additionalArguments);
|
||||
}
|
||||
|
||||
args.push(targetPath);
|
||||
return args;
|
||||
}
|
||||
|
||||
async function isMachBinary(filePath) {
|
||||
const extension = extname(filePath);
|
||||
if (extension === ".dylib" || extension === ".node") {
|
||||
return true;
|
||||
}
|
||||
|
||||
const { stdout } = await runCommand("/usr/bin/file", ["-b", filePath], true);
|
||||
return stdout.includes("Mach-O");
|
||||
}
|
||||
|
||||
async function collectSignTargets(rootPath) {
|
||||
const bundleTargets = [];
|
||||
const binaryTargets = [];
|
||||
|
||||
async function walk(currentPath) {
|
||||
const entries = await readdir(currentPath, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
const fullPath = `${currentPath}/${entry.name}`;
|
||||
|
||||
if (entry.isSymbolicLink()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
if (
|
||||
entry.name.endsWith(".app") ||
|
||||
entry.name.endsWith(".framework") ||
|
||||
entry.name.endsWith(".xpc") ||
|
||||
entry.name.endsWith(".appex") ||
|
||||
entry.name.endsWith(".plugin")
|
||||
) {
|
||||
bundleTargets.push(fullPath);
|
||||
}
|
||||
await walk(fullPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (await isMachBinary(fullPath)) {
|
||||
binaryTargets.push(fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await walk(rootPath);
|
||||
|
||||
bundleTargets.sort((left, right) => right.length - left.length);
|
||||
binaryTargets.sort((left, right) => right.length - left.length);
|
||||
|
||||
return { bundleTargets, binaryTargets };
|
||||
}
|
||||
|
||||
async function signTarget(targetPath, context) {
|
||||
const fileOptions = context.optionsForFile?.(targetPath) ?? {};
|
||||
const args = buildCodesignArgs(targetPath, context.identity, context.keychain, fileOptions);
|
||||
|
||||
let lastError;
|
||||
for (let attempt = 0; attempt < 3; attempt += 1) {
|
||||
try {
|
||||
await runCodesign(args);
|
||||
return;
|
||||
} catch (error) {
|
||||
lastError = error;
|
||||
if (attempt === 2) {
|
||||
throw error;
|
||||
}
|
||||
await delay(5000);
|
||||
}
|
||||
}
|
||||
|
||||
throw lastError;
|
||||
}
|
||||
|
||||
export default async function sign(context) {
|
||||
const { bundleTargets, binaryTargets } = await collectSignTargets(context.app);
|
||||
|
||||
for (const target of binaryTargets) {
|
||||
await signTarget(target, context);
|
||||
}
|
||||
|
||||
for (const target of bundleTargets) {
|
||||
await signTarget(target, context);
|
||||
}
|
||||
|
||||
await signTarget(context.app, context);
|
||||
}
|
||||
Reference in new issue
Block a user