Skip to content

Commit 4be81dc

Browse files
committed
feat(windows): Support passing the sha1 of a certificate in Windows codesign
Close #1297
1 parent 7bd11e1 commit 4be81dc

32 files changed

+474
-241
lines changed

.gitignore

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,8 @@ dist/
1515

1616
/docs/.idea/
1717

18-
/typings/browser/
19-
/typings/browser.d.ts
20-
/typings/main.d.ts
21-
2218
.DS_Store
2319

24-
/test/typings/electron-builder.d.ts
25-
/test/typings/electron-updater.d.ts
26-
2720
/packages/*/out/
2821
/out/
2922
# to not exclude .js.snap (jest snapshots)

docs/Options.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ To use Squirrel.Windows please install `electron-builder-squirrel-windows` depen
247247
| certificateFile | <a name="WinBuildOptions-certificateFile"></a><p>The path to the *.pfx certificate you want to sign with. Please use it only if you cannot use env variable <code>CSC_LINK</code> (<code>WIN_CSC_LINK</code>) for some reason. Please see [Code Signing](https://github.com/electron-userland/electron-builder/wiki/Code-Signing).</p>
248248
| certificatePassword | <a name="WinBuildOptions-certificatePassword"></a><p>The password to the certificate provided in <code>certificateFile</code>. Please use it only if you cannot use env variable <code>CSC_KEY_PASSWORD</code> (<code>WIN_CSC_KEY_PASSWORD</code>) for some reason. Please see [Code Signing](https://github.com/electron-userland/electron-builder/wiki/Code-Signing).</p>
249249
| certificateSubjectName | <a name="WinBuildOptions-certificateSubjectName"></a>The name of the subject of the signing certificate. Required only for EV Code Signing and works only on Windows.
250+
| certificateSha1 | <a name="WinBuildOptions-certificateSha1"></a>* The SHA1 hash of the signing certificate. The SHA1 hash is commonly specified when multiple certificates satisfy the criteria specified by the remaining switches. Works only on Windows.
250251
| rfc3161TimeStampServer | <a name="WinBuildOptions-rfc3161TimeStampServer"></a>The URL of the RFC 3161 time stamp server. Defaults to `http://timestamp.comodoca.com/rfc3161`.
251252
| timeStampServer | <a name="WinBuildOptions-timeStampServer"></a>The URL of the time stamp server. Defaults to `http://timestamp.verisign.com/scripts/timstamp.dll`.
252253
| publisherName | <a name="WinBuildOptions-publisherName"></a><p>[The publisher name](https://github.com/electron-userland/electron-builder/issues/1187#issuecomment-278972073), exactly as in your code signed certificate. Several names can be provided. Defaults to common name from your code signing certificate.</p>

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"pretest": "node ./test/vendor/yarn.js compile && node ./test/vendor/yarn.js lint && node ./test/vendor/yarn.js lint-deps",
88
"lint-deps": "node ./test/out/helpers/checkDeps.js",
99
"///": "Please see https://github.com/electron-userland/electron-builder/blob/master/CONTRIBUTING.md#run-test-using-cli how to run particular test instead full (and very slow) run",
10-
"test": "node ./test/out/helpers/runTests.js skipFpm skipSw skipArtifactPublisher",
10+
"test": "node ./test/out/helpers/runTests.js skipArtifactPublisher ALL_TESTS=false",
1111
"test-all": "node ./test/vendor/yarn.js pretest && node ./test/out/helpers/runTests.js",
1212
"test-linux": "docker run --rm -ti -v ${PWD}: /project -v ${PWD##*/}-node-modules:/project/node_modules -v ~/.electron:/root/.electron electronuserland/electron-builder:wine /bin/bash -c \"node ./test/vendor/yarn.js && node ./test/vendor/yarn.js test\"",
1313
"//": "Update wiki if docs changed. Update only if functionalily are generally available (latest release, not next)",
@@ -28,8 +28,8 @@
2828
"ajv": "^5.0.2-beta",
2929
"ajv-keywords": "^2.0.1-beta.0",
3030
"archiver": "^1.3.0",
31-
"asar-electron-builder": "~0.14.2",
32-
"aws-sdk": "^2.17.0",
31+
"asar": "~0.13.0",
32+
"aws-sdk": "^2.19.0",
3333
"bluebird-lst": "^1.0.1",
3434
"chalk": "^1.1.3",
3535
"chromium-pickle-js": "^0.2.0",
@@ -79,7 +79,7 @@
7979
"depcheck": "^0.6.7",
8080
"docdash": "https://github.com/develar/docdash.git",
8181
"electron-download-tf": "3.2.0",
82-
"jest-cli": "^19.0.1",
82+
"jest-cli": "^19.0.2",
8383
"jest-environment-node-debug": "^2.0.0",
8484
"jest-junit-reporter": "^1.0.1",
8585
"jsdoc": "^3.4.3",

