mm_os 3.2.8 → 3.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 (38) hide show
  1. package/README.md +47 -1
  2. package/core/base/mqtt/index.js +344 -157
  3. package/core/base/web/index.js +98 -11
  4. package/core/com/middleware/com.js +152 -152
  5. package/core/com/socket/config.tpl.json +2 -2
  6. package/core/com/socket/drive.js +2 -2
  7. package/core/com/socket/index.js +1 -1
  8. package/core/com/sql/drive.js +7 -7
  9. package/index.js +41 -37
  10. package/middleware/performance/index.js +150 -142
  11. package/middleware/security_audit/index.js +549 -0
  12. package/middleware/security_audit/middleware.json +48 -0
  13. package/middleware/security_headers/index.js +487 -0
  14. package/middleware/security_headers/middleware.json +45 -0
  15. package/middleware/waf/index.js +277 -6
  16. package/middleware/waf/middleware.json +2 -1
  17. package/middleware/waf_ddos/index.js +520 -0
  18. package/middleware/waf_ddos/middleware.json +38 -0
  19. package/middleware/waf_ip/index.js +231 -20
  20. package/middleware/waf_ip/middleware.json +43 -4
  21. package/middleware/waf_xss/index.js +269 -0
  22. package/middleware/waf_xss/middleware.json +18 -0
  23. package/middleware/web_before/middleware.json +1 -1
  24. package/middleware/web_socket/middleware.json +2 -2
  25. package/package.json +18 -7
  26. package/middleware/cors/index.js +0 -103
  27. package/middleware/cors/middleware.json +0 -9
  28. package/middleware/log/index.js +0 -32
  29. package/middleware/log/middleware.json +0 -9
  30. package/middleware/rate_limit/index.js +0 -112
  31. package/middleware/rate_limit/middleware.json +0 -10
  32. package/nodemon.json +0 -31
  33. package/package.txt +0 -1
  34. package/rps.bat +0 -3
  35. package/test.js +0 -5
  36. package/tps.bat +0 -3
  37. package/update.bat +0 -1
  38. package//347/263/273/347/273/237/346/236/266/346/236/204/350/257/204/344/274/260/344/270/216/344/274/230/345/214/226/345/273/272/350/256/256.md +0 -599
