chanjs 2.1.1 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/App.js +387 -0
  2. package/base/Context.js +78 -0
  3. package/base/Controller.js +137 -0
  4. package/base/Database.js +314 -0
  5. package/base/Service.js +539 -0
  6. package/common/api.js +25 -0
  7. package/common/category.js +22 -0
  8. package/common/code.js +42 -0
  9. package/common/email.js +110 -0
  10. package/common/index.js +7 -0
  11. package/common/pages.js +86 -0
  12. package/common/sms.js +104 -0
  13. package/common/utils.js +73 -0
  14. package/config/code.js +110 -52
  15. package/config/index.js +10 -0
  16. package/config/paths.js +60 -0
  17. package/extend/art-template.js +46 -28
  18. package/extend/index.js +6 -0
  19. package/global/env.js +11 -5
  20. package/global/global.js +63 -39
  21. package/global/import.js +43 -39
  22. package/global/index.js +8 -3
  23. package/helper/cache.js +182 -0
  24. package/helper/data-parse.js +121 -37
  25. package/helper/db.js +71 -83
  26. package/helper/file.js +158 -208
  27. package/helper/filter.js +34 -0
  28. package/helper/html.js +30 -47
  29. package/helper/index.js +29 -5
  30. package/helper/ip.js +48 -31
  31. package/helper/jwt.js +78 -11
  32. package/helper/loader.js +93 -50
  33. package/helper/request.js +41 -144
  34. package/helper/sign.js +96 -33
  35. package/helper/time.js +89 -74
  36. package/helper/tree.js +77 -0
  37. package/index.js +15 -181
  38. package/middleware/cookie.js +20 -4
  39. package/middleware/cors.js +20 -0
  40. package/middleware/favicon.js +21 -5
  41. package/middleware/header.js +26 -9
  42. package/middleware/index.js +14 -23
  43. package/middleware/preventRetry.js +30 -0
  44. package/middleware/setBody.js +24 -10
  45. package/middleware/static.js +31 -10
  46. package/middleware/template.js +34 -14
  47. package/middleware/validator.js +43 -23
  48. package/middleware/waf.js +147 -287
  49. package/package.json +1 -1
  50. package/utils/checker.js +68 -0
  51. package/utils/error-handler.js +115 -0
  52. package/utils/error.js +81 -0
  53. package/utils/index.js +6 -0
  54. package/utils/keywords.js +126 -0
  55. package/utils/rate-limit.js +116 -0
  56. package/utils/response.js +103 -64
  57. package/utils/xss-filter.js +42 -0
  58. package/core/controller.js +0 -33
  59. package/core/index.js +0 -3
  60. package/core/service.js +0 -307
  61. package/middleware/log.js +0 -21
