Skip to content

Commit

Permalink
feat(windows): specification of signing algorithms
Browse files Browse the repository at this point in the history
Under the hood a lot of changes:
* electron-packages fork use promises, option added to avoid move on electron-builder side (generated app out dir customized)
* windows bootstrap loadingGif delay removed
* windows bootstrap zip uses default compression level to speedup decompression (package is still compressed using -9)
* app out dir changed — **osx** for OS X instead of appName-darwin-arch, **linux** for Linux instead of appName-linux-arch
* **Windows Code Signing on Linux**

@heinzbeinz added `signingHashAlgorithms` and code signing on windows 2008 r2, thanks for electron-userland#434.

Closes electron-userland#374, electron-userland#416
  • Loading branch information
develar committed May 25, 2016
1 parent bffbbf1 commit a783312
Show file tree
Hide file tree
Showing 15 changed files with 60 additions and 72 deletions.
10 changes: 7 additions & 3 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
FROM buildpack-deps:xenial-curl

# rpm is required for FPM to build rpm package
# yasm is required to build p7zip
# osslsigncode to sign windows on Linux

RUN apt-get update -y && \
apt-get install --no-install-recommends -y bsdtar build-essential autoconf libssl-dev icnsutils graphicsmagick gcc-multilib g++-multilib libgnome-keyring-dev zip lzip rpm && \
apt-get install --no-install-recommends -y bsdtar build-essential autoconf libssl-dev icnsutils graphicsmagick gcc-multilib g++-multilib libgnome-keyring-dev lzip rpm osslsigncode yasm && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

Expand All @@ -23,12 +25,15 @@ RUN set -ex \

ENV NODE_VERSION 6.2.0
ENV XZ_VERSION 5.2.2
# we don't use our bundled 7za because it is better to build for specific platform - not generic
ENV USE_SYSTEM_7ZA true

# https://github.com/npm/npm/issues/4531

# install modern multi-thread xz
# ldconfig - see 4.6. liblzma.so (or similar) not found when running xz
RUN curl -L http://tukaani.org/xz/xz-$XZ_VERSION.tar.xz | tar -xJ && cd xz-$XZ_VERSION && ./configure && make && make install && cd .. && rm -rf xz-$XZ_VERSION && ldconfig && \
mkdir -p /tmp/7z && curl -L http://downloads.sourceforge.net/project/p7zip/p7zip/15.14.1/p7zip_15.14.1_src_all.tar.bz2 | tar -xj -C /tmp/7z --strip-components 1 && cd /tmp/7z && cp makefile.linux_amd64_asm makefile.machine && make && make install && cd .. && rm -rf /tmp/7z && \
curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \
&& gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
Expand Down Expand Up @@ -98,14 +103,13 @@ ENV BUNDLE_PATH="$GEM_HOME" \
ENV PATH $BUNDLE_BIN:$PATH
RUN mkdir -p "$GEM_HOME" "$BUNDLE_BIN" \
&& chmod 777 "$GEM_HOME" "$BUNDLE_BIN" \
&& mkdir /fpm && curl -L https://github.com/jordansissel/fpm/archive/6e2514df27664912826b4fcd89affa19df0e713b.tar.gz | tar -xz -C /fpm --strip-components 1 && cd /fpm && bundle install && make install && cd ..
&& mkdir -p /tmp/fpm && curl -L https://github.com/jordansissel/fpm/archive/6e2514df27664912826b4fcd89affa19df0e713b.tar.gz | tar -xz -C /tmp/fpm --strip-components 1 && cd /tmp/fpm && bundle install && make install && cd .. && rm -rf /tmp/fpm

# use fpm commit https://github.com/jordansissel/fpm/commit/6e2514df27664912826b4fcd89affa19df0e713b because of some important unreleased fixes:
# https://github.com/jordansissel/fpm/commit/94be82c0a23c8cd641ab9e60f3eb4a8db445fff0
# https://github.com/jordansissel/fpm/commit/77b95747b9cc01ca420ee24084a449b3ac19e6d5

