Skip to content

Commit

Permalink
fix: import bundled certs into login.keychain
Browse files Browse the repository at this point in the history
  • Loading branch information
develar committed May 23, 2016
1 parent a3bbb3f commit 86dc34e
Show file tree
Hide file tree
Showing 10 changed files with 65 additions and 122 deletions.
3 changes: 2 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
*.ico filter=lfs diff=lfs merge=lfs -text
*.icns filter=lfs diff=lfs merge=lfs -text
vendor/**/* filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
*.keychain filter=lfs diff=lfs merge=lfs -text
2 changes: 1 addition & 1 deletion .idea/runConfigurations/CodeSignTest.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file removed certs/AppleWWDRCA.cer
Binary file not shown.
97 changes: 0 additions & 97 deletions certs/bundle.crt

This file was deleted.

18 changes: 15 additions & 3 deletions certs/create.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
#!/usr/bin/env bash

> bundle.crt
curl https://www.startssl.com/certs/sca.code2.crt >> bundle.crt
curl https://www.startssl.com/certs/sca.code3.crt >> bundle.crt
curl https://www.startssl.com/certs/sca.code2.crt >> /tmp/bundle.crt
curl https://www.startssl.com/certs/sca.code3.crt >> /tmp/bundle.crt

curl https://repository.certum.pl/cscasha2.pem >> /tmp/bundle.crt


rm -rf $PWD/root_certs.keychain
security create-keychain -p pass $PWD/root_certs.keychain
security set-keychain-settings -t 86400 -u $PWD/root_certs.keychain

security import /tmp/bundle.crt -k $PWD/root_certs.keychain -T /usr/bin/codesign -T /usr/bin/productbuild

curl https://repository.certum.pl/cscasha2.pem >> bundle.crt
curl https://developer.apple.com/certificationauthority/AppleWWDRCA.cer > /tmp/AppleWWDRCA.cer
security import /tmp/AppleWWDRCA.cer -k $PWD/root_certs.keychain -T /usr/bin/codesign -T /usr/bin/productbuild
3 changes: 3 additions & 0 deletions certs/root_certs.keychain
Git LFS file not shown
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"files": [
"out",
"templates",
"certs"
"certs/root_certs.keychain"
],
"bin": {
"build": "./out/build-cli.js",
Expand Down
52 changes: 38 additions & 14 deletions src/codeSign.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { exec } from "./util"
import { deleteFile, outputFile } from "fs-extra-p"
import { exec, getTempName } from "./util"
import { deleteFile, outputFile, copy, rename } from "fs-extra-p"
import { download } from "./httpRequest"
import { tmpdir } from "os"
import * as path from "path"
import { executeFinally, all } from "./promise"
import { Promise as BluebirdPromise } from "bluebird"
import { randomBytes } from "crypto"
import { homedir } from "os"

//noinspection JSUnusedLocalSymbols
const __awaiter = require("./awaiter")
Expand Down Expand Up @@ -34,7 +35,38 @@ function downloadUrlOrBase64(urlOrBase64: string, destination: string): Bluebird
}
}

export function createKeychain(keychainName: string, cscLink: string, cscKeyPassword: string, cscILink?: string | null, cscIKeyPassword?: string | null, csaLink?: string | null): Promise<CodeSigningInfo> {
let bundledCertKeychainAdded = false

export async function createKeychain(keychainName: string, cscLink: string, cscKeyPassword: string, cscILink?: string | null, cscIKeyPassword?: string | null, csaLink?: string | null): Promise<CodeSigningInfo> {
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<Array<string> | string>([
exec("security", ["list-keychains"]),
copy(path.join(__dirname, "..", "certs", "root_certs.keychain"), tmpKeychainPath)
.then(() => rename(tmpKeychainPath, keychainPath)),
])
const list = (<string[]>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])
}
}

const certLinks = csaLink == null ? [] : [csaLink]
certLinks.push(cscLink)
if (cscILink != null) {
Expand All @@ -43,15 +75,15 @@ export function createKeychain(keychainName: string, cscLink: string, cscKeyPass

const certPaths = certLinks.map(it => path.join(tmpdir(), randomString() + (it.endsWith(".cer") ? ".cer" : ".p12")))
const keychainPassword = randomString()
return executeFinally(BluebirdPromise.all([
return await executeFinally(BluebirdPromise.all([
BluebirdPromise.map(certPaths, (p, i) => downloadUrlOrBase64(certLinks[i], p)),
BluebirdPromise.mapSeries([
["create-keychain", "-p", keychainPassword, keychainName],
["unlock-keychain", "-p", keychainPassword, keychainName],
["set-keychain-settings", "-t", "3600", "-u", keychainName]
], it => exec("security", it))
])
.then(() => importCerts(keychainName, certPaths, [cscKeyPassword, cscIKeyPassword].filter(it => it != null), csaLink == null)),
.then(() => importCerts(keychainName, certPaths, [cscKeyPassword, cscIKeyPassword].filter(it => it != null))),
errorOccurred => {
const tasks = certPaths.map(it => deleteFile(it, true))
if (errorOccurred) {
Expand All @@ -61,16 +93,8 @@ export function createKeychain(keychainName: string, cscLink: string, cscKeyPass
})
}

async function importCerts(keychainName: string, paths: Array<string>, keyPasswords: Array<string | null | undefined>, importBundledCerts: boolean): Promise<CodeSigningInfo> {
async function importCerts(keychainName: string, paths: Array<string>, keyPasswords: Array<string | null | undefined>): Promise<CodeSigningInfo> {
const certFiles = paths.slice(0, -keyPasswords.length)
if (importBundledCerts) {
const bundledCertsPath = path.join(__dirname, "..", "certs")
certFiles.push(
path.join(bundledCertsPath, "AppleWWDRCA.cer"),
path.join(bundledCertsPath, "bundle.crt")
)
}

for (let file of certFiles) {
await exec("security", ["import", file, "-k", keychainName, "-T", "/usr/bin/codesign"])
}
Expand Down
6 changes: 3 additions & 3 deletions src/packager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Buffer[]> | null = null
let wineCheck: Promise<string[]> | null = null
if (checkWine && process.platform !== "win32" && platform === Platform.WINDOWS) {
wineCheck = exec("wine", ["--version"])
}
Expand Down Expand Up @@ -228,14 +228,14 @@ function checkConflictingOptions(options: any) {
}
}

async function checkWineVersion(checkPromise: Promise<Buffer[]>) {
async function checkWineVersion(checkPromise: Promise<string[]>) {
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].toString().trim()
wineVersion = (await checkPromise)[0].trim()
}
catch (e) {
if (e.code === "ENOENT") {
Expand Down
4 changes: 2 additions & 2 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ export interface ExecOptions extends BaseExecOptions {
killSignal?: string
}

export function exec(file: string, args?: Array<string> | null, options?: ExecOptions): BluebirdPromise<Buffer[]> {
export function exec(file: string, args?: Array<string> | null, options?: ExecOptions): BluebirdPromise<string[]> {
if (debug.enabled) {
debug(`Executing ${file} ${args == null ? "" : args.join(" ")}`)
}

return new BluebirdPromise<Buffer[]>((resolve, reject) => {
return new BluebirdPromise<string[]>((resolve, reject) => {
execFile(file, <any>args, options, function (error, stdout, stderr) {
if (error == null) {
resolve(<any>[stdout, stderr])
Expand Down

0 comments on commit 86dc34e

Please sign in to comment.