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
Show file tree
Hide file tree
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
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
}