Skip to content

Commit

Permalink
fix(electron-updater): Updater crash on windows, fails on MacOS X
Browse files Browse the repository at this point in the history
Close #3308, #3377
  • Loading branch information
develar committed Nov 7, 2018
1 parent eb9c1d6 commit 76fdd42
Show file tree
Hide file tree
Showing 55 changed files with 2,537 additions and 949 deletions.
6 changes: 3 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
- deps-{{ checksum "yarn.lock" }}
- restore_cache:
keys:
- v-3.0.7-electron
- v-3.0.8-electron
- run:
command: yarn --frozen-lockfile
- run:
Expand All @@ -23,7 +23,7 @@ jobs:
- run:
command: node ./test/out/helpers/downloadElectron.js
- save_cache:
key: v-3.0.7-electron
key: v-3.0.8-electron
paths:
- ~/.cache/electron

Expand All @@ -41,7 +41,7 @@ jobs:
- deps-{{ checksum "yarn.lock" }}
- restore_cache:
keys:
- v-3.0.7-electron
- v-3.0.8-electron
# because in the build job we use circleci docker image and circleci restores cache to original user home
- run:
command: |
Expand Down
2 changes: 2 additions & 0 deletions .idea/dictionaries/develar.xml

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

9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"dependencies": {
"7zip-bin": "~4.1.0",
"@types/is-ci": "^1.1.0",
"app-builder-bin": "2.3.1",
"app-builder-bin": "2.4.1",
"archiver": "^3.0.0",
"async-exit-hook": "^2.0.1",
"bluebird-lst": "^1.0.6",
Expand All @@ -53,6 +53,7 @@
"mime": "^2.3.1",
"minimatch": "^3.0.4",
"normalize-package-data": "^2.4.0",
"pako": "^1.0.6",
"parse-color": "^1.0.0",
"plist": "^3.0.1",
"read-config-file": "3.2.0",
Expand All @@ -62,13 +63,13 @@
"source-map-support": "^0.5.9",
"stat-mode": "^0.2.2",
"sumchecker": "^2.0.2",
"temp-file": "^3.1.3",
"temp-file": "^3.2.0",
"tunnel-agent": "^0.6.0",
"update-notifier": "^2.5.0",
"yargs": "^12.0.2"
},
"devDependencies": {
"@babel/core": "^7.1.2",
"@babel/core": "^7.1.5",
"@babel/plugin-proposal-class-properties": "^7.1.0",
"@babel/plugin-proposal-decorators": "^7.1.2",
"@babel/plugin-proposal-do-expressions": "^7.0.0",
Expand All @@ -85,7 +86,7 @@
"@babel/plugin-proposal-throw-expressions": "^7.0.0",
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
"@babel/plugin-syntax-import-meta": "^7.0.0",
"@babel/preset-env": "^7.1.0",
"@babel/preset-env": "^7.1.5",
"@babel/preset-react": "^7.0.0",
"@types/debug": "^0.0.31",
"@types/ejs": "^2.6.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/app-builder-lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"homepage": "https://github.com/electron-userland/electron-builder",
"dependencies": {
"7zip-bin": "~4.1.0",
"app-builder-bin": "2.3.1",
"app-builder-bin": "2.4.1",
"async-exit-hook": "^2.0.1",
"bluebird-lst": "^1.0.6",
"chromium-pickle-js": "^0.2.0",
Expand All @@ -63,7 +63,7 @@
"semver": "^5.6.0",
"debug": "^4.1.0",
"lazy-val": "^1.0.3",
"temp-file": "^3.1.3",
"temp-file": "^3.2.0",
"ejs": "^2.6.1"
},
"typings": "./out/index.d.ts"
Expand Down
12 changes: 11 additions & 1 deletion packages/app-builder-lib/src/Framework.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,21 @@ export interface Framework {

prepareApplicationStageDirectory(options: PrepareApplicationStageDirectoryOptions): Promise<any>

beforeCopyExtraFiles?(packager: PlatformPackager<any>, appOutDir: string, asarIntegrity: AsarIntegrity | null): Promise<any>
beforeCopyExtraFiles?(options: BeforeCopyExtraFilesOptions): Promise<any>

createTransformer?(): FileTransformer | null
}

export interface BeforeCopyExtraFilesOptions {
packager: PlatformPackager<any>
appOutDir: string

asarIntegrity: AsarIntegrity | null

// ElectronPlatformName
platformName: string
}

export interface PrepareApplicationStageDirectoryOptions {
readonly packager: PlatformPackager<any>
/**
Expand Down
16 changes: 15 additions & 1 deletion packages/app-builder-lib/src/appInfo.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isEmptyOrSpaces, log, smarten } from "builder-util"
import { isEmptyOrSpaces, log } from "builder-util"
import sanitizeFileName from "sanitize-filename"
import { prerelease, SemVer } from "semver"
import { PlatformSpecificBuildOptions } from "./options/PlatformSpecificBuildOptions"
Expand Down Expand Up @@ -126,4 +126,18 @@ export function filterCFBundleIdentifier(identifier: string) {
// Remove special characters and allow only alphanumeric (A-Z,a-z,0-9), hyphen (-), and period (.)
// Apple documentation: https://developer.apple.com/library/mac/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/20001431-102070
return identifier.replace(/ /g, "-").replace(/[^a-zA-Z0-9.-]/g, "")
}

// fpm bug - rpm build --description is not escaped, well... decided to replace quite to smart quote
// http://leancrew.com/all-this/2010/11/smart-quotes-in-javascript/
export function smarten(s: string): string {
// opening singles
s = s.replace(/(^|[-\u2014\s(\["])'/g, "$1\u2018")
// closing singles & apostrophes
s = s.replace(/'/g, "\u2019")
// opening doubles
s = s.replace(/(^|[-\u2014/\[(\u2018\s])"/g, "$1\u201c")
// closing doubles
s = s.replace(/"/g, "\u201d")
return s
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import BluebirdPromise from "bluebird-lst"
import { exec, InvalidConfigurationError, isEmptyOrSpaces, isEnvTrue, isMacOsSierra, isPullRequest, log, TmpDir } from "builder-util"
import { exec, InvalidConfigurationError, isEmptyOrSpaces, isEnvTrue, isMacOsSierra, isPullRequest, log, TmpDir } from "builder-util/out/util"
import { copyFile, statOrNull, unlinkIfExists } from "builder-util/out/fs"
import { Fields, Logger } from "builder-util/out/log"
import { randomBytes } from "crypto"
Expand All @@ -8,8 +8,8 @@ import { Lazy } from "lazy-val"
import { homedir } from "os"
import * as path from "path"
import { getTempName } from "temp-file"
import { download } from "./binDownload"
import { isAutoDiscoveryCodeSignIdentity } from "./util/flags"
import { download } from "../binDownload"
import { isAutoDiscoveryCodeSignIdentity } from "../util/flags"

export const appleCertificatePrefixes = ["Developer ID Application:", "Developer ID Installer:", "3rd Party Mac Developer Application:", "3rd Party Mac Developer Installer:"]

Expand Down Expand Up @@ -142,7 +142,7 @@ const bundledCertKeychainAdded = new Lazy<void>(async () => {
const keychainPath = path.join(cacheDir, "electron-builder-root-certs.keychain")
const results = await Promise.all<any>([
listUserKeychains(),
copyFile(path.join(__dirname, "..", "certs", "root_certs.keychain"), tmpKeychainPath)
copyFile(path.join(__dirname, "..", "..", "certs", "root_certs.keychain"), tmpKeychainPath)
.then(() => rename(tmpKeychainPath, keychainPath)),
])
const list = results[0]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { asArray, isMacOsSierra, log } from "builder-util"
import { getBinFromGithub } from "./binDownload"
import { computeToolEnv, ToolInfo } from "./util/bundledTool"
import { executeAppBuilderAsJson, InvalidConfigurationError, asArray, isMacOsSierra, log } from "builder-util/out/util"
import { getBinFromGithub } from "../binDownload"
import { computeToolEnv, ToolInfo } from "../util/bundledTool"
import { rename } from "fs-extra-p"
import isCi from "is-ci"
import * as os from "os"
import * as path from "path"
import { WindowsConfiguration } from "./options/winOptions"
import { resolveFunction } from "./platformPackager"
import { isUseSystemSigncode } from "./util/flags"
import { VmManager } from "./vm/vm"
import { WinPackager } from "./winPackager"
import { WindowsConfiguration } from ".."
import { resolveFunction } from "../platformPackager"
import { isUseSystemSigncode } from "../util/flags"
import { VmManager } from "../vm/vm"
import { WinPackager } from "../winPackager"

export function getSignVendorPath() {
//noinspection SpellCheckingInspection
Expand Down Expand Up @@ -80,6 +80,27 @@ export interface FileCodeSigningInfo {
readonly password: string | null
}

export async function getCertInfo(file: string, password: string): Promise<CertificateInfo> {
let result: any = null
try {
result = await executeAppBuilderAsJson<any>(["certificate-info", "--input", file, "--password", password])
}
catch (e) {
throw new Error(`Cannot extract publisher name from code signing certificate, please file issue. As workaround, set win.publisherName: ${e.stack || e}`)
}

if (result.error != null) {
// noinspection ExceptionCaughtLocallyJS
throw new InvalidConfigurationError(`Cannot extract publisher name from code signing certificate: ${result.error}`)
}
return result
}

export interface CertificateInfo {
readonly commonName: string
readonly bloodyMicrosoftSubjectDn: string
}

export interface CertificateFromStoreInfo {
thumbprint: string
subject: string
Expand Down
19 changes: 10 additions & 9 deletions packages/app-builder-lib/src/electron/ElectronFramework.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import { emptyDir, readdir, remove, rename } from "fs-extra-p"
import { Lazy } from "lazy-val"
import * as path from "path"
import * as semver from "semver"
import { AsarIntegrity } from "../asar/integrity"
import { Configuration } from "../configuration"
import { Framework, PrepareApplicationStageDirectoryOptions } from "../Framework"
import { ElectronPlatformName, Packager, Platform, PlatformPackager } from "../index"
import { BeforeCopyExtraFilesOptions, Framework, PrepareApplicationStageDirectoryOptions } from "../Framework"
import { ElectronPlatformName, Packager, Platform } from "../index"
import { LinuxPackager } from "../linuxPackager"
import MacPackager from "../macPackager"
import { createMacApp } from "./electronMac"
Expand Down Expand Up @@ -52,7 +51,9 @@ function createDownloadOpts(opts: Configuration, platform: ElectronPlatformName,
}
}

async function beforeCopyExtraFiles(packager: PlatformPackager<any>, appOutDir: string, asarIntegrity: AsarIntegrity | null, isClearExecStack: boolean) {
async function beforeCopyExtraFiles(options: BeforeCopyExtraFilesOptions, isClearExecStack: boolean) {
const packager = options.packager
const appOutDir = options.appOutDir
if (packager.platform === Platform.LINUX) {
const linuxPackager = (packager as LinuxPackager)
const executable = path.join(appOutDir, linuxPackager.executableName)
Expand All @@ -72,7 +73,7 @@ async function beforeCopyExtraFiles(packager: PlatformPackager<any>, appOutDir:
await rename(path.join(appOutDir, `${packager.electronDistExecutableName}.exe`), executable)
}
else {
await createMacApp(packager as MacPackager, appOutDir, asarIntegrity)
await createMacApp(packager as MacPackager, appOutDir, options.asarIntegrity, (options.platformName as ElectronPlatformName) === "mas")

const wantedLanguages = asArray(packager.platformSpecificBuildOptions.electronLanguages)
if (wantedLanguages.length === 0) {
Expand Down Expand Up @@ -115,8 +116,8 @@ export async function createElectronFrameworkSupport(configuration: Configuratio
}, distMacOsAppName)
},
isNpmRebuildRequired: true,
beforeCopyExtraFiles: (packager: PlatformPackager<any>, appOutDir: string, asarIntegrity: AsarIntegrity | null) => {
return beforeCopyExtraFiles(packager, appOutDir, asarIntegrity, false)
beforeCopyExtraFiles: options => {
return beforeCopyExtraFiles(options, false)
},
}
}
Expand Down Expand Up @@ -146,8 +147,8 @@ export async function createElectronFrameworkSupport(configuration: Configuratio
distMacOsAppName,
isNpmRebuildRequired: true,
prepareApplicationStageDirectory: options => unpack(options, createDownloadOpts(options.packager.config, options.platformName, options.arch, version!!), distMacOsAppName),
beforeCopyExtraFiles: (packager: PlatformPackager<any>, appOutDir: string, asarIntegrity: AsarIntegrity | null) => {
return beforeCopyExtraFiles(packager, appOutDir, asarIntegrity, semver.lte(version || "1.8.3", "1.8.3"))
beforeCopyExtraFiles: options => {
return beforeCopyExtraFiles(options, semver.lte(version || "1.8.3", "1.8.3"))
},
}
}
Expand Down
32 changes: 31 additions & 1 deletion packages/app-builder-lib/src/electron/electronMac.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function getAvailableHelperSuffixes(helperEHPlist: string | null, helperNPPlist:
}

/** @internal */
export async function createMacApp(packager: MacPackager, appOutDir: string, asarIntegrity: AsarIntegrity | null) {
export async function createMacApp(packager: MacPackager, appOutDir: string, asarIntegrity: AsarIntegrity | null, isMas: boolean) {
const appInfo = packager.appInfo
const appFilename = appInfo.productFilename

Expand Down Expand Up @@ -76,6 +76,11 @@ export async function createMacApp(packager: MacPackager, appOutDir: string, asa

await packager.applyCommonInfo(appPlist, contentsPath)

// required for electron-updater proxy
if (!isMas) {
configureLocalhostAts(appPlist)
}

helperPlist.CFBundleExecutable = `${appFilename} Helper`
helperPlist.CFBundleDisplayName = `${appInfo.productName} Helper`
helperPlist.CFBundleIdentifier = helperBundleIdentifier
Expand Down Expand Up @@ -172,4 +177,29 @@ export async function createMacApp(packager: MacPackager, appOutDir: string, asa
// https://github.com/electron-userland/electron-builder/issues/840
const now = Date.now() / 1000
await utimes(appPath, now, now)
}

function configureLocalhostAts(appPlist: any) {
// https://bencoding.com/2015/07/20/app-transport-security-and-localhost/
let ats = appPlist.NSAppTransportSecurity
if (ats == null) {
ats = {}
appPlist.NSAppTransportSecurity = ats
}

let exceptionDomains = ats.NSExceptionDomains
if (exceptionDomains == null) {
exceptionDomains = {}
ats.NSExceptionDomains = exceptionDomains
}

if (exceptionDomains.localhost == null) {
exceptionDomains.localhost = {
NSTemporaryExceptionAllowsInsecureHTTPSLoads: false,
NSIncludesSubdomains: false,
NSTemporaryExceptionAllowsInsecureHTTPLoads: true,
NSTemporaryExceptionMinimumTLSVersion: "1.0",
NSTemporaryExceptionRequiresForwardSecrecy: false
}
}
}
2 changes: 1 addition & 1 deletion packages/app-builder-lib/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export { SnapOptions } from "./options/SnapOptions"
export { Metadata, AuthorMetadata, RepositoryInfo } from "./options/metadata"
export { AppInfo } from "./appInfo"
export { SquirrelWindowsOptions } from "./options/SquirrelWindowsOptions"
export { WindowsSignOptions, CustomWindowsSignTaskConfiguration, WindowsSignTaskConfiguration, CustomWindowsSign, FileCodeSigningInfo, CertificateFromStoreInfo } from "./windowsCodeSign"
export { WindowsSignOptions, CustomWindowsSignTaskConfiguration, WindowsSignTaskConfiguration, CustomWindowsSign, FileCodeSigningInfo, CertificateFromStoreInfo } from "./codeSign/windowsCodeSign"
export { CancellationToken, ProgressInfo } from "builder-util-runtime"
export { PublishOptions, UploadTask } from "electron-publish"
export { PublishManager } from "./publish/PublishManager"
Expand Down
2 changes: 1 addition & 1 deletion packages/app-builder-lib/src/macPackager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Lazy } from "lazy-val"
import * as path from "path"
import { copyFile, unlinkIfExists } from "builder-util/out/fs"
import { AppInfo } from "./appInfo"
import { appleCertificatePrefixes, CertType, CodeSigningInfo, createKeychain, findIdentity, Identity, isSignAllowed, reportError } from "./codeSign"
import { appleCertificatePrefixes, CertType, CodeSigningInfo, createKeychain, findIdentity, Identity, isSignAllowed, reportError } from "./codeSign/macCodeSign"
import { DIR_TARGET, Platform, Target } from "./core"
import { ElectronPlatformName } from "./index"
import { MacConfiguration, MasConfiguration } from "./options/macOptions"
Expand Down
2 changes: 1 addition & 1 deletion packages/app-builder-lib/src/options/winOptions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PlatformSpecificBuildOptions, TargetConfigType } from "../index"
import { CustomWindowsSign } from "../windowsCodeSign"
import { CustomWindowsSign } from "../codeSign/windowsCodeSign"

export interface WindowsConfiguration extends PlatformSpecificBuildOptions {
/**
Expand Down
7 changes: 6 additions & 1 deletion packages/app-builder-lib/src/platformPackager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,12 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>

const beforeCopyExtraFiles = this.info.framework.beforeCopyExtraFiles
if (beforeCopyExtraFiles != null) {
await beforeCopyExtraFiles(this, appOutDir, asarOptions == null ? null : await computeData(resourcesPath, asarOptions.externalAllowed ? {externalAllowed: true} : null))
await beforeCopyExtraFiles({
packager: this,
appOutDir,
asarIntegrity: asarOptions == null ? null : await computeData(resourcesPath, asarOptions.externalAllowed ? {externalAllowed: true} : null),
platformName,
})
}

const transformerForExtraFiles = this.createTransformerForExtraFiles(packContext)
Expand Down
Loading

0 comments on commit 76fdd42

Please sign in to comment.