@@ -49,12 +49,36 @@ WEB.prototype.init = function(config) {
49
49
  if (config) {
50
50
  this.config = Object.assign(this.config, config);
51
51
  }
52
- this.server = new Koa();
52
+ // 确保Koa实例正确创建
53
+ try {
54
+ this.server = new Koa();
55
+ if (!this.server) {
56
+ throw new Error('无法创建Koa服务器实例');
57
+ }
58
+ console.log('[WEB] 成功创建Koa服务器实例');
59
+ } catch (error) {
60
+ console.error('[WEB] 创建Koa实例失败:', error);
61
+ // 即使创建失败也初始化一个空对象防止后续空引用错误
62
+ this.server = {};
63
+ }
53
64
 
54
65
  // 添加统一错误处理中间件(确保是第一个被注册的中间件)
55
66
  this.server.use(async (ctx, next) => {
56
67
  try {
68
+ console.log(`[WEB] 接收到请求: ${ctx.method} ${ctx.path}`);
69
+ console.log(`[WEB] 请求头:`, ctx.headers);
70
+
71
+ // 在请求开始时记录时间
72
+ const startTime = Date.now();
73
+
74
+ // 执行后续中间件
57
75
  await next();
76
+
77
+ // 计算响应时间
78
+ const responseTime = Date.now() - startTime;
79
+ console.log(`[WEB] 响应: ${ctx.status} ${responseTime}ms ${ctx.path}`);
80
+ console.log(`[WEB] 响应头:`, ctx.response.headers);
81
+
58
82
  // 处理404错误
59
83
  if (ctx.status === 404 && !ctx.body) {
60
84
  ctx.status = 404;
@@ -90,7 +114,19 @@ WEB.prototype.init = function(config) {
90
114
  * @param {Function} 函数
91
115
  */
92
116
  WEB.prototype.use = function(func) {
93
- this.server.use(func);
117
+ console.log(`[WEB] 注册中间件: ${func.name || '匿名函数'}`);
118
+ // 确保server实例和use方法存在
119
+ if (!this.server) {
120
+ console.error('[WEB] 服务器实例未初始化,尝试重新初始化');
121
+ this.server = new Koa();
122
+ }
123
+ if (typeof this.server.use === 'function') {
124
+ this.server.use(func);
125
+ console.log('[WEB] 中间件注册成功');
126
+ } else {
127
+ console.error('[WEB] 服务器实例缺少use方法');
128
+ }
129
+ return this; // 支持链式调用
94
130
  };
95
131
 
96
132
  /**
@@ -104,6 +140,13 @@ WEB.prototype.main = function(state) {
104
140
  host = '127.0.0.1'
105
141
  }
106
142
 
143
+ // 确保server实例初始化
144
+ if (!this.server) {
145
+ console.error('[WEB] 服务器实例未初始化,尝试重新初始化');
146
+ this.server = new Koa();
147
+ this.init();
148
+ }
149
+
107
150
  // 启动HTTP服务器
108
151
  const httpServer = this.server.listen(cg.port, cg.host, () => {
109
152
  console.info(`HTTP访问 http://${host}:${cg.port}`);
@@ -127,12 +170,45 @@ WEB.prototype.main = function(state) {
127
170
  * @param {String} state 状态
128
171
  */
129
172
  WEB.prototype.before = async function(state) {
173
+ // 确保server实例初始化
174
+ if (!this.server) {
175
+ console.error('[WEB] 服务器实例未初始化,尝试重新初始化');
176
+ this.server = new Koa();
177
+ }
178
+
130
179
  var list = this.list;
131
- for (var i = 0; i < list.length; i++) {
132
- var o = list[i];
133
- o.func = require(o.func_file);
134
- if (o.func) {
135
- o.func(this.server, this.config);
180
+ console.log(`[WEB] 准备加载中间件,共有 ${list ? list.length : 0} 个中间件`);
181
+ if (list && list.length > 0) {
182
+ // 按优先级顺序应用中间件
183
+ for (var i = 0; i < list.length; i++) {
184
+ var o = list[i];
185
+ console.log(`[WEB] 尝试加载中间件: ${o.name}`);
186
+ try {
187
+ o.func = require(o.func_file);
188
+ if (o.func) {
189
+ // 检查中间件函数的参数个数,支持不同的调用方式
190
+ if (o.func.length === 1) {
191
+ // 仅接收server参数的中间件
192
+ console.log(`[WEB] 应用中间件 ${o.name} (单参数模式)`);
193
+ o.func(this.server);
194
+ } else {
195
+ // 接收server和config参数的中间件
196
+ console.log(`[WEB] 应用中间件 ${o.name} (双参数模式)`);
197
+ o.func(this.server, this.config);
198
+ }
199
+ // 记录中间件加载日志
200
+ if ($.log && $.log.info) {
201
+ $.log.info(`中间件已加载: ${o.name} (优先级: ${o.sort || 5})`);
202
+ }
203
+ }
204
+ } catch (error) {
205
+ // 记录中间件加载错误
206
+ if ($.log && $.log.error) {
207
+ $.log.error(`中间件加载失败: ${o.name}`, error);
208
+ } else {
209
+ console.error(`中间件加载失败: ${o.name}`, error);
210
+ }
211
+ }
136
212
  }
137
213
  }
138
214
  };
@@ -141,16 +217,27 @@ WEB.prototype.before = async function(state) {
141
217
  * 运行主程序后
142
218
  * @param {String} state 状态
143
219
  */
144
- WEB.prototype.after = async function(state) {};
220
+ WEB.prototype.after = async function(state) {
221
+ // 可以在这里添加启动后的清理工作
222
+ };
145
223
 
146
224
  /**
147
225
  * 运行
148
226
  * @param {String} state 状态
149
227
  */
150
228
  WEB.prototype.run = async function(state = 'start') {
151
- await this.before(state);
152
- await this.main(state);
153
- await this.after(state);
229
+ try {
230
+ await this.before(state);
231
+ this.main(state);
232
+ await this.after(state);
233
+ } catch (error) {
234
+ // 记录运行错误
235
+ if ($.log && $.log.error) {
236
+ $.log.error('Web服务器运行错误:', error);
237
+ } else {
238
+ console.error('Web服务器运行错误:', error);
239
+ }
240
+ }
154
241
  };
155
242
 
156
243
  module.exports = WEB;
@@ -1,153 +1,153 @@
1
- class Middleware {
2
- /**
3
- * 构造函数
4
- * @param {Object} config 配置参数
5
- */
6
- constructor(config) {
7
- // 中间件列表
8
- this.list = [];
9
-
10
- this.config = {
11
- path: "./middleware".fullname($.runPath),
12
- file: "middleware.json",
13
- mode: "web"
14
- };
15
- this.init(config);
16
- }
17
- }
18
-
19
- Middleware.prototype.init = function(config) {
20
- if (config) {
21
- Object.assign(this.config, config);
22
- }
23
- }
24
-
25
- /**
26
- * 新建脚本
27
- * @param {String} 文件
28
- */
29
- Middleware.prototype.new_script = function(file) {
30
- var fl = __dirname + "/script.js";
31
- if (fl.hasFile()) {
32
- var text = fl.loadText();
33
- if (text) {
34
- var l = $.slash;
35
- if (file.indexOf('middleware' + l) !== -1) {
36
- var name = file.between('middleware' + l, l);
37
- text = text.replaceAll("{0}", name);
38
- }
39
- file.saveText(text);
40
- }
41
- }
42
- };
43
-
44
- /**
45
- * 新建配置
46
- * @param {String} 文件
47
- */
48
- Middleware.prototype.new_config = function(file) {
49
- var fl = __dirname + "/config.tpl.json";
50
- if (fl.hasFile()) {
51
- var text = fl.loadText();
52
- if (text) {
53
- var l = $.slash;
54
- if (file.indexOf('middleware' + l) !== -1) {
55
- var name = file.between('middleware' + l, l);
56
- text = text.replaceAll("{0}", name);
57
- }
58
- file.saveText(text);
59
- }
60
- }
61
- };
62
-
63
- /**
64
- * 加载配置
65
- * @param {String} file 配置文件路径
66
- */
67
- Middleware.prototype.load_item = function(file) {
68
- var config = file.loadJson();
69
- if (config) {
70
- var cg = this.list.getObj({
71
- name: config.name
72
- });
73
- if (cg) {
74
- $.push(cg, config, true);
75
- } else {
76
- cg = {
77
- func_file: file.replace(this.config.file, 'index.js')
78
- }
79
- $.push(cg, config, true);
80
- this.list.push(cg);
81
- }
82
- } else {
83
- this.new_config(file);
84
- }
85
- var script_file = file.replace('middleware.json', 'index.js');
86
- if (!script_file.hasFile()) {
87
- this.new_script(script_file);
88
- }
89
- };
90
-
91
- /**
92
- * 遍历加载配置
93
- * @param {Object} path
94
- */
95
- Middleware.prototype.update_config_all = function(path, accurate) {
96
- if (path.hasDir()) {
97
- var dirs = $.dir.getAll(path);
98
- // 遍历目录路径
99
- var file = this.config.file;
100
- for (var i = 0; i < dirs.length; i++) {
101
- var d = dirs[i];
102
- this.load_item(d + file);
103
- }
104
- }
105
- };
106
-
107
- /**
108
- * 排序
109
- */
110
- Middleware.prototype.sort = function() {
111
- return this.list.sortBy('asc', 'sort');
112
- };
113
-
114
- /**
115
- * 清除接口缓存
116
- */
117
- Middleware.prototype.clear = function() {
118
- this.list = [];
119
- };
120
-
121
- /**
122
- * 遍历加载配置
123
- */
124
- Middleware.prototype.update_config = function(path, accurate = true, clear = true) {
125
- if (clear) {
126
- this.clear();
127
- }
128
- this.update_config_all("../../../middleware/".fullname(__dirname));
129
- if (path) {
130
- this.update_config_all(path);
131
- }
132
- this.update_config_all(this.config.path);
133
- var p = "./middleware".fullname($.runPath);
134
- if (this.config.path !== p) {
135
- this.update_config_all(p);
136
- }
137
- this.sort();
138
- };
139
-
140
- /**
141
- * 更新
142
- * @param {String} dir 检索的路径
143
- * @param {Boolean} loadJS 是否加载JS
144
- */
145
- Middleware.prototype.update = function(dir, accurate = true, loadJS = true, clear = true) {
146
- this.update_config(dir, accurate, clear);
147
- }
148
-
149
- if (!$.middleware) {
150
- $.middleware = new Middleware();
151
- }
152
-
1
+ class Middleware {
2
+ /**
3
+ * 构造函数
4
+ * @param {Object} config 配置参数
5
+ */
6
+ constructor(config) {
7
+ // 中间件列表
8
+ this.list = [];
9
+
10
+ this.config = {
11
+ path: "./middleware".fullname($.runPath),
12
+ file: "middleware.json",
13
+ mode: "web"
14
+ };
15
+ this.init(config);
16
+ }
17
+ }
18
+
19
+ Middleware.prototype.init = function(config) {
20
+ if (config) {
21
+ Object.assign(this.config, config);
22
+ }
23
+ }
24
+
25
+ /**
26
+ * 新建脚本
27
+ * @param {String} 文件
28
+ */
29
+ Middleware.prototype.new_script = function(file) {
30
+ var fl = __dirname + "/script.js";
31
+ if (fl.hasFile()) {
32
+ var text = fl.loadText();
33
+ if (text) {
34
+ var l = $.slash;
35
+ if (file.indexOf('middleware' + l) !== -1) {
36
+ var name = file.between('middleware' + l, l);
37
+ text = text.replaceAll("{0}", name);
38
+ }
39
+ file.saveText(text);
40
+ }
41
+ }
42
+ };
43
+
44
+ /**
45
+ * 新建配置
46
+ * @param {String} 文件
47
+ */
48
+ Middleware.prototype.new_config = function(file) {
49
+ var fl = __dirname + "/config.tpl.json";
50
+ if (fl.hasFile()) {
51
+ var text = fl.loadText();
52
+ if (text) {
53
+ var l = $.slash;
54
+ if (file.indexOf('middleware' + l) !== -1) {
55
+ var name = file.between('middleware' + l, l);
56
+ text = text.replaceAll("{0}", name);
57
+ }
58
+ file.saveText(text);
59
+ }
60
+ }
61
+ };
62
+
63
+ /**
64
+ * 加载配置
65
+ * @param {String} file 配置文件路径
66
+ */
67
+ Middleware.prototype.load_item = function(file) {
68
+ var config = file.loadJson();
69
+ if (config) {
70
+ var cg = this.list.getObj({
71
+ name: config.name
72
+ });
73
+ if (cg) {
74
+ $.push(cg, config, true);
75
+ } else {
76
+ cg = {
77
+ func_file: file.replace(this.config.file, 'index.js')
78
+ }
79
+ $.push(cg, config, true);
80
+ this.list.push(cg);
81
+ }
82
+ } else {
83
+ this.new_config(file);
84
+ }
85
+ var script_file = file.replace('middleware.json', 'index.js');
86
+ if (!script_file.hasFile()) {
87
+ this.new_script(script_file);
88
+ }
89
+ };
90
+
91
+ /**
92
+ * 遍历加载配置
93
+ * @param {Object} path
94
+ */
95
+ Middleware.prototype.update_config_all = function(path, accurate) {
96
+ if (path.hasDir()) {
97
+ var dirs = $.dir.getAll(path);
98
+ // 遍历目录路径
99
+ var file = this.config.file;
100
+ for (var i = 0; i < dirs.length; i++) {
101
+ var d = dirs[i];
102
+ this.load_item(d + file);
103
+ }
104
+ }
105
+ };
106
+
107
+ /**
108
+ * 排序
109
+ */
110
+ Middleware.prototype.sort = function() {
111
+ return this.list.sortBy('asc', 'sort');
112
+ };
113
+
114
+ /**
115
+ * 清除接口缓存
116
+ */
117
+ Middleware.prototype.clear = function() {
118
+ this.list = [];
119
+ };
120
+
121
+ /**
122
+ * 遍历加载配置
123
+ */
124
+ Middleware.prototype.update_config = function(path, accurate = true, clear = true) {
125
+ if (clear) {
126
+ this.clear();
127
+ }
128
+ this.update_config_all("../../../middleware/".fullname(__dirname));
129
+ if (path) {
130
+ this.update_config_all(path);
131
+ }
132
+ this.update_config_all(this.config.path);
133
+ var p = "./middleware".fullname($.runPath);
134
+ if (this.config.path !== p) {
135
+ this.update_config_all(p);
136
+ }
137
+ this.sort();
138
+ };
139
+
140
+ /**
141
+ * 更新
142
+ * @param {String} dir 检索的路径
143
+ * @param {Boolean} loadJS 是否加载JS
144
+ */
145
+ Middleware.prototype.update = function(dir, accurate = true, loadJS = true, clear = true) {
146
+ this.update_config(dir, accurate, clear);
147
+ }
148
+
149
+ if (!$.middleware) {
150
+ $.middleware = new Middleware();
151
+ }
152
+
153
153
  module.exports = Middleware;
@@ -1,5 +1,5 @@
1
1
  {
2
- // webscoket请求路由地址
2
+ // websocket请求路由地址
3
3
  "path": "/ws/{0}",
4
4
  // 名称
5
5
  "name": "{0}",
@@ -7,7 +7,7 @@
7
7
  "title": "示例websocket",
8
8
  // 描述,用来介绍该websocket程序是做什么用的
9
9
  "description": "用来测试",
10
- // webscoket调用的脚本文件
10
+ // websocket调用的脚本文件
11
11
  "func_file": "./index.js",
12
12
  // 同步消息循环发送的时间间隔
13
13
  "interval": 1000
@@ -336,7 +336,7 @@ Drive.prototype.run = async function(bodyStr, ctx, token) {
336
336
  }
337
337
  return await this.main(bodyStr, ws, request);
338
338
  } catch (err) {
339
- $.log.error("webscoket 错误", err);
339
+ $.log.error("websocket 错误", err);
340
340
  return $.log.error(10000, "代码错误!原因:" + err.toString());
341
341
  }
342
342
  };
@@ -400,4 +400,4 @@ Drive.prototype.plugin = function(app, name) {
400
400
  return plus
401
401
  }
402
402
 
403
- module.exports = Drive;
403
+ module.exports = Drive;
@@ -32,7 +32,7 @@ Socket.prototype.run = async function(ctx, next) {
32
32
  var list = this.list;
33
33
  const path = ctx.path.toLocaleLowerCase();
34
34
  for (var i = 0, o; o = list[i++];) {
35
- // console.log("监听webscoket路径是否正确", path === o.config.path);
35
+ // console.log("监听websocket路径是否正确", path === o.config.path);
36
36
  if (path === o.config.path) {
37
37
  o.add(ctx);
38
38
  break;
@@ -592,10 +592,10 @@ Drive.prototype.get_params = async function(db, fields) {
592
592
  var list = dt.config.fields;
593
593
  for (var i = 0; i < list.length; i++) {
594
594
  var o = list[i];
595
- var name = o.replace(/`/g, '');
595
+ var name = o.name.replace(/`/g, '');
596
596
  lt.push({
597
597
  name,
598
- title: name
598
+ title: title: o.title
599
599
  });
600
600
  }
601
601
  }
@@ -790,7 +790,7 @@ Drive.prototype.export_main = async function(db, query, body) {
790
790
  var {
791
791
  path,
792
792
  file,
793
- fields
793
+ field
794
794
  } = body;
795
795
  var table = db.table || this.config.table;
796
796
  var date = new Date();
@@ -806,17 +806,17 @@ Drive.prototype.export_main = async function(db, query, body) {
806
806
  if (!file) {
807
807
  file = this.save_dir + name;
808
808
  }
809
- if (!fields) {
809
+ if (!field) {
810
810
  if (query.field) {
811
- fields = query.field;
811
+ field = query.field;
812
812
  } else {
813
813
  var f = this.config.field_default;
814
814
  if (f.length !== "*") {
815
- fields = f;
815
+ field = f;
816
816
  }
817
817
  }
818
818
  }
819
- var params = await this.get_params(db, fields);
819
+ var params = await this.get_params(db, field);
820
820
  var format = await this.get_format(db);
821
821
  file = file.fullname(path);
822
822
  file.addDir();
package/index.js CHANGED
@@ -1,3 +1,10 @@
1
+ // 增强版补丁:彻底解决util._extend API弃用警告
2
+ const util = require('util');
3
+ // 完全替换util._extend为Object.assign的包装函数,确保行为一致
4
+ util._extend = function(target, source) {
5
+ return Object.assign({}, target, source);
6
+ };
7
+
1
8
  require('mm_logs');
2
9
  require('mm_ret');
3
10
  $.Tpl = require('mm_tpl');
@@ -41,13 +48,7 @@ class OS {
41
48
  "static": true,
42
49
  "maxAge": 7200,
43
50
  "static_path": "./static",
44
- "proxy": {},
45
- "rateLimit": {
46
- "windowMs": 60 * 1000, // 时间窗口,默认15分钟
47
- "maxRequests": 5000, // 每个时间窗口内的最大请求数
48
- "message": "请求过于频繁,请稍后再试", // 超过限制时的提示信息
49
- "statusCode": 429 // 超过限制时的HTTP状态码
50
- }
51
+ "proxy": {}
51
52
  },
52
53
  "mqtt": {
53
54
  "state": true,
@@ -79,6 +80,11 @@ class OS {
79
80
  "database": "mm",
80
81
  "user": "admin",
81
82
  "password": "asd123"
83
+ },
84
+ "modules": {
85
+ "hotReload": true,
86
+ "watchInterval": 5000,
87
+ "autoLoad": true
82
88
  }
83
89
  };
84
90
  this.init(config);
@@ -210,34 +216,34 @@ OS.prototype.init = function(config) {
210
216
  this.initErrorHandler();
211
217
  }
212
218
 
213
- /**
214
- * 运行基础数据
215
- * @param {Object} cg - 配置对象
216
- */
217
- OS.prototype.initBase = function(cg) {
218
- var middleware = $.middleware;
219
- middleware.update();
220
- var mqtt, web;
221
- if (cg.web && cg.web.state) {
222
- web = new WEB(cg.web);
223
- web.list = middleware.list.filter((o) => {
224
- return !o.mode || o.mode == "web"
225
- });
226
- web.init();
227
- this.web = web;
228
- }
229
-
230
- if (cg.mqtt && cg.mqtt.state) {
231
- mqtt = new MQTT(Object.assign(cg.mqtt, {
232
- redis: cg.redis,
233
- mongodb: cg.mongodb
234
- }));
235
- mqtt.list = middleware.list.filter((o) => {
236
- return o.mode == "mqtt"
237
- });
238
- mqtt.init();
239
- this.mqtt = mqtt;
240
- }
219
+ /**
220
+ * 运行基础数据
221
+ * @param {Object} cg - 配置对象
222
+ */
223
+ OS.prototype.initBase = function(cg) {
224
+ var middleware = $.middleware;
225
+ middleware.update();
226
+ var mqtt, web;
227
+ if (cg.web && cg.web.state) {
228
+ web = new WEB(cg.web);
229
+ web.list = middleware.list.filter((o) => {
230
+ return !o.mode || o.mode == "web"
231
+ });
232
+ web.init();
233
+ this.web = web;
234
+ }
235
+
236
+ if (cg.mqtt && cg.mqtt.state) {
237
+ mqtt = new MQTT(Object.assign(cg.mqtt, {
238
+ redis: cg.redis,
239
+ mongodb: cg.mongodb
240
+ }));
241
+ mqtt.list = middleware.list.filter((o) => {
242
+ return o.mode == "mqtt"
243
+ });
244
+ mqtt.init();
245
+ this.mqtt = mqtt;
246
+ }
241
247
  }
242
248
 
243
249
  /**
@@ -249,8 +255,6 @@ OS.prototype.main = async function(state) {
249
255
  $.timer.run();
250
256
 
251
257
  var cg = this.config;
252
- var web_server = this.web_server;
253
- var mqtt_server = this.mqtt_server;
254
258
  var tip = "启动";
255
259
  if (cg.web && cg.web.state) {
256
260
  tip += " web";