mm_os 3.3.0 → 3.3.1

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 (42) hide show
  1. package/core/base/mqtt/index.js +1109 -1106
  2. package/core/base/web/index.js +245 -243
  3. package/core/com/event/README.md +4 -4
  4. package/core/com/event/com.json +3 -3
  5. package/core/com/event/config.tpl.json +18 -18
  6. package/core/com/event/drive.js +132 -132
  7. package/core/com/event/index.js +344 -344
  8. package/core/com/event/script.js +25 -25
  9. package/core/com/middleware/com.js +1 -0
  10. package/core/com/sql/drive.js +1 -1
  11. package/core/com/static/index.js +1 -1
  12. package/index.js +50 -31
  13. package/middleware/cors/index.js +119 -0
  14. package/middleware/cors/middleware.json +20 -0
  15. package/middleware/csrf/index.js +202 -0
  16. package/middleware/csrf/middleware.json +24 -0
  17. package/middleware/ip_firewall/index.js +476 -0
  18. package/middleware/ip_firewall/middleware.json +109 -0
  19. package/middleware/mqtt_base/middleware.json +2 -1
  20. package/middleware/security_audit/index.js +13 -19
  21. package/middleware/security_audit/middleware.json +3 -3
  22. package/middleware/waf/index.js +27 -32
  23. package/middleware/waf_ddos/index.js +2 -2
  24. package/middleware/waf_ddos/middleware.json +3 -3
  25. package/middleware/waf_xss/index.js +1 -1
  26. package/middleware/waf_xss/middleware.json +1 -1
  27. package/middleware/web_after/middleware.json +2 -1
  28. package/middleware/web_base/middleware.json +2 -1
  29. package/middleware/web_before/middleware.json +2 -1
  30. package/middleware/web_check/middleware.json +2 -1
  31. package/middleware/web_main/middleware.json +2 -1
  32. package/middleware/web_proxy/middleware.json +2 -1
  33. package/middleware/web_render/middleware.json +2 -1
  34. package/middleware/web_socket/middleware.json +2 -1
  35. package/middleware/web_static/middleware.json +2 -1
  36. package/package.json +13 -11
  37. package/middleware/performance/index.js +0 -151
  38. package/middleware/performance/middleware.json +0 -16
  39. package/middleware/security_headers/index.js +0 -487
  40. package/middleware/security_headers/middleware.json +0 -45
  41. package/middleware/waf_ip/index.js +0 -379
  42. package/middleware/waf_ip/middleware.json +0 -49
@@ -1,26 +1,26 @@
1
- // 使用api管理器
2
- var api = $.api_admin('{0}', '{0}');
3
- // 首次启动更新api接口;
4
- api.update();
5
-
6
- // 使用mysql数据库管理器
7
- var sql = $.mysql_admin('sys', __dirname);
8
- // sql.setConfig($.config.mysql);
9
- // sql.open();
10
-
11
- /**
12
- * @description 接口主函数
13
- * @param {Object} ctx HTTP上下文
14
- * @param {Object} db 数据管理器,如: { next: async function{}, ret: {} }
15
- * @return {Object} 执行结果
16
- */
17
- async function main(ctx, db) {
18
- // 使用模板引擎
19
- db.tpl = new $.Tpl();
20
-
21
- // 在这定义要访问的数据库 (分布式开发时设置不同的数据库名)
22
- $.push(db, sql.db(), true);
23
- return api.run(ctx, db);
24
- };
25
-
1
+ // 使用api管理器
2
+ var api = $.api_admin('{0}', '{0}');
3
+ // 首次启动更新api接口;
4
+ api.update();
5
+
6
+ // 使用mysql数据库管理器
7
+ var sql = $.mysql_admin('sys', __dirname);
8
+ // sql.setConfig($.config.mysql);
9
+ // sql.open();
10
+
11
+ /**
12
+ * @description 接口主函数
13
+ * @param {Object} ctx HTTP上下文
14
+ * @param {Object} db 数据管理器,如: { next: async function{}, ret: {} }
15
+ * @return {Object} 执行结果
16
+ */
17
+ async function main(ctx, db) {
18
+ // 使用模板引擎
19
+ db.tpl = new $.Tpl();
20
+
21
+ // 在这定义要访问的数据库 (分布式开发时设置不同的数据库名)
22
+ $.push(db, sql.db(), true);
23
+ return api.run(ctx, db);
24
+ };
25
+
26
26
  exports.main = main;
