@node-c/api-http 1.0.0-alpha9 → 1.0.0-beta1

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 (74) hide show
  1. package/dist/common/definitions/common.constants.d.ts +1 -1
  2. package/dist/common/definitions/common.constants.js +1 -1
  3. package/dist/common/definitions/common.constants.js.map +1 -1
  4. package/dist/common/utils/index.d.ts +1 -0
  5. package/dist/{exceptionFilters → common/utils}/index.js +1 -1
  6. package/dist/common/utils/index.js.map +1 -0
  7. package/dist/common/utils/utils.checkRoutes.d.ts +1 -0
  8. package/dist/common/utils/utils.checkRoutes.js +27 -0
  9. package/dist/common/utils/utils.checkRoutes.js.map +1 -0
  10. package/dist/decorators/http.decorators.accessControl.d.ts +9 -0
  11. package/dist/decorators/http.decorators.accessControl.js +7 -0
  12. package/dist/decorators/http.decorators.accessControl.js.map +1 -0
  13. package/dist/decorators/index.d.ts +1 -0
  14. package/dist/decorators/index.js +18 -0
  15. package/dist/decorators/index.js.map +1 -0
  16. package/dist/{exceptionFilters/http.exceptionFilters.httpException.js → filters/http.filtes.exception.js} +1 -1
  17. package/dist/filters/http.filtes.exception.js.map +1 -0
  18. package/dist/filters/index.d.ts +1 -0
  19. package/dist/filters/index.js +18 -0
  20. package/dist/filters/index.js.map +1 -0
  21. package/dist/index.d.ts +2 -1
  22. package/dist/index.js +2 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/interceptors/http.interceptors.accessControl.d.ts +12 -0
  25. package/dist/interceptors/http.interceptors.accessControl.js +94 -0
  26. package/dist/interceptors/http.interceptors.accessControl.js.map +1 -0
  27. package/dist/interceptors/http.interceptors.error.d.ts +3 -0
  28. package/dist/interceptors/http.interceptors.error.js +11 -3
  29. package/dist/interceptors/http.interceptors.error.js.map +1 -1
  30. package/dist/interceptors/index.d.ts +1 -1
  31. package/dist/interceptors/index.js +1 -1
  32. package/dist/middlewares/http.middlewares.authorization.d.ts +15 -0
  33. package/dist/middlewares/http.middlewares.authorization.js +156 -0
  34. package/dist/middlewares/http.middlewares.authorization.js.map +1 -0
  35. package/dist/middlewares/http.middlewares.cors.js +1 -1
  36. package/dist/middlewares/http.middlewares.cors.js.map +1 -1
  37. package/dist/middlewares/http.middlewares.requestLogging.d.ts +10 -0
  38. package/dist/middlewares/http.middlewares.requestLogging.js +35 -0
  39. package/dist/middlewares/http.middlewares.requestLogging.js.map +1 -0
  40. package/dist/middlewares/index.d.ts +2 -1
  41. package/dist/middlewares/index.js +2 -1
  42. package/dist/middlewares/index.js.map +1 -1
  43. package/dist/module/http.api.module.js +15 -7
  44. package/dist/module/http.api.module.js.map +1 -1
  45. package/package.json +12 -7
  46. package/src/common/definitions/common.constants.ts +1 -1
  47. package/src/common/utils/index.ts +1 -0
  48. package/src/common/utils/utils.checkRoutes.ts +31 -0
  49. package/src/decorators/http.decorators.accessControl.ts +8 -0
  50. package/src/decorators/index.ts +1 -0
  51. package/src/filters/index.ts +1 -0
  52. package/src/index.ts +2 -1
  53. package/src/interceptors/http.interceptors.accessControl.ts +101 -0
  54. package/src/interceptors/http.interceptors.error.ts +8 -7
  55. package/src/interceptors/index.ts +1 -1
  56. package/src/middlewares/http.middlewares.authorization.ts +155 -0
  57. package/src/middlewares/http.middlewares.cors.ts +1 -1
  58. package/src/middlewares/http.middlewares.requestLogging.ts +22 -0
  59. package/src/middlewares/index.ts +2 -1
  60. package/src/module/http.api.module.ts +17 -6
  61. package/dist/exceptionFilters/http.exceptionFilters.httpException.js.map +0 -1
  62. package/dist/exceptionFilters/index.d.ts +0 -1
  63. package/dist/exceptionFilters/index.js.map +0 -1
  64. package/dist/interceptors/http.interceptors.authorization.d.ts +0 -11
  65. package/dist/interceptors/http.interceptors.authorization.js +0 -87
  66. package/dist/interceptors/http.interceptors.authorization.js.map +0 -1
  67. package/dist/middlewares/http.middlewares.authentication.d.ts +0 -13
  68. package/dist/middlewares/http.middlewares.authentication.js +0 -128
  69. package/dist/middlewares/http.middlewares.authentication.js.map +0 -1
  70. package/src/exceptionFilters/index.ts +0 -1
  71. package/src/interceptors/http.interceptors.authorization.ts +0 -82
  72. package/src/middlewares/http.middlewares.authentication.ts +0 -111
  73. /package/dist/{exceptionFilters/http.exceptionFilters.httpException.d.ts → filters/http.filtes.exception.d.ts} +0 -0
  74. /package/src/{exceptionFilters/http.exceptionFilters.httpException.ts → filters/http.filtes.exception.ts} +0 -0
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.HTTPRequestLoggingMiddleware = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const core_1 = require("@node-c/core");
18
+ const definitions_1 = require("../common/definitions");
19
+ let HTTPRequestLoggingMiddleware = class HTTPRequestLoggingMiddleware {
20
+ constructor(logger, moduleName) {
21
+ this.logger = logger;
22
+ this.moduleName = moduleName;
23
+ }
24
+ use(req, _res, next) {
25
+ this.logger.info(`[${this.moduleName}]: ${req.method} ${req.baseUrl}`);
26
+ next();
27
+ }
28
+ };
29
+ exports.HTTPRequestLoggingMiddleware = HTTPRequestLoggingMiddleware;
30
+ exports.HTTPRequestLoggingMiddleware = HTTPRequestLoggingMiddleware = __decorate([
31
+ (0, common_1.Injectable)(),
32
+ __param(1, (0, common_1.Inject)(definitions_1.Constants.API_MODULE_NAME)),
33
+ __metadata("design:paramtypes", [core_1.LoggerService, String])
34
+ ], HTTPRequestLoggingMiddleware);
35
+ //# sourceMappingURL=http.middlewares.requestLogging.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.middlewares.requestLogging.js","sourceRoot":"","sources":["../../src/middlewares/http.middlewares.requestLogging.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAoE;AAEpE,uCAA6C;AAG7C,uDAAqE;AAG9D,IAAM,4BAA4B,GAAlC,MAAM,4BAA4B;IACvC,YAEY,MAAqB,EAGrB,UAAkB;QAHlB,WAAM,GAAN,MAAM,CAAe;QAGrB,eAAU,GAAV,UAAU,CAAQ;IAC3B,CAAC;IAEJ,GAAG,CAAC,GAA+B,EAAE,IAAc,EAAE,IAAkB;QACrE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,MAAM,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACvE,IAAI,EAAE,CAAC;IACT,CAAC;CACF,CAAA;AAbY,oEAA4B;uCAA5B,4BAA4B;IADxC,IAAA,mBAAU,GAAE;IAKR,WAAA,IAAA,eAAM,EAAC,uBAAS,CAAC,eAAe,CAAC,CAAA;qCADhB,oBAAa;GAHtB,4BAA4B,CAaxC"}
@@ -1,2 +1,3 @@
1
- export * from './http.middlewares.authentication';
1
+ export * from './http.middlewares.authorization';
2
2
  export * from './http.middlewares.cors';
