node-server-engine 1.4.9 → 1.5.1

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 (277) hide show
  1. package/.commitlintrc.js +27 -0
  2. package/.releaserc.js +56 -0
  3. package/README.md +154 -2
  4. package/dist/const/tokenIssuer.js +1 -0
  5. package/dist/const/tokenIssuer.js.map +1 -1
  6. package/dist/db/models/SequelizeMeta.js +3 -1
  7. package/dist/db/models/SequelizeMeta.js.map +1 -1
  8. package/dist/entities/ElasticSearch/ElasticSearch.js +1 -2
  9. package/dist/entities/ElasticSearch/ElasticSearch.js.map +1 -1
  10. package/dist/entities/Sequelize/Sequelize.js +4 -1
  11. package/dist/entities/Sequelize/Sequelize.js.map +1 -1
  12. package/dist/entities/Server/Server.js +8 -11
  13. package/dist/entities/Server/Server.js.map +1 -1
  14. package/dist/entities/SocketClient/SocketClient.d.ts +4 -1
  15. package/dist/entities/SocketClient/SocketClient.js +5 -1
  16. package/dist/entities/SocketClient/SocketClient.js.map +1 -1
  17. package/dist/index.js +1 -2
  18. package/dist/index.js.map +1 -1
  19. package/dist/middleware/checkPermission/checkPermission.d.ts +1 -1
  20. package/dist/middleware/checkPermission/checkPermission.js +4 -2
  21. package/dist/middleware/checkPermission/checkPermission.js.map +1 -1
  22. package/dist/utils/createSortedObject/createSortedObject.d.ts +5 -1
  23. package/dist/utils/createSortedObject/createSortedObject.js +13 -4
  24. package/dist/utils/createSortedObject/createSortedObject.js.map +1 -1
  25. package/dist/utils/dbMigration/dbMigration.js +34 -15
  26. package/dist/utils/dbMigration/dbMigration.js.map +1 -1
  27. package/dist/utils/geminiFileUpload/geminiFileUpload.js +2 -1
  28. package/dist/utils/geminiFileUpload/geminiFileUpload.js.map +1 -1
  29. package/dist/utils/jwt/jwt.js +1 -1
  30. package/dist/utils/jwt/jwt.js.map +1 -1
  31. package/dist/utils/report/report.d.ts +9 -3
  32. package/dist/utils/report/report.js +29 -12
  33. package/dist/utils/report/report.js.map +1 -1
  34. package/dist/utils/secretManager/secretLoader.js +5 -1
  35. package/dist/utils/secretManager/secretLoader.js.map +1 -1
  36. package/dist/utils/semverCompare/semverCompare.d.ts +4 -4
  37. package/dist/utils/semverCompare/semverCompare.js +16 -18
  38. package/dist/utils/semverCompare/semverCompare.js.map +1 -1
  39. package/package.json +30 -19
  40. package/.env.example +0 -186
  41. package/.github/workflows/publish.yml +0 -41
  42. package/.prettierrc +0 -7
  43. package/Dockerfile +0 -31
  44. package/babel.config.json +0 -34
  45. package/eslint.config.mjs +0 -11
  46. package/src/const/DebeziumEvent.ts +0 -6
  47. package/src/const/LogSeverity.ts +0 -7
  48. package/src/const/index.ts +0 -5
  49. package/src/const/metrics.ts +0 -6
  50. package/src/const/mime.ts +0 -37
  51. package/src/const/tokenIssuer.ts +0 -7
  52. package/src/db/migrations/20241030121500-create-sequelize-meta-table.ts +0 -29
  53. package/src/db/models/SequelizeMeta.ts +0 -16
  54. package/src/db/models/index.ts +0 -2
  55. package/src/entities/ElasticSearch/ElasticSearch.ts +0 -103
  56. package/src/entities/ElasticSearch/ElasticSearch.types.ts +0 -7
  57. package/src/entities/ElasticSearch/index.ts +0 -2
  58. package/src/entities/Endpoint/Endpoint.test.ts +0 -248
  59. package/src/entities/Endpoint/Endpoint.ts +0 -221
  60. package/src/entities/Endpoint/Endpoint.types.ts +0 -181
  61. package/src/entities/Endpoint/index.ts +0 -2
  62. package/src/entities/EngineError/EngineError.ts +0 -28
  63. package/src/entities/EngineError/EngineError.types.ts +0 -15
  64. package/src/entities/EngineError/index.ts +0 -2
  65. package/src/entities/KeySet/KeySet.test.ts +0 -126
  66. package/src/entities/KeySet/KeySet.ts +0 -172
  67. package/src/entities/KeySet/KeySet.types.ts +0 -28
  68. package/src/entities/KeySet/index.ts +0 -2
  69. package/src/entities/LifecycleController/LifecycleController.test.ts +0 -48
  70. package/src/entities/LifecycleController/LifecycleController.ts +0 -24
  71. package/src/entities/LifecycleController/LifecycleController.types.ts +0 -5
  72. package/src/entities/LifecycleController/index.ts +0 -2
  73. package/src/entities/Localizator/Localizator.ts +0 -139
  74. package/src/entities/Localizator/Localizator.types.ts +0 -52
  75. package/src/entities/Localizator/guessNamingConvention/guessNamingConvention.test.ts +0 -165
  76. package/src/entities/Localizator/guessNamingConvention/guessNamingConvention.ts +0 -58
  77. package/src/entities/Localizator/guessNamingConvention/index.ts +0 -1
  78. package/src/entities/Localizator/index.ts +0 -2
  79. package/src/entities/MessageHandler/MessageHandler.test.ts +0 -130
  80. package/src/entities/MessageHandler/MessageHandler.ts +0 -72
  81. package/src/entities/MessageHandler/MessageHandler.types.ts +0 -15
  82. package/src/entities/MessageHandler/index.ts +0 -2
  83. package/src/entities/PubSub/PubSub.test.ts +0 -297
  84. package/src/entities/PubSub/PubSub.ts +0 -202
  85. package/src/entities/PubSub/PubSub.types.ts +0 -76
  86. package/src/entities/PubSub/handleMessage/handleMessage.test.ts +0 -102
  87. package/src/entities/PubSub/handleMessage/handleMessage.ts +0 -65
  88. package/src/entities/PubSub/handleMessage/index.ts +0 -1
  89. package/src/entities/PubSub/index.ts +0 -2
  90. package/src/entities/PushNotification/PushNotification.test.ts +0 -35
  91. package/src/entities/PushNotification/PushNotification.ts +0 -44
  92. package/src/entities/PushNotification/PushNotification.types.ts +0 -25
  93. package/src/entities/PushNotification/index.ts +0 -2
  94. package/src/entities/Redis/Redis.ts +0 -71
  95. package/src/entities/Redis/Redis.types.ts +0 -19
  96. package/src/entities/Redis/Redis.validate.ts +0 -17
  97. package/src/entities/Redis/index.ts +0 -2
  98. package/src/entities/Sequelize/Sequelize.config.ts +0 -59
  99. package/src/entities/Sequelize/Sequelize.test.ts +0 -21
  100. package/src/entities/Sequelize/Sequelize.ts +0 -75
  101. package/src/entities/Sequelize/Sequelize.types.ts +0 -10
  102. package/src/entities/Sequelize/Sequelize.validate.ts +0 -15
  103. package/src/entities/Sequelize/index.ts +0 -2
  104. package/src/entities/Server/Server.const.ts +0 -56
  105. package/src/entities/Server/Server.test.ts +0 -272
  106. package/src/entities/Server/Server.ts +0 -471
  107. package/src/entities/Server/Server.types.ts +0 -88
  108. package/src/entities/Server/index.ts +0 -2
  109. package/src/entities/SocketClient/SocketClient.test.ts +0 -392
  110. package/src/entities/SocketClient/SocketClient.ts +0 -401
  111. package/src/entities/SocketClient/SocketClient.types.ts +0 -62
  112. package/src/entities/SocketClient/index.ts +0 -2
  113. package/src/entities/SocketClient/parseMessage/index.ts +0 -1
  114. package/src/entities/SocketClient/parseMessage/parseMessage.test.ts +0 -20
  115. package/src/entities/SocketClient/parseMessage/parseMessage.ts +0 -26
  116. package/src/entities/Storage/Storage.test.ts +0 -58
  117. package/src/entities/Storage/Storage.ts +0 -219
  118. package/src/entities/Storage/Storage.types.ts +0 -57
  119. package/src/entities/Storage/index.ts +0 -2
  120. package/src/entities/ValidationError/ValidationError.ts +0 -34
  121. package/src/entities/ValidationError/index.ts +0 -1
  122. package/src/entities/WebError/WebError.test.ts +0 -18
  123. package/src/entities/WebError/WebError.ts +0 -23
  124. package/src/entities/WebError/WebError.types.ts +0 -9
  125. package/src/entities/WebError/index.ts +0 -2
  126. package/src/entities/index.ts +0 -16
  127. package/src/index.ts +0 -6
  128. package/src/metrics/debug.ts +0 -10
  129. package/src/metrics/index.ts +0 -2
  130. package/src/metrics/request.ts +0 -17
  131. package/src/middleware/authHmac/authHmac.test.ts +0 -86
  132. package/src/middleware/authHmac/authHmac.ts +0 -56
  133. package/src/middleware/authHmac/authHmac.types.ts +0 -7
  134. package/src/middleware/authHmac/index.ts +0 -2
  135. package/src/middleware/authJwt/authJwt.test.ts +0 -54
  136. package/src/middleware/authJwt/authJwt.ts +0 -55
  137. package/src/middleware/authJwt/authJwt.types.ts +0 -14
  138. package/src/middleware/authJwt/index.ts +0 -2
  139. package/src/middleware/authStatic/authStatic.test.ts +0 -36
  140. package/src/middleware/authStatic/authStatic.ts +0 -45
  141. package/src/middleware/authStatic/index.ts +0 -1
  142. package/src/middleware/authTls/authTls.test.ts +0 -138
  143. package/src/middleware/authTls/authTls.ts +0 -119
  144. package/src/middleware/authTls/authTls.types.ts +0 -13
  145. package/src/middleware/authTls/index.ts +0 -2
  146. package/src/middleware/checkPermission/checkPermission.ts +0 -33
  147. package/src/middleware/checkPermission/index.ts +0 -1
  148. package/src/middleware/error/error.test.ts +0 -60
  149. package/src/middleware/error/error.ts +0 -25
  150. package/src/middleware/error/index.ts +0 -1
  151. package/src/middleware/fileUploader/fileUploader.ts +0 -154
  152. package/src/middleware/fileUploader/fileUploader.types.ts +0 -35
  153. package/src/middleware/fileUploader/index.ts +0 -2
  154. package/src/middleware/fileUploader/isMultiPart/index.ts +0 -1
  155. package/src/middleware/fileUploader/isMultiPart/isMultipart.ts +0 -9
  156. package/src/middleware/fileUploader/validate/index.ts +0 -1
  157. package/src/middleware/fileUploader/validate/validate.ts +0 -27
  158. package/src/middleware/fourOhFour/fourOhFour.test.ts +0 -14
  159. package/src/middleware/fourOhFour/fourOhFour.ts +0 -13
  160. package/src/middleware/fourOhFour/index.ts +0 -1
  161. package/src/middleware/geminiFileUploader/geminiFileUploader.ts +0 -68
  162. package/src/middleware/geminiFileUploader/index.ts +0 -1
  163. package/src/middleware/healthCheck/healthCheck.test.ts +0 -12
  164. package/src/middleware/healthCheck/healthCheck.ts +0 -14
  165. package/src/middleware/healthCheck/index.ts +0 -1
  166. package/src/middleware/index.ts +0 -17
  167. package/src/middleware/metrics/index.ts +0 -1
  168. package/src/middleware/metrics/metrics.test.ts +0 -46
  169. package/src/middleware/metrics/metrics.ts +0 -24
  170. package/src/middleware/multiPartFileUploader/index.ts +0 -2
  171. package/src/middleware/multiPartFileUploader/multiPartFileUploader.ts +0 -249
  172. package/src/middleware/multiPartFileUploader/multiPartFileUploader.types.ts +0 -23
  173. package/src/middleware/multiPartFileUploader/validate/index.ts +0 -1
  174. package/src/middleware/multiPartFileUploader/validate/validate.ts +0 -27
  175. package/src/middleware/requestMetrics/index.ts +0 -1
  176. package/src/middleware/requestMetrics/requestMetrics.test.ts +0 -77
  177. package/src/middleware/requestMetrics/requestMetrics.ts +0 -20
  178. package/src/middleware/swaggerDocs/index.ts +0 -2
  179. package/src/middleware/swaggerDocs/swaggerDocs.ts +0 -114
  180. package/src/middleware/swaggerDocs/swaggerDocs.types.ts +0 -41
  181. package/src/middleware/userResolver/index.ts +0 -1
  182. package/src/middleware/userResolver/userResolver.ts +0 -53
  183. package/src/middleware/validate/index.ts +0 -1
  184. package/src/middleware/validate/validate.test.ts +0 -43
  185. package/src/middleware/validate/validate.ts +0 -25
  186. package/src/middleware/version/index.ts +0 -1
  187. package/src/middleware/version/version.test.ts +0 -23
  188. package/src/middleware/version/version.ts +0 -12
  189. package/src/utils/checkEnvironment/index.ts +0 -49
  190. package/src/utils/createHttpServer/createHttpServer.test.ts +0 -24
  191. package/src/utils/createHttpServer/createHttpServer.ts +0 -34
  192. package/src/utils/createHttpServer/createHttpServer.validate.ts +0 -17
  193. package/src/utils/createHttpServer/index.ts +0 -1
  194. package/src/utils/createSortedObject/createSortedObject.ts +0 -20
  195. package/src/utils/createSortedObject/createSortedObjet.test.ts +0 -47
  196. package/src/utils/createSortedObject/index.ts +0 -1
  197. package/src/utils/dbMigration/dbMigration.test.ts +0 -209
  198. package/src/utils/dbMigration/dbMigration.ts +0 -199
  199. package/src/utils/dbMigration/dbMigration.types.ts +0 -11
  200. package/src/utils/dbMigration/index.ts +0 -2
  201. package/src/utils/dbMigration/migrateMetadataTable/index.ts +0 -1
  202. package/src/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.test.ts +0 -59
  203. package/src/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.ts +0 -102
  204. package/src/utils/envAssert/envAssert.ts +0 -31
  205. package/src/utils/envAssert/index.ts +0 -1
  206. package/src/utils/envAssert/validators/hostList.ts +0 -17
  207. package/src/utils/envAssert/validators/index.ts +0 -5
  208. package/src/utils/envAssert/validators/ipList.ts +0 -13
  209. package/src/utils/envAssert/validators/path.ts +0 -13
  210. package/src/utils/envAssert/validators/string.ts +0 -9
  211. package/src/utils/envAssert/validators/stringList.ts +0 -13
  212. package/src/utils/filter/filter.ts +0 -17
  213. package/src/utils/filter/index.ts +0 -1
  214. package/src/utils/geminiFileUpload/geminiFileUpload.ts +0 -93
  215. package/src/utils/geminiFileUpload/index.ts +0 -1
  216. package/src/utils/hmac/checkEnv/checkEnv.test.ts +0 -18
  217. package/src/utils/hmac/checkEnv/checkEnv.ts +0 -9
  218. package/src/utils/hmac/checkEnv/index.ts +0 -1
  219. package/src/utils/hmac/createHmac/createHmac.ts +0 -33
  220. package/src/utils/hmac/createHmac/index.ts +0 -1
  221. package/src/utils/hmac/index.ts +0 -4
  222. package/src/utils/hmac/index.types.ts +0 -13
  223. package/src/utils/hmac/signPayload/index.ts +0 -1
  224. package/src/utils/hmac/signPayload/signPayload.ts +0 -16
  225. package/src/utils/hmac/verifySignature/index.ts +0 -1
  226. package/src/utils/hmac/verifySignature/verifySignature.ts +0 -24
  227. package/src/utils/index.ts +0 -29
  228. package/src/utils/jwt/index.ts +0 -2
  229. package/src/utils/jwt/jwt.test.ts +0 -28
  230. package/src/utils/jwt/jwt.ts +0 -182
  231. package/src/utils/jwt/jwt.types.ts +0 -21
  232. package/src/utils/report/index.ts +0 -3
  233. package/src/utils/report/output.ts +0 -45
  234. package/src/utils/report/output.types.ts +0 -70
  235. package/src/utils/report/report.test.ts +0 -133
  236. package/src/utils/report/report.ts +0 -133
  237. package/src/utils/report/report.types.ts +0 -13
  238. package/src/utils/request/index.ts +0 -1
  239. package/src/utils/request/request.test.ts +0 -26
  240. package/src/utils/request/request.ts +0 -48
  241. package/src/utils/secretManager/index.ts +0 -2
  242. package/src/utils/secretManager/secretLoader.ts +0 -62
  243. package/src/utils/secretManager/secretResolver.ts +0 -35
  244. package/src/utils/semverCompare/index.ts +0 -1
  245. package/src/utils/semverCompare/semverCompare.test.ts +0 -49
  246. package/src/utils/semverCompare/semverCompare.ts +0 -60
  247. package/src/utils/sendEmail/index.ts +0 -2
  248. package/src/utils/sendEmail/sendEmail.ts +0 -61
  249. package/src/utils/sendEmail/sendEmail.types.ts +0 -61
  250. package/src/utils/sendPush/index.ts +0 -2
  251. package/src/utils/sendPush/sendPush.ts +0 -20
  252. package/src/utils/sendPush/sendPush.types.ts +0 -25
  253. package/src/utils/tlsConfig/index.ts +0 -2
  254. package/src/utils/tlsConfig/tlsConfig.test.ts +0 -32
  255. package/src/utils/tlsConfig/tlsConfig.ts +0 -47
  256. package/src/utils/tlsConfig/tlsConfig.types.ts +0 -11
  257. package/src/utils/tlsConfig/tlsConfig.validate.ts +0 -25
  258. package/src/utils/tlsRequest/index.ts +0 -1
  259. package/src/utils/tlsRequest/tlsRequest.test.ts +0 -63
  260. package/src/utils/tlsRequest/tlsRequest.ts +0 -12
  261. package/src/utils/trimPathSlash/index.ts +0 -1
  262. package/src/utils/trimPathSlash/trimPathSlash.test.ts +0 -26
  263. package/src/utils/trimPathSlash/trimPathSlash.ts +0 -8
  264. package/test/env.ts +0 -53
  265. package/test/factory/index.ts +0 -8
  266. package/test/factory/sequelizeMeta.ts +0 -12
  267. package/test/hooks.ts +0 -35
  268. package/test/index.ts +0 -3
  269. package/test/stub/index.ts +0 -3
  270. package/test/stub/stubLocales.ts +0 -68
  271. package/test/stub/stubPubSub.ts +0 -7
  272. package/test/stub/stubStorage.ts +0 -77
  273. package/test/stub/stubStorage.types.ts +0 -11
  274. package/test/utils/app.ts +0 -31
  275. package/test/utils/index.ts +0 -1
  276. package/tsconfig.build.json +0 -5
  277. package/tsconfig.json +0 -32
