node-server-engine 1.4.8 → 1.5.0

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 (261) 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/SocketClient/SocketClient.js +1 -0
  11. package/dist/entities/SocketClient/SocketClient.js.map +1 -1
  12. package/dist/index.js +1 -2
  13. package/dist/index.js.map +1 -1
  14. package/dist/middleware/checkPermission/checkPermission.d.ts +1 -1
  15. package/dist/middleware/checkPermission/checkPermission.js +4 -2
  16. package/dist/middleware/checkPermission/checkPermission.js.map +1 -1
  17. package/dist/utils/createHttpServer/createHttpServer.js +1 -1
  18. package/dist/utils/createHttpServer/createHttpServer.js.map +1 -1
  19. package/dist/utils/jwt/jwt.js +1 -1
  20. package/dist/utils/jwt/jwt.js.map +1 -1
  21. package/dist/utils/semverCompare/semverCompare.js +1 -5
  22. package/dist/utils/semverCompare/semverCompare.js.map +1 -1
  23. package/package.json +30 -19
  24. package/.env.example +0 -186
  25. package/.github/workflows/publish.yml +0 -41
  26. package/.prettierrc +0 -7
  27. package/Dockerfile +0 -31
  28. package/babel.config.json +0 -34
  29. package/eslint.config.mjs +0 -11
  30. package/src/const/DebeziumEvent.ts +0 -6
  31. package/src/const/LogSeverity.ts +0 -7
  32. package/src/const/index.ts +0 -5
  33. package/src/const/metrics.ts +0 -6
  34. package/src/const/mime.ts +0 -37
  35. package/src/const/tokenIssuer.ts +0 -7
  36. package/src/db/migrations/20241030121500-create-sequelize-meta-table.ts +0 -29
  37. package/src/db/models/SequelizeMeta.ts +0 -16
  38. package/src/db/models/index.ts +0 -2
  39. package/src/entities/ElasticSearch/ElasticSearch.ts +0 -103
  40. package/src/entities/ElasticSearch/ElasticSearch.types.ts +0 -7
  41. package/src/entities/ElasticSearch/index.ts +0 -2
  42. package/src/entities/Endpoint/Endpoint.test.ts +0 -248
  43. package/src/entities/Endpoint/Endpoint.ts +0 -221
  44. package/src/entities/Endpoint/Endpoint.types.ts +0 -181
  45. package/src/entities/Endpoint/index.ts +0 -2
  46. package/src/entities/EngineError/EngineError.ts +0 -28
  47. package/src/entities/EngineError/EngineError.types.ts +0 -15
  48. package/src/entities/EngineError/index.ts +0 -2
  49. package/src/entities/KeySet/KeySet.test.ts +0 -126
  50. package/src/entities/KeySet/KeySet.ts +0 -172
  51. package/src/entities/KeySet/KeySet.types.ts +0 -28
  52. package/src/entities/KeySet/index.ts +0 -2
  53. package/src/entities/LifecycleController/LifecycleController.test.ts +0 -48
  54. package/src/entities/LifecycleController/LifecycleController.ts +0 -24
  55. package/src/entities/LifecycleController/LifecycleController.types.ts +0 -5
  56. package/src/entities/LifecycleController/index.ts +0 -2
  57. package/src/entities/Localizator/Localizator.ts +0 -139
  58. package/src/entities/Localizator/Localizator.types.ts +0 -52
  59. package/src/entities/Localizator/guessNamingConvention/guessNamingConvention.test.ts +0 -165
  60. package/src/entities/Localizator/guessNamingConvention/guessNamingConvention.ts +0 -58
  61. package/src/entities/Localizator/guessNamingConvention/index.ts +0 -1
  62. package/src/entities/Localizator/index.ts +0 -2
  63. package/src/entities/MessageHandler/MessageHandler.test.ts +0 -130
  64. package/src/entities/MessageHandler/MessageHandler.ts +0 -72
  65. package/src/entities/MessageHandler/MessageHandler.types.ts +0 -15
  66. package/src/entities/MessageHandler/index.ts +0 -2
  67. package/src/entities/PubSub/PubSub.test.ts +0 -297
  68. package/src/entities/PubSub/PubSub.ts +0 -202
  69. package/src/entities/PubSub/PubSub.types.ts +0 -76
  70. package/src/entities/PubSub/handleMessage/handleMessage.test.ts +0 -102
  71. package/src/entities/PubSub/handleMessage/handleMessage.ts +0 -65
  72. package/src/entities/PubSub/handleMessage/index.ts +0 -1
  73. package/src/entities/PubSub/index.ts +0 -2
  74. package/src/entities/PushNotification/PushNotification.test.ts +0 -35
  75. package/src/entities/PushNotification/PushNotification.ts +0 -44
  76. package/src/entities/PushNotification/PushNotification.types.ts +0 -25
  77. package/src/entities/PushNotification/index.ts +0 -2
  78. package/src/entities/Redis/Redis.ts +0 -71
  79. package/src/entities/Redis/Redis.types.ts +0 -19
  80. package/src/entities/Redis/Redis.validate.ts +0 -17
  81. package/src/entities/Redis/index.ts +0 -2
  82. package/src/entities/Sequelize/Sequelize.config.ts +0 -59
  83. package/src/entities/Sequelize/Sequelize.test.ts +0 -21
  84. package/src/entities/Sequelize/Sequelize.ts +0 -75
  85. package/src/entities/Sequelize/Sequelize.types.ts +0 -10
  86. package/src/entities/Sequelize/Sequelize.validate.ts +0 -15
  87. package/src/entities/Sequelize/index.ts +0 -2
  88. package/src/entities/Server/Server.const.ts +0 -56
  89. package/src/entities/Server/Server.test.ts +0 -272
  90. package/src/entities/Server/Server.ts +0 -471
  91. package/src/entities/Server/Server.types.ts +0 -88
  92. package/src/entities/Server/index.ts +0 -2
  93. package/src/entities/SocketClient/SocketClient.test.ts +0 -392
  94. package/src/entities/SocketClient/SocketClient.ts +0 -401
  95. package/src/entities/SocketClient/SocketClient.types.ts +0 -62
  96. package/src/entities/SocketClient/index.ts +0 -2
  97. package/src/entities/SocketClient/parseMessage/index.ts +0 -1
  98. package/src/entities/SocketClient/parseMessage/parseMessage.test.ts +0 -20
  99. package/src/entities/SocketClient/parseMessage/parseMessage.ts +0 -26
  100. package/src/entities/Storage/Storage.test.ts +0 -58
  101. package/src/entities/Storage/Storage.ts +0 -219
  102. package/src/entities/Storage/Storage.types.ts +0 -57
  103. package/src/entities/Storage/index.ts +0 -2
  104. package/src/entities/ValidationError/ValidationError.ts +0 -34
  105. package/src/entities/ValidationError/index.ts +0 -1
  106. package/src/entities/WebError/WebError.test.ts +0 -18
  107. package/src/entities/WebError/WebError.ts +0 -23
  108. package/src/entities/WebError/WebError.types.ts +0 -9
  109. package/src/entities/WebError/index.ts +0 -2
  110. package/src/entities/index.ts +0 -16
  111. package/src/index.ts +0 -6
  112. package/src/metrics/debug.ts +0 -10
  113. package/src/metrics/index.ts +0 -2
  114. package/src/metrics/request.ts +0 -17
  115. package/src/middleware/authHmac/authHmac.test.ts +0 -86
  116. package/src/middleware/authHmac/authHmac.ts +0 -56
  117. package/src/middleware/authHmac/authHmac.types.ts +0 -7
  118. package/src/middleware/authHmac/index.ts +0 -2
  119. package/src/middleware/authJwt/authJwt.test.ts +0 -54
  120. package/src/middleware/authJwt/authJwt.ts +0 -55
  121. package/src/middleware/authJwt/authJwt.types.ts +0 -14
  122. package/src/middleware/authJwt/index.ts +0 -2
  123. package/src/middleware/authStatic/authStatic.test.ts +0 -36
  124. package/src/middleware/authStatic/authStatic.ts +0 -45
  125. package/src/middleware/authStatic/index.ts +0 -1
  126. package/src/middleware/authTls/authTls.test.ts +0 -138
  127. package/src/middleware/authTls/authTls.ts +0 -119
  128. package/src/middleware/authTls/authTls.types.ts +0 -13
  129. package/src/middleware/authTls/index.ts +0 -2
  130. package/src/middleware/checkPermission/checkPermission.ts +0 -33
  131. package/src/middleware/checkPermission/index.ts +0 -1
  132. package/src/middleware/error/error.test.ts +0 -60
  133. package/src/middleware/error/error.ts +0 -25
  134. package/src/middleware/error/index.ts +0 -1
  135. package/src/middleware/fileUploader/fileUploader.ts +0 -154
  136. package/src/middleware/fileUploader/fileUploader.types.ts +0 -35
  137. package/src/middleware/fileUploader/index.ts +0 -2
  138. package/src/middleware/fileUploader/isMultiPart/index.ts +0 -1
  139. package/src/middleware/fileUploader/isMultiPart/isMultipart.ts +0 -9
  140. package/src/middleware/fileUploader/validate/index.ts +0 -1
  141. package/src/middleware/fileUploader/validate/validate.ts +0 -27
  142. package/src/middleware/fourOhFour/fourOhFour.test.ts +0 -14
  143. package/src/middleware/fourOhFour/fourOhFour.ts +0 -13
  144. package/src/middleware/fourOhFour/index.ts +0 -1
  145. package/src/middleware/geminiFileUploader/geminiFileUploader.ts +0 -68
  146. package/src/middleware/geminiFileUploader/index.ts +0 -1
  147. package/src/middleware/healthCheck/healthCheck.test.ts +0 -12
  148. package/src/middleware/healthCheck/healthCheck.ts +0 -14
  149. package/src/middleware/healthCheck/index.ts +0 -1
  150. package/src/middleware/index.ts +0 -17
  151. package/src/middleware/metrics/index.ts +0 -1
  152. package/src/middleware/metrics/metrics.test.ts +0 -46
  153. package/src/middleware/metrics/metrics.ts +0 -24
  154. package/src/middleware/multiPartFileUploader/index.ts +0 -2
  155. package/src/middleware/multiPartFileUploader/multiPartFileUploader.ts +0 -249
  156. package/src/middleware/multiPartFileUploader/multiPartFileUploader.types.ts +0 -23
  157. package/src/middleware/multiPartFileUploader/validate/index.ts +0 -1
  158. package/src/middleware/multiPartFileUploader/validate/validate.ts +0 -27
  159. package/src/middleware/requestMetrics/index.ts +0 -1
  160. package/src/middleware/requestMetrics/requestMetrics.test.ts +0 -77
  161. package/src/middleware/requestMetrics/requestMetrics.ts +0 -20
  162. package/src/middleware/swaggerDocs/index.ts +0 -2
  163. package/src/middleware/swaggerDocs/swaggerDocs.ts +0 -114
  164. package/src/middleware/swaggerDocs/swaggerDocs.types.ts +0 -41
  165. package/src/middleware/userResolver/index.ts +0 -1
  166. package/src/middleware/userResolver/userResolver.ts +0 -53
  167. package/src/middleware/validate/index.ts +0 -1
  168. package/src/middleware/validate/validate.test.ts +0 -43
  169. package/src/middleware/validate/validate.ts +0 -25
  170. package/src/middleware/version/index.ts +0 -1
  171. package/src/middleware/version/version.test.ts +0 -23
  172. package/src/middleware/version/version.ts +0 -12
  173. package/src/utils/checkEnvironment/index.ts +0 -49
  174. package/src/utils/createHttpServer/createHttpServer.test.ts +0 -24
  175. package/src/utils/createHttpServer/createHttpServer.ts +0 -34
  176. package/src/utils/createHttpServer/createHttpServer.validate.ts +0 -17
  177. package/src/utils/createHttpServer/index.ts +0 -1
  178. package/src/utils/createSortedObject/createSortedObject.ts +0 -20
  179. package/src/utils/createSortedObject/createSortedObjet.test.ts +0 -47
  180. package/src/utils/createSortedObject/index.ts +0 -1
  181. package/src/utils/dbMigration/dbMigration.test.ts +0 -209
  182. package/src/utils/dbMigration/dbMigration.ts +0 -199
  183. package/src/utils/dbMigration/dbMigration.types.ts +0 -11
  184. package/src/utils/dbMigration/index.ts +0 -2
  185. package/src/utils/dbMigration/migrateMetadataTable/index.ts +0 -1
  186. package/src/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.test.ts +0 -59
  187. package/src/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.ts +0 -102
  188. package/src/utils/envAssert/envAssert.ts +0 -31
  189. package/src/utils/envAssert/index.ts +0 -1
  190. package/src/utils/envAssert/validators/hostList.ts +0 -17
  191. package/src/utils/envAssert/validators/index.ts +0 -5
  192. package/src/utils/envAssert/validators/ipList.ts +0 -13
  193. package/src/utils/envAssert/validators/path.ts +0 -13
  194. package/src/utils/envAssert/validators/string.ts +0 -9
  195. package/src/utils/envAssert/validators/stringList.ts +0 -13
  196. package/src/utils/filter/filter.ts +0 -17
  197. package/src/utils/filter/index.ts +0 -1
  198. package/src/utils/geminiFileUpload/geminiFileUpload.ts +0 -93
  199. package/src/utils/geminiFileUpload/index.ts +0 -1
  200. package/src/utils/hmac/checkEnv/checkEnv.test.ts +0 -18
  201. package/src/utils/hmac/checkEnv/checkEnv.ts +0 -9
  202. package/src/utils/hmac/checkEnv/index.ts +0 -1
  203. package/src/utils/hmac/createHmac/createHmac.ts +0 -33
  204. package/src/utils/hmac/createHmac/index.ts +0 -1
  205. package/src/utils/hmac/index.ts +0 -4
  206. package/src/utils/hmac/index.types.ts +0 -13
  207. package/src/utils/hmac/signPayload/index.ts +0 -1
  208. package/src/utils/hmac/signPayload/signPayload.ts +0 -16
  209. package/src/utils/hmac/verifySignature/index.ts +0 -1
  210. package/src/utils/hmac/verifySignature/verifySignature.ts +0 -24
  211. package/src/utils/index.ts +0 -29
  212. package/src/utils/jwt/index.ts +0 -2
  213. package/src/utils/jwt/jwt.test.ts +0 -28
  214. package/src/utils/jwt/jwt.ts +0 -182
  215. package/src/utils/jwt/jwt.types.ts +0 -21
  216. package/src/utils/report/index.ts +0 -3
  217. package/src/utils/report/output.ts +0 -45
  218. package/src/utils/report/output.types.ts +0 -70
  219. package/src/utils/report/report.test.ts +0 -133
  220. package/src/utils/report/report.ts +0 -133
  221. package/src/utils/report/report.types.ts +0 -13
  222. package/src/utils/request/index.ts +0 -1
  223. package/src/utils/request/request.test.ts +0 -26
  224. package/src/utils/request/request.ts +0 -48
  225. package/src/utils/secretManager/index.ts +0 -2
  226. package/src/utils/secretManager/secretLoader.ts +0 -62
  227. package/src/utils/secretManager/secretResolver.ts +0 -35
  228. package/src/utils/semverCompare/index.ts +0 -1
  229. package/src/utils/semverCompare/semverCompare.test.ts +0 -49
  230. package/src/utils/semverCompare/semverCompare.ts +0 -60
  231. package/src/utils/sendEmail/index.ts +0 -2
  232. package/src/utils/sendEmail/sendEmail.ts +0 -61
  233. package/src/utils/sendEmail/sendEmail.types.ts +0 -61
  234. package/src/utils/sendPush/index.ts +0 -2
  235. package/src/utils/sendPush/sendPush.ts +0 -20
  236. package/src/utils/sendPush/sendPush.types.ts +0 -25
  237. package/src/utils/tlsConfig/index.ts +0 -2
  238. package/src/utils/tlsConfig/tlsConfig.test.ts +0 -32
  239. package/src/utils/tlsConfig/tlsConfig.ts +0 -47
  240. package/src/utils/tlsConfig/tlsConfig.types.ts +0 -11
  241. package/src/utils/tlsConfig/tlsConfig.validate.ts +0 -25
  242. package/src/utils/tlsRequest/index.ts +0 -1
  243. package/src/utils/tlsRequest/tlsRequest.test.ts +0 -63
  244. package/src/utils/tlsRequest/tlsRequest.ts +0 -12
  245. package/src/utils/trimPathSlash/index.ts +0 -1
  246. package/src/utils/trimPathSlash/trimPathSlash.test.ts +0 -26
  247. package/src/utils/trimPathSlash/trimPathSlash.ts +0 -8
  248. package/test/env.ts +0 -53
  249. package/test/factory/index.ts +0 -8
  250. package/test/factory/sequelizeMeta.ts +0 -12
  251. package/test/hooks.ts +0 -35
  252. package/test/index.ts +0 -3
  253. package/test/stub/index.ts +0 -3
  254. package/test/stub/stubLocales.ts +0 -68
  255. package/test/stub/stubPubSub.ts +0 -7
  256. package/test/stub/stubStorage.ts +0 -77
  257. package/test/stub/stubStorage.types.ts +0 -11
  258. package/test/utils/app.ts +0 -31
  259. package/test/utils/index.ts +0 -1
  260. package/tsconfig.build.json +0 -5
  261. package/tsconfig.json +0 -32
