Skip to content

Commit cb87588

Browse files
committed
fix(electron-auto-updater): uncaught SHA2 checksum mismatch exception
1 parent c06f3f4 commit cb87588

File tree

8 files changed

+98
-28
lines changed

8 files changed

+98
-28
lines changed

.idea/dictionaries/develar.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/electron-auto-updater/src/NsisUpdater.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { spawn } from "child_process"
33
import * as path from "path"
44
import { tmpdir } from "os"
55
import { gt as isVersionGreaterThan, valid as parseVersion } from "semver"
6-
import { download, executorHolder } from "electron-builder-http"
7-
import { Provider, UpdateCheckResult, FileInfo } from "./api"
6+
import { download, executorHolder, DownloadOptions } from "electron-builder-http"
7+
import { Provider, UpdateCheckResult, FileInfo, UpdaterSignal, DOWNLOAD_PROGRESS } from "./api"
88
import { BintrayProvider } from "./BintrayProvider"
99
import BluebirdPromise from "bluebird-lst-c"
1010
import { BintrayOptions, PublishConfiguration, GithubOptions, GenericServerOptions, VersionInfo } from "electron-builder-http/out/publishOptions"
@@ -38,6 +38,8 @@ export class NsisUpdater extends EventEmitter {
3838
private versionInfo: VersionInfo | null
3939
private fileInfo: FileInfo | null
4040

41+
public signals = new UpdaterSignal(this)
42+
4143
constructor(options?: PublishConfiguration | BintrayOptions | GithubOptions) {
4244
super()
4345

@@ -148,12 +150,16 @@ export class NsisUpdater extends EventEmitter {
148150
async downloadUpdate() {
149151
const versionInfo = this.versionInfo
150152
const fileInfo = this.fileInfo
151-
const downloadOptions: any = {
152-
onProgress: (progress: any) => this.emit("download-progress", {}, progress)
153+
const downloadOptions: DownloadOptions = {
154+
skipDirCreation: true,
155+
}
156+
157+
if (this.listenerCount(DOWNLOAD_PROGRESS) > 0) {
158+
downloadOptions.onProgress = it => this.emit(DOWNLOAD_PROGRESS, it)
153159
}
154160

155-
if (fileInfo && fileInfo.sha2) {
156-
downloadOptions["sha2"] = fileInfo.sha2
161+
if (fileInfo != null && fileInfo.sha2 != null) {
162+
downloadOptions.sha2 = fileInfo.sha2
157163
}
158164

159165
if (versionInfo == null || fileInfo == null) {

packages/electron-auto-updater/src/api.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { VersionInfo } from "electron-builder-http/out/publishOptions"
2+
import { EventEmitter } from "events"
3+
import { ProgressInfo } from "electron-builder-http"
24

35
export interface FileInfo {
46
name: string
@@ -19,4 +21,29 @@ export interface UpdateCheckResult {
1921
readonly fileInfo?: FileInfo
2022

2123
readonly downloadPromise?: Promise<any> | null
24+
}
25+
26+
export const DOWNLOAD_PROGRESS = "download-progress"
27+
28+
export class UpdaterSignal {
29+
constructor(private emitter: EventEmitter) {
30+
}
31+
32+
progress(handler: (event: ProgressInfo) => void) {
33+
addHandler(this.emitter, DOWNLOAD_PROGRESS, handler)
34+
}
35+
}
36+
37+
const isLogEvent = false
38+
39+
function addHandler(emitter: EventEmitter, event: string, handler: Function) {
40+
if (isLogEvent) {
41+
emitter.on(event, function (...args: any[]) {
42+
console.log("%s %s", event, args)
43+
handler.apply(this, args)
44+
})
45+
}
46+
else {
47+
emitter.on(event, handler)
48+
}
2249
}

packages/electron-auto-updater/src/electronHttpExecutor.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ export class ElectronHttpExecutor extends HttpExecutor<Electron.RequestOptions,
7777

7878
doApiRequest<T>(options: Electron.RequestOptions, token: string | null, requestProcessor: (request: Electron.ClientRequest, reject: (error: Error) => void) => void, redirectCount: number = 0): Promise<T> {
7979
const requestOptions: any = options
80-
this.debug(`HTTPS request: ${JSON.stringify(requestOptions, null, 2)}`)
80+
if (this.debug.enabled) {
81+
this.debug(`HTTPS request: ${JSON.stringify(requestOptions, null, 2)}`)
82+
}
8183

8284
if (token != null) {
8385
(<any>requestOptions.headers).authorization = token.startsWith("Basic") ? token : `token ${token}`

packages/electron-builder-http/src/httpExecutor.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ export function configurePipes(options: DownloadOptions, response: any, destinat
198198

199199
let lastStream = response
200200
for (const stream of streams) {
201+
stream.on("error", callback)
201202
lastStream = lastStream.pipe(stream)
202203
}
203204

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,10 @@ export class NodeHttpExecutor extends HttpExecutor<RequestOptions, ClientRequest
8080
request.end()
8181
}
8282

83-
8483
doApiRequest<T>(options: RequestOptions, token: string | null, requestProcessor: (request: ClientRequest, reject: (error: Error) => void) => void, redirectCount: number = 0): Promise<T> {
85-
debug(`HTTPS request: ${JSON.stringify(options, null, 2)}`)
84+
if (debug.enabled) {
85+
debug(`HTTPS request: ${JSON.stringify(options, null, 2)}`)
86+
}
8687

8788
if (token != null) {
8889
(<any>options.headers).authorization = token.startsWith("Basic") ? token : `token ${token}`

test/out/__snapshots__/nsisUpdaterTest.js.snap

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,22 @@ Object {
6161
}
6262
`;
6363

64+
exports[`test sha2 mismatch error event 1`] = `
65+
Object {
66+
"name": "TestApp Setup 1.1.0.exe",
67+
"sha2": "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd1",
68+
"url": "https://develar.s3.amazonaws.com/test/TestApp Setup 1.1.0.exe",
69+
}
70+
`;
71+
72+
exports[`test sha2 mismatch error event 2`] = `
73+
Array [
74+
"checking-for-update",
75+
"update-available",
76+
"error",
77+
]
78+
`;
79+
6480
exports[`test test error 1`] = `
6581
Array [
6682
"checking-for-update",

test/src/nsisUpdaterTest.ts

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ if (process.env.ELECTRON_BUILDER_OFFLINE === "true") {
1212
})
1313
}
1414

15-
const NsisUpdaterClass = require("../../packages/electron-auto-updater/out/NsisUpdater").NsisUpdater
16-
1715
const g = (<any>global)
1816
g.__test_app = {
1917
getVersion: function () {
@@ -26,17 +24,17 @@ g.__test_app = {
2624
}
2725

2826
test("check updates - no versions at all", async () => {
29-
const updater: NsisUpdater = new NsisUpdaterClass({
30-
provider: "bintray",
31-
owner: "actperepo",
32-
package: "no-versions",
33-
})
27+
const updater = new NsisUpdater({
28+
provider: "bintray",
29+
owner: "actperepo",
30+
package: "no-versions",
31+
})
3432

3533
await assertThat(updater.checkForUpdates()).throws(/No latest version, please ensure that/)
3634
})
3735

3836
test("cannot find suitable file for version", async () => {
39-
const updater: NsisUpdater = new NsisUpdaterClass({
37+
const updater = new NsisUpdater({
4038
provider: "bintray",
4139
owner: "actperepo",
4240
package: "incorrect-file-version",
@@ -54,7 +52,7 @@ test("file url", async () => {
5452
package: "TestApp",
5553
}))
5654
g.__test_resourcesPath = testResourcesPath
57-
const updater: NsisUpdater = new NsisUpdaterClass()
55+
const updater = new NsisUpdater()
5856

5957
const actualEvents: Array<string> = []
6058
const expectedEvents = ["checking-for-update", "update-available", "update-downloaded"]
@@ -79,7 +77,7 @@ test("file url generic", async () => {
7977
url: "https://develar.s3.amazonaws.com/test",
8078
}))
8179
g.__test_resourcesPath = testResourcesPath
82-
const updater: NsisUpdater = new NsisUpdaterClass()
80+
const updater = new NsisUpdater()
8381

8482
const actualEvents = trackEvents(updater)
8583

@@ -90,6 +88,26 @@ test("file url generic", async () => {
9088
expect(actualEvents).toMatchSnapshot()
9189
})
9290

91+
test("sha2 mismatch error event", async () => {
92+
const tmpDir = new TmpDir()
93+
const testResourcesPath = await tmpDir.getTempFile("update-config")
94+
await outputFile(path.join(testResourcesPath, "app-update.yml"), safeDump(<GenericServerOptions>{
95+
provider: "generic",
96+
url: "https://develar.s3.amazonaws.com/test",
97+
channel: "beta",
98+
}))
99+
g.__test_resourcesPath = testResourcesPath
100+
const updater = new NsisUpdater()
101+
102+
const actualEvents = trackEvents(updater)
103+
104+
const updateCheckResult = await updater.checkForUpdates()
105+
expect(updateCheckResult.fileInfo).toMatchSnapshot()
106+
await assertThat(updateCheckResult.downloadPromise).throws(/SHA2 checksum mismatch,/)
107+
108+
expect(actualEvents).toMatchSnapshot()
109+
})
110+
93111
test("file url generic - manual download", async () => {
94112
const tmpDir = new TmpDir()
95113
const testResourcesPath = await tmpDir.getTempFile("update-config")
@@ -98,7 +116,7 @@ test("file url generic - manual download", async () => {
98116
url: "https://develar.s3.amazonaws.com/test",
99117
}))
100118
g.__test_resourcesPath = testResourcesPath
101-
const updater: NsisUpdater = new NsisUpdaterClass()
119+
const updater = new NsisUpdater()
102120
updater.autoDownload = false
103121

104122
const actualEvents = trackEvents(updater)
@@ -120,7 +138,7 @@ test("checkForUpdates several times", async () => {
120138
url: "https://develar.s3.amazonaws.com/test",
121139
}))
122140
g.__test_resourcesPath = testResourcesPath
123-
const updater: NsisUpdater = new NsisUpdaterClass()
141+
const updater: NsisUpdater = new NsisUpdater()
124142

125143
const actualEvents = trackEvents(updater)
126144

@@ -144,7 +162,7 @@ test("file url github", async () => {
144162
repo: "__test_nsis_release",
145163
}))
146164
g.__test_resourcesPath = testResourcesPath
147-
const updater: NsisUpdater = new NsisUpdaterClass()
165+
const updater: NsisUpdater = new NsisUpdater()
148166

149167
const actualEvents: Array<string> = []
150168
const expectedEvents = ["checking-for-update", "update-available", "update-downloaded"]
@@ -163,7 +181,7 @@ test("file url github", async () => {
163181

164182
test("test error", async () => {
165183
g.__test_resourcesPath = null
166-
const updater: NsisUpdater = new NsisUpdaterClass()
184+
const updater: NsisUpdater = new NsisUpdater()
167185

168186
const actualEvents = trackEvents(updater)
169187

@@ -179,14 +197,12 @@ test("test download progress", async () => {
179197
url: "https://develar.s3.amazonaws.com/test",
180198
}))
181199
g.__test_resourcesPath = testResourcesPath
182-
const updater: NsisUpdater = new NsisUpdaterClass()
200+
const updater = new NsisUpdater()
183201
updater.autoDownload = false
184202

185203
const progressEvents: Array<any> = []
186204

187-
updater.addListener("download-progress", (e: any, progress: any) => {
188-
progressEvents.push(progress)
189-
})
205+
updater.signals.progress(it => progressEvents.push(it))
190206

191207
await updater.checkForUpdates()
192208
await updater.downloadUpdate()
@@ -195,7 +211,7 @@ test("test download progress", async () => {
195211

196212
const lastEvent = progressEvents.pop()
197213

198-
expect(parseInt(lastEvent.percent, 10)).toBe(100)
214+
expect(lastEvent.percent).toBe(100)
199215
expect(lastEvent.bytesPerSecond).toBeGreaterThan(1)
200216
expect(lastEvent.transferred).toBe(lastEvent.total)
201217
})

0 commit comments

Comments
 (0)