@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.
- package/README.md +2 -6
- package/dist/app/extend/application.d.ts +14 -0
- package/dist/app/extend/application.js +83 -0
- package/dist/app/extend/context.d.ts +25 -0
- package/dist/app/extend/context.js +34 -0
- package/dist/config/config.default.d.ts +24 -0
- package/dist/config/config.default.js +10 -0
- package/dist/error/JSONPForbiddenReferrerError.d.ts +8 -0
- package/dist/error/JSONPForbiddenReferrerError.js +15 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/private_key.d.ts +4 -0
- package/dist/lib/private_key.js +5 -0
- package/dist/types.d.ts +35 -0
- package/dist/types.js +1 -0
- package/package.json +39 -61
- package/dist/commonjs/app/extend/application.d.ts +0 -10
- package/dist/commonjs/app/extend/application.js +0 -115
- package/dist/commonjs/app/extend/context.d.ts +0 -15
- package/dist/commonjs/app/extend/context.js +0 -35
- package/dist/commonjs/config/config.default.d.ts +0 -5
- package/dist/commonjs/config/config.default.js +0 -11
- package/dist/commonjs/error/JSONPForbiddenReferrerError.d.ts +0 -5
- package/dist/commonjs/error/JSONPForbiddenReferrerError.js +0 -16
- package/dist/commonjs/index.d.ts +0 -1
- package/dist/commonjs/index.js +0 -4
- package/dist/commonjs/lib/private_key.d.ts +0 -1
- package/dist/commonjs/lib/private_key.js +0 -5
- package/dist/commonjs/package.json +0 -3
- package/dist/commonjs/types.d.ts +0 -50
- package/dist/commonjs/types.js +0 -3
- package/dist/esm/app/extend/application.d.ts +0 -10
- package/dist/esm/app/extend/application.js +0 -112
- package/dist/esm/app/extend/context.d.ts +0 -15
- package/dist/esm/app/extend/context.js +0 -32
- package/dist/esm/config/config.default.d.ts +0 -5
- package/dist/esm/config/config.default.js +0 -9
- package/dist/esm/error/JSONPForbiddenReferrerError.d.ts +0 -5
- package/dist/esm/error/JSONPForbiddenReferrerError.js +0 -12
- package/dist/esm/index.d.ts +0 -1
- package/dist/esm/index.js +0 -2
- package/dist/esm/lib/private_key.d.ts +0 -1
- package/dist/esm/lib/private_key.js +0 -2
- package/dist/esm/package.json +0 -3
- package/dist/esm/types.d.ts +0 -50
- package/dist/esm/types.js +0 -2
- package/dist/package.json +0 -4
- package/src/app/extend/application.ts +0 -131
- package/src/app/extend/context.ts +0 -34
- package/src/config/config.default.ts +0 -10
- package/src/error/JSONPForbiddenReferrerError.ts +0 -12
- package/src/index.ts +0 -1
- package/src/lib/private_key.ts +0 -1
- package/src/types.ts +0 -55
- package/src/typings/index.d.ts +0 -4
package/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# @eggjs/jsonp
|
|
2
2
|
|
|
3
3
|
[![NPM version][npm-image]][npm-url]
|
|
4
|
-
[](https://github.com/eggjs/jsonp/actions/workflows/nodejs.yml)
|
|
5
|
-
[![Test coverage][codecov-image]][codecov-url]
|
|
6
4
|
[![Known Vulnerabilities][snyk-image]][snyk-url]
|
|
7
5
|
[![npm download][download-image]][download-url]
|
|
8
6
|
[](https://nodejs.org/en/download/)
|
|
@@ -10,8 +8,6 @@
|
|
|
10
8
|
|
|
11
9
|
[npm-image]: https://img.shields.io/npm/v/@eggjs/jsonp.svg?style=flat-square
|
|
12
10
|
[npm-url]: https://npmjs.org/package/@eggjs/jsonp
|
|
13
|
-
[codecov-image]: https://img.shields.io/codecov/c/github/eggjs/jsonp.svg?style=flat-square
|
|
14
|
-
[codecov-url]: https://codecov.io/github/eggjs/jsonp?branch=master
|
|
15
11
|
[snyk-image]: https://snyk.io/test/npm/@eggjs/jsonp/badge.svg?style=flat-square
|
|
16
12
|
[snyk-url]: https://snyk.io/test/npm/@eggjs/jsonp
|
|
17
13
|
[download-image]: https://img.shields.io/npm/dm/@eggjs/jsonp.svg?style=flat-square
|
|
@@ -100,7 +96,7 @@ whiteList also can be an array:
|
|
|
100
96
|
```ts
|
|
101
97
|
export default {
|
|
102
98
|
jsonp: {
|
|
103
|
-
whiteList: [
|
|
99
|
+
whiteList: ['.foo.com', '.bar.com'],
|
|
104
100
|
},
|
|
105
101
|
};
|
|
106
102
|
```
|
|
@@ -136,6 +132,6 @@ Please open an issue [here](https://github.com/eggjs/egg/issues).
|
|
|
136
132
|
|
|
137
133
|
## Contributors
|
|
138
134
|
|
|
139
|
-
[](https://github.com/eggjs/egg/graphs/contributors)
|
|
140
136
|
|
|
141
137
|
Made with [contributors-img](https://contrib.rocks).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { JSONPConfig } from "../../config/config.default.js";
|
|
2
|
+
import { Application, MiddlewareFunc } from "egg";
|
|
3
|
+
|
|
4
|
+
//#region src/app/extend/application.d.ts
|
|
5
|
+
declare class JSONPApplication extends Application {
|
|
6
|
+
/**
|
|
7
|
+
* return a middleware to enable jsonp response.
|
|
8
|
+
* will do some security check inside.
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
11
|
+
jsonp(initOptions?: Partial<JSONPConfig>): MiddlewareFunc;
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { JSONPApplication as default };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { JSONPForbiddenReferrerError } from "../../error/JSONPForbiddenReferrerError.js";
|
|
2
|
+
import { JSONP_CONFIG } from "../../lib/private_key.js";
|
|
3
|
+
import "./context.js";
|
|
4
|
+
import { debuglog } from "node:util";
|
|
5
|
+
import { parse } from "node:url";
|
|
6
|
+
import { Application } from "egg";
|
|
7
|
+
|
|
8
|
+
//#region src/app/extend/application.ts
|
|
9
|
+
const debug = debuglog("egg/jsonp/app/extend/application");
|
|
10
|
+
var JSONPApplication = class extends Application {
|
|
11
|
+
/**
|
|
12
|
+
* return a middleware to enable jsonp response.
|
|
13
|
+
* will do some security check inside.
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
jsonp(initOptions = {}) {
|
|
17
|
+
const options = {
|
|
18
|
+
...this.config.jsonp,
|
|
19
|
+
...initOptions
|
|
20
|
+
};
|
|
21
|
+
if (!Array.isArray(options.callback)) options.callback = [options.callback];
|
|
22
|
+
const csrfEnable = this.plugins.security && this.plugins.security.enable && this.config.security.csrf && this.config.security.csrf.enable !== false && options.csrf;
|
|
23
|
+
const validateReferrer = options.whiteList && createValidateReferer(options.whiteList);
|
|
24
|
+
if (!csrfEnable && !validateReferrer) this.coreLogger.warn("[@eggjs/jsonp] SECURITY WARNING!! csrf check and referrer check are both closed!");
|
|
25
|
+
/**
|
|
26
|
+
* jsonp request security check, pass if
|
|
27
|
+
*
|
|
28
|
+
* 1. hit referrer white list
|
|
29
|
+
* 2. or pass csrf check
|
|
30
|
+
* 3. both check are disabled
|
|
31
|
+
*
|
|
32
|
+
* @param {Context} ctx request context
|
|
33
|
+
*/
|
|
34
|
+
function securityAssert(ctx) {
|
|
35
|
+
if (!csrfEnable && !validateReferrer) return;
|
|
36
|
+
const referrer = ctx.get("referrer");
|
|
37
|
+
if (validateReferrer && validateReferrer(referrer)) return;
|
|
38
|
+
if (csrfEnable && validateCsrf(ctx)) return;
|
|
39
|
+
throw new JSONPForbiddenReferrerError("jsonp request security validate failed", referrer, 403);
|
|
40
|
+
}
|
|
41
|
+
return async function jsonp(ctx, next) {
|
|
42
|
+
ctx[JSONP_CONFIG] = {
|
|
43
|
+
jsonpFunction: getJsonpFunction(ctx.query, options.callback),
|
|
44
|
+
options
|
|
45
|
+
};
|
|
46
|
+
securityAssert(ctx);
|
|
47
|
+
await next();
|
|
48
|
+
ctx.createJsonpBody(ctx.body);
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
function createValidateReferer(whiteList) {
|
|
53
|
+
if (!Array.isArray(whiteList)) whiteList = [whiteList];
|
|
54
|
+
return (referrer) => {
|
|
55
|
+
let parsed;
|
|
56
|
+
for (const rule of whiteList) {
|
|
57
|
+
if (rule instanceof RegExp) {
|
|
58
|
+
if (rule.test(referrer)) return true;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
parsed = parsed ?? parse(referrer);
|
|
62
|
+
const hostname = parsed.hostname || "";
|
|
63
|
+
if (rule[0] === "." && (hostname.endsWith(rule) || hostname === rule.slice(1))) return true;
|
|
64
|
+
else if (hostname === rule) return true;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function validateCsrf(ctx) {
|
|
70
|
+
try {
|
|
71
|
+
ctx.assertCsrf();
|
|
72
|
+
return true;
|
|
73
|
+
} catch (err) {
|
|
74
|
+
debug("validate csrf failed: %s", err);
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function getJsonpFunction(query, callbacks) {
|
|
79
|
+
for (const callback of callbacks) if (query[callback]) return query[callback];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
//#endregion
|
|
83
|
+
export { JSONPApplication as default };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { JSONPConfig } from "../../config/config.default.js";
|
|
2
|
+
import { JSONP_CONFIG } from "../../lib/private_key.js";
|
|
3
|
+
import { Context } from "egg";
|
|
4
|
+
|
|
5
|
+
//#region src/app/extend/context.d.ts
|
|
6
|
+
declare class JSONPContext extends Context {
|
|
7
|
+
[JSONP_CONFIG]?: {
|
|
8
|
+
jsonpFunction?: string;
|
|
9
|
+
options?: JSONPConfig;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* detect if response should be jsonp
|
|
13
|
+
*/
|
|
14
|
+
get acceptJSONP(): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* JSONP wrap body function
|
|
17
|
+
* Set jsonp response wrap function, other plugin can use it.
|
|
18
|
+
* If not necessary, please don't use this method in your application code.
|
|
19
|
+
* @param {Object} body response body
|
|
20
|
+
* @private
|
|
21
|
+
*/
|
|
22
|
+
createJsonpBody(body: any): void;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { JSONPContext as default };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { JSONP_CONFIG } from "../../lib/private_key.js";
|
|
2
|
+
import { Context } from "egg";
|
|
3
|
+
import { jsonp } from "jsonp-body";
|
|
4
|
+
|
|
5
|
+
//#region src/app/extend/context.ts
|
|
6
|
+
var JSONPContext = class extends Context {
|
|
7
|
+
/**
|
|
8
|
+
* detect if response should be jsonp
|
|
9
|
+
*/
|
|
10
|
+
get acceptJSONP() {
|
|
11
|
+
return !!this[JSONP_CONFIG]?.jsonpFunction;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* JSONP wrap body function
|
|
15
|
+
* Set jsonp response wrap function, other plugin can use it.
|
|
16
|
+
* If not necessary, please don't use this method in your application code.
|
|
17
|
+
* @param {Object} body response body
|
|
18
|
+
* @private
|
|
19
|
+
*/
|
|
20
|
+
createJsonpBody(body) {
|
|
21
|
+
const jsonpConfig = this[JSONP_CONFIG];
|
|
22
|
+
if (!jsonpConfig?.jsonpFunction) {
|
|
23
|
+
this.body = body;
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
this.set("x-content-type-options", "nosniff");
|
|
27
|
+
this.type = "js";
|
|
28
|
+
body = body === void 0 ? null : body;
|
|
29
|
+
this.body = jsonp(body, jsonpConfig.jsonpFunction, jsonpConfig.options);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
export { JSONPContext as default };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { PartialEggConfig } from "egg";
|
|
2
|
+
|
|
3
|
+
//#region src/config/config.default.d.ts
|
|
4
|
+
interface JSONPConfig {
|
|
5
|
+
/**
|
|
6
|
+
* jsonp callback methods key, default to `['_callback', 'callback' ]`
|
|
7
|
+
*/
|
|
8
|
+
callback: string[] | string;
|
|
9
|
+
/**
|
|
10
|
+
* callback method name's max length, default to `50`
|
|
11
|
+
*/
|
|
12
|
+
limit: number;
|
|
13
|
+
/**
|
|
14
|
+
* enable csrf check or not, default to `false`
|
|
15
|
+
*/
|
|
16
|
+
csrf: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* referrer white list, default to `undefined`
|
|
19
|
+
*/
|
|
20
|
+
whiteList?: string | RegExp | (string | RegExp)[];
|
|
21
|
+
}
|
|
22
|
+
declare const _default: PartialEggConfig;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { JSONPConfig, _default as default };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/error/JSONPForbiddenReferrerError.d.ts
|
|
2
|
+
declare class JSONPForbiddenReferrerError extends Error {
|
|
3
|
+
referrer: string;
|
|
4
|
+
status: number;
|
|
5
|
+
constructor(message: string, referrer: string, status: number);
|
|
6
|
+
}
|
|
7
|
+
//#endregion
|
|
8
|
+
export { JSONPForbiddenReferrerError };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/error/JSONPForbiddenReferrerError.ts
|
|
2
|
+
var JSONPForbiddenReferrerError = class extends Error {
|
|
3
|
+
referrer;
|
|
4
|
+
status;
|
|
5
|
+
constructor(message, referrer, status) {
|
|
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
|
+
};
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
export { JSONPForbiddenReferrerError };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { JSONPConfig } from "./config/config.default.js";
|
|
2
|
+
import { MiddlewareFunc } from "egg";
|
|
3
|
+
|
|
4
|
+
//#region src/types.d.ts
|
|
5
|
+
declare module 'egg' {
|
|
6
|
+
interface EggAppConfig {
|
|
7
|
+
/**
|
|
8
|
+
* jsonp options
|
|
9
|
+
* @member Config#jsonp
|
|
10
|
+
*/
|
|
11
|
+
jsonp?: JSONPConfig;
|
|
12
|
+
}
|
|
13
|
+
interface Context {
|
|
14
|
+
/**
|
|
15
|
+
* detect if response should be jsonp
|
|
16
|
+
*/
|
|
17
|
+
acceptJSONP: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* JSONP wrap body function
|
|
20
|
+
* Set jsonp response wrap function, other plugin can use it.
|
|
21
|
+
* If not necessary, please don't use this method in your application code.
|
|
22
|
+
* @param {Object} body response body
|
|
23
|
+
* @private
|
|
24
|
+
*/
|
|
25
|
+
createJsonpBody(body: any): void;
|
|
26
|
+
}
|
|
27
|
+
interface Application {
|
|
28
|
+
/**
|
|
29
|
+
* return a middleware to enable jsonp response.
|
|
30
|
+
* will do some security check inside.
|
|
31
|
+
* @public
|
|
32
|
+
*/
|
|
33
|
+
jsonp(initOptions?: Partial<JSONPConfig>): MiddlewareFunc;
|
|
34
|
+
}
|
|
35
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/package.json
CHANGED
|
@@ -1,20 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eggjs/jsonp",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-beta.17",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./dist/index.js",
|
|
10
|
+
"./app/extend/application": "./dist/app/extend/application.js",
|
|
11
|
+
"./app/extend/context": "./dist/app/extend/context.js",
|
|
12
|
+
"./config/config.default": "./dist/config/config.default.js",
|
|
13
|
+
"./error/JSONPForbiddenReferrerError": "./dist/error/JSONPForbiddenReferrerError.js",
|
|
14
|
+
"./lib/private_key": "./dist/lib/private_key.js",
|
|
15
|
+
"./types": "./dist/types.js",
|
|
16
|
+
"./package.json": "./package.json"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
7
21
|
"description": "jsonp support for egg",
|
|
8
22
|
"eggPlugin": {
|
|
9
23
|
"name": "jsonp",
|
|
10
24
|
"optionalDependencies": [
|
|
11
25
|
"security"
|
|
12
|
-
]
|
|
13
|
-
"exports": {
|
|
14
|
-
"import": "./dist/esm",
|
|
15
|
-
"require": "./dist/commonjs",
|
|
16
|
-
"typescript": "./src"
|
|
17
|
-
}
|
|
26
|
+
]
|
|
18
27
|
},
|
|
19
28
|
"keywords": [
|
|
20
29
|
"egg",
|
|
@@ -24,71 +33,40 @@
|
|
|
24
33
|
],
|
|
25
34
|
"repository": {
|
|
26
35
|
"type": "git",
|
|
27
|
-
"url": "git
|
|
36
|
+
"url": "git://github.com/eggjs/egg.git",
|
|
37
|
+
"directory": "plugins/jsonp"
|
|
28
38
|
},
|
|
29
39
|
"bugs": {
|
|
30
40
|
"url": "https://github.com/eggjs/egg/issues"
|
|
31
41
|
},
|
|
32
|
-
"homepage": "https://github.com/eggjs/jsonp
|
|
42
|
+
"homepage": "https://github.com/eggjs/egg/tree/next/plugins/jsonp",
|
|
33
43
|
"author": "dead-horse",
|
|
34
44
|
"license": "MIT",
|
|
35
45
|
"engines": {
|
|
36
|
-
"node": ">=
|
|
46
|
+
"node": ">=22.18.0"
|
|
37
47
|
},
|
|
38
48
|
"dependencies": {
|
|
39
|
-
"@eggjs/core": "^6.2.13",
|
|
40
49
|
"jsonp-body": "^2.0.0"
|
|
41
50
|
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"egg": "4.1.0-beta.17"
|
|
53
|
+
},
|
|
42
54
|
"devDependencies": {
|
|
43
|
-
"@
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"@
|
|
48
|
-
"@
|
|
49
|
-
"egg": "4",
|
|
50
|
-
"eslint": "8",
|
|
51
|
-
"eslint-config-egg": "14",
|
|
52
|
-
"rimraf": "6",
|
|
53
|
-
"tshy": "3",
|
|
54
|
-
"tshy-after": "1",
|
|
55
|
-
"typescript": "5"
|
|
55
|
+
"@types/node": "24.5.2",
|
|
56
|
+
"tsdown": "^0.15.4",
|
|
57
|
+
"typescript": "5.9.2",
|
|
58
|
+
"vitest": "4.0.0-beta.13",
|
|
59
|
+
"@eggjs/mock": "7.0.0-beta.17",
|
|
60
|
+
"@eggjs/tsconfig": "3.1.0-beta.17"
|
|
56
61
|
},
|
|
62
|
+
"main": "./dist/index.js",
|
|
63
|
+
"module": "./dist/index.js",
|
|
64
|
+
"types": "./dist/index.d.ts",
|
|
57
65
|
"scripts": {
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
"prepublishOnly": "tshy && tshy-after && attw --pack"
|
|
66
|
-
},
|
|
67
|
-
"type": "module",
|
|
68
|
-
"tshy": {
|
|
69
|
-
"exports": {
|
|
70
|
-
".": "./src/index.ts",
|
|
71
|
-
"./package.json": "./package.json"
|
|
72
|
-
}
|
|
73
|
-
},
|
|
74
|
-
"exports": {
|
|
75
|
-
".": {
|
|
76
|
-
"import": {
|
|
77
|
-
"types": "./dist/esm/index.d.ts",
|
|
78
|
-
"default": "./dist/esm/index.js"
|
|
79
|
-
},
|
|
80
|
-
"require": {
|
|
81
|
-
"types": "./dist/commonjs/index.d.ts",
|
|
82
|
-
"default": "./dist/commonjs/index.js"
|
|
83
|
-
}
|
|
84
|
-
},
|
|
85
|
-
"./package.json": "./package.json"
|
|
86
|
-
},
|
|
87
|
-
"files": [
|
|
88
|
-
"dist",
|
|
89
|
-
"src"
|
|
90
|
-
],
|
|
91
|
-
"types": "./dist/commonjs/index.d.ts",
|
|
92
|
-
"main": "./dist/commonjs/index.js",
|
|
93
|
-
"module": "./dist/esm/index.js"
|
|
94
|
-
}
|
|
66
|
+
"build": "tsdown",
|
|
67
|
+
"typecheck": "tsc --noEmit",
|
|
68
|
+
"lint": "oxlint --type-aware",
|
|
69
|
+
"lint:fix": "npm run lint -- --fix",
|
|
70
|
+
"test": "npm run lint:fix && vitest run"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -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,115 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const node_util_1 = require("node:util");
|
|
4
|
-
const node_url_1 = require("node:url");
|
|
5
|
-
const core_1 = require("@eggjs/core");
|
|
6
|
-
const private_key_js_1 = require("../../lib/private_key.js");
|
|
7
|
-
const JSONPForbiddenReferrerError_js_1 = require("../../error/JSONPForbiddenReferrerError.js");
|
|
8
|
-
const debug = (0, node_util_1.debuglog)('@egg/jsonp/app/extend/application');
|
|
9
|
-
class JSONPApplication extends core_1.EggCore {
|
|
10
|
-
/**
|
|
11
|
-
* return a middleware to enable jsonp response.
|
|
12
|
-
* will do some security check inside.
|
|
13
|
-
* @public
|
|
14
|
-
*/
|
|
15
|
-
jsonp(initOptions = {}) {
|
|
16
|
-
const options = {
|
|
17
|
-
...this.config.jsonp,
|
|
18
|
-
...initOptions,
|
|
19
|
-
};
|
|
20
|
-
if (!Array.isArray(options.callback)) {
|
|
21
|
-
options.callback = [options.callback];
|
|
22
|
-
}
|
|
23
|
-
const csrfEnable = this.plugins.security && this.plugins.security.enable // security enable
|
|
24
|
-
&& this.config.security.csrf && this.config.security.csrf.enable !== false // csrf enable
|
|
25
|
-
&& options.csrf; // jsonp csrf enabled
|
|
26
|
-
const validateReferrer = options.whiteList && createValidateReferer(options.whiteList);
|
|
27
|
-
if (!csrfEnable && !validateReferrer) {
|
|
28
|
-
this.coreLogger.warn('[@eggjs/jsonp] SECURITY WARNING!! csrf check and referrer check are both closed!');
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* jsonp request security check, pass if
|
|
32
|
-
*
|
|
33
|
-
* 1. hit referrer white list
|
|
34
|
-
* 2. or pass csrf check
|
|
35
|
-
* 3. both check are disabled
|
|
36
|
-
*
|
|
37
|
-
* @param {Context} ctx request context
|
|
38
|
-
*/
|
|
39
|
-
function securityAssert(ctx) {
|
|
40
|
-
// all disabled. don't need check
|
|
41
|
-
if (!csrfEnable && !validateReferrer)
|
|
42
|
-
return;
|
|
43
|
-
// pass referrer check
|
|
44
|
-
const referrer = ctx.get('referrer');
|
|
45
|
-
if (validateReferrer && validateReferrer(referrer))
|
|
46
|
-
return;
|
|
47
|
-
if (csrfEnable && validateCsrf(ctx))
|
|
48
|
-
return;
|
|
49
|
-
throw new JSONPForbiddenReferrerError_js_1.JSONPForbiddenReferrerError('jsonp request security validate failed', referrer, 403);
|
|
50
|
-
}
|
|
51
|
-
return async function jsonp(ctx, next) {
|
|
52
|
-
const jsonpFunction = getJsonpFunction(ctx.query, options.callback);
|
|
53
|
-
ctx[private_key_js_1.JSONP_CONFIG] = {
|
|
54
|
-
jsonpFunction,
|
|
55
|
-
options,
|
|
56
|
-
};
|
|
57
|
-
// before handle request, must do some security checks
|
|
58
|
-
securityAssert(ctx);
|
|
59
|
-
await next();
|
|
60
|
-
// generate jsonp body
|
|
61
|
-
ctx.createJsonpBody(ctx.body);
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
exports.default = JSONPApplication;
|
|
66
|
-
function createValidateReferer(whiteList) {
|
|
67
|
-
if (!Array.isArray(whiteList)) {
|
|
68
|
-
whiteList = [whiteList];
|
|
69
|
-
}
|
|
70
|
-
return (referrer) => {
|
|
71
|
-
let parsed;
|
|
72
|
-
for (const rule of whiteList) {
|
|
73
|
-
if (rule instanceof RegExp) {
|
|
74
|
-
if (rule.test(referrer)) {
|
|
75
|
-
// regexp(/^https?:\/\/github.com\//): test the referrer with rule
|
|
76
|
-
return true;
|
|
77
|
-
}
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
parsed = parsed ?? (0, node_url_1.parse)(referrer);
|
|
81
|
-
const hostname = parsed.hostname || '';
|
|
82
|
-
// check if referrer's hostname match the string rule
|
|
83
|
-
if (rule[0] === '.' &&
|
|
84
|
-
(hostname.endsWith(rule) || hostname === rule.slice(1))) {
|
|
85
|
-
// string start with `.`(.github.com): referrer's hostname must ends with rule
|
|
86
|
-
return true;
|
|
87
|
-
}
|
|
88
|
-
else if (hostname === rule) {
|
|
89
|
-
// string not start with `.`(github.com): referrer's hostname must strict equal to rule
|
|
90
|
-
return true;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
// no rule matched
|
|
94
|
-
return false;
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
function validateCsrf(ctx) {
|
|
98
|
-
try {
|
|
99
|
-
// TODO(fengmk2): remove this when @eggjs/security support ctx.assertCsrf type define
|
|
100
|
-
ctx.assertCsrf();
|
|
101
|
-
return true;
|
|
102
|
-
}
|
|
103
|
-
catch (err) {
|
|
104
|
-
debug('validate csrf failed: %s', err);
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
function getJsonpFunction(query, callbacks) {
|
|
109
|
-
for (const callback of callbacks) {
|
|
110
|
-
if (query[callback]) {
|
|
111
|
-
return query[callback];
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwbGljYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvYXBwL2V4dGVuZC9hcHBsaWNhdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHlDQUFxQztBQUNyQyx1Q0FBc0U7QUFFdEUsc0NBQTJEO0FBQzNELDZEQUF3RDtBQUV4RCwrRkFBeUY7QUFHekYsTUFBTSxLQUFLLEdBQUcsSUFBQSxvQkFBUSxFQUFDLG1DQUFtQyxDQUFDLENBQUM7QUFFNUQsTUFBcUIsZ0JBQWlCLFNBQVEsY0FBTztJQUNuRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLGNBQW9DLEVBQUU7UUFDMUMsTUFBTSxPQUFPLEdBQUc7WUFDZCxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSztZQUNwQixHQUFHLFdBQVc7U0FDeUIsQ0FBQztRQUMxQyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztZQUNyQyxPQUFPLENBQUMsUUFBUSxHQUFHLENBQUUsT0FBTyxDQUFDLFFBQVEsQ0FBRSxDQUFDO1FBQzFDLENBQUM7UUFFRCxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsa0JBQWtCO2VBQ3RGLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLElBQUksSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLEtBQUssQ0FBQyxjQUFjO2VBQ3RGLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxxQkFBcUI7UUFFeEMsTUFBTSxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsU0FBUyxJQUFJLHFCQUFxQixDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUV2RixJQUFJLENBQUMsVUFBVSxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUNyQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxrRkFBa0YsQ0FBQyxDQUFDO1FBQzNHLENBQUM7UUFDRDs7Ozs7Ozs7V0FRRztRQUNILFNBQVMsY0FBYyxDQUFDLEdBQWlCO1lBQ3ZDLGlDQUFpQztZQUNqQyxJQUFJLENBQUMsVUFBVSxJQUFJLENBQUMsZ0JBQWdCO2dCQUFFLE9BQU87WUFFN0Msc0JBQXNCO1lBQ3RCLE1BQU0sUUFBUSxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQVMsVUFBVSxDQUFDLENBQUM7WUFDN0MsSUFBSSxnQkFBZ0IsSUFBSSxnQkFBZ0IsQ0FBQyxRQUFRLENBQUM7Z0JBQUUsT0FBTztZQUMzRCxJQUFJLFVBQVUsSUFBSSxZQUFZLENBQUMsR0FBRyxDQUFDO2dCQUFFLE9BQU87WUFFNUMsTUFBTSxJQUFJLDREQUEyQixDQUNuQyx3Q0FBd0MsRUFDeEMsUUFBUSxFQUNSLEdBQUcsQ0FBQyxDQUFDO1FBQ1QsQ0FBQztRQUVELE9BQU8sS0FBSyxVQUFVLEtBQUssQ0FBQyxHQUFpQixFQUFFLElBQUk7WUFDakQsTUFBTSxhQUFhLEdBQUcsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7WUFFcEUsR0FBRyxDQUFDLDZCQUFZLENBQUMsR0FBRztnQkFDbEIsYUFBYTtnQkFDYixPQUFPO2FBQ1IsQ0FBQztZQUVGLHNEQUFzRDtZQUN0RCxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUM7WUFFcEIsTUFBTSxJQUFJLEVBQUUsQ0FBQztZQUViLHNCQUFzQjtZQUN0QixHQUFHLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNoQyxDQUFDLENBQUM7SUFDSixDQUFDO0NBQ0Y7QUFqRUQsbUNBaUVDO0FBRUQsU0FBUyxxQkFBcUIsQ0FBQyxTQUE2QztJQUMxRSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1FBQzlCLFNBQVMsR0FBRyxDQUFFLFNBQVMsQ0FBRSxDQUFDO0lBQzVCLENBQUM7SUFFRCxPQUFPLENBQUMsUUFBZ0IsRUFBRSxFQUFFO1FBQzFCLElBQUksTUFBc0MsQ0FBQztRQUMzQyxLQUFLLE1BQU0sSUFBSSxJQUFJLFNBQVMsRUFBRSxDQUFDO1lBQzdCLElBQUksSUFBSSxZQUFZLE1BQU0sRUFBRSxDQUFDO2dCQUMzQixJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztvQkFDeEIsa0VBQWtFO29CQUNsRSxPQUFPLElBQUksQ0FBQztnQkFDZCxDQUFDO2dCQUNELFNBQVM7WUFDWCxDQUFDO1lBRUQsTUFBTSxHQUFHLE1BQU0sSUFBSSxJQUFBLGdCQUFRLEVBQUMsUUFBUSxDQUFDLENBQUM7WUFDdEMsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLFFBQVEsSUFBSSxFQUFFLENBQUM7WUFFdkMscURBQXFEO1lBQ3JELElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUc7Z0JBQ2pCLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxRQUFRLEtBQUssSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7Z0JBQzFELDhFQUE4RTtnQkFDOUUsT0FBTyxJQUFJLENBQUM7WUFDZCxDQUFDO2lCQUFNLElBQUksUUFBUSxLQUFLLElBQUksRUFBRSxDQUFDO2dCQUM3Qix1RkFBdUY7Z0JBQ3ZGLE9BQU8sSUFBSSxDQUFDO1lBQ2QsQ0FBQztRQUNILENBQUM7UUFFRCxrQkFBa0I7UUFDbEIsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDLENBQUM7QUFDSixDQUFDO0FBRUQsU0FBUyxZQUFZLENBQUMsR0FBUTtJQUM1QixJQUFJLENBQUM7UUFDSCxxRkFBcUY7UUFDckYsR0FBRyxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ2pCLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixLQUFLLENBQUMsMEJBQTBCLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDdkMsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0FBQ0gsQ0FBQztBQUVELFNBQVMsZ0JBQWdCLENBQUMsS0FBcUIsRUFBRSxTQUFtQjtJQUNsRSxLQUFLLE1BQU0sUUFBUSxJQUFJLFNBQVMsRUFBRSxDQUFDO1FBQ2pDLElBQUksS0FBSyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7WUFDcEIsT0FBTyxLQUFLLENBQUMsUUFBUSxDQUFXLENBQUM7UUFDbkMsQ0FBQztJQUNILENBQUM7QUFDSCxDQUFDIn0=
|
|
@@ -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,35 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const jsonp_body_1 = require("jsonp-body");
|
|
4
|
-
const core_1 = require("@eggjs/core");
|
|
5
|
-
const private_key_js_1 = require("../../lib/private_key.js");
|
|
6
|
-
class JSONPContext extends core_1.Context {
|
|
7
|
-
/**
|
|
8
|
-
* detect if response should be jsonp
|
|
9
|
-
*/
|
|
10
|
-
get acceptJSONP() {
|
|
11
|
-
const jsonpConfig = Reflect.get(this, private_key_js_1.JSONP_CONFIG);
|
|
12
|
-
return !!(jsonpConfig?.jsonpFunction);
|
|
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) {
|
|
22
|
-
const jsonpConfig = Reflect.get(this, private_key_js_1.JSONP_CONFIG);
|
|
23
|
-
if (!jsonpConfig?.jsonpFunction) {
|
|
24
|
-
this.body = body;
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
this.set('x-content-type-options', 'nosniff');
|
|
28
|
-
this.type = 'js';
|
|
29
|
-
body = body === undefined ? null : body;
|
|
30
|
-
// protect from jsonp xss
|
|
31
|
-
this.body = (0, jsonp_body_1.jsonp)(body, jsonpConfig.jsonpFunction, jsonpConfig.options);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
exports.default = JSONPContext;
|
|
35
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGV4dC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9hcHAvZXh0ZW5kL2NvbnRleHQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSwyQ0FBZ0Q7QUFDaEQsc0NBQXNDO0FBQ3RDLDZEQUF3RDtBQUV4RCxNQUFxQixZQUFhLFNBQVEsY0FBTztJQUMvQzs7T0FFRztJQUNILElBQUksV0FBVztRQUNiLE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLDZCQUFZLENBQVEsQ0FBQztRQUMzRCxPQUFPLENBQUMsQ0FBQyxDQUFDLFdBQVcsRUFBRSxhQUFhLENBQUMsQ0FBQztJQUN4QyxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0gsZUFBZSxDQUFDLElBQVM7UUFDdkIsTUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsNkJBQVksQ0FBUSxDQUFDO1FBQzNELElBQUksQ0FBQyxXQUFXLEVBQUUsYUFBYSxFQUFFLENBQUM7WUFDaEMsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7WUFDakIsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLENBQUMsR0FBRyxDQUFDLHdCQUF3QixFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBQzlDLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO1FBQ2pCLElBQUksR0FBRyxJQUFJLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUN4Qyx5QkFBeUI7UUFDekIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFBLGtCQUFTLEVBQUMsSUFBSSxFQUFFLFdBQVcsQ0FBQyxhQUFhLEVBQUUsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzlFLENBQUM7Q0FDRjtBQTdCRCwrQkE2QkMifQ==
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.default = {
|
|
4
|
-
jsonp: {
|
|
5
|
-
limit: 50,
|
|
6
|
-
callback: ['_callback', 'callback'],
|
|
7
|
-
csrf: false,
|
|
8
|
-
whiteList: undefined,
|
|
9
|
-
},
|
|
10
|
-
};
|
|
11
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmRlZmF1bHQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY29uZmlnL2NvbmZpZy5kZWZhdWx0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBRUEsa0JBQWU7SUFDYixLQUFLLEVBQUU7UUFDTCxLQUFLLEVBQUUsRUFBRTtRQUNULFFBQVEsRUFBRSxDQUFFLFdBQVcsRUFBRSxVQUFVLENBQUU7UUFDckMsSUFBSSxFQUFFLEtBQUs7UUFDWCxTQUFTLEVBQUUsU0FBUztLQUNOO0NBQ2pCLENBQUMifQ==
|