electron-updater 7.0.0-alpha.8 → 7.0.0-alpha.9
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/dist/AppImageUpdater.d.ts.map +1 -1
- package/dist/AppImageUpdater.js +4 -2
- package/dist/AppImageUpdater.js.map +1 -1
- package/dist/AppUpdater.d.ts +45 -4
- package/dist/AppUpdater.d.ts.map +1 -1
- package/dist/AppUpdater.js +199 -36
- package/dist/AppUpdater.js.map +1 -1
- package/dist/BaseUpdater.d.ts +6 -2
- package/dist/BaseUpdater.d.ts.map +1 -1
- package/dist/BaseUpdater.js +31 -8
- package/dist/BaseUpdater.js.map +1 -1
- package/dist/DownloadedUpdateHelper.d.ts +22 -1
- package/dist/DownloadedUpdateHelper.d.ts.map +1 -1
- package/dist/DownloadedUpdateHelper.js +51 -1
- package/dist/DownloadedUpdateHelper.js.map +1 -1
- package/dist/NsisUpdater.d.ts +23 -5
- package/dist/NsisUpdater.d.ts.map +1 -1
- package/dist/NsisUpdater.js +122 -38
- package/dist/NsisUpdater.js.map +1 -1
- package/dist/differentialDownloader/ProgressDifferentialDownloadCallbackTransform.d.ts +1 -0
- package/dist/differentialDownloader/ProgressDifferentialDownloadCallbackTransform.d.ts.map +1 -1
- package/dist/differentialDownloader/ProgressDifferentialDownloadCallbackTransform.js +7 -3
- package/dist/differentialDownloader/ProgressDifferentialDownloadCallbackTransform.js.map +1 -1
- package/dist/index.d.ts +1 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/providers/BitbucketProvider.d.ts +1 -0
- package/dist/providers/BitbucketProvider.d.ts.map +1 -1
- package/dist/providers/BitbucketProvider.js +3 -0
- package/dist/providers/BitbucketProvider.js.map +1 -1
- package/dist/providers/GenericProvider.d.ts +1 -0
- package/dist/providers/GenericProvider.d.ts.map +1 -1
- package/dist/providers/GenericProvider.js +3 -0
- package/dist/providers/GenericProvider.js.map +1 -1
- package/dist/providers/GitHubProvider.d.ts +1 -0
- package/dist/providers/GitHubProvider.d.ts.map +1 -1
- package/dist/providers/GitHubProvider.js +3 -0
- package/dist/providers/GitHubProvider.js.map +1 -1
- package/dist/providers/GitLabProvider.d.ts +1 -0
- package/dist/providers/GitLabProvider.d.ts.map +1 -1
- package/dist/providers/GitLabProvider.js +3 -0
- package/dist/providers/GitLabProvider.js.map +1 -1
- package/dist/providers/KeygenProvider.d.ts +1 -0
- package/dist/providers/KeygenProvider.d.ts.map +1 -1
- package/dist/providers/KeygenProvider.js +3 -0
- package/dist/providers/KeygenProvider.js.map +1 -1
- package/dist/providers/PrivateGitHubProvider.d.ts +1 -0
- package/dist/providers/PrivateGitHubProvider.d.ts.map +1 -1
- package/dist/providers/PrivateGitHubProvider.js +4 -0
- package/dist/providers/PrivateGitHubProvider.js.map +1 -1
- package/dist/providers/Provider.d.ts +7 -0
- package/dist/providers/Provider.d.ts.map +1 -1
- package/dist/providers/Provider.js +15 -0
- package/dist/providers/Provider.js.map +1 -1
- package/dist/types.d.ts +59 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +6 -0
- package/dist/util.js.map +1 -1
- package/dist/windowsExecutableCodeSignatureVerifier.d.ts +2 -1
- package/dist/windowsExecutableCodeSignatureVerifier.d.ts.map +1 -1
- package/dist/windowsExecutableCodeSignatureVerifier.js +7 -8
- package/dist/windowsExecutableCodeSignatureVerifier.js.map +1 -1
- package/package.json +3 -3
|
@@ -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;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;
|
|
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;YAuB3F,oBAAoB;IAyBlC,SAAS,CAAC,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO;CA+CtD"}
|
package/dist/AppImageUpdater.js
CHANGED
|
@@ -43,8 +43,10 @@ export class AppImageUpdater extends BaseUpdater {
|
|
|
43
43
|
if (downloadUpdateOptions.disableDifferentialDownload || (await this.downloadDifferential(fileInfo, oldFile, updateFile, provider, downloadUpdateOptions))) {
|
|
44
44
|
await this.httpExecutor.download(fileInfo.url, updateFile, downloadOptions);
|
|
45
45
|
}
|
|
46
|
-
await fsExtra.chmod(updateFile, 0o755);
|
|
47
46
|
},
|
|
47
|
+
// deferred until after verification: the temporary path is predictable, so marking the AppImage executable
|
|
48
|
+
// before it is verified would leave an unverified binary runnable for as long as verification takes
|
|
49
|
+
afterVerification: updateFile => fsExtra.chmod(updateFile, 0o755),
|
|
48
50
|
});
|
|
49
51
|
}
|
|
50
52
|
async downloadDifferential(fileInfo, oldFile, updateFile, provider, downloadUpdateOptions) {
|
|
@@ -55,7 +57,7 @@ export class AppImageUpdater extends BaseUpdater {
|
|
|
55
57
|
logger: this._logger,
|
|
56
58
|
newFile: updateFile,
|
|
57
59
|
isUseMultipleRangeRequest: provider.isUseMultipleRangeRequest,
|
|
58
|
-
requestHeaders:
|
|
60
|
+
requestHeaders: this.downloadRequestHeaders(fileInfo.url, downloadUpdateOptions),
|
|
59
61
|
cancellationToken: downloadUpdateOptions.cancellationToken,
|
|
60
62
|
};
|
|
61
63
|
if (this.listenerCount(DOWNLOAD_PROGRESS) > 0) {
|
|
@@ -1 +1 @@
|
|
|
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"]}
|
|
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 // deferred until after verification: the temporary path is predictable, so marking the AppImage executable\n // before it is verified would leave an unverified binary runnable for as long as verification takes\n afterVerification: updateFile => fsExtra.chmod(updateFile, 0o755),\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: this.downloadRequestHeaders(fileInfo.url, downloadUpdateOptions),\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,8 +9,8 @@ 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, DownloadExecutorResult, UpdateDownloadedEvent, UpdaterSignal } from "./types.js";
|
|
13
|
-
import { VerifyUpdateSupport } from "./index.js";
|
|
12
|
+
import { AutoInstallEvent, Logger, QuitAndInstallOptions, ResolvedUpdateFileInfo, UpdateCheckResult, DownloadExecutorResult, UpdateDownloadedEvent, UpdaterSignal, VerifyUpdateFile } from "./types.js";
|
|
13
|
+
import type { VerifyUpdateSupport } from "./index.js";
|
|
14
14
|
export type AppUpdaterEvents = {
|
|
15
15
|
error: (error: Error, message?: string) => void;
|
|
16
16
|
login: (info: AuthInfo, callback: LoginCallback) => void;
|
|
@@ -127,15 +127,22 @@ export declare abstract class AppUpdater extends AppUpdater_base {
|
|
|
127
127
|
*/
|
|
128
128
|
allowUnverifiedLinuxPackages: boolean;
|
|
129
129
|
private _disableWebInstaller;
|
|
130
|
+
protected disableWebInstallerDefault: boolean;
|
|
130
131
|
/**
|
|
131
|
-
* Whether to block NSIS web-installer packages. Web installer files might not have signature verification, so they are disabled by default as of v27
|
|
132
|
+
* Whether to block NSIS web-installer packages. Web installer files might not have signature verification, so they are disabled by default as of v27:
|
|
133
|
+
* a web-installer update is rejected with `ERR_UPDATER_WEB_INSTALLER_DISABLED` at download time, before an install on next launch, and at install time unless this is `false`.
|
|
132
134
|
*
|
|
133
|
-
*
|
|
135
|
+
* `NsisUpdater` defaults it to `false` for installs made by an `nsis-web` installer built with electron-builder v27+ (`resources/package-type` marker).
|
|
136
|
+
* Set it to `false` explicitly only if you intentionally publish and rely on NSIS web-installer packages and your installs lack that marker.
|
|
137
|
+
*
|
|
138
|
+
* Set it before the app is `ready` (e.g. right after creating the updater): with `autoInstallEvent: "onNextLaunch"` a pending
|
|
139
|
+
* web-installer update is checked against it when the app is ready, and rejected (its pending-install marker cleared) while it is `true`.
|
|
134
140
|
*
|
|
135
141
|
* @default true
|
|
136
142
|
*/
|
|
137
143
|
get disableWebInstaller(): boolean;
|
|
138
144
|
set disableWebInstaller(value: boolean);
|
|
145
|
+
protected get isWebInstallerEnabledByApp(): boolean;
|
|
139
146
|
/**
|
|
140
147
|
* *NSIS only* Disable differential downloads and always perform full download of installer.
|
|
141
148
|
*
|
|
@@ -189,6 +196,8 @@ export declare abstract class AppUpdater extends AppUpdater_base {
|
|
|
189
196
|
*/
|
|
190
197
|
updateManifestPublicKey: string | Array<string> | null;
|
|
191
198
|
private manifestVerificationWarned;
|
|
199
|
+
private crossOriginHeadersWarned;
|
|
200
|
+
private crossOriginFeedQueryWarned;
|
|
192
201
|
/**
|
|
193
202
|
* The request headers.
|
|
194
203
|
*/
|
|
@@ -215,6 +224,26 @@ export declare abstract class AppUpdater extends AppUpdater_base {
|
|
|
215
224
|
* @private
|
|
216
225
|
*/
|
|
217
226
|
set updateConfigPath(value: string | null);
|
|
227
|
+
protected _verifyUpdateFile: VerifyUpdateFile;
|
|
228
|
+
/**
|
|
229
|
+
* Allows developer to set custom logic for verifying an update file before it is allowed to become installable.
|
|
230
|
+
* When the verification fails, the file is deleted and electron-updater emits an `ERR_UPDATER_INVALID_UPDATE_FILE` error.
|
|
231
|
+
* The default behavior is a stub – immediately succeeds.
|
|
232
|
+
*
|
|
233
|
+
* It runs on every path that can lead to an install:
|
|
234
|
+
* - right after a fresh download, while the file still sits under a temporary name and before it is renamed into the
|
|
235
|
+
* updater cache under its real filename, so an unverified file can never be executed under its real name;
|
|
236
|
+
* - when an update downloaded by an earlier session is reused from the updater cache;
|
|
237
|
+
* - before an install-on-next-launch spawns the cached installer (see {@link BaseUpdater}).
|
|
238
|
+
*
|
|
239
|
+
* The custom logic gets `updateFilePath` (the file to verify), `originalUpdateFileName` (its real filename), the
|
|
240
|
+
* optional `packageFilePath` of an NSIS web installer package, and the active `cancellationToken` when the
|
|
241
|
+
* verification belongs to a download.
|
|
242
|
+
*
|
|
243
|
+
* Assigning `null` restores the default stub.
|
|
244
|
+
*/
|
|
245
|
+
get verifyUpdateFile(): VerifyUpdateFile;
|
|
246
|
+
set verifyUpdateFile(value: VerifyUpdateFile | null | undefined);
|
|
218
247
|
protected _isUpdateSupported: VerifyUpdateSupport;
|
|
219
248
|
/**
|
|
220
249
|
* Allows developer to override default logic for determining if an update is supported.
|
|
@@ -295,6 +324,13 @@ export declare abstract class AppUpdater extends AppUpdater_base {
|
|
|
295
324
|
abstract quitAndInstall(options?: QuitAndInstallOptions): void;
|
|
296
325
|
private loadUpdateConfig;
|
|
297
326
|
private computeRequestHeaders;
|
|
327
|
+
/**
|
|
328
|
+
* Headers for a download from `url`: when the provider has a `feedBaseUrl`, the credential-bearing ones are dropped if `url` is on
|
|
329
|
+
* another origin than `originUrl` (the feed by default). `null` keeps them for every URL.
|
|
330
|
+
*/
|
|
331
|
+
protected downloadRequestHeaders(url: URL, downloadUpdateOptions: DownloadUpdateOptions, originUrl?: URL): OutgoingHttpHeaders;
|
|
332
|
+
private announceCrossOriginDownload;
|
|
333
|
+
private static checkFeedBaseUrlDeclared;
|
|
298
334
|
private getOrCreateStagingUserId;
|
|
299
335
|
protected getOrCreateDownloadHelper(): Promise<DownloadedUpdateHelper>;
|
|
300
336
|
protected executeDownload(taskOptions: DownloadExecutorTask): Promise<DownloadExecutorResult>;
|
|
@@ -322,6 +358,11 @@ export interface DownloadExecutorTask {
|
|
|
322
358
|
readonly fileInfo: ResolvedUpdateFileInfo;
|
|
323
359
|
readonly downloadUpdateOptions: DownloadUpdateOptions;
|
|
324
360
|
readonly task: (destinationFile: string, downloadOptions: DownloadOptions, packageFile: string | null, removeTempDirIfAny: () => Promise<any>) => Promise<any>;
|
|
361
|
+
/**
|
|
362
|
+
* Runs after the downloaded file passed verification and before it is renamed into the cache under its real name.
|
|
363
|
+
* For anything that must not be done to a file that is still unverified — making it executable, in particular.
|
|
364
|
+
*/
|
|
365
|
+
readonly afterVerification?: (destinationFile: string) => Promise<void>;
|
|
325
366
|
readonly done?: (event: UpdateDownloadedEvent) => Promise<any>;
|
|
326
367
|
}
|
|
327
368
|
export interface DownloadNotification {
|
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,
|
|
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, collectManifestSignatures, normalizePublicKeyList, verifyManifestSignatures, } from "builder-util-runtime";
|
|
2
|
+
import { asArray, CancellationToken, newError, UUID, CancellationError, HttpExecutor, 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";
|
|
@@ -15,8 +15,10 @@ import { GenericProvider } from "./providers/GenericProvider.js";
|
|
|
15
15
|
import { createClient, isUrlProbablySupportMultiRangeRequests } from "./providerFactory.js";
|
|
16
16
|
import { gunzipSync, gzipSync } from "zlib";
|
|
17
17
|
import { GenericDifferentialDownloader } from "./differentialDownloader/GenericDifferentialDownloader.js";
|
|
18
|
-
import { DOWNLOAD_PROGRESS, UPDATE_DOWNLOADED, UpdaterSignal, } from "./types.js";
|
|
18
|
+
import { DOWNLOAD_PROGRESS, UPDATE_DOWNLOADED, UpdaterSignal, verificationFailureMessage, } from "./types.js";
|
|
19
19
|
const require = createRequire(import.meta.url);
|
|
20
|
+
// shared rather than per-instance so that `updater.verifyUpdateFile === DEFAULT_VERIFY_UPDATE_FILE` identifies "no custom verifier"
|
|
21
|
+
const DEFAULT_VERIFY_UPDATE_FILE = _params => Promise.resolve({ response: "success" });
|
|
20
22
|
export class AppUpdater extends EventEmitter {
|
|
21
23
|
/**
|
|
22
24
|
* @deprecated Removed in v27 — use {@link autoInstallEvent}. This accessor is a compatibility shim
|
|
@@ -61,18 +63,27 @@ export class AppUpdater extends EventEmitter {
|
|
|
61
63
|
return Promise.resolve(false);
|
|
62
64
|
}
|
|
63
65
|
/**
|
|
64
|
-
* Whether to block NSIS web-installer packages. Web installer files might not have signature verification, so they are disabled by default as of v27
|
|
66
|
+
* Whether to block NSIS web-installer packages. Web installer files might not have signature verification, so they are disabled by default as of v27:
|
|
67
|
+
* a web-installer update is rejected with `ERR_UPDATER_WEB_INSTALLER_DISABLED` at download time, before an install on next launch, and at install time unless this is `false`.
|
|
65
68
|
*
|
|
66
|
-
*
|
|
69
|
+
* `NsisUpdater` defaults it to `false` for installs made by an `nsis-web` installer built with electron-builder v27+ (`resources/package-type` marker).
|
|
70
|
+
* Set it to `false` explicitly only if you intentionally publish and rely on NSIS web-installer packages and your installs lack that marker.
|
|
71
|
+
*
|
|
72
|
+
* Set it before the app is `ready` (e.g. right after creating the updater): with `autoInstallEvent: "onNextLaunch"` a pending
|
|
73
|
+
* web-installer update is checked against it when the app is ready, and rejected (its pending-install marker cleared) while it is `true`.
|
|
67
74
|
*
|
|
68
75
|
* @default true
|
|
69
76
|
*/
|
|
70
77
|
get disableWebInstaller() {
|
|
71
|
-
return this._disableWebInstaller ??
|
|
78
|
+
return this._disableWebInstaller ?? this.disableWebInstallerDefault;
|
|
72
79
|
}
|
|
73
80
|
set disableWebInstaller(value) {
|
|
74
81
|
this._disableWebInstaller = value;
|
|
75
82
|
}
|
|
83
|
+
// the app itself set disableWebInstaller to false (not the nsis-web default)
|
|
84
|
+
get isWebInstallerEnabledByApp() {
|
|
85
|
+
return this._disableWebInstaller === false;
|
|
86
|
+
}
|
|
76
87
|
/**
|
|
77
88
|
* Get the update channel. Doesn't return `channel` from the update configuration, only if was previously set.
|
|
78
89
|
*/
|
|
@@ -129,6 +140,29 @@ export class AppUpdater extends EventEmitter {
|
|
|
129
140
|
this._appUpdateConfigPath = value;
|
|
130
141
|
this.configOnDisk = new Lazy(() => this.loadUpdateConfig());
|
|
131
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Allows developer to set custom logic for verifying an update file before it is allowed to become installable.
|
|
145
|
+
* When the verification fails, the file is deleted and electron-updater emits an `ERR_UPDATER_INVALID_UPDATE_FILE` error.
|
|
146
|
+
* The default behavior is a stub – immediately succeeds.
|
|
147
|
+
*
|
|
148
|
+
* It runs on every path that can lead to an install:
|
|
149
|
+
* - right after a fresh download, while the file still sits under a temporary name and before it is renamed into the
|
|
150
|
+
* updater cache under its real filename, so an unverified file can never be executed under its real name;
|
|
151
|
+
* - when an update downloaded by an earlier session is reused from the updater cache;
|
|
152
|
+
* - before an install-on-next-launch spawns the cached installer (see {@link BaseUpdater}).
|
|
153
|
+
*
|
|
154
|
+
* The custom logic gets `updateFilePath` (the file to verify), `originalUpdateFileName` (its real filename), the
|
|
155
|
+
* optional `packageFilePath` of an NSIS web installer package, and the active `cancellationToken` when the
|
|
156
|
+
* verification belongs to a download.
|
|
157
|
+
*
|
|
158
|
+
* Assigning `null` restores the default stub.
|
|
159
|
+
*/
|
|
160
|
+
get verifyUpdateFile() {
|
|
161
|
+
return this._verifyUpdateFile;
|
|
162
|
+
}
|
|
163
|
+
set verifyUpdateFile(value) {
|
|
164
|
+
this._verifyUpdateFile = value ?? DEFAULT_VERIFY_UPDATE_FILE;
|
|
165
|
+
}
|
|
132
166
|
/**
|
|
133
167
|
* Allows developer to override default logic for determining if an update is supported.
|
|
134
168
|
* The default logic compares the `UpdateInfo` minimum system version against the `os.release()` with `semver` package
|
|
@@ -228,7 +262,10 @@ export class AppUpdater extends EventEmitter {
|
|
|
228
262
|
* @default true
|
|
229
263
|
*/
|
|
230
264
|
this.allowUnverifiedLinuxPackages = true;
|
|
265
|
+
// undefined until the app sets disableWebInstaller, so NsisUpdater can tell a `false` set by the app from the nsis-web default
|
|
231
266
|
this._disableWebInstaller = undefined;
|
|
267
|
+
// the value of disableWebInstaller while the app has not set it; NsisUpdater sets it to false for an install made by an nsis-web installer
|
|
268
|
+
this.disableWebInstallerDefault = true;
|
|
232
269
|
/**
|
|
233
270
|
* *NSIS only* Disable differential downloads and always perform full download of installer.
|
|
234
271
|
*
|
|
@@ -268,6 +305,9 @@ export class AppUpdater extends EventEmitter {
|
|
|
268
305
|
*/
|
|
269
306
|
this.updateManifestPublicKey = null;
|
|
270
307
|
this.manifestVerificationWarned = false;
|
|
308
|
+
// v27 behaviour changes a plain-JavaScript app would otherwise not notice: each is announced once per updater
|
|
309
|
+
this.crossOriginHeadersWarned = false;
|
|
310
|
+
this.crossOriginFeedQueryWarned = false;
|
|
271
311
|
/**
|
|
272
312
|
* The request headers.
|
|
273
313
|
*/
|
|
@@ -279,6 +319,7 @@ export class AppUpdater extends EventEmitter {
|
|
|
279
319
|
*/
|
|
280
320
|
this.signals = new UpdaterSignal(this);
|
|
281
321
|
this._appUpdateConfigPath = null;
|
|
322
|
+
this._verifyUpdateFile = DEFAULT_VERIFY_UPDATE_FILE;
|
|
282
323
|
this._isUpdateSupported = updateInfo => this.checkIfUpdateSupported(updateInfo);
|
|
283
324
|
this._isUserWithinRollout = updateInfo => this.isStagingMatch(updateInfo);
|
|
284
325
|
this.clientPromise = null;
|
|
@@ -389,7 +430,10 @@ export class AppUpdater extends EventEmitter {
|
|
|
389
430
|
}
|
|
390
431
|
void it.downloadPromise.then(() => {
|
|
391
432
|
const notificationContent = AppUpdater.formatDownloadNotification(it.updateInfo.version, this.app.name, downloadNotification);
|
|
392
|
-
|
|
433
|
+
const ElectronNotification = require("electron").Notification;
|
|
434
|
+
new ElectronNotification(notificationContent).show();
|
|
435
|
+
}, () => {
|
|
436
|
+
// downloadUpdate already dispatches the error event
|
|
393
437
|
});
|
|
394
438
|
return it;
|
|
395
439
|
});
|
|
@@ -530,7 +574,12 @@ export class AppUpdater extends EventEmitter {
|
|
|
530
574
|
// `reason` is set when the manifest fails the structural checks a signed manifest must pass (e.g. an empty
|
|
531
575
|
// `files` list or control characters in a signed field) — those are rejected before any key is tried.
|
|
532
576
|
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
|
-
|
|
577
|
+
// download URLs written into latest*.yml after signing (e.g. pre-signed URLs) are the likely cause, rather than tampering
|
|
578
|
+
const blockMapUrlHint = (info.files ?? []).some(it => it?.blockMapUrl != null)
|
|
579
|
+
? " files[].blockMapUrl is covered by the signature, like files[].url, so it has to be in latest*.yml before the manifest is signed: " +
|
|
580
|
+
"https://www.electron.build/docs/features/signed-update-manifests#what-is-signed"
|
|
581
|
+
: "";
|
|
582
|
+
throw newError(`Update manifest signature verification failed for version ${info.version}: ${cause}. The update metadata may have been tampered with. Refusing to update.${blockMapUrlHint}`, "ERR_UPDATER_MANIFEST_SIGNATURE_INVALID");
|
|
534
583
|
}
|
|
535
584
|
this._logger.debug?.(`Update manifest for version ${info.version} verified with trusted key ${result.keyId}`);
|
|
536
585
|
this._logger.info(`Update manifest signature verified for version ${info.version}`);
|
|
@@ -604,11 +653,19 @@ export class AppUpdater extends EventEmitter {
|
|
|
604
653
|
}
|
|
605
654
|
return e;
|
|
606
655
|
};
|
|
656
|
+
const requestHeaders = this.computeRequestHeaders(updateInfoAndProvider.provider);
|
|
657
|
+
try {
|
|
658
|
+
// fail before any download rather than in the middle of one
|
|
659
|
+
AppUpdater.checkFeedBaseUrlDeclared(updateInfoAndProvider.provider, requestHeaders);
|
|
660
|
+
}
|
|
661
|
+
catch (e) {
|
|
662
|
+
return Promise.reject(errorHandler(e));
|
|
663
|
+
}
|
|
607
664
|
this.downloadPromise = this.doDownloadUpdate({
|
|
608
665
|
updateInfoAndProvider,
|
|
609
|
-
requestHeaders
|
|
666
|
+
requestHeaders,
|
|
610
667
|
cancellationToken,
|
|
611
|
-
disableWebInstaller: this.
|
|
668
|
+
disableWebInstaller: this.disableWebInstaller,
|
|
612
669
|
disableDifferentialDownload: this.disableDifferentialDownload,
|
|
613
670
|
})
|
|
614
671
|
.catch((e) => {
|
|
@@ -665,6 +722,55 @@ export class AppUpdater extends EventEmitter {
|
|
|
665
722
|
}
|
|
666
723
|
return this.computeFinalHeaders({ accept: "*/*" });
|
|
667
724
|
}
|
|
725
|
+
/**
|
|
726
|
+
* Headers for a download from `url`: when the provider has a `feedBaseUrl`, the credential-bearing ones are dropped if `url` is on
|
|
727
|
+
* another origin than `originUrl` (the feed by default). `null` keeps them for every URL.
|
|
728
|
+
*/
|
|
729
|
+
downloadRequestHeaders(url, downloadUpdateOptions, originUrl) {
|
|
730
|
+
const provider = downloadUpdateOptions.updateInfoAndProvider.provider;
|
|
731
|
+
const headers = downloadUpdateOptions.requestHeaders;
|
|
732
|
+
AppUpdater.checkFeedBaseUrlDeclared(provider, headers);
|
|
733
|
+
const feedBaseUrl = provider.feedBaseUrl;
|
|
734
|
+
if (feedBaseUrl == null) {
|
|
735
|
+
return headers;
|
|
736
|
+
}
|
|
737
|
+
const credentialOrigin = originUrl ?? feedBaseUrl;
|
|
738
|
+
if (HttpExecutor.isCrossOrigin(credentialOrigin, url)) {
|
|
739
|
+
this.announceCrossOriginDownload(url, credentialOrigin, headers, originUrl == null ? feedBaseUrl : null);
|
|
740
|
+
}
|
|
741
|
+
return HttpExecutor.removeCrossOriginSensitiveHeaders(headers, credentialOrigin, url);
|
|
742
|
+
}
|
|
743
|
+
// Only names are logged (header names, query parameter names, origins), never values.
|
|
744
|
+
announceCrossOriginDownload(url, credentialOrigin, headers, feedBaseUrl) {
|
|
745
|
+
const docs = "https://www.electron.build/docs/migration/v27-breaking-changes#update-credentials-stay-on-the-feeds-origin";
|
|
746
|
+
const names = HttpExecutor.sensitiveHeaderNames(headers);
|
|
747
|
+
if (names.length !== 0 && !this.crossOriginHeadersWarned) {
|
|
748
|
+
this.crossOriginHeadersWarned = true;
|
|
749
|
+
this._logger.warn(`electron-updater 7 (electron-builder v27) sends the credential headers from requestHeaders / addAuthHeader only to the update feed's origin (${credentialOrigin.origin}): ` +
|
|
750
|
+
`${names.join(", ")} not sent to ${url.origin}, which is another origin. ` +
|
|
751
|
+
`If that server needs them, serve the update files from the feed origin or use pre-signed URLs. ${docs}`);
|
|
752
|
+
}
|
|
753
|
+
const feedQueryNames = feedBaseUrl == null ? [] : [...new Set(feedBaseUrl.searchParams.keys())];
|
|
754
|
+
if (feedQueryNames.length !== 0 && !this.crossOriginFeedQueryWarned) {
|
|
755
|
+
this.crossOriginFeedQueryWarned = true;
|
|
756
|
+
this._logger.warn(`electron-updater 7 (electron-builder v27) adds the feed URL's query string (${feedQueryNames.join(", ")}) only to URLs on the update feed's origin (${feedBaseUrl.origin}): ` +
|
|
757
|
+
`not added to the download from ${url.origin}, which keeps its own query string. ` +
|
|
758
|
+
`If that server needs it, serve the update files from the feed origin or use pre-signed URLs. ${docs}`);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
// Credential headers are only sent where the provider says (Provider.feedBaseUrl); a provider that does not say is a configuration error.
|
|
762
|
+
static checkFeedBaseUrlDeclared(provider, headers) {
|
|
763
|
+
if (provider.feedBaseUrl !== undefined) {
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
const names = HttpExecutor.sensitiveHeaderNames(headers);
|
|
767
|
+
if (names.length !== 0) {
|
|
768
|
+
throw newError(`The custom update provider ${provider.constructor.name} does not declare feedBaseUrl, but its downloads would send the credential headers ${names.join(", ")} ` +
|
|
769
|
+
`(from requestHeaders, addAuthHeader or fileExtraDownloadHeaders). Override Provider.feedBaseUrl to return the feed URL ` +
|
|
770
|
+
`(the headers are then only sent to its origin), or null to send the request headers to every origin. ` +
|
|
771
|
+
`https://www.electron.build/docs/migration/v27-breaking-changes#update-credentials-stay-on-the-feeds-origin`, "ERR_UPDATER_FEED_BASE_URL_NOT_DECLARED");
|
|
772
|
+
}
|
|
773
|
+
}
|
|
668
774
|
async getOrCreateStagingUserId() {
|
|
669
775
|
const file = path.join(this.app.userDataPath, ".updaterId");
|
|
670
776
|
try {
|
|
@@ -729,7 +835,7 @@ export class AppUpdater extends EventEmitter {
|
|
|
729
835
|
this._logger.warn("Update artifact is validated with a SHA-256 (sha2) checksum only. SHA-256 update checksums are deprecated; electron-builder v28 will require SHA-512 and reject SHA-256-only update metadata (fail-closed). Regenerate latest*.yml with a current electron-builder and avoid pinning electronUpdaterCompatibility to a legacy (<2.15 / 1.x) range.");
|
|
730
836
|
}
|
|
731
837
|
const downloadOptions = {
|
|
732
|
-
headers: taskOptions.downloadUpdateOptions
|
|
838
|
+
headers: this.downloadRequestHeaders(fileInfo.url, taskOptions.downloadUpdateOptions),
|
|
733
839
|
cancellationToken: taskOptions.downloadUpdateOptions.cancellationToken,
|
|
734
840
|
sha2: fileInfo.info.sha2,
|
|
735
841
|
sha512: fileInfo.info.sha512,
|
|
@@ -740,22 +846,10 @@ export class AppUpdater extends EventEmitter {
|
|
|
740
846
|
const updateInfo = taskOptions.downloadUpdateOptions.updateInfoAndProvider.info;
|
|
741
847
|
const version = updateInfo.version;
|
|
742
848
|
const packageInfo = fileInfo.packageInfo;
|
|
743
|
-
function getCacheUpdateFileName() {
|
|
744
|
-
// NodeJS URL doesn't decode automatically
|
|
745
|
-
const urlPath = decodeURIComponent(taskOptions.fileInfo.url.pathname);
|
|
746
|
-
if (urlPath.toLowerCase().endsWith(`.${taskOptions.fileExtension.toLowerCase()}`)) {
|
|
747
|
-
return path.basename(urlPath);
|
|
748
|
-
}
|
|
749
|
-
else {
|
|
750
|
-
// url like /latest — use basename so a server-supplied path like "../../etc/evil"
|
|
751
|
-
// cannot escape the cache directory via path.join
|
|
752
|
-
return path.basename(taskOptions.fileInfo.info.url);
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
849
|
const downloadedUpdateHelper = await this.getOrCreateDownloadHelper();
|
|
756
850
|
const cacheDir = downloadedUpdateHelper.cacheDirForPendingUpdate;
|
|
757
851
|
await fsExtra.mkdir(cacheDir, { recursive: true });
|
|
758
|
-
const updateFileName = getCacheUpdateFileName();
|
|
852
|
+
const updateFileName = getCacheUpdateFileName(taskOptions.fileInfo, taskOptions.fileExtension);
|
|
759
853
|
let updateFile = path.join(cacheDir, updateFileName);
|
|
760
854
|
const packageFile = packageInfo == null ? null : path.join(cacheDir, `package-${version}${path.extname(packageInfo.path) || ".7z"}`);
|
|
761
855
|
const pendingBlockMapFile = path.join(cacheDir, "current.blockmap");
|
|
@@ -780,11 +874,7 @@ export class AppUpdater extends EventEmitter {
|
|
|
780
874
|
return withLegacyArrayCompat(packageFile == null ? { updateFile } : { updateFile, packageFile }, this._logger);
|
|
781
875
|
};
|
|
782
876
|
const log = this._logger;
|
|
783
|
-
const
|
|
784
|
-
if (cachedUpdateFile != null) {
|
|
785
|
-
updateFile = cachedUpdateFile;
|
|
786
|
-
return await done(false);
|
|
787
|
-
}
|
|
877
|
+
const cancellationToken = taskOptions.downloadUpdateOptions.cancellationToken;
|
|
788
878
|
const removeFileIfAny = async () => {
|
|
789
879
|
await downloadedUpdateHelper.clear().catch(() => {
|
|
790
880
|
// ignore
|
|
@@ -793,6 +883,35 @@ export class AppUpdater extends EventEmitter {
|
|
|
793
883
|
// ignore
|
|
794
884
|
});
|
|
795
885
|
};
|
|
886
|
+
const verifyUpdateFile = async (fileToVerify) => {
|
|
887
|
+
const failure = verificationFailureMessage(await this.verifyUpdateFile({
|
|
888
|
+
updateFilePath: fileToVerify,
|
|
889
|
+
originalUpdateFileName: updateFileName,
|
|
890
|
+
// only offered when the companion package was actually written: `packageFile` is derived from the update
|
|
891
|
+
// metadata, so it is non-null for any channel file carrying a `packages` block even on targets that never
|
|
892
|
+
// download one
|
|
893
|
+
packageFilePath: packageFile != null && (await fsExtra.pathExists(packageFile)) ? packageFile : undefined,
|
|
894
|
+
cancellationToken,
|
|
895
|
+
}));
|
|
896
|
+
if (failure != null) {
|
|
897
|
+
throw newError(`Downloaded update file ${updateFileName} failed verification: ${failure}`, "ERR_UPDATER_INVALID_UPDATE_FILE");
|
|
898
|
+
}
|
|
899
|
+
};
|
|
900
|
+
const cachedUpdateFile = await downloadedUpdateHelper.validateDownloadedPath(updateFile, updateInfo, fileInfo, log);
|
|
901
|
+
if (cachedUpdateFile != null) {
|
|
902
|
+
updateFile = cachedUpdateFile;
|
|
903
|
+
// an update downloaded by an earlier session is about to be announced as ready to install without being
|
|
904
|
+
// downloaded again, so the custom verifier has to gate it here too — its only other gate is the sha512 taken
|
|
905
|
+
// from the very update metadata a custom verifier exists to distrust
|
|
906
|
+
try {
|
|
907
|
+
await verifyUpdateFile(updateFile);
|
|
908
|
+
}
|
|
909
|
+
catch (e) {
|
|
910
|
+
await removeFileIfAny();
|
|
911
|
+
throw e;
|
|
912
|
+
}
|
|
913
|
+
return await done(false);
|
|
914
|
+
}
|
|
796
915
|
// a fresh download starts — drop any blockmap left over from a previous update round, so that when this round
|
|
797
916
|
// does not produce a new one (e.g. the differential download is skipped), the leftover cannot be promoted to the
|
|
798
917
|
// cache next to a file it does not describe
|
|
@@ -800,6 +919,18 @@ export class AppUpdater extends EventEmitter {
|
|
|
800
919
|
const tempUpdateFile = await createTempUpdateFile(`temp-${updateFileName}`, cacheDir, log);
|
|
801
920
|
try {
|
|
802
921
|
await taskOptions.task(tempUpdateFile, downloadOptions, packageFile, removeFileIfAny);
|
|
922
|
+
// checked before verifying as well as after: verification can be arbitrarily expensive (hashing a large
|
|
923
|
+
// installer, a remote attestation call), and there is no point paying for it on a download already cancelled
|
|
924
|
+
if (cancellationToken.cancelled) {
|
|
925
|
+
throw new CancellationError();
|
|
926
|
+
}
|
|
927
|
+
await verifyUpdateFile(tempUpdateFile);
|
|
928
|
+
if (cancellationToken.cancelled) {
|
|
929
|
+
throw new CancellationError();
|
|
930
|
+
}
|
|
931
|
+
// only now may the file be made executable — doing it inside `task` would leave an unverified binary
|
|
932
|
+
// executable under a predictable path for as long as verification takes
|
|
933
|
+
await taskOptions.afterVerification?.(tempUpdateFile);
|
|
803
934
|
await retry(() => fsExtra.rename(tempUpdateFile, updateFile), {
|
|
804
935
|
retries: 60,
|
|
805
936
|
interval: 500,
|
|
@@ -835,11 +966,24 @@ export class AppUpdater extends EventEmitter {
|
|
|
835
966
|
return true;
|
|
836
967
|
}
|
|
837
968
|
const provider = downloadUpdateOptions.updateInfoAndProvider.provider;
|
|
838
|
-
const
|
|
839
|
-
|
|
840
|
-
|
|
969
|
+
const override = this.previousBlockmapBaseUrlOverride;
|
|
970
|
+
const getBlockMapFiles = () => provider.getBlockMapFiles(fileInfo.url, this.app.version, downloadUpdateOptions.updateInfoAndProvider.info.version, override);
|
|
971
|
+
let oldBlockMapUrl;
|
|
972
|
+
let newBlockMapUrl;
|
|
973
|
+
if (fileInfo.blockMapUrl == null) {
|
|
974
|
+
;
|
|
975
|
+
[oldBlockMapUrl, newBlockMapUrl] = await getBlockMapFiles();
|
|
976
|
+
}
|
|
977
|
+
else {
|
|
978
|
+
// The update manifest names the new blockmap (e.g. separately pre-signed), so a URL derived from the new file's URL is not
|
|
979
|
+
// valid for the old one: the old blockmap comes from the cache, else from previousBlockmapBaseUrlOverride.
|
|
980
|
+
newBlockMapUrl = fileInfo.blockMapUrl;
|
|
981
|
+
oldBlockMapUrl = override ? (await getBlockMapFiles())[0] : null;
|
|
982
|
+
}
|
|
983
|
+
this._logger.info(`Download block maps (old: "${oldBlockMapUrl ?? "cache only"}", new: ${newBlockMapUrl})`);
|
|
984
|
+
const downloadBlockMap = async (url, originUrl) => {
|
|
841
985
|
const data = await this.httpExecutor.downloadToBuffer(url, {
|
|
842
|
-
headers:
|
|
986
|
+
headers: this.downloadRequestHeaders(url, downloadUpdateOptions, originUrl),
|
|
843
987
|
cancellationToken: downloadUpdateOptions.cancellationToken,
|
|
844
988
|
});
|
|
845
989
|
if (data == null || data.length === 0) {
|
|
@@ -858,7 +1002,7 @@ export class AppUpdater extends EventEmitter {
|
|
|
858
1002
|
logger: this._logger,
|
|
859
1003
|
newFile: installerPath,
|
|
860
1004
|
isUseMultipleRangeRequest: provider.isUseMultipleRangeRequest,
|
|
861
|
-
requestHeaders:
|
|
1005
|
+
requestHeaders: this.downloadRequestHeaders(fileInfo.url, downloadUpdateOptions),
|
|
862
1006
|
cancellationToken: downloadUpdateOptions.cancellationToken,
|
|
863
1007
|
};
|
|
864
1008
|
if (this.listenerCount(DOWNLOAD_PROGRESS) > 0) {
|
|
@@ -880,14 +1024,21 @@ export class AppUpdater extends EventEmitter {
|
|
|
880
1024
|
}
|
|
881
1025
|
return null;
|
|
882
1026
|
};
|
|
883
|
-
const newBlockMapData = await downloadBlockMap(
|
|
1027
|
+
const newBlockMapData = await downloadBlockMap(newBlockMapUrl);
|
|
884
1028
|
await saveBlockMapToCacheDir(newBlockMapData, this.downloadedUpdateHelper.cacheDirForPendingUpdate);
|
|
885
1029
|
// get old blockmap from cache dir first, if not found, download it
|
|
886
1030
|
let oldBlockMapData = await getBlockMapFromCacheDir(this.downloadedUpdateHelper.cacheDir);
|
|
887
1031
|
isOldBlockMapFromCache = oldBlockMapData != null;
|
|
888
1032
|
if (oldBlockMapData == null) {
|
|
889
|
-
|
|
890
|
-
|
|
1033
|
+
if (oldBlockMapUrl == null) {
|
|
1034
|
+
// the full download caches the new blockmap downloaded above, so the next update can be differential
|
|
1035
|
+
this._logger.info("No cached blockmap for the old installer, and the update manifest sets blockMapUrl, so the old blockmap URL cannot be derived " +
|
|
1036
|
+
"(set previousBlockmapBaseUrlOverride to download it): downloading the full update");
|
|
1037
|
+
return true;
|
|
1038
|
+
}
|
|
1039
|
+
this._logger.info(`No cached blockmap for the old installer, downloading it from "${oldBlockMapUrl}"`);
|
|
1040
|
+
// the old blockmap comes from previousBlockmapBaseUrlOverride when the app sets it, so that origin gets the credentials
|
|
1041
|
+
oldBlockMapData = await downloadBlockMap(oldBlockMapUrl, override ? new URL(override) : undefined);
|
|
891
1042
|
}
|
|
892
1043
|
await new GenericDifferentialDownloader(fileInfo.info, this.httpExecutor, downloadOptions).download(oldBlockMapData, newBlockMapData);
|
|
893
1044
|
return false;
|
|
@@ -905,6 +1056,18 @@ export class AppUpdater extends EventEmitter {
|
|
|
905
1056
|
}
|
|
906
1057
|
}
|
|
907
1058
|
}
|
|
1059
|
+
/** @internal */
|
|
1060
|
+
export function getCacheUpdateFileName(fileInfo, fileExtension) {
|
|
1061
|
+
// NodeJS URL doesn't decode automatically
|
|
1062
|
+
const urlPath = decodeURIComponent(fileInfo.url.pathname);
|
|
1063
|
+
const fileName = path.basename(urlPath.toLowerCase().endsWith(`.${fileExtension.toLowerCase()}`) ? urlPath : fileInfo.info.url);
|
|
1064
|
+
// basename(".") and basename("..") remain traversal segments. Reject them explicitly,
|
|
1065
|
+
// along with values that cannot be represented as a single portable filename.
|
|
1066
|
+
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.includes("\0") || fileName.includes("/") || fileName.includes("\\")) {
|
|
1067
|
+
throw newError(`Invalid update file name: ${JSON.stringify(fileName)}`, "ERR_UPDATER_INVALID_FILE_NAME");
|
|
1068
|
+
}
|
|
1069
|
+
return fileName;
|
|
1070
|
+
}
|
|
908
1071
|
function hasPrereleaseComponents(version) {
|
|
909
1072
|
const versionPrereleaseComponent = getVersionPreleaseComponents(version);
|
|
910
1073
|
return versionPrereleaseComponent != null && versionPrereleaseComponent.length > 0;
|