mm_session 1.6.0 → 1.6.2
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/lib/helper.js +10 -13
- package/lib/session.js +29 -43
- package/package.json +3 -3
package/lib/helper.js
CHANGED
|
@@ -47,28 +47,25 @@ Helper.prototype.aesDecode = function (text, key, iv) {
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
51
|
-
* @param {string}
|
|
52
|
-
* @returns {string}
|
|
50
|
+
* 从key派生IV(固定派生,不依赖user_agent)
|
|
51
|
+
* @param {string} key 密钥
|
|
52
|
+
* @returns {string} IV(16字节)
|
|
53
53
|
*/
|
|
54
|
-
Helper.prototype.
|
|
55
|
-
|
|
56
|
-
return user_agent.md5().substring(0, 16);
|
|
54
|
+
Helper.prototype._getIvFromKey = function (key) {
|
|
55
|
+
return key.md5().substring(0, 16);
|
|
57
56
|
};
|
|
58
57
|
|
|
59
58
|
/**
|
|
60
59
|
* 生成session ID
|
|
61
60
|
* @param {string} key 密钥
|
|
62
61
|
* @param {string} ip 客户端IP
|
|
63
|
-
* @param {string} user_agent
|
|
62
|
+
* @param {string} user_agent 用户代理字符串(不再用于IV,仅保留参数兼容)
|
|
64
63
|
* @param {number} uuid_expire 过期时间(秒)
|
|
65
64
|
* @returns {string} session ID
|
|
66
65
|
*/
|
|
67
66
|
Helper.prototype.genId = function (key, ip, user_agent = 'mm', uuid_expire = 604800) {
|
|
68
|
-
|
|
69
|
-
var iv = this._getSecret(user_agent);
|
|
67
|
+
var iv = this._getIvFromKey(key);
|
|
70
68
|
var end_time = new Date().addSeconds(uuid_expire).stamp();
|
|
71
|
-
// 加密
|
|
72
69
|
var uuid = this.aesEncode(ip + '_' + end_time, key, iv);
|
|
73
70
|
return uuid;
|
|
74
71
|
};
|
|
@@ -77,15 +74,15 @@ Helper.prototype.genId = function (key, ip, user_agent = 'mm', uuid_expire = 604
|
|
|
77
74
|
* 解析session ID
|
|
78
75
|
* @param {string} key 密钥
|
|
79
76
|
* @param {string} uuid session ID
|
|
80
|
-
* @param {string} user_agent
|
|
77
|
+
* @param {string} user_agent 用户代理字符串(不再用于IV,仅保留参数兼容)
|
|
81
78
|
* @returns {object} 解析结果
|
|
82
79
|
*/
|
|
83
80
|
Helper.prototype.parseId = function (key, uuid, user_agent = 'mm') {
|
|
84
|
-
var iv = this.
|
|
81
|
+
var iv = this._getIvFromKey(key);
|
|
85
82
|
var dec = this.aesDecode(uuid, key, iv);
|
|
86
83
|
var parts = dec.split('_');
|
|
87
84
|
if (parts.length !== 2) {
|
|
88
|
-
|
|
85
|
+
return null;
|
|
89
86
|
}
|
|
90
87
|
return {
|
|
91
88
|
ip: parts[0],
|
package/lib/session.js
CHANGED
|
@@ -25,7 +25,7 @@ class Session {
|
|
|
25
25
|
uuid_expire: 60 * 60 * 24 * 7,
|
|
26
26
|
max_age: 60 * 60 * 2,
|
|
27
27
|
expired_handling: 'reject',
|
|
28
|
-
options: {},
|
|
28
|
+
options: { path: '/' },
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
/**
|
|
@@ -83,30 +83,23 @@ Session.prototype.middleware = function () {
|
|
|
83
83
|
* @returns {object} session对象
|
|
84
84
|
*/
|
|
85
85
|
Session.prototype.get = async function (ctx) {
|
|
86
|
-
// 获取协议头信息
|
|
87
86
|
let { ip, user_agent } = this._getHeaderInfo(ctx);
|
|
88
|
-
// 获取session ID
|
|
89
87
|
let session_id = this.getId(ctx);
|
|
90
88
|
|
|
91
|
-
// 验证session ID标识的有效性
|
|
92
89
|
if (session_id) {
|
|
93
90
|
let is_valid = await this._checkSessionId(session_id, ip, user_agent);
|
|
94
91
|
if (!is_valid) {
|
|
95
|
-
// token验证失败,返回null创建新session
|
|
96
92
|
session_id = null;
|
|
97
93
|
}
|
|
98
94
|
}
|
|
99
95
|
|
|
100
|
-
// 获取session对象
|
|
101
96
|
let session = await this._get(session_id);
|
|
102
97
|
|
|
103
98
|
if (!session.uuid) {
|
|
104
99
|
session.uuid = this._genId(ip, user_agent);
|
|
105
100
|
}
|
|
106
|
-
|
|
101
|
+
this._bindSessionMethods(session, ctx);
|
|
107
102
|
ctx.session = this._create(session);
|
|
108
|
-
// 追加方法
|
|
109
|
-
this._addMethod(ctx);
|
|
110
103
|
return ctx.session;
|
|
111
104
|
};
|
|
112
105
|
|
|
@@ -120,6 +113,9 @@ Session.prototype._handle = async function (ctx, next) {
|
|
|
120
113
|
await this.get(ctx);
|
|
121
114
|
await next();
|
|
122
115
|
await this._save(ctx, session_id);
|
|
116
|
+
if (ctx.session) {
|
|
117
|
+
this._setCookie(ctx, ctx.session.uuid);
|
|
118
|
+
}
|
|
123
119
|
};
|
|
124
120
|
|
|
125
121
|
/**
|
|
@@ -128,24 +124,21 @@ Session.prototype._handle = async function (ctx, next) {
|
|
|
128
124
|
* @returns {string} 客户端IP地址
|
|
129
125
|
*/
|
|
130
126
|
Session.prototype._getClientIP = function (ctx) {
|
|
131
|
-
|
|
127
|
+
var ip;
|
|
132
128
|
if (ctx.ip) {
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
129
|
+
ip = ctx.ip;
|
|
130
|
+
} else if (ctx.headers['x-forwarded-for']) {
|
|
131
|
+
ip = ctx.headers['x-forwarded-for'].split(',')[0].trim();
|
|
132
|
+
} else if (ctx.headers['x-real-ip']) {
|
|
133
|
+
ip = ctx.headers['x-real-ip'];
|
|
134
|
+
} else {
|
|
135
|
+
ip = '127.0.0.1';
|
|
140
136
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
return ctx.headers['x-real-ip'];
|
|
137
|
+
// 归一化本地回环地址,避免 IPv6/IPv4 格式差异导致校验失败
|
|
138
|
+
if (ip === '::1' || ip === '::ffff:127.0.0.1' || ip === 'localhost') {
|
|
139
|
+
ip = '127.0.0.1';
|
|
145
140
|
}
|
|
146
|
-
|
|
147
|
-
// 默认返回本地IP
|
|
148
|
-
return '127.0.0.1';
|
|
141
|
+
return ip;
|
|
149
142
|
};
|
|
150
143
|
|
|
151
144
|
/**
|
|
@@ -250,27 +243,29 @@ Session.prototype._create = function (session) {
|
|
|
250
243
|
};
|
|
251
244
|
|
|
252
245
|
/**
|
|
253
|
-
*
|
|
246
|
+
* 给session目标对象绑定方法(在创建Proxy前调用,避免触发set陷阱)
|
|
247
|
+
* @param {object} session session目标对象
|
|
254
248
|
* @param {object} ctx HTTP上下文
|
|
255
249
|
*/
|
|
256
|
-
Session.prototype.
|
|
250
|
+
Session.prototype._bindSessionMethods = function (session, ctx) {
|
|
251
|
+
var self = this;
|
|
252
|
+
|
|
257
253
|
/**
|
|
258
254
|
* 刷新session
|
|
259
255
|
*/
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
ctx.session._modified = true;
|
|
256
|
+
session.refresh = function () {
|
|
257
|
+
this._modified = true;
|
|
263
258
|
};
|
|
264
259
|
|
|
265
260
|
/**
|
|
266
261
|
* 获取session ID
|
|
267
262
|
* @returns {string} session ID
|
|
268
263
|
*/
|
|
269
|
-
|
|
270
|
-
if (!
|
|
271
|
-
|
|
264
|
+
session.getId = function () {
|
|
265
|
+
if (!this.uuid) {
|
|
266
|
+
this.uuid = self.genId(ctx);
|
|
272
267
|
}
|
|
273
|
-
return
|
|
268
|
+
return this.uuid;
|
|
274
269
|
};
|
|
275
270
|
};
|
|
276
271
|
|
|
@@ -335,23 +330,18 @@ Session.prototype._handleCookie = async function (ctx, session_id) {
|
|
|
335
330
|
* @returns {Promise<void>} 保存结果
|
|
336
331
|
*/
|
|
337
332
|
Session.prototype._save = async function (ctx, session_id) {
|
|
338
|
-
// 如果session不存在,直接删除session
|
|
339
333
|
if (!ctx.session) {
|
|
340
334
|
await this._delSession(ctx, session_id);
|
|
341
335
|
return;
|
|
342
336
|
}
|
|
343
337
|
|
|
344
|
-
|
|
345
|
-
if (ctx.session._modified) {
|
|
338
|
+
if (ctx.session._is_new || ctx.session._modified) {
|
|
346
339
|
await this._handleCookie(ctx, session_id);
|
|
347
340
|
|
|
348
|
-
// 提取session数据
|
|
349
341
|
const session_to_save = this._extractSessionData(ctx);
|
|
350
342
|
|
|
351
|
-
// 清理session
|
|
352
343
|
this._cleanup(ctx);
|
|
353
344
|
|
|
354
|
-
// 保存session到存储
|
|
355
345
|
return await this._store.set(ctx.session.uuid, session_to_save, this.config.max_age || 7200);
|
|
356
346
|
}
|
|
357
347
|
};
|
|
@@ -435,14 +425,11 @@ Session.prototype._verifyExpiration = function (end_time) {
|
|
|
435
425
|
*/
|
|
436
426
|
Session.prototype._checkSessionId = async function (session_id, client_ip, client_ua) {
|
|
437
427
|
try {
|
|
438
|
-
// 解码session_id
|
|
439
428
|
var data = this._helper.parseId(this.config.encrypt_key, session_id, client_ua);
|
|
440
429
|
if (!data) return false;
|
|
441
430
|
let { ip, end_time } = data;
|
|
442
|
-
// 验证IP
|
|
443
431
|
if (ip !== client_ip) return false;
|
|
444
432
|
|
|
445
|
-
// 验证时效性
|
|
446
433
|
var is_expired = this._verifyExpiration(end_time);
|
|
447
434
|
if (is_expired) {
|
|
448
435
|
if (this.config.expired_handling !== 'allow') {
|
|
@@ -450,7 +437,6 @@ Session.prototype._checkSessionId = async function (session_id, client_ip, clien
|
|
|
450
437
|
}
|
|
451
438
|
}
|
|
452
439
|
|
|
453
|
-
// 所有验证通过
|
|
454
440
|
return true;
|
|
455
441
|
} catch (err) {
|
|
456
442
|
$.log.debug('Session ID验证错误:', err);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mm_session",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.2",
|
|
4
4
|
"description": "这是超级美眉session函数模块,用于web服务端session缓存",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
},
|
|
31
31
|
"homepage": "https://gitee.com/qiuwenwu91/mm_session#readme",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"mm_cache": "^1.5.
|
|
33
|
+
"mm_cache": "^1.5.2"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"eslint-plugin-jsdoc": "^
|
|
36
|
+
"eslint-plugin-jsdoc": "^64.0.1",
|
|
37
37
|
"mm_eslint": "^1.7.5"
|
|
38
38
|
}
|
|
39
39
|
}
|