@flowerforce/flowerbase 1.0.1-beta.3
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/CHANGELOG.md +0 -0
- package/LICENSE +3 -0
- package/README.md +18 -0
- package/dist/auth/controller.d.ts +8 -0
- package/dist/auth/controller.d.ts.map +1 -0
- package/dist/auth/controller.js +76 -0
- package/dist/auth/dtos.d.ts +6 -0
- package/dist/auth/dtos.d.ts.map +1 -0
- package/dist/auth/dtos.js +2 -0
- package/dist/auth/plugins/jwt.d.ts +14 -0
- package/dist/auth/plugins/jwt.d.ts.map +1 -0
- package/dist/auth/plugins/jwt.js +68 -0
- package/dist/auth/providers/local-userpass/controller.d.ts +8 -0
- package/dist/auth/providers/local-userpass/controller.d.ts.map +1 -0
- package/dist/auth/providers/local-userpass/controller.js +184 -0
- package/dist/auth/providers/local-userpass/dtos.d.ts +35 -0
- package/dist/auth/providers/local-userpass/dtos.d.ts.map +1 -0
- package/dist/auth/providers/local-userpass/dtos.js +2 -0
- package/dist/auth/utils.d.ts +126 -0
- package/dist/auth/utils.d.ts.map +1 -0
- package/dist/auth/utils.js +122 -0
- package/dist/constants.d.ts +18 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +34 -0
- package/dist/features/endpoints/index.d.ts +10 -0
- package/dist/features/endpoints/index.d.ts.map +1 -0
- package/dist/features/endpoints/index.js +31 -0
- package/dist/features/endpoints/interface.d.ts +27 -0
- package/dist/features/endpoints/interface.d.ts.map +1 -0
- package/dist/features/endpoints/interface.js +2 -0
- package/dist/features/endpoints/utils.d.ts +31 -0
- package/dist/features/endpoints/utils.d.ts.map +1 -0
- package/dist/features/endpoints/utils.js +85 -0
- package/dist/features/functions/controller.d.ts +9 -0
- package/dist/features/functions/controller.d.ts.map +1 -0
- package/dist/features/functions/controller.js +88 -0
- package/dist/features/functions/dtos.d.ts +34 -0
- package/dist/features/functions/dtos.d.ts.map +1 -0
- package/dist/features/functions/dtos.js +2 -0
- package/dist/features/functions/index.d.ts +9 -0
- package/dist/features/functions/index.d.ts.map +1 -0
- package/dist/features/functions/index.js +28 -0
- package/dist/features/functions/interface.d.ts +32 -0
- package/dist/features/functions/interface.d.ts.map +1 -0
- package/dist/features/functions/interface.js +2 -0
- package/dist/features/functions/utils.d.ts +23 -0
- package/dist/features/functions/utils.d.ts.map +1 -0
- package/dist/features/functions/utils.js +75 -0
- package/dist/features/rules/index.d.ts +1 -0
- package/dist/features/rules/index.d.ts.map +1 -0
- package/dist/features/rules/index.js +1 -0
- package/dist/features/rules/interface.d.ts +22 -0
- package/dist/features/rules/interface.d.ts.map +1 -0
- package/dist/features/rules/interface.js +2 -0
- package/dist/features/rules/utils.d.ts +3 -0
- package/dist/features/rules/utils.d.ts.map +1 -0
- package/dist/features/rules/utils.js +31 -0
- package/dist/features/triggers/dtos.d.ts +9 -0
- package/dist/features/triggers/dtos.d.ts.map +1 -0
- package/dist/features/triggers/dtos.js +2 -0
- package/dist/features/triggers/index.d.ts +10 -0
- package/dist/features/triggers/index.d.ts.map +1 -0
- package/dist/features/triggers/index.js +57 -0
- package/dist/features/triggers/interface.d.ts +44 -0
- package/dist/features/triggers/interface.d.ts.map +1 -0
- package/dist/features/triggers/interface.js +2 -0
- package/dist/features/triggers/utils.d.ts +16 -0
- package/dist/features/triggers/utils.d.ts.map +1 -0
- package/dist/features/triggers/utils.js +153 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +84 -0
- package/dist/model.d.ts +2 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +2 -0
- package/dist/services/api/index.d.ts +36 -0
- package/dist/services/api/index.d.ts.map +1 -0
- package/dist/services/api/index.js +36 -0
- package/dist/services/api/model.d.ts +33 -0
- package/dist/services/api/model.d.ts.map +1 -0
- package/dist/services/api/model.js +2 -0
- package/dist/services/api/utils.d.ts +16 -0
- package/dist/services/api/utils.d.ts.map +1 -0
- package/dist/services/api/utils.js +45 -0
- package/dist/services/aws/index.d.ts +13 -0
- package/dist/services/aws/index.d.ts.map +1 -0
- package/dist/services/aws/index.js +50 -0
- package/dist/services/index.d.ts +41 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +14 -0
- package/dist/services/interface.d.ts +3 -0
- package/dist/services/interface.d.ts.map +1 -0
- package/dist/services/interface.js +2 -0
- package/dist/services/mongodb-atlas/index.d.ts +4 -0
- package/dist/services/mongodb-atlas/index.d.ts.map +1 -0
- package/dist/services/mongodb-atlas/index.js +483 -0
- package/dist/services/mongodb-atlas/model.d.ts +39 -0
- package/dist/services/mongodb-atlas/model.d.ts.map +1 -0
- package/dist/services/mongodb-atlas/model.js +2 -0
- package/dist/services/mongodb-atlas/utils.d.ts +8 -0
- package/dist/services/mongodb-atlas/utils.d.ts.map +1 -0
- package/dist/services/mongodb-atlas/utils.js +33 -0
- package/dist/state.d.ts +6 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +18 -0
- package/dist/utils/context/helpers.d.ts +74 -0
- package/dist/utils/context/helpers.d.ts.map +1 -0
- package/dist/utils/context/helpers.js +60 -0
- package/dist/utils/context/index.d.ts +14 -0
- package/dist/utils/context/index.d.ts.map +1 -0
- package/dist/utils/context/index.js +50 -0
- package/dist/utils/context/interface.d.ts +18 -0
- package/dist/utils/context/interface.d.ts.map +1 -0
- package/dist/utils/context/interface.js +2 -0
- package/dist/utils/crypto/index.d.ts +19 -0
- package/dist/utils/crypto/index.d.ts.map +1 -0
- package/dist/utils/crypto/index.js +50 -0
- package/dist/utils/helpers/someAsync.d.ts +12 -0
- package/dist/utils/helpers/someAsync.d.ts.map +1 -0
- package/dist/utils/helpers/someAsync.js +56 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +11 -0
- package/dist/utils/initializer/exposeRoutes.d.ts +8 -0
- package/dist/utils/initializer/exposeRoutes.d.ts.map +1 -0
- package/dist/utils/initializer/exposeRoutes.js +41 -0
- package/dist/utils/initializer/registerPlugins.d.ts +19 -0
- package/dist/utils/initializer/registerPlugins.d.ts.map +1 -0
- package/dist/utils/initializer/registerPlugins.js +84 -0
- package/dist/utils/roles/helpers.d.ts +4 -0
- package/dist/utils/roles/helpers.d.ts.map +1 -0
- package/dist/utils/roles/helpers.js +47 -0
- package/dist/utils/roles/interface.d.ts +33 -0
- package/dist/utils/roles/interface.d.ts.map +1 -0
- package/dist/utils/roles/interface.js +2 -0
- package/dist/utils/roles/machines/commonValidators.d.ts +6 -0
- package/dist/utils/roles/machines/commonValidators.d.ts.map +1 -0
- package/dist/utils/roles/machines/commonValidators.js +34 -0
- package/dist/utils/roles/machines/index.d.ts +14 -0
- package/dist/utils/roles/machines/index.d.ts.map +1 -0
- package/dist/utils/roles/machines/index.js +27 -0
- package/dist/utils/roles/machines/interface.d.ts +46 -0
- package/dist/utils/roles/machines/interface.d.ts.map +1 -0
- package/dist/utils/roles/machines/interface.js +2 -0
- package/dist/utils/roles/machines/machine.d.ts +15 -0
- package/dist/utils/roles/machines/machine.d.ts.map +1 -0
- package/dist/utils/roles/machines/machine.js +97 -0
- package/dist/utils/roles/machines/read/A/index.d.ts +3 -0
- package/dist/utils/roles/machines/read/A/index.d.ts.map +1 -0
- package/dist/utils/roles/machines/read/A/index.js +27 -0
- package/dist/utils/roles/machines/read/B/index.d.ts +3 -0
- package/dist/utils/roles/machines/read/B/index.d.ts.map +1 -0
- package/dist/utils/roles/machines/read/B/index.js +36 -0
- package/dist/utils/roles/machines/read/C/index.d.ts +3 -0
- package/dist/utils/roles/machines/read/C/index.d.ts.map +1 -0
- package/dist/utils/roles/machines/read/C/index.js +38 -0
- package/dist/utils/roles/machines/read/D/index.d.ts +3 -0
- package/dist/utils/roles/machines/read/D/index.d.ts.map +1 -0
- package/dist/utils/roles/machines/read/D/index.js +26 -0
- package/dist/utils/roles/machines/read/D/validators.d.ts +4 -0
- package/dist/utils/roles/machines/read/D/validators.d.ts.map +1 -0
- package/dist/utils/roles/machines/read/D/validators.js +24 -0
- package/dist/utils/roles/machines/read/index.d.ts +2 -0
- package/dist/utils/roles/machines/read/index.d.ts.map +1 -0
- package/dist/utils/roles/machines/read/index.js +8 -0
- package/dist/utils/roles/machines/utils.d.ts +37 -0
- package/dist/utils/roles/machines/utils.d.ts.map +1 -0
- package/dist/utils/roles/machines/utils.js +54 -0
- package/dist/utils/roles/machines/write/A/index.d.ts +3 -0
- package/dist/utils/roles/machines/write/A/index.d.ts.map +1 -0
- package/dist/utils/roles/machines/write/A/index.js +29 -0
- package/dist/utils/roles/machines/write/B/index.d.ts +3 -0
- package/dist/utils/roles/machines/write/B/index.d.ts.map +1 -0
- package/dist/utils/roles/machines/write/B/index.js +47 -0
- package/dist/utils/roles/machines/write/C/index.d.ts +3 -0
- package/dist/utils/roles/machines/write/C/index.d.ts.map +1 -0
- package/dist/utils/roles/machines/write/C/index.js +26 -0
- package/dist/utils/roles/machines/write/C/validators.d.ts +4 -0
- package/dist/utils/roles/machines/write/C/validators.d.ts.map +1 -0
- package/dist/utils/roles/machines/write/C/validators.js +24 -0
- package/dist/utils/roles/machines/write/index.d.ts +2 -0
- package/dist/utils/roles/machines/write/index.d.ts.map +1 -0
- package/dist/utils/roles/machines/write/index.js +7 -0
- package/dist/utils/rules-matcher/interface.d.ts +338 -0
- package/dist/utils/rules-matcher/interface.d.ts.map +1 -0
- package/dist/utils/rules-matcher/interface.js +26 -0
- package/dist/utils/rules-matcher/utils.d.ts +11 -0
- package/dist/utils/rules-matcher/utils.d.ts.map +1 -0
- package/dist/utils/rules-matcher/utils.js +214 -0
- package/dist/utils/rules.d.ts +2 -0
- package/dist/utils/rules.d.ts.map +1 -0
- package/dist/utils/rules.js +22 -0
- package/jest.config.ts +24 -0
- package/package.json +63 -0
- package/project.json +10 -0
- package/rollup.config.js +17 -0
- package/src/auth/controller.ts +78 -0
- package/src/auth/dtos.ts +6 -0
- package/src/auth/plugins/jwt.ts +68 -0
- package/src/auth/providers/local-userpass/controller.ts +226 -0
- package/src/auth/providers/local-userpass/dtos.ts +40 -0
- package/src/auth/utils.ts +165 -0
- package/src/babel.config.json +3 -0
- package/src/constants.ts +22 -0
- package/src/fastify.d.ts +28 -0
- package/src/features/endpoints/index.ts +27 -0
- package/src/features/endpoints/interface.ts +29 -0
- package/src/features/endpoints/utils.ts +72 -0
- package/src/features/functions/controller.ts +102 -0
- package/src/features/functions/dtos.ts +41 -0
- package/src/features/functions/index.ts +21 -0
- package/src/features/functions/interface.ts +38 -0
- package/src/features/functions/utils.ts +82 -0
- package/src/features/rules/index.tsx +0 -0
- package/src/features/rules/interface.ts +24 -0
- package/src/features/rules/utils.ts +20 -0
- package/src/features/triggers/dtos.ts +9 -0
- package/src/features/triggers/index.ts +34 -0
- package/src/features/triggers/interface.ts +44 -0
- package/src/features/triggers/utils.ts +157 -0
- package/src/global.d.ts +0 -0
- package/src/index.ts +75 -0
- package/src/model.ts +1 -0
- package/src/services/api/index.ts +50 -0
- package/src/services/api/model.ts +38 -0
- package/src/services/api/utils.ts +39 -0
- package/src/services/aws/index.ts +48 -0
- package/src/services/index.ts +9 -0
- package/src/services/interface.ts +3 -0
- package/src/services/mongodb-atlas/index.ts +569 -0
- package/src/services/mongodb-atlas/model.ts +67 -0
- package/src/services/mongodb-atlas/utils.ts +44 -0
- package/src/state.ts +24 -0
- package/src/utils/__tests__/STEP_A_STATES.test.ts +54 -0
- package/src/utils/__tests__/STEP_B_STATES.test.ts +113 -0
- package/src/utils/__tests__/STEP_C_STATES.test.ts +87 -0
- package/src/utils/__tests__/STEP_D_STATES.test.ts +93 -0
- package/src/utils/__tests__/checkAdditionalFieldsFn.test.ts +45 -0
- package/src/utils/__tests__/checkApplyWhen.test.ts +49 -0
- package/src/utils/__tests__/checkFieldsPropertyExists.test.ts +47 -0
- package/src/utils/__tests__/checkIsValidFieldNameFn.test.ts +190 -0
- package/src/utils/__tests__/comparePassword.test.ts +38 -0
- package/src/utils/__tests__/evaluateDocumentsFiltersReadFn.test.ts +57 -0
- package/src/utils/__tests__/evaluateDocumentsFiltersWriteFn.test.ts +57 -0
- package/src/utils/__tests__/evaluateTopLevelReadFn.test.ts +58 -0
- package/src/utils/__tests__/evaluateTopLevelWriteFn.test.ts +66 -0
- package/src/utils/__tests__/exposeRoutes.test.ts +65 -0
- package/src/utils/__tests__/generateContextData.test.ts +75 -0
- package/src/utils/__tests__/getDefaultRule.test.ts +29 -0
- package/src/utils/__tests__/getKey.test.ts +12 -0
- package/src/utils/__tests__/getKeys.test.ts +11 -0
- package/src/utils/__tests__/getWinningRole.test.ts +66 -0
- package/src/utils/__tests__/hashPassword.test.ts +28 -0
- package/src/utils/__tests__/isEmpty.test.ts +17 -0
- package/src/utils/__tests__/logMachineInfo.test.ts +15 -0
- package/src/utils/__tests__/operators.test.ts +99 -0
- package/src/utils/__tests__/readFileContent.test.ts +35 -0
- package/src/utils/__tests__/registerPlugins.test.ts +59 -0
- package/src/utils/__tests__/rule.test.ts +51 -0
- package/src/utils/__tests__/rulesMatcherInterfaces.test.ts +57 -0
- package/src/utils/__tests__/rulesMatcherUtils.test.ts +56 -0
- package/src/utils/__tests__/someAsync.test.ts +55 -0
- package/src/utils/context/helpers.ts +71 -0
- package/src/utils/context/index.ts +52 -0
- package/src/utils/context/interface.ts +19 -0
- package/src/utils/crypto/index.ts +36 -0
- package/src/utils/helpers/someAsync.ts +24 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/initializer/exposeRoutes.ts +26 -0
- package/src/utils/initializer/registerPlugins.ts +97 -0
- package/src/utils/roles/helpers.ts +47 -0
- package/src/utils/roles/interface.ts +42 -0
- package/src/utils/roles/machines/commonValidators.ts +24 -0
- package/src/utils/roles/machines/index.ts +20 -0
- package/src/utils/roles/machines/interface.ts +46 -0
- package/src/utils/roles/machines/machine.ts +85 -0
- package/src/utils/roles/machines/read/A/index.ts +19 -0
- package/src/utils/roles/machines/read/B/index.ts +31 -0
- package/src/utils/roles/machines/read/C/index.ts +30 -0
- package/src/utils/roles/machines/read/D/index.ts +20 -0
- package/src/utils/roles/machines/read/D/validators.ts +24 -0
- package/src/utils/roles/machines/read/index.ts +6 -0
- package/src/utils/roles/machines/utils.ts +54 -0
- package/src/utils/roles/machines/write/A/index.ts +25 -0
- package/src/utils/roles/machines/write/B/index.ts +43 -0
- package/src/utils/roles/machines/write/C/index.ts +20 -0
- package/src/utils/roles/machines/write/C/validators.ts +24 -0
- package/src/utils/roles/machines/write/index.ts +5 -0
- package/src/utils/rules-matcher/interface.ts +365 -0
- package/src/utils/rules-matcher/utils.ts +281 -0
- package/src/utils/rules.ts +19 -0
- package/tsconfig.json +28 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { FastifyInstance } from 'fastify'
|
|
2
|
+
import { Arguments, User } from '../../auth/dtos'
|
|
3
|
+
import { Function, Functions } from '../../features/functions/interface'
|
|
4
|
+
import { Rules } from '../../features/rules/interface'
|
|
5
|
+
import { Services } from '../../services/interface'
|
|
6
|
+
|
|
7
|
+
export interface GenerateContextParams {
|
|
8
|
+
app: FastifyInstance
|
|
9
|
+
currentFunction: Function
|
|
10
|
+
functionsList: Functions
|
|
11
|
+
rules: Rules
|
|
12
|
+
user: User
|
|
13
|
+
services: Services
|
|
14
|
+
args: Arguments
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface GenerateContextDataParams extends Omit<GenerateContextParams, 'args'> {
|
|
18
|
+
GenerateContext: (params: GenerateContextParams) => Promise<void>
|
|
19
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import crypto from 'node:crypto'
|
|
2
|
+
import { promisify } from 'node:util'
|
|
3
|
+
|
|
4
|
+
const scrypt = promisify(crypto.scrypt)
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* > Creates the hash for a string
|
|
8
|
+
* @param plaintext -> the string that should be encrypted
|
|
9
|
+
* @tested
|
|
10
|
+
*/
|
|
11
|
+
export const hashPassword = async (plaintext: string) => {
|
|
12
|
+
const salt = crypto.randomBytes(128).toString('hex')
|
|
13
|
+
const buffer = (await scrypt(plaintext, salt, 64)) as Buffer
|
|
14
|
+
return `${buffer.toString('hex')}.${salt}`
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* > Compares two strings
|
|
19
|
+
* @param plaintext -> the first string
|
|
20
|
+
* @param storedPassword -> the second string
|
|
21
|
+
* @tested
|
|
22
|
+
*/
|
|
23
|
+
export const comparePassword = async (plaintext: string, storedPassword: string) => {
|
|
24
|
+
const [storedHash, storedSalt] = storedPassword.split('.')
|
|
25
|
+
const storedBuffer = Buffer.from(storedHash, 'hex')
|
|
26
|
+
const buffer = (await scrypt(plaintext, storedSalt, 64)) as Buffer
|
|
27
|
+
return crypto.timingSafeEqual(buffer, storedBuffer)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* > Generate a random token
|
|
32
|
+
* @param length -> the token length
|
|
33
|
+
*/
|
|
34
|
+
export const generateToken = (length = 32) => {
|
|
35
|
+
return crypto.randomBytes(length).toString('hex');
|
|
36
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asynchronously checks if at least one element in the array satisfies the given asynchronous callback function.
|
|
3
|
+
*
|
|
4
|
+
* @template T - The type of elements in the array.
|
|
5
|
+
* @param {T[]} array - The array to iterate over.
|
|
6
|
+
* @param {(element: T, index: number, arr: T[]) => Promise<boolean>} callback - An asynchronous function that takes an element, its index, and the original array,
|
|
7
|
+
* and returns a Promise resolving to `true` if the condition is met, otherwise `false`.
|
|
8
|
+
* @returns {Promise<boolean>} A promise that resolves to `true` if at least one element satisfies the callback condition, otherwise `false`.
|
|
9
|
+
* @tested
|
|
10
|
+
*/
|
|
11
|
+
export async function someAsync<T>(
|
|
12
|
+
array: T[],
|
|
13
|
+
callback: (element: T, index: number, arr: T[]) => Promise<boolean>
|
|
14
|
+
): Promise<boolean> {
|
|
15
|
+
let i = 0;
|
|
16
|
+
for await (const el of array) {
|
|
17
|
+
const isValid = await callback(el, i, array);
|
|
18
|
+
if (isValid) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
i++;
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { uptime } from 'node:process'
|
|
2
|
+
import { FastifyInstance } from 'fastify'
|
|
3
|
+
import { API_VERSION } from '../../constants'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* > Used to expose all app routes
|
|
7
|
+
* @param fastify -> the fastify instance
|
|
8
|
+
* @tested
|
|
9
|
+
*/
|
|
10
|
+
export const exposeRoutes = async (fastify: FastifyInstance) => {
|
|
11
|
+
try {
|
|
12
|
+
fastify.get(`${API_VERSION}/app/:appId/location`, async (req) => ({
|
|
13
|
+
deployment_model: 'LOCAL',
|
|
14
|
+
location: 'IE',
|
|
15
|
+
hostname: `http://${req.headers.host}`,
|
|
16
|
+
ws_hostname: `wss://${req.headers.host}`
|
|
17
|
+
}))
|
|
18
|
+
|
|
19
|
+
fastify.get('/health', async () => ({
|
|
20
|
+
status: 'ok',
|
|
21
|
+
uptime: uptime()
|
|
22
|
+
}))
|
|
23
|
+
} catch (e) {
|
|
24
|
+
console.error('Error while exposing routes', (e as Error).message)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import cors from '@fastify/cors'
|
|
2
|
+
import fastifyMongodb from '@fastify/mongodb'
|
|
3
|
+
import { FastifyInstance } from 'fastify'
|
|
4
|
+
import { authController } from '../../auth/controller'
|
|
5
|
+
import jwtAuthPlugin from '../../auth/plugins/jwt'
|
|
6
|
+
import { localUserPassController } from '../../auth/providers/local-userpass/controller'
|
|
7
|
+
import { API_VERSION } from '../../constants'
|
|
8
|
+
import { Functions } from '../../features/functions/interface'
|
|
9
|
+
|
|
10
|
+
type RegisterFunction = FastifyInstance['register']
|
|
11
|
+
type RegisterParameters = Parameters<RegisterFunction>
|
|
12
|
+
|
|
13
|
+
type RegisterPluginsParams = {
|
|
14
|
+
register: RegisterFunction
|
|
15
|
+
mongodbUrl: string
|
|
16
|
+
jwtSecret: string
|
|
17
|
+
functionsList: Functions
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type RegisterConfig = {
|
|
21
|
+
plugin: RegisterParameters[0]
|
|
22
|
+
options: RegisterParameters[1]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* > Used to register all plugins
|
|
27
|
+
* @param register -> the fastify register method
|
|
28
|
+
* @param mongodbUrl -> the database connection string
|
|
29
|
+
* @param jwtSecret -> connection jwt
|
|
30
|
+
* @tested
|
|
31
|
+
*/
|
|
32
|
+
export const registerPlugins = async ({
|
|
33
|
+
register,
|
|
34
|
+
mongodbUrl,
|
|
35
|
+
jwtSecret,
|
|
36
|
+
functionsList
|
|
37
|
+
}: RegisterPluginsParams) => {
|
|
38
|
+
try {
|
|
39
|
+
const registersConfig = await getRegisterConfig({
|
|
40
|
+
mongodbUrl,
|
|
41
|
+
jwtSecret,
|
|
42
|
+
functionsList
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
registersConfig.forEach(({ plugin, options }) => {
|
|
46
|
+
register(plugin, options)
|
|
47
|
+
})
|
|
48
|
+
} catch (e) {
|
|
49
|
+
console.error('Error while registering plugins', (e as Error).message)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* > Used to generate the register congig
|
|
55
|
+
* @param mongodbUrl -> the database connection string
|
|
56
|
+
* @param jwtSecret -> connection jwt
|
|
57
|
+
* @testable
|
|
58
|
+
*/
|
|
59
|
+
const getRegisterConfig = async ({
|
|
60
|
+
mongodbUrl,
|
|
61
|
+
jwtSecret
|
|
62
|
+
}: Pick<RegisterPluginsParams, 'jwtSecret' | 'mongodbUrl' | 'functionsList'>): Promise<
|
|
63
|
+
RegisterConfig[]
|
|
64
|
+
> => {
|
|
65
|
+
return [
|
|
66
|
+
{
|
|
67
|
+
plugin: cors,
|
|
68
|
+
options: {
|
|
69
|
+
origin: '*',
|
|
70
|
+
methods: ['POST', 'GET']
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
plugin: fastifyMongodb,
|
|
75
|
+
options: {
|
|
76
|
+
forceClose: true,
|
|
77
|
+
url: mongodbUrl
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
plugin: jwtAuthPlugin,
|
|
82
|
+
options: {
|
|
83
|
+
secret: jwtSecret
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
plugin: authController,
|
|
88
|
+
options: { prefix: `${API_VERSION}/auth` }
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
plugin: localUserPassController,
|
|
92
|
+
options: {
|
|
93
|
+
prefix: `${API_VERSION}/app/:appId/auth/providers/local-userpass`
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
] as RegisterConfig[]
|
|
97
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { services } from '../../services'
|
|
2
|
+
import { StateManager } from '../../state'
|
|
3
|
+
import { GenerateContext } from '../context'
|
|
4
|
+
import { expandQuery } from '../rules'
|
|
5
|
+
import rulesMatcherUtils from '../rules-matcher/utils'
|
|
6
|
+
import { PermissionExpression } from './interface'
|
|
7
|
+
import { MachineContext } from './machines/interface'
|
|
8
|
+
|
|
9
|
+
const functionsConditions = ["%%true", "%%false"]
|
|
10
|
+
|
|
11
|
+
export const evaluateExpression = async (params: MachineContext["params"], expression?: PermissionExpression, user?: MachineContext["user"]): Promise<boolean> => {
|
|
12
|
+
if (!expression || typeof expression === 'boolean') return !!expression
|
|
13
|
+
|
|
14
|
+
const value = {
|
|
15
|
+
...params.expansions,
|
|
16
|
+
...params.cursor,
|
|
17
|
+
"%%user": user,
|
|
18
|
+
'%%true': true
|
|
19
|
+
}
|
|
20
|
+
const conditions = expandQuery(expression, value)
|
|
21
|
+
const complexCondition = Object.entries<Record<string, any>>(conditions).find(([key]) => functionsConditions.includes(key))
|
|
22
|
+
return complexCondition ? await evaluateComplexExpression(complexCondition, params, user) : rulesMatcherUtils.checkRule(conditions, value, {})
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const evaluateComplexExpression = async (condition: [string, Record<string, any>], params: MachineContext["params"], user: MachineContext["user"]) => {
|
|
27
|
+
const [key, config] = condition
|
|
28
|
+
|
|
29
|
+
const { name } = config["%function"]
|
|
30
|
+
const functionsList = StateManager.select("functions")
|
|
31
|
+
const app = StateManager.select("app")
|
|
32
|
+
const currentFunction = functionsList[name]
|
|
33
|
+
const response = await GenerateContext({
|
|
34
|
+
args: [params.cursor],
|
|
35
|
+
app,
|
|
36
|
+
rules: {},
|
|
37
|
+
user,
|
|
38
|
+
currentFunction,
|
|
39
|
+
functionsList,
|
|
40
|
+
services
|
|
41
|
+
})
|
|
42
|
+
return key === "%%true" ? response : !response
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export type PermissionExpression = boolean // TODO: add complex condition (%%true: %function)
|
|
2
|
+
|
|
3
|
+
export type FieldPermissionExpression = {
|
|
4
|
+
read?: boolean,
|
|
5
|
+
write?: boolean
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface DocumentFiltersPermissions {
|
|
9
|
+
read?: PermissionExpression
|
|
10
|
+
write?: PermissionExpression
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface Role {
|
|
14
|
+
name: string
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
|
+
apply_when: Record<string, any> // TODO -> define this type
|
|
17
|
+
search?: PermissionExpression
|
|
18
|
+
document_filters?: DocumentFiltersPermissions
|
|
19
|
+
read?: PermissionExpression
|
|
20
|
+
write?: PermissionExpression
|
|
21
|
+
insert?: PermissionExpression
|
|
22
|
+
delete?: PermissionExpression
|
|
23
|
+
fields?: {
|
|
24
|
+
[K: string]: FieldPermissionExpression
|
|
25
|
+
}
|
|
26
|
+
additional_fields?: {
|
|
27
|
+
[K: string]: FieldPermissionExpression
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface Params {
|
|
32
|
+
roles: Role[]
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
|
+
cursor: any // TODO -> define this type
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
|
+
expansions: Record<string, any> // TODO -> define this type
|
|
37
|
+
type: 'insert' | 'read' | 'delete' | 'search' | 'write'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
+
export type Condition = Record<string, any>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { someAsync } from "../../helpers/someAsync"
|
|
2
|
+
import { evaluateExpression } from "../helpers"
|
|
3
|
+
import { DocumentFiltersPermissions } from "../interface"
|
|
4
|
+
import { MachineContext } from "./interface"
|
|
5
|
+
|
|
6
|
+
const readOnlyPermissions = ['read']
|
|
7
|
+
const readWritePermissions = ['write', 'delete', 'insert', ...readOnlyPermissions]
|
|
8
|
+
|
|
9
|
+
export const evaluateDocumentFiltersFn = async ({ params, role, user }: MachineContext, currentType: keyof DocumentFiltersPermissions) => {
|
|
10
|
+
const permissions = currentType === "read" ? readOnlyPermissions : readWritePermissions
|
|
11
|
+
return await someAsync([
|
|
12
|
+
permissions.includes(params.type) && role.document_filters?.[currentType]
|
|
13
|
+
]
|
|
14
|
+
.filter(Boolean), async (expr) => evaluateExpression(params, expr, user))
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
export const evaluateTopLevelPermissionsFn = async ({ params, role, user }: MachineContext, currentType: MachineContext["params"]["type"]) => {
|
|
19
|
+
return role[currentType] ? await evaluateExpression(params, role[currentType], user) : undefined
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const checkFieldsPropertyExists = ({ role }: MachineContext) => {
|
|
23
|
+
return !!Object.keys(role.fields ?? {}).length
|
|
24
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { User } from '../../../auth/dtos'
|
|
2
|
+
import { Params, Role } from '../interface'
|
|
3
|
+
import { StepResult } from './interface'
|
|
4
|
+
import { StateMachine } from './machine'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Executes the validation process using the `StateMachine` for the given role, parameters, and user.
|
|
8
|
+
*
|
|
9
|
+
* @param {Role} role - The role configuration for validation.
|
|
10
|
+
* @param {Params} params - The parameters relevant to the validation process.
|
|
11
|
+
* @param {User} user - The user for whom the validation is being performed.
|
|
12
|
+
*
|
|
13
|
+
* @returns {Promise<StepResult>} - The result of the state machine's validation process.
|
|
14
|
+
*/
|
|
15
|
+
export const checkValidation = async (role: Role, params: Params, user: User, enableLog?: boolean): Promise<StepResult> => {
|
|
16
|
+
const stateMachine = new StateMachine(role, params, user, enableLog)
|
|
17
|
+
return await stateMachine.runValidation()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { Document } from 'mongodb'
|
|
3
|
+
import { User } from '../../../auth/dtos'
|
|
4
|
+
import { Params, Role } from '../interface'
|
|
5
|
+
|
|
6
|
+
export type PrevParams = Record<string, any>
|
|
7
|
+
export interface MachineContext {
|
|
8
|
+
user: User
|
|
9
|
+
role: Role
|
|
10
|
+
params: Params
|
|
11
|
+
prevParams?: PrevParams
|
|
12
|
+
enableLog?: boolean
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type StateFunction = (
|
|
16
|
+
params: RunParams & {
|
|
17
|
+
context: MachineContext
|
|
18
|
+
} & {
|
|
19
|
+
next: (step: string, params?: Record<string, any>) => void
|
|
20
|
+
endValidation: ({ success, document }: { success: boolean, document?: Document }) => void
|
|
21
|
+
goToNextValidationStage: (initialStep?: string | null) => void
|
|
22
|
+
}
|
|
23
|
+
) => Promise<void>
|
|
24
|
+
|
|
25
|
+
export type States = Record<string, StateFunction>
|
|
26
|
+
|
|
27
|
+
export interface RunParams {
|
|
28
|
+
initialStep: string | null
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ValidationStatus {
|
|
32
|
+
status: boolean | null
|
|
33
|
+
document?: Document
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
export interface StepResult { status: boolean | null; nextInitialStep: string | null; document?: Document }
|
|
38
|
+
|
|
39
|
+
export interface EndValidationParams { success: boolean, document?: Document }
|
|
40
|
+
|
|
41
|
+
export type LogMachineInfoParams = {
|
|
42
|
+
enabled?: boolean
|
|
43
|
+
machine: string
|
|
44
|
+
step: number
|
|
45
|
+
stepName: string
|
|
46
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Document } from "mongodb"
|
|
2
|
+
import { User } from "../../../auth/dtos";
|
|
3
|
+
import { Params, Role } from "../interface";
|
|
4
|
+
import { MachineContext, PrevParams, States, StepResult, ValidationStatus } from "./interface";
|
|
5
|
+
import { READ_MACHINE } from "./read";
|
|
6
|
+
import { WRITE_MACHINE } from "./write";
|
|
7
|
+
|
|
8
|
+
export class StateMachine {
|
|
9
|
+
private _context: MachineContext
|
|
10
|
+
private _validation: StepResult = {
|
|
11
|
+
status: null,
|
|
12
|
+
nextInitialStep: null
|
|
13
|
+
}
|
|
14
|
+
private _machines: States[]
|
|
15
|
+
private _currentStep: {
|
|
16
|
+
names: readonly string[]
|
|
17
|
+
states: States
|
|
18
|
+
validation: ValidationStatus,
|
|
19
|
+
completed?: boolean,
|
|
20
|
+
initialStep: string | null
|
|
21
|
+
}
|
|
22
|
+
constructor(role: Role, params: Params, user: User, enableLog?: boolean) {
|
|
23
|
+
this._context = { role, params, user, enableLog }
|
|
24
|
+
this._machines = params.type === "read" ? READ_MACHINE : WRITE_MACHINE
|
|
25
|
+
this._currentStep = {
|
|
26
|
+
names: [],
|
|
27
|
+
states: {},
|
|
28
|
+
validation: {
|
|
29
|
+
status: null
|
|
30
|
+
},
|
|
31
|
+
initialStep: null
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async runValidation() {
|
|
36
|
+
for await (const machine of this._machines) {
|
|
37
|
+
this._currentStep = { names: Object.freeze(Object.keys(machine)) as readonly (keyof typeof machine)[], states: machine, validation: { status: null }, initialStep: null }
|
|
38
|
+
await this.runMachine(this._validation.nextInitialStep);
|
|
39
|
+
|
|
40
|
+
this._validation.nextInitialStep = this._currentStep.initialStep;
|
|
41
|
+
if (this._currentStep.validation.status !== null) {
|
|
42
|
+
this._validation.status = this._currentStep.validation.status;
|
|
43
|
+
this._validation.document = this._currentStep.validation.document;
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return this._validation;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private async runMachine(initialStep: string | null) {
|
|
51
|
+
const executeStep = async (step: keyof typeof this._currentStep.states, params?: PrevParams) => {
|
|
52
|
+
const currentStep = this._currentStep.states[step]
|
|
53
|
+
const next = (nextStep: keyof typeof this._currentStep.states, params?: PrevParams) =>
|
|
54
|
+
executeStep(nextStep, params)
|
|
55
|
+
|
|
56
|
+
await currentStep({
|
|
57
|
+
context: { ...this._context, prevParams: params },
|
|
58
|
+
next,
|
|
59
|
+
endValidation: this.endValidation.bind(this),
|
|
60
|
+
goToNextValidationStage: this.goToNextValidationStage.bind(this),
|
|
61
|
+
initialStep
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
if (this._currentStep.validation.status !== null || this._currentStep.completed !== undefined)
|
|
65
|
+
return { isValid: this._currentStep.validation.status, ...this._currentStep }
|
|
66
|
+
}
|
|
67
|
+
const nextStep = initialStep && this._currentStep.states[initialStep] ? initialStep : this._currentStep.names[0]
|
|
68
|
+
await executeStep(nextStep)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private endValidation({ success, document }: { success: boolean, document?: Document }) {
|
|
72
|
+
this._currentStep.validation.status = success
|
|
73
|
+
if (success) {
|
|
74
|
+
this._currentStep.validation.document = document || this._context.params.cursor
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
private goToNextValidationStage(initialStep: string | null = null) {
|
|
80
|
+
this._currentStep.completed = true
|
|
81
|
+
this._currentStep.initialStep = initialStep
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { States } from '../../interface'
|
|
2
|
+
import { logMachineInfo } from '../../utils'
|
|
3
|
+
|
|
4
|
+
export const STEP_A_STATES: States = {
|
|
5
|
+
checkSearchRequest: async ({ context, next, goToNextValidationStage }) => {
|
|
6
|
+
logMachineInfo({ enabled: context.enableLog, machine: "A", step: 1, stepName: "checkSearchRequest" })
|
|
7
|
+
if (context.params.type === 'search') {
|
|
8
|
+
return next('evaluateSearch')
|
|
9
|
+
}
|
|
10
|
+
return goToNextValidationStage()
|
|
11
|
+
},
|
|
12
|
+
evaluateSearch: async ({ context, endValidation }) => {
|
|
13
|
+
logMachineInfo({ enabled: context.enableLog, machine: "A", step: 2, stepName: "evaluateSearch" })
|
|
14
|
+
// NOTE -> we don't support search operations
|
|
15
|
+
return endValidation({ success: false })
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { evaluateDocumentFiltersFn } from '../../commonValidators'
|
|
2
|
+
import { States } from '../../interface'
|
|
3
|
+
import { logMachineInfo } from '../../utils'
|
|
4
|
+
|
|
5
|
+
export const STEP_B_STATES: States = {
|
|
6
|
+
checkDocumentsFilters: async ({ context, next, goToNextValidationStage }) => {
|
|
7
|
+
logMachineInfo({ enabled: context.enableLog, machine: "B", step: 1, stepName: "checkDocumentsFilters" })
|
|
8
|
+
const { role } = context
|
|
9
|
+
if (role.document_filters) {
|
|
10
|
+
return next('evaluateDocumentsFiltersRead')
|
|
11
|
+
}
|
|
12
|
+
return goToNextValidationStage()
|
|
13
|
+
},
|
|
14
|
+
evaluateDocumentsFiltersRead: async ({ context, next, goToNextValidationStage }) => {
|
|
15
|
+
logMachineInfo({ enabled: context.enableLog, machine: "B", step: 2, stepName: "evaluateDocumentsFiltersRead" })
|
|
16
|
+
const hasDocumentFiltersRead = await evaluateDocumentFiltersFn(context, "read")
|
|
17
|
+
if (!hasDocumentFiltersRead) return next('evaluateDocumentsFiltersWrite')
|
|
18
|
+
return goToNextValidationStage()
|
|
19
|
+
},
|
|
20
|
+
evaluateDocumentsFiltersWrite: async ({
|
|
21
|
+
context,
|
|
22
|
+
endValidation,
|
|
23
|
+
goToNextValidationStage
|
|
24
|
+
}) => {
|
|
25
|
+
logMachineInfo({ enabled: context.enableLog, machine: "B", step: 3, stepName: "evaluateDocumentsFiltersWrite" })
|
|
26
|
+
const check = await evaluateDocumentFiltersFn(context, "write")
|
|
27
|
+
return check ? goToNextValidationStage() : endValidation({ success: false })
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { checkFieldsPropertyExists, evaluateTopLevelPermissionsFn } from '../../commonValidators'
|
|
2
|
+
import { States } from '../../interface'
|
|
3
|
+
import { logMachineInfo } from '../../utils'
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export const STEP_C_STATES: States = {
|
|
7
|
+
evaluateTopLevelRead: async ({ context, next, endValidation }) => {
|
|
8
|
+
logMachineInfo({ enabled: context.enableLog, machine: "C", step: 1, stepName: "evaluateTopLevelRead" })
|
|
9
|
+
const check = await evaluateTopLevelPermissionsFn(context, "read")
|
|
10
|
+
return check
|
|
11
|
+
? endValidation({ success: true })
|
|
12
|
+
: next('evaluateTopLevelWrite', { check })
|
|
13
|
+
},
|
|
14
|
+
evaluateTopLevelWrite: async ({ context, next, endValidation }) => {
|
|
15
|
+
logMachineInfo({ enabled: context.enableLog, machine: "C", step: 2, stepName: "evaluateTopLevelWrite" })
|
|
16
|
+
const check = await evaluateTopLevelPermissionsFn(context, "write")
|
|
17
|
+
if (check) return endValidation({ success: true })
|
|
18
|
+
return context?.prevParams?.check === false
|
|
19
|
+
? endValidation({ success: false })
|
|
20
|
+
: next('checkFieldsProperty')
|
|
21
|
+
},
|
|
22
|
+
checkFieldsProperty: async ({ context, goToNextValidationStage }) => {
|
|
23
|
+
logMachineInfo({ enabled: context.enableLog, machine: "C", step: 3, stepName: "checkFieldsProperty" })
|
|
24
|
+
const check = checkFieldsPropertyExists(context)
|
|
25
|
+
return goToNextValidationStage(
|
|
26
|
+
check ? 'checkIsValidFieldName' : 'checkAdditionalFields'
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { States } from '../../interface'
|
|
2
|
+
import { logMachineInfo } from '../../utils'
|
|
3
|
+
import {
|
|
4
|
+
checkAdditionalFieldsFn,
|
|
5
|
+
checkIsValidFieldNameFn,
|
|
6
|
+
} from './validators'
|
|
7
|
+
|
|
8
|
+
export const STEP_D_STATES: States = {
|
|
9
|
+
checkAdditionalFields: async ({ context, next, endValidation }) => {
|
|
10
|
+
logMachineInfo({ enabled: context.enableLog, machine: "D", step: 1, stepName: "checkAdditionalFields" })
|
|
11
|
+
const check = checkAdditionalFieldsFn(context)
|
|
12
|
+
return check ? next('checkIsValidFieldName') : endValidation({ success: false })
|
|
13
|
+
},
|
|
14
|
+
checkIsValidFieldName: async ({ context, endValidation }) => {
|
|
15
|
+
logMachineInfo({ enabled: context.enableLog, machine: "D", step: 2, stepName: "checkIsValidFieldName" })
|
|
16
|
+
const document = checkIsValidFieldNameFn(context)
|
|
17
|
+
return endValidation({ success: !!Object.keys(document).length, document })
|
|
18
|
+
},
|
|
19
|
+
}
|
|
20
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { MachineContext } from "../../interface"
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export const checkAdditionalFieldsFn = ({ role }: MachineContext) => {
|
|
5
|
+
return !!Object.keys(role.additional_fields || {}).length
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const checkIsValidFieldNameFn = ({ role, params }: MachineContext) => {
|
|
9
|
+
const { cursor } = params
|
|
10
|
+
|
|
11
|
+
const { fields = {}, additional_fields = {} } = role
|
|
12
|
+
const rulesOnId = !!(fields["_id"] || additional_fields["_id"])
|
|
13
|
+
const filteredDocument = Object.entries(cursor).reduce((filteredDocument, [key, value]) => {
|
|
14
|
+
if (fields![key]) {
|
|
15
|
+
return (role.fields![key].read || role.fields![key].write) ? { ...filteredDocument, [key]: value } : filteredDocument
|
|
16
|
+
}
|
|
17
|
+
if (additional_fields[key]) {
|
|
18
|
+
return (additional_fields[key]?.read || additional_fields[key]?.write) ? { ...filteredDocument, [key]: value } : filteredDocument
|
|
19
|
+
}
|
|
20
|
+
return { ...filteredDocument, [key]: value }
|
|
21
|
+
}, {})
|
|
22
|
+
|
|
23
|
+
return (rulesOnId || cursor._id === undefined) ? filteredDocument : { ...filteredDocument, "_id": cursor._id }
|
|
24
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Document, OptionalId } from "mongodb"
|
|
2
|
+
import { User } from "../../../auth/dtos";
|
|
3
|
+
import { Filter } from "../../../features/rules/interface";
|
|
4
|
+
import { getValidRule } from "../../../services/mongodb-atlas/utils";
|
|
5
|
+
import { Role } from "../interface"
|
|
6
|
+
import { LogMachineInfoParams } from "./interface";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Determines the first applicable role for a given user and document.
|
|
10
|
+
*
|
|
11
|
+
* @param {OptionalId<Document> | null} document - The document to check against role conditions.
|
|
12
|
+
* @param {User} user - The user for whom the role is being determined.
|
|
13
|
+
* @param {Role[]} [roles=[]] - The list of available roles to evaluate.
|
|
14
|
+
*
|
|
15
|
+
* @returns {Role | null} - Returns the first role that matches the `apply_when` condition, or `null` if none match.
|
|
16
|
+
*/
|
|
17
|
+
export const getWinningRole = (document: OptionalId<Document> | null, user: User, roles: Role[] = []): Role | null => {
|
|
18
|
+
if (!roles.length) return null
|
|
19
|
+
for (const role of roles) {
|
|
20
|
+
if (checkApplyWhen(role.apply_when, user, document)) {
|
|
21
|
+
return role;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return null
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Checks if the `apply_when` condition is valid for the given user and document.
|
|
29
|
+
*
|
|
30
|
+
* @param {Role["apply_when"]} apply_when - The rule condition to evaluate.
|
|
31
|
+
* @param {User} user - The user for whom the condition is being checked.
|
|
32
|
+
* @param {WithId<Document> | null} document - The document to check against the condition.
|
|
33
|
+
*
|
|
34
|
+
* @returns {boolean} - Returns `true` if at least one valid rule is found, otherwise `false`.
|
|
35
|
+
*/
|
|
36
|
+
export const checkApplyWhen = (apply_when: Role["apply_when"], user: User, document: OptionalId<Document> | null) => {
|
|
37
|
+
const validRule = getValidRule({ filters: [{ apply_when } as Filter], user, record: document })
|
|
38
|
+
return !!validRule.length
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Logs machine step information if logging is enabled.
|
|
43
|
+
*
|
|
44
|
+
* @param {Object} params - The parameters for logging machine info.
|
|
45
|
+
* @param {boolean} params.enabled - Whether logging is enabled.
|
|
46
|
+
* @param {string} params.machine - The name of the machine.
|
|
47
|
+
* @param {number} params.step - The current step number.
|
|
48
|
+
* @param {string} params.stepName - The name of the current step.
|
|
49
|
+
*
|
|
50
|
+
* @returns {void}
|
|
51
|
+
*/
|
|
52
|
+
export const logMachineInfo = ({ enabled, machine, step, stepName }: LogMachineInfoParams) => {
|
|
53
|
+
if (enabled) console.log(`MACHINE ${machine} -> STEP ${step}: ${stepName}`)
|
|
54
|
+
}
|