@eggjs/jsonp 3.0.0 → 4.0.0-beta.17

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.
Files changed (55) hide show
  1. package/README.md +2 -6
  2. package/dist/app/extend/application.d.ts +14 -0
  3. package/dist/app/extend/application.js +83 -0
  4. package/dist/app/extend/context.d.ts +25 -0
  5. package/dist/app/extend/context.js +34 -0
  6. package/dist/config/config.default.d.ts +24 -0
  7. package/dist/config/config.default.js +10 -0
  8. package/dist/error/JSONPForbiddenReferrerError.d.ts +8 -0
  9. package/dist/error/JSONPForbiddenReferrerError.js +15 -0
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.js +1 -0
  12. package/dist/lib/private_key.d.ts +4 -0
  13. package/dist/lib/private_key.js +5 -0
  14. package/dist/types.d.ts +35 -0
  15. package/dist/types.js +1 -0
  16. package/package.json +39 -61
  17. package/dist/commonjs/app/extend/application.d.ts +0 -10
  18. package/dist/commonjs/app/extend/application.js +0 -115
  19. package/dist/commonjs/app/extend/context.d.ts +0 -15
  20. package/dist/commonjs/app/extend/context.js +0 -35
  21. package/dist/commonjs/config/config.default.d.ts +0 -5
  22. package/dist/commonjs/config/config.default.js +0 -11
  23. package/dist/commonjs/error/JSONPForbiddenReferrerError.d.ts +0 -5
  24. package/dist/commonjs/error/JSONPForbiddenReferrerError.js +0 -16
  25. package/dist/commonjs/index.d.ts +0 -1
  26. package/dist/commonjs/index.js +0 -4
  27. package/dist/commonjs/lib/private_key.d.ts +0 -1
  28. package/dist/commonjs/lib/private_key.js +0 -5
  29. package/dist/commonjs/package.json +0 -3
  30. package/dist/commonjs/types.d.ts +0 -50
  31. package/dist/commonjs/types.js +0 -3
  32. package/dist/esm/app/extend/application.d.ts +0 -10
  33. package/dist/esm/app/extend/application.js +0 -112
  34. package/dist/esm/app/extend/context.d.ts +0 -15
  35. package/dist/esm/app/extend/context.js +0 -32
  36. package/dist/esm/config/config.default.d.ts +0 -5
  37. package/dist/esm/config/config.default.js +0 -9
  38. package/dist/esm/error/JSONPForbiddenReferrerError.d.ts +0 -5
  39. package/dist/esm/error/JSONPForbiddenReferrerError.js +0 -12
  40. package/dist/esm/index.d.ts +0 -1
  41. package/dist/esm/index.js +0 -2
  42. package/dist/esm/lib/private_key.d.ts +0 -1
  43. package/dist/esm/lib/private_key.js +0 -2
  44. package/dist/esm/package.json +0 -3
  45. package/dist/esm/types.d.ts +0 -50
  46. package/dist/esm/types.js +0 -2
  47. package/dist/package.json +0 -4
  48. package/src/app/extend/application.ts +0 -131
  49. package/src/app/extend/context.ts +0 -34
  50. package/src/config/config.default.ts +0 -10
  51. package/src/error/JSONPForbiddenReferrerError.ts +0 -12
  52. package/src/index.ts +0 -1
  53. package/src/lib/private_key.ts +0 -1
  54. package/src/types.ts +0 -55
  55. package/src/typings/index.d.ts +0 -4
