electron-incremental-update 0.4.0 → 0.5.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/README.md +7 -15
- package/dist/chunk-SSJ6PDMK.mjs +61 -0
- package/dist/index.cjs +86 -75
- package/dist/index.d.ts +12 -13
- package/dist/index.mjs +63 -75
- package/dist/vite.cjs +113 -59
- package/dist/vite.mjs +83 -61
- package/package.json +2 -2
- package/dist/chunk-AKU6F3WT.mjs +0 -11
package/README.md
CHANGED
|
@@ -91,9 +91,12 @@ export default function (updater: Updater) {
|
|
|
91
91
|
console.log(`\tentry: ${getEntryVersion()}`)
|
|
92
92
|
console.log(`\tapp: ${getAppVersion(name)}`)
|
|
93
93
|
let size = 0
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
updater.on('downloading', (progress) => {
|
|
95
|
+
console.log(`${(progress / size).toFixed(2)}%`)
|
|
96
|
+
})
|
|
97
|
+
updater.on('debug', data => console.log('[updater]:', data))
|
|
98
|
+
updater.checkUpdate().then(async (result) => {
|
|
99
|
+
if (result === undefined) {
|
|
97
100
|
console.log('Update Unavailable')
|
|
98
101
|
} else if (result instanceof Error) {
|
|
99
102
|
console.error(result)
|
|
@@ -105,20 +108,9 @@ export default function (updater: Updater) {
|
|
|
105
108
|
buttons: ['Download', 'Later'],
|
|
106
109
|
message: 'Application update available!',
|
|
107
110
|
})
|
|
108
|
-
response === 0 && await updater.downloadUpdate()
|
|
111
|
+
response === 0 && console.log(await updater.downloadUpdate())
|
|
109
112
|
}
|
|
110
113
|
})
|
|
111
|
-
updater.on('download', () => console.log('download start'))
|
|
112
|
-
updater.on('downloading', (len) => {
|
|
113
|
-
currentSize += len
|
|
114
|
-
console.log(`${(currentSize / size).toFixed(2)}%`)
|
|
115
|
-
})
|
|
116
|
-
updater.on('downloaded', () => console.log('download end'))
|
|
117
|
-
updater.on('donwnloadError', console.error)
|
|
118
|
-
// to debug, it need to set debug to true in updater options
|
|
119
|
-
updater.on('debug', data => console.log('[updater]:', data))
|
|
120
|
-
updater.checkUpdate()
|
|
121
|
-
|
|
122
114
|
// app logics
|
|
123
115
|
app.whenReady().then(() => {
|
|
124
116
|
// ...
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined")
|
|
5
|
+
return require.apply(this, arguments);
|
|
6
|
+
throw new Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
// src/crypto.ts
|
|
10
|
+
import { constants, createCipheriv, createDecipheriv, createHash, createSign, createVerify, generateKeyPairSync } from "node:crypto";
|
|
11
|
+
import { Buffer as Buffer2 } from "node:buffer";
|
|
12
|
+
var aesEncode = "base64url";
|
|
13
|
+
function generateRSA(length = 2048) {
|
|
14
|
+
const pair = generateKeyPairSync("rsa", { modulusLength: length });
|
|
15
|
+
const privateKey = pair.privateKey.export({ type: "pkcs1", format: "pem" });
|
|
16
|
+
const publicKey = pair.publicKey.export({ type: "pkcs1", format: "pem" });
|
|
17
|
+
return {
|
|
18
|
+
privateKey,
|
|
19
|
+
publicKey
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function encrypt(plainText, key, iv) {
|
|
23
|
+
const cipher = createCipheriv("aes-256-cbc", key, iv);
|
|
24
|
+
let encrypted = cipher.update(plainText, "utf8", aesEncode);
|
|
25
|
+
encrypted += cipher.final(aesEncode);
|
|
26
|
+
return encrypted;
|
|
27
|
+
}
|
|
28
|
+
function decrypt(encryptedText, key, iv) {
|
|
29
|
+
const decipher = createDecipheriv("aes-256-cbc", key, iv);
|
|
30
|
+
let decrypted = decipher.update(encryptedText, aesEncode, "utf8");
|
|
31
|
+
decrypted += decipher.final("utf8");
|
|
32
|
+
return decrypted;
|
|
33
|
+
}
|
|
34
|
+
function generateKey(buffer, str, length) {
|
|
35
|
+
str += createHash("md5").update(buffer.map((v, i) => i & length / 4 && v)).digest("hex");
|
|
36
|
+
const hash = createHash("SHA256").update(str).digest("binary");
|
|
37
|
+
return Buffer2.from(hash).subarray(0, length);
|
|
38
|
+
}
|
|
39
|
+
function signature(buffer, privateKey, publicKey, name) {
|
|
40
|
+
const sig = createSign("RSA-SHA256").update(buffer).sign({
|
|
41
|
+
key: privateKey,
|
|
42
|
+
padding: constants.RSA_PKCS1_PADDING,
|
|
43
|
+
saltLength: constants.RSA_PSS_SALTLEN_DIGEST
|
|
44
|
+
}, "base64");
|
|
45
|
+
return encrypt(sig, generateKey(buffer, publicKey, 32), generateKey(buffer, name, 16));
|
|
46
|
+
}
|
|
47
|
+
function verify(buffer, signature2, publicKey, name) {
|
|
48
|
+
try {
|
|
49
|
+
const sig = decrypt(signature2, generateKey(buffer, publicKey, 32), generateKey(buffer, name, 16));
|
|
50
|
+
return createVerify("RSA-SHA256").update(buffer).verify(publicKey, sig, "base64");
|
|
51
|
+
} catch (error) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export {
|
|
57
|
+
__require,
|
|
58
|
+
generateRSA,
|
|
59
|
+
signature,
|
|
60
|
+
verify
|
|
61
|
+
};
|
package/dist/index.cjs
CHANGED
|
@@ -46,14 +46,37 @@ var import_electron3 = require("electron");
|
|
|
46
46
|
|
|
47
47
|
// src/updater/index.ts
|
|
48
48
|
var import_node_events = require("events");
|
|
49
|
-
var import_node_crypto = require("crypto");
|
|
50
49
|
var import_node_zlib = require("zlib");
|
|
51
50
|
var import_node_fs2 = require("fs");
|
|
52
51
|
var import_promises = require("fs/promises");
|
|
53
52
|
var import_electron2 = require("electron");
|
|
54
53
|
|
|
55
|
-
// src/
|
|
54
|
+
// src/crypto.ts
|
|
55
|
+
var import_node_crypto = require("crypto");
|
|
56
56
|
var import_node_buffer = require("buffer");
|
|
57
|
+
var aesEncode = "base64url";
|
|
58
|
+
function decrypt(encryptedText, key, iv) {
|
|
59
|
+
const decipher = (0, import_node_crypto.createDecipheriv)("aes-256-cbc", key, iv);
|
|
60
|
+
let decrypted = decipher.update(encryptedText, aesEncode, "utf8");
|
|
61
|
+
decrypted += decipher.final("utf8");
|
|
62
|
+
return decrypted;
|
|
63
|
+
}
|
|
64
|
+
function generateKey(buffer, str, length) {
|
|
65
|
+
str += (0, import_node_crypto.createHash)("md5").update(buffer.map((v, i) => i & length / 4 && v)).digest("hex");
|
|
66
|
+
const hash = (0, import_node_crypto.createHash)("SHA256").update(str).digest("binary");
|
|
67
|
+
return import_node_buffer.Buffer.from(hash).subarray(0, length);
|
|
68
|
+
}
|
|
69
|
+
function verify(buffer, signature, publicKey, name) {
|
|
70
|
+
try {
|
|
71
|
+
const sig = decrypt(signature, generateKey(buffer, publicKey, 32), generateKey(buffer, name, 16));
|
|
72
|
+
return (0, import_node_crypto.createVerify)("RSA-SHA256").update(buffer).verify(publicKey, sig, "base64");
|
|
73
|
+
} catch (error) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// src/updater/defaultFunctions.ts
|
|
79
|
+
var import_node_buffer2 = require("buffer");
|
|
57
80
|
var import_node_https = __toESM(require("https"), 1);
|
|
58
81
|
function downloadJSONDefault(url, updater, headers) {
|
|
59
82
|
return new Promise((resolve2, reject) => {
|
|
@@ -80,16 +103,18 @@ function downloadJSONDefault(url, updater, headers) {
|
|
|
80
103
|
});
|
|
81
104
|
}
|
|
82
105
|
function downloadBufferDefault(url, updater, headers) {
|
|
106
|
+
let progress = 0;
|
|
83
107
|
return new Promise((resolve2, reject) => {
|
|
84
108
|
import_node_https.default.get(url, (res) => {
|
|
85
109
|
let data = [];
|
|
86
110
|
res.headers = headers;
|
|
87
111
|
res.on("data", (chunk) => {
|
|
88
|
-
|
|
112
|
+
progress += chunk.length;
|
|
113
|
+
updater.emit("downloading", progress);
|
|
89
114
|
data.push(chunk);
|
|
90
115
|
});
|
|
91
116
|
res.on("end", () => {
|
|
92
|
-
resolve2(
|
|
117
|
+
resolve2(import_node_buffer2.Buffer.concat(data));
|
|
93
118
|
});
|
|
94
119
|
}).on("error", (e) => {
|
|
95
120
|
reject(e);
|
|
@@ -225,9 +250,6 @@ function createUpdater({
|
|
|
225
250
|
});
|
|
226
251
|
});
|
|
227
252
|
}
|
|
228
|
-
function verify(buffer, signature2) {
|
|
229
|
-
return (0, import_node_crypto.createVerify)("RSA-SHA256").update(buffer).verify(SIGNATURE_PUB, signature2, "base64");
|
|
230
|
-
}
|
|
231
253
|
function needUpdate(version2) {
|
|
232
254
|
if (!import_electron2.app.isPackaged) {
|
|
233
255
|
log("in dev mode, no need to update");
|
|
@@ -240,86 +262,75 @@ function createUpdater({
|
|
|
240
262
|
const _compare = compareVersion ?? compareVersionDefault;
|
|
241
263
|
return _compare(currentVersion, version2);
|
|
242
264
|
}
|
|
243
|
-
async
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
throw new Error("updateJsonURL or repository are not set");
|
|
249
|
-
}
|
|
250
|
-
url = `${repository.replace("github.com", "raw.githubusercontent.com")}/master/version.json`;
|
|
251
|
-
}
|
|
252
|
-
if ((0, import_node_fs2.existsSync)(tmpFile)) {
|
|
253
|
-
log(`remove tmp file: ${tmpFile}`);
|
|
254
|
-
await (0, import_promises.rm)(tmpFile);
|
|
255
|
-
}
|
|
256
|
-
if ((0, import_node_fs2.existsSync)(gzipPath)) {
|
|
257
|
-
log(`remove .gz file: ${gzipPath}`);
|
|
258
|
-
await (0, import_promises.rm)(gzipPath);
|
|
259
|
-
}
|
|
260
|
-
const json = await download(url, "json");
|
|
261
|
-
const {
|
|
262
|
-
signature: _sig,
|
|
263
|
-
version: _v,
|
|
264
|
-
size
|
|
265
|
-
} = json;
|
|
266
|
-
log(`update info: ${JSON.stringify(json, null, 2)}`);
|
|
267
|
-
if (!await needUpdate(_v)) {
|
|
268
|
-
log(`update unavailable: ${_v}`);
|
|
269
|
-
return false;
|
|
270
|
-
} else {
|
|
271
|
-
log(`update available: ${_v}`);
|
|
272
|
-
signature = _sig;
|
|
273
|
-
version = _v;
|
|
274
|
-
return { size, version };
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
async function downloadUpdate(src) {
|
|
278
|
-
if (typeof src !== "object") {
|
|
279
|
-
let _url = src ?? _release;
|
|
280
|
-
if (!_url) {
|
|
281
|
-
log("no releaseAsarURL, fallback to use repository");
|
|
265
|
+
updater.checkUpdate = async (url) => {
|
|
266
|
+
try {
|
|
267
|
+
url ??= _update;
|
|
268
|
+
if (!url) {
|
|
269
|
+
log("no updateJsonURL, fallback to use repository");
|
|
282
270
|
if (!repository) {
|
|
283
|
-
throw new Error("
|
|
271
|
+
throw new Error("updateJsonURL or repository are not set");
|
|
284
272
|
}
|
|
285
|
-
|
|
273
|
+
url = `${repository.replace("github.com", "raw.githubusercontent.com")}/master/version.json`;
|
|
274
|
+
}
|
|
275
|
+
if ((0, import_node_fs2.existsSync)(tmpFile)) {
|
|
276
|
+
log(`remove tmp file: ${tmpFile}`);
|
|
277
|
+
await (0, import_promises.rm)(tmpFile);
|
|
278
|
+
}
|
|
279
|
+
if ((0, import_node_fs2.existsSync)(gzipPath)) {
|
|
280
|
+
log(`remove .gz file: ${gzipPath}`);
|
|
281
|
+
await (0, import_promises.rm)(gzipPath);
|
|
282
|
+
}
|
|
283
|
+
const json = await download(url, "json");
|
|
284
|
+
const {
|
|
285
|
+
signature: _sig,
|
|
286
|
+
version: _v,
|
|
287
|
+
size
|
|
288
|
+
} = json;
|
|
289
|
+
log(`update info: ${JSON.stringify(json, null, 2)}`);
|
|
290
|
+
if (!await needUpdate(_v)) {
|
|
291
|
+
log(`update unavailable: ${_v}`);
|
|
292
|
+
return void 0;
|
|
293
|
+
} else {
|
|
294
|
+
log(`update available: ${_v}`);
|
|
295
|
+
signature = _sig;
|
|
296
|
+
version = _v;
|
|
297
|
+
return { size, version };
|
|
286
298
|
}
|
|
287
|
-
src = await download(_url, "buffer");
|
|
288
|
-
}
|
|
289
|
-
log("verify start");
|
|
290
|
-
if (!verify(src, signature)) {
|
|
291
|
-
log("verify failed");
|
|
292
|
-
throw new Error("invalid signature");
|
|
293
|
-
}
|
|
294
|
-
log("verify success");
|
|
295
|
-
log(`write file: ${gzipPath}`);
|
|
296
|
-
await (0, import_promises.writeFile)(gzipPath, src);
|
|
297
|
-
log(`extract file: ${gzipPath}`);
|
|
298
|
-
await extractFile(gzipPath);
|
|
299
|
-
log(`update success, version: ${version}`);
|
|
300
|
-
updater.emit("downloaded");
|
|
301
|
-
}
|
|
302
|
-
const onCheck = async (url) => {
|
|
303
|
-
try {
|
|
304
|
-
const result = await checkUpdate(url);
|
|
305
|
-
updater.emit("checkResult", result);
|
|
306
299
|
} catch (error) {
|
|
307
300
|
log(error);
|
|
308
|
-
|
|
301
|
+
return error;
|
|
309
302
|
}
|
|
310
303
|
};
|
|
311
|
-
updater.
|
|
312
|
-
updater.checkUpdate = onCheck;
|
|
313
|
-
const onDownload = async (src) => {
|
|
304
|
+
updater.downloadUpdate = async (src) => {
|
|
314
305
|
try {
|
|
315
|
-
|
|
306
|
+
if (typeof src !== "object") {
|
|
307
|
+
let _url = src ?? _release;
|
|
308
|
+
if (!_url) {
|
|
309
|
+
log("no releaseAsarURL, fallback to use repository");
|
|
310
|
+
if (!repository) {
|
|
311
|
+
throw new Error("releaseAsarURL or repository are not set");
|
|
312
|
+
}
|
|
313
|
+
_url = `${repository}/releases/download/latest/${productName}.asar.gz`;
|
|
314
|
+
}
|
|
315
|
+
src = await download(_url, "buffer");
|
|
316
|
+
}
|
|
317
|
+
log("verify start");
|
|
318
|
+
if (!verify(src, signature, SIGNATURE_PUB, productName)) {
|
|
319
|
+
log("verify failed");
|
|
320
|
+
throw new Error("invalid signature");
|
|
321
|
+
}
|
|
322
|
+
log("verify success");
|
|
323
|
+
log(`write file: ${gzipPath}`);
|
|
324
|
+
await (0, import_promises.writeFile)(gzipPath, src);
|
|
325
|
+
log(`extract file: ${gzipPath}`);
|
|
326
|
+
await extractFile(gzipPath);
|
|
327
|
+
log(`update success, version: ${version}`);
|
|
328
|
+
return true;
|
|
316
329
|
} catch (error) {
|
|
317
330
|
log(error);
|
|
318
|
-
|
|
331
|
+
return error;
|
|
319
332
|
}
|
|
320
333
|
};
|
|
321
|
-
updater.on("download", onDownload);
|
|
322
|
-
updater.downloadUpdate = onDownload;
|
|
323
334
|
return updater;
|
|
324
335
|
}
|
|
325
336
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
2
|
|
|
3
|
-
type CheckResultType =
|
|
3
|
+
type CheckResultType = Omit<UpdateJSON, 'signature'> | undefined | Error;
|
|
4
|
+
type DownloadResult = true | Error;
|
|
4
5
|
type UpdateEvents = {
|
|
5
|
-
|
|
6
|
-
checkResult: [data: CheckResultType];
|
|
7
|
-
download: [src?: string | Buffer];
|
|
8
|
-
downloading: [current: number];
|
|
9
|
-
downloaded: null;
|
|
10
|
-
donwnloadError: [error: unknown];
|
|
6
|
+
downloading: [progress: number];
|
|
11
7
|
debug: [msg: string | Error];
|
|
12
8
|
};
|
|
13
9
|
type UpdateJSON = {
|
|
@@ -21,16 +17,19 @@ interface TypedUpdater<T extends Record<string | symbol, MaybeArray<any>>, Event
|
|
|
21
17
|
listeners<E extends Event>(eventName: E): Function[];
|
|
22
18
|
eventNames(): (Event)[];
|
|
23
19
|
on<E extends Event>(eventName: E, listener: (...data: MaybeArray<T[E]>) => void): this;
|
|
24
|
-
once<E extends Event>(eventName: E, listener: (...args: MaybeArray<T[E]>) => void): this;
|
|
25
20
|
emit<E extends Event>(eventName: E, ...args: MaybeArray<T[E]>): boolean;
|
|
26
21
|
off<E extends Event>(eventName: E, listener: (...args: MaybeArray<T[E]>) => void): this;
|
|
27
22
|
/**
|
|
28
|
-
* - `
|
|
23
|
+
* - `{size: number, version: string}`: available
|
|
29
24
|
* - `false`: unavailable
|
|
30
|
-
* - `
|
|
25
|
+
* - `Error`: fail
|
|
31
26
|
*/
|
|
32
|
-
checkUpdate(url?: string): Promise<
|
|
33
|
-
|
|
27
|
+
checkUpdate(url?: string): Promise<CheckResultType>;
|
|
28
|
+
/**
|
|
29
|
+
* - `true`: success
|
|
30
|
+
* - `Error`: fail
|
|
31
|
+
*/
|
|
32
|
+
downloadUpdate(url?: string | Buffer): Promise<DownloadResult>;
|
|
34
33
|
}
|
|
35
34
|
type Updater = TypedUpdater<UpdateEvents>;
|
|
36
35
|
interface UpdaterOption {
|
|
@@ -210,4 +209,4 @@ declare function initApp(appOptions: AppOption): {
|
|
|
210
209
|
*/
|
|
211
210
|
declare function initApp(appOptions: AppOption, updaterOptions: InitUpdaterOptions): undefined;
|
|
212
211
|
|
|
213
|
-
export { AppOption, CheckResultType, InitUpdaterOptions, UpdateJSON, Updater, UpdaterOption, createUpdater, getAppAsarPath, getAppVersion, getEntryVersion, getGithubReleaseCdnGroup, initApp, parseGithubCdnURL, requireNative, restartApp };
|
|
212
|
+
export { AppOption, CheckResultType, DownloadResult, InitUpdaterOptions, UpdateJSON, Updater, UpdaterOption, createUpdater, getAppAsarPath, getAppVersion, getEntryVersion, getGithubReleaseCdnGroup, initApp, parseGithubCdnURL, requireNative, restartApp };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
-
__require
|
|
3
|
-
|
|
2
|
+
__require,
|
|
3
|
+
verify
|
|
4
|
+
} from "./chunk-SSJ6PDMK.mjs";
|
|
4
5
|
|
|
5
6
|
// src/index.ts
|
|
6
7
|
import { resolve } from "node:path";
|
|
@@ -8,7 +9,6 @@ import { app as app3 } from "electron";
|
|
|
8
9
|
|
|
9
10
|
// src/updater/index.ts
|
|
10
11
|
import { EventEmitter } from "node:events";
|
|
11
|
-
import { createVerify } from "node:crypto";
|
|
12
12
|
import { createGunzip } from "node:zlib";
|
|
13
13
|
import { createReadStream, createWriteStream, existsSync } from "node:fs";
|
|
14
14
|
import { rm, writeFile } from "node:fs/promises";
|
|
@@ -42,12 +42,14 @@ function downloadJSONDefault(url, updater, headers) {
|
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
44
|
function downloadBufferDefault(url, updater, headers) {
|
|
45
|
+
let progress = 0;
|
|
45
46
|
return new Promise((resolve2, reject) => {
|
|
46
47
|
https.get(url, (res) => {
|
|
47
48
|
let data = [];
|
|
48
49
|
res.headers = headers;
|
|
49
50
|
res.on("data", (chunk) => {
|
|
50
|
-
|
|
51
|
+
progress += chunk.length;
|
|
52
|
+
updater.emit("downloading", progress);
|
|
51
53
|
data.push(chunk);
|
|
52
54
|
});
|
|
53
55
|
res.on("end", () => {
|
|
@@ -187,9 +189,6 @@ function createUpdater({
|
|
|
187
189
|
});
|
|
188
190
|
});
|
|
189
191
|
}
|
|
190
|
-
function verify(buffer, signature2) {
|
|
191
|
-
return createVerify("RSA-SHA256").update(buffer).verify(SIGNATURE_PUB, signature2, "base64");
|
|
192
|
-
}
|
|
193
192
|
function needUpdate(version2) {
|
|
194
193
|
if (!app2.isPackaged) {
|
|
195
194
|
log("in dev mode, no need to update");
|
|
@@ -202,86 +201,75 @@ function createUpdater({
|
|
|
202
201
|
const _compare = compareVersion ?? compareVersionDefault;
|
|
203
202
|
return _compare(currentVersion, version2);
|
|
204
203
|
}
|
|
205
|
-
async
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
throw new Error("updateJsonURL or repository are not set");
|
|
211
|
-
}
|
|
212
|
-
url = `${repository.replace("github.com", "raw.githubusercontent.com")}/master/version.json`;
|
|
213
|
-
}
|
|
214
|
-
if (existsSync(tmpFile)) {
|
|
215
|
-
log(`remove tmp file: ${tmpFile}`);
|
|
216
|
-
await rm(tmpFile);
|
|
217
|
-
}
|
|
218
|
-
if (existsSync(gzipPath)) {
|
|
219
|
-
log(`remove .gz file: ${gzipPath}`);
|
|
220
|
-
await rm(gzipPath);
|
|
221
|
-
}
|
|
222
|
-
const json = await download(url, "json");
|
|
223
|
-
const {
|
|
224
|
-
signature: _sig,
|
|
225
|
-
version: _v,
|
|
226
|
-
size
|
|
227
|
-
} = json;
|
|
228
|
-
log(`update info: ${JSON.stringify(json, null, 2)}`);
|
|
229
|
-
if (!await needUpdate(_v)) {
|
|
230
|
-
log(`update unavailable: ${_v}`);
|
|
231
|
-
return false;
|
|
232
|
-
} else {
|
|
233
|
-
log(`update available: ${_v}`);
|
|
234
|
-
signature = _sig;
|
|
235
|
-
version = _v;
|
|
236
|
-
return { size, version };
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
async function downloadUpdate(src) {
|
|
240
|
-
if (typeof src !== "object") {
|
|
241
|
-
let _url = src ?? _release;
|
|
242
|
-
if (!_url) {
|
|
243
|
-
log("no releaseAsarURL, fallback to use repository");
|
|
204
|
+
updater.checkUpdate = async (url) => {
|
|
205
|
+
try {
|
|
206
|
+
url ??= _update;
|
|
207
|
+
if (!url) {
|
|
208
|
+
log("no updateJsonURL, fallback to use repository");
|
|
244
209
|
if (!repository) {
|
|
245
|
-
throw new Error("
|
|
210
|
+
throw new Error("updateJsonURL or repository are not set");
|
|
246
211
|
}
|
|
247
|
-
|
|
212
|
+
url = `${repository.replace("github.com", "raw.githubusercontent.com")}/master/version.json`;
|
|
213
|
+
}
|
|
214
|
+
if (existsSync(tmpFile)) {
|
|
215
|
+
log(`remove tmp file: ${tmpFile}`);
|
|
216
|
+
await rm(tmpFile);
|
|
217
|
+
}
|
|
218
|
+
if (existsSync(gzipPath)) {
|
|
219
|
+
log(`remove .gz file: ${gzipPath}`);
|
|
220
|
+
await rm(gzipPath);
|
|
221
|
+
}
|
|
222
|
+
const json = await download(url, "json");
|
|
223
|
+
const {
|
|
224
|
+
signature: _sig,
|
|
225
|
+
version: _v,
|
|
226
|
+
size
|
|
227
|
+
} = json;
|
|
228
|
+
log(`update info: ${JSON.stringify(json, null, 2)}`);
|
|
229
|
+
if (!await needUpdate(_v)) {
|
|
230
|
+
log(`update unavailable: ${_v}`);
|
|
231
|
+
return void 0;
|
|
232
|
+
} else {
|
|
233
|
+
log(`update available: ${_v}`);
|
|
234
|
+
signature = _sig;
|
|
235
|
+
version = _v;
|
|
236
|
+
return { size, version };
|
|
248
237
|
}
|
|
249
|
-
src = await download(_url, "buffer");
|
|
250
|
-
}
|
|
251
|
-
log("verify start");
|
|
252
|
-
if (!verify(src, signature)) {
|
|
253
|
-
log("verify failed");
|
|
254
|
-
throw new Error("invalid signature");
|
|
255
|
-
}
|
|
256
|
-
log("verify success");
|
|
257
|
-
log(`write file: ${gzipPath}`);
|
|
258
|
-
await writeFile(gzipPath, src);
|
|
259
|
-
log(`extract file: ${gzipPath}`);
|
|
260
|
-
await extractFile(gzipPath);
|
|
261
|
-
log(`update success, version: ${version}`);
|
|
262
|
-
updater.emit("downloaded");
|
|
263
|
-
}
|
|
264
|
-
const onCheck = async (url) => {
|
|
265
|
-
try {
|
|
266
|
-
const result = await checkUpdate(url);
|
|
267
|
-
updater.emit("checkResult", result);
|
|
268
238
|
} catch (error) {
|
|
269
239
|
log(error);
|
|
270
|
-
|
|
240
|
+
return error;
|
|
271
241
|
}
|
|
272
242
|
};
|
|
273
|
-
updater.
|
|
274
|
-
updater.checkUpdate = onCheck;
|
|
275
|
-
const onDownload = async (src) => {
|
|
243
|
+
updater.downloadUpdate = async (src) => {
|
|
276
244
|
try {
|
|
277
|
-
|
|
245
|
+
if (typeof src !== "object") {
|
|
246
|
+
let _url = src ?? _release;
|
|
247
|
+
if (!_url) {
|
|
248
|
+
log("no releaseAsarURL, fallback to use repository");
|
|
249
|
+
if (!repository) {
|
|
250
|
+
throw new Error("releaseAsarURL or repository are not set");
|
|
251
|
+
}
|
|
252
|
+
_url = `${repository}/releases/download/latest/${productName}.asar.gz`;
|
|
253
|
+
}
|
|
254
|
+
src = await download(_url, "buffer");
|
|
255
|
+
}
|
|
256
|
+
log("verify start");
|
|
257
|
+
if (!verify(src, signature, SIGNATURE_PUB, productName)) {
|
|
258
|
+
log("verify failed");
|
|
259
|
+
throw new Error("invalid signature");
|
|
260
|
+
}
|
|
261
|
+
log("verify success");
|
|
262
|
+
log(`write file: ${gzipPath}`);
|
|
263
|
+
await writeFile(gzipPath, src);
|
|
264
|
+
log(`extract file: ${gzipPath}`);
|
|
265
|
+
await extractFile(gzipPath);
|
|
266
|
+
log(`update success, version: ${version}`);
|
|
267
|
+
return true;
|
|
278
268
|
} catch (error) {
|
|
279
269
|
log(error);
|
|
280
|
-
|
|
270
|
+
return error;
|
|
281
271
|
}
|
|
282
272
|
};
|
|
283
|
-
updater.on("download", onDownload);
|
|
284
|
-
updater.downloadUpdate = onDownload;
|
|
285
273
|
return updater;
|
|
286
274
|
}
|
|
287
275
|
|
package/dist/vite.cjs
CHANGED
|
@@ -36,11 +36,44 @@ module.exports = __toCommonJS(vite_exports);
|
|
|
36
36
|
var import_vite = require("vite");
|
|
37
37
|
|
|
38
38
|
// src/build-plugins/asar.ts
|
|
39
|
-
var import_node_crypto = require("crypto");
|
|
40
39
|
var import_node_fs = require("fs");
|
|
41
40
|
var import_promises = require("fs/promises");
|
|
42
41
|
var import_node_zlib = __toESM(require("zlib"), 1);
|
|
43
|
-
|
|
42
|
+
|
|
43
|
+
// src/crypto.ts
|
|
44
|
+
var import_node_crypto = require("crypto");
|
|
45
|
+
var import_node_buffer = require("buffer");
|
|
46
|
+
var aesEncode = "base64url";
|
|
47
|
+
function generateRSA(length = 2048) {
|
|
48
|
+
const pair = (0, import_node_crypto.generateKeyPairSync)("rsa", { modulusLength: length });
|
|
49
|
+
const privateKey = pair.privateKey.export({ type: "pkcs1", format: "pem" });
|
|
50
|
+
const publicKey = pair.publicKey.export({ type: "pkcs1", format: "pem" });
|
|
51
|
+
return {
|
|
52
|
+
privateKey,
|
|
53
|
+
publicKey
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function encrypt(plainText, key, iv) {
|
|
57
|
+
const cipher = (0, import_node_crypto.createCipheriv)("aes-256-cbc", key, iv);
|
|
58
|
+
let encrypted = cipher.update(plainText, "utf8", aesEncode);
|
|
59
|
+
encrypted += cipher.final(aesEncode);
|
|
60
|
+
return encrypted;
|
|
61
|
+
}
|
|
62
|
+
function generateKey(buffer, str, length) {
|
|
63
|
+
str += (0, import_node_crypto.createHash)("md5").update(buffer.map((v, i) => i & length / 4 && v)).digest("hex");
|
|
64
|
+
const hash = (0, import_node_crypto.createHash)("SHA256").update(str).digest("binary");
|
|
65
|
+
return import_node_buffer.Buffer.from(hash).subarray(0, length);
|
|
66
|
+
}
|
|
67
|
+
function signature(buffer, privateKey, publicKey, name) {
|
|
68
|
+
const sig = (0, import_node_crypto.createSign)("RSA-SHA256").update(buffer).sign({
|
|
69
|
+
key: privateKey,
|
|
70
|
+
padding: import_node_crypto.constants.RSA_PKCS1_PADDING,
|
|
71
|
+
saltLength: import_node_crypto.constants.RSA_PSS_SALTLEN_DIGEST
|
|
72
|
+
}, "base64");
|
|
73
|
+
return encrypt(sig, generateKey(buffer, publicKey, 32), generateKey(buffer, name, 16));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// src/build-plugins/asar.ts
|
|
44
77
|
function gzipFile(filePath) {
|
|
45
78
|
return new Promise((resolve, reject) => {
|
|
46
79
|
const gzip = import_node_zlib.default.createGzip();
|
|
@@ -49,13 +82,6 @@ function gzipFile(filePath) {
|
|
|
49
82
|
input.pipe(gzip).pipe(output).on("finish", () => resolve(null)).on("error", (err) => reject(err));
|
|
50
83
|
});
|
|
51
84
|
}
|
|
52
|
-
function generateSignature(buffer, privateKey) {
|
|
53
|
-
return (0, import_node_crypto.createSign)("RSA-SHA256").update(buffer).sign({
|
|
54
|
-
key: privateKey,
|
|
55
|
-
padding: import_node_crypto.constants.RSA_PKCS1_PADDING,
|
|
56
|
-
saltLength: import_node_crypto.constants.RSA_PSS_SALTLEN_DIGEST
|
|
57
|
-
}, "base64");
|
|
58
|
-
}
|
|
59
85
|
async function pack(dir, target) {
|
|
60
86
|
let asar = null;
|
|
61
87
|
try {
|
|
@@ -76,47 +102,61 @@ async function pack(dir, target) {
|
|
|
76
102
|
async function buildAsar({
|
|
77
103
|
version,
|
|
78
104
|
asarOutputPath,
|
|
79
|
-
privateKeyPath,
|
|
80
105
|
electronDistPath,
|
|
81
|
-
rendererDistPath
|
|
82
|
-
versionPath
|
|
106
|
+
rendererDistPath
|
|
83
107
|
}) {
|
|
84
108
|
await (0, import_promises.rename)(rendererDistPath, `${electronDistPath}/renderer`);
|
|
85
109
|
await (0, import_promises.writeFile)(`${electronDistPath}/version`, version);
|
|
86
110
|
await pack(electronDistPath, asarOutputPath);
|
|
87
111
|
await gzipFile(asarOutputPath);
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
112
|
+
}
|
|
113
|
+
async function generateVersion({
|
|
114
|
+
asarOutputPath,
|
|
115
|
+
versionPath,
|
|
116
|
+
privateKey,
|
|
117
|
+
publicKey,
|
|
118
|
+
productName,
|
|
119
|
+
version
|
|
120
|
+
}) {
|
|
91
121
|
const buffer = await (0, import_promises.readFile)(`${asarOutputPath}.gz`);
|
|
92
|
-
const signature = generateSignature(buffer, await (0, import_promises.readFile)(privateKeyPath, "utf-8"));
|
|
93
122
|
await (0, import_promises.writeFile)(versionPath, JSON.stringify({
|
|
94
|
-
signature,
|
|
123
|
+
signature: signature(buffer, privateKey, publicKey, productName),
|
|
95
124
|
version,
|
|
96
125
|
size: buffer.length
|
|
97
126
|
}, null, 2));
|
|
98
127
|
}
|
|
99
128
|
|
|
100
129
|
// src/build-plugins/entry.ts
|
|
130
|
+
var import_esbuild = require("esbuild");
|
|
131
|
+
async function buildEntry({
|
|
132
|
+
entryPath,
|
|
133
|
+
entryOutputPath: outfile,
|
|
134
|
+
minify
|
|
135
|
+
}) {
|
|
136
|
+
await (0, import_esbuild.build)({
|
|
137
|
+
entryPoints: [entryPath],
|
|
138
|
+
bundle: true,
|
|
139
|
+
platform: "node",
|
|
140
|
+
outfile,
|
|
141
|
+
minify,
|
|
142
|
+
external: ["electron"]
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// src/build-plugins/key.ts
|
|
101
147
|
var import_node_fs2 = require("fs");
|
|
102
148
|
var import_node_path = require("path");
|
|
103
|
-
var import_promises2 = require("fs/promises");
|
|
104
|
-
var import_node_crypto2 = require("crypto");
|
|
105
149
|
var import_node_os = require("os");
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const publicKey = pair.publicKey.export({ type: "pkcs1", format: "pem" });
|
|
112
|
-
await (0, import_promises2.writeFile)(privateKeyPath, privateKey);
|
|
113
|
-
await (0, import_promises2.writeFile)(publicKeyPath, publicKey);
|
|
150
|
+
function generateKey2(privateKeyPath, publicKeyPath, length) {
|
|
151
|
+
const ret = generateRSA(length);
|
|
152
|
+
(0, import_node_fs2.writeFileSync)(privateKeyPath, ret.privateKey);
|
|
153
|
+
(0, import_node_fs2.writeFileSync)(publicKeyPath, ret.publicKey);
|
|
154
|
+
return ret;
|
|
114
155
|
}
|
|
115
|
-
|
|
116
|
-
const file =
|
|
117
|
-
const key = await (0, import_promises2.readFile)(publicKeyPath, "utf-8");
|
|
156
|
+
function writePublicKeyToMain(entryPath, publicKey) {
|
|
157
|
+
const file = (0, import_node_fs2.readFileSync)(entryPath, "utf-8");
|
|
118
158
|
const regex = /const SIGNATURE_PUB = ['`][\s\S]*?['`]/;
|
|
119
|
-
const replacement = `const SIGNATURE_PUB = \`${
|
|
159
|
+
const replacement = `const SIGNATURE_PUB = \`${publicKey}\``;
|
|
120
160
|
let replaced = file;
|
|
121
161
|
const signaturePubExists = regex.test(file);
|
|
122
162
|
if (signaturePubExists) {
|
|
@@ -136,33 +176,34 @@ async function writePublicKeyToMain(updatePath, publicKeyPath) {
|
|
|
136
176
|
!isMatched && lines.push(r);
|
|
137
177
|
replaced = lines.join(import_node_os.EOL);
|
|
138
178
|
}
|
|
139
|
-
|
|
179
|
+
(0, import_node_fs2.writeFileSync)(entryPath, replaced);
|
|
140
180
|
}
|
|
141
|
-
|
|
181
|
+
function getKeys({
|
|
182
|
+
keyLength,
|
|
142
183
|
privateKeyPath,
|
|
143
184
|
publicKeyPath,
|
|
144
|
-
entryPath
|
|
145
|
-
entryOutputPath: outfile,
|
|
146
|
-
minify,
|
|
147
|
-
keyLength
|
|
185
|
+
entryPath
|
|
148
186
|
}) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
187
|
+
const keysDir = (0, import_node_path.dirname)(privateKeyPath);
|
|
188
|
+
!(0, import_node_fs2.existsSync)(keysDir) && (0, import_node_fs2.mkdirSync)(keysDir);
|
|
189
|
+
let privateKey, publicKey;
|
|
190
|
+
if (!(0, import_node_fs2.existsSync)(privateKeyPath)) {
|
|
191
|
+
const keys = generateKey2(privateKeyPath, publicKeyPath, keyLength);
|
|
192
|
+
privateKey = keys.privateKey;
|
|
193
|
+
publicKey = keys.publicKey;
|
|
194
|
+
} else {
|
|
195
|
+
privateKey = (0, import_node_fs2.readFileSync)(privateKeyPath, "utf-8");
|
|
196
|
+
publicKey = (0, import_node_fs2.readFileSync)(publicKeyPath, "utf-8");
|
|
154
197
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
minify,
|
|
161
|
-
external: ["electron"]
|
|
162
|
-
});
|
|
198
|
+
writePublicKeyToMain(entryPath, publicKey);
|
|
199
|
+
return {
|
|
200
|
+
privateKey,
|
|
201
|
+
publicKey
|
|
202
|
+
};
|
|
163
203
|
}
|
|
164
204
|
|
|
165
205
|
// src/build-plugins/option.ts
|
|
206
|
+
var import_ci_info = require("ci-info");
|
|
166
207
|
function parseOptions(options) {
|
|
167
208
|
const { isBuild, productName, version, minify = false, paths = {}, keys = {} } = options;
|
|
168
209
|
const {
|
|
@@ -181,25 +222,37 @@ function parseOptions(options) {
|
|
|
181
222
|
const buildAsarOption = {
|
|
182
223
|
version,
|
|
183
224
|
asarOutputPath,
|
|
184
|
-
privateKeyPath,
|
|
185
225
|
electronDistPath,
|
|
186
|
-
rendererDistPath
|
|
187
|
-
versionPath
|
|
226
|
+
rendererDistPath
|
|
188
227
|
};
|
|
189
228
|
const buildEntryOption = {
|
|
190
|
-
privateKeyPath,
|
|
191
|
-
publicKeyPath,
|
|
192
229
|
entryPath,
|
|
193
230
|
entryOutputPath,
|
|
194
|
-
minify
|
|
195
|
-
keyLength
|
|
231
|
+
minify
|
|
196
232
|
};
|
|
197
|
-
|
|
233
|
+
let buildVersionOption;
|
|
234
|
+
if (!import_ci_info.isCI) {
|
|
235
|
+
const { privateKey, publicKey } = getKeys({
|
|
236
|
+
keyLength,
|
|
237
|
+
privateKeyPath,
|
|
238
|
+
publicKeyPath,
|
|
239
|
+
entryPath
|
|
240
|
+
});
|
|
241
|
+
buildVersionOption = {
|
|
242
|
+
version,
|
|
243
|
+
asarOutputPath,
|
|
244
|
+
privateKey,
|
|
245
|
+
publicKey,
|
|
246
|
+
productName,
|
|
247
|
+
versionPath
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
return { isBuild, buildAsarOption, buildEntryOption, buildVersionOption };
|
|
198
251
|
}
|
|
199
252
|
|
|
200
253
|
// src/vite.ts
|
|
201
254
|
function vite_default(options) {
|
|
202
|
-
const { isBuild, buildAsarOption, buildEntryOption } = parseOptions(options);
|
|
255
|
+
const { isBuild, buildAsarOption, buildEntryOption, buildVersionOption } = parseOptions(options);
|
|
203
256
|
const { entryPath, entryOutputPath } = buildEntryOption;
|
|
204
257
|
const { asarOutputPath } = buildAsarOption;
|
|
205
258
|
const id = "electron-incremental-updater";
|
|
@@ -216,6 +269,7 @@ function vite_default(options) {
|
|
|
216
269
|
}
|
|
217
270
|
log.info("build asar start");
|
|
218
271
|
await buildAsar(buildAsarOption);
|
|
272
|
+
buildVersionOption && await generateVersion(buildVersionOption);
|
|
219
273
|
log.info(`build asar end, output to ${asarOutputPath}`);
|
|
220
274
|
}
|
|
221
275
|
};
|
package/dist/vite.mjs
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
generateRSA,
|
|
3
|
+
signature
|
|
4
|
+
} from "./chunk-SSJ6PDMK.mjs";
|
|
2
5
|
|
|
3
6
|
// src/vite.ts
|
|
4
7
|
import { createLogger } from "vite";
|
|
5
8
|
|
|
6
9
|
// src/build-plugins/asar.ts
|
|
7
|
-
import { constants, createSign } from "node:crypto";
|
|
8
10
|
import { createReadStream, createWriteStream } from "node:fs";
|
|
9
11
|
import { readFile, rename, writeFile } from "node:fs/promises";
|
|
10
12
|
import zlib from "node:zlib";
|
|
11
|
-
import { isCI } from "ci-info";
|
|
12
13
|
function gzipFile(filePath) {
|
|
13
14
|
return new Promise((resolve, reject) => {
|
|
14
15
|
const gzip = zlib.createGzip();
|
|
@@ -17,13 +18,6 @@ function gzipFile(filePath) {
|
|
|
17
18
|
input.pipe(gzip).pipe(output).on("finish", () => resolve(null)).on("error", (err) => reject(err));
|
|
18
19
|
});
|
|
19
20
|
}
|
|
20
|
-
function generateSignature(buffer, privateKey) {
|
|
21
|
-
return createSign("RSA-SHA256").update(buffer).sign({
|
|
22
|
-
key: privateKey,
|
|
23
|
-
padding: constants.RSA_PKCS1_PADDING,
|
|
24
|
-
saltLength: constants.RSA_PSS_SALTLEN_DIGEST
|
|
25
|
-
}, "base64");
|
|
26
|
-
}
|
|
27
21
|
async function pack(dir, target) {
|
|
28
22
|
let asar = null;
|
|
29
23
|
try {
|
|
@@ -44,47 +38,61 @@ async function pack(dir, target) {
|
|
|
44
38
|
async function buildAsar({
|
|
45
39
|
version,
|
|
46
40
|
asarOutputPath,
|
|
47
|
-
privateKeyPath,
|
|
48
41
|
electronDistPath,
|
|
49
|
-
rendererDistPath
|
|
50
|
-
versionPath
|
|
42
|
+
rendererDistPath
|
|
51
43
|
}) {
|
|
52
44
|
await rename(rendererDistPath, `${electronDistPath}/renderer`);
|
|
53
45
|
await writeFile(`${electronDistPath}/version`, version);
|
|
54
46
|
await pack(electronDistPath, asarOutputPath);
|
|
55
47
|
await gzipFile(asarOutputPath);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
48
|
+
}
|
|
49
|
+
async function generateVersion({
|
|
50
|
+
asarOutputPath,
|
|
51
|
+
versionPath,
|
|
52
|
+
privateKey,
|
|
53
|
+
publicKey,
|
|
54
|
+
productName,
|
|
55
|
+
version
|
|
56
|
+
}) {
|
|
59
57
|
const buffer = await readFile(`${asarOutputPath}.gz`);
|
|
60
|
-
const signature = generateSignature(buffer, await readFile(privateKeyPath, "utf-8"));
|
|
61
58
|
await writeFile(versionPath, JSON.stringify({
|
|
62
|
-
signature,
|
|
59
|
+
signature: signature(buffer, privateKey, publicKey, productName),
|
|
63
60
|
version,
|
|
64
61
|
size: buffer.length
|
|
65
62
|
}, null, 2));
|
|
66
63
|
}
|
|
67
64
|
|
|
68
65
|
// src/build-plugins/entry.ts
|
|
69
|
-
import {
|
|
66
|
+
import { build } from "esbuild";
|
|
67
|
+
async function buildEntry({
|
|
68
|
+
entryPath,
|
|
69
|
+
entryOutputPath: outfile,
|
|
70
|
+
minify
|
|
71
|
+
}) {
|
|
72
|
+
await build({
|
|
73
|
+
entryPoints: [entryPath],
|
|
74
|
+
bundle: true,
|
|
75
|
+
platform: "node",
|
|
76
|
+
outfile,
|
|
77
|
+
minify,
|
|
78
|
+
external: ["electron"]
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/build-plugins/key.ts
|
|
83
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
70
84
|
import { dirname } from "node:path";
|
|
71
|
-
import { mkdir, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
72
|
-
import { generateKeyPairSync } from "node:crypto";
|
|
73
85
|
import { EOL } from "node:os";
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const publicKey = pair.publicKey.export({ type: "pkcs1", format: "pem" });
|
|
80
|
-
await writeFile2(privateKeyPath, privateKey);
|
|
81
|
-
await writeFile2(publicKeyPath, publicKey);
|
|
86
|
+
function generateKey(privateKeyPath, publicKeyPath, length) {
|
|
87
|
+
const ret = generateRSA(length);
|
|
88
|
+
writeFileSync(privateKeyPath, ret.privateKey);
|
|
89
|
+
writeFileSync(publicKeyPath, ret.publicKey);
|
|
90
|
+
return ret;
|
|
82
91
|
}
|
|
83
|
-
|
|
84
|
-
const file =
|
|
85
|
-
const key = await readFile2(publicKeyPath, "utf-8");
|
|
92
|
+
function writePublicKeyToMain(entryPath, publicKey) {
|
|
93
|
+
const file = readFileSync(entryPath, "utf-8");
|
|
86
94
|
const regex = /const SIGNATURE_PUB = ['`][\s\S]*?['`]/;
|
|
87
|
-
const replacement = `const SIGNATURE_PUB = \`${
|
|
95
|
+
const replacement = `const SIGNATURE_PUB = \`${publicKey}\``;
|
|
88
96
|
let replaced = file;
|
|
89
97
|
const signaturePubExists = regex.test(file);
|
|
90
98
|
if (signaturePubExists) {
|
|
@@ -104,33 +112,34 @@ async function writePublicKeyToMain(updatePath, publicKeyPath) {
|
|
|
104
112
|
!isMatched && lines.push(r);
|
|
105
113
|
replaced = lines.join(EOL);
|
|
106
114
|
}
|
|
107
|
-
|
|
115
|
+
writeFileSync(entryPath, replaced);
|
|
108
116
|
}
|
|
109
|
-
|
|
117
|
+
function getKeys({
|
|
118
|
+
keyLength,
|
|
110
119
|
privateKeyPath,
|
|
111
120
|
publicKeyPath,
|
|
112
|
-
entryPath
|
|
113
|
-
entryOutputPath: outfile,
|
|
114
|
-
minify,
|
|
115
|
-
keyLength
|
|
121
|
+
entryPath
|
|
116
122
|
}) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
123
|
+
const keysDir = dirname(privateKeyPath);
|
|
124
|
+
!existsSync(keysDir) && mkdirSync(keysDir);
|
|
125
|
+
let privateKey, publicKey;
|
|
126
|
+
if (!existsSync(privateKeyPath)) {
|
|
127
|
+
const keys = generateKey(privateKeyPath, publicKeyPath, keyLength);
|
|
128
|
+
privateKey = keys.privateKey;
|
|
129
|
+
publicKey = keys.publicKey;
|
|
130
|
+
} else {
|
|
131
|
+
privateKey = readFileSync(privateKeyPath, "utf-8");
|
|
132
|
+
publicKey = readFileSync(publicKeyPath, "utf-8");
|
|
122
133
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
minify,
|
|
129
|
-
external: ["electron"]
|
|
130
|
-
});
|
|
134
|
+
writePublicKeyToMain(entryPath, publicKey);
|
|
135
|
+
return {
|
|
136
|
+
privateKey,
|
|
137
|
+
publicKey
|
|
138
|
+
};
|
|
131
139
|
}
|
|
132
140
|
|
|
133
141
|
// src/build-plugins/option.ts
|
|
142
|
+
import { isCI } from "ci-info";
|
|
134
143
|
function parseOptions(options) {
|
|
135
144
|
const { isBuild, productName, version, minify = false, paths = {}, keys = {} } = options;
|
|
136
145
|
const {
|
|
@@ -149,25 +158,37 @@ function parseOptions(options) {
|
|
|
149
158
|
const buildAsarOption = {
|
|
150
159
|
version,
|
|
151
160
|
asarOutputPath,
|
|
152
|
-
privateKeyPath,
|
|
153
161
|
electronDistPath,
|
|
154
|
-
rendererDistPath
|
|
155
|
-
versionPath
|
|
162
|
+
rendererDistPath
|
|
156
163
|
};
|
|
157
164
|
const buildEntryOption = {
|
|
158
|
-
privateKeyPath,
|
|
159
|
-
publicKeyPath,
|
|
160
165
|
entryPath,
|
|
161
166
|
entryOutputPath,
|
|
162
|
-
minify
|
|
163
|
-
keyLength
|
|
167
|
+
minify
|
|
164
168
|
};
|
|
165
|
-
|
|
169
|
+
let buildVersionOption;
|
|
170
|
+
if (!isCI) {
|
|
171
|
+
const { privateKey, publicKey } = getKeys({
|
|
172
|
+
keyLength,
|
|
173
|
+
privateKeyPath,
|
|
174
|
+
publicKeyPath,
|
|
175
|
+
entryPath
|
|
176
|
+
});
|
|
177
|
+
buildVersionOption = {
|
|
178
|
+
version,
|
|
179
|
+
asarOutputPath,
|
|
180
|
+
privateKey,
|
|
181
|
+
publicKey,
|
|
182
|
+
productName,
|
|
183
|
+
versionPath
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
return { isBuild, buildAsarOption, buildEntryOption, buildVersionOption };
|
|
166
187
|
}
|
|
167
188
|
|
|
168
189
|
// src/vite.ts
|
|
169
190
|
function vite_default(options) {
|
|
170
|
-
const { isBuild, buildAsarOption, buildEntryOption } = parseOptions(options);
|
|
191
|
+
const { isBuild, buildAsarOption, buildEntryOption, buildVersionOption } = parseOptions(options);
|
|
171
192
|
const { entryPath, entryOutputPath } = buildEntryOption;
|
|
172
193
|
const { asarOutputPath } = buildAsarOption;
|
|
173
194
|
const id = "electron-incremental-updater";
|
|
@@ -184,6 +205,7 @@ function vite_default(options) {
|
|
|
184
205
|
}
|
|
185
206
|
log.info("build asar start");
|
|
186
207
|
await buildAsar(buildAsarOption);
|
|
208
|
+
buildVersionOption && await generateVersion(buildVersionOption);
|
|
187
209
|
log.info(`build asar end, output to ${asarOutputPath}`);
|
|
188
210
|
}
|
|
189
211
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "electron-incremental-update",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "electron incremental update tools, powered by vite",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "tsup",
|
|
@@ -63,4 +63,4 @@
|
|
|
63
63
|
"dependencies": {
|
|
64
64
|
"ci-info": "^3.8.0"
|
|
65
65
|
}
|
|
66
|
-
}
|
|
66
|
+
}
|
package/dist/chunk-AKU6F3WT.mjs
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
-
}) : x)(function(x) {
|
|
4
|
-
if (typeof require !== "undefined")
|
|
5
|
-
return require.apply(this, arguments);
|
|
6
|
-
throw new Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
export {
|
|
10
|
-
__require
|
|
11
|
-
};
|