@nattyjs/core 0.0.1-beta.37 → 0.0.1-beta.39
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 +31 -2
- package/dist/index.mjs +31 -2
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -27,6 +27,12 @@ function route(path) {
|
|
|
27
27
|
const CONTROLLER = "controller";
|
|
28
28
|
const INVALID_VALUE = "INVALID_VALUE";
|
|
29
29
|
const BLANK = "";
|
|
30
|
+
const DENY_BY_DEFAULT = {
|
|
31
|
+
type: "https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html#deny-by-default",
|
|
32
|
+
title: "Deny-by-default",
|
|
33
|
+
description: `Zero Trust Architecture (NIST SP 800-207) \u2014 Core principle is "never trust, always verify," which translates to deny-by-default behavior. OWASP Secure Defaults Principle \u2014 \u201CSecurity should be a default setting, and everything should be locked down unless explicitly permitted.\u201D`,
|
|
34
|
+
solution: `Please implement proper authentication and authorization checks. If this API needs to be accessed anonymously, add the @anonymous() decorator above the HTTP action.`
|
|
35
|
+
};
|
|
30
36
|
|
|
31
37
|
function get(path) {
|
|
32
38
|
return function(target, propertyKey, descriptor) {
|
|
@@ -863,6 +869,8 @@ class ModelBindingContext extends ParameterTypeConverter {
|
|
|
863
869
|
else
|
|
864
870
|
this.data = body;
|
|
865
871
|
this.instance = this.convertToInstance(this.type, this.data);
|
|
872
|
+
if (!this.isValid)
|
|
873
|
+
throw new HttpBadRequestException(CreateProblemDetail(this.type, this.errors));
|
|
866
874
|
}
|
|
867
875
|
get isValid() {
|
|
868
876
|
const errors = runValidators(this.type, this.instance);
|
|
@@ -879,6 +887,9 @@ class ActionExecutedContext extends AbstractExecutionContext {
|
|
|
879
887
|
super(httpContext, routeInfo);
|
|
880
888
|
this.content = content;
|
|
881
889
|
}
|
|
890
|
+
get response() {
|
|
891
|
+
return this.context.response;
|
|
892
|
+
}
|
|
882
893
|
}
|
|
883
894
|
|
|
884
895
|
class AuthorizationContext extends AbstractExecutionContext {
|
|
@@ -919,6 +930,8 @@ class RequestProcessor extends RouteParser {
|
|
|
919
930
|
const authentication = this.getAuthenticationClass();
|
|
920
931
|
const authenticationFilter = authentication ? this.resolveFilter(authentication) : void 0;
|
|
921
932
|
const anonymousInfo = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.anonymous);
|
|
933
|
+
if (!anonymousInfo && !authenticationFilter)
|
|
934
|
+
throw new UnauthorizedAccessException(DENY_BY_DEFAULT);
|
|
922
935
|
if (authenticationFilter) {
|
|
923
936
|
const result = await authenticationFilter.onAuthentication(this.httpContext);
|
|
924
937
|
this.httpContext.user = result;
|
|
@@ -943,8 +956,19 @@ class RequestProcessor extends RouteParser {
|
|
|
943
956
|
throw new ForbiddenAccessException(authorizationFilter.onFailedAuthorization());
|
|
944
957
|
}
|
|
945
958
|
}
|
|
946
|
-
async
|
|
947
|
-
|
|
959
|
+
async onModelBinding(methodParameters) {
|
|
960
|
+
const { actionExecutingContext, actionFilters } = this.getExecutingContext(methodParameters);
|
|
961
|
+
for (const actionFilter of actionFilters) {
|
|
962
|
+
const filter = this.resolveFilter(actionFilter);
|
|
963
|
+
this.actionFilterInstances.push(filter);
|
|
964
|
+
await filter.onActionExecuting(actionExecutingContext);
|
|
965
|
+
if (actionExecutingContext.result) {
|
|
966
|
+
return actionExecutingContext.result;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
return null;
|
|
970
|
+
}
|
|
971
|
+
getExecutingContext(methodParameters) {
|
|
948
972
|
let actionFilters = common.commonContainer.globalConfig.actionFilters || [];
|
|
949
973
|
const actionFiltersConfig = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.useFilter);
|
|
950
974
|
actionFilters = [...actionFilters, ...actionFiltersConfig.controllerConfig?.actionFilters || [], ...actionFiltersConfig.methodConfig?.actionFilters || []];
|
|
@@ -953,6 +977,11 @@ class RequestProcessor extends RouteParser {
|
|
|
953
977
|
this.httpContext,
|
|
954
978
|
this.routeInfo
|
|
955
979
|
);
|
|
980
|
+
return { actionFilters, actionExecutingContext };
|
|
981
|
+
}
|
|
982
|
+
async onActionExecuting(methodParameters) {
|
|
983
|
+
await this.onAuthorization(methodParameters);
|
|
984
|
+
const { actionExecutingContext, actionFilters } = this.getExecutingContext(methodParameters);
|
|
956
985
|
for (const actionFilter of actionFilters) {
|
|
957
986
|
const filter = this.resolveFilter(actionFilter);
|
|
958
987
|
this.actionFilterInstances.push(filter);
|
package/dist/index.mjs
CHANGED
|
@@ -25,6 +25,12 @@ function route(path) {
|
|
|
25
25
|
const CONTROLLER = "controller";
|
|
26
26
|
const INVALID_VALUE = "INVALID_VALUE";
|
|
27
27
|
const BLANK = "";
|
|
28
|
+
const DENY_BY_DEFAULT = {
|
|
29
|
+
type: "https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html#deny-by-default",
|
|
30
|
+
title: "Deny-by-default",
|
|
31
|
+
description: `Zero Trust Architecture (NIST SP 800-207) \u2014 Core principle is "never trust, always verify," which translates to deny-by-default behavior. OWASP Secure Defaults Principle \u2014 \u201CSecurity should be a default setting, and everything should be locked down unless explicitly permitted.\u201D`,
|
|
32
|
+
solution: `Please implement proper authentication and authorization checks. If this API needs to be accessed anonymously, add the @anonymous() decorator above the HTTP action.`
|
|
33
|
+
};
|
|
28
34
|
|
|
29
35
|
function get(path) {
|
|
30
36
|
return function(target, propertyKey, descriptor) {
|
|
@@ -861,6 +867,8 @@ class ModelBindingContext extends ParameterTypeConverter {
|
|
|
861
867
|
else
|
|
862
868
|
this.data = body;
|
|
863
869
|
this.instance = this.convertToInstance(this.type, this.data);
|
|
870
|
+
if (!this.isValid)
|
|
871
|
+
throw new HttpBadRequestException(CreateProblemDetail(this.type, this.errors));
|
|
864
872
|
}
|
|
865
873
|
get isValid() {
|
|
866
874
|
const errors = runValidators(this.type, this.instance);
|
|
@@ -877,6 +885,9 @@ class ActionExecutedContext extends AbstractExecutionContext {
|
|
|
877
885
|
super(httpContext, routeInfo);
|
|
878
886
|
this.content = content;
|
|
879
887
|
}
|
|
888
|
+
get response() {
|
|
889
|
+
return this.context.response;
|
|
890
|
+
}
|
|
880
891
|
}
|
|
881
892
|
|
|
882
893
|
class AuthorizationContext extends AbstractExecutionContext {
|
|
@@ -917,6 +928,8 @@ class RequestProcessor extends RouteParser {
|
|
|
917
928
|
const authentication = this.getAuthenticationClass();
|
|
918
929
|
const authenticationFilter = authentication ? this.resolveFilter(authentication) : void 0;
|
|
919
930
|
const anonymousInfo = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.anonymous);
|
|
931
|
+
if (!anonymousInfo && !authenticationFilter)
|
|
932
|
+
throw new UnauthorizedAccessException(DENY_BY_DEFAULT);
|
|
920
933
|
if (authenticationFilter) {
|
|
921
934
|
const result = await authenticationFilter.onAuthentication(this.httpContext);
|
|
922
935
|
this.httpContext.user = result;
|
|
@@ -941,8 +954,19 @@ class RequestProcessor extends RouteParser {
|
|
|
941
954
|
throw new ForbiddenAccessException(authorizationFilter.onFailedAuthorization());
|
|
942
955
|
}
|
|
943
956
|
}
|
|
944
|
-
async
|
|
945
|
-
|
|
957
|
+
async onModelBinding(methodParameters) {
|
|
958
|
+
const { actionExecutingContext, actionFilters } = this.getExecutingContext(methodParameters);
|
|
959
|
+
for (const actionFilter of actionFilters) {
|
|
960
|
+
const filter = this.resolveFilter(actionFilter);
|
|
961
|
+
this.actionFilterInstances.push(filter);
|
|
962
|
+
await filter.onActionExecuting(actionExecutingContext);
|
|
963
|
+
if (actionExecutingContext.result) {
|
|
964
|
+
return actionExecutingContext.result;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
return null;
|
|
968
|
+
}
|
|
969
|
+
getExecutingContext(methodParameters) {
|
|
946
970
|
let actionFilters = commonContainer.globalConfig.actionFilters || [];
|
|
947
971
|
const actionFiltersConfig = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.useFilter);
|
|
948
972
|
actionFilters = [...actionFilters, ...actionFiltersConfig.controllerConfig?.actionFilters || [], ...actionFiltersConfig.methodConfig?.actionFilters || []];
|
|
@@ -951,6 +975,11 @@ class RequestProcessor extends RouteParser {
|
|
|
951
975
|
this.httpContext,
|
|
952
976
|
this.routeInfo
|
|
953
977
|
);
|
|
978
|
+
return { actionFilters, actionExecutingContext };
|
|
979
|
+
}
|
|
980
|
+
async onActionExecuting(methodParameters) {
|
|
981
|
+
await this.onAuthorization(methodParameters);
|
|
982
|
+
const { actionExecutingContext, actionFilters } = this.getExecutingContext(methodParameters);
|
|
954
983
|
for (const actionFilter of actionFilters) {
|
|
955
984
|
const filter = this.resolveFilter(actionFilter);
|
|
956
985
|
this.actionFilterInstances.push(filter);
|
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.39",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"author": "ajayojha",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"reflect-metadata": "0.2.2",
|
|
19
19
|
"tsyringe": "^4.7.0",
|
|
20
20
|
"path-to-regexp": "6.2.1",
|
|
21
|
-
"@nattyjs/common": "0.0.1-beta.
|
|
21
|
+
"@nattyjs/common": "0.0.1-beta.39"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"unbuild": "1.2.1"
|