@nestia/core 3.0.0-dev.20231209 → 3.0.0

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 (132) hide show
  1. package/README.md +12 -9
  2. package/lib/decorators/DynamicModule.js +3 -3
  3. package/lib/decorators/DynamicModule.js.map +1 -1
  4. package/lib/decorators/EncryptedBody.js +14 -13
  5. package/lib/decorators/EncryptedBody.js.map +1 -1
  6. package/lib/decorators/EncryptedModule.d.ts +1 -1
  7. package/lib/decorators/EncryptedModule.js +45 -21
  8. package/lib/decorators/EncryptedModule.js.map +1 -1
  9. package/lib/decorators/EncryptedRoute.d.ts +5 -5
  10. package/lib/decorators/EncryptedRoute.js +12 -29
  11. package/lib/decorators/EncryptedRoute.js.map +1 -1
  12. package/lib/decorators/PlainBody.js +3 -0
  13. package/lib/decorators/PlainBody.js.map +1 -1
  14. package/lib/decorators/SwaggerCustomizer.d.ts +79 -0
  15. package/lib/decorators/SwaggerCustomizer.js +32 -0
  16. package/lib/decorators/SwaggerCustomizer.js.map +1 -0
  17. package/lib/decorators/TypedBody.js +3 -0
  18. package/lib/decorators/TypedBody.js.map +1 -1
  19. package/lib/decorators/TypedException.d.ts +0 -1
  20. package/lib/decorators/TypedException.js +0 -1
  21. package/lib/decorators/TypedException.js.map +1 -1
  22. package/lib/decorators/TypedFormData.d.ts +60 -0
  23. package/lib/decorators/TypedFormData.js +403 -0
  24. package/lib/decorators/TypedFormData.js.map +1 -0
  25. package/lib/decorators/TypedQuery.d.ts +11 -6
  26. package/lib/decorators/TypedQuery.js +6 -1
  27. package/lib/decorators/TypedQuery.js.map +1 -1
  28. package/lib/decorators/TypedRoute.d.ts +5 -5
  29. package/lib/decorators/internal/get_path_and_querify.js +3 -0
  30. package/lib/decorators/internal/get_path_and_querify.js.map +1 -1
  31. package/lib/decorators/internal/load_controller.js.map +1 -1
  32. package/lib/decorators/internal/validate_request_body.d.ts +1 -3
  33. package/lib/decorators/internal/validate_request_body.js +15 -0
  34. package/lib/decorators/internal/validate_request_body.js.map +1 -1
  35. package/lib/decorators/internal/validate_request_form_data.js +79 -0
  36. package/lib/decorators/internal/validate_request_form_data.js.map +1 -0
  37. package/lib/decorators/internal/validate_request_headers.d.ts +1 -3
  38. package/lib/decorators/internal/validate_request_headers.js +15 -0
  39. package/lib/decorators/internal/validate_request_headers.js.map +1 -1
  40. package/lib/decorators/internal/validate_request_query.d.ts +1 -3
  41. package/lib/decorators/internal/validate_request_query.js +15 -0
  42. package/lib/decorators/internal/validate_request_query.js.map +1 -1
  43. package/lib/module.d.ts +2 -0
  44. package/lib/module.js +2 -0
  45. package/lib/module.js.map +1 -1
  46. package/lib/options/IRequestFormDataProps.d.ts +23 -0
  47. package/lib/options/IRequestFormDataProps.js +3 -0
  48. package/lib/options/IRequestFormDataProps.js.map +1 -0
  49. package/lib/programmers/PlainBodyProgrammer.js +1 -1
  50. package/lib/programmers/PlainBodyProgrammer.js.map +1 -1
  51. package/lib/programmers/TypedExceptionProgrammer.js +5 -5
  52. package/lib/programmers/TypedExceptionProgrammer.js.map +1 -1
  53. package/lib/programmers/TypedFormDataBodyProgrammer.d.ts +6 -0
  54. package/lib/programmers/TypedFormDataBodyProgrammer.js +84 -0
  55. package/lib/programmers/TypedFormDataBodyProgrammer.js.map +1 -0
  56. package/lib/programmers/http/HttpQuerifyProgrammer.js +2 -2
  57. package/lib/programmers/http/HttpQuerifyProgrammer.js.map +1 -1
  58. package/lib/transformers/NodeTransformer.js.map +1 -1
  59. package/lib/transformers/ParameterDecoratorTransformer.js +7 -1
  60. package/lib/transformers/ParameterDecoratorTransformer.js.map +1 -1
  61. package/lib/transformers/TypedExceptionTransformer.js +1 -1
  62. package/lib/transformers/TypedExceptionTransformer.js.map +1 -1
  63. package/lib/transformers/TypedRouteTransformer.js +1 -1
  64. package/lib/transformers/TypedRouteTransformer.js.map +1 -1
  65. package/package.json +15 -16
  66. package/src/decorators/DynamicModule.ts +39 -39
  67. package/src/decorators/EncryptedBody.ts +105 -107
  68. package/src/decorators/EncryptedController.ts +38 -38
  69. package/src/decorators/EncryptedModule.ts +96 -79
  70. package/src/decorators/EncryptedRoute.ts +182 -206
  71. package/src/decorators/PlainBody.ts +75 -72
  72. package/src/decorators/SwaggerCustomizer.ts +115 -0
  73. package/src/decorators/TypedBody.ts +62 -59
  74. package/src/decorators/TypedException.ts +90 -89
  75. package/src/decorators/TypedFormData.ts +219 -0
  76. package/src/decorators/TypedHeaders.ts +69 -69
  77. package/src/decorators/TypedParam.ts +65 -65
  78. package/src/decorators/TypedQuery.ts +251 -246
  79. package/src/decorators/TypedRoute.ts +144 -144
  80. package/src/decorators/internal/EncryptedConstant.ts +4 -4
  81. package/src/decorators/internal/NoTransformConfigureError.ts +8 -8
  82. package/src/decorators/internal/get_path_and_querify.ts +106 -103
  83. package/src/decorators/internal/get_path_and_stringify.ts +91 -91
  84. package/src/decorators/internal/get_text_body.ts +20 -20
  85. package/src/decorators/internal/headers_to_object.ts +13 -13
  86. package/src/decorators/internal/load_controller.ts +51 -51
  87. package/src/decorators/internal/route_error.ts +45 -45
  88. package/src/decorators/internal/validate_request_body.ts +72 -57
  89. package/src/decorators/internal/validate_request_form_data.ts +75 -0
  90. package/src/decorators/internal/validate_request_headers.ts +83 -68
  91. package/src/decorators/internal/validate_request_query.ts +71 -56
  92. package/src/index.ts +5 -5
  93. package/src/module.ts +16 -14
  94. package/src/options/INestiaTransformOptions.ts +17 -17
  95. package/src/options/INestiaTransformProject.ts +7 -7
  96. package/src/options/IRequestBodyValidator.ts +20 -20
  97. package/src/options/IRequestFormDataProps.ts +27 -0
  98. package/src/options/IRequestHeadersValidator.ts +22 -22
  99. package/src/options/IRequestQueryValidator.ts +20 -20
  100. package/src/options/IResponseBodyQuerifier.ts +25 -25
  101. package/src/options/IResponseBodyStringifier.ts +25 -25
  102. package/src/programmers/PlainBodyProgrammer.ts +52 -52
  103. package/src/programmers/TypedBodyProgrammer.ts +108 -108
  104. package/src/programmers/TypedExceptionProgrammer.ts +71 -72
  105. package/src/programmers/TypedFormDataBodyProgrammer.ts +108 -0
  106. package/src/programmers/TypedHeadersProgrammer.ts +56 -56
  107. package/src/programmers/TypedParamProgrammer.ts +24 -24
  108. package/src/programmers/TypedQueryBodyProgrammer.ts +56 -56
  109. package/src/programmers/TypedQueryProgrammer.ts +56 -56
  110. package/src/programmers/TypedQueryRouteProgrammer.ts +51 -51
  111. package/src/programmers/TypedRouteProgrammer.ts +51 -51
  112. package/src/programmers/http/HttpAssertQuerifyProgrammer.ts +58 -58
  113. package/src/programmers/http/HttpIsQuerifyProgrammer.ts +62 -62
  114. package/src/programmers/http/HttpQuerifyProgrammer.ts +96 -96
  115. package/src/programmers/http/HttpValidateQuerifyProgrammer.ts +63 -63
  116. package/src/programmers/internal/CoreMetadataUtil.ts +21 -21
  117. package/src/transform.ts +35 -35
  118. package/src/transformers/FileTransformer.ts +66 -66
  119. package/src/transformers/MethodTransformer.ts +94 -94
  120. package/src/transformers/NodeTransformer.ts +16 -16
  121. package/src/transformers/ParameterDecoratorTransformer.ts +120 -121
  122. package/src/transformers/ParameterTransformer.ts +48 -48
  123. package/src/transformers/TypedExceptionTransformer.ts +48 -49
  124. package/src/transformers/TypedRouteTransformer.ts +88 -95
  125. package/src/typings/Creator.ts +3 -3
  126. package/src/utils/ExceptionManager.ts +112 -112
  127. package/src/utils/Singleton.ts +20 -20
  128. package/src/utils/SourceFinder.ts +57 -57
  129. package/lib/decorators/internal/get_binary_body.js +0 -66
  130. package/lib/decorators/internal/get_binary_body.js.map +0 -1
  131. package/src/decorators/internal/get_binary_body.ts +0 -18
  132. /package/lib/decorators/internal/{get_binary_body.d.ts → validate_request_form_data.d.ts} +0 -0
