electron-incremental-update 0.3.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 +40 -118
- package/dist/chunk-SSJ6PDMK.mjs +61 -0
- package/dist/index.cjs +122 -90
- package/dist/index.d.ts +71 -63
- package/dist/index.mjs +99 -90
- package/dist/vite.cjs +113 -59
- package/dist/vite.mjs +83 -61
- package/package.json +1 -1
- package/dist/chunk-AKU6F3WT.mjs +0 -11
package/README.md
CHANGED
|
@@ -16,6 +16,8 @@ using RSA + Signature to sign the new `main.asar` downloaded from remote and rep
|
|
|
16
16
|
|
|
17
17
|
develop with [vite-plugin-electron](https://github.com/electron-vite/vite-plugin-electron), and may be effect in other electron vite frameworks
|
|
18
18
|
|
|
19
|
+
**all options are documented in the jsdoc**
|
|
20
|
+
|
|
19
21
|
## install
|
|
20
22
|
|
|
21
23
|
### npm
|
|
@@ -50,21 +52,28 @@ src
|
|
|
50
52
|
|
|
51
53
|
### setup app
|
|
52
54
|
|
|
53
|
-
more example see comment on `initApp()`
|
|
54
55
|
|
|
55
56
|
```ts
|
|
56
57
|
// electron/app.ts
|
|
57
|
-
import { createUpdater, initApp } from 'electron-incremental-update'
|
|
58
|
+
import { createUpdater, getGithubReleaseCdnGroup, initApp, parseGithubCdnURL } from 'electron-incremental-update'
|
|
58
59
|
import { name, repository } from '../package.json'
|
|
59
60
|
|
|
60
61
|
const SIGNATURE_PUB = '' // auto generate RSA public key when start app
|
|
61
62
|
|
|
63
|
+
// create updater when init, no need to set productName
|
|
64
|
+
initApp({ name }, { SIGNATURE_PUB, repository })
|
|
65
|
+
|
|
66
|
+
// or create updater manually
|
|
67
|
+
const { cdnPrefix } = getGithubReleaseCdnGroup()[0]
|
|
62
68
|
const updater = createUpdater({
|
|
63
69
|
SIGNATURE_PUB,
|
|
64
|
-
repository,
|
|
65
70
|
productName: name,
|
|
71
|
+
repository,
|
|
72
|
+
updateJsonURL: parseGithubCdnURL(repository, 'fastly.jsdelivr.net/gh', 'version.json'),
|
|
73
|
+
releaseAsarURL: parseGithubCdnURL(repository, cdnPrefix, `download/latest/${name}.asar.gz`),
|
|
74
|
+
debug: true,
|
|
66
75
|
})
|
|
67
|
-
initApp(name
|
|
76
|
+
initApp({ name }).setUpdater(updater)
|
|
68
77
|
```
|
|
69
78
|
|
|
70
79
|
### setup main
|
|
@@ -72,44 +81,36 @@ initApp(name, updater)
|
|
|
72
81
|
```ts
|
|
73
82
|
// electron/main/index.ts
|
|
74
83
|
import type { Updater } from 'electron-incremental-update'
|
|
75
|
-
import { getAppAsarPath, getAppVersion,
|
|
84
|
+
import { getAppAsarPath, getAppVersion, getEntryVersion } from 'electron-incremental-update'
|
|
76
85
|
import { app } from 'electron'
|
|
77
86
|
import { name } from '../../package.json'
|
|
78
87
|
|
|
79
88
|
export default function (updater: Updater) {
|
|
80
89
|
console.log('\ncurrent:')
|
|
81
|
-
console.log(`\telectron: ${getElectronVersion()}`)
|
|
82
90
|
console.log(`\tasar path: ${getAppAsarPath(name)}`)
|
|
91
|
+
console.log(`\tentry: ${getEntryVersion()}`)
|
|
83
92
|
console.log(`\tapp: ${getAppVersion(name)}`)
|
|
84
|
-
|
|
85
|
-
updater.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
case 'fail':
|
|
104
|
-
console.error(err)
|
|
105
|
-
break
|
|
93
|
+
let size = 0
|
|
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) {
|
|
100
|
+
console.log('Update Unavailable')
|
|
101
|
+
} else if (result instanceof Error) {
|
|
102
|
+
console.error(result)
|
|
103
|
+
} else {
|
|
104
|
+
size = result.size
|
|
105
|
+
console.log('new version: ', result.version)
|
|
106
|
+
const { response } = await dialog.showMessageBox({
|
|
107
|
+
type: 'info',
|
|
108
|
+
buttons: ['Download', 'Later'],
|
|
109
|
+
message: 'Application update available!',
|
|
110
|
+
})
|
|
111
|
+
response === 0 && console.log(await updater.downloadUpdate())
|
|
106
112
|
}
|
|
107
113
|
})
|
|
108
|
-
updater.on('downloadStart', console.log)
|
|
109
|
-
updater.on('downloading', console.log)
|
|
110
|
-
updater.on('downloadEnd', console.log)
|
|
111
|
-
updater.on('donwnloadError', console.error)
|
|
112
|
-
|
|
113
114
|
// app logics
|
|
114
115
|
app.whenReady().then(() => {
|
|
115
116
|
// ...
|
|
@@ -144,7 +145,12 @@ db.close()
|
|
|
144
145
|
|
|
145
146
|
### setup vite.config.ts
|
|
146
147
|
|
|
148
|
+
make sure the plugin is set in the **last** build task plugin option
|
|
149
|
+
|
|
150
|
+
- set it to preload task plugin, as the end of build task
|
|
151
|
+
|
|
147
152
|
```ts
|
|
153
|
+
// vite.config.ts
|
|
148
154
|
export default defineConfig(({ command }) => {
|
|
149
155
|
|
|
150
156
|
const isBuild = command === 'build'
|
|
@@ -162,7 +168,7 @@ export default defineConfig(({ command }) => {
|
|
|
162
168
|
// ...
|
|
163
169
|
vite: {
|
|
164
170
|
plugins: [
|
|
165
|
-
updater({
|
|
171
|
+
updater({
|
|
166
172
|
productName: pkg.name,
|
|
167
173
|
version: pkg.version,
|
|
168
174
|
isBuild,
|
|
@@ -179,90 +185,6 @@ export default defineConfig(({ command }) => {
|
|
|
179
185
|
})
|
|
180
186
|
```
|
|
181
187
|
|
|
182
|
-
#### plugin options
|
|
183
|
-
|
|
184
|
-
```ts
|
|
185
|
-
type Options = {
|
|
186
|
-
/**
|
|
187
|
-
* whether is in build mode
|
|
188
|
-
*/
|
|
189
|
-
isBuild: boolean
|
|
190
|
-
/**
|
|
191
|
-
* the name of you application
|
|
192
|
-
*
|
|
193
|
-
* you can set as 'name' in package.json
|
|
194
|
-
*/
|
|
195
|
-
productName: string
|
|
196
|
-
/**
|
|
197
|
-
* the version of you application
|
|
198
|
-
*
|
|
199
|
-
* you can set as 'version' in package.json
|
|
200
|
-
*/
|
|
201
|
-
version: string
|
|
202
|
-
/**
|
|
203
|
-
* Whether to minify
|
|
204
|
-
*/
|
|
205
|
-
minify?: boolean
|
|
206
|
-
/**
|
|
207
|
-
* path config
|
|
208
|
-
*/
|
|
209
|
-
paths?: {
|
|
210
|
-
/**
|
|
211
|
-
* Path to app entry file
|
|
212
|
-
* @default 'electron/app.ts'
|
|
213
|
-
*/
|
|
214
|
-
entryPath?: string
|
|
215
|
-
/**
|
|
216
|
-
* Path to app entry output file
|
|
217
|
-
* @default 'app.js'
|
|
218
|
-
*/
|
|
219
|
-
entryOutputPath?: string
|
|
220
|
-
/**
|
|
221
|
-
* Path to asar file
|
|
222
|
-
* @default `release/${ProductName}.asar`
|
|
223
|
-
*/
|
|
224
|
-
asarOutputPath?: string
|
|
225
|
-
/**
|
|
226
|
-
* Path to electron build output
|
|
227
|
-
* @default `dist-electron`
|
|
228
|
-
*/
|
|
229
|
-
electronDistPath?: string
|
|
230
|
-
/**
|
|
231
|
-
* Path to renderer build output
|
|
232
|
-
* @default `dist`
|
|
233
|
-
*/
|
|
234
|
-
rendererDistPath?: string
|
|
235
|
-
/**
|
|
236
|
-
* Path to version info output
|
|
237
|
-
* @default `version.json`
|
|
238
|
-
*/
|
|
239
|
-
versionPath?: string
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* signature config
|
|
243
|
-
*/
|
|
244
|
-
keys?: {
|
|
245
|
-
/**
|
|
246
|
-
* Path to the pem file that contains private key
|
|
247
|
-
* if not ended with .pem, it will be appended
|
|
248
|
-
* @default 'public/private.pem'
|
|
249
|
-
*/
|
|
250
|
-
privateKeyPath?: string
|
|
251
|
-
/**
|
|
252
|
-
* Path to the pem file that contains public key
|
|
253
|
-
* if not ended with .pem, it will be appended
|
|
254
|
-
* @default 'public/public.pem'
|
|
255
|
-
*/
|
|
256
|
-
publicKeyPath?: string
|
|
257
|
-
/**
|
|
258
|
-
* Length of the key
|
|
259
|
-
* @default 2048
|
|
260
|
-
*/
|
|
261
|
-
keyLength?: number
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
```
|
|
265
|
-
|
|
266
188
|
### electron-builder config
|
|
267
189
|
|
|
268
190
|
```js
|
|
@@ -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) => {
|
|
@@ -63,11 +86,15 @@ function downloadJSONDefault(url, updater, headers) {
|
|
|
63
86
|
res.headers = headers;
|
|
64
87
|
res.on("data", (chunk) => data += chunk);
|
|
65
88
|
res.on("end", () => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
89
|
+
try {
|
|
90
|
+
const json = JSON.parse(data);
|
|
91
|
+
if ("signature" in json && "version" in json && "size" in json) {
|
|
92
|
+
resolve2(json);
|
|
93
|
+
} else {
|
|
94
|
+
throw Error;
|
|
95
|
+
}
|
|
96
|
+
} catch (e) {
|
|
97
|
+
reject(new Error("invalid json"));
|
|
71
98
|
}
|
|
72
99
|
});
|
|
73
100
|
}).on("error", (e) => {
|
|
@@ -76,16 +103,18 @@ function downloadJSONDefault(url, updater, headers) {
|
|
|
76
103
|
});
|
|
77
104
|
}
|
|
78
105
|
function downloadBufferDefault(url, updater, headers) {
|
|
106
|
+
let progress = 0;
|
|
79
107
|
return new Promise((resolve2, reject) => {
|
|
80
108
|
import_node_https.default.get(url, (res) => {
|
|
81
109
|
let data = [];
|
|
82
110
|
res.headers = headers;
|
|
83
111
|
res.on("data", (chunk) => {
|
|
84
|
-
|
|
112
|
+
progress += chunk.length;
|
|
113
|
+
updater.emit("downloading", progress);
|
|
85
114
|
data.push(chunk);
|
|
86
115
|
});
|
|
87
116
|
res.on("end", () => {
|
|
88
|
-
resolve2(
|
|
117
|
+
resolve2(import_node_buffer2.Buffer.concat(data));
|
|
89
118
|
});
|
|
90
119
|
}).on("error", (e) => {
|
|
91
120
|
reject(e);
|
|
@@ -177,6 +206,7 @@ function createUpdater({
|
|
|
177
206
|
}) {
|
|
178
207
|
const updater = new import_node_events.EventEmitter();
|
|
179
208
|
let signature = "";
|
|
209
|
+
let version = "";
|
|
180
210
|
const gzipPath = `../${productName}.asar.gz`;
|
|
181
211
|
const tmpFile = gzipPath.replace(".asar.gz", ".tmp.gz");
|
|
182
212
|
const { downloadBuffer, downloadJSON, extraHeader, userAgent } = downloadConfig || {};
|
|
@@ -190,12 +220,16 @@ function createUpdater({
|
|
|
190
220
|
UserAgent: ua,
|
|
191
221
|
...extraHeader
|
|
192
222
|
};
|
|
193
|
-
log(`headers: ${headers}`);
|
|
223
|
+
log(`download headers: ${JSON.stringify(headers, null, 2)}`);
|
|
194
224
|
const downloadFn = format === "json" ? downloadJSON ?? downloadJSONDefault : downloadBuffer ?? downloadBufferDefault;
|
|
195
|
-
|
|
225
|
+
log(`download ${format} from ${url}`);
|
|
226
|
+
const ret = await downloadFn(url, updater, headers);
|
|
227
|
+
log(`download ${format} success`);
|
|
228
|
+
return ret;
|
|
196
229
|
}
|
|
197
230
|
async function extractFile(gzipFilePath) {
|
|
198
231
|
if (!gzipFilePath.endsWith(".asar.gz") || !(0, import_node_fs2.existsSync)(gzipFilePath)) {
|
|
232
|
+
log("update .asar.gz file not exist");
|
|
199
233
|
return;
|
|
200
234
|
}
|
|
201
235
|
gzipFilePath = gzipFilePath.replace(".asar.gz", ".tmp.gz");
|
|
@@ -207,121 +241,119 @@ function createUpdater({
|
|
|
207
241
|
log(`outputFilePath: ${outputFilePath}`);
|
|
208
242
|
input.pipe(gunzip).pipe(output).on("finish", async () => {
|
|
209
243
|
await (0, import_promises.rm)(gzipFilePath);
|
|
210
|
-
log(
|
|
244
|
+
log(`${gzipFilePath} unzipped`);
|
|
211
245
|
resolve2(outputFilePath);
|
|
212
246
|
}).on("error", async (err) => {
|
|
213
247
|
await (0, import_promises.rm)(gzipFilePath);
|
|
214
|
-
log(`error: ${err}`);
|
|
215
248
|
output.destroy(err);
|
|
216
249
|
reject(err);
|
|
217
250
|
});
|
|
218
251
|
});
|
|
219
252
|
}
|
|
220
|
-
function
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
224
|
-
function needUpdate(version) {
|
|
225
|
-
if (!version || !import_electron2.app.isPackaged) {
|
|
253
|
+
function needUpdate(version2) {
|
|
254
|
+
if (!import_electron2.app.isPackaged) {
|
|
255
|
+
log("in dev mode, no need to update");
|
|
226
256
|
return false;
|
|
227
257
|
}
|
|
228
258
|
const currentVersion = getEntryVersion();
|
|
229
|
-
log(`
|
|
230
|
-
|
|
259
|
+
log(`check update:
|
|
260
|
+
current version is ${currentVersion},
|
|
261
|
+
new version is ${version2}`);
|
|
231
262
|
const _compare = compareVersion ?? compareVersionDefault;
|
|
232
|
-
return _compare(currentVersion,
|
|
263
|
+
return _compare(currentVersion, version2);
|
|
233
264
|
}
|
|
234
|
-
async
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
throw new Error("updateJsonURL or repository are not set");
|
|
240
|
-
}
|
|
241
|
-
url = `${repository.replace("github.com", "raw.githubusercontent.com")}/version.json`;
|
|
242
|
-
}
|
|
243
|
-
log(`updateJsonURL: ${url}`);
|
|
244
|
-
if ((0, import_node_fs2.existsSync)(tmpFile)) {
|
|
245
|
-
log(`remove tmp file: ${tmpFile}`);
|
|
246
|
-
await (0, import_promises.rm)(tmpFile);
|
|
247
|
-
}
|
|
248
|
-
const json = await download(url, "json");
|
|
249
|
-
const {
|
|
250
|
-
signature: _sig,
|
|
251
|
-
version,
|
|
252
|
-
size
|
|
253
|
-
} = json;
|
|
254
|
-
log(`UpdateJSON: ${JSON.stringify(json, null, 2)}`);
|
|
255
|
-
if (!needUpdate(version)) {
|
|
256
|
-
return false;
|
|
257
|
-
} else {
|
|
258
|
-
signature = _sig;
|
|
259
|
-
return { size, version };
|
|
260
|
-
}
|
|
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");
|
|
265
|
+
updater.checkUpdate = async (url) => {
|
|
266
|
+
try {
|
|
267
|
+
url ??= _update;
|
|
268
|
+
if (!url) {
|
|
269
|
+
log("no updateJsonURL, fallback to use repository");
|
|
267
270
|
if (!repository) {
|
|
268
|
-
throw new Error("
|
|
271
|
+
throw new Error("updateJsonURL or repository are not set");
|
|
269
272
|
}
|
|
270
|
-
|
|
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 };
|
|
271
298
|
}
|
|
272
|
-
log(`releaseAsarURL: ${_url}`);
|
|
273
|
-
src = await download(_url, "buffer");
|
|
274
|
-
}
|
|
275
|
-
log("start verify");
|
|
276
|
-
if (!verify(src, signature)) {
|
|
277
|
-
throw new Error("file broken, invalid signature!");
|
|
278
|
-
}
|
|
279
|
-
log(`write file: ${gzipPath}`);
|
|
280
|
-
await (0, import_promises.writeFile)(gzipPath, src);
|
|
281
|
-
log(`extract file: ${gzipPath}`);
|
|
282
|
-
await extractFile(gzipPath);
|
|
283
|
-
updater.emit("downloaded");
|
|
284
|
-
}
|
|
285
|
-
const onCheck = async (url) => {
|
|
286
|
-
try {
|
|
287
|
-
const result = await checkUpdate(url);
|
|
288
|
-
updater.emit("checkResult", result);
|
|
289
299
|
} catch (error) {
|
|
290
300
|
log(error);
|
|
291
|
-
|
|
301
|
+
return error;
|
|
292
302
|
}
|
|
293
303
|
};
|
|
294
|
-
updater.
|
|
295
|
-
updater.checkUpdate = onCheck;
|
|
296
|
-
const onDownload = async (src) => {
|
|
304
|
+
updater.downloadUpdate = async (src) => {
|
|
297
305
|
try {
|
|
298
|
-
|
|
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;
|
|
299
329
|
} catch (error) {
|
|
300
330
|
log(error);
|
|
301
|
-
|
|
331
|
+
return error;
|
|
302
332
|
}
|
|
303
333
|
};
|
|
304
|
-
updater.on("download", onDownload);
|
|
305
|
-
updater.downloadUpdate = onDownload;
|
|
306
334
|
return updater;
|
|
307
335
|
}
|
|
308
336
|
|
|
309
337
|
// src/index.ts
|
|
310
|
-
function initApp(
|
|
338
|
+
function initApp(appOptions, updaterOptions) {
|
|
311
339
|
const {
|
|
340
|
+
name: productName,
|
|
312
341
|
electronDistPath = "dist-electron",
|
|
313
342
|
mainPath = "main/index.js"
|
|
314
|
-
} =
|
|
343
|
+
} = appOptions ?? {};
|
|
315
344
|
const mainDir = import_electron3.app.isPackaged ? `../${productName}.asar` : electronDistPath;
|
|
316
345
|
const entry = (0, import_node_path2.resolve)(__dirname, mainDir, mainPath);
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
346
|
+
if (updaterOptions) {
|
|
347
|
+
require(entry)(
|
|
348
|
+
createUpdater({ ...updaterOptions, productName })
|
|
349
|
+
);
|
|
321
350
|
} else {
|
|
322
|
-
|
|
351
|
+
return {
|
|
352
|
+
setUpdater(updater) {
|
|
353
|
+
require(entry)(updater);
|
|
354
|
+
}
|
|
355
|
+
};
|
|
323
356
|
}
|
|
324
|
-
return require(entry)(_updater);
|
|
325
357
|
}
|
|
326
358
|
// Annotate the CommonJS export names for ESM import in node:
|
|
327
359
|
0 && (module.exports = {
|