@flowerforce/flowerbase 1.7.6-beta.0 → 1.7.6-beta.10
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/anon-user/controller.d.ts.map +1 -1
- package/dist/auth/providers/anon-user/controller.js +1 -0
- package/dist/auth/providers/custom-function/controller.d.ts.map +1 -1
- package/dist/auth/providers/custom-function/controller.js +6 -9
- package/dist/auth/providers/local-userpass/controller.d.ts.map +1 -1
- package/dist/auth/providers/local-userpass/controller.js +58 -18
- package/dist/auth/providers/local-userpass/dtos.d.ts +5 -1
- package/dist/auth/providers/local-userpass/dtos.d.ts.map +1 -1
- package/dist/auth/utils.d.ts +1 -0
- package/dist/auth/utils.d.ts.map +1 -1
- package/dist/auth/utils.js +1 -0
- 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/endpoints/utils.d.ts.map +1 -1
- package/dist/features/endpoints/utils.js +3 -0
- package/dist/features/functions/controller.d.ts +2 -0
- package/dist/features/functions/controller.d.ts.map +1 -1
- package/dist/features/functions/controller.js +7 -1
- package/dist/features/rules/interface.d.ts +6 -5
- package/dist/features/rules/interface.d.ts.map +1 -1
- 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/interface.d.ts +1 -1
- package/dist/features/triggers/interface.d.ts.map +1 -1
- package/dist/features/triggers/utils.d.ts.map +1 -1
- package/dist/features/triggers/utils.js +85 -33
- 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 +3 -0
- package/dist/services/mongodb-atlas/index.d.ts.map +1 -1
- package/dist/services/mongodb-atlas/index.js +136 -43
- package/dist/services/mongodb-atlas/model.d.ts +2 -1
- package/dist/services/mongodb-atlas/model.d.ts.map +1 -1
- package/dist/utils/context/helpers.d.ts.map +1 -1
- package/dist/utils/context/helpers.js +3 -2
- package/dist/utils/context/index.d.ts.map +1 -1
- package/dist/utils/context/index.js +4 -2
- 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/dist/utils/roles/helpers.d.ts.map +1 -1
- package/dist/utils/roles/helpers.js +6 -3
- package/dist/utils/roles/machines/fieldPermissions.d.ts.map +1 -1
- package/dist/utils/roles/machines/fieldPermissions.js +19 -10
- package/dist/utils/rules-matcher/interface.d.ts +2 -0
- package/dist/utils/rules-matcher/interface.d.ts.map +1 -1
- package/dist/utils/rules-matcher/interface.js +1 -0
- package/dist/utils/rules-matcher/utils.d.ts.map +1 -1
- package/dist/utils/rules-matcher/utils.js +23 -6
- package/package.json +4 -2
- package/src/auth/providers/anon-user/controller.ts +1 -0
- package/src/auth/providers/custom-function/controller.ts +10 -11
- package/src/auth/providers/local-userpass/__tests__/controller.test.ts +200 -0
- package/src/auth/providers/local-userpass/controller.ts +87 -34
- package/src/auth/providers/local-userpass/dtos.ts +6 -1
- package/src/auth/utils.ts +1 -0
- 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/endpoints/__tests__/utils.test.ts +65 -0
- package/src/features/endpoints/utils.ts +3 -0
- package/src/features/functions/__tests__/watch-filter.test.ts +11 -1
- package/src/features/functions/controller.ts +8 -0
- package/src/features/rules/interface.ts +18 -17
- package/src/features/rules/utils.ts +1 -11
- package/src/features/triggers/__tests__/index.test.ts +6 -4
- package/src/features/triggers/index.ts +5 -1
- package/src/features/triggers/interface.ts +1 -1
- package/src/features/triggers/utils.ts +86 -37
- 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 +3 -5
- 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/__tests__/realmCompatibility.test.ts +205 -7
- package/src/services/mongodb-atlas/__tests__/utils.test.ts +27 -0
- package/src/services/mongodb-atlas/__tests__/watch-filter.test.ts +78 -0
- package/src/services/mongodb-atlas/index.ts +379 -182
- package/src/services/mongodb-atlas/model.ts +3 -1
- package/src/types/fastify-raw-body.d.ts +0 -9
- package/src/utils/__tests__/checkIsValidFieldNameFn.test.ts +74 -5
- package/src/utils/__tests__/contextExecuteCompatibility.test.ts +27 -1
- package/src/utils/__tests__/evaluateExpression.test.ts +33 -0
- package/src/utils/__tests__/generateContextData.test.ts +5 -1
- package/src/utils/__tests__/mongodbCSFLE.test.ts +105 -0
- package/src/utils/__tests__/rule.test.ts +38 -0
- package/src/utils/context/helpers.ts +3 -2
- package/src/utils/context/index.ts +4 -3
- package/src/utils/index.ts +12 -1
- package/src/utils/initializer/mongodbCSFLE.ts +224 -0
- package/src/utils/initializer/registerPlugins.ts +45 -10
- package/src/utils/roles/helpers.ts +10 -5
- package/src/utils/roles/machines/fieldPermissions.ts +17 -8
- package/src/utils/rules-matcher/interface.ts +2 -0
- package/src/utils/rules-matcher/utils.ts +33 -17
- package/src/utils/__tests__/readFileContent.test.ts +0 -35
package/README.md
CHANGED
|
@@ -265,8 +265,132 @@ Example
|
|
|
265
265
|
```
|
|
266
266
|
If you're configuring the project from scratch, you can skip ahead to the [Build](#build) step.
|
|
267
267
|
|
|
268
|
-
|
|
268
|
+
## 🔐 7 Client-Side Field Level Encryption (CSFLE)
|
|
269
269
|
|
|
270
|
+
Flowerbase supports MongoDB Client-Side Field Level Encryption. When enabled, sensitive fields are encrypted by the MongoDB driver before writing to MongoDB and decrypted automatically when reading.
|
|
271
|
+
|
|
272
|
+
What Flowerbase does for you:
|
|
273
|
+
|
|
274
|
+
- Loads all `encryption.json` files under `data_sources/mongodb-atlas/**`.
|
|
275
|
+
- Builds the MongoDB `schemaMap` automatically from those files.
|
|
276
|
+
- Resolves each `keyAlias` in your schemas to a real Data Encryption Key (DEK) `keyId`.
|
|
277
|
+
- Ensures DEKs exist in the key vault (creates them if missing).
|
|
278
|
+
- Configures Fastify MongoDB plugin `autoEncryption` with the generated `schemaMap`.
|
|
279
|
+
|
|
280
|
+
### 1. Install encryption drivers
|
|
281
|
+
|
|
282
|
+
Refer to the official MongoDB documentation for CSFLE installation requirements: https://www.mongodb.com/docs/manual/core/csfle/install.
|
|
283
|
+
|
|
284
|
+
It is recommended to use the [**Automatic Encryption Shared Library**](https://www.mongodb.com/docs/manual/core/csfle/reference/install-library/?encryption-component=crypt_shared#std-label-csfle-reference-shared-library-download) instead of mongocryptd.
|
|
285
|
+
|
|
286
|
+
Note that the project should also install [mongodb-client-encryption](https://www.npmjs.com/package/mongodb-client-encryption), matching the mongodb driver version.
|
|
287
|
+
|
|
288
|
+
### 2. Add encryption schema files
|
|
289
|
+
|
|
290
|
+
Create one `encryption.json` per collection you want to encrypt:
|
|
291
|
+
|
|
292
|
+
Path example:
|
|
293
|
+
|
|
294
|
+
```text
|
|
295
|
+
src/data_sources/mongodb-atlas/<database>/<collection>/encryption.json
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Example:
|
|
299
|
+
|
|
300
|
+
```json
|
|
301
|
+
{
|
|
302
|
+
"database": "appDb",
|
|
303
|
+
"collection": "records",
|
|
304
|
+
"schema": {
|
|
305
|
+
"bsonType": "object",
|
|
306
|
+
"encryptMetadata": {
|
|
307
|
+
"keyAlias": "root-key"
|
|
308
|
+
},
|
|
309
|
+
"properties": {
|
|
310
|
+
"protectedField1": {
|
|
311
|
+
"encrypt": {
|
|
312
|
+
"bsonType": "string",
|
|
313
|
+
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
"protectedField2": {
|
|
317
|
+
"encrypt": {
|
|
318
|
+
"bsonType": "string",
|
|
319
|
+
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic",
|
|
320
|
+
"keyAlias": "deep-key"
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Notes:
|
|
329
|
+
|
|
330
|
+
- `encryptMetadata.keyAlias` applies as default key for that object level.
|
|
331
|
+
- `encrypt.keyAlias` overrides key selection for a specific field.
|
|
332
|
+
- If a field has `encrypt` but no `keyAlias`, MongoDB uses nearest `encryptMetadata`.
|
|
333
|
+
|
|
334
|
+
### 3. Pass `mongodbEncryptionConfig` to `initialize()`
|
|
335
|
+
|
|
336
|
+
`initialize()` accepts `mongodbEncryptionConfig` to configure KMS providers and key vault settings.
|
|
337
|
+
|
|
338
|
+
#### Local KMS provider example (development)
|
|
339
|
+
|
|
340
|
+
```ts
|
|
341
|
+
import { initialize } from "@flowerforce/flowerbase";
|
|
342
|
+
|
|
343
|
+
await initialize({
|
|
344
|
+
projectId: "my-project-id",
|
|
345
|
+
mongodbUrl: process.env.MONGODB_URL,
|
|
346
|
+
jwtSecret: process.env.JWT_SECRET,
|
|
347
|
+
mongodbEncryptionConfig: {
|
|
348
|
+
kmsProviders: [
|
|
349
|
+
{
|
|
350
|
+
provider: "local",
|
|
351
|
+
keyAlias: "root-key",
|
|
352
|
+
config: {
|
|
353
|
+
// 96-byte local master key encoded as base64
|
|
354
|
+
key: process.env.LOCAL_MASTER_KEY_BASE64,
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
provider: "local",
|
|
359
|
+
keyAlias: "deep-key",
|
|
360
|
+
config: { key: process.env.LOCAL_MASTER_KEY_BASE64 },
|
|
361
|
+
},
|
|
362
|
+
],
|
|
363
|
+
keyVaultDb: "encryption",
|
|
364
|
+
keyVaultCollection: "__keyVault",
|
|
365
|
+
extraOptions: {
|
|
366
|
+
// Optional: path to crypt shared library
|
|
367
|
+
// cryptSharedLibPath: '/opt/mongo_crypt_v1/lib/mongo_crypt_v1.so'
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
});
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
#### AWS KMS provider example
|
|
374
|
+
|
|
375
|
+
```ts
|
|
376
|
+
mongodbEncryptionConfig: {
|
|
377
|
+
kmsProviders: [
|
|
378
|
+
{
|
|
379
|
+
provider: "aws",
|
|
380
|
+
keyAlias: "root-key",
|
|
381
|
+
config: {
|
|
382
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
383
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
|
384
|
+
},
|
|
385
|
+
masterKey: {
|
|
386
|
+
key: process.env.AWS_KMS_KEY_ARN,
|
|
387
|
+
region: process.env.AWS_REGION,
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
];
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
---
|
|
270
394
|
|
|
271
395
|
<a id="migration"></a>
|
|
272
396
|
## 🔄 [Migration Guide](#migration) - Migrating Your Realm Project
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/anon-user/controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAOzC;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/anon-user/controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAOzC;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,eAAe,iBAyE5D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/custom-function/controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAUzC;;;;GAIG;AACH,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/custom-function/controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAUzC;;;;GAIG;AACH,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,eAAe,iBA0IlE"}
|
|
@@ -38,10 +38,7 @@ function customFunctionController(app) {
|
|
|
38
38
|
* @returns {Promise<Object>} A promise resolving with access and refresh tokens.
|
|
39
39
|
*/
|
|
40
40
|
app.post(utils_1.AUTH_ENDPOINTS.LOGIN, {
|
|
41
|
-
schema: schema_1.LOGIN_SCHEMA
|
|
42
|
-
errorHandler: (_error, _request, reply) => {
|
|
43
|
-
reply.code(500).send({ message: 'Internal Server Error' });
|
|
44
|
-
}
|
|
41
|
+
schema: schema_1.LOGIN_SCHEMA
|
|
45
42
|
}, function (req, reply) {
|
|
46
43
|
return __awaiter(this, void 0, void 0, function* () {
|
|
47
44
|
var _a, _b, _c;
|
|
@@ -114,23 +111,23 @@ function customFunctionController(app) {
|
|
|
114
111
|
user_data: Object.assign(Object.assign({}, (user || {})), { id: authUser._id.toString(), email: authUser.email }),
|
|
115
112
|
custom_data: Object.assign({}, (user || {}))
|
|
116
113
|
};
|
|
114
|
+
const now = new Date();
|
|
117
115
|
const refreshToken = this.createRefreshToken(currentUserData);
|
|
118
116
|
const refreshTokenHash = (0, crypto_1.hashToken)(refreshToken);
|
|
119
117
|
yield authDb.collection(refreshTokensCollection).insertOne({
|
|
120
118
|
userId: authUser._id,
|
|
121
119
|
tokenHash: refreshTokenHash,
|
|
122
|
-
createdAt:
|
|
120
|
+
createdAt: now,
|
|
123
121
|
expiresAt: new Date(Date.now() + refreshTokenTtlMs),
|
|
124
122
|
revokedAt: null
|
|
125
123
|
});
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
access_token:
|
|
124
|
+
yield authDb.collection(authCollection).updateOne({ _id: authUser._id }, { $set: { lastLoginAt: now } });
|
|
125
|
+
return {
|
|
126
|
+
access_token: this.createAccessToken(currentUserData),
|
|
129
127
|
refresh_token: refreshToken,
|
|
130
128
|
device_id: '',
|
|
131
129
|
user_id: authUser._id.toString()
|
|
132
130
|
};
|
|
133
|
-
reply.code(200).send(responsePayload);
|
|
134
131
|
});
|
|
135
132
|
});
|
|
136
133
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/local-userpass/controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/local-userpass/controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AA4CzC;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,eAAe,iBAmajE"}
|
|
@@ -49,14 +49,22 @@ function localUserPassController(app) {
|
|
|
49
49
|
const resetMaxAttempts = constants_1.DEFAULT_CONFIG.AUTH_RESET_MAX_ATTEMPTS;
|
|
50
50
|
const refreshTokenTtlMs = constants_1.DEFAULT_CONFIG.REFRESH_TOKEN_TTL_DAYS * 24 * 60 * 60 * 1000;
|
|
51
51
|
const resolveLocalUserpassProvider = () => { var _a; return (_a = constants_1.AUTH_CONFIG.authProviders) === null || _a === void 0 ? void 0 : _a['local-userpass']; };
|
|
52
|
+
const invalidPasswordError = {
|
|
53
|
+
error: 'unauthorized',
|
|
54
|
+
error_code: 'InvalidPassword'
|
|
55
|
+
};
|
|
52
56
|
try {
|
|
53
|
-
yield authDb
|
|
57
|
+
yield authDb
|
|
58
|
+
.collection(resetPasswordCollection)
|
|
59
|
+
.createIndex({ createdAt: 1 }, { expireAfterSeconds: resetPasswordTtlSeconds });
|
|
54
60
|
}
|
|
55
61
|
catch (error) {
|
|
56
62
|
console.error('Failed to ensure reset password TTL index', error);
|
|
57
63
|
}
|
|
58
64
|
try {
|
|
59
|
-
yield authDb
|
|
65
|
+
yield authDb
|
|
66
|
+
.collection(refreshTokensCollection)
|
|
67
|
+
.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 });
|
|
60
68
|
}
|
|
61
69
|
catch (error) {
|
|
62
70
|
console.error('Failed to ensure refresh token TTL index', error);
|
|
@@ -80,8 +88,10 @@ function localUserPassController(app) {
|
|
|
80
88
|
const services = state_1.StateManager.select('services');
|
|
81
89
|
const currentFunction = functionsList[resetPasswordConfig.resetFunctionName];
|
|
82
90
|
const baseArgs = { token, tokenId, email, password, username: email };
|
|
83
|
-
const args = Array.isArray(extraArguments)
|
|
84
|
-
|
|
91
|
+
const args = Array.isArray(extraArguments)
|
|
92
|
+
? [baseArgs, ...extraArguments]
|
|
93
|
+
: [baseArgs];
|
|
94
|
+
const response = (yield (0, context_1.GenerateContext)({
|
|
85
95
|
args,
|
|
86
96
|
app,
|
|
87
97
|
rules: {},
|
|
@@ -89,10 +99,32 @@ function localUserPassController(app) {
|
|
|
89
99
|
currentFunction,
|
|
90
100
|
functionName: resetPasswordConfig.resetFunctionName,
|
|
91
101
|
functionsList,
|
|
92
|
-
services
|
|
93
|
-
|
|
94
|
-
|
|
102
|
+
services,
|
|
103
|
+
runAsSystem: true
|
|
104
|
+
}));
|
|
105
|
+
const resetStatus = response === null || response === void 0 ? void 0 : response.status;
|
|
106
|
+
if (resetStatus === 'success') {
|
|
107
|
+
if (!password) {
|
|
108
|
+
throw new Error(utils_1.AUTH_ERRORS.INVALID_RESET_FUNCTION_RESPONSE);
|
|
109
|
+
}
|
|
110
|
+
const hashedPassword = yield (0, crypto_1.hashPassword)(password);
|
|
111
|
+
yield authDb.collection(authCollection).updateOne({ email }, {
|
|
112
|
+
$set: {
|
|
113
|
+
password: hashedPassword
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
yield (authDb === null || authDb === void 0 ? void 0 : authDb.collection(resetPasswordCollection).deleteOne({ email }));
|
|
117
|
+
return { status: 'success' };
|
|
118
|
+
}
|
|
119
|
+
if (resetStatus === 'pending') {
|
|
120
|
+
return { status: 'pending' };
|
|
121
|
+
}
|
|
122
|
+
if (resetStatus === 'fail') {
|
|
123
|
+
throw new Error(utils_1.AUTH_ERRORS.INVALID_RESET_PARAMS);
|
|
124
|
+
}
|
|
125
|
+
throw new Error(utils_1.AUTH_ERRORS.INVALID_RESET_FUNCTION_RESPONSE);
|
|
95
126
|
}
|
|
127
|
+
return { status: 'pending' };
|
|
96
128
|
});
|
|
97
129
|
/**
|
|
98
130
|
* Endpoint for user registration.
|
|
@@ -116,13 +148,17 @@ function localUserPassController(app) {
|
|
|
116
148
|
}
|
|
117
149
|
let result;
|
|
118
150
|
try {
|
|
119
|
-
result = yield (0, handleUserRegistration_1.default)(app, {
|
|
151
|
+
result = yield (0, handleUserRegistration_1.default)(app, {
|
|
152
|
+
run_as_system: true,
|
|
153
|
+
provider: handleUserRegistration_model_1.PROVIDER.LOCAL_USERPASS
|
|
154
|
+
})({
|
|
120
155
|
email: req.body.email.toLowerCase(),
|
|
121
156
|
password: req.body.password
|
|
122
157
|
});
|
|
123
158
|
}
|
|
124
159
|
catch (error) {
|
|
125
|
-
if (error instanceof Error &&
|
|
160
|
+
if (error instanceof Error &&
|
|
161
|
+
error.message === 'This email address is already used') {
|
|
126
162
|
res.status(409).send({
|
|
127
163
|
error: 'name already in use',
|
|
128
164
|
error_code: 'AccountNameInUse'
|
|
@@ -157,10 +193,10 @@ function localUserPassController(app) {
|
|
|
157
193
|
res.status(429).send({ message: 'Too many requests' });
|
|
158
194
|
return;
|
|
159
195
|
}
|
|
160
|
-
const existing = yield authDb.collection(authCollection).findOne({
|
|
196
|
+
const existing = (yield authDb.collection(authCollection).findOne({
|
|
161
197
|
confirmationToken: req.body.token,
|
|
162
198
|
confirmationTokenId: req.body.tokenId
|
|
163
|
-
});
|
|
199
|
+
}));
|
|
164
200
|
if (!existing) {
|
|
165
201
|
res.status(500);
|
|
166
202
|
throw new Error(utils_1.AUTH_ERRORS.INVALID_TOKEN);
|
|
@@ -198,11 +234,13 @@ function localUserPassController(app) {
|
|
|
198
234
|
email: req.body.username
|
|
199
235
|
});
|
|
200
236
|
if (!authUser) {
|
|
201
|
-
|
|
237
|
+
res.status(401);
|
|
238
|
+
return invalidPasswordError;
|
|
202
239
|
}
|
|
203
240
|
const passwordMatches = yield (0, crypto_1.comparePassword)(req.body.password, authUser.password);
|
|
204
241
|
if (!passwordMatches) {
|
|
205
|
-
|
|
242
|
+
res.status(401);
|
|
243
|
+
return invalidPasswordError;
|
|
206
244
|
}
|
|
207
245
|
const user = user_id_field && userCollection
|
|
208
246
|
? yield customUserDb
|
|
@@ -214,15 +252,19 @@ function localUserPassController(app) {
|
|
|
214
252
|
if (authUser && authUser.status !== 'confirmed') {
|
|
215
253
|
throw new Error(utils_1.AUTH_ERRORS.USER_NOT_CONFIRMED);
|
|
216
254
|
}
|
|
255
|
+
const now = new Date();
|
|
217
256
|
const refreshToken = this.createRefreshToken(userWithCustomData);
|
|
218
257
|
const refreshTokenHash = (0, crypto_1.hashToken)(refreshToken);
|
|
219
258
|
yield authDb.collection(refreshTokensCollection).insertOne({
|
|
220
259
|
userId: authUser._id,
|
|
221
260
|
tokenHash: refreshTokenHash,
|
|
222
|
-
createdAt:
|
|
261
|
+
createdAt: now,
|
|
223
262
|
expiresAt: new Date(Date.now() + refreshTokenTtlMs),
|
|
224
263
|
revokedAt: null
|
|
225
264
|
});
|
|
265
|
+
yield authDb
|
|
266
|
+
.collection(authCollection)
|
|
267
|
+
.updateOne({ _id: authUser._id }, { $set: { lastLoginAt: now } });
|
|
226
268
|
return {
|
|
227
269
|
access_token: this.createAccessToken(userWithCustomData),
|
|
228
270
|
refresh_token: refreshToken,
|
|
@@ -271,11 +313,9 @@ function localUserPassController(app) {
|
|
|
271
313
|
res.status(429);
|
|
272
314
|
return { message: 'Too many requests' };
|
|
273
315
|
}
|
|
274
|
-
yield handleResetPasswordRequest(req.body.email, req.body.password, req.body.arguments);
|
|
316
|
+
const result = yield handleResetPasswordRequest(req.body.email, req.body.password, req.body.arguments);
|
|
275
317
|
res.status(202);
|
|
276
|
-
return
|
|
277
|
-
status: 'ok'
|
|
278
|
-
};
|
|
318
|
+
return result;
|
|
279
319
|
});
|
|
280
320
|
});
|
|
281
321
|
/**
|
|
@@ -15,12 +15,16 @@ export type LoginSuccessDto = {
|
|
|
15
15
|
export type ErrorResponseDto = {
|
|
16
16
|
message: string;
|
|
17
17
|
};
|
|
18
|
+
export type InvalidPasswordResponseDto = {
|
|
19
|
+
error: 'unauthorized';
|
|
20
|
+
error_code: 'InvalidPassword';
|
|
21
|
+
};
|
|
18
22
|
export interface RegistrationDto {
|
|
19
23
|
Body: RegisterUserDto;
|
|
20
24
|
}
|
|
21
25
|
export interface LoginDto {
|
|
22
26
|
Body: LoginUserDto;
|
|
23
|
-
Reply: LoginSuccessDto | ErrorResponseDto;
|
|
27
|
+
Reply: LoginSuccessDto | ErrorResponseDto | InvalidPasswordResponseDto;
|
|
24
28
|
}
|
|
25
29
|
export interface ResetPasswordSendDto {
|
|
26
30
|
Body: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dtos.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/local-userpass/dtos.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,eAAe,CAAA;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE,eAAe,GAAG,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"dtos.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/local-userpass/dtos.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,0BAA0B,GAAG;IACvC,KAAK,EAAE,cAAc,CAAA;IACrB,UAAU,EAAE,iBAAiB,CAAA;CAC9B,CAAA;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,eAAe,CAAA;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE,eAAe,GAAG,gBAAgB,GAAG,0BAA0B,CAAA;CACvE;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;KACd,CAAA;CACF;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,CAAC,EAAE,OAAO,EAAE,CAAA;KACtB,CAAA;CACF;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,MAAM,CAAA;QACf,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;CACF;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;CACF"}
|
package/dist/auth/utils.d.ts
CHANGED
|
@@ -146,6 +146,7 @@ export declare enum AUTH_ERRORS {
|
|
|
146
146
|
INVALID_TOKEN = "Invalid refresh token provided",
|
|
147
147
|
INVALID_RESET_PARAMS = "Invalid token or tokenId provided",
|
|
148
148
|
MISSING_RESET_FUNCTION = "Missing reset function",
|
|
149
|
+
INVALID_RESET_FUNCTION_RESPONSE = "Invalid reset function response",
|
|
149
150
|
USER_NOT_CONFIRMED = "User not confirmed"
|
|
150
151
|
}
|
|
151
152
|
export interface AuthConfig {
|
package/dist/auth/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/auth/utils.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,cAAc;;;CAA4C,CAAC;AACxE,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;CAexB,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;CAc7B,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;CAgB7B,CAAA;AAED,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;CAWhC,CAAA;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;CAU/B,CAAA;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;;;;CAAoB,CAAA;AAE7C,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;CAe/B,CAAA;AAED,oBAAY,cAAc;IACxB,KAAK,WAAW;IAChB,YAAY,cAAc;IAC1B,OAAO,aAAa;IACpB,OAAO,aAAa;IACpB,OAAO,aAAa;IACpB,KAAK,gBAAgB;IACrB,UAAU,gBAAgB;IAC1B,aAAa,WAAW;IACxB,UAAU,sBAAsB;CACjC;AAED,oBAAY,WAAW;IACrB,mBAAmB,wBAAwB;IAC3C,aAAa,mCAAmC;IAChD,oBAAoB,sCAAsC;IAC1D,sBAAsB,2BAA2B;IACjD,kBAAkB,uBAAuB;CAC1C;AAED,MAAM,WAAW,UAAU;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE,aAAa,CAAA;IAC/B,iBAAiB,EAAE,cAAc,CAAA;IACjC,WAAW,CAAC,EAAE,QAAQ,CAAA;CACvB;AAED,UAAU,MAAM;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;CAClB;AACD,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE;QACN,kBAAkB,EAAE,MAAM,CAAA;KAC3B,CAAA;CACF;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,WAAW,CAAA;IACjB,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,MAAM;IACrB,WAAW,EAAE,OAAO,CAAA;IACpB,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,iBAAiB,EAAE,MAAM,CAAA;IACzB,gBAAgB,EAAE,MAAM,CAAA;IACxB,uBAAuB,EAAE,OAAO,CAAA;IAChC,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAA;IAChB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,aAAa,EAAE,MAAM,CAAA;IACrB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,8BAA8B,EAAE,MAAM,CAAA;CACvC;AAMD;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAO,UAuCjC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAO,oBAarC,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAI,eAAW,WAG3C,CAAA"}
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/auth/utils.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,cAAc;;;CAA4C,CAAC;AACxE,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;CAexB,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;CAc7B,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;CAgB7B,CAAA;AAED,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;CAWhC,CAAA;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;CAU/B,CAAA;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;;;;CAAoB,CAAA;AAE7C,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;CAe/B,CAAA;AAED,oBAAY,cAAc;IACxB,KAAK,WAAW;IAChB,YAAY,cAAc;IAC1B,OAAO,aAAa;IACpB,OAAO,aAAa;IACpB,OAAO,aAAa;IACpB,KAAK,gBAAgB;IACrB,UAAU,gBAAgB;IAC1B,aAAa,WAAW;IACxB,UAAU,sBAAsB;CACjC;AAED,oBAAY,WAAW;IACrB,mBAAmB,wBAAwB;IAC3C,aAAa,mCAAmC;IAChD,oBAAoB,sCAAsC;IAC1D,sBAAsB,2BAA2B;IACjD,+BAA+B,oCAAoC;IACnE,kBAAkB,uBAAuB;CAC1C;AAED,MAAM,WAAW,UAAU;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE,aAAa,CAAA;IAC/B,iBAAiB,EAAE,cAAc,CAAA;IACjC,WAAW,CAAC,EAAE,QAAQ,CAAA;CACvB;AAED,UAAU,MAAM;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;CAClB;AACD,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE;QACN,kBAAkB,EAAE,MAAM,CAAA;KAC3B,CAAA;CACF;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,WAAW,CAAA;IACjB,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,MAAM;IACrB,WAAW,EAAE,OAAO,CAAA;IACpB,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,iBAAiB,EAAE,MAAM,CAAA;IACzB,gBAAgB,EAAE,MAAM,CAAA;IACxB,uBAAuB,EAAE,OAAO,CAAA;IAChC,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAA;IAChB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,aAAa,EAAE,MAAM,CAAA;IACrB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,8BAA8B,EAAE,MAAM,CAAA;CACvC;AAMD;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAO,UAuCjC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAO,oBAarC,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAI,eAAW,WAG3C,CAAA"}
|
package/dist/auth/utils.js
CHANGED
|
@@ -115,6 +115,7 @@ var AUTH_ERRORS;
|
|
|
115
115
|
AUTH_ERRORS["INVALID_TOKEN"] = "Invalid refresh token provided";
|
|
116
116
|
AUTH_ERRORS["INVALID_RESET_PARAMS"] = "Invalid token or tokenId provided";
|
|
117
117
|
AUTH_ERRORS["MISSING_RESET_FUNCTION"] = "Missing reset function";
|
|
118
|
+
AUTH_ERRORS["INVALID_RESET_FUNCTION_RESPONSE"] = "Invalid reset function response";
|
|
118
119
|
AUTH_ERRORS["USER_NOT_CONFIRMED"] = "User not confirmed";
|
|
119
120
|
})(AUTH_ERRORS || (exports.AUTH_ERRORS = AUTH_ERRORS = {}));
|
|
120
121
|
const resolveAppPath = () => { var _a, _b, _c; return (_c = (_a = process.env.FLOWERBASE_APP_PATH) !== null && _a !== void 0 ? _a : (_b = require.main) === null || _b === void 0 ? void 0 : _b.path) !== null && _c !== void 0 ? _c : process.cwd(); };
|
package/dist/constants.d.ts
CHANGED
|
@@ -33,6 +33,10 @@ export declare const DEFAULT_CONFIG: {
|
|
|
33
33
|
origin: string;
|
|
34
34
|
methods: ALLOWED_METHODS[];
|
|
35
35
|
};
|
|
36
|
+
MONGODB_ENCRYPTION_CONFIG: {
|
|
37
|
+
keyVaultDb: string;
|
|
38
|
+
keyVaultCollection: string;
|
|
39
|
+
};
|
|
36
40
|
};
|
|
37
41
|
export declare const API_VERSION: string;
|
|
38
42
|
export declare const HTTPS_SCHEMA: string;
|
|
@@ -63,5 +67,11 @@ export declare const S3_CONFIG: {
|
|
|
63
67
|
ACCESS_KEY_ID: string | undefined;
|
|
64
68
|
SECRET_ACCESS_KEY: string | undefined;
|
|
65
69
|
};
|
|
70
|
+
/**
|
|
71
|
+
* Name of the MongoDB client to use for change streams.
|
|
72
|
+
* This may be a separate instance because streams do not work
|
|
73
|
+
* when the main client has auto encryption enabled.
|
|
74
|
+
*/
|
|
75
|
+
export declare const CHANGESTREAM = "changestream";
|
|
66
76
|
export {};
|
|
67
77
|
//# sourceMappingURL=constants.d.ts.map
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,IAAI,CAAA;AAsBpC,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmCsB,eAAe,EAAE
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,IAAI,CAAA;AAsBpC,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmCsB,eAAe,EAAE;;;;;;CAMjE,CAAA;AACD,eAAO,MAAM,WAAW,QAA8C,CAAA;AACtE,eAAO,MAAM,YAAY,QAA8B,CAAA;AACvD,eAAO,MAAM,OAAO,QAAgB,CAAA;AACpC,eAAO,MAAM,YAAY,QAAiC,CAAA;AAE1D,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAAA;AAE7E,eAAO,MAAM,WAAW;;;;;;;mBAOqB,aAAa;;;;;;;;;CAOzD,CAAA;AAED,eAAO,MAAM,SAAS;;;CAGrB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY,iBAAiB,CAAA"}
|
package/dist/constants.js
CHANGED
|
@@ -12,7 +12,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
12
12
|
};
|
|
13
13
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.S3_CONFIG = exports.AUTH_CONFIG = exports.AUTH_DB_NAME = exports.DB_NAME = exports.HTTPS_SCHEMA = exports.API_VERSION = exports.DEFAULT_CONFIG = void 0;
|
|
15
|
+
exports.CHANGESTREAM = exports.S3_CONFIG = exports.AUTH_CONFIG = exports.AUTH_DB_NAME = exports.DB_NAME = exports.HTTPS_SCHEMA = exports.API_VERSION = exports.DEFAULT_CONFIG = void 0;
|
|
16
16
|
const utils_1 = require("./auth/utils");
|
|
17
17
|
const parseBoolean = (value) => {
|
|
18
18
|
if (!value)
|
|
@@ -63,6 +63,10 @@ exports.DEFAULT_CONFIG = {
|
|
|
63
63
|
CORS_OPTIONS: {
|
|
64
64
|
origin: "*",
|
|
65
65
|
methods: ["GET", "POST", "PUT", "DELETE"]
|
|
66
|
+
},
|
|
67
|
+
MONGODB_ENCRYPTION_CONFIG: {
|
|
68
|
+
keyVaultDb: "encryption",
|
|
69
|
+
keyVaultCollection: "__keyVault"
|
|
66
70
|
}
|
|
67
71
|
};
|
|
68
72
|
exports.API_VERSION = `/api/client/${exports.DEFAULT_CONFIG.API_VERSION}`;
|
|
@@ -89,3 +93,9 @@ exports.S3_CONFIG = {
|
|
|
89
93
|
ACCESS_KEY_ID: process.env.S3_ACCESS_KEY_ID,
|
|
90
94
|
SECRET_ACCESS_KEY: process.env.S3_SECRET_ACCESS_KEY
|
|
91
95
|
};
|
|
96
|
+
/**
|
|
97
|
+
* Name of the MongoDB client to use for change streams.
|
|
98
|
+
* This may be a separate instance because streams do not work
|
|
99
|
+
* when the main client has auto encryption enabled.
|
|
100
|
+
*/
|
|
101
|
+
exports.CHANGESTREAM = "changestream";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { UUID } from "mongodb";
|
|
2
|
+
export type EncryptionSchemaProperty = EncryptionSchema | {
|
|
3
|
+
encrypt: {
|
|
4
|
+
algorithm: string;
|
|
5
|
+
bsonType: string;
|
|
6
|
+
keyAlias?: string;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
export type EncryptionSchema = {
|
|
10
|
+
bsonType: "object";
|
|
11
|
+
properties: Record<string, EncryptionSchemaProperty>;
|
|
12
|
+
encryptMetadata?: {
|
|
13
|
+
keyAlias: string;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export type MappedEncryptionSchemaProperty = MappedEncryptionSchema | {
|
|
17
|
+
encrypt: {
|
|
18
|
+
algorithm: string;
|
|
19
|
+
bsonType: string;
|
|
20
|
+
keyId?: [UUID];
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
export type MappedEncryptionSchema = {
|
|
24
|
+
bsonType: "object";
|
|
25
|
+
properties: Record<string, MappedEncryptionSchemaProperty>;
|
|
26
|
+
encryptMetadata?: {
|
|
27
|
+
keyId: [UUID];
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export type EncryptionSchemaFile = {
|
|
31
|
+
database: string;
|
|
32
|
+
collection: string;
|
|
33
|
+
schema: EncryptionSchema;
|
|
34
|
+
};
|
|
35
|
+
export type EncryptionSchemas = Record<string, EncryptionSchema>;
|
|
36
|
+
//# sourceMappingURL=interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../../src/features/encryption/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAEnC,MAAM,MAAM,wBAAwB,GAChC,gBAAgB,GAChB;IACA,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAA;QACjB,QAAQ,EAAE,MAAM,CAAA;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;KAClB,CAAA;CACF,CAAA;AAEH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,QAAQ,CAAA;IAClB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAA;IACpD,eAAe,CAAC,EAAE;QAChB,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAC;CACH,CAAA;AAGD,MAAM,MAAM,8BAA8B,GACtC,sBAAsB,GACtB;IACA,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAA;QACjB,QAAQ,EAAE,MAAM,CAAA;QAChB,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,CAAA;KACf,CAAA;CACF,CAAA;AAEH,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,QAAQ,CAAA;IAClB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,8BAA8B,CAAC,CAAA;IAC1D,eAAe,CAAC,EAAE;QAChB,KAAK,EAAE,CAAC,IAAI,CAAC,CAAA;KACd,CAAC;CACH,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,gBAAgB,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { EncryptionSchemas } from "./interface";
|
|
2
|
+
/**
|
|
3
|
+
* @experimental
|
|
4
|
+
* Schemas used for Client-Side Level Encryption configuration.
|
|
5
|
+
*
|
|
6
|
+
* **Important:** These schemas do not perform JSON validation.
|
|
7
|
+
*/
|
|
8
|
+
export declare const loadEncryptionSchemas: (rootDir?: string) => Promise<EncryptionSchemas>;
|
|
9
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/features/encryption/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwB,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAErE;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAU,gBAAuB,KAAG,OAAO,CAAC,iBAAiB,CAW9F,CAAA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.loadEncryptionSchemas = void 0;
|
|
16
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
17
|
+
const utils_1 = require("../../utils");
|
|
18
|
+
/**
|
|
19
|
+
* @experimental
|
|
20
|
+
* Schemas used for Client-Side Level Encryption configuration.
|
|
21
|
+
*
|
|
22
|
+
* **Important:** These schemas do not perform JSON validation.
|
|
23
|
+
*/
|
|
24
|
+
const loadEncryptionSchemas = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (rootDir = process.cwd()) {
|
|
25
|
+
const schemasRoot = node_path_1.default.join(rootDir, 'data_sources', 'mongodb-atlas');
|
|
26
|
+
const files = (0, utils_1.recursivelyCollectFiles)(schemasRoot);
|
|
27
|
+
const schemaFiles = files.filter((x) => x.endsWith('encryption.json'));
|
|
28
|
+
return schemaFiles.reduce((acc, filePath) => {
|
|
29
|
+
const { collection, database, schema } = (0, utils_1.readJsonContent)(filePath);
|
|
30
|
+
acc[`${database}.${collection}`] = schema;
|
|
31
|
+
return acc;
|
|
32
|
+
}, {});
|
|
33
|
+
});
|
|
34
|
+
exports.loadEncryptionSchemas = loadEncryptionSchemas;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/features/endpoints/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAKvE,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAE9D;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAU,gBAAuB,KAAG,OAAO,CAAC,SAAS,CA+B9E,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAC3B,KAAK,eAAe,EACpB,SAAS,UAAU,CAAC,OAAO,eAAe,CAAC,EAC3C,UAAU,MAAM;;;;;;;CAkDhB,CAAA;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,kEAM7B,qBAAqB,MACR,KAAK,cAAc,EAAE,KAAK,YAAY,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/features/endpoints/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAKvE,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAE9D;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAU,gBAAuB,KAAG,OAAO,CAAC,SAAS,CA+B9E,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAC3B,KAAK,eAAe,EACpB,SAAS,UAAU,CAAC,OAAO,eAAe,CAAC,EAC3C,UAAU,MAAM;;;;;;;CAkDhB,CAAA;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,kEAM7B,qBAAqB,MACR,KAAK,cAAc,EAAE,KAAK,YAAY,gBAgDrD,CAAA"}
|
|
@@ -135,6 +135,9 @@ const generateHandler = ({ app, currentFunction, functionName, functionsList, ru
|
|
|
135
135
|
setStatusCode: (code) => {
|
|
136
136
|
res.status(code);
|
|
137
137
|
},
|
|
138
|
+
setHeader: (name, value) => {
|
|
139
|
+
res.header(name, value);
|
|
140
|
+
},
|
|
138
141
|
setBody: (body) => {
|
|
139
142
|
customResponseBody.data = body;
|
|
140
143
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import type { Document } from 'mongodb';
|
|
1
2
|
import { FunctionController } from './interface';
|
|
2
3
|
export declare const mapWatchFilterToChangeStreamMatch: (value: unknown) => unknown;
|
|
3
4
|
export declare const mapWatchFilterToDocumentQuery: (value: unknown) => unknown;
|
|
5
|
+
export declare const shouldSkipReadabilityLookupForChange: (change: Document) => boolean;
|
|
4
6
|
/**
|
|
5
7
|
* > Creates a pre handler for every query
|
|
6
8
|
* @param app -> the fastify instance
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../src/features/functions/controller.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../src/features/functions/controller.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAIvC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAmHhD,eAAO,MAAM,iCAAiC,GAAI,OAAO,OAAO,KAAG,OA0BlE,CAAA;AAID,eAAO,MAAM,6BAA6B,GAAI,OAAO,OAAO,KAAG,OAgD9D,CAAA;AAqHD,eAAO,MAAM,oCAAoC,GAAI,QAAQ,QAAQ,YAClC,CAAA;AAEnC;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,kBAyRjC,CAAA"}
|
|
@@ -20,7 +20,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
20
20
|
return t;
|
|
21
21
|
};
|
|
22
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.functionsController = exports.mapWatchFilterToDocumentQuery = exports.mapWatchFilterToChangeStreamMatch = void 0;
|
|
23
|
+
exports.functionsController = exports.shouldSkipReadabilityLookupForChange = exports.mapWatchFilterToDocumentQuery = exports.mapWatchFilterToChangeStreamMatch = void 0;
|
|
24
24
|
const bson_1 = require("bson");
|
|
25
25
|
const services_1 = require("../../services");
|
|
26
26
|
const context_1 = require("../../utils/context");
|
|
@@ -262,6 +262,8 @@ const isReadableDocumentResult = (value) => !!value &&
|
|
|
262
262
|
typeof value === 'object' &&
|
|
263
263
|
!Array.isArray(value) &&
|
|
264
264
|
Object.keys(value).length > 0;
|
|
265
|
+
const shouldSkipReadabilityLookupForChange = (change) => change.operationType === 'delete';
|
|
266
|
+
exports.shouldSkipReadabilityLookupForChange = shouldSkipReadabilityLookupForChange;
|
|
265
267
|
/**
|
|
266
268
|
* > Creates a pre handler for every query
|
|
267
269
|
* @param app -> the fastify instance
|
|
@@ -431,6 +433,10 @@ const functionsController = (app_1, _a) => __awaiter(void 0, [app_1, _a], void 0
|
|
|
431
433
|
const docId = (_b = (_a = change === null || change === void 0 ? void 0 : change.documentKey) === null || _a === void 0 ? void 0 : _a._id) !== null && _b !== void 0 ? _b : (_c = change === null || change === void 0 ? void 0 : change.fullDocument) === null || _c === void 0 ? void 0 : _c._id;
|
|
432
434
|
if (typeof docId === 'undefined')
|
|
433
435
|
return;
|
|
436
|
+
if ((0, exports.shouldSkipReadabilityLookupForChange)(change)) {
|
|
437
|
+
subscriberRes.write(`data: ${serializeEjson(change)}\n\n`);
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
434
440
|
const readQuery = subscriber.documentFilter
|
|
435
441
|
? { $and: [subscriber.documentFilter, { _id: docId }] }
|
|
436
442
|
: { _id: docId };
|