electron-incremental-update 1.3.0 → 2.0.0-beta.10

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.
@@ -0,0 +1,78 @@
1
+ import { Promisable } from '@subframe7536/type-utils';
2
+ import { a as UpdateJSON, U as UpdateInfo } from './version-C4tF_trh.cjs';
3
+
4
+ type URLHandler = (url: URL, isDownloadAsar: boolean) => Promisable<URL | string | undefined | null>;
5
+ type OnDownloading = (progress: DownloadingInfo) => void;
6
+ interface DownloadingInfo {
7
+ /**
8
+ * Download buffer delta
9
+ */
10
+ delta: number;
11
+ /**
12
+ * Downloaded percent, 0 ~ 100
13
+ *
14
+ * If no `Content-Length` header, will be nagative
15
+ */
16
+ percent: number;
17
+ /**
18
+ * Total size
19
+ *
20
+ * If not `Content-Length` header, will be -1
21
+ */
22
+ total: number;
23
+ /**
24
+ * Downloaded size
25
+ */
26
+ transferred: number;
27
+ /**
28
+ * Download speed, bytes per second
29
+ */
30
+ bps: number;
31
+ }
32
+ interface IProvider {
33
+ /**
34
+ * Provider name
35
+ */
36
+ name: string;
37
+ /**
38
+ * Custom url handler
39
+ *
40
+ * for Github, there are some {@link https://github.com/XIU2/UserScript/blob/master/GithubEnhanced-High-Speed-Download.user.js#L34 public CDN links}
41
+ */
42
+ urlHandler?: URLHandler;
43
+ onDownloading?: OnDownloading;
44
+ /**
45
+ * Download update json
46
+ * @param versionPath parsed version path in project
47
+ */
48
+ downloadJSON: (versionPath: string) => Promise<UpdateJSON>;
49
+ /**
50
+ * Download update asar
51
+ * @param name app name
52
+ * @param updateInfo existing update info
53
+ * @param onDownloading hook for on downloading
54
+ */
55
+ downloadAsar: (name: string, updateInfo: UpdateInfo, onDownloading?: (info: DownloadingInfo) => void) => Promise<Buffer>;
56
+ /**
57
+ * Check the old version is less than new version
58
+ * @param oldVer old version string
59
+ * @param newVer new version string
60
+ */
61
+ isLowerVersion: (oldVer: string, newVer: string) => boolean;
62
+ /**
63
+ * Function to decompress file using brotli
64
+ * @param buffer compressed file buffer
65
+ */
66
+ unzipFile: (buffer: Buffer) => Promise<Buffer>;
67
+ /**
68
+ * Verify asar signature,
69
+ * if signature is valid, returns the version, otherwise returns `undefined`
70
+ * @param buffer file buffer
71
+ * @param version target version
72
+ * @param signature signature
73
+ * @param cert certificate
74
+ */
75
+ verifySignaure: (buffer: Buffer, version: string, signature: string, cert: string) => Promisable<boolean>;
76
+ }
77
+
78
+ export type { DownloadingInfo as D, IProvider as I, OnDownloading as O, URLHandler as U };
package/dist/utils.cjs CHANGED
@@ -1,225 +1,122 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
1
+ 'use strict';
19
2
 
20
- // src/utils/index.ts
21
- var utils_exports = {};
22
- __export(utils_exports, {
23
- disableHWAccForWin7: () => disableHWAccForWin7,
24
- getPathFromAppNameAsar: () => getPathFromAppNameAsar,
25
- getPaths: () => getPaths,
26
- getVersions: () => getVersions,
27
- handleUnexpectedErrors: () => handleUnexpectedErrors,
28
- is: () => is,
29
- isUpdateJSON: () => isUpdateJSON,
30
- loadNativeModuleFromEntry: () => loadNativeModuleFromEntry,
31
- parseGithubCdnURL: () => parseGithubCdnURL,
32
- parseVersion: () => parseVersion,
33
- restartApp: () => restartApp,
34
- setAppUserModelId: () => setAppUserModelId,
35
- setPortableAppDataPath: () => setPortableAppDataPath,
36
- singleInstance: () => singleInstance,
37
- unzipFile: () => unzipFile,
38
- waitAppReady: () => waitAppReady,
39
- zipFile: () => zipFile
40
- });
41
- module.exports = __toCommonJS(utils_exports);
3
+ var fs = require('fs');
4
+ var path = require('path');
5
+ var electron = require('electron');
6
+ var zlib = require('zlib');
7
+ var crypto = require('crypto');
8
+
9
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
+
11
+ var fs__default = /*#__PURE__*/_interopDefault(fs);
12
+ var path__default = /*#__PURE__*/_interopDefault(path);
13
+ var zlib__default = /*#__PURE__*/_interopDefault(zlib);
14
+ var crypto__default = /*#__PURE__*/_interopDefault(crypto);
42
15
 