packages/electron-builder/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"ajv": "^5.0.2-beta",
4848
"ajv-keywords": "^2.0.1-beta.0",
4949
"7zip-bin": "^2.0.4",
50-
"asar-electron-builder": "~0.14.2",
50+
"asar": "~0.13.0",
5151
"bluebird-lst": "^1.0.1",
5252
"chalk": "^1.1.3",
5353
"chromium-pickle-js": "^0.2.0",

packages/electron-builder/src/asarUtil.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AsarFileInfo, listPackage, statFile } from "asar-electron-builder"
1+
import { AsarFileInfo, listPackage, statFile } from "asar"
22
import BluebirdPromise from "bluebird-lst"
33
import { debug } from "electron-builder-util"
44
import { deepAssign } from "electron-builder-util/out/deepAssign"
@@ -10,7 +10,7 @@ import { AsarOptions } from "./metadata"
1010

1111
const isBinaryFile: any = BluebirdPromise.promisify(require("isbinaryfile"))
1212
const pickle = require ("chromium-pickle-js")
13-
const Filesystem = require("asar-electron-builder/lib/filesystem")
13+
const Filesystem = require("asar/lib/filesystem")
1414
const UINT64 = require("cuint").UINT64
1515

1616
const NODE_MODULES_PATTERN = `${path.sep}node_modules${path.sep}`

