@faasjs/http 0.0.2-beta.37 → 0.0.2-beta.370

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/index.d.ts DELETED
@@ -1,94 +0,0 @@
1
- import { Plugin, InvokeData, MountData, DeployData, Next } from '@faasjs/func';
2
- import { Cookie, CookieOptions } from './cookie';
3
- import { Session, SessionOptions } from './session';
4
- import { Validator, ValidatorOptions, ValidatorRuleOptions } from './validator';
5
- export { Cookie, CookieOptions, Session, SessionOptions, Validator, ValidatorOptions, ValidatorRuleOptions };
6
- export declare const ContentType: {
7
- [key: string]: string;
8
- };
9
- export interface HttpConfig {
10
- [key: string]: any;
11
- name?: string;
12
- config?: {
13
- [key: string]: any;
14
- method?: string;
15
- timeout?: number;
16
- functionName?: string;
17
- cookie?: CookieOptions;
18
- };
19
- validator?: {
20
- params?: ValidatorOptions;
21
- cookie?: ValidatorOptions;
22
- session?: ValidatorOptions;
23
- };
24
- }
25
- export interface Response {
26
- statusCode?: number;
27
- headers: {
28
- [key: string]: any;
29
- };
30
- body?: string;
31
- }
32
- export declare class Http implements Plugin {
33
- readonly type: string;
34
- name?: string;
35
- headers: {
36
- [key: string]: string;
37
- };
38
- params: any;
39
- cookie: Cookie;
40
- session: Session;
41
- config: HttpConfig;
42
- private validatorOptions?;
43
- private response?;
44
- private validator?;
45
- private logger;
46
- /**
47
- * 创建 Http 插件实例
48
- * @param config {object} 配置项
49
- * @param config.name {string} 配置名
50
- * @param config.config {object} 网关配置
51
- * @param config.config.method {string} 请求方法,默认为 POST
52
- * @param config.config.path {string} 请求路径
53
- * @param config.config.cookie {object} Cookie 配置
54
- * @param config.validator {object} 入参校验配置
55
- * @param config.validator.params {object} params 校验配置
56
- * @param config.validator.params.whitelist {string} 白名单配置
57
- * @param config.validator.params.onError {function} 自定义报错
58
- * @param config.validator.params.rules {object} 参数校验规则
59
- * @param config.validator.cookie {object} cookie 校验配置
60
- * @param config.validator.cookie.whitelist {string} 白名单配置
61
- * @param config.validator.cookie.onError {function} 自定义报错
62
- * @param config.validator.cookie.rules {object} 参数校验规则
63
- * @param config.validator.session {object} session 校验配置
64
- * @param config.validator.session.whitelist {string} 白名单配置
65
- * @param config.validator.session.onError {function} 自定义报错
66
- * @param config.validator.session.rules {object} 参数校验规则
67
- */
68
- constructor(config?: HttpConfig);
69
- onDeploy(data: DeployData, next: Next): Promise<void>;
70
- onMount(data: MountData, next: Next): Promise<void>;
71
- onInvoke(data: InvokeData, next: Next): Promise<void>;
72
- /**
73
- * 设置 header
74
- * @param key {string} key
75
- * @param value {*} value
76
- */
77
- setHeader(key: string, value: any): Http;
78
- /**
79
- * 设置 Content-Type
80
- * @param type {string} 类型
81
- * @param charset {string} 编码
82
- */
83
- setContentType(type: string, charset?: string): Http;
84
- /**
85
- * 设置状态码
86
- * @param code {number} 状态码
87
- */
88
- setStatusCode(code: number): Http;
89
- /**
90
- * 设置 body
91
- * @param body {*} 内容
92
- */
93
- setBody(body: string): Http;
94
- }
package/lib/index.es.js DELETED
@@ -1,514 +0,0 @@
1
- import deepMerge from '@faasjs/deep_merge';
2
- import Logger from '@faasjs/logger';
3
- import { randomBytes, pbkdf2Sync, createCipheriv, createHmac, createDecipheriv } from 'crypto';
4
-
5
- class Session {
6
- constructor(cookie, config) {
7
- this.cookie = cookie;
8
- this.config = Object.assign({
9
- key: 'key',
10
- secret: randomBytes(128).toString('hex'),
11
- salt: 'salt',
12
- signedSalt: 'signedSalt',
13
- keylen: 64,
14
- iterations: 100,
15
- digest: 'sha256',
16
- cipherName: 'aes-256-cbc'
17
- }, config);
18
- this.secret = pbkdf2Sync(this.config.secret, this.config.salt, this.config.iterations, this.config.keylen / 2, this.config.digest);
19
- this.signedSecret = pbkdf2Sync(this.config.secret, this.config.signedSalt, this.config.iterations, this.config.keylen, this.config.digest);
20
- this.content = Object.create(null);
21
- }
22
- invoke(cookie) {
23
- try {
24
- this.content = cookie ? this.decode(cookie) : Object.create(null);
25
- }
26
- catch (error) {
27
- console.error(error);
28
- this.content = Object.create(null);
29
- }
30
- this.changed = false;
31
- }
32
- encode(text) {
33
- if (typeof text !== 'string') {
34
- text = JSON.stringify(text);
35
- }
36
- const iv = randomBytes(16);
37
- const cipher = createCipheriv(this.config.cipherName, this.secret, iv);
38
- const encrypted = Buffer.concat([cipher.update(text), cipher.final()]).toString('base64');
39
- const main = Buffer.from([encrypted, iv.toString('base64')].join('--')).toString('base64');
40
- const hmac = createHmac(this.config.digest, this.signedSecret);
41
- hmac.update(main);
42
- const digest = hmac.digest('hex');
43
- return main + '--' + digest;
44
- }
45
- decode(text) {
46
- text = decodeURIComponent(text);
47
- const signedParts = text.split('--');
48
- const hmac = createHmac(this.config.digest, this.signedSecret);
49
- hmac.update(signedParts[0]);
50
- const digest = hmac.digest('hex');
51
- if (signedParts[1] !== digest) {
52
- throw Error('Not valid');
53
- }
54
- const message = Buffer.from(signedParts[0], 'base64').toString();
55
- const parts = message.split('--').map(function (part) {
56
- return Buffer.from(part, 'base64');
57
- });
58
- const cipher = createDecipheriv(this.config.cipherName, this.secret, parts[1]);
59
- const part = Buffer.from(cipher.update(parts[0])).toString('utf8');
60
- const final = cipher.final('utf8');
61
- const decryptor = [part, final].join('');
62
- return JSON.parse(decryptor);
63
- }
64
- read(key) {
65
- return this.content[key];
66
- }
67
- write(key, value) {
68
- if (value === null || typeof value === 'undefined') {
69
- delete this.content[key];
70
- }
71
- else {
72
- this.content[key] = value;
73
- }
74
- this.changed = true;
75
- return this;
76
- }
77
- update() {
78
- if (this.changed) {
79
- this.cookie.write(this.config.key, this.encode(JSON.stringify(this.content)));
80
- }
81
- return this;
82
- }
83
- }
84
-
85
- class Cookie {
86
- constructor(config) {
87
- this.config = deepMerge({
88
- path: '/',
89
- expires: 31536000,
90
- secure: true,
91
- httpOnly: true,
92
- session: {}
93
- }, config);
94
- this.session = new Session(this, this.config.session);
95
- this.content = Object.create(null);
96
- this.setCookie = Object.create(null);
97
- }
98
- invoke(cookie) {
99
- this.content = Object.create(null);
100
- // 解析 cookie
101
- if (cookie) {
102
- cookie.split(';').map((x) => {
103
- x = x.trim();
104
- const k = x.match(/([^=]+)/);
105
- if (k !== null) {
106
- this.content[k[0]] = decodeURIComponent(x.replace(`${k[0]}=`, '').replace(/;$/, ''));
107
- }
108
- });
109
- }
110
- this.setCookie = Object.create(null);
111
- // 预读取 session
112
- this.session.invoke(this.read(this.session.config.key));
113
- return this;
114
- }
115
- read(key) {
116
- return this.content[key];
117
- }
118
- write(key, value, opts) {
119
- opts = Object.assign(this.config, opts || {});
120
- let cookie;
121
- if (value === null || typeof value === 'undefined') {
122
- opts.expires = 'Thu, 01 Jan 1970 00:00:01 GMT';
123
- cookie = `${key}=;`;
124
- delete this.content[key];
125
- }
126
- else {
127
- cookie = `${key}=${encodeURIComponent(value)};`;
128
- this.content[key] = value;
129
- }
130
- if (typeof opts.expires === 'number') {
131
- cookie += `max-age=${opts.expires};`;
132
- }
133
- else if (typeof opts.expires === 'string') {
134
- cookie += `expires=${opts.expires};`;
135
- }
136
- cookie += `path=${opts.path || '/'};`;
137
- if (opts.domain) {
138
- cookie += `domain=${opts.domain};`;
139
- }
140
- if (opts.secure) {
141
- cookie += 'Secure;';
142
- }
143
- if (opts.httpOnly) {
144
- cookie += 'HttpOnly;';
145
- }
146
- if (opts.sameSite) {
147
- cookie += `SameSite=${opts.sameSite};`;
148
- }
149
- this.setCookie[key] = cookie;
150
- return this;
151
- }
152
- headers() {
153
- if (!Object.keys(this.setCookie).length) {
154
- return {};
155
- }
156
- else {
157
- return {
158
- 'Set-Cookie': Object.values(this.setCookie)
159
- };
160
- }
161
- }
162
- }
163
-
164
- class ValidError extends Error {
165
- constructor({ statusCode, headers, message }) {
166
- super(message);
167
- this.statusCode = statusCode || 500;
168
- this.headers = headers || Object.create(null);
169
- }
170
- }
171
- class Validator {
172
- constructor(config) {
173
- this.paramsConfig = config.params;
174
- this.cookieConfig = config.cookie;
175
- this.sessionConfig = config.session;
176
- this.logger = new Logger('Http.Validator');
177
- }
178
- valid({ params, cookie, session }) {
179
- this.request = {
180
- params,
181
- cookie,
182
- session
183
- };
184
- this.logger.debug('Begin');
185
- if (this.paramsConfig) {
186
- this.logger.debug('Valid params');
187
- this.validContent('params', params, '', this.paramsConfig);
188
- }
189
- if (this.cookieConfig) {
190
- this.logger.debug('Valid cookie');
191
- if (!cookie) {
192
- throw Error('Not found Cookie');
193
- }
194
- this.validContent('cookie', cookie.content, '', this.cookieConfig);
195
- }
196
- if (this.sessionConfig) {
197
- this.logger.debug('Valid Session');
198
- if (!session) {
199
- throw Error('Not found Session');
200
- }
201
- this.validContent('session', session.content, '', this.sessionConfig);
202
- }
203
- }
204
- validContent(type, params, baseKey, config) {
205
- if (config.whitelist) {
206
- const paramsKeys = Object.keys(params);
207
- const rulesKeys = Object.keys(config.rules);
208
- const diff = paramsKeys.filter(k => !rulesKeys.includes(k));
209
- if (diff.length) {
210
- if (config.whitelist === 'error') {
211
- const diffKeys = diff.map(k => `${baseKey}${k}`);
212
- const error = Error(`[${type}] Unpermitted keys: ${diffKeys.join(', ')}`);
213
- if (config.onError) {
214
- const res = config.onError(`${type}.whitelist`, baseKey, diffKeys);
215
- if (res) {
216
- throw new ValidError(res);
217
- }
218
- }
219
- throw error;
220
- }
221
- else if (config.whitelist === 'ignore') {
222
- for (const key of diff) {
223
- delete params[key];
224
- }
225
- }
226
- }
227
- }
228
- for (const key in config.rules) {
229
- const rule = config.rules[key];
230
- let value = params[key];
231
- // default
232
- if (rule.default) {
233
- if (type === 'cookie' || type === 'session') {
234
- this.logger.warn('Cookie and Session not support default rule.');
235
- }
236
- else if (typeof value === 'undefined' && rule.default) {
237
- value = typeof rule.default === 'function' ? rule.default(this.request) : rule.default;
238
- params[key] = value;
239
- }
240
- }
241
- // required
242
- if (rule.required === true) {
243
- if (typeof value === 'undefined' || value === null) {
244
- const error = Error(`[${type}] ${baseKey}${key} is required.`);
245
- if (config.onError) {
246
- const res = config.onError(`${type}.rule.required`, `${baseKey}${key}`, value);
247
- if (res) {
248
- throw new ValidError(res);
249
- }
250
- }
251
- throw error;
252
- }
253
- }
254
- if (typeof value !== 'undefined' && value !== null) {
255
- // type
256
- if (rule.type) {
257
- if (type === 'cookie') {
258
- this.logger.warn('Cookie not support type rule');
259
- }
260
- else {
261
- let typed = true;
262
- switch (rule.type) {
263
- case 'array':
264
- typed = Array.isArray(value);
265
- break;
266
- case 'object':
267
- typed = Object.prototype.toString.call(value) === '[object Object]';
268
- break;
269
- default:
270
- typed = typeof value === rule.type;
271
- break;
272
- }
273
- if (!typed) {
274
- const error = Error(`[${type}] ${baseKey}${key} must be a ${rule.type}.`);
275
- if (config.onError) {
276
- const res = config.onError(`${type}.rule.type`, `${baseKey}${key}`, value);
277
- if (res) {
278
- throw new ValidError(res);
279
- }
280
- }
281
- throw error;
282
- }
283
- }
284
- }
285
- // in
286
- if (rule.in && !rule.in.includes(value)) {
287
- const error = Error(`[${type}] ${baseKey}${key} must be in ${rule.in.join(', ')}.`);
288
- if (config.onError) {
289
- const res = config.onError(`${type}.rule.in`, `${baseKey}${key}`, value);
290
- if (res) {
291
- throw new ValidError(res);
292
- }
293
- }
294
- throw error;
295
- }
296
- // nest config
297
- if (rule.config) {
298
- if (type === 'cookie') {
299
- this.logger.warn('Cookie not support nest rule.');
300
- }
301
- else {
302
- if (Array.isArray(value)) {
303
- // array
304
- for (const val of value) {
305
- this.validContent(type, val, (baseKey ? `${baseKey}.${key}.` : `${key}.`), rule.config);
306
- }
307
- }
308
- else if (typeof value === 'object') {
309
- // object
310
- this.validContent(type, value, (baseKey ? `${baseKey}.${key}.` : `${key}.`), rule.config);
311
- }
312
- }
313
- }
314
- }
315
- }
316
- }
317
- }
318
-
319
- const ContentType = {
320
- plain: 'text/plain',
321
- html: 'text/html',
322
- xml: 'application/xml',
323
- csv: 'text/csv',
324
- css: 'text/css',
325
- javascript: 'application/javascript',
326
- json: 'application/json',
327
- jsonp: 'application/javascript'
328
- };
329
- class Http {
330
- /**
331
- * 创建 Http 插件实例
332
- * @param config {object} 配置项
333
- * @param config.name {string} 配置名
334
- * @param config.config {object} 网关配置
335
- * @param config.config.method {string} 请求方法,默认为 POST
336
- * @param config.config.path {string} 请求路径
337
- * @param config.config.cookie {object} Cookie 配置
338
- * @param config.validator {object} 入参校验配置
339
- * @param config.validator.params {object} params 校验配置
340
- * @param config.validator.params.whitelist {string} 白名单配置
341
- * @param config.validator.params.onError {function} 自定义报错
342
- * @param config.validator.params.rules {object} 参数校验规则
343
- * @param config.validator.cookie {object} cookie 校验配置
344
- * @param config.validator.cookie.whitelist {string} 白名单配置
345
- * @param config.validator.cookie.onError {function} 自定义报错
346
- * @param config.validator.cookie.rules {object} 参数校验规则
347
- * @param config.validator.session {object} session 校验配置
348
- * @param config.validator.session.whitelist {string} 白名单配置
349
- * @param config.validator.session.onError {function} 自定义报错
350
- * @param config.validator.session.rules {object} 参数校验规则
351
- */
352
- constructor(config = Object.create(null)) {
353
- this.logger = new Logger('Http');
354
- this.type = 'http';
355
- this.name = config.name;
356
- this.config = config.config || Object.create(null);
357
- if (config.validator)
358
- this.validatorOptions = config.validator;
359
- this.headers = Object.create(null);
360
- this.cookie = new Cookie(this.config.cookie || {});
361
- this.session = this.cookie.session;
362
- }
363
- async onDeploy(data, next) {
364
- await next();
365
- this.logger.debug('[Http] 组装网关配置');
366
- this.logger.debug('%o', data);
367
- const config = deepMerge(data.config.plugins[this.name || this.type], { config: this.config });
368
- // 根据文件及文件夹名生成路径
369
- if (!config.config.path)
370
- config.config.path = '=/' + data.name.replace(/_/g, '/').replace(/\/index$/, '');
371
- this.logger.debug('[Http] 组装完成 %o', config);
372
- // 引用服务商部署插件
373
- // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
374
- const Provider = require(config.provider.type);
375
- const provider = new Provider(config.provider.config);
376
- // 部署网关
377
- await provider.deploy(this.type, data, config);
378
- }
379
- async onMount(data, next) {
380
- this.logger.debug('[onMount] merge config');
381
- if (data.config.plugins[this.name || this.type])
382
- this.config = deepMerge(this.config, data.config.plugins[this.name || this.type].config);
383
- this.logger.debug('[onMount] prepare cookie & session');
384
- this.cookie = new Cookie(this.config.cookie || {});
385
- this.session = this.cookie.session;
386
- if (this.validatorOptions) {
387
- this.logger.debug('[onMount] prepare validator');
388
- this.validator = new Validator(this.validatorOptions);
389
- }
390
- await next();
391
- }
392
- async onInvoke(data, next) {
393
- this.logger.debug('[onInvoke] Parse & valid');
394
- this.logger.time('http');
395
- this.headers = data.event.headers || Object.create(null);
396
- this.params = Object.create(null);
397
- this.response = { headers: Object.create(null) };
398
- if (data.event.body)
399
- if (data.event.headers && data.event.headers['content-type'] && data.event.headers['content-type'].includes('application/json')) {
400
- this.logger.debug('[onInvoke] Parse params from json body');
401
- this.params = JSON.parse(data.event.body);
402
- }
403
- else {
404
- this.logger.debug('[onInvoke] Parse params from raw body');
405
- this.params = data.event.body;
406
- }
407
- else if (data.event.queryString) {
408
- this.logger.debug('[onInvoke] Parse params from queryString');
409
- this.params = data.event.queryString;
410
- }
411
- this.logger.debug('[onInvoke] Parse cookie');
412
- this.cookie.invoke(this.headers['cookie']);
413
- this.logger.debug('[onInvoke] Cookie: %o', this.cookie.content);
414
- this.logger.debug('[onInvoke] Session: %o', this.session.content);
415
- if (this.validator) {
416
- this.logger.debug('[onInvoke] Valid request');
417
- try {
418
- this.validator.valid({
419
- params: this.params,
420
- cookie: this.cookie,
421
- session: this.session
422
- });
423
- }
424
- catch (error) {
425
- this.logger.error(error);
426
- data.response = {
427
- statusCode: error.statusCode || 500,
428
- headers: Object.assign({
429
- 'Content-Type': 'application/json; charset=utf-8',
430
- 'X-Request-Id': data.context.request_id
431
- }, error.headers || {}),
432
- body: JSON.stringify({ error: { message: error.message } })
433
- };
434
- return;
435
- }
436
- }
437
- this.logger.timeEnd('http', '[onInvoke] Parse & valid done');
438
- try {
439
- await next();
440
- }
441
- catch (error) {
442
- data.response = error;
443
- }
444
- this.logger.debug('[onInvoke] Generate response');
445
- this.logger.time('http');
446
- // update seesion
447
- this.session.update();
448
- // 处理 body
449
- if (data.response)
450
- if (data.response instanceof Error || (data.response.constructor && data.response.constructor.name === 'Error')) {
451
- // 当结果是错误类型时
452
- this.logger.error(data.response);
453
- this.response.body = JSON.stringify({ error: { message: data.response.message } });
454
- this.response.statusCode = 500;
455
- }
456
- else if (Object.prototype.toString.call(data.response) === '[object Object]' && data.response.statusCode && data.response.headers) {
457
- // 当返回结果是响应结构体时
458
- this.response = data.response;
459
- }
460
- else {
461
- this.response.body = JSON.stringify({ data: data.response });
462
- }
463
- // 处理 statusCode
464
- if (!this.response.statusCode)
465
- this.response.statusCode = this.response.body ? 200 : 201;
466
- // 处理 headers
467
- this.response.headers = Object.assign({
468
- 'Content-Type': 'application/json; charset=utf-8',
469
- 'X-Request-Id': new Date().getTime().toString()
470
- }, this.cookie.headers(), this.response.headers);
471
- /* eslint-disable-next-line require-atomic-updates */
472
- data.response = this.response;
473
- this.logger.timeEnd('http', '[onInvoke] done');
474
- }
475
- /**
476
- * 设置 header
477
- * @param key {string} key
478
- * @param value {*} value
479
- */
480
- setHeader(key, value) {
481
- this.response.headers[key] = value;
482
- return this;
483
- }
484
- /**
485
- * 设置 Content-Type
486
- * @param type {string} 类型
487
- * @param charset {string} 编码
488
- */
489
- setContentType(type, charset = 'utf-8') {
490
- if (ContentType[type])
491
- this.setHeader('Content-Type', `${ContentType[type]}; charset=${charset}`);
492
- else
493
- this.setHeader('Content-Type', `${type}; charset=${charset}`);
494
- return this;
495
- }
496
- /**
497
- * 设置状态码
498
- * @param code {number} 状态码
499
- */
500
- setStatusCode(code) {
501
- this.response.statusCode = code;
502
- return this;
503
- }
504
- /**
505
- * 设置 body
506
- * @param body {*} 内容
507
- */
508
- setBody(body) {
509
- this.response.body = body;
510
- return this;
511
- }
512
- }
513
-
514
- export { ContentType, Cookie, Http, Session, Validator };