@nattyjs/core 0.0.1-beta.3 → 0.0.1-beta.31
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/dist/index.cjs +111 -36
- package/dist/index.d.ts +91 -59
- package/dist/index.mjs +106 -37
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -60,10 +60,13 @@ const nattyContainer = new class {
|
|
|
60
60
|
this.container = /* @__PURE__ */ new Map();
|
|
61
61
|
this.containerState = /* @__PURE__ */ new Map();
|
|
62
62
|
}
|
|
63
|
-
|
|
63
|
+
get types() {
|
|
64
|
+
return common.commonContainer.types;
|
|
65
|
+
}
|
|
66
|
+
setup(config, routes, resolver) {
|
|
64
67
|
this.config = config;
|
|
65
68
|
this.routes = routes;
|
|
66
|
-
this.
|
|
69
|
+
this.resolver = resolver;
|
|
67
70
|
}
|
|
68
71
|
getTypes() {
|
|
69
72
|
return StaticContainer.types;
|
|
@@ -116,7 +119,7 @@ const nattyContainer = new class {
|
|
|
116
119
|
function init(config, appConfig) {
|
|
117
120
|
common.commonContainer.setupConfig(config);
|
|
118
121
|
common.commonContainer.setEnvTsDefinition(appConfig.envTsDefinition);
|
|
119
|
-
nattyContainer.setup(config, appConfig.routes, appConfig.
|
|
122
|
+
nattyContainer.setup(config, appConfig.routes, appConfig.resolver);
|
|
120
123
|
return initializeModule(config);
|
|
121
124
|
}
|
|
122
125
|
function initializeModule(config) {
|
|
@@ -125,22 +128,26 @@ function initializeModule(config) {
|
|
|
125
128
|
}
|
|
126
129
|
}
|
|
127
130
|
|
|
128
|
-
function getPreResponseBody(body) {
|
|
131
|
+
function getPreResponseBody(body, isBuffer = false) {
|
|
129
132
|
let bodyInfo;
|
|
130
133
|
if (body) {
|
|
131
|
-
if (
|
|
132
|
-
bodyInfo = {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
134
|
+
if (isBuffer)
|
|
135
|
+
bodyInfo = { buffer: body };
|
|
136
|
+
else {
|
|
137
|
+
if (common.isObject(body) || Array.isArray(body))
|
|
138
|
+
bodyInfo = { json: body };
|
|
139
|
+
const typeText = typeof body;
|
|
140
|
+
switch (typeText) {
|
|
141
|
+
case "string":
|
|
142
|
+
bodyInfo = { string: body };
|
|
143
|
+
break;
|
|
144
|
+
case "number":
|
|
145
|
+
bodyInfo = { number: body };
|
|
146
|
+
break;
|
|
147
|
+
case "boolean":
|
|
148
|
+
bodyInfo = { boolean: body };
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
144
151
|
}
|
|
145
152
|
}
|
|
146
153
|
return bodyInfo;
|
|
@@ -154,6 +161,7 @@ class HttpResponse {
|
|
|
154
161
|
}
|
|
155
162
|
setValues(responseInit) {
|
|
156
163
|
if (responseInit) {
|
|
164
|
+
this._isBuffer = responseInit.isBuffer;
|
|
157
165
|
if (responseInit.headers)
|
|
158
166
|
for (const [key, value] of Object.entries(responseInit.headers))
|
|
159
167
|
this.headers.append(key, value);
|
|
@@ -185,7 +193,7 @@ class HttpResponse {
|
|
|
185
193
|
return this._body;
|
|
186
194
|
}
|
|
187
195
|
set body(value) {
|
|
188
|
-
this._body = getPreResponseBody(value);
|
|
196
|
+
this._body = getPreResponseBody(value, this._isBuffer);
|
|
189
197
|
}
|
|
190
198
|
write(responseInit) {
|
|
191
199
|
this.setValues(responseInit);
|
|
@@ -207,6 +215,26 @@ var RequestPipeline = /* @__PURE__ */ ((RequestPipeline2) => {
|
|
|
207
215
|
return RequestPipeline2;
|
|
208
216
|
})(RequestPipeline || {});
|
|
209
217
|
|
|
218
|
+
function lessThan(value) {
|
|
219
|
+
return value ? value.replace(/</g, "<") : value;
|
|
220
|
+
}
|
|
221
|
+
function greaterThan(value) {
|
|
222
|
+
return value ? value.replace(/>/g, ">") : value;
|
|
223
|
+
}
|
|
224
|
+
function ampersand(value) {
|
|
225
|
+
return value ? value.replace(/&/g, "&") : value;
|
|
226
|
+
}
|
|
227
|
+
function doubleDash(value) {
|
|
228
|
+
return value ? value.replace(/--/g, "") : value;
|
|
229
|
+
}
|
|
230
|
+
function sanitizeSpecialCodes(value) {
|
|
231
|
+
value = ampersand(value);
|
|
232
|
+
value = lessThan(value);
|
|
233
|
+
value = greaterThan(value);
|
|
234
|
+
value = doubleDash(value);
|
|
235
|
+
return value;
|
|
236
|
+
}
|
|
237
|
+
|
|
210
238
|
function isBoolean(value) {
|
|
211
239
|
return typeof value === "boolean" || value === "1" || value === "true" || value === "0" || value === "false";
|
|
212
240
|
}
|
|
@@ -267,7 +295,7 @@ function toInt(value, radix = 0) {
|
|
|
267
295
|
}
|
|
268
296
|
function toString(value) {
|
|
269
297
|
if (isNotBlank(value))
|
|
270
|
-
return String(value);
|
|
298
|
+
return sanitizeSpecialCodes(String(value));
|
|
271
299
|
return value;
|
|
272
300
|
}
|
|
273
301
|
function whitelist(value, chars) {
|
|
@@ -348,6 +376,7 @@ class BaseResult {
|
|
|
348
376
|
}
|
|
349
377
|
|
|
350
378
|
function getResponseBodyObject(body, props) {
|
|
379
|
+
const sensitiveProps = common.commonContainer.nattyConfig?.secure?.sensitiveProps;
|
|
351
380
|
if (body instanceof common.List)
|
|
352
381
|
return getResponseBodyObject(body.values, body.props);
|
|
353
382
|
if (Array.isArray(body)) {
|
|
@@ -361,7 +390,8 @@ function getResponseBodyObject(body, props) {
|
|
|
361
390
|
const keys = Object.keys(body);
|
|
362
391
|
const getterProps = props ? Object.keys(props).map((key) => props[key]) : [];
|
|
363
392
|
for (const key of [...keys, ...getterProps])
|
|
364
|
-
|
|
393
|
+
if (!sensitiveProps || sensitiveProps.filter((t) => t == key.toLowerCase()).length == 0)
|
|
394
|
+
jObject[key] = getResponseBodyObject(body[key]);
|
|
365
395
|
return jObject;
|
|
366
396
|
}
|
|
367
397
|
return body;
|
|
@@ -524,12 +554,14 @@ class ParameterTypeConverter extends BaseResponse {
|
|
|
524
554
|
} else {
|
|
525
555
|
if (this.isArrayType(property.type) && Array.isArray(value)) {
|
|
526
556
|
let arrayValue = body[property.name] = [];
|
|
527
|
-
let arrayInvalidProps = invalidProps[property.name] = [];
|
|
528
557
|
for (const item of value) {
|
|
529
558
|
const sanitizeValue = this.sanitizer[property.type.toLowerCase()] ? this.sanitizer[property.type.toLowerCase()](item) : item;
|
|
530
|
-
if (sanitizeValue === INVALID_VALUE)
|
|
559
|
+
if (sanitizeValue === INVALID_VALUE) {
|
|
560
|
+
let arrayInvalidProps = invalidProps[property.name];
|
|
561
|
+
if (!arrayInvalidProps)
|
|
562
|
+
arrayInvalidProps = invalidProps[property.name] = [];
|
|
531
563
|
arrayInvalidProps.push(property);
|
|
532
|
-
else
|
|
564
|
+
} else
|
|
533
565
|
arrayValue.push(sanitizeValue);
|
|
534
566
|
}
|
|
535
567
|
} else
|
|
@@ -557,7 +589,7 @@ class ParameterTypeConverter extends BaseResponse {
|
|
|
557
589
|
}
|
|
558
590
|
convertToInstance(entityName, data) {
|
|
559
591
|
const typesInfo = this.types[entityName];
|
|
560
|
-
const target = this.getClassTarget(typesInfo.path) || entityContainer.getTarget(entityName);
|
|
592
|
+
const target = this.getClassTarget(typesInfo.path, entityName) || entityContainer.getTarget(entityName);
|
|
561
593
|
let instance = null;
|
|
562
594
|
if (target) {
|
|
563
595
|
instance = new target();
|
|
@@ -566,11 +598,10 @@ class ParameterTypeConverter extends BaseResponse {
|
|
|
566
598
|
instance = data;
|
|
567
599
|
return instance;
|
|
568
600
|
}
|
|
569
|
-
getClassTarget(
|
|
570
|
-
if (
|
|
571
|
-
const classInfo = resolver();
|
|
572
|
-
|
|
573
|
-
return classInfo[name];
|
|
601
|
+
getClassTarget(path, entityName) {
|
|
602
|
+
if (path) {
|
|
603
|
+
const classInfo = nattyContainer.resolver(path);
|
|
604
|
+
return classInfo[entityName];
|
|
574
605
|
}
|
|
575
606
|
return void 0;
|
|
576
607
|
}
|
|
@@ -847,6 +878,14 @@ class ActionExecutedContext extends AbstractExecutionContext {
|
|
|
847
878
|
}
|
|
848
879
|
}
|
|
849
880
|
|
|
881
|
+
class AuthorizationContext extends AbstractExecutionContext {
|
|
882
|
+
constructor(models, context, routeInfo, config) {
|
|
883
|
+
super(context, routeInfo);
|
|
884
|
+
this.models = models;
|
|
885
|
+
this.config = config;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
|
|
850
889
|
class RequestProcessor extends RouteParser {
|
|
851
890
|
constructor() {
|
|
852
891
|
super(...arguments);
|
|
@@ -857,9 +896,6 @@ class RequestProcessor extends RouteParser {
|
|
|
857
896
|
case RequestPipeline.onAuthentication:
|
|
858
897
|
await this.onAuthentication();
|
|
859
898
|
break;
|
|
860
|
-
case RequestPipeline.onAuthorization:
|
|
861
|
-
await this.onAuthorization();
|
|
862
|
-
break;
|
|
863
899
|
}
|
|
864
900
|
}
|
|
865
901
|
resolveFilter(instance) {
|
|
@@ -885,21 +921,27 @@ class RequestProcessor extends RouteParser {
|
|
|
885
921
|
this.httpContext.user = result;
|
|
886
922
|
if (!result.isAuthenticate && !anonymousInfo.controllerConfig && !anonymousInfo.methodConfig)
|
|
887
923
|
throw new UnauthorizedAccessException(authenticationFilter.onFailedResponse());
|
|
888
|
-
await this.onAuthorization();
|
|
889
924
|
}
|
|
890
925
|
}
|
|
891
|
-
async onAuthorization() {
|
|
926
|
+
async onAuthorization(methodParameters) {
|
|
892
927
|
const authorization = common.commonContainer.globalConfig.authorization;
|
|
893
928
|
const authorizationFilter = authorization ? this.resolveFilter(authorization) : void 0;
|
|
894
929
|
const authorizeConfig = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.authorize);
|
|
895
930
|
const authenticationOnly = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.authenticationOnly);
|
|
896
|
-
if (this.httpContext.user?.isAuthenticate && authorizationFilter && (!authenticationOnly.controllerConfig && !authenticationOnly.methodConfig)) {
|
|
897
|
-
const
|
|
931
|
+
if (this.httpContext.user?.isAuthenticate && authorizationFilter && (authorizeConfig.controllerConfig || authorizeConfig.methodConfig) && (!authenticationOnly.controllerConfig && !authenticationOnly.methodConfig)) {
|
|
932
|
+
const authorizationContext = new AuthorizationContext(
|
|
933
|
+
methodParameters.filter((t) => t instanceof ModelBindingContext),
|
|
934
|
+
this.httpContext,
|
|
935
|
+
this.routeInfo,
|
|
936
|
+
authorizeConfig.methodConfig || authorizeConfig.controllerConfig
|
|
937
|
+
);
|
|
938
|
+
const result = await authorizationFilter.onAuthorization(authorizationContext);
|
|
898
939
|
if (!result)
|
|
899
940
|
throw new ForbiddenAccessException(authorizationFilter.onFailedAuthorization());
|
|
900
941
|
}
|
|
901
942
|
}
|
|
902
943
|
async onActionExecuting(methodParameters) {
|
|
944
|
+
await this.onAuthorization(methodParameters);
|
|
903
945
|
let actionFilters = common.commonContainer.globalConfig.actionFilters || [];
|
|
904
946
|
const actionFiltersConfig = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.useFilter);
|
|
905
947
|
actionFilters = [...actionFilters, ...actionFiltersConfig.controllerConfig?.actionFilters || [], ...actionFiltersConfig.methodConfig?.actionFilters || []];
|
|
@@ -1205,6 +1247,16 @@ function badRequest(value, response) {
|
|
|
1205
1247
|
return new BadRequestResult(value || common.BLANK, response);
|
|
1206
1248
|
}
|
|
1207
1249
|
|
|
1250
|
+
class FileResult extends BaseResult {
|
|
1251
|
+
constructor(value, response) {
|
|
1252
|
+
super({ ...{ isBuffer: true, body: value }, ...{ status: HttpStatusCode.success } }, response);
|
|
1253
|
+
this.value = value;
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
function fileResult(value, response) {
|
|
1257
|
+
return new FileResult(value || common.BLANK, response);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1208
1260
|
function base(params, type, additionaConfig) {
|
|
1209
1261
|
decoratorStateContainer.register(params, type, additionaConfig);
|
|
1210
1262
|
}
|
|
@@ -1231,12 +1283,31 @@ function authenticationOnly() {
|
|
|
1231
1283
|
};
|
|
1232
1284
|
}
|
|
1233
1285
|
|
|
1286
|
+
function setEnvInfo(envTsDefinition, envValueInfo) {
|
|
1287
|
+
if (envTsDefinition && envValueInfo) {
|
|
1288
|
+
common.commonContainer.setEnvTsDefinition(envTsDefinition);
|
|
1289
|
+
Object.keys(envValueInfo).forEach((key) => process.env[key] = envValueInfo[key]);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
function authorize(permission) {
|
|
1294
|
+
return function(target, propertyKey, descriptor) {
|
|
1295
|
+
base({
|
|
1296
|
+
target,
|
|
1297
|
+
propertyKey,
|
|
1298
|
+
descriptor
|
|
1299
|
+
}, DecoratorType.authorize, permission);
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1234
1303
|
exports.$request = $request;
|
|
1235
1304
|
exports.AbstractModelState = AbstractModelState;
|
|
1236
1305
|
exports.BadRequestResult = BadRequestResult;
|
|
1237
1306
|
exports.BaseController = BaseController;
|
|
1307
|
+
exports.CreateProblemDetail = CreateProblemDetail;
|
|
1238
1308
|
exports.CreatedResult = CreatedResult;
|
|
1239
1309
|
exports.Delete = Delete;
|
|
1310
|
+
exports.FileResult = FileResult;
|
|
1240
1311
|
exports.ForbiddenAccessException = ForbiddenAccessException;
|
|
1241
1312
|
exports.ForbiddenAccessInfoResult = ForbiddenAccessInfoResult;
|
|
1242
1313
|
exports.HttpBadRequestException = HttpBadRequestException;
|
|
@@ -1245,6 +1316,7 @@ exports.HttpException = HttpException;
|
|
|
1245
1316
|
exports.HttpHandler = HttpHandler;
|
|
1246
1317
|
exports.HttpNotFoundException = HttpNotFoundException;
|
|
1247
1318
|
exports.HttpResponse = HttpResponse;
|
|
1319
|
+
exports.HttpStatusCode = HttpStatusCode;
|
|
1248
1320
|
exports.ModelBindingContext = ModelBindingContext;
|
|
1249
1321
|
exports.NoContentResult = NoContentResult;
|
|
1250
1322
|
exports.NotFoundResult = NotFoundResult;
|
|
@@ -1253,10 +1325,12 @@ exports.RunOn = RunOn;
|
|
|
1253
1325
|
exports.UnauthorizedAccessException = UnauthorizedAccessException;
|
|
1254
1326
|
exports.anonymous = anonymous;
|
|
1255
1327
|
exports.authenticationOnly = authenticationOnly;
|
|
1328
|
+
exports.authorize = authorize;
|
|
1256
1329
|
exports.badRequest = badRequest;
|
|
1257
1330
|
exports.created = created;
|
|
1258
1331
|
exports.defineNattyConfig = defineNattyConfig;
|
|
1259
1332
|
exports.entityContainer = entityContainer;
|
|
1333
|
+
exports.fileResult = fileResult;
|
|
1260
1334
|
exports.filter = filter;
|
|
1261
1335
|
exports.forbiddenAccessInfo = forbiddenAccessInfo;
|
|
1262
1336
|
exports.get = get;
|
|
@@ -1269,4 +1343,5 @@ exports.post = post;
|
|
|
1269
1343
|
exports.put = put;
|
|
1270
1344
|
exports.registerDecorator = registerDecorator;
|
|
1271
1345
|
exports.route = route;
|
|
1346
|
+
exports.setEnvInfo = setEnvInfo;
|
|
1272
1347
|
exports.useFilter = useFilter;
|
package/dist/index.d.ts
CHANGED
|
@@ -59,6 +59,64 @@ declare function put(path: string): (target: any, propertyKey?: string, descript
|
|
|
59
59
|
|
|
60
60
|
declare function Delete(): (target: any, propertyKey?: string, descriptor?: any) => void;
|
|
61
61
|
|
|
62
|
+
interface RouteConfig {
|
|
63
|
+
controller: Function;
|
|
64
|
+
parameters: Array<{
|
|
65
|
+
name: string;
|
|
66
|
+
type: string;
|
|
67
|
+
}>;
|
|
68
|
+
get: {
|
|
69
|
+
[key: string]: {
|
|
70
|
+
name: string;
|
|
71
|
+
parameters: Array<{
|
|
72
|
+
name: string;
|
|
73
|
+
type: string;
|
|
74
|
+
}>;
|
|
75
|
+
returnType: string;
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
post: {
|
|
79
|
+
[key: string]: {
|
|
80
|
+
name: string;
|
|
81
|
+
parameters: Array<{
|
|
82
|
+
name: string;
|
|
83
|
+
type: string;
|
|
84
|
+
}>;
|
|
85
|
+
returnType: string;
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
put: {
|
|
89
|
+
[key: string]: {
|
|
90
|
+
name: string;
|
|
91
|
+
parameters: Array<{
|
|
92
|
+
name: string;
|
|
93
|
+
type: string;
|
|
94
|
+
}>;
|
|
95
|
+
returnType: string;
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
delete: {
|
|
99
|
+
[key: string]: {
|
|
100
|
+
name: string;
|
|
101
|
+
parameters: Array<{
|
|
102
|
+
name: string;
|
|
103
|
+
type: string;
|
|
104
|
+
}>;
|
|
105
|
+
returnType: string;
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
declare function init(config: NattyConfig, appConfig: {
|
|
111
|
+
routes: {
|
|
112
|
+
[key: string]: RouteConfig;
|
|
113
|
+
};
|
|
114
|
+
envTsDefinition: {
|
|
115
|
+
[key: string]: string;
|
|
116
|
+
};
|
|
117
|
+
resolver: (path: string) => {};
|
|
118
|
+
}): any;
|
|
119
|
+
|
|
62
120
|
interface DecoratorInfo {
|
|
63
121
|
httpMethod: string;
|
|
64
122
|
route: string;
|
|
@@ -81,6 +139,7 @@ type HttpRequestBodyInfo = {
|
|
|
81
139
|
number?: number | number[];
|
|
82
140
|
boolean?: boolean | boolean[];
|
|
83
141
|
FormData?: FormData;
|
|
142
|
+
buffer?: any;
|
|
84
143
|
ArrayBuffer?: ArrayBuffer;
|
|
85
144
|
Blob?: Blob;
|
|
86
145
|
json?: {
|
|
@@ -120,6 +179,7 @@ interface HttpResponseInit {
|
|
|
120
179
|
headers?: HeadersInit;
|
|
121
180
|
cookies?: Cookie[];
|
|
122
181
|
enableContentNegotiation?: boolean;
|
|
182
|
+
isBuffer?: boolean;
|
|
123
183
|
}
|
|
124
184
|
|
|
125
185
|
interface ProblemDetail {
|
|
@@ -190,64 +250,6 @@ interface IHttpResult {
|
|
|
190
250
|
getResponse(): HttpResponseInit;
|
|
191
251
|
}
|
|
192
252
|
|
|
193
|
-
interface RouteConfig {
|
|
194
|
-
controller: Function;
|
|
195
|
-
parameters: Array<{
|
|
196
|
-
name: string;
|
|
197
|
-
type: string;
|
|
198
|
-
}>;
|
|
199
|
-
get: {
|
|
200
|
-
[key: string]: {
|
|
201
|
-
name: string;
|
|
202
|
-
parameters: Array<{
|
|
203
|
-
name: string;
|
|
204
|
-
type: string;
|
|
205
|
-
}>;
|
|
206
|
-
returnType: string;
|
|
207
|
-
};
|
|
208
|
-
};
|
|
209
|
-
post: {
|
|
210
|
-
[key: string]: {
|
|
211
|
-
name: string;
|
|
212
|
-
parameters: Array<{
|
|
213
|
-
name: string;
|
|
214
|
-
type: string;
|
|
215
|
-
}>;
|
|
216
|
-
returnType: string;
|
|
217
|
-
};
|
|
218
|
-
};
|
|
219
|
-
put: {
|
|
220
|
-
[key: string]: {
|
|
221
|
-
name: string;
|
|
222
|
-
parameters: Array<{
|
|
223
|
-
name: string;
|
|
224
|
-
type: string;
|
|
225
|
-
}>;
|
|
226
|
-
returnType: string;
|
|
227
|
-
};
|
|
228
|
-
};
|
|
229
|
-
delete: {
|
|
230
|
-
[key: string]: {
|
|
231
|
-
name: string;
|
|
232
|
-
parameters: Array<{
|
|
233
|
-
name: string;
|
|
234
|
-
type: string;
|
|
235
|
-
}>;
|
|
236
|
-
returnType: string;
|
|
237
|
-
};
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
declare function init(config: NattyConfig, appConfig: {
|
|
242
|
-
routes: {
|
|
243
|
-
[key: string]: RouteConfig;
|
|
244
|
-
};
|
|
245
|
-
envTsDefinition: {
|
|
246
|
-
[key: string]: string;
|
|
247
|
-
};
|
|
248
|
-
types?: TypesInfo;
|
|
249
|
-
}): any;
|
|
250
|
-
|
|
251
253
|
declare class HttpRequest {
|
|
252
254
|
private httpRequest;
|
|
253
255
|
constructor(http: HttpRequestInit);
|
|
@@ -264,6 +266,7 @@ declare class HttpResponse {
|
|
|
264
266
|
private _headers;
|
|
265
267
|
private _body;
|
|
266
268
|
private _status;
|
|
269
|
+
private _isBuffer;
|
|
267
270
|
constructor(response?: HttpResponseInit);
|
|
268
271
|
private setValues;
|
|
269
272
|
addCookie(cookie: Cookie): void;
|
|
@@ -435,6 +438,12 @@ declare class BadRequestResult extends BaseResult implements IHttpResult {
|
|
|
435
438
|
}
|
|
436
439
|
declare function badRequest(value?: ExceptionTypeInfo, response?: Pick<HttpResponseInit, "headers" | "cookies">): BadRequestResult;
|
|
437
440
|
|
|
441
|
+
declare class FileResult extends BaseResult {
|
|
442
|
+
value: any;
|
|
443
|
+
constructor(value: any, response?: Pick<HttpResponseInit, "headers" | "cookies">);
|
|
444
|
+
}
|
|
445
|
+
declare function fileResult(value?: any, response?: Pick<HttpResponseInit, "headers" | "cookies">): FileResult;
|
|
446
|
+
|
|
438
447
|
declare class HttpException {
|
|
439
448
|
private httpResponse;
|
|
440
449
|
constructor(response: HttpResponseInit);
|
|
@@ -463,4 +472,27 @@ declare function anonymous(): (target: any, propertyKey?: string, descriptor?: a
|
|
|
463
472
|
|
|
464
473
|
declare function authenticationOnly(): (target: any, propertyKey?: string, descriptor?: any) => void;
|
|
465
474
|
|
|
466
|
-
|
|
475
|
+
declare function setEnvInfo(envTsDefinition: {
|
|
476
|
+
[key: string]: string;
|
|
477
|
+
}, envValueInfo: {
|
|
478
|
+
[key: string]: any;
|
|
479
|
+
}): void;
|
|
480
|
+
|
|
481
|
+
declare enum HttpStatusCode {
|
|
482
|
+
success = 200,
|
|
483
|
+
created = 201,
|
|
484
|
+
noContent = 204,
|
|
485
|
+
notFound = 404,
|
|
486
|
+
unAuthorized = 401,
|
|
487
|
+
forbiddenAccess = 403,
|
|
488
|
+
badRequest = 400,
|
|
489
|
+
serverError = 500
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
declare function authorize(permission: {
|
|
493
|
+
[key: string]: any;
|
|
494
|
+
}): (target: any, propertyKey?: string, descriptor?: any) => void;
|
|
495
|
+
|
|
496
|
+
declare function CreateProblemDetail(modelName: string, detail: any): ProblemDetail;
|
|
497
|
+
|
|
498
|
+
export { $request, AbstractModelState, BadRequestResult, BaseController, BuildOptions, ClassTypeInfo, CreateProblemDetail, CreatedResult, Delete, FileResult, ForbiddenAccessException, ForbiddenAccessInfoResult, HttpBadRequestException, HttpContext, HttpException, HttpHandler, HttpModule, HttpNotFoundException, HttpResponse, HttpStatusCode, MethodInfo$1 as MethodInfo, ModelBindingContext, NoContentResult, NotFoundResult, OkResult, ParameterInfo, RunOn, TypeInfo$1 as TypeInfo, UnauthorizedAccessException, anonymous, authenticationOnly, authorize, badRequest, created, defineNattyConfig, entityContainer, fileResult, filter, forbiddenAccessInfo, get, init, injectable, noContent, notFound, ok, post, put, registerDecorator, route, setEnvInfo, useFilter };
|
package/dist/index.mjs
CHANGED
|
@@ -58,10 +58,13 @@ const nattyContainer = new class {
|
|
|
58
58
|
this.container = /* @__PURE__ */ new Map();
|
|
59
59
|
this.containerState = /* @__PURE__ */ new Map();
|
|
60
60
|
}
|
|
61
|
-
|
|
61
|
+
get types() {
|
|
62
|
+
return commonContainer.types;
|
|
63
|
+
}
|
|
64
|
+
setup(config, routes, resolver) {
|
|
62
65
|
this.config = config;
|
|
63
66
|
this.routes = routes;
|
|
64
|
-
this.
|
|
67
|
+
this.resolver = resolver;
|
|
65
68
|
}
|
|
66
69
|
getTypes() {
|
|
67
70
|
return StaticContainer.types;
|
|
@@ -114,7 +117,7 @@ const nattyContainer = new class {
|
|
|
114
117
|
function init(config, appConfig) {
|
|
115
118
|
commonContainer.setupConfig(config);
|
|
116
119
|
commonContainer.setEnvTsDefinition(appConfig.envTsDefinition);
|
|
117
|
-
nattyContainer.setup(config, appConfig.routes, appConfig.
|
|
120
|
+
nattyContainer.setup(config, appConfig.routes, appConfig.resolver);
|
|
118
121
|
return initializeModule(config);
|
|
119
122
|
}
|
|
120
123
|
function initializeModule(config) {
|
|
@@ -123,22 +126,26 @@ function initializeModule(config) {
|
|
|
123
126
|
}
|
|
124
127
|
}
|
|
125
128
|
|
|
126
|
-
function getPreResponseBody(body) {
|
|
129
|
+
function getPreResponseBody(body, isBuffer = false) {
|
|
127
130
|
let bodyInfo;
|
|
128
131
|
if (body) {
|
|
129
|
-
if (
|
|
130
|
-
bodyInfo = {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
132
|
+
if (isBuffer)
|
|
133
|
+
bodyInfo = { buffer: body };
|
|
134
|
+
else {
|
|
135
|
+
if (isObject(body) || Array.isArray(body))
|
|
136
|
+
bodyInfo = { json: body };
|
|
137
|
+
const typeText = typeof body;
|
|
138
|
+
switch (typeText) {
|
|
139
|
+
case "string":
|
|
140
|
+
bodyInfo = { string: body };
|
|
141
|
+
break;
|
|
142
|
+
case "number":
|
|
143
|
+
bodyInfo = { number: body };
|
|
144
|
+
break;
|
|
145
|
+
case "boolean":
|
|
146
|
+
bodyInfo = { boolean: body };
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
142
149
|
}
|
|
143
150
|
}
|
|
144
151
|
return bodyInfo;
|
|
@@ -152,6 +159,7 @@ class HttpResponse {
|
|
|
152
159
|
}
|
|
153
160
|
setValues(responseInit) {
|
|
154
161
|
if (responseInit) {
|
|
162
|
+
this._isBuffer = responseInit.isBuffer;
|
|
155
163
|
if (responseInit.headers)
|
|
156
164
|
for (const [key, value] of Object.entries(responseInit.headers))
|
|
157
165
|
this.headers.append(key, value);
|
|
@@ -183,7 +191,7 @@ class HttpResponse {
|
|
|
183
191
|
return this._body;
|
|
184
192
|
}
|
|
185
193
|
set body(value) {
|
|
186
|
-
this._body = getPreResponseBody(value);
|
|
194
|
+
this._body = getPreResponseBody(value, this._isBuffer);
|
|
187
195
|
}
|
|
188
196
|
write(responseInit) {
|
|
189
197
|
this.setValues(responseInit);
|
|
@@ -205,6 +213,26 @@ var RequestPipeline = /* @__PURE__ */ ((RequestPipeline2) => {
|
|
|
205
213
|
return RequestPipeline2;
|
|
206
214
|
})(RequestPipeline || {});
|
|
207
215
|
|
|
216
|
+
function lessThan(value) {
|
|
217
|
+
return value ? value.replace(/</g, "<") : value;
|
|
218
|
+
}
|
|
219
|
+
function greaterThan(value) {
|
|
220
|
+
return value ? value.replace(/>/g, ">") : value;
|
|
221
|
+
}
|
|
222
|
+
function ampersand(value) {
|
|
223
|
+
return value ? value.replace(/&/g, "&") : value;
|
|
224
|
+
}
|
|
225
|
+
function doubleDash(value) {
|
|
226
|
+
return value ? value.replace(/--/g, "") : value;
|
|
227
|
+
}
|
|
228
|
+
function sanitizeSpecialCodes(value) {
|
|
229
|
+
value = ampersand(value);
|
|
230
|
+
value = lessThan(value);
|
|
231
|
+
value = greaterThan(value);
|
|
232
|
+
value = doubleDash(value);
|
|
233
|
+
return value;
|
|
234
|
+
}
|
|
235
|
+
|
|
208
236
|
function isBoolean(value) {
|
|
209
237
|
return typeof value === "boolean" || value === "1" || value === "true" || value === "0" || value === "false";
|
|
210
238
|
}
|
|
@@ -265,7 +293,7 @@ function toInt(value, radix = 0) {
|
|
|
265
293
|
}
|
|
266
294
|
function toString(value) {
|
|
267
295
|
if (isNotBlank(value))
|
|
268
|
-
return String(value);
|
|
296
|
+
return sanitizeSpecialCodes(String(value));
|
|
269
297
|
return value;
|
|
270
298
|
}
|
|
271
299
|
function whitelist(value, chars) {
|
|
@@ -346,6 +374,7 @@ class BaseResult {
|
|
|
346
374
|
}
|
|
347
375
|
|
|
348
376
|
function getResponseBodyObject(body, props) {
|
|
377
|
+
const sensitiveProps = commonContainer.nattyConfig?.secure?.sensitiveProps;
|
|
349
378
|
if (body instanceof List)
|
|
350
379
|
return getResponseBodyObject(body.values, body.props);
|
|
351
380
|
if (Array.isArray(body)) {
|
|
@@ -359,7 +388,8 @@ function getResponseBodyObject(body, props) {
|
|
|
359
388
|
const keys = Object.keys(body);
|
|
360
389
|
const getterProps = props ? Object.keys(props).map((key) => props[key]) : [];
|
|
361
390
|
for (const key of [...keys, ...getterProps])
|
|
362
|
-
|
|
391
|
+
if (!sensitiveProps || sensitiveProps.filter((t) => t == key.toLowerCase()).length == 0)
|
|
392
|
+
jObject[key] = getResponseBodyObject(body[key]);
|
|
363
393
|
return jObject;
|
|
364
394
|
}
|
|
365
395
|
return body;
|
|
@@ -522,12 +552,14 @@ class ParameterTypeConverter extends BaseResponse {
|
|
|
522
552
|
} else {
|
|
523
553
|
if (this.isArrayType(property.type) && Array.isArray(value)) {
|
|
524
554
|
let arrayValue = body[property.name] = [];
|
|
525
|
-
let arrayInvalidProps = invalidProps[property.name] = [];
|
|
526
555
|
for (const item of value) {
|
|
527
556
|
const sanitizeValue = this.sanitizer[property.type.toLowerCase()] ? this.sanitizer[property.type.toLowerCase()](item) : item;
|
|
528
|
-
if (sanitizeValue === INVALID_VALUE)
|
|
557
|
+
if (sanitizeValue === INVALID_VALUE) {
|
|
558
|
+
let arrayInvalidProps = invalidProps[property.name];
|
|
559
|
+
if (!arrayInvalidProps)
|
|
560
|
+
arrayInvalidProps = invalidProps[property.name] = [];
|
|
529
561
|
arrayInvalidProps.push(property);
|
|
530
|
-
else
|
|
562
|
+
} else
|
|
531
563
|
arrayValue.push(sanitizeValue);
|
|
532
564
|
}
|
|
533
565
|
} else
|
|
@@ -555,7 +587,7 @@ class ParameterTypeConverter extends BaseResponse {
|
|
|
555
587
|
}
|
|
556
588
|
convertToInstance(entityName, data) {
|
|
557
589
|
const typesInfo = this.types[entityName];
|
|
558
|
-
const target = this.getClassTarget(typesInfo.path) || entityContainer.getTarget(entityName);
|
|
590
|
+
const target = this.getClassTarget(typesInfo.path, entityName) || entityContainer.getTarget(entityName);
|
|
559
591
|
let instance = null;
|
|
560
592
|
if (target) {
|
|
561
593
|
instance = new target();
|
|
@@ -564,11 +596,10 @@ class ParameterTypeConverter extends BaseResponse {
|
|
|
564
596
|
instance = data;
|
|
565
597
|
return instance;
|
|
566
598
|
}
|
|
567
|
-
getClassTarget(
|
|
568
|
-
if (
|
|
569
|
-
const classInfo = resolver();
|
|
570
|
-
|
|
571
|
-
return classInfo[name];
|
|
599
|
+
getClassTarget(path, entityName) {
|
|
600
|
+
if (path) {
|
|
601
|
+
const classInfo = nattyContainer.resolver(path);
|
|
602
|
+
return classInfo[entityName];
|
|
572
603
|
}
|
|
573
604
|
return void 0;
|
|
574
605
|
}
|
|
@@ -845,6 +876,14 @@ class ActionExecutedContext extends AbstractExecutionContext {
|
|
|
845
876
|
}
|
|
846
877
|
}
|
|
847
878
|
|
|
879
|
+
class AuthorizationContext extends AbstractExecutionContext {
|
|
880
|
+
constructor(models, context, routeInfo, config) {
|
|
881
|
+
super(context, routeInfo);
|
|
882
|
+
this.models = models;
|
|
883
|
+
this.config = config;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
848
887
|
class RequestProcessor extends RouteParser {
|
|
849
888
|
constructor() {
|
|
850
889
|
super(...arguments);
|
|
@@ -855,9 +894,6 @@ class RequestProcessor extends RouteParser {
|
|
|
855
894
|
case RequestPipeline.onAuthentication:
|
|
856
895
|
await this.onAuthentication();
|
|
857
896
|
break;
|
|
858
|
-
case RequestPipeline.onAuthorization:
|
|
859
|
-
await this.onAuthorization();
|
|
860
|
-
break;
|
|
861
897
|
}
|
|
862
898
|
}
|
|
863
899
|
resolveFilter(instance) {
|
|
@@ -883,21 +919,27 @@ class RequestProcessor extends RouteParser {
|
|
|
883
919
|
this.httpContext.user = result;
|
|
884
920
|
if (!result.isAuthenticate && !anonymousInfo.controllerConfig && !anonymousInfo.methodConfig)
|
|
885
921
|
throw new UnauthorizedAccessException(authenticationFilter.onFailedResponse());
|
|
886
|
-
await this.onAuthorization();
|
|
887
922
|
}
|
|
888
923
|
}
|
|
889
|
-
async onAuthorization() {
|
|
924
|
+
async onAuthorization(methodParameters) {
|
|
890
925
|
const authorization = commonContainer.globalConfig.authorization;
|
|
891
926
|
const authorizationFilter = authorization ? this.resolveFilter(authorization) : void 0;
|
|
892
927
|
const authorizeConfig = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.authorize);
|
|
893
928
|
const authenticationOnly = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.authenticationOnly);
|
|
894
|
-
if (this.httpContext.user?.isAuthenticate && authorizationFilter && (!authenticationOnly.controllerConfig && !authenticationOnly.methodConfig)) {
|
|
895
|
-
const
|
|
929
|
+
if (this.httpContext.user?.isAuthenticate && authorizationFilter && (authorizeConfig.controllerConfig || authorizeConfig.methodConfig) && (!authenticationOnly.controllerConfig && !authenticationOnly.methodConfig)) {
|
|
930
|
+
const authorizationContext = new AuthorizationContext(
|
|
931
|
+
methodParameters.filter((t) => t instanceof ModelBindingContext),
|
|
932
|
+
this.httpContext,
|
|
933
|
+
this.routeInfo,
|
|
934
|
+
authorizeConfig.methodConfig || authorizeConfig.controllerConfig
|
|
935
|
+
);
|
|
936
|
+
const result = await authorizationFilter.onAuthorization(authorizationContext);
|
|
896
937
|
if (!result)
|
|
897
938
|
throw new ForbiddenAccessException(authorizationFilter.onFailedAuthorization());
|
|
898
939
|
}
|
|
899
940
|
}
|
|
900
941
|
async onActionExecuting(methodParameters) {
|
|
942
|
+
await this.onAuthorization(methodParameters);
|
|
901
943
|
let actionFilters = commonContainer.globalConfig.actionFilters || [];
|
|
902
944
|
const actionFiltersConfig = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.useFilter);
|
|
903
945
|
actionFilters = [...actionFilters, ...actionFiltersConfig.controllerConfig?.actionFilters || [], ...actionFiltersConfig.methodConfig?.actionFilters || []];
|
|
@@ -1203,6 +1245,16 @@ function badRequest(value, response) {
|
|
|
1203
1245
|
return new BadRequestResult(value || BLANK$1, response);
|
|
1204
1246
|
}
|
|
1205
1247
|
|
|
1248
|
+
class FileResult extends BaseResult {
|
|
1249
|
+
constructor(value, response) {
|
|
1250
|
+
super({ ...{ isBuffer: true, body: value }, ...{ status: HttpStatusCode.success } }, response);
|
|
1251
|
+
this.value = value;
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
function fileResult(value, response) {
|
|
1255
|
+
return new FileResult(value || BLANK$1, response);
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1206
1258
|
function base(params, type, additionaConfig) {
|
|
1207
1259
|
decoratorStateContainer.register(params, type, additionaConfig);
|
|
1208
1260
|
}
|
|
@@ -1229,4 +1281,21 @@ function authenticationOnly() {
|
|
|
1229
1281
|
};
|
|
1230
1282
|
}
|
|
1231
1283
|
|
|
1232
|
-
|
|
1284
|
+
function setEnvInfo(envTsDefinition, envValueInfo) {
|
|
1285
|
+
if (envTsDefinition && envValueInfo) {
|
|
1286
|
+
commonContainer.setEnvTsDefinition(envTsDefinition);
|
|
1287
|
+
Object.keys(envValueInfo).forEach((key) => process.env[key] = envValueInfo[key]);
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
function authorize(permission) {
|
|
1292
|
+
return function(target, propertyKey, descriptor) {
|
|
1293
|
+
base({
|
|
1294
|
+
target,
|
|
1295
|
+
propertyKey,
|
|
1296
|
+
descriptor
|
|
1297
|
+
}, DecoratorType.authorize, permission);
|
|
1298
|
+
};
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
export { $request, AbstractModelState, BadRequestResult, BaseController, CreateProblemDetail, CreatedResult, Delete, FileResult, ForbiddenAccessException, ForbiddenAccessInfoResult, HttpBadRequestException, HttpContext, HttpException, HttpHandler, HttpNotFoundException, HttpResponse, HttpStatusCode, ModelBindingContext, NoContentResult, NotFoundResult, OkResult, RunOn, UnauthorizedAccessException, anonymous, authenticationOnly, authorize, badRequest, created, defineNattyConfig, entityContainer, fileResult, filter, forbiddenAccessInfo, get, init, injectable, noContent, notFound, ok, post, put, registerDecorator, route, setEnvInfo, useFilter };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nattyjs/core",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.31",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"author": "ajayojha",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"tsyringe": "^4.7.0",
|
|
19
19
|
"path-to-regexp": "6.2.1",
|
|
20
|
-
"@nattyjs/common": "0.0.1-beta.
|
|
20
|
+
"@nattyjs/common": "0.0.1-beta.31"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"unbuild": "1.2.1"
|