@@ -1,55 +0,0 @@
1
- import { Request, Response, NextFunction } from 'express';
2
- import { TokenIssuer } from 'const';
3
- import { EngineError } from 'entities/EngineError';
4
- import { WebError } from 'entities/WebError';
5
- import { jwtVerify } from 'utils/jwt';
6
- import { reportDebug } from 'utils/report';
7
- import {} from './authJwt.types';
8
-
9
- const namespace = 'engine:middleware:authJwt';
10
-
11
- /** Generate a middleware to authenticate the client connection with a JWT */
12
- export function authJwt(): (
13
- request: Request,
14
- response: Response,
15
- next: NextFunction
16
- ) => Promise<void> {
17
- if (!process.env.ACCESS_TOKEN_AUDIENCE)
18
- throw new EngineError({
19
- message: 'Env variable ACCESS_TOKEN_AUDIENCE is not defined'
20
- });
21
-
22
- return async (
23
- request: Request,
24
- response: Response,
25
- next: NextFunction
26
- ): Promise<void> => {
27
- const [scheme, credentials] =
28
- request.headers?.authorization?.split(' ') ?? [];
29
- // No bearer token has been sent
30
- if (!credentials || scheme.toLowerCase() !== 'bearer') {
31
- throw new WebError({
32
- message: 'No bearer token found',
33
- errorCode: 'unauthorized',
34
- statusCode: 401,
35
- data: { authorization: request.headers?.authorization }
36
- });
37
- }
38
- reportDebug({
39
- namespace,
40
- message: 'Performing JWT authentication',
41
- data: { scheme, credentials }
42
- });
43
- // Verify token and extract its payload
44
- const payload = await jwtVerify(credentials, TokenIssuer.AUTH_SERVICE);
45
- reportDebug({
46
- namespace,
47
- message: 'Extracted user data from JWT',
48
- data: { payload, credentials }
49
- });
50
- // The user object on the request is hydrated with data from the token
51
- request.user = payload.user;
52
-
53
- next();
54
- };
55
- }
@@ -1,14 +0,0 @@
1
- export {};
2
-
3
- // Override the Express request object to add the files
4
- declare global {
5
- // eslint-disable-next-line @typescript-eslint/no-namespace
6
- namespace Express {
7
- /** Express request object */
8
- interface Request {
9
- /** User that identified using a JWT */
10
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
- user?: Record<string, any>;
12
- }
13
- }
14
- }
@@ -1,2 +0,0 @@
1
- export * from './authJwt';
2
- export * from './authJwt.types';
@@ -1,36 +0,0 @@
1
- import { expect } from 'chai';
2
- import { Request, Response } from 'express';
3
- import { faker } from '@faker-js/faker';
4
- import { fake } from 'sinon';
5
- import { authStatic } from './authStatic';
6
-
7
- describe('Middleware - Auth Static', () => {
8
- beforeEach(() => {
9
- process.env.STATIC_TOKEN = faker.lorem.slug();
10
- });
11
-
12
- it('should authenticate with static token', () => {
13
- const bearer = `Bearer ${process.env.STATIC_TOKEN as string}`;
14
- const request = { headers: { authorization: bearer } };
15
- const next = fake();
16
- authStatic()(request as Request, undefined as unknown as Response, next);
17
- expect(next).to.have.been.calledOnceWithExactly();
18
- });
19
-
20
- it('should throw an error if the token is invalid', () => {
21
- const bearer = 'Bearer ' + faker.lorem.word();
22
- const request = { headers: { authorization: bearer } };
23
- const next = fake();
24
- expect(() => {
25
- authStatic()(request as Request, undefined as unknown as Response, next);
26
- }).to.throw();
27
- });
28
-
29
- it('should throw an error if there is no token', () => {
30
- const request = { headers: {} };
31
- const next = fake();
32
- expect(() => {
33
- authStatic()(request as Request, undefined as unknown as Response, next);
34
- }).to.throw();
35
- });
36
- });
@@ -1,45 +0,0 @@
1
- import { Request, Response, NextFunction } from 'express';
2
- import { WebError } from 'entities/WebError';
3
- import { assertEnvironment, envAssert, reportDebug } from 'utils';
4
-
5
- const namespace = 'engine:middleware:authStatic';
6
-
7
- /**
8
- * Generate a middleware to authenticate the client connection with a static token
9
- * @return {Function}
10
- */
11
- export function authStatic(): (
12
- req: Request,
13
- res: Response,
14
- next: NextFunction
15
- ) => void {
16
- assertEnvironment({ STATIC_TOKEN: envAssert.isString() });
17
-
18
- return (req: Request, res: Response, next: NextFunction): void => {
19
- const [scheme, credentials] = req.headers?.authorization?.split(' ') ?? [];
20
- // No bearer token has been sent
21
- if (!credentials || scheme.toLowerCase() !== 'bearer') {
22
- throw new WebError({
23
- statusCode: 401,
24
- errorCode: 'unauthorized',
25
- message: 'No bearer token found',
26
- data: { authorization: req.headers?.authorization }
27
- });
28
- }
29
- reportDebug({
30
- namespace,
31
- message: 'Performing Static authentication',
32
- data: { scheme, credentials }
33
- });
34
- // Verify token
35
- if (credentials !== process.env.STATIC_TOKEN) {
36
- throw new WebError({
37
- statusCode: 401,
38
- errorCode: 'unauthorized',
39
- message: 'Invalid token supplied',
40
- data: { credentials }
41
- });
42
- }
43
- next();
44
- };
45
- }
@@ -1 +0,0 @@
1
- export * from './authStatic';
@@ -1,138 +0,0 @@
1
- import { expect } from 'chai';
2
- import { NextFunction, Request, Response } from 'express';
3
- import { faker } from '@faker-js/faker';
4
- import { fake } from 'sinon';
5
- import { authTlsMiddleware, loadEnv } from './authTls';
6
-
7
- describe('Middleware - Auth TLS', () => {
8
- const response = {} as unknown as Response;
9
- afterEach(() => {
10
- delete process.env.ALLOWED_CLIENT_HOSTS;
11
- loadEnv();
12
- });
13
-
14
- it('should reject unauthenticated requests', () => {
15
- const request = { client: { authorized: false } } as unknown as Request;
16
- const next = fake();
17
- expect(() => {
18
- authTlsMiddleware(request, response, next);
19
- }).to.throw();
20
- expect(next).to.not.have.been.called;
21
- });
22
-
23
- it('should accept properly authenticated requests', () => {
24
- const request = {
25
- socket: {
26
- getPeerCertificate: () => ({
27
- subject: { CN: faker.internet.domainName() }
28
- }),
29
- authorized: true
30
- }
31
- } as unknown as Request;
32
- const next = fake();
33
- authTlsMiddleware(request, response, next);
34
- expect(next).to.have.been.calledOnceWithExactly();
35
- });
36
-
37
- it('should reject when not on whitelist', () => {
38
- process.env.ALLOWED_CLIENT_HOSTS = faker.internet.domainName();
39
- loadEnv();
40
- const request = {
41
- socket: {
42
- getPeerCertificate: () => ({
43
- subject: { CN: faker.internet.domainName() }
44
- }),
45
- authorized: true
46
- }
47
- } as unknown as Request;
48
- const next = fake();
49
- expect(() => {
50
- authTlsMiddleware(request, response, next);
51
- }).to.throw();
52
- expect(next).to.not.have.been.called;
53
- });
54
-
55
- it('should accept when subject is in whitelist', () => {
56
- const domain = faker.internet.domainName();
57
- process.env.ALLOWED_CLIENT_HOSTS = domain;
58
- loadEnv();
59
- const request = {
60
- socket: {
61
- getPeerCertificate: () => ({ subject: { CN: domain } }),
62
- authorized: true
63
- }
64
- } as unknown as Request;
65
- const next = fake();
66
- authTlsMiddleware(request, response, next);
67
- expect(next).to.have.been.calledOnceWithExactly();
68
- });
69
-
70
- it('should accept when subject is in whitelist specific to this domain', () => {
71
- const domain = faker.internet.domainName();
72
- loadEnv();
73
- const request = {
74
- socket: {
75
- getPeerCertificate: () => ({ subject: { CN: domain } }),
76
- authorized: true
77
- }
78
- } as unknown as Request;
79
- const next = fake();
80
- authTlsMiddleware(request, response, next, { whitelist: [domain] });
81
- expect(next).to.have.been.calledOnceWithExactly();
82
- });
83
-
84
- it('should accept when subject is in altnames as domain', () => {
85
- const domain = faker.internet.domainName();
86
- process.env.ALLOWED_CLIENT_HOSTS = domain;
87
- loadEnv();
88
- const request = {
89
- socket: {
90
- getPeerCertificate: () => ({
91
- subject: { CN: faker.internet.domainName() },
92
- subjectaltname: `DNS:${domain}, IP Address:${faker.internet.ip()}`
93
- }),
94
- authorized: true
95
- }
96
- } as unknown as Request;
97
- const next = fake();
98
- authTlsMiddleware(request, response, next);
99
- expect(next).to.have.been.calledOnceWithExactly();
100
- });
101
-
102
- // it('should accept when subject is in altnames as ip', () => {
103
- // const ip = faker.internet.ip();
104
- // process.env.ALLOWED_CLIENT_HOSTS = ip;
105
- // loadEnv();
106
- // const request = {
107
- // socket: {
108
- // getPeerCertificate: () => ({
109
- // subject: { CN: faker.internet.domainName() },
110
- // subjectaltname: `DNS:${faker.internet.domainName()}, IP Address:${ip}`
111
- // }),
112
- // authorized: true
113
- // }
114
- // } as unknown as Request;
115
- // const next = fake();
116
- // authTlsMiddleware(request, response, next);
117
- // expect(next).to.have.been.calledOnceWithExactly();
118
- // });
119
-
120
- // it('should pass down subjects', () => {
121
- // const host = faker.internet.domainName();
122
- // const altHost = faker.internet.domainName();
123
- // const ip = faker.internet.ip();
124
- // process.env.ALLOWED_CLIENT_HOSTS = ip;
125
- // loadEnv();
126
- // const request = {
127
- // socket: {
128
- // getPeerCertificate: () => ({
129
- // subject: { CN: host },
130
- // subjectaltname: `DNS:${altHost}, IP Address:${ip}`
131
- // }),
132
- // authorized: true
133
- // }
134
- // } as unknown as Request;
135
- // authTlsMiddleware(request, response, fake() as unknown as NextFunction);
136
- // expect(request.hosts).to.have.members([host, altHost, ip]);
137
- // });
138
- });
@@ -1,119 +0,0 @@
1
- import { TLSSocket } from 'tls';
2
- import { Request, Response, NextFunction } from 'express';
3
- import { EndpointAuthParams, EndpointAuthType } from 'entities/Endpoint';
4
- import { WebError } from 'entities/WebError';
5
- import { assertEnvironment } from 'utils/checkEnvironment';
6
- import { envAssert } from 'utils/envAssert';
7
- import { reportDebug } from 'utils/report';
8
- import {} from './authTls.types';
9
-
10
- const namespace = 'engine:middleware:authTls';
11
-
12
- /**
13
- * Returns a middleware for TLS authentication
14
- * Both client and server must have a certificate signed by the same CA
15
- * Host name of the client is added to the express request object under 'request.user.host'
16
- * A limited number of hosts can be specified with the environment variable ALLOWED_CLIENT_HOSTS
17
- * @param {Object} options
18
- * @param {Array<String>} options.whitelist - List of certificate Common Name or Alt Name that are permitted to make requests to this endpoint
19
- * @return {Function}
20
- */
21
- export function authTls(
22
- options: EndpointAuthParams<EndpointAuthType.TLS> = {}
23
- ): (request: Request, response: Response, next: NextFunction) => void {
24
- assertEnvironment({
25
- TLS_SERVER_KEY: envAssert.isPath(),
26
- TLS_SERVER_CERT: envAssert.isPath()
27
- });
28
-
29
- return (request: Request, response: Response, next: NextFunction): void => {
30
- authTlsMiddleware(request, response, next, options);
31
- };
32
- }
33
-
34
- let allowedClientHosts: Array<string> = [];
35
-
36
- /** Load TLS auth related environment variables */
37
- export function loadEnv(): void {
38
- if (process.env.ALLOWED_CLIENT_HOSTS) {
39
- assertEnvironment({ ALLOWED_CLIENT_HOSTS: envAssert.isHostList() });
40
- allowedClientHosts = process.env.ALLOWED_CLIENT_HOSTS.split(',').map(
41
- (value) => value.trim()
42
- );
43
- } else {
44
- allowedClientHosts = [];
45
- }
46
- }
47
-
48
- loadEnv();
49
-
50
- /** Middleware that handles mTLS based authentication */
51
- export function authTlsMiddleware(
52
- request: Request,
53
- response: Response,
54
- next: NextFunction,
55
- options: EndpointAuthParams<EndpointAuthType.TLS> = {}
56
- ): void {
57
- const socket = request.socket as TLSSocket;
58
-
59
- reportDebug({
60
- namespace,
61
- message: 'TLS socket auth state',
62
- data: {
63
- authorized: socket?.authorized,
64
- authorizationError: (
65
- socket as TLSSocket & { authorizationError?: string }
66
- )?.authorizationError,
67
- peerCert: socket?.getPeerCertificate?.()
68
- }
69
- });
70
-
71
- // Check if the client's tls certificate is valid
72
- if (!socket?.authorized) {
73
- throw new WebError({
74
- errorCode: 'unauthorized',
75
- statusCode: 401,
76
- message: 'TLS certificate could not be validated'
77
- });
78
- }
79
-
80
- // Extract the subjects for the client certificate
81
- const clientCertificate = socket.getPeerCertificate();
82
- const subjects = [];
83
- if (clientCertificate.subject.CN) subjects.push(clientCertificate.subject.CN);
84
- if (clientCertificate.subjectaltname?.length) {
85
- const altNames = clientCertificate.subjectaltname
86
- .split(',')
87
- .map((subject) => subject.trim())
88
- .map((value) => value.split(':')[1]);
89
- subjects.push(...altNames);
90
- }
91
-
92
- const whitelist = options.whitelist ?? allowedClientHosts;
93
- reportDebug({
94
- namespace,
95
- message: 'Performing TLS authentication',
96
- data: { certificate: clientCertificate, whitelist, subjects }
97
- });
98
- // Check that the subject is authorized
99
- if (whitelist?.length) {
100
- let allowed = false;
101
- for (const subject of subjects) {
102
- if (whitelist.includes(subject)) {
103
- allowed = true;
104
- break;
105
- }
106
- }
107
- // Throw error if there is no subject in the whitelist
108
- if (!allowed)
109
- throw new WebError({
110
- errorCode: 'unauthorized',
111
- statusCode: 401,
112
- message: 'Client host is not in the whitelist',
113
- data: { subjects }
114
- });
115
- }
116
- // Pas subjects down
117
- request.hosts = subjects;
118
- next();
119
- }
@@ -1,13 +0,0 @@
1
- // Override the Express request object to add the files
2
- declare global {
3
- // eslint-disable-next-line @typescript-eslint/no-namespace
4
- namespace Express {
5
- /** Express HTTP request */
6
- interface Request {
7
- /** Host names provided by the mTLS authenticated client */
8
- hosts?: Array<string>;
9
- }
10
- }
11
- }
12
-
13
- export {};
@@ -1,2 +0,0 @@
1
- export * from './authTls';
2
- export {} from './authTls.types';
@@ -1,33 +0,0 @@
1
- import { Request, Response, NextFunction } from 'express';
2
-
3
- /** Middleware to check if the user has at least one of the required permissions (case-insensitive). */
4
- function checkPermission(requiredActions: string | string[]) {
5
- return function (req: Request, res: Response, next: NextFunction) {
6
- const user = req.user;
7
-
8
- if (!user || !user.permissions) {
9
- return res.status(403).json({ message: 'User does not have permissions' });
10
- }
11
-
12
- // Normalize input to an array of strings
13
- const requiredActionsArray = Array.isArray(requiredActions)
14
- ? requiredActions
15
- : [requiredActions];
16
-
17
- // Normalize required actions to lowercase
18
- const requiredActionsLower = requiredActionsArray.map(action => action.toLowerCase());
19
-
20
- // Check if the user has any of the required permissions (case-insensitive)
21
- const hasPermission = user.permissions.some((permission: string) =>
22
- requiredActionsLower.includes(permission.toLowerCase())
23
- );
24
-
25
- if (!hasPermission) {
26
- return res.status(403).json({ message: 'Permission denied' });
27
- }
28
-
29
- next();
30
- };
31
- }
32
-
33
- export { checkPermission };
@@ -1 +0,0 @@
1
- export * from './checkPermission';
@@ -1,60 +0,0 @@
1
- import express, { Application } from 'express';
2
- import { faker } from '@faker-js/faker';
3
- import request from 'supertest';
4
- import { error } from './error';
5
- import { WebError } from 'entities/WebError';
6
-
7
- const PATH = '/test';
8
- let app: Application;
9
-
10
- describe('Middleware - error', () => {
11
- beforeEach(() => {
12
- app = express();
13
- });
14
-
15
- it('should handle WebError', async () => {
16
- const errorCode = faker.lorem.word();
17
- const message = faker.lorem.sentence();
18
- const hint = faker.lorem.sentence();
19
- const statusCode = 505;
20
- app.get(PATH, () => {
21
- throw new WebError({ statusCode, errorCode, message, hint });
22
- });
23
- app.use(error);
24
- await request(app).get(PATH).expect(statusCode, { errorCode, hint });
25
- });
26
-
27
- it('should not return hint if none is specified', async () => {
28
- const errorCode = faker.lorem.word();
29
- const message = faker.lorem.sentence();
30
- const statusCode = 505;
31
- app.get(PATH, () => {
32
- throw new WebError({ statusCode, errorCode, message });
33
- });
34
- app.use(error);
35
- await request(app).get(PATH).expect(statusCode, { errorCode });
36
- });
37
-
38
- it('should return server error 500 for unknown error', async () => {
39
- app.get(PATH, () => {
40
- throw new Error();
41
- });
42
- app.use(error);
43
- await request(app).get(PATH).expect(500, { errorCode: 'server-error' });
44
- });
45
-
46
- it('should not trigger if no errors', async () => {
47
- app.get(PATH, (req: any, res: any) => res.sendStatus(200));
48
- app.use(error);
49
- await request(app).get(PATH).expect(200);
50
- });
51
-
52
- it('should pass to next if no error to handle', async () => {
53
- app.get(PATH, (req, res, next) => {
54
- next();
55
- });
56
- app.use(error);
57
- app.get(PATH, (req: any, res: any) => res.sendStatus(200));
58
- await request(app).get(PATH).expect(200);
59
- });
60
- });
@@ -1,25 +0,0 @@
1
- import { Request, Response, NextFunction } from 'express';
2
- import { WebError } from 'entities/WebError';
3
- import { reportError, reportDebug } from 'utils/report';
4
-
5
- const namespace = 'engine:middleware:error';
6
-
7
- /** Handle errors globally */
8
- export function error(
9
- error: Error,
10
- request: Request,
11
- response: Response,
12
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
13
- next: NextFunction
14
- ): void {
15
- reportDebug({ namespace, message: 'Received error', data: { error } });
16
- reportError(error, request);
17
- if (error instanceof WebError) {
18
- response.status(error.statusCode).json({
19
- errorCode: error.errorCode,
20
- hint: error.hint
21
- });
22
- return;
23
- }
24
- response.status(500).json({ errorCode: 'server-error' });
25
- }
@@ -1 +0,0 @@
1
- export * from './error';