packages/electron-builder/src/options/winOptions.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ export interface WinBuildOptions extends PlatformSpecificBuildOptions {
4747
*/
4848
readonly certificateSubjectName?: string
4949

50+
/**
51+
* The SHA1 hash of the signing certificate. The SHA1 hash is commonly specified when multiple certificates satisfy the criteria specified by the remaining switches. Works only on Windows.
52+
*/
53+
readonly certificateSha1?: string
54+
5055
/**
5156
The URL of the RFC 3161 time stamp server. Defaults to `http://timestamp.comodoca.com/rfc3161`.
5257
*/

packages/electron-builder/src/packager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { extractFile } from "asar-electron-builder"
1+
import { extractFile } from "asar"
22
import BluebirdPromise from "bluebird-lst"
33
import { Arch, Platform, Target } from "electron-builder-core"
44
import { CancellationToken } from "electron-builder-http/out/CancellationToken"

packages/electron-builder/src/targets/appx.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ export default class AppXTarget extends Target {
2626
async build(appOutDir: string, arch: Arch): Promise<any> {
2727
const packager = this.packager
2828

29-
const cscInfo = await packager.cscInfo
30-
if (cscInfo == null) {
29+
if ((await packager.cscInfo) == null) {
3130
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")
3231
}
3332

packages/electron-builder/src/util/readPackageJson.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Ajv from "ajv"
2-
import { extractFile } from "asar-electron-builder"
2+
import { extractFile } from "asar"
33
import { log, warn } from "electron-builder-util/out/log"
44
import { readFile, readJson } from "fs-extra-p"
55
import { safeLoad } from "js-yaml"

packages/electron-builder/src/winPackager.ts

Lines changed: 41 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -12,48 +12,44 @@ import { PlatformPackager } from "./platformPackager"
1212
import AppXTarget from "./targets/appx"
1313
import NsisTarget from "./targets/nsis"
1414
import { createCommonTarget, DIR_TARGET } from "./targets/targetFactory"
15-
import { getSignVendorPath, sign, SignOptions } from "./windowsCodeSign"
16-
17-
export interface FileCodeSigningInfo {
18-
readonly file?: string | null
19-
readonly password?: string | null
20-
21-
readonly subjectName?: string | null
22-
}
15+
import { FileCodeSigningInfo, getSignVendorPath, sign, SignOptions } from "./windowsCodeSign"
2316

2417
export class WinPackager extends PlatformPackager<WinBuildOptions> {
2518
readonly cscInfo = new Lazy<FileCodeSigningInfo | null>(() => {
26-
const subjectName = this.platformSpecificBuildOptions.certificateSubjectName
27-
if (subjectName == null) {
28-
const certificateFile = this.platformSpecificBuildOptions.certificateFile
29-
if (certificateFile != null) {
30-
const certificatePassword = this.getCscPassword()
31-
return BluebirdPromise.resolve({
32-
file: certificateFile,
33-
password: certificatePassword == null ? null : certificatePassword.trim(),
34-
})
35-
}
36-
else {
37-
const cscLink = process.env.WIN_CSC_LINK || this.packagerOptions.cscLink
38-
if (cscLink != null) {
39-
return downloadCertificate(cscLink, this.info.tempDirManager)
40-
.then(path => {
41-
return {
42-
file: path,
43-
password: this.getCscPassword(),
44-
}
45-
})
46-
}
47-
else {
48-
return BluebirdPromise.resolve(null)
49-
}
50-
}
19+
const platformSpecificBuildOptions = this.platformSpecificBuildOptions
20+
const subjectName = platformSpecificBuildOptions.certificateSubjectName
21+
if (subjectName != null) {
22+
return BluebirdPromise.resolve({subjectName})
5123
}
52-
else {
24+
25+
const certificateSha1 = platformSpecificBuildOptions.certificateSha1
26+
if (certificateSha1 != null) {
27+
return BluebirdPromise.resolve({certificateSha1})
28+
}
29+
30+
const certificateFile = platformSpecificBuildOptions.certificateFile
31+
if (certificateFile != null) {
32+
const certificatePassword = this.getCscPassword()
5333
return BluebirdPromise.resolve({
54-
subjectName: subjectName
34+
file: certificateFile,
35+
password: certificatePassword == null ? null : certificatePassword.trim(),
5536
})
5637
}
38+
else {
39+
const cscLink = process.env.WIN_CSC_LINK || this.packagerOptions.cscLink
40+
if (cscLink != null) {
41+
return downloadCertificate(cscLink, this.info.tempDirManager)
42+
.then(path => {
43+
return {
44+
file: path,
45+
password: this.getCscPassword(),
46+
}
47+
})
48+
}
49+
else {
50+
return BluebirdPromise.resolve(null)
51+
}
52+
}
5753
})
5854

5955
private iconPath: Promise<string> | null
@@ -171,7 +167,12 @@ export class WinPackager extends PlatformPackager<WinBuildOptions> {
171167
logMessagePrefix = `Signing ${path.basename(file)}`
172168
}
173169
if (certFile == null) {
174-
log(`${logMessagePrefix} (subject name: "${cscInfo.subjectName}")`)
170+
if (cscInfo.subjectName == null) {
171+
log(`${logMessagePrefix} (certificate SHA1: "${cscInfo.certificateSha1}")`)
172+
}
173+
else {
174+
log(`${logMessagePrefix} (certificate subject name: "${cscInfo.subjectName}")`)
175+
}
175176
}
176177
else {
177178
log(`${logMessagePrefix} (certificate file: "${certFile}")`)
@@ -181,12 +182,14 @@ export class WinPackager extends PlatformPackager<WinBuildOptions> {
181182
path: file,
182183

183184
cert: certFile,
184-
subjectName: cscInfo.subjectName,
185185

186186
password: cscInfo.password,
187187
name: this.appInfo.productName,
188188
site: await this.appInfo.computePackageUrl(),
189-
options: this.platformSpecificBuildOptions,
189+
options: Object.assign({}, this.platformSpecificBuildOptions, {
190+
certificateSubjectName: cscInfo.subjectName,
191+
certificateSha1: cscInfo.certificateSha1,
192+
}),
190193
})
191194
}
192195

0 commit comments

Comments
 (0)