@@ -1,79 +1,96 @@
1
- import { IEncryptionPassword } from "@nestia/fetcher/lib/IEncryptionPassword";
2
- import { Module } from "@nestjs/common";
3
-
4
- import { Creator } from "../typings/Creator";
5
- import { ENCRYPTION_METADATA_KEY } from "./internal/EncryptedConstant";
6
- import { load_controllers } from "./internal/load_controller";
7
-
8
- /**
9
- * Encrypted module.
10
- *
11
- * `EncryptedModule` is an extension of the {@link Module} class decorator function
12
- * who configures encryption password of the AES-128/256 algorithm. The encryption
13
- * algorithm and password would be used by {@link EncryptedRoute} and {@link EncryptedBody}
14
- * to encrypt the request and response bod of the HTTP protocol.
15
- *
16
- * By using this `EncryptedModule` decorator function, all of the
17
- * {@link Controller controllers} configured in the *metadata* would be automatically
18
- * changed to the {@link EncryptedController} with the *password*. If there're some
19
- * original {@link EncryptedController} decorated classes in the *metadata*, their
20
- * encryption password would be kept.
21
- *
22
- * Therefore, if you're planning to place original {@link EncryptedController} decorated
23
- * classes in the *metadata*, I hope them to have different encryption password from the
24
- * module level. If not, I recommend you use the {@link Controller} decorator
25
- * function instead.
26
- *
27
- * In addition, the `EncryptedModule` supports a convenient dynamic controller importing
28
- * function, {@link EncryptedModule.dynamic}. If you utilize the function with directory
29
- * path of the controller classes, it imports and configures the controller classes into
30
- * the `Module`, automatically.
31
- *
32
- * @param metadata Module configuration metadata
33
- * @param password Encryption password or its getter function
34
- * @returns Class decorator
35
- *
36
- * @author Jeongho Nam - https://github.com/samchon
37
- */
38
- export function EncryptedModule(
39
- metadata: Parameters<typeof Module>[0],
40
- password: IEncryptionPassword | IEncryptionPassword.Closure,
41
- ): ClassDecorator {
42
- return function (target: any) {
43
- Module(metadata)(target);
44
- if (metadata.controllers === undefined) return;
45
-
46
- for (const c of metadata.controllers)
47
- if (Reflect.hasMetadata(ENCRYPTION_METADATA_KEY, c) === false)
48
- Reflect.defineMetadata(ENCRYPTION_METADATA_KEY, password, c);
49
- };
50
- }
51
-
52
- export namespace EncryptedModule {
53
- /**
54
- * Dynamic encrypted module.
55
- *
56
- * `EncryptedModule.dynamic` is an extension of the {@link EncryptedModule} function
57
- * who configures controller classes by the dynamic importing. By specifying directory
58
- * path of the controller classes, those controllers would be automatically imported
59
- * and configured.
60
- *
61
- * @param path Directory path of the controller classes
62
- * @param password Encryption password or its getter function
63
- * @param options Additional options except controller
64
- * @returns Class decorated module instance
65
- */
66
- export async function dynamic(
67
- path: string | string[] | { include: string[]; exclude?: string[] },
68
- password: IEncryptionPassword | IEncryptionPassword.Closure,
69
- options: Omit<Parameters<typeof Module>[0], "controllers"> = {},
70
- ): Promise<object> {
71
- // LOAD CONTROLLERS
72
- const controllers: Creator<object>[] = await load_controllers(path);
73
-
74
- // RETURNS WITH DECORATING
75
- @EncryptedModule({ ...options, controllers }, password)
76
- class NestiaModule {}
77
- return NestiaModule;
78
- }
79
- }
1
+ import { IEncryptionPassword } from "@nestia/fetcher/lib/IEncryptionPassword";
2
+ import { Module } from "@nestjs/common";
3
+
4
+ import { Creator } from "../typings/Creator";
5
+ import { ENCRYPTION_METADATA_KEY } from "./internal/EncryptedConstant";
6
+ import { load_controllers } from "./internal/load_controller";
7
+
8
+ /**
9
+ * Encrypted module.
10
+ *
11
+ * `EncryptedModule` is an extension of the {@link Module} class decorator function
12
+ * who configures encryption password of the AES-128/256 algorithm. The encryption
13
+ * algorithm and password would be used by {@link EncryptedRoute} and {@link EncryptedBody}
14
+ * to encrypt the request and response bod of the HTTP protocol.
15
+ *
16
+ * By using this `EncryptedModule` decorator function, all of the
17
+ * {@link Controller controllers} configured in the *metadata* would be automatically
18
+ * changed to the {@link EncryptedController} with the *password*. If there're some
19
+ * original {@link EncryptedController} decorated classes in the *metadata*, their
20
+ * encryption password would be kept.
21
+ *
22
+ * Therefore, if you're planning to place original {@link EncryptedController} decorated
23
+ * classes in the *metadata*, I hope them to have different encryption password from the
24
+ * module level. If not, I recommend you use the {@link Controller} decorator
25
+ * function instead.
26
+ *
27
+ * In addition, the `EncryptedModule` supports a convenient dynamic controller importing
28
+ * function, {@link EncryptedModule.dynamic}. If you utilize the function with directory
29
+ * path of the controller classes, it imports and configures the controller classes into
30
+ * the `Module`, automatically.
31
+ *
32
+ * @param metadata Module configuration metadata
33
+ * @param password Encryption password or its getter function
34
+ * @returns Class decorator
35
+ *
36
+ * @author Jeongho Nam - https://github.com/samchon
37
+ */
38
+ export function EncryptedModule(
39
+ metadata: Parameters<typeof Module>[0],
40
+ password: IEncryptionPassword.Closure,
41
+ ): ClassDecorator {
42
+ return function (target: any) {
43
+ Module(metadata)(target);
44
+ iterate(password)(target);
45
+ };
46
+ }
47
+
48
+ export namespace EncryptedModule {
49
+ /**
50
+ * Dynamic encrypted module.
51
+ *
52
+ * `EncryptedModule.dynamic` is an extension of the {@link EncryptedModule} function
53
+ * who configures controller classes by the dynamic importing. By specifying directory
54
+ * path of the controller classes, those controllers would be automatically imported
55
+ * and configured.
56
+ *
57
+ * @param path Directory path of the controller classes
58
+ * @param password Encryption password or its getter function
59
+ * @param options Additional options except controller
60
+ * @returns Class decorated module instance
61
+ */
62
+ export async function dynamic(
63
+ path: string | string[] | { include: string[]; exclude?: string[] },
64
+ password: IEncryptionPassword | IEncryptionPassword.Closure,
65
+ options: Omit<Parameters<typeof Module>[0], "controllers"> = {},
66
+ ): Promise<object> {
67
+ // LOAD CONTROLLERS
68
+ const controllers: Creator<object>[] = await load_controllers(path);
69
+
70
+ // RETURNS WITH DECORATING
71
+ @EncryptedModule(
72
+ { ...options, controllers },
73
+ typeof password === "object" ? () => password : password,
74
+ )
75
+ class NestiaModule {}
76
+ return NestiaModule;
77
+ }
78
+ }
79
+
80
+ /**
81
+ * @internal
82
+ */
83
+ const iterate =
84
+ (password: IEncryptionPassword.Closure) =>
85
+ (modulo: any): void => {
86
+ const imports = Reflect.getMetadata("imports", modulo);
87
+ if (Array.isArray(imports))
88
+ for (const imp of imports)
89
+ if (typeof imp === "function") iterate(password)(imp);
90
+
91
+ const controllers = Reflect.getMetadata("controllers", modulo);
92
+ if (Array.isArray(controllers))
93
+ for (const c of controllers)
94
+ if (typeof c === "function")
95
+ Reflect.defineMetadata(ENCRYPTION_METADATA_KEY, password, c);
96
+ };
@@ -1,206 +1,182 @@
1
- import { IEncryptionPassword } from "@nestia/fetcher/lib/IEncryptionPassword";
2
- import { AesPkcs5 } from "@nestia/fetcher/lib/internal/AesPkcs5";
3
- import {
4
- CallHandler,
5
- Delete,
6
- ExecutionContext,
7
- Get,
8
- NestInterceptor,
9
- Patch,
10
- Post,
11
- Put,
12
- UseInterceptors,
13
- applyDecorators,
14
- } from "@nestjs/common";
15
- import { HttpArgumentsHost } from "@nestjs/common/interfaces";
16
- import express from "express";
17
- import type { FastifyRequest } from "fastify";
18
- import { catchError, map } from "rxjs/operators";
19
- import typia from "typia";
20
-
21
- import { IResponseBodyStringifier } from "../options/IResponseBodyStringifier";
22
- import { Singleton } from "../utils/Singleton";
23
- import { ENCRYPTION_METADATA_KEY } from "./internal/EncryptedConstant";
24
- import { NoTransformConfigureError } from "./internal/NoTransformConfigureError";
25
- import { get_path_and_stringify } from "./internal/get_path_and_stringify";
26
- import { headers_to_object } from "./internal/headers_to_object";
27
- import { route_error } from "./internal/route_error";
28
-
29
- /**
30
- * Encrypted router decorator functions.
31
- *
32
- * `EncryptedRoute` is a module containing router decorator functions which encrypts
33
- * response body data through AES-128/256 encryption. Furthermore, they can boost
34
- * up JSON string conversion speed about 50x times faster than `class-transformer`,
35
- * even type safe through [typia](https://github.com/samchon/typia).
36
- *
37
- * For reference, if you try to invalid data that is not following the promised
38
- * type `T`, 500 internal server error would be thrown. Also, as `EncryptedRoute`
39
- * composes JSON string through `typia.assertStringify<T>()` function, it is not
40
- * possible to modify response data through interceptors.
41
- *
42
- * - AES-128/256
43
- * - CBC mode
44
- * - PKCS #5 Padding
45
- * - Base64 Encoding
46
- *
47
- * @author Jeongho Nam - https://github.com/samchon
48
- */
49
- export namespace EncryptedRoute {
50
- /**
51
- * Encrypted router decorator function for the GET method.
52
- *
53
- * @param paths Path(s) of the HTTP request
54
- * @returns Method decorator
55
- */
56
- export const Get = Generator("Get");
57
-
58
- /**
59
- * Encrypted router decorator function for the GET method.
60
- *
61
- * @param paths Path(s) of the HTTP request
62
- * @returns Method decorator
63
- */
64
- export const Post = Generator("Post");
65
-
66
- /**
67
- * Encrypted router decorator function for the PATCH method.
68
- *
69
- * @param path Path of the HTTP request
70
- * @returns Method decorator
71
- */
72
- export const Patch = Generator("Patch");
73
-
74
- /**
75
- * Encrypted router decorator function for the PUT method.
76
- *
77
- * @param path Path of the HTTP request
78
- * @returns Method decorator
79
- */
80
- export const Put = Generator("Put");
81
-
82
- /**
83
- * Encrypted router decorator function for the DELETE method.
84
- *
85
- * @param path Path of the HTTP request
86
- * @returns Method decorator
87
- */
88
- export const Delete = Generator("Delete");
89
-
90
- function Generator(method: "Get" | "Post" | "Put" | "Patch" | "Delete") {
91
- function route(path?: string | string[]): MethodDecorator;
92
- function route<T>(
93
- stringify?: IResponseBodyStringifier<T> | null,
94
- ): MethodDecorator;
95
- function route<T>(
96
- path: string | string[],
97
- stringify?: IResponseBodyStringifier<T> | null,
98
- ): MethodDecorator;
99
-
100
- function route(...args: any[]): MethodDecorator {
101
- const [path, stringify] = get_path_and_stringify(
102
- `EncryptedRoute.${method}`,
103
- )(...args);
104
- return applyDecorators(
105
- ROUTERS[method](path),
106
- UseInterceptors(new EncryptedRouteInterceptor(method, stringify)),
107
- );
108
- }
109
- return route;
110
- }
111
- }
112
-
113
- for (const method of [
114
- typia.json.isStringify,
115
- typia.json.assertStringify,
116
- typia.json.validateStringify,
117
- typia.json.stringify,
118
- ])
119
- for (const [key, value] of Object.entries(method))
120
- for (const deco of [
121
- EncryptedRoute.Get,
122
- EncryptedRoute.Delete,
123
- EncryptedRoute.Post,
124
- EncryptedRoute.Put,
125
- EncryptedRoute.Patch,
126
- ])
127
- (deco as any)[key] = value;
128
-
129
- /**
130
- * @internal
131
- */
132
- class EncryptedRouteInterceptor implements NestInterceptor {
133
- private readonly success: number;
134
-
135
- public constructor(
136
- private readonly method: string,
137
- private readonly stringify: (input: any) => string,
138
- ) {
139
- this.success =
140
- this.method === "GET" || this.method === "DELETE" ? 200 : 201;
141
- }
142
-
143
- public intercept(context: ExecutionContext, next: CallHandler) {
144
- const http: HttpArgumentsHost = context.switchToHttp();
145
- return next.handle().pipe(
146
- map((value) => {
147
- const param:
148
- | IEncryptionPassword
149
- | IEncryptionPassword.Closure
150
- | undefined = Reflect.getMetadata(
151
- ENCRYPTION_METADATA_KEY,
152
- context.getClass(),
153
- );
154
- if (!param)
155
- throw NoTransformConfigureError(`EncryptedRoute.${this.method}`);
156
-
157
- const headers: Singleton<Record<string, string>> = new Singleton(() => {
158
- const request: express.Request = http.getRequest();
159
- return headers_to_object(request.headers);
160
- });
161
- const body: Uint8Array = (() => {
162
- const body = this.stringify(value);
163
- if (body === undefined) return Buffer.from([]);
164
-
165
- const password: IEncryptionPassword =
166
- typeof param === "function"
167
- ? param({
168
- body,
169
- direction: "encode",
170
- headers: headers.get(),
171
- })
172
- : param;
173
- return AesPkcs5.encrypt(body, password.key, password.iv);
174
- })();
175
- // return body;
176
- const response: express.Response = http.getResponse();
177
- if (isExpressRequest(http.getRequest()))
178
- response
179
- .header("Content-Type", "application/octet-stream")
180
- .status(this.success)
181
- .send(body)
182
- .end();
183
- return body;
184
- }),
185
- catchError((err) => route_error(http.getRequest(), err)),
186
- );
187
- }
188
- }
189
-
190
- /**
191
- * @internal
192
- */
193
- const ROUTERS = {
194
- Get,
195
- Post,
196
- Put,
197
- Patch,
198
- Delete,
199
- };
200
-
201
- /**
202
- * @internal
203
- */
204
- const isExpressRequest = (
205
- request: express.Request | FastifyRequest,
206
- ): request is express.Request => (request as express.Request).app !== undefined;
1
+ import { AesPkcs5 } from "@nestia/fetcher/lib/AesPkcs5";
2
+ import { IEncryptionPassword } from "@nestia/fetcher/lib/IEncryptionPassword";
3
+ import {
4
+ CallHandler,
5
+ Delete,
6
+ ExecutionContext,
7
+ Get,
8
+ NestInterceptor,
9
+ Patch,
10
+ Post,
11
+ Put,
12
+ UseInterceptors,
13
+ applyDecorators,
14
+ } from "@nestjs/common";
15
+ import { HttpArgumentsHost } from "@nestjs/common/interfaces";
16
+ import express from "express";
17
+ import { catchError, map } from "rxjs/operators";
18
+ import typia from "typia";
19
+
20
+ import { IResponseBodyStringifier } from "../options/IResponseBodyStringifier";
21
+ import { Singleton } from "../utils/Singleton";
22
+ import { ENCRYPTION_METADATA_KEY } from "./internal/EncryptedConstant";
23
+ import { NoTransformConfigureError } from "./internal/NoTransformConfigureError";
24
+ import { get_path_and_stringify } from "./internal/get_path_and_stringify";
25
+ import { headers_to_object } from "./internal/headers_to_object";
26
+ import { route_error } from "./internal/route_error";
27
+
28
+ /**
29
+ * Encrypted router decorator functions.
30
+ *
31
+ * `EncryptedRoute` is a module containing router decorator functions which encrypts
32
+ * response body data through AES-128/256 encryption. Furthermore, they can boost
33
+ * up JSON string conversion speed about 50x times faster than `class-transformer`,
34
+ * even type safe through [typia](https://github.com/samchon/typia).
35
+ *
36
+ * For reference, if you try to invalid data that is not following the promised
37
+ * type `T`, 500 internal server error would be thrown. Also, as `EncryptedRoute`
38
+ * composes JSON string through `typia.assertStringify<T>()` function, it is not
39
+ * possible to modify response data through interceptors.
40
+ *
41
+ * - AES-128/256
42
+ * - CBC mode
43
+ * - PKCS #5 Padding
44
+ * - Base64 Encoding
45
+ *
46
+ * @author Jeongho Nam - https://github.com/samchon
47
+ */
48
+ export namespace EncryptedRoute {
49
+ /**
50
+ * Encrypted router decorator function for the GET method.
51
+ *
52
+ * @param paths Path(s) of the HTTP request
53
+ * @returns Method decorator
54
+ */
55
+ export const Get = Generator("Get");
56
+
57
+ /**
58
+ * Encrypted router decorator function for the GET method.
59
+ *
60
+ * @param paths Path(s) of the HTTP request
61
+ * @returns Method decorator
62
+ */
63
+ export const Post = Generator("Post");
64
+
65
+ /**
66
+ * Encrypted router decorator function for the PATCH method.
67
+ *
68
+ * @param path Path of the HTTP request
69
+ * @returns Method decorator
70
+ */
71
+ export const Patch = Generator("Patch");
72
+
73
+ /**
74
+ * Encrypted router decorator function for the PUT method.
75
+ *
76
+ * @param path Path of the HTTP request
77
+ * @returns Method decorator
78
+ */
79
+ export const Put = Generator("Put");
80
+
81
+ /**
82
+ * Encrypted router decorator function for the DELETE method.
83
+ *
84
+ * @param path Path of the HTTP request
85
+ * @returns Method decorator
86
+ */
87
+ export const Delete = Generator("Delete");
88
+
89
+ function Generator(method: "Get" | "Post" | "Put" | "Patch" | "Delete") {
90
+ function route(path?: string | string[]): MethodDecorator;
91
+ function route<T>(
92
+ stringify?: IResponseBodyStringifier<T> | null,
93
+ ): MethodDecorator;
94
+ function route<T>(
95
+ path: string | string[],
96
+ stringify?: IResponseBodyStringifier<T> | null,
97
+ ): MethodDecorator;
98
+
99
+ function route(...args: any[]): MethodDecorator {
100
+ const [path, stringify] = get_path_and_stringify(
101
+ `EncryptedRoute.${method}`,
102
+ )(...args);
103
+ return applyDecorators(
104
+ ROUTERS[method](path),
105
+ UseInterceptors(new EncryptedRouteInterceptor(method, stringify)),
106
+ );
107
+ }
108
+ return route;
109
+ }
110
+ }
111
+
112
+ for (const method of [
113
+ typia.json.isStringify,
114
+ typia.json.assertStringify,
115
+ typia.json.validateStringify,
116
+ typia.json.stringify,
117
+ ])
118
+ for (const [key, value] of Object.entries(method))
119
+ for (const deco of [
120
+ EncryptedRoute.Get,
121
+ EncryptedRoute.Delete,
122
+ EncryptedRoute.Post,
123
+ EncryptedRoute.Put,
124
+ EncryptedRoute.Patch,
125
+ ])
126
+ (deco as any)[key] = value;
127
+
128
+ /**
129
+ * @internal
130
+ */
131
+ class EncryptedRouteInterceptor implements NestInterceptor {
132
+ public constructor(
133
+ private readonly method: string,
134
+ private readonly stringify: (input: any) => string,
135
+ ) {}
136
+
137
+ public intercept(context: ExecutionContext, next: CallHandler) {
138
+ const http: HttpArgumentsHost = context.switchToHttp();
139
+ return next.handle().pipe(
140
+ map((value) => {
141
+ const param:
142
+ | IEncryptionPassword
143
+ | IEncryptionPassword.Closure
144
+ | undefined = Reflect.getMetadata(
145
+ ENCRYPTION_METADATA_KEY,
146
+ context.getClass(),
147
+ );
148
+ if (!param)
149
+ throw NoTransformConfigureError(`EncryptedRoute.${this.method}`);
150
+
151
+ const headers: Singleton<Record<string, string>> = new Singleton(() => {
152
+ const request: express.Request = http.getRequest();
153
+ return headers_to_object(request.headers);
154
+ });
155
+ const body: string | undefined = this.stringify(value);
156
+ const password: IEncryptionPassword =
157
+ typeof param === "function"
158
+ ? param({
159
+ headers: headers.get(),
160
+ body,
161
+ direction: "encode",
162
+ })
163
+ : param;
164
+
165
+ if (body === undefined) return body;
166
+ return AesPkcs5.encrypt(body, password.key, password.iv);
167
+ }),
168
+ catchError((err) => route_error(http.getRequest(), err)),
169
+ );
170
+ }
171
+ }
172
+
173
+ /**
174
+ * @internal
175
+ */
176
+ const ROUTERS = {
177
+ Get,
178
+ Post,
179
+ Put,
180
+ Patch,
181
+ Delete,
182
+ };