@@ -1,16 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.JSONPForbiddenReferrerError = void 0;
4
- class JSONPForbiddenReferrerError extends Error {
5
- referrer;
6
- status;
7
- constructor(message, referrer, status) {
8
- super(message);
9
- this.name = this.constructor.name;
10
- this.referrer = referrer;
11
- this.status = status;
12
- Error.captureStackTrace(this, this.constructor);
13
- }
14
- }
15
- exports.JSONPForbiddenReferrerError = JSONPForbiddenReferrerError;
16
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSlNPTlBGb3JiaWRkZW5SZWZlcnJlckVycm9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2Vycm9yL0pTT05QRm9yYmlkZGVuUmVmZXJyZXJFcnJvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxNQUFhLDJCQUE0QixTQUFRLEtBQUs7SUFDcEQsUUFBUSxDQUFTO0lBQ2pCLE1BQU0sQ0FBUztJQUVmLFlBQVksT0FBZSxFQUFFLFFBQWdCLEVBQUUsTUFBYztRQUMzRCxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDO1FBQ2xDLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ2xELENBQUM7Q0FDRjtBQVhELGtFQVdDIn0=
@@ -1 +0,0 @@
1
- import './types.js';
@@ -1,4 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- require("./types.js");
4
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxzQkFBb0IifQ==
@@ -1 +0,0 @@
1
- export declare const JSONP_CONFIG: unique symbol;
@@ -1,5 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.JSONP_CONFIG = void 0;
4
- exports.JSONP_CONFIG = Symbol('jsonp#config');
5
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJpdmF0ZV9rZXkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3ByaXZhdGVfa2V5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFhLFFBQUEsWUFBWSxHQUFHLE1BQU0sQ0FBQyxjQUFjLENBQUMsQ0FBQyJ9
@@ -1,3 +0,0 @@
1
- {
2
- "type": "commonjs"
3
- }
@@ -1,50 +0,0 @@
1
- import type { MiddlewareFunc } from '@eggjs/core';
2
- /**
3
- * jsonp options
4
- * @member Config#jsonp
5
- */
6
- export interface JSONPConfig {
7
- /**
8
- * jsonp callback methods key, default to `['_callback', 'callback' ]`
9
- */
10
- callback: string[] | string;
11
- /**
12
- * callback method name's max length, default to `50`
13
- */
14
- limit: number;
15
- /**
16
- * enable csrf check or not, default to `false`
17
- */
18
- csrf: boolean;
19
- /**
20
- * referrer white list, default to `undefined`
21
- */
22
- whiteList?: string | RegExp | (string | RegExp)[];
23
- }
24
- declare module '@eggjs/core' {
25
- interface EggAppConfig {
26
- jsonp: JSONPConfig;
27
- }
28
- interface Context {
29
- /**
30
- * detect if response should be jsonp
31
- */
32
- acceptJSONP: boolean;
33
- /**
34
- * JSONP wrap body function
35
- * Set jsonp response wrap function, other plugin can use it.
36
- * If not necessary, please don't use this method in your application code.
37
- * @param {Object} body response body
38
- * @private
39
- */
40
- createJsonpBody(body: any): void;
41
- }
42
- interface EggCore {
43
- /**
44
- * return a middleware to enable jsonp response.
45
- * will do some security check inside.
46
- * @public
47
- */
48
- jsonp(initOptions?: Partial<JSONPConfig>): MiddlewareFunc;
49
- }
50
- }
@@ -1,3 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9
@@ -1,10 +0,0 @@
1
- import { EggCore, type MiddlewareFunc } from '@eggjs/core';
2
- import { JSONPConfig } from '../../types.js';
3
- export default class JSONPApplication extends EggCore {
4
- /**
5
- * return a middleware to enable jsonp response.
6
- * will do some security check inside.
7
- * @public
8
- */
9
- jsonp(initOptions?: Partial<JSONPConfig>): MiddlewareFunc;
10
- }
@@ -1,112 +0,0 @@
1
- import { debuglog } from 'node:util';
2
- import { parse as urlParse } from 'node:url';
3
- import { EggCore } from '@eggjs/core';
4
- import { JSONP_CONFIG } from '../../lib/private_key.js';
5
- import { JSONPForbiddenReferrerError } from '../../error/JSONPForbiddenReferrerError.js';
6
- const debug = debuglog('@egg/jsonp/app/extend/application');
7
- export default class JSONPApplication extends EggCore {
8
- /**
9
- * return a middleware to enable jsonp response.
10
- * will do some security check inside.
11
- * @public
12
- */
13
- jsonp(initOptions = {}) {
14
- const options = {
15
- ...this.config.jsonp,
16
- ...initOptions,
17
- };
18
- if (!Array.isArray(options.callback)) {
19
- options.callback = [options.callback];
20
- }
21
- const csrfEnable = this.plugins.security && this.plugins.security.enable // security enable
22
- && this.config.security.csrf && this.config.security.csrf.enable !== false // csrf enable
23
- && options.csrf; // jsonp csrf enabled
24
- const validateReferrer = options.whiteList && createValidateReferer(options.whiteList);
25
- if (!csrfEnable && !validateReferrer) {
26
- this.coreLogger.warn('[@eggjs/jsonp] SECURITY WARNING!! csrf check and referrer check are both closed!');
27
- }
28
- /**
29
- * jsonp request security check, pass if
30
- *
31
- * 1. hit referrer white list
32
- * 2. or pass csrf check
33
- * 3. both check are disabled
34
- *
35
- * @param {Context} ctx request context
36
- */
37
- function securityAssert(ctx) {
38
- // all disabled. don't need check
39
- if (!csrfEnable && !validateReferrer)
40
- return;
41
- // pass referrer check
42
- const referrer = ctx.get('referrer');
43
- if (validateReferrer && validateReferrer(referrer))
44
- return;
45
- if (csrfEnable && validateCsrf(ctx))
46
- return;
47
- throw new JSONPForbiddenReferrerError('jsonp request security validate failed', referrer, 403);
48
- }
49
- return async function jsonp(ctx, next) {
50
- const jsonpFunction = getJsonpFunction(ctx.query, options.callback);
51
- ctx[JSONP_CONFIG] = {
52
- jsonpFunction,
53
- options,
54
- };
55
- // before handle request, must do some security checks
56
- securityAssert(ctx);
57
- await next();
58
- // generate jsonp body
59
- ctx.createJsonpBody(ctx.body);
60
- };
61
- }
62
- }
63
- function createValidateReferer(whiteList) {
64
- if (!Array.isArray(whiteList)) {
65
- whiteList = [whiteList];
66
- }
67
- return (referrer) => {
68
- let parsed;
69
- for (const rule of whiteList) {
70
- if (rule instanceof RegExp) {
71
- if (rule.test(referrer)) {
72
- // regexp(/^https?:\/\/github.com\//): test the referrer with rule
73
- return true;
74
- }
75
- continue;
76
- }
77
- parsed = parsed ?? urlParse(referrer);
78
- const hostname = parsed.hostname || '';
79
- // check if referrer's hostname match the string rule
80
- if (rule[0] === '.' &&
81
- (hostname.endsWith(rule) || hostname === rule.slice(1))) {
82
- // string start with `.`(.github.com): referrer's hostname must ends with rule
83
- return true;
84
- }
85
- else if (hostname === rule) {
86
- // string not start with `.`(github.com): referrer's hostname must strict equal to rule
87
- return true;
88
- }
89
- }
90
- // no rule matched
91
- return false;
92
- };
93
- }
94
- function validateCsrf(ctx) {
95
- try {
96
- // TODO(fengmk2): remove this when @eggjs/security support ctx.assertCsrf type define
97
- ctx.assertCsrf();
98
- return true;
99
- }
100
- catch (err) {
101
- debug('validate csrf failed: %s', err);
102
- return false;
103
- }
104
- }
105
- function getJsonpFunction(query, callbacks) {
106
- for (const callback of callbacks) {
107
- if (query[callback]) {
108
- return query[callback];
109
- }
110
- }
111
- }
112
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwbGljYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvYXBwL2V4dGVuZC9hcHBsaWNhdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ3JDLE9BQU8sRUFBRSxLQUFLLElBQUksUUFBUSxFQUEyQixNQUFNLFVBQVUsQ0FBQztBQUV0RSxPQUFPLEVBQUUsT0FBTyxFQUF1QixNQUFNLGFBQWEsQ0FBQztBQUMzRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFeEQsT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFHekYsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLG1DQUFtQyxDQUFDLENBQUM7QUFFNUQsTUFBTSxDQUFDLE9BQU8sT0FBTyxnQkFBaUIsU0FBUSxPQUFPO0lBQ25EOzs7O09BSUc7SUFDSCxLQUFLLENBQUMsY0FBb0MsRUFBRTtRQUMxQyxNQUFNLE9BQU8sR0FBRztZQUNkLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLO1lBQ3BCLEdBQUcsV0FBVztTQUN5QixDQUFDO1FBQzFDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQ3JDLE9BQU8sQ0FBQyxRQUFRLEdBQUcsQ0FBRSxPQUFPLENBQUMsUUFBUSxDQUFFLENBQUM7UUFDMUMsQ0FBQztRQUVELE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxrQkFBa0I7ZUFDdEYsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBSSxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxNQUFNLEtBQUssS0FBSyxD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
@@ -1,15 +0,0 @@
1
- import { Context } from '@eggjs/core';
2
- export default class JSONPContext extends Context {
3
- /**
4
- * detect if response should be jsonp
5
- */
6
- get acceptJSONP(): boolean;
7
- /**
8
- * JSONP wrap body function
9
- * Set jsonp response wrap function, other plugin can use it.
10
- * If not necessary, please don't use this method in your application code.
11
- * @param {Object} body response body
12
- * @private
13
- */
14
- createJsonpBody(body: any): void;
15
- }
@@ -1,32 +0,0 @@
1
- import { jsonp as jsonpBody } from 'jsonp-body';
2
- import { Context } from '@eggjs/core';
3
- import { JSONP_CONFIG } from '../../lib/private_key.js';
4
- export default class JSONPContext extends Context {
5
- /**
6
- * detect if response should be jsonp
7
- */
8
- get acceptJSONP() {
9
- const jsonpConfig = Reflect.get(this, JSONP_CONFIG);
10
- return !!(jsonpConfig?.jsonpFunction);
11
- }
12
- /**
13
- * JSONP wrap body function
14
- * Set jsonp response wrap function, other plugin can use it.
15
- * If not necessary, please don't use this method in your application code.
16
- * @param {Object} body response body
17
- * @private
18
- */
19
- createJsonpBody(body) {
20
- const jsonpConfig = Reflect.get(this, JSONP_CONFIG);
21
- if (!jsonpConfig?.jsonpFunction) {
22
- this.body = body;
23
- return;
24
- }
25
- this.set('x-content-type-options', 'nosniff');
26
- this.type = 'js';
27
- body = body === undefined ? null : body;
28
- // protect from jsonp xss
29
- this.body = jsonpBody(body, jsonpConfig.jsonpFunction, jsonpConfig.options);
30
- }
31
- }
32
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGV4dC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9hcHAvZXh0ZW5kL2NvbnRleHQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLEtBQUssSUFBSSxTQUFTLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDaEQsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN0QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFeEQsTUFBTSxDQUFDLE9BQU8sT0FBTyxZQUFhLFNBQVEsT0FBTztJQUMvQzs7T0FFRztJQUNILElBQUksV0FBVztRQUNiLE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLFlBQVksQ0FBUSxDQUFDO1FBQzNELE9BQU8sQ0FBQyxDQUFDLENBQUMsV0FBVyxFQUFFLGFBQWEsQ0FBQyxDQUFDO0lBQ3hDLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSCxlQUFlLENBQUMsSUFBUztRQUN2QixNQUFNLFdBQVcsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxZQUFZLENBQVEsQ0FBQztRQUMzRCxJQUFJLENBQUMsV0FBVyxFQUFFLGFBQWEsRUFBRSxDQUFDO1lBQ2hDLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO1lBQ2pCLE9BQU87UUFDVCxDQUFDO1FBRUQsSUFBSSxDQUFDLEdBQUcsQ0FBQyx3QkFBd0IsRUFBRSxTQUFTLENBQUMsQ0FBQztRQUM5QyxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztRQUNqQixJQUFJLEdBQUcsSUFBSSxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7UUFDeEMseUJBQXlCO1FBQ3pCLElBQUksQ0FBQyxJQUFJLEdBQUcsU0FBUyxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsYUFBYSxFQUFFLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUM5RSxDQUFDO0NBQ0YifQ==
@@ -1,5 +0,0 @@
1
- import type { JSONPConfig } from '../types.js';
2
- declare const _default: {
3
- jsonp: JSONPConfig;
4
- };
5
- export default _default;
@@ -1,9 +0,0 @@
1
- export default {
2
- jsonp: {
3
- limit: 50,
4
- callback: ['_callback', 'callback'],
5
- csrf: false,
6
- whiteList: undefined,
7
- },
8
- };
9
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmRlZmF1bHQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY29uZmlnL2NvbmZpZy5kZWZhdWx0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLGVBQWU7SUFDYixLQUFLLEVBQUU7UUFDTCxLQUFLLEVBQUUsRUFBRTtRQUNULFFBQVEsRUFBRSxDQUFFLFdBQVcsRUFBRSxVQUFVLENBQUU7UUFDckMsSUFBSSxFQUFFLEtBQUs7UUFDWCxTQUFTLEVBQUUsU0FBUztLQUNOO0NBQ2pCLENBQUMifQ==
@@ -1,5 +0,0 @@
1
- export declare class JSONPForbiddenReferrerError extends Error {
2
- referrer: string;
3
- status: number;
4
- constructor(message: string, referrer: string, status: number);
5
- }
@@ -1,12 +0,0 @@
1
- export class JSONPForbiddenReferrerError extends Error {
2
- referrer;
3
- status;
4
- constructor(message, referrer, status) {
5
- super(message);
6
- this.name = this.constructor.name;
7
- this.referrer = referrer;
8
- this.status = status;
9
- Error.captureStackTrace(this, this.constructor);
10
- }
11
- }
12
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSlNPTlBGb3JiaWRkZW5SZWZlcnJlckVycm9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2Vycm9yL0pTT05QRm9yYmlkZGVuUmVmZXJyZXJFcnJvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxNQUFNLE9BQU8sMkJBQTRCLFNBQVEsS0FBSztJQUNwRCxRQUFRLENBQVM7SUFDakIsTUFBTSxDQUFTO0lBRWYsWUFBWSxPQUFlLEVBQUUsUUFBZ0IsRUFBRSxNQUFjO1FBQzNELEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNmLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUM7UUFDbEMsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7UUFDekIsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsS0FBSyxDQUFDLGlCQUFpQixDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDbEQsQ0FBQztDQUNGIn0=
@@ -1 +0,0 @@
1
- import './types.js';
package/dist/esm/index.js DELETED
@@ -1,2 +0,0 @@
1
- import './types.js';
2
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxZQUFZLENBQUMifQ==
@@ -1 +0,0 @@
1
- export declare const JSONP_CONFIG: unique symbol;
@@ -1,2 +0,0 @@
1
- export const JSONP_CONFIG = Symbol('jsonp#config');
2
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJpdmF0ZV9rZXkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3ByaXZhdGVfa2V5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBRyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUMifQ==
@@ -1,3 +0,0 @@
1
- {
2
- "type": "module"
3
- }
@@ -1,50 +0,0 @@
1
- import type { MiddlewareFunc } from '@eggjs/core';
2
- /**
3
- * jsonp options
4
- * @member Config#jsonp
5
- */
6
- export interface JSONPConfig {
7
- /**
8
- * jsonp callback methods key, default to `['_callback', 'callback' ]`
9
- */
10
- callback: string[] | string;
11
- /**
12
- * callback method name's max length, default to `50`
13
- */
14
- limit: number;
15
- /**
16
- * enable csrf check or not, default to `false`
17
- */
18
- csrf: boolean;
19
- /**
20
- * referrer white list, default to `undefined`
21
- */
22
- whiteList?: string | RegExp | (string | RegExp)[];
23
- }
24
- declare module '@eggjs/core' {
25
- interface EggAppConfig {
26
- jsonp: JSONPConfig;
27
- }
28
- interface Context {
29
- /**
30
- * detect if response should be jsonp
31
- */
32
- acceptJSONP: boolean;
33
- /**
34
- * JSONP wrap body function
35
- * Set jsonp response wrap function, other plugin can use it.
36
- * If not necessary, please don't use this method in your application code.
37
- * @param {Object} body response body
38
- * @private
39
- */
40
- createJsonpBody(body: any): void;
41
- }
42
- interface EggCore {
43
- /**
44
- * return a middleware to enable jsonp response.
45
- * will do some security check inside.
46
- * @public
47
- */
48
- jsonp(initOptions?: Partial<JSONPConfig>): MiddlewareFunc;
49
- }
50
- }
package/dist/esm/types.js DELETED
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9
package/dist/package.json DELETED
@@ -1,4 +0,0 @@
1
- {
2
- "name": "@eggjs/jsonp",
3
- "version": "3.0.0"
4
- }
@@ -1,131 +0,0 @@
1
- import { debuglog } from 'node:util';
2
- import { parse as urlParse, type UrlWithStringQuery } from 'node:url';
3
- import type { ParsedUrlQuery } from 'node:querystring';
4
- import { EggCore, type MiddlewareFunc } from '@eggjs/core';
5
- import { JSONP_CONFIG } from '../../lib/private_key.js';
6
- import { JSONPConfig } from '../../types.js';
7
- import { JSONPForbiddenReferrerError } from '../../error/JSONPForbiddenReferrerError.js';
8
- import JSONPContext from './context.js';
9
-
10
- const debug = debuglog('@egg/jsonp/app/extend/application');
11
-
12
- export default class JSONPApplication extends EggCore {
13
- /**
14
- * return a middleware to enable jsonp response.
15
- * will do some security check inside.
16
- * @public
17
- */
18
- jsonp(initOptions: Partial<JSONPConfig> = {}): MiddlewareFunc {
19
- const options = {
20
- ...this.config.jsonp,
21
- ...initOptions,
22
- } as JSONPConfig & { callback: string[] };
23
- if (!Array.isArray(options.callback)) {
24
- options.callback = [ options.callback ];
25
- }
26
-
27
- const csrfEnable = this.plugins.security && this.plugins.security.enable // security enable
28
- && this.config.security.csrf && this.config.security.csrf.enable !== false // csrf enable
29
- && options.csrf; // jsonp csrf enabled
30
-
31
- const validateReferrer = options.whiteList && createValidateReferer(options.whiteList);
32
-
33
- if (!csrfEnable && !validateReferrer) {
34
- this.coreLogger.warn('[@eggjs/jsonp] SECURITY WARNING!! csrf check and referrer check are both closed!');
35
- }
36
- /**
37
- * jsonp request security check, pass if
38
- *
39
- * 1. hit referrer white list
40
- * 2. or pass csrf check
41
- * 3. both check are disabled
42
- *
43
- * @param {Context} ctx request context
44
- */
45
- function securityAssert(ctx: JSONPContext) {
46
- // all disabled. don't need check
47
- if (!csrfEnable && !validateReferrer) return;
48
-
49
- // pass referrer check
50
- const referrer = ctx.get<string>('referrer');
51
- if (validateReferrer && validateReferrer(referrer)) return;
52
- if (csrfEnable && validateCsrf(ctx)) return;
53
-
54
- throw new JSONPForbiddenReferrerError(
55
- 'jsonp request security validate failed',
56
- referrer,
57
- 403);
58
- }
59
-
60
- return async function jsonp(ctx: JSONPContext, next) {
61
- const jsonpFunction = getJsonpFunction(ctx.query, options.callback);
62
-
63
- ctx[JSONP_CONFIG] = {
64
- jsonpFunction,
65
- options,
66
- };
67
-
68
- // before handle request, must do some security checks
69
- securityAssert(ctx);
70
-
71
- await next();
72
-
73
- // generate jsonp body
74
- ctx.createJsonpBody(ctx.body);
75
- };
76
- }
77
- }
78
-
79
- function createValidateReferer(whiteList: Required<JSONPConfig>['whiteList']) {
80
- if (!Array.isArray(whiteList)) {
81
- whiteList = [ whiteList ];
82
- }
83
-
84
- return (referrer: string) => {
85
- let parsed: UrlWithStringQuery | undefined;
86
- for (const rule of whiteList) {
87
- if (rule instanceof RegExp) {
88
- if (rule.test(referrer)) {
89
- // regexp(/^https?:\/\/github.com\//): test the referrer with rule
90
- return true;
91
- }
92
- continue;
93
- }
94
-
95
- parsed = parsed ?? urlParse(referrer);
96
- const hostname = parsed.hostname || '';
97
-
98
- // check if referrer's hostname match the string rule
99
- if (rule[0] === '.' &&
100
- (hostname.endsWith(rule) || hostname === rule.slice(1))) {
101
- // string start with `.`(.github.com): referrer's hostname must ends with rule
102
- return true;
103
- } else if (hostname === rule) {
104
- // string not start with `.`(github.com): referrer's hostname must strict equal to rule
105
- return true;
106
- }
107
- }
108
-
109
- // no rule matched
110
- return false;
111
- };
112
- }
113
-
114
- function validateCsrf(ctx: any) {
115
- try {
116
- // TODO(fengmk2): remove this when @eggjs/security support ctx.assertCsrf type define
117
- ctx.assertCsrf();
118
- return true;
119
- } catch (err) {
120
- debug('validate csrf failed: %s', err);
121
- return false;
122
- }
123
- }
124
-
125
- function getJsonpFunction(query: ParsedUrlQuery, callbacks: string[]) {
126
- for (const callback of callbacks) {
127
- if (query[callback]) {
128
- return query[callback] as string;
129
- }
130
- }
131
- }
@@ -1,34 +0,0 @@
1
- import { jsonp as jsonpBody } from 'jsonp-body';
2
- import { Context } from '@eggjs/core';
3
- import { JSONP_CONFIG } from '../../lib/private_key.js';
4
-
5
- export default class JSONPContext extends Context {
6
- /**
7
- * detect if response should be jsonp
8
- */
9
- get acceptJSONP() {
10
- const jsonpConfig = Reflect.get(this, JSONP_CONFIG) as any;
11
- return !!(jsonpConfig?.jsonpFunction);
12
- }
13
-
14
- /**
15
- * JSONP wrap body function
16
- * Set jsonp response wrap function, other plugin can use it.
17
- * If not necessary, please don't use this method in your application code.
18
- * @param {Object} body response body
19
- * @private
20
- */
21
- createJsonpBody(body: any) {
22
- const jsonpConfig = Reflect.get(this, JSONP_CONFIG) as any;
23
- if (!jsonpConfig?.jsonpFunction) {
24
- this.body = body;
25
- return;
26
- }
27
-
28
- this.set('x-content-type-options', 'nosniff');
29
- this.type = 'js';
30
- body = body === undefined ? null : body;
31
- // protect from jsonp xss
32
- this.body = jsonpBody(body, jsonpConfig.jsonpFunction, jsonpConfig.options);
33
- }
34
- }
@@ -1,10 +0,0 @@
1
- import type { JSONPConfig } from '../types.js';
2
-
3
- export default {
4
- jsonp: {
5
- limit: 50,
6
- callback: [ '_callback', 'callback' ],
7
- csrf: false,
8
- whiteList: undefined,
9
- } as JSONPConfig,
10
- };
@@ -1,12 +0,0 @@
1
- export class JSONPForbiddenReferrerError extends Error {
2
- referrer: string;
3
- status: number;
4
-
5
- constructor(message: string, referrer: string, status: number) {
6
- super(message);
7
- this.name = this.constructor.name;
8
- this.referrer = referrer;
9
- this.status = status;
10
- Error.captureStackTrace(this, this.constructor);
11
- }
12
- }
package/src/index.ts DELETED
@@ -1 +0,0 @@
1
- import './types.js';
@@ -1 +0,0 @@
1
- export const JSONP_CONFIG = Symbol('jsonp#config');
package/src/types.ts DELETED
@@ -1,55 +0,0 @@
1
- import type { MiddlewareFunc } from '@eggjs/core';
2
-
3
- /**
4
- * jsonp options
5
- * @member Config#jsonp
6
- */
7
- export interface JSONPConfig {
8
- /**
9
- * jsonp callback methods key, default to `['_callback', 'callback' ]`
10
- */
11
- callback: string[] | string;
12
- /**
13
- * callback method name's max length, default to `50`
14
- */
15
- limit: number;
16
- /**
17
- * enable csrf check or not, default to `false`
18
- */
19
- csrf: boolean;
20
- /**
21
- * referrer white list, default to `undefined`
22
- */
23
- whiteList?: string | RegExp | (string | RegExp)[];
24
- }
25
-
26
- declare module '@eggjs/core' {
27
- // add EggAppConfig overrides types
28
- interface EggAppConfig {
29
- jsonp: JSONPConfig;
30
- }
31
-
32
- interface Context {
33
- /**
34
- * detect if response should be jsonp
35
- */
36
- acceptJSONP: boolean;
37
- /**
38
- * JSONP wrap body function
39
- * Set jsonp response wrap function, other plugin can use it.
40
- * If not necessary, please don't use this method in your application code.
41
- * @param {Object} body response body
42
- * @private
43
- */
44
- createJsonpBody(body: any): void;
45
- }
46
-
47
- interface EggCore {
48
- /**
49
- * return a middleware to enable jsonp response.
50
- * will do some security check inside.
51
- * @public
52
- */
53
- jsonp(initOptions?: Partial<JSONPConfig>): MiddlewareFunc;
54
- }
55
- }
@@ -1,4 +0,0 @@
1
- // make sure to import egg typings and let typescript know about it
2
- // @see https://github.com/whxaxes/blog/issues/11
3
- // and https://www.typescriptlang.org/docs/handbook/declaration-merging.html
4
- import 'egg';