@@ -15,6 +15,7 @@ class Middleware {
15
15
  this.init(config);
16
16
  }
17
17
  }
18
+
18
19
 
19
20
  Middleware.prototype.init = function(config) {
20
21
  if (config) {
@@ -595,7 +595,7 @@ Drive.prototype.get_params = async function(db, fields) {
595
595
  var name = o.name.replace(/`/g, '');
596
596
  lt.push({
597
597
  name,
598
- title: title: o.title
598
+ title: o.title
599
599
  });
600
600
  }
601
601
  }
@@ -117,7 +117,7 @@ Static.prototype.getObj = async function(dir) {
117
117
  */
118
118
  Static.prototype.update_config_all = async function(path) {
119
119
  if (!path) {
120
- path = $.runPath + 'app' + $.slash;
120
+ path = './app'.fullname();
121
121
  }
122
122
  // 获取所有应用路径
123
123
  var search_dir = "static";
package/index.js CHANGED
@@ -98,7 +98,7 @@ class OS {
98
98
  OS.prototype.initData = function(config) {
99
99
  var p = config.runPath;
100
100
  if (!p) {
101
- config.runPath = $.runPath
101
+ config.runPath = $.runPath;
102
102
  } else if (p.substring(p.length - 1) !== $.slash) {
103
103
  config.runPath += $.slash;
104
104
  }
@@ -216,34 +216,53 @@ OS.prototype.init = function(config) {
216
216
  this.initErrorHandler();
217
217
  }
218
218
 
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
- }
219
+ /**
220
+ * 运行基础数据
221
+ * @param {Object} cg - 配置对象
222
+ */
223
+ OS.prototype.initBase = function(cg) {
224
+ var middleware = $.middleware;
225
+ // 更新中间件配置,并且加载JS文件
226
+ middleware.update();
227
+ var mqtt, web;
228
+ if (cg.web && cg.web.state) {
229
+ web = new WEB(cg.web);
230
+ // 过滤出web模式的中间件
231
+ web.list = middleware.list.filter((o) => {
232
+ return !o.mode || o.mode == "web"
233
+ });
234
+ // 预加载中间件函数,确保list中的每个中间件都有func属性
235
+ if (web.list && web.list.length > 0) {
236
+ for (var i = 0; i < web.list.length; i++) {
237
+ var o = web.list[i];
238
+ try {
239
+ if (o.func_file && !o.func) {
240
+ o.func = require(o.func_file);
241
+ }
242
+ } catch (error) {
243
+ if ($.log && $.log.error) {
244
+ $.log.error(`预加载中间件失败: ${o.name}`, error);
245
+ } else {
246
+ console.error(`预加载中间件失败: ${o.name}`, error);
247
+ }
248
+ }
249
+ }
250
+ }
251
+ web.init();
252
+ this.web = web;
253
+ }
254
+
255
+ if (cg.mqtt && cg.mqtt.state) {
256
+ mqtt = new MQTT(Object.assign(cg.mqtt, {
257
+ redis: cg.redis,
258
+ mongodb: cg.mongodb
259
+ }));
260
+ mqtt.list = middleware.list.filter((o) => {
261
+ return o.mode == "mqtt"
262
+ });
263
+ mqtt.init();
264
+ this.mqtt = mqtt;
265
+ }
247
266
  }
248
267
 
249
268
  /**
@@ -261,8 +280,8 @@ OS.prototype.main = async function(state) {
261
280
  if (cg.web.socket) {
262
281
  tip += " socket";
263
282
  }
264
- var eventer = $.event_admin('api');
265
- eventer.update();
283
+ var evt = $.event_admin('api');
284
+ evt.update();
266
285
  this.web.run();
267
286
  }
268
287
 
@@ -0,0 +1,119 @@
1
+ /**
2
+ * CORS跨域中间件
3
+ * 处理跨域资源共享(CORS)配置
4
+ */
5
+ class CorsMiddleware {
6
+ constructor() {
7
+ this.default = {
8
+ // 启用CORS
9
+ enable: true,
10
+ // 允许的源
11
+ origin: '*',
12
+ // 允许的请求头
13
+ headers: '*',
14
+ // 允许的HTTP方法
15
+ methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'HEAD'],
16
+ // 允许携带凭证
17
+ credentials: false,
18
+ // 预检请求的有效期(秒)
19
+ max_age: 3600,
20
+ // 暴露的响应头
21
+ expose_headers: [],
22
+ // 忽略的路径
23
+ ignore_paths: []
24
+ };
25
+ }
26
+ }
27
+
28
+ CorsMiddleware.prototype.init = function(config) {
29
+ this.config = Object.assign({}, this.default, config || {});
30
+ return this;
31
+ };
32
+
33
+ CorsMiddleware.prototype.run = async function(ctx, next) {
34
+ const config = this.config;
35
+
36
+ if (!config.enable) {
37
+ return await next();
38
+ }
39
+
40
+ // 检查是否应该忽略该路径
41
+ const path = ctx.path;
42
+ if (config.ignore_paths.some(p => path.startsWith(p))) {
43
+ return await next();
44
+ }
45
+
46
+ // 设置CORS头
47
+ this._setCorsHeaders(ctx, config);
48
+
49
+ // 处理预检请求
50
+ if (ctx.method === 'OPTIONS') {
51
+ ctx.status = 204;
52
+ return;
53
+ }
54
+
55
+ await next();
56
+ };
57
+
58
+ CorsMiddleware.prototype._setCorsHeaders = function(ctx, config) {
59
+ // 设置Access-Control-Allow-Origin
60
+ if (config.origin === '*') {
61
+ ctx.set('Access-Control-Allow-Origin', '*');
62
+ } else if (Array.isArray(config.origin)) {
63
+ const requestOrigin = ctx.get('Origin');
64
+ if (config.origin.includes(requestOrigin)) {
65
+ ctx.set('Access-Control-Allow-Origin', requestOrigin);
66
+ }
67
+ } else {
68
+ ctx.set('Access-Control-Allow-Origin', config.origin);
69
+ }
70
+
71
+ // 设置Access-Control-Allow-Headers
72
+ if (config.headers === '*') {
73
+ ctx.set('Access-Control-Allow-Headers', '*');
74
+ } else if (Array.isArray(config.headers)) {
75
+ ctx.set('Access-Control-Allow-Headers', config.headers.join(', '));
76
+ } else {
77
+ ctx.set('Access-Control-Allow-Headers', config.headers);
78
+ }
79
+
80
+ // 设置Access-Control-Allow-Methods
81
+ ctx.set('Access-Control-Allow-Methods', config.methods.join(', '));
82
+
83
+ // 设置Access-Control-Allow-Credentials
84
+ if (config.credentials) {
85
+ ctx.set('Access-Control-Allow-Credentials', 'true');
86
+ }
87
+
88
+ // 设置Access-Control-Max-Age
89
+ if (config.max_age > 0) {
90
+ ctx.set('Access-Control-Max-Age', config.max_age.toString());
91
+ }
92
+
93
+ // 设置Access-Control-Expose-Headers
94
+ if (config.expose_headers.length > 0) {
95
+ ctx.set('Access-Control-Expose-Headers', config.expose_headers.join(', '));
96
+ }
97
+ };
98
+
99
+ // 创建中间件实例
100
+ const middleware = new CorsMiddleware();
101
+
102
+ // 导出符合系统期望的函数
103
+ exports = module.exports = function(server, config) {
104
+ // 初始化中间件
105
+ middleware.init(config);
106
+
107
+ // 注册中间件到服务器
108
+ server.use(middleware.run.bind(middleware));
109
+
110
+ // 记录中间件初始化信息
111
+ if ($.log && $.log.info) {
112
+ $.log.info(`CORS中间件已加载: 启用=${middleware.config.enable}, 源=${middleware.config.origin}`);
113
+ }
114
+
115
+ return server;
116
+ };
117
+
118
+ // 保留原始实例,以便其他方式调用
119
+ exports.middleware = middleware;
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "cors",
3
+ "title": "CORS跨域中间件",
4
+ "description": "处理跨域资源共享(CORS)配置,支持灵活的跨域策略",
5
+ "version": "1.0",
6
+ "type": "web",
7
+ "process_type": "common_before",
8
+ "sort": 15,
9
+ "state": 1,
10
+ "config": {
11
+ "enable": true,
12
+ "origin": "*",
13
+ "headers": "*",
14
+ "methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD"],
15
+ "credentials": false,
16
+ "max_age": 3600,
17
+ "expose_headers": [],
18
+ "ignore_paths": []
19
+ }
20
+ }
@@ -0,0 +1,202 @@
1
+ /**
2
+ * CSRF保护中间件
3
+ * 防止跨站请求伪造攻击
4
+ */
5
+ class CsrfMiddleware {
6
+ constructor() {
7
+ this.default = {
8
+ // 启用CSRF保护
9
+ enable: true,
10
+ // CSRF令牌的Cookie名称
11
+ cookie_name: 'csrf_token',
12
+ // CSRF令牌的请求头名称
13
+ header_name: 'X-CSRF-Token',
14
+ // CSRF令牌的表单字段名称
15
+ form_field: '_csrf',
16
+ // CSRF令牌的过期时间(毫秒)
17
+ max_age: 3600000, // 1小时
18
+ // 忽略的HTTP方法
19
+ ignore_methods: ['GET', 'HEAD', 'OPTIONS'],
20
+ // 忽略的路径
21
+ ignore_paths: [],
22
+ // 是否生成新的令牌
23
+ generate_new: true,
24
+ // 是否验证来源
25
+ check_origin: true,
26
+ // 是否记录CSRF攻击尝试
27
+ log: true,
28
+ // 是否阻止恶意请求
29
+ block: true,
30
+ // 允许的来源域名
31
+ allowed_origins: []
32
+ };
33
+ }
34
+ }
35
+
36
+ CsrfMiddleware.prototype.init = function(config) {
37
+ this.config = Object.assign({}, this.default, config || {});
38
+ return this;
39
+ };
40
+
41
+ CsrfMiddleware.prototype.run = async function(ctx, next) {
42
+ const config = this.config;
43
+
44
+ if (!config.enable) {
45
+ return await next();
46
+ }
47
+
48
+ // 生成CSRF令牌
49
+ const token = await this._generateToken(ctx);
50
+
51
+ // 将令牌添加到上下文,供模板使用
52
+ ctx.state.csrf = token;
53
+
54
+ // 检查是否需要验证CSRF
55
+ if (!this._shouldSkipCsrfValidation(ctx, config)) {
56
+ // 验证来源
57
+ if (config.check_origin && !this._validateOrigin(ctx, config)) {
58
+ if (config.block) {
59
+ ctx.status = 403;
60
+ ctx.body = {
61
+ code: 403,
62
+ msg: 'Forbidden: Invalid request origin'
63
+ };
64
+ return;
65
+ }
66
+ }
67
+
68
+ // 验证CSRF令牌
69
+ if (!this._validateToken(ctx, config)) {
70
+ if (config.block) {
71
+ ctx.status = 403;
72
+ ctx.body = {
73
+ code: 403,
74
+ msg: 'Forbidden: Invalid CSRF token'
75
+ };
76
+ return;
77
+ }
78
+ }
79
+
80
+ // 如果需要生成新令牌
81
+ if (config.generate_new) {
82
+ await this._setNewToken(ctx, config);
83
+ }
84
+ }
85
+
86
+ await next();
87
+ };
88
+
89
+ CsrfMiddleware.prototype._generateToken = async function(ctx) {
90
+ let token = ctx.cookies.get(this.config.cookie_name);
91
+
92
+ // 如果没有令牌或需要生成新令牌,则创建一个新的
93
+ if (!token || this.config.generate_new) {
94
+ await this._setNewToken(ctx, this.config);
95
+ token = ctx.cookies.get(this.config.cookie_name);
96
+ }
97
+
98
+ return token;
99
+ };
100
+
101
+ CsrfMiddleware.prototype._setNewToken = async function(ctx, config) {
102
+ // 生成随机令牌
103
+ const token = this._createRandomToken();
104
+
105
+ // 将令牌存储到Cookie
106
+ ctx.cookies.set(config.cookie_name, token, {
107
+ httpOnly: false, // CSRF令牌需要从前端读取,所以不能设置httpOnly
108
+ maxAge: config.max_age,
109
+ sameSite: 'lax'
110
+ });
111
+ };
112
+
113
+ CsrfMiddleware.prototype._createRandomToken = function() {
114
+ return Math.random().toString(36).substring(2) +
115
+ Math.random().toString(36).substring(2) +
116
+ Math.random().toString(36).substring(2);
117
+ };
118
+
119
+ CsrfMiddleware.prototype._shouldSkipCsrfValidation = function(ctx, config) {
120
+ const method = ctx.method;
121
+ const path = ctx.path;
122
+
123
+ // 检查是否在忽略的方法列表中
124
+ if (config.ignore_methods.includes(method)) {
125
+ return true;
126
+ }
127
+
128
+ // 检查是否在忽略的路径列表中
129
+ if (config.ignore_paths.some(p => path.startsWith(p))) {
130
+ return true;
131
+ }
132
+
133
+ return false;
134
+ };
135
+
136
+ CsrfMiddleware.prototype._validateOrigin = function(ctx, config) {
137
+ const origin = ctx.get('Origin');
138
+ const host = ctx.get('Host');
139
+
140
+ // 如果没有Origin头,可能是同源请求
141
+ if (!origin) {
142
+ return true;
143
+ }
144
+
145
+ // 检查是否在允许的来源列表中
146
+ if (config.allowed_origins.length > 0) {
147
+ return config.allowed_origins.includes(origin);
148
+ }
149
+
150
+ // 默认情况下,只允许同源请求
151
+ return origin.includes(host);
152
+ };
153
+
154
+ CsrfMiddleware.prototype._validateToken = function(ctx, config) {
155
+ const tokenFromCookie = ctx.cookies.get(config.cookie_name);
156
+
157
+ // 从请求头获取令牌
158
+ const tokenFromHeader = ctx.get(config.header_name);
159
+
160
+ // 从请求体获取令牌
161
+ let tokenFromBody = null;
162
+ if (ctx.request.body && ctx.request.body[config.form_field]) {
163
+ tokenFromBody = ctx.request.body[config.form_field];
164
+ }
165
+
166
+ // 从查询参数获取令牌
167
+ const tokenFromQuery = ctx.query[config.form_field];
168
+
169
+ // 检查令牌是否匹配
170
+ const receivedToken = tokenFromHeader || tokenFromBody || tokenFromQuery;
171
+
172
+ if (!receivedToken || !tokenFromCookie) {
173
+ return false;
174
+ }
175
+
176
+ return receivedToken === tokenFromCookie;
177
+ };
178
+
179
+ // 创建中间件实例
180
+ const middleware = new CsrfMiddleware();
181
+
182
+ // 导出符合系统期望的函数
183
+ exports = module.exports = function(server, config) {
184
+ // 获取当前中间件的配置(从middleware.json加载的配置)
185
+ var middleware_config = this && this.config ? this.config : config;
186
+
187
+ // 初始化中间件
188
+ middleware.init(middleware_config);
189
+
190
+ // 注册中间件到服务器
191
+ server.use(middleware.run.bind(middleware));
192
+
193
+ // 记录中间件初始化信息
194
+ if ($.log && $.log.info) {
195
+ $.log.info(`CSRF中间件已加载: 启用=${middleware.config.enable}, 忽略路径=${middleware.config.ignore_paths.length}`);
196
+ }
197
+
198
+ return server;
199
+ };
200
+
201
+ // 保留原始实例,以便其他方式调用
202
+ exports.middleware = middleware;
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "csrf",
3
+ "title": "CSRF保护中间件",
4
+ "description": "防止跨站请求伪造攻击,提供安全的令牌验证机制",
5
+ "version": "1.0",
6
+ "type": "web",
7
+ "process_type": "common_before",
8
+ "sort": 20,
9
+ "state": 1,
10
+ "config": {
11
+ "enable": true,
12
+ "cookie_name": "csrf_token",
13
+ "header_name": "X-CSRF-Token",
14
+ "form_field": "_csrf",
15
+ "max_age": 3600000,
16
+ "ignore_methods": ["GET", "HEAD", "OPTIONS"],
17
+ "ignore_paths": ["/api/user/sign_in", "/user/login", "/login", "/admin/login"],
18
+ "generate_new": true,
19
+ "check_origin": true,
20
+ "log": true,
21
+ "block": true,
22
+ "allowed_origins": []
23
+ }
24
+ }