Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Windows code signing from OS X #341

Merged
merged 1 commit into from
Apr 20, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
feat: Windows code signing from OS X
Closes #314
develar committed Apr 20, 2016
commit 9134f61eaab707f8ad651928eee92d944a92317c
2 changes: 1 addition & 1 deletion docs/Multi Platform Build.md
Original file line number Diff line number Diff line change
@@ -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.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
@@ -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"
},
3 changes: 1 addition & 2 deletions src/macPackager.ts
Original file line number Diff line number Diff line change
@@ -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> {
46 changes: 33 additions & 13 deletions src/winPackager.ts
Original file line number Diff line number Diff line change
@@ -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")
@@ -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))
@@ -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) {
@@ -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) {
@@ -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,
@@ -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) {
2 changes: 1 addition & 1 deletion test/fixtures/test-app-one/package.json
Original file line number Diff line number Diff line change
@@ -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",
2 changes: 1 addition & 1 deletion test/fixtures/test-app/package.json
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
"start": "electron ."
},
"devDependencies": {
"electron-prebuilt": "^0.37.5"
"electron-prebuilt": "^0.37.6"
},
"build": {
"app-bundle-id": "your.id",
2 changes: 1 addition & 1 deletion test/src/BuildTest.ts
Original file line number Diff line number Diff line change
@@ -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 = {}
2 changes: 1 addition & 1 deletion test/src/helpers/runTests.ts
Original file line number Diff line number Diff line change
@@ -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(),
1 change: 1 addition & 0 deletions test/tsconfig.json
Original file line number Diff line number Diff line change
@@ -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",
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -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",
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
}