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.
- 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/Sequelize/Sequelize.js +4 -1
- package/dist/entities/Sequelize/Sequelize.js.map +1 -1
- package/dist/entities/Server/Server.js +8 -11
- package/dist/entities/Server/Server.js.map +1 -1
- package/dist/entities/SocketClient/SocketClient.d.ts +4 -1
- package/dist/entities/SocketClient/SocketClient.js +5 -1
- 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/createSortedObject/createSortedObject.d.ts +5 -1
- package/dist/utils/createSortedObject/createSortedObject.js +13 -4
- package/dist/utils/createSortedObject/createSortedObject.js.map +1 -1
- package/dist/utils/dbMigration/dbMigration.js +34 -15
- package/dist/utils/dbMigration/dbMigration.js.map +1 -1
- package/dist/utils/geminiFileUpload/geminiFileUpload.js +2 -1
- package/dist/utils/geminiFileUpload/geminiFileUpload.js.map +1 -1
- package/dist/utils/jwt/jwt.js +1 -1
- package/dist/utils/jwt/jwt.js.map +1 -1
- package/dist/utils/report/report.d.ts +9 -3
- package/dist/utils/report/report.js +29 -12
- package/dist/utils/report/report.js.map +1 -1
- package/dist/utils/secretManager/secretLoader.js +5 -1
- package/dist/utils/secretManager/secretLoader.js.map +1 -1
- package/dist/utils/semverCompare/semverCompare.d.ts +4 -4
- package/dist/utils/semverCompare/semverCompare.js +16 -18
- 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,219 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'crypto';
|
|
2
|
-
import { Readable } from 'stream';
|
|
3
|
-
import {
|
|
4
|
-
Storage as CloudStorage,
|
|
5
|
-
CreateWriteStreamOptions,
|
|
6
|
-
File
|
|
7
|
-
} from '@google-cloud/storage';
|
|
8
|
-
import fileSizeParser from 'filesize-parser';
|
|
9
|
-
import mimeTypes from 'mime-types';
|
|
10
|
-
import {
|
|
11
|
-
UploadDestinationOptions,
|
|
12
|
-
StorageUploadedFile,
|
|
13
|
-
UploaderOptions,
|
|
14
|
-
StorageGetResponse,
|
|
15
|
-
StorageDownloadResponse
|
|
16
|
-
} from './Storage.types';
|
|
17
|
-
import { WebError } from 'entities/WebError';
|
|
18
|
-
import { reportDebug } from 'utils/report';
|
|
19
|
-
import { trimPathSlash } from 'utils/trimPathSlash';
|
|
20
|
-
|
|
21
|
-
const namespace = 'engine:storage';
|
|
22
|
-
|
|
23
|
-
export const Storage = {
|
|
24
|
-
cloudStorage: new CloudStorage({
|
|
25
|
-
projectId: process.env.GC_PROJECT,
|
|
26
|
-
keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS
|
|
27
|
-
}),
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Upload a file to the cloud storage
|
|
31
|
-
* @param readStream - Stream of the file content
|
|
32
|
-
* @param bucket - Bucket in which the file should be stored
|
|
33
|
-
* @param destinationOptions - Options for the destination generator [see: generateFileDestination(options)]
|
|
34
|
-
* @param storageOptions - Storage library options
|
|
35
|
-
* @param uploaderOptions - Options for this service's specific behavior
|
|
36
|
-
* @return {Promise<Object>} - Details regarding the uploaded file's metadata
|
|
37
|
-
*/
|
|
38
|
-
async upload(
|
|
39
|
-
readStream: Readable,
|
|
40
|
-
bucket: string,
|
|
41
|
-
destinationOptions: UploadDestinationOptions = {},
|
|
42
|
-
storageOptions: CreateWriteStreamOptions = {},
|
|
43
|
-
uploaderOptions: UploaderOptions = {}
|
|
44
|
-
): Promise<StorageUploadedFile> {
|
|
45
|
-
const { maxSize } = uploaderOptions;
|
|
46
|
-
|
|
47
|
-
let file: File;
|
|
48
|
-
reportDebug({
|
|
49
|
-
namespace,
|
|
50
|
-
message: 'Uploading file to storage',
|
|
51
|
-
data: { bucket, destinationOptions, storageOptions, uploaderOptions }
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
// Generate the file path
|
|
55
|
-
// We either use a given file name, or we generate a random file name
|
|
56
|
-
const { fileName, directory } = destinationOptions;
|
|
57
|
-
|
|
58
|
-
// Upload file with given file name
|
|
59
|
-
if (fileName) {
|
|
60
|
-
// Only keep required slashes in full path
|
|
61
|
-
const trimmedDirectory = trimPathSlash(directory ?? '/');
|
|
62
|
-
const path = `${trimmedDirectory}/${fileName}`;
|
|
63
|
-
file = this.cloudStorage.bucket(bucket).file(path);
|
|
64
|
-
}
|
|
65
|
-
// Generate random destination for file and check that it is not already occupied
|
|
66
|
-
else {
|
|
67
|
-
do {
|
|
68
|
-
const path = this.generateFileDestination(destinationOptions);
|
|
69
|
-
file = this.cloudStorage.bucket(bucket).file(path);
|
|
70
|
-
} while ((await file.exists())[0]);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Pipe user's file stream to the storage
|
|
74
|
-
return new Promise((resolve, reject) => {
|
|
75
|
-
let receivedSize = 0;
|
|
76
|
-
const writeStream = file.createWriteStream(storageOptions);
|
|
77
|
-
const intMaxSize = maxSize && fileSizeParser(maxSize);
|
|
78
|
-
// Calculate transferred size and write to storage stream
|
|
79
|
-
readStream.on('data', function (data: Buffer) {
|
|
80
|
-
receivedSize += data.length;
|
|
81
|
-
// Fail if transferred data over max size
|
|
82
|
-
if (intMaxSize && receivedSize > intMaxSize) {
|
|
83
|
-
reject(
|
|
84
|
-
new WebError({
|
|
85
|
-
statusCode: 413,
|
|
86
|
-
errorCode: 'file-too-large',
|
|
87
|
-
message: 'Request contains a file that is over the maximum size',
|
|
88
|
-
hint: { maxSize },
|
|
89
|
-
data: {
|
|
90
|
-
bucket,
|
|
91
|
-
destinationOptions,
|
|
92
|
-
storageOptions,
|
|
93
|
-
receivedSize,
|
|
94
|
-
maxSize
|
|
95
|
-
}
|
|
96
|
-
})
|
|
97
|
-
);
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
writeStream.write(data);
|
|
101
|
-
});
|
|
102
|
-
// Error handling
|
|
103
|
-
readStream.on('error', (err) => {
|
|
104
|
-
reject(err);
|
|
105
|
-
});
|
|
106
|
-
writeStream.on('error', (err) => {
|
|
107
|
-
reject(err);
|
|
108
|
-
});
|
|
109
|
-
// Graceful termination of the read
|
|
110
|
-
readStream.on('end', () => {
|
|
111
|
-
writeStream.end();
|
|
112
|
-
});
|
|
113
|
-
// Graceful termination of the write
|
|
114
|
-
writeStream.on('finish', () => {
|
|
115
|
-
(async (): Promise<void> => {
|
|
116
|
-
const [metadata] = (await file.getMetadata()) as [
|
|
117
|
-
StorageUploadedFile,
|
|
118
|
-
unknown
|
|
119
|
-
];
|
|
120
|
-
reportDebug({
|
|
121
|
-
namespace,
|
|
122
|
-
message: 'File uploaded to storage',
|
|
123
|
-
data: metadata
|
|
124
|
-
});
|
|
125
|
-
resolve(metadata);
|
|
126
|
-
})().catch((error) => {
|
|
127
|
-
reject(error);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
},
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Return the read stream for a given file and bucket
|
|
135
|
-
*/
|
|
136
|
-
async get(bucket: string, path: string): Promise<StorageGetResponse> {
|
|
137
|
-
const file = this.cloudStorage.bucket(bucket).file(path);
|
|
138
|
-
const [[metadata], [data]] = (await Promise.all([
|
|
139
|
-
file.getMetadata(),
|
|
140
|
-
file.download()
|
|
141
|
-
])) as [[StorageUploadedFile, unknown], [Buffer]];
|
|
142
|
-
reportDebug({
|
|
143
|
-
namespace,
|
|
144
|
-
message: 'Downloaded file from storage',
|
|
145
|
-
data: { bucket, path, metadata }
|
|
146
|
-
});
|
|
147
|
-
return {
|
|
148
|
-
data,
|
|
149
|
-
metadata
|
|
150
|
-
};
|
|
151
|
-
},
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Return the read stream for a given file and bucket
|
|
155
|
-
*/
|
|
156
|
-
async download(
|
|
157
|
-
bucket: string,
|
|
158
|
-
path: string
|
|
159
|
-
): Promise<StorageDownloadResponse> {
|
|
160
|
-
const file = this.cloudStorage.bucket(bucket).file(path);
|
|
161
|
-
const [metadata] = (await file.getMetadata()) as [
|
|
162
|
-
StorageUploadedFile,
|
|
163
|
-
unknown
|
|
164
|
-
];
|
|
165
|
-
reportDebug({
|
|
166
|
-
namespace,
|
|
167
|
-
message: 'Fetched file stream from storage',
|
|
168
|
-
data: { bucket, path, metadata }
|
|
169
|
-
});
|
|
170
|
-
return {
|
|
171
|
-
stream: file.createReadStream(),
|
|
172
|
-
metadata
|
|
173
|
-
};
|
|
174
|
-
},
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Return the read stream for a given file path and bucket
|
|
178
|
-
* @param {String} bucket
|
|
179
|
-
* @param {String} path
|
|
180
|
-
*/
|
|
181
|
-
getFileStream(bucket: string, path: string): Readable {
|
|
182
|
-
const file = this.cloudStorage.bucket(bucket).file(path);
|
|
183
|
-
reportDebug({
|
|
184
|
-
namespace,
|
|
185
|
-
message: "Fetched file stream from storage's bucket",
|
|
186
|
-
data: { bucket, path }
|
|
187
|
-
});
|
|
188
|
-
return file.createReadStream();
|
|
189
|
-
},
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Delete a file from the cloud storage
|
|
193
|
-
*/
|
|
194
|
-
async delete(bucket: string, path: string): Promise<void> {
|
|
195
|
-
reportDebug({
|
|
196
|
-
namespace,
|
|
197
|
-
message: 'Deleting file from storage',
|
|
198
|
-
data: { bucket, path }
|
|
199
|
-
});
|
|
200
|
-
await this.cloudStorage.bucket(bucket).file(path).delete();
|
|
201
|
-
},
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Builds the full file path on the cloud and generates it a random name
|
|
205
|
-
*/
|
|
206
|
-
generateFileDestination(options: UploadDestinationOptions = {}): string {
|
|
207
|
-
const { directory = '/', mime, noExtension = false } = options;
|
|
208
|
-
|
|
209
|
-
// use provided mime type default otherwise
|
|
210
|
-
const extension =
|
|
211
|
-
mime && mimeTypes.extension(mime) ? mimeTypes.extension(mime) : undefined;
|
|
212
|
-
// Build the full name
|
|
213
|
-
const fullName =
|
|
214
|
-
extension && !noExtension ? `${randomUUID()}.${extension}` : randomUUID();
|
|
215
|
-
// Only keep required slashes in full path
|
|
216
|
-
const trimmedDirectory = trimPathSlash(directory);
|
|
217
|
-
return `${trimmedDirectory ? `${trimmedDirectory}/` : ''}${fullName}`;
|
|
218
|
-
}
|
|
219
|
-
};
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { Readable } from 'stream';
|
|
2
|
-
|
|
3
|
-
/** Options to set where an uploaded file is stored in the bucket */
|
|
4
|
-
export interface UploadDestinationOptions {
|
|
5
|
-
/** Directory of the bucket in which the file is stored. Defaults to the root directory */
|
|
6
|
-
directory?: string;
|
|
7
|
-
/** Name under which the file is stored. If specified, the file is stored with that name. Otherwise random name generation is done */
|
|
8
|
-
fileName?: string;
|
|
9
|
-
/** When using random file name generation (ie: fileName is undefined). We use the MIME type to determine which is the best extension to apply to the file */
|
|
10
|
-
mime?: string;
|
|
11
|
-
/** When using random file name generation (ie: fileName is undefined), use this parameter to skip adding an extension to the file */
|
|
12
|
-
noExtension?: boolean;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/** Options of the file uploader */
|
|
16
|
-
export interface UploaderOptions {
|
|
17
|
-
/** Maximum size of the file (ex: 2MB) */
|
|
18
|
-
maxSize?: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** Object representing a file that has been uploaded */
|
|
22
|
-
export interface StorageUploadedFile {
|
|
23
|
-
/** Bucket in which the file has been uploaded */
|
|
24
|
-
bucket: string;
|
|
25
|
-
/** Name of the stored object with path */
|
|
26
|
-
name: string;
|
|
27
|
-
/** Content-type of the file */
|
|
28
|
-
contentType: string;
|
|
29
|
-
/** Byte size of the file */
|
|
30
|
-
size: string;
|
|
31
|
-
/** ISO string of the creation date */
|
|
32
|
-
timeCreated: string;
|
|
33
|
-
/** ISO string of the update date */
|
|
34
|
-
updated: string;
|
|
35
|
-
/** MD5 hash of the content */
|
|
36
|
-
md5Hash: string;
|
|
37
|
-
/** CRC32C hash of the content */
|
|
38
|
-
crc32c: string;
|
|
39
|
-
/** Storage class applied */
|
|
40
|
-
storageClass: string;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** Return type for a file download */
|
|
44
|
-
export interface StorageGetResponse {
|
|
45
|
-
/** The file raw binary content */
|
|
46
|
-
data: Buffer;
|
|
47
|
-
/** The file's metadata */
|
|
48
|
-
metadata: StorageUploadedFile;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/** Return time for a file streaming fetching */
|
|
52
|
-
export interface StorageDownloadResponse {
|
|
53
|
-
/** A readable stream with the file's content */
|
|
54
|
-
stream: Readable;
|
|
55
|
-
/** The file's metadata */
|
|
56
|
-
metadata: StorageUploadedFile;
|
|
57
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ValidationError as ExpressValidationError,
|
|
3
|
-
Result
|
|
4
|
-
} from 'express-validator';
|
|
5
|
-
import { LogSeverity } from 'const';
|
|
6
|
-
import { EngineError } from 'entities/EngineError';
|
|
7
|
-
import { WebError } from 'entities/WebError';
|
|
8
|
-
|
|
9
|
-
/** Error class for request/message validation errors */
|
|
10
|
-
export class ValidationError extends WebError {
|
|
11
|
-
/** Create an ValidationError this represents errors in parsing incoming messages/requests */
|
|
12
|
-
public constructor(validationResult: Result<ExpressValidationError>) {
|
|
13
|
-
if (validationResult.isEmpty())
|
|
14
|
-
throw new EngineError({
|
|
15
|
-
message:
|
|
16
|
-
'Attempted to create a validation error while validation was successful'
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
const errors = validationResult.array();
|
|
20
|
-
// Hint that is sent to the client as logged as data
|
|
21
|
-
const hint = errors.reduce(
|
|
22
|
-
(hint, error) => ({ ...hint, [error.type]: error.msg as string }),
|
|
23
|
-
{}
|
|
24
|
-
);
|
|
25
|
-
super({
|
|
26
|
-
message: 'Request did not pass validation',
|
|
27
|
-
errorCode: 'invalid-request',
|
|
28
|
-
statusCode: 400,
|
|
29
|
-
severity: LogSeverity.WARNING,
|
|
30
|
-
data: hint,
|
|
31
|
-
hint
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './ValidationError';
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { expect } from 'chai';
|
|
2
|
-
import { WebError } from './WebError';
|
|
3
|
-
|
|
4
|
-
describe('Entity - WebError', () => {
|
|
5
|
-
it('should set the error code and message', () => {
|
|
6
|
-
const statusCode = 401;
|
|
7
|
-
const errorCode = 'example-errorCode';
|
|
8
|
-
const message = 'this is an example message';
|
|
9
|
-
const error = new WebError({
|
|
10
|
-
message,
|
|
11
|
-
errorCode,
|
|
12
|
-
statusCode
|
|
13
|
-
});
|
|
14
|
-
expect(error.message).to.equal(message);
|
|
15
|
-
expect(error.errorCode).to.equal(errorCode);
|
|
16
|
-
expect(error.statusCode).to.equal(statusCode);
|
|
17
|
-
});
|
|
18
|
-
});
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { WebErrorOptions } from './WebError.types';
|
|
2
|
-
import { LogSeverity } from 'const';
|
|
3
|
-
import { EngineError } from 'entities/EngineError';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Error class used when errors should be reported to the client
|
|
7
|
-
*/
|
|
8
|
-
export class WebError extends EngineError {
|
|
9
|
-
/** Machine readable error code that will be sent to the client */
|
|
10
|
-
public errorCode: string;
|
|
11
|
-
/** HTTP status code associated with this error */
|
|
12
|
-
public statusCode: number;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Create a WebError, these errors are best suited for runtime errors
|
|
16
|
-
*/
|
|
17
|
-
public constructor(config: WebErrorOptions) {
|
|
18
|
-
super({ ...config, severity: config.severity ?? LogSeverity.WARNING });
|
|
19
|
-
|
|
20
|
-
this.statusCode = config.statusCode ?? 400;
|
|
21
|
-
this.errorCode = config.errorCode;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { EngineErrorOptions } from 'entities/EngineError';
|
|
2
|
-
|
|
3
|
-
/** Options to create a Web Error */
|
|
4
|
-
export interface WebErrorOptions extends EngineErrorOptions {
|
|
5
|
-
/** Machine readable error code that will be sent to the client */
|
|
6
|
-
errorCode: string;
|
|
7
|
-
/** HTTP status code associated with this error (default: 400) */
|
|
8
|
-
statusCode?: number;
|
|
9
|
-
}
|
package/src/entities/index.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export * from './EngineError';
|
|
2
|
-
export * from './WebError';
|
|
3
|
-
export * from './ValidationError';
|
|
4
|
-
export * from './KeySet';
|
|
5
|
-
export * from './Endpoint';
|
|
6
|
-
export * from './MessageHandler';
|
|
7
|
-
export * from './SocketClient';
|
|
8
|
-
export * from './Server';
|
|
9
|
-
export * from './Redis';
|
|
10
|
-
export * from './Localizator';
|
|
11
|
-
export * from './Storage';
|
|
12
|
-
export * from './Sequelize';
|
|
13
|
-
export * from './ElasticSearch';
|
|
14
|
-
export * from './LifecycleController';
|
|
15
|
-
export * from './PubSub';
|
|
16
|
-
export * from './PushNotification';
|
package/src/index.ts
DELETED
package/src/metrics/debug.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Gauge } from 'prom-client';
|
|
2
|
-
import { instanceRegistry } from 'const';
|
|
3
|
-
|
|
4
|
-
export const debugActivated = new Gauge({
|
|
5
|
-
name: 'debug_activated',
|
|
6
|
-
help: 'Debug is activated',
|
|
7
|
-
registers: [instanceRegistry]
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
debugActivated.set(process.env.DEBUG?.length ? 1 : 0);
|
package/src/metrics/index.ts
DELETED
package/src/metrics/request.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { Counter, Histogram } from 'prom-client';
|
|
2
|
-
import { instanceRegistry } from 'const';
|
|
3
|
-
|
|
4
|
-
export const httpRequestCount = new Counter({
|
|
5
|
-
name: 'http_requests_total',
|
|
6
|
-
help: 'Total count of request received',
|
|
7
|
-
registers: [instanceRegistry],
|
|
8
|
-
labelNames: ['service', 'path', 'method', 'status']
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
export const httpRequestDuration = new Histogram({
|
|
12
|
-
name: 'http_requests_duration',
|
|
13
|
-
help: 'Duration of the request received',
|
|
14
|
-
registers: [instanceRegistry],
|
|
15
|
-
labelNames: ['service', 'path', 'method', 'status'],
|
|
16
|
-
buckets: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 0.5, 1, 2.5, 5, 10]
|
|
17
|
-
});
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import crypto from 'crypto';
|
|
2
|
-
import express, { json, Request, Response, Application } from 'express';
|
|
3
|
-
import { faker } from '@faker-js/faker';
|
|
4
|
-
import request from 'supertest';
|
|
5
|
-
import {
|
|
6
|
-
Endpoint,
|
|
7
|
-
EndpointAuthType,
|
|
8
|
-
EndpointMethod,
|
|
9
|
-
EndpointOptions
|
|
10
|
-
} from 'entities/Endpoint';
|
|
11
|
-
import { signPayload } from 'utils/hmac';
|
|
12
|
-
|
|
13
|
-
describe('Middleware - authHmac', () => {
|
|
14
|
-
let app: Application;
|
|
15
|
-
|
|
16
|
-
const PATH = '/test';
|
|
17
|
-
const config: EndpointOptions<EndpointAuthType.HMAC> = {
|
|
18
|
-
path: PATH,
|
|
19
|
-
method: EndpointMethod.POST,
|
|
20
|
-
handler: (req: Request, res: Response) => {
|
|
21
|
-
res.sendStatus(200);
|
|
22
|
-
},
|
|
23
|
-
authType: EndpointAuthType.HMAC,
|
|
24
|
-
validator: {}
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
beforeEach(() => {
|
|
28
|
-
app = express();
|
|
29
|
-
app.use(json());
|
|
30
|
-
process.env.PAYLOAD_SIGNATURE_SECRET = faker.lorem.slug();
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('should allow properly signed requests', async () => {
|
|
34
|
-
const payload = signPayload({ test: 'test' });
|
|
35
|
-
const endpoint = new Endpoint({
|
|
36
|
-
...config,
|
|
37
|
-
authType: EndpointAuthType.HMAC
|
|
38
|
-
});
|
|
39
|
-
endpoint.register(app);
|
|
40
|
-
await request(app).post(PATH).send(payload).expect(200);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('should allow properly signed requests with a custom secret', async () => {
|
|
44
|
-
const secret = faker.lorem.word();
|
|
45
|
-
const payload = signPayload({ test: 'test' }, { secret });
|
|
46
|
-
const endpoint = new Endpoint({
|
|
47
|
-
...config,
|
|
48
|
-
authType: EndpointAuthType.HMAC,
|
|
49
|
-
authParams: { secret }
|
|
50
|
-
});
|
|
51
|
-
endpoint.register(app);
|
|
52
|
-
await request(app).post(PATH).send(payload);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('should not allow wrongly signed requests', async () => {
|
|
56
|
-
const payload = signPayload({ test: 'test' }, { secret: 'hacker' });
|
|
57
|
-
const endpoint = new Endpoint({
|
|
58
|
-
...config,
|
|
59
|
-
authType: EndpointAuthType.HMAC
|
|
60
|
-
});
|
|
61
|
-
endpoint.register(app);
|
|
62
|
-
await request(app).post(PATH).send(payload).expect(401);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('should allow signed requests from Github', async () => {
|
|
66
|
-
const payload = {
|
|
67
|
-
z: faker.lorem.word(),
|
|
68
|
-
a: { z: faker.lorem.word(), a: faker.lorem.word() }
|
|
69
|
-
};
|
|
70
|
-
const signature = crypto
|
|
71
|
-
.createHmac('sha1', process.env.PAYLOAD_SIGNATURE_SECRET as string)
|
|
72
|
-
.update(JSON.stringify(payload))
|
|
73
|
-
.digest('hex');
|
|
74
|
-
const endpoint = new Endpoint({
|
|
75
|
-
...config,
|
|
76
|
-
authType: EndpointAuthType.HMAC,
|
|
77
|
-
authParams: { isGithub: true }
|
|
78
|
-
});
|
|
79
|
-
endpoint.register(app);
|
|
80
|
-
await request(app)
|
|
81
|
-
.post(PATH)
|
|
82
|
-
.send(payload)
|
|
83
|
-
.set({ 'X-Hub-Signature': `sha1=${signature}` })
|
|
84
|
-
.expect(200);
|
|
85
|
-
});
|
|
86
|
-
});
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { BinaryToTextEncoding } from 'crypto';
|
|
2
|
-
import { Request, Response, NextFunction } from 'express';
|
|
3
|
-
import { HmacPayload } from './authHmac.types';
|
|
4
|
-
import { EndpointAuthParams, EndpointAuthType } from 'entities/Endpoint';
|
|
5
|
-
import { WebError } from 'entities/WebError';
|
|
6
|
-
import { verifySignature } from 'utils/hmac';
|
|
7
|
-
import { reportDebug } from 'utils/report';
|
|
8
|
-
|
|
9
|
-
const namespace = 'engine:middleware:authHmac';
|
|
10
|
-
|
|
11
|
-
/** Generate an HMAC authentication middleware */
|
|
12
|
-
export function authHmac(
|
|
13
|
-
options: EndpointAuthParams<EndpointAuthType.HMAC> = {}
|
|
14
|
-
): (req: Request, res: Response, next: NextFunction) => void {
|
|
15
|
-
return (req: Request, res: Response, next: NextFunction): void => {
|
|
16
|
-
const payload = (
|
|
17
|
-
req.method === 'GET' ? req.query : req.body
|
|
18
|
-
) as HmacPayload;
|
|
19
|
-
let signature: string | undefined;
|
|
20
|
-
let signatureSettings;
|
|
21
|
-
if (options.isGithub) {
|
|
22
|
-
// For GitHub, the signature is in the header and is has specific settings
|
|
23
|
-
signature =
|
|
24
|
-
req.headers['x-hub-signature'] &&
|
|
25
|
-
(req.headers['x-hub-signature'] as string).substr(5);
|
|
26
|
-
signatureSettings = {
|
|
27
|
-
algorithm: 'sha1',
|
|
28
|
-
sort: false,
|
|
29
|
-
encode: 'hex' as BinaryToTextEncoding
|
|
30
|
-
};
|
|
31
|
-
} else {
|
|
32
|
-
// In our standard authentication, the signature is included in the payload
|
|
33
|
-
signature = payload.signature;
|
|
34
|
-
delete payload.signature;
|
|
35
|
-
}
|
|
36
|
-
const settings = { secret: options.secret, ...signatureSettings };
|
|
37
|
-
if (!signature)
|
|
38
|
-
throw new WebError({
|
|
39
|
-
message: 'No signature was provided',
|
|
40
|
-
errorCode: 'unauthorized',
|
|
41
|
-
statusCode: 401
|
|
42
|
-
});
|
|
43
|
-
reportDebug({
|
|
44
|
-
namespace,
|
|
45
|
-
message: 'Performing HMAC authentication',
|
|
46
|
-
data: { payload, signature, settings }
|
|
47
|
-
});
|
|
48
|
-
if (!verifySignature(payload, signature, settings))
|
|
49
|
-
throw new WebError({
|
|
50
|
-
message: 'Signature does not match hmac of payload',
|
|
51
|
-
errorCode: 'unauthorized',
|
|
52
|
-
statusCode: 401
|
|
53
|
-
});
|
|
54
|
-
next();
|
|
55
|
-
};
|
|
56
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { factory, getBearer } from 'backend-test-tools';
|
|
2
|
-
import { expect } from 'chai';
|
|
3
|
-
import { Request, Response } from 'express';
|
|
4
|
-
import { faker } from '@faker-js/faker';
|
|
5
|
-
import { fake } from 'sinon';
|
|
6
|
-
import { authJwt } from './authJwt';
|
|
7
|
-
|
|
8
|
-
describe('Middleware - Auth JWT', () => {
|
|
9
|
-
it('should authenticate with a JWT (auth-service)', async () => {
|
|
10
|
-
const user = factory.build('user');
|
|
11
|
-
const request = { headers: { authorization: getBearer(user.id) } };
|
|
12
|
-
const next = fake();
|
|
13
|
-
|
|
14
|
-
await authJwt()(request as Request, undefined as unknown as Response, next);
|
|
15
|
-
|
|
16
|
-
expect(next).to.have.been.calledOnceWithExactly();
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('should populate the user object in the request (auth-service)', async () => {
|
|
20
|
-
const user = factory.build('user');
|
|
21
|
-
const request = {
|
|
22
|
-
headers: { authorization: getBearer(user.id) }
|
|
23
|
-
} as Request;
|
|
24
|
-
const next = fake();
|
|
25
|
-
|
|
26
|
-
await authJwt()(request, undefined as unknown as Response, next);
|
|
27
|
-
|
|
28
|
-
expect(request.user).to.not.be.undefined;
|
|
29
|
-
expect(request.user?.id).to.equal(user.id);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('should throw an error if there is no token', async () => {
|
|
33
|
-
const request = { headers: {} };
|
|
34
|
-
const next = fake();
|
|
35
|
-
|
|
36
|
-
await expect(
|
|
37
|
-
authJwt()(request as Request, undefined as unknown as Response, next)
|
|
38
|
-
).to.eventually.rejected;
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should throw an error if the audience is not valid', async () => {
|
|
42
|
-
const user = factory.build('user');
|
|
43
|
-
const request = {
|
|
44
|
-
headers: {
|
|
45
|
-
authorization: getBearer(user.id, { audience: faker.internet.url() })
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
const next = fake();
|
|
49
|
-
|
|
50
|
-
await expect(
|
|
51
|
-
authJwt()(request as Request, undefined as unknown as Response, next)
|
|
52
|
-
).to.eventually.rejected;
|
|
53
|
-
});
|
|
54
|
-
});
|