# we don't use our bundled fpm because it is better to build ruby & tools for specific platform - not generic. And easy to maintain (update ruby and so on).

ENV USE_SYSTEM_FPM true

# fix error /usr/local/bundle/gems/fpm-1.5.0/lib/fpm/package/freebsd.rb:72:in `encode': "\xE2" from ASCII-8BIT to UTF-8 (Encoding::UndefinedConversionError)
Expand Down
4 changes: 2 additions & 2 deletions docs/Multi Platform Build.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ To build app in distributable format for Windows on Linux:
sudo apt-get install --no-install-recommends -y mono-devel ca-certificates-mono
```

* Install zip.
* Install osslsigncode.
```
apt-get install --no-install-recommends -y zip
apt-get install --no-install-recommends -y osslsigncode
```

To build app in 32 bit from a machine with 64 bit:
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@
"debug": "^2.2.0",
"deep-assign": "^2.0.0",
"electron-osx-sign-tf": "0.4.0-beta.0",
"electron-packager-tf": "~7.1.0",
"electron-winstaller-fixed": "~2.9.0",
"electron-packager-tf": "~7.2.0",
"electron-winstaller-fixed": "~2.9.2",
"fs-extra-p": "^1.0.1",
"globby": "^4.1.0",
"hosted-git-info": "^2.1.5",
Expand All @@ -77,7 +77,7 @@
"progress": "^1.1.8",
"progress-stream": "^1.2.0",
"read-package-json": "^2.0.4",
"signcode-tf": "^0.6.3",
"signcode-tf": "~0.7.3",
"source-map-support": "^0.4.0"
},
"optionalDependencies": {
Expand Down Expand Up @@ -107,7 +107,7 @@
"ts-babel": "^0.8.6",
"tsconfig-glob": "^0.4.3",
"tslint": "3.10.0-dev.2",
"typescript": "1.9.0-dev.20160520-1.0",
"typescript": "1.9.0-dev.20160525-1.0",
"whitespace": "^2.0.0"
},
"babel": {
Expand Down
2 changes: 1 addition & 1 deletion src/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,4 @@ export async function build(originalOptions?: BuildOptions): Promise<void> {
return BluebirdPromise.all(publishTasks)
}
})
}
}
2 changes: 1 addition & 1 deletion src/codeSign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export async function createKeychain(keychainName: string, cscLink: string, cscK
.filter(it => it.length > 0)

if (!list.includes(keychainPath)) {
await exec("security", ["list-keychains", "-d", "user", "-s", keychainPath])
await exec("security", ["list-keychains", "-d", "user", "-s", keychainPath].concat(list))
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/linuxPackager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class LinuxPackager extends PlatformPackager<LinuxBuildOptions> {

async pack(outDir: string, arch: string, postAsyncTasks: Array<Promise<any>>): Promise<any> {
const appOutDir = this.computeAppOutDir(outDir, arch)
await this.doPack(this.computePackOptions(outDir, arch), outDir, appOutDir, arch, this.customBuildOptions)
await this.doPack(this.computePackOptions(outDir, appOutDir, arch), outDir, appOutDir, arch, this.customBuildOptions)

if (this.options.dist) {
for (let target of this.targets) {
Expand Down
6 changes: 5 additions & 1 deletion src/metadata.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import ElectronPackagerOptions = ElectronPackager.ElectronPackagerOptions
import { ElectronPackagerOptions } from "electron-packager-tf"

export interface Metadata {
readonly repository?: string | RepositoryInfo | null
}
Expand Down Expand Up @@ -256,6 +257,9 @@ export interface WinBuildOptions extends PlatformSpecificBuildOptions {
Authentication token for remote updates
*/
readonly remoteToken?: string | null

readonly signingHashAlgorithms?: Array<string> | null
readonly signcodePath?: string | null
}

/*
Expand Down
6 changes: 3 additions & 3 deletions src/osxPackager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default class OsXPackager extends PlatformPackager<OsXBuildOptions> {
}

async pack(outDir: string, arch: string, postAsyncTasks: Array<Promise<any>>): Promise<any> {
const packOptions = this.computePackOptions(outDir, arch)
const packOptions = this.computePackOptions(outDir, this.computeAppOutDir(outDir, arch), arch)
let nonMasPromise: Promise<any> | null = null
if (this.targets.length > 1 || this.targets[0] !== "mas") {
const appOutDir = this.computeAppOutDir(outDir, arch)
Expand All @@ -51,9 +51,9 @@ export default class OsXPackager extends PlatformPackager<OsXBuildOptions> {

if (this.targets.includes("mas")) {
// osx-sign - disable warning
const appOutDir = path.join(outDir, `${this.appName}-mas-${arch}`)
const appOutDir = path.join(outDir, "mas")
const masBuildOptions = deepAssign({}, this.customBuildOptions, (<any>this.devMetadata.build)["mas"])
await this.doPack(Object.assign({}, packOptions, {platform: "mas", "osx-sign": false}), outDir, appOutDir, arch, masBuildOptions)
await this.doPack(Object.assign({}, packOptions, {platform: "mas", "osx-sign": false, generateFinalBasename: function () { return "mas" }}), outDir, appOutDir, arch, masBuildOptions)
await this.sign(appOutDir, masBuildOptions)
}

Expand Down
12 changes: 5 additions & 7 deletions src/platformPackager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,18 @@ import { AppMetadata, DevMetadata, Platform, PlatformSpecificBuildOptions, getPr
import EventEmitter = NodeJS.EventEmitter
import { Promise as BluebirdPromise } from "bluebird"
import * as path from "path"
import packager = require("electron-packager-tf")
import { pack, ElectronPackagerOptions } from "electron-packager-tf"
import globby = require("globby")
import { copy, unlink } from "fs-extra-p"
import { statOrNull, use, spawn, debug7zArgs, debug } from "./util"
import { Packager } from "./packager"
import deepAssign = require("deep-assign")
import { listPackage, statFile } from "asar"
import ElectronPackagerOptions = ElectronPackager.ElectronPackagerOptions
import { path7za } from "7zip-bin"

//noinspection JSUnusedLocalSymbols
const __awaiter = require("./awaiter")

const pack = BluebirdPromise.promisify(packager)

class CompressionDescriptor {
constructor(public flag: string, public env: string, public minLevel: string, public maxLevel: string = "-9") {
}
Expand Down Expand Up @@ -122,7 +119,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
protected abstract get supportedTargets(): Array<string>

protected computeAppOutDir(outDir: string, arch: string): string {
return path.join(outDir, `${this.appName}-${this.platform.nodeName}-${arch}`)
return path.join(outDir, `${this.platform.buildConfigurationKey}${arch === "x64" ? "" : `-${arch}`}`)
}

protected dispatchArtifactCreated(file: string, artifactName?: string) {
Expand All @@ -140,7 +137,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
await this.copyExtraResources(appOutDir, arch, customBuildOptions)
}

protected computePackOptions(outDir: string, arch: string): ElectronPackagerOptions {
protected computePackOptions(outDir: string, appOutDir: string, arch: string): ElectronPackagerOptions {
const version = this.metadata.version
let buildVersion = version
const buildNumber = this.computeBuildNumber()
Expand All @@ -163,6 +160,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
"app-copyright": `Copyright © ${new Date().getFullYear()} ${this.metadata.author.name || this.appName}`,
"build-version": buildVersion,
tmpdir: false,
generateFinalBasename: () => path.basename(appOutDir),
"version-string": {
CompanyName: this.metadata.author.name,
FileDescription: smarten(this.metadata.description),
Expand Down Expand Up @@ -398,4 +396,4 @@ export function smarten(s: string): string {
// closing doubles
s = s.replace(/"/g, "\u201d")
return s
}
}
30 changes: 14 additions & 16 deletions src/winPackager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { PlatformPackager, BuildInfo, smarten, archSuffix } from "./platformPack
import { Platform, WinBuildOptions } from "./metadata"
import * as path from "path"
import { log, statOrNull, warn } from "./util"
import { deleteFile, emptyDir, open, close, read, move } from "fs-extra-p"
import { deleteFile, emptyDir, open, close, read } from "fs-extra-p"
import { sign } from "signcode-tf"
import ElectronPackagerOptions = ElectronPackager.ElectronPackagerOptions
import { ElectronPackagerOptions } from "electron-packager-tf"

//noinspection JSUnusedLocalSymbols
const __awaiter = require("./awaiter")
Expand Down Expand Up @@ -63,33 +63,30 @@ export class WinPackager extends PlatformPackager<WinBuildOptions> {
// we must check icon before pack because electron-packager uses icon and it leads to cryptic error message "spawn wine ENOENT"
await this.iconPath

let appOutDir = this.computeAppOutDir(outDir, arch)
const packOptions = this.computePackOptions(outDir, arch)
const appOutDir = this.computeAppOutDir(outDir, arch)
const packOptions = this.computePackOptions(outDir, appOutDir, arch)

if (!this.options.dist) {
await this.doPack(packOptions, outDir, appOutDir, arch, this.customBuildOptions)
return
}

const unpackedDir = path.join(outDir, `win${arch === "x64" ? "" : `-${arch}`}-unpacked`)
const finalAppOut = path.join(unpackedDir, "lib", "net45")
const installerOut = computeDistOut(outDir, arch)
log("Removing %s and %s", path.relative(this.projectDir, installerOut), path.relative(this.projectDir, unpackedDir))
const installerOut = this.options.dist ? computeDistOut(outDir, arch) : null
await BluebirdPromise.all([
this.packApp(packOptions, appOutDir),
emptyDir(installerOut),
emptyDir(unpackedDir)
installerOut == null ? BluebirdPromise.resolve() : emptyDir(installerOut)
])

await move(appOutDir, finalAppOut)
appOutDir = finalAppOut

await this.copyExtraResources(appOutDir, arch, this.customBuildOptions)
if (this.options.dist) {
postAsyncTasks.push(this.packageInDistributableFormat(outDir, appOutDir, arch, packOptions))
postAsyncTasks.push(this.packageInDistributableFormat(outDir, appOutDir, installerOut!, arch, packOptions))
}
}

protected computeAppOutDir(outDir: string, arch: string): string {
return path.join(outDir, `win${arch === "x64" ? "" : `-${arch}`}-unpacked`)
}

protected async packApp(options: any, appOutDir: string) {
await super.packApp(options, appOutDir)

Expand All @@ -103,6 +100,7 @@ export class WinPackager extends PlatformPackager<WinBuildOptions> {
name: this.appName,
site: await this.computePackageUrl(),
overwrite: true,
hash: this.customBuildOptions.signingHashAlgorithms,
})
}
}
Expand Down Expand Up @@ -157,6 +155,7 @@ export class WinPackager extends PlatformPackager<WinBuildOptions> {
name: this.appName,
site: projectUrl,
overwrite: true,
hash: this.customBuildOptions.signingHashAlgorithms,
},
rcedit: rceditOptions,
}, this.customBuildOptions)
Expand All @@ -168,8 +167,7 @@ export class WinPackager extends PlatformPackager<WinBuildOptions> {
return options
}

async packageInDistributableFormat(outDir: string, appOutDir: string, arch: string, packOptions: ElectronPackagerOptions): Promise<any> {
const installerOutDir = computeDistOut(outDir, arch)
protected async packageInDistributableFormat(outDir: string, appOutDir: string, installerOutDir: string, arch: string, packOptions: ElectronPackagerOptions): Promise<any> {
const winstaller = require("electron-winstaller-fixed")
const version = this.metadata.version
const archSuffix = arch === "x64" ? "" : ("-" + arch)
Expand Down
10 changes: 4 additions & 6 deletions test/src/BuildTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,12 @@ test("www as default dir", () => assertPack("test-app", currentPlatform(), {
tempDirCreated: projectDir => move(path.join(projectDir, "app"), path.join(projectDir, "www"))
}))

test("afterPack", t => {
test.ifDevOrLinuxCi("afterPack", t => {
let called = false
return assertPack("test-app-one", {
// linux pack is very fast, so, we use it :)
platform: [Platform.LINUX],
dist: true,
dist: false,
devMetadata: {
build: {
afterPack: () => {
Expand All @@ -147,8 +147,6 @@ test("copy extra resource", async () => {
platform: [platform],
// to check NuGet package
dist: platform === Platform.WINDOWS,
cscLink: null,
cscInstallerLink: null,
}, {
tempDirCreated: (projectDir) => {
return BluebirdPromise.all([
Expand Down Expand Up @@ -178,12 +176,12 @@ test("copy extra resource", async () => {
])
},
packed: async (projectDir) => {
let resourcesDir = path.join(projectDir, outDirName, "TestApp-" + platform.nodeName + "-" + process.arch)
let resourcesDir = path.join(projectDir, outDirName, platform.buildConfigurationKey)
if (platform === Platform.OSX) {
resourcesDir = path.join(resourcesDir, "TestApp.app", "Contents", "Resources")
}
else if (platform === Platform.WINDOWS) {
resourcesDir = path.join(projectDir, outDirName, "win-unpacked", "lib", "net45")
resourcesDir = path.join(projectDir, outDirName, "win-unpacked")
}
await assertThat(path.join(resourcesDir, "foo")).isDirectory()
await assertThat(path.join(resourcesDir, "foo", "nameWithoutDot")).isFile()
Expand Down
2 changes: 1 addition & 1 deletion test/src/helpers/packTester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ async function checkWindowsResult(packager: Packager, packagerOptions: PackagerO
const expectedContents = checkOptions == null || checkOptions.expectedContents == null ? expectedWinContents : checkOptions.expectedContents
assertThat(files).deepEqual(expectedContents.map(it => {
if (it === "lib/net45/TestApp.exe") {
return `lib/net45/${productName}.exe`
return `lib/net45/${encodeURI(productName)}.exe`
}
else {
return it
Expand Down
2 changes: 1 addition & 1 deletion test/src/osxPackagerTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as path from "path"
import { BuildInfo, PackagerOptions } from "out/platformPackager"
import { Promise as BluebirdPromise } from "bluebird"
import * as assertThat from "should/as-function"
import ElectronPackagerOptions = ElectronPackager.ElectronPackagerOptions
import { ElectronPackagerOptions } from "electron-packager-tf"
import { OsXBuildOptions } from "out/metadata"
import { SignOptions, FlatOptions } from "electron-osx-sign-tf"

Expand Down
9 changes: 5 additions & 4 deletions test/src/winPackagerTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { WinPackager, computeDistOut } from "out/winPackager"
import { BuildInfo } from "out/platformPackager"
import { Promise as BluebirdPromise } from "bluebird"
import * as assertThat from "should/as-function"
import ElectronPackagerOptions = ElectronPackager.ElectronPackagerOptions
import { ElectronPackagerOptions } from "electron-packager-tf"

//noinspection JSUnusedLocalSymbols
const __awaiter = require("out/awaiter")
Expand Down Expand Up @@ -113,11 +113,12 @@ class CheckingWinPackager extends WinPackager {
async pack(outDir: string, arch: string): Promise<any> {
// skip pack
const installerOutDir = computeDistOut(outDir, arch)
const packOptions = this.computePackOptions(outDir, arch)
this.effectiveDistOptions = await this.computeEffectiveDistOptions(this.computeAppOutDir(outDir, arch), installerOutDir, packOptions, "Foo.exe")
const appOutDir = this.computeAppOutDir(outDir, arch)
const packOptions = this.computePackOptions(outDir, appOutDir, arch)
this.effectiveDistOptions = await this.computeEffectiveDistOptions(appOutDir, installerOutDir, packOptions, "Foo.exe")
}

async packageInDistributableFormat(outDir: string, appOutDir: string, arch: string, packOptions: ElectronPackagerOptions): Promise<any> {
async packageInDistributableFormat(outDir: string, appOutDir: string, installerOutDir: string, arch: string, packOptions: ElectronPackagerOptions): Promise<any> {
// skip
}
}
Loading

0 comments on commit a783312

Please sign in to comment.