electron-updater 7.0.0-alpha.6 → 7.0.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/AppImageUpdater.d.ts +2 -1
- package/dist/AppImageUpdater.d.ts.map +1 -1
- package/dist/AppImageUpdater.js.map +1 -1
- package/dist/AppUpdater.d.ts +43 -5
- package/dist/AppUpdater.d.ts.map +1 -1
- package/dist/AppUpdater.js +164 -9
- package/dist/AppUpdater.js.map +1 -1
- package/dist/BaseUpdater.d.ts +3 -3
- package/dist/BaseUpdater.d.ts.map +1 -1
- package/dist/BaseUpdater.js +2 -2
- package/dist/BaseUpdater.js.map +1 -1
- package/dist/DebUpdater.d.ts +2 -2
- package/dist/DebUpdater.d.ts.map +1 -1
- package/dist/DebUpdater.js.map +1 -1
- package/dist/MacUpdater.d.ts +3 -3
- package/dist/MacUpdater.d.ts.map +1 -1
- package/dist/MacUpdater.js +5 -4
- package/dist/MacUpdater.js.map +1 -1
- package/dist/NsisUpdater.d.ts +2 -1
- package/dist/NsisUpdater.d.ts.map +1 -1
- package/dist/NsisUpdater.js.map +1 -1
- package/dist/PacmanUpdater.d.ts +2 -2
- package/dist/PacmanUpdater.d.ts.map +1 -1
- package/dist/PacmanUpdater.js.map +1 -1
- package/dist/RpmUpdater.d.ts +2 -2
- package/dist/RpmUpdater.d.ts.map +1 -1
- package/dist/RpmUpdater.js.map +1 -1
- package/dist/differentialDownloader/DataSplitter.d.ts +3 -2
- package/dist/differentialDownloader/DataSplitter.d.ts.map +1 -1
- package/dist/differentialDownloader/DataSplitter.js +36 -15
- package/dist/differentialDownloader/DataSplitter.js.map +1 -1
- package/dist/differentialDownloader/multipleRangeDownloader.d.ts.map +1 -1
- package/dist/differentialDownloader/multipleRangeDownloader.js +22 -2
- package/dist/differentialDownloader/multipleRangeDownloader.js.map +1 -1
- package/dist/types.d.ts +22 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/windowsExecutableCodeSignatureVerifier.d.ts.map +1 -1
- package/dist/windowsExecutableCodeSignatureVerifier.js +117 -78
- package/dist/windowsExecutableCodeSignatureVerifier.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
This module allows you to automatically update your application. You only need to install this module and write two lines of code!
|
|
4
4
|
To publish your updates you just need simple file hosting, it does not require a dedicated server.
|
|
5
5
|
|
|
6
|
-
See [Auto Update](https://electron.build/auto-update) for more information.
|
|
6
|
+
See [Auto Update](https://electron.build/docs/features/auto-update) for more information.
|
|
7
7
|
|
|
8
8
|
Supported OS:
|
|
9
9
|
- macOS ([Squirrel.Mac](https://github.com/Squirrel/Squirrel.Mac)).
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { AllPublishOptions } from "builder-util-runtime";
|
|
2
2
|
import { DownloadUpdateOptions } from "./AppUpdater.js";
|
|
3
3
|
import { BaseUpdater, InstallOptions } from "./BaseUpdater.js";
|
|
4
|
+
import { DownloadExecutorResult } from "./types.js";
|
|
4
5
|
export declare class AppImageUpdater extends BaseUpdater {
|
|
5
6
|
constructor(options?: AllPublishOptions | null, app?: any);
|
|
6
7
|
isUpdaterActive(): boolean;
|
|
7
8
|
protected get isAutoInstallOnNextLaunchSupported(): boolean;
|
|
8
9
|
/*** @private */
|
|
9
|
-
protected doDownloadUpdate(downloadUpdateOptions: DownloadUpdateOptions): Promise<
|
|
10
|
+
protected doDownloadUpdate(downloadUpdateOptions: DownloadUpdateOptions): Promise<DownloadExecutorResult>;
|
|
10
11
|
private downloadDifferential;
|
|
11
12
|
protected doInstall(options: InstallOptions): boolean;
|
|
12
13
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppImageUpdater.d.ts","sourceRoot":"","sources":["../src/AppImageUpdater.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAY,MAAM,sBAAsB,CAAA;AAKlE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"AppImageUpdater.d.ts","sourceRoot":"","sources":["../src/AppImageUpdater.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAY,MAAM,sBAAsB,CAAA;AAKlE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAI9D,OAAO,EAA6C,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAE9F,qBAAa,eAAgB,SAAQ,WAAW;gBAClC,OAAO,CAAC,EAAE,iBAAiB,GAAG,IAAI,EAAE,GAAG,CAAC,EAAE,GAAG;IAIlD,eAAe,IAAI,OAAO;IAajC,SAAS,KAAK,kCAAkC,IAAI,OAAO,CAE1D;IAED,gBAAgB;IAChB,SAAS,CAAC,gBAAgB,CAAC,qBAAqB,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC;YAsB3F,oBAAoB;IAyBlC,SAAS,CAAC,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO;CA+CtD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppImageUpdater.js","sourceRoot":"","sources":["../src/AppImageUpdater.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,OAAO,MAAM,UAAU,CAAA;AAC9B,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAA;AAC/B,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAE5B,OAAO,EAAE,WAAW,EAAkB,MAAM,kBAAkB,CAAA;AAE9D,OAAO,EAAE,8CAA8C,EAAE,MAAM,4EAA4E,CAAA;AAC3I,OAAO,EAAE,QAAQ,EAAY,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"AppImageUpdater.js","sourceRoot":"","sources":["../src/AppImageUpdater.ts"],"names":[],"mappings":"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","sourcesContent":["import { AllPublishOptions, newError } from \"builder-util-runtime\"\nimport { execFileSync } from \"child_process\"\nimport fsExtra from \"fs-extra\"\nimport { unlinkSync } from \"fs\"\nimport * as path from \"path\"\nimport { DownloadUpdateOptions } from \"./AppUpdater.js\"\nimport { BaseUpdater, InstallOptions } from \"./BaseUpdater.js\"\nimport { DifferentialDownloaderOptions } from \"./differentialDownloader/DifferentialDownloader.js\"\nimport { FileWithEmbeddedBlockMapDifferentialDownloader } from \"./differentialDownloader/FileWithEmbeddedBlockMapDifferentialDownloader.js\"\nimport { findFile, Provider } from \"./providers/Provider.js\"\nimport { DOWNLOAD_PROGRESS, ResolvedUpdateFileInfo, DownloadExecutorResult } from \"./types.js\"\n\nexport class AppImageUpdater extends BaseUpdater {\n constructor(options?: AllPublishOptions | null, app?: any) {\n super(options, app)\n }\n\n public isUpdaterActive(): boolean {\n if (process.env[\"APPIMAGE\"] == null && !this.forceDevUpdateConfig) {\n if (process.env[\"SNAP\"] == null) {\n this._logger.warn(\"APPIMAGE env is not defined, current application is not an AppImage\")\n } else {\n this._logger.info(\"SNAP env is defined, updater is disabled\")\n }\n return false\n }\n return super.isUpdaterActive()\n }\n\n // replacing the AppImage file needs no elevation, so the automatic install at startup is allowed\n protected get isAutoInstallOnNextLaunchSupported(): boolean {\n return true\n }\n\n /*** @private */\n protected doDownloadUpdate(downloadUpdateOptions: DownloadUpdateOptions): Promise<DownloadExecutorResult> {\n const provider = downloadUpdateOptions.updateInfoAndProvider.provider\n const fileInfo = findFile(provider.resolveFiles(downloadUpdateOptions.updateInfoAndProvider.info), \"AppImage\", [\"rpm\", \"deb\", \"pacman\"])!\n return this.executeDownload({\n fileExtension: \"AppImage\",\n fileInfo,\n downloadUpdateOptions,\n task: async (updateFile, downloadOptions) => {\n const oldFile = process.env[\"APPIMAGE\"]!\n if (oldFile == null) {\n throw newError(\"APPIMAGE env is not defined\", \"ERR_UPDATER_OLD_FILE_NOT_FOUND\")\n }\n\n if (downloadUpdateOptions.disableDifferentialDownload || (await this.downloadDifferential(fileInfo, oldFile, updateFile, provider, downloadUpdateOptions))) {\n await this.httpExecutor.download(fileInfo.url, updateFile, downloadOptions)\n }\n\n await fsExtra.chmod(updateFile, 0o755)\n },\n })\n }\n\n private async downloadDifferential(fileInfo: ResolvedUpdateFileInfo, oldFile: string, updateFile: string, provider: Provider<any>, downloadUpdateOptions: DownloadUpdateOptions) {\n try {\n const downloadOptions: DifferentialDownloaderOptions = {\n newUrl: fileInfo.url,\n oldFile,\n logger: this._logger,\n newFile: updateFile,\n isUseMultipleRangeRequest: provider.isUseMultipleRangeRequest,\n requestHeaders: downloadUpdateOptions.requestHeaders,\n cancellationToken: downloadUpdateOptions.cancellationToken,\n }\n\n if (this.listenerCount(DOWNLOAD_PROGRESS) > 0) {\n downloadOptions.onProgress = it => this.emit(DOWNLOAD_PROGRESS, it)\n }\n\n await new FileWithEmbeddedBlockMapDifferentialDownloader(fileInfo.info, this.httpExecutor, downloadOptions).download()\n return false\n } catch (e: any) {\n this._logger.error(`Cannot download differentially, fallback to full download: ${e.stack || e}`)\n // during test (developer machine mac) we must throw error\n return process.platform === \"linux\"\n }\n }\n\n protected doInstall(options: InstallOptions): boolean {\n const appImageFile = process.env[\"APPIMAGE\"]!\n if (appImageFile == null) {\n throw newError(\"APPIMAGE env is not defined\", \"ERR_UPDATER_OLD_FILE_NOT_FOUND\")\n }\n if (!path.isAbsolute(appImageFile) || appImageFile.includes(\"\\0\")) {\n throw newError(`APPIMAGE env is not a valid absolute path: \"${appImageFile}\"`, \"ERR_UPDATER_OLD_FILE_NOT_FOUND\")\n }\n\n // https://stackoverflow.com/a/1712051/1910191\n unlinkSync(appImageFile)\n\n let destination: string\n const existingBaseName = path.basename(appImageFile)\n const installerPath = this.installerPath\n if (installerPath == null) {\n this.dispatchError(new Error(\"No update filepath provided, can't quit and install\"))\n return false\n }\n // https://github.com/electron-userland/electron-builder/issues/2964\n // if no version in existing file name, it means that user wants to preserve current custom name\n if (path.basename(installerPath) === existingBaseName || !/\\d+\\.\\d+\\.\\d+/.test(existingBaseName)) {\n // no version in the file name, overwrite existing\n destination = appImageFile\n } else {\n destination = path.join(path.dirname(appImageFile), path.basename(installerPath))\n }\n\n execFileSync(\"mv\", [\"-f\", installerPath, destination])\n if (destination !== appImageFile) {\n this.emit(\"appimage-filename-updated\", destination)\n }\n\n const env: NodeJS.ProcessEnv = {\n ...process.env,\n APPIMAGE_SILENT_INSTALL: \"true\",\n }\n\n if (options.isForceRunAfter) {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.spawnLog(destination, [], env)\n } else {\n env.APPIMAGE_EXIT_AFTER_INSTALL = \"true\"\n execFileSync(destination, [], { env })\n }\n return true\n }\n}\n"]}
|
package/dist/AppUpdater.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { Provider, ProviderPlatform } from "./providers/Provider.js";
|
|
|
9
9
|
import type { TypedEmitter } from "tiny-typed-emitter";
|
|
10
10
|
type Session = Electron.Session;
|
|
11
11
|
import type { AuthInfo } from "electron";
|
|
12
|
-
import { AutoInstallEvent, Logger, QuitAndInstallOptions, ResolvedUpdateFileInfo, UpdateCheckResult, UpdateDownloadedEvent, UpdaterSignal } from "./types.js";
|
|
12
|
+
import { AutoInstallEvent, Logger, QuitAndInstallOptions, ResolvedUpdateFileInfo, UpdateCheckResult, DownloadExecutorResult, UpdateDownloadedEvent, UpdaterSignal } from "./types.js";
|
|
13
13
|
import { VerifyUpdateSupport } from "./index.js";
|
|
14
14
|
export type AppUpdaterEvents = {
|
|
15
15
|
error: (error: Error, message?: string) => void;
|
|
@@ -49,6 +49,17 @@ export declare abstract class AppUpdater extends AppUpdater_base {
|
|
|
49
49
|
* @default "onQuit"
|
|
50
50
|
*/
|
|
51
51
|
autoInstallEvent: AutoInstallEvent;
|
|
52
|
+
/**
|
|
53
|
+
* @deprecated Removed in v27 — use {@link autoInstallEvent}. This accessor is a compatibility shim
|
|
54
|
+
* and will be deleted in v28.
|
|
55
|
+
*
|
|
56
|
+
* A boolean cannot express the three install timings, so `autoInstallOnAppQuit` was replaced rather
|
|
57
|
+
* than extended. Without this shim the property assignment silently no-ops on a plain object: an app
|
|
58
|
+
* that set `autoInstallOnAppQuit = false` to opt *out* of install-on-quit would keep the `"onQuit"`
|
|
59
|
+
* default and install on quit anyway — the exact opposite of what it asked for.
|
|
60
|
+
*/
|
|
61
|
+
get autoInstallOnAppQuit(): boolean;
|
|
62
|
+
set autoInstallOnAppQuit(value: boolean);
|
|
52
63
|
/**
|
|
53
64
|
* Installs an update that a previous launch marked as pending (see `autoInstallEvent: "onNextLaunch"` and
|
|
54
65
|
* `quitAndInstall({ waitUntilNextLaunch: true })`), then quits the app.
|
|
@@ -166,6 +177,18 @@ export declare abstract class AppUpdater extends AppUpdater_base {
|
|
|
166
177
|
* `allowDowngrade` will be automatically set to `true`. If this behavior is not suitable for you, simple set `allowDowngrade` explicitly after.
|
|
167
178
|
*/
|
|
168
179
|
set channel(value: string | null);
|
|
180
|
+
/**
|
|
181
|
+
* The Ed25519 public key(s) (PEM or base64 SPKI) trusted to have signed the update manifest — the
|
|
182
|
+
* install's trust list. A single string or an array of keys; a manifest is accepted when any listed key
|
|
183
|
+
* validates one of its signatures. When set (non-empty), overrides the `updateManifestPublicKey` value
|
|
184
|
+
* embedded in `app-update.yml`.
|
|
185
|
+
*
|
|
186
|
+
* When at least one key is available (here or in config) the manifest signature is enforced and a
|
|
187
|
+
* download will not start unless verification succeeds. When no key is available, verification is
|
|
188
|
+
* skipped (opt-in) and a one-time warning is logged.
|
|
189
|
+
*/
|
|
190
|
+
updateManifestPublicKey: string | Array<string> | null;
|
|
191
|
+
private manifestVerificationWarned;
|
|
169
192
|
/**
|
|
170
193
|
* The request headers.
|
|
171
194
|
*/
|
|
@@ -233,17 +256,32 @@ export declare abstract class AppUpdater extends AppUpdater_base {
|
|
|
233
256
|
private isUpdateAvailable;
|
|
234
257
|
private checkIfUpdateSupported;
|
|
235
258
|
protected getUpdateInfoAndProvider(): Promise<UpdateInfoAndProvider>;
|
|
259
|
+
/**
|
|
260
|
+
* Verifies the Ed25519 signature(s) embedded in the update manifest against the configured trust list.
|
|
261
|
+
* Provider-agnostic: runs for every provider since it operates on the resolved `UpdateInfo`.
|
|
262
|
+
*
|
|
263
|
+
* - No public key configured → verification skipped (opt-in phase), warns once.
|
|
264
|
+
* - Key(s) configured, manifest carries no signature at all → throws ERR_UPDATER_MANIFEST_NOT_SIGNED.
|
|
265
|
+
* - Key(s) configured, no trusted key validates any signature → throws ERR_UPDATER_MANIFEST_SIGNATURE_INVALID.
|
|
266
|
+
*
|
|
267
|
+
* A manifest may carry several signatures (`signatures`, one per signing key, tagged with the key id) plus
|
|
268
|
+
* the legacy single `signature`; any trusted key matching any of them is sufficient, which is what allows
|
|
269
|
+
* a release to be dual-signed while installs trust `[old, new]` during key rotation. Never fails open once
|
|
270
|
+
* a key is configured. A throw here propagates before any download starts (fail-closed).
|
|
271
|
+
*/
|
|
272
|
+
private verifyManifestSignature;
|
|
236
273
|
private createProviderRuntimeOptions;
|
|
237
274
|
private doCheckForUpdates;
|
|
238
275
|
protected onUpdateAvailable(updateInfo: UpdateInfo): void;
|
|
239
276
|
/**
|
|
240
277
|
* Start downloading update manually. You can use this method if `autoDownload` option is set to `false`.
|
|
241
|
-
* @returns {Promise<
|
|
278
|
+
* @returns {Promise<DownloadExecutorResult>} The downloaded files: `updateFile` is the path to the downloaded update (installer, AppImage, zip, ...),
|
|
279
|
+
* `packageFile` is the path to the NSIS web installer package and is only set for web installers.
|
|
242
280
|
*/
|
|
243
|
-
downloadUpdate(cancellationToken?: CancellationToken): Promise<
|
|
281
|
+
downloadUpdate(cancellationToken?: CancellationToken): Promise<DownloadExecutorResult>;
|
|
244
282
|
protected dispatchError(e: Error): void;
|
|
245
283
|
protected dispatchUpdateDownloaded(event: UpdateDownloadedEvent): void;
|
|
246
|
-
protected abstract doDownloadUpdate(downloadUpdateOptions: DownloadUpdateOptions): Promise<
|
|
284
|
+
protected abstract doDownloadUpdate(downloadUpdateOptions: DownloadUpdateOptions): Promise<DownloadExecutorResult>;
|
|
247
285
|
/**
|
|
248
286
|
* Restarts the app and installs the update after it has been downloaded.
|
|
249
287
|
* It should only be called after `update-downloaded` has been emitted.
|
|
@@ -259,7 +297,7 @@ export declare abstract class AppUpdater extends AppUpdater_base {
|
|
|
259
297
|
private computeRequestHeaders;
|
|
260
298
|
private getOrCreateStagingUserId;
|
|
261
299
|
protected getOrCreateDownloadHelper(): Promise<DownloadedUpdateHelper>;
|
|
262
|
-
protected executeDownload(taskOptions: DownloadExecutorTask): Promise<
|
|
300
|
+
protected executeDownload(taskOptions: DownloadExecutorTask): Promise<DownloadExecutorResult>;
|
|
263
301
|
protected differentialDownloadInstaller(fileInfo: ResolvedUpdateFileInfo, downloadUpdateOptions: DownloadUpdateOptions, installerPath: string, provider: Provider<any>, oldInstallerFileName: string): Promise<boolean>;
|
|
264
302
|
}
|
|
265
303
|
export interface DownloadUpdateOptions {
|
package/dist/AppUpdater.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppUpdater.d.ts","sourceRoot":"","sources":["../src/AppUpdater.ts"],"names":[],"mappings":"AACA,OAAO,EACL,iBAAiB,EAEjB,iBAAiB,EAEjB,oBAAoB,EACpB,UAAU,EAEV,eAAe,EAEf,YAAY,
|
|
1
|
+
{"version":3,"file":"AppUpdater.d.ts","sourceRoot":"","sources":["../src/AppUpdater.ts"],"names":[],"mappings":"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"}
|
package/dist/AppUpdater.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
import { asArray, CancellationToken, newError, UUID, CancellationError, retry, } from "builder-util-runtime";
|
|
2
|
+
import { asArray, CancellationToken, newError, UUID, CancellationError, retry, collectManifestSignatures, normalizePublicKeyList, verifyManifestSignatures, } from "builder-util-runtime";
|
|
3
3
|
import { randomBytes } from "crypto";
|
|
4
4
|
import { release } from "os";
|
|
5
5
|
import { EventEmitter } from "events";
|
|
@@ -18,6 +18,26 @@ import { GenericDifferentialDownloader } from "./differentialDownloader/GenericD
|
|
|
18
18
|
import { DOWNLOAD_PROGRESS, UPDATE_DOWNLOADED, UpdaterSignal, } from "./types.js";
|
|
19
19
|
const require = createRequire(import.meta.url);
|
|
20
20
|
export class AppUpdater extends EventEmitter {
|
|
21
|
+
/**
|
|
22
|
+
* @deprecated Removed in v27 — use {@link autoInstallEvent}. This accessor is a compatibility shim
|
|
23
|
+
* and will be deleted in v28.
|
|
24
|
+
*
|
|
25
|
+
* A boolean cannot express the three install timings, so `autoInstallOnAppQuit` was replaced rather
|
|
26
|
+
* than extended. Without this shim the property assignment silently no-ops on a plain object: an app
|
|
27
|
+
* that set `autoInstallOnAppQuit = false` to opt *out* of install-on-quit would keep the `"onQuit"`
|
|
28
|
+
* default and install on quit anyway — the exact opposite of what it asked for.
|
|
29
|
+
*/
|
|
30
|
+
get autoInstallOnAppQuit() {
|
|
31
|
+
return this.autoInstallEvent === "onQuit";
|
|
32
|
+
}
|
|
33
|
+
set autoInstallOnAppQuit(value) {
|
|
34
|
+
const mapped = value ? "onQuit" : "manual";
|
|
35
|
+
this._logger.warn(`autoInstallOnAppQuit was removed in electron-updater 7 (electron-builder v27) — use autoInstallEvent instead. ` +
|
|
36
|
+
`Mapping autoInstallOnAppQuit = ${value} to autoInstallEvent = "${mapped}". ` +
|
|
37
|
+
`This compatibility shim is removed in v28. ` +
|
|
38
|
+
`https://www.electron.build/docs/migration/v27-breaking-changes#autoinstallevent-replaces-autoinstallonappquit`);
|
|
39
|
+
this.autoInstallEvent = mapped;
|
|
40
|
+
}
|
|
21
41
|
/**
|
|
22
42
|
* Installs an update that a previous launch marked as pending (see `autoInstallEvent: "onNextLaunch"` and
|
|
23
43
|
* `quitAndInstall({ waitUntilNextLaunch: true })`), then quits the app.
|
|
@@ -236,6 +256,18 @@ export class AppUpdater extends EventEmitter {
|
|
|
236
256
|
this.previousBlockmapBaseUrlOverride = null;
|
|
237
257
|
this._channel = null;
|
|
238
258
|
this.downloadedUpdateHelper = null;
|
|
259
|
+
/**
|
|
260
|
+
* The Ed25519 public key(s) (PEM or base64 SPKI) trusted to have signed the update manifest — the
|
|
261
|
+
* install's trust list. A single string or an array of keys; a manifest is accepted when any listed key
|
|
262
|
+
* validates one of its signatures. When set (non-empty), overrides the `updateManifestPublicKey` value
|
|
263
|
+
* embedded in `app-update.yml`.
|
|
264
|
+
*
|
|
265
|
+
* When at least one key is available (here or in config) the manifest signature is enforced and a
|
|
266
|
+
* download will not start unless verification succeeds. When no key is available, verification is
|
|
267
|
+
* skipped (opt-in) and a one-time warning is logged.
|
|
268
|
+
*/
|
|
269
|
+
this.updateManifestPublicKey = null;
|
|
270
|
+
this.manifestVerificationWarned = false;
|
|
239
271
|
/**
|
|
240
272
|
* The request headers.
|
|
241
273
|
*/
|
|
@@ -381,8 +413,8 @@ export class AppUpdater extends EventEmitter {
|
|
|
381
413
|
if (stagingPercentage == null) {
|
|
382
414
|
return true;
|
|
383
415
|
}
|
|
384
|
-
stagingPercentage =
|
|
385
|
-
if (
|
|
416
|
+
stagingPercentage = Number(stagingPercentage);
|
|
417
|
+
if (!Number.isFinite(stagingPercentage)) {
|
|
386
418
|
this._logger.warn(`Staging percentage is NaN: ${rawStagingPercentage}`);
|
|
387
419
|
return true;
|
|
388
420
|
}
|
|
@@ -449,11 +481,60 @@ export class AppUpdater extends EventEmitter {
|
|
|
449
481
|
const client = await this.clientPromise;
|
|
450
482
|
const stagingUserId = await this.stagingUserIdPromise.value;
|
|
451
483
|
client.setRequestHeaders(this.computeFinalHeaders({ "x-user-staging-id": stagingUserId }));
|
|
484
|
+
const info = await client.getLatestVersion();
|
|
485
|
+
await this.verifyManifestSignature(info);
|
|
452
486
|
return {
|
|
453
|
-
info
|
|
487
|
+
info,
|
|
454
488
|
provider: client,
|
|
455
489
|
};
|
|
456
490
|
}
|
|
491
|
+
/**
|
|
492
|
+
* Verifies the Ed25519 signature(s) embedded in the update manifest against the configured trust list.
|
|
493
|
+
* Provider-agnostic: runs for every provider since it operates on the resolved `UpdateInfo`.
|
|
494
|
+
*
|
|
495
|
+
* - No public key configured → verification skipped (opt-in phase), warns once.
|
|
496
|
+
* - Key(s) configured, manifest carries no signature at all → throws ERR_UPDATER_MANIFEST_NOT_SIGNED.
|
|
497
|
+
* - Key(s) configured, no trusted key validates any signature → throws ERR_UPDATER_MANIFEST_SIGNATURE_INVALID.
|
|
498
|
+
*
|
|
499
|
+
* A manifest may carry several signatures (`signatures`, one per signing key, tagged with the key id) plus
|
|
500
|
+
* the legacy single `signature`; any trusted key matching any of them is sufficient, which is what allows
|
|
501
|
+
* a release to be dual-signed while installs trust `[old, new]` during key rotation. Never fails open once
|
|
502
|
+
* a key is configured. A throw here propagates before any download starts (fail-closed).
|
|
503
|
+
*/
|
|
504
|
+
async verifyManifestSignature(info) {
|
|
505
|
+
let trustedKeys = normalizePublicKeyList(this.updateManifestPublicKey);
|
|
506
|
+
if (trustedKeys.length === 0) {
|
|
507
|
+
try {
|
|
508
|
+
trustedKeys = normalizePublicKeyList((await this.configOnDisk.value)?.updateManifestPublicKey);
|
|
509
|
+
}
|
|
510
|
+
catch (e) {
|
|
511
|
+
// app-update.yml is read elsewhere too; a missing/unreadable config here just means "no key"
|
|
512
|
+
if (e.code !== "ENOENT") {
|
|
513
|
+
this._logger.warn(`Cannot read updateManifestPublicKey from update config: ${e.message || e}`);
|
|
514
|
+
}
|
|
515
|
+
trustedKeys = [];
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
if (trustedKeys.length === 0) {
|
|
519
|
+
if (!this.manifestVerificationWarned) {
|
|
520
|
+
this.manifestVerificationWarned = true;
|
|
521
|
+
this._logger.warn("update manifest signature verification is disabled. Configure updateManifestPublicKey (and sign manifests at build time) to enable it.");
|
|
522
|
+
}
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
if (collectManifestSignatures(info).length === 0) {
|
|
526
|
+
throw newError(`Update manifest for version ${info.version} is not signed, but updateManifestPublicKey is configured. Refusing to update.`, "ERR_UPDATER_MANIFEST_NOT_SIGNED");
|
|
527
|
+
}
|
|
528
|
+
const result = verifyManifestSignatures(info, trustedKeys);
|
|
529
|
+
if (!result.ok) {
|
|
530
|
+
// `reason` is set when the manifest fails the structural checks a signed manifest must pass (e.g. an empty
|
|
531
|
+
// `files` list or control characters in a signed field) — those are rejected before any key is tried.
|
|
532
|
+
const cause = result.reason == null ? `none of the ${trustedKeys.length} trusted key(s) validates any of its signatures` : `the signed manifest is malformed (${result.reason})`;
|
|
533
|
+
throw newError(`Update manifest signature verification failed for version ${info.version}: ${cause}. The update metadata may have been tampered with. Refusing to update.`, "ERR_UPDATER_MANIFEST_SIGNATURE_INVALID");
|
|
534
|
+
}
|
|
535
|
+
this._logger.debug?.(`Update manifest for version ${info.version} verified with trusted key ${result.keyId}`);
|
|
536
|
+
this._logger.info(`Update manifest signature verified for version ${info.version}`);
|
|
537
|
+
}
|
|
457
538
|
createProviderRuntimeOptions() {
|
|
458
539
|
return {
|
|
459
540
|
isUseMultipleRangeRequest: true,
|
|
@@ -494,7 +575,8 @@ export class AppUpdater extends EventEmitter {
|
|
|
494
575
|
}
|
|
495
576
|
/**
|
|
496
577
|
* Start downloading update manually. You can use this method if `autoDownload` option is set to `false`.
|
|
497
|
-
* @returns {Promise<
|
|
578
|
+
* @returns {Promise<DownloadExecutorResult>} The downloaded files: `updateFile` is the path to the downloaded update (installer, AppImage, zip, ...),
|
|
579
|
+
* `packageFile` is the path to the NSIS web installer package and is only set for web installers.
|
|
498
580
|
*/
|
|
499
581
|
downloadUpdate(cancellationToken = new CancellationToken()) {
|
|
500
582
|
const updateInfoAndProvider = this.updateInfoAndProvider;
|
|
@@ -543,6 +625,27 @@ export class AppUpdater extends EventEmitter {
|
|
|
543
625
|
dispatchUpdateDownloaded(event) {
|
|
544
626
|
this.emit(UPDATE_DOWNLOADED, event);
|
|
545
627
|
}
|
|
628
|
+
/**
|
|
629
|
+
* Accepts the v26 positional call shape, `quitAndInstall(isSilent, isForceRunAfter)`.
|
|
630
|
+
*
|
|
631
|
+
* TypeScript callers get a compile error, but plain JavaScript does not: the boolean lands in the
|
|
632
|
+
* destructured options parameter, every field reads back `undefined`, and the defaults silently take
|
|
633
|
+
* over — so `quitAndInstall(true)` performs a NON-silent install. Warn and map instead of ignoring.
|
|
634
|
+
*
|
|
635
|
+
* @internal
|
|
636
|
+
*/
|
|
637
|
+
normalizeQuitAndInstallOptions(options, legacyIsForceRunAfter) {
|
|
638
|
+
if (typeof options !== "boolean" && typeof legacyIsForceRunAfter !== "boolean") {
|
|
639
|
+
return options ?? {};
|
|
640
|
+
}
|
|
641
|
+
const isSilent = typeof options === "boolean" ? options : false;
|
|
642
|
+
const isForceRunAfter = legacyIsForceRunAfter === true;
|
|
643
|
+
this._logger.warn(`quitAndInstall(isSilent, isForceRunAfter) was replaced by quitAndInstall({ isSilent, isForceRunAfter }) in electron-updater 7 (electron-builder v27). ` +
|
|
644
|
+
`Interpreting the positional arguments as { isSilent: ${isSilent}, isForceRunAfter: ${isForceRunAfter} }. ` +
|
|
645
|
+
`This compatibility shim is removed in v28. ` +
|
|
646
|
+
`https://www.electron.build/docs/migration/v27-breaking-changes#quitandinstall-takes-an-options-object`);
|
|
647
|
+
return { isSilent, isForceRunAfter };
|
|
648
|
+
}
|
|
546
649
|
async loadUpdateConfig() {
|
|
547
650
|
if (this._appUpdateConfigPath == null) {
|
|
548
651
|
this._appUpdateConfigPath = this.app.appUpdateConfigPath;
|
|
@@ -655,17 +758,26 @@ export class AppUpdater extends EventEmitter {
|
|
|
655
758
|
const updateFileName = getCacheUpdateFileName();
|
|
656
759
|
let updateFile = path.join(cacheDir, updateFileName);
|
|
657
760
|
const packageFile = packageInfo == null ? null : path.join(cacheDir, `package-${version}${path.extname(packageInfo.path) || ".7z"}`);
|
|
761
|
+
const pendingBlockMapFile = path.join(cacheDir, "current.blockmap");
|
|
762
|
+
const cachedBlockMapFile = path.join(downloadedUpdateHelper.cacheDir, "current.blockmap");
|
|
658
763
|
const done = async (isSaveCache) => {
|
|
659
764
|
await downloadedUpdateHelper.setDownloadedFile(updateFile, packageFile, updateInfo, fileInfo, updateFileName, isSaveCache);
|
|
660
765
|
await taskOptions.done({
|
|
661
766
|
...updateInfo,
|
|
662
767
|
downloadedFile: updateFile,
|
|
768
|
+
...(packageFile == null ? {} : { packageFile }),
|
|
663
769
|
});
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
770
|
+
if (await fsExtra.pathExists(pendingBlockMapFile)) {
|
|
771
|
+
await fsExtra.copyFile(pendingBlockMapFile, cachedBlockMapFile);
|
|
772
|
+
}
|
|
773
|
+
else if (!taskOptions.downloadUpdateOptions.disableDifferentialDownload) {
|
|
774
|
+
// this download did not produce a blockmap, but `taskOptions.done` above refreshes the cached installer —
|
|
775
|
+
// remove the cached blockmap too, so a stale one cannot sit next to a fresh file and poison the next
|
|
776
|
+
// differential download with a wrong copy plan (https://github.com/electron-userland/electron-builder/issues/10097).
|
|
777
|
+
// The differential downloader re-fetches the old blockmap from the server when no cached one exists.
|
|
778
|
+
await fsExtra.remove(cachedBlockMapFile);
|
|
667
779
|
}
|
|
668
|
-
return packageFile == null ?
|
|
780
|
+
return withLegacyArrayCompat(packageFile == null ? { updateFile } : { updateFile, packageFile }, this._logger);
|
|
669
781
|
};
|
|
670
782
|
const log = this._logger;
|
|
671
783
|
const cachedUpdateFile = await downloadedUpdateHelper.validateDownloadedPath(updateFile, updateInfo, fileInfo, log);
|
|
@@ -681,6 +793,10 @@ export class AppUpdater extends EventEmitter {
|
|
|
681
793
|
// ignore
|
|
682
794
|
});
|
|
683
795
|
};
|
|
796
|
+
// a fresh download starts — drop any blockmap left over from a previous update round, so that when this round
|
|
797
|
+
// does not produce a new one (e.g. the differential download is skipped), the leftover cannot be promoted to the
|
|
798
|
+
// cache next to a file it does not describe
|
|
799
|
+
await fsExtra.remove(pendingBlockMapFile);
|
|
684
800
|
const tempUpdateFile = await createTempUpdateFile(`temp-${updateFileName}`, cacheDir, log);
|
|
685
801
|
try {
|
|
686
802
|
await taskOptions.task(tempUpdateFile, downloadOptions, packageFile, removeFileIfAny);
|
|
@@ -702,12 +818,18 @@ export class AppUpdater extends EventEmitter {
|
|
|
702
818
|
log.info("cancelled");
|
|
703
819
|
this.emit("update-cancelled", updateInfo);
|
|
704
820
|
}
|
|
821
|
+
else if (e.code === "ERR_CHECKSUM_MISMATCH") {
|
|
822
|
+
// a differential-download failure never escapes the task (it falls back to a full download),
|
|
823
|
+
// so a checksum mismatch here means the fully downloaded file itself failed verification
|
|
824
|
+
log.warn(`sha512 checksum mismatch after full download of ${updateFileName}: the downloaded file is corrupted or the published update metadata does not match the uploaded file`);
|
|
825
|
+
}
|
|
705
826
|
throw e;
|
|
706
827
|
}
|
|
707
828
|
log.info(`New version ${version} has been downloaded to ${updateFile}`);
|
|
708
829
|
return await done(true);
|
|
709
830
|
}
|
|
710
831
|
async differentialDownloadInstaller(fileInfo, downloadUpdateOptions, installerPath, provider, oldInstallerFileName) {
|
|
832
|
+
let isOldBlockMapFromCache = false;
|
|
711
833
|
try {
|
|
712
834
|
if (this._testOnlyOptions != null && !this._testOnlyOptions.isUseDifferentialDownload) {
|
|
713
835
|
return true;
|
|
@@ -762,13 +884,18 @@ export class AppUpdater extends EventEmitter {
|
|
|
762
884
|
await saveBlockMapToCacheDir(newBlockMapData, this.downloadedUpdateHelper.cacheDirForPendingUpdate);
|
|
763
885
|
// get old blockmap from cache dir first, if not found, download it
|
|
764
886
|
let oldBlockMapData = await getBlockMapFromCacheDir(this.downloadedUpdateHelper.cacheDir);
|
|
887
|
+
isOldBlockMapFromCache = oldBlockMapData != null;
|
|
765
888
|
if (oldBlockMapData == null) {
|
|
889
|
+
this._logger.info(`No cached blockmap for the old installer, downloading it from "${blockmapFileUrls[0]}"`);
|
|
766
890
|
oldBlockMapData = await downloadBlockMap(blockmapFileUrls[0]);
|
|
767
891
|
}
|
|
768
892
|
await new GenericDifferentialDownloader(fileInfo.info, this.httpExecutor, downloadOptions).download(oldBlockMapData, newBlockMapData);
|
|
769
893
|
return false;
|
|
770
894
|
}
|
|
771
895
|
catch (e) {
|
|
896
|
+
if (e.code === "ERR_CHECKSUM_MISMATCH") {
|
|
897
|
+
this._logger.warn(`sha512 checksum mismatch after differential download (old blockmap ${isOldBlockMapFromCache ? "was read from the local cache" : "was downloaded from the server"}): cached "${oldInstallerFileName}" is likely out of sync with the old blockmap, e.g. because one of them was replaced or evicted independently of the other`);
|
|
898
|
+
}
|
|
772
899
|
this._logger.error(`Cannot download differentially, fallback to full download: ${e.stack || e}`);
|
|
773
900
|
if (this._testOnlyOptions != null) {
|
|
774
901
|
// test mode
|
|
@@ -797,4 +924,32 @@ export class NoOpLogger {
|
|
|
797
924
|
// ignore
|
|
798
925
|
}
|
|
799
926
|
}
|
|
927
|
+
/**
|
|
928
|
+
* Adds a warning `Symbol.iterator` to a {@link DownloadExecutorResult}, for callers still written
|
|
929
|
+
* against v26's `Array<string>` return.
|
|
930
|
+
*
|
|
931
|
+
* `const [installer] = await downloadUpdate()` otherwise throws a bare
|
|
932
|
+
* `TypeError: ... is not iterable`, which names neither `downloadUpdate` nor the replacement, and
|
|
933
|
+
* `files[0]` silently evaluates to `undefined`. Yielding the same positional order the array had
|
|
934
|
+
* ([updateFile, packageFile]) keeps those call sites working for one major while they migrate.
|
|
935
|
+
*
|
|
936
|
+
* Non-enumerable so the object still serializes and compares as a plain `{ updateFile, packageFile }`.
|
|
937
|
+
*/
|
|
938
|
+
function withLegacyArrayCompat(result, logger) {
|
|
939
|
+
return Object.defineProperty(result, Symbol.iterator, {
|
|
940
|
+
enumerable: false,
|
|
941
|
+
configurable: true,
|
|
942
|
+
writable: true,
|
|
943
|
+
value: function* () {
|
|
944
|
+
logger.warn("downloadUpdate() resolves with a DownloadExecutorResult object in electron-updater 7 (electron-builder v27), not an array. " +
|
|
945
|
+
"Replace `const [updateFile] = await downloadUpdate()` with `const { updateFile } = await downloadUpdate()`. " +
|
|
946
|
+
"This compatibility shim is removed in v28. " +
|
|
947
|
+
"https://www.electron.build/docs/migration/v27-breaking-changes#downloadupdate-resolves-with-a-downloadexecutorresult-object");
|
|
948
|
+
yield result.updateFile;
|
|
949
|
+
if (result.packageFile != null) {
|
|
950
|
+
yield result.packageFile;
|
|
951
|
+
}
|
|
952
|
+
},
|
|
953
|
+
});
|
|
954
|
+
}
|
|
800
955
|
//# sourceMappingURL=AppUpdater.js.map
|