43
- // src/utils/electron.ts
44
- var import_node_fs = require("fs");
45
- var import_node_path = require("path");
46
- var import_node_os = require("os");
47
- var import_electron = require("electron");
48
- var is = {
49
- dev: !import_electron.app.isPackaged,
50
- win: process.platform === "win32",
51
- mac: process.platform === "darwin",
52
- linux: process.platform === "linux"
53
- };
54
- function getPathFromAppNameAsar(...path) {
55
- return is.dev ? "DEV.asar" : (0, import_node_path.join)((0, import_node_path.dirname)(import_electron.app.getAppPath()), `${import_electron.app.name}.asar`, ...path);
16
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
17
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
18
+ }) : x)(function(x) {
19
+ if (typeof require !== "undefined") return require.apply(this, arguments);
20
+ throw Error('Dynamic require of "' + x + '" is not supported');
21
+ });
22
+ var isDev = __EIU_IS_DEV__;
23
+ var isWin = process.platform === "win32";
24
+ var isMac = process.platform === "darwin";
25
+ var isLinux = process.platform === "linux";
26
+ function getPathFromAppNameAsar(...paths) {
27
+ return isDev ? "DEV.asar" : path__default.default.join(path__default.default.dirname(electron.app.getAppPath()), `${electron.app.name}.asar`, ...paths);
56
28
  }
