@cosui/genui-toolkit 1.0.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 +43 -0
- package/bin/genui +2 -0
- package/dist/auth.d.ts +3 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +132 -0
- package/dist/auth.js.map +1 -0
- package/dist/check/artifact.d.ts +16 -0
- package/dist/check/artifact.d.ts.map +1 -0
- package/dist/check/artifact.js +209 -0
- package/dist/check/artifact.js.map +1 -0
- package/dist/check/checker.d.ts +6 -0
- package/dist/check/checker.d.ts.map +1 -0
- package/dist/check/checker.js +79 -0
- package/dist/check/checker.js.map +1 -0
- package/dist/check/cli.d.ts +5 -0
- package/dist/check/cli.d.ts.map +1 -0
- package/dist/check/cli.js +110 -0
- package/dist/check/cli.js.map +1 -0
- package/dist/check/rules/artifact.d.ts +3 -0
- package/dist/check/rules/artifact.d.ts.map +1 -0
- package/dist/check/rules/artifact.js +96 -0
- package/dist/check/rules/artifact.js.map +1 -0
- package/dist/check/rules/common.d.ts +16 -0
- package/dist/check/rules/common.d.ts.map +1 -0
- package/dist/check/rules/common.js +60 -0
- package/dist/check/rules/common.js.map +1 -0
- package/dist/check/rules/file.d.ts +3 -0
- package/dist/check/rules/file.d.ts.map +1 -0
- package/dist/check/rules/file.js +157 -0
- package/dist/check/rules/file.js.map +1 -0
- package/dist/check/rules/html.d.ts +3 -0
- package/dist/check/rules/html.d.ts.map +1 -0
- package/dist/check/rules/html.js +414 -0
- package/dist/check/rules/html.js.map +1 -0
- package/dist/check/rules/index.d.ts +6 -0
- package/dist/check/rules/index.d.ts.map +1 -0
- package/dist/check/rules/index.js +59 -0
- package/dist/check/rules/index.js.map +1 -0
- package/dist/check/rules/javascript.d.ts +3 -0
- package/dist/check/rules/javascript.d.ts.map +1 -0
- package/dist/check/rules/javascript.js +541 -0
- package/dist/check/rules/javascript.js.map +1 -0
- package/dist/check/rules/svg.d.ts +8 -0
- package/dist/check/rules/svg.d.ts.map +1 -0
- package/dist/check/rules/svg.js +100 -0
- package/dist/check/rules/svg.js.map +1 -0
- package/dist/check/types.d.ts +50 -0
- package/dist/check/types.d.ts.map +1 -0
- package/dist/check/types.js +3 -0
- package/dist/check/types.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +62 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +64 -0
- package/dist/config.js.map +1 -0
- package/dist/env.d.ts +2 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +25 -0
- package/dist/env.js.map +1 -0
- package/dist/output.d.ts +8 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +42 -0
- package/dist/output.js.map +1 -0
- package/dist/preview.d.ts +21 -0
- package/dist/preview.d.ts.map +1 -0
- package/dist/preview.js +295 -0
- package/dist/preview.js.map +1 -0
- package/dist/project.d.ts +5 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project.js +22 -0
- package/dist/project.js.map +1 -0
- package/dist/push.d.ts +2 -0
- package/dist/push.d.ts.map +1 -0
- package/dist/push.js +322 -0
- package/dist/push.js.map +1 -0
- package/dist/remote.d.ts +15 -0
- package/dist/remote.d.ts.map +1 -0
- package/dist/remote.js +73 -0
- package/dist/remote.js.map +1 -0
- package/package.json +27 -0
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# GenUI Toolkit
|
|
2
|
+
|
|
3
|
+
GenUI 项目的本地预览、规则检查与发布工具。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i @cosui/genui-toolkit -g
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 使用
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
genui preview ./project.zip
|
|
15
|
+
genui check ./project.zip
|
|
16
|
+
genui login
|
|
17
|
+
genui list
|
|
18
|
+
genui publish -p ./project.zip -n "应用名称" -l ./logo.png -b "应用简介" --description "应用摘要"
|
|
19
|
+
genui publish -a existing-appkey --description "新的应用摘要"
|
|
20
|
+
genui publish -a existing-appkey --description "新的应用摘要" --dry-run
|
|
21
|
+
genui logout
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`publish` 会读取当前目录的 `app.json`,命令行显式参数优先于配置文件:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"appkey": "existing-appkey",
|
|
29
|
+
"projectPath": "./project.zip",
|
|
30
|
+
"name": "应用名称",
|
|
31
|
+
"logo": "./logo.png",
|
|
32
|
+
"brief": "应用简介",
|
|
33
|
+
"description": "应用摘要"
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
配置完成后可直接执行 `genui publish`。`--dry-run` 会完成检查、登录、权限和应用信息合并,展示最终信息后停止,不上传或提交;确认信息无误后可用相同参数追加 `--yes` 正式提交。`--dry-run` 和 `--yes` 仅接受命令行传入,不从 `app.json` 读取。
|
|
38
|
+
|
|
39
|
+
`check` 只接受单个 HTML、ZIP:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
genui check ./page.html --format json
|
|
43
|
+
```
|
package/bin/genui
ADDED
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAmCA,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsG5D;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAO7D"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runLogin = runLogin;
|
|
7
|
+
exports.runLogout = runLogout;
|
|
8
|
+
const node_crypto_1 = require("node:crypto");
|
|
9
|
+
const node_child_process_1 = require("node:child_process");
|
|
10
|
+
const node_http_1 = __importDefault(require("node:http"));
|
|
11
|
+
const config_js_1 = require("./config.js");
|
|
12
|
+
const output_js_1 = require("./output.js");
|
|
13
|
+
const LOGIN_URL = 'https://genui.baidu.com/pages/login.html';
|
|
14
|
+
const LOGIN_ORIGIN = new URL(LOGIN_URL).origin;
|
|
15
|
+
const TIMEOUT_MS = 120_000;
|
|
16
|
+
function openBrowser(url) {
|
|
17
|
+
const command = process.platform === 'darwin'
|
|
18
|
+
? 'open'
|
|
19
|
+
: process.platform === 'win32'
|
|
20
|
+
? 'cmd'
|
|
21
|
+
: 'xdg-open';
|
|
22
|
+
const args = process.platform === 'win32'
|
|
23
|
+
? ['/c', 'start', '', url]
|
|
24
|
+
: [url];
|
|
25
|
+
(0, node_child_process_1.spawn)(command, args, { detached: true, stdio: 'ignore' }).unref();
|
|
26
|
+
}
|
|
27
|
+
function sendJson(response, status, body) {
|
|
28
|
+
response.writeHead(status, {
|
|
29
|
+
'Access-Control-Allow-Origin': LOGIN_ORIGIN,
|
|
30
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
31
|
+
});
|
|
32
|
+
response.end(JSON.stringify(body));
|
|
33
|
+
}
|
|
34
|
+
async function runLogin(argv) {
|
|
35
|
+
if (argv.length) {
|
|
36
|
+
throw new Error('login 命令不接受参数');
|
|
37
|
+
}
|
|
38
|
+
if ((0, config_js_1.getToken)()) {
|
|
39
|
+
output_js_1.output.success('当前已登录');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const state = (0, node_crypto_1.randomUUID)();
|
|
43
|
+
const token = await new Promise((resolve, reject) => {
|
|
44
|
+
let timer;
|
|
45
|
+
const server = node_http_1.default.createServer((request, response) => {
|
|
46
|
+
if (request.method === 'OPTIONS') {
|
|
47
|
+
response.writeHead(204, {
|
|
48
|
+
'Access-Control-Allow-Origin': LOGIN_ORIGIN,
|
|
49
|
+
'Access-Control-Allow-Headers': 'content-type',
|
|
50
|
+
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
|
51
|
+
'Access-Control-Allow-Private-Network': 'true',
|
|
52
|
+
});
|
|
53
|
+
response.end();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const requestUrl = new URL(request.url || '/', 'http://127.0.0.1');
|
|
57
|
+
if (request.method !== 'POST' || requestUrl.pathname !== '/auth/postToken') {
|
|
58
|
+
sendJson(response, 404, { status: 404, errMsg: 'Not found' });
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
let raw = '';
|
|
62
|
+
request.setEncoding('utf8');
|
|
63
|
+
request.on('data', chunk => {
|
|
64
|
+
raw += chunk;
|
|
65
|
+
if (raw.length > 64 * 1024) {
|
|
66
|
+
request.destroy();
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
request.on('end', async () => {
|
|
70
|
+
try {
|
|
71
|
+
const body = JSON.parse(raw);
|
|
72
|
+
if (typeof body.token !== 'string'
|
|
73
|
+
|| !body.token
|
|
74
|
+
|| body.state !== state) {
|
|
75
|
+
sendJson(response, 400, {
|
|
76
|
+
status: 400,
|
|
77
|
+
errMsg: 'Invalid token or state',
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (!(0, config_js_1.isValidToken)(body.token)) {
|
|
82
|
+
throw new Error('登录页未返回有效 JWT');
|
|
83
|
+
}
|
|
84
|
+
sendJson(response, 200, { status: 0, errMsg: '' });
|
|
85
|
+
if (timer) {
|
|
86
|
+
clearTimeout(timer);
|
|
87
|
+
}
|
|
88
|
+
setTimeout(() => {
|
|
89
|
+
server.close();
|
|
90
|
+
}, 400);
|
|
91
|
+
resolve(body.token);
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
sendJson(response, 400, {
|
|
95
|
+
status: 400,
|
|
96
|
+
errMsg: error instanceof Error ? error.message : String(error),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
server.on('error', reject);
|
|
102
|
+
server.listen(0, '127.0.0.1', () => {
|
|
103
|
+
const address = server.address();
|
|
104
|
+
if (!address || typeof address === 'string') {
|
|
105
|
+
server.close();
|
|
106
|
+
reject(new Error('登录服务启动失败'));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const url = new URL(LOGIN_URL);
|
|
110
|
+
url.searchParams.set('host', `http://127.0.0.1:${address.port}`);
|
|
111
|
+
url.searchParams.set('state', state);
|
|
112
|
+
url.searchParams.set('api-host', LOGIN_URL);
|
|
113
|
+
output_js_1.output.info('请在浏览器完成百度账号登录:');
|
|
114
|
+
output_js_1.output.info(` ${url}`);
|
|
115
|
+
openBrowser(url.toString());
|
|
116
|
+
timer = setTimeout(() => {
|
|
117
|
+
server.close();
|
|
118
|
+
reject(new Error('登录超时,请重试'));
|
|
119
|
+
}, TIMEOUT_MS);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
(0, config_js_1.saveToken)(token);
|
|
123
|
+
output_js_1.output.success('登录成功');
|
|
124
|
+
}
|
|
125
|
+
async function runLogout(argv) {
|
|
126
|
+
if (argv.length) {
|
|
127
|
+
throw new Error('logout 命令不接受参数');
|
|
128
|
+
}
|
|
129
|
+
(0, config_js_1.clearToken)();
|
|
130
|
+
output_js_1.output.success('登出成功');
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Artifact, CheckOptions } from './types';
|
|
2
|
+
export declare const DEFAULT_MAX_ARTIFACT_BYTES: number;
|
|
3
|
+
export declare const DEFAULT_MAX_ZIP_ENTRIES = 1000;
|
|
4
|
+
export declare const ALLOWED_ARTIFACT_EXTENSIONS: Set<string>;
|
|
5
|
+
export declare function isMacOsMetadata(entryPath: string): boolean;
|
|
6
|
+
export declare function formatMegabytes(bytes: number): string;
|
|
7
|
+
export declare class ArtifactCheckError extends Error {
|
|
8
|
+
readonly ruleId: string;
|
|
9
|
+
readonly file: string;
|
|
10
|
+
constructor(ruleId: string, file: string, message: string);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 将本地产物完整读入内存,供后续规则共享同一份只读内容
|
|
14
|
+
*/
|
|
15
|
+
export declare function readArtifact(inputPath: string, options?: CheckOptions): Promise<Artifact>;
|
|
16
|
+
//# sourceMappingURL=artifact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact.d.ts","sourceRoot":"","sources":["../../src/check/artifact.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACR,QAAQ,EAIR,YAAY,EACf,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,0BAA0B,QAAkB,CAAC;AAC1D,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAC5C,eAAO,MAAM,2BAA2B,aAatC,CAAC;AAEH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAI1D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGrD;AAcD,qBAAa,kBAAmB,SAAQ,KAAK;IAErC,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM;gBADZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM;CAItB;AAuHD;;GAEG;AACH,wBAAsB,YAAY,CAC9B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,YAAiB,GAC3B,OAAO,CAAC,QAAQ,CAAC,CAsGnB"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ArtifactCheckError = exports.ALLOWED_ARTIFACT_EXTENSIONS = exports.DEFAULT_MAX_ZIP_ENTRIES = exports.DEFAULT_MAX_ARTIFACT_BYTES = void 0;
|
|
7
|
+
exports.isMacOsMetadata = isMacOsMetadata;
|
|
8
|
+
exports.formatMegabytes = formatMegabytes;
|
|
9
|
+
exports.readArtifact = readArtifact;
|
|
10
|
+
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
11
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
12
|
+
const yauzl_1 = require("yauzl");
|
|
13
|
+
const node_stream_1 = require("node:stream");
|
|
14
|
+
exports.DEFAULT_MAX_ARTIFACT_BYTES = 8 * 1024 * 1024;
|
|
15
|
+
exports.DEFAULT_MAX_ZIP_ENTRIES = 1000;
|
|
16
|
+
exports.ALLOWED_ARTIFACT_EXTENSIONS = new Set([
|
|
17
|
+
'.html',
|
|
18
|
+
'.css',
|
|
19
|
+
'.js',
|
|
20
|
+
'.png',
|
|
21
|
+
'.jpg',
|
|
22
|
+
'.jpeg',
|
|
23
|
+
'.gif',
|
|
24
|
+
'.webp',
|
|
25
|
+
'.svg',
|
|
26
|
+
'.woff',
|
|
27
|
+
'.woff2',
|
|
28
|
+
'.json',
|
|
29
|
+
]);
|
|
30
|
+
function isMacOsMetadata(entryPath) {
|
|
31
|
+
const segments = entryPath.split('/');
|
|
32
|
+
const name = segments[segments.length - 1];
|
|
33
|
+
return segments[0] === '__MACOSX' || name === '.DS_Store' || name.startsWith('._');
|
|
34
|
+
}
|
|
35
|
+
function formatMegabytes(bytes) {
|
|
36
|
+
const megabytes = bytes / 1024 / 1024;
|
|
37
|
+
return `${Number(megabytes.toFixed(megabytes >= 1 ? 2 : 6))} MB`;
|
|
38
|
+
}
|
|
39
|
+
function isHttpUrl(value) {
|
|
40
|
+
return /^https?:\/\//i.test(value);
|
|
41
|
+
}
|
|
42
|
+
function getArtifactName(inputPath) {
|
|
43
|
+
if (!isHttpUrl(inputPath)) {
|
|
44
|
+
return node_path_1.default.basename(inputPath);
|
|
45
|
+
}
|
|
46
|
+
const name = node_path_1.default.posix.basename(new URL(inputPath).pathname);
|
|
47
|
+
return /\.(html?|zip)$/i.test(name) ? name : 'index.html';
|
|
48
|
+
}
|
|
49
|
+
class ArtifactCheckError extends Error {
|
|
50
|
+
ruleId;
|
|
51
|
+
file;
|
|
52
|
+
constructor(ruleId, file, message) {
|
|
53
|
+
super(message);
|
|
54
|
+
this.ruleId = ruleId;
|
|
55
|
+
this.file = file;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.ArtifactCheckError = ArtifactCheckError;
|
|
59
|
+
/**
|
|
60
|
+
* 根据文件头识别产物类型
|
|
61
|
+
* 非 ZIP 内容交给后续文件格式解析规则判断
|
|
62
|
+
*/
|
|
63
|
+
function identifyArtifact(bytes) {
|
|
64
|
+
const isZip = bytes[0] === 0x50 && bytes[1] === 0x4b && (bytes[2] === 0x03 && bytes[3] === 0x04
|
|
65
|
+
|| bytes[2] === 0x05 && bytes[3] === 0x06
|
|
66
|
+
|| bytes[2] === 0x07 && bytes[3] === 0x08);
|
|
67
|
+
return isZip ? 'zip' : 'html';
|
|
68
|
+
}
|
|
69
|
+
async function readStream(stream, maxBytes, file = '', sizeName = '产物解压后大小') {
|
|
70
|
+
const chunks = [];
|
|
71
|
+
let size = 0;
|
|
72
|
+
for await (const chunk of stream) {
|
|
73
|
+
const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
74
|
+
size += bytes.length;
|
|
75
|
+
if (size > maxBytes) {
|
|
76
|
+
stream.destroy();
|
|
77
|
+
throw new ArtifactCheckError('artifact', file, `${sizeName}超过 ${formatMegabytes(maxBytes)},请压缩或删除不必要资源后重新提交`);
|
|
78
|
+
}
|
|
79
|
+
chunks.push(bytes);
|
|
80
|
+
}
|
|
81
|
+
return Buffer.concat(chunks, size);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 逐条解压到内存文件表
|
|
85
|
+
*/
|
|
86
|
+
async function readZipFiles(bytes, maxArtifactBytes, maxZipEntries) {
|
|
87
|
+
const zip = await (0, yauzl_1.fromBufferPromise)(bytes, {
|
|
88
|
+
strictFileNames: true,
|
|
89
|
+
validateEntrySizes: true,
|
|
90
|
+
});
|
|
91
|
+
const files = new Map();
|
|
92
|
+
const entries = [];
|
|
93
|
+
let entryCount = 0;
|
|
94
|
+
let totalUncompressedBytes = 0;
|
|
95
|
+
for await (const entry of zip.eachEntry()) {
|
|
96
|
+
entryCount += 1;
|
|
97
|
+
if (entryCount > maxZipEntries) {
|
|
98
|
+
throw new ArtifactCheckError('artifact', '', `ZIP 内文件数量超过 ${maxZipEntries} 个,请删除不必要的文件后重新打包`);
|
|
99
|
+
}
|
|
100
|
+
if (isMacOsMetadata(entry.fileName)) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
entries.push({
|
|
104
|
+
fileName: entry.fileName,
|
|
105
|
+
externalFileAttributes: entry.externalFileAttributes,
|
|
106
|
+
versionMadeBy: entry.versionMadeBy,
|
|
107
|
+
generalPurposeBitFlag: entry.generalPurposeBitFlag,
|
|
108
|
+
});
|
|
109
|
+
if (entry.fileName.endsWith('/')) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if ((entry.generalPurposeBitFlag & 0x1) !== 0) {
|
|
113
|
+
files.set(entry.fileName, { path: entry.fileName, bytes: new Uint8Array() });
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
totalUncompressedBytes += entry.uncompressedSize;
|
|
117
|
+
if (totalUncompressedBytes > maxArtifactBytes) {
|
|
118
|
+
throw new ArtifactCheckError('artifact', '', `代码包解压后大小超过 ${formatMegabytes(maxArtifactBytes)},请压缩或删除不必要资源后重新提交`);
|
|
119
|
+
}
|
|
120
|
+
if (!exports.ALLOWED_ARTIFACT_EXTENSIONS.has(node_path_1.default.posix.extname(entry.fileName).toLowerCase())) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const fileBytes = await readStream(await zip.openReadStreamPromise(entry), maxArtifactBytes - (totalUncompressedBytes - entry.uncompressedSize));
|
|
124
|
+
if (!files.has(entry.fileName)) {
|
|
125
|
+
files.set(entry.fileName, {
|
|
126
|
+
path: entry.fileName,
|
|
127
|
+
bytes: fileBytes,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return { files, entries };
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 将本地产物完整读入内存,供后续规则共享同一份只读内容
|
|
135
|
+
*/
|
|
136
|
+
async function readArtifact(inputPath, options = {}) {
|
|
137
|
+
const remote = isHttpUrl(inputPath);
|
|
138
|
+
const artifactPath = remote ? inputPath : node_path_1.default.resolve(inputPath);
|
|
139
|
+
const artifactName = getArtifactName(inputPath);
|
|
140
|
+
const maxArtifactBytes = options.maxArtifactBytes ?? exports.DEFAULT_MAX_ARTIFACT_BYTES;
|
|
141
|
+
const maxZipEntries = options.maxZipEntries ?? exports.DEFAULT_MAX_ZIP_ENTRIES;
|
|
142
|
+
let bytes = Buffer.alloc(0);
|
|
143
|
+
try {
|
|
144
|
+
if (remote) {
|
|
145
|
+
const response = await fetch(inputPath);
|
|
146
|
+
if (!response.ok) {
|
|
147
|
+
throw new Error(`远程文件下载失败: ${response.status} ${response.statusText}`);
|
|
148
|
+
}
|
|
149
|
+
const contentLength = Number(response.headers.get('content-length'));
|
|
150
|
+
if (Number.isFinite(contentLength) && contentLength > maxArtifactBytes) {
|
|
151
|
+
throw new ArtifactCheckError('artifact', artifactName, `文件大小超过 ${formatMegabytes(maxArtifactBytes)},请压缩或删除不必要资源后重新提交`);
|
|
152
|
+
}
|
|
153
|
+
bytes = response.body
|
|
154
|
+
? Buffer.from(await readStream(node_stream_1.Readable.fromWeb(response.body), maxArtifactBytes, artifactName, '文件大小'))
|
|
155
|
+
: Buffer.alloc(0);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
const stats = await promises_1.default.stat(artifactPath);
|
|
159
|
+
if (stats.size > maxArtifactBytes) {
|
|
160
|
+
throw new ArtifactCheckError('artifact', artifactName, `文件大小超过 ${formatMegabytes(maxArtifactBytes)},请压缩或删除不必要资源后重新提交`);
|
|
161
|
+
}
|
|
162
|
+
bytes = await promises_1.default.readFile(artifactPath);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
if (error instanceof ArtifactCheckError) {
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
169
|
+
if (remote && error instanceof Error) {
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
throw new Error('文件无法读取,请确认文件存在且当前用户有读取权限');
|
|
173
|
+
}
|
|
174
|
+
const type = identifyArtifact(bytes);
|
|
175
|
+
let files = new Map();
|
|
176
|
+
let zipEntries = [];
|
|
177
|
+
if (type === 'zip') {
|
|
178
|
+
try {
|
|
179
|
+
const zip = await readZipFiles(bytes, maxArtifactBytes, maxZipEntries);
|
|
180
|
+
files = zip.files;
|
|
181
|
+
zipEntries = zip.entries;
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
if (error instanceof ArtifactCheckError) {
|
|
185
|
+
throw new ArtifactCheckError(error.ruleId, error.file || artifactName, error.message);
|
|
186
|
+
}
|
|
187
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
188
|
+
if (['absolute path:', 'invalid relative path:', 'invalid characters in fileName:']
|
|
189
|
+
.some(prefix => message.startsWith(prefix))) {
|
|
190
|
+
throw new ArtifactCheckError('file', artifactName, 'ZIP 文件路径不符合要求,请将所有文件放在项目根目录下并使用相对路径,然后重新打包上传');
|
|
191
|
+
}
|
|
192
|
+
throw new ArtifactCheckError('artifact', artifactName, 'ZIP 文件损坏或无法解析,请检查文件是否完整后重新打包');
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
files = new Map([[
|
|
197
|
+
artifactName,
|
|
198
|
+
{ path: artifactName, bytes },
|
|
199
|
+
]]);
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
path: artifactPath,
|
|
203
|
+
type,
|
|
204
|
+
bytes,
|
|
205
|
+
files,
|
|
206
|
+
zipEntries,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=artifact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact.js","sourceRoot":"","sources":["../../src/check/artifact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checker.d.ts","sourceRoot":"","sources":["../../src/check/checker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACR,YAAY,EACZ,WAAW,EAEX,IAAI,EACP,MAAM,SAAS,CAAC;AAiDjB;;IAEI;AACJ,wBAAsB,aAAa,CAC/B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,IAAI,EAAE,EACb,OAAO,GAAE,YAAiB,GAC3B,OAAO,CAAC,WAAW,CAAC,CAgCtB"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkArtifact = checkArtifact;
|
|
4
|
+
const artifact_1 = require("./artifact");
|
|
5
|
+
/**
|
|
6
|
+
* 按文件位置和规则 ID 生成稳定的诊断输出顺序
|
|
7
|
+
*/
|
|
8
|
+
function compareDiagnostics(left, right) {
|
|
9
|
+
return (left.file ?? '').localeCompare(right.file ?? '')
|
|
10
|
+
|| (left.line ?? 0) - (right.line ?? 0)
|
|
11
|
+
|| (left.column ?? 0) - (right.column ?? 0)
|
|
12
|
+
|| left.ruleId.localeCompare(right.ruleId);
|
|
13
|
+
}
|
|
14
|
+
function createSummary(passed, warnings, diagnostics) {
|
|
15
|
+
if (diagnostics.length === 0) {
|
|
16
|
+
return '代码包已通过安全检测。';
|
|
17
|
+
}
|
|
18
|
+
const isPackageError = !passed
|
|
19
|
+
&& diagnostics.every(diagnostic => ['artifact', 'file'].includes(diagnostic.ruleId));
|
|
20
|
+
const summary = isPackageError
|
|
21
|
+
? `代码包检查未通过。发现 ${diagnostics.length} 项问题:`
|
|
22
|
+
: passed
|
|
23
|
+
? `代码包已通过安全检测,但存在安全风险。发现 ${warnings} 项风险提示:`
|
|
24
|
+
: `代码包未通过安全检测,存在安全风险。发现 ${diagnostics.length} 项风险:`;
|
|
25
|
+
const details = diagnostics.map((diagnostic, index) => {
|
|
26
|
+
const position = diagnostic.line
|
|
27
|
+
? `:${diagnostic.line}${diagnostic.column ? `:${diagnostic.column}` : ''}`
|
|
28
|
+
: '';
|
|
29
|
+
const location = diagnostic.file ? `${diagnostic.file}${position}:` : '';
|
|
30
|
+
return `[${index + 1}] ${location}${diagnostic.message}`;
|
|
31
|
+
});
|
|
32
|
+
return `${summary}${details.join(';')}`;
|
|
33
|
+
}
|
|
34
|
+
function createResult(startedAt, diagnostics) {
|
|
35
|
+
diagnostics.sort(compareDiagnostics);
|
|
36
|
+
const errors = diagnostics.filter(item => item.severity === 'error').length;
|
|
37
|
+
const passed = errors === 0;
|
|
38
|
+
return {
|
|
39
|
+
schemaVersion: 1,
|
|
40
|
+
passed,
|
|
41
|
+
errors,
|
|
42
|
+
warnings: diagnostics.length - errors,
|
|
43
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
44
|
+
summary: createSummary(passed, diagnostics.length - errors, diagnostics),
|
|
45
|
+
diagnostics,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 读取产物、执行已注册规则、输出结果
|
|
50
|
+
*/
|
|
51
|
+
async function checkArtifact(inputPath, rules, options = {}) {
|
|
52
|
+
const startedAt = performance.now();
|
|
53
|
+
const artifact = await (0, artifact_1.readArtifact)(inputPath, options).catch(error => {
|
|
54
|
+
if (!(error instanceof artifact_1.ArtifactCheckError)) {
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
return error;
|
|
58
|
+
});
|
|
59
|
+
if (artifact instanceof artifact_1.ArtifactCheckError) {
|
|
60
|
+
return createResult(startedAt, [{
|
|
61
|
+
ruleId: artifact.ruleId,
|
|
62
|
+
severity: 'error',
|
|
63
|
+
file: artifact.file,
|
|
64
|
+
message: artifact.message,
|
|
65
|
+
}]);
|
|
66
|
+
}
|
|
67
|
+
const diagnostics = [];
|
|
68
|
+
const gateRuleIds = new Set(['artifact', 'file']);
|
|
69
|
+
for (const rule of rules.filter(item => gateRuleIds.has(item.id))) {
|
|
70
|
+
diagnostics.push(...await rule.check({ artifact, options }));
|
|
71
|
+
if (diagnostics.some(item => item.severity === 'error')) {
|
|
72
|
+
return createResult(startedAt, diagnostics);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
diagnostics.push(...(await Promise.all(rules.filter(rule => !gateRuleIds.has(rule.id))
|
|
76
|
+
.map(rule => rule.check({ artifact, options })))).flat());
|
|
77
|
+
return createResult(startedAt, diagnostics);
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=checker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checker.js","sourceRoot":"","sources":["../../src/check/checker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/check/cli.ts"],"names":[],"mappings":"AAgHA;;GAEG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAe5D"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runCheck = runCheck;
|
|
7
|
+
const minimist_1 = __importDefault(require("minimist"));
|
|
8
|
+
const artifact_1 = require("./artifact");
|
|
9
|
+
const rules_1 = require("./rules");
|
|
10
|
+
const checker_1 = require("./checker");
|
|
11
|
+
const USAGE = `Usage:
|
|
12
|
+
genui check <artifact> [options]
|
|
13
|
+
|
|
14
|
+
Arguments:
|
|
15
|
+
<artifact> 待诊断的单 HTML 或 ZIP 文件路径
|
|
16
|
+
|
|
17
|
+
Options:
|
|
18
|
+
--format text|json 输出格式,默认 text
|
|
19
|
+
--max-artifact-bytes N
|
|
20
|
+
产物文件及 ZIP 解压后最大大小,默认 ${artifact_1.DEFAULT_MAX_ARTIFACT_BYTES / 1024 / 1024} MB
|
|
21
|
+
--max-zip-entries N ZIP 最大条目数,默认 ${artifact_1.DEFAULT_MAX_ZIP_ENTRIES}
|
|
22
|
+
--help 显示帮助`;
|
|
23
|
+
/**
|
|
24
|
+
* 将检查结果渲染为适合终端阅读的文本
|
|
25
|
+
*/
|
|
26
|
+
function printText(result) {
|
|
27
|
+
console.log(result.summary
|
|
28
|
+
.replace(/:(?=\[1\] )/, ':\n\n')
|
|
29
|
+
.replace(/;(?=\[\d+\] )/g, '\n\n'));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 校验并归一化 check 命令参数
|
|
33
|
+
*
|
|
34
|
+
* @param args minimist 解析后的原始参数
|
|
35
|
+
* @returns 参数合法时返回归一化后的选项,非法时返回 undefined
|
|
36
|
+
*/
|
|
37
|
+
function resolveCheckOptions(args) {
|
|
38
|
+
const [artifact, ...extra] = args._;
|
|
39
|
+
const format = args.format ?? 'text';
|
|
40
|
+
const maxArtifactBytes = args['max-artifact-bytes'];
|
|
41
|
+
const maxZipEntries = args['max-zip-entries'];
|
|
42
|
+
const knownArgs = new Set([
|
|
43
|
+
'_',
|
|
44
|
+
'format',
|
|
45
|
+
'max-artifact-bytes',
|
|
46
|
+
'max-zip-entries',
|
|
47
|
+
'help',
|
|
48
|
+
]);
|
|
49
|
+
const validLimit = (value) => value === undefined || (Number.isInteger(value) && value > 0);
|
|
50
|
+
if (!artifact
|
|
51
|
+
|| extra.length > 0
|
|
52
|
+
|| Object.keys(args).some(key => !knownArgs.has(key))
|
|
53
|
+
|| !['text', 'json'].includes(format)
|
|
54
|
+
|| !validLimit(maxArtifactBytes)
|
|
55
|
+
|| !validLimit(maxZipEntries)) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
return { artifact, format, maxArtifactBytes, maxZipEntries };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 按指定格式输出检查结果
|
|
62
|
+
*
|
|
63
|
+
* @param result 检查结果
|
|
64
|
+
* @param format 输出格式,text 或 json
|
|
65
|
+
*/
|
|
66
|
+
function printResult(result, format) {
|
|
67
|
+
if (format === 'json') {
|
|
68
|
+
console.log(JSON.stringify(result, null, 2));
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
printText(result);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 执行产物检查并设置进程退出码
|
|
76
|
+
*
|
|
77
|
+
* @param options 归一化后的检查选项
|
|
78
|
+
*/
|
|
79
|
+
async function checkAndReport(options) {
|
|
80
|
+
try {
|
|
81
|
+
const result = await (0, checker_1.checkArtifact)(options.artifact, rules_1.rules, {
|
|
82
|
+
maxArtifactBytes: options.maxArtifactBytes,
|
|
83
|
+
maxZipEntries: options.maxZipEntries,
|
|
84
|
+
});
|
|
85
|
+
printResult(result, options.format);
|
|
86
|
+
process.exitCode = result.passed ? 0 : 1;
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
90
|
+
process.exitCode = 2;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 解析 check 命令参数,运行检查
|
|
95
|
+
*/
|
|
96
|
+
async function runCheck(argv) {
|
|
97
|
+
const args = (0, minimist_1.default)(argv);
|
|
98
|
+
if (args.help) {
|
|
99
|
+
console.log(USAGE);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const options = resolveCheckOptions(args);
|
|
103
|
+
if (!options) {
|
|
104
|
+
console.error(USAGE);
|
|
105
|
+
process.exitCode = 2;
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
await checkAndReport(options);
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=cli.js.map
|