electron-incremental-update 0.2.1 → 0.3.0
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/index.cjs +99 -78
- package/dist/index.d.ts +21 -9
- package/dist/index.mjs +95 -76
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -34,9 +34,11 @@ __export(src_exports, {
|
|
|
34
34
|
getAppAsarPath: () => getAppAsarPath,
|
|
35
35
|
getAppVersion: () => getAppVersion,
|
|
36
36
|
getEntryVersion: () => getEntryVersion,
|
|
37
|
-
|
|
37
|
+
getGithubReleaseCdnGroup: () => getGithubReleaseCdnGroup,
|
|
38
38
|
initApp: () => initApp,
|
|
39
|
-
|
|
39
|
+
parseGithubCdnURL: () => parseGithubCdnURL,
|
|
40
|
+
requireNative: () => requireNative,
|
|
41
|
+
restartApp: () => restartApp
|
|
40
42
|
});
|
|
41
43
|
module.exports = __toCommonJS(src_exports);
|
|
42
44
|
var import_node_path2 = require("path");
|
|
@@ -61,7 +63,6 @@ function downloadJSONDefault(url, updater, headers) {
|
|
|
61
63
|
res.headers = headers;
|
|
62
64
|
res.on("data", (chunk) => data += chunk);
|
|
63
65
|
res.on("end", () => {
|
|
64
|
-
updater.emit("downloadEnd", true);
|
|
65
66
|
const json = JSON.parse(data);
|
|
66
67
|
if ("signature" in json && "version" in json && "size" in json) {
|
|
67
68
|
resolve2(json);
|
|
@@ -70,8 +71,6 @@ function downloadJSONDefault(url, updater, headers) {
|
|
|
70
71
|
}
|
|
71
72
|
});
|
|
72
73
|
}).on("error", (e) => {
|
|
73
|
-
e && updater.emit("donwnloadError", e);
|
|
74
|
-
updater.emit("downloadEnd", false);
|
|
75
74
|
reject(e);
|
|
76
75
|
});
|
|
77
76
|
});
|
|
@@ -86,12 +85,9 @@ function downloadBufferDefault(url, updater, headers) {
|
|
|
86
85
|
data.push(chunk);
|
|
87
86
|
});
|
|
88
87
|
res.on("end", () => {
|
|
89
|
-
updater.emit("downloadEnd", true);
|
|
90
88
|
resolve2(import_node_buffer.Buffer.concat(data));
|
|
91
89
|
});
|
|
92
90
|
}).on("error", (e) => {
|
|
93
|
-
e && updater.emit("donwnloadError", e);
|
|
94
|
-
updater.emit("downloadEnd", false);
|
|
95
91
|
reject(e);
|
|
96
92
|
});
|
|
97
93
|
});
|
|
@@ -130,39 +126,43 @@ function getEntryVersion() {
|
|
|
130
126
|
return import_electron.app.getVersion();
|
|
131
127
|
}
|
|
132
128
|
function getAppVersion(name) {
|
|
133
|
-
return import_electron.app.isPackaged ? (0, import_node_fs.readFileSync)((0, import_node_path.join)(getAppAsarPath(name), "version"), "utf-8")
|
|
129
|
+
return import_electron.app.isPackaged ? (0, import_node_fs.readFileSync)((0, import_node_path.join)(getAppAsarPath(name), "version"), "utf-8") : getEntryVersion();
|
|
134
130
|
}
|
|
135
131
|
function requireNative(packageName) {
|
|
136
132
|
const path = import_electron.app.isPackaged ? (0, import_node_path.join)(import_electron.app.getAppPath(), "node_modules", packageName) : packageName;
|
|
137
133
|
return require(path);
|
|
138
134
|
}
|
|
139
|
-
function
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
throw new Error("URL must start with 'https://github.com/'");
|
|
135
|
+
function parseGithubCdnURL(repository, cdnPrefix, relativeFilePath) {
|
|
136
|
+
if (!repository.startsWith("https://github.com/")) {
|
|
137
|
+
throw new Error("url must start with https://github.com/");
|
|
143
138
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
139
|
+
repository = repository.trim().replace(/\/?$/, "/").trim();
|
|
140
|
+
relativeFilePath = relativeFilePath.trim().replace(/^\/|\/?$/g, "").trim();
|
|
141
|
+
cdnPrefix = cdnPrefix.trim().replace(/^\/?|\/?$/g, "").trim();
|
|
142
|
+
return repository.replace("github.com", cdnPrefix) + relativeFilePath;
|
|
143
|
+
}
|
|
144
|
+
function getGithubReleaseCdnGroup() {
|
|
148
145
|
return [
|
|
149
|
-
{
|
|
150
|
-
{
|
|
151
|
-
{
|
|
152
|
-
{
|
|
153
|
-
{
|
|
154
|
-
{
|
|
155
|
-
{
|
|
156
|
-
{
|
|
157
|
-
{
|
|
158
|
-
{
|
|
159
|
-
{
|
|
160
|
-
{
|
|
161
|
-
{
|
|
162
|
-
{
|
|
163
|
-
{ url: `https://download.nuaa.cf/${_url}`, maintainer: "LibraryCloud-nuaa" }
|
|
146
|
+
{ cdnPrefix: "gh.gh2233.ml", maintainer: "@X.I.U/XIU2" },
|
|
147
|
+
{ cdnPrefix: "ghproxy.com", maintainer: "gh-proxy" },
|
|
148
|
+
{ cdnPrefix: "gh.ddlc.top", maintainer: "@mtr-static-official" },
|
|
149
|
+
{ cdnPrefix: "ghdl.feizhuqwq.cf", maintainer: "feizhuqwq.com" },
|
|
150
|
+
{ cdnPrefix: "slink.ltd", maintainer: "\u77E5\u4E86\u5C0F\u7AD9" },
|
|
151
|
+
{ cdnPrefix: "git.xfj0.cn", maintainer: "anonymous1" },
|
|
152
|
+
{ cdnPrefix: "gh.con.sh", maintainer: "anonymous2" },
|
|
153
|
+
{ cdnPrefix: "ghps.cc", maintainer: "anonymous3" },
|
|
154
|
+
{ cdnPrefix: "cors.isteed.cc/github.com", maintainer: "Lufs's" },
|
|
155
|
+
{ cdnPrefix: "hub.gitmirror.com", maintainer: "GitMirror" },
|
|
156
|
+
{ cdnPrefix: "js.xxooo.ml", maintainer: "\u996D\u592A\u786C" },
|
|
157
|
+
{ cdnPrefix: "download.njuu.cf", maintainer: "LibraryCloud-njuu" },
|
|
158
|
+
{ cdnPrefix: "download.yzuu.cf", maintainer: "LibraryCloud-yzuu" },
|
|
159
|
+
{ cdnPrefix: "download.nuaa.cf", maintainer: "LibraryCloud-nuaa" }
|
|
164
160
|
];
|
|
165
161
|
}
|
|
162
|
+
function restartApp() {
|
|
163
|
+
import_electron.app.relaunch();
|
|
164
|
+
import_electron.app.quit();
|
|
165
|
+
}
|
|
166
166
|
|
|
167
167
|
// src/updater/index.ts
|
|
168
168
|
function createUpdater({
|
|
@@ -176,9 +176,12 @@ function createUpdater({
|
|
|
176
176
|
compareVersion
|
|
177
177
|
}) {
|
|
178
178
|
const updater = new import_node_events.EventEmitter();
|
|
179
|
+
let signature = "";
|
|
180
|
+
const gzipPath = `../${productName}.asar.gz`;
|
|
181
|
+
const tmpFile = gzipPath.replace(".asar.gz", ".tmp.gz");
|
|
179
182
|
const { downloadBuffer, downloadJSON, extraHeader, userAgent } = downloadConfig || {};
|
|
180
|
-
function log(
|
|
181
|
-
debug &&
|
|
183
|
+
function log(msg) {
|
|
184
|
+
debug && updater.emit("debug", msg);
|
|
182
185
|
}
|
|
183
186
|
async function download(url, format) {
|
|
184
187
|
const ua = userAgent || "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36";
|
|
@@ -187,7 +190,7 @@ function createUpdater({
|
|
|
187
190
|
UserAgent: ua,
|
|
188
191
|
...extraHeader
|
|
189
192
|
};
|
|
190
|
-
log(
|
|
193
|
+
log(`headers: ${headers}`);
|
|
191
194
|
const downloadFn = format === "json" ? downloadJSON ?? downloadJSONDefault : downloadBuffer ?? downloadBufferDefault;
|
|
192
195
|
return await downloadFn(url, updater, headers);
|
|
193
196
|
}
|
|
@@ -201,89 +204,105 @@ function createUpdater({
|
|
|
201
204
|
const input = (0, import_node_fs2.createReadStream)(gzipFilePath);
|
|
202
205
|
const outputFilePath = gzipFilePath.replace(".tmp.gz", ".asar");
|
|
203
206
|
const output = (0, import_node_fs2.createWriteStream)(outputFilePath);
|
|
204
|
-
log(
|
|
207
|
+
log(`outputFilePath: ${outputFilePath}`);
|
|
205
208
|
input.pipe(gunzip).pipe(output).on("finish", async () => {
|
|
206
209
|
await (0, import_promises.rm)(gzipFilePath);
|
|
207
|
-
log("
|
|
210
|
+
log("finish");
|
|
208
211
|
resolve2(outputFilePath);
|
|
209
212
|
}).on("error", async (err) => {
|
|
210
213
|
await (0, import_promises.rm)(gzipFilePath);
|
|
211
|
-
log(
|
|
214
|
+
log(`error: ${err}`);
|
|
212
215
|
output.destroy(err);
|
|
213
216
|
reject(err);
|
|
214
217
|
});
|
|
215
218
|
});
|
|
216
219
|
}
|
|
217
|
-
function verify(buffer,
|
|
218
|
-
log(
|
|
219
|
-
return (0, import_node_crypto.createVerify)("RSA-SHA256").update(buffer).verify(SIGNATURE_PUB,
|
|
220
|
+
function verify(buffer, signature2) {
|
|
221
|
+
log(`signature: ${signature2}`);
|
|
222
|
+
return (0, import_node_crypto.createVerify)("RSA-SHA256").update(buffer).verify(SIGNATURE_PUB, signature2, "base64");
|
|
220
223
|
}
|
|
221
224
|
function needUpdate(version) {
|
|
222
225
|
if (!version || !import_electron2.app.isPackaged) {
|
|
223
226
|
return false;
|
|
224
227
|
}
|
|
225
228
|
const currentVersion = getEntryVersion();
|
|
226
|
-
log(
|
|
227
|
-
log(
|
|
229
|
+
log(`currentVersion: ${currentVersion}`);
|
|
230
|
+
log(`newVersion: ${version}`);
|
|
228
231
|
const _compare = compareVersion ?? compareVersionDefault;
|
|
229
232
|
return _compare(currentVersion, version);
|
|
230
233
|
}
|
|
231
|
-
async function checkUpdate(
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
} = option || {};
|
|
236
|
-
if (!updateJsonURL || !releaseAsarURL) {
|
|
237
|
-
log("[updater] no updateJsonURL or releaseAsarURL, use repository");
|
|
234
|
+
async function checkUpdate(url) {
|
|
235
|
+
url ??= _update;
|
|
236
|
+
if (!url) {
|
|
237
|
+
log("no updateJsonURL, use repository");
|
|
238
238
|
if (!repository) {
|
|
239
|
-
throw new Error("updateJsonURL or
|
|
239
|
+
throw new Error("updateJsonURL or repository are not set");
|
|
240
240
|
}
|
|
241
|
-
|
|
242
|
-
releaseAsarURL = `${repository}/releases/download/latest/${productName}.asar.gz`;
|
|
241
|
+
url = `${repository.replace("github.com", "raw.githubusercontent.com")}/version.json`;
|
|
243
242
|
}
|
|
244
|
-
log(
|
|
245
|
-
log("[updater] releaseAsarURL", releaseAsarURL);
|
|
246
|
-
const gzipPath = `../${productName}.asar.gz`;
|
|
247
|
-
const tmpFile = gzipPath.replace(".asar.gz", ".tmp.gz");
|
|
243
|
+
log(`updateJsonURL: ${url}`);
|
|
248
244
|
if ((0, import_node_fs2.existsSync)(tmpFile)) {
|
|
249
|
-
log(
|
|
245
|
+
log(`remove tmp file: ${tmpFile}`);
|
|
250
246
|
await (0, import_promises.rm)(tmpFile);
|
|
251
247
|
}
|
|
252
|
-
const json = await download(
|
|
253
|
-
if (!json) {
|
|
254
|
-
throw new Error("fetch update json failed");
|
|
255
|
-
}
|
|
248
|
+
const json = await download(url, "json");
|
|
256
249
|
const {
|
|
257
|
-
signature,
|
|
250
|
+
signature: _sig,
|
|
258
251
|
version,
|
|
259
252
|
size
|
|
260
253
|
} = json;
|
|
261
|
-
log(
|
|
254
|
+
log(`UpdateJSON: ${JSON.stringify(json, null, 2)}`);
|
|
262
255
|
if (!needUpdate(version)) {
|
|
263
|
-
return
|
|
256
|
+
return false;
|
|
257
|
+
} else {
|
|
258
|
+
signature = _sig;
|
|
259
|
+
return { size, version };
|
|
264
260
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
261
|
+
}
|
|
262
|
+
async function downloadUpdate(src) {
|
|
263
|
+
if (typeof src !== "object") {
|
|
264
|
+
let _url = src ?? _release;
|
|
265
|
+
if (!_url) {
|
|
266
|
+
log("no releaseAsarURL, use repository");
|
|
267
|
+
if (!repository) {
|
|
268
|
+
throw new Error("releaseAsarURL or repository are not set");
|
|
269
|
+
}
|
|
270
|
+
_url = `${repository}/releases/download/latest/${productName}.asar.gz`;
|
|
271
|
+
}
|
|
272
|
+
log(`releaseAsarURL: ${_url}`);
|
|
273
|
+
src = await download(_url, "buffer");
|
|
274
|
+
}
|
|
275
|
+
log("start verify");
|
|
276
|
+
if (!verify(src, signature)) {
|
|
269
277
|
throw new Error("file broken, invalid signature!");
|
|
270
278
|
}
|
|
271
|
-
log(
|
|
272
|
-
await (0, import_promises.writeFile)(gzipPath,
|
|
273
|
-
log(
|
|
279
|
+
log(`write file: ${gzipPath}`);
|
|
280
|
+
await (0, import_promises.writeFile)(gzipPath, src);
|
|
281
|
+
log(`extract file: ${gzipPath}`);
|
|
274
282
|
await extractFile(gzipPath);
|
|
275
|
-
|
|
283
|
+
updater.emit("downloaded");
|
|
276
284
|
}
|
|
277
|
-
const onCheck = async (
|
|
285
|
+
const onCheck = async (url) => {
|
|
278
286
|
try {
|
|
279
|
-
const result = await checkUpdate(
|
|
287
|
+
const result = await checkUpdate(url);
|
|
280
288
|
updater.emit("checkResult", result);
|
|
281
289
|
} catch (error) {
|
|
282
|
-
|
|
290
|
+
log(error);
|
|
291
|
+
updater.emit("checkResult", error);
|
|
283
292
|
}
|
|
284
293
|
};
|
|
285
294
|
updater.on("check", onCheck);
|
|
286
295
|
updater.checkUpdate = onCheck;
|
|
296
|
+
const onDownload = async (src) => {
|
|
297
|
+
try {
|
|
298
|
+
await downloadUpdate(src);
|
|
299
|
+
} catch (error) {
|
|
300
|
+
log(error);
|
|
301
|
+
updater.emit("donwnloadError", error);
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
updater.on("download", onDownload);
|
|
305
|
+
updater.downloadUpdate = onDownload;
|
|
287
306
|
return updater;
|
|
288
307
|
}
|
|
289
308
|
|
|
@@ -310,7 +329,9 @@ function initApp(productName, updater, option) {
|
|
|
310
329
|
getAppAsarPath,
|
|
311
330
|
getAppVersion,
|
|
312
331
|
getEntryVersion,
|
|
313
|
-
|
|
332
|
+
getGithubReleaseCdnGroup,
|
|
314
333
|
initApp,
|
|
315
|
-
|
|
334
|
+
parseGithubCdnURL,
|
|
335
|
+
requireNative,
|
|
336
|
+
restartApp
|
|
316
337
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
2
|
|
|
3
|
-
type CheckResultType =
|
|
3
|
+
type CheckResultType = Error | false | Omit<UpdateJSON, 'signature'>;
|
|
4
4
|
type UpdateEvents = {
|
|
5
5
|
check: null;
|
|
6
|
-
checkResult: [data: CheckResultType
|
|
7
|
-
|
|
6
|
+
checkResult: [data: CheckResultType];
|
|
7
|
+
download: null;
|
|
8
8
|
downloading: [current: number];
|
|
9
|
-
|
|
9
|
+
downloaded: null;
|
|
10
10
|
donwnloadError: [error: unknown];
|
|
11
|
+
debug: [msg: string | Error];
|
|
11
12
|
};
|
|
12
13
|
type UpdateJSON = {
|
|
13
14
|
signature: string;
|
|
@@ -37,7 +38,13 @@ interface TypedUpdater<T extends Record<string | symbol, MaybeArray<any>>, Event
|
|
|
37
38
|
once<E extends Event>(eventName: E, listener: (...args: MaybeArray<T[E]>) => void): this;
|
|
38
39
|
emit<E extends Event>(eventName: E, ...args: MaybeArray<T[E]>): boolean;
|
|
39
40
|
off<E extends Event>(eventName: E, listener: (...args: MaybeArray<T[E]>) => void): this;
|
|
40
|
-
|
|
41
|
+
/**
|
|
42
|
+
* - `undefined`: errror
|
|
43
|
+
* - `false`: unavailable
|
|
44
|
+
* - `{size: number, version: string}`: success
|
|
45
|
+
*/
|
|
46
|
+
checkUpdate(url?: BaseOption['updateJsonURL']): Promise<void>;
|
|
47
|
+
downloadUpdate(url?: BaseOption['releaseAsarURL'] | Buffer): Promise<void>;
|
|
41
48
|
}
|
|
42
49
|
type Updater = TypedUpdater<UpdateEvents>;
|
|
43
50
|
interface UpdaterOption extends BaseOption {
|
|
@@ -123,12 +130,17 @@ declare function getAppVersion(name: string): string;
|
|
|
123
130
|
*/
|
|
124
131
|
declare function requireNative<T = any>(packageName: string): T;
|
|
125
132
|
/**
|
|
126
|
-
* get
|
|
133
|
+
* get github version.json CDN URL for accelerating the speed of downloading version info
|
|
134
|
+
*/
|
|
135
|
+
declare function parseGithubCdnURL(repository: string, cdnPrefix: string, relativeFilePath: string): string;
|
|
136
|
+
/**
|
|
137
|
+
* get group of github release CDN prefix for accelerating the speed of downloading release
|
|
127
138
|
*/
|
|
128
|
-
declare function
|
|
129
|
-
|
|
139
|
+
declare function getGithubReleaseCdnGroup(): {
|
|
140
|
+
cdnPrefix: string;
|
|
130
141
|
maintainer: string;
|
|
131
142
|
}[];
|
|
143
|
+
declare function restartApp(): void;
|
|
132
144
|
|
|
133
145
|
declare function createUpdater({ SIGNATURE_PUB, repository, productName, releaseAsarURL: _release, updateJsonURL: _update, debug, downloadConfig, compareVersion, }: UpdaterOption): Updater;
|
|
134
146
|
|
|
@@ -189,4 +201,4 @@ declare function initApp(productName: string, updater: Updater | Omit<UpdaterOpt
|
|
|
189
201
|
productName?: string;
|
|
190
202
|
}, option?: AppOption): any;
|
|
191
203
|
|
|
192
|
-
export { BaseOption, CheckResultType, UpdateJSON, Updater, UpdaterOption, createUpdater, getAppAsarPath, getAppVersion, getEntryVersion,
|
|
204
|
+
export { BaseOption, CheckResultType, UpdateJSON, Updater, UpdaterOption, createUpdater, getAppAsarPath, getAppVersion, getEntryVersion, getGithubReleaseCdnGroup, initApp, parseGithubCdnURL, requireNative, restartApp };
|
package/dist/index.mjs
CHANGED
|
@@ -25,7 +25,6 @@ function downloadJSONDefault(url, updater, headers) {
|
|
|
25
25
|
res.headers = headers;
|
|
26
26
|
res.on("data", (chunk) => data += chunk);
|
|
27
27
|
res.on("end", () => {
|
|
28
|
-
updater.emit("downloadEnd", true);
|
|
29
28
|
const json = JSON.parse(data);
|
|
30
29
|
if ("signature" in json && "version" in json && "size" in json) {
|
|
31
30
|
resolve2(json);
|
|
@@ -34,8 +33,6 @@ function downloadJSONDefault(url, updater, headers) {
|
|
|
34
33
|
}
|
|
35
34
|
});
|
|
36
35
|
}).on("error", (e) => {
|
|
37
|
-
e && updater.emit("donwnloadError", e);
|
|
38
|
-
updater.emit("downloadEnd", false);
|
|
39
36
|
reject(e);
|
|
40
37
|
});
|
|
41
38
|
});
|
|
@@ -50,12 +47,9 @@ function downloadBufferDefault(url, updater, headers) {
|
|
|
50
47
|
data.push(chunk);
|
|
51
48
|
});
|
|
52
49
|
res.on("end", () => {
|
|
53
|
-
updater.emit("downloadEnd", true);
|
|
54
50
|
resolve2(Buffer.concat(data));
|
|
55
51
|
});
|
|
56
52
|
}).on("error", (e) => {
|
|
57
|
-
e && updater.emit("donwnloadError", e);
|
|
58
|
-
updater.emit("downloadEnd", false);
|
|
59
53
|
reject(e);
|
|
60
54
|
});
|
|
61
55
|
});
|
|
@@ -94,39 +88,43 @@ function getEntryVersion() {
|
|
|
94
88
|
return app.getVersion();
|
|
95
89
|
}
|
|
96
90
|
function getAppVersion(name) {
|
|
97
|
-
return app.isPackaged ? readFileSync(join(getAppAsarPath(name), "version"), "utf-8")
|
|
91
|
+
return app.isPackaged ? readFileSync(join(getAppAsarPath(name), "version"), "utf-8") : getEntryVersion();
|
|
98
92
|
}
|
|
99
93
|
function requireNative(packageName) {
|
|
100
94
|
const path = app.isPackaged ? join(app.getAppPath(), "node_modules", packageName) : packageName;
|
|
101
95
|
return __require(path);
|
|
102
96
|
}
|
|
103
|
-
function
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
throw new Error("URL must start with 'https://github.com/'");
|
|
97
|
+
function parseGithubCdnURL(repository, cdnPrefix, relativeFilePath) {
|
|
98
|
+
if (!repository.startsWith("https://github.com/")) {
|
|
99
|
+
throw new Error("url must start with https://github.com/");
|
|
107
100
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
101
|
+
repository = repository.trim().replace(/\/?$/, "/").trim();
|
|
102
|
+
relativeFilePath = relativeFilePath.trim().replace(/^\/|\/?$/g, "").trim();
|
|
103
|
+
cdnPrefix = cdnPrefix.trim().replace(/^\/?|\/?$/g, "").trim();
|
|
104
|
+
return repository.replace("github.com", cdnPrefix) + relativeFilePath;
|
|
105
|
+
}
|
|
106
|
+
function getGithubReleaseCdnGroup() {
|
|
112
107
|
return [
|
|
113
|
-
{
|
|
114
|
-
{
|
|
115
|
-
{
|
|
116
|
-
{
|
|
117
|
-
{
|
|
118
|
-
{
|
|
119
|
-
{
|
|
120
|
-
{
|
|
121
|
-
{
|
|
122
|
-
{
|
|
123
|
-
{
|
|
124
|
-
{
|
|
125
|
-
{
|
|
126
|
-
{
|
|
127
|
-
{ url: `https://download.nuaa.cf/${_url}`, maintainer: "LibraryCloud-nuaa" }
|
|
108
|
+
{ cdnPrefix: "gh.gh2233.ml", maintainer: "@X.I.U/XIU2" },
|
|
109
|
+
{ cdnPrefix: "ghproxy.com", maintainer: "gh-proxy" },
|
|
110
|
+
{ cdnPrefix: "gh.ddlc.top", maintainer: "@mtr-static-official" },
|
|
111
|
+
{ cdnPrefix: "ghdl.feizhuqwq.cf", maintainer: "feizhuqwq.com" },
|
|
112
|
+
{ cdnPrefix: "slink.ltd", maintainer: "\u77E5\u4E86\u5C0F\u7AD9" },
|
|
113
|
+
{ cdnPrefix: "git.xfj0.cn", maintainer: "anonymous1" },
|
|
114
|
+
{ cdnPrefix: "gh.con.sh", maintainer: "anonymous2" },
|
|
115
|
+
{ cdnPrefix: "ghps.cc", maintainer: "anonymous3" },
|
|
116
|
+
{ cdnPrefix: "cors.isteed.cc/github.com", maintainer: "Lufs's" },
|
|
117
|
+
{ cdnPrefix: "hub.gitmirror.com", maintainer: "GitMirror" },
|
|
118
|
+
{ cdnPrefix: "js.xxooo.ml", maintainer: "\u996D\u592A\u786C" },
|
|
119
|
+
{ cdnPrefix: "download.njuu.cf", maintainer: "LibraryCloud-njuu" },
|
|
120
|
+
{ cdnPrefix: "download.yzuu.cf", maintainer: "LibraryCloud-yzuu" },
|
|
121
|
+
{ cdnPrefix: "download.nuaa.cf", maintainer: "LibraryCloud-nuaa" }
|
|
128
122
|
];
|
|
129
123
|
}
|
|
124
|
+
function restartApp() {
|
|
125
|
+
app.relaunch();
|
|
126
|
+
app.quit();
|
|
127
|
+
}
|
|
130
128
|
|
|
131
129
|
// src/updater/index.ts
|
|
132
130
|
function createUpdater({
|
|
@@ -140,9 +138,12 @@ function createUpdater({
|
|
|
140
138
|
compareVersion
|
|
141
139
|
}) {
|
|
142
140
|
const updater = new EventEmitter();
|
|
141
|
+
let signature = "";
|
|
142
|
+
const gzipPath = `../${productName}.asar.gz`;
|
|
143
|
+
const tmpFile = gzipPath.replace(".asar.gz", ".tmp.gz");
|
|
143
144
|
const { downloadBuffer, downloadJSON, extraHeader, userAgent } = downloadConfig || {};
|
|
144
|
-
function log(
|
|
145
|
-
debug &&
|
|
145
|
+
function log(msg) {
|
|
146
|
+
debug && updater.emit("debug", msg);
|
|
146
147
|
}
|
|
147
148
|
async function download(url, format) {
|
|
148
149
|
const ua = userAgent || "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36";
|
|
@@ -151,7 +152,7 @@ function createUpdater({
|
|
|
151
152
|
UserAgent: ua,
|
|
152
153
|
...extraHeader
|
|
153
154
|
};
|
|
154
|
-
log(
|
|
155
|
+
log(`headers: ${headers}`);
|
|
155
156
|
const downloadFn = format === "json" ? downloadJSON ?? downloadJSONDefault : downloadBuffer ?? downloadBufferDefault;
|
|
156
157
|
return await downloadFn(url, updater, headers);
|
|
157
158
|
}
|
|
@@ -165,89 +166,105 @@ function createUpdater({
|
|
|
165
166
|
const input = createReadStream(gzipFilePath);
|
|
166
167
|
const outputFilePath = gzipFilePath.replace(".tmp.gz", ".asar");
|
|
167
168
|
const output = createWriteStream(outputFilePath);
|
|
168
|
-
log(
|
|
169
|
+
log(`outputFilePath: ${outputFilePath}`);
|
|
169
170
|
input.pipe(gunzip).pipe(output).on("finish", async () => {
|
|
170
171
|
await rm(gzipFilePath);
|
|
171
|
-
log("
|
|
172
|
+
log("finish");
|
|
172
173
|
resolve2(outputFilePath);
|
|
173
174
|
}).on("error", async (err) => {
|
|
174
175
|
await rm(gzipFilePath);
|
|
175
|
-
log(
|
|
176
|
+
log(`error: ${err}`);
|
|
176
177
|
output.destroy(err);
|
|
177
178
|
reject(err);
|
|
178
179
|
});
|
|
179
180
|
});
|
|
180
181
|
}
|
|
181
|
-
function verify(buffer,
|
|
182
|
-
log(
|
|
183
|
-
return createVerify("RSA-SHA256").update(buffer).verify(SIGNATURE_PUB,
|
|
182
|
+
function verify(buffer, signature2) {
|
|
183
|
+
log(`signature: ${signature2}`);
|
|
184
|
+
return createVerify("RSA-SHA256").update(buffer).verify(SIGNATURE_PUB, signature2, "base64");
|
|
184
185
|
}
|
|
185
186
|
function needUpdate(version) {
|
|
186
187
|
if (!version || !app2.isPackaged) {
|
|
187
188
|
return false;
|
|
188
189
|
}
|
|
189
190
|
const currentVersion = getEntryVersion();
|
|
190
|
-
log(
|
|
191
|
-
log(
|
|
191
|
+
log(`currentVersion: ${currentVersion}`);
|
|
192
|
+
log(`newVersion: ${version}`);
|
|
192
193
|
const _compare = compareVersion ?? compareVersionDefault;
|
|
193
194
|
return _compare(currentVersion, version);
|
|
194
195
|
}
|
|
195
|
-
async function checkUpdate(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
} = option || {};
|
|
200
|
-
if (!updateJsonURL || !releaseAsarURL) {
|
|
201
|
-
log("[updater] no updateJsonURL or releaseAsarURL, use repository");
|
|
196
|
+
async function checkUpdate(url) {
|
|
197
|
+
url ??= _update;
|
|
198
|
+
if (!url) {
|
|
199
|
+
log("no updateJsonURL, use repository");
|
|
202
200
|
if (!repository) {
|
|
203
|
-
throw new Error("updateJsonURL or
|
|
201
|
+
throw new Error("updateJsonURL or repository are not set");
|
|
204
202
|
}
|
|
205
|
-
|
|
206
|
-
releaseAsarURL = `${repository}/releases/download/latest/${productName}.asar.gz`;
|
|
203
|
+
url = `${repository.replace("github.com", "raw.githubusercontent.com")}/version.json`;
|
|
207
204
|
}
|
|
208
|
-
log(
|
|
209
|
-
log("[updater] releaseAsarURL", releaseAsarURL);
|
|
210
|
-
const gzipPath = `../${productName}.asar.gz`;
|
|
211
|
-
const tmpFile = gzipPath.replace(".asar.gz", ".tmp.gz");
|
|
205
|
+
log(`updateJsonURL: ${url}`);
|
|
212
206
|
if (existsSync(tmpFile)) {
|
|
213
|
-
log(
|
|
207
|
+
log(`remove tmp file: ${tmpFile}`);
|
|
214
208
|
await rm(tmpFile);
|
|
215
209
|
}
|
|
216
|
-
const json = await download(
|
|
217
|
-
if (!json) {
|
|
218
|
-
throw new Error("fetch update json failed");
|
|
219
|
-
}
|
|
210
|
+
const json = await download(url, "json");
|
|
220
211
|
const {
|
|
221
|
-
signature,
|
|
212
|
+
signature: _sig,
|
|
222
213
|
version,
|
|
223
214
|
size
|
|
224
215
|
} = json;
|
|
225
|
-
log(
|
|
216
|
+
log(`UpdateJSON: ${JSON.stringify(json, null, 2)}`);
|
|
226
217
|
if (!needUpdate(version)) {
|
|
227
|
-
return
|
|
218
|
+
return false;
|
|
219
|
+
} else {
|
|
220
|
+
signature = _sig;
|
|
221
|
+
return { size, version };
|
|
228
222
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
223
|
+
}
|
|
224
|
+
async function downloadUpdate(src) {
|
|
225
|
+
if (typeof src !== "object") {
|
|
226
|
+
let _url = src ?? _release;
|
|
227
|
+
if (!_url) {
|
|
228
|
+
log("no releaseAsarURL, use repository");
|
|
229
|
+
if (!repository) {
|
|
230
|
+
throw new Error("releaseAsarURL or repository are not set");
|
|
231
|
+
}
|
|
232
|
+
_url = `${repository}/releases/download/latest/${productName}.asar.gz`;
|
|
233
|
+
}
|
|
234
|
+
log(`releaseAsarURL: ${_url}`);
|
|
235
|
+
src = await download(_url, "buffer");
|
|
236
|
+
}
|
|
237
|
+
log("start verify");
|
|
238
|
+
if (!verify(src, signature)) {
|
|
233
239
|
throw new Error("file broken, invalid signature!");
|
|
234
240
|
}
|
|
235
|
-
log(
|
|
236
|
-
await writeFile(gzipPath,
|
|
237
|
-
log(
|
|
241
|
+
log(`write file: ${gzipPath}`);
|
|
242
|
+
await writeFile(gzipPath, src);
|
|
243
|
+
log(`extract file: ${gzipPath}`);
|
|
238
244
|
await extractFile(gzipPath);
|
|
239
|
-
|
|
245
|
+
updater.emit("downloaded");
|
|
240
246
|
}
|
|
241
|
-
const onCheck = async (
|
|
247
|
+
const onCheck = async (url) => {
|
|
242
248
|
try {
|
|
243
|
-
const result = await checkUpdate(
|
|
249
|
+
const result = await checkUpdate(url);
|
|
244
250
|
updater.emit("checkResult", result);
|
|
245
251
|
} catch (error) {
|
|
246
|
-
|
|
252
|
+
log(error);
|
|
253
|
+
updater.emit("checkResult", error);
|
|
247
254
|
}
|
|
248
255
|
};
|
|
249
256
|
updater.on("check", onCheck);
|
|
250
257
|
updater.checkUpdate = onCheck;
|
|
258
|
+
const onDownload = async (src) => {
|
|
259
|
+
try {
|
|
260
|
+
await downloadUpdate(src);
|
|
261
|
+
} catch (error) {
|
|
262
|
+
log(error);
|
|
263
|
+
updater.emit("donwnloadError", error);
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
updater.on("download", onDownload);
|
|
267
|
+
updater.downloadUpdate = onDownload;
|
|
251
268
|
return updater;
|
|
252
269
|
}
|
|
253
270
|
|
|
@@ -273,7 +290,9 @@ export {
|
|
|
273
290
|
getAppAsarPath,
|
|
274
291
|
getAppVersion,
|
|
275
292
|
getEntryVersion,
|
|
276
|
-
|
|
293
|
+
getGithubReleaseCdnGroup,
|
|
277
294
|
initApp,
|
|
278
|
-
|
|
295
|
+
parseGithubCdnURL,
|
|
296
|
+
requireNative,
|
|
297
|
+
restartApp
|
|
279
298
|
};
|