403 lines
11 KiB
JavaScript
403 lines
11 KiB
JavaScript
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.getSignVendorPath = getSignVendorPath;
|
|
exports.sign = sign;
|
|
exports.getCertInfo = getCertInfo;
|
|
exports.getCertificateFromStoreInfo = getCertificateFromStoreInfo;
|
|
exports.isOldWin6 = isOldWin6;
|
|
|
|
function _util() {
|
|
const data = require("builder-util/out/util");
|
|
|
|
_util = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _binDownload() {
|
|
const data = require("../binDownload");
|
|
|
|
_binDownload = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _appBuilder() {
|
|
const data = require("../util/appBuilder");
|
|
|
|
_appBuilder = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _bundledTool() {
|
|
const data = require("../util/bundledTool");
|
|
|
|
_bundledTool = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _fsExtra() {
|
|
const data = require("fs-extra");
|
|
|
|
_fsExtra = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function os() {
|
|
const data = _interopRequireWildcard(require("os"));
|
|
|
|
os = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
var path = _interopRequireWildcard(require("path"));
|
|
|
|
function _platformPackager() {
|
|
const data = require("../platformPackager");
|
|
|
|
_platformPackager = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _flags() {
|
|
const data = require("../util/flags");
|
|
|
|
_flags = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _vm() {
|
|
const data = require("../vm/vm");
|
|
|
|
_vm = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
|
|
|
|
function getSignVendorPath() {
|
|
return (0, _binDownload().getBin)("winCodeSign");
|
|
}
|
|
|
|
async function sign(options, packager) {
|
|
let hashes = options.options.signingHashAlgorithms; // msi does not support dual-signing
|
|
|
|
if (options.path.endsWith(".msi")) {
|
|
hashes = [hashes != null && !hashes.includes("sha1") ? "sha256" : "sha1"];
|
|
} else if (options.path.endsWith(".appx")) {
|
|
hashes = ["sha256"];
|
|
} else if (hashes == null) {
|
|
hashes = ["sha1", "sha256"];
|
|
} else {
|
|
hashes = Array.isArray(hashes) ? hashes : [hashes];
|
|
}
|
|
|
|
function defaultExecutor(configuration) {
|
|
return doSign(configuration, packager);
|
|
}
|
|
|
|
const executor = (0, _platformPackager().resolveFunction)(options.options.sign, "sign") || defaultExecutor;
|
|
let isNest = false;
|
|
|
|
for (const hash of hashes) {
|
|
const taskConfiguration = Object.assign({}, options, {
|
|
hash,
|
|
isNest
|
|
});
|
|
await executor(Object.assign({}, taskConfiguration, {
|
|
computeSignToolArgs: isWin => computeSignToolArgs(taskConfiguration, isWin)
|
|
}));
|
|
isNest = true;
|
|
|
|
if (taskConfiguration.resultOutputPath != null) {
|
|
await (0, _fsExtra().rename)(taskConfiguration.resultOutputPath, options.path);
|
|
}
|
|
}
|
|
}
|
|
|
|
async function getCertInfo(file, password) {
|
|
let result = null;
|
|
const errorMessagePrefix = "Cannot extract publisher name from code signing certificate. As workaround, set win.publisherName. Error: ";
|
|
|
|
try {
|
|
result = await (0, _appBuilder().executeAppBuilderAsJson)(["certificate-info", "--input", file, "--password", password]);
|
|
} catch (e) {
|
|
throw new Error(`${errorMessagePrefix}${e.stack || e}`);
|
|
}
|
|
|
|
if (result.error != null) {
|
|
// noinspection ExceptionCaughtLocallyJS
|
|
throw new (_util().InvalidConfigurationError)(`${errorMessagePrefix}${result.error}`);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
async function getCertificateFromStoreInfo(options, vm) {
|
|
const certificateSubjectName = options.certificateSubjectName;
|
|
const certificateSha1 = options.certificateSha1; // ExcludeProperty doesn't work, so, we cannot exclude RawData, it is ok
|
|
// powershell can return object if the only item
|
|
|
|
const rawResult = await vm.exec("powershell.exe", ["Get-ChildItem -Recurse Cert: -CodeSigningCert | Select-Object -Property Subject,PSParentPath,Thumbprint | ConvertTo-Json -Compress"]);
|
|
const certList = rawResult.length === 0 ? [] : (0, _util().asArray)(JSON.parse(rawResult));
|
|
|
|
for (const certInfo of certList) {
|
|
if (certificateSubjectName != null) {
|
|
if (!certInfo.Subject.includes(certificateSubjectName)) {
|
|
continue;
|
|
}
|
|
} else if (certInfo.Thumbprint !== certificateSha1) {
|
|
continue;
|
|
}
|
|
|
|
const parentPath = certInfo.PSParentPath;
|
|
const store = parentPath.substring(parentPath.lastIndexOf("\\") + 1);
|
|
|
|
_util().log.debug({
|
|
store,
|
|
PSParentPath: parentPath
|
|
}, "auto-detect certificate store"); // https://github.com/electron-userland/electron-builder/issues/1717
|
|
|
|
|
|
const isLocalMachineStore = parentPath.includes("Certificate::LocalMachine");
|
|
|
|
_util().log.debug(null, "auto-detect using of LocalMachine store");
|
|
|
|
return {
|
|
thumbprint: certInfo.Thumbprint,
|
|
subject: certInfo.Subject,
|
|
store,
|
|
isLocalMachineStore
|
|
};
|
|
}
|
|
|
|
throw new Error(`Cannot find certificate ${certificateSubjectName || certificateSha1}, all certs: ${rawResult}`);
|
|
}
|
|
|
|
async function doSign(configuration, packager) {
|
|
// https://github.com/electron-userland/electron-builder/pull/1944
|
|
const timeout = parseInt(process.env.SIGNTOOL_TIMEOUT, 10) || 10 * 60 * 1000;
|
|
let tool;
|
|
let args;
|
|
let env = process.env;
|
|
let vm;
|
|
|
|
if (configuration.path.endsWith(".appx") || !("file" in configuration.cscInfo)
|
|
/* certificateSubjectName and other such options */
|
|
) {
|
|
vm = await packager.vm.value;
|
|
tool = getWinSignTool((await getSignVendorPath()));
|
|
args = computeSignToolArgs(configuration, true, vm);
|
|
} else {
|
|
vm = new (_vm().VmManager)();
|
|
const toolInfo = await getToolPath();
|
|
tool = toolInfo.path;
|
|
args = configuration.computeSignToolArgs(process.platform === "win32");
|
|
|
|
if (toolInfo.env != null) {
|
|
env = toolInfo.env;
|
|
}
|
|
}
|
|
|
|
try {
|
|
await vm.exec(tool, args, {
|
|
timeout,
|
|
env
|
|
});
|
|
} catch (e) {
|
|
if (e.message.includes("The file is being used by another process") || e.message.includes("The specified timestamp server either could not be reached")) {
|
|
_util().log.warn(`First attempt to code sign failed, another attempt will be made in 2 seconds: ${e.message}`);
|
|
|
|
await new Promise((resolve, reject) => {
|
|
setTimeout(() => {
|
|
vm.exec(tool, args, {
|
|
timeout,
|
|
env
|
|
}).then(resolve).catch(reject);
|
|
}, 2000);
|
|
});
|
|
}
|
|
|
|
throw e;
|
|
}
|
|
} // on windows be aware of http://stackoverflow.com/a/32640183/1910191
|
|
|
|
|
|
function computeSignToolArgs(options, isWin, vm = new (_vm().VmManager)()) {
|
|
const inputFile = vm.toVmFile(options.path);
|
|
const outputPath = isWin ? inputFile : getOutputPath(inputFile, options.hash);
|
|
|
|
if (!isWin) {
|
|
options.resultOutputPath = outputPath;
|
|
}
|
|
|
|
const args = isWin ? ["sign"] : ["-in", inputFile, "-out", outputPath];
|
|
|
|
if (process.env.ELECTRON_BUILDER_OFFLINE !== "true") {
|
|
const timestampingServiceUrl = options.options.timeStampServer || "http://timestamp.digicert.com";
|
|
|
|
if (isWin) {
|
|
args.push(options.isNest || options.hash === "sha256" ? "/tr" : "/t", options.isNest || options.hash === "sha256" ? options.options.rfc3161TimeStampServer || "http://timestamp.comodoca.com/rfc3161" : timestampingServiceUrl);
|
|
} else {
|
|
args.push("-t", timestampingServiceUrl);
|
|
}
|
|
}
|
|
|
|
const certificateFile = options.cscInfo.file;
|
|
|
|
if (certificateFile == null) {
|
|
const cscInfo = options.cscInfo;
|
|
const subjectName = cscInfo.thumbprint;
|
|
|
|
if (!isWin) {
|
|
throw new Error(`${subjectName == null ? "certificateSha1" : "certificateSubjectName"} supported only on Windows`);
|
|
}
|
|
|
|
args.push("/sha1", cscInfo.thumbprint);
|
|
args.push("/s", cscInfo.store);
|
|
|
|
if (cscInfo.isLocalMachineStore) {
|
|
args.push("/sm");
|
|
}
|
|
} else {
|
|
const certExtension = path.extname(certificateFile);
|
|
|
|
if (certExtension === ".p12" || certExtension === ".pfx") {
|
|
args.push(isWin ? "/f" : "-pkcs12", vm.toVmFile(certificateFile));
|
|
} else {
|
|
throw new Error(`Please specify pkcs12 (.p12/.pfx) file, ${certificateFile} is not correct`);
|
|
}
|
|
}
|
|
|
|
if (!isWin || options.hash !== "sha1") {
|
|
args.push(isWin ? "/fd" : "-h", options.hash);
|
|
|
|
if (isWin && process.env.ELECTRON_BUILDER_OFFLINE !== "true") {
|
|
args.push("/td", "sha256");
|
|
}
|
|
}
|
|
|
|
if (options.name) {
|
|
args.push(isWin ? "/d" : "-n", options.name);
|
|
}
|
|
|
|
if (options.site) {
|
|
args.push(isWin ? "/du" : "-i", options.site);
|
|
} // msi does not support dual-signing
|
|
|
|
|
|
if (options.isNest) {
|
|
args.push(isWin ? "/as" : "-nest");
|
|
}
|
|
|
|
const password = options.cscInfo == null ? null : options.cscInfo.password;
|
|
|
|
if (password) {
|
|
args.push(isWin ? "/p" : "-pass", password);
|
|
}
|
|
|
|
if (options.options.additionalCertificateFile) {
|
|
args.push(isWin ? "/ac" : "-ac", vm.toVmFile(options.options.additionalCertificateFile));
|
|
}
|
|
|
|
const httpsProxyFromEnv = process.env.HTTPS_PROXY;
|
|
|
|
if (!isWin && httpsProxyFromEnv != null && httpsProxyFromEnv.length) {
|
|
args.push("-p", httpsProxyFromEnv);
|
|
}
|
|
|
|
if (isWin) {
|
|
// https://github.com/electron-userland/electron-builder/issues/2875#issuecomment-387233610
|
|
args.push("/debug"); // must be last argument
|
|
|
|
args.push(inputFile);
|
|
}
|
|
|
|
return args;
|
|
}
|
|
|
|
function getOutputPath(inputPath, hash) {
|
|
const extension = path.extname(inputPath);
|
|
return path.join(path.dirname(inputPath), `${path.basename(inputPath, extension)}-signed-${hash}${extension}`);
|
|
}
|
|
/** @internal */
|
|
|
|
|
|
function isOldWin6() {
|
|
const winVersion = os().release();
|
|
return winVersion.startsWith("6.") && !winVersion.startsWith("6.3");
|
|
}
|
|
|
|
function getWinSignTool(vendorPath) {
|
|
// use modern signtool on Windows Server 2012 R2 to be able to sign AppX
|
|
if (isOldWin6()) {
|
|
return path.join(vendorPath, "windows-6", "signtool.exe");
|
|
} else {
|
|
return path.join(vendorPath, "windows-10", process.arch, "signtool.exe");
|
|
}
|
|
}
|
|
|
|
async function getToolPath() {
|
|
if ((0, _flags().isUseSystemSigncode)()) {
|
|
return {
|
|
path: "osslsigncode"
|
|
};
|
|
}
|
|
|
|
const result = process.env.SIGNTOOL_PATH;
|
|
|
|
if (result) {
|
|
return {
|
|
path: result
|
|
};
|
|
}
|
|
|
|
const vendorPath = await getSignVendorPath();
|
|
|
|
if (process.platform === "win32") {
|
|
// use modern signtool on Windows Server 2012 R2 to be able to sign AppX
|
|
return {
|
|
path: getWinSignTool(vendorPath)
|
|
};
|
|
} else if (process.platform === "darwin") {
|
|
const toolDirPath = path.join(vendorPath, process.platform, "10.12");
|
|
return {
|
|
path: path.join(toolDirPath, "osslsigncode"),
|
|
env: (0, _bundledTool().computeToolEnv)([path.join(toolDirPath, "lib")])
|
|
};
|
|
} else {
|
|
return {
|
|
path: path.join(vendorPath, process.platform, "osslsigncode")
|
|
};
|
|
}
|
|
}
|
|
// __ts-babel@6.0.4
|
|
//# sourceMappingURL=windowsCodeSign.js.map
|