dsh-wechat-remote 1.7.4 → 1.7.5
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/assets/plugin.tgz +0 -0
- package/assets/release.json +35 -35
- package/lib/install-control.js +1268 -1268
- package/lib/install-profile.js +210 -210
- package/lib/install-runtime.js +64 -64
- package/lib/package.json +1 -1
- package/lib/secure-file.js +76 -76
- package/lib/update-download.js +98 -98
- package/lib/update-policy.js +147 -147
- package/lib/update-worker.js +689 -689
- package/package.json +1 -1
package/lib/secure-file.js
CHANGED
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
/* Generated from the shared plugin installation sources. */
|
|
2
|
-
|
|
3
|
-
// src/secure-file.ts
|
|
4
|
-
import { execFileSync } from "node:child_process";
|
|
5
|
-
import {
|
|
6
|
-
chmodSync,
|
|
7
|
-
closeSync,
|
|
8
|
-
existsSync,
|
|
9
|
-
fsyncSync,
|
|
10
|
-
mkdirSync,
|
|
11
|
-
openSync,
|
|
12
|
-
readFileSync,
|
|
13
|
-
renameSync,
|
|
14
|
-
rmSync,
|
|
15
|
-
writeFileSync
|
|
16
|
-
} from "node:fs";
|
|
17
|
-
import { dirname } from "node:path";
|
|
18
|
-
import { userInfo } from "node:os";
|
|
19
|
-
import { randomBytes } from "node:crypto";
|
|
20
|
-
function tightenPrivateFile(file) {
|
|
21
|
-
try {
|
|
22
|
-
chmodSync(file, 384);
|
|
23
|
-
} catch {
|
|
24
|
-
}
|
|
25
|
-
if (process.platform !== "win32") return;
|
|
26
|
-
try {
|
|
27
|
-
execFileSync("icacls", [file, "/inheritance:r", "/grant:r", `${userInfo().username}:F`], {
|
|
28
|
-
timeout: 5e3,
|
|
29
|
-
windowsHide: true,
|
|
30
|
-
stdio: "ignore"
|
|
31
|
-
});
|
|
32
|
-
} catch {
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
function writePrivateJsonAtomic(file, value) {
|
|
36
|
-
const parent = dirname(file);
|
|
37
|
-
mkdirSync(parent, { recursive: true, mode: 448 });
|
|
38
|
-
const temporary = `${file}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
|
|
39
|
-
try {
|
|
40
|
-
writeFileSync(temporary, `${JSON.stringify(value, null, 2)}
|
|
41
|
-
`, {
|
|
42
|
-
encoding: "utf8",
|
|
43
|
-
mode: 384,
|
|
44
|
-
flag: "wx"
|
|
45
|
-
});
|
|
46
|
-
const fd = openSync(temporary, "r+");
|
|
47
|
-
try {
|
|
48
|
-
try {
|
|
49
|
-
fsyncSync(fd);
|
|
50
|
-
} catch {
|
|
51
|
-
}
|
|
52
|
-
} finally {
|
|
53
|
-
closeSync(fd);
|
|
54
|
-
}
|
|
55
|
-
tightenPrivateFile(temporary);
|
|
56
|
-
renameSync(temporary, file);
|
|
57
|
-
tightenPrivateFile(file);
|
|
58
|
-
} finally {
|
|
59
|
-
if (existsSync(temporary)) {
|
|
60
|
-
try {
|
|
61
|
-
rmSync(temporary, { force: true });
|
|
62
|
-
} catch {
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
function readPrivateJson(file) {
|
|
68
|
-
const value = JSON.parse(readFileSync(file, "utf8"));
|
|
69
|
-
tightenPrivateFile(file);
|
|
70
|
-
return value;
|
|
71
|
-
}
|
|
72
|
-
export {
|
|
73
|
-
readPrivateJson,
|
|
74
|
-
tightenPrivateFile,
|
|
75
|
-
writePrivateJsonAtomic
|
|
76
|
-
};
|
|
1
|
+
/* Generated from the shared plugin installation sources. */
|
|
2
|
+
|
|
3
|
+
// src/secure-file.ts
|
|
4
|
+
import { execFileSync } from "node:child_process";
|
|
5
|
+
import {
|
|
6
|
+
chmodSync,
|
|
7
|
+
closeSync,
|
|
8
|
+
existsSync,
|
|
9
|
+
fsyncSync,
|
|
10
|
+
mkdirSync,
|
|
11
|
+
openSync,
|
|
12
|
+
readFileSync,
|
|
13
|
+
renameSync,
|
|
14
|
+
rmSync,
|
|
15
|
+
writeFileSync
|
|
16
|
+
} from "node:fs";
|
|
17
|
+
import { dirname } from "node:path";
|
|
18
|
+
import { userInfo } from "node:os";
|
|
19
|
+
import { randomBytes } from "node:crypto";
|
|
20
|
+
function tightenPrivateFile(file) {
|
|
21
|
+
try {
|
|
22
|
+
chmodSync(file, 384);
|
|
23
|
+
} catch {
|
|
24
|
+
}
|
|
25
|
+
if (process.platform !== "win32") return;
|
|
26
|
+
try {
|
|
27
|
+
execFileSync("icacls", [file, "/inheritance:r", "/grant:r", `${userInfo().username}:F`], {
|
|
28
|
+
timeout: 5e3,
|
|
29
|
+
windowsHide: true,
|
|
30
|
+
stdio: "ignore"
|
|
31
|
+
});
|
|
32
|
+
} catch {
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function writePrivateJsonAtomic(file, value) {
|
|
36
|
+
const parent = dirname(file);
|
|
37
|
+
mkdirSync(parent, { recursive: true, mode: 448 });
|
|
38
|
+
const temporary = `${file}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
|
|
39
|
+
try {
|
|
40
|
+
writeFileSync(temporary, `${JSON.stringify(value, null, 2)}
|
|
41
|
+
`, {
|
|
42
|
+
encoding: "utf8",
|
|
43
|
+
mode: 384,
|
|
44
|
+
flag: "wx"
|
|
45
|
+
});
|
|
46
|
+
const fd = openSync(temporary, "r+");
|
|
47
|
+
try {
|
|
48
|
+
try {
|
|
49
|
+
fsyncSync(fd);
|
|
50
|
+
} catch {
|
|
51
|
+
}
|
|
52
|
+
} finally {
|
|
53
|
+
closeSync(fd);
|
|
54
|
+
}
|
|
55
|
+
tightenPrivateFile(temporary);
|
|
56
|
+
renameSync(temporary, file);
|
|
57
|
+
tightenPrivateFile(file);
|
|
58
|
+
} finally {
|
|
59
|
+
if (existsSync(temporary)) {
|
|
60
|
+
try {
|
|
61
|
+
rmSync(temporary, { force: true });
|
|
62
|
+
} catch {
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function readPrivateJson(file) {
|
|
68
|
+
const value = JSON.parse(readFileSync(file, "utf8"));
|
|
69
|
+
tightenPrivateFile(file);
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
export {
|
|
73
|
+
readPrivateJson,
|
|
74
|
+
tightenPrivateFile,
|
|
75
|
+
writePrivateJsonAtomic
|
|
76
|
+
};
|
package/lib/update-download.js
CHANGED
|
@@ -1,98 +1,98 @@
|
|
|
1
|
-
/* Generated from the shared plugin installation sources. */
|
|
2
|
-
|
|
3
|
-
// src/update-download.ts
|
|
4
|
-
import { createHash } from "node:crypto";
|
|
5
|
-
import { gunzipSync } from "node:zlib";
|
|
6
|
-
|
|
7
|
-
// src/update-policy.ts
|
|
8
|
-
function trustedReleaseAsset(asset, version) {
|
|
9
|
-
if (!asset || !/^[a-f0-9]{64}$/.test(asset.sha256) || !Number.isSafeInteger(asset.bytes) || asset.bytes < 1 || asset.bytes > 32 * 1024 * 1024) return false;
|
|
10
|
-
try {
|
|
11
|
-
const u = new URL(asset.url);
|
|
12
|
-
return u.origin === "https://github.com" && !u.username && !u.password && !u.search && !u.hash && u.pathname.startsWith(`/martinbear1/dsh-wechat-remote/releases/download/v${version}/`) && /^[-A-Za-z0-9_.]+\.tgz$/.test(u.pathname.slice(`/martinbear1/dsh-wechat-remote/releases/download/v${version}/`.length));
|
|
13
|
-
} catch {
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// src/update-download.ts
|
|
19
|
-
async function boundedFetch(url, maxBytes, fetcher = fetch) {
|
|
20
|
-
let next = url;
|
|
21
|
-
for (let i = 0; i < 5; i++) {
|
|
22
|
-
const u = new URL(next);
|
|
23
|
-
if (u.protocol !== "https:" || u.username || u.password || u.port || !["github.com", "release-assets.githubusercontent.com", "objects.githubusercontent.com", "relay.xyxfood.xyz"].includes(u.hostname)) throw new Error("\u66F4\u65B0\u4E0B\u8F7D\u6765\u6E90\u4E0D\u53D7\u4FE1\u4EFB");
|
|
24
|
-
const res = await fetcher(next, { signal: AbortSignal.timeout(maxBytes <= 256 * 1024 ? 1e4 : 6e4), redirect: "manual" });
|
|
25
|
-
if ([301, 302, 303, 307, 308].includes(res.status)) {
|
|
26
|
-
await res.body?.cancel();
|
|
27
|
-
const location = res.headers.get("location");
|
|
28
|
-
if (!location) throw new Error("\u66F4\u65B0\u6765\u6E90\u91CD\u5B9A\u5411\u65E0\u6548");
|
|
29
|
-
next = new URL(location, next).href;
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
if (!res.ok || !res.body) {
|
|
33
|
-
await res.body?.cancel();
|
|
34
|
-
throw new Error("\u66F4\u65B0\u670D\u52A1\u6682\u4E0D\u53EF\u7528");
|
|
35
|
-
}
|
|
36
|
-
if (Number(res.headers.get("content-length")) > maxBytes) {
|
|
37
|
-
await res.body.cancel();
|
|
38
|
-
throw new Error("\u66F4\u65B0\u54CD\u5E94\u8D85\u8FC7\u5927\u5C0F\u9650\u5236");
|
|
39
|
-
}
|
|
40
|
-
const reader = res.body.getReader(), chunks = [];
|
|
41
|
-
let size = 0;
|
|
42
|
-
try {
|
|
43
|
-
for (; ; ) {
|
|
44
|
-
const { done, value } = await reader.read();
|
|
45
|
-
if (done) break;
|
|
46
|
-
size += value.length;
|
|
47
|
-
if (size > maxBytes) throw new Error("\u66F4\u65B0\u54CD\u5E94\u8D85\u8FC7\u5927\u5C0F\u9650\u5236");
|
|
48
|
-
chunks.push(value);
|
|
49
|
-
}
|
|
50
|
-
} catch (error) {
|
|
51
|
-
await reader.cancel();
|
|
52
|
-
throw error;
|
|
53
|
-
}
|
|
54
|
-
return Buffer.concat(chunks);
|
|
55
|
-
}
|
|
56
|
-
throw new Error("\u66F4\u65B0\u6765\u6E90\u91CD\u5B9A\u5411\u8FC7\u591A");
|
|
57
|
-
}
|
|
58
|
-
function auditArchive(archive, release) {
|
|
59
|
-
if (!release.asset || archive.length !== release.asset.bytes || createHash("sha256").update(archive).digest("hex") !== release.asset.sha256) throw new Error("\u66F4\u65B0\u5305\u6821\u9A8C\u5931\u8D25\uFF0C\u672A\u4FEE\u6539\u5F53\u524D\u63D2\u4EF6");
|
|
60
|
-
const tar = gunzipSync(archive, { maxOutputLength: 64 * 1024 * 1024 });
|
|
61
|
-
const seen = /* @__PURE__ */ new Set();
|
|
62
|
-
let manifest, entries = 0;
|
|
63
|
-
for (let offset = 0; offset + 512 <= tar.length; ) {
|
|
64
|
-
const header = tar.subarray(offset, offset + 512);
|
|
65
|
-
if (header.every((b) => b === 0)) break;
|
|
66
|
-
if (++entries > 5e3) throw new Error("\u66F4\u65B0\u5305\u6587\u4EF6\u6570\u91CF\u5F02\u5E38");
|
|
67
|
-
const field = (start, size2) => header.subarray(start, start + size2).toString("utf8").replace(/\0.*$/s, "");
|
|
68
|
-
const name = (field(345, 155) ? field(345, 155) + "/" : "") + field(0, 100);
|
|
69
|
-
const type = field(156, 1);
|
|
70
|
-
const sizeText = field(124, 12).trim();
|
|
71
|
-
if (!/^[0-7]+$/.test(sizeText)) throw new Error("\u66F4\u65B0\u5305\u5927\u5C0F\u5B57\u6BB5\u65E0\u6548");
|
|
72
|
-
const size = parseInt(sizeText, 8);
|
|
73
|
-
const sumText = field(148, 8).trim();
|
|
74
|
-
const sum = [...header].reduce((n, b, i) => n + (i >= 148 && i < 156 ? 32 : b), 0);
|
|
75
|
-
if (!/^[0-7]+$/.test(sumText) || parseInt(sumText, 8) !== sum) throw new Error("\u66F4\u65B0\u5305\u5934\u6821\u9A8C\u5931\u8D25");
|
|
76
|
-
if (!name.startsWith("package/") || /[\\:\x00-\x1f]/.test(name) || name.split("/").some((part) => part === ".." || part === ".") || name.split("/").some((part) => /[. ]$/.test(part) || /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(part)) || !["0", "", "5"].includes(type) || seen.has(name.toLowerCase()) || !Number.isSafeInteger(size) || size < 0 || offset + 512 + size > tar.length) throw new Error("\u66F4\u65B0\u5305\u5305\u542B\u4E0D\u5B89\u5168\u7684\u8DEF\u5F84\u6216\u6587\u4EF6\u7C7B\u578B");
|
|
77
|
-
seen.add(name.toLowerCase());
|
|
78
|
-
if (name === "package/package.json") {
|
|
79
|
-
if (size > 65536) throw new Error("\u66F4\u65B0\u5305\u6E05\u5355\u8FC7\u5927");
|
|
80
|
-
manifest = JSON.parse(tar.subarray(offset + 512, offset + 512 + size).toString("utf8"));
|
|
81
|
-
}
|
|
82
|
-
offset += 512 + Math.ceil(size / 512) * 512;
|
|
83
|
-
}
|
|
84
|
-
if (!manifest || manifest.name !== "@harness-remote/dsh-wechat-remote" || manifest.version !== release.version || !seen.has("package/lib/index.js") || !seen.has("package/lib/client.js")) throw new Error("\u66F4\u65B0\u5305\u540D\u79F0\u3001\u7248\u672C\u6216\u5165\u53E3\u4E0D\u5339\u914D");
|
|
85
|
-
const scripts = manifest.scripts;
|
|
86
|
-
if (["preinstall", "install", "postinstall", "prepare"].some((name) => scripts?.[name])) throw new Error("\u66F4\u65B0\u5305\u5305\u542B\u4E0D\u5141\u8BB8\u7684\u5B89\u88C5\u811A\u672C");
|
|
87
|
-
}
|
|
88
|
-
async function downloadRelease(release, fetcher = fetch) {
|
|
89
|
-
if (!trustedReleaseAsset(release.asset, release.version)) throw new Error("\u6682\u65E0\u53EF\u9A8C\u8BC1\u7684\u6B63\u5F0F\u66F4\u65B0\u5305");
|
|
90
|
-
const body = await boundedFetch(release.asset.url, release.asset.bytes, fetcher);
|
|
91
|
-
auditArchive(body, release);
|
|
92
|
-
return body;
|
|
93
|
-
}
|
|
94
|
-
export {
|
|
95
|
-
auditArchive,
|
|
96
|
-
boundedFetch,
|
|
97
|
-
downloadRelease
|
|
98
|
-
};
|
|
1
|
+
/* Generated from the shared plugin installation sources. */
|
|
2
|
+
|
|
3
|
+
// src/update-download.ts
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
import { gunzipSync } from "node:zlib";
|
|
6
|
+
|
|
7
|
+
// src/update-policy.ts
|
|
8
|
+
function trustedReleaseAsset(asset, version) {
|
|
9
|
+
if (!asset || !/^[a-f0-9]{64}$/.test(asset.sha256) || !Number.isSafeInteger(asset.bytes) || asset.bytes < 1 || asset.bytes > 32 * 1024 * 1024) return false;
|
|
10
|
+
try {
|
|
11
|
+
const u = new URL(asset.url);
|
|
12
|
+
return u.origin === "https://github.com" && !u.username && !u.password && !u.search && !u.hash && u.pathname.startsWith(`/martinbear1/dsh-wechat-remote/releases/download/v${version}/`) && /^[-A-Za-z0-9_.]+\.tgz$/.test(u.pathname.slice(`/martinbear1/dsh-wechat-remote/releases/download/v${version}/`.length));
|
|
13
|
+
} catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/update-download.ts
|
|
19
|
+
async function boundedFetch(url, maxBytes, fetcher = fetch) {
|
|
20
|
+
let next = url;
|
|
21
|
+
for (let i = 0; i < 5; i++) {
|
|
22
|
+
const u = new URL(next);
|
|
23
|
+
if (u.protocol !== "https:" || u.username || u.password || u.port || !["github.com", "release-assets.githubusercontent.com", "objects.githubusercontent.com", "relay.xyxfood.xyz"].includes(u.hostname)) throw new Error("\u66F4\u65B0\u4E0B\u8F7D\u6765\u6E90\u4E0D\u53D7\u4FE1\u4EFB");
|
|
24
|
+
const res = await fetcher(next, { signal: AbortSignal.timeout(maxBytes <= 256 * 1024 ? 1e4 : 6e4), redirect: "manual" });
|
|
25
|
+
if ([301, 302, 303, 307, 308].includes(res.status)) {
|
|
26
|
+
await res.body?.cancel();
|
|
27
|
+
const location = res.headers.get("location");
|
|
28
|
+
if (!location) throw new Error("\u66F4\u65B0\u6765\u6E90\u91CD\u5B9A\u5411\u65E0\u6548");
|
|
29
|
+
next = new URL(location, next).href;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (!res.ok || !res.body) {
|
|
33
|
+
await res.body?.cancel();
|
|
34
|
+
throw new Error("\u66F4\u65B0\u670D\u52A1\u6682\u4E0D\u53EF\u7528");
|
|
35
|
+
}
|
|
36
|
+
if (Number(res.headers.get("content-length")) > maxBytes) {
|
|
37
|
+
await res.body.cancel();
|
|
38
|
+
throw new Error("\u66F4\u65B0\u54CD\u5E94\u8D85\u8FC7\u5927\u5C0F\u9650\u5236");
|
|
39
|
+
}
|
|
40
|
+
const reader = res.body.getReader(), chunks = [];
|
|
41
|
+
let size = 0;
|
|
42
|
+
try {
|
|
43
|
+
for (; ; ) {
|
|
44
|
+
const { done, value } = await reader.read();
|
|
45
|
+
if (done) break;
|
|
46
|
+
size += value.length;
|
|
47
|
+
if (size > maxBytes) throw new Error("\u66F4\u65B0\u54CD\u5E94\u8D85\u8FC7\u5927\u5C0F\u9650\u5236");
|
|
48
|
+
chunks.push(value);
|
|
49
|
+
}
|
|
50
|
+
} catch (error) {
|
|
51
|
+
await reader.cancel();
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
return Buffer.concat(chunks);
|
|
55
|
+
}
|
|
56
|
+
throw new Error("\u66F4\u65B0\u6765\u6E90\u91CD\u5B9A\u5411\u8FC7\u591A");
|
|
57
|
+
}
|
|
58
|
+
function auditArchive(archive, release) {
|
|
59
|
+
if (!release.asset || archive.length !== release.asset.bytes || createHash("sha256").update(archive).digest("hex") !== release.asset.sha256) throw new Error("\u66F4\u65B0\u5305\u6821\u9A8C\u5931\u8D25\uFF0C\u672A\u4FEE\u6539\u5F53\u524D\u63D2\u4EF6");
|
|
60
|
+
const tar = gunzipSync(archive, { maxOutputLength: 64 * 1024 * 1024 });
|
|
61
|
+
const seen = /* @__PURE__ */ new Set();
|
|
62
|
+
let manifest, entries = 0;
|
|
63
|
+
for (let offset = 0; offset + 512 <= tar.length; ) {
|
|
64
|
+
const header = tar.subarray(offset, offset + 512);
|
|
65
|
+
if (header.every((b) => b === 0)) break;
|
|
66
|
+
if (++entries > 5e3) throw new Error("\u66F4\u65B0\u5305\u6587\u4EF6\u6570\u91CF\u5F02\u5E38");
|
|
67
|
+
const field = (start, size2) => header.subarray(start, start + size2).toString("utf8").replace(/\0.*$/s, "");
|
|
68
|
+
const name = (field(345, 155) ? field(345, 155) + "/" : "") + field(0, 100);
|
|
69
|
+
const type = field(156, 1);
|
|
70
|
+
const sizeText = field(124, 12).trim();
|
|
71
|
+
if (!/^[0-7]+$/.test(sizeText)) throw new Error("\u66F4\u65B0\u5305\u5927\u5C0F\u5B57\u6BB5\u65E0\u6548");
|
|
72
|
+
const size = parseInt(sizeText, 8);
|
|
73
|
+
const sumText = field(148, 8).trim();
|
|
74
|
+
const sum = [...header].reduce((n, b, i) => n + (i >= 148 && i < 156 ? 32 : b), 0);
|
|
75
|
+
if (!/^[0-7]+$/.test(sumText) || parseInt(sumText, 8) !== sum) throw new Error("\u66F4\u65B0\u5305\u5934\u6821\u9A8C\u5931\u8D25");
|
|
76
|
+
if (!name.startsWith("package/") || /[\\:\x00-\x1f]/.test(name) || name.split("/").some((part) => part === ".." || part === ".") || name.split("/").some((part) => /[. ]$/.test(part) || /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(part)) || !["0", "", "5"].includes(type) || seen.has(name.toLowerCase()) || !Number.isSafeInteger(size) || size < 0 || offset + 512 + size > tar.length) throw new Error("\u66F4\u65B0\u5305\u5305\u542B\u4E0D\u5B89\u5168\u7684\u8DEF\u5F84\u6216\u6587\u4EF6\u7C7B\u578B");
|
|
77
|
+
seen.add(name.toLowerCase());
|
|
78
|
+
if (name === "package/package.json") {
|
|
79
|
+
if (size > 65536) throw new Error("\u66F4\u65B0\u5305\u6E05\u5355\u8FC7\u5927");
|
|
80
|
+
manifest = JSON.parse(tar.subarray(offset + 512, offset + 512 + size).toString("utf8"));
|
|
81
|
+
}
|
|
82
|
+
offset += 512 + Math.ceil(size / 512) * 512;
|
|
83
|
+
}
|
|
84
|
+
if (!manifest || manifest.name !== "@harness-remote/dsh-wechat-remote" || manifest.version !== release.version || !seen.has("package/lib/index.js") || !seen.has("package/lib/client.js")) throw new Error("\u66F4\u65B0\u5305\u540D\u79F0\u3001\u7248\u672C\u6216\u5165\u53E3\u4E0D\u5339\u914D");
|
|
85
|
+
const scripts = manifest.scripts;
|
|
86
|
+
if (["preinstall", "install", "postinstall", "prepare"].some((name) => scripts?.[name])) throw new Error("\u66F4\u65B0\u5305\u5305\u542B\u4E0D\u5141\u8BB8\u7684\u5B89\u88C5\u811A\u672C");
|
|
87
|
+
}
|
|
88
|
+
async function downloadRelease(release, fetcher = fetch) {
|
|
89
|
+
if (!trustedReleaseAsset(release.asset, release.version)) throw new Error("\u6682\u65E0\u53EF\u9A8C\u8BC1\u7684\u6B63\u5F0F\u66F4\u65B0\u5305");
|
|
90
|
+
const body = await boundedFetch(release.asset.url, release.asset.bytes, fetcher);
|
|
91
|
+
auditArchive(body, release);
|
|
92
|
+
return body;
|
|
93
|
+
}
|
|
94
|
+
export {
|
|
95
|
+
auditArchive,
|
|
96
|
+
boundedFetch,
|
|
97
|
+
downloadRelease
|
|
98
|
+
};
|