@jayfong/x-server 2.12.14 → 2.12.16
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/_cjs/cli/api_generator.js +20 -54
- package/lib/_cjs/cli/build_util.js +16 -45
- package/lib/_cjs/cli/cli.js +17 -29
- package/lib/_cjs/cli/deploy_util.js +0 -12
- package/lib/_cjs/cli/dev_util.js +18 -0
- package/lib/_cjs/cli/env_util.js +16 -49
- package/lib/_cjs/cli/{register.js → esbuild_register.js} +0 -1
- package/lib/_cjs/cli/template_util.js +26 -29
- package/lib/_cjs/core/define_bus.js +9 -6
- package/lib/_cjs/core/define_cron.js +0 -2
- package/lib/_cjs/core/define_handler.js +10 -12
- package/lib/_cjs/core/define_hook.js +0 -2
- package/lib/_cjs/core/define_server.js +0 -2
- package/lib/_cjs/core/define_task.js +7 -13
- package/lib/_cjs/core/get_handler_url.js +1 -2
- package/lib/_cjs/core/handler.js +8 -29
- package/lib/_cjs/core/http_error.js +0 -3
- package/lib/_cjs/core/http_header.js +8 -12
- package/lib/_cjs/core/server.js +8 -41
- package/lib/_cjs/core/types.js +0 -7
- package/lib/_cjs/index.js +0 -72
- package/lib/_cjs/plugins/cors.js +0 -7
- package/lib/_cjs/plugins/file_parser.js +2 -9
- package/lib/_cjs/plugins/form_body_parser.js +0 -6
- package/lib/_cjs/plugins/ws_parser.js +0 -6
- package/lib/_cjs/plugins/xml_parser.js +0 -12
- package/lib/_cjs/services/cache.js +18 -58
- package/lib/_cjs/services/captcha.js +0 -14
- package/lib/_cjs/services/dingtalk.js +0 -14
- package/lib/_cjs/services/dispose.js +0 -9
- package/lib/_cjs/services/emoji.js +2 -5
- package/lib/_cjs/services/jwt.js +0 -21
- package/lib/_cjs/services/log.js +0 -17
- package/lib/_cjs/services/mail.js +0 -9
- package/lib/_cjs/services/pay.js +9 -40
- package/lib/_cjs/services/rate_limit.js +0 -12
- package/lib/_cjs/services/redis.js +0 -4
- package/lib/_cjs/services/request.js +0 -5
- package/lib/_cjs/services/sensitive_words.js +13 -19
- package/lib/_cjs/x.js +0 -11
- package/lib/cli/api_generator.js +20 -42
- package/lib/cli/build_util.js +16 -19
- package/lib/cli/cli.js +17 -14
- package/lib/cli/deploy_util.js +0 -4
- package/lib/cli/dev_util.d.ts +8 -0
- package/lib/cli/dev_util.js +12 -0
- package/lib/cli/env_util.js +16 -37
- package/lib/cli/template_util.d.ts +1 -0
- package/lib/cli/template_util.js +26 -14
- package/lib/core/define_bus.js +7 -5
- package/lib/core/define_handler.js +10 -9
- package/lib/core/define_task.js +7 -6
- package/lib/core/get_handler_url.js +2 -1
- package/lib/core/handler.js +9 -22
- package/lib/core/http_header.js +6 -9
- package/lib/core/server.js +8 -31
- package/lib/core/types.js +0 -7
- package/lib/index.js +4 -3
- package/lib/plugins/cors.js +0 -3
- package/lib/plugins/file_parser.js +2 -5
- package/lib/plugins/form_body_parser.js +0 -3
- package/lib/plugins/ws_parser.js +0 -3
- package/lib/plugins/xml_parser.js +0 -10
- package/lib/services/cache.js +18 -52
- package/lib/services/captcha.js +0 -7
- package/lib/services/dingtalk.js +0 -7
- package/lib/services/dispose.js +0 -5
- package/lib/services/emoji.js +2 -3
- package/lib/services/jwt.js +0 -13
- package/lib/services/log.js +0 -8
- package/lib/services/mail.js +0 -3
- package/lib/services/pay.js +9 -30
- package/lib/services/rate_limit.js +0 -8
- package/lib/services/redis.js +0 -1
- package/lib/services/request.js +0 -1
- package/lib/services/sensitive_words.js +13 -15
- package/package.json +3 -3
- /package/lib/cli/{register.d.ts → esbuild_register.d.ts} +0 -0
- /package/lib/cli/{register.js → esbuild_register.js} +0 -0
package/lib/services/cache.js
CHANGED
|
@@ -8,10 +8,10 @@ export class CacheService {
|
|
|
8
8
|
this.prefix = void 0;
|
|
9
9
|
this.prefix = `${x.appId}:`;
|
|
10
10
|
}
|
|
11
|
-
|
|
12
11
|
toRedisKey(key) {
|
|
13
12
|
return `${this.prefix}${Array.isArray(key) ? key.join('_') : String(key)}`;
|
|
14
13
|
}
|
|
14
|
+
|
|
15
15
|
/**
|
|
16
16
|
* 设置缓存内容。对象类内容尽量避免使用,以免造成问题。
|
|
17
17
|
*
|
|
@@ -20,68 +20,59 @@ export class CacheService {
|
|
|
20
20
|
* @param ttl 缓存时间
|
|
21
21
|
* @returns 返回设置的缓存内容
|
|
22
22
|
*/
|
|
23
|
-
|
|
24
|
-
|
|
25
23
|
async set(key, value, ttl = this.options.ttl) {
|
|
26
24
|
const redisTtl = typeof ttl === 'function' ? ttl(value, this.options.ttl) : ttl;
|
|
27
|
-
|
|
28
25
|
if (redisTtl) {
|
|
29
26
|
const redisKey = this.toRedisKey(key);
|
|
30
27
|
const redisValue = JSON.stringify(value);
|
|
31
|
-
await x.redis.set(redisKey, redisValue,
|
|
28
|
+
await x.redis.set(redisKey, redisValue,
|
|
29
|
+
// 毫秒
|
|
32
30
|
'PX', ms(redisTtl));
|
|
33
31
|
}
|
|
34
|
-
|
|
35
32
|
return value;
|
|
36
33
|
}
|
|
34
|
+
|
|
37
35
|
/**
|
|
38
36
|
* 存储值然后返回其对应的键,该键 URL 友好。
|
|
39
37
|
*
|
|
40
38
|
* @param value 值
|
|
41
39
|
* @param ttl 存活时间
|
|
42
40
|
*/
|
|
43
|
-
|
|
44
|
-
|
|
45
41
|
async save(value, ttl = this.options.ttl) {
|
|
46
42
|
const key = `X__${cuid()}`;
|
|
47
43
|
await this.set(key, typeof value === 'function' ? await value(key) : value, ttl);
|
|
48
44
|
return key;
|
|
49
45
|
}
|
|
46
|
+
|
|
50
47
|
/**
|
|
51
48
|
* 获取缓存内容。
|
|
52
49
|
*
|
|
53
50
|
* @param key 键
|
|
54
51
|
* @returns 返回获取到的缓存内容
|
|
55
52
|
*/
|
|
56
|
-
|
|
57
|
-
|
|
58
53
|
async get(key) {
|
|
59
54
|
const redisKey = this.toRedisKey(key);
|
|
60
55
|
const gotValue = await x.redis.get(redisKey);
|
|
61
|
-
|
|
62
56
|
if (gotValue) {
|
|
63
57
|
try {
|
|
64
58
|
return JSON.parse(gotValue);
|
|
65
59
|
} catch {}
|
|
66
60
|
}
|
|
67
|
-
|
|
68
61
|
return null;
|
|
69
62
|
}
|
|
63
|
+
|
|
70
64
|
/**
|
|
71
65
|
* 获取多个缓存内容。
|
|
72
66
|
*
|
|
73
67
|
* @param keys 键
|
|
74
68
|
* @returns 返回获取到的缓存内容
|
|
75
69
|
*/
|
|
76
|
-
|
|
77
|
-
|
|
78
70
|
async getMany(...keys) {
|
|
79
71
|
const redisKeys = keys.map(key => this.toRedisKey(key));
|
|
80
72
|
if (!redisKeys.length) return [];
|
|
81
73
|
const gotValues = await x.redis.mget(...redisKeys);
|
|
82
74
|
return gotValues.map(value => {
|
|
83
75
|
if (value == null) return null;
|
|
84
|
-
|
|
85
76
|
try {
|
|
86
77
|
return JSON.parse(value);
|
|
87
78
|
} catch {
|
|
@@ -89,18 +80,18 @@ export class CacheService {
|
|
|
89
80
|
}
|
|
90
81
|
});
|
|
91
82
|
}
|
|
83
|
+
|
|
92
84
|
/**
|
|
93
85
|
* 获取距离过期时间的毫秒数(未设置过期时间返回-1,键不存在返回-2)。
|
|
94
86
|
*
|
|
95
87
|
* @param key 键
|
|
96
88
|
* @returns 返回距离过期时间的毫秒数
|
|
97
89
|
*/
|
|
98
|
-
|
|
99
|
-
|
|
100
90
|
async ttl(key) {
|
|
101
91
|
const redisKey = this.toRedisKey(key);
|
|
102
92
|
return x.redis.pttl(redisKey);
|
|
103
93
|
}
|
|
94
|
+
|
|
104
95
|
/**
|
|
105
96
|
* 缓存内容。
|
|
106
97
|
*
|
|
@@ -109,30 +100,23 @@ export class CacheService {
|
|
|
109
100
|
* @param ttl 缓存时间
|
|
110
101
|
* @returns 返回获取到的内容
|
|
111
102
|
*/
|
|
112
|
-
|
|
113
|
-
|
|
114
103
|
async remember(key, action, ttl = this.options.ttl) {
|
|
115
104
|
let value = await this.get(key);
|
|
116
|
-
|
|
117
105
|
if (value === null) {
|
|
118
106
|
value = await action();
|
|
119
107
|
await this.set(key, value, ttl);
|
|
120
108
|
}
|
|
121
|
-
|
|
122
109
|
return value;
|
|
123
110
|
}
|
|
124
|
-
|
|
125
111
|
async rememberMany(raws, key, action, ttl = this.options.ttl) {
|
|
126
112
|
const keys = raws.map(key);
|
|
127
113
|
const values = await this.getMany(...keys);
|
|
128
114
|
const shouldUpdateIndexes = [];
|
|
129
|
-
|
|
130
115
|
for (let i = 0, len = values.length; i < len; i++) {
|
|
131
116
|
if (values[i] === null) {
|
|
132
117
|
shouldUpdateIndexes.push(i);
|
|
133
118
|
}
|
|
134
119
|
}
|
|
135
|
-
|
|
136
120
|
if (shouldUpdateIndexes.length) {
|
|
137
121
|
const nextValues = await action(shouldUpdateIndexes.map(i => raws[i]));
|
|
138
122
|
await Promise.all(nextValues.map(async (nextValue, index) => {
|
|
@@ -140,123 +124,105 @@ export class CacheService {
|
|
|
140
124
|
await this.set(keys[shouldUpdateIndexes[index]], nextValue, ttl);
|
|
141
125
|
}));
|
|
142
126
|
}
|
|
143
|
-
|
|
144
127
|
return values;
|
|
145
128
|
}
|
|
129
|
+
|
|
146
130
|
/**
|
|
147
131
|
* 自增。
|
|
148
132
|
*
|
|
149
133
|
* @param key 键
|
|
150
134
|
* @param increment 增量
|
|
151
135
|
*/
|
|
152
|
-
|
|
153
|
-
|
|
154
136
|
async increase(key, increment = 1) {
|
|
155
137
|
const redisKey = this.toRedisKey(key);
|
|
156
138
|
return x.redis.incrby(redisKey, increment);
|
|
157
139
|
}
|
|
140
|
+
|
|
158
141
|
/**
|
|
159
142
|
* 自减。
|
|
160
143
|
*
|
|
161
144
|
* @param key 键
|
|
162
145
|
* @param decrement 减量
|
|
163
146
|
*/
|
|
164
|
-
|
|
165
|
-
|
|
166
147
|
async decrease(key, decrement = 1) {
|
|
167
148
|
return this.increase(key, -decrement);
|
|
168
149
|
}
|
|
150
|
+
|
|
169
151
|
/**
|
|
170
152
|
* 新增元素。
|
|
171
153
|
*
|
|
172
154
|
* @param key 键
|
|
173
155
|
* @param values 元素列表
|
|
174
156
|
*/
|
|
175
|
-
|
|
176
|
-
|
|
177
157
|
async push(key, ...values) {
|
|
178
158
|
const redisKey = this.toRedisKey(key);
|
|
179
159
|
return x.redis.rpush(redisKey, ...values.map(value => JSON.stringify(value)));
|
|
180
160
|
}
|
|
161
|
+
|
|
181
162
|
/**
|
|
182
163
|
* 从头部弹出元素并返回。
|
|
183
164
|
*
|
|
184
165
|
* @param key 键
|
|
185
166
|
* @param count 弹出元素个数
|
|
186
167
|
*/
|
|
187
|
-
|
|
188
|
-
|
|
189
168
|
async shift(key, count = 1) {
|
|
190
169
|
const redisKey = this.toRedisKey(key);
|
|
191
170
|
const res = [];
|
|
192
|
-
|
|
193
171
|
for (let i = 0; i < count; i++) {
|
|
194
172
|
const item = await x.redis.lpop(redisKey);
|
|
195
|
-
|
|
196
173
|
if (item) {
|
|
197
174
|
res.push(JSON.parse(item));
|
|
198
175
|
} else {
|
|
199
176
|
break;
|
|
200
177
|
}
|
|
201
178
|
}
|
|
202
|
-
|
|
203
179
|
return res;
|
|
204
180
|
}
|
|
181
|
+
|
|
205
182
|
/**
|
|
206
183
|
* 删除缓存。
|
|
207
184
|
*
|
|
208
185
|
* @param keys 键列表
|
|
209
186
|
*/
|
|
210
|
-
|
|
211
|
-
|
|
212
187
|
async remove(...keys) {
|
|
213
188
|
if (!keys.length) {
|
|
214
189
|
return 0;
|
|
215
190
|
}
|
|
216
|
-
|
|
217
191
|
return x.redis.del(...keys.map(key => this.toRedisKey(key)));
|
|
218
192
|
}
|
|
193
|
+
|
|
219
194
|
/**
|
|
220
195
|
* 清空全部缓存。
|
|
221
196
|
*/
|
|
222
|
-
|
|
223
|
-
|
|
224
197
|
async clearAll() {
|
|
225
198
|
const keys = await x.redis.keys(`${this.prefix}*`);
|
|
226
|
-
|
|
227
199
|
if (keys.length) {
|
|
228
200
|
return x.redis.del(...keys);
|
|
229
201
|
}
|
|
230
|
-
|
|
231
202
|
return 0;
|
|
232
203
|
}
|
|
204
|
+
|
|
233
205
|
/**
|
|
234
206
|
* 清空指定前缀的缓存。
|
|
235
207
|
*/
|
|
236
|
-
|
|
237
|
-
|
|
238
208
|
async clear(...prefixes) {
|
|
239
209
|
if (!prefixes.length) {
|
|
240
210
|
return 0;
|
|
241
211
|
}
|
|
242
|
-
|
|
243
212
|
const keys = (await Promise.all(prefixes.map(prefix => x.redis.keys(`${this.toRedisKey(prefix)}*`)))).flat();
|
|
244
|
-
|
|
245
213
|
if (keys.length) {
|
|
246
214
|
return x.redis.del(...keys);
|
|
247
215
|
}
|
|
248
|
-
|
|
249
216
|
return 0;
|
|
250
217
|
}
|
|
218
|
+
|
|
251
219
|
/**
|
|
252
220
|
* 派生出一个指定类型的缓存服务。
|
|
253
221
|
*/
|
|
254
|
-
|
|
255
|
-
|
|
256
222
|
fork(options) {
|
|
257
|
-
return options ? new CacheService({
|
|
223
|
+
return options ? new CacheService({
|
|
224
|
+
...this.options,
|
|
258
225
|
...options
|
|
259
226
|
}) : this;
|
|
260
227
|
}
|
|
261
|
-
|
|
262
228
|
}
|
package/lib/services/captcha.js
CHANGED
|
@@ -6,7 +6,6 @@ export class CaptchaService {
|
|
|
6
6
|
this.options = options;
|
|
7
7
|
this.serviceName = 'captcha';
|
|
8
8
|
}
|
|
9
|
-
|
|
10
9
|
async generate(scene) {
|
|
11
10
|
const code = Math.random().toString().slice(0 - this.options.size);
|
|
12
11
|
const token = await x.cache.save({
|
|
@@ -18,7 +17,6 @@ export class CaptchaService {
|
|
|
18
17
|
code: code
|
|
19
18
|
};
|
|
20
19
|
}
|
|
21
|
-
|
|
22
20
|
async generateDataUrl(scene) {
|
|
23
21
|
const {
|
|
24
22
|
text: code,
|
|
@@ -37,20 +35,15 @@ export class CaptchaService {
|
|
|
37
35
|
dataUrl: dataUrl
|
|
38
36
|
};
|
|
39
37
|
}
|
|
40
|
-
|
|
41
38
|
async verify(options) {
|
|
42
39
|
if (options.code.length !== this.options.size) {
|
|
43
40
|
return false;
|
|
44
41
|
}
|
|
45
|
-
|
|
46
42
|
const expected = await x.cache.get(options.token);
|
|
47
|
-
|
|
48
43
|
if (expected == null) {
|
|
49
44
|
return false;
|
|
50
45
|
}
|
|
51
|
-
|
|
52
46
|
await x.cache.remove(options.token);
|
|
53
47
|
return expected.scene === options.scene && options.code.toLowerCase() === expected.code.toLowerCase();
|
|
54
48
|
}
|
|
55
|
-
|
|
56
49
|
}
|
package/lib/services/dingtalk.js
CHANGED
|
@@ -5,7 +5,6 @@ export class DingtalkService {
|
|
|
5
5
|
this.options = options;
|
|
6
6
|
this.serviceName = 'dingtalk';
|
|
7
7
|
}
|
|
8
|
-
|
|
9
8
|
async send(options) {
|
|
10
9
|
const timestamp = Date.now();
|
|
11
10
|
const sign = crypto.createHmac('sha256', this.options.secret).update(`${timestamp}\n${this.options.secret}`).digest('base64');
|
|
@@ -20,16 +19,13 @@ export class DingtalkService {
|
|
|
20
19
|
isAtAll: options.at === 'all'
|
|
21
20
|
}
|
|
22
21
|
};
|
|
23
|
-
|
|
24
22
|
if (!data.at.isAtAll && data.at.atMobiles.length) {
|
|
25
23
|
const atMobiles = data.at.atMobiles.filter(mobile => !data.markdown.text.includes(`@${mobile}`));
|
|
26
|
-
|
|
27
24
|
if (atMobiles.length) {
|
|
28
25
|
const atMobilesText = atMobiles.map(mobile => `@${mobile}`).join(' ');
|
|
29
26
|
data.markdown.text += `<!-- ${atMobilesText} -->`;
|
|
30
27
|
}
|
|
31
28
|
}
|
|
32
|
-
|
|
33
29
|
const {
|
|
34
30
|
body
|
|
35
31
|
} = await got.post('https://oapi.dingtalk.com/robot/send', {
|
|
@@ -41,12 +37,9 @@ export class DingtalkService {
|
|
|
41
37
|
},
|
|
42
38
|
json: data
|
|
43
39
|
});
|
|
44
|
-
|
|
45
40
|
if (body.errcode !== 0) {
|
|
46
41
|
throw new Error(body.errmsg);
|
|
47
42
|
}
|
|
48
|
-
|
|
49
43
|
return body;
|
|
50
44
|
}
|
|
51
|
-
|
|
52
45
|
}
|
package/lib/services/dispose.js
CHANGED
|
@@ -2,22 +2,17 @@ import onExit from 'exit-hook';
|
|
|
2
2
|
export class DisposeService {
|
|
3
3
|
constructor(options) {
|
|
4
4
|
var _this$options;
|
|
5
|
-
|
|
6
5
|
this.options = options;
|
|
7
6
|
this.serviceName = 'dispose';
|
|
8
7
|
this.disposes = [];
|
|
9
|
-
|
|
10
8
|
if ((_this$options = this.options) != null && _this$options.disposeOnExit) {
|
|
11
9
|
onExit(() => this.dispose());
|
|
12
10
|
}
|
|
13
11
|
}
|
|
14
|
-
|
|
15
12
|
add(fn) {
|
|
16
13
|
this.disposes.push(fn);
|
|
17
14
|
}
|
|
18
|
-
|
|
19
15
|
dispose() {
|
|
20
16
|
return Promise.all(this.disposes.map(dispose => dispose()));
|
|
21
17
|
}
|
|
22
|
-
|
|
23
18
|
}
|
package/lib/services/emoji.js
CHANGED
|
@@ -2015,16 +2015,15 @@ const softbankOrDocomoOrAuOrGoogleToUnified = {
|
|
|
2015
2015
|
"": "㊙️",
|
|
2016
2016
|
"": "㊙️",
|
|
2017
2017
|
"": "㊙️"
|
|
2018
|
-
};
|
|
2018
|
+
};
|
|
2019
|
+
// softbankOrDocomoOrAuOrGoogleToUnified
|
|
2019
2020
|
|
|
2020
2021
|
const softbankOrDocomoOrGoogleRegExp = new RegExp(Object.keys(softbankOrDocomoOrAuOrGoogleToUnified).join('|'), 'g');
|
|
2021
2022
|
export class EmojiService {
|
|
2022
2023
|
constructor() {
|
|
2023
2024
|
this.serviceName = 'emoji';
|
|
2024
2025
|
}
|
|
2025
|
-
|
|
2026
2026
|
unify(text) {
|
|
2027
2027
|
return text.replace(softbankOrDocomoOrGoogleRegExp, v => softbankOrDocomoOrAuOrGoogleToUnified[v]);
|
|
2028
2028
|
}
|
|
2029
|
-
|
|
2030
2029
|
}
|
package/lib/services/jwt.js
CHANGED
|
@@ -8,29 +8,23 @@ export class JwtService {
|
|
|
8
8
|
this.options = options;
|
|
9
9
|
this.serviceName = 'jwt';
|
|
10
10
|
this.cache = void 0;
|
|
11
|
-
|
|
12
11
|
if (options.cache) {
|
|
13
12
|
this.cache = new LRUCache(options.cache);
|
|
14
13
|
}
|
|
15
14
|
}
|
|
16
|
-
|
|
17
15
|
sign(payload, ttl = this.options.ttl) {
|
|
18
16
|
const token = jwt.sign(payload, this.options.secret, {
|
|
19
17
|
expiresIn: ms(ttl, true)
|
|
20
18
|
});
|
|
21
|
-
|
|
22
19
|
if (this.cache) {
|
|
23
20
|
this.cache.set(token, payload, {
|
|
24
21
|
ttl: ms(ttl)
|
|
25
22
|
});
|
|
26
23
|
}
|
|
27
|
-
|
|
28
24
|
return token;
|
|
29
25
|
}
|
|
30
|
-
|
|
31
26
|
async verify(token) {
|
|
32
27
|
var _this$options$onVerif, _this$options;
|
|
33
|
-
|
|
34
28
|
const data = await new Promise((resolve, reject) => {
|
|
35
29
|
if (this.cache && this.cache.has(token)) {
|
|
36
30
|
resolve(this.cache.get(token));
|
|
@@ -46,7 +40,6 @@ export class JwtService {
|
|
|
46
40
|
ttl: differenceInMilliseconds(fromUnixTime(data.exp), new Date())
|
|
47
41
|
});
|
|
48
42
|
}
|
|
49
|
-
|
|
50
43
|
resolve(data);
|
|
51
44
|
}
|
|
52
45
|
});
|
|
@@ -55,21 +48,15 @@ export class JwtService {
|
|
|
55
48
|
await ((_this$options$onVerif = (_this$options = this.options).onVerify) == null ? void 0 : _this$options$onVerif.call(_this$options, data));
|
|
56
49
|
return data;
|
|
57
50
|
}
|
|
58
|
-
|
|
59
51
|
async verifyFromHttpHeaders(headers) {
|
|
60
52
|
const authorization = headers.authorization || headers['sec-websocket-protocol'] && `Bearer ${headers['sec-websocket-protocol']}` || '';
|
|
61
|
-
|
|
62
53
|
if (!authorization) {
|
|
63
54
|
throw new HttpError.Unauthorized('header');
|
|
64
55
|
}
|
|
65
|
-
|
|
66
56
|
const [scheme, token] = authorization.split(' ');
|
|
67
|
-
|
|
68
57
|
if (scheme.toLowerCase() !== 'bearer') {
|
|
69
58
|
throw new HttpError.Unauthorized('bearer');
|
|
70
59
|
}
|
|
71
|
-
|
|
72
60
|
return this.verify(token);
|
|
73
61
|
}
|
|
74
|
-
|
|
75
62
|
}
|
package/lib/services/log.js
CHANGED
|
@@ -14,17 +14,14 @@ export class LogService {
|
|
|
14
14
|
});
|
|
15
15
|
}, logFile => logFile);
|
|
16
16
|
}
|
|
17
|
-
|
|
18
17
|
getLogFile(date) {
|
|
19
18
|
const year = date.getFullYear();
|
|
20
19
|
const month = date.getMonth() + 1;
|
|
21
20
|
return path.join(x.dataDir, `log/${year}/${month < 10 ? `0${month}` : month}.log`);
|
|
22
21
|
}
|
|
23
|
-
|
|
24
22
|
get logFile() {
|
|
25
23
|
return this.getLogFile(new Date());
|
|
26
24
|
}
|
|
27
|
-
|
|
28
25
|
parseLogLineText(text) {
|
|
29
26
|
const [time, level, title, ...desc] = text.split(this.separator);
|
|
30
27
|
return {
|
|
@@ -38,11 +35,9 @@ export class LogService {
|
|
|
38
35
|
}, {})
|
|
39
36
|
};
|
|
40
37
|
}
|
|
41
|
-
|
|
42
38
|
log(payload) {
|
|
43
39
|
this.getLogWriter(this.logFile).write(`${[formatDate(new Date(), 'yyyy-mm-dd hh:ii:ss'), payload.level, payload.title, ...Object.keys(payload.desc || {}).map(key => `${key}:${payload.desc[key]}`)].join(this.separator).replace(/[\r\n]+/g, ' ')}\n`);
|
|
44
40
|
}
|
|
45
|
-
|
|
46
41
|
info(title, desc) {
|
|
47
42
|
this.log({
|
|
48
43
|
level: 'info',
|
|
@@ -50,7 +45,6 @@ export class LogService {
|
|
|
50
45
|
desc
|
|
51
46
|
});
|
|
52
47
|
}
|
|
53
|
-
|
|
54
48
|
success(title, desc) {
|
|
55
49
|
this.log({
|
|
56
50
|
level: 'success',
|
|
@@ -58,7 +52,6 @@ export class LogService {
|
|
|
58
52
|
desc
|
|
59
53
|
});
|
|
60
54
|
}
|
|
61
|
-
|
|
62
55
|
error(title, desc) {
|
|
63
56
|
this.log({
|
|
64
57
|
level: 'error',
|
|
@@ -66,5 +59,4 @@ export class LogService {
|
|
|
66
59
|
desc
|
|
67
60
|
});
|
|
68
61
|
}
|
|
69
|
-
|
|
70
62
|
}
|
package/lib/services/mail.js
CHANGED
|
@@ -6,7 +6,6 @@ export class MailService {
|
|
|
6
6
|
this.serviceName = 'mail';
|
|
7
7
|
this.transporter = void 0;
|
|
8
8
|
}
|
|
9
|
-
|
|
10
9
|
async send(options) {
|
|
11
10
|
if (!this.transporter) {
|
|
12
11
|
this.transporter = nodemailer.createTransport({
|
|
@@ -21,8 +20,6 @@ export class MailService {
|
|
|
21
20
|
await this.transporter.verify();
|
|
22
21
|
x.dispose.add(() => this.transporter.close());
|
|
23
22
|
}
|
|
24
|
-
|
|
25
23
|
return this.transporter.sendMail(options);
|
|
26
24
|
}
|
|
27
|
-
|
|
28
25
|
}
|
package/lib/services/pay.js
CHANGED
|
@@ -9,7 +9,6 @@ export class PayService {
|
|
|
9
9
|
this.serviceName = 'pay';
|
|
10
10
|
this.alipaySdk = void 0;
|
|
11
11
|
}
|
|
12
|
-
|
|
13
12
|
async prepareAlipay(options) {
|
|
14
13
|
if (!this.alipaySdk) {
|
|
15
14
|
this.alipaySdk = new AlipaySdk({
|
|
@@ -18,15 +17,12 @@ export class PayService {
|
|
|
18
17
|
alipayPublicKey: this.options.alipay.publicKey
|
|
19
18
|
});
|
|
20
19
|
}
|
|
21
|
-
|
|
22
20
|
const formData = new AlipayFormData();
|
|
23
21
|
formData.setMethod('get');
|
|
24
22
|
formData.addField('notifyUrl', options.notifyUrl);
|
|
25
|
-
|
|
26
23
|
if (options.returnUrl) {
|
|
27
24
|
formData.addField('returnUrl', options.returnUrl);
|
|
28
25
|
}
|
|
29
|
-
|
|
30
26
|
formData.addField('bizContent', {
|
|
31
27
|
outTradeNo: options.tradeNumber,
|
|
32
28
|
productCode: 'FAST_INSTANT_TRADE_PAY',
|
|
@@ -42,7 +38,6 @@ export class PayService {
|
|
|
42
38
|
payUrl: payUrl
|
|
43
39
|
};
|
|
44
40
|
}
|
|
45
|
-
|
|
46
41
|
async prepareWepay(options) {
|
|
47
42
|
const appId = options.appId || this.options.wepay.appId;
|
|
48
43
|
const res = await this.wepayRequest('https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi', {
|
|
@@ -60,12 +55,10 @@ export class PayService {
|
|
|
60
55
|
openid: options.openid
|
|
61
56
|
}
|
|
62
57
|
});
|
|
63
|
-
|
|
64
58
|
if (!res || !res.prepay_id) {
|
|
65
59
|
const error = res && res.message || '支付错误';
|
|
66
60
|
throw new Error(error);
|
|
67
61
|
}
|
|
68
|
-
|
|
69
62
|
const params = {
|
|
70
63
|
appId: appId,
|
|
71
64
|
timestamp: String(Math.round(Date.now() / 1000)),
|
|
@@ -79,57 +72,47 @@ export class PayService {
|
|
|
79
72
|
payParams: params
|
|
80
73
|
};
|
|
81
74
|
}
|
|
82
|
-
|
|
83
75
|
verifyNotifyData(data) {
|
|
84
76
|
try {
|
|
85
77
|
if (!data || typeof data !== 'object') {
|
|
86
78
|
return false;
|
|
87
|
-
}
|
|
88
|
-
// https://opendocs.alipay.com/open/270/105902
|
|
89
|
-
|
|
79
|
+
}
|
|
90
80
|
|
|
81
|
+
// 支付宝
|
|
82
|
+
// https://opendocs.alipay.com/open/270/105902
|
|
91
83
|
if (data.passback_params === 'alipay') {
|
|
92
84
|
var _this$alipaySdk;
|
|
93
|
-
|
|
94
85
|
if (!((_this$alipaySdk = this.alipaySdk) != null && _this$alipaySdk.checkNotifySign(data))) {
|
|
95
86
|
return false;
|
|
96
87
|
}
|
|
97
|
-
|
|
98
88
|
return {
|
|
99
89
|
channelOrderNo: data.trade_no
|
|
100
90
|
};
|
|
101
|
-
}
|
|
102
|
-
// https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_5.shtml
|
|
103
|
-
|
|
91
|
+
}
|
|
104
92
|
|
|
93
|
+
// 微信支付
|
|
94
|
+
// https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_5.shtml
|
|
105
95
|
if (data.resource) {
|
|
106
96
|
const params = JSON.parse(this.wepayDecrypt(data.resource));
|
|
107
|
-
|
|
108
97
|
if (params.attach === 'wepay') {
|
|
109
98
|
return {
|
|
110
99
|
channelOrderNo: params.transaction_id
|
|
111
100
|
};
|
|
112
101
|
}
|
|
113
|
-
|
|
114
102
|
return false;
|
|
115
103
|
}
|
|
116
|
-
|
|
117
104
|
return false;
|
|
118
105
|
} catch {
|
|
119
106
|
return false;
|
|
120
107
|
}
|
|
121
108
|
}
|
|
122
|
-
|
|
123
109
|
verifyNotifyDataOrFail(data, message) {
|
|
124
110
|
const res = this.verifyNotifyData(data);
|
|
125
|
-
|
|
126
111
|
if (!res) {
|
|
127
112
|
throw new HttpError.BadRequest(message);
|
|
128
113
|
}
|
|
129
|
-
|
|
130
114
|
return res;
|
|
131
115
|
}
|
|
132
|
-
|
|
133
116
|
async getOrderInfo(payload) {
|
|
134
117
|
// 微信支付
|
|
135
118
|
// https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_2.shtml
|
|
@@ -140,10 +123,10 @@ export class PayService {
|
|
|
140
123
|
orderNo: res.out_trade_no,
|
|
141
124
|
status: res.trade_state === 'SUCCESS' ? 'success' : 'fail'
|
|
142
125
|
};
|
|
143
|
-
}
|
|
144
|
-
// https://opendocs.alipay.com/open/028woa?scene=common&pathHash=dbf247eb
|
|
145
|
-
|
|
126
|
+
}
|
|
146
127
|
|
|
128
|
+
// 支付宝
|
|
129
|
+
// https://opendocs.alipay.com/open/028woa?scene=common&pathHash=dbf247eb
|
|
147
130
|
const res = await this.alipaySdk.exec('alipay.trade.query', {
|
|
148
131
|
biz_content: payload.orderNo ? {
|
|
149
132
|
out_trade_no: payload.orderNo
|
|
@@ -157,11 +140,9 @@ export class PayService {
|
|
|
157
140
|
status: res.trade_status === 'TRADE_SUCCESS' || res.trade_status === 'TRADE_FINISHED' ? 'success' : 'fail'
|
|
158
141
|
};
|
|
159
142
|
}
|
|
160
|
-
|
|
161
143
|
wepaySign(data) {
|
|
162
144
|
return crypto.createSign('RSA-SHA256').update(data.map(v => `${v}\n`).join('')).sign(this.options.wepay.privateKey, 'base64');
|
|
163
145
|
}
|
|
164
|
-
|
|
165
146
|
wepayDecrypt(payload) {
|
|
166
147
|
const ciphertextBuffer = Buffer.from(payload.ciphertext, 'base64');
|
|
167
148
|
const authTag = ciphertextBuffer.slice(ciphertextBuffer.length - 16);
|
|
@@ -173,7 +154,6 @@ export class PayService {
|
|
|
173
154
|
decipherIv.final();
|
|
174
155
|
return decryptStr;
|
|
175
156
|
}
|
|
176
|
-
|
|
177
157
|
async wepayRequest(url, data) {
|
|
178
158
|
const path = url.replace(/^https?:\/\/[^/]+/, '');
|
|
179
159
|
const method = data == null ? 'GET' : 'POST';
|
|
@@ -204,5 +184,4 @@ export class PayService {
|
|
|
204
184
|
});
|
|
205
185
|
return res;
|
|
206
186
|
}
|
|
207
|
-
|
|
208
187
|
}
|
|
@@ -4,32 +4,24 @@ export class RateLimitService {
|
|
|
4
4
|
constructor() {
|
|
5
5
|
this.serviceName = 'rateLimit';
|
|
6
6
|
}
|
|
7
|
-
|
|
8
7
|
async limitByCount(options) {
|
|
9
8
|
const cacheKey = `rateLimit_${options.key}`;
|
|
10
9
|
const remainingCount = await x.cache.get(cacheKey);
|
|
11
|
-
|
|
12
10
|
if (remainingCount == null) {
|
|
13
11
|
await x.cache.set(cacheKey, options.count, options.ttl);
|
|
14
12
|
return options.count;
|
|
15
13
|
}
|
|
16
|
-
|
|
17
14
|
if (remainingCount === 0) {
|
|
18
15
|
return 0;
|
|
19
16
|
}
|
|
20
|
-
|
|
21
17
|
await x.cache.decrease(cacheKey);
|
|
22
18
|
return remainingCount - 1;
|
|
23
19
|
}
|
|
24
|
-
|
|
25
20
|
async limitByCountOrFail(options) {
|
|
26
21
|
const count = await this.limitByCount(options);
|
|
27
|
-
|
|
28
22
|
if (count === 0) {
|
|
29
23
|
throw new HttpError.Forbidden(options.message);
|
|
30
24
|
}
|
|
31
|
-
|
|
32
25
|
return count;
|
|
33
26
|
}
|
|
34
|
-
|
|
35
27
|
}
|
package/lib/services/redis.js
CHANGED