mm_os 2.1.8 → 2.2.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.
@@ -0,0 +1,447 @@
1
+ var sql = $.mysql_admin('sys');
2
+ var dbs = sql.dbs;
3
+
4
+ /**
5
+ * 服务端类
6
+ */
7
+ class Server {
8
+
9
+ }
10
+
11
+ /**
12
+ * 获取用户
13
+ * @param {String} table 数据表
14
+ * @param {Number} project_id 项目ID
15
+ * @param {String} customId 自定义身份ID
16
+ * @param {String} name 用户姓名
17
+ * @param {String} phone 用户手机号码
18
+ * @param {String} idcard 用户身份证号
19
+ * @returns {Object} 返回用户对象
20
+ */
21
+ Server.prototype.get_user_sub = async function(table, project_id, customId, name, phone, idcard) {
22
+ var db1 = dbs.new("face_" + table, "user_id");
23
+ var query = {
24
+ project_id
25
+ }
26
+ if (customId && customId !== "0") {
27
+ query.customId = customId;
28
+ } else {
29
+ query.name = name;
30
+ if (phone) {
31
+ query.phone = phone;
32
+ } else if (idcard) {
33
+ query.idcard = idcard;
34
+ }
35
+ }
36
+ // 先查询1次,看内部人员是否存在
37
+ var enter = await db2.getObj(query, "", "*", false);
38
+
39
+ if (!enter) {
40
+ // 如果不存在,则用名字再查一次,看内部人员是否存在
41
+ query = {
42
+ project_id,
43
+ name
44
+ };
45
+ enter = await db2.getObj(query, "`time_create` desc", "*", false);
46
+ }
47
+ return enter;
48
+ }
49
+
50
+ /**
51
+ * 获取用户
52
+ * @param {String} project_id 项目ID
53
+ * @param {String} table 数据表
54
+ * @param {Number} project_id 项目ID
55
+ * @param {String} customId 自定义身份ID
56
+ * @param {String} name 用户姓名
57
+ * @param {String} phone 用户手机号码
58
+ * @param {String} idcard 用户身份证号
59
+ * @returns {Object} 返回用户对象和用户类型
60
+ */
61
+ Server.prototype.get_user = async function(project_id, customId, name, phone, idcard) {
62
+ // 默认为 1内部人员类型
63
+ var user_type = 1;
64
+ var enter = await this.get_user_sub("enter", project_id, customId, name, phone, idcard);
65
+
66
+ if (!enter) {
67
+ // 2为访客
68
+ user_type = 2;
69
+ enter = await this.get_user_sub("visitor", project_id, customId, name, phone, idcard);
70
+ }
71
+
72
+ if (enter) {
73
+ var by = {};
74
+ if (!enter.customId && customId && customId !== "0") {
75
+ by.customId = customId;
76
+ }
77
+ if (!enter.phone && phone) {
78
+ by.phone = phone;
79
+ }
80
+ if (!enter.idcard && idcard && idcard !== '0') {
81
+ by.idcard = idcard;
82
+ }
83
+ if (Object.keys(by).length) {
84
+ var db3;
85
+ var qy = {};
86
+ if (user_type == 2) {
87
+ db3 = dbs.new("face_visitor", "visitor_id");
88
+ qy.visitor_id = enter.visitor_id
89
+ } else {
90
+ db3 = dbs.new("face_enter", "user_id");
91
+ qy.user_id == enter.user_id;
92
+ qy.project_id = enter.project_id;
93
+ }
94
+ await db3.set(qy, by);
95
+ enter = Object.assign({}, enter, by);
96
+ }
97
+ } else {
98
+ // 3为外部人员(非平台成员)
99
+ user_type = 3;
100
+ enter = {
101
+ department_id: 0,
102
+ team_id: 0,
103
+ job: '',
104
+ phone,
105
+ idcard
106
+ };
107
+ }
108
+ var user = Object.assign({}, enter, {
109
+ customId,
110
+ name,
111
+ phone,
112
+ idcard
113
+ })
114
+ return {
115
+ user_type,
116
+ user
117
+ }
118
+ }
119
+
120
+ /**
121
+ * 处理上传记录
122
+ * @param {String} clientid 设备ID
123
+ * @param {Object} log 记录
124
+ */
125
+ Server.prototype.exec_log = async function(clientid, log) {
126
+ var {
127
+ device,
128
+ tip
129
+ } = await this.check_device(clientid);
130
+
131
+ if (tip) {
132
+ return tip
133
+ }
134
+
135
+ var project_id = device.project_id;
136
+ var {
137
+ project,
138
+ tip
139
+ } = check_project(project_id);
140
+
141
+ if (tip) {
142
+ return tip
143
+ }
144
+
145
+ var {
146
+ customId,
147
+ name,
148
+ phone,
149
+ idcard
150
+ } = log;
151
+ // 通过项目id和用户唯一标识获取用户
152
+ var {
153
+ user,
154
+ user_type
155
+ } = await this.get_user(project_id, customId, name, phone, idcard);
156
+
157
+ // 如果不记录外部人员,则终止,不保存记录
158
+ if (!project.save_outboard && user_type === 3) {
159
+ return
160
+ }
161
+ log.user_type = user_type;
162
+ log.clientid = clientid;
163
+ log.direction = device.direction;
164
+ return this.save_log(log);
165
+ }
166
+
167
+ /**
168
+ * 检查设备
169
+ * @param {String} clientid 客户端ID
170
+ * @param {Object} key 键
171
+ */
172
+ Server.prototype.check_device = async function(clientid, key) {
173
+ var tip;
174
+ var db2 = dbs.new("face_device");
175
+ var device = await db2.getObj({
176
+ clientid
177
+ });
178
+ if (device) {
179
+ if (device.available) {
180
+ if (key && !device[key]) {
181
+ tip = "没有功能权限"
182
+ }
183
+ } else {
184
+ tip = "设备已禁用"
185
+ }
186
+ } else {
187
+ tip = "没有找到设备"
188
+ }
189
+ return {
190
+ device,
191
+ tip
192
+ };
193
+ }
194
+
195
+
196
+ /**
197
+ * 检查项目
198
+ * @param {String} project_id 项目ID
199
+ * @param {Object} key 键
200
+ */
201
+ Server.prototype.check_project = async function(project_id, key) {
202
+ var tip;
203
+ var db2 = dbs.new("face_project");
204
+ var project = await db2.getObj({
205
+ project_id
206
+ });
207
+ if (project) {
208
+ if (project.available) {
209
+ var now = new Date().getTime();
210
+ if (now > new Date(project.time_valid).getTime()) {
211
+ tip = "项目已过期"
212
+ } else if (key && !project[key]) {
213
+ tip = "没有功能权限"
214
+ }
215
+ } else {
216
+ tip = "项目已禁用"
217
+ }
218
+ } else {
219
+ tip = "没有找到项目"
220
+ }
221
+ return {
222
+ project,
223
+ tip
224
+ }
225
+ }
226
+
227
+ /**
228
+ * 保存记录
229
+ * @param {Object} log 记录
230
+ */
231
+ Server.prototype.save_log = async function(log) {
232
+ var db = dbs.new("face_log", "user_id");
233
+ var project_id = log.project_id;
234
+ var user_id = log.user_id || 0;
235
+ var time = log.time;
236
+ var count = await db.count({
237
+ project_id,
238
+ user_id,
239
+ time
240
+ });
241
+
242
+ // 如果记录已存在,则不再保存
243
+ if (count) {
244
+ return
245
+ }
246
+
247
+ // 重新定义方向
248
+ var direction = log.direction;
249
+ if (user_id && direction == "通用") {
250
+ var qy = {
251
+ user_id,
252
+ project_id,
253
+ type_has: "1,3,4",
254
+ time_min: now.toStr('yyyy-MM-dd 00:00:00')
255
+ };
256
+ var obj = await db.getObj(qy, '`time` desc');
257
+ if (obj) {
258
+ direction = obj.direction == "进" ? "出" : "进"
259
+ } else {
260
+ direction = "进"
261
+ }
262
+ }
263
+ log.direction = direction;
264
+
265
+ // 重新定义头像
266
+ var pic;
267
+ var fname = time.replace(/[-: ]/g, '_');
268
+ var avatar = log.avatar;
269
+ if (avatar) {
270
+ if (project.upload_pic) {
271
+ pic = avatar;
272
+ avatar = `/face/img/user/${user_id}/${fname}.png`;
273
+ } else {
274
+ avatar = "";
275
+ }
276
+ }
277
+
278
+ // 如果是访客则追加备注
279
+ var visitor_id = log.visitor_id;
280
+ if (visitor_id) {
281
+ var {
282
+ respondent,
283
+ date,
284
+ source
285
+ } = log;
286
+ if (typeof(date) == "string") {
287
+ date = date.toTime().toStr("yyyy-MM-dd");
288
+ } else if (typeof(date) == "object") {
289
+ date = date.toStr("yyyy-MM-dd");
290
+ } else {
291
+ date = ''
292
+ }
293
+ log.note = `${visitor_id},${source},${date},${respondent},${log.nfc}`;
294
+ delete log.visitor_id;
295
+ delete log.respondent;
296
+ delete log.date;
297
+ delete log.source;
298
+ }
299
+
300
+ // 添加新记录
301
+ var n = await db.add(log);
302
+
303
+ var bl = n > 0;
304
+ if (bl) {
305
+ // 更新用户状态
306
+ var body = {
307
+ clientid: log.clientid,
308
+ direction,
309
+ time
310
+ };
311
+ if (log.user_type == 1) {
312
+ var db4 = dbs.new("face_enter", "enter_id");
313
+ await db4.set({
314
+ user_id,
315
+ project_id
316
+ }, body);
317
+ } else if (user_type == 2) {
318
+ var db4 = dbs.new("face_visitor", "visitor_id");
319
+ await db4.set({
320
+ visitor_id
321
+ }, body);
322
+ }
323
+
324
+ if (pic) {
325
+ var file = (`/app/face/static/img/user/${user_id}/${fname}.png`).fullname();
326
+ file.addDir();
327
+ var po = pic.replace(/^data:image\/\w+;base64,/, "");
328
+ var bf = Buffer.from(po, 'base64');
329
+ fs.writeFileSync(file, bf);
330
+ }
331
+ }
332
+ return bl;
333
+ }
334
+
335
+ /**
336
+ * 处理扫描二维码开门
337
+ * @param {String} clientid 客户端ID
338
+ * @param {String} qrcode 二维码内容
339
+ */
340
+ Server.prototype.exec_qrcode = async function(clientid, qrcode = "") {
341
+ var ret;
342
+ var db = dbs.new("face_qrcode", "qrcode_id");
343
+ var now = new Date();
344
+ var time = now.toStr('yyyy-MM-dd hh:mm:ss');
345
+ var obj = await db.getObj({
346
+ qrcode,
347
+ time_end_min: time
348
+ });
349
+ if (obj) {
350
+ var {
351
+ device,
352
+ tip
353
+ } = await this.check_device(clientid, "qrcode");
354
+ if (tip) {
355
+ // 发送开门控制
356
+ ret = {
357
+ "uuid": obj.user_id,
358
+ // 0不开门,1开门
359
+ "pass": false,
360
+ "tip": tip
361
+ }
362
+ } else {
363
+ if (obj.count == 0 || obj.num < obj.count) {
364
+ var db = dbs.new("face_enter");
365
+ var user = await db.getObj({
366
+ user_id: obj.user_id,
367
+ project_id: obj.project_id,
368
+ state: 3
369
+ });
370
+ if (user) {
371
+ if (user.client && user.client.indexOf(clientid) !== -1) {
372
+ obj.num++;
373
+ // 发送开门控制
374
+ ret = {
375
+ "uuid": user.customId || user.project_id + "-" + user.user_id,
376
+ // 0不开门,1开门
377
+ "pass": true,
378
+ "tip": "请通行",
379
+ user
380
+ }
381
+ var log = {
382
+ project_id: 0,
383
+ user_id: 0,
384
+ name: "",
385
+ // 1内部人员|2访客|3非系统名单
386
+ user_type: 1,
387
+ // 1人脸验证|2远程开门|3扫码开门|4刷卡验证
388
+ type: 3,
389
+ record_type: 1,
390
+ action: "智码开门",
391
+ // 1白名单|2黑名单
392
+ person_type: 1,
393
+ department_id: 0,
394
+ team_id: 0,
395
+ job: "",
396
+ phone: "",
397
+ idcard: "",
398
+ nfc: "",
399
+ note: ""
400
+ }
401
+ $.push(u, user);
402
+ log.direction = device.direction;
403
+ log.clientid = clientid;
404
+ log.time = time;
405
+ await this.save_log(log);
406
+ } else {
407
+ // 发送开门控制
408
+ ret = {
409
+ "uuid": user.customId || user.project_id + "-" + user.user_id,
410
+ // 0不开门,1开门
411
+ "pass": false,
412
+ "tip": "没有访问权限"
413
+ }
414
+ }
415
+ } else {
416
+ // 发送开门控制
417
+ ret = {
418
+ "uuid": obj.project_id + "-" + obj.user_id,
419
+ // 0不开门,1开门
420
+ "pass": false,
421
+ "tip": "非法用户"
422
+ }
423
+ }
424
+ } else {
425
+ // 发送开门控制
426
+ ret = {
427
+ "uuid": obj.project_id + "-" + obj.user_id,
428
+ // 0不开门,1开门
429
+ "pass": false,
430
+ "tip": "使用次数超限"
431
+ }
432
+ }
433
+ }
434
+ } else {
435
+ // 发送开门控制
436
+ ret = {
437
+ "uuid": "0",
438
+ // 0不开门,1开门
439
+ "pass": false,
440
+ "tip": "非法二维码"
441
+ }
442
+ }
443
+
444
+ return ret;
445
+ }
446
+
447
+ $.server = new Server();
@@ -34,16 +34,22 @@
34
34
  // 静态文件缓存时长
