@node-c/api-http 1.0.0-alpha4

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 (68) hide show
  1. package/README.md +4 -0
  2. package/dist/common/definitions/common.constants.d.ts +9 -0
  3. package/dist/common/definitions/common.constants.js +14 -0
  4. package/dist/common/definitions/common.constants.js.map +1 -0
  5. package/dist/common/definitions/common.definitions.d.ts +9 -0
  6. package/dist/common/definitions/common.definitions.js +3 -0
  7. package/dist/common/definitions/common.definitions.js.map +1 -0
  8. package/dist/common/definitions/common.errors.d.ts +9 -0
  9. package/dist/common/definitions/common.errors.js +12 -0
  10. package/dist/common/definitions/common.errors.js.map +1 -0
  11. package/dist/common/definitions/index.d.ts +2 -0
  12. package/dist/common/definitions/index.js +19 -0
  13. package/dist/common/definitions/index.js.map +1 -0
  14. package/dist/exceptionFilters/http.exceptionFilters.httpException.d.ts +4 -0
  15. package/dist/exceptionFilters/http.exceptionFilters.httpException.js +26 -0
  16. package/dist/exceptionFilters/http.exceptionFilters.httpException.js.map +1 -0
  17. package/dist/exceptionFilters/index.d.ts +1 -0
  18. package/dist/exceptionFilters/index.js +18 -0
  19. package/dist/exceptionFilters/index.js.map +1 -0
  20. package/dist/index.d.ts +5 -0
  21. package/dist/index.js +22 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/interceptors/http.interceptors.authorization.d.ts +11 -0
  24. package/dist/interceptors/http.interceptors.authorization.js +87 -0
  25. package/dist/interceptors/http.interceptors.authorization.js.map +1 -0
  26. package/dist/interceptors/http.interceptors.error.d.ts +5 -0
  27. package/dist/interceptors/http.interceptors.error.js +61 -0
  28. package/dist/interceptors/http.interceptors.error.js.map +1 -0
  29. package/dist/interceptors/index.d.ts +2 -0
  30. package/dist/interceptors/index.js +19 -0
  31. package/dist/interceptors/index.js.map +1 -0
  32. package/dist/middlewares/http.middlewares.authentication.d.ts +13 -0
  33. package/dist/middlewares/http.middlewares.authentication.js +128 -0
  34. package/dist/middlewares/http.middlewares.authentication.js.map +1 -0
  35. package/dist/middlewares/http.middlewares.cors.d.ts +10 -0
  36. package/dist/middlewares/http.middlewares.cors.js +47 -0
  37. package/dist/middlewares/http.middlewares.cors.js.map +1 -0
  38. package/dist/middlewares/index.d.ts +2 -0
  39. package/dist/middlewares/index.js +19 -0
  40. package/dist/middlewares/index.js.map +1 -0
  41. package/dist/module/http.api.module.d.ts +13 -0
  42. package/dist/module/http.api.module.definitions.d.ts +14 -0
  43. package/dist/module/http.api.module.definitions.js +3 -0
  44. package/dist/module/http.api.module.definitions.js.map +1 -0
  45. package/dist/module/http.api.module.js +82 -0
  46. package/dist/module/http.api.module.js.map +1 -0
  47. package/dist/module/index.d.ts +2 -0
  48. package/dist/module/index.js +19 -0
  49. package/dist/module/index.js.map +1 -0
  50. package/package.json +29 -0
  51. package/src/common/definitions/common.constants.ts +16 -0
  52. package/src/common/definitions/common.definitions.ts +10 -0
  53. package/src/common/definitions/common.errors.ts +13 -0
  54. package/src/common/definitions/index.ts +2 -0
  55. package/src/exceptionFilters/http.exceptionFilters.httpException.ts +21 -0
  56. package/src/exceptionFilters/index.ts +1 -0
  57. package/src/index.ts +5 -0
  58. package/src/interceptors/http.interceptors.authorization.ts +82 -0
  59. package/src/interceptors/http.interceptors.error.ts +50 -0
  60. package/src/interceptors/index.ts +2 -0
  61. package/src/middlewares/http.middlewares.authentication.ts +111 -0
  62. package/src/middlewares/http.middlewares.cors.ts +37 -0
  63. package/src/middlewares/index.ts +2 -0
  64. package/src/module/http.api.module.definitions.ts +16 -0
  65. package/src/module/http.api.module.ts +69 -0
  66. package/src/module/index.ts +2 -0
  67. package/tsconfig.build.json +9 -0
  68. package/tsconfig.json +9 -0
