@nestia/core 1.2.0 → 1.2.1-dev.20230506
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/decorators/EncryptedBody.js +35 -73
- package/lib/decorators/EncryptedBody.js.map +1 -1
- package/lib/decorators/EncryptedController.d.ts +0 -5
- package/lib/decorators/EncryptedController.js +0 -5
- package/lib/decorators/EncryptedController.js.map +1 -1
- package/lib/decorators/EncryptedRoute.js +2 -9
- package/lib/decorators/EncryptedRoute.js.map +1 -1
- package/lib/decorators/PlainBody.js +14 -55
- package/lib/decorators/PlainBody.js.map +1 -1
- package/lib/decorators/TypedBody.js +20 -65
- package/lib/decorators/TypedBody.js.map +1 -1
- package/lib/decorators/TypedParam.js +6 -5
- package/lib/decorators/TypedParam.js.map +1 -1
- package/lib/decorators/TypedQuery.js +42 -59
- package/lib/decorators/TypedQuery.js.map +1 -1
- package/lib/decorators/internal/get_path_and_stringify.js +5 -3
- package/lib/decorators/internal/get_path_and_stringify.js.map +1 -1
- package/lib/decorators/internal/send_bad_request.d.ts +2 -0
- package/lib/decorators/internal/send_bad_request.js +13 -0
- package/lib/decorators/internal/send_bad_request.js.map +1 -0
- package/lib/decorators/internal/validate_request_body.d.ts +2 -1
- package/lib/decorators/internal/validate_request_body.js +15 -9
- package/lib/decorators/internal/validate_request_body.js.map +1 -1
- package/package.json +3 -3
- package/src/decorators/EncryptedBody.ts +30 -21
- package/src/decorators/EncryptedController.ts +0 -5
- package/src/decorators/EncryptedRoute.ts +2 -15
- package/src/decorators/PlainBody.ts +21 -7
- package/src/decorators/TypedBody.ts +26 -12
- package/src/decorators/TypedParam.ts +16 -8
- package/src/decorators/TypedQuery.ts +21 -15
- package/src/decorators/internal/get_path_and_stringify.ts +2 -3
- package/src/decorators/internal/send_bad_request.ts +12 -0
- package/src/decorators/internal/validate_request_body.ts +16 -13
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.get_path_and_stringify = void 0;
|
|
4
7
|
var common_1 = require("@nestjs/common");
|
|
5
|
-
var typia_1 = require("typia");
|
|
8
|
+
var typia_1 = __importDefault(require("typia"));
|
|
6
9
|
var TransformError_1 = require("./TransformError");
|
|
7
10
|
var get_path_and_stringify = function (method) {
|
|
8
11
|
return function () {
|
|
@@ -43,7 +46,7 @@ var assert = function (closure) {
|
|
|
43
46
|
return closure(data);
|
|
44
47
|
}
|
|
45
48
|
catch (exp) {
|
|
46
|
-
if (
|
|
49
|
+
if (typia_1.default.is(exp))
|
|
47
50
|
throw new common_1.InternalServerErrorException({
|
|
48
51
|
path: exp.path,
|
|
49
52
|
reason: exp.message,
|
|
@@ -51,7 +54,6 @@ var assert = function (closure) {
|
|
|
51
54
|
value: exp.value,
|
|
52
55
|
message: MESSAGE,
|
|
53
56
|
});
|
|
54
|
-
}
|
|
55
57
|
throw exp;
|
|
56
58
|
}
|
|
57
59
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get_path_and_stringify.js","sourceRoot":"","sources":["../../../src/decorators/internal/get_path_and_stringify.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"get_path_and_stringify.js","sourceRoot":"","sources":["../../../src/decorators/internal/get_path_and_stringify.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.send_bad_request = void 0;
|
|
4
|
+
var send_bad_request = function (context) {
|
|
5
|
+
return function (error) {
|
|
6
|
+
var response = context
|
|
7
|
+
.switchToHttp()
|
|
8
|
+
.getResponse();
|
|
9
|
+
response.status(error.getStatus()).send(error.getResponse());
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
exports.send_bad_request = send_bad_request;
|
|
13
|
+
//# sourceMappingURL=send_bad_request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send_bad_request.js","sourceRoot":"","sources":["../../../src/decorators/internal/send_bad_request.ts"],"names":[],"mappings":";;;AAIO,IAAM,gBAAgB,GACzB,UAAC,OAAyB;IAC1B,OAAA,UAAC,KAA0B;QACvB,IAAM,QAAQ,GAAoC,OAAO;aACpD,YAAY,EAAE;aACd,WAAW,EAAE,CAAC;QACnB,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;IACjE,CAAC;AALD,CAKC,CAAC;AAPO,QAAA,gBAAgB,oBAOvB"}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
+
import { BadRequestException } from "@nestjs/common";
|
|
1
2
|
import { IRequestBodyValidator } from "../../options/IRequestBodyValidator";
|
|
2
|
-
export declare const validate_request_body: (method: string) => <T>(validator?: IRequestBodyValidator<T> | undefined) => (data: T) =>
|
|
3
|
+
export declare const validate_request_body: (method: string) => <T>(validator?: IRequestBodyValidator<T> | undefined) => (() => Error) | ((data: T) => BadRequestException | null);
|
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.validate_request_body = void 0;
|
|
4
7
|
var common_1 = require("@nestjs/common");
|
|
5
|
-
var typia_1 = require("typia");
|
|
8
|
+
var typia_1 = __importDefault(require("typia"));
|
|
6
9
|
var TransformError_1 = require("./TransformError");
|
|
7
10
|
var validate_request_body = function (method) {
|
|
8
11
|
return function (validator) {
|
|
9
12
|
if (!validator)
|
|
10
|
-
|
|
13
|
+
return function () { return (0, TransformError_1.TransformError)(method); };
|
|
11
14
|
else if (validator.type === "assert")
|
|
12
15
|
return assert(validator.assert);
|
|
13
16
|
else if (validator.type === "is")
|
|
14
17
|
return is(validator.is);
|
|
15
18
|
else if (validator.type === "validate")
|
|
16
19
|
return validate(validator.validate);
|
|
17
|
-
|
|
20
|
+
return function () {
|
|
21
|
+
return new Error("Error on nestia.core.".concat(method, "(): invalid typed validator."));
|
|
22
|
+
};
|
|
18
23
|
};
|
|
19
24
|
};
|
|
20
25
|
exports.validate_request_body = validate_request_body;
|
|
@@ -22,10 +27,11 @@ var assert = function (closure) {
|
|
|
22
27
|
return function (data) {
|
|
23
28
|
try {
|
|
24
29
|
closure(data);
|
|
30
|
+
return null;
|
|
25
31
|
}
|
|
26
32
|
catch (exp) {
|
|
27
|
-
if (
|
|
28
|
-
|
|
33
|
+
if (typia_1.default.is(exp)) {
|
|
34
|
+
return new common_1.BadRequestException({
|
|
29
35
|
path: exp.path,
|
|
30
36
|
reason: exp.message,
|
|
31
37
|
expected: exp.expected,
|
|
@@ -40,15 +46,15 @@ var assert = function (closure) {
|
|
|
40
46
|
var is = function (closure) {
|
|
41
47
|
return function (data) {
|
|
42
48
|
var success = closure(data);
|
|
43
|
-
|
|
44
|
-
throw new common_1.BadRequestException(MESSAGE);
|
|
49
|
+
return success ? null : new common_1.BadRequestException(MESSAGE);
|
|
45
50
|
};
|
|
46
51
|
};
|
|
47
52
|
var validate = function (closure) {
|
|
48
53
|
return function (data) {
|
|
49
54
|
var result = closure(data);
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
return result.success
|
|
56
|
+
? null
|
|
57
|
+
: new common_1.BadRequestException({
|
|
52
58
|
errors: result.errors,
|
|
53
59
|
message: MESSAGE,
|
|
54
60
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate_request_body.js","sourceRoot":"","sources":["../../../src/decorators/internal/validate_request_body.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validate_request_body.js","sourceRoot":"","sources":["../../../src/decorators/internal/validate_request_body.ts"],"names":[],"mappings":";;;;;;AAAA,yCAAqD;AAErD,gDAA2D;AAG3D,mDAAkD;AAE3C,IAAM,qBAAqB,GAC9B,UAAC,MAAc;IACf,OAAA,UAAI,SAAoC;QACpC,IAAI,CAAC,SAAS;YAAE,OAAO,cAAM,OAAA,IAAA,+BAAc,EAAC,MAAM,CAAC,EAAtB,CAAsB,CAAC;aAC/C,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;aACjE,IAAI,SAAS,CAAC,IAAI,KAAK,IAAI;YAAE,OAAO,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;aACrD,IAAI,SAAS,CAAC,IAAI,KAAK,UAAU;YAClC,OAAO,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACxC,OAAO;YACH,OAAA,IAAI,KAAK,CACL,+BAAwB,MAAM,iCAA8B,CAC/D;QAFD,CAEC,CAAC;IACV,CAAC;AAVD,CAUC,CAAC;AAZO,QAAA,qBAAqB,yBAY5B;AAEN,IAAM,MAAM,GACR,UAAI,OAAuB;IAC3B,OAAA,UAAC,IAAO;QACJ,IAAI;YACA,OAAO,CAAC,IAAI,CAAC,CAAC;YACd,OAAO,IAAI,CAAC;SACf;QAAC,OAAO,GAAG,EAAE;YACV,IAAI,eAAK,CAAC,EAAE,CAAiB,GAAG,CAAC,EAAE;gBAC/B,OAAO,IAAI,4BAAmB,CAAC;oBAC3B,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,MAAM,EAAE,GAAG,CAAC,OAAO;oBACnB,QAAQ,EAAE,GAAG,CAAC,QAAQ;oBACtB,KAAK,EAAE,GAAG,CAAC,KAAK;oBAChB,OAAO,EAAE,OAAO;iBACnB,CAAC,CAAC;aACN;YACD,MAAM,GAAG,CAAC;SACb;IACL,CAAC;AAhBD,CAgBC,CAAC;AAEN,IAAM,EAAE,GACJ,UAAI,OAA6B;IACjC,OAAA,UAAC,IAAO;QACJ,IAAM,OAAO,GAAY,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,OAAO,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,4BAAmB,CAAC,OAAO,CAAC,CAAC;IAC7D,CAAC;AAHD,CAGC,CAAC;AAEN,IAAM,QAAQ,GACV,UAAI,OAAoC;IACxC,OAAA,UAAC,IAAO;QACJ,IAAM,MAAM,GAAmB,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7C,OAAO,MAAM,CAAC,OAAO;YACjB,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,IAAI,4BAAmB,CAAC;gBACpB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,OAAO,EAAE,OAAO;aACnB,CAAC,CAAC;IACb,CAAC;AARD,CAQC,CAAC;AAEN,IAAM,OAAO,GAAG,uDAAuD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nestia/core",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1-dev.20230506",
|
|
4
4
|
"description": "Super-fast validation decorators of NestJS",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
@@ -33,13 +33,13 @@
|
|
|
33
33
|
},
|
|
34
34
|
"homepage": "https://github.com/samchon/nestia",
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@nestia/fetcher": "^1.2.
|
|
36
|
+
"@nestia/fetcher": "^1.2.1",
|
|
37
37
|
"@nestjs/common": ">= 7.0.1",
|
|
38
38
|
"@nestjs/core": ">= 7.0.1",
|
|
39
39
|
"@nestjs/platform-express": ">= 7.0.1",
|
|
40
|
+
"@nestjs/platform-fastify": ">= 7.0.1",
|
|
40
41
|
"detect-ts-node": "^1.0.5",
|
|
41
42
|
"glob": "^7.2.0",
|
|
42
|
-
"raw-body": ">= 2.0.0",
|
|
43
43
|
"reflect-metadata": ">= 0.1.12",
|
|
44
44
|
"rxjs": ">= 6.0.0",
|
|
45
45
|
"typia": "^3.8.4"
|
|
@@ -2,10 +2,11 @@ import { AesPkcs5, IEncryptionPassword } from "@nestia/fetcher";
|
|
|
2
2
|
import {
|
|
3
3
|
BadRequestException,
|
|
4
4
|
ExecutionContext,
|
|
5
|
+
HttpException,
|
|
5
6
|
createParamDecorator,
|
|
6
7
|
} from "@nestjs/common";
|
|
7
8
|
import type express from "express";
|
|
8
|
-
import
|
|
9
|
+
import type { FastifyRequest } from "fastify";
|
|
9
10
|
|
|
10
11
|
import { assert, is, validate } from "typia";
|
|
11
12
|
|
|
@@ -13,6 +14,7 @@ import { IRequestBodyValidator } from "../options/IRequestBodyValidator";
|
|
|
13
14
|
import { Singleton } from "../utils/Singleton";
|
|
14
15
|
import { ENCRYPTION_METADATA_KEY } from "./internal/EncryptedConstant";
|
|
15
16
|
import { headers_to_object } from "./internal/headers_to_object";
|
|
17
|
+
import { send_bad_request } from "./internal/send_bad_request";
|
|
16
18
|
import { validate_request_body } from "./internal/validate_request_body";
|
|
17
19
|
|
|
18
20
|
/**
|
|
@@ -40,14 +42,18 @@ export function EncryptedBody<T>(
|
|
|
40
42
|
validator?: IRequestBodyValidator<T>,
|
|
41
43
|
): ParameterDecorator {
|
|
42
44
|
const checker = validate_request_body("EncryptedBody")(validator);
|
|
43
|
-
return createParamDecorator(
|
|
45
|
+
return createParamDecorator(function EncryptedBody(
|
|
44
46
|
_unknown: any,
|
|
45
|
-
|
|
47
|
+
context: ExecutionContext,
|
|
46
48
|
) {
|
|
47
|
-
const request: express.Request =
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
const request: express.Request | FastifyRequest = context
|
|
50
|
+
.switchToHttp()
|
|
51
|
+
.getRequest();
|
|
52
|
+
if (isTextPlain(request.headers["content-type"]) === false)
|
|
53
|
+
return send_bad_request(context)(
|
|
54
|
+
new BadRequestException(
|
|
55
|
+
`Request body type is not "text/plain".`,
|
|
56
|
+
),
|
|
51
57
|
);
|
|
52
58
|
|
|
53
59
|
const param:
|
|
@@ -55,7 +61,7 @@ export function EncryptedBody<T>(
|
|
|
55
61
|
| IEncryptionPassword.Closure
|
|
56
62
|
| undefined = Reflect.getMetadata(
|
|
57
63
|
ENCRYPTION_METADATA_KEY,
|
|
58
|
-
|
|
64
|
+
context.getClass(),
|
|
59
65
|
);
|
|
60
66
|
if (!param)
|
|
61
67
|
throw new Error(
|
|
@@ -66,23 +72,19 @@ export function EncryptedBody<T>(
|
|
|
66
72
|
const headers: Singleton<Record<string, string>> = new Singleton(() =>
|
|
67
73
|
headers_to_object(request.headers),
|
|
68
74
|
);
|
|
69
|
-
const body: string =
|
|
75
|
+
const body: string = request.body;
|
|
70
76
|
const password: IEncryptionPassword =
|
|
71
77
|
typeof param === "function"
|
|
72
78
|
? param({ headers: headers.get(), body }, false)
|
|
73
79
|
: param;
|
|
74
|
-
const disabled: boolean =
|
|
75
|
-
password.disabled === undefined
|
|
76
|
-
? false
|
|
77
|
-
: typeof password.disabled === "function"
|
|
78
|
-
? password.disabled({ headers: headers.get(), body }, true)
|
|
79
|
-
: password.disabled;
|
|
80
80
|
|
|
81
81
|
// PARSE AND VALIDATE DATA
|
|
82
|
-
const data: any = JSON.parse(
|
|
83
|
-
|
|
84
|
-
)
|
|
85
|
-
|
|
82
|
+
const data: any = JSON.parse(decrypt(body, password.key, password.iv));
|
|
83
|
+
const error: Error | null = checker(data);
|
|
84
|
+
if (error !== null)
|
|
85
|
+
if (error instanceof HttpException)
|
|
86
|
+
return send_bad_request(context)(error);
|
|
87
|
+
else throw error;
|
|
86
88
|
return data;
|
|
87
89
|
})();
|
|
88
90
|
}
|
|
@@ -93,7 +95,7 @@ Object.assign(EncryptedBody, validate);
|
|
|
93
95
|
/**
|
|
94
96
|
* @internal
|
|
95
97
|
*/
|
|
96
|
-
|
|
98
|
+
const decrypt = (body: string, key: string, iv: string): string => {
|
|
97
99
|
try {
|
|
98
100
|
return AesPkcs5.decrypt(body, key, iv);
|
|
99
101
|
} catch (exp) {
|
|
@@ -103,4 +105,11 @@ function decrypt(body: string, key: string, iv: string): string {
|
|
|
103
105
|
);
|
|
104
106
|
else throw exp;
|
|
105
107
|
}
|
|
106
|
-
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const isTextPlain = (text?: string): boolean =>
|
|
111
|
+
text !== undefined &&
|
|
112
|
+
text
|
|
113
|
+
.split(";")
|
|
114
|
+
.map((str) => str.trim())
|
|
115
|
+
.some((str) => str === "text/plain");
|
|
@@ -11,11 +11,6 @@ import { ENCRYPTION_METADATA_KEY } from "./internal/EncryptedConstant";
|
|
|
11
11
|
* encryption algorithm and password would be used by {@link EncryptedRoute} and
|
|
12
12
|
* {@link EncryptedBody} to encrypt the request and response body of the HTTP protocol.
|
|
13
13
|
*
|
|
14
|
-
* > However, if you've configure the {@link IEncryptionPassword.disabled} to be `true`,
|
|
15
|
-
* > you can disable the encryption and decryption algorithm. Therefore, when the
|
|
16
|
-
* > {@link IEncryptionPassword.disable} becomes the `true`, content like request and
|
|
17
|
-
* > response body would be considered as a plain text instead.
|
|
18
|
-
*
|
|
19
14
|
* By the way, you can configure the encryption password in the global level by using
|
|
20
15
|
* {@link EncryptedModule} instead of the {@link nest.Module} in the module level. In
|
|
21
16
|
* that case, you don't need to use this `EncryptedController` more. Just use the
|
|
@@ -165,24 +165,11 @@ class EncryptedRouteInterceptor implements NestInterceptor {
|
|
|
165
165
|
typeof param === "function"
|
|
166
166
|
? param({ headers: headers.get(), body }, false)
|
|
167
167
|
: param;
|
|
168
|
-
const disabled: boolean =
|
|
169
|
-
password.disabled === undefined
|
|
170
|
-
? false
|
|
171
|
-
: typeof password.disabled === "function"
|
|
172
|
-
? password.disabled(
|
|
173
|
-
{ headers: headers.get(), body },
|
|
174
|
-
false,
|
|
175
|
-
)
|
|
176
|
-
: password.disabled;
|
|
177
168
|
|
|
178
169
|
const response: express.Response = http.getResponse();
|
|
179
|
-
response.header(
|
|
180
|
-
"Content-Type",
|
|
181
|
-
disabled ? "application/json" : "text/plain",
|
|
182
|
-
);
|
|
170
|
+
response.header("Content-Type", "text/plain");
|
|
183
171
|
|
|
184
|
-
if (
|
|
185
|
-
else if (body === undefined) return body;
|
|
172
|
+
if (body === undefined) return body;
|
|
186
173
|
return AesPkcs5.encrypt(body, password.key, password.iv);
|
|
187
174
|
}),
|
|
188
175
|
catchError((err) => route_error(http.getRequest(), err)),
|
|
@@ -4,7 +4,9 @@ import {
|
|
|
4
4
|
createParamDecorator,
|
|
5
5
|
} from "@nestjs/common";
|
|
6
6
|
import type express from "express";
|
|
7
|
-
import
|
|
7
|
+
import type { FastifyRequest } from "fastify";
|
|
8
|
+
|
|
9
|
+
import { send_bad_request } from "./internal/send_bad_request";
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Plain body decorator.
|
|
@@ -28,11 +30,23 @@ import raw from "raw-body";
|
|
|
28
30
|
* @author Jeongho Nam - https://github.com/samchon
|
|
29
31
|
*/
|
|
30
32
|
export const PlainBody: () => ParameterDecorator = createParamDecorator(
|
|
31
|
-
|
|
32
|
-
const request: express.Request = context
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
function PlainBody(_data: any, context: ExecutionContext) {
|
|
34
|
+
const request: express.Request | FastifyRequest = context
|
|
35
|
+
.switchToHttp()
|
|
36
|
+
.getRequest();
|
|
37
|
+
return isTextPlain(request.headers["content-type"])
|
|
38
|
+
? request.body
|
|
39
|
+
: send_bad_request(context)(
|
|
40
|
+
new BadRequestException(
|
|
41
|
+
`Request body type is not "text/plain".`,
|
|
42
|
+
),
|
|
43
|
+
);
|
|
37
44
|
},
|
|
38
45
|
);
|
|
46
|
+
|
|
47
|
+
const isTextPlain = (text?: string): boolean =>
|
|
48
|
+
text !== undefined &&
|
|
49
|
+
text
|
|
50
|
+
.split(";")
|
|
51
|
+
.map((str) => str.trim())
|
|
52
|
+
.some((str) => str === "text/plain");
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BadRequestException,
|
|
3
3
|
ExecutionContext,
|
|
4
|
+
HttpException,
|
|
4
5
|
createParamDecorator,
|
|
5
6
|
} from "@nestjs/common";
|
|
6
7
|
import type express from "express";
|
|
7
|
-
import
|
|
8
|
+
import type { FastifyRequest } from "fastify";
|
|
8
9
|
|
|
9
10
|
import { assert, is, validate } from "typia";
|
|
10
11
|
|
|
11
12
|
import { IRequestBodyValidator } from "../options/IRequestBodyValidator";
|
|
13
|
+
import { send_bad_request } from "./internal/send_bad_request";
|
|
12
14
|
import { validate_request_body } from "./internal/validate_request_body";
|
|
13
15
|
|
|
14
16
|
/**
|
|
@@ -29,24 +31,36 @@ export function TypedBody<T>(
|
|
|
29
31
|
validator?: IRequestBodyValidator<T>,
|
|
30
32
|
): ParameterDecorator {
|
|
31
33
|
const checker = validate_request_body("TypedBody")(validator);
|
|
32
|
-
return createParamDecorator(
|
|
34
|
+
return createParamDecorator(function TypedBody(
|
|
33
35
|
_unknown: any,
|
|
34
36
|
context: ExecutionContext,
|
|
35
37
|
) {
|
|
36
|
-
const request: express.Request = context
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
const request: express.Request | FastifyRequest = context
|
|
39
|
+
.switchToHttp()
|
|
40
|
+
.getRequest();
|
|
41
|
+
if (isApplicationJson(request.headers["content-type"]) === false)
|
|
42
|
+
return send_bad_request(context)(
|
|
43
|
+
new BadRequestException(
|
|
44
|
+
`Request body type is not "application/json".`,
|
|
45
|
+
),
|
|
40
46
|
);
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
|
|
48
|
+
const error: Error | null = checker(request.body);
|
|
49
|
+
if (error !== null)
|
|
50
|
+
if (error instanceof HttpException)
|
|
51
|
+
return send_bad_request(context)(error);
|
|
52
|
+
else throw error;
|
|
53
|
+
return request.body;
|
|
47
54
|
})();
|
|
48
55
|
}
|
|
49
56
|
|
|
50
57
|
Object.assign(TypedBody, is);
|
|
51
58
|
Object.assign(TypedBody, assert);
|
|
52
59
|
Object.assign(TypedBody, validate);
|
|
60
|
+
|
|
61
|
+
const isApplicationJson = (text?: string): boolean =>
|
|
62
|
+
text !== undefined &&
|
|
63
|
+
text
|
|
64
|
+
.split(";")
|
|
65
|
+
.map((str) => str.trim())
|
|
66
|
+
.some((str) => str === "application/json");
|
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
} from "@nestjs/common";
|
|
6
6
|
import type express from "express";
|
|
7
7
|
|
|
8
|
+
import { send_bad_request } from "./internal/send_bad_request";
|
|
9
|
+
|
|
8
10
|
/**
|
|
9
11
|
* Type safe URL parameter decorator.
|
|
10
12
|
*
|
|
@@ -40,8 +42,8 @@ export function TypedParam(
|
|
|
40
42
|
type?: "boolean" | "number" | "string" | "uuid",
|
|
41
43
|
nullable?: false | true,
|
|
42
44
|
): ParameterDecorator {
|
|
43
|
-
function TypedParam({}: any,
|
|
44
|
-
const request: express.Request =
|
|
45
|
+
function TypedParam({}: any, context: ExecutionContext) {
|
|
46
|
+
const request: express.Request = context.switchToHttp().getRequest();
|
|
45
47
|
const str: string = request.params[name];
|
|
46
48
|
|
|
47
49
|
if (nullable === true && str === "null") return null;
|
|
@@ -49,20 +51,26 @@ export function TypedParam(
|
|
|
49
51
|
if (str === "true" || str === "1") return true;
|
|
50
52
|
else if (str === "false" || str === "0") return false;
|
|
51
53
|
else
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
return send_bad_request(context)(
|
|
55
|
+
new BadRequestException(
|
|
56
|
+
`Value of the URL parameter '${name}' is not a boolean.`,
|
|
57
|
+
),
|
|
54
58
|
);
|
|
55
59
|
} else if (type === "number") {
|
|
56
60
|
const value: number = Number(str);
|
|
57
61
|
if (isNaN(value))
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
return send_bad_request(context)(
|
|
63
|
+
new BadRequestException(
|
|
64
|
+
`Value of the URL parameter "${name}" is not a number.`,
|
|
65
|
+
),
|
|
60
66
|
);
|
|
61
67
|
return value;
|
|
62
68
|
} else if (type === "uuid") {
|
|
63
69
|
if (UUID_PATTERN.test(str) === false)
|
|
64
|
-
|
|
65
|
-
|
|
70
|
+
return send_bad_request(context)(
|
|
71
|
+
new BadRequestException(
|
|
72
|
+
`Value of the URL parameter "${name}" is not a valid UUID.`,
|
|
73
|
+
),
|
|
66
74
|
);
|
|
67
75
|
return str;
|
|
68
76
|
} else return str;
|
|
@@ -3,11 +3,13 @@ import {
|
|
|
3
3
|
ExecutionContext,
|
|
4
4
|
createParamDecorator,
|
|
5
5
|
} from "@nestjs/common";
|
|
6
|
-
import express from "express";
|
|
6
|
+
import type express from "express";
|
|
7
|
+
import type { FastifyRequest } from "fastify";
|
|
7
8
|
|
|
8
|
-
import { TypeGuardError, assert } from "typia";
|
|
9
|
+
import typia, { TypeGuardError, assert } from "typia";
|
|
9
10
|
|
|
10
11
|
import { TransformError } from "./internal/TransformError";
|
|
12
|
+
import { send_bad_request } from "./internal/send_bad_request";
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* Type safe URL query decorator.
|
|
@@ -27,25 +29,29 @@ export function TypedQuery<T>(
|
|
|
27
29
|
): ParameterDecorator {
|
|
28
30
|
if (decoder === undefined) throw TransformError("TypedQuery");
|
|
29
31
|
|
|
30
|
-
return createParamDecorator(
|
|
32
|
+
return createParamDecorator(function TypedQuery(
|
|
31
33
|
_unknown: any,
|
|
32
|
-
|
|
34
|
+
context: ExecutionContext,
|
|
33
35
|
) {
|
|
34
|
-
const request: express.Request =
|
|
36
|
+
const request: express.Request | FastifyRequest = context
|
|
37
|
+
.switchToHttp()
|
|
38
|
+
.getRequest();
|
|
35
39
|
const params: URLSearchParams = new URLSearchParams(tail(request.url));
|
|
40
|
+
|
|
36
41
|
try {
|
|
37
42
|
return decoder(params);
|
|
38
43
|
} catch (exp) {
|
|
39
|
-
if (exp
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
if (typia.is<TypeGuardError>(exp))
|
|
45
|
+
return send_bad_request(context)(
|
|
46
|
+
new BadRequestException({
|
|
47
|
+
path: exp.path,
|
|
48
|
+
reason: exp.message,
|
|
49
|
+
expected: exp.expected,
|
|
50
|
+
value: exp.value,
|
|
51
|
+
message:
|
|
52
|
+
"Request query parameters are not following the promised type.",
|
|
53
|
+
}),
|
|
54
|
+
);
|
|
49
55
|
throw exp;
|
|
50
56
|
}
|
|
51
57
|
})();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { InternalServerErrorException } from "@nestjs/common";
|
|
2
2
|
|
|
3
|
-
import { IValidation, TypeGuardError } from "typia";
|
|
3
|
+
import typia, { IValidation, TypeGuardError } from "typia";
|
|
4
4
|
|
|
5
5
|
import { IResponseBodyStringifier } from "../../options/IResponseBodyStringifier";
|
|
6
6
|
import { TransformError } from "./TransformError";
|
|
@@ -41,7 +41,7 @@ const assert =
|
|
|
41
41
|
try {
|
|
42
42
|
return closure(data);
|
|
43
43
|
} catch (exp) {
|
|
44
|
-
if (exp
|
|
44
|
+
if (typia.is<TypeGuardError>(exp))
|
|
45
45
|
throw new InternalServerErrorException({
|
|
46
46
|
path: exp.path,
|
|
47
47
|
reason: exp.message,
|
|
@@ -49,7 +49,6 @@ const assert =
|
|
|
49
49
|
value: exp.value,
|
|
50
50
|
message: MESSAGE,
|
|
51
51
|
});
|
|
52
|
-
}
|
|
53
52
|
throw exp;
|
|
54
53
|
}
|
|
55
54
|
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BadRequestException, ExecutionContext } from "@nestjs/common";
|
|
2
|
+
import type express from "express";
|
|
3
|
+
import type { FastifyReply } from "fastify";
|
|
4
|
+
|
|
5
|
+
export const send_bad_request =
|
|
6
|
+
(context: ExecutionContext) =>
|
|
7
|
+
(error: BadRequestException): void => {
|
|
8
|
+
const response: express.Response | FastifyReply = context
|
|
9
|
+
.switchToHttp()
|
|
10
|
+
.getResponse();
|
|
11
|
+
response.status(error.getStatus()).send(error.getResponse());
|
|
12
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BadRequestException } from "@nestjs/common";
|
|
2
2
|
|
|
3
|
-
import { IValidation, TypeGuardError } from "typia";
|
|
3
|
+
import typia, { IValidation, TypeGuardError } from "typia";
|
|
4
4
|
|
|
5
5
|
import { IRequestBodyValidator } from "../../options/IRequestBodyValidator";
|
|
6
6
|
import { TransformError } from "./TransformError";
|
|
@@ -8,14 +8,15 @@ import { TransformError } from "./TransformError";
|
|
|
8
8
|
export const validate_request_body =
|
|
9
9
|
(method: string) =>
|
|
10
10
|
<T>(validator?: IRequestBodyValidator<T>) => {
|
|
11
|
-
if (!validator)
|
|
11
|
+
if (!validator) return () => TransformError(method);
|
|
12
12
|
else if (validator.type === "assert") return assert(validator.assert);
|
|
13
13
|
else if (validator.type === "is") return is(validator.is);
|
|
14
14
|
else if (validator.type === "validate")
|
|
15
15
|
return validate(validator.validate);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
return () =>
|
|
17
|
+
new Error(
|
|
18
|
+
`Error on nestia.core.${method}(): invalid typed validator.`,
|
|
19
|
+
);
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
const assert =
|
|
@@ -23,9 +24,10 @@ const assert =
|
|
|
23
24
|
(data: T) => {
|
|
24
25
|
try {
|
|
25
26
|
closure(data);
|
|
27
|
+
return null;
|
|
26
28
|
} catch (exp) {
|
|
27
|
-
if (exp
|
|
28
|
-
|
|
29
|
+
if (typia.is<TypeGuardError>(exp)) {
|
|
30
|
+
return new BadRequestException({
|
|
29
31
|
path: exp.path,
|
|
30
32
|
reason: exp.message,
|
|
31
33
|
expected: exp.expected,
|
|
@@ -41,18 +43,19 @@ const is =
|
|
|
41
43
|
<T>(closure: (data: T) => boolean) =>
|
|
42
44
|
(data: T) => {
|
|
43
45
|
const success: boolean = closure(data);
|
|
44
|
-
|
|
46
|
+
return success ? null : new BadRequestException(MESSAGE);
|
|
45
47
|
};
|
|
46
48
|
|
|
47
49
|
const validate =
|
|
48
50
|
<T>(closure: (data: T) => IValidation<T>) =>
|
|
49
51
|
(data: T) => {
|
|
50
52
|
const result: IValidation<T> = closure(data);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
return result.success
|
|
54
|
+
? null
|
|
55
|
+
: new BadRequestException({
|
|
56
|
+
errors: result.errors,
|
|
57
|
+
message: MESSAGE,
|
|
58
|
+
});
|
|
56
59
|
};
|
|
57
60
|
|
|
58
61
|
const MESSAGE = "Request body data is not following the promised type.";
|