@@ -0,0 +1,115 @@
1
+ /**
2
+ * 数据库错误处理工具
3
+ * 提供数据库错误解析和错误响应生成功能
4
+ */
5
+
6
+ export const DB_ERROR = {
7
+ ECONNREFUSED: 6001,
8
+ ER_ACCESS_DENIED_ERROR: 6002,
9
+ ER_ROW_IS_REFERENCED_2: 6003,
10
+ ER_BAD_FIELD_ERROR: 6004,
11
+ ER_DUP_ENTRY: 6005,
12
+ ER_NO_SUCH_TABLE: 6006,
13
+ ETIMEOUT: 6007,
14
+ ER_TABLE_EXISTS_ERROR: 4003,
15
+ };
16
+
17
+ export const ERROR_MESSAGES = {
18
+ 6001: "数据库连接失败",
19
+ 6002: "数据库访问被拒绝",
20
+ 6003: "存在关联数据,操作失败",
21
+ 6004: "数据库字段错误",
22
+ 6005: "数据重复,违反唯一性约束",
23
+ 6006: "目标表不存在",
24
+ 6007: "数据库操作超时",
25
+ 6008: "数据库语法错误,请检查查询语句",
26
+ 6009: "数据库连接已关闭,请重试",
27
+ 4003: "资源已存在",
28
+ 5001: "系统内部错误",
29
+ };
30
+
31
+ /**
32
+ * 解析数据库错误
33
+ * @param {Error} error - 数据库错误对象
34
+ * @returns {Object} 包含 code、msg 和 statusCode 的对象
35
+ * @description
36
+ * 根据数据库错误代码映射为业务状态码
37
+ * 返回对应的错误消息和 HTTP 状态码
38
+ * @example
39
+ * const errorInfo = parseDatabaseError({ code: 'ER_DUP_ENTRY' });
40
+ * console.log(errorInfo); // { code: 6005, msg: '数据重复...', statusCode: 500 }
41
+ */
42
+ export function parseDatabaseError(error) {
43
+ const errorCode = error?.code && DB_ERROR[error.code]
44
+ ? DB_ERROR[error.code]
45
+ : error?.message?.includes("syntax") || error?.message?.includes("SQL")
46
+ ? 6008
47
+ : error?.message?.includes("Connection closed")
48
+ ? 6009
49
+ : error?.message?.includes("permission")
50
+ ? 3003
51
+ : 5001;
52
+
53
+ return {
54
+ code: errorCode,
55
+ msg: ERROR_MESSAGES[errorCode] || error?.message || "服务器内部错误",
56
+ statusCode: errorCode >= 6000 ? 500 : errorCode >= 4000 ? 400 : 500,
57
+ };
58
+ }
59
+
60
+ /**
61
+ * 生成 404 响应
62
+ * @param {Object} req - Express 请求对象
63
+ * @returns {Object} 404 响应对象
64
+ * @description
65
+ * 返回标准的接口不存在响应
66
+ * 包含请求的路径和方法
67
+ * @example
68
+ * const response = notFoundResponse(req);
69
+ */
70
+ export function notFoundResponse(req) {
71
+ return {
72
+ success: false,
73
+ msg: "接口不存在",
74
+ code: 404,
75
+ data: { path: req.path, method: req.method },
76
+ };
77
+ }
78
+
79
+ /**
80
+ * 生成错误响应
81
+ * @param {Error} err - 错误对象
82
+ * @param {Object} req - Express 请求对象
83
+ * @returns {Object} 错误响应对象
84
+ * @description
85
+ * 根据错误类型生成相应的错误响应
86
+ * 开发环境下包含详细的错误信息
87
+ * @example
88
+ * const response = errorResponse(error, req);
89
+ */
90
+ export function errorResponse(err, req) {
91
+ const errorInfo = parseDatabaseError(err);
92
+
93
+ console.error(`[Error Handler] ${errorInfo.msg} - ${err?.message}`, {
94
+ code: errorInfo.code,
95
+ path: req?.path,
96
+ method: req?.method,
97
+ sql: err?.sql,
98
+ sqlMessage: err?.sqlMessage,
99
+ stack: err?.stack,
100
+ });
101
+
102
+ return {
103
+ success: false,
104
+ msg: errorInfo.msg,
105
+ code: errorInfo.code,
106
+ data: process.env.NODE_ENV === "development"
107
+ ? {
108
+ message: err?.message,
109
+ sql: err?.sql,
110
+ sqlMessage: err?.sqlMessage,
111
+ stack: err?.stack,
112
+ }
113
+ : {},
114
+ };
115
+ }
package/utils/error.js ADDED
@@ -0,0 +1,81 @@
1
+ /**
2
+ * 错误处理和日志工具
3
+ * 提供错误码定义和错误日志记录功能
4
+ */
5
+
6
+ export const CODE = {
7
+ SUCCESS: { code: 200, message: "操作成功" },
8
+ FAIL: { code: 201, message: "操作失败" },
9
+ ERROR: { code: 500, message: "服务器错误" },
10
+ UNAUTHORIZED: { code: 401, message: "未授权" },
11
+ FORBIDDEN: { code: 403, message: "禁止访问" },
12
+ NOT_FOUND: { code: 404, message: "资源不存在" },
13
+ VALIDATION: { code: 400, message: "参数校验失败" },
14
+ CONFIG: { code: 500, message: "配置错误" },
15
+ };
16
+
17
+ /**
18
+ * 记录错误日志
19
+ * @private
20
+ * @param {string} type - 错误类型
21
+ * @param {string} message - 错误消息
22
+ * @param {Object} [extra={}] - 额外信息
23
+ * @description
24
+ * 将错误信息格式化为 JSON 并输出到控制台
25
+ * 包含时间戳、错误类型和消息
26
+ */
27
+ function logError(type, message, extra = {}) {
28
+ const timestamp = new Date().toISOString();
29
+ console.error(JSON.stringify({
30
+ timestamp,
31
+ type,
32
+ message,
33
+ ...extra,
34
+ }));
35
+ }
36
+
37
+ /**
38
+ * 创建错误对象
39
+ * @private
40
+ * @param {string} message - 错误消息
41
+ * @param {number} [statusCode=500] - HTTP 状态码
42
+ * @param {string} [code="ERROR"] - 错误代码
43
+ * @returns {Object} 错误对象
44
+ */
45
+ function createError(message, statusCode = 500, code = "ERROR") {
46
+ logError(code, message, { statusCode });
47
+ return {
48
+ isError: true,
49
+ message,
50
+ statusCode,
51
+ code,
52
+ };
53
+ }
54
+
55
+ /**
56
+ * 生成配置错误
57
+ * @param {string} message - 错误消息
58
+ * @returns {Object} 配置错误对象
59
+ * @description
60
+ * 生成配置类型错误并记录日志
61
+ * @example
62
+ * const error = configError('数据库配置缺失');
63
+ */
64
+ export function configError(message) {
65
+ logError("CONFIG_ERROR", message);
66
+ return createError(message, CODE.CONFIG.code, "CONFIG_ERROR");
67
+ }
68
+
69
+ /**
70
+ * 生成认证错误
71
+ * @param {string} [message=CODE.UNAUTHORIZED.message] - 错误消息
72
+ * @returns {Object} 认证错误对象
73
+ * @description
74
+ * 生成认证类型错误并记录日志
75
+ * @example
76
+ * const error = authError('Token已过期');
77
+ */
78
+ export function authError(message = CODE.UNAUTHORIZED.message) {
79
+ logError("AUTH_ERROR", message);
80
+ return createError(message, CODE.UNAUTHORIZED.code, "AUTH_ERROR");
81
+ }
package/utils/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { success, fail, error } from "./response.js";
2
+ export { parseDatabaseError, notFoundResponse, errorResponse } from "./error-handler.js";
3
+ export { configError, authError } from "./error.js";
4
+ export { checkKeywords, isIgnored } from "./checker.js";
5
+ export { filterXSS } from "./xss-filter.js";
6
+ export { createRateLimitMiddleware } from "./rate-limit.js";
@@ -0,0 +1,126 @@
1
+ /**
2
+ * 安全关键词规则定义
3
+ * 定义各类恶意攻击的关键词检测规则
4
+ */
5
+
6
+ export const KEYWORD_RULES = {
7
+ /**
8
+ * 整词匹配规则(需完整匹配)
9
+ */
10
+ wholeWord: [
11
+ "netcat", "nc", "php-cgi", "process", "require",
12
+ "child_process", "execSync", "mainModule"
13
+ ],
14
+ /**
15
+ * 敏感文件扩展名
16
+ */
17
+ extensions: [
18
+ ".php", ".asp", ".aspx", ".jsp", ".jspx", ".do", ".action", ".cgi",
19
+ ".py", ".pl", ".cfm", ".jhtml", ".shtml"
20
+ ],
21
+ /**
22
+ * 敏感目录名称
23
+ */
24
+ directories: [
25
+ "/administrator", "/wp-admin", "phpMyAdmin", "cgi-bin",
26
+ "setup", "staging", "internal", "debug", "metadata", "secret"
27
+ ],
28
+ /**
29
+ * SQL 注入关键词
30
+ */
31
+ sqlInjection: [
32
+ "sleep(", "benchmark(", "concat(", "extractvalue(", "updatexml(", "version(",
33
+ "union select", "union all", "select @@", "drop ", "alter ", "truncate ",
34
+ "(select", "information_schema", "load_file(", "into outfile", "into dumpfile"
35
+ ],
36
+ /**
37
+ * 命令注入关键词
38
+ */
39
+ commandInjection: [
40
+ "cmd=", "system(", "exec(", "shell_exec(", "passthru(",
41
+ "eval(", "assert(", "preg_replace", "bash -i", "rm -rf",
42
+ "wget ", "curl ", "chmod ", "base64_decode", "phpinfo()"
43
+ ],
44
+ /**
45
+ * 路径遍历关键词
46
+ */
47
+ pathTraversal: [
48
+ "../", "..\\", "/etc/passwd", "/etc/shadow", "/etc/hosts",
49
+ "/etc/", "/var/www/", "/app/", "/root/", "__dirname", "__filename"
50
+ ],
51
+ /**
52
+ * XSS 攻击关键词
53
+ */
54
+ xss: [
55
+ "<script", "javascript:", "onerror=", "onload=", "onclick=",
56
+ "alert(", "document.cookie", "document.write"
57
+ ],
58
+ /**
59
+ * 编码绕过关键词
60
+ */
61
+ encoding: [
62
+ "0x7e", "UNION%20SELECT", "%27OR%27", "{{", "}}", "${", "1+1"
63
+ ],
64
+ /**
65
+ * 敏感标识符
66
+ */
67
+ sensitiveIdentifiers: [
68
+ "wp-", "smtp", "redirect", "configs", ".well-known/",
69
+ "fs.readFile", "fs.existsSync", "process.env", "process.argv"
70
+ ],
71
+ };
72
+
73
+ /**
74
+ * 关键词正则表达式缓存
75
+ * 将关键词规则编译为正则表达式以提高检测性能
76
+ */
77
+ export let keywordRegexCache = (() => {
78
+ const regexSpecialChars = /[.*+?^${}()|[\]\\]/g;
79
+ const cache = {};
80
+
81
+ for (const [category, keywords] of Object.entries(KEYWORD_RULES)) {
82
+ if (!Array.isArray(keywords)) continue;
83
+
84
+ cache[category] = keywords.map((keyword) => {
85
+ const escaped = keyword.replace(regexSpecialChars, "\\$&").replace(/ /g, "\\s");
86
+ return {
87
+ keyword,
88
+ regex: new RegExp(
89
+ category === 'wholeWord' ? `\\b${escaped}\\b` : escaped,
90
+ "i"
91
+ ),
92
+ };
93
+ });
94
+ }
95
+
96
+ return cache;
97
+ })();
98
+
99
+ /**
100
+ * 更新关键词缓存
101
+ * @param {Object} newRules - 新的关键词规则
102
+ * @description
103
+ * 允许动态添加或更新关键词检测规则
104
+ * @example
105
+ * updateKeywordCache({
106
+ * customKeywords: ['malicious', 'attack']
107
+ * });
108
+ */
109
+ export function updateKeywordCache(newRules = {}) {
110
+ const regexSpecialChars = /[.*+?^${}()|[\]\\]/g;
111
+
112
+ for (const [category, keywords] of Object.entries(newRules)) {
113
+ if (!Array.isArray(keywords)) continue;
114
+
115
+ keywordRegexCache[category] = keywords.map((keyword) => {
116
+ const escaped = keyword.replace(regexSpecialChars, "\\$&").replace(/ /g, "\\s");
117
+ return {
118
+ keyword,
119
+ regex: new RegExp(
120
+ category === 'wholeWord' ? `\\b${escaped}\\b` : escaped,
121
+ "i"
122
+ ),
123
+ };
124
+ });
125
+ }
126
+ }
@@ -0,0 +1,116 @@
1
+ import { isIgnored } from "./checker.js";
2
+ import { getIp } from "../helper/ip.js";
3
+
4
+ /**
5
+ * 访问频率限制工具
6
+ * 提供基于 IP 和 Cookie 的访问限流功能
7
+ */
8
+
9
+ const COOKIE_NAME = `${process.env.APP_NAME || 'app'}_ratelimit`;
10
+
11
+ /**
12
+ * 解析时间窗口参数
13
+ * @private
14
+ * @param {number|string} time - 时间值
15
+ * @returns {number} 毫秒数
16
+ * @description
17
+ * 支持以下格式:
18
+ * - 数字:直接作为毫秒数
19
+ * - 数字+s:秒
20
+ * - 数字+m:分钟
21
+ * - 数字+h:小时
22
+ * - 数字+d:天
23
+ */
24
+ function parseWindowMs(time) {
25
+ if (typeof time === 'number') return time;
26
+ if (typeof time !== 'string') return 60 * 60 * 1000;
27
+
28
+ const match = time.match(/^(\d+)([smhd])$/);
29
+ if (!match) return 60 * 60 * 1000;
30
+
31
+ const value = parseInt(match[1], 10);
32
+ const unit = match[2];
33
+
34
+ const multipliers = {
35
+ 's': 1000,
36
+ 'm': 60 * 1000,
37
+ 'h': 60 * 60 * 1000,
38
+ 'd': 24 * 60 * 60 * 1000,
39
+ };
40
+
41
+ return value * (multipliers[unit] || 1000);
42
+ }
43
+
44
+ /**
45
+ * 创建限流中间件
46
+ * @param {Object} rateLimitConfig - 限流配置
47
+ * @param {number|string} rateLimitConfig.windowMs - 时间窗口
48
+ * @param {number} rateLimitConfig.max - 最大请求次数
49
+ * @param {Array<string>} [rateLimitConfig.ignorePaths] - 忽略的路径数组
50
+ * @returns {Function} Express 中间件函数
51
+ * @description
52
+ * 基于客户端 IP 实现滑动窗口限流算法
53
+ * 使用 Cookie 存储限流状态,避免内存泄漏
54
+ * @example
55
+ * const rateLimiter = createRateLimitMiddleware({
56
+ * windowMs: '1m',
57
+ * max: 60,
58
+ * ignorePaths: ['/health']
59
+ * });
60
+ */
61
+ export function createRateLimitMiddleware(rateLimitConfig) {
62
+ const config = {
63
+ ...rateLimitConfig,
64
+ windowMs: parseWindowMs(rateLimitConfig?.windowMs),
65
+ };
66
+
67
+ return (req, res, next) => {
68
+ try {
69
+ if (isIgnored(req.path, config.ignorePaths)) {
70
+ return next();
71
+ }
72
+
73
+ const now = Date.now();
74
+ const ip = getIp(req);
75
+ const cookieValue = req.cookies && req.cookies[COOKIE_NAME];
76
+ let currentData = null;
77
+
78
+ if (cookieValue) {
79
+ try {
80
+ currentData = JSON.parse(cookieValue);
81
+ if (currentData && currentData.ip !== ip) {
82
+ currentData = null;
83
+ }
84
+ } catch (e) {
85
+ currentData = null;
86
+ }
87
+ }
88
+
89
+ let newData;
90
+ if (!currentData || now > currentData.resetTime) {
91
+ newData = { count: 1, resetTime: now + config.windowMs, ip };
92
+ } else if (currentData.count >= config.max) {
93
+ console.error(`[WAF 限流拦截] 路径:${req.path} 计数:${currentData.count}/${config.max} IP:${ip}`);
94
+ return res.status(429).json({
95
+ code: 429,
96
+ success: false,
97
+ msg: '请求过于频繁,请稍后重试',
98
+ retryAfter: Math.ceil((currentData.resetTime - now) / 1000),
99
+ });
100
+ } else {
101
+ newData = { count: currentData.count + 1, resetTime: currentData.resetTime, ip };
102
+ }
103
+
104
+ res.cookie(COOKIE_NAME, JSON.stringify(newData), {
105
+ httpOnly: true,
106
+ maxAge: config.windowMs,
107
+ sameSite: 'strict',
108
+ });
109
+
110
+ next();
111
+ } catch (error) {
112
+ console.error(`[WAF 限流异常] 路径:${req.path} 错误:${error.message}`);
113
+ next();
114
+ }
115
+ };
116
+ }
package/utils/response.js CHANGED
@@ -1,64 +1,103 @@
1
- import { CODE, DB_ERROR } from "../config/code.js";
2
-
3
- /**
4
- * @description 获取数据库错误码
5
- * @param {*} error
6
- * @returns {Number} 默认错误码
7
- */
8
- const getDefaultErrorCode = (error) => {
9
- if (error.message.includes("syntax") || error.message.includes("SQL")) {
10
- return 6008;
11
- } else if (error.message.includes("Connection closed")) {
12
- return 6009;
13
- } else if (error.message.includes("permission")) {
14
- return 3003;
15
- }
16
- return 5001;
17
- };
18
-
19
- /**
20
- * @description 数据库错误响应处理函数
21
- * @param {*} err
22
- * @returns {Object} 错误响应对象
23
- */
24
- export const error = (err) => {
25
- console.error("DB Error:", err);
26
- const errorCode = DB_ERROR[err.code] || getDefaultErrorCode(err);
27
- return {
28
- success: false,
29
- msg: CODE[errorCode], // 从CODE对象获取错误消息
30
- code: errorCode,
31
- data: {
32
- sql: err.sql,
33
- sqlMessage: err.sqlMessage,
34
- },
35
- };
36
- };
37
-
38
- /**
39
- * @description 错误响应处理函数
40
- * @param {*} msg
41
- * @param {*} data
42
- * @returns {Object} 失败响应对象
43
- */
44
- export const fail = (msg = CODE[201], data = {}) => {
45
- return {
46
- success: false,
47
- msg,
48
- code: 201, // 使用通用失败码
49
- data,
50
- };
51
- };
52
-
53
- /**
54
- * @description 成功响应处理函数
55
- * @param {*} data
56
- * @param {*} msg
57
- * @returns {Object} 成功响应对象
58
- */
59
- export const success = (data = {}, msg = CODE[200]) => ({
60
- success: true,
61
- msg,
62
- code: 200, // 使用标准成功码
63
- data,
64
- });
1
+ import { CODE, DB_ERROR } from "../config/code.js";
2
+
3
+ /**
4
+ * 响应工具函数
5
+ * 提供统一的响应格式和错误处理
6
+ */
7
+
8
+ /**
9
+ * 获取默认错误代码
10
+ * @private
11
+ * @param {Error} error - 错误对象
12
+ * @returns {number} 错误代码
13
+ */
14
+ const getDefaultErrorCode = (error) => {
15
+ if (!error?.message) return 5001;
16
+ if (error.message.includes("syntax") || error.message.includes("SQL")) {
17
+ return 6008;
18
+ } else if (error.message.includes("Connection closed")) {
19
+ return 6009;
20
+ } else if (error.message.includes("permission")) {
21
+ return 3003;
22
+ }
23
+ return 5001;
24
+ };
25
+
26
+ /**
27
+ * 生成错误响应
28
+ * @param {Object} options - 响应选项
29
+ * @param {Error} options.err - 错误对象
30
+ * @param {Object} [options.data={}] - 响应数据
31
+ * @param {number} [options.code=500] - 错误代码
32
+ * @returns {Object} 错误响应对象
33
+ * @description
34
+ * 根据错误类型生成标准错误响应
35
+ * 开发环境下包含数据库错误详情
36
+ * @example
37
+ * const response = error({ err: databaseError });
38
+ */
39
+ export const error = ({ err, data = {}, code = 500 } = {}) => {
40
+ if (err) {
41
+ console.error("[DB Error]", err?.message || err);
42
+ const errorCode = err?.code && DB_ERROR[err.code] ? DB_ERROR[err.code] : getDefaultErrorCode(err);
43
+ const msg = CODE[errorCode] || "操作失败";
44
+
45
+ return {
46
+ success: false,
47
+ msg,
48
+ code: errorCode,
49
+ data: process.env.NODE_ENV === 'development' ? {
50
+ sql: err?.sql,
51
+ sqlMessage: err?.sqlMessage,
52
+ message: err?.message,
53
+ } : {},
54
+ };
55
+ }
56
+
57
+ const msg = CODE[code] || "操作失败";
58
+ return {
59
+ success: false,
60
+ msg,
61
+ code,
62
+ data,
63
+ };
64
+ };
65
+
66
+ /**
67
+ * 生成失败响应
68
+ * @param {Object} options - 响应选项
69
+ * @param {string} [options.msg="操作失败"] - 错误消息
70
+ * @param {Object} [options.data={}] - 响应数据
71
+ * @param {number} [options.code=201] - 错误代码
72
+ * @returns {Object} 失败响应对象
73
+ * @description
74
+ * 生成标准失败响应
75
+ * @example
76
+ * const response = fail({ msg: '用户不存在', code: 404 });
77
+ */
78
+ export const fail = ({ msg = "操作失败", data = {}, code = 201 } = {}) => {
79
+ return {
80
+ success: false,
81
+ msg,
82
+ code,
83
+ data,
84
+ };
85
+ };
86
+
87
+ /**
88
+ * 生成成功响应
89
+ * @param {Object} options - 响应选项
90
+ * @param {Object} [options.data={}] - 响应数据
91
+ * @param {string} [options.msg="操作成功"] - 成功消息
92
+ * @returns {Object} 成功响应对象
93
+ * @description
94
+ * 生成标准成功响应
95
+ * @example
96
+ * const response = success({ data: { id: 1, name: '张三' } });
97
+ */
98
+ export const success = ({ data = {}, msg = "操作成功" } = {}) => ({
99
+ success: true,
100
+ msg,
101
+ code: 200,
102
+ data,
103
+ });
@@ -0,0 +1,42 @@
1
+ import xss from 'xss';
2
+
3
+ /**
4
+ * XSS 过滤工具
5
+ * 提供跨站脚本攻击过滤功能
6
+ */
7
+
8
+ /**
9
+ * 过滤 XSS 攻击代码
10
+ * @param {*} data - 要过滤的数据,可以是字符串、数组或对象
11
+ * @returns {*} 过滤后的数据
12
+ * @description
13
+ * 递归过滤数据中的所有字符串值
14
+ * 使用 xss 库清除危险的 HTML 和 JavaScript 代码
15
+ * 支持字符串、数组和对象的递归处理
16
+ * @example
17
+ * const clean = filterXSS({
18
+ * name: '<script>alert(1)</script>',
19
+ * items: ['<img src=x onerror=alert(1)>']
20
+ * });
21
+ */
22
+ export function filterXSS(data) {
23
+ if (typeof data === 'string') {
24
+ return xss(data);
25
+ }
26
+
27
+ if (Array.isArray(data)) {
28
+ return data.map(item => filterXSS(item));
29
+ }
30
+
31
+ if (data && typeof data === 'object') {
32
+ const result = {};
33
+ for (const key in data) {
34
+ if (Object.prototype.hasOwnProperty.call(data, key)) {
35
+ result[key] = filterXSS(data[key]);
36
+ }
37
+ }
38
+ return result;
39
+ }
40
+
41
+ return data;
42
+ }
@@ -1,33 +0,0 @@
1
-
2
- import {formatTime} from "../helper/time.js";
3
-
4
- export default class Controller {
5
- constructor() {}
6
-
7
- success(data){
8
- return {
9
- success: true,
10
- msg: "操作成功",
11
- code: 200,
12
- data,
13
- };
14
- }
15
-
16
- fail(data, code = 201) {
17
- return {
18
- success: false,
19
- msg: "操作失败",
20
- code,
21
- data,
22
- };
23
- }
24
-
25
- err(data = {}, code = 500) {
26
- return {
27
- success: false,
28
- msg: "系统异常",
29
- code,
30
- data,
31
- };
32
- }
33
- }
package/core/index.js DELETED
@@ -1,3 +0,0 @@
1
- import Controller from "./controller.js";
2
- import Service from "./service.js";
3
- export {Controller, Service};