@flowerforce/flowerbase 1.7.6-beta.0 → 1.7.6-beta.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/README.md +125 -1
- package/dist/auth/providers/custom-function/controller.d.ts.map +1 -1
- package/dist/auth/providers/custom-function/controller.js +3 -8
- package/dist/constants.d.ts +10 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +11 -1
- package/dist/features/encryption/interface.d.ts +36 -0
- package/dist/features/encryption/interface.d.ts.map +1 -0
- package/dist/features/encryption/interface.js +2 -0
- package/dist/features/encryption/utils.d.ts +9 -0
- package/dist/features/encryption/utils.d.ts.map +1 -0
- package/dist/features/encryption/utils.js +34 -0
- package/dist/features/rules/utils.d.ts.map +1 -1
- package/dist/features/rules/utils.js +1 -11
- package/dist/features/triggers/index.d.ts.map +1 -1
- package/dist/features/triggers/index.js +4 -0
- package/dist/features/triggers/utils.d.ts.map +1 -1
- package/dist/features/triggers/utils.js +30 -38
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -4
- package/dist/monitoring/plugin.d.ts.map +1 -1
- package/dist/monitoring/plugin.js +31 -0
- package/dist/services/mongodb-atlas/index.d.ts.map +1 -1
- package/dist/services/mongodb-atlas/index.js +9 -7
- package/dist/services/mongodb-atlas/model.d.ts +2 -1
- package/dist/services/mongodb-atlas/model.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +14 -3
- package/dist/utils/initializer/mongodbCSFLE.d.ts +69 -0
- package/dist/utils/initializer/mongodbCSFLE.d.ts.map +1 -0
- package/dist/utils/initializer/mongodbCSFLE.js +131 -0
- package/dist/utils/initializer/registerPlugins.d.ts +5 -1
- package/dist/utils/initializer/registerPlugins.d.ts.map +1 -1
- package/dist/utils/initializer/registerPlugins.js +27 -5
- package/package.json +4 -2
- package/src/auth/providers/custom-function/controller.ts +4 -10
- package/src/constants.ts +11 -2
- package/src/features/encryption/interface.ts +46 -0
- package/src/features/encryption/utils.ts +22 -0
- package/src/features/rules/utils.ts +1 -11
- package/src/features/triggers/index.ts +5 -1
- package/src/features/triggers/utils.ts +31 -42
- package/src/index.ts +10 -2
- package/src/monitoring/plugin.ts +33 -0
- package/src/monitoring/ui.collections.js +7 -10
- package/src/monitoring/ui.css +378 -0
- package/src/monitoring/ui.endpoints.js +5 -10
- package/src/monitoring/ui.events.js +2 -4
- package/src/monitoring/ui.functions.js +64 -71
- package/src/monitoring/ui.html +8 -0
- package/src/monitoring/ui.js +189 -0
- package/src/monitoring/ui.shared.js +237 -2
- package/src/monitoring/ui.triggers.js +2 -3
- package/src/monitoring/ui.users.js +5 -9
- package/src/services/mongodb-atlas/index.ts +10 -13
- package/src/services/mongodb-atlas/model.ts +3 -1
- package/src/types/fastify-raw-body.d.ts +0 -9
- package/src/utils/__tests__/mongodbCSFLE.test.ts +105 -0
- package/src/utils/index.ts +12 -1
- package/src/utils/initializer/mongodbCSFLE.ts +224 -0
- package/src/utils/initializer/registerPlugins.ts +45 -10
|
@@ -32,6 +32,7 @@ const utils_1 = require("../../monitoring/utils");
|
|
|
32
32
|
const machines_1 = require("../../utils/roles/machines");
|
|
33
33
|
const utils_2 = require("../../utils/roles/machines/utils");
|
|
34
34
|
const monitoring_1 = require("../monitoring");
|
|
35
|
+
const constants_1 = require("../../constants");
|
|
35
36
|
const model_1 = require("./model");
|
|
36
37
|
const utils_3 = require("./utils");
|
|
37
38
|
//TODO aggiungere no-sql inject security
|
|
@@ -333,8 +334,9 @@ const areUpdatedFieldsAllowed = (filtered, updated, updatedPaths) => {
|
|
|
333
334
|
return (0, isEqual_1.default)(filtered, updated);
|
|
334
335
|
return updatedPaths.every((path) => (0, isEqual_1.default)((0, get_1.default)(filtered, path), (0, get_1.default)(updated, path)));
|
|
335
336
|
};
|
|
336
|
-
const getOperators = (
|
|
337
|
+
const getOperators = (mongo, { rules, dbName, collName, user, run_as_system, monitoringOrigin }) => {
|
|
337
338
|
var _a, _b;
|
|
339
|
+
const collection = mongo.client.db(dbName).collection(collName);
|
|
338
340
|
const normalizedRules = rules !== null && rules !== void 0 ? rules : {};
|
|
339
341
|
const collectionRules = normalizedRules[collName];
|
|
340
342
|
const filters = (_a = collectionRules === null || collectionRules === void 0 ? void 0 : collectionRules.filters) !== null && _a !== void 0 ? _a : [];
|
|
@@ -852,6 +854,7 @@ const getOperators = (collection, { rules, collName, user, run_as_system, monito
|
|
|
852
854
|
* This allows fine-grained control over what change events a user can observe, based on roles and filters.
|
|
853
855
|
*/
|
|
854
856
|
watch: (pipelineOrOptions = [], options) => {
|
|
857
|
+
const changestreamCollection = mongo[constants_1.CHANGESTREAM].client.db(dbName).collection(collName);
|
|
855
858
|
try {
|
|
856
859
|
const { pipeline, options: watchOptions, extraMatches } = resolveWatchArgs(pipelineOrOptions, options);
|
|
857
860
|
if (!run_as_system) {
|
|
@@ -867,7 +870,7 @@ const getOperators = (collection, { rules, collName, user, run_as_system, monito
|
|
|
867
870
|
}
|
|
868
871
|
: undefined;
|
|
869
872
|
const formattedPipeline = [firstStep, ...extraMatches, ...pipeline].filter(Boolean);
|
|
870
|
-
const result =
|
|
873
|
+
const result = changestreamCollection.watch(formattedPipeline, watchOptions);
|
|
871
874
|
const originalOn = result.on.bind(result);
|
|
872
875
|
/**
|
|
873
876
|
* Validates a change event against the user's roles.
|
|
@@ -917,7 +920,7 @@ const getOperators = (collection, { rules, collName, user, run_as_system, monito
|
|
|
917
920
|
return result;
|
|
918
921
|
}
|
|
919
922
|
// System mode: no filtering applied
|
|
920
|
-
const result =
|
|
923
|
+
const result = changestreamCollection.watch([...extraMatches, ...pipeline], watchOptions);
|
|
921
924
|
emitMongoEvent('watch');
|
|
922
925
|
return result;
|
|
923
926
|
}
|
|
@@ -1138,11 +1141,10 @@ const MongodbAtlas = (app, { rules, user, run_as_system, monitoring } = {}) => (
|
|
|
1138
1141
|
db: (dbName) => {
|
|
1139
1142
|
return {
|
|
1140
1143
|
collection: (collName) => {
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
return getOperators(collection, {
|
|
1144
|
-
rules,
|
|
1144
|
+
return getOperators(app.mongo, {
|
|
1145
|
+
dbName,
|
|
1145
1146
|
collName,
|
|
1147
|
+
rules,
|
|
1146
1148
|
user,
|
|
1147
1149
|
run_as_system,
|
|
1148
1150
|
monitoringOrigin: monitoring === null || monitoring === void 0 ? void 0 : monitoring.invokedFrom
|
|
@@ -22,10 +22,11 @@ export type GetValidRuleParams<T extends Role | Filter> = {
|
|
|
22
22
|
record?: WithId<Document> | Document | null;
|
|
23
23
|
};
|
|
24
24
|
type Method<T extends keyof Collection<Document>> = Collection<Document>[T];
|
|
25
|
-
export type GetOperatorsFunction = (
|
|
25
|
+
export type GetOperatorsFunction = (mongoInstance: FastifyInstance["mongo"], { rules, dbName, collName, user, run_as_system, monitoringOrigin }: {
|
|
26
26
|
user?: User;
|
|
27
27
|
rules?: Rules;
|
|
28
28
|
run_as_system?: boolean;
|
|
29
|
+
dbName: string;
|
|
29
30
|
collName: string;
|
|
30
31
|
monitoringOrigin?: string;
|
|
31
32
|
}) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../../src/services/mongodb-atlas/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AACzC,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,UAAU,EACV,QAAQ,EACR,UAAU,EACV,uBAAuB,EACvB,cAAc,EACd,WAAW,EACX,MAAM,IAAI,WAAW,EACrB,YAAY,EACZ,MAAM,EACP,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AACtC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAA;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,6BAA6B,CAAA;AAElD,MAAM,MAAM,oBAAoB,GAAG,CACjC,GAAG,EAAE,eAAe,EACpB,EACE,KAAK,EACL,IAAI,EACJ,aAAa,EACb,UAAU,EACX,EAAE;IACD,IAAI,CAAC,EAAE,IAAI,CAAA;IACX,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,UAAU,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CACtC,KACE;IACH,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK;QACtB,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,UAAU,CAAC,oBAAoB,CAAC,CAAA;KACnE,CAAA;IACD,YAAY,EAAE,CAAC,OAAO,CAAC,EAAE,oBAAoB,KAAK,aAAa,CAAA;CAChE,CAAA;AAED,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,IAAI,GAAG,MAAM,IAAI;IACxD,OAAO,EAAE,CAAC,EAAE,CAAA;IACZ,IAAI,EAAE,IAAI,CAAA;IACV,MAAM,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,QAAQ,GAAG,IAAI,CAAA;CAC5C,CAAA;AACD,KAAK,MAAM,CAAC,CAAC,SAAS,MAAM,UAAU,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;AAE3E,MAAM,MAAM,oBAAoB,GAAG,CACjC,
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../../src/services/mongodb-atlas/model.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,eAAe,GAAI,UAAU,MAAM,WAAuC,CAAA;AACvF,eAAO,MAAM,eAAe,GAAI,UAAU,MAAM,KACL,OAAO,CAAA;AAElD,eAAO,MAAM,uBAAuB,GAAI,KAAK,MAAM,KAAG,MAAM,EAQ3D,CAAA"}
|
package/dist/utils/index.js
CHANGED
|
@@ -3,9 +3,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.readJsonContent = exports.readFileContent = void 0;
|
|
7
|
-
const
|
|
8
|
-
const
|
|
6
|
+
exports.recursivelyCollectFiles = exports.readJsonContent = exports.readFileContent = void 0;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const readFileContent = (filePath) => node_fs_1.default.readFileSync(filePath, 'utf-8');
|
|
9
10
|
exports.readFileContent = readFileContent;
|
|
10
11
|
const readJsonContent = (filePath) => JSON.parse((0, exports.readFileContent)(filePath));
|
|
11
12
|
exports.readJsonContent = readJsonContent;
|
|
13
|
+
const recursivelyCollectFiles = (dir) => {
|
|
14
|
+
return node_fs_1.default.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
|
|
15
|
+
const fullPath = node_path_1.default.join(dir, entry.name);
|
|
16
|
+
if (entry.isDirectory()) {
|
|
17
|
+
return (0, exports.recursivelyCollectFiles)(fullPath);
|
|
18
|
+
}
|
|
19
|
+
return entry.isFile() ? [fullPath] : [];
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
exports.recursivelyCollectFiles = recursivelyCollectFiles;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { UUID, type Document, type AWSEncryptionKeyOptions, type AWSKMSProviderConfiguration, type AzureEncryptionKeyOptions, type AzureKMSProviderConfiguration, type GCPKMSProviderConfiguration, type GCPEncryptionKeyOptions, type KMIPKMSProviderConfiguration, type KMIPEncryptionKeyOptions, type LocalKMSProviderConfiguration, type AutoEncryptionExtraOptions, type AutoEncryptionOptions } from "mongodb";
|
|
2
|
+
import { type EncryptionSchemas } from "../../features/encryption/interface";
|
|
3
|
+
type KMSProviderConfig = {
|
|
4
|
+
/**
|
|
5
|
+
* The alias of the key. It must be referenced in the schema map
|
|
6
|
+
* to select which key to use for encryption.
|
|
7
|
+
*/
|
|
8
|
+
keyAlias: string;
|
|
9
|
+
/**
|
|
10
|
+
* KMS Provider name.
|
|
11
|
+
*/
|
|
12
|
+
provider: "aws";
|
|
13
|
+
/**
|
|
14
|
+
* KMS Provider specific authorization configuration.
|
|
15
|
+
*/
|
|
16
|
+
config: AWSKMSProviderConfiguration;
|
|
17
|
+
/**
|
|
18
|
+
* Configuration of the master key.
|
|
19
|
+
*/
|
|
20
|
+
masterKey: AWSEncryptionKeyOptions;
|
|
21
|
+
} | {
|
|
22
|
+
keyAlias: string;
|
|
23
|
+
provider: "azure";
|
|
24
|
+
config: AzureKMSProviderConfiguration;
|
|
25
|
+
masterKey: AzureEncryptionKeyOptions;
|
|
26
|
+
} | {
|
|
27
|
+
keyAlias: string;
|
|
28
|
+
provider: "gcp";
|
|
29
|
+
config: GCPKMSProviderConfiguration;
|
|
30
|
+
masterKey: GCPEncryptionKeyOptions;
|
|
31
|
+
} | {
|
|
32
|
+
keyAlias: string;
|
|
33
|
+
provider: "kmip";
|
|
34
|
+
config: KMIPKMSProviderConfiguration;
|
|
35
|
+
masterKey: KMIPEncryptionKeyOptions;
|
|
36
|
+
} | {
|
|
37
|
+
keyAlias: string;
|
|
38
|
+
provider: "local";
|
|
39
|
+
config: LocalKMSProviderConfiguration;
|
|
40
|
+
};
|
|
41
|
+
export type MongoDbEncryptionConfig = {
|
|
42
|
+
kmsProviders: KMSProviderConfig[];
|
|
43
|
+
/**
|
|
44
|
+
* The Key Vault database name
|
|
45
|
+
* @default encryption
|
|
46
|
+
*/
|
|
47
|
+
keyVaultDb?: string;
|
|
48
|
+
/**
|
|
49
|
+
* The Key Vault database collection
|
|
50
|
+
* @default __keyVault
|
|
51
|
+
*/
|
|
52
|
+
keyVaultCollection?: string;
|
|
53
|
+
extraOptions?: AutoEncryptionExtraOptions;
|
|
54
|
+
};
|
|
55
|
+
type DataKey = {
|
|
56
|
+
dataKeyId: UUID;
|
|
57
|
+
dataKeyAlias: string;
|
|
58
|
+
};
|
|
59
|
+
export declare const buildSchemaMap: (schemas: EncryptionSchemas, dataKeys: DataKey[]) => Record<string, Document>;
|
|
60
|
+
/**
|
|
61
|
+
* Setup MongoDB Client-Side Field Level Encryption (CSFLE).
|
|
62
|
+
* @see https://www.mongodb.com/docs/manual/core/csfle
|
|
63
|
+
*/
|
|
64
|
+
export declare const setupMongoDbCSFLE: (config: MongoDbEncryptionConfig & {
|
|
65
|
+
mongodbUrl: string;
|
|
66
|
+
schemas?: EncryptionSchemas;
|
|
67
|
+
}) => Promise<AutoEncryptionOptions>;
|
|
68
|
+
export {};
|
|
69
|
+
//# sourceMappingURL=mongodbCSFLE.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mongodbCSFLE.d.ts","sourceRoot":"","sources":["../../../src/utils/initializer/mongodbCSFLE.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,IAAI,EAEJ,KAAK,QAAQ,EACb,KAAK,uBAAuB,EAC5B,KAAK,2BAA2B,EAChC,KAAK,yBAAyB,EAC9B,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,KAAK,uBAAuB,EAC5B,KAAK,4BAA4B,EACjC,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,EAClC,KAAK,0BAA0B,EAE/B,KAAK,qBAAqB,EAC3B,MAAM,SAAS,CAAC;AACjB,OAAO,EAAoF,KAAK,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAG/J,KAAK,iBAAiB,GAClB;IACA;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;OAEG;IACH,QAAQ,EAAE,KAAK,CAAA;IACf;;OAEG;IACH,MAAM,EAAE,2BAA2B,CAAA;IACnC;;OAEG;IACH,SAAS,EAAE,uBAAuB,CAAA;CACnC,GAAG;IACF,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,6BAA6B,CAAC;IACtC,SAAS,EAAE,yBAAyB,CAAA;CACrC,GAAG;IACF,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,KAAK,CAAA;IACf,MAAM,EAAE,2BAA2B,CAAC;IACpC,SAAS,EAAE,uBAAuB,CAAA;CACnC,GAAG;IACF,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,4BAA4B,CAAC;IACrC,SAAS,EAAE,wBAAwB,CAAA;CACpC,GAAG;IACF,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,6BAA6B,CAAC;CACvC,CAAA;AAEH,MAAM,MAAM,uBAAuB,GAAG;IACpC,YAAY,EAAE,iBAAiB,EAAE,CAAC;IAClC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;KAGC;IACD,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,YAAY,CAAC,EAAE,0BAA0B,CAAA;CAC1C,CAAA;AAOD,KAAK,OAAO,GAAG;IAAE,SAAS,EAAE,IAAI,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAA;AAkFxD,eAAO,MAAM,cAAc,GAAI,SAAS,iBAAiB,EAAE,UAAU,OAAO,EAAE,6BAK7E,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,uBAAuB,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,iBAAiB,CAAA;CAAE,KACpF,OAAO,CAAC,qBAAqB,CA8C/B,CAAA"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.setupMongoDbCSFLE = exports.buildSchemaMap = void 0;
|
|
13
|
+
const mongodb_1 = require("mongodb");
|
|
14
|
+
const constants_1 = require("../../constants");
|
|
15
|
+
function ensureUniqueKeyAltNameIndex(db, config) {
|
|
16
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
17
|
+
yield db.collection(config.keyVaultCollection).createIndex({ keyAltNames: 1 }, {
|
|
18
|
+
unique: true,
|
|
19
|
+
partialFilterExpression: { keyAltNames: { $exists: true } },
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Ensure provided KMS Providers DEK keys exist in the key vault. If not, they are created.
|
|
25
|
+
*/
|
|
26
|
+
function ensureDataEncryptionKeys(clientEncryption, keyVaultDb, config) {
|
|
27
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28
|
+
const keys = [];
|
|
29
|
+
for (const kmsProvider of config.kmsProviders) {
|
|
30
|
+
const existingKey = yield keyVaultDb.collection(config.keyVaultCollection).findOne({
|
|
31
|
+
keyAltNames: kmsProvider.keyAlias,
|
|
32
|
+
});
|
|
33
|
+
if ((existingKey === null || existingKey === void 0 ? void 0 : existingKey._id) instanceof mongodb_1.Binary) {
|
|
34
|
+
keys.push({ dataKeyId: existingKey._id, dataKeyAlias: kmsProvider.keyAlias });
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const dataKeyId = yield clientEncryption.createDataKey(kmsProvider.provider, {
|
|
38
|
+
masterKey: "masterKey" in kmsProvider ? kmsProvider.masterKey : undefined,
|
|
39
|
+
keyAltNames: [kmsProvider.keyAlias],
|
|
40
|
+
});
|
|
41
|
+
console.log(`[MongoDB Encryption] Created new key with alias ${kmsProvider.keyAlias}`);
|
|
42
|
+
keys.push({ dataKeyId, dataKeyAlias: kmsProvider.keyAlias });
|
|
43
|
+
}
|
|
44
|
+
return keys;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Recursively resolve key aliases in an encryption schema to their corresponding key IDs.
|
|
49
|
+
*/
|
|
50
|
+
const resolveKeyAliases = (schema, dataKeys) => {
|
|
51
|
+
var _a, _b;
|
|
52
|
+
if ("encrypt" in schema) {
|
|
53
|
+
if (!schema.encrypt.keyAlias) {
|
|
54
|
+
return schema;
|
|
55
|
+
}
|
|
56
|
+
const keyId = (_a = dataKeys.find(k => k.dataKeyAlias === schema.encrypt.keyAlias)) === null || _a === void 0 ? void 0 : _a.dataKeyId;
|
|
57
|
+
if (!keyId) {
|
|
58
|
+
throw new Error(`Key with alias ${schema.encrypt.keyAlias} could not be found in the Key Vault.`);
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
encrypt: {
|
|
62
|
+
bsonType: schema.encrypt.bsonType,
|
|
63
|
+
algorithm: schema.encrypt.algorithm,
|
|
64
|
+
keyId: [keyId]
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const mappedSchema = {
|
|
69
|
+
bsonType: "object",
|
|
70
|
+
properties: Object.entries(schema.properties).reduce((acc, [property, config]) => {
|
|
71
|
+
acc[property] = resolveKeyAliases(config, dataKeys);
|
|
72
|
+
return acc;
|
|
73
|
+
}, {})
|
|
74
|
+
};
|
|
75
|
+
if (schema.encryptMetadata) {
|
|
76
|
+
const keyId = (_b = dataKeys.find(k => k.dataKeyAlias === schema.encryptMetadata.keyAlias)) === null || _b === void 0 ? void 0 : _b.dataKeyId;
|
|
77
|
+
if (!keyId) {
|
|
78
|
+
throw new Error(`Key with alias ${schema.encryptMetadata.keyAlias} could not be found in the Key Vault.`);
|
|
79
|
+
}
|
|
80
|
+
mappedSchema.encryptMetadata = { keyId: [keyId] };
|
|
81
|
+
}
|
|
82
|
+
return mappedSchema;
|
|
83
|
+
};
|
|
84
|
+
const buildSchemaMap = (schemas, dataKeys) => {
|
|
85
|
+
return Object.entries(schemas).reduce((acc, [key, schema]) => {
|
|
86
|
+
acc[key] = resolveKeyAliases(schema, dataKeys);
|
|
87
|
+
return acc;
|
|
88
|
+
}, {});
|
|
89
|
+
};
|
|
90
|
+
exports.buildSchemaMap = buildSchemaMap;
|
|
91
|
+
/**
|
|
92
|
+
* Setup MongoDB Client-Side Field Level Encryption (CSFLE).
|
|
93
|
+
* @see https://www.mongodb.com/docs/manual/core/csfle
|
|
94
|
+
*/
|
|
95
|
+
const setupMongoDbCSFLE = (config) => __awaiter(void 0, void 0, void 0, function* () {
|
|
96
|
+
var _a, _b;
|
|
97
|
+
if (config.kmsProviders.length === 0) {
|
|
98
|
+
throw new Error('At least one KMS Provider is required when using MongoDB encryption');
|
|
99
|
+
}
|
|
100
|
+
const requiredConfig = {
|
|
101
|
+
kmsProviders: config.kmsProviders,
|
|
102
|
+
keyVaultDb: (_a = config.keyVaultDb) !== null && _a !== void 0 ? _a : constants_1.DEFAULT_CONFIG.MONGODB_ENCRYPTION_CONFIG.keyVaultDb,
|
|
103
|
+
keyVaultCollection: (_b = config.keyVaultDb) !== null && _b !== void 0 ? _b : constants_1.DEFAULT_CONFIG.MONGODB_ENCRYPTION_CONFIG.keyVaultCollection,
|
|
104
|
+
};
|
|
105
|
+
const kmsProviders = requiredConfig.kmsProviders.reduce((acc, { provider, config }) => (Object.assign(Object.assign({}, acc), { [provider]: config })), {});
|
|
106
|
+
const keyVaultNamespace = `${requiredConfig.keyVaultDb}.${requiredConfig.keyVaultCollection}`;
|
|
107
|
+
const keyVaultClient = new mongodb_1.MongoClient(config.mongodbUrl, {
|
|
108
|
+
maxPoolSize: 1,
|
|
109
|
+
autoEncryption: {
|
|
110
|
+
keyVaultNamespace,
|
|
111
|
+
kmsProviders,
|
|
112
|
+
extraOptions: config.extraOptions
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
yield keyVaultClient.connect();
|
|
116
|
+
const keyVaultDb = keyVaultClient.db(requiredConfig.keyVaultDb);
|
|
117
|
+
yield ensureUniqueKeyAltNameIndex(keyVaultDb, requiredConfig);
|
|
118
|
+
const clientEncryption = new mongodb_1.ClientEncryption(keyVaultClient, {
|
|
119
|
+
keyVaultNamespace,
|
|
120
|
+
kmsProviders,
|
|
121
|
+
});
|
|
122
|
+
const dataKeys = yield ensureDataEncryptionKeys(clientEncryption, keyVaultDb, requiredConfig);
|
|
123
|
+
yield keyVaultClient.close();
|
|
124
|
+
return {
|
|
125
|
+
keyVaultNamespace,
|
|
126
|
+
kmsProviders,
|
|
127
|
+
schemaMap: config.schemas ? (0, exports.buildSchemaMap)(config.schemas, dataKeys) : undefined,
|
|
128
|
+
extraOptions: config.extraOptions
|
|
129
|
+
};
|
|
130
|
+
});
|
|
131
|
+
exports.setupMongoDbCSFLE = setupMongoDbCSFLE;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { FastifyInstance } from 'fastify';
|
|
2
2
|
import { CorsConfig } from '../../';
|
|
3
3
|
import { Functions } from '../../features/functions/interface';
|
|
4
|
+
import { EncryptionSchemas } from '../../features/encryption/interface';
|
|
5
|
+
import { MongoDbEncryptionConfig } from './mongodbCSFLE';
|
|
4
6
|
type RegisterFunction = FastifyInstance['register'];
|
|
5
7
|
type RegisterPluginsParams = {
|
|
6
8
|
register: RegisterFunction;
|
|
@@ -8,6 +10,8 @@ type RegisterPluginsParams = {
|
|
|
8
10
|
jwtSecret: string;
|
|
9
11
|
functionsList: Functions;
|
|
10
12
|
corsConfig?: CorsConfig;
|
|
13
|
+
encryptionSchemas?: EncryptionSchemas;
|
|
14
|
+
mongodbEncryptionConfig?: MongoDbEncryptionConfig;
|
|
11
15
|
};
|
|
12
16
|
/**
|
|
13
17
|
* > Used to register all plugins
|
|
@@ -16,6 +20,6 @@ type RegisterPluginsParams = {
|
|
|
16
20
|
* @param jwtSecret -> connection jwt
|
|
17
21
|
* @tested
|
|
18
22
|
*/
|
|
19
|
-
export declare const registerPlugins: ({ register, mongodbUrl, jwtSecret, functionsList, corsConfig }: RegisterPluginsParams) => Promise<void>;
|
|
23
|
+
export declare const registerPlugins: ({ register, mongodbUrl, jwtSecret, functionsList, corsConfig, mongodbEncryptionConfig, encryptionSchemas }: RegisterPluginsParams) => Promise<void>;
|
|
20
24
|
export {};
|
|
21
25
|
//# sourceMappingURL=registerPlugins.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registerPlugins.d.ts","sourceRoot":"","sources":["../../../src/utils/initializer/registerPlugins.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAEzC,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAOnC,OAAO,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAA;
|
|
1
|
+
{"version":3,"file":"registerPlugins.d.ts","sourceRoot":"","sources":["../../../src/utils/initializer/registerPlugins.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAEzC,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAOnC,OAAO,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAA;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAA;AAEvE,OAAO,EAAqB,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAE3E,KAAK,gBAAgB,GAAG,eAAe,CAAC,UAAU,CAAC,CAAA;AAGnD,KAAK,qBAAqB,GAAG;IAC3B,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,SAAS,CAAA;IACxB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC,uBAAuB,CAAC,EAAE,uBAAuB,CAAA;CAClD,CAAA;AAQD;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAU,4GAQnC,qBAAqB,kBAwBvB,CAAA"}
|
|
@@ -23,6 +23,7 @@ const controller_3 = require("../../auth/providers/custom-function/controller");
|
|
|
23
23
|
const controller_4 = require("../../auth/providers/local-userpass/controller");
|
|
24
24
|
const constants_1 = require("../../constants");
|
|
25
25
|
const plugin_1 = __importDefault(require("../../monitoring/plugin"));
|
|
26
|
+
const mongodbCSFLE_1 = require("./mongodbCSFLE");
|
|
26
27
|
/**
|
|
27
28
|
* > Used to register all plugins
|
|
28
29
|
* @param register -> the fastify register method
|
|
@@ -30,13 +31,15 @@ const plugin_1 = __importDefault(require("../../monitoring/plugin"));
|
|
|
30
31
|
* @param jwtSecret -> connection jwt
|
|
31
32
|
* @tested
|
|
32
33
|
*/
|
|
33
|
-
const registerPlugins = (_a) => __awaiter(void 0, [_a], void 0, function* ({ register, mongodbUrl, jwtSecret, functionsList, corsConfig }) {
|
|
34
|
+
const registerPlugins = (_a) => __awaiter(void 0, [_a], void 0, function* ({ register, mongodbUrl, jwtSecret, functionsList, corsConfig, mongodbEncryptionConfig, encryptionSchemas }) {
|
|
34
35
|
try {
|
|
35
36
|
const registersConfig = yield getRegisterConfig({
|
|
36
37
|
mongodbUrl,
|
|
37
38
|
jwtSecret,
|
|
38
39
|
corsConfig,
|
|
39
|
-
functionsList
|
|
40
|
+
functionsList,
|
|
41
|
+
mongodbEncryptionConfig,
|
|
42
|
+
encryptionSchemas
|
|
40
43
|
});
|
|
41
44
|
registersConfig.forEach(({ plugin, options, pluginName }) => {
|
|
42
45
|
try {
|
|
@@ -61,11 +64,14 @@ exports.registerPlugins = registerPlugins;
|
|
|
61
64
|
* @param jwtSecret -> connection jwt
|
|
62
65
|
* @testable
|
|
63
66
|
*/
|
|
64
|
-
const getRegisterConfig = (_a) => __awaiter(void 0, [_a], void 0, function* ({ mongodbUrl, jwtSecret, corsConfig }) {
|
|
67
|
+
const getRegisterConfig = (_a) => __awaiter(void 0, [_a], void 0, function* ({ mongodbUrl, jwtSecret, corsConfig, encryptionSchemas, mongodbEncryptionConfig, }) {
|
|
65
68
|
const corsOptions = corsConfig !== null && corsConfig !== void 0 ? corsConfig : {
|
|
66
69
|
origin: '*',
|
|
67
70
|
methods: ['POST', 'GET']
|
|
68
71
|
};
|
|
72
|
+
const autoEncryption = mongodbEncryptionConfig
|
|
73
|
+
? yield (0, mongodbCSFLE_1.setupMongoDbCSFLE)(Object.assign({ mongodbUrl, schemas: encryptionSchemas }, mongodbEncryptionConfig))
|
|
74
|
+
: undefined;
|
|
69
75
|
const baseConfig = [
|
|
70
76
|
{
|
|
71
77
|
pluginName: 'cors',
|
|
@@ -76,8 +82,24 @@ const getRegisterConfig = (_a) => __awaiter(void 0, [_a], void 0, function* ({ m
|
|
|
76
82
|
pluginName: 'fastifyMongodb',
|
|
77
83
|
plugin: mongodb_1.default,
|
|
78
84
|
options: {
|
|
85
|
+
url: mongodbUrl,
|
|
79
86
|
forceClose: true,
|
|
80
|
-
|
|
87
|
+
autoEncryption
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
/**
|
|
91
|
+
* When auto-encryption is active, add another MongoDB client with bypass for change streams.
|
|
92
|
+
* The $changeStream operator does not support automatic encryption, only decryption.
|
|
93
|
+
* @see https://www.mongodb.com/docs/manual/core/csfle/reference/supported-operations
|
|
94
|
+
*/
|
|
95
|
+
autoEncryption && {
|
|
96
|
+
pluginName: 'fastifyMongodb',
|
|
97
|
+
plugin: mongodb_1.default,
|
|
98
|
+
options: {
|
|
99
|
+
name: "changestream",
|
|
100
|
+
url: mongodbUrl,
|
|
101
|
+
forceClose: true,
|
|
102
|
+
autoEncryption: Object.assign(Object.assign({}, autoEncryption), { bypassAutoEncryption: true })
|
|
81
103
|
}
|
|
82
104
|
},
|
|
83
105
|
{
|
|
@@ -133,5 +155,5 @@ const getRegisterConfig = (_a) => __awaiter(void 0, [_a], void 0, function* ({ m
|
|
|
133
155
|
options: { basePath: '/monit' }
|
|
134
156
|
});
|
|
135
157
|
}
|
|
136
|
-
return baseConfig;
|
|
158
|
+
return baseConfig.filter(Boolean);
|
|
137
159
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowerforce/flowerbase",
|
|
3
|
-
"version": "1.7.6-beta.
|
|
3
|
+
"version": "1.7.6-beta.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"scripts": {
|
|
15
15
|
"test": "npx jest",
|
|
16
16
|
"build": "rm -rf dist/ && tsc",
|
|
17
|
-
"start": "node dist/src/index.ts"
|
|
17
|
+
"start": "node dist/src/index.ts",
|
|
18
|
+
"tsc:noemit": "tsc --noEmit"
|
|
18
19
|
},
|
|
19
20
|
"keywords": [],
|
|
20
21
|
"author": "",
|
|
@@ -30,6 +31,7 @@
|
|
|
30
31
|
"@fastify/swagger-ui": "^5.2.3",
|
|
31
32
|
"@fastify/websocket": "^11.2.0",
|
|
32
33
|
"bson": "^6.8.0",
|
|
34
|
+
"codemirror": "^5.65.16",
|
|
33
35
|
"dotenv": "^16.4.7",
|
|
34
36
|
"fastify": "^5.0.0",
|
|
35
37
|
"fastify-plugin": "^5.0.1",
|
|
@@ -32,10 +32,7 @@ export async function customFunctionController(app: FastifyInstance) {
|
|
|
32
32
|
app.post<LoginDto>(
|
|
33
33
|
AUTH_ENDPOINTS.LOGIN,
|
|
34
34
|
{
|
|
35
|
-
schema: LOGIN_SCHEMA
|
|
36
|
-
errorHandler: (_error, _request, reply) => {
|
|
37
|
-
reply.code(500).send({ message: 'Internal Server Error' })
|
|
38
|
-
}
|
|
35
|
+
schema: LOGIN_SCHEMA
|
|
39
36
|
},
|
|
40
37
|
async function (req, reply) {
|
|
41
38
|
const customFunctionProvider = AUTH_CONFIG.authProviders?.['custom-function']
|
|
@@ -82,6 +79,7 @@ export async function customFunctionController(app: FastifyInstance) {
|
|
|
82
79
|
}
|
|
83
80
|
}) as CustomFunctionAuthResult
|
|
84
81
|
|
|
82
|
+
|
|
85
83
|
if (!authResult.id) {
|
|
86
84
|
reply.code(401).send({ message: 'Unauthorized' })
|
|
87
85
|
return
|
|
@@ -130,7 +128,6 @@ export async function customFunctionController(app: FastifyInstance) {
|
|
|
130
128
|
...(user || {})
|
|
131
129
|
}
|
|
132
130
|
}
|
|
133
|
-
|
|
134
131
|
const refreshToken = this.createRefreshToken(currentUserData)
|
|
135
132
|
const refreshTokenHash = hashToken(refreshToken)
|
|
136
133
|
await authDb.collection(refreshTokensCollection).insertOne({
|
|
@@ -140,15 +137,12 @@ export async function customFunctionController(app: FastifyInstance) {
|
|
|
140
137
|
expiresAt: new Date(Date.now() + refreshTokenTtlMs),
|
|
141
138
|
revokedAt: null
|
|
142
139
|
})
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const responsePayload = {
|
|
146
|
-
access_token: accessToken,
|
|
140
|
+
return {
|
|
141
|
+
access_token: this.createAccessToken(currentUserData),
|
|
147
142
|
refresh_token: refreshToken,
|
|
148
143
|
device_id: '',
|
|
149
144
|
user_id: authUser._id.toString()
|
|
150
145
|
}
|
|
151
|
-
reply.code(200).send(responsePayload)
|
|
152
146
|
}
|
|
153
147
|
)
|
|
154
148
|
|
package/src/constants.ts
CHANGED
|
@@ -57,6 +57,10 @@ export const DEFAULT_CONFIG = {
|
|
|
57
57
|
CORS_OPTIONS: {
|
|
58
58
|
origin: "*",
|
|
59
59
|
methods: ["GET", "POST", "PUT", "DELETE"] as ALLOWED_METHODS[]
|
|
60
|
+
},
|
|
61
|
+
MONGODB_ENCRYPTION_CONFIG: {
|
|
62
|
+
keyVaultDb: "encryption",
|
|
63
|
+
keyVaultCollection: "__keyVault"
|
|
60
64
|
}
|
|
61
65
|
}
|
|
62
66
|
export const API_VERSION = `/api/client/${DEFAULT_CONFIG.API_VERSION}`
|
|
@@ -82,9 +86,14 @@ export const AUTH_CONFIG = {
|
|
|
82
86
|
}
|
|
83
87
|
}
|
|
84
88
|
|
|
85
|
-
|
|
86
|
-
|
|
87
89
|
export const S3_CONFIG = {
|
|
88
90
|
ACCESS_KEY_ID: process.env.S3_ACCESS_KEY_ID,
|
|
89
91
|
SECRET_ACCESS_KEY: process.env.S3_SECRET_ACCESS_KEY
|
|
90
92
|
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Name of the MongoDB client to use for change streams.
|
|
96
|
+
* This may be a separate instance because streams do not work
|
|
97
|
+
* when the main client has auto encryption enabled.
|
|
98
|
+
*/
|
|
99
|
+
export const CHANGESTREAM = "changestream"
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { UUID } from "mongodb"
|
|
2
|
+
|
|
3
|
+
export type EncryptionSchemaProperty =
|
|
4
|
+
| EncryptionSchema
|
|
5
|
+
| {
|
|
6
|
+
encrypt: {
|
|
7
|
+
algorithm: string
|
|
8
|
+
bsonType: string
|
|
9
|
+
keyAlias?: string
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type EncryptionSchema = {
|
|
14
|
+
bsonType: "object"
|
|
15
|
+
properties: Record<string, EncryptionSchemaProperty>
|
|
16
|
+
encryptMetadata?: {
|
|
17
|
+
keyAlias: string
|
|
18
|
+
},
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
export type MappedEncryptionSchemaProperty =
|
|
23
|
+
| MappedEncryptionSchema
|
|
24
|
+
| {
|
|
25
|
+
encrypt: {
|
|
26
|
+
algorithm: string
|
|
27
|
+
bsonType: string
|
|
28
|
+
keyId?: [UUID]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type MappedEncryptionSchema = {
|
|
33
|
+
bsonType: "object"
|
|
34
|
+
properties: Record<string, MappedEncryptionSchemaProperty>
|
|
35
|
+
encryptMetadata?: {
|
|
36
|
+
keyId: [UUID]
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type EncryptionSchemaFile = {
|
|
41
|
+
database: string
|
|
42
|
+
collection: string
|
|
43
|
+
schema: EncryptionSchema
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type EncryptionSchemas = Record<string, EncryptionSchema>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import path from "node:path"
|
|
2
|
+
import { readJsonContent, recursivelyCollectFiles } from "../../utils"
|
|
3
|
+
import { EncryptionSchemaFile, EncryptionSchemas } from "./interface"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @experimental
|
|
7
|
+
* Schemas used for Client-Side Level Encryption configuration.
|
|
8
|
+
*
|
|
9
|
+
* **Important:** These schemas do not perform JSON validation.
|
|
10
|
+
*/
|
|
11
|
+
export const loadEncryptionSchemas = async (rootDir = process.cwd()): Promise<EncryptionSchemas> => {
|
|
12
|
+
const schemasRoot = path.join(rootDir, 'data_sources', 'mongodb-atlas')
|
|
13
|
+
|
|
14
|
+
const files = recursivelyCollectFiles(schemasRoot)
|
|
15
|
+
const schemaFiles = files.filter((x) => x.endsWith('encryption.json'))
|
|
16
|
+
|
|
17
|
+
return schemaFiles.reduce((acc, filePath) => {
|
|
18
|
+
const { collection, database, schema } = readJsonContent(filePath) as EncryptionSchemaFile
|
|
19
|
+
acc[`${database}.${collection}`] = schema
|
|
20
|
+
return acc
|
|
21
|
+
}, {} as EncryptionSchemas)
|
|
22
|
+
}
|
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
import fs from 'fs'
|
|
2
1
|
import path from 'node:path'
|
|
3
|
-
import { readJsonContent } from '../../utils'
|
|
2
|
+
import { readJsonContent, recursivelyCollectFiles } from '../../utils'
|
|
4
3
|
import { Rules, RulesConfig } from './interface'
|
|
5
4
|
|
|
6
5
|
export const loadRules = async (rootDir = process.cwd()): Promise<Rules> => {
|
|
7
6
|
const rulesRoot = path.join(rootDir, 'data_sources', 'mongodb-atlas')
|
|
8
|
-
const recursivelyCollectFiles = (dir: string): string[] => {
|
|
9
|
-
return fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
|
|
10
|
-
const fullPath = path.join(dir, entry.name)
|
|
11
|
-
if (entry.isDirectory()) {
|
|
12
|
-
return recursivelyCollectFiles(fullPath)
|
|
13
|
-
}
|
|
14
|
-
return entry.isFile() ? [fullPath] : []
|
|
15
|
-
})
|
|
16
|
-
}
|
|
17
7
|
const files = recursivelyCollectFiles(rulesRoot)
|
|
18
8
|
const rulesFiles = files.filter((x) => (x as string).endsWith('rules.json'))
|
|
19
9
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AUTH_CONFIG, AUTH_DB_NAME } from '../../constants'
|
|
1
|
+
import { AUTH_CONFIG, AUTH_DB_NAME, CHANGESTREAM } from '../../constants'
|
|
2
2
|
import { services } from '../../services'
|
|
3
3
|
import { Function, Functions } from '../functions/interface'
|
|
4
4
|
import { ActivateTriggersParams } from './dtos'
|
|
@@ -18,6 +18,10 @@ export const activateTriggers = async ({
|
|
|
18
18
|
}: ActivateTriggersParams) => {
|
|
19
19
|
console.log('START ACTIVATION TRIGGERS')
|
|
20
20
|
try {
|
|
21
|
+
// Ensure the changestream MongoDB client exist, or use the main client
|
|
22
|
+
if (!fastify.mongo[CHANGESTREAM]) {
|
|
23
|
+
fastify.mongo[CHANGESTREAM] = fastify.mongo
|
|
24
|
+
}
|
|
21
25
|
const triggersToActivate = [...triggersList]
|
|
22
26
|
if (AUTH_CONFIG.on_user_creation_function_name) {
|
|
23
27
|
const alreadyDeclared = triggersToActivate.some(
|