-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
204 lines (176 loc) · 5.39 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
"use strict";
/**
* LtpaToken generator and verifier
*/
let crypto = require("crypto");
let iconv = require('iconv-lite');
let ltpaSecrets;
// 默认过期时间为43200秒(12小时)
let validity = 43200;
// 过期后的这个时间内仍然有效,默认300秒(5分钟)
let gracePeriod = 300;
/***
* 设置过期时间,秒
* 默认为43200秒(12小时)
* @param {number} seconds 秒
*/
function setValidity(seconds) {
validity = seconds;
}
/***
* 设置一个时间,当有效期过了的这段时间内仍然有效
* 校验token的时候也会把这个时间计算进去
* 默认为300秒()
* @param {number} seconds 秒
*/
function setGracePeriod(seconds) {
gracePeriod = seconds;
}
/***
* 设置秘钥
* @param {string} secrets 秘钥
*/
function setSecrets(secrets) {
ltpaSecrets = secrets;
}
/***
* Generate a userName Buffer. Currently hardcoded to CP-850, but the
* true char encoding is LMBCS
* @param {string} userName The username to be converted to a CP-850 buffer
* @returns {buffer} Username encoded in CP-850 and stuffed into a Buffer
*/
function generateUserNameBuf(userName) {
return iconv.encode(userName, "ibm850");
};
/***
* Generate an LtpaToken suitable for writing to a cookie
* @param {buffer} userName The username for whom the cookie is signed
* @param {number} timeStart Timestamp (seconds) for when the token validity should start. Default: now
* @returns {string} The LtpaToken encoded as Base64
*/
function generate(userNameBuf, secret, timeStart) {
let start = timeStart ? timeStart : Math.floor(Date.now() / 1000);
let timeCreation = (start - gracePeriod).toString(16);
let timeExpiration = (start + validity + gracePeriod).toString(16);
let size = userNameBuf.length + 40;
let ltpaToken = new Buffer(size);
ltpaToken.write("00010203", "hex");
ltpaToken.write(timeCreation, 4);
ltpaToken.write(timeExpiration, 12);
userNameBuf.copy(ltpaToken, 20);
let serverSecret = secret || ltpaSecrets;
ltpaToken.write(serverSecret, size - 20, "base64");
let hash = crypto.createHash("sha1");
hash.update(ltpaToken);
// Paranoid overwrite of the server secret
ltpaToken.write("0123456789abcdefghij", size - 20, "utf-8");
// Append the token hash
ltpaToken.write(hash.digest("hex"), size - 20, "hex");
return ltpaToken.toString("base64");
};
/***
* 校验token过期时间、用户身份
* @param {string} token
* @param {string} secret 可选,秘钥
* @return {object}
*/
function validate(token, secret) {
let ltpaToken;
ltpaToken = new Buffer(token, "base64");
if (ltpaToken.length < 41) {
// userName must be at least one character long
return {
code: -1,
data: 'token too short'
}
}
let signature = ltpaToken.toString("hex", ltpaToken.length - 20);
let serverSecret = secret || ltpaSecrets;
ltpaToken.write(serverSecret, ltpaToken.length - 20, "base64");
let hash = crypto.createHash("sha1");
hash.update(ltpaToken);
let hexDigest = hash.digest("hex");
if (hexDigest !== signature) {
return {
code: -2,
data: 'token 签名错误'
}
}
let version = ltpaToken.toString("hex", 0, 4);
if (version !== "00010203") {
console.log(version);
return {
code: -3,
data: `${version}不正确`
}
}
let timeCreation = parseInt(ltpaToken.toString("utf8", 4, 12), 16);
let timeExpiration = parseInt(ltpaToken.toString("utf8", 12, 20), 16);
let now = Math.floor(Date.now() / 1000);
if (timeCreation > (now + gracePeriod)) {
return {
code: -4,
data: 'token创建时间不正确'
}
}
if ((timeCreation + validity) < (now - gracePeriod)) {
return {
code: -5,
data: 'token时间过期'
}
}
return {
code: 0,
data: getUserName(token)
}
};
/***
* Retrieve the username from the token. No validation of the token takes place
* @param {string} token The LtpaToken string in Base64 encoded format
* @returns {buffer} Buffer containing the encoded username
*/
function getUserNameBuf(token) {
let ltpaToken = new Buffer(token, "base64");
return (ltpaToken.slice(20, ltpaToken.length - 20));
};
/***
* Retrieve the username from the token as a string. No validation of the token takes place
* @returns {string} Username as a UTF-8 string
*/
function getUserName(token) {
return iconv.decode(getUserNameBuf(token), "ibm850");
};
/**
* 刷新token
* @param {string} token
* @param {string} secret 可选,秘钥
* @return {string} base64的token
*/
function refresh(token, secret) {
if (!token) {
return
}
return generateToken(getUserNameBuf(token), secret);
}
/**
* 生成一个token
* @param {string} user 用户标识
* @param {string} secret 可选,秘钥
* @param {number} timeStart token的开始时间,默认为now
* @return {string} base64的token
*/
function generateToken(user, secret, timeStart) {
if (!user) {
return;
}
return generate(generateUserNameBuf(user), secret, timeStart);
}
let ltpa = module.exports;
ltpa.refresh = refresh;
ltpa.generate = generateToken;
ltpa.validate = validate;
ltpa.init = function (options) {
setValidity(options.validity || validity);
setGracePeriod(options.gracePeriod || gracePeriod);
setSecrets(options.secret);
}