Skip to content

Commit

Permalink
feat: Windows code signing from OS X
Browse files Browse the repository at this point in the history
Closes #314
  • Loading branch information
develar committed Apr 20, 2016
1 parent 2b959fe commit 9134f61
Show file tree
Hide file tree
Showing 11 changed files with 56 additions and 21 deletions.
2 changes: 1 addition & 1 deletion docs/Multi Platform Build.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Don't expect that you can build app for all platforms on one platform.
[prebuild](https://www.npmjs.com/package/prebuild) is a solution, but most node modules [don't provide](https://github.com/atom/node-keytar/issues/27) prebuilt binaries.

* OS Code Signing works only OS X. [Cannot be fixed](http://stackoverflow.com/a/12156576).
* Windows Code Signing works only on Windows. We are going [to fix it](https://developer.mozilla.org/en/docs/Signing_an_executable_with_Authenticode) soon.
* Windows Code Signing doesn't work on Linux. We are going to fix it soon.

Don't think that mentioned issues are major, you should use build servers — e.g. [AppVeyor](http://www.appveyor.com/) to build Windows app and [Travis](https://travis-ci.org) to build OS X/Linux apps.

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"command-line-args": "^2.1.6",
"deep-assign": "^2.0.0",
"electron-packager": "^7.0.0",
"electron-winstaller-fixed": "~2.3.0-beta.1",
"electron-winstaller-fixed": "~2.3.0-beta.4",
"fs-extra": "^0.28.0",
"fs-extra-p": "^0.2.0",
"globby": "^4.0.0",
Expand All @@ -70,6 +70,7 @@
"progress": "^1.1.8",
"progress-stream": "^1.2.0",
"read-package-json": "^2.0.3",
"signcode": "^0.4.0",
"source-map-support": "^0.4.0",
"tmp": "0.0.28"
},
Expand Down
3 changes: 1 addition & 2 deletions src/macPackager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ export default class MacPackager extends PlatformPackager<OsXBuildOptions> {

async pack(outDir: string, appOutDir: string, arch: string): Promise<any> {
await super.pack(outDir, appOutDir, arch)
const codeSigningInfo = await this.codeSigningInfo
await this.signMac(path.join(appOutDir, this.appName + ".app"), codeSigningInfo)
await this.signMac(path.join(appOutDir, this.appName + ".app"), await this.codeSigningInfo)
}

private signMac(distPath: string, codeSigningInfo: CodeSigningInfo): Promise<any> {
Expand Down
46 changes: 33 additions & 13 deletions src/winPackager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Platform, WinBuildOptions } from "./metadata"
import * as path from "path"
import { log, statOrNull } from "./util"
import { readFile, deleteFile, stat, rename, copy, emptyDir, writeFile, open, close, read } from "fs-extra-p"
import { sign } from "signcode"

//noinspection JSUnusedLocalSymbols
const __awaiter = require("./awaiter")
Expand All @@ -21,9 +22,7 @@ export class WinPackager extends PlatformPackager<WinBuildOptions> {
constructor(info: BuildInfo, cleanupTasks: Array<() => Promise<any>>) {
super(info)

// https://developer.mozilla.org/en-US/docs/Signing_an_executable_with_Authenticode
// https://github.com/Squirrel/Squirrel.Windows/pull/505
if (this.options.cscLink != null && this.options.cscKeyPassword != null && process.platform !== "darwin") {
if (this.options.cscLink != null && this.options.cscKeyPassword != null) {
this.certFilePromise = downloadCertificate(this.options.cscLink)
.then(path => {
cleanupTasks.push(() => deleteFile(path, true))
Expand Down Expand Up @@ -58,16 +57,15 @@ export class WinPackager extends PlatformPackager<WinBuildOptions> {
await this.iconPath

if (!this.options.dist) {
return super.pack(outDir, appOutDir, arch)
return await super.pack(outDir, appOutDir, arch)
}

const installerOut = computeDistOut(outDir, arch)
log("Removing %s", installerOut)
await
BluebirdPromise.all([
this.doPack(outDir, appOutDir, arch),
emptyDir(installerOut)
])
await BluebirdPromise.all([
this.doPack(outDir, appOutDir, arch),
emptyDir(installerOut)
])

const extraResources = await this.copyExtraResources(appOutDir, arch)
if (extraResources.length > 0) {
Expand All @@ -82,6 +80,24 @@ export class WinPackager extends PlatformPackager<WinBuildOptions> {
}
}

protected async doPack(outDir: string, appOutDir: string, arch: string) {
await super.doPack(outDir, appOutDir, arch)

if (process.platform === "darwin" && this.options.cscLink != null && this.options.cscKeyPassword != null) {
const filename = this.appName + ".exe"
log(`Signing ${filename}`)
await BluebirdPromise.promisify(sign)({
path: path.join(appOutDir, filename),
cert: await this.certFilePromise,
password: this.options.cscKeyPassword,
name: this.appName,
site: await this.computePackageUrl(),
hash: ["sha256"],
overwrite: true,
})
}
}

protected async computeEffectiveDistOptions(appOutDir: string, installerOutDir: string): Promise<any> {
let iconUrl = this.devMetadata.build.iconUrl
if (!iconUrl) {
Expand All @@ -98,11 +114,9 @@ export class WinPackager extends PlatformPackager<WinBuildOptions> {
}
}

const certificateFile = await this.certFilePromise
const projectUrl = await this.computePackageUrl()

use(this.customBuildOptions, checkConflictingOptions)

const projectUrl = await this.computePackageUrl()
const options: any = Object.assign({
name: this.metadata.name,
productName: this.appName,
Expand All @@ -115,14 +129,20 @@ export class WinPackager extends PlatformPackager<WinBuildOptions> {
authors: this.metadata.author.name,
iconUrl: iconUrl,
setupIcon: await this.iconPath,
certificateFile: certificateFile,
certificateFile: await this.certFilePromise,
certificatePassword: this.options.cscKeyPassword,
fixUpPaths: false,
skipUpdateIcon: true,
usePackageJson: false,
noMsi: true,
extraFileSpecs: this.extraNuGetFileSources == null ? null : ("\n" + (await this.extraNuGetFileSources).join("\n")),
extraMetadataSpecs: projectUrl == null ? null : `\n<projectUrl>${projectUrl}</projectUrl>`,
sign: {
name: this.appName,
site: projectUrl,
hash: ["sha256"],
overwrite: true,
}
}, this.customBuildOptions)

if (this.loadingGifStat != null) {
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/test-app-one/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"author": "Foo Bar <[email protected]>",
"license": "MIT",
"devDependencies": {
"electron-prebuilt": "^0.37.5"
"electron-prebuilt": "^0.37.6"
},
"build": {
"app-bundle-id": "your.id",
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/test-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"start": "electron ."
},
"devDependencies": {
"electron-prebuilt": "^0.37.5"
"electron-prebuilt": "^0.37.6"
},
"build": {
"app-bundle-id": "your.id",
Expand Down
2 changes: 1 addition & 1 deletion test/src/BuildTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ test("version from electron-prebuilt dependency", () => assertPack("test-app-one
tempDirCreated: projectDir => {
return BluebirdPromise.all([
outputJson(path.join(projectDir, "node_modules", "electron-prebuilt", "package.json"), {
version: "0.37.5"
version: "0.37.6"
}),
modifyPackageJson(projectDir, data => {
data.devDependencies = {}
Expand Down
2 changes: 1 addition & 1 deletion test/src/helpers/runTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const rootDir = path.join(__dirname, "..", "..", "..")
const testPackageDir = path.join(require("os").tmpdir(), "electron_builder_published")
const testNodeModules = path.join(testPackageDir, "node_modules")

const electronVersion = "0.37.5"
const electronVersion = "0.37.6"

BluebirdPromise.all([
deleteOldElectronVersion(),
Expand Down
1 change: 1 addition & 0 deletions test/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"../typings/node.d.ts",
"../typings/progress-stream.d.ts",
"../typings/read-package-json.d.ts",
"../typings/signcode.d.ts",
"typings/ava.d.ts",
"typings/decompress-zip.d.ts",
"typings/json-parse-helpfulerror.d.ts",
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"typings/node.d.ts",
"typings/progress-stream.d.ts",
"typings/read-package-json.d.ts",
"typings/signcode.d.ts",
"node_modules/typescript/lib/lib.es7.d.ts",
"node_modules/fs-extra-p/index.d.ts",
"node_modules/7zip-bin/index.d.ts",
Expand Down
13 changes: 13 additions & 0 deletions typings/signcode.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
declare module "signcode" {
export interface SignOptions {
path: string
cert: string
name?: string
password: string
site?: string
hash?: Array<string>
overwrite?: boolean
}

export function sign(options: SignOptions, callback: (error: Error) => void): void
}

0 comments on commit 9134f61

Please sign in to comment.