signing-enclave
Version:
A code signing and notarization tool for macOS and Windows applications. Uses Azure Key Vault for secret and certificate management.
105 lines • 4.68 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.downloadMacCertificateFromHSM = downloadMacCertificateFromHSM;
exports.macOsSign = macOsSign;
const execa_1 = __importDefault(require("execa"));
const secretClient_1 = require("./secretClient");
const osx_sign_1 = require("@electron/osx-sign");
async function downloadMacCertificateFromHSM(certName) {
return await (0, secretClient_1.downloadCertificateFile)(certName, { postfix: ".p12" });
}
/**
* Imports the certificate into a temporary Keychain.
* @param {string} tempFilePath - Path to the temporary p12/pfx file.
* @param {string} keychainName - Name of the temporary Keychain.
* @param {string} keychainPassword - Password for the temporary Keychain.
*/
async function importCertToKeychain(tempFilePath, keychainName, keychainPassword) {
await (0, execa_1.default)(`security list-keychains -d user -s login.keychain`, {
shell: "/bin/bash",
});
// Create the temporary Keychain
await (0, execa_1.default)(`security create-keychain -p ${keychainPassword} ${keychainName}`, { shell: "/bin/bash" });
// Append temp keychain to the user domain
await (0, execa_1.default)(`security list-keychains -d user -s ${keychainName} $(security list-keychains -d user | sed s/\\"//g)`, { shell: "/bin/bash" });
// Remove relock timeout
await (0, execa_1.default)(`security set-keychain-settings ${keychainName}`, {
shell: "/bin/bash",
});
// Unlock the Keychain
await (0, execa_1.default)(`security unlock-keychain -p ${keychainPassword} ${keychainName}`, { shell: "/bin/bash" });
// Import the p12 file into the temporary Keychain
await (0, execa_1.default)(`security import "${tempFilePath}" -k "${keychainName}" -P "" -T /usr/bin/codesign`, { shell: "/bin/bash" });
const identity = await findSigningIdentity(keychainName);
// Enable codesigning from a non user interactive shell
await (0, execa_1.default)(`security set-key-partition-list -S apple-tool:,apple:, -s -k ${keychainPassword} -D "${identity}" -t private ${keychainName}`, { shell: "/bin/bash" });
return identity;
}
/**
* Finds the signing identity in the Keychain.
* @param {string} keychainName - Name of the Keychain.
* @returns {string} - The signing identity name.
*/
async function findSigningIdentity(keychainName) {
const output = (await (0, execa_1.default)(`security find-identity -p codesigning -v "${keychainName}"`, {
shell: "/bin/bash",
})).stdout;
const match = output.match(/"([^"]+)"/);
if (match && match[1]) {
return match[1];
}
else {
throw new Error("No valid signing identity found.");
}
}
/**
* Deletes the temporary Keychain.
* @param {string} keychainName - Name of the Keychain to delete.
*/
async function deleteKeychain(keychainName) {
console.log(`Deleting keychain: ${keychainName}`);
await (0, execa_1.default)(`security delete-keychain "${keychainName}"`, {
shell: "/bin/bash",
});
}
/**
* Signs an application using a certificate from Azure KeyVault.
* @param pathToSign - The path to the application to sign.
* @param certName - The name of the certificate to use on Azure KeyVault.
*/
async function macOsSign(pathToSign, $certName) {
const hrstart = process.hrtime();
const keychain = crypto.randomUUID();
const keychainPassword = crypto.randomUUID();
const tempFile = await downloadMacCertificateFromHSM($certName);
try {
const identity = await importCertToKeychain(tempFile.secretFilePath, keychain, keychainPassword);
try {
await tempFile.cleanup();
const initTime = process.hrtime(hrstart);
console.debug(`Cert imported in ${initTime[0]}s ${(initTime[1] / 1000000).toFixed(0)}ms: ${$certName}`);
const hrsignstart = process.hrtime();
console.log(`Signing: ${pathToSign}`);
await (0, osx_sign_1.signAsync)({
app: pathToSign,
keychain: keychain,
identity: identity,
strictVerify: false,
});
const signTime = process.hrtime(hrsignstart);
console.debug(`Signed in ${signTime[0]}s ${(signTime[1] / 1000000).toFixed(0)}ms: ${$certName}`);
}
finally {
await deleteKeychain(keychain);
}
}
catch (error) {
console.error(error);
await tempFile.cleanup();
throw error;
}
}
//# sourceMappingURL=macOSSigning.js.map