@node-c/api-http 1.0.0-alpha14 → 1.0.0-alpha16
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/common/utils/index.d.ts +1 -0
- package/dist/common/utils/index.js +18 -0
- package/dist/common/utils/index.js.map +1 -0
- package/dist/common/utils/utils.checkRoutes.d.ts +1 -0
- package/dist/common/utils/utils.checkRoutes.js +27 -0
- package/dist/common/utils/utils.checkRoutes.js.map +1 -0
- package/dist/interceptors/http.interceptors.authorization.js +5 -2
- package/dist/interceptors/http.interceptors.authorization.js.map +1 -1
- package/dist/middlewares/http.middlewares.authentication.d.ts +3 -3
- package/dist/middlewares/http.middlewares.authentication.js +57 -11
- package/dist/middlewares/http.middlewares.authentication.js.map +1 -1
- package/package.json +6 -5
- package/src/common/utils/index.ts +1 -0
- package/src/common/utils/utils.checkRoutes.ts +31 -0
- package/src/interceptors/http.interceptors.authorization.ts +2 -2
- package/src/middlewares/http.middlewares.authentication.ts +59 -12
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './utils.checkRoutes';
|
|
@@ -0,0 +1,18 @@
|
|
|
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("./utils.checkRoutes"), exports);
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/common/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,sDAAoC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function checkRoutes(route: string, routes: string[]): boolean;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkRoutes = checkRoutes;
|
|
4
|
+
function checkRoutes(route, routes) {
|
|
5
|
+
const splitRoute = route.split('/');
|
|
6
|
+
for (const i in routes) {
|
|
7
|
+
const item = routes[i], splitItem = item.split('/');
|
|
8
|
+
if (item === '*' || route === item) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
if (item.indexOf(':') !== -1 && splitItem.length === splitRoute.length) {
|
|
12
|
+
let valid = true;
|
|
13
|
+
for (const j in splitItem) {
|
|
14
|
+
const innerItem = splitItem[j], routeItem = splitRoute[j];
|
|
15
|
+
if (routeItem !== innerItem && innerItem.indexOf(':') === -1) {
|
|
16
|
+
valid = false;
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (valid) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=utils.checkRoutes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.checkRoutes.js","sourceRoot":"","sources":["../../../src/common/utils/utils.checkRoutes.ts"],"names":[],"mappings":";;AAMA,kCAwBC;AAxBD,SAAgB,WAAW,CAAC,KAAa,EAAE,MAAgB;IACzD,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,EACpB,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,IAAI,KAAK,GAAG,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,UAAU,CAAC,MAAM,EAAE,CAAC;YACvE,IAAI,KAAK,GAAG,IAAI,CAAC;YACjB,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;gBAC1B,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,EAC5B,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;gBAC5B,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;oBAC7D,KAAK,GAAG,KAAK,CAAC;oBACd,MAAM;gBACR,CAAC;YACH,CAAC;YACD,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -20,12 +20,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
20
20
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
21
21
|
});
|
|
22
22
|
};
|
|
23
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
24
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
25
|
+
};
|
|
23
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
27
|
exports.HTTPAuthorizationInterceptor = void 0;
|
|
25
28
|
const common_1 = require("@nestjs/common");
|
|
26
29
|
const core_1 = require("@node-c/core");
|
|
27
30
|
const domain_iam_1 = require("@node-c/domain-iam");
|
|
28
|
-
const
|
|
31
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
29
32
|
const definitions_1 = require("../common/definitions");
|
|
30
33
|
let HTTPAuthorizationInterceptor = class HTTPAuthorizationInterceptor {
|
|
31
34
|
constructor(authorizationService, configProvider, moduleName) {
|
|
@@ -70,7 +73,7 @@ let HTTPAuthorizationInterceptor = class HTTPAuthorizationInterceptor {
|
|
|
70
73
|
throw new common_1.HttpException('Forbidden', common_1.HttpStatus.FORBIDDEN);
|
|
71
74
|
}
|
|
72
75
|
for (const key in inputDataToBeMutated) {
|
|
73
|
-
|
|
76
|
+
lodash_1.default.set(req, key, inputDataToBeMutated[key]);
|
|
74
77
|
}
|
|
75
78
|
return next.handle();
|
|
76
79
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.interceptors.authorization.js","sourceRoot":"","sources":["../../src/interceptors/http.interceptors.authorization.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"http.interceptors.authorization.js","sourceRoot":"","sources":["../../src/interceptors/http.interceptors.authorization.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,8 +6,8 @@ import { RequestWithLocals } from '../common/definitions';
|
|
|
6
6
|
export declare class HTTPAuthenticationMiddleware<User extends object> implements NestMiddleware {
|
|
7
7
|
protected configProvider: ConfigProviderService;
|
|
8
8
|
protected moduleName: string;
|
|
9
|
-
protected tokenManager
|
|
10
|
-
protected usersService
|
|
11
|
-
constructor(configProvider: ConfigProviderService, moduleName: string, tokenManager
|
|
9
|
+
protected tokenManager?: IAMTokenManagerService<UserTokenEnityFields> | undefined;
|
|
10
|
+
protected usersService?: IAMUsersService<User> | undefined;
|
|
11
|
+
constructor(configProvider: ConfigProviderService, moduleName: string, tokenManager?: IAMTokenManagerService<UserTokenEnityFields> | undefined, usersService?: IAMUsersService<User> | undefined);
|
|
12
12
|
use(req: RequestWithLocals<unknown>, res: Response, next: NextFunction): void;
|
|
13
13
|
}
|
|
@@ -20,13 +20,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
20
20
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
21
21
|
});
|
|
22
22
|
};
|
|
23
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
24
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
25
|
+
};
|
|
23
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
27
|
exports.HTTPAuthenticationMiddleware = void 0;
|
|
28
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
25
29
|
const common_1 = require("@nestjs/common");
|
|
26
30
|
const core_1 = require("@node-c/core");
|
|
27
31
|
const domain_iam_1 = require("@node-c/domain-iam");
|
|
28
|
-
const general_tools_1 = require("@ramster/general-tools");
|
|
29
32
|
const definitions_1 = require("../common/definitions");
|
|
33
|
+
const utils_1 = require("../common/utils");
|
|
30
34
|
let HTTPAuthenticationMiddleware = class HTTPAuthenticationMiddleware {
|
|
31
35
|
constructor(configProvider, moduleName, tokenManager, usersService) {
|
|
32
36
|
this.configProvider = configProvider;
|
|
@@ -36,8 +40,9 @@ let HTTPAuthenticationMiddleware = class HTTPAuthenticationMiddleware {
|
|
|
36
40
|
}
|
|
37
41
|
use(req, res, next) {
|
|
38
42
|
(() => __awaiter(this, void 0, void 0, function* () {
|
|
39
|
-
var _a;
|
|
40
|
-
const { anonymousAccessRoutes } = this.configProvider.config.api[this.moduleName];
|
|
43
|
+
var _a, _b, _c;
|
|
44
|
+
const { anonymousAccessRoutes, apiKey, apiSecret, apiSecretAlgorithm } = this.configProvider.config.api[this.moduleName];
|
|
45
|
+
const requestMethod = req.method.toLowerCase();
|
|
41
46
|
if (!req.locals) {
|
|
42
47
|
req.locals = {};
|
|
43
48
|
}
|
|
@@ -45,8 +50,8 @@ let HTTPAuthenticationMiddleware = class HTTPAuthenticationMiddleware {
|
|
|
45
50
|
const originalUrl = req.originalUrl.split('?')[0];
|
|
46
51
|
let isAnonymous = false;
|
|
47
52
|
for (const route in anonymousAccessRoutes) {
|
|
48
|
-
if ((0,
|
|
49
|
-
anonymousAccessRoutes[route].find(method => method ===
|
|
53
|
+
if ((0, utils_1.checkRoutes)(originalUrl, [route]) &&
|
|
54
|
+
anonymousAccessRoutes[route].find(method => method === requestMethod)) {
|
|
50
55
|
isAnonymous = true;
|
|
51
56
|
break;
|
|
52
57
|
}
|
|
@@ -58,6 +63,45 @@ let HTTPAuthenticationMiddleware = class HTTPAuthenticationMiddleware {
|
|
|
58
63
|
}
|
|
59
64
|
}
|
|
60
65
|
const { tokenManager, usersService } = this;
|
|
66
|
+
if (apiKey) {
|
|
67
|
+
const [apiKeyFromHeader, requestSignature] = ((_b = (_a = req.headers.authorization) === null || _a === void 0 ? void 0 : _a.replace(/^ApiKey\s/, '')) === null || _b === void 0 ? void 0 : _b.split(' ')) || [];
|
|
68
|
+
if (apiKey !== apiKeyFromHeader) {
|
|
69
|
+
console.error(`${(apiKeyFromHeader === null || apiKeyFromHeader === void 0 ? void 0 : apiKeyFromHeader.length) ? 'Invalid' : 'Missing'} api key in the authorization header.`);
|
|
70
|
+
throw new common_1.HttpException('Unauthorized', common_1.HttpStatus.UNAUTHORIZED);
|
|
71
|
+
}
|
|
72
|
+
if (apiSecret && apiSecretAlgorithm) {
|
|
73
|
+
if (!requestSignature) {
|
|
74
|
+
console.error('Missing request signature in the authorization header.');
|
|
75
|
+
throw new common_1.HttpException('Unauthorized', common_1.HttpStatus.UNAUTHORIZED);
|
|
76
|
+
}
|
|
77
|
+
let signatureContent = '';
|
|
78
|
+
if (requestMethod === 'get' && req.query && Object.keys(req.query).length) {
|
|
79
|
+
signatureContent = JSON.stringify(req.query);
|
|
80
|
+
}
|
|
81
|
+
else if ((requestMethod === 'patch' || requestMethod === 'post' || requestMethod === 'put') &&
|
|
82
|
+
req.body &&
|
|
83
|
+
Object.keys(req.body).length) {
|
|
84
|
+
signatureContent = JSON.stringify(req.body);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
signatureContent = req.originalUrl.split('?')[0];
|
|
88
|
+
}
|
|
89
|
+
const calcualtedSignature = crypto_1.default
|
|
90
|
+
.createHmac(apiSecretAlgorithm, apiSecret)
|
|
91
|
+
.update(signatureContent)
|
|
92
|
+
.digest('hex');
|
|
93
|
+
if (calcualtedSignature !== requestSignature) {
|
|
94
|
+
console.error(`Invalid request signature in the authorization header. Expected: ${calcualtedSignature}. Provided: ${requestSignature}`);
|
|
95
|
+
throw new common_1.HttpException('Unauthorized', common_1.HttpStatus.UNAUTHORIZED);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
next();
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
else if (!tokenManager) {
|
|
102
|
+
console.error('Missing api key in the configuration and no tokenManager set up.');
|
|
103
|
+
throw new common_1.HttpException('Unauthorized', common_1.HttpStatus.UNAUTHORIZED);
|
|
104
|
+
}
|
|
61
105
|
let tokens = [];
|
|
62
106
|
let authToken = req.headers.authorization;
|
|
63
107
|
let authTokenIsNew = false;
|
|
@@ -82,7 +126,7 @@ let HTTPAuthenticationMiddleware = class HTTPAuthenticationMiddleware {
|
|
|
82
126
|
try {
|
|
83
127
|
const tokenRes = yield tokenManager.verifyAccessToken(authToken, {
|
|
84
128
|
deleteFromStoreIfExpired: true,
|
|
85
|
-
identifierDataField: 'userId',
|
|
129
|
+
identifierDataField: usersService ? 'userId' : undefined,
|
|
86
130
|
persistNewToken: true,
|
|
87
131
|
purgeStoreOnRenew: true,
|
|
88
132
|
refreshToken,
|
|
@@ -103,12 +147,14 @@ let HTTPAuthenticationMiddleware = class HTTPAuthenticationMiddleware {
|
|
|
103
147
|
res.cookie('sid', authToken);
|
|
104
148
|
}
|
|
105
149
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
150
|
+
if (usersService) {
|
|
151
|
+
const userId = (_c = tokenContent === null || tokenContent === void 0 ? void 0 : tokenContent.data) === null || _c === void 0 ? void 0 : _c.userId;
|
|
152
|
+
if (!userId) {
|
|
153
|
+
console.error('Missing userId in the tokenContent data.');
|
|
154
|
+
throw new common_1.HttpException('Unauthorized', common_1.HttpStatus.UNAUTHORIZED);
|
|
155
|
+
}
|
|
156
|
+
req.locals.user = yield usersService.getUserWithPermissionsData({ filters: { id: userId } });
|
|
110
157
|
}
|
|
111
|
-
req.locals.user = yield usersService.getUserWithPermissionsData({ filters: { id: userId } });
|
|
112
158
|
next();
|
|
113
159
|
}))().then(() => true, err => {
|
|
114
160
|
console.error(err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.middlewares.authentication.js","sourceRoot":"","sources":["../../src/middlewares/http.middlewares.authentication.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"http.middlewares.authentication.js","sourceRoot":"","sources":["../../src/middlewares/http.middlewares.authentication.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,oDAA4B;AAE5B,2CAA+F;AAE/F,uCAAuE;AACvE,mDAAwH;AAIxH,uDAAqE;AACrE,2CAA8C;AAGvC,IAAM,4BAA4B,GAAlC,MAAM,4BAA4B;IACvC,YAEY,cAAqC,EAGrC,UAAkB,EAGlB,YAA2D,EAG3D,YAAoC;QATpC,mBAAc,GAAd,cAAc,CAAuB;QAGrC,eAAU,GAAV,UAAU,CAAQ;QAGlB,iBAAY,GAAZ,YAAY,CAA+C;QAG3D,iBAAY,GAAZ,YAAY,CAAwB;IAC7C,CAAC;IAEJ,GAAG,CAAC,GAA+B,EAAE,GAAa,EAAE,IAAkB;QACpE,CAAC,GAAS,EAAE;;YACV,MAAM,EAAE,qBAAqB,EAAE,MAAM,EAAE,SAAS,EAAE,kBAAkB,EAAE,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,GAAI,CACtG,IAAI,CAAC,UAAU,CACI,CAAC;YACtB,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YAC/C,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;gBAChB,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;YAClB,CAAC;YACD,IAAI,qBAAqB,IAAI,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,MAAM,EAAE,CAAC;gBACvE,MAAM,WAAW,GAAG,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBAClD,IAAI,WAAW,GAAG,KAAK,CAAC;gBACxB,KAAK,MAAM,KAAK,IAAI,qBAAqB,EAAE,CAAC;oBAC1C,IACE,IAAA,mBAAW,EAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC;wBACjC,qBAAqB,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,KAAK,aAAa,CAAC,EACrE,CAAC;wBACD,WAAW,GAAG,IAAI,CAAC;wBACnB,MAAM;oBACR,CAAC;gBACH,CAAC;gBACD,IAAI,WAAW,EAAE,CAAC;oBAChB,GAAG,CAAC,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC;oBAC9B,IAAI,EAAE,CAAC;oBACP,OAAO;gBACT,CAAC;YACH,CAAC;YACD,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;YAC5C,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,GACxC,CAAA,MAAA,MAAA,GAAG,CAAC,OAAO,CAAC,aAAa,0CAAE,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,0CAAE,KAAK,CAAC,GAAG,CAAC,KAAI,EAAE,CAAC;gBACxE,IAAI,MAAM,KAAK,gBAAgB,EAAE,CAAC;oBAChC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,MAAM,EAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,uCAAuC,CAAC,CAAC;oBAC1G,MAAM,IAAI,sBAAa,CAAC,cAAc,EAAE,mBAAU,CAAC,YAAY,CAAC,CAAC;gBACnE,CAAC;gBACD,IAAI,SAAS,IAAI,kBAAkB,EAAE,CAAC;oBACpC,IAAI,CAAC,gBAAgB,EAAE,CAAC;wBACtB,OAAO,CAAC,KAAK,CAAC,wDAAwD,CAAC,CAAC;wBACxE,MAAM,IAAI,sBAAa,CAAC,cAAc,EAAE,mBAAU,CAAC,YAAY,CAAC,CAAC;oBACnE,CAAC;oBACD,IAAI,gBAAgB,GAAG,EAAE,CAAC;oBAC1B,IAAI,aAAa,KAAK,KAAK,IAAI,GAAG,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;wBAC1E,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;oBAC/C,CAAC;yBAAM,IACL,CAAC,aAAa,KAAK,OAAO,IAAI,aAAa,KAAK,MAAM,IAAI,aAAa,KAAK,KAAK,CAAC;wBAClF,GAAG,CAAC,IAAI;wBACR,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,EAC5B,CAAC;wBACD,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBAC9C,CAAC;yBAAM,CAAC;wBACN,gBAAgB,GAAG,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;oBACnD,CAAC;oBACD,MAAM,mBAAmB,GAAG,gBAAM;yBAC/B,UAAU,CAAC,kBAAkB,EAAE,SAAS,CAAC;yBACzC,MAAM,CAAC,gBAAgB,CAAC;yBACxB,MAAM,CAAC,KAAK,CAAC,CAAC;oBACjB,IAAI,mBAAmB,KAAK,gBAAgB,EAAE,CAAC;wBAC7C,OAAO,CAAC,KAAK,CACX,oEAAoE,mBAAmB,eAAe,gBAAgB,EAAE,CACzH,CAAC;wBACF,MAAM,IAAI,sBAAa,CAAC,cAAc,EAAE,mBAAU,CAAC,YAAY,CAAC,CAAC;oBACnE,CAAC;gBACH,CAAC;gBACD,IAAI,EAAE,CAAC;gBACP,OAAO;YACT,CAAC;iBAAM,IAAI,CAAC,YAAY,EAAE,CAAC;gBACzB,OAAO,CAAC,KAAK,CAAC,kEAAkE,CAAC,CAAC;gBAClF,MAAM,IAAI,sBAAa,CAAC,cAAc,EAAE,mBAAU,CAAC,YAAY,CAAC,CAAC;YACnE,CAAC;YACD,IAAI,MAAM,GAAa,EAAE,CAAC;YAC1B,IAAI,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;YAC1C,IAAI,cAAc,GAAG,KAAK,CAAC;YAC3B,IAAI,YAAgC,CAAC;YACrC,IAAI,YAAmE,CAAC;YACxE,IAAI,SAAS,GAAG,KAAK,CAAC;YACtB,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,CAAC,MAAM,IAAI,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;gBACtF,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC9B,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;oBAClB,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;oBACtB,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;gBAC3B,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBAC/B,SAAS,GAAG,IAAI,CAAC;YACnB,CAAC;YACD,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;gBACrC,MAAM,IAAI,sBAAa,CAAC,cAAc,EAAE,mBAAU,CAAC,YAAY,CAAC,CAAC;YACnE,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,iBAAiB,CAAC,SAAS,EAAE;oBAC/D,wBAAwB,EAAE,IAAI;oBAC9B,mBAAmB,EAAE,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;oBACxD,eAAe,EAAE,IAAI;oBACrB,iBAAiB,EAAE,IAAI;oBACvB,YAAY;oBACZ,0CAA0C,EAAE,aAAa;iBAC1D,CAAC,CAAC;gBACH,YAAY,GAAG,QAAQ,CAAC,OAAQ,CAAC;gBACjC,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;oBACtB,cAAc,GAAG,IAAI,CAAC;gBACxB,CAAC;YACH,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,OAAO,CAAC,KAAK,CAAC,8CAA8C,EAAE,CAAC,CAAC,CAAC;gBACjE,MAAM,IAAI,sBAAa,CAAC,cAAc,EAAE,mBAAU,CAAC,YAAY,CAAC,CAAC;YACnE,CAAC;YACD,IAAI,cAAc,EAAE,CAAC;gBACnB,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,UAAU,SAAS,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC/F,IAAI,SAAS,EAAE,CAAC;oBACd,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;gBAC/B,CAAC;YACH,CAAC;YACD,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,MAAM,GAAG,MAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,IAAI,0CAAE,MAAM,CAAC;gBAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;oBAC1D,MAAM,IAAI,sBAAa,CAAC,cAAc,EAAE,mBAAU,CAAC,YAAY,CAAC,CAAC;gBACnE,CAAC;gBACD,GAAG,CAAC,MAAO,CAAC,IAAI,GAAG,MAAM,YAAY,CAAC,0BAA0B,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;YAChG,CAAC;YACD,IAAI,EAAE,CAAC;QACT,CAAC,CAAA,CAAC,EAAE,CAAC,IAAI,CACP,GAAG,EAAE,CAAC,IAAI,EACV,GAAG,CAAC,EAAE;YACJ,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,mBAAU,CAAC,qBAAqB,CAAC,CAAC,GAAG,EAAE,CAAC;QAC5E,CAAC,CACF,CAAC;IACJ,CAAC;CACF,CAAA;AAhJY,oEAA4B;uCAA5B,4BAA4B;IADxC,IAAA,mBAAU,GAAE;IAKR,WAAA,IAAA,eAAM,EAAC,uBAAS,CAAC,eAAe,CAAC,CAAA;IAGjC,WAAA,IAAA,eAAM,EAAC,uBAAS,CAAC,+CAA+C,CAAC,CAAA;IAGjE,WAAA,IAAA,eAAM,EAAC,uBAAS,CAAC,uCAAuC,CAAC,CAAA;qCAPhC,4BAAqB,UAMtB,mCAAsB;QAGtB,4BAAe;GAZ/B,4BAA4B,CAgJxC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node-c/api-http",
|
|
3
|
-
"version": "1.0.0-
|
|
3
|
+
"version": "1.0.0-alpha16",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -13,17 +13,18 @@
|
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@nestjs/common": "^10.4.12",
|
|
16
|
-
"@ramster/general-tools": "^2.3.0",
|
|
17
16
|
"cookie-parser": "^1.4.7",
|
|
18
17
|
"express": "^4.21.2",
|
|
18
|
+
"lodash": "^4.17.21",
|
|
19
19
|
"rxjs": "^7.8.1"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@types/cookie-parser": "^1.4.8",
|
|
23
|
-
"@types/express": "^5.0.0"
|
|
23
|
+
"@types/express": "^5.0.0",
|
|
24
|
+
"@types/lodash": "^4.17.19"
|
|
24
25
|
},
|
|
25
26
|
"peerDependencies": {
|
|
26
|
-
"@node-c/core": "^1.0.0-
|
|
27
|
-
"@node-c/domain-iam": "^1.0.0-
|
|
27
|
+
"@node-c/core": "^1.0.0-alpha16",
|
|
28
|
+
"@node-c/domain-iam": "^1.0.0-alpha16"
|
|
28
29
|
}
|
|
29
30
|
}
|
|
@@ -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
|
+
}
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import { ConfigProviderService, EndpointSecurityMode } from '@node-c/core';
|
|
12
12
|
import { AuthorizationPoint, IAMAuthorizationService, UserWithPermissionsData } from '@node-c/domain-iam';
|
|
13
13
|
|
|
14
|
-
import
|
|
14
|
+
import ld from 'lodash';
|
|
15
15
|
import { Observable } from 'rxjs';
|
|
16
16
|
|
|
17
17
|
import { Constants, RequestWithLocals } from '../common/definitions';
|
|
@@ -75,7 +75,7 @@ export class HTTPAuthorizationInterceptor<User extends UserWithPermissionsData<u
|
|
|
75
75
|
throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
|
|
76
76
|
}
|
|
77
77
|
for (const key in inputDataToBeMutated) {
|
|
78
|
-
|
|
78
|
+
ld.set(req, key, inputDataToBeMutated[key]);
|
|
79
79
|
}
|
|
80
80
|
return next.handle();
|
|
81
81
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
|
|
1
3
|
import { HttpException, HttpStatus, Inject, Injectable, NestMiddleware } from '@nestjs/common';
|
|
2
4
|
|
|
3
5
|
import { AppConfigAPIHTTP, ConfigProviderService } from '@node-c/core';
|
|
4
6
|
import { DecodedTokenContent, IAMTokenManagerService, IAMUsersService, UserTokenEnityFields } from '@node-c/domain-iam';
|
|
5
7
|
|
|
6
|
-
import { checkRoutes } from '@ramster/general-tools';
|
|
7
|
-
|
|
8
8
|
import { NextFunction, Response } from 'express';
|
|
9
9
|
|
|
10
10
|
import { Constants, RequestWithLocals } from '../common/definitions';
|
|
11
|
+
import { checkRoutes } from '../common/utils';
|
|
11
12
|
|
|
12
13
|
@Injectable()
|
|
13
14
|
export class HTTPAuthenticationMiddleware<User extends object> implements NestMiddleware {
|
|
@@ -19,15 +20,18 @@ export class HTTPAuthenticationMiddleware<User extends object> implements NestMi
|
|
|
19
20
|
protected moduleName: string,
|
|
20
21
|
@Inject(Constants.AUTHENTICATION_MIDDLEWARE_TOKEN_MANAGER_SERVICE)
|
|
21
22
|
// eslint-disable-next-line no-unused-vars
|
|
22
|
-
protected tokenManager
|
|
23
|
+
protected tokenManager?: IAMTokenManagerService<UserTokenEnityFields>,
|
|
23
24
|
@Inject(Constants.AUTHENTICATION_MIDDLEWARE_USERS_SERVICE)
|
|
24
25
|
// eslint-disable-next-line no-unused-vars
|
|
25
|
-
protected usersService
|
|
26
|
+
protected usersService?: IAMUsersService<User>
|
|
26
27
|
) {}
|
|
27
28
|
|
|
28
29
|
use(req: RequestWithLocals<unknown>, res: Response, next: NextFunction): void {
|
|
29
30
|
(async () => {
|
|
30
|
-
const { anonymousAccessRoutes } = this.configProvider.config.api![
|
|
31
|
+
const { anonymousAccessRoutes, apiKey, apiSecret, apiSecretAlgorithm } = this.configProvider.config.api![
|
|
32
|
+
this.moduleName
|
|
33
|
+
] as AppConfigAPIHTTP;
|
|
34
|
+
const requestMethod = req.method.toLowerCase();
|
|
31
35
|
if (!req.locals) {
|
|
32
36
|
req.locals = {};
|
|
33
37
|
}
|
|
@@ -37,7 +41,7 @@ export class HTTPAuthenticationMiddleware<User extends object> implements NestMi
|
|
|
37
41
|
for (const route in anonymousAccessRoutes) {
|
|
38
42
|
if (
|
|
39
43
|
checkRoutes(originalUrl, [route]) &&
|
|
40
|
-
anonymousAccessRoutes[route].find(method => method ===
|
|
44
|
+
anonymousAccessRoutes[route].find(method => method === requestMethod)
|
|
41
45
|
) {
|
|
42
46
|
isAnonymous = true;
|
|
43
47
|
break;
|
|
@@ -50,6 +54,47 @@ export class HTTPAuthenticationMiddleware<User extends object> implements NestMi
|
|
|
50
54
|
}
|
|
51
55
|
}
|
|
52
56
|
const { tokenManager, usersService } = this;
|
|
57
|
+
if (apiKey) {
|
|
58
|
+
const [apiKeyFromHeader, requestSignature] =
|
|
59
|
+
req.headers.authorization?.replace(/^ApiKey\s/, '')?.split(' ') || [];
|
|
60
|
+
if (apiKey !== apiKeyFromHeader) {
|
|
61
|
+
console.error(`${apiKeyFromHeader?.length ? 'Invalid' : 'Missing'} api key in the authorization header.`);
|
|
62
|
+
throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED);
|
|
63
|
+
}
|
|
64
|
+
if (apiSecret && apiSecretAlgorithm) {
|
|
65
|
+
if (!requestSignature) {
|
|
66
|
+
console.error('Missing request signature in the authorization header.');
|
|
67
|
+
throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED);
|
|
68
|
+
}
|
|
69
|
+
let signatureContent = '';
|
|
70
|
+
if (requestMethod === 'get' && req.query && Object.keys(req.query).length) {
|
|
71
|
+
signatureContent = JSON.stringify(req.query);
|
|
72
|
+
} else if (
|
|
73
|
+
(requestMethod === 'patch' || requestMethod === 'post' || requestMethod === 'put') &&
|
|
74
|
+
req.body &&
|
|
75
|
+
Object.keys(req.body).length
|
|
76
|
+
) {
|
|
77
|
+
signatureContent = JSON.stringify(req.body);
|
|
78
|
+
} else {
|
|
79
|
+
signatureContent = req.originalUrl.split('?')[0];
|
|
80
|
+
}
|
|
81
|
+
const calcualtedSignature = crypto
|
|
82
|
+
.createHmac(apiSecretAlgorithm, apiSecret)
|
|
83
|
+
.update(signatureContent)
|
|
84
|
+
.digest('hex');
|
|
85
|
+
if (calcualtedSignature !== requestSignature) {
|
|
86
|
+
console.error(
|
|
87
|
+
`Invalid request signature in the authorization header. Expected: ${calcualtedSignature}. Provided: ${requestSignature}`
|
|
88
|
+
);
|
|
89
|
+
throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
next();
|
|
93
|
+
return;
|
|
94
|
+
} else if (!tokenManager) {
|
|
95
|
+
console.error('Missing api key in the configuration and no tokenManager set up.');
|
|
96
|
+
throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED);
|
|
97
|
+
}
|
|
53
98
|
let tokens: string[] = [];
|
|
54
99
|
let authToken = req.headers.authorization;
|
|
55
100
|
let authTokenIsNew = false;
|
|
@@ -73,7 +118,7 @@ export class HTTPAuthenticationMiddleware<User extends object> implements NestMi
|
|
|
73
118
|
try {
|
|
74
119
|
const tokenRes = await tokenManager.verifyAccessToken(authToken, {
|
|
75
120
|
deleteFromStoreIfExpired: true,
|
|
76
|
-
identifierDataField: 'userId',
|
|
121
|
+
identifierDataField: usersService ? 'userId' : undefined,
|
|
77
122
|
persistNewToken: true,
|
|
78
123
|
purgeStoreOnRenew: true,
|
|
79
124
|
refreshToken,
|
|
@@ -93,12 +138,14 @@ export class HTTPAuthenticationMiddleware<User extends object> implements NestMi
|
|
|
93
138
|
res.cookie('sid', authToken);
|
|
94
139
|
}
|
|
95
140
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
141
|
+
if (usersService) {
|
|
142
|
+
const userId = tokenContent?.data?.userId;
|
|
143
|
+
if (!userId) {
|
|
144
|
+
console.error('Missing userId in the tokenContent data.');
|
|
145
|
+
throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED);
|
|
146
|
+
}
|
|
147
|
+
req.locals!.user = await usersService.getUserWithPermissionsData({ filters: { id: userId } });
|
|
100
148
|
}
|
|
101
|
-
req.locals!.user = await usersService.getUserWithPermissionsData({ filters: { id: userId } });
|
|
102
149
|
next();
|
|
103
150
|
})().then(
|
|
104
151
|
() => true,
|