@@ -0,0 +1,47 @@
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.HTTPCORSMiddleware = 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 HTTPCORSMiddleware = class HTTPCORSMiddleware {
20
+ constructor(configProvider, moduleName) {
21
+ this.configProvider = configProvider;
22
+ this.moduleName = moduleName;
23
+ }
24
+ use(req, res, next) {
25
+ const allowedOrigins = this.configProvider.config.api[this.moduleName].allowedOrigins;
26
+ const origin = req.headers.origin;
27
+ if (allowedOrigins === null || allowedOrigins === void 0 ? void 0 : allowedOrigins.includes(origin)) {
28
+ res.set('Access-Control-Allow-Origin', origin);
29
+ }
30
+ res.set('Access-Control-Allow-Headers', 'accept,accept-encoding,accept-language,authorization,connection,content-type,host,origin,referer,user-agent');
31
+ res.set('Access-Control-Expose-Headers', 'Authorization');
32
+ res.set('Access-Control-Allow-Methods', 'OPTIONS,GET,POST,PUT,PATCH,DELETE');
33
+ res.set('Access-Control-Allow-Credentials', 'true');
34
+ if (req.method.toLowerCase() === 'options') {
35
+ res.status(common_1.HttpStatus.OK).end();
36
+ return;
37
+ }
38
+ next();
39
+ }
40
+ };
41
+ exports.HTTPCORSMiddleware = HTTPCORSMiddleware;
42
+ exports.HTTPCORSMiddleware = HTTPCORSMiddleware = __decorate([
43
+ (0, common_1.Injectable)(),
44
+ __param(1, (0, common_1.Inject)(definitions_1.Constants.API_MODULE_NAME)),
45
+ __metadata("design:paramtypes", [core_1.ConfigProviderService, String])
46
+ ], HTTPCORSMiddleware);
47
+ //# sourceMappingURL=http.middlewares.cors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.middlewares.cors.js","sourceRoot":"","sources":["../../src/middlewares/http.middlewares.cors.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAgF;AAEhF,uCAAuE;AAGvE,uDAAqE;AAG9D,IAAM,kBAAkB,GAAxB,MAAM,kBAAkB;IAC7B,YAEY,cAAqC,EAGrC,UAAkB;QAHlB,mBAAc,GAAd,cAAc,CAAuB;QAGrC,eAAU,GAAV,UAAU,CAAQ;IAC3B,CAAC;IAEJ,GAAG,CAAC,GAA+B,EAAE,GAAa,EAAE,IAAkB;QACpE,MAAM,cAAc,GAAI,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,GAAI,CAAC,IAAI,CAAC,UAAU,CAAsB,CAAC,cAAc,CAAC;QAC7G,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,MAAgB,CAAC;QAC5C,IAAI,cAAc,aAAd,cAAc,uBAAd,cAAc,CAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACrC,GAAG,CAAC,GAAG,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;QACjD,CAAC;QACD,GAAG,CAAC,GAAG,CACL,8BAA8B,EAC9B,6GAA6G,CAC9G,CAAC;QACF,GAAG,CAAC,GAAG,CAAC,+BAA+B,EAAE,eAAe,CAAC,CAAC;QAC1D,GAAG,CAAC,GAAG,CAAC,8BAA8B,EAAE,mCAAmC,CAAC,CAAC;QAC7E,GAAG,CAAC,GAAG,CAAC,kCAAkC,EAAE,MAAM,CAAC,CAAC;QACpD,IAAI,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,SAAS,EAAE,CAAC;YAC3C,GAAG,CAAC,MAAM,CAAC,mBAAU,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;YAChC,OAAO;QACT,CAAC;QACD,IAAI,EAAE,CAAC;IACT,CAAC;CACF,CAAA;AA5BY,gDAAkB;6BAAlB,kBAAkB;IAD9B,IAAA,mBAAU,GAAE;IAKR,WAAA,IAAA,eAAM,EAAC,uBAAS,CAAC,eAAe,CAAC,CAAA;qCADR,4BAAqB;GAHtC,kBAAkB,CA4B9B"}
@@ -0,0 +1,2 @@
1
+ export * from './http.middlewares.authentication';
2
+ export * from './http.middlewares.cors';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./http.middlewares.authentication"), exports);
18
+ __exportStar(require("./http.middlewares.cors"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middlewares/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,oEAAkD;AAClD,0DAAwC"}
@@ -0,0 +1,13 @@
1
+ import { DynamicModule, MiddlewareConsumer } from '@nestjs/common';
2
+ import { ConfigProviderService } from '@node-c/core';
3
+ import { Response } from 'express';
4
+ import { HTTPAPIModuleOptions } from './http.api.module.definitions';
5
+ import { RequestWithLocals } from '../common/definitions';
6
+ export declare class HTTPAPIModule {
7
+ protected configProvider: ConfigProviderService;
8
+ protected moduleName: string;
9
+ constructor(configProvider: ConfigProviderService, moduleName: string);
10
+ configure(consumer: MiddlewareConsumer): void;
11
+ static rawBodyBuffer(req: RequestWithLocals<unknown>, _res: Response, buffer: Buffer): void;
12
+ static register(options: HTTPAPIModuleOptions): DynamicModule;
13
+ }
@@ -0,0 +1,14 @@
1
+ import { ModuleMetadata } from '@nestjs/common';
2
+ import { GenericObject } from '@node-c/core';
3
+ export interface HTTPAPIModuleOptions {
4
+ controllers?: ModuleMetadata['controllers'];
5
+ exports?: ModuleMetadata['exports'];
6
+ folderData: GenericObject<unknown>;
7
+ imports?: {
8
+ atEnd?: ModuleMetadata['imports'];
9
+ atStart?: ModuleMetadata['imports'];
10
+ };
11
+ moduleClass: unknown;
12
+ moduleName: string;
13
+ providers?: ModuleMetadata['providers'];
14
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=http.api.module.definitions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.api.module.definitions.js","sourceRoot":"","sources":["../../src/module/http.api.module.definitions.ts"],"names":[],"mappings":""}
@@ -0,0 +1,82 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ var HTTPAPIModule_1;
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.HTTPAPIModule = void 0;
20
+ const common_1 = require("@nestjs/common");
21
+ const core_1 = require("@node-c/core");
22
+ const cookie_parser_1 = __importDefault(require("cookie-parser"));
23
+ const express_1 = __importDefault(require("express"));
24
+ const definitions_1 = require("../common/definitions");
25
+ const exceptionFilters_1 = require("../exceptionFilters");
26
+ const interceptors_1 = require("../interceptors");
27
+ const middlewares_1 = require("../middlewares");
28
+ let HTTPAPIModule = HTTPAPIModule_1 = class HTTPAPIModule {
29
+ constructor(configProvider, moduleName) {
30
+ this.configProvider = configProvider;
31
+ this.moduleName = moduleName;
32
+ }
33
+ configure(consumer) {
34
+ consumer.apply(express_1.default.urlencoded({ verify: HTTPAPIModule_1.rawBodyBuffer, extended: true })).forRoutes('*');
35
+ consumer.apply(express_1.default.json({ verify: HTTPAPIModule_1.rawBodyBuffer })).forRoutes('*');
36
+ consumer.apply((0, cookie_parser_1.default)()).forRoutes('*');
37
+ consumer.apply(middlewares_1.HTTPCORSMiddleware).forRoutes('*');
38
+ consumer.apply(middlewares_1.HTTPAuthenticationMiddleware).forRoutes('*');
39
+ }
40
+ static rawBodyBuffer(req, _res, buffer) {
41
+ if (buffer && buffer.length) {
42
+ req.rawBody = buffer.toString();
43
+ }
44
+ }
45
+ static register(options) {
46
+ const { folderData, imports: additionalImports, moduleClass } = options;
47
+ const { atEnd: importsAtEnd, atStart: importsAtStart } = additionalImports || {};
48
+ const { controllers, services } = (0, core_1.loadDynamicModules)(folderData);
49
+ return {
50
+ module: moduleClass,
51
+ imports: [...(importsAtStart || []), ...(importsAtEnd || [])],
52
+ providers: [
53
+ {
54
+ provide: definitions_1.Constants.API_MODULE_NAME,
55
+ useValue: options.moduleName
56
+ },
57
+ {
58
+ provide: definitions_1.Constants.AUTHORIZATION_INTERCEPTOR,
59
+ useClass: interceptors_1.HTTPAuthorizationInterceptor
60
+ },
61
+ {
62
+ provide: definitions_1.Constants.ERROR_INTERCEPTOR,
63
+ useClass: interceptors_1.HTTPErrorInterceptor
64
+ },
65
+ {
66
+ provide: definitions_1.Constants.HTTP_EXCEPTION_FILTER,
67
+ useClass: exceptionFilters_1.HttpExceptionFilter
68
+ },
69
+ ...(options.providers || []),
70
+ ...(services || [])
71
+ ],
72
+ controllers: [...(controllers || []), ...(options.controllers || [])],
73
+ exports: [...(services || []), ...(options.exports || [])]
74
+ };
75
+ }
76
+ };
77
+ exports.HTTPAPIModule = HTTPAPIModule;
78
+ exports.HTTPAPIModule = HTTPAPIModule = HTTPAPIModule_1 = __decorate([
79
+ __param(1, (0, common_1.Inject)(definitions_1.Constants.API_MODULE_NAME)),
80
+ __metadata("design:paramtypes", [core_1.ConfigProviderService, String])
81
+ ], HTTPAPIModule);
82
+ //# sourceMappingURL=http.api.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.api.module.js","sourceRoot":"","sources":["../../src/module/http.api.module.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * from './http.api.module';
2
+ export * from './http.api.module.definitions';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./http.api.module"), exports);
18
+ __exportStar(require("./http.api.module.definitions"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/module/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,oDAAkC;AAClC,gEAA8C"}
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@node-c/api-http",
3
+ "version": "1.0.0-alpha4",
4
+ "license": "MIT",
5
+ "main": "dist/index.js",
6
+ "scripts": {
7
+ "build": "tsc -p tsconfig.build.json",
8
+ "check-types": "tsc -p tsconfig.build.json --noEmit",
9
+ "dev": "tsc -p tsconfig.build.json --watch",
10
+ "publish-package": "rm -rf dist/* && rm -f *.tsbuildinfo && npm run build && npm publish --access public",
11
+ "test": "vitest --config src/vitest.config.ts",
12
+ "test:coverage": "vitest --config src/vitest.config.ts --coverage"
13
+ },
14
+ "dependencies": {
15
+ "@nestjs/common": "^10.4.12",
16
+ "@ramster/general-tools": "^2.3.0",
17
+ "cookie-parser": "^1.4.7",
18
+ "express": "^4.21.2",
19
+ "rxjs": "^7.8.1"
20
+ },
21
+ "devDependencies": {
22
+ "@types/cookie-parser": "^1.4.8",
23
+ "@types/express": "^5.0.0"
24
+ },
25
+ "peerDependencies": {
26
+ "@node-c/core": "^1.0.0-alpha4",
27
+ "@node-c/domain-iam": "^1.0.0-alpha4"
28
+ }
29
+ }
@@ -0,0 +1,16 @@
1
+ export enum Constants {
2
+ // eslint-disable-next-line no-unused-vars
3
+ API_MODULE_AUTHORIZATION_SERVICE = 'API_MODULE_AUTHORIZATION_SERVICE',
4
+ // eslint-disable-next-line no-unused-vars
5
+ API_MODULE_NAME = 'API_MODULE_NAME',
6
+ // eslint-disable-next-line no-unused-vars
7
+ AUTHENTICATION_MIDDLEWARE_TOKEN_MANAGER_SERVICE = 'AUTHENTICATION_MIDDLEWARE_TOKEN_MANAGER_SERVICE',
8
+ // eslint-disable-next-line no-unused-vars
9
+ AUTHENTICATION_MIDDLEWARE_USERS_SERVICE = 'AUTHENTICATION_MIDDLEWARE_USERS_SERVICE',
10
+ // eslint-disable-next-line no-unused-vars
11
+ AUTHORIZATION_INTERCEPTOR = 'AUTHORIZATION_INTERCEPTOR',
12
+ // eslint-disable-next-line no-unused-vars
13
+ ERROR_INTERCEPTOR = 'ERROR_INTERCEPTOR',
14
+ // eslint-disable-next-line no-unused-vars
15
+ HTTP_EXCEPTION_FILTER = 'HTTP_EXCEPTION_FILTER'
16
+ }
@@ -0,0 +1,10 @@
1
+ import { Request } from 'express';
2
+
3
+ export interface RequestWithLocals<User> extends Request {
4
+ locals?: {
5
+ isAnonymous?: boolean;
6
+ user?: User;
7
+ [fieldName: string]: unknown;
8
+ };
9
+ rawBody?: string;
10
+ }
@@ -0,0 +1,13 @@
1
+ import { GenericObject } from '@node-c/core';
2
+
3
+ export class ServerError implements Error {
4
+ data: { statusCode: number } | GenericObject;
5
+ message: string;
6
+ name: string;
7
+
8
+ constructor(message: string, data?: GenericObject) {
9
+ this.message = message;
10
+ this.name = 'ServerError';
11
+ this.data = data || {};
12
+ }
13
+ }
@@ -0,0 +1,2 @@
1
+ export * from './common.constants';
2
+ export * from './common.definitions';
@@ -0,0 +1,21 @@
1
+ import { ArgumentsHost, Catch, ExceptionFilter, HttpException } from '@nestjs/common';
2
+ import { Response } from 'express';
3
+
4
+ // The purpose of the class is to handle HttpExceptions that are not caught by the HTTPErrorInterceptor.
5
+ @Catch(HttpException)
6
+ export class HttpExceptionFilter implements ExceptionFilter {
7
+ catch(exception: HttpException, host: ArgumentsHost): void {
8
+ const ctx = host.switchToHttp();
9
+ const response = ctx.getResponse<Response>();
10
+ const status = exception.getStatus();
11
+ // else if (error instanceof BadRequestException) {
12
+ // const { statusCode, message: errorText } = error.getResponse() as unknown
13
+ // status = statusCode
14
+ // message = errorText || message
15
+ // }
16
+ response.status(status).json({
17
+ statusCode: status,
18
+ message: exception.message
19
+ });
20
+ }
21
+ }
@@ -0,0 +1 @@
1
+ export * from './http.exceptionFilters.httpException';
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export * from './common/definitions';
2
+ export * from './exceptionFilters';
3
+ export * from './interceptors';
4
+ export * from './middlewares';
5
+ export * from './module';
@@ -0,0 +1,82 @@
1
+ import {
2
+ CallHandler,
3
+ ExecutionContext,
4
+ HttpException,
5
+ HttpStatus,
6
+ Inject,
7
+ Injectable,
8
+ NestInterceptor
9
+ } from '@nestjs/common';
10
+
11
+ import { ConfigProviderService, EndpointSecurityMode } from '@node-c/core';
12
+ import { AuthorizationPoint, IAMAuthorizationService, UserWithPermissionsData } from '@node-c/domain-iam';
13
+
14
+ import { setNested } from '@ramster/general-tools';
15
+ import { Observable } from 'rxjs';
16
+
17
+ import { Constants, RequestWithLocals } from '../common/definitions';
18
+
19
+ @Injectable()
20
+ export class HTTPAuthorizationInterceptor<User extends UserWithPermissionsData<unknown, unknown>>
21
+ implements NestInterceptor
22
+ {
23
+ constructor(
24
+ @Inject(Constants.API_MODULE_AUTHORIZATION_SERVICE)
25
+ // eslint-disable-next-line no-unused-vars
26
+ protected authorizationService: IAMAuthorizationService<AuthorizationPoint<unknown>>,
27
+ // eslint-disable-next-line no-unused-vars
28
+ protected configProvider: ConfigProviderService,
29
+ @Inject(Constants.API_MODULE_NAME)
30
+ // eslint-disable-next-line no-unused-vars
31
+ protected moduleName: string
32
+ ) {}
33
+
34
+ async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<unknown>> {
35
+ const [req]: [RequestWithLocals<User>, unknown] = context.getArgs();
36
+ const locals = req.locals!;
37
+ if (!locals) {
38
+ throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
39
+ } else if (locals.isAnonymous) {
40
+ return next.handle();
41
+ }
42
+ const { moduleName } = this;
43
+ const controllerName = context.getClass().name;
44
+ const handlerName = context.getHandler().name;
45
+ // TODO: cache this in-memory
46
+ const authorizationData = await this.authorizationService.mapAuthorizationPoints(moduleName);
47
+ let controllerData = authorizationData![controllerName];
48
+ if (!controllerData) {
49
+ controllerData = authorizationData.__all;
50
+ }
51
+ const user = locals.user!; // we'll always have this, otherwise the system has not been configured properly
52
+ let handlerData = controllerData[handlerName];
53
+ if (!handlerData) {
54
+ handlerData = controllerData.__all;
55
+ if (!Object.keys(handlerData).length) {
56
+ const { endpointSecurityMode } = this.configProvider.config.api[moduleName];
57
+ if (!endpointSecurityMode || endpointSecurityMode === EndpointSecurityMode.Strict) {
58
+ console.info(
59
+ `[${moduleName}][HTTPAuthorizationInterceptor]: No authorization point data for handler ${controllerName}.${handlerName}.`
60
+ );
61
+ throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
62
+ }
63
+ return next.handle();
64
+ }
65
+ }
66
+ const { hasAccess, inputDataToBeMutated } = IAMAuthorizationService.checkAccess(
67
+ handlerData,
68
+ { body: req.body, headers: req.headers, params: req.params, query: req.query },
69
+ user
70
+ );
71
+ if (!hasAccess) {
72
+ console.info(
73
+ `[${moduleName}][HTTPAuthorizationInterceptor]: No user access to handler ${controllerName}.${handlerName}.`
74
+ );
75
+ throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
76
+ }
77
+ for (const key in inputDataToBeMutated) {
78
+ setNested(req, key, inputDataToBeMutated[key]);
79
+ }
80
+ return next.handle();
81
+ }
82
+ }
@@ -0,0 +1,50 @@
1
+ import { CallHandler, ExecutionContext, HttpException, Injectable, NestInterceptor } from '@nestjs/common';
2
+
3
+ import { ApplicationError } from '@node-c/core';
4
+
5
+ import { Observable } from 'rxjs';
6
+ import { catchError } from 'rxjs/operators';
7
+
8
+ import { ServerError } from '../common/definitions/common.errors';
9
+
10
+ @Injectable()
11
+ export class HTTPErrorInterceptor implements NestInterceptor {
12
+ intercept(_context: ExecutionContext, next: CallHandler): Observable<unknown> {
13
+ return next.handle().pipe(
14
+ catchError(error => {
15
+ console.error(error);
16
+ let message = 'An error has occurred.';
17
+ let status = 500;
18
+ if (error instanceof ApplicationError || error instanceof ServerError) {
19
+ if (error.message) {
20
+ message = error.message;
21
+ }
22
+ if (error.data) {
23
+ if ('errorCode' in error.data) {
24
+ status = error.data.errorCode as number;
25
+ } else if ('statusCode' in error.data) {
26
+ status = error.data.statusCode as number;
27
+ } else {
28
+ status = 400;
29
+ }
30
+ } else {
31
+ status = 400;
32
+ }
33
+ } else if (error.response) {
34
+ const { response } = error;
35
+ if (response.statusCode) {
36
+ status = response.statusCode;
37
+ }
38
+ if (response.message) {
39
+ message = response.message;
40
+ }
41
+ } else if (error instanceof Error) {
42
+ if (error.message) {
43
+ message = error.message;
44
+ }
45
+ }
46
+ throw new HttpException({ message, statusCode: status }, status);
47
+ })
48
+ );
49
+ }
50
+ }
@@ -0,0 +1,2 @@
1
+ export * from './http.interceptors.authorization';
2
+ export * from './http.interceptors.error';
@@ -0,0 +1,111 @@
1
+ import { HttpException, HttpStatus, Inject, Injectable, NestMiddleware } from '@nestjs/common';
2
+
3
+ import { AppConfigAPIHTTP, ConfigProviderService } from '@node-c/core';
4
+ import { DecodedTokenContent, IAMTokenManagerService, IAMUsersService, UserTokenEnityFields } from '@node-c/domain-iam';
5
+
6
+ import { checkRoutes } from '@ramster/general-tools';
7
+
8
+ import { NextFunction, Response } from 'express';
9
+
10
+ import { Constants, RequestWithLocals } from '../common/definitions';
11
+
12
+ @Injectable()
13
+ export class HTTPAuthenticationMiddleware<User extends object> implements NestMiddleware {
14
+ constructor(
15
+ // eslint-disable-next-line no-unused-vars
16
+ protected configProvider: ConfigProviderService,
17
+ @Inject(Constants.API_MODULE_NAME)
18
+ // eslint-disable-next-line no-unused-vars
19
+ protected moduleName: string,
20
+ @Inject(Constants.AUTHENTICATION_MIDDLEWARE_TOKEN_MANAGER_SERVICE)
21
+ // eslint-disable-next-line no-unused-vars
22
+ protected tokenManager: IAMTokenManagerService<UserTokenEnityFields>,
23
+ @Inject(Constants.AUTHENTICATION_MIDDLEWARE_USERS_SERVICE)
24
+ // eslint-disable-next-line no-unused-vars
25
+ protected usersService: IAMUsersService<User>
26
+ ) {}
27
+
28
+ use(req: RequestWithLocals<unknown>, res: Response, next: NextFunction): void {
29
+ (async () => {
30
+ const { anonymousAccessRoutes } = this.configProvider.config.api![this.moduleName] as AppConfigAPIHTTP;
31
+ if (!req.locals) {
32
+ req.locals = {};
33
+ }
34
+ if (anonymousAccessRoutes && Object.keys(anonymousAccessRoutes).length) {
35
+ const originalUrl = req.originalUrl.split('?')[0];
36
+ let isAnonymous = false;
37
+ for (const route in anonymousAccessRoutes) {
38
+ if (
39
+ checkRoutes(originalUrl, [route]) &&
40
+ anonymousAccessRoutes[route].find(method => method === req.method.toLowerCase())
41
+ ) {
42
+ isAnonymous = true;
43
+ break;
44
+ }
45
+ }
46
+ if (isAnonymous) {
47
+ req.locals.isAnonymous = true;
48
+ next();
49
+ return;
50
+ }
51
+ }
52
+ const { tokenManager, usersService } = this;
53
+ let tokens: string[] = [];
54
+ let authToken = req.headers.authorization;
55
+ let authTokenIsNew = false;
56
+ let refreshToken: string | undefined;
57
+ let tokenContent: DecodedTokenContent<UserTokenEnityFields> | undefined;
58
+ let useCookie = false;
59
+ if (typeof authToken === 'string' && authToken.length && authToken.match(/^Bearer\s/)) {
60
+ tokens = authToken.split(' ');
61
+ if (tokens.length) {
62
+ authToken = tokens[1];
63
+ refreshToken = tokens[2];
64
+ }
65
+ } else {
66
+ authToken = req.cookies['sid'];
67
+ useCookie = true;
68
+ }
69
+ if (!authToken) {
70
+ console.error('Missing auth token.');
71
+ throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED);
72
+ }
73
+ try {
74
+ const tokenRes = await tokenManager.verifyAccessToken(authToken, {
75
+ deleteFromStoreIfExpired: true,
76
+ identifierDataField: 'userId',
77
+ persistNewToken: true,
78
+ purgeStoreOnRenew: true,
79
+ refreshToken,
80
+ refreshTokenAccessTokenIdentifierDataField: 'accessToken'
81
+ });
82
+ tokenContent = tokenRes.content!;
83
+ if (tokenRes.newToken) {
84
+ authTokenIsNew = true;
85
+ }
86
+ } catch (e) {
87
+ console.error('Failed to parse the access or refresh token:', e);
88
+ throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED);
89
+ }
90
+ if (authTokenIsNew) {
91
+ res.setHeader('Authorization', `Bearer ${authToken}${refreshToken ? ` ${refreshToken}` : ''}`);
92
+ if (useCookie) {
93
+ res.cookie('sid', authToken);
94
+ }
95
+ }
96
+ const userId = tokenContent?.data?.userId;
97
+ if (!userId) {
98
+ console.error('Missing userId in the tokenContent data.');
99
+ throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED);
100
+ }
101
+ req.locals!.user = await usersService.getUserWithPermissionsData({ filters: { id: userId } });
102
+ next();
103
+ })().then(
104
+ () => true,
105
+ err => {
106
+ console.error(err);
107
+ res.status((err && err.status) || HttpStatus.INTERNAL_SERVER_ERROR).end();
108
+ }
109
+ );
110
+ }
111
+ }
@@ -0,0 +1,37 @@
1
+ import { HttpStatus, Inject, Injectable, NestMiddleware } from '@nestjs/common';
2
+
3
+ import { AppConfigAPIHTTP, ConfigProviderService } from '@node-c/core';
4
+ import { NextFunction, Response } from 'express';
5
+
6
+ import { Constants, RequestWithLocals } from '../common/definitions';
7
+
8
+ @Injectable()
9
+ export class HTTPCORSMiddleware implements NestMiddleware {
10
+ constructor(
11
+ // eslint-disable-next-line no-unused-vars
12
+ protected configProvider: ConfigProviderService,
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
+ const allowedOrigins = (this.configProvider.config.api![this.moduleName] as AppConfigAPIHTTP).allowedOrigins;
20
+ const origin = req.headers.origin as string;
21
+ if (allowedOrigins?.includes(origin)) {
22
+ res.set('Access-Control-Allow-Origin', origin);
23
+ }
24
+ res.set(
25
+ 'Access-Control-Allow-Headers',
26
+ 'accept,accept-encoding,accept-language,authorization,connection,content-type,host,origin,referer,user-agent'
27
+ );
28
+ res.set('Access-Control-Expose-Headers', 'Authorization');
29
+ res.set('Access-Control-Allow-Methods', 'OPTIONS,GET,POST,PUT,PATCH,DELETE');
30
+ res.set('Access-Control-Allow-Credentials', 'true');
31
+ if (req.method.toLowerCase() === 'options') {
32
+ res.status(HttpStatus.OK).end();
33
+ return;
34
+ }
35
+ next();
36
+ }
37
+ }
@@ -0,0 +1,2 @@
1
+ export * from './http.middlewares.authentication';
2
+ export * from './http.middlewares.cors';