UNPKG

vrrv-installer-builder

Version:

A complete solution to package and build a ready for distribution Electron app for MacOS, Windows and Linux with “auto update” support out of the box

165 lines (164 loc) 8.76 kB
"use strict"; const util_1 = require("./util/util"); const fs_extra_p_1 = require("fs-extra-p"); const httpRequest_1 = require("./util/httpRequest"); const path = require("path"); const promise_1 = require("./util/promise"); const bluebird_1 = require("bluebird"); const crypto_1 = require("crypto"); const os_1 = require("os"); //noinspection JSUnusedLocalSymbols const __awaiter = require("./util/awaiter"); const appleCertificatePrefixes = ["Developer ID Application:", "3rd Party Mac Developer Application:", "Developer ID Installer:", "3rd Party Mac Developer Installer:"]; function downloadCertificate(urlOrBase64, tmpDir) { if (urlOrBase64.startsWith("file://")) { return bluebird_1.Promise.resolve(urlOrBase64.substring("file://".length)); } return tmpDir.getTempFile(".p12").then(tempFile => (urlOrBase64.startsWith("https://") ? httpRequest_1.download(urlOrBase64, tempFile) : fs_extra_p_1.outputFile(tempFile, new Buffer(urlOrBase64, "base64"))).thenReturn(tempFile)); } exports.downloadCertificate = downloadCertificate; let bundledCertKeychainAdded = null; // "Note that filename will not be searched to resolve the signing identity's certificate chain unless it is also on the user's keychain search list." // but "security list-keychains" doesn't support add - we should 1) get current list 2) set new list - it is very bad http://stackoverflow.com/questions/10538942/add-a-keychain-to-search-list // "overly complicated and introduces a race condition." // https://github.com/electron-userland/electron-builder/issues/398 function createCustomCertKeychain() { return __awaiter(this, void 0, void 0, function* () { // copy to temp and then atomic rename to final path const tmpKeychainPath = path.join(os_1.homedir(), ".cache", util_1.getTempName("electron_builder_root_certs")); const keychainPath = path.join(os_1.homedir(), ".cache", "electron_builder_root_certs.keychain"); const results = yield bluebird_1.Promise.all([util_1.exec("security", ["list-keychains"]), fs_extra_p_1.copy(path.join(__dirname, "..", "certs", "root_certs.keychain"), tmpKeychainPath).then(() => fs_extra_p_1.rename(tmpKeychainPath, keychainPath))]); const list = results[0].split("\n").map(it => { let r = it.trim(); return r.substring(1, r.length - 1); }).filter(it => it.length > 0); if (!(list.indexOf(keychainPath) !== -1)) { yield util_1.exec("security", ["list-keychains", "-d", "user", "-s", keychainPath].concat(list)); } }); } function createKeychain(tmpDir, cscLink, cscKeyPassword, cscILink, cscIKeyPassword) { return __awaiter(this, void 0, void 0, function* () { if (bundledCertKeychainAdded == null) { bundledCertKeychainAdded = createCustomCertKeychain(); } yield bundledCertKeychainAdded; const keychainName = yield tmpDir.getTempFile(".keychain"); const certLinks = [cscLink]; if (cscILink != null) { certLinks.push(cscILink); } const certPaths = new Array(certLinks.length); const keychainPassword = crypto_1.randomBytes(8).toString("hex"); return yield promise_1.executeFinally(bluebird_1.Promise.all([bluebird_1.Promise.map(certLinks, (link, i) => downloadCertificate(link, tmpDir).then(it => certPaths[i] = it)), bluebird_1.Promise.mapSeries([["create-keychain", "-p", keychainPassword, keychainName], ["unlock-keychain", "-p", keychainPassword, keychainName], ["set-keychain-settings", "-t", "3600", "-u", keychainName]], it => util_1.exec("security", it))]).then(() => importCerts(keychainName, certPaths, [cscKeyPassword, cscIKeyPassword].filter(it => it != null))), () => promise_1.all(certPaths.map((it, index) => certLinks[index].startsWith("https://") ? fs_extra_p_1.deleteFile(it, true) : bluebird_1.Promise.resolve()))); }); } exports.createKeychain = createKeychain; function importCerts(keychainName, paths, keyPasswords) { return __awaiter(this, void 0, void 0, function* () { for (let i = 0; i < paths.length; i++) { yield util_1.exec("security", ["import", paths[i], "-k", keychainName, "-T", "/usr/bin/codesign", "-T", "/usr/bin/productbuild", "-P", keyPasswords[i]]); } return { keychainName: keychainName }; }); } function sign(path, name, keychain) { const args = ["--deep", "--force", "--sign", name, path]; if (keychain != null) { args.push("--keychain", keychain); } return util_1.exec("codesign", args); } exports.sign = sign; exports.findIdentityRawResult = null; function getValidIdentities(keychain) { return __awaiter(this, void 0, void 0, function* () { function addKeychain(args) { if (keychain != null) { args.push(keychain); } return args; } let result = exports.findIdentityRawResult; if (result == null || keychain != null) { // https://github.com/electron-userland/electron-builder/issues/481 // https://github.com/electron-userland/electron-builder/issues/535 result = bluebird_1.Promise.all([util_1.exec("security", addKeychain(["find-identity", "-v"])).then(it => it.trim().split("\n").filter(it => { for (let prefix of appleCertificatePrefixes) { if (it.indexOf(prefix) !== -1) { return true; } } return false; })), util_1.exec("security", addKeychain(["find-identity", "-v", "-p", "codesigning"])).then(it => it.trim().split("\n"))]).then(it => { const array = it[0].concat(it[1]).filter(it => !(it.indexOf("(Missing required extension)") !== -1) && !(it.indexOf("valid identities found") !== -1) && !(it.indexOf("iPhone ") !== -1) && !(it.indexOf("com.apple.idms.appleid.prd.") !== -1) && !(it.indexOf("Mac Developer:") !== -1)).map(it => it.substring(it.indexOf(")") + 1).trim()); return Array.from(new Set(array)); }); if (keychain == null) { exports.findIdentityRawResult = result; } } return result; }); } function _findIdentity(namePrefix, qualifier, keychain) { return __awaiter(this, void 0, void 0, function* () { // https://github.com/electron-userland/electron-builder/issues/484 //noinspection SpellCheckingInspection const lines = yield getValidIdentities(keychain); for (let line of lines) { if (qualifier != null && !(line.indexOf(qualifier) !== -1)) { continue; } if (line.indexOf(namePrefix) !== -1) { return line.substring(line.indexOf('"') + 1, line.lastIndexOf('"')); } } if (namePrefix === "Developer ID Application") { // find non-Apple certificate // https://github.com/electron-userland/electron-builder/issues/458 l: for (let line of lines) { if (qualifier != null && !(line.indexOf(qualifier) !== -1)) { continue; } for (let prefix of appleCertificatePrefixes) { if (line.indexOf(prefix) !== -1) { continue l; } } return line.substring(line.indexOf('"') + 1, line.lastIndexOf('"')); } } return null; }); } function findIdentity(certType, qualifier, keychain) { return __awaiter(this, void 0, void 0, function* () { let identity = process.env.CSC_NAME || qualifier; if (util_1.isEmptyOrSpaces(identity)) { if (keychain == null && process.env.CI == null && process.env.CSC_IDENTITY_AUTO_DISCOVERY === "false") { return null; } return yield _findIdentity(certType, null, keychain); } else { identity = identity.trim(); for (let prefix of appleCertificatePrefixes) { checkPrefix(identity, prefix); } const result = yield _findIdentity(certType, identity, keychain); if (result == null) { throw new Error(`Identity name "${ identity }" is specified, but no valid identity with this name in the keychain`); } return result; } }); } exports.findIdentity = findIdentity; function checkPrefix(name, prefix) { if (name.startsWith(prefix)) { throw new Error(`Please remove prefix "${ prefix }" from the specified name — appropriate certificate will be chosen automatically`); } } //# sourceMappingURL=codeSign.js.map