From fe533882031323b8ef473ee18149c3ed80124323 Mon Sep 17 00:00:00 2001 From: develar Date: Mon, 30 May 2016 09:53:16 +0200 Subject: [PATCH] feat: user-friendly MAS code signing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * `identity` is removed from the `build.mas`. * Env `CSC_INSTALLER_NAME` is removed. * You don't need to specify `CSC_NAME` env or `build.osx.identity`. Valid identity from your keychain will be automatically used. * `CSC_NAME` env or `build.osx.identity` is still not removed because it is required if you have several identities. But now instead of `Developer ID Installer: Your Name (XXXXXXXXXX)`, you should specify only `Your Name` — appropriate certificate will be chosen automatically. --- .idea/dictionaries/develar.xml | 1 + docs/Code Signing.md | 12 ++-- docs/Options.md | 2 +- src/codeSign.ts | 96 ++++++++++++++++++------------- src/linuxPackager.ts | 3 +- src/metadata.ts | 8 +-- src/osxPackager.ts | 101 ++++++++++++++++++++++++--------- src/packager.ts | 6 +- src/platformPackager.ts | 36 +++++------- src/util.ts | 8 +-- src/winPackager.ts | 1 - test/src/BuildTest.ts | 4 +- test/src/helpers/packTester.ts | 6 +- test/src/osxPackagerTest.ts | 34 ++++------- 14 files changed, 179 insertions(+), 139 deletions(-) diff --git a/.idea/dictionaries/develar.xml b/.idea/dictionaries/develar.xml index 634f0bacb07..3b093d007b0 100644 --- a/.idea/dictionaries/develar.xml +++ b/.idea/dictionaries/develar.xml @@ -10,6 +10,7 @@ circleci clcerts cleanuper + codesigning coroutine crypto debian diff --git a/docs/Code Signing.md b/docs/Code Signing.md index 2b0569d18cd..d0d24548f2b 100644 --- a/docs/Code Signing.md +++ b/docs/Code Signing.md @@ -1,6 +1,6 @@ OS X and Windows code signing is supported. Windows is dual code-signed (SHA1 & SHA256 hashing algorithms). -On a development machine set environment variable `CSC_NAME` (and `CSC_INSTALLER_NAME` if you build for Mac App Store) to your identity. +On a OS X development machine valid and appropriate identity from your keychain will be automatically used. | Env name | Description | -------------- | ----------- @@ -8,12 +8,7 @@ On a development machine set environment variable `CSC_NAME` (and `CSC_INSTALLER | `CSC_KEY_PASSWORD` | The password to decrypt the certificate given in `CSC_LINK`. | `CSC_INSTALLER_LINK` | *osx-only* The HTTPS link (or base64-encoded data) to certificate to sign Mac App Store build (`*.p12` file). | `CSC_INSTALLER_KEY_PASSWORD` | *osx-only* The password to decrypt the certificate given in `CSC_INSTALLER_LINK`. -| `CSC_NAME` | *osx-only* Name of certificate (to retrieve from login.keychain). Useful on a development machine (not on CI). -| `CSC_INSTALLER_NAME` | *osx-only* Name of installer certificate (to retrieve from login.keychain). Useful on a development machine (not on CI). - -``` -export CSC_NAME="Developer ID Application: Your Name (code)" -``` +| `CSC_NAME` | *osx-only* Name of certificate (to retrieve from login.keychain). Useful on a development machine (not on CI) if you have several identities (otherwise don't specify it). ## Travis, AppVeyor and other CI Servers To sign app on build server you need to set `CSC_LINK`, `CSC_KEY_PASSWORD` (and `CSC_INSTALLER_LINK`, `CSC_INSTALLER_KEY_PASSWORD` if you build for Mac App Store): @@ -29,4 +24,5 @@ To sign app on build server you need to set `CSC_LINK`, `CSC_KEY_PASSWORD` (and In case of AppVeyor, don't forget to click on lock icon to “Toggle variable encryption”. # Where to Buy Code Signing Certificate -[StartSSL](https://startssl.com/Support?v=34) is recommended. \ No newline at end of file +[StartSSL](https://startssl.com/Support?v=34) is recommended. +Please note — Gatekeeper only recognises [Apple digital certificates](http://stackoverflow.com/questions/11833481/non-apple-issued-code-signing-certificate-can-it-work-with-mac-os-10-8-gatekeep). \ No newline at end of file diff --git a/docs/Options.md b/docs/Options.md index df030db0a5d..2686d548590 100644 --- a/docs/Options.md +++ b/docs/Options.md @@ -84,7 +84,6 @@ MAS (Mac Application Store) specific options (in addition to `build.osx`). | Name | Description | --- | --- -| identity | The name of certificate to use when signing. Consider using environment variables [CSC_INSTALLER_LINK or CSC_INSTALLER_NAME](https://github.com/electron-userland/electron-builder/wiki/Code-Signing). | entitlements |