57
- function getVersions() {
58
- const platform = is.win ? "Windows" : is.mac ? "MacOS" : process.platform.toUpperCase();
59
- return {
60
- appVersion: is.dev ? import_electron.app.getVersion() : (0, import_node_fs.readFileSync)(getPathFromAppNameAsar("version"), "utf-8"),
61
- entryVersion: import_electron.app.getVersion(),
62
- electronVersion: process.versions.electron,
63
- nodeVersion: process.versions.node,
64
- systemVersion: `${platform} ${(0, import_node_os.release)()}`
65
- };
29
+ function getAppVersion() {
30
+ return isDev ? getEntryVersion() : fs__default.default.readFileSync(getPathFromAppNameAsar("version"), "utf-8");
66
31
  }
67
- function loadNativeModuleFromEntry(devEntryDirPath = "../../dist-entry", entryDirPath = (0, import_node_path.join)(import_electron.app.getAppPath(), (0, import_node_path.basename)(devEntryDirPath))) {
68
- const path = is.dev ? devEntryDirPath : entryDirPath;
69
- return (moduleName) => {
70
- try {
71
- return require((0, import_node_path.join)(path, moduleName));
72
- } catch (error) {
73
- console.error("fail to load module", error);
74
- }
75
- };
32
+ function getEntryVersion() {
33
+ return electron.app.getVersion();
34
+ }
35
+ function requireNative(moduleName) {
36
+ return __require(path__default.default.join(electron.app.getAppPath(), __EIU_ENTRY_DIST_PATH__, moduleName));
76
37
  }
77
38
  function restartApp() {
78
- import_electron.app.relaunch();
79
- import_electron.app.quit();
39
+ electron.app.relaunch();
40
+ electron.app.quit();
80
41
  }
81
42
  function setAppUserModelId(id) {
82
- import_electron.app.setAppUserModelId(is.dev ? process.execPath : id ?? `org.${import_electron.app.name}`);
43
+ if (isWin) {
44
+ electron.app.setAppUserModelId(id ?? `org.${electron.app.name}`);
45
+ }
83
46
  }
84
47
  function disableHWAccForWin7() {
85
- if ((0, import_node_os.release)().startsWith("6.1")) {
86
- import_electron.app.disableHardwareAcceleration();
48
+ if (__require("os").release().startsWith("6.1")) {
49
+ electron.app.disableHardwareAcceleration();
87
50
  }
88
51
  }
89
52
  function singleInstance(window) {
90
- const result = import_electron.app.requestSingleInstanceLock();
91
- result ? import_electron.app.on("second-instance", () => {
92
- if (window) {
93
- window.show();
94
- if (window.isMinimized()) {
95
- window.restore();
53
+ const result = electron.app.requestSingleInstanceLock();
54
+ if (result) {
55
+ electron.app.on("second-instance", () => {
56
+ if (window) {
57
+ window.show();
58
+ if (window.isMinimized()) {
59
+ window.restore();
60
+ }
61
+ window.focus();
96
62
  }
97
- window.focus();
98
- }
99
- }) : import_electron.app.quit();
63
+ });
64
+ } else {
65
+ electron.app.quit();
66
+ }
100
67
  return result;
101
68
  }
102
69
  function setPortableAppDataPath(dirName = "data") {
103
- const portablePath = (0, import_node_path.join)((0, import_node_path.dirname)(import_electron.app.getPath("exe")), dirName);
104
- if (!(0, import_node_fs.existsSync)(portablePath)) {
105
- (0, import_node_fs.mkdirSync)(portablePath);
70
+ const portablePath = path__default.default.join(path__default.default.dirname(electron.app.getPath("exe")), dirName);
71
+ if (!fs__default.default.existsSync(portablePath)) {
72
+ fs__default.default.mkdirSync(portablePath);
106
73
  }
107
- import_electron.app.setPath("appData", portablePath);
74
+ electron.app.setPath("appData", portablePath);
108
75
  }
109
- function waitAppReady(timeout = 1e3) {
110
- return import_electron.app.isReady() ? Promise.resolve() : new Promise((resolve, reject) => {
111
- const _ = setTimeout(() => {
112
- reject(new Error("app is not ready"));
113
- }, timeout);
114
- import_electron.app.whenReady().then(() => {
115
- clearTimeout(_);
116
- resolve();
117
- });
118
- });
76
+ function loadPage(win, htmlFilePath = "index.html") {
77
+ if (isDev) {
78
+ win.loadURL(process.env.VITE_DEV_SERVER_URL + htmlFilePath);
79
+ } else {
80
+ win.loadFile(getPathFromAppNameAsar("renderer", htmlFilePath));
81
+ }
119
82
  }
120
- function getPaths(entryDirName = "dist-entry") {
121
- const root = (0, import_node_path.join)(__dirname, "..");
122
- const mainDirPath = (0, import_node_path.join)(root, "main");
123
- const preloadDirPath = (0, import_node_path.join)(root, "preload");
124
- const rendererDirPath = (0, import_node_path.join)(root, "renderer");
125
- const devServerURL = process.env.VITE_DEV_SERVER_URL;
126
- const indexHTMLPath = (0, import_node_path.join)(rendererDirPath, "index.html");
127
- const publicDirPath = devServerURL ? (0, import_node_path.join)(root, "../public") : rendererDirPath;
128
- return {
129
- /**
130
- * @example
131
- * ```ts
132
- * devServerURL && win.loadURL(devServerURL)
133
- * ```
134
- */
135
- devServerURL,
136
- /**
137
- * @example
138
- * ```ts
139
- * win.loadFile(indexHTMLPath)
140
- * ```
141
- */
142
- indexHTMLPath,
143
- /**
144
- * get path inside entry asar
145
- * @param paths joined path
146
- */
147
- getPathFromEntryAsar(...paths) {
148
- return (0, import_node_path.join)(import_electron.app.getAppPath(), entryDirName, ...paths);
149
- },
150
- /**
151
- * get path inside `${electron.app.name}.asar/main`
152
- * @param paths joined path
153
- */
154
- getPathFromMain(...paths) {
155
- return (0, import_node_path.join)(mainDirPath, ...paths);
156
- },
157
- /**
158
- * get path inside `${electron.app.name}.asar/preload`
159
- * @param paths joined path
160
- */
161
- getPathFromPreload(...paths) {
162
- return (0, import_node_path.join)(preloadDirPath, ...paths);
163
- },
164
- /**
165
- * get path inside public dir
166
- * @param paths joined path
167
- */
168
- getPathFromPublic(...paths) {
169
- return (0, import_node_path.join)(publicDirPath, ...paths);
170
- }
171
- };
83
+ function getPathFromPreload(...paths) {
84
+ return isDev ? path__default.default.join(electron.app.getAppPath(), __EIU_ELECTRON_DIST_PATH__, "preload", ...paths) : getPathFromAppNameAsar("preload", ...paths);
172
85
  }
173
-
174
- // src/utils/zip.ts
175
- var import_node_fs2 = require("fs");
176
- var import_node_zlib = require("zlib");
177
- async function unzipFile(gzipPath, targetFilePath = gzipPath.slice(0, -3)) {
178
- if (!(0, import_node_fs2.existsSync)(gzipPath)) {
179
- throw new Error(`path to zipped file not exist: ${gzipPath}`);
180
- }
181
- const compressedBuffer = (0, import_node_fs2.readFileSync)(gzipPath);
86
+ function getPathFromPublic(...paths) {
87
+ return isDev ? path__default.default.join(electron.app.getAppPath(), "public", ...paths) : getPathFromAppNameAsar("renderer", ...paths);
88
+ }
89
+ function getPathFromEntryAsar(...paths) {
90
+ return path__default.default.join(electron.app.getAppPath(), __EIU_ENTRY_DIST_PATH__, ...paths);
91
+ }
92
+ function handleUnexpectedErrors(callback) {
93
+ process.on("uncaughtException", callback);
94
+ process.on("unhandledRejection", callback);
95
+ }
96
+ async function defaultZipFile(buffer) {
182
97
  return new Promise((resolve, reject) => {
183
- (0, import_node_zlib.brotliDecompress)(compressedBuffer, (err, buffer) => {
184
- (0, import_node_fs2.rmSync)(gzipPath);
98
+ zlib__default.default.brotliCompress(buffer, (err, buffer2) => {
185
99
  if (err) {
186
100
  reject(err);
101
+ } else {
102
+ resolve(buffer2);
187
103
  }
188
- (0, import_node_fs2.writeFileSync)(targetFilePath, buffer);
189
- resolve(null);
190
104
  });
191
105
  });
192
106
  }
193
- async function zipFile(filePath, targetFilePath = `${filePath}.gz`) {
194
- if (!(0, import_node_fs2.existsSync)(filePath)) {
195
- throw new Error(`path to be zipped not exist: ${filePath}`);
196
- }
197
- const buffer = (0, import_node_fs2.readFileSync)(filePath);
107
+ async function defaultUnzipFile(buffer) {
198
108
  return new Promise((resolve, reject) => {
199
- (0, import_node_zlib.brotliCompress)(buffer, (err, buffer2) => {
109
+ zlib__default.default.brotliDecompress(buffer, (err, buffer2) => {
200
110
  if (err) {
201
111
  reject(err);
112
+ } else {
113
+ resolve(buffer2);
202
114
  }
203
- (0, import_node_fs2.writeFileSync)(targetFilePath, buffer2);
204
- resolve(null);
205
115
  });
206
116
  });
207
117
  }
208
118
 
209
- // src/utils/pure.ts
210
- function parseGithubCdnURL(originRepoURL, cdnPrefix, relativeFilePath) {
211
- if (!originRepoURL.startsWith("https://github.com/")) {
212
- throw new Error("origin url must start with https://github.com/");
213
- }
214
- originRepoURL = originRepoURL.trim().replace(/\/?$/, "/").trim();
215
- relativeFilePath = relativeFilePath.trim().replace(/^\/|\/?$/g, "").trim();
216
- cdnPrefix = cdnPrefix.trim().replace(/^\/?|\/?$/g, "").trim();
217
- return originRepoURL.replace("github.com", cdnPrefix) + relativeFilePath;
218
- }
219
- function handleUnexpectedErrors(callback) {
220
- process.on("uncaughtException", callback);
221
- process.on("unhandledRejection", callback);
222
- }
119
+ // src/utils/version.ts
223
120
  function parseVersion(version) {
224
121
  const match = /^(\d+)\.(\d+)\.(\d+)(?:-([a-z0-9.-]+))?/i.exec(version);
225
122
  if (!match) {
@@ -243,27 +140,97 @@ function parseVersion(version) {
243
140
  }
244
141
  return ret;
245
142
  }
143
+ function defaultIsLowerVersion(oldVer, newVer) {
144
+ const oldV = parseVersion(oldVer);
145
+ const newV = parseVersion(newVer);
146
+ function compareStrings(str1, str2) {
147
+ if (str1 === "") {
148
+ return str2 !== "";
149
+ } else if (str2 === "") {
150
+ return true;
151
+ }
152
+ return str1 < str2;
153
+ }
154
+ for (let key of Object.keys(oldV)) {
155
+ if (key === "stage" && compareStrings(oldV[key], newV[key])) {
156
+ return true;
157
+ } else if (oldV[key] !== newV[key]) {
158
+ return oldV[key] < newV[key];
159
+ }
160
+ }
161
+ return false;
162
+ }
246
163
  function isUpdateJSON(json) {
247
- const is2 = (j) => !!(j && j.minimumVersion && j.signature && j.size && j.version);
248
- return is2(json) && is2(json?.beta);
164
+ const is = (j) => !!(j && j.minimumVersion && j.signature && j.version);
165
+ return is(json) && is(json?.beta);
166
+ }
167
+ function defaultVersionJsonGenerator(existingJson, signature, version, minimumVersion) {
168
+ existingJson.beta = {
169
+ version,
170
+ minimumVersion,
171
+ signature
172
+ };
173
+ if (!parseVersion(version).stage) {
174
+ existingJson.version = version;
175
+ existingJson.minimumVersion = minimumVersion;
176
+ existingJson.signature = signature;
177
+ }
178
+ return existingJson;
249
179
  }
250
- // Annotate the CommonJS export names for ESM import in node:
251
- 0 && (module.exports = {
252
- disableHWAccForWin7,
253
- getPathFromAppNameAsar,
254
- getPaths,
255
- getVersions,
256
- handleUnexpectedErrors,
257
- is,
258
- isUpdateJSON,
259
- loadNativeModuleFromEntry,
260
- parseGithubCdnURL,
261
- parseVersion,
262
- restartApp,
263
- setAppUserModelId,
264
- setPortableAppDataPath,
265
- singleInstance,
266
- unzipFile,
267
- waitAppReady,
268
- zipFile
269
- });
180
+ function hashBuffer(data, length) {
181
+ const hash = crypto__default.default.createHash("SHA256").update(data).digest("binary");
182
+ return Buffer.from(hash).subarray(0, length);
183
+ }
184
+ function aesEncrypt(plainText, key, iv) {
185
+ const cipher = crypto__default.default.createCipheriv("aes-256-cbc", key, iv);
186
+ return cipher.update(plainText, "utf8", "base64url") + cipher.final("base64url");
187
+ }
188
+ function defaultSignature(buffer, privateKey, cert, version) {
189
+ const sig = crypto__default.default.createSign("RSA-SHA256").update(buffer).sign(crypto__default.default.createPrivateKey(privateKey), "base64");
190
+ return aesEncrypt(`${sig}%${version}`, hashBuffer(cert, 32), hashBuffer(buffer, 16));
191
+ }
192
+ function aesDecrypt(encryptedText, key, iv) {
193
+ const decipher = crypto__default.default.createDecipheriv("aes-256-cbc", key, iv);
194
+ return decipher.update(encryptedText, "base64url", "utf8") + decipher.final("utf8");
195
+ }
196
+ function defaultVerifySignature(buffer, version, signature, cert) {
197
+ try {
198
+ const [sig, ver] = aesDecrypt(signature, hashBuffer(cert, 32), hashBuffer(buffer, 16)).split("%");
199
+ if (ver !== version) {
200
+ return false;
201
+ }
202
+ return crypto__default.default.createVerify("RSA-SHA256").update(buffer).verify(cert, sig, "base64");
203
+ } catch {
204
+ return false;
205
+ }
206
+ }
207
+
208
+ exports.aesDecrypt = aesDecrypt;
209
+ exports.aesEncrypt = aesEncrypt;
210
+ exports.defaultIsLowerVersion = defaultIsLowerVersion;
211
+ exports.defaultSignature = defaultSignature;
212
+ exports.defaultUnzipFile = defaultUnzipFile;
213
+ exports.defaultVerifySignature = defaultVerifySignature;
214
+ exports.defaultVersionJsonGenerator = defaultVersionJsonGenerator;
215
+ exports.defaultZipFile = defaultZipFile;
216
+ exports.disableHWAccForWin7 = disableHWAccForWin7;
217
+ exports.getAppVersion = getAppVersion;
218
+ exports.getEntryVersion = getEntryVersion;
219
+ exports.getPathFromAppNameAsar = getPathFromAppNameAsar;
220
+ exports.getPathFromEntryAsar = getPathFromEntryAsar;
221
+ exports.getPathFromPreload = getPathFromPreload;
222
+ exports.getPathFromPublic = getPathFromPublic;
223
+ exports.handleUnexpectedErrors = handleUnexpectedErrors;
224
+ exports.hashBuffer = hashBuffer;
225
+ exports.isDev = isDev;
226
+ exports.isLinux = isLinux;
227
+ exports.isMac = isMac;
228
+ exports.isUpdateJSON = isUpdateJSON;
229
+ exports.isWin = isWin;
230
+ exports.loadPage = loadPage;
231
+ exports.parseVersion = parseVersion;
232
+ exports.requireNative = requireNative;
233
+ exports.restartApp = restartApp;
234
+ exports.setAppUserModelId = setAppUserModelId;
235
+ exports.setPortableAppDataPath = setPortableAppDataPath;
236
+ exports.singleInstance = singleInstance;