35
35
  "max_age": 120000,
36
36
  // 代理转发
37
- "proxy": {}
37
+ "proxy": {},
38
+ // 单位秒, 3600 = 1小时
39
+ "request_duration": 60,
40
+ // 请求次数上限
41
+ "request_limit": 10,
42
+ // 是否加入黑名单
43
+ "request_block": true
38
44
  },
39
45
  "mqtt": {
40
46
  // 是否启用MQTT
41
- "state": false,
47
+ "state": true,
42
48
  // mqtt访问端口号
43
49
  "socket_port": 1883,
44
50
  // websocket 访问端口
45
51
  "http_port": 8083,
46
- // 缓存方式
52
+ // 缓存方式 memory、mongodb、redis
47
53
  "cache": "memory",
48
54
  // 缓存服务器地址
49
55
  "cache_host": "mongodb://localhost:27017/mosca",
@@ -52,7 +58,7 @@
52
58
  // 协议头
53
59
  "protocol": "mqtt",
54
60
  // MQTT服务器地址
55
- "hostname": "mqtt.aieliantong.com",
61
+ "hostname": "127.0.0.1",
56
62
  // MQTT服务器用户名
57
63
  "username": "developer",
58
64
  // MQTT服务器密码
@@ -37,15 +37,15 @@
37
37
  "proxy": {}
38
38
  },
