node-server-engine 1.4.9 → 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.
- package/.commitlintrc.js +27 -0
- package/.releaserc.js +56 -0
- package/README.md +154 -2
- package/dist/const/tokenIssuer.js +1 -0
- package/dist/const/tokenIssuer.js.map +1 -1
- package/dist/db/models/SequelizeMeta.js +3 -1
- package/dist/db/models/SequelizeMeta.js.map +1 -1
- package/dist/entities/ElasticSearch/ElasticSearch.js +1 -2
- package/dist/entities/ElasticSearch/ElasticSearch.js.map +1 -1
- package/dist/entities/SocketClient/SocketClient.js +1 -0
- package/dist/entities/SocketClient/SocketClient.js.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/middleware/checkPermission/checkPermission.d.ts +1 -1
- package/dist/middleware/checkPermission/checkPermission.js +4 -2
- package/dist/middleware/checkPermission/checkPermission.js.map +1 -1
- package/dist/utils/jwt/jwt.js +1 -1
- package/dist/utils/jwt/jwt.js.map +1 -1
- package/dist/utils/semverCompare/semverCompare.js +1 -5
- package/dist/utils/semverCompare/semverCompare.js.map +1 -1
- package/package.json +30 -19
- package/.env.example +0 -186
- package/.github/workflows/publish.yml +0 -41
- package/.prettierrc +0 -7
- package/Dockerfile +0 -31
- package/babel.config.json +0 -34
- package/eslint.config.mjs +0 -11
- package/src/const/DebeziumEvent.ts +0 -6
- package/src/const/LogSeverity.ts +0 -7
- package/src/const/index.ts +0 -5
- package/src/const/metrics.ts +0 -6
- package/src/const/mime.ts +0 -37
- package/src/const/tokenIssuer.ts +0 -7
- package/src/db/migrations/20241030121500-create-sequelize-meta-table.ts +0 -29
- package/src/db/models/SequelizeMeta.ts +0 -16
- package/src/db/models/index.ts +0 -2
- package/src/entities/ElasticSearch/ElasticSearch.ts +0 -103
- package/src/entities/ElasticSearch/ElasticSearch.types.ts +0 -7
- package/src/entities/ElasticSearch/index.ts +0 -2
- package/src/entities/Endpoint/Endpoint.test.ts +0 -248
- package/src/entities/Endpoint/Endpoint.ts +0 -221
- package/src/entities/Endpoint/Endpoint.types.ts +0 -181
- package/src/entities/Endpoint/index.ts +0 -2
- package/src/entities/EngineError/EngineError.ts +0 -28
- package/src/entities/EngineError/EngineError.types.ts +0 -15
- package/src/entities/EngineError/index.ts +0 -2
- package/src/entities/KeySet/KeySet.test.ts +0 -126
- package/src/entities/KeySet/KeySet.ts +0 -172
- package/src/entities/KeySet/KeySet.types.ts +0 -28
- package/src/entities/KeySet/index.ts +0 -2
- package/src/entities/LifecycleController/LifecycleController.test.ts +0 -48
- package/src/entities/LifecycleController/LifecycleController.ts +0 -24
- package/src/entities/LifecycleController/LifecycleController.types.ts +0 -5
- package/src/entities/LifecycleController/index.ts +0 -2
- package/src/entities/Localizator/Localizator.ts +0 -139
- package/src/entities/Localizator/Localizator.types.ts +0 -52
- package/src/entities/Localizator/guessNamingConvention/guessNamingConvention.test.ts +0 -165
- package/src/entities/Localizator/guessNamingConvention/guessNamingConvention.ts +0 -58
- package/src/entities/Localizator/guessNamingConvention/index.ts +0 -1
- package/src/entities/Localizator/index.ts +0 -2
- package/src/entities/MessageHandler/MessageHandler.test.ts +0 -130
- package/src/entities/MessageHandler/MessageHandler.ts +0 -72
- package/src/entities/MessageHandler/MessageHandler.types.ts +0 -15
- package/src/entities/MessageHandler/index.ts +0 -2
- package/src/entities/PubSub/PubSub.test.ts +0 -297
- package/src/entities/PubSub/PubSub.ts +0 -202
- package/src/entities/PubSub/PubSub.types.ts +0 -76
- package/src/entities/PubSub/handleMessage/handleMessage.test.ts +0 -102
- package/src/entities/PubSub/handleMessage/handleMessage.ts +0 -65
- package/src/entities/PubSub/handleMessage/index.ts +0 -1
- package/src/entities/PubSub/index.ts +0 -2
- package/src/entities/PushNotification/PushNotification.test.ts +0 -35
- package/src/entities/PushNotification/PushNotification.ts +0 -44
- package/src/entities/PushNotification/PushNotification.types.ts +0 -25
- package/src/entities/PushNotification/index.ts +0 -2
- package/src/entities/Redis/Redis.ts +0 -71
- package/src/entities/Redis/Redis.types.ts +0 -19
- package/src/entities/Redis/Redis.validate.ts +0 -17
- package/src/entities/Redis/index.ts +0 -2
- package/src/entities/Sequelize/Sequelize.config.ts +0 -59
- package/src/entities/Sequelize/Sequelize.test.ts +0 -21
- package/src/entities/Sequelize/Sequelize.ts +0 -75
- package/src/entities/Sequelize/Sequelize.types.ts +0 -10
- package/src/entities/Sequelize/Sequelize.validate.ts +0 -15
- package/src/entities/Sequelize/index.ts +0 -2
- package/src/entities/Server/Server.const.ts +0 -56
- package/src/entities/Server/Server.test.ts +0 -272
- package/src/entities/Server/Server.ts +0 -471
- package/src/entities/Server/Server.types.ts +0 -88
- package/src/entities/Server/index.ts +0 -2
- package/src/entities/SocketClient/SocketClient.test.ts +0 -392
- package/src/entities/SocketClient/SocketClient.ts +0 -401
- package/src/entities/SocketClient/SocketClient.types.ts +0 -62
- package/src/entities/SocketClient/index.ts +0 -2
- package/src/entities/SocketClient/parseMessage/index.ts +0 -1
- package/src/entities/SocketClient/parseMessage/parseMessage.test.ts +0 -20
- package/src/entities/SocketClient/parseMessage/parseMessage.ts +0 -26
- package/src/entities/Storage/Storage.test.ts +0 -58
- package/src/entities/Storage/Storage.ts +0 -219
- package/src/entities/Storage/Storage.types.ts +0 -57
- package/src/entities/Storage/index.ts +0 -2
- package/src/entities/ValidationError/ValidationError.ts +0 -34
- package/src/entities/ValidationError/index.ts +0 -1
- package/src/entities/WebError/WebError.test.ts +0 -18
- package/src/entities/WebError/WebError.ts +0 -23
- package/src/entities/WebError/WebError.types.ts +0 -9
- package/src/entities/WebError/index.ts +0 -2
- package/src/entities/index.ts +0 -16
- package/src/index.ts +0 -6
- package/src/metrics/debug.ts +0 -10
- package/src/metrics/index.ts +0 -2
- package/src/metrics/request.ts +0 -17
- package/src/middleware/authHmac/authHmac.test.ts +0 -86
- package/src/middleware/authHmac/authHmac.ts +0 -56
- package/src/middleware/authHmac/authHmac.types.ts +0 -7
- package/src/middleware/authHmac/index.ts +0 -2
- package/src/middleware/authJwt/authJwt.test.ts +0 -54
- package/src/middleware/authJwt/authJwt.ts +0 -55
- package/src/middleware/authJwt/authJwt.types.ts +0 -14
- package/src/middleware/authJwt/index.ts +0 -2
- package/src/middleware/authStatic/authStatic.test.ts +0 -36
- package/src/middleware/authStatic/authStatic.ts +0 -45
- package/src/middleware/authStatic/index.ts +0 -1
- package/src/middleware/authTls/authTls.test.ts +0 -138
- package/src/middleware/authTls/authTls.ts +0 -119
- package/src/middleware/authTls/authTls.types.ts +0 -13
- package/src/middleware/authTls/index.ts +0 -2
- package/src/middleware/checkPermission/checkPermission.ts +0 -33
- package/src/middleware/checkPermission/index.ts +0 -1
- package/src/middleware/error/error.test.ts +0 -60
- package/src/middleware/error/error.ts +0 -25
- package/src/middleware/error/index.ts +0 -1
- package/src/middleware/fileUploader/fileUploader.ts +0 -154
- package/src/middleware/fileUploader/fileUploader.types.ts +0 -35
- package/src/middleware/fileUploader/index.ts +0 -2
- package/src/middleware/fileUploader/isMultiPart/index.ts +0 -1
- package/src/middleware/fileUploader/isMultiPart/isMultipart.ts +0 -9
- package/src/middleware/fileUploader/validate/index.ts +0 -1
- package/src/middleware/fileUploader/validate/validate.ts +0 -27
- package/src/middleware/fourOhFour/fourOhFour.test.ts +0 -14
- package/src/middleware/fourOhFour/fourOhFour.ts +0 -13
- package/src/middleware/fourOhFour/index.ts +0 -1
- package/src/middleware/geminiFileUploader/geminiFileUploader.ts +0 -68
- package/src/middleware/geminiFileUploader/index.ts +0 -1
- package/src/middleware/healthCheck/healthCheck.test.ts +0 -12
- package/src/middleware/healthCheck/healthCheck.ts +0 -14
- package/src/middleware/healthCheck/index.ts +0 -1
- package/src/middleware/index.ts +0 -17
- package/src/middleware/metrics/index.ts +0 -1
- package/src/middleware/metrics/metrics.test.ts +0 -46
- package/src/middleware/metrics/metrics.ts +0 -24
- package/src/middleware/multiPartFileUploader/index.ts +0 -2
- package/src/middleware/multiPartFileUploader/multiPartFileUploader.ts +0 -249
- package/src/middleware/multiPartFileUploader/multiPartFileUploader.types.ts +0 -23
- package/src/middleware/multiPartFileUploader/validate/index.ts +0 -1
- package/src/middleware/multiPartFileUploader/validate/validate.ts +0 -27
- package/src/middleware/requestMetrics/index.ts +0 -1
- package/src/middleware/requestMetrics/requestMetrics.test.ts +0 -77
- package/src/middleware/requestMetrics/requestMetrics.ts +0 -20
- package/src/middleware/swaggerDocs/index.ts +0 -2
- package/src/middleware/swaggerDocs/swaggerDocs.ts +0 -114
- package/src/middleware/swaggerDocs/swaggerDocs.types.ts +0 -41
- package/src/middleware/userResolver/index.ts +0 -1
- package/src/middleware/userResolver/userResolver.ts +0 -53
- package/src/middleware/validate/index.ts +0 -1
- package/src/middleware/validate/validate.test.ts +0 -43
- package/src/middleware/validate/validate.ts +0 -25
- package/src/middleware/version/index.ts +0 -1
- package/src/middleware/version/version.test.ts +0 -23
- package/src/middleware/version/version.ts +0 -12
- package/src/utils/checkEnvironment/index.ts +0 -49
- package/src/utils/createHttpServer/createHttpServer.test.ts +0 -24
- package/src/utils/createHttpServer/createHttpServer.ts +0 -34
- package/src/utils/createHttpServer/createHttpServer.validate.ts +0 -17
- package/src/utils/createHttpServer/index.ts +0 -1
- package/src/utils/createSortedObject/createSortedObject.ts +0 -20
- package/src/utils/createSortedObject/createSortedObjet.test.ts +0 -47
- package/src/utils/createSortedObject/index.ts +0 -1
- package/src/utils/dbMigration/dbMigration.test.ts +0 -209
- package/src/utils/dbMigration/dbMigration.ts +0 -199
- package/src/utils/dbMigration/dbMigration.types.ts +0 -11
- package/src/utils/dbMigration/index.ts +0 -2
- package/src/utils/dbMigration/migrateMetadataTable/index.ts +0 -1
- package/src/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.test.ts +0 -59
- package/src/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.ts +0 -102
- package/src/utils/envAssert/envAssert.ts +0 -31
- package/src/utils/envAssert/index.ts +0 -1
- package/src/utils/envAssert/validators/hostList.ts +0 -17
- package/src/utils/envAssert/validators/index.ts +0 -5
- package/src/utils/envAssert/validators/ipList.ts +0 -13
- package/src/utils/envAssert/validators/path.ts +0 -13
- package/src/utils/envAssert/validators/string.ts +0 -9
- package/src/utils/envAssert/validators/stringList.ts +0 -13
- package/src/utils/filter/filter.ts +0 -17
- package/src/utils/filter/index.ts +0 -1
- package/src/utils/geminiFileUpload/geminiFileUpload.ts +0 -93
- package/src/utils/geminiFileUpload/index.ts +0 -1
- package/src/utils/hmac/checkEnv/checkEnv.test.ts +0 -18
- package/src/utils/hmac/checkEnv/checkEnv.ts +0 -9
- package/src/utils/hmac/checkEnv/index.ts +0 -1
- package/src/utils/hmac/createHmac/createHmac.ts +0 -33
- package/src/utils/hmac/createHmac/index.ts +0 -1
- package/src/utils/hmac/index.ts +0 -4
- package/src/utils/hmac/index.types.ts +0 -13
- package/src/utils/hmac/signPayload/index.ts +0 -1
- package/src/utils/hmac/signPayload/signPayload.ts +0 -16
- package/src/utils/hmac/verifySignature/index.ts +0 -1
- package/src/utils/hmac/verifySignature/verifySignature.ts +0 -24
- package/src/utils/index.ts +0 -29
- package/src/utils/jwt/index.ts +0 -2
- package/src/utils/jwt/jwt.test.ts +0 -28
- package/src/utils/jwt/jwt.ts +0 -182
- package/src/utils/jwt/jwt.types.ts +0 -21
- package/src/utils/report/index.ts +0 -3
- package/src/utils/report/output.ts +0 -45
- package/src/utils/report/output.types.ts +0 -70
- package/src/utils/report/report.test.ts +0 -133
- package/src/utils/report/report.ts +0 -133
- package/src/utils/report/report.types.ts +0 -13
- package/src/utils/request/index.ts +0 -1
- package/src/utils/request/request.test.ts +0 -26
- package/src/utils/request/request.ts +0 -48
- package/src/utils/secretManager/index.ts +0 -2
- package/src/utils/secretManager/secretLoader.ts +0 -62
- package/src/utils/secretManager/secretResolver.ts +0 -35
- package/src/utils/semverCompare/index.ts +0 -1
- package/src/utils/semverCompare/semverCompare.test.ts +0 -49
- package/src/utils/semverCompare/semverCompare.ts +0 -60
- package/src/utils/sendEmail/index.ts +0 -2
- package/src/utils/sendEmail/sendEmail.ts +0 -61
- package/src/utils/sendEmail/sendEmail.types.ts +0 -61
- package/src/utils/sendPush/index.ts +0 -2
- package/src/utils/sendPush/sendPush.ts +0 -20
- package/src/utils/sendPush/sendPush.types.ts +0 -25
- package/src/utils/tlsConfig/index.ts +0 -2
- package/src/utils/tlsConfig/tlsConfig.test.ts +0 -32
- package/src/utils/tlsConfig/tlsConfig.ts +0 -47
- package/src/utils/tlsConfig/tlsConfig.types.ts +0 -11
- package/src/utils/tlsConfig/tlsConfig.validate.ts +0 -25
- package/src/utils/tlsRequest/index.ts +0 -1
- package/src/utils/tlsRequest/tlsRequest.test.ts +0 -63
- package/src/utils/tlsRequest/tlsRequest.ts +0 -12
- package/src/utils/trimPathSlash/index.ts +0 -1
- package/src/utils/trimPathSlash/trimPathSlash.test.ts +0 -26
- package/src/utils/trimPathSlash/trimPathSlash.ts +0 -8
- package/test/env.ts +0 -53
- package/test/factory/index.ts +0 -8
- package/test/factory/sequelizeMeta.ts +0 -12
- package/test/hooks.ts +0 -35
- package/test/index.ts +0 -3
- package/test/stub/index.ts +0 -3
- package/test/stub/stubLocales.ts +0 -68
- package/test/stub/stubPubSub.ts +0 -7
- package/test/stub/stubStorage.ts +0 -77
- package/test/stub/stubStorage.types.ts +0 -11
- package/test/utils/app.ts +0 -31
- package/test/utils/index.ts +0 -1
- package/tsconfig.build.json +0 -5
- package/tsconfig.json +0 -32
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { readdirSync } from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { Client } from '@elastic/elasticsearch';
|
|
4
|
-
import { ElasticSearchMigration } from './ElasticSearch.types';
|
|
5
|
-
import { EngineError } from 'entities/EngineError';
|
|
6
|
-
import { LifecycleController } from 'entities/LifecycleController';
|
|
7
|
-
import { envAssert, reportError, reportInfo } from 'utils';
|
|
8
|
-
import { checkEnvironment } from 'utils/checkEnvironment';
|
|
9
|
-
|
|
10
|
-
/** Elastic search client */
|
|
11
|
-
let client: undefined | Client;
|
|
12
|
-
|
|
13
|
-
export const ElasticSearch = {
|
|
14
|
-
/**
|
|
15
|
-
* Init function that should be called on server startup to establish the connection
|
|
16
|
-
*/
|
|
17
|
-
async init(): Promise<void> {
|
|
18
|
-
checkEnvironment({
|
|
19
|
-
ELASTIC_SEARCH_HOST: envAssert.isString(),
|
|
20
|
-
ELASTIC_SEARCH_USERNAME: envAssert.isString(),
|
|
21
|
-
ELASTIC_SEARCH_PASSWORD: envAssert.isString(),
|
|
22
|
-
ELASTIC_SEARCH_MIGRATION_PATH: envAssert.isString()
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
if (!process.env.ELASTIC_SEARCH_HOST)
|
|
26
|
-
throw new EngineError({
|
|
27
|
-
message: 'ElasticSearch Hosts not set in environment'
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
client = new Client({
|
|
31
|
-
node: process.env.ELASTIC_SEARCH_HOST,
|
|
32
|
-
auth: {
|
|
33
|
-
username: process.env.ELASTIC_SEARCH_USERNAME as string,
|
|
34
|
-
password: process.env.ELASTIC_SEARCH_PASSWORD as string
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
// In test environment flush the database before running migrations
|
|
38
|
-
if (process.env.NODE_ENV === 'test')
|
|
39
|
-
await client.indices.delete({ index: '*' });
|
|
40
|
-
await this.migrate();
|
|
41
|
-
LifecycleController.register(this);
|
|
42
|
-
},
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Migration function called during the init process
|
|
46
|
-
* Manages the database structure
|
|
47
|
-
*/
|
|
48
|
-
async migrate(): Promise<void> {
|
|
49
|
-
if (!client) throw new EngineError('ElasticSearch was not initialized');
|
|
50
|
-
const migrationPath = path.resolve(
|
|
51
|
-
process.env.ELASTIC_SEARCH_MIGRATION_PATH as string
|
|
52
|
-
);
|
|
53
|
-
const files = readdirSync(`${migrationPath}`);
|
|
54
|
-
const indexExists = await client.indices.exists({
|
|
55
|
-
index: 'migrations'
|
|
56
|
-
});
|
|
57
|
-
const ran = [];
|
|
58
|
-
for (const file of files) {
|
|
59
|
-
if (indexExists) {
|
|
60
|
-
const {
|
|
61
|
-
hits: { total }
|
|
62
|
-
} = await client.search({
|
|
63
|
-
index: 'migrations',
|
|
64
|
-
body: { query: { match: { file } } }
|
|
65
|
-
});
|
|
66
|
-
let tot = 0;
|
|
67
|
-
if (typeof total === 'number') {
|
|
68
|
-
tot = total;
|
|
69
|
-
} else {
|
|
70
|
-
tot = total?.value ?? 0;
|
|
71
|
-
}
|
|
72
|
-
if (tot > 0) continue;
|
|
73
|
-
}
|
|
74
|
-
ran.push(file);
|
|
75
|
-
const migration = (await import(
|
|
76
|
-
`${migrationPath}/${file}`
|
|
77
|
-
)) as ElasticSearchMigration;
|
|
78
|
-
try {
|
|
79
|
-
await migration.migrate(client);
|
|
80
|
-
} catch (error) {
|
|
81
|
-
reportError(error);
|
|
82
|
-
process.exit(1);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
await client.create({
|
|
86
|
-
index: 'migrations',
|
|
87
|
-
id: file,
|
|
88
|
-
body: { file, ranAt: new Date() }
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
reportInfo({
|
|
92
|
-
message: `ElasticSearch: ran ${ran.length} migrations`,
|
|
93
|
-
data: { files: ran }
|
|
94
|
-
});
|
|
95
|
-
},
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Shutdown function that should be called on server stop to close the connection
|
|
99
|
-
*/
|
|
100
|
-
async shutdown(): Promise<void> {
|
|
101
|
-
if (client) await client.close();
|
|
102
|
-
}
|
|
103
|
-
};
|
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'crypto';
|
|
2
|
-
import { generateAccessToken } from 'backend-test-tools';
|
|
3
|
-
import { expect } from 'chai';
|
|
4
|
-
import express, { Request, Response, NextFunction } from 'express';
|
|
5
|
-
import { faker } from '@faker-js/faker';
|
|
6
|
-
import { fake } from 'sinon';
|
|
7
|
-
import request from 'supertest';
|
|
8
|
-
import { Endpoint } from './Endpoint';
|
|
9
|
-
import {
|
|
10
|
-
EndpointMethod,
|
|
11
|
-
EndpointAuthType,
|
|
12
|
-
EndpointOptions
|
|
13
|
-
} from './Endpoint.types';
|
|
14
|
-
import { Server } from 'entities/Server';
|
|
15
|
-
import { request as httpRequest } from 'utils/request';
|
|
16
|
-
import { tlsRequest } from 'utils/tlsRequest';
|
|
17
|
-
|
|
18
|
-
const PATH = '/test';
|
|
19
|
-
let app = express();
|
|
20
|
-
|
|
21
|
-
const config: EndpointOptions<EndpointAuthType.NONE> = {
|
|
22
|
-
method: EndpointMethod.GET,
|
|
23
|
-
path: PATH,
|
|
24
|
-
handler: (req: Request, res: Response) => {
|
|
25
|
-
res.sendStatus(200);
|
|
26
|
-
},
|
|
27
|
-
validator: {},
|
|
28
|
-
authType: EndpointAuthType.NONE
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
describe('Entity - Endpoint', () => {
|
|
32
|
-
beforeEach(() => {
|
|
33
|
-
app = express();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// Base
|
|
37
|
-
|
|
38
|
-
it('should create a valid Endpoint', async () => {
|
|
39
|
-
const endpoint = new Endpoint(config);
|
|
40
|
-
endpoint.register(app);
|
|
41
|
-
await request(app).get(PATH).expect(200);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// Async
|
|
45
|
-
|
|
46
|
-
it('should handle asynchronous errors', async () => {
|
|
47
|
-
const endpoint = new Endpoint({
|
|
48
|
-
...config,
|
|
49
|
-
handler: async (): Promise<void> => {
|
|
50
|
-
return new Promise((resolve, reject) => {
|
|
51
|
-
reject(new Error());
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
endpoint.register(app);
|
|
56
|
-
await request(app).get(PATH).expect(500);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
// Middleware
|
|
60
|
-
|
|
61
|
-
it('should handle specific middleware', async () => {
|
|
62
|
-
const middleware = fake(
|
|
63
|
-
(req: Request, res: Response, next: NextFunction) => {
|
|
64
|
-
next();
|
|
65
|
-
}
|
|
66
|
-
);
|
|
67
|
-
const endpoint = new Endpoint({
|
|
68
|
-
...config,
|
|
69
|
-
middleware: [middleware]
|
|
70
|
-
});
|
|
71
|
-
endpoint.register(app);
|
|
72
|
-
await request(app).get(PATH).expect(200);
|
|
73
|
-
expect(middleware).to.have.been.called;
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('should handle specific error middleware', async () => {
|
|
77
|
-
const middleware = fake(
|
|
78
|
-
(err: Error, req: Request, res: Response, next: NextFunction) => {
|
|
79
|
-
res.sendStatus(200);
|
|
80
|
-
}
|
|
81
|
-
);
|
|
82
|
-
const endpoint = new Endpoint({
|
|
83
|
-
...config,
|
|
84
|
-
handler: (): void => {
|
|
85
|
-
throw new Error();
|
|
86
|
-
},
|
|
87
|
-
errorMiddleware: [middleware]
|
|
88
|
-
});
|
|
89
|
-
endpoint.register(app);
|
|
90
|
-
await request(app).get(PATH).expect(200);
|
|
91
|
-
expect(middleware).to.have.been.called;
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
// Validator
|
|
95
|
-
|
|
96
|
-
it('should accept request with a valid shape', async () => {
|
|
97
|
-
const endpoint = new Endpoint({
|
|
98
|
-
...config,
|
|
99
|
-
validator: { number: { in: 'query', isInt: true } }
|
|
100
|
-
});
|
|
101
|
-
endpoint.register(app);
|
|
102
|
-
await request(app)
|
|
103
|
-
.get(PATH)
|
|
104
|
-
.query({ number: faker.number.int() })
|
|
105
|
-
.expect(200);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('should reject request with an invalid shape', async () => {
|
|
109
|
-
const endpoint = new Endpoint({
|
|
110
|
-
...config,
|
|
111
|
-
validator: { number: { in: 'query', isInt: true } }
|
|
112
|
-
});
|
|
113
|
-
endpoint.register(app);
|
|
114
|
-
await request(app)
|
|
115
|
-
.get(PATH)
|
|
116
|
-
.query({ number: faker.lorem.word() })
|
|
117
|
-
.expect(400);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
// Middleware
|
|
121
|
-
it('should inject middlewares', async () => {
|
|
122
|
-
const middleware = fake(
|
|
123
|
-
(req: Request, res: Response, next: NextFunction) => {
|
|
124
|
-
next();
|
|
125
|
-
}
|
|
126
|
-
);
|
|
127
|
-
const endpoint = new Endpoint({
|
|
128
|
-
...config,
|
|
129
|
-
middleware
|
|
130
|
-
});
|
|
131
|
-
endpoint.register(app);
|
|
132
|
-
await request(app).get(PATH).expect(200);
|
|
133
|
-
expect(middleware.called).to.be.true;
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('should inject multiple middlewares', async () => {
|
|
137
|
-
const middleware = [
|
|
138
|
-
fake((req: Request, res: Response, next: NextFunction) => {
|
|
139
|
-
next();
|
|
140
|
-
}),
|
|
141
|
-
fake((req: Request, res: Response, next: NextFunction) => {
|
|
142
|
-
next();
|
|
143
|
-
})
|
|
144
|
-
];
|
|
145
|
-
const endpoint = new Endpoint({
|
|
146
|
-
...config,
|
|
147
|
-
middleware
|
|
148
|
-
});
|
|
149
|
-
endpoint.register(app);
|
|
150
|
-
await request(app).get(PATH).expect(200);
|
|
151
|
-
expect(middleware[0].called).to.be.true;
|
|
152
|
-
expect(middleware[1].called).to.be.true;
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
// AUTH JWT
|
|
156
|
-
|
|
157
|
-
it('it should authenticate with authJwt middleware', async () => {
|
|
158
|
-
const id = randomUUID();
|
|
159
|
-
const token = generateAccessToken(id);
|
|
160
|
-
const endpoint = new Endpoint({
|
|
161
|
-
...config,
|
|
162
|
-
authType: EndpointAuthType.JWT,
|
|
163
|
-
handler: (req: Request, res: Response) => {
|
|
164
|
-
res.sendStatus(200);
|
|
165
|
-
}
|
|
166
|
-
} as EndpointOptions<EndpointAuthType.JWT>);
|
|
167
|
-
const server = new Server({ endpoints: [endpoint] });
|
|
168
|
-
|
|
169
|
-
await server.init();
|
|
170
|
-
|
|
171
|
-
await request(server.getApp())
|
|
172
|
-
.get(PATH)
|
|
173
|
-
.set('Authorization', 'Bearer ' + token)
|
|
174
|
-
.expect(200);
|
|
175
|
-
|
|
176
|
-
await server.shutdown();
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
it('it should reject if the user has no valid JWT', async () => {
|
|
180
|
-
const endpoint = new Endpoint({
|
|
181
|
-
...config,
|
|
182
|
-
authType: EndpointAuthType.JWT,
|
|
183
|
-
handler: (req: Request, res: Response) => {
|
|
184
|
-
res.sendStatus(200);
|
|
185
|
-
}
|
|
186
|
-
} as EndpointOptions<EndpointAuthType.JWT>);
|
|
187
|
-
endpoint.register(app);
|
|
188
|
-
await request(app).get(PATH).expect(401);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
it('it should not trigger JWT error if acceptInvalid is set', async () => {
|
|
192
|
-
const endpoint = new Endpoint({
|
|
193
|
-
...config,
|
|
194
|
-
authType: EndpointAuthType.JWT,
|
|
195
|
-
authParams: { acceptInvalid: true },
|
|
196
|
-
handler: (req: Request, res: Response) => {
|
|
197
|
-
res.sendStatus(200);
|
|
198
|
-
}
|
|
199
|
-
} as EndpointOptions<EndpointAuthType.JWT>);
|
|
200
|
-
endpoint.register(app);
|
|
201
|
-
await request(app).get(PATH).expect(200);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
// TLS
|
|
205
|
-
it('it should authenticate with authTLS middleware', async () => {
|
|
206
|
-
const endpoint = new Endpoint({
|
|
207
|
-
...config,
|
|
208
|
-
authType: EndpointAuthType.TLS,
|
|
209
|
-
handler: (req: Request, res: Response) => {
|
|
210
|
-
res.sendStatus(200);
|
|
211
|
-
}
|
|
212
|
-
} as EndpointOptions<EndpointAuthType.TLS>);
|
|
213
|
-
const server = new Server({ endpoints: [endpoint] });
|
|
214
|
-
|
|
215
|
-
await server.init();
|
|
216
|
-
|
|
217
|
-
await expect(
|
|
218
|
-
tlsRequest({
|
|
219
|
-
method: 'get',
|
|
220
|
-
url: `https://127.0.0.1:${process.env.PORT as string}${PATH}`
|
|
221
|
-
})
|
|
222
|
-
).to.not.be.rejected;
|
|
223
|
-
|
|
224
|
-
await server.shutdown();
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
it('it should reject if the user has no valid TLS credentials', async () => {
|
|
228
|
-
const endpoint = new Endpoint({
|
|
229
|
-
...config,
|
|
230
|
-
authType: EndpointAuthType.TLS,
|
|
231
|
-
handler: (req: Request, res: Response) => {
|
|
232
|
-
res.sendStatus(200);
|
|
233
|
-
}
|
|
234
|
-
} as EndpointOptions<EndpointAuthType.TLS>);
|
|
235
|
-
const server = new Server({ endpoints: [endpoint] });
|
|
236
|
-
|
|
237
|
-
await server.init();
|
|
238
|
-
|
|
239
|
-
await expect(
|
|
240
|
-
httpRequest({
|
|
241
|
-
method: 'get',
|
|
242
|
-
url: `https://127.0.0.1:${process.env.PORT as string}${PATH}`
|
|
243
|
-
})
|
|
244
|
-
).to.be.rejected;
|
|
245
|
-
|
|
246
|
-
await server.shutdown();
|
|
247
|
-
});
|
|
248
|
-
});
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
RequestHandler,
|
|
3
|
-
ErrorRequestHandler,
|
|
4
|
-
Application,
|
|
5
|
-
Request,
|
|
6
|
-
Response,
|
|
7
|
-
NextFunction
|
|
8
|
-
} from 'express';
|
|
9
|
-
import { Schema } from 'express-validator';
|
|
10
|
-
import { EngineError } from '../EngineError';
|
|
11
|
-
import {
|
|
12
|
-
EndpointOptions,
|
|
13
|
-
EndpointAuthType,
|
|
14
|
-
EndpointAuthTypes,
|
|
15
|
-
EndpointMethod,
|
|
16
|
-
EndpointMethods,
|
|
17
|
-
EndpointAuthParams,
|
|
18
|
-
Middleware,
|
|
19
|
-
MiddlewareChainElement,
|
|
20
|
-
SafeMiddleWareChain,
|
|
21
|
-
EndpointAuthHandlers,
|
|
22
|
-
EndpointAuthHandler,
|
|
23
|
-
EndpointRequestType,
|
|
24
|
-
EndpointHandler
|
|
25
|
-
} from './Endpoint.types';
|
|
26
|
-
import { LogSeverity } from 'const';
|
|
27
|
-
import {
|
|
28
|
-
validate,
|
|
29
|
-
fileUploader,
|
|
30
|
-
requestMetrics,
|
|
31
|
-
multiPartFileUploader
|
|
32
|
-
} from 'middleware';
|
|
33
|
-
import { FileUploaderConfig } from 'middleware/fileUploader';
|
|
34
|
-
import { MultiPartFileUploaderConfig } from 'middleware/multiPartFileUploader';
|
|
35
|
-
import { reportDebug, reportError, reportInfo } from 'utils/report';
|
|
36
|
-
|
|
37
|
-
const namespace = 'engine:Endpoint';
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Object representing a REST endpoint served by server
|
|
41
|
-
*/
|
|
42
|
-
export class Endpoint<T extends EndpointAuthType> {
|
|
43
|
-
/** Path at which the endpoint is reachable */
|
|
44
|
-
public readonly path: string;
|
|
45
|
-
/** HTTP method of the endpoint */
|
|
46
|
-
public readonly method: EndpointMethod;
|
|
47
|
-
/** Authentication system required by this endpoint */
|
|
48
|
-
public readonly authType: T;
|
|
49
|
-
/** Function handling the endpoint's business logic */
|
|
50
|
-
private handler: EndpointHandler<T>;
|
|
51
|
-
/** Validation schema that the request must pass before reaching the handler */
|
|
52
|
-
private validator: Schema;
|
|
53
|
-
/** Authentication related options for this endpoint */
|
|
54
|
-
private authParams?: EndpointAuthParams<T>;
|
|
55
|
-
/** Settings to upload files through this endpoint (this will automatically switch the expected request to be a multipart) */
|
|
56
|
-
private files?: Array<FileUploaderConfig>;
|
|
57
|
-
/** Settings to upload file parts (Chunks) through this endpoint (this will automatically switch the expected request to be a multipart) */
|
|
58
|
-
private multiPartFile?: MultiPartFileUploaderConfig;
|
|
59
|
-
/** Express request handlers that should run on this endpoint before the business logic, they will run after the global middleware */
|
|
60
|
-
private middleware?: Array<Middleware<T>>;
|
|
61
|
-
/** Express error handlers that should be registered for this endpoint. they will run before the global error handler */
|
|
62
|
-
private errorMiddleware?: Array<ErrorRequestHandler>;
|
|
63
|
-
|
|
64
|
-
/** Create a REST endpoint */
|
|
65
|
-
public constructor(config: EndpointOptions<T>) {
|
|
66
|
-
reportDebug({
|
|
67
|
-
namespace,
|
|
68
|
-
message: `Creating Endpoint [${config.method} - ${config.path}]`,
|
|
69
|
-
data: {
|
|
70
|
-
method: config.method,
|
|
71
|
-
path: config.path,
|
|
72
|
-
authType: config.authType,
|
|
73
|
-
authParams: config.authParams,
|
|
74
|
-
file: config.file,
|
|
75
|
-
files: config.files,
|
|
76
|
-
multiPartFile: config.multiPartFile
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
if (typeof config.path !== 'string')
|
|
81
|
-
throw new EngineError({
|
|
82
|
-
message: 'Endpoint path was not declared as a string'
|
|
83
|
-
});
|
|
84
|
-
this.path = config.path;
|
|
85
|
-
|
|
86
|
-
if (!EndpointMethods.includes(config.method))
|
|
87
|
-
throw new EngineError({
|
|
88
|
-
message: 'Endpoint method is not a valid HTTP method'
|
|
89
|
-
});
|
|
90
|
-
this.method = config.method;
|
|
91
|
-
|
|
92
|
-
if (typeof config.handler !== 'function')
|
|
93
|
-
throw new EngineError({ message: 'Endpoint handler is not a function' });
|
|
94
|
-
this.handler = config.handler;
|
|
95
|
-
|
|
96
|
-
if (!EndpointAuthTypes.includes(config.authType))
|
|
97
|
-
throw new EngineError({ message: 'Endpoint auth type is not valid' });
|
|
98
|
-
this.authType = config.authType;
|
|
99
|
-
|
|
100
|
-
this.validator = config.validator;
|
|
101
|
-
this.authParams = config.authParams;
|
|
102
|
-
this.files = config.file ? [config.file] : config.files;
|
|
103
|
-
|
|
104
|
-
// Middleware can both be function or arrays
|
|
105
|
-
if (typeof config.middleware === 'function')
|
|
106
|
-
this.middleware = [config.middleware];
|
|
107
|
-
if (config.middleware instanceof Array) this.middleware = config.middleware;
|
|
108
|
-
if (typeof config.errorMiddleware === 'function')
|
|
109
|
-
this.errorMiddleware = [config.errorMiddleware];
|
|
110
|
-
if (config.errorMiddleware instanceof Array)
|
|
111
|
-
this.errorMiddleware = config.errorMiddleware;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Register the endpoint to a react app
|
|
116
|
-
*/
|
|
117
|
-
public register(app: Application): void {
|
|
118
|
-
// First initialize the handling calculation
|
|
119
|
-
const middlewareChain: Array<MiddlewareChainElement<T>> = [requestMetrics];
|
|
120
|
-
// Register auth middleware
|
|
121
|
-
middlewareChain.push(...this.getAuthMiddleware(this.authType));
|
|
122
|
-
if (this.files) {
|
|
123
|
-
// Register file upload
|
|
124
|
-
// Validation is included in the file upload process as this uses multipart/form-data
|
|
125
|
-
middlewareChain.push(fileUploader(this.files, this.validator));
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (this.multiPartFile) {
|
|
129
|
-
middlewareChain.push(
|
|
130
|
-
multiPartFileUploader(this.multiPartFile, this.validator)
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (!this.files && !this.multiPartFile) {
|
|
135
|
-
// Register validator for regular cases
|
|
136
|
-
middlewareChain.push(validate(this.validator));
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Register additional middleware
|
|
140
|
-
if (this.middleware) {
|
|
141
|
-
middlewareChain.push(...this.middleware);
|
|
142
|
-
}
|
|
143
|
-
// Register handler
|
|
144
|
-
middlewareChain.push(this.handler);
|
|
145
|
-
// Wrap middleware to await any async execution and catch any errors thrown
|
|
146
|
-
const safeMiddlewareChain: SafeMiddleWareChain =
|
|
147
|
-
this.catchExceptionForExpress(middlewareChain);
|
|
148
|
-
// Register error middleware
|
|
149
|
-
if (this.errorMiddleware) {
|
|
150
|
-
safeMiddlewareChain.push(...this.errorMiddleware);
|
|
151
|
-
}
|
|
152
|
-
app[this.method](
|
|
153
|
-
this.path,
|
|
154
|
-
...(safeMiddlewareChain.flat() as Array<
|
|
155
|
-
RequestHandler | ErrorRequestHandler
|
|
156
|
-
>)
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Catch exceptions thrown inside of middleware and pass them properly to express
|
|
162
|
-
*/
|
|
163
|
-
private catchExceptionForExpress(
|
|
164
|
-
middlewareChain: Array<MiddlewareChainElement<T>>
|
|
165
|
-
): SafeMiddleWareChain {
|
|
166
|
-
return middlewareChain.map((middleware) => {
|
|
167
|
-
if (middleware instanceof Array) {
|
|
168
|
-
return this.catchExceptionForExpress(middleware);
|
|
169
|
-
}
|
|
170
|
-
if (typeof middleware === 'function') {
|
|
171
|
-
return (req: Request, res: Response, next: NextFunction) => {
|
|
172
|
-
(async (): Promise<void> => {
|
|
173
|
-
try {
|
|
174
|
-
await middleware(req as EndpointRequestType[T], res, next);
|
|
175
|
-
} catch (err) {
|
|
176
|
-
next(err);
|
|
177
|
-
}
|
|
178
|
-
})().catch((error) => {
|
|
179
|
-
reportError(error);
|
|
180
|
-
});
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
throw new EngineError({
|
|
184
|
-
message: 'Middleware is not a function nor an array',
|
|
185
|
-
data: { type: typeof middleware }
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Get the authentication middleware for a given type of authentication
|
|
192
|
-
*/
|
|
193
|
-
private getAuthMiddleware(authType: EndpointAuthType): Array<RequestHandler> {
|
|
194
|
-
const middlewareChain: Array<RequestHandler> = [];
|
|
195
|
-
|
|
196
|
-
const handler = EndpointAuthHandlers[authType] as EndpointAuthHandler<T>;
|
|
197
|
-
if (!handler) {
|
|
198
|
-
reportInfo({
|
|
199
|
-
severity: LogSeverity.WARNING,
|
|
200
|
-
message: `Endpoint "${this.method} - ${this.path}" was declared with no authentication method`
|
|
201
|
-
});
|
|
202
|
-
return [];
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const middleware = handler(this.authParams);
|
|
206
|
-
|
|
207
|
-
middlewareChain.push(
|
|
208
|
-
async (request: Request, response: Response, next: NextFunction) => {
|
|
209
|
-
try {
|
|
210
|
-
await middleware(request, response, next);
|
|
211
|
-
} catch (error) {
|
|
212
|
-
if (!this.authParams?.acceptInvalid) throw error;
|
|
213
|
-
reportError(error);
|
|
214
|
-
next();
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
);
|
|
218
|
-
|
|
219
|
-
return middlewareChain;
|
|
220
|
-
}
|
|
221
|
-
}
|