The path to entitlements file for signing the app. build/mas.entitlements will be used if exists (it is a recommended way to set). Otherwise [default](https://github.com/electron-userland/electron-osx-sign/blob/master/default.mas.entitlements).

| entitlementsInherit |

The path to child entitlements which inherit the security settings for signing frameworks and bundles of a distribution. build/mas.inherit.entitlements will be used if exists (it is a recommended way to set). Otherwise [default](https://github.com/electron-userland/electron-osx-sign/blob/master/default.mas.inherit.entitlements).

@@ -97,6 +96,7 @@ MAS (Mac Application Store) specific options (in addition to `build.osx`). | msi | Whether to create an MSI installer. Defaults to `false` (MSI is not created). | remoteReleases | A URL to your existing updates. If given, these will be downloaded to create delta updates. | remoteToken | Authentication token for remote updates +| signingHashAlgorithms | Array of signing algorithms used. Defaults to `['sha1', 'sha256']` ### `.build.linux` diff --git a/src/codeSign.ts b/src/codeSign.ts index 5c05f0a8e50..57daac549fa 100644 --- a/src/codeSign.ts +++ b/src/codeSign.ts @@ -18,12 +18,8 @@ export interface CodeSigningInfo { installerName?: string | null } -function randomString(): string { - return randomBytes(8).toString("hex") -} - export function generateKeychainName(): string { - return "csc-" + randomString() + ".keychain" + return path.join(tmpdir(), getTempName("csc") + ".keychain") } function downloadUrlOrBase64(urlOrBase64: string, destination: string): BluebirdPromise { @@ -35,37 +31,39 @@ function downloadUrlOrBase64(urlOrBase64: string, destination: string): Bluebird } } -let bundledCertKeychainAdded = false +let bundledCertKeychainAdded: Promise | null = 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 +async function createCustomCertKeychain() { + // copy to temp and then atomic rename to final path + const tmpKeychainPath = path.join(homedir(), ".cache", getTempName("electron_builder_root_certs")) + const keychainPath = path.join(homedir(), ".cache", "electron_builder_root_certs.keychain") + const results = await BluebirdPromise.all([ + exec("security", ["list-keychains"]), + copy(path.join(__dirname, "..", "certs", "root_certs.keychain"), tmpKeychainPath) + .then(() => 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.includes(keychainPath)) { + await exec("security", ["list-keychains", "-d", "user", "-s", keychainPath].concat(list)) + } +} export async function createKeychain(keychainName: string, cscLink: string, cscKeyPassword: string, cscILink?: string | null, cscIKeyPassword?: string | null): Promise { - if (!bundledCertKeychainAdded) { - // "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 - - bundledCertKeychainAdded = true - - // copy to temp and then atomic rename to final path - const tmpKeychainPath = path.join(homedir(), ".cache", getTempName("electron_builder_root_certs")) - const keychainPath = path.join(homedir(), ".cache", "electron_builder_root_certs.keychain") - const results = await BluebirdPromise.all | string>([ - exec("security", ["list-keychains"]), - copy(path.join(__dirname, "..", "certs", "root_certs.keychain"), tmpKeychainPath) - .then(() => rename(tmpKeychainPath, keychainPath)), - ]) - const list = (results[0])[0] - .split("\n") - .map(it => { - let r = it.trim() - return r.substring(1, r.length - 1) - }) - .filter(it => it.length > 0) - - if (!list.includes(keychainPath)) { - await exec("security", ["list-keychains", "-d", "user", "-s", keychainPath].concat(list)) - } + if (bundledCertKeychainAdded == null) { + bundledCertKeychainAdded = createCustomCertKeychain() } + await bundledCertKeychainAdded const certLinks = [cscLink] if (cscILink != null) { @@ -73,10 +71,10 @@ export async function createKeychain(keychainName: string, cscLink: string, cscK } const certPaths = new Array(certLinks.length) - const keychainPassword = randomString() + const keychainPassword = randomBytes(8).toString("hex") return await executeFinally(BluebirdPromise.all([ BluebirdPromise.map(certLinks, (link, i) => { - const tempFile = path.join(tmpdir(), `${randomString()}.p12`) + const tempFile = path.join(tmpdir(), `${getTempName()}.p12`) certPaths[i] = tempFile return downloadUrlOrBase64(link, tempFile) }), @@ -117,7 +115,7 @@ async function importCerts(keychainName: string, paths: Array, keyPasswo function extractCommonName(password: string, certPath: string): BluebirdPromise { return exec("openssl", ["pkcs12", "-nokeys", "-nodes", "-passin", "pass:" + password, "-nomacver", "-clcerts", "-in", certPath]) .then(result => { - const match = | null>(result[0].toString().match(/^subject.*\/CN=([^\/\n]+)/m)) + const match = | null>(result.match(/^subject.*\/CN=([^\/\n]+)/m)) if (match == null || match[1] == null) { throw new Error("Cannot extract common name from p12") } @@ -136,8 +134,7 @@ export function sign(path: string, options: CodeSigningInfo): BluebirdPromise { - // exec("security", ["delete-keychain", keychainName]) - const result = BluebirdPromise.resolve() + const result = exec("security", ["delete-keychain", keychainName]) if (ignoreNotFound) { return result.catch(error => { if (!error.message.includes("The specified keychain could not be found.")) { @@ -151,7 +148,28 @@ export function deleteKeychain(keychainName: string, ignoreNotFound: boolean = t } export function downloadCertificate(cscLink: string): Promise { - const certPath = path.join(tmpdir(), randomString() + ".p12") + const certPath = path.join(tmpdir(), `${getTempName()}.p12`) return downloadUrlOrBase64(cscLink, certPath) .thenReturn(certPath) } + +let findIdentityRawResult: Promise | null = null + +export async function findIdentity(namePrefix: string, qualifier?: string): Promise { + if (findIdentityRawResult == null) { + findIdentityRawResult = exec("security", ["find-identity", "-v", "-p", "codesigning"]) + } + + const lines = (await findIdentityRawResult).split("\n") + for (let line of lines) { + if (qualifier != null && !line.includes(qualifier)) { + continue + } + + const location = line.indexOf(namePrefix) + if (location >= 0) { + return line.substring(location, line.lastIndexOf('"')) + } + } + return null +} \ No newline at end of file diff --git a/src/linuxPackager.ts b/src/linuxPackager.ts index eec0416b4a7..13c0172a5ac 100755 --- a/src/linuxPackager.ts +++ b/src/linuxPackager.ts @@ -126,8 +126,7 @@ Icon=${this.metadata.name} } private async createFromIcns(tempDir: string): Promise> { - const outputs = await exec("icns2png", ["-x", "-o", tempDir, path.join(this.buildResourcesDir, "icon.icns")]) - const output = outputs[0].toString() + const output = await exec("icns2png", ["-x", "-o", tempDir, path.join(this.buildResourcesDir, "icon.icns")]) debug(output) const imagePath = path.join(tempDir, "icon_256x256x32.png") diff --git a/src/metadata.ts b/src/metadata.ts index 99f4330763d..766f208e410 100755 --- a/src/metadata.ts +++ b/src/metadata.ts @@ -207,11 +207,6 @@ export interface OsXBuildOptions extends PlatformSpecificBuildOptions { MAS (Mac Application Store) specific options (in addition to `build.osx`). */ export interface MasBuildOptions extends OsXBuildOptions { - /* - The name of certificate to use when signing. Consider using environment variables [CSC_INSTALLER_LINK or CSC_INSTALLER_NAME](https://github.com/electron-userland/electron-builder/wiki/Code-Signing). - */ - readonly identity?: string | null - /* The path to entitlements file for signing the app. `build/mas.entitlements` will be used if exists (it is a recommended way to set). Otherwise [default](https://github.com/electron-userland/electron-osx-sign/blob/master/default.mas.entitlements). @@ -263,6 +258,9 @@ export interface WinBuildOptions extends PlatformSpecificBuildOptions { */ readonly remoteToken?: string | null + /* + Array of signing algorithms used. Defaults to `['sha1', 'sha256']` + */ readonly signingHashAlgorithms?: Array | null readonly signcodePath?: string | null } diff --git a/src/osxPackager.ts b/src/osxPackager.ts index 26fd12a60a5..006f4746311 100644 --- a/src/osxPackager.ts +++ b/src/osxPackager.ts @@ -3,7 +3,7 @@ import { Platform, OsXBuildOptions, MasBuildOptions } from "./metadata" import * as path from "path" import { Promise as BluebirdPromise } from "bluebird" import { log, debug, warn } from "./util" -import { createKeychain, deleteKeychain, CodeSigningInfo, generateKeychainName } from "./codeSign" +import { createKeychain, deleteKeychain, CodeSigningInfo, generateKeychainName, findIdentity } from "./codeSign" import deepAssign = require("deep-assign") import { sign, flat, BaseSignOptions, SignOptions, FlatOptions } from "electron-osx-sign-tf" @@ -16,14 +16,18 @@ export default class OsXPackager extends PlatformPackager { constructor(info: BuildInfo, cleanupTasks: Array<() => Promise>) { super(info) - if (this.options.cscLink != null && this.options.cscKeyPassword != null) { + if (this.options.cscLink == null) { + this.codeSigningInfo = BluebirdPromise.resolve(null) + } + else { + if (this.options.cscKeyPassword == null) { + throw new Error("cscLink is set, but cscKeyPassword not") + } + const keychainName = generateKeychainName() cleanupTasks.push(() => deleteKeychain(keychainName)) this.codeSigningInfo = createKeychain(keychainName, this.options.cscLink, this.options.cscKeyPassword, this.options.cscInstallerLink, this.options.cscInstallerKeyPassword) } - else { - this.codeSigningInfo = BluebirdPromise.resolve(null) - } } get platform() { @@ -59,33 +63,77 @@ export default class OsXPackager extends PlatformPackager { } } + private static async findIdentity(certType: string, name?: string | null): Promise { + let identity = process.env.CSC_NAME || name + if (identity == null || identity.trim().length === 0) { + return await findIdentity(certType) + } + else { + identity = identity.trim() + checkPrefix(identity, "Developer ID Application:") + checkPrefix(identity, "3rd Party Mac Developer Application:") + checkPrefix(identity, "Developer ID Installer:") + checkPrefix(identity, "3rd Party Mac Developer Installer:") + const result = await findIdentity(certType, identity) + if (result == null) { + throw new Error(`Identity name "${identity}" is specified, but no valid identity with this name in the keychain`) + } + return result + } + } + private async sign(appOutDir: string, masOptions: MasBuildOptions | null): Promise { let codeSigningInfo = await this.codeSigningInfo if (codeSigningInfo == null) { - codeSigningInfo = { - name: process.env.CSC_NAME || this.customBuildOptions.identity, - installerName: process.env.CSC_INSTALLER_NAME || (masOptions == null ? null : masOptions.identity), + if (process.env.CSC_LINK != null) { + throw new Error("codeSigningInfo is null, but CSC_LINK defined") + } + + const identity = await OsXPackager.findIdentity(masOptions == null ? "Developer ID Application" : "3rd Party Mac Developer Application", this.customBuildOptions.identity) + if (identity == null) { + const message = "App is not signed: CSC_LINK or CSC_NAME are not specified, and no valid identity in the keychain, see https://github.com/electron-userland/electron-builder/wiki/Code-Signing" + if (masOptions == null) { + warn(message) + return + } + else { + throw new Error(message) + } } - } - const identity = codeSigningInfo.name - if (identity == null) { - const message = "App is not signed: CSC_LINK or CSC_NAME are not specified, see https://github.com/electron-userland/electron-builder/wiki/Code-Signing" if (masOptions != null) { - throw new Error(message) + const installerName = masOptions == null ? null : (await OsXPackager.findIdentity("3rd Party Mac Developer Installer", this.customBuildOptions.identity)) + if (installerName == null) { + throw new Error("Cannot find valid installer certificate: CSC_LINK or CSC_NAME are not specified, and no valid identity in the keychain, see https://github.com/electron-userland/electron-builder/wiki/Code-Signing") + } + + codeSigningInfo = { + name: identity, + installerName: installerName, + } + } + else { + codeSigningInfo = { + name: identity, + } + } + } + else { + if (codeSigningInfo.name == null && masOptions == null) { + throw new Error("codeSigningInfo.name is null, but CSC_LINK defined") + } + if (masOptions != null && codeSigningInfo.installerName == null) { + throw new Error("Signing is required for mas builds but CSC_INSTALLER_LINK is not specified") } - warn(message) - return } + const identity = codeSigningInfo.name log(`Signing app (identity: ${identity})`) const baseSignOptions: BaseSignOptions = { - app: path.join(appOutDir, this.appName + ".app"), - platform: masOptions == null ? "darwin" : "mas" - } - if (codeSigningInfo.keychainName != null) { - baseSignOptions.keychain = codeSigningInfo.keychainName + app: path.join(appOutDir, `${this.appName}.app`), + platform: masOptions == null ? "darwin" : "mas", + keychain: codeSigningInfo.keychainName, } const signOptions = Object.assign({ @@ -118,15 +166,10 @@ export default class OsXPackager extends PlatformPackager { await this.doSign(signOptions) if (masOptions != null) { - const installerIdentity = codeSigningInfo.installerName - if (installerIdentity == null) { - throw new Error("Signing is required for mas builds but CSC_INSTALLER_LINK or CSC_INSTALLER_NAME are not specified") - } - const pkg = path.join(appOutDir, `${this.appName}-${this.metadata.version}.pkg`) await this.doFlat(Object.assign({ pkg: pkg, - identity: installerIdentity, + identity: codeSigningInfo.installerName, }, baseSignOptions)) this.dispatchArtifactCreated(pkg, `${this.metadata.name}-${this.metadata.version}.pkg`) } @@ -225,4 +268,10 @@ export default class OsXPackager extends PlatformPackager { this.dispatchArtifactCreated(artifactPath, `${this.metadata.name}-${this.metadata.version}.dmg`) } +} + +function checkPrefix(name: string, prefix: string) { + if (name.startsWith(prefix)) { + throw new Error(`Please remove prefix "${prefix}" from the specified name — appropriate certificate will be chosen automatically`) + } } \ No newline at end of file diff --git a/src/packager.ts b/src/packager.ts index 8176c8d3d5b..fca0e4a2776 100644 --- a/src/packager.ts +++ b/src/packager.ts @@ -77,7 +77,7 @@ export class Packager implements BuildInfo { // custom packager - don't check wine let checkWine = this.options.platformPackagerFactory == null for (let platform of platforms) { - let wineCheck: Promise | null = null + let wineCheck: Promise | null = null if (checkWine && process.platform !== "win32" && platform === Platform.WINDOWS) { wineCheck = exec("wine", ["--version"]) } @@ -231,14 +231,14 @@ function checkConflictingOptions(options: any) { } } -async function checkWineVersion(checkPromise: Promise) { +async function checkWineVersion(checkPromise: Promise) { function wineError(prefix: string): string { return `${prefix}, please see https://github.com/electron-userland/electron-builder/wiki/Multi-Platform-Build#${(process.platform === "linux" ? "linux" : "os-x")}` } let wineVersion: string try { - wineVersion = (await checkPromise)[0].trim() + wineVersion = (await checkPromise).trim() } catch (e) { if (e.code === "ENOENT") { diff --git a/src/platformPackager.ts b/src/platformPackager.ts index 287715964b3..f1537b3bada 100644 --- a/src/platformPackager.ts +++ b/src/platformPackager.ts @@ -275,6 +275,19 @@ export abstract class PlatformPackager return statFile(path.join(resourcesDir, "app.asar"), relativeFile) != null } catch (e) { + const asarFile = path.join(resourcesDir, "app.asar") + const fileStat = await statOrNull(asarFile) + if (fileStat == null) { + throw new Error(`File "${asarFile}" does not exist. Seems like a wrong configuration.`) + } + + try { + listPackage(asarFile) + } + catch (e) { + throw new Error(`File "${asarFile}" is corrupted: ${e}`) + } + // asar throws error on access to undefined object (info.link) return false } @@ -285,36 +298,17 @@ export abstract class PlatformPackager } } - private static async sanityCheckAsar(asarFile: string): Promise { - const outStat = await statOrNull(asarFile) - - if (outStat == null) { - throw new Error(`Package file ${asarFile} was not created.`) - } - - try { - listPackage(asarFile) - } - catch (e) { - throw new Error(`Package file ${asarFile} is corrupted.`) - } - } - private async sanityCheckPackage(appOutDir: string, isAsar: boolean): Promise { const outStat = await statOrNull(appOutDir) if (outStat == null) { - throw new Error(`Output directory ${appOutDir} does not exists. Seems like a wrong configuration.`) + throw new Error(`Output directory "${appOutDir}" does not exist. Seems like a wrong configuration.`) } else if (!outStat.isDirectory()) { - throw new Error(`Output directory ${appOutDir} is not a directory. Seems like a wrong configuration.`) + throw new Error(`Output directory "${appOutDir}" is not a directory. Seems like a wrong configuration.`) } const resourcesDir = this.getResourcesDir(appOutDir) - if (isAsar) { - await PlatformPackager.sanityCheckAsar(path.join(resourcesDir, "app.asar")) - } - const mainFile = this.metadata.main || "index.js" const mainFileExists = await this.statFileInPackage(resourcesDir, mainFile, isAsar) if (!mainFileExists) { diff --git a/src/util.ts b/src/util.ts index d601633da19..39066b9b89e 100644 --- a/src/util.ts +++ b/src/util.ts @@ -67,15 +67,15 @@ export interface ExecOptions extends BaseExecOptions { killSignal?: string } -export function exec(file: string, args?: Array | null, options?: ExecOptions): BluebirdPromise { +export function exec(file: string, args?: Array | null, options?: ExecOptions): BluebirdPromise { if (debug.enabled) { debug(`Executing ${file} ${args == null ? "" : args.join(" ")}`) } - return new BluebirdPromise((resolve, reject) => { + return new BluebirdPromise((resolve, reject) => { execFile(file, args, options, function (error, stdout, stderr) { if (error == null) { - resolve([stdout, stderr]) + resolve(stdout) } else { if (stdout.length !== 0) { @@ -217,5 +217,5 @@ export function debug7zArgs(command: "a" | "x"): Array { let tmpDirCounter = 0 export function getTempName(prefix?: string | n): string { - return `${prefix == null ? "" : prefix + "-"}${process.pid}-${tmpDirCounter++}-${Date.now()}` + return `${prefix == null ? "" : prefix + "-"}${process.pid}-${tmpDirCounter++}` } \ No newline at end of file diff --git a/src/winPackager.ts b/src/winPackager.ts index 215650e72cf..b3ed5c67d1d 100644 --- a/src/winPackager.ts +++ b/src/winPackager.ts @@ -137,7 +137,6 @@ export class WinPackager extends PlatformPackager { fixUpPaths: false, skipUpdateIcon: true, usePackageJson: false, - msi: false, extraMetadataSpecs: projectUrl == null ? null : `\n ${projectUrl}`, copyright: packOptions["app-copyright"], sign: { diff --git a/test/src/BuildTest.ts b/test/src/BuildTest.ts index 8e0adbba6a8..d2da7aa9ee5 100755 --- a/test/src/BuildTest.ts +++ b/test/src/BuildTest.ts @@ -103,7 +103,7 @@ test("relative index", () => assertPack("test-app", allPlatforms(false), { const electronVersion = "0.37.8" -test("electron version from electron-prebuilt dependency", () => assertPack("test-app-one", { +test.ifNotWindows("electron version from electron-prebuilt dependency", () => assertPack("test-app-one", { platform: [Platform.LINUX], target: ["dir"], }, { @@ -117,7 +117,7 @@ test("electron version from electron-prebuilt dependency", () => assertPack("tes ]) })) -test("electron version from build", () => assertPack("test-app-one", { +test.ifNotWindows("electron version from build", () => assertPack("test-app-one", { platform: [Platform.LINUX], target: [DIR_TARGET], }, { diff --git a/test/src/helpers/packTester.ts b/test/src/helpers/packTester.ts index 4a5c63a39f8..da645d39d59 100755 --- a/test/src/helpers/packTester.ts +++ b/test/src/helpers/packTester.ts @@ -153,7 +153,7 @@ async function checkLinuxResult(projectDir: string, packager: Packager, packager assertThat(await getContents(`${projectDir}/${outDirName}/TestApp-1.1.0-i386.deb`, productName)).deepEqual(expectedContents) } - assertThat(parseDebControl((await exec("dpkg", ["--info", packageFile])).toString())).has.properties({ + assertThat(parseDebControl(await exec("dpkg", ["--info", packageFile]))).has.properties({ License: "MIT", Homepage: "http://foo.example.com", Maintainer: "Foo Bar ", @@ -196,7 +196,7 @@ async function checkOsXResult(packager: Packager, packagerOptions: PackagerOptio if (packagerOptions.cscLink != null) { const result = await exec("codesign", ["--verify", packedAppDir]) - assertThat(result[0].toString()).not.match(/is not signed at all/) + assertThat(result).not.match(/is not signed at all/) } const actualFiles = artifacts.map(it => path.basename(it.file)).sort() @@ -288,7 +288,7 @@ async function checkWindowsResult(packager: Packager, packagerOptions: PackagerO async function getContents(path: string, productName: string) { const result = await exec("dpkg", ["--contents", path]) - return pathSorter(result[0].toString() + return pathSorter(result .split("\n") .map(it => it.length === 0 ? null : it.substring(it.indexOf(".") + 1)) .filter(it => it != null && !(it.startsWith(`/opt/${productName}/locales/`) || it.startsWith(`/opt/${productName}/libgcrypt`))) diff --git a/test/src/osxPackagerTest.ts b/test/src/osxPackagerTest.ts index 394fa29f6de..6ec15d62d30 100644 --- a/test/src/osxPackagerTest.ts +++ b/test/src/osxPackagerTest.ts @@ -50,55 +50,49 @@ test.ifOsx("mas and 7z", createTargetTest(["mas", "7z"], ["TestApp-1.1.0-osx.7z" test.ifOsx("custom mas", () => { let platformPackager: CheckingOsXPackager = null - return assertPack("test-app-one", { + return assertPack("test-app-one", signed({ platform: [Platform.OSX], platformPackagerFactory: (packager, platform, cleanupTasks) => platformPackager = new CheckingOsXPackager(packager, cleanupTasks), devMetadata: { build: { osx: { - identity: "osx", - target: ["mas"] + target: ["mas"], + identity: "Test Test", }, mas: { - identity: "MAS", entitlements: "mas-entitlements file path", entitlementsInherit: "mas-entitlementsInherit file path", } } } - }, { + }), { packed: () => { assertThat(platformPackager.effectiveSignOptions).has.properties({ - identity: "osx", + identity: "Test Test", entitlements: "mas-entitlements file path", "entitlements-inherit": "mas-entitlementsInherit file path", }) - assertThat(platformPackager.effectiveFlatOptions).has.properties({ - identity: "MAS", - }) return BluebirdPromise.resolve(null) } }) }) -test.ifOsx("identity in package.json", () => { +test.ifOsx("entitlements in the package.json", () => { let platformPackager: CheckingOsXPackager = null - return assertPack("test-app-one", { + return assertPack("test-app-one", signed({ platform: [Platform.OSX], platformPackagerFactory: (packager, platform, cleanupTasks) => platformPackager = new CheckingOsXPackager(packager, cleanupTasks), devMetadata: { build: { osx: { - identity: "osx", entitlements: "osx-entitlements file path", entitlementsInherit: "osx-entitlementsInherit file path", } } } - }, { + }), { packed: () => { assertThat(platformPackager.effectiveSignOptions).has.properties({ - identity: "osx", entitlements: "osx-entitlements file path", "entitlements-inherit": "osx-entitlementsInherit file path", }) @@ -109,24 +103,16 @@ test.ifOsx("identity in package.json", () => { test.ifOsx("entitlements in build dir", () => { let platformPackager: CheckingOsXPackager = null - return assertPack("test-app-one", { + return assertPack("test-app-one", signed({ platform: [Platform.OSX], platformPackagerFactory: (packager, platform, cleanupTasks) => platformPackager = new CheckingOsXPackager(packager, cleanupTasks), - devMetadata: { - build: { - osx: { - identity: "osx", - } - } - } - }, { + }), { tempDirCreated: projectDir => BluebirdPromise.all([ writeFile(path.join(projectDir, "build", "osx.entitlements"), ""), writeFile(path.join(projectDir, "build", "osx.inherit.entitlements"), ""), ]), packed: projectDir => { assertThat(platformPackager.effectiveSignOptions).has.properties({ - identity: "osx", entitlements: path.join(projectDir, "build", "osx.entitlements"), "entitlements-inherit": path.join(projectDir, "build", "osx.inherit.entitlements"), })