electron-updater 6.3.2 → 6.3.4
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/out/BaseUpdater.js +8 -1
- package/out/BaseUpdater.js.map +1 -1
- package/out/differentialDownloader/DifferentialDownloader.js +5 -1
- package/out/differentialDownloader/DifferentialDownloader.js.map +1 -1
- package/out/providers/GitHubProvider.d.ts +1 -0
- package/out/providers/GitHubProvider.js +9 -2
- package/out/providers/GitHubProvider.js.map +1 -1
- package/out/windowsExecutableCodeSignatureVerifier.js +3 -1
- package/out/windowsExecutableCodeSignatureVerifier.js.map +1 -1
- package/package.json +2 -2
package/out/BaseUpdater.js
CHANGED
|
@@ -41,7 +41,14 @@ class BaseUpdater extends AppUpdater_1.AppUpdater {
|
|
|
41
41
|
return false;
|
|
42
42
|
}
|
|
43
43
|
const downloadedUpdateHelper = this.downloadedUpdateHelper;
|
|
44
|
-
|
|
44
|
+
// Get the installer path, ensuring spaces are escaped on Linux
|
|
45
|
+
// 1. Check if downloadedUpdateHelper is not null
|
|
46
|
+
// 2. Check if downloadedUpdateHelper.file is not null
|
|
47
|
+
// 3. If both checks pass:
|
|
48
|
+
// a. If the platform is Linux, replace spaces with '\ ' for shell compatibility
|
|
49
|
+
// b. If the platform is not Linux, use the original path
|
|
50
|
+
// 4. If any check fails, set installerPath to null
|
|
51
|
+
const installerPath = downloadedUpdateHelper && downloadedUpdateHelper.file ? (process.platform === "linux" ? downloadedUpdateHelper.file.replace(/ /g, "\\ ") : downloadedUpdateHelper.file) : null;
|
|
45
52
|
const downloadedFileInfo = downloadedUpdateHelper == null ? null : downloadedUpdateHelper.downloadedFileInfo;
|
|
46
53
|
if (installerPath == null || downloadedFileInfo == null) {
|
|
47
54
|
this.dispatchError(new Error("No valid update available, can't quit and install"));
|
package/out/BaseUpdater.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseUpdater.js","sourceRoot":"","sources":["../src/BaseUpdater.ts"],"names":[],"mappings":"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","sourcesContent":["import { AllPublishOptions } from \"builder-util-runtime\"\nimport { spawn, SpawnOptions, spawnSync, StdioOptions } from \"child_process\"\nimport { AppAdapter } from \"./AppAdapter\"\nimport { AppUpdater, DownloadExecutorTask } from \"./AppUpdater\"\n\nexport abstract class BaseUpdater extends AppUpdater {\n protected quitAndInstallCalled = false\n private quitHandlerAdded = false\n\n protected constructor(options?: AllPublishOptions | null, app?: AppAdapter) {\n super(options, app)\n }\n\n quitAndInstall(isSilent = false, isForceRunAfter = false): void {\n this._logger.info(`Install on explicit quitAndInstall`)\n // If NOT in silent mode use `autoRunAppAfterInstall` to determine whether to force run the app\n const isInstalled = this.install(isSilent, isSilent ? isForceRunAfter : this.autoRunAppAfterInstall)\n if (isInstalled) {\n setImmediate(() => {\n // this event is normally emitted when calling quitAndInstall, this emulates that\n require(\"electron\").autoUpdater.emit(\"before-quit-for-update\")\n this.app.quit()\n })\n } else {\n this.quitAndInstallCalled = false\n }\n }\n\n protected executeDownload(taskOptions: DownloadExecutorTask): Promise<Array<string>> {\n return super.executeDownload({\n ...taskOptions,\n done: event => {\n this.dispatchUpdateDownloaded(event)\n this.addQuitHandler()\n return Promise.resolve()\n },\n })\n }\n\n // must be sync\n protected abstract doInstall(options: InstallOptions): boolean\n\n // must be sync (because quit even handler is not async)\n install(isSilent = false, isForceRunAfter = false): boolean {\n if (this.quitAndInstallCalled) {\n this._logger.warn(\"install call ignored: quitAndInstallCalled is set to true\")\n return false\n }\n\n const downloadedUpdateHelper = this.downloadedUpdateHelper\n const installerPath = downloadedUpdateHelper == null ? null : downloadedUpdateHelper.file\n const downloadedFileInfo = downloadedUpdateHelper == null ? null : downloadedUpdateHelper.downloadedFileInfo\n if (installerPath == null || downloadedFileInfo == null) {\n this.dispatchError(new Error(\"No valid update available, can't quit and install\"))\n return false\n }\n\n // prevent calling several times\n this.quitAndInstallCalled = true\n\n try {\n this._logger.info(`Install: isSilent: ${isSilent}, isForceRunAfter: ${isForceRunAfter}`)\n return this.doInstall({\n installerPath,\n isSilent,\n isForceRunAfter,\n isAdminRightsRequired: downloadedFileInfo.isAdminRightsRequired,\n })\n } catch (e: any) {\n this.dispatchError(e)\n return false\n }\n }\n\n protected addQuitHandler(): void {\n if (this.quitHandlerAdded || !this.autoInstallOnAppQuit) {\n return\n }\n\n this.quitHandlerAdded = true\n\n this.app.onQuit(exitCode => {\n if (this.quitAndInstallCalled) {\n this._logger.info(\"Update installer has already been triggered. Quitting application.\")\n return\n }\n\n if (!this.autoInstallOnAppQuit) {\n this._logger.info(\"Update will not be installed on quit because autoInstallOnAppQuit is set to false.\")\n return\n }\n\n if (exitCode !== 0) {\n this._logger.info(`Update will be not installed on quit because application is quitting with exit code ${exitCode}`)\n return\n }\n\n this._logger.info(\"Auto install update on quit\")\n this.install(true, false)\n })\n }\n\n protected wrapSudo() {\n const { name } = this.app\n const installComment = `\"${name} would like to update\"`\n const sudo = this.spawnSyncLog(\"which gksudo || which kdesudo || which pkexec || which beesu\")\n const command = [sudo]\n if (/kdesudo/i.test(sudo)) {\n command.push(\"--comment\", installComment)\n command.push(\"-c\")\n } else if (/gksudo/i.test(sudo)) {\n command.push(\"--message\", installComment)\n } else if (/pkexec/i.test(sudo)) {\n command.push(\"--disable-internal-agent\")\n }\n return command.join(\" \")\n }\n\n protected spawnSyncLog(cmd: string, args: string[] = [], env = {}): string {\n this._logger.info(`Executing: ${cmd} with args: ${args}`)\n const response = spawnSync(cmd, args, {\n env: { ...process.env, ...env },\n encoding: \"utf-8\",\n shell: true,\n })\n return response.stdout.trim()\n }\n\n /**\n * This handles both node 8 and node 10 way of emitting error when spawning a process\n * - node 8: Throws the error\n * - node 10: Emit the error(Need to listen with on)\n */\n // https://github.com/electron-userland/electron-builder/issues/1129\n // Node 8 sends errors: https://nodejs.org/dist/latest-v8.x/docs/api/errors.html#errors_common_system_errors\n protected async spawnLog(cmd: string, args: string[] = [], env: any = undefined, stdio: StdioOptions = \"ignore\"): Promise<boolean> {\n this._logger.info(`Executing: ${cmd} with args: ${args}`)\n return new Promise<boolean>((resolve, reject) => {\n try {\n const params: SpawnOptions = { stdio, env, detached: true }\n const p = spawn(cmd, args, params)\n p.on(\"error\", error => {\n reject(error)\n })\n p.unref()\n if (p.pid !== undefined) {\n resolve(true)\n }\n } catch (error) {\n reject(error)\n }\n })\n }\n}\n\nexport interface InstallOptions {\n readonly installerPath: string\n readonly isSilent: boolean\n readonly isForceRunAfter: boolean\n readonly isAdminRightsRequired: boolean\n}\n"]}
|
|
1
|
+
{"version":3,"file":"BaseUpdater.js","sourceRoot":"","sources":["../src/BaseUpdater.ts"],"names":[],"mappings":"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","sourcesContent":["import { AllPublishOptions } from \"builder-util-runtime\"\nimport { spawn, SpawnOptions, spawnSync, StdioOptions } from \"child_process\"\nimport { AppAdapter } from \"./AppAdapter\"\nimport { AppUpdater, DownloadExecutorTask } from \"./AppUpdater\"\n\nexport abstract class BaseUpdater extends AppUpdater {\n protected quitAndInstallCalled = false\n private quitHandlerAdded = false\n\n protected constructor(options?: AllPublishOptions | null, app?: AppAdapter) {\n super(options, app)\n }\n\n quitAndInstall(isSilent = false, isForceRunAfter = false): void {\n this._logger.info(`Install on explicit quitAndInstall`)\n // If NOT in silent mode use `autoRunAppAfterInstall` to determine whether to force run the app\n const isInstalled = this.install(isSilent, isSilent ? isForceRunAfter : this.autoRunAppAfterInstall)\n if (isInstalled) {\n setImmediate(() => {\n // this event is normally emitted when calling quitAndInstall, this emulates that\n require(\"electron\").autoUpdater.emit(\"before-quit-for-update\")\n this.app.quit()\n })\n } else {\n this.quitAndInstallCalled = false\n }\n }\n\n protected executeDownload(taskOptions: DownloadExecutorTask): Promise<Array<string>> {\n return super.executeDownload({\n ...taskOptions,\n done: event => {\n this.dispatchUpdateDownloaded(event)\n this.addQuitHandler()\n return Promise.resolve()\n },\n })\n }\n\n // must be sync\n protected abstract doInstall(options: InstallOptions): boolean\n\n // must be sync (because quit even handler is not async)\n install(isSilent = false, isForceRunAfter = false): boolean {\n if (this.quitAndInstallCalled) {\n this._logger.warn(\"install call ignored: quitAndInstallCalled is set to true\")\n return false\n }\n\n const downloadedUpdateHelper = this.downloadedUpdateHelper\n\n // Get the installer path, ensuring spaces are escaped on Linux\n // 1. Check if downloadedUpdateHelper is not null\n // 2. Check if downloadedUpdateHelper.file is not null\n // 3. If both checks pass:\n // a. If the platform is Linux, replace spaces with '\\ ' for shell compatibility\n // b. If the platform is not Linux, use the original path\n // 4. If any check fails, set installerPath to null\n const installerPath =\n downloadedUpdateHelper && downloadedUpdateHelper.file ? (process.platform === \"linux\" ? downloadedUpdateHelper.file.replace(/ /g, \"\\\\ \") : downloadedUpdateHelper.file) : null\n\n const downloadedFileInfo = downloadedUpdateHelper == null ? null : downloadedUpdateHelper.downloadedFileInfo\n if (installerPath == null || downloadedFileInfo == null) {\n this.dispatchError(new Error(\"No valid update available, can't quit and install\"))\n return false\n }\n\n // prevent calling several times\n this.quitAndInstallCalled = true\n\n try {\n this._logger.info(`Install: isSilent: ${isSilent}, isForceRunAfter: ${isForceRunAfter}`)\n return this.doInstall({\n installerPath,\n isSilent,\n isForceRunAfter,\n isAdminRightsRequired: downloadedFileInfo.isAdminRightsRequired,\n })\n } catch (e: any) {\n this.dispatchError(e)\n return false\n }\n }\n\n protected addQuitHandler(): void {\n if (this.quitHandlerAdded || !this.autoInstallOnAppQuit) {\n return\n }\n\n this.quitHandlerAdded = true\n\n this.app.onQuit(exitCode => {\n if (this.quitAndInstallCalled) {\n this._logger.info(\"Update installer has already been triggered. Quitting application.\")\n return\n }\n\n if (!this.autoInstallOnAppQuit) {\n this._logger.info(\"Update will not be installed on quit because autoInstallOnAppQuit is set to false.\")\n return\n }\n\n if (exitCode !== 0) {\n this._logger.info(`Update will be not installed on quit because application is quitting with exit code ${exitCode}`)\n return\n }\n\n this._logger.info(\"Auto install update on quit\")\n this.install(true, false)\n })\n }\n\n protected wrapSudo() {\n const { name } = this.app\n const installComment = `\"${name} would like to update\"`\n const sudo = this.spawnSyncLog(\"which gksudo || which kdesudo || which pkexec || which beesu\")\n const command = [sudo]\n if (/kdesudo/i.test(sudo)) {\n command.push(\"--comment\", installComment)\n command.push(\"-c\")\n } else if (/gksudo/i.test(sudo)) {\n command.push(\"--message\", installComment)\n } else if (/pkexec/i.test(sudo)) {\n command.push(\"--disable-internal-agent\")\n }\n return command.join(\" \")\n }\n\n protected spawnSyncLog(cmd: string, args: string[] = [], env = {}): string {\n this._logger.info(`Executing: ${cmd} with args: ${args}`)\n const response = spawnSync(cmd, args, {\n env: { ...process.env, ...env },\n encoding: \"utf-8\",\n shell: true,\n })\n return response.stdout.trim()\n }\n\n /**\n * This handles both node 8 and node 10 way of emitting error when spawning a process\n * - node 8: Throws the error\n * - node 10: Emit the error(Need to listen with on)\n */\n // https://github.com/electron-userland/electron-builder/issues/1129\n // Node 8 sends errors: https://nodejs.org/dist/latest-v8.x/docs/api/errors.html#errors_common_system_errors\n protected async spawnLog(cmd: string, args: string[] = [], env: any = undefined, stdio: StdioOptions = \"ignore\"): Promise<boolean> {\n this._logger.info(`Executing: ${cmd} with args: ${args}`)\n return new Promise<boolean>((resolve, reject) => {\n try {\n const params: SpawnOptions = { stdio, env, detached: true }\n const p = spawn(cmd, args, params)\n p.on(\"error\", error => {\n reject(error)\n })\n p.unref()\n if (p.pid !== undefined) {\n resolve(true)\n }\n } catch (error) {\n reject(error)\n }\n })\n }\n}\n\nexport interface InstallOptions {\n readonly installerPath: string\n readonly isSilent: boolean\n readonly isForceRunAfter: boolean\n readonly isAdminRightsRequired: boolean\n}\n"]}
|
|
@@ -189,7 +189,7 @@ class DifferentialDownloader {
|
|
|
189
189
|
}
|
|
190
190
|
const request = this.httpExecutor.createRequest(requestOptions, response => {
|
|
191
191
|
response.on("error", reject);
|
|
192
|
-
response.on("
|
|
192
|
+
response.on("aborted", () => {
|
|
193
193
|
reject(new Error("response has been aborted by the server"));
|
|
194
194
|
});
|
|
195
195
|
// Electron net handles redirects automatically, our NodeJS test server doesn't use redirects - so, we don't check 3xx codes.
|
|
@@ -245,6 +245,10 @@ class DifferentialDownloader {
|
|
|
245
245
|
if (!(0, multipleRangeDownloader_1.checkIsRangesSupported)(response, reject)) {
|
|
246
246
|
return;
|
|
247
247
|
}
|
|
248
|
+
response.on("error", reject);
|
|
249
|
+
response.on("aborted", () => {
|
|
250
|
+
reject(new Error("response has been aborted by the server"));
|
|
251
|
+
});
|
|
248
252
|
response.on("data", dataHandler);
|
|
249
253
|
response.on("end", () => resolve());
|
|
250
254
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DifferentialDownloader.js","sourceRoot":"","sources":["../../src/differentialDownloader/DifferentialDownloader.ts"],"names":[],"mappings":"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","sourcesContent":["import { BlockMapDataHolder, createHttpError, DigestTransform, HttpExecutor, configureRequestUrl, configureRequestOptions } from \"builder-util-runtime\"\nimport { BlockMap } from \"builder-util-runtime/out/blockMapApi\"\nimport { close, open } from \"fs-extra\"\nimport { createWriteStream } from \"fs\"\nimport { OutgoingHttpHeaders, RequestOptions } from \"http\"\nimport { ProgressInfo, CancellationToken } from \"builder-util-runtime\"\nimport { Logger } from \"../main\"\nimport { copyData } from \"./DataSplitter\"\nimport { URL } from \"url\"\nimport { computeOperations, Operation, OperationKind } from \"./downloadPlanBuilder\"\nimport { checkIsRangesSupported, executeTasksUsingMultipleRangeRequests } from \"./multipleRangeDownloader\"\nimport { ProgressDifferentialDownloadCallbackTransform, ProgressDifferentialDownloadInfo } from \"./ProgressDifferentialDownloadCallbackTransform\"\n\nexport interface DifferentialDownloaderOptions {\n readonly oldFile: string\n readonly newUrl: URL\n readonly logger: Logger\n readonly newFile: string\n\n readonly requestHeaders: OutgoingHttpHeaders | null\n\n readonly isUseMultipleRangeRequest?: boolean\n\n readonly cancellationToken: CancellationToken\n onProgress?: (progress: ProgressInfo) => void\n}\n\nexport abstract class DifferentialDownloader {\n fileMetadataBuffer: Buffer | null = null\n\n private readonly logger: Logger\n\n // noinspection TypeScriptAbstractClassConstructorCanBeMadeProtected\n constructor(\n protected readonly blockAwareFileInfo: BlockMapDataHolder,\n readonly httpExecutor: HttpExecutor<any>,\n readonly options: DifferentialDownloaderOptions\n ) {\n this.logger = options.logger\n }\n\n createRequestOptions(): RequestOptions {\n const result = {\n headers: {\n ...this.options.requestHeaders,\n accept: \"*/*\",\n },\n }\n configureRequestUrl(this.options.newUrl, result)\n // user-agent, cache-control and other common options\n configureRequestOptions(result)\n return result\n }\n\n protected doDownload(oldBlockMap: BlockMap, newBlockMap: BlockMap): Promise<any> {\n // we don't check other metadata like compressionMethod - generic check that it is make sense to differentially update is suitable for it\n if (oldBlockMap.version !== newBlockMap.version) {\n throw new Error(`version is different (${oldBlockMap.version} - ${newBlockMap.version}), full download is required`)\n }\n\n const logger = this.logger\n const operations = computeOperations(oldBlockMap, newBlockMap, logger)\n if (logger.debug != null) {\n logger.debug(JSON.stringify(operations, null, 2))\n }\n\n let downloadSize = 0\n let copySize = 0\n for (const operation of operations) {\n const length = operation.end - operation.start\n if (operation.kind === OperationKind.DOWNLOAD) {\n downloadSize += length\n } else {\n copySize += length\n }\n }\n\n const newSize = this.blockAwareFileInfo.size\n if (downloadSize + copySize + (this.fileMetadataBuffer == null ? 0 : this.fileMetadataBuffer.length) !== newSize) {\n throw new Error(`Internal error, size mismatch: downloadSize: ${downloadSize}, copySize: ${copySize}, newSize: ${newSize}`)\n }\n\n logger.info(`Full: ${formatBytes(newSize)}, To download: ${formatBytes(downloadSize)} (${Math.round(downloadSize / (newSize / 100))}%)`)\n\n return this.downloadFile(operations)\n }\n\n private downloadFile(tasks: Array<Operation>): Promise<any> {\n const fdList: Array<OpenedFile> = []\n const closeFiles = (): Promise<Array<void>> => {\n return Promise.all(\n fdList.map(openedFile => {\n return close(openedFile.descriptor).catch((e: any) => {\n this.logger.error(`cannot close file \"${openedFile.path}\": ${e}`)\n })\n })\n )\n }\n return this.doDownloadFile(tasks, fdList)\n .then(closeFiles)\n .catch((e: any) => {\n // then must be after catch here (since then always throws error)\n return closeFiles()\n .catch(closeFilesError => {\n // closeFiles never throw error, but just to be sure\n try {\n this.logger.error(`cannot close files: ${closeFilesError}`)\n } catch (errorOnLog) {\n try {\n console.error(errorOnLog)\n } catch (ignored) {\n // ok, give up and ignore error\n }\n }\n throw e\n })\n .then(() => {\n throw e\n })\n })\n }\n\n private async doDownloadFile(tasks: Array<Operation>, fdList: Array<OpenedFile>): Promise<any> {\n const oldFileFd = await open(this.options.oldFile, \"r\")\n fdList.push({ descriptor: oldFileFd, path: this.options.oldFile })\n const newFileFd = await open(this.options.newFile, \"w\")\n fdList.push({ descriptor: newFileFd, path: this.options.newFile })\n const fileOut = createWriteStream(this.options.newFile, { fd: newFileFd })\n await new Promise((resolve, reject) => {\n const streams: Array<any> = []\n\n // Create our download info transformer if we have one\n let downloadInfoTransform: ProgressDifferentialDownloadCallbackTransform | undefined = undefined\n if (!this.options.isUseMultipleRangeRequest && this.options.onProgress) {\n // TODO: Does not support multiple ranges (someone feel free to PR this!)\n const expectedByteCounts: Array<number> = []\n let grandTotalBytes = 0\n\n for (const task of tasks) {\n if (task.kind === OperationKind.DOWNLOAD) {\n expectedByteCounts.push(task.end - task.start)\n grandTotalBytes += task.end - task.start\n }\n }\n\n const progressDifferentialDownloadInfo: ProgressDifferentialDownloadInfo = {\n expectedByteCounts: expectedByteCounts,\n grandTotal: grandTotalBytes,\n }\n\n downloadInfoTransform = new ProgressDifferentialDownloadCallbackTransform(progressDifferentialDownloadInfo, this.options.cancellationToken, this.options.onProgress)\n streams.push(downloadInfoTransform)\n }\n\n const digestTransform = new DigestTransform(this.blockAwareFileInfo.sha512)\n // to simply debug, do manual validation to allow file to be fully written\n digestTransform.isValidateOnEnd = false\n streams.push(digestTransform)\n\n // noinspection JSArrowFunctionCanBeReplacedWithShorthand\n fileOut.on(\"finish\", () => {\n ;(fileOut.close as any)(() => {\n // remove from fd list because closed successfully\n fdList.splice(1, 1)\n try {\n digestTransform.validate()\n } catch (e: any) {\n reject(e)\n return\n }\n\n resolve(undefined)\n })\n })\n\n streams.push(fileOut)\n\n let lastStream = null\n for (const stream of streams) {\n stream.on(\"error\", reject)\n if (lastStream == null) {\n lastStream = stream\n } else {\n lastStream = lastStream.pipe(stream)\n }\n }\n\n const firstStream = streams[0]\n\n let w: any\n if (this.options.isUseMultipleRangeRequest) {\n w = executeTasksUsingMultipleRangeRequests(this, tasks, firstStream, oldFileFd, reject)\n w(0)\n return\n }\n\n let downloadOperationCount = 0\n let actualUrl: string | null = null\n this.logger.info(`Differential download: ${this.options.newUrl}`)\n\n const requestOptions = this.createRequestOptions()\n ;(requestOptions as any).redirect = \"manual\"\n\n w = (index: number): void => {\n if (index >= tasks.length) {\n if (this.fileMetadataBuffer != null) {\n firstStream.write(this.fileMetadataBuffer)\n }\n firstStream.end()\n return\n }\n\n const operation = tasks[index++]\n if (operation.kind === OperationKind.COPY) {\n // We are copying, let's not send status updates to the UI\n if (downloadInfoTransform) {\n downloadInfoTransform.beginFileCopy()\n }\n\n copyData(operation, firstStream, oldFileFd, reject, () => w(index))\n return\n }\n\n const range = `bytes=${operation.start}-${operation.end - 1}`\n requestOptions.headers!.range = range\n\n this.logger?.debug?.(`download range: ${range}`)\n\n // We are starting to download\n if (downloadInfoTransform) {\n downloadInfoTransform.beginRangeDownload()\n }\n\n const request = this.httpExecutor.createRequest(requestOptions, response => {\n response.on(\"error\", reject)\n response.on(\"abort\", () => {\n reject(new Error(\"response has been aborted by the server\"))\n })\n // Electron net handles redirects automatically, our NodeJS test server doesn't use redirects - so, we don't check 3xx codes.\n if (response.statusCode >= 400) {\n reject(createHttpError(response))\n }\n\n response.pipe(firstStream, {\n end: false,\n })\n response.once(\"end\", () => {\n // Pass on that we are downloading a segment\n if (downloadInfoTransform) {\n downloadInfoTransform.endRangeDownload()\n }\n\n if (++downloadOperationCount === 100) {\n downloadOperationCount = 0\n setTimeout(() => w(index), 1000)\n } else {\n w(index)\n }\n })\n })\n request.on(\"redirect\", (statusCode: number, method: string, redirectUrl: string) => {\n this.logger.info(`Redirect to ${removeQuery(redirectUrl)}`)\n actualUrl = redirectUrl\n configureRequestUrl(new URL(actualUrl), requestOptions)\n request.followRedirect()\n })\n this.httpExecutor.addErrorAndTimeoutHandlers(request, reject)\n request.end()\n }\n\n w(0)\n })\n }\n\n protected async readRemoteBytes(start: number, endInclusive: number): Promise<Buffer> {\n const buffer = Buffer.allocUnsafe(endInclusive + 1 - start)\n const requestOptions = this.createRequestOptions()\n requestOptions.headers!.range = `bytes=${start}-${endInclusive}`\n let position = 0\n await this.request(requestOptions, chunk => {\n chunk.copy(buffer, position)\n position += chunk.length\n })\n\n if (position !== buffer.length) {\n throw new Error(`Received data length ${position} is not equal to expected ${buffer.length}`)\n }\n return buffer\n }\n\n private request(requestOptions: RequestOptions, dataHandler: (chunk: Buffer) => void): Promise<void> {\n return new Promise((resolve, reject) => {\n const request = this.httpExecutor.createRequest(requestOptions, response => {\n if (!checkIsRangesSupported(response, reject)) {\n return\n }\n\n response.on(\"data\", dataHandler)\n response.on(\"end\", () => resolve())\n })\n this.httpExecutor.addErrorAndTimeoutHandlers(request, reject)\n request.end()\n })\n }\n}\n\nfunction formatBytes(value: number, symbol = \" KB\"): string {\n return new Intl.NumberFormat(\"en\").format((value / 1024).toFixed(2) as any) + symbol\n}\n\n// safety\nfunction removeQuery(url: string): string {\n const index = url.indexOf(\"?\")\n return index < 0 ? url : url.substring(0, index)\n}\n\ninterface OpenedFile {\n readonly descriptor: number\n readonly path: string\n}\n"]}
|
|
1
|
+
{"version":3,"file":"DifferentialDownloader.js","sourceRoot":"","sources":["../../src/differentialDownloader/DifferentialDownloader.ts"],"names":[],"mappings":"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","sourcesContent":["import { BlockMapDataHolder, createHttpError, DigestTransform, HttpExecutor, configureRequestUrl, configureRequestOptions } from \"builder-util-runtime\"\nimport { BlockMap } from \"builder-util-runtime/out/blockMapApi\"\nimport { close, open } from \"fs-extra\"\nimport { createWriteStream } from \"fs\"\nimport { OutgoingHttpHeaders, RequestOptions } from \"http\"\nimport { ProgressInfo, CancellationToken } from \"builder-util-runtime\"\nimport { Logger } from \"../main\"\nimport { copyData } from \"./DataSplitter\"\nimport { URL } from \"url\"\nimport { computeOperations, Operation, OperationKind } from \"./downloadPlanBuilder\"\nimport { checkIsRangesSupported, executeTasksUsingMultipleRangeRequests } from \"./multipleRangeDownloader\"\nimport { ProgressDifferentialDownloadCallbackTransform, ProgressDifferentialDownloadInfo } from \"./ProgressDifferentialDownloadCallbackTransform\"\n\nexport interface DifferentialDownloaderOptions {\n readonly oldFile: string\n readonly newUrl: URL\n readonly logger: Logger\n readonly newFile: string\n\n readonly requestHeaders: OutgoingHttpHeaders | null\n\n readonly isUseMultipleRangeRequest?: boolean\n\n readonly cancellationToken: CancellationToken\n onProgress?: (progress: ProgressInfo) => void\n}\n\nexport abstract class DifferentialDownloader {\n fileMetadataBuffer: Buffer | null = null\n\n private readonly logger: Logger\n\n // noinspection TypeScriptAbstractClassConstructorCanBeMadeProtected\n constructor(\n protected readonly blockAwareFileInfo: BlockMapDataHolder,\n readonly httpExecutor: HttpExecutor<any>,\n readonly options: DifferentialDownloaderOptions\n ) {\n this.logger = options.logger\n }\n\n createRequestOptions(): RequestOptions {\n const result = {\n headers: {\n ...this.options.requestHeaders,\n accept: \"*/*\",\n },\n }\n configureRequestUrl(this.options.newUrl, result)\n // user-agent, cache-control and other common options\n configureRequestOptions(result)\n return result\n }\n\n protected doDownload(oldBlockMap: BlockMap, newBlockMap: BlockMap): Promise<any> {\n // we don't check other metadata like compressionMethod - generic check that it is make sense to differentially update is suitable for it\n if (oldBlockMap.version !== newBlockMap.version) {\n throw new Error(`version is different (${oldBlockMap.version} - ${newBlockMap.version}), full download is required`)\n }\n\n const logger = this.logger\n const operations = computeOperations(oldBlockMap, newBlockMap, logger)\n if (logger.debug != null) {\n logger.debug(JSON.stringify(operations, null, 2))\n }\n\n let downloadSize = 0\n let copySize = 0\n for (const operation of operations) {\n const length = operation.end - operation.start\n if (operation.kind === OperationKind.DOWNLOAD) {\n downloadSize += length\n } else {\n copySize += length\n }\n }\n\n const newSize = this.blockAwareFileInfo.size\n if (downloadSize + copySize + (this.fileMetadataBuffer == null ? 0 : this.fileMetadataBuffer.length) !== newSize) {\n throw new Error(`Internal error, size mismatch: downloadSize: ${downloadSize}, copySize: ${copySize}, newSize: ${newSize}`)\n }\n\n logger.info(`Full: ${formatBytes(newSize)}, To download: ${formatBytes(downloadSize)} (${Math.round(downloadSize / (newSize / 100))}%)`)\n\n return this.downloadFile(operations)\n }\n\n private downloadFile(tasks: Array<Operation>): Promise<any> {\n const fdList: Array<OpenedFile> = []\n const closeFiles = (): Promise<Array<void>> => {\n return Promise.all(\n fdList.map(openedFile => {\n return close(openedFile.descriptor).catch((e: any) => {\n this.logger.error(`cannot close file \"${openedFile.path}\": ${e}`)\n })\n })\n )\n }\n return this.doDownloadFile(tasks, fdList)\n .then(closeFiles)\n .catch((e: any) => {\n // then must be after catch here (since then always throws error)\n return closeFiles()\n .catch(closeFilesError => {\n // closeFiles never throw error, but just to be sure\n try {\n this.logger.error(`cannot close files: ${closeFilesError}`)\n } catch (errorOnLog) {\n try {\n console.error(errorOnLog)\n } catch (ignored) {\n // ok, give up and ignore error\n }\n }\n throw e\n })\n .then(() => {\n throw e\n })\n })\n }\n\n private async doDownloadFile(tasks: Array<Operation>, fdList: Array<OpenedFile>): Promise<any> {\n const oldFileFd = await open(this.options.oldFile, \"r\")\n fdList.push({ descriptor: oldFileFd, path: this.options.oldFile })\n const newFileFd = await open(this.options.newFile, \"w\")\n fdList.push({ descriptor: newFileFd, path: this.options.newFile })\n const fileOut = createWriteStream(this.options.newFile, { fd: newFileFd })\n await new Promise((resolve, reject) => {\n const streams: Array<any> = []\n\n // Create our download info transformer if we have one\n let downloadInfoTransform: ProgressDifferentialDownloadCallbackTransform | undefined = undefined\n if (!this.options.isUseMultipleRangeRequest && this.options.onProgress) {\n // TODO: Does not support multiple ranges (someone feel free to PR this!)\n const expectedByteCounts: Array<number> = []\n let grandTotalBytes = 0\n\n for (const task of tasks) {\n if (task.kind === OperationKind.DOWNLOAD) {\n expectedByteCounts.push(task.end - task.start)\n grandTotalBytes += task.end - task.start\n }\n }\n\n const progressDifferentialDownloadInfo: ProgressDifferentialDownloadInfo = {\n expectedByteCounts: expectedByteCounts,\n grandTotal: grandTotalBytes,\n }\n\n downloadInfoTransform = new ProgressDifferentialDownloadCallbackTransform(progressDifferentialDownloadInfo, this.options.cancellationToken, this.options.onProgress)\n streams.push(downloadInfoTransform)\n }\n\n const digestTransform = new DigestTransform(this.blockAwareFileInfo.sha512)\n // to simply debug, do manual validation to allow file to be fully written\n digestTransform.isValidateOnEnd = false\n streams.push(digestTransform)\n\n // noinspection JSArrowFunctionCanBeReplacedWithShorthand\n fileOut.on(\"finish\", () => {\n ;(fileOut.close as any)(() => {\n // remove from fd list because closed successfully\n fdList.splice(1, 1)\n try {\n digestTransform.validate()\n } catch (e: any) {\n reject(e)\n return\n }\n\n resolve(undefined)\n })\n })\n\n streams.push(fileOut)\n\n let lastStream = null\n for (const stream of streams) {\n stream.on(\"error\", reject)\n if (lastStream == null) {\n lastStream = stream\n } else {\n lastStream = lastStream.pipe(stream)\n }\n }\n\n const firstStream = streams[0]\n\n let w: any\n if (this.options.isUseMultipleRangeRequest) {\n w = executeTasksUsingMultipleRangeRequests(this, tasks, firstStream, oldFileFd, reject)\n w(0)\n return\n }\n\n let downloadOperationCount = 0\n let actualUrl: string | null = null\n this.logger.info(`Differential download: ${this.options.newUrl}`)\n\n const requestOptions = this.createRequestOptions()\n ;(requestOptions as any).redirect = \"manual\"\n\n w = (index: number): void => {\n if (index >= tasks.length) {\n if (this.fileMetadataBuffer != null) {\n firstStream.write(this.fileMetadataBuffer)\n }\n firstStream.end()\n return\n }\n\n const operation = tasks[index++]\n if (operation.kind === OperationKind.COPY) {\n // We are copying, let's not send status updates to the UI\n if (downloadInfoTransform) {\n downloadInfoTransform.beginFileCopy()\n }\n\n copyData(operation, firstStream, oldFileFd, reject, () => w(index))\n return\n }\n\n const range = `bytes=${operation.start}-${operation.end - 1}`\n requestOptions.headers!.range = range\n\n this.logger?.debug?.(`download range: ${range}`)\n\n // We are starting to download\n if (downloadInfoTransform) {\n downloadInfoTransform.beginRangeDownload()\n }\n\n const request = this.httpExecutor.createRequest(requestOptions, response => {\n response.on(\"error\", reject)\n response.on(\"aborted\", () => {\n reject(new Error(\"response has been aborted by the server\"))\n })\n // Electron net handles redirects automatically, our NodeJS test server doesn't use redirects - so, we don't check 3xx codes.\n if (response.statusCode >= 400) {\n reject(createHttpError(response))\n }\n\n response.pipe(firstStream, {\n end: false,\n })\n response.once(\"end\", () => {\n // Pass on that we are downloading a segment\n if (downloadInfoTransform) {\n downloadInfoTransform.endRangeDownload()\n }\n\n if (++downloadOperationCount === 100) {\n downloadOperationCount = 0\n setTimeout(() => w(index), 1000)\n } else {\n w(index)\n }\n })\n })\n request.on(\"redirect\", (statusCode: number, method: string, redirectUrl: string) => {\n this.logger.info(`Redirect to ${removeQuery(redirectUrl)}`)\n actualUrl = redirectUrl\n configureRequestUrl(new URL(actualUrl), requestOptions)\n request.followRedirect()\n })\n this.httpExecutor.addErrorAndTimeoutHandlers(request, reject)\n request.end()\n }\n\n w(0)\n })\n }\n\n protected async readRemoteBytes(start: number, endInclusive: number): Promise<Buffer> {\n const buffer = Buffer.allocUnsafe(endInclusive + 1 - start)\n const requestOptions = this.createRequestOptions()\n requestOptions.headers!.range = `bytes=${start}-${endInclusive}`\n let position = 0\n await this.request(requestOptions, chunk => {\n chunk.copy(buffer, position)\n position += chunk.length\n })\n\n if (position !== buffer.length) {\n throw new Error(`Received data length ${position} is not equal to expected ${buffer.length}`)\n }\n return buffer\n }\n\n private request(requestOptions: RequestOptions, dataHandler: (chunk: Buffer) => void): Promise<void> {\n return new Promise((resolve, reject) => {\n const request = this.httpExecutor.createRequest(requestOptions, response => {\n if (!checkIsRangesSupported(response, reject)) {\n return\n }\n\n response.on(\"error\", reject)\n response.on(\"aborted\", () => {\n reject(new Error(\"response has been aborted by the server\"))\n })\n\n response.on(\"data\", dataHandler)\n response.on(\"end\", () => resolve())\n })\n this.httpExecutor.addErrorAndTimeoutHandlers(request, reject)\n request.end()\n })\n }\n}\n\nfunction formatBytes(value: number, symbol = \" KB\"): string {\n return new Intl.NumberFormat(\"en\").format((value / 1024).toFixed(2) as any) + symbol\n}\n\n// safety\nfunction removeQuery(url: string): string {\n const index = url.indexOf(\"?\")\n return index < 0 ? url : url.substring(0, index)\n}\n\ninterface OpenedFile {\n readonly descriptor: number\n readonly path: string\n}\n"]}
|
|
@@ -18,6 +18,7 @@ export declare class GitHubProvider extends BaseGitHubProvider<GithubUpdateInfo>
|
|
|
18
18
|
protected readonly options: GithubOptions;
|
|
19
19
|
private readonly updater;
|
|
20
20
|
constructor(options: GithubOptions, updater: AppUpdater, runtimeOptions: ProviderRuntimeOptions);
|
|
21
|
+
private get channel();
|
|
21
22
|
getLatestVersion(): Promise<GithubUpdateInfo>;
|
|
22
23
|
private getLatestTagName;
|
|
23
24
|
private get basePath();
|
|
@@ -33,8 +33,12 @@ class GitHubProvider extends BaseGitHubProvider {
|
|
|
33
33
|
this.options = options;
|
|
34
34
|
this.updater = updater;
|
|
35
35
|
}
|
|
36
|
+
get channel() {
|
|
37
|
+
const result = this.updater.channel || this.options.channel;
|
|
38
|
+
return result == null ? this.getDefaultChannelName() : this.getCustomChannelName(result);
|
|
39
|
+
}
|
|
36
40
|
async getLatestVersion() {
|
|
37
|
-
var _a, _b, _c, _d;
|
|
41
|
+
var _a, _b, _c, _d, _e;
|
|
38
42
|
const cancellationToken = new builder_util_runtime_1.CancellationToken();
|
|
39
43
|
const feedXml = (await this.httpRequest((0, util_1.newUrlFromBase)(`${this.basePath}.atom`, this.baseUrl), {
|
|
40
44
|
accept: "application/xml, application/atom+xml, text/xml, */*",
|
|
@@ -112,7 +116,10 @@ class GitHubProvider extends BaseGitHubProvider {
|
|
|
112
116
|
}
|
|
113
117
|
};
|
|
114
118
|
try {
|
|
115
|
-
|
|
119
|
+
let channel = this.channel;
|
|
120
|
+
if (this.updater.allowPrerelease && ((_d = semver.prerelease(tag)) === null || _d === void 0 ? void 0 : _d[0])) {
|
|
121
|
+
channel = this.getCustomChannelName(String((_e = semver.prerelease(tag)) === null || _e === void 0 ? void 0 : _e[0]));
|
|
122
|
+
}
|
|
116
123
|
rawData = await fetchData(channel);
|
|
117
124
|
}
|
|
118
125
|
catch (e) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GitHubProvider.js","sourceRoot":"","sources":["../../src/providers/GitHubProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import { CancellationToken, GithubOptions, githubUrl, HttpError, newError, parseXml, ReleaseNoteInfo, UpdateInfo, XElement } from \"builder-util-runtime\"\nimport * as semver from \"semver\"\nimport { URL } from \"url\"\nimport { AppUpdater } from \"../AppUpdater\"\nimport { ResolvedUpdateFileInfo } from \"../main\"\nimport { getChannelFilename, newBaseUrl, newUrlFromBase } from \"../util\"\nimport { parseUpdateInfo, Provider, ProviderRuntimeOptions, resolveFiles } from \"./Provider\"\n\nconst hrefRegExp = /\\/tag\\/([^/]+)$/\n\ninterface GithubUpdateInfo extends UpdateInfo {\n tag: string\n}\nexport abstract class BaseGitHubProvider<T extends UpdateInfo> extends Provider<T> {\n // so, we don't need to parse port (because node http doesn't support host as url does)\n protected readonly baseUrl: URL\n protected readonly baseApiUrl: URL\n\n protected constructor(\n protected readonly options: GithubOptions,\n defaultHost: string,\n runtimeOptions: ProviderRuntimeOptions\n ) {\n super({\n ...runtimeOptions,\n /* because GitHib uses S3 */\n isUseMultipleRangeRequest: false,\n })\n\n this.baseUrl = newBaseUrl(githubUrl(options, defaultHost))\n const apiHost = defaultHost === \"github.com\" ? \"api.github.com\" : defaultHost\n this.baseApiUrl = newBaseUrl(githubUrl(options, apiHost))\n }\n\n protected computeGithubBasePath(result: string): string {\n // https://github.com/electron-userland/electron-builder/issues/1903#issuecomment-320881211\n const host = this.options.host\n return host && ![\"github.com\", \"api.github.com\"].includes(host) ? `/api/v3${result}` : result\n }\n}\n\nexport class GitHubProvider extends BaseGitHubProvider<GithubUpdateInfo> {\n constructor(\n protected readonly options: GithubOptions,\n private readonly updater: AppUpdater,\n runtimeOptions: ProviderRuntimeOptions\n ) {\n super(options, \"github.com\", runtimeOptions)\n }\n\n async getLatestVersion(): Promise<GithubUpdateInfo> {\n const cancellationToken = new CancellationToken()\n\n const feedXml: string = (await this.httpRequest(\n newUrlFromBase(`${this.basePath}.atom`, this.baseUrl),\n {\n accept: \"application/xml, application/atom+xml, text/xml, */*\",\n },\n cancellationToken\n ))!\n\n const feed = parseXml(feedXml)\n // noinspection TypeScriptValidateJSTypes\n let latestRelease = feed.element(\"entry\", false, `No published versions on GitHub`)\n let tag: string | null = null\n try {\n if (this.updater.allowPrerelease) {\n const currentChannel = this.updater?.channel || (semver.prerelease(this.updater.currentVersion)?.[0] as string) || null\n\n if (currentChannel === null) {\n // noinspection TypeScriptValidateJSTypes\n tag = hrefRegExp.exec(latestRelease.element(\"link\").attribute(\"href\"))![1]\n } else {\n for (const element of feed.getElements(\"entry\")) {\n // noinspection TypeScriptValidateJSTypes\n const hrefElement = hrefRegExp.exec(element.element(\"link\").attribute(\"href\"))!\n\n // If this is null then something is wrong and skip this release\n if (hrefElement === null) continue\n\n // This Release's Tag\n const hrefTag = hrefElement[1]\n //Get Channel from this release's tag\n const hrefChannel = (semver.prerelease(hrefTag)?.[0] as string) || null\n\n const shouldFetchVersion = !currentChannel || [\"alpha\", \"beta\"].includes(currentChannel)\n const isCustomChannel = hrefChannel !== null && ![\"alpha\", \"beta\"].includes(String(hrefChannel))\n // Allow moving from alpha to beta but not down\n const channelMismatch = currentChannel === \"beta\" && hrefChannel === \"alpha\"\n\n if (shouldFetchVersion && !isCustomChannel && !channelMismatch) {\n tag = hrefTag\n break\n }\n\n const isNextPreRelease = hrefChannel && hrefChannel === currentChannel\n if (isNextPreRelease) {\n tag = hrefTag\n break\n }\n }\n }\n } else {\n tag = await this.getLatestTagName(cancellationToken)\n for (const element of feed.getElements(\"entry\")) {\n // noinspection TypeScriptValidateJSTypes\n if (hrefRegExp.exec(element.element(\"link\").attribute(\"href\"))![1] === tag) {\n latestRelease = element\n break\n }\n }\n }\n } catch (e: any) {\n throw newError(`Cannot parse releases feed: ${e.stack || e.message},\\nXML:\\n${feedXml}`, \"ERR_UPDATER_INVALID_RELEASE_FEED\")\n }\n\n if (tag == null) {\n throw newError(`No published versions on GitHub`, \"ERR_UPDATER_NO_PUBLISHED_VERSIONS\")\n }\n\n let rawData: string\n let channelFile = \"\"\n let channelFileUrl: any = \"\"\n const fetchData = async (channelName: string) => {\n channelFile = getChannelFilename(channelName)\n channelFileUrl = newUrlFromBase(this.getBaseDownloadPath(String(tag), channelFile), this.baseUrl)\n const requestOptions = this.createRequestOptions(channelFileUrl)\n try {\n return (await this.executor.request(requestOptions, cancellationToken))!\n } catch (e: any) {\n if (e instanceof HttpError && e.statusCode === 404) {\n throw newError(`Cannot find ${channelFile} in the latest release artifacts (${channelFileUrl}): ${e.stack || e.message}`, \"ERR_UPDATER_CHANNEL_FILE_NOT_FOUND\")\n }\n throw e\n }\n }\n\n try {\n const channel = this.updater.allowPrerelease ? this.getCustomChannelName(String(semver.prerelease(tag)?.[0] || \"latest\")) : this.getDefaultChannelName()\n rawData = await fetchData(channel)\n } catch (e: any) {\n if (this.updater.allowPrerelease) {\n // Allow fallback to `latest.yml`\n rawData = await fetchData(this.getDefaultChannelName())\n } else {\n throw e\n }\n }\n\n const result = parseUpdateInfo(rawData, channelFile, channelFileUrl)\n if (result.releaseName == null) {\n result.releaseName = latestRelease.elementValueOrEmpty(\"title\")\n }\n\n if (result.releaseNotes == null) {\n result.releaseNotes = computeReleaseNotes(this.updater.currentVersion, this.updater.fullChangelog, feed, latestRelease)\n }\n return {\n tag: tag,\n ...result,\n }\n }\n\n private async getLatestTagName(cancellationToken: CancellationToken): Promise<string | null> {\n const options = this.options\n // do not use API for GitHub to avoid limit, only for custom host or GitHub Enterprise\n const url =\n options.host == null || options.host === \"github.com\"\n ? newUrlFromBase(`${this.basePath}/latest`, this.baseUrl)\n : new URL(`${this.computeGithubBasePath(`/repos/${options.owner}/${options.repo}/releases`)}/latest`, this.baseApiUrl)\n try {\n const rawData = await this.httpRequest(url, { Accept: \"application/json\" }, cancellationToken)\n if (rawData == null) {\n return null\n }\n\n const releaseInfo: GithubReleaseInfo = JSON.parse(rawData)\n return releaseInfo.tag_name\n } catch (e: any) {\n throw newError(`Unable to find latest version on GitHub (${url}), please ensure a production release exists: ${e.stack || e.message}`, \"ERR_UPDATER_LATEST_VERSION_NOT_FOUND\")\n }\n }\n\n private get basePath(): string {\n return `/${this.options.owner}/${this.options.repo}/releases`\n }\n\n resolveFiles(updateInfo: GithubUpdateInfo): Array<ResolvedUpdateFileInfo> {\n // still replace space to - due to backward compatibility\n return resolveFiles(updateInfo, this.baseUrl, p => this.getBaseDownloadPath(updateInfo.tag, p.replace(/ /g, \"-\")))\n }\n\n private getBaseDownloadPath(tag: string, fileName: string): string {\n return `${this.basePath}/download/${tag}/${fileName}`\n }\n}\n\ninterface GithubReleaseInfo {\n readonly tag_name: string\n}\n\nfunction getNoteValue(parent: XElement): string {\n const result = parent.elementValueOrEmpty(\"content\")\n // GitHub reports empty notes as <content>No content.</content>\n return result === \"No content.\" ? \"\" : result\n}\n\nexport function computeReleaseNotes(currentVersion: semver.SemVer, isFullChangelog: boolean, feed: XElement, latestRelease: any): string | Array<ReleaseNoteInfo> | null {\n if (!isFullChangelog) {\n return getNoteValue(latestRelease)\n }\n\n const releaseNotes: Array<ReleaseNoteInfo> = []\n for (const release of feed.getElements(\"entry\")) {\n // noinspection TypeScriptValidateJSTypes\n const versionRelease = /\\/tag\\/v?([^/]+)$/.exec(release.element(\"link\").attribute(\"href\"))![1]\n if (semver.lt(currentVersion, versionRelease)) {\n releaseNotes.push({\n version: versionRelease,\n note: getNoteValue(release),\n })\n }\n }\n return releaseNotes.sort((a, b) => semver.rcompare(a.version, b.version))\n}\n"]}
|
|
1
|
+
{"version":3,"file":"GitHubProvider.js","sourceRoot":"","sources":["../../src/providers/GitHubProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import { CancellationToken, GithubOptions, githubUrl, HttpError, newError, parseXml, ReleaseNoteInfo, UpdateInfo, XElement } from \"builder-util-runtime\"\nimport * as semver from \"semver\"\nimport { URL } from \"url\"\nimport { AppUpdater } from \"../AppUpdater\"\nimport { ResolvedUpdateFileInfo } from \"../main\"\nimport { getChannelFilename, newBaseUrl, newUrlFromBase } from \"../util\"\nimport { parseUpdateInfo, Provider, ProviderRuntimeOptions, resolveFiles } from \"./Provider\"\n\nconst hrefRegExp = /\\/tag\\/([^/]+)$/\n\ninterface GithubUpdateInfo extends UpdateInfo {\n tag: string\n}\nexport abstract class BaseGitHubProvider<T extends UpdateInfo> extends Provider<T> {\n // so, we don't need to parse port (because node http doesn't support host as url does)\n protected readonly baseUrl: URL\n protected readonly baseApiUrl: URL\n\n protected constructor(\n protected readonly options: GithubOptions,\n defaultHost: string,\n runtimeOptions: ProviderRuntimeOptions\n ) {\n super({\n ...runtimeOptions,\n /* because GitHib uses S3 */\n isUseMultipleRangeRequest: false,\n })\n\n this.baseUrl = newBaseUrl(githubUrl(options, defaultHost))\n const apiHost = defaultHost === \"github.com\" ? \"api.github.com\" : defaultHost\n this.baseApiUrl = newBaseUrl(githubUrl(options, apiHost))\n }\n\n protected computeGithubBasePath(result: string): string {\n // https://github.com/electron-userland/electron-builder/issues/1903#issuecomment-320881211\n const host = this.options.host\n return host && ![\"github.com\", \"api.github.com\"].includes(host) ? `/api/v3${result}` : result\n }\n}\n\nexport class GitHubProvider extends BaseGitHubProvider<GithubUpdateInfo> {\n constructor(\n protected readonly options: GithubOptions,\n private readonly updater: AppUpdater,\n runtimeOptions: ProviderRuntimeOptions\n ) {\n super(options, \"github.com\", runtimeOptions)\n }\n\n private get channel(): string {\n const result = this.updater.channel || this.options.channel\n return result == null ? this.getDefaultChannelName() : this.getCustomChannelName(result)\n }\n\n async getLatestVersion(): Promise<GithubUpdateInfo> {\n const cancellationToken = new CancellationToken()\n\n const feedXml: string = (await this.httpRequest(\n newUrlFromBase(`${this.basePath}.atom`, this.baseUrl),\n {\n accept: \"application/xml, application/atom+xml, text/xml, */*\",\n },\n cancellationToken\n ))!\n\n const feed = parseXml(feedXml)\n // noinspection TypeScriptValidateJSTypes\n let latestRelease = feed.element(\"entry\", false, `No published versions on GitHub`)\n let tag: string | null = null\n try {\n if (this.updater.allowPrerelease) {\n const currentChannel = this.updater?.channel || (semver.prerelease(this.updater.currentVersion)?.[0] as string) || null\n\n if (currentChannel === null) {\n // noinspection TypeScriptValidateJSTypes\n tag = hrefRegExp.exec(latestRelease.element(\"link\").attribute(\"href\"))![1]\n } else {\n for (const element of feed.getElements(\"entry\")) {\n // noinspection TypeScriptValidateJSTypes\n const hrefElement = hrefRegExp.exec(element.element(\"link\").attribute(\"href\"))!\n\n // If this is null then something is wrong and skip this release\n if (hrefElement === null) continue\n\n // This Release's Tag\n const hrefTag = hrefElement[1]\n //Get Channel from this release's tag\n const hrefChannel = (semver.prerelease(hrefTag)?.[0] as string) || null\n\n const shouldFetchVersion = !currentChannel || [\"alpha\", \"beta\"].includes(currentChannel)\n const isCustomChannel = hrefChannel !== null && ![\"alpha\", \"beta\"].includes(String(hrefChannel))\n // Allow moving from alpha to beta but not down\n const channelMismatch = currentChannel === \"beta\" && hrefChannel === \"alpha\"\n\n if (shouldFetchVersion && !isCustomChannel && !channelMismatch) {\n tag = hrefTag\n break\n }\n\n const isNextPreRelease = hrefChannel && hrefChannel === currentChannel\n if (isNextPreRelease) {\n tag = hrefTag\n break\n }\n }\n }\n } else {\n tag = await this.getLatestTagName(cancellationToken)\n for (const element of feed.getElements(\"entry\")) {\n // noinspection TypeScriptValidateJSTypes\n if (hrefRegExp.exec(element.element(\"link\").attribute(\"href\"))![1] === tag) {\n latestRelease = element\n break\n }\n }\n }\n } catch (e: any) {\n throw newError(`Cannot parse releases feed: ${e.stack || e.message},\\nXML:\\n${feedXml}`, \"ERR_UPDATER_INVALID_RELEASE_FEED\")\n }\n\n if (tag == null) {\n throw newError(`No published versions on GitHub`, \"ERR_UPDATER_NO_PUBLISHED_VERSIONS\")\n }\n\n let rawData: string\n let channelFile = \"\"\n let channelFileUrl: any = \"\"\n const fetchData = async (channelName: string) => {\n channelFile = getChannelFilename(channelName)\n channelFileUrl = newUrlFromBase(this.getBaseDownloadPath(String(tag), channelFile), this.baseUrl)\n const requestOptions = this.createRequestOptions(channelFileUrl)\n try {\n return (await this.executor.request(requestOptions, cancellationToken))!\n } catch (e: any) {\n if (e instanceof HttpError && e.statusCode === 404) {\n throw newError(`Cannot find ${channelFile} in the latest release artifacts (${channelFileUrl}): ${e.stack || e.message}`, \"ERR_UPDATER_CHANNEL_FILE_NOT_FOUND\")\n }\n throw e\n }\n }\n\n try {\n let channel = this.channel\n if (this.updater.allowPrerelease && semver.prerelease(tag)?.[0]) {\n channel = this.getCustomChannelName(String(semver.prerelease(tag)?.[0]))\n }\n rawData = await fetchData(channel)\n } catch (e: any) {\n if (this.updater.allowPrerelease) {\n // Allow fallback to `latest.yml`\n rawData = await fetchData(this.getDefaultChannelName())\n } else {\n throw e\n }\n }\n\n const result = parseUpdateInfo(rawData, channelFile, channelFileUrl)\n if (result.releaseName == null) {\n result.releaseName = latestRelease.elementValueOrEmpty(\"title\")\n }\n\n if (result.releaseNotes == null) {\n result.releaseNotes = computeReleaseNotes(this.updater.currentVersion, this.updater.fullChangelog, feed, latestRelease)\n }\n return {\n tag: tag,\n ...result,\n }\n }\n\n private async getLatestTagName(cancellationToken: CancellationToken): Promise<string | null> {\n const options = this.options\n // do not use API for GitHub to avoid limit, only for custom host or GitHub Enterprise\n const url =\n options.host == null || options.host === \"github.com\"\n ? newUrlFromBase(`${this.basePath}/latest`, this.baseUrl)\n : new URL(`${this.computeGithubBasePath(`/repos/${options.owner}/${options.repo}/releases`)}/latest`, this.baseApiUrl)\n try {\n const rawData = await this.httpRequest(url, { Accept: \"application/json\" }, cancellationToken)\n if (rawData == null) {\n return null\n }\n\n const releaseInfo: GithubReleaseInfo = JSON.parse(rawData)\n return releaseInfo.tag_name\n } catch (e: any) {\n throw newError(`Unable to find latest version on GitHub (${url}), please ensure a production release exists: ${e.stack || e.message}`, \"ERR_UPDATER_LATEST_VERSION_NOT_FOUND\")\n }\n }\n\n private get basePath(): string {\n return `/${this.options.owner}/${this.options.repo}/releases`\n }\n\n resolveFiles(updateInfo: GithubUpdateInfo): Array<ResolvedUpdateFileInfo> {\n // still replace space to - due to backward compatibility\n return resolveFiles(updateInfo, this.baseUrl, p => this.getBaseDownloadPath(updateInfo.tag, p.replace(/ /g, \"-\")))\n }\n\n private getBaseDownloadPath(tag: string, fileName: string): string {\n return `${this.basePath}/download/${tag}/${fileName}`\n }\n}\n\ninterface GithubReleaseInfo {\n readonly tag_name: string\n}\n\nfunction getNoteValue(parent: XElement): string {\n const result = parent.elementValueOrEmpty(\"content\")\n // GitHub reports empty notes as <content>No content.</content>\n return result === \"No content.\" ? \"\" : result\n}\n\nexport function computeReleaseNotes(currentVersion: semver.SemVer, isFullChangelog: boolean, feed: XElement, latestRelease: any): string | Array<ReleaseNoteInfo> | null {\n if (!isFullChangelog) {\n return getNoteValue(latestRelease)\n }\n\n const releaseNotes: Array<ReleaseNoteInfo> = []\n for (const release of feed.getElements(\"entry\")) {\n // noinspection TypeScriptValidateJSTypes\n const versionRelease = /\\/tag\\/v?([^/]+)$/.exec(release.element(\"link\").attribute(\"href\"))![1]\n if (semver.lt(currentVersion, versionRelease)) {\n releaseNotes.push({\n version: versionRelease,\n note: getNoteValue(release),\n })\n }\n }\n return releaseNotes.sort((a, b) => semver.rcompare(a.version, b.version))\n}\n"]}
|
|
@@ -33,7 +33,9 @@ function verifySignature(publisherNames, unescapedTempUpdateFile, logger) {
|
|
|
33
33
|
// https://github.com/electron-userland/electron-builder/issues/2421
|
|
34
34
|
// https://github.com/electron-userland/electron-builder/issues/2535
|
|
35
35
|
// Resetting PSModulePath is necessary https://github.com/electron-userland/electron-builder/issues/7127
|
|
36
|
-
|
|
36
|
+
// semicolon wont terminate the set command and run chcp thus leading to verification errors on certificats with special chars like german umlauts, so rather
|
|
37
|
+
// join commands using & https://github.com/electron-userland/electron-builder/issues/8162
|
|
38
|
+
(0, child_process_1.execFile)(`set "PSModulePath=" & chcp 65001 >NUL & powershell.exe`, ["-NoProfile", "-NonInteractive", "-InputFormat", "None", "-Command", `"Get-AuthenticodeSignature -LiteralPath '${tempUpdateFile}' | ConvertTo-Json -Compress"`], {
|
|
37
39
|
shell: true,
|
|
38
40
|
timeout: 20 * 1000,
|
|
39
41
|
}, (error, stdout, stderr) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"windowsExecutableCodeSignatureVerifier.js","sourceRoot":"","sources":["../src/windowsExecutableCodeSignatureVerifier.ts"],"names":[],"mappings":"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","sourcesContent":["import { parseDn } from \"builder-util-runtime\"\nimport { execFile, execFileSync } from \"child_process\"\nimport * as os from \"os\"\nimport { Logger } from \"./main\"\nimport * as path from \"path\"\n\n// $certificateInfo = (Get-AuthenticodeSignature 'xxx\\yyy.exe'\n// | where {$_.Status.Equals([System.Management.Automation.SignatureStatus]::Valid) -and $_.SignerCertificate.Subject.Contains(\"CN=siemens.com\")})\n// | Out-String ; if ($certificateInfo) { exit 0 } else { exit 1 }\nexport function verifySignature(publisherNames: Array<string>, unescapedTempUpdateFile: string, logger: Logger): Promise<string | null> {\n return new Promise<string | null>((resolve, reject) => {\n // Escape quotes and backticks in filenames to prevent user from breaking the\n // arguments and perform a remote command injection.\n //\n // Consider example powershell command:\n // ```powershell\n // Get-AuthenticodeSignature 'C:\\\\path\\\\my-bad-';calc;'filename.exe'\n // ```\n // The above would work expected and find the file name, however, it will also execute `;calc;`\n // command and start the calculator app.\n //\n // From Powershell quoting rules:\n // https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules?view=powershell-7\n // * Double quotes `\"` are treated literally within single-quoted strings;\n // * Single quotes can be escaped by doubling them: 'don''t' -> don't;\n //\n // Also note that at this point the file has already been written to the disk, thus we are\n // guaranteed that the path will not contain any illegal characters like <>:\"/\\|?*\n // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file\n const tempUpdateFile = unescapedTempUpdateFile.replace(/'/g, \"''\")\n logger.info(`Verifying signature ${tempUpdateFile}`)\n\n // https://github.com/electron-userland/electron-builder/issues/2421\n // https://github.com/electron-userland/electron-builder/issues/2535\n // Resetting PSModulePath is necessary https://github.com/electron-userland/electron-builder/issues/7127\n execFile(\n `set \"PSModulePath=\"; chcp 65001 >NUL & powershell.exe`,\n [\"-NoProfile\", \"-NonInteractive\", \"-InputFormat\", \"None\", \"-Command\", `\"Get-AuthenticodeSignature -LiteralPath '${tempUpdateFile}' | ConvertTo-Json -Compress\"`],\n {\n shell: true,\n timeout: 20 * 1000,\n },\n (error, stdout, stderr) => {\n try {\n if (error != null || stderr) {\n handleError(logger, error, stderr, reject)\n resolve(null)\n return\n }\n const data = parseOut(stdout)\n if (data.Status === 0) {\n try {\n const normlaizedUpdateFilePath = path.normalize(data.Path)\n const normalizedTempUpdateFile = path.normalize(unescapedTempUpdateFile)\n logger.info(`LiteralPath: ${normlaizedUpdateFilePath}. Update Path: ${normalizedTempUpdateFile}`)\n if (normlaizedUpdateFilePath !== normalizedTempUpdateFile) {\n handleError(logger, new Error(`LiteralPath of ${normlaizedUpdateFilePath} is different than ${normalizedTempUpdateFile}`), stderr, reject)\n resolve(null)\n return\n }\n } catch (error: any) {\n logger.warn(`Unable to verify LiteralPath of update asset due to missing data.Path. Skipping this step of validation. Message: ${error.message ?? error.stack}`)\n }\n const subject = parseDn(data.SignerCertificate.Subject)\n let match = false\n for (const name of publisherNames) {\n const dn = parseDn(name)\n if (dn.size) {\n // if we have a full DN, compare all values\n const allKeys = Array.from(dn.keys())\n match = allKeys.every(key => {\n return dn.get(key) === subject.get(key)\n })\n } else if (name === subject.get(\"CN\")!) {\n logger.warn(`Signature validated using only CN ${name}. Please add your full Distinguished Name (DN) to publisherNames configuration`)\n match = true\n }\n if (match) {\n resolve(null)\n return\n }\n }\n }\n\n const result = `publisherNames: ${publisherNames.join(\" | \")}, raw info: ` + JSON.stringify(data, (name, value) => (name === \"RawData\" ? undefined : value), 2)\n logger.warn(`Sign verification failed, installer signed with incorrect certificate: ${result}`)\n resolve(result)\n } catch (e: any) {\n handleError(logger, e, null, reject)\n resolve(null)\n return\n }\n }\n )\n })\n}\n\nfunction parseOut(out: string): any {\n const data = JSON.parse(out)\n delete data.PrivateKey\n delete data.IsOSBinary\n delete data.SignatureType\n const signerCertificate = data.SignerCertificate\n if (signerCertificate != null) {\n delete signerCertificate.Archived\n delete signerCertificate.Extensions\n delete signerCertificate.Handle\n delete signerCertificate.HasPrivateKey\n // duplicates data.SignerCertificate (contains RawData)\n delete signerCertificate.SubjectName\n }\n return data\n}\n\nfunction handleError(logger: Logger, error: Error | null, stderr: string | null, reject: (reason: any) => void): void {\n if (isOldWin6()) {\n logger.warn(\n `Cannot execute Get-AuthenticodeSignature: ${error || stderr}. Ignoring signature validation due to unsupported powershell version. Please upgrade to powershell 3 or higher.`\n )\n return\n }\n\n try {\n execFileSync(\"powershell.exe\", [\"-NoProfile\", \"-NonInteractive\", \"-Command\", \"ConvertTo-Json test\"], { timeout: 10 * 1000 } as any)\n } catch (testError: any) {\n logger.warn(\n `Cannot execute ConvertTo-Json: ${testError.message}. Ignoring signature validation due to unsupported powershell version. Please upgrade to powershell 3 or higher.`\n )\n return\n }\n\n if (error != null) {\n reject(error)\n }\n\n if (stderr) {\n reject(new Error(`Cannot execute Get-AuthenticodeSignature, stderr: ${stderr}. Failing signature validation due to unknown stderr.`))\n }\n}\n\nfunction isOldWin6(): boolean {\n const winVersion = os.release()\n return winVersion.startsWith(\"6.\") && !winVersion.startsWith(\"6.3\")\n}\n"]}
|
|
1
|
+
{"version":3,"file":"windowsExecutableCodeSignatureVerifier.js","sourceRoot":"","sources":["../src/windowsExecutableCodeSignatureVerifier.ts"],"names":[],"mappings":"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","sourcesContent":["import { parseDn } from \"builder-util-runtime\"\nimport { execFile, execFileSync } from \"child_process\"\nimport * as os from \"os\"\nimport { Logger } from \"./main\"\nimport * as path from \"path\"\n\n// $certificateInfo = (Get-AuthenticodeSignature 'xxx\\yyy.exe'\n// | where {$_.Status.Equals([System.Management.Automation.SignatureStatus]::Valid) -and $_.SignerCertificate.Subject.Contains(\"CN=siemens.com\")})\n// | Out-String ; if ($certificateInfo) { exit 0 } else { exit 1 }\nexport function verifySignature(publisherNames: Array<string>, unescapedTempUpdateFile: string, logger: Logger): Promise<string | null> {\n return new Promise<string | null>((resolve, reject) => {\n // Escape quotes and backticks in filenames to prevent user from breaking the\n // arguments and perform a remote command injection.\n //\n // Consider example powershell command:\n // ```powershell\n // Get-AuthenticodeSignature 'C:\\\\path\\\\my-bad-';calc;'filename.exe'\n // ```\n // The above would work expected and find the file name, however, it will also execute `;calc;`\n // command and start the calculator app.\n //\n // From Powershell quoting rules:\n // https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules?view=powershell-7\n // * Double quotes `\"` are treated literally within single-quoted strings;\n // * Single quotes can be escaped by doubling them: 'don''t' -> don't;\n //\n // Also note that at this point the file has already been written to the disk, thus we are\n // guaranteed that the path will not contain any illegal characters like <>:\"/\\|?*\n // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file\n const tempUpdateFile = unescapedTempUpdateFile.replace(/'/g, \"''\")\n logger.info(`Verifying signature ${tempUpdateFile}`)\n\n // https://github.com/electron-userland/electron-builder/issues/2421\n // https://github.com/electron-userland/electron-builder/issues/2535\n // Resetting PSModulePath is necessary https://github.com/electron-userland/electron-builder/issues/7127\n // semicolon wont terminate the set command and run chcp thus leading to verification errors on certificats with special chars like german umlauts, so rather\n // join commands using & https://github.com/electron-userland/electron-builder/issues/8162\n execFile(\n `set \"PSModulePath=\" & chcp 65001 >NUL & powershell.exe`,\n [\"-NoProfile\", \"-NonInteractive\", \"-InputFormat\", \"None\", \"-Command\", `\"Get-AuthenticodeSignature -LiteralPath '${tempUpdateFile}' | ConvertTo-Json -Compress\"`],\n {\n shell: true,\n timeout: 20 * 1000,\n },\n (error, stdout, stderr) => {\n try {\n if (error != null || stderr) {\n handleError(logger, error, stderr, reject)\n resolve(null)\n return\n }\n const data = parseOut(stdout)\n if (data.Status === 0) {\n try {\n const normlaizedUpdateFilePath = path.normalize(data.Path)\n const normalizedTempUpdateFile = path.normalize(unescapedTempUpdateFile)\n logger.info(`LiteralPath: ${normlaizedUpdateFilePath}. Update Path: ${normalizedTempUpdateFile}`)\n if (normlaizedUpdateFilePath !== normalizedTempUpdateFile) {\n handleError(logger, new Error(`LiteralPath of ${normlaizedUpdateFilePath} is different than ${normalizedTempUpdateFile}`), stderr, reject)\n resolve(null)\n return\n }\n } catch (error: any) {\n logger.warn(`Unable to verify LiteralPath of update asset due to missing data.Path. Skipping this step of validation. Message: ${error.message ?? error.stack}`)\n }\n const subject = parseDn(data.SignerCertificate.Subject)\n let match = false\n for (const name of publisherNames) {\n const dn = parseDn(name)\n if (dn.size) {\n // if we have a full DN, compare all values\n const allKeys = Array.from(dn.keys())\n match = allKeys.every(key => {\n return dn.get(key) === subject.get(key)\n })\n } else if (name === subject.get(\"CN\")!) {\n logger.warn(`Signature validated using only CN ${name}. Please add your full Distinguished Name (DN) to publisherNames configuration`)\n match = true\n }\n if (match) {\n resolve(null)\n return\n }\n }\n }\n\n const result = `publisherNames: ${publisherNames.join(\" | \")}, raw info: ` + JSON.stringify(data, (name, value) => (name === \"RawData\" ? undefined : value), 2)\n logger.warn(`Sign verification failed, installer signed with incorrect certificate: ${result}`)\n resolve(result)\n } catch (e: any) {\n handleError(logger, e, null, reject)\n resolve(null)\n return\n }\n }\n )\n })\n}\n\nfunction parseOut(out: string): any {\n const data = JSON.parse(out)\n delete data.PrivateKey\n delete data.IsOSBinary\n delete data.SignatureType\n const signerCertificate = data.SignerCertificate\n if (signerCertificate != null) {\n delete signerCertificate.Archived\n delete signerCertificate.Extensions\n delete signerCertificate.Handle\n delete signerCertificate.HasPrivateKey\n // duplicates data.SignerCertificate (contains RawData)\n delete signerCertificate.SubjectName\n }\n return data\n}\n\nfunction handleError(logger: Logger, error: Error | null, stderr: string | null, reject: (reason: any) => void): void {\n if (isOldWin6()) {\n logger.warn(\n `Cannot execute Get-AuthenticodeSignature: ${error || stderr}. Ignoring signature validation due to unsupported powershell version. Please upgrade to powershell 3 or higher.`\n )\n return\n }\n\n try {\n execFileSync(\"powershell.exe\", [\"-NoProfile\", \"-NonInteractive\", \"-Command\", \"ConvertTo-Json test\"], { timeout: 10 * 1000 } as any)\n } catch (testError: any) {\n logger.warn(\n `Cannot execute ConvertTo-Json: ${testError.message}. Ignoring signature validation due to unsupported powershell version. Please upgrade to powershell 3 or higher.`\n )\n return\n }\n\n if (error != null) {\n reject(error)\n }\n\n if (stderr) {\n reject(new Error(`Cannot execute Get-AuthenticodeSignature, stderr: ${stderr}. Failing signature validation due to unknown stderr.`))\n }\n}\n\nfunction isOldWin6(): boolean {\n const winVersion = os.release()\n return winVersion.startsWith(\"6.\") && !winVersion.startsWith(\"6.3\")\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "electron-updater",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.4",
|
|
4
4
|
"description": "Cross platform updater for electron applications",
|
|
5
5
|
"main": "out/main.js",
|
|
6
6
|
"author": "Vladimir Krivosheev",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"lazy-val": "^1.0.5",
|
|
22
22
|
"lodash.escaperegexp": "^4.1.2",
|
|
23
23
|
"lodash.isequal": "^4.5.0",
|
|
24
|
-
"semver": "^7.3
|
|
24
|
+
"semver": "^7.6.3",
|
|
25
25
|
"tiny-typed-emitter": "^2.1.0",
|
|
26
26
|
"builder-util-runtime": "9.2.5"
|
|
27
27
|
},
|