From e713bbe9284d3169aaa9539ba8d1d338e15a7dad Mon Sep 17 00:00:00 2001 From: develar Date: Mon, 12 Jun 2017 11:42:50 +0200 Subject: [PATCH] fix(electron-updater): update sign verification error Close #1641 --- circle.yml | 2 +- .../src/rfc2253Parser.ts | 87 +++++ packages/electron-builder/package.json | 2 +- packages/electron-builder/src/builder.ts | 131 ++++++- .../electron-builder/src/cli/build-cli.ts | 30 -- .../electron-builder/src/cli/cliOptions.ts | 127 ++----- .../src/cli/create-self-signed-cert.ts | 22 +- packages/electron-builder/src/targets/appx.ts | 25 +- packages/electron-builder/src/winPackager.ts | 5 +- .../templates/appx/appxmanifest.xml | 3 +- packages/electron-updater/src/NsisUpdater.ts | 63 ++-- test/out/__snapshots__/globTest.js.snap | 2 +- .../out/__snapshots__/nsisUpdaterTest.js.snap | 4 - test/src/BuildTest.ts | 6 +- test/src/windows/appxTest.ts | 2 +- typings/fcopy-pre-bundled.d.ts | 2 +- typings/yargs.d.ts | 357 ++++++++++++++---- yarn.lock | 18 +- 18 files changed, 599 insertions(+), 289 deletions(-) create mode 100644 packages/electron-builder-http/src/rfc2253Parser.ts delete mode 100644 packages/electron-builder/src/cli/build-cli.ts diff --git a/circle.yml b/circle.yml index ab486ac3c0c..6909099bf2b 100644 --- a/circle.yml +++ b/circle.yml @@ -15,7 +15,7 @@ dependencies: - ssh git@github.com git-lfs-authenticate $CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME.git download - git lfs pull - mkdir -p $CIRCLE_TEST_REPORTS/reports - - docker run --rm --env-file ./test/docker-env.list -v ${PWD}:/project -v ~/.electron:/root/.electron -v ~/.cache/electron-builder:/root/.cache/electron-builder electronuserland/electron-builder:wine /bin/bash -c "node ./test/vendor/yarn.js --link-duplicates --pure-lockfile && node ./test/vendor/yarn.js test" && mv -f test/test-report.xml $CIRCLE_TEST_REPORTS/reports/test-report.xml + - docker run --rm --env-file ./test/docker-env.list -v ${PWD}:/project -v ~/.cache/electron:/root/.cache/electron -v ~/.cache/electron-builder:/root/.cache/electron-builder electronuserland/electron-builder:wine /bin/bash -c "node ./test/vendor/yarn.js --link-duplicates --pure-lockfile && node ./test/vendor/yarn.js test" && mv -f test/test-report.xml $CIRCLE_TEST_REPORTS/reports/test-report.xml test: override: diff --git a/packages/electron-builder-http/src/rfc2253Parser.ts b/packages/electron-builder-http/src/rfc2253Parser.ts new file mode 100644 index 00000000000..dfe0e4256ec --- /dev/null +++ b/packages/electron-builder-http/src/rfc2253Parser.ts @@ -0,0 +1,87 @@ +export function parseDn(seq: string): Map { + let quoted = false + let key: string | null = null + let token = "" + let nextNonSpace = 0 + + seq = seq.trim() + const result = new Map() + for (let i = 0; i <= seq.length; i++) { + if (i === seq.length) { + if (key !== null) { + result.set(key, token) + } + break + } + + const ch = seq[i] + if (quoted) { + if (ch === '"') { + quoted = false + continue + } + } + else { + if (ch === '"') { + quoted = true + continue + } + + if (ch === "\\") { + i++ + const ord = parseInt(seq.slice(i, i + 2), 16) + if (Number.isNaN(ord)) { + token += seq[i] + } + else { + i++ + token += String.fromCharCode(ord) + } + continue + } + + if (key === null && ch === "=") { + key = token + token = "" + continue + } + + if (ch === "," || ch === ";" || ch === "+") { + if (key !== null) { + result.set(key, token) + } + key = null + token = "" + continue + } + } + + if (ch === " " && !quoted) { + if (token.length === 0) { + continue + } + + if (i > nextNonSpace) { + let j = i + while (seq[j] === " ") { + j++ + } + nextNonSpace = j + } + + if (nextNonSpace >= seq.length + || seq[nextNonSpace] === "," + || seq[nextNonSpace] === ";" + || (key === null && seq[nextNonSpace] === "=") + || (key !== null && seq[nextNonSpace] === "+") + ) { + i = nextNonSpace - 1 + continue + } + } + + token += ch + } + + return result +} \ No newline at end of file diff --git a/packages/electron-builder/package.json b/packages/electron-builder/package.json index 1b885f450c5..d9afd25c3b8 100644 --- a/packages/electron-builder/package.json +++ b/packages/electron-builder/package.json @@ -11,7 +11,7 @@ "certs/root_certs.keychain" ], "bin": { - "build": "./out/cli/build-cli.js", + "build": "./out/cli/cliOptions.js", "install-app-deps": "./out/cli/install-app-deps.js", "node-gyp-rebuild": "./out/cli/node-gyp-rebuild.js" }, diff --git a/packages/electron-builder/src/builder.ts b/packages/electron-builder/src/builder.ts index 7dcbb70cf69..d467698eac5 100644 --- a/packages/electron-builder/src/builder.ts +++ b/packages/electron-builder/src/builder.ts @@ -1,10 +1,15 @@ import BluebirdPromise from "bluebird-lst" +import { cyan, dim, green, reset, underline } from "chalk" import { Arch, archFromString, DIR_TARGET, Platform } from "electron-builder-core" import { CancellationToken } from "electron-builder-http/out/CancellationToken" import { addValue, isEmptyOrSpaces } from "electron-builder-util" import { warn } from "electron-builder-util/out/log" -import { executeFinally } from "electron-builder-util/out/promise" +import { executeFinally, printErrorAndExit } from "electron-builder-util/out/promise" import { PublishOptions } from "electron-publish" +import { readJson } from "fs-extra-p" +import isCi from "is-ci" +import * as path from "path" +import updateNotifier from "update-notifier" import { normalizePlatforms, Packager } from "./packager" import { PackagerOptions } from "./packagerApi" import { PublishManager } from "./publish/PublishManager" @@ -212,4 +217,128 @@ export async function build(rawOptions?: CliOptions): Promise> { return publishManager.awaitTasks() } }) +} + +/** @private */ +export function configureBuildCommand(yargs: yargs.Yargs): yargs.Yargs { + const publishGroup = "Publishing:" + const buildGroup = "Building:" + const deprecated = "Deprecated:" + + return yargs + .option("mac", { + group: buildGroup, + alias: ["m", "o", "macos"], + describe: `Build for macOS, accepts target list (see ${underline("https://goo.gl/HAnnq8")}).`, + type: "array", + }) + .option("linux", { + group: buildGroup, + alias: "l", + describe: `Build for Linux, accepts target list (see ${underline("https://goo.gl/O80IL2")})`, + type: "array", + }) + .option("win", { + group: buildGroup, + alias: ["w", "windows"], + describe: `Build for Windows, accepts target list (see ${underline("https://goo.gl/dL4i8i")})`, + type: "array", + }) + .option("x64", { + group: buildGroup, + describe: "Build for x64", + type: "boolean", + }) + .option("ia32", { + group: buildGroup, + describe: "Build for ia32", + type: "boolean", + }) + .option("armv7l", { + group: buildGroup, + describe: "Build for armv7l", + type: "boolean", + }) + .option("dir", { + group: buildGroup, + describe: "Build unpacked dir. Useful to test.", + type: "boolean", + }) + .option("publish", { + group: publishGroup, + alias: "p", + describe: `Publish artifacts (to GitHub Releases), see ${underline("https://goo.gl/WMlr4n")}`, + choices: ["onTag", "onTagOrDraft", "always", "never"], + }) + .option("draft", { + group: publishGroup, + describe: "Create a draft (unpublished) release", + type: "boolean", + default: undefined, + }) + .option("prerelease", { + group: publishGroup, + describe: "Identify the release as a prerelease", + type: "boolean", + default: undefined, + }) + .option("platform", { + group: deprecated, + describe: "The target platform (preferred to use --mac, --win or --linux)", + choices: ["mac", "win", "linux", "darwin", "win32", "all"], + }) + .option("arch", { + group: deprecated, + describe: "The target arch (preferred to use --x64 or --ia32)", + choices: ["ia32", "x64", "all"], + }) + .option("extraMetadata", { + alias: ["em"], + group: buildGroup, + describe: "Inject properties to package.json (asar only)", + }) + .option("prepackaged", { + alias: ["pd"], + group: buildGroup, + describe: "The path to prepackaged app (to pack in a distributable format)", + }) + .option("projectDir", { + alias: ["project"], + group: buildGroup, + describe: "The path to project directory. Defaults to current working directory.", + }) + .option("config", { + alias: ["c"], + group: buildGroup, + describe: "The path to an electron-builder config. Defaults to `electron-builder.yml` (or `json`, or `json5`), see " + underline("https://goo.gl/YFRJOM"), + }) + .group(["help", "version"], "Other:") + .example("build -mwl", "build for macOS, Windows and Linux") + .example("build --linux deb tar.xz", "build deb and tar.xz for Linux") + .example("build --win --ia32", "build for Windows ia32") + .example("build --em.foo=bar", "set package.json property `foo` to `bar`") + .example("build --config.nsis.unicode=false", "configure unicode options for NSIS") +} + +/** @private */ +export function buildCommandHandler(args: CliOptions) { + if (!isCi && process.env.NO_UPDATE_NOTIFIER == null) { + readJson(path.join(__dirname, "..", "..", "package.json")) + .then(it => { + if (it.version === "0.0.0-semantic-release") { + return + } + + const notifier = updateNotifier({pkg: it}) + if (notifier.update != null) { + notifier.notify({ + message: `Update available ${dim(notifier.update.current)}${reset(" → ")}${green(notifier.update.latest)} \nRun ${cyan("npm i electron-builder --save-dev")} to update` + }) + } + }) + .catch(e => warn(`Cannot check updates: ${e}`)) + } + + build(args) + .catch(printErrorAndExit) } \ No newline at end of file diff --git a/packages/electron-builder/src/cli/build-cli.ts b/packages/electron-builder/src/cli/build-cli.ts deleted file mode 100644 index d1b6d58fa2f..00000000000 --- a/packages/electron-builder/src/cli/build-cli.ts +++ /dev/null @@ -1,30 +0,0 @@ -#! /usr/bin/env node -import { build, CliOptions } from "../builder" -import { printErrorAndExit } from "electron-builder-util/out/promise" -import { createYargs } from "./cliOptions" -import { readJson } from "fs-extra-p" -import * as path from "path" -import { dim, reset, green, cyan } from "chalk" -import updateNotifier from "update-notifier" -import { warn } from "electron-builder-util/out/log" -import isCi from "is-ci" - -if (!isCi && process.env.NO_UPDATE_NOTIFIER == null) { - readJson(path.join(__dirname, "..", "..", "package.json")) - .then(it => { - if (it.version === "0.0.0-semantic-release") { - return - } - - const notifier = updateNotifier({pkg: it}) - if (notifier.update != null) { - notifier.notify({ - message: `Update available ${dim(notifier.update.current)}${reset(" → ")}${green(notifier.update.latest)} \nRun ${cyan("npm i electron-builder --save-dev")} to update` - }) - } - }) - .catch(e => warn(`Cannot check updates: ${e}`)) -} - -build((createYargs().argv)) - .catch(printErrorAndExit) \ No newline at end of file diff --git a/packages/electron-builder/src/cli/cliOptions.ts b/packages/electron-builder/src/cli/cliOptions.ts index 4d6eca69377..2f2b9f8bb7e 100644 --- a/packages/electron-builder/src/cli/cliOptions.ts +++ b/packages/electron-builder/src/cli/cliOptions.ts @@ -1,107 +1,26 @@ +#! /usr/bin/env node + import { underline } from "chalk" +import { printErrorAndExit } from "electron-builder-util/out/promise" import yargs from "yargs" +import { buildCommandHandler, configureBuildCommand } from "../builder" +import { createSelfSignedCert } from "./create-self-signed-cert" -const publishGroup = "Publishing:" -const buildGroup = "Building:" -const deprecated = "Deprecated:" - -export function createYargs(): any { - //noinspection ReservedWordAsName - return yargs - .example("build -mwl", "build for macOS, Windows and Linux") - .example("build --linux deb tar.xz", "build deb and tar.xz for Linux") - .example("build --win --ia32", "build for Windows ia32") - .example("build --em.foo=bar", "set package.json property `foo` to `bar`") - .example("build --config.nsis.unicode=false", "configure unicode options for NSIS") - .option("mac", { - group: buildGroup, - alias: ["m", "o", "macos"], - describe: `Build for macOS, accepts target list (see ${underline("https://goo.gl/HAnnq8")}).`, - type: "array", - }) - .option("linux", { - group: buildGroup, - alias: "l", - describe: `Build for Linux, accepts target list (see ${underline("https://goo.gl/O80IL2")})`, - type: "array", - }) - .option("win", { - group: buildGroup, - alias: ["w", "windows"], - describe: `Build for Windows, accepts target list (see ${underline("https://goo.gl/dL4i8i")})`, - type: "array", - }) - .option("x64", { - group: buildGroup, - describe: "Build for x64", - type: "boolean", - }) - .option("ia32", { - group: buildGroup, - describe: "Build for ia32", - type: "boolean", - }) - .option("armv7l", { - group: buildGroup, - describe: "Build for armv7l", - type: "boolean", - }) - .option("dir", { - group: buildGroup, - describe: "Build unpacked dir. Useful to test.", - type: "boolean", - }) - .option("publish", { - group: publishGroup, - alias: "p", - describe: `Publish artifacts (to GitHub Releases), see ${underline("https://goo.gl/WMlr4n")}`, - choices: ["onTag", "onTagOrDraft", "always", "never"], - }) - .option("draft", { - group: publishGroup, - describe: "Create a draft (unpublished) release", - type: "boolean", - default: undefined, - }) - .option("prerelease", { - group: publishGroup, - describe: "Identify the release as a prerelease", - type: "boolean", - default: undefined, - }) - .option("platform", { - group: deprecated, - describe: "The target platform (preferred to use --mac, --win or --linux)", - choices: ["mac", "win", "linux", "darwin", "win32", "all"], - }) - .option("arch", { - group: deprecated, - describe: "The target arch (preferred to use --x64 or --ia32)", - choices: ["ia32", "x64", "all"], - }) - .option("extraMetadata", { - alias: ["em"], - group: buildGroup, - describe: "Inject properties to package.json (asar only)", - }) - .option("prepackaged", { - alias: ["pd"], - group: buildGroup, - describe: "The path to prepackaged app (to pack in a distributable format)", - }) - .option("projectDir", { - alias: ["project"], - group: buildGroup, - describe: "The path to project directory. Defaults to current working directory.", - }) - .option("config", { - alias: ["c"], - group: buildGroup, - describe: "The path to an electron-builder config. Defaults to `electron-builder.yml` (or `json`, or `json5`), see " + underline("https://goo.gl/YFRJOM"), - }) - .strict() - .group(["help", "version"], "Other:") - .help() - .version() - .epilog(`See the Wiki (${underline("https://github.com/electron-userland/electron-builder/wiki")}) for more documentation.`) -} +yargs + .command(["build", "*"], "Build", configureBuildCommand, buildCommandHandler) + .command("create-self-signed-cert", "Create self-signed code signing cert for Windows apps", + yargs => yargs + .option("publisher", { + alias: ["p"], + type: "string", + requiresArg: true, + }) + .demandOption("publisher"), + argv => { + createSelfSignedCert(argv.publisher) + .catch(printErrorAndExit) + }) + .help() + .epilog(`See the Wiki (${underline("https://github.com/electron-userland/electron-builder/wiki")}) for more documentation.`) + .strict() + .argv diff --git a/packages/electron-builder/src/cli/create-self-signed-cert.ts b/packages/electron-builder/src/cli/create-self-signed-cert.ts index 7441f856271..fc5dad24f7b 100644 --- a/packages/electron-builder/src/cli/create-self-signed-cert.ts +++ b/packages/electron-builder/src/cli/create-self-signed-cert.ts @@ -2,24 +2,17 @@ import { bold } from "chalk" import { exec, spawn } from "electron-builder-util" import { unlinkIfExists } from "electron-builder-util/out/fs" import { log } from "electron-builder-util/out/log" -import { printErrorAndExit } from "electron-builder-util/out/promise" import { TmpDir } from "electron-builder-util/out/tmp" import { ensureDir } from "fs-extra-p" import * as path from "path" import sanitizeFileName from "sanitize-filename" -import yargs from "yargs" +import { quoteString } from "../targets/appx" import { getSignVendorPath } from "../windowsCodeSign" -async function main() { - const args: any = yargs - .option("publisher", { - alias: ["p"], - requiresArg: true, - }).argv - +export async function createSelfSignedCert(publisher: string) { const tmpDir = new TmpDir() const targetDir = process.cwd() - const tempPrefix = path.join(await tmpDir.getTempFile(""), sanitizeFileName(args.publisher)) + const tempPrefix = path.join(await tmpDir.getTempFile(""), sanitizeFileName(publisher)) const cer = `${tempPrefix}.cer` const pvk = `${tempPrefix}.pvk` @@ -29,9 +22,9 @@ async function main() { await ensureDir(path.dirname(tempPrefix)) const vendorPath = path.join(await getSignVendorPath(), "windows-10", process.arch) await exec(path.join(vendorPath, "makecert.exe"), - ["-r", "-h", "0", "-n", `CN=${args.publisher}`, "-eku", "1.3.6.1.5.5.7.3.3", "-pe", "-sv", pvk, cer]) + ["-r", "-h", "0", "-n", `CN=${quoteString(publisher)}`, "-eku", "1.3.6.1.5.5.7.3.3", "-pe", "-sv", pvk, cer]) - const pfx = path.join(targetDir, `${sanitizeFileName(args.publisher)}.pfx`) + const pfx = path.join(targetDir, `${sanitizeFileName(publisher)}.pfx`) await unlinkIfExists(pfx) await exec(path.join(vendorPath, "pvk2pfx.exe"), ["-pvk", pvk, "-spc", cer, "-pfx", pfx]) log(`${pfx} created. Please see https://github.com/electron-userland/electron-builder/wiki/Code-Signing how to use it to sign.`) @@ -43,7 +36,4 @@ async function main() { finally { await tmpDir.cleanup() } -} - -main() - .catch(printErrorAndExit) \ No newline at end of file +} \ No newline at end of file diff --git a/packages/electron-builder/src/targets/appx.ts b/packages/electron-builder/src/targets/appx.ts index f0ba5a12735..f3d1eb16cad 100644 --- a/packages/electron-builder/src/targets/appx.ts +++ b/packages/electron-builder/src/targets/appx.ts @@ -1,6 +1,6 @@ import BluebirdPromise from "bluebird-lst" import { Arch, getArchSuffix, Target } from "electron-builder-core" -import { spawn, use } from "electron-builder-util" +import { exec, spawn, use } from "electron-builder-util" import { copyDir, copyFile } from "electron-builder-util/out/fs" import { emptyDir, readFile, writeFile } from "fs-extra-p" import * as path from "path" @@ -24,18 +24,21 @@ export default class AppXTarget extends Target { async build(appOutDir: string, arch: Arch): Promise { const packager = this.packager - if ((await packager.cscInfo.value) == null) { + const cscInfo = await this.packager.cscInfo.value + if (cscInfo == null) { throw new Error("AppX package must be signed, but certificate is not set, please see https://github.com/electron-userland/electron-builder/wiki/Code-Signing\n\nYou can use `./node_modules/.bin/create-self-signed-cert -p YourName` to create self-signed certificate") } let publisher = this.options.publisher if (publisher == null) { - const computed = await packager.computedPublisherName.value - if (computed != null) { - publisher = `CN=${computed[0]}` + const cscFile = cscInfo.file + if (cscFile == null) { + throw new Error("Please specify appx.publisher: cannot get publisher from your code signing certificate if EV cert is used") } - if (publisher == null) { - throw new Error("Please specify appx.publisher") + + publisher = (await exec("powershell.exe", [`(Get-PfxCertificate "${cscFile}").Subject`])).trim() + if (!publisher) { + throw new Error("Please specify appx.publisher: Get-PfxCertificate returns empty string") } } @@ -121,3 +124,11 @@ export default class AppXTarget extends Target { await writeFile(path.join(preAppx, "appxmanifest.xml"), manifest) } } + +export function quoteString(s: string): string { + if (!s.includes(",") && !s.includes('"')) { + return s + } + + return `"${s.replace(/"/g, '\\"')}"` +} \ No newline at end of file diff --git a/packages/electron-builder/src/winPackager.ts b/packages/electron-builder/src/winPackager.ts index 7a339bbf9b2..68f42080afd 100644 --- a/packages/electron-builder/src/winPackager.ts +++ b/packages/electron-builder/src/winPackager.ts @@ -1,5 +1,6 @@ import BluebirdPromise from "bluebird-lst" import { DIR_TARGET, Platform, Target } from "electron-builder-core" +import { parseDn } from "electron-builder-http/out/rfc2253Parser" import { asArray, exec, Lazy, use } from "electron-builder-util" import { log, warn } from "electron-builder-util/out/log" import { close, open, read, readFile, rename } from "fs-extra-p" @@ -70,9 +71,9 @@ export class WinPackager extends PlatformPackager { if (publisherName == null && cscFile != null) { if (process.platform === "win32") { try { - const subject = (await exec("powershell.exe", [`(Get-PfxCertificate "${cscFile}").Subject`])).trim().match(/CN=([^,]+)/) + const subject = parseDn(await exec("powershell.exe", [`(Get-PfxCertificate "${cscFile}").Subject`])).get("CN") if (subject) { - return asArray(subject[1]) + return asArray(subject) } } catch (e) { diff --git a/packages/electron-builder/templates/appx/appxmanifest.xml b/packages/electron-builder/templates/appx/appxmanifest.xml index 2f1cc530543..bc4558d7a9a 100644 --- a/packages/electron-builder/templates/appx/appxmanifest.xml +++ b/packages/electron-builder/templates/appx/appxmanifest.xml @@ -3,9 +3,10 @@ xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"> + ${displayName} diff --git a/packages/electron-updater/src/NsisUpdater.ts b/packages/electron-updater/src/NsisUpdater.ts index 498e483b630..23cf10f3240 100644 --- a/packages/electron-updater/src/NsisUpdater.ts +++ b/packages/electron-updater/src/NsisUpdater.ts @@ -3,6 +3,7 @@ import { execFile, spawn } from "child_process" import { DownloadOptions } from "electron-builder-http" import { CancellationError, CancellationToken } from "electron-builder-http/out/CancellationToken" import { PublishConfiguration, VersionInfo } from "electron-builder-http/out/publishOptions" +import { parseDn } from "electron-builder-http/out/rfc2253Parser" import { mkdtemp, remove } from "fs-extra-p" import { tmpdir } from "os" import * as path from "path" @@ -81,45 +82,43 @@ export class NsisUpdater extends AppUpdater { } return await new BluebirdPromise((resolve, reject) => { - const commonNameConstraint = (Array.isArray(publisherName) ? >publisherName : [publisherName]).map(it => `$_.SignerCertificate.Subject.Contains('CN=${it},')`).join(" -or ") - const constraintCommand = `where {$_.Status.Equals([System.Management.Automation.SignatureStatus]::Valid) -and (${commonNameConstraint})}` - const verifySignatureCommand = `Get-AuthenticodeSignature '${tempUpdateFile}' | ${constraintCommand}` - const powershellChild = spawn("powershell.exe", [(`$certificateInfo = (${verifySignatureCommand}) | Out-String ; if ($certificateInfo) { exit 0 } else { exit 1 }`)]) - powershellChild.on("error", reject) - powershellChild.on("exit", code => { - if (code !== 1) { - resolve(null) + execFile("powershell.exe", [`Get-AuthenticodeSignature '${tempUpdateFile}' | ConvertTo-Json -Compress`], {maxBuffer: 4 * 1024000}, (error, stdout, stderr) => { + if (error != null) { + reject(error) return } - execFile("powershell.exe", [`Get-AuthenticodeSignature '${tempUpdateFile}' | ConvertTo-Json -Compress`], {maxBuffer: 4 * 1024000}, (error, stdout, stderr) => { - if (error != null) { - reject(error) - return - } + if (stderr) { + reject(new Error(`Cannot execute Get-AuthenticodeSignature: ${stderr}`)) + return + } - if (stderr) { - reject(new Error(`Cannot execute Get-AuthenticodeSignature: ${stderr}`)) - return - } + const data = JSON.parse(stdout) + delete data.PrivateKey + delete data.IsOSBinary + delete data.SignatureType + const signerCertificate = data.SignerCertificate + if (signerCertificate != null) { + delete signerCertificate.Archived + delete signerCertificate.Extensions + delete signerCertificate.Handle + delete signerCertificate.HasPrivateKey + // duplicates data.SignerCertificate (contains RawData) + delete signerCertificate.SubjectName + } + delete data.Path - const data = JSON.parse(stdout) - delete data.PrivateKey - delete data.IsOSBinary - delete data.SignatureType - const signerCertificate = data.SignerCertificate - if (signerCertificate != null) { - delete signerCertificate.Archived - delete signerCertificate.Extensions - delete signerCertificate.Handle - delete signerCertificate.HasPrivateKey + if (data.Status === 0) { + const name = parseDn(data.SignerCertificate.Subject).get("CN") + if ((Array.isArray(publisherName) ? >publisherName : [publisherName]).includes(name)) { + resolve(null) + return } - delete data.Path + } - const result = JSON.stringify(data, (name, value) => name === "RawData" ? undefined : value, 2) - this._logger.info(`Sign verification failed, installer signed with incorrect certificate: ${result}`) - resolve(result) - }) + const result = JSON.stringify(data, (name, value) => name === "RawData" ? undefined : value, 2) + this._logger.info(`Sign verification failed, installer signed with incorrect certificate: ${result}`) + resolve(result) }) }) } diff --git a/test/out/__snapshots__/globTest.js.snap b/test/out/__snapshots__/globTest.js.snap index 072668de96e..ebfcf0a11d3 100644 --- a/test/out/__snapshots__/globTest.js.snap +++ b/test/out/__snapshots__/globTest.js.snap @@ -26,7 +26,7 @@ Object { exports[`outside link 2`] = ` Object { - "offset": "4876", + "offset": "4879", "size": 4, } `; diff --git a/test/out/__snapshots__/nsisUpdaterTest.js.snap b/test/out/__snapshots__/nsisUpdaterTest.js.snap index 42a335dafe7..cff44dee733 100644 --- a/test/out/__snapshots__/nsisUpdaterTest.js.snap +++ b/test/out/__snapshots__/nsisUpdaterTest.js.snap @@ -148,10 +148,6 @@ exports[`invalid signature 1`] = ` \\"EncodedParameters\\": \\"System.Security.Cryptography.AsnEncodedData\\" }, \\"SerialNumber\\": \\"18CB5EC53FB14EC2DBB44BD1518AF901\\", - \\"SubjectName\\": { - \\"Name\\": \\"CN=Vladimir Krivosheev, O=Vladimir Krivosheev, L=Grunwald, S=Bayern, C=DE\\", - \\"Oid\\": \\"System.Security.Cryptography.Oid\\" - }, \\"SignatureAlgorithm\\": { \\"Value\\": \\"1.2.840.113549.1.1.11\\", \\"FriendlyName\\": \\"sha256RSA\\" diff --git a/test/src/BuildTest.ts b/test/src/BuildTest.ts index ec6e50a2f90..3e34f88c651 100644 --- a/test/src/BuildTest.ts +++ b/test/src/BuildTest.ts @@ -2,8 +2,7 @@ import BluebirdPromise from "bluebird-lst" import { Arch, BuildOptions, createTargets, DIR_TARGET, Platform } from "electron-builder" import { walk } from "electron-builder-util/out/fs" import { readAsarJson } from "electron-builder/out/asar" -import { normalizeOptions } from "electron-builder/out/builder" -import { createYargs } from "electron-builder/out/cli/cliOptions" +import { configureBuildCommand, normalizeOptions } from "electron-builder/out/builder" import { checkWineVersion } from "electron-builder/out/packager" import { move, outputJson } from "fs-extra-p" import * as path from "path" @@ -13,7 +12,8 @@ import { app, appTwo, appTwoThrows, assertPack, modifyPackageJson, packageJson } const linuxDirTarget = Platform.LINUX.createTarget(DIR_TARGET) test("cli", async () => { - const yargs = createYargs() + const yargs = require("yargs") + configureBuildCommand(yargs) function parse(input: string): BuildOptions { return normalizeOptions(yargs.parse(input.split(" "))) diff --git a/test/src/windows/appxTest.ts b/test/src/windows/appxTest.ts index 10b93ee2f15..0ed53cfaac7 100644 --- a/test/src/windows/appxTest.ts +++ b/test/src/windows/appxTest.ts @@ -4,6 +4,6 @@ import { app } from "../helpers/packTester" // noinspection SpellCheckingInspection test.ifWindows("AppX", app({ targets: Platform.WINDOWS.createTarget(["appx"]), - cscLink: "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", + cscLink: "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\n", cscKeyPassword: "", })) \ No newline at end of file diff --git a/typings/fcopy-pre-bundled.d.ts b/typings/fcopy-pre-bundled.d.ts index 5a07f200407..41bb9f68876 100644 --- a/typings/fcopy-pre-bundled.d.ts +++ b/typings/fcopy-pre-bundled.d.ts @@ -1,3 +1,3 @@ declare module "fcopy-pre-bundled" { - export default function fcopy(src: string, dest: string, opts: any, callback: (error?: Error) => void) + export default function fcopy(src: string, dest: string, opts: any, callback: (error?: Error) => void): void } \ No newline at end of file diff --git a/typings/yargs.d.ts b/typings/yargs.d.ts index b3331d4b293..543df9c10a9 100644 --- a/typings/yargs.d.ts +++ b/typings/yargs.d.ts @@ -1,100 +1,303 @@ -// Generated by typings -// Source: https://raw.githubusercontent.com/typed-typings/npm-yargs/1318e35095ddc705f62d180b6517fff2f6664301/index.d.ts -declare module 'yargs' { - interface Argv { - _: string[]; - '$0': string; - [key: string]: any; +declare namespace yargs { + interface Yargs { + argv: any; + + (...args: any[]): any; + + parse(...args: any[]): any; + + reset(): Yargs; + + locale(): string; + + locale(loc: string): Yargs; + + detectLocale(detect: boolean): Yargs; + + terminalWidth(): number; + + alias(shortName: string, longName: string): Yargs; + + alias(aliases: { [shortName: string]: string }): Yargs; + + alias(aliases: { [shortName: string]: string[] }): Yargs; + + array(key: string): Yargs; + + array(keys: string[]): Yargs; + + default(key: string, value: any, description?: string): Yargs; + + default(defaults: { [key: string]: any }, description?: string): Yargs; + + /** + * @deprecated since version 6.6.0 + */ + demand(key: string, msg: string): Yargs; + + demand(key: string, required?: boolean): Yargs; + + demand(keys: string[], msg: string): Yargs; + + demand(keys: string[], required?: boolean): Yargs; + + demand(positionals: number, required?: boolean): Yargs; + + demand(positionals: number, msg: string): Yargs; + + demand(positionals: number, max: number, msg?: string): Yargs; + + demandCommand(min: number, minMsg?: string): Yargs; + + demandCommand(min: number, max?: number, minMsg?: string, maxMsg?: string): Yargs; + + demandOption(key: string | string[], msg?: string): Yargs; + + demandOption(key: string | string[], demand?: boolean): Yargs; + + /** + * @deprecated since version 6.6.0 + */ + require(key: string, msg: string): Yargs; + + require(key: string, required: boolean): Yargs; + + require(keys: number[], msg: string): Yargs; + + require(keys: number[], required: boolean): Yargs; + + require(positionals: number, required: boolean): Yargs; + + require(positionals: number, msg: string): Yargs; + + /** + * @deprecated since version 6.6.0 + */ + required(key: string, msg: string): Yargs; + + required(key: string, required: boolean): Yargs; + + required(keys: number[], msg: string): Yargs; + + required(keys: number[], required: boolean): Yargs; + + required(positionals: number, required: boolean): Yargs; + + required(positionals: number, msg: string): Yargs; + + requiresArg(key: string): Yargs; + + requiresArg(keys: string[]): Yargs; + + describe(key: string, description: string): Yargs; + + describe(descriptions: { [key: string]: string }): Yargs; + + option(key: string, options: Options): Yargs; + + option(options: { [key: string]: Options }): Yargs; + + options(key: string, options: Options): Yargs; + + options(options: { [key: string]: Options }): Yargs; + + usage(message: string, options?: { [key: string]: Options }): Yargs; + + usage(options?: { [key: string]: Options }): Yargs; + + command(command: string, description: string): Yargs; + + command(command: string | Array, description: string, builder: (args: Yargs) => Yargs): Yargs; + + command(command: string | Array, description: string, builder: { [optionName: string]: Options }): Yargs; + + // command(command: string, description: string, builder: { [optionName: string]: Options }, handler: (args: any) => void): Yargs; + + command(command: string | Array, description: string, builder: (args: Yargs) => Yargs, handler: (args: any) => void): Yargs; + + command(command: string | Array, description: string, module: CommandModule): Yargs; + + command(module: CommandModule): Yargs; + + commandDir(dir: string, opts?: RequireDirectoryOptions): Yargs; + + completion(): Yargs; + + completion(cmd: string, fn?: AsyncCompletionFunction): Yargs; + + completion(cmd: string, fn?: SyncCompletionFunction): Yargs; + + completion(cmd: string, description?: string, fn?: AsyncCompletionFunction): Yargs; + + completion(cmd: string, description?: string, fn?: SyncCompletionFunction): Yargs; + + example(command: string, description: string): Yargs; + + check(func: (Yargs: any, aliases: { [alias: string]: string }) => any): Yargs; + + boolean(key: string): Yargs; + + boolean(keys: string[]): Yargs; + + string(key: string): Yargs; + + string(keys: string[]): Yargs; + + number(key: string): Yargs; + + number(keys: string[]): Yargs; + + choices(choices: Object): Yargs; + + choices(key: string, values: any[]): Yargs; + + config(): Yargs; + + config(explicitConfigurationObject: Object): Yargs; + + config(key: string, description?: string, parseFn?: (configPath: string) => Object): Yargs; + + config(keys: string[], description?: string, parseFn?: (configPath: string) => Object): Yargs; + + config(key: string, parseFn: (configPath: string) => Object): Yargs; + + config(keys: string[], parseFn: (configPath: string) => Object): Yargs; + + conflicts(key: string, value: string): Yargs; + + conflicts(conflicts: { [key: string]: string }): Yargs; + + wrap(columns: number): Yargs; + + strict(): Yargs; + + help(): Yargs; + + help(enableExplicit: boolean): Yargs; + + help(option: string, enableExplicit: boolean): Yargs; + + help(option: string, description?: string, enableExplicit?: boolean): Yargs; + + env(prefix?: string): Yargs; + + env(enable: boolean): Yargs; + + epilog(msg: string): Yargs; + + epilogue(msg: string): Yargs; + + version(version?: string, option?: string, description?: string): Yargs; + + version(version: () => string, option?: string, description?: string): Yargs; + + showHelpOnFail(enable: boolean, message?: string): Yargs; + + showHelp(consoleLevel?: string): Yargs; + + exitProcess(enabled: boolean): Yargs; + + global(key: string): Yargs; + + global(keys: string[]): Yargs; + + group(key: string, groupName: string): Yargs; + + group(keys: string[], groupName: string): Yargs; + + nargs(key: string, count: number): Yargs; + + nargs(nargs: { [key: string]: number }): Yargs; + + normalize(key: string): Yargs; + + normalize(keys: string[]): Yargs; + + implies(key: string, value: string): Yargs; + + implies(implies: { [key: string]: string }): Yargs; + + count(key: string): Yargs; + + count(keys: string[]): Yargs; + + fail(func: (msg: string, err: Error) => any): Yargs; + + coerce(key: string | string[], func: (arg: T) => U): Yargs; + + coerce(opts: { [key: string]: (arg: T) => U; }): Yargs; + + getCompletion(args: string[], done: (completions: string[]) => void): Yargs; + + pkgConf(key: string, cwd?: string): Yargs; + + pkgConf(keys: string[], cwd?: string): Yargs; + + recommendCommands(): Yargs; + + showCompletionScript(): Yargs; + + skipValidation(key: string): Yargs; + + skipValidation(keys: string[]): Yargs; + + updateLocale(obj: Object): Yargs; + + updateStrings(obj: { [key: string]: string }): Yargs; } - interface Yargs { - argv: Argv; - (args: string[]): T & Argv; - parse (args: string[]): T & Argv; - alias (key: string, alias: string): Yargs; - alias (aliases: { [key: string]: string | string[] }): Yargs; - array (key: string): Yargs; - boolean (key: string): Yargs; - check (fn: (argv: Argv, aliases: { [key: string]: string[] }) => any): Yargs; - choices (key: string, choices: (string | number)[]): Yargs; - command (command: string, description: string, fn?: (yargs: Yargs, argv: Argv) => void): Yargs; - completion (cmd: string, fn?: SyncCompletionFunction | AsyncCompletionFunction): Yargs; - completion (cmd: string, description?: string, fn?: SyncCompletionFunction | AsyncCompletionFunction): Yargs; - config (key: string, description?: string): Yargs; - count (key: string): Yargs; - default (key: string, value: any, description?: string): Yargs; - default (defaults: { [key: string]: any }): Yargs; - demand (key: string | string[], msg?: string): Yargs; - demand (key: string | string[], required?: boolean): Yargs; - demand (count: number, msg?: string): Yargs; - demand (count: number, max?: number, msg?: string): Yargs; - require (key: string | string[], msg?: string): Yargs; - require (key: string | string[], required?: boolean): Yargs; - require (count: number, msg?: string): Yargs; - require (count: number, max?: number, msg?: string): Yargs; - required (key: string | string[], msg?: string): Yargs; - required (key: string | string[], required?: boolean): Yargs; - required (count: number, msg?: string): Yargs; - required (count: number, max?: number, msg?: string): Yargs; - describe (key: string, description: string): Yargs; - detectLocale (enable: boolean): Yargs; - env (prefix?: string | boolean): Yargs; - epilog (str: string): Yargs; - epilogue (str: string): Yargs; - example (cmd: string, description: string): Yargs; - exitProcess (enable: boolean): Yargs; - fail (fn: (message: string) => any): Yargs; - group (keys: string | string[], groupName: string): Yargs; - help (option?: string, description?: string): Yargs; - implies (x: string, y: string): Yargs; - locale (): string; - locale (locale: string): Yargs; - nargs (key: string, count: number): Yargs; - option (key: string, options: Options): Yargs; - options (key: string, options: Options): Yargs; - option (options: { [key: string]: Options }): Yargs; - options (options: { [key: string]: Options }): Yargs; - requiresArg (key: string): Yargs; - reset (): Yargs; - showCompletionScript (): string; - showHelp (consoleLevel?: string): Yargs; - showHelpOnFail (enable: boolean, message?: string): Yargs; - strict (): Yargs; - string (key: string): Yargs; - updateLocale (obj: { [key: string]: string }): Yargs; - updateStrings (obj: { [key: string]: string }): Yargs; - usage (message: string, opts?: Options): Yargs; - version (version?: string | (() => string), option?: string, description?: string): Yargs; - wrap (columns: number | null): Yargs; - - terminalWidth(): number + interface RequireDirectoryOptions { + recurse?: boolean; + extensions?: string[]; + visit?: (commandObject: any, pathToFile?: string, filename?: string) => any; + include?: RegExp | ((pathToFile: string) => boolean); + exclude?: RegExp | ((pathToFile: string) => boolean); } interface Options { alias?: string | string[]; array?: boolean; boolean?: boolean; - choices?: (string | number)[]; + choices?: string[]; + coerce?: (arg: any) => any; config?: boolean; + configParser?: (configPath: string) => Object; count?: boolean; default?: any; defaultDescription?: string; + /** @deprecated since version 6.6.0 */ demand?: boolean | string; - require?: boolean | string; - required?: boolean | string; + demandOption?: boolean | string; desc?: string; describe?: string; description?: string; + global?: boolean; group?: string; nargs?: number; - requiresArg?: boolean; + normalize?: boolean; + number?: boolean; + require?: boolean | string; + required?: boolean | string; + requiresArg?: boolean | string; + skipValidation?: boolean; string?: boolean; - type?: string; + type?: "array" | "boolean" | "count" | "number" | "string"; + } + + interface CommandModule { + aliases?: string[] | string; + builder?: CommandBuilder; + command?: string[] | string; + describe?: string | false; + handler: (args: any) => void; } - type SyncCompletionFunction = (current: string, argv: any) => string[]; - type AsyncCompletionFunction = (current: string, argv: any, done: (completion: string[]) => void) => void; + type CommandBuilder = { [key: string]: Options } | ((args: Yargs) => Yargs); + type SyncCompletionFunction = (current: string, Yargs: any) => string[]; + type AsyncCompletionFunction = (current: string, Yargs: any, done: (completion: string[]) => void) => void; +} - const yargs: Yargs; +declare module "yargs" { + const yargs: yargs.Yargs; export default yargs; -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index 67d3552e890..0c90a45cbe7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -524,9 +524,9 @@ babylon@^6.1.21, babylon@^6.13.0, babylon@^6.17.2: version "6.17.3" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.3.tgz#1327d709950b558f204e5352587fd0290f8d8e48" -balanced-match@^0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" base64-js@1.2.0, base64-js@^1.0.2: version "1.2.0" @@ -584,10 +584,10 @@ boxen@^1.0.0: widest-line "^1.0.0" brace-expansion@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" + version "1.1.8" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" dependencies: - balanced-match "^0.4.1" + balanced-match "^1.0.0" concat-map "0.0.1" braces@^1.8.2: @@ -2948,10 +2948,14 @@ sanitize-filename@^1.6.1: dependencies: truncate-utf8-bytes "^1.0.0" -sax@1.2.1, sax@>=0.6.0, sax@^1.2.1: +sax@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" +sax@>=0.6.0, sax@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828" + semver-diff@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"