@@ -1,182 +0,0 @@
1
- import {
2
- verify,
3
- JwtHeader,
4
- SigningKeyCallback,
5
- Algorithm,
6
- VerifyOptions,
7
- sign
8
- } from 'jsonwebtoken';
9
- import { UserTokenPayload } from './jwt.types';
10
- import { TokenIssuer } from 'const';
11
- import { EngineError } from 'entities/EngineError';
12
- import { KeySet } from 'entities/KeySet';
13
- import { WebError } from 'entities/WebError';
14
- import { assertEnvironment } from 'utils/checkEnvironment';
15
- import { envAssert } from 'utils/envAssert';
16
- import { reportDebug } from 'utils/report';
17
- import { getSecretOrFile } from 'utils';
18
-
19
- export let keySet: KeySet | undefined;
20
-
21
- const namespace = 'engine:utils:jwt';
22
-
23
- /** Initiate key fetching mechanism */
24
- export async function initKeySets(): Promise<void> {
25
- // Create the KeySet instance
26
- // The auth-service fetches its key from its disk and not from a network request
27
- // This prevents fetch failures the first time the auth-service is started
28
- if (process.env.CHART === 'auth-service') {
29
- if (!process.env.ECDSA_PUBLIC_KEY)
30
- throw new EngineError({
31
- message: 'Environment variable "ECDSA_PUBLIC_KEY" is not defined'
32
- });
33
- keySet = new KeySet(process.env.ECDSA_PUBLIC_KEY, { file: true });
34
- } else {
35
- if (process.env.AUTH_SERVICE_URL)
36
- keySet = new KeySet(
37
- `${process.env.AUTH_SERVICE_URL}/.well-known/jwks.json`,
38
- { internal: true }
39
- );
40
- else
41
- keySet = new KeySet(`./keys/jwks.json`, { internal: true, file: true });
42
-
43
- if (!keySet)
44
- throw new EngineError({
45
- message:
46
- 'Environment variable "AUTH_SERVICE_URL" is not defined or JWKS not found'
47
- });
48
- }
49
- const promise = [keySet.init.bind(keySet)()];
50
-
51
- await Promise.all(promise);
52
- }
53
-
54
- /** Stop fetching keys regularly */
55
- export function shutdownKeySets(): void {
56
- if (keySet) keySet.shutdown.bind(keySet)();
57
- }
58
-
59
- /** Get the JWT public key */
60
- function jwtGetKey(header: JwtHeader, callback: SigningKeyCallback): void {
61
- // In test environment we return the symmetric signature secret
62
- if (process.env.NODE_ENV === 'test') {
63
- callback(null, process.env.JWT_SECRET);
64
- return;
65
- }
66
- // Check that KeySet has been initialized
67
- if (!keySet) {
68
- callback(new EngineError({ message: 'KeySet has not been initialized' }));
69
- return;
70
- }
71
- // Check that the token has a key ID
72
- if (!header.kid) {
73
- callback(
74
- new EngineError({
75
- message:
76
- 'Token has not key ID in header, impossible to match with known key',
77
- data: header
78
- })
79
- );
80
- return;
81
- }
82
-
83
- // In test environment we use a symmetrical secret bases signature
84
- if (process.env.NODE_ENV === 'test') {
85
- callback(null, process.env.JWT_SECRET);
86
- return;
87
- }
88
- reportDebug({
89
- namespace,
90
- message: `Looking for key with ID "${header.kid}"`
91
- });
92
- // Go through each key set to check if the token's key is in one of them
93
- let key;
94
- try {
95
- key = keySet.getKey(header.kid);
96
- } catch (error: Error | null | unknown) {
97
- callback(error instanceof Error ? error : null);
98
- return;
99
- }
100
-
101
- if (key) {
102
- reportDebug({ namespace, message: `Found key with ID "${header.kid}"` });
103
- callback(null, key);
104
- return;
105
- }
106
- callback(
107
- new WebError({
108
- statusCode: 401,
109
- errorCode: 'unauthorized',
110
- message: 'Could not find the tokens key in any key set',
111
- data: { kid: header.kid }
112
- })
113
- );
114
- }
115
-
116
- /** Verify an user Json Web Token */
117
- export async function jwtVerify(
118
- token: string,
119
- issuer: TokenIssuer = TokenIssuer.AUTH_SERVICE
120
- ): Promise<UserTokenPayload> {
121
- let algorithms = ['ES256' as Algorithm];
122
- if (process.env.NODE_ENV === 'test') {
123
- assertEnvironment({ JWT_SECRET: envAssert.isString() });
124
- algorithms = ['HS256' as Algorithm];
125
- }
126
- assertEnvironment({
127
- ACCESS_TOKEN_AUDIENCE: envAssert.isString(),
128
- ACCESS_TOKEN_ISSUER: envAssert.isString(),
129
- ACCESS_TOKEN_EXPIRATION_TIME: envAssert.isString()
130
- });
131
- let options: VerifyOptions | undefined;
132
-
133
- switch (issuer) {
134
- case TokenIssuer.AUTH_SERVICE:
135
- options = {
136
- audience: [process.env.ACCESS_TOKEN_AUDIENCE as string],
137
- issuer: [process.env.ACCESS_TOKEN_ISSUER as string],
138
- algorithms
139
- };
140
- break;
141
- default:
142
- throw new EngineError({
143
- message: `Invalid token issuer specified "${issuer as string}"`
144
- });
145
- }
146
-
147
- return new Promise<UserTokenPayload>((resolve, reject) => {
148
- verify(token, jwtGetKey, options, (error, result) => {
149
- if (error) {
150
- reject(
151
- new WebError({
152
- errorCode: 'unauthorized',
153
- statusCode: 401,
154
- message: 'Invalid token supplied',
155
- data: { token },
156
- error: error instanceof Error ? error : undefined
157
- })
158
- );
159
- return;
160
- }
161
- resolve(result as UserTokenPayload);
162
- });
163
- });
164
- }
165
-
166
- export function generateJwtToken(user: unknown) {
167
- const signOptions = {
168
- algorithm: 'ES256' as const, // or 'ES256' as Algorithm
169
- expiresIn: process.env.ACCESS_TOKEN_EXPIRATION_TIME
170
- ? parseInt(process.env.ACCESS_TOKEN_EXPIRATION_TIME, 10)
171
- : undefined,
172
- issuer: process.env.ACCESS_TOKEN_ISSUER,
173
- audience: process.env.ACCESS_TOKEN_AUDIENCE,
174
- keyid: Object.keys(keySet?.getKeys() ?? {})[0]
175
- };
176
-
177
- const privateKey = getSecretOrFile('PRIVATE_KEY_PATH');
178
-
179
- const token = sign({ user }, privateKey, signOptions);
180
-
181
- return token;
182
- }
@@ -1,21 +0,0 @@
1
-
2
- /** Content of the payload of user authentication tokens */
3
- export interface UserTokenPayload {
4
- /** ID of the user */
5
- sub: string;
6
- /** URL of the service that issued the token */
7
- iss: string;
8
- /** URL of the services that can consume the token */
9
- aud: Array<string> | string;
10
- /** Unique ID of the token */
11
- jti: string;
12
- /** ID of the device the token was issued to */
13
- dev: string;
14
- /** Timestamp at which the token will expire */
15
- exp: number;
16
- /** List of permissions that the user has (only on the admin API) */
17
- per?: Array<string> | string;
18
- /** User */
19
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
- user: Record<string, any> | undefined;
21
- }
@@ -1,3 +0,0 @@
1
- export * from './report';
2
- export * from './output.types';
3
- export * from './report.types';
@@ -1,45 +0,0 @@
1
- import { randomUUID } from 'crypto';
2
- import callsite from 'callsite';
3
- import stringify from 'json-stringify-safe';
4
- import { LogEntry, FullLogEntry } from './output.types';
5
-
6
- // NOTE: Server instance id (helpful for distributed logs)
7
- export const INSTANCE_ID = randomUUID();
8
-
9
- /** Add metadata to the log entry and print it */
10
- export function output(data: LogEntry): FullLogEntry {
11
- // Gather useful information about where the logger was called from
12
- const call = callsite()[2];
13
-
14
- // Append additional metadata to the log entry
15
- const fullEntry: FullLogEntry = {
16
- ...data,
17
- lineNumber: call.getLineNumber(),
18
- fileName: call
19
- .getFileName()
20
- .replace(/.*node_modules\//, '')
21
- .replace(/.*src\//, 'src/'),
22
- serviceContext: {
23
- service: process.env.CHART ?? process.env.HOSTNAME,
24
- version: process.env.BUILD_ID,
25
- environment: process.env.NODE_ENV,
26
- instance: process.env.KUBERNETES_POD_NAME ?? INSTANCE_ID
27
- }
28
- };
29
-
30
- const entry = stringify(fullEntry);
31
- // Ignore when silenced
32
- if (process.env.SILENCE_REPORT) return fullEntry;
33
-
34
- if (process.env.NODE_ENV === 'test') {
35
- // In test mode pretty print
36
- console.dir(fullEntry, { depth: 5 });
37
- } else if (data.statusCode && data.statusCode >= 500) {
38
- // Log to stderr when it is a 500+ error
39
- console.error(entry);
40
- } else {
41
- // Default to regular logging
42
- console.log(entry);
43
- }
44
- return fullEntry;
45
- }
@@ -1,70 +0,0 @@
1
- import { LogSeverity } from 'const';
2
-
3
- /** Structure of the request reporting in log entries */
4
- interface LogEntryRequest {
5
- /** Requested URL */
6
- url: string;
7
- /** HTTP method used */
8
- method: string;
9
- /** Referer website */
10
- referrer?: string;
11
- /** User-Agent of the connected client */
12
- userAgent?: string;
13
- /** IP address of the client */
14
- remoteIp: string | undefined;
15
- /** HTTP status code returned to the client */
16
- responseStatusCode?: number;
17
- }
18
-
19
- /** Structure of the context entry in log entries */
20
- interface LogEntryContext {
21
- /** User that made a request */
22
- user?: string;
23
- /** Info on the processed HTTP request */
24
- httpRequest?: LogEntryRequest;
25
- }
26
-
27
- /** Structure of a log entry */
28
- export interface LogEntry {
29
- /** Severity level at which the entry should be logged */
30
- severity: LogSeverity;
31
- /** Type of error */
32
- errorType?: string;
33
- /** Human readable error message that will be logged */
34
- message: string;
35
- /** Stack-trace of the error */
36
-
37
- stack_trace?: string;
38
- /** Additional data that accompanies the error in the logs */
39
- data?: unknown;
40
- /** Machine readable error code that is returned to the client */
41
- errorCode?: string;
42
- /** HTTP status code that is returned to the client */
43
- statusCode?: number;
44
- /** GCP error type */
45
- '@type'?: string;
46
- /** Error context */
47
- context?: LogEntryContext;
48
- }
49
-
50
- /** Stricture of a log entry context entry */
51
- interface LogEntryServiceContext {
52
- /** Name of the service in which the error ocurred */
53
- service?: string;
54
- /** Version of the service in which the error ocurred */
55
- version?: string;
56
- /** Environment in which the error ocurred (dev/staging/prod) */
57
- environment?: string;
58
- /** ID of the instance that got the error */
59
- instance?: string;
60
- }
61
-
62
- /** Complete log entry with call-stack */
63
- export interface FullLogEntry extends LogEntry {
64
- /** Line at which the error was thrown */
65
- lineNumber: number;
66
- /** Name of the file in which the error was thrown */
67
- fileName: string;
68
- /** Context of the error */
69
- serviceContext: LogEntryServiceContext;
70
- }
@@ -1,133 +0,0 @@
1
- import { expect } from 'chai';
2
- import { faker } from '@faker-js/faker';
3
- import { describe, it, beforeEach } from 'mocha';
4
- import { stub, match } from 'sinon';
5
- import * as output from './output';
6
- import { reportInfo, reportDebug, resetNamespaceSelector } from './report';
7
- import { InfoLogEntry } from './report.types';
8
-
9
- describe('Utils - Report', () => {
10
- it('should collect filename and line number', () => {
11
- let result = reportInfo('example');
12
- expect(result.fileName).to.equal(
13
- `${__dirname}/report.test.ts`.replace(/.*src\//, 'src/')
14
- );
15
- expect(result.severity).to.equal('INFO');
16
- expect(result.message).to.equal('example');
17
-
18
- const data: InfoLogEntry = { message: 'world' };
19
- result = reportInfo(data);
20
- expect(result.message).to.equal('world');
21
- expect(result.fileName).to.equal(
22
- `${__dirname}/report.test.ts`.replace(/.*src\//, 'src/')
23
- );
24
- });
25
-
26
- describe('Report Debug', () => {
27
- let globalNamespace: string;
28
-
29
- beforeEach(() => {
30
- resetNamespaceSelector();
31
-
32
- globalNamespace = faker.lorem.slug();
33
- reportDebug.setNameSpace(globalNamespace);
34
- });
35
-
36
- afterEach(() => {
37
- reportDebug.clearNamespace();
38
- });
39
-
40
- it('should report when the namespace is specified', () => {
41
- const namespace = faker.lorem.word();
42
- process.env.DEBUG = globalNamespace + ':' + namespace;
43
- const outputStub = stub(output, 'output');
44
- const message = faker.lorem.sentence();
45
- reportDebug({ message, namespace });
46
- expect(outputStub).to.have.been.calledOnceWithExactly(
47
- match({
48
- message: `[${namespace}] ${message}`,
49
- severity: 'DEBUG',
50
- namespace: namespace
51
- })
52
- );
53
- });
54
-
55
- it('should report when the namespace is specified with a wildcard', () => {
56
- const namespace = faker.lorem.word();
57
- process.env.DEBUG = globalNamespace + ':' + `${namespace}:*`;
58
- const outputStub = stub(output, 'output');
59
- const message = faker.lorem.sentence();
60
- const prefix = faker.lorem.word();
61
- const actualNamespace = `${namespace}:${prefix}`;
62
- reportDebug({ message, namespace: actualNamespace });
63
- expect(outputStub).to.have.been.calledOnceWithExactly(
64
- match({
65
- message: `[${prefix}] ${message}`,
66
- severity: 'DEBUG',
67
- namespace: actualNamespace
68
- })
69
- );
70
- });
71
-
72
- it('should report when multiple namespaces are specified', () => {
73
- const namespace = faker.lorem.word();
74
- process.env.DEBUG =
75
- globalNamespace +
76
- ':' +
77
- `${namespace},${faker.lorem.word()},${faker.lorem.word()}`;
78
- const outputStub = stub(output, 'output');
79
- const message = faker.lorem.sentence();
80
- reportDebug({ message, namespace });
81
- expect(outputStub).to.have.been.calledOnceWithExactly(
82
- match({
83
- message: `[${namespace}] ${message}`,
84
- severity: 'DEBUG',
85
- namespace: namespace
86
- })
87
- );
88
- });
89
-
90
- it('should not report when another namespace is specified', () => {
91
- process.env.DEBUG = faker.lorem.word();
92
- const outputStub = stub(output, 'output');
93
- reportDebug({
94
- message: faker.lorem.sentence(),
95
- namespace: faker.lorem.word()
96
- });
97
- expect(outputStub).to.not.have.been.called;
98
- });
99
-
100
- it('should ignore the global namespace in server engine report debug', () => {
101
- const namespace = 'engine';
102
- process.env.DEBUG = `${namespace}:*`;
103
- const prefix = faker.lorem.word();
104
- const actualNamespace = `${namespace}:${prefix}`;
105
- const outputStub = stub(output, 'output');
106
- const message = faker.lorem.sentence();
107
- reportDebug({ message, namespace: actualNamespace });
108
- expect(outputStub).to.have.been.calledOnceWithExactly(
109
- match({
110
- message: `[${prefix}] ${message}`,
111
- severity: 'DEBUG',
112
- namespace: actualNamespace
113
- })
114
- );
115
- });
116
-
117
- it('should report with no global namespace', () => {
118
- reportDebug.clearNamespace();
119
- const namespace = faker.lorem.word();
120
- process.env.DEBUG = namespace;
121
- const outputStub = stub(output, 'output');
122
- const message = faker.lorem.sentence();
123
- reportDebug({ message, namespace });
124
- expect(outputStub).to.have.been.calledOnceWithExactly(
125
- match({
126
- message: `[${namespace}] ${message}`,
127
- severity: 'DEBUG',
128
- namespace
129
- })
130
- );
131
- });
132
- });
133
- });
@@ -1,133 +0,0 @@
1
- import { Request } from 'express';
2
- import { output } from './output';
3
- import { LogEntry, FullLogEntry } from './output.types';
4
- import { DebugLogEntry, InfoLogEntry } from './report.types';
5
- import { LogSeverity } from 'const';
6
- import { EngineError } from 'entities/EngineError';
7
- import { WebError } from 'entities/WebError';
8
- import {} from 'middleware/authHmac/authHmac.types';
9
- import {} from 'middleware/authJwt/authJwt.types';
10
- import {} from 'middleware/authTls/authTls.types';
11
-
12
- /** Default generic logger */
13
- export function reportInfo(data: InfoLogEntry | string): FullLogEntry {
14
- return output({
15
- severity: LogSeverity.INFO,
16
- ...(typeof data === 'string' ? { message: data } : data)
17
- });
18
- }
19
-
20
- /** Error specific logger */
21
- export function reportError(
22
- error: unknown | Error | EngineError | WebError,
23
- request?: Request
24
- ): FullLogEntry {
25
- let logEntry: LogEntry =
26
- error instanceof Error
27
- ? {
28
- message: error.message,
29
- stack_trace: error.stack,
30
- severity: LogSeverity.ERROR
31
- }
32
- : {
33
- message: 'An unknown error occurred',
34
- data: error,
35
- severity: LogSeverity.CRITICAL
36
- };
37
-
38
- if (error instanceof EngineError) {
39
- logEntry = {
40
- ...logEntry,
41
- severity: error.severity,
42
- errorType: error.constructor.name,
43
- data: error.data,
44
- '@type':
45
- !(error instanceof WebError) || error.statusCode >= 500
46
- ? 'type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.ReportedErrorEvent'
47
- : undefined
48
- };
49
- }
50
-
51
- if (error instanceof WebError) {
52
- logEntry = {
53
- ...logEntry,
54
- errorCode: error.errorCode,
55
- statusCode: error.statusCode
56
- };
57
- }
58
-
59
- if (request) {
60
- logEntry = {
61
- ...logEntry,
62
- context: {
63
- user:
64
- request.user?.id ?? request.hosts?.join(','),
65
- httpRequest: {
66
- url: request.originalUrl,
67
- method: request.method,
68
- referrer: request.header('Referer'),
69
- userAgent: request.header('User-Agent'),
70
- remoteIp: request.ip,
71
- responseStatusCode:
72
- error instanceof WebError ? error.statusCode : undefined
73
- }
74
- }
75
- };
76
- }
77
-
78
- return output(logEntry);
79
- }
80
-
81
- export let NAMESPACE_SELECTORS: undefined | Array<RegExp>;
82
-
83
- /** Generate the namespace selectors based on the debug variable */
84
- function initNamespaceSelector(): void {
85
- if (process.env.DEBUG)
86
- NAMESPACE_SELECTORS = process.env.DEBUG.split(',').map(
87
- (namespace) => new RegExp('^' + namespace.replace(/\*/g, '.*?') + '$')
88
- );
89
- }
90
-
91
- /** Reset the namespace selectors */
92
- export function resetNamespaceSelector(): void {
93
- NAMESPACE_SELECTORS = undefined;
94
- }
95
-
96
- let debugNamespace: string | undefined;
97
-
98
- /** Log a message for debugging purpose, based on a namespace specified in an environment variable */
99
- export function reportDebug(data: DebugLogEntry): FullLogEntry | undefined {
100
- if (!NAMESPACE_SELECTORS) initNamespaceSelector();
101
- let { namespace } = data;
102
- const isEngineReport = namespace ? namespace.startsWith('engine') : false;
103
-
104
- if (debugNamespace && !isEngineReport) {
105
- namespace = debugNamespace + ':' + namespace;
106
- }
107
-
108
- const match =
109
- namespace &&
110
- NAMESPACE_SELECTORS &&
111
- NAMESPACE_SELECTORS.some((selector) => selector.test(namespace));
112
- if (!match) return;
113
-
114
- // Generate a prefix with the right most part of the namespace
115
- const spaces = namespace.split(':');
116
- const prefix = spaces[spaces.length - 1];
117
-
118
- return output({
119
- severity: LogSeverity.DEBUG,
120
- ...data,
121
- message: `[${prefix}] ${data.message}`
122
- });
123
- }
124
-
125
- /** Specify a global debugging namespace */
126
- reportDebug.setNameSpace = function (globalNamespace: string): void {
127
- debugNamespace = globalNamespace;
128
- };
129
-
130
- /** Remove any defined global namespace */
131
- reportDebug.clearNamespace = function (): void {
132
- debugNamespace = undefined;
133
- };
@@ -1,13 +0,0 @@
1
- import { LogEntry } from './output.types';
2
- import { LogSeverity } from 'const';
3
-
4
- /** Structure of debug logs */
5
- export interface DebugLogEntry extends Omit<LogEntry, 'severity'> {
6
- /** Debugging namespace in which the entry is */
7
- namespace: string;
8
- }
9
-
10
- export type InfoLogEntry = Omit<LogEntry, 'severity'> & {
11
- /** Severity level of the entries */
12
- severity?: LogSeverity;
13
- };
@@ -1 +0,0 @@
1
- export * from './request';
@@ -1,26 +0,0 @@
1
- import { expect } from 'chai';
2
- import { faker } from '@faker-js/faker';
3
- import nock, { cleanAll } from 'nock';
4
- import { request } from './request';
5
- import { EngineError } from 'entities/EngineError';
6
-
7
- describe('Utils - Request', function () {
8
- afterEach(() => {
9
- cleanAll();
10
- });
11
-
12
- it('should retry a request 5 times if network errors happen', async () => {
13
- const url = faker.internet.url();
14
-
15
- const scope = nock(url)
16
- .get('/')
17
- .times(5)
18
- .replyWithError({ code: 'ECONNREFUSED' });
19
-
20
- const promise = request({ url });
21
-
22
- await expect(promise).to.eventually.be.rejectedWith(EngineError);
23
-
24
- scope.isDone();
25
- });
26
- });
@@ -1,48 +0,0 @@
1
- import axios, { AxiosResponse, AxiosRequestConfig } from 'axios';
2
- import { LogSeverity } from 'const';
3
- import { EngineError, EngineErrorOptions } from 'entities/EngineError';
4
-
5
- /** Make a http(s) request through axios with proper error handling */
6
- export async function request<T = unknown>(
7
- options: AxiosRequestConfig,
8
- tryCount = 1
9
- ): Promise<AxiosResponse<T>> {
10
- try {
11
- return await axios.request<T, AxiosResponse<T>>(options);
12
- } catch (error: unknown) {
13
- // In case of networking error, we attempt to retry the connection if we did less than 5 attempts
14
- if (
15
- tryCount < 5 &&
16
- axios.isAxiosError(error) &&
17
- error.code &&
18
- ['ECONNABORTED', 'ECONNREFUSED', 'ECONNRESET', 'EAI_AGAIN'].includes(
19
- error.code
20
- )
21
- ) {
22
- return request<T>(options, tryCount + 1);
23
- }
24
- const errorOptions: EngineErrorOptions = {
25
- message:
26
- error instanceof Error
27
- ? error.message
28
- : typeof error === 'string'
29
- ? error
30
- : 'An unknown error occurred',
31
- severity: LogSeverity.CRITICAL,
32
- data: { error }
33
- };
34
- if (error instanceof Error) {
35
- errorOptions.message = error.message;
36
- errorOptions.error = error;
37
- }
38
- // A response was returned but it was not a 200
39
- if (axios.isAxiosError(error) && error.response) {
40
- errorOptions.data = {
41
- data: error.response.data as unknown,
42
- status: error.response.status,
43
- headers: error.response.headers as unknown
44
- };
45
- }
46
- throw new EngineError(errorOptions);
47
- }
48
- }
@@ -1,2 +0,0 @@
1
- export * from './secretResolver';
2
- export * from './secretLoader';