3
+ export * from './http.middlewares.requestLogging';
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./http.middlewares.authentication"), exports);
17
+ __exportStar(require("./http.middlewares.authorization"), exports);
18
18
  __exportStar(require("./http.middlewares.cors"), exports);
19
+ __exportStar(require("./http.middlewares.requestLogging"), exports);
19
20
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middlewares/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,oEAAkD;AAClD,0DAAwC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middlewares/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mEAAiD;AACjD,0DAAwC;AACxC,oEAAkD"}
@@ -18,11 +18,12 @@ var HTTPAPIModule_1;
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
19
  exports.HTTPAPIModule = void 0;
20
20
  const common_1 = require("@nestjs/common");
21
- const core_1 = require("@node-c/core");
21
+ const core_1 = require("@nestjs/core");
22
+ const core_2 = require("@node-c/core");
22
23
  const cookie_parser_1 = __importDefault(require("cookie-parser"));
23
24
  const express_1 = __importDefault(require("express"));
24
25
  const definitions_1 = require("../common/definitions");
25
- const exceptionFilters_1 = require("../exceptionFilters");
26
+ const filters_1 = require("../filters");
26
27
  const interceptors_1 = require("../interceptors");
27
28
  const middlewares_1 = require("../middlewares");
28
29
  let HTTPAPIModule = HTTPAPIModule_1 = class HTTPAPIModule {
@@ -34,8 +35,9 @@ let HTTPAPIModule = HTTPAPIModule_1 = class HTTPAPIModule {
34
35
  consumer.apply(express_1.default.urlencoded({ verify: HTTPAPIModule_1.rawBodyBuffer, extended: true })).forRoutes('*');
35
36
  consumer.apply(express_1.default.json({ verify: HTTPAPIModule_1.rawBodyBuffer })).forRoutes('*');
36
37
  consumer.apply((0, cookie_parser_1.default)()).forRoutes('*');
38
+ consumer.apply(middlewares_1.HTTPRequestLoggingMiddleware).forRoutes('*');
37
39
  consumer.apply(middlewares_1.HTTPCORSMiddleware).forRoutes('*');
38
- consumer.apply(middlewares_1.HTTPAuthenticationMiddleware).forRoutes('*');
40
+ consumer.apply(middlewares_1.HTTPAuthorizationMiddleware).forRoutes('*');
39
41
  }
40
42
  static rawBodyBuffer(req, _res, buffer) {
41
43
  if (buffer && buffer.length) {
@@ -45,18 +47,24 @@ let HTTPAPIModule = HTTPAPIModule_1 = class HTTPAPIModule {
45
47
  static register(options) {
46
48
  const { folderData, imports: additionalImports, moduleClass } = options;
47
49
  const { atEnd: importsAtEnd, atStart: importsAtStart } = additionalImports || {};
48
- const { controllers, services } = (0, core_1.loadDynamicModules)(folderData);
50
+ const { controllers, services } = (0, core_2.loadDynamicModules)(folderData);
49
51
  return {
50
52
  module: moduleClass,
51
53
  imports: [...(importsAtStart || []), ...(importsAtEnd || [])],
52
54
  providers: [
55
+ {
56
+ provide: core_1.APP_PIPE,
57
+ useValue: new common_1.ValidationPipe({
58
+ whitelist: true
59
+ })
60
+ },
53
61
  {
54
62
  provide: definitions_1.Constants.API_MODULE_NAME,
55
63
  useValue: options.moduleName
56
64
  },
57
65
  {
58
66
  provide: definitions_1.Constants.AUTHORIZATION_INTERCEPTOR,
59
- useClass: interceptors_1.HTTPAuthorizationInterceptor
67
+ useClass: interceptors_1.HTTPAccessControlInterceptor
60
68
  },
61
69
  {
62
70
  provide: definitions_1.Constants.ERROR_INTERCEPTOR,
@@ -64,7 +72,7 @@ let HTTPAPIModule = HTTPAPIModule_1 = class HTTPAPIModule {
64
72
  },
65
73
  {
66
74
  provide: definitions_1.Constants.HTTP_EXCEPTION_FILTER,
67
- useClass: exceptionFilters_1.HttpExceptionFilter
75
+ useClass: filters_1.HttpExceptionFilter
68
76
  },
69
77
  ...(options.providers || []),
70
78
  ...(services || [])
@@ -77,6 +85,6 @@ let HTTPAPIModule = HTTPAPIModule_1 = class HTTPAPIModule {
77
85
  exports.HTTPAPIModule = HTTPAPIModule;
78
86
  exports.HTTPAPIModule = HTTPAPIModule = HTTPAPIModule_1 = __decorate([
79
87
  __param(1, (0, common_1.Inject)(definitions_1.Constants.API_MODULE_NAME)),
80
- __metadata("design:paramtypes", [core_1.ConfigProviderService, String])
88
+ __metadata("design:paramtypes", [core_2.ConfigProviderService, String])
81
89
  ], HTTPAPIModule);
82
90
  //# sourceMappingURL=http.api.module.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"http.api.module.js","sourceRoot":"","sources":["../../src/module/http.api.module.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"http.api.module.js","sourceRoot":"","sources":["../../src/module/http.api.module.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,29 +1,34 @@
1
1
  {
2
2
  "name": "@node-c/api-http",
3
- "version": "1.0.0-alpha9",
3
+ "version": "1.0.0-beta1",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
7
7
  "build": "tsc -p tsconfig.build.json",
8
+ "build:clean": "rm -rf dist/* && rm -f *.tsbuildinfo && npm run build",
8
9
  "check-types": "tsc -p tsconfig.build.json --noEmit",
9
10
  "dev": "tsc -p tsconfig.build.json --watch",
10
- "publish-package": "rm -rf dist/* && rm -f *.tsbuildinfo && npm run build && npm publish --access public",
11
+ "lint": "eslint src",
12
+ "lint:fix": "eslint src --fix",
13
+ "publish-package": "npm run build:clean && npm publish --access public",
11
14
  "test": "vitest --config src/vitest.config.ts",
12
15
  "test:coverage": "vitest --config src/vitest.config.ts --coverage"
13
16
  },
14
17
  "dependencies": {
15
- "@nestjs/common": "^10.4.12",
16
- "@ramster/general-tools": "^2.3.0",
18
+ "@nestjs/common": "^11.1.16",
19
+ "@nestjs/platform-express": "^11.1.16",
17
20
  "cookie-parser": "^1.4.7",
18
21
  "express": "^4.21.2",
22
+ "lodash": "^4.17.21",
19
23
  "rxjs": "^7.8.1"
20
24
  },
21
25
  "devDependencies": {
22
26
  "@types/cookie-parser": "^1.4.8",
23
- "@types/express": "^5.0.0"
27
+ "@types/express": "^5.0.0",
28
+ "@types/lodash": "^4.17.19"
24
29
  },
25
30
  "peerDependencies": {
26
- "@node-c/core": "^1.0.0-alpha9",
27
- "@node-c/domain-iam": "^1.0.0-alpha9"
31
+ "@node-c/core": "^1.0.0-beta1",
32
+ "@node-c/domain-iam": "^1.0.0-beta1"
28
33
  }
29
34
  }
@@ -4,7 +4,7 @@ export enum Constants {
4
4
  // eslint-disable-next-line no-unused-vars
5
5
  API_MODULE_NAME = 'API_MODULE_NAME',
6
6
  // eslint-disable-next-line no-unused-vars
7
- AUTHENTICATION_MIDDLEWARE_TOKEN_MANAGER_SERVICE = 'AUTHENTICATION_MIDDLEWARE_TOKEN_MANAGER_SERVICE',
7
+ AUTHORIZATION_MIDDLEWARE_TOKEN_MANAGER_SERVICE = 'AUTHORIZATION_MIDDLEWARE_TOKEN_MANAGER_SERVICE',
8
8
  // eslint-disable-next-line no-unused-vars
9
9
  AUTHENTICATION_MIDDLEWARE_USERS_SERVICE = 'AUTHENTICATION_MIDDLEWARE_USERS_SERVICE',
10
10
  // eslint-disable-next-line no-unused-vars
@@ -0,0 +1 @@
1
+ export * from './utils.checkRoutes';
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Checks whether a route exists in a list of HTTP routes. Supports ExpressJS-style route parameters, i.e. /users/item/:id.
3
+ * @param route (required) - The route to be checked.
4
+ * @param routes (required) - The array of routes to check in.
5
+ * @returns A boolean, which is the result of the check.
6
+ */
7
+ export function checkRoutes(route: string, routes: string[]): boolean {
8
+ const splitRoute = route.split('/');
9
+ for (const i in routes) {
10
+ const item = routes[i],
11
+ splitItem = item.split('/');
12
+ if (item === '*' || route === item) {
13
+ return true;
14
+ }
15
+ if (item.indexOf(':') !== -1 && splitItem.length === splitRoute.length) {
16
+ let valid = true;
17
+ for (const j in splitItem) {
18
+ const innerItem = splitItem[j],
19
+ routeItem = splitRoute[j];
20
+ if (routeItem !== innerItem && innerItem.indexOf(':') === -1) {
21
+ valid = false;
22
+ break;
23
+ }
24
+ }
25
+ if (valid) {
26
+ return true;
27
+ }
28
+ }
29
+ }
30
+ return false;
31
+ }
@@ -0,0 +1,8 @@
1
+ import { Reflector } from '@nestjs/core';
2
+ import { GenericObject } from '@node-c/core';
3
+
4
+ export const AccessControlContext = Reflector.createDecorator<
5
+ string | { context: string; resourceMap: GenericObject<string> }
6
+ >();
7
+
8
+ export const AccessControlResource = Reflector.createDecorator<string>();
@@ -0,0 +1 @@
1
+ export * from './http.decorators.accessControl';
@@ -0,0 +1 @@
1
+ export * from './http.filtes.exception';
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './common/definitions';
2
- export * from './exceptionFilters';
2
+ export * from './filters';
3
+ export * from './decorators';
3
4
  export * from './interceptors';
4
5
  export * from './middlewares';
5
6
  export * from './module';
@@ -0,0 +1,101 @@
1
+ import { CallHandler, ExecutionContext, HttpException, HttpStatus, Injectable, NestInterceptor } from '@nestjs/common';
2
+ import { ModuleRef, Reflector } from '@nestjs/core';
3
+
4
+ import { GenericObject, LoggerService, Constants as NodeCCoreConstants, setNested } from '@node-c/core';
5
+ import {
6
+ IAMAuthorizationService,
7
+ IAMUserManagerUserWithPermissionsData,
8
+ Constants as NodeCDomainIAMConstants
9
+ } from '@node-c/domain-iam';
10
+
11
+ import { Observable, map } from 'rxjs';
12
+
13
+ import { RequestWithLocals } from '../common/definitions';
14
+ import { AccessControlContext, AccessControlResource } from '../decorators';
15
+
16
+ /*
17
+ * Authorization interceptor - used for role-based and fine-grained access control.
18
+ */
19
+ @Injectable()
20
+ export class HTTPAccessControlInterceptor<
21
+ User extends IAMUserManagerUserWithPermissionsData<unknown, unknown>
22
+ > implements NestInterceptor {
23
+ constructor(
24
+ // eslint-disable-next-line no-unused-vars
25
+ protected logger: LoggerService,
26
+ // eslint-disable-next-line no-unused-vars
27
+ protected moduleRef: ModuleRef,
28
+ // eslint-disable-next-line no-unused-vars
29
+ protected reflector: Reflector
30
+ ) {}
31
+
32
+ async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<unknown>> {
33
+ const [req]: [RequestWithLocals<User>, unknown] = context.getArgs();
34
+ const locals = req.locals!;
35
+ if (!locals) {
36
+ throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
37
+ } else if (locals.isAnonymous) {
38
+ return next.handle();
39
+ }
40
+ const { logger, moduleRef, reflector } = this;
41
+ const contextClass = context.getClass();
42
+ const contextHandler = context.getHandler();
43
+ const moduleName =
44
+ moduleRef.get(NodeCDomainIAMConstants.ACCESS_CONTROL_MODULE_NAME) ||
45
+ moduleRef.get(NodeCCoreConstants.API_MODULE_NAME);
46
+ if (!moduleName) {
47
+ logger.error(
48
+ `[HTTPAccessControlInterceptor]: No moduleName configured for ${contextClass.name}.${contextHandler.name}.`
49
+ );
50
+ throw new HttpException('Internal Server Error', HttpStatus.INTERNAL_SERVER_ERROR);
51
+ }
52
+ const resourceContextData = reflector.get(AccessControlContext, contextClass);
53
+ const accessControlOptions = {
54
+ moduleName,
55
+ resource:
56
+ reflector.get(AccessControlResource, contextHandler) ||
57
+ (typeof resourceContextData !== 'string' && resourceContextData?.resourceMap?.[contextHandler.name]) ||
58
+ contextHandler.name,
59
+ resourceContext:
60
+ (typeof resourceContextData === 'string' && resourceContextData) ||
61
+ (typeof resourceContextData !== 'string' && resourceContextData?.context) ||
62
+ contextClass.name
63
+ };
64
+ const user = locals.user!; // we'll always have this, otherwise the system has not been configured properly
65
+ const {
66
+ authorizationPoints: usedAuthorizationPoints,
67
+ errorCode,
68
+ hasAccess,
69
+ inputDataToBeMutated
70
+ } = IAMAuthorizationService.checkAccess(
71
+ { body: req.body, headers: req.headers, params: req.params, query: req.query },
72
+ user,
73
+ accessControlOptions
74
+ );
75
+ if (!hasAccess) {
76
+ logger.error(
77
+ `[${moduleName}][HTTPAccessControlInterceptor]: No user access to resource ${accessControlOptions.moduleName}.${accessControlOptions.resourceContext}.${accessControlOptions.resource} - ${errorCode}.`
78
+ );
79
+ throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
80
+ }
81
+ for (const key in inputDataToBeMutated) {
82
+ setNested(req, key, inputDataToBeMutated[key], { removeNestedFieldEscapeSign: true });
83
+ }
84
+ return next.handle().pipe(
85
+ map((data?: unknown) => {
86
+ if (typeof data === 'undefined' || data === null || typeof data !== 'object' || data instanceof Date) {
87
+ return data;
88
+ }
89
+ const actualData = data as GenericObject;
90
+ const { outputDataToBeMutated } = IAMAuthorizationService.processOutputData(
91
+ usedAuthorizationPoints,
92
+ actualData
93
+ );
94
+ for (const key in outputDataToBeMutated) {
95
+ setNested(actualData, key, outputDataToBeMutated[key]);
96
+ }
97
+ return actualData;
98
+ })
99
+ );
100
+ }
101
+ }
@@ -1,6 +1,6 @@
1
1
  import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
2
2
 
3
- import { ApplicationError } from '@node-c/core';
3
+ import { ApplicationError, LoggerService } from '@node-c/core';
4
4
 
5
5
  import { Observable } from 'rxjs';
6
6
  import { catchError } from 'rxjs/operators';
@@ -9,10 +9,15 @@ import { ServerError } from '../common/definitions/common.errors';
9
9
 
10
10
  @Injectable()
11
11
  export class HTTPErrorInterceptor implements NestInterceptor {
12
+ constructor(
13
+ // eslint-disable-next-line no-unused-vars
14
+ protected logger: LoggerService
15
+ ) {}
16
+
12
17
  intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
13
18
  return next.handle().pipe(
14
19
  catchError(error => {
15
- console.error(error);
20
+ this.logger.error(error);
16
21
  let message: string | string[] = 'An error has occurred.';
17
22
  let status = 500;
18
23
  if (error instanceof ApplicationError || error instanceof ServerError) {
@@ -43,16 +48,12 @@ export class HTTPErrorInterceptor implements NestInterceptor {
43
48
  message = error.message;
44
49
  }
45
50
  }
46
- // TODO: fix this, as we're still getting error 500 when throwing the exception
47
51
  context
48
52
  .switchToHttp()
49
53
  .getResponse()
50
54
  .status(status)
51
55
  .json({ error: message instanceof Array ? message.join('\n') : message });
52
- return [];
53
- // return throwError(
54
- // () => new HttpException({ error: message instanceof Array ? message.join('\n') : message }, status)
55
- // );
56
+ return new Observable();
56
57
  })
57
58
  );
58
59
  }
@@ -1,2 +1,2 @@
1
- export * from './http.interceptors.authorization';
1
+ export * from './http.interceptors.accessControl';
2
2
  export * from './http.interceptors.error';
@@ -0,0 +1,155 @@
1
+ import { HttpException, HttpStatus, Inject, Injectable, NestMiddleware } from '@nestjs/common';
2
+
3
+ import { AppConfigAPIHTTP, ConfigProviderService, LoggerService } from '@node-c/core';
4
+ import {
5
+ AuthorizationPoint,
6
+ IAMAuthorizationService,
7
+ IAMTokenManagerService,
8
+ IAMUserManagerService,
9
+ IAMUserManagerUserTokenEnityFields
10
+ } from '@node-c/domain-iam';
11
+
12
+ import { NextFunction, Response } from 'express';
13
+
14
+ import { Constants, RequestWithLocals } from '../common/definitions';
15
+ import { checkRoutes } from '../common/utils';
16
+
17
+ /*
18
+ * Authorization middleware - used for general authorization of the HTTP resource.
19
+ */
20
+ @Injectable()
21
+ export class HTTPAuthorizationMiddleware<User extends object> implements NestMiddleware {
22
+ constructor(
23
+ @Inject(Constants.API_MODULE_AUTHORIZATION_SERVICE)
24
+ // eslint-disable-next-line no-unused-vars
25
+ protected authorizationService: IAMAuthorizationService<AuthorizationPoint<unknown>>,
26
+ // eslint-disable-next-line no-unused-vars
27
+ protected configProvider: ConfigProviderService,
28
+ // eslint-disable-next-line no-unused-vars
29
+ protected logger: LoggerService,
30
+ @Inject(Constants.API_MODULE_NAME)
31
+ // eslint-disable-next-line no-unused-vars
32
+ protected moduleName: string,
33
+ @Inject(Constants.AUTHORIZATION_MIDDLEWARE_TOKEN_MANAGER_SERVICE)
34
+ // eslint-disable-next-line no-unused-vars
35
+ protected tokenManager?: IAMTokenManagerService<IAMUserManagerUserTokenEnityFields>,
36
+ @Inject(Constants.AUTHENTICATION_MIDDLEWARE_USERS_SERVICE)
37
+ // eslint-disable-next-line no-unused-vars
38
+ protected usersService?: IAMUserManagerService<User>
39
+ ) {}
40
+
41
+ use(req: RequestWithLocals<unknown>, res: Response, next: NextFunction): void {
42
+ const { configProvider, logger, moduleName, tokenManager, usersService } = this;
43
+ (async () => {
44
+ const moduleConfig = configProvider.config.api![moduleName] as AppConfigAPIHTTP;
45
+ const { anonymousAccessRoutes } = moduleConfig;
46
+ const requestMethod = req.method.toLowerCase();
47
+ if (!req.locals) {
48
+ req.locals = {};
49
+ }
50
+ if (anonymousAccessRoutes && Object.keys(anonymousAccessRoutes).length) {
51
+ const originalUrl = req.originalUrl.split('?')[0];
52
+ let isAnonymous = false;
53
+ for (const route in anonymousAccessRoutes) {
54
+ if (
55
+ checkRoutes(originalUrl, [route]) &&
56
+ anonymousAccessRoutes[route].find(method => method === requestMethod)
57
+ ) {
58
+ isAnonymous = true;
59
+ break;
60
+ }
61
+ }
62
+ if (isAnonymous) {
63
+ req.locals.isAnonymous = true;
64
+ next();
65
+ return;
66
+ }
67
+ }
68
+ const hasApiKey = !!req.headers.authorization?.match(/^ApiKey\s/);
69
+ if (hasApiKey) {
70
+ const [apiKeyFromHeader, requestSignature] =
71
+ req.headers.authorization?.replace(/^ApiKey\s/, '')?.split(' ') || [];
72
+ let signatureContent = '';
73
+ if (requestMethod === 'get' && req.query && Object.keys(req.query).length) {
74
+ signatureContent = JSON.stringify(req.query);
75
+ } else if (
76
+ (requestMethod === 'delete' ||
77
+ requestMethod === 'patch' ||
78
+ requestMethod === 'post' ||
79
+ requestMethod === 'put') &&
80
+ req.body &&
81
+ Object.keys(req.body).length
82
+ ) {
83
+ signatureContent = JSON.stringify(req.body);
84
+ } else {
85
+ signatureContent = req.originalUrl.split('?')[0];
86
+ }
87
+ const { valid } = await this.authorizationService.authorizeApiKey(
88
+ {
89
+ apiKey: apiKeyFromHeader,
90
+ signature: requestSignature,
91
+ signatureContent
92
+ },
93
+ { config: moduleConfig }
94
+ );
95
+ if (!valid) {
96
+ throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED);
97
+ }
98
+ next();
99
+ return;
100
+ } else if (!tokenManager) {
101
+ logger.error('Missing api key in the configuration and no tokenManager set up.');
102
+ throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED);
103
+ }
104
+ let tokens: string[] = [];
105
+ let authToken = req.headers.authorization;
106
+ let refreshToken: string | undefined;
107
+ let useCookie = false;
108
+ if (typeof authToken === 'string' && authToken.length && authToken.match(/^Bearer\s/)) {
109
+ tokens = authToken.split(' ');
110
+ if (tokens.length) {
111
+ authToken = tokens[1];
112
+ refreshToken = tokens[2];
113
+ }
114
+ } else {
115
+ authToken = req.cookies['sid'];
116
+ useCookie = true;
117
+ }
118
+ const { newAuthToken, tokenContent, valid } =
119
+ await this.authorizationService.authorizeBearer<IAMUserManagerUserTokenEnityFields>(
120
+ { authToken, refreshToken },
121
+ { identifierDataField: usersService ? 'userId' : undefined }
122
+ );
123
+ if (!valid) {
124
+ throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED);
125
+ }
126
+ if (usersService) {
127
+ const userId = tokenContent?.data?.userId;
128
+ if (!userId) {
129
+ logger.error('Missing userId in the tokenContent data.');
130
+ throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED);
131
+ }
132
+ // use the bearer auth token decoded payload for the user data, if configured this way
133
+ const user = tokenContent?.data?.user;
134
+ if (user) {
135
+ req.locals!.user = user;
136
+ } else {
137
+ req.locals!.user = await usersService.getUserWithPermissionsData({ filters: { id: userId } });
138
+ }
139
+ }
140
+ if (newAuthToken) {
141
+ res.setHeader('Authorization', `Bearer ${newAuthToken}${refreshToken ? ` ${refreshToken}` : ''}`);
142
+ if (useCookie) {
143
+ res.cookie('sid', newAuthToken);
144
+ }
145
+ }
146
+ next();
147
+ })().then(
148
+ () => true,
149
+ err => {
150
+ logger.error(err);
151
+ res.status((err && err.status) || HttpStatus.INTERNAL_SERVER_ERROR).end();
152
+ }
153
+ );
154
+ }
155
+ }
@@ -25,9 +25,9 @@ export class HTTPCORSMiddleware implements NestMiddleware {
25
25
  'Access-Control-Allow-Headers',
26
26
  'accept,accept-encoding,accept-language,authorization,connection,content-type,host,origin,referer,user-agent'
27
27
  );
28
- res.set('Access-Control-Expose-Headers', 'Authorization');
29
28
  res.set('Access-Control-Allow-Methods', 'OPTIONS,GET,POST,PUT,PATCH,DELETE');
30
29
  res.set('Access-Control-Allow-Credentials', 'true');
30
+ res.set('Access-Control-Expose-Headers', 'Authorization');
31
31
  if (req.method.toLowerCase() === 'options') {
32
32
  res.status(HttpStatus.OK).end();
33
33
  return;
@@ -0,0 +1,22 @@
1
+ import { Inject, Injectable, NestMiddleware } from '@nestjs/common';
2
+
3
+ import { LoggerService } from '@node-c/core';
4
+ import { NextFunction, Response } from 'express';
5
+
6
+ import { Constants, RequestWithLocals } from '../common/definitions';
7
+
8
+ @Injectable()
9
+ export class HTTPRequestLoggingMiddleware implements NestMiddleware {
10
+ constructor(
11
+ // eslint-disable-next-line no-unused-vars
12
+ protected logger: LoggerService,
13
+ @Inject(Constants.API_MODULE_NAME)
14
+ // eslint-disable-next-line no-unused-vars
15
+ protected moduleName: string
16
+ ) {}
17
+
18
+ use(req: RequestWithLocals<unknown>, _res: Response, next: NextFunction): void {
19
+ this.logger.info(`[${this.moduleName}]: ${req.method} ${req.baseUrl}`);
20
+ next();
21
+ }
22
+ }
@@ -1,2 +1,3 @@
1
- export * from './http.middlewares.authentication';
1
+ export * from './http.middlewares.authorization';
2
2
  export * from './http.middlewares.cors';
3
+ export * from './http.middlewares.requestLogging';