39
39
  "mqtt": {
40
- "state": false,
40
+ "state": true,
41
41
  // mqtt访问端口号
42
42
  "socket_port": 1883,
43
43
  // 服务端
44
44
  "http_host": "localhost",
45
45
  // websocket 访问端口
46
46
  "http_port": 8083,
47
- // 缓存方式
48
- "cache": "mongodb",
47
+ // 缓存方式 memory、mongodb、redis
48
+ "cache": "memory",
49
49
  // 缓存服务器地址
50
50
  "cache_host": "mongodb://localhost:27017/mosca",
51
51
  // MQTT订阅方式
@@ -57,7 +57,7 @@
57
57
  // MQTT服务器用户名
58
58
  "username": "server",
59
59
  // MQTT服务器密码
60
- "password": "df6897hu",
60
+ "password": "asd123",
61
61
  "port": 1883
62
62
  },
63
63
  "mysql": {
@@ -52,7 +52,7 @@
52
52
  // 协议头
53
53
  "protocol": "mqtt",
54
54
  // MQTT服务器地址
55
- "hostname": "mqtt.aieliantong.com",
55
+ "hostname": "127.0.0.1",
56
56
  // MQTT服务器用户名
57
57
  "username": "developer",
58
58
  // MQTT服务器密码
package/demo/index.js CHANGED
@@ -11,4 +11,13 @@ $.sql = $.mysql_admin('sys', __dirname);
11
11
  $.sql.setConfig(config.mysql);
12
12
  $.sql.open();
13
13
 
14
+ setTimeout(async () => {
15
+ var mqtt = $.mqtt_admin("sys");
16
+ mqtt.init(config.mqtt);
17
+ mqtt.start();
18
+ await mqtt.update();
19
+ mqtt.run(null, 'init');
20
+ // console.log("打印", $.eventer, mqtt);
21
+ }, 2000);
22
+
14
23
  os.run();
package/index.js CHANGED
@@ -239,7 +239,6 @@ OS.prototype.main = async function(state) {
239
239
  }
240
240
 
241
241
  if (cg.sys && cg.sys.task) {
242
- console.log('【启动定时任务】');
243
242
  $.task.update();
244
243
  $.task.run();
245
244
  }
@@ -0,0 +1,106 @@
1
+ const os = require('os');
2
+ const {
3
+ exec
4
+ } = require('child_process');
5
+ const platform = os.platform();
6
+
7
+ /**
8
+ * 获取客户端IP
9
+ * @param {Object} req 请求对象
10
+ *
11
+ */
12
+ function getClientIP(req) {
13
+ return req.headers['x-forwarded-for'] || req.headers['X-Forwarded-For'] ||
14
+ req.connection.remoteAddress ||
15
+ req.socket.remoteAddress ||
16
+ req.connection.socket.remoteAddress;
17
+ };
18
+
19
+ /**
20
+ * 设置黑名单
21
+ * @param {String} ip IP地址
22
+ */
23
+ function setting_blacklist(ip) {
24
+ var cmd;
25
+ if (platform == "win32") {
26
+ // window 系统
27
+ cmd =
28
+ `netsh advfirewall firewall add rule name="Blacklist ${ip}" dir=in action=block remoteip="${ip}" protocol=any`
29
+ } else {
30
+ // linux 系统
31
+ cmd = `sudo iptables -A INPUT -s ${ip} -j DROP`;
32
+ }
33
+
34
+ exec(cmd, (error, stdout, stderr) => {
35
+ if (error) {
36
+ console.error(`执行的错误: ${error}`);
37
+ return;
38
+ }
39
+ $.log.info(`加入黑名单: ${ip}`);
40
+ if (stderr) {
41
+ console.error(`标准错误输出: ${stderr}`);
42
+ }
43
+ });
44
+ }
45
+
46
+ /**
47
+ * 应用
48
+ * @param {Object} server 服务
49
+ * @param {Object} config 配置参数
50
+ */
51
+ module.exports = function(server, config) {
52
+ var limit = config.request_limit || 0;
53
+ var duration = config.request_duration || 0;
54
+ var block = config.request_block || false;
55
+
56
+ if (limit && duration) {
57
+ /* WAF(web防火墙) */
58
+ server.use(async (ctx, next) => {
59
+ var pass = true;
60
+ // 获取IP
61
+ var ip = getClientIP(ctx.req);
62
+ var num = 1;
63
+ var now = new Date();
64
+ var date = now.toStr('yyyy-MM-dd');
65
+ var time;
66
+ var str = await $.cache.get("ip_" + ip);
67
+ var json;
68
+ if (str) {
69
+ json = JSON.parse(str);
70
+ if (json.date !== date) {
71
+ num = 1;
72
+ } else {
73
+ // 判断时间间隔是否在范围外
74
+ if (json.time.toTime().interval(now) > duration) {
75
+ num = 1;
76
+ } else {
77
+ // 如果是在周期内,访问次数+1,并判断是否超出上限
78
+ num = json.num + 1;
79
+ if (num > limit) {
80
+ // 超出上限禁止访问,并加入黑名单
81
+ pass = false;
82
+ if (block) {
83
+ setting_blacklist(ip);
84
+ }
85
+ }
86
+ }
87
+ }
88
+ }
89
+ if (!time) {
90
+ time = now.toStr('yyyy-MM-dd hh:mm:ss');
91
+ }
92
+ if (pass) {
93
+ await $.cache.set("ip_" + ip, JSON.stringify({
94
+ date,
95
+ time,
96
+ num
97
+ }), duration);
98
+ await next();
99
+ } else {
100
+ ctx.status = 429;
101
+ ctx.body = '请求频率过高,请稍后再试。';
102
+ }
103
+ });
104
+ }
105
+ return server;
106
+ };
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "web_waf_ip",
3
+ "title": "IP防火墙",
4
+ "description": "用于防止DOS攻击",
5
+ "version": "1.0",
6
+ "type": "web",
7
+ "process_type": "common_before",
8
+ "sort": 1,
9
+ "state": 0
10
+ }
@@ -48,10 +48,12 @@ class Event {
48
48
  if (config.event && $.event_admin) {
49
49
  // 创建一个API事件
50
50
  var apis = $.event_admin('api', 'API事件');
51
- apis.update();
52
- for (var k in this.events) {
53
- this.events[k] = apis["list_" + k];
51
+ apis.update_after = () => {
52
+ for (var k in this.events) {
53
+ this.events[k] = apis["list_" + k];
54
+ }
54
55
  }
56
+ apis.update();
55
57
  };
56
58
 
57
59
  /**
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "mm_os",
3
- "version": "2.1.8",
3
+ "version": "2.2.0",
4
4
  "description": "这是超级美眉服务端框架,用于快速构建应用程序。",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "test": "cross-env NODE_ENV=test node ./demo/index.js",
8
- "start": "node ./demo/index.js",
8
+ "start": "node --trace-warnings ./demo/index.js",
9
9
  "dev": "cross-env NODE_ENV=development nodemon ./demo/index.js"
10
10
  },
11
11
  "repository": {
@@ -41,7 +41,7 @@
41
41
  "mm_html": "^1.1.6",
42
42
  "mm_koa_proxy": "^1.0.0",
43
43
  "mm_logs": "^1.1.4",
44
- "mm_machine": "^1.6.5",
44
+ "mm_machine": "^1.7.2",
45
45
  "mm_mongodb": "^1.4.2",
46
46
  "mm_mqtt": "^1.0.6",
47
47
  "mm_mysql": "^1.8.0",