@flowerforce/flowerbase 1.7.5 → 1.7.6-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/controller.d.ts.map +1 -1
- package/dist/auth/controller.js +11 -10
- package/dist/auth/plugins/jwt.js +1 -1
- package/dist/auth/providers/anon-user/controller.js +1 -1
- package/dist/auth/providers/custom-function/controller.d.ts.map +1 -1
- package/dist/auth/providers/custom-function/controller.js +36 -10
- package/dist/auth/providers/local-userpass/controller.d.ts.map +1 -1
- package/dist/auth/providers/local-userpass/controller.js +15 -14
- package/dist/auth/utils.d.ts +1 -0
- package/dist/auth/utils.d.ts.map +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +4 -3
- package/dist/features/triggers/index.js +1 -1
- package/dist/features/triggers/utils.d.ts.map +1 -1
- package/dist/features/triggers/utils.js +38 -30
- package/dist/monitoring/routes/users.d.ts.map +1 -1
- package/dist/monitoring/routes/users.js +7 -6
- package/dist/monitoring/utils.d.ts.map +1 -1
- package/dist/monitoring/utils.js +5 -4
- package/dist/services/api/index.d.ts +4 -0
- package/dist/services/api/index.d.ts.map +1 -1
- package/dist/services/api/utils.d.ts +1 -0
- package/dist/services/api/utils.d.ts.map +1 -1
- package/dist/services/index.d.ts +4 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/shared/handleUserDeletion.js +1 -1
- package/dist/shared/handleUserRegistration.js +2 -2
- package/dist/utils/context/helpers.d.ts +12 -0
- package/dist/utils/context/helpers.d.ts.map +1 -1
- package/dist/utils/initializer/exposeRoutes.js +1 -1
- package/dist/utils/rules-matcher/interface.d.ts +5 -1
- package/dist/utils/rules-matcher/interface.d.ts.map +1 -1
- package/dist/utils/rules-matcher/interface.js +2 -0
- package/dist/utils/rules-matcher/utils.d.ts.map +1 -1
- package/dist/utils/rules-matcher/utils.js +51 -16
- package/package.json +1 -1
- package/src/auth/__tests__/controller.test.ts +1 -0
- package/src/auth/controller.ts +12 -11
- package/src/auth/plugins/jwt.ts +2 -2
- package/src/auth/providers/anon-user/__tests__/controller.test.ts +1 -0
- package/src/auth/providers/anon-user/controller.ts +2 -2
- package/src/auth/providers/custom-function/controller.ts +39 -12
- package/src/auth/providers/local-userpass/controller.ts +16 -15
- package/src/auth/utils.ts +1 -0
- package/src/constants.ts +3 -2
- package/src/features/triggers/__tests__/index.test.ts +1 -0
- package/src/features/triggers/index.ts +2 -2
- package/src/features/triggers/utils.ts +42 -31
- package/src/monitoring/routes/users.ts +8 -7
- package/src/monitoring/ui.css +5 -1
- package/src/monitoring/ui.events.js +2 -2
- package/src/monitoring/ui.shared.js +2 -1
- package/src/monitoring/utils.ts +6 -5
- package/src/shared/handleUserDeletion.ts +2 -2
- package/src/shared/handleUserRegistration.ts +3 -3
- package/src/utils/__tests__/operators.test.ts +24 -0
- package/src/utils/__tests__/rule.test.ts +39 -0
- package/src/utils/__tests__/rulesMatcherInterfaces.test.ts +2 -0
- package/src/utils/initializer/exposeRoutes.ts +2 -2
- package/src/utils/rules-matcher/interface.ts +5 -1
- package/src/utils/rules-matcher/utils.ts +78 -32
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ObjectId } from 'mongodb'
|
|
1
2
|
import { operators } from '../rules-matcher/utils'
|
|
2
3
|
|
|
3
4
|
describe('operators', () => {
|
|
@@ -8,10 +9,15 @@ describe('operators', () => {
|
|
|
8
9
|
it('should check equals values', () => {
|
|
9
10
|
expect(operators.$eq('a', 'a')).toBe(true)
|
|
10
11
|
expect(!operators.$eq('a', 'b')).toBe(true)
|
|
12
|
+
const id = new ObjectId()
|
|
13
|
+
expect(operators.$eq(id, id.toHexString())).toBe(true)
|
|
14
|
+
expect(operators.$eq(id, new ObjectId(id.toHexString()))).toBe(true)
|
|
11
15
|
})
|
|
12
16
|
it('should check different values', () => {
|
|
13
17
|
expect(operators.$ne('a', 'a')).toBe(false)
|
|
14
18
|
expect(operators.$ne('a', 'b')).toBe(true)
|
|
19
|
+
const id = new ObjectId()
|
|
20
|
+
expect(operators.$ne(id, id.toHexString())).toBe(false)
|
|
15
21
|
})
|
|
16
22
|
it('should check string length values', () => {
|
|
17
23
|
// test $strGt
|
|
@@ -69,6 +75,8 @@ describe('operators', () => {
|
|
|
69
75
|
expect(operators.$in([3, 4], [3, 4, 5])).toBe(true)
|
|
70
76
|
expect(operators.$in([3, 6], [3, 4, 5])).toBe(true)
|
|
71
77
|
expect(operators.$in({ name: 'ciao' }, [{ name: 'ciao' }, 4, 5])).toBe(false)
|
|
78
|
+
const id = new ObjectId()
|
|
79
|
+
expect(operators.$in(id, [id.toHexString()])).toBe(true)
|
|
72
80
|
})
|
|
73
81
|
it("should check if a value isn't in an array", () => {
|
|
74
82
|
expect(operators.$nin(2, [3])).toBe(true)
|
|
@@ -76,6 +84,8 @@ describe('operators', () => {
|
|
|
76
84
|
expect(operators.$nin([3, 4], [3, 4, 5])).toBe(false)
|
|
77
85
|
expect(operators.$nin([3, 6], [3, 4, 5])).toBe(false)
|
|
78
86
|
expect(operators.$nin({ name: 'ciao' }, [{ name: 'ciao' }, 4, 5])).toBe(true)
|
|
87
|
+
const id = new ObjectId()
|
|
88
|
+
expect(operators.$nin(id, [id.toHexString()])).toBe(false)
|
|
79
89
|
})
|
|
80
90
|
it('should find all values in an array', () => {
|
|
81
91
|
expect(operators.$all(2, [3])).toBe(false)
|
|
@@ -85,6 +95,8 @@ describe('operators', () => {
|
|
|
85
95
|
expect(operators.$all([3, 6], [3, 4, 5])).toBe(false)
|
|
86
96
|
expect(operators.$all({ name: 'ciao' }, [{ name: 'ciao' }, 4, 5])).toBe(false)
|
|
87
97
|
expect(operators.$all([{ name: 'ciao' }, 4, 5], [{ name: 'ciao' }, 4, 5])).toBe(false)
|
|
98
|
+
const id = new ObjectId()
|
|
99
|
+
expect(operators.$all([id], [id.toHexString()])).toBe(true)
|
|
88
100
|
})
|
|
89
101
|
it('should check array size', () => {
|
|
90
102
|
expect(operators.$size([1, 2, 3], 3)).toBe(true)
|
|
@@ -100,4 +112,16 @@ describe('operators', () => {
|
|
|
100
112
|
expect(operators.$regex('1234567890', numberRegex)).toBe(true)
|
|
101
113
|
expect(operators.$regex('12345r', numberRegex)).toBe(false)
|
|
102
114
|
})
|
|
115
|
+
|
|
116
|
+
it('should support %stringToOid conversion operator', () => {
|
|
117
|
+
const id = new ObjectId()
|
|
118
|
+
expect(operators['%stringToOid'](id, id.toHexString())).toBe(true)
|
|
119
|
+
expect(operators['%stringToOid'](id, 'not-an-object-id')).toBe(false)
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('should support %oidToString conversion operator', () => {
|
|
123
|
+
const id = new ObjectId()
|
|
124
|
+
expect(operators['%oidToString'](id.toHexString(), id)).toBe(true)
|
|
125
|
+
expect(operators['%oidToString']('not-matching', id)).toBe(false)
|
|
126
|
+
})
|
|
103
127
|
})
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ObjectId } from 'mongodb'
|
|
1
2
|
import rulesMatcherUtils from '../rules-matcher/utils'
|
|
2
3
|
|
|
3
4
|
describe('rule function', () => {
|
|
@@ -46,4 +47,42 @@ describe('rule function', () => {
|
|
|
46
47
|
rulesMatcherUtils.rule(missingOperatorBlock, mockData, mockOptions)
|
|
47
48
|
}).toThrow('Error missing operator:$notFoundOperator')
|
|
48
49
|
})
|
|
50
|
+
|
|
51
|
+
it('should support %stringToOid with $ref values', () => {
|
|
52
|
+
const companyId = new ObjectId()
|
|
53
|
+
const data = {
|
|
54
|
+
user: {
|
|
55
|
+
_id: companyId
|
|
56
|
+
},
|
|
57
|
+
auth: {
|
|
58
|
+
company: companyId.toHexString()
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const result = rulesMatcherUtils.rule({ _id: { '%stringToOid': '$ref:auth.company' } }, data, {
|
|
63
|
+
prefix: 'user'
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
expect(result.valid).toBe(true)
|
|
67
|
+
expect(result.name).toBe('user._id___%stringToOid')
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('should support %oidToString with $ref values', () => {
|
|
71
|
+
const authId = new ObjectId()
|
|
72
|
+
const data = {
|
|
73
|
+
user: {
|
|
74
|
+
authId: authId.toHexString()
|
|
75
|
+
},
|
|
76
|
+
auth: {
|
|
77
|
+
id: authId
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const result = rulesMatcherUtils.rule({ authId: { '%oidToString': '$ref:auth.id' } }, data, {
|
|
82
|
+
prefix: 'user'
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
expect(result.valid).toBe(true)
|
|
86
|
+
expect(result.name).toBe('user.authId___%oidToString')
|
|
87
|
+
})
|
|
49
88
|
})
|
|
@@ -22,6 +22,8 @@ describe('Enums and Types', () => {
|
|
|
22
22
|
expect(RulesOperators.$nin).toBe('$nin')
|
|
23
23
|
expect(RulesOperators.$all).toBe('$all')
|
|
24
24
|
expect(RulesOperators.$regex).toBe('$regex')
|
|
25
|
+
expect(RulesOperators['%stringToOid']).toBe('%stringToOid')
|
|
26
|
+
expect(RulesOperators['%oidToString']).toBe('%oidToString')
|
|
25
27
|
})
|
|
26
28
|
|
|
27
29
|
it('should validate RulesOperatorsInArray type', () => {
|
|
@@ -2,7 +2,7 @@ import { uptime } from 'node:process'
|
|
|
2
2
|
import { FastifyInstance } from 'fastify'
|
|
3
3
|
import { RegistrationDto } from '../../auth/providers/local-userpass/dtos'
|
|
4
4
|
import { AUTH_ENDPOINTS, REGISTRATION_SCHEMA } from '../../auth/utils'
|
|
5
|
-
import { API_VERSION, AUTH_CONFIG,
|
|
5
|
+
import { API_VERSION, AUTH_CONFIG, AUTH_DB_NAME, DEFAULT_CONFIG } from '../../constants'
|
|
6
6
|
import { PROVIDER } from '../../shared/models/handleUserRegistration.model'
|
|
7
7
|
import { hashPassword } from '../crypto'
|
|
8
8
|
|
|
@@ -46,7 +46,7 @@ export const exposeRoutes = async (fastify: FastifyInstance) => {
|
|
|
46
46
|
schema: REGISTRATION_SCHEMA
|
|
47
47
|
}, async function (req, res) {
|
|
48
48
|
const { authCollection } = AUTH_CONFIG
|
|
49
|
-
const db = fastify.mongo.client.db(
|
|
49
|
+
const db = fastify.mongo.client.db(AUTH_DB_NAME)
|
|
50
50
|
const { email, password } = req.body
|
|
51
51
|
const hashedPassword = await hashPassword(password)
|
|
52
52
|
const now = new Date()
|
|
@@ -331,6 +331,8 @@ export type Operators = {
|
|
|
331
331
|
* @returns
|
|
332
332
|
*/
|
|
333
333
|
$regex: OperatorsFunction
|
|
334
|
+
'%stringToOid': OperatorsFunction
|
|
335
|
+
'%oidToString': OperatorsFunction
|
|
334
336
|
}
|
|
335
337
|
|
|
336
338
|
export enum RulesOperators {
|
|
@@ -349,7 +351,9 @@ export enum RulesOperators {
|
|
|
349
351
|
$nin = '$nin',
|
|
350
352
|
$all = '$all',
|
|
351
353
|
$size = '$size',
|
|
352
|
-
$regex = '$regex'
|
|
354
|
+
$regex = '$regex',
|
|
355
|
+
'%stringToOid' = '%stringToOid',
|
|
356
|
+
'%oidToString' = '%oidToString'
|
|
353
357
|
}
|
|
354
358
|
|
|
355
359
|
export type RulesOperatorsInArray<T> = Partial<{
|
|
@@ -1,9 +1,59 @@
|
|
|
1
|
+
import { ObjectId } from 'bson'
|
|
1
2
|
import _get from 'lodash/get'
|
|
2
|
-
import _intersection from 'lodash/intersection'
|
|
3
3
|
import _trimStart from 'lodash/trimStart'
|
|
4
4
|
import { Operators, RulesMatcherUtils, RulesObject } from './interface'
|
|
5
5
|
|
|
6
6
|
const EMPTY_STRING_REGEXP = /^\s*$/
|
|
7
|
+
const HEX_24_REGEXP = /^[a-fA-F0-9]{24}$/
|
|
8
|
+
|
|
9
|
+
const toObjectIdHex = (value: unknown): string | null => {
|
|
10
|
+
if (value instanceof ObjectId) {
|
|
11
|
+
return value.toHexString()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (typeof value === 'string') {
|
|
15
|
+
if (!HEX_24_REGEXP.test(value) || !ObjectId.isValid(value)) {
|
|
16
|
+
return null
|
|
17
|
+
}
|
|
18
|
+
return new ObjectId(value).toHexString()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!value || typeof value !== 'object') {
|
|
22
|
+
return null
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const maybeObjectId = value as { _bsontype?: string; toHexString?: () => string }
|
|
26
|
+
if (maybeObjectId._bsontype === 'ObjectId' && typeof maybeObjectId.toHexString === 'function') {
|
|
27
|
+
const hex = maybeObjectId.toHexString()
|
|
28
|
+
return HEX_24_REGEXP.test(hex) ? hex.toLowerCase() : null
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return null
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const areSemanticallyEqual = (left: unknown, right: unknown): boolean => {
|
|
35
|
+
const leftOid = toObjectIdHex(left)
|
|
36
|
+
const rightOid = toObjectIdHex(right)
|
|
37
|
+
|
|
38
|
+
if (leftOid || rightOid) {
|
|
39
|
+
return leftOid !== null && rightOid !== null && leftOid === rightOid
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return left === right
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const includesWithSemanticEquality = (value: unknown, candidate: unknown): boolean =>
|
|
46
|
+
rulesMatcherUtils
|
|
47
|
+
.forceArray(candidate)
|
|
48
|
+
.some((item) =>
|
|
49
|
+
rulesMatcherUtils
|
|
50
|
+
.forceArray(value)
|
|
51
|
+
.some((sourceItem) =>
|
|
52
|
+
rulesMatcherUtils.forceArray(item).some((candidateItem) =>
|
|
53
|
+
areSemanticallyEqual(sourceItem, candidateItem)
|
|
54
|
+
)
|
|
55
|
+
)
|
|
56
|
+
)
|
|
7
57
|
|
|
8
58
|
/**
|
|
9
59
|
* Defines a utility object named rulesMatcherUtils, which contains various helper functions used for processing rules and data in a rule-matching context.
|
|
@@ -24,10 +74,10 @@ const rulesMatcherUtils: RulesMatcherUtils = {
|
|
|
24
74
|
const valueRef =
|
|
25
75
|
value && String(value).indexOf('$ref:') === 0
|
|
26
76
|
? _get(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
77
|
+
data,
|
|
78
|
+
rulesMatcherUtils.getPath(value.replace('$ref:', ''), prefix),
|
|
79
|
+
undefined
|
|
80
|
+
)
|
|
31
81
|
: value
|
|
32
82
|
|
|
33
83
|
if (!operators[op]) {
|
|
@@ -230,9 +280,9 @@ const rulesMatcherUtils: RulesMatcherUtils = {
|
|
|
230
280
|
export const operators: Operators = {
|
|
231
281
|
$exists: (a, b) => !rulesMatcherUtils.isEmpty(a) === b,
|
|
232
282
|
|
|
233
|
-
$eq: (a, b) => a
|
|
283
|
+
$eq: (a, b) => areSemanticallyEqual(a, b),
|
|
234
284
|
|
|
235
|
-
$ne: (a, b) => a
|
|
285
|
+
$ne: (a, b) => !areSemanticallyEqual(a, b),
|
|
236
286
|
|
|
237
287
|
$gt: (a, b) => rulesMatcherUtils.forceNumber(a) > parseFloat(b),
|
|
238
288
|
|
|
@@ -250,39 +300,35 @@ export const operators: Operators = {
|
|
|
250
300
|
|
|
251
301
|
$strLte: (a, b) => String(a || '').length <= parseFloat(b),
|
|
252
302
|
|
|
253
|
-
$in: (a, b) =>
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
.some(
|
|
257
|
-
(c) =>
|
|
258
|
-
_intersection(rulesMatcherUtils.forceArray(a), rulesMatcherUtils.forceArray(c))
|
|
259
|
-
.length
|
|
260
|
-
),
|
|
261
|
-
|
|
262
|
-
$nin: (a, b) =>
|
|
263
|
-
!rulesMatcherUtils
|
|
264
|
-
.forceArray(b)
|
|
265
|
-
.some(
|
|
266
|
-
(c) =>
|
|
267
|
-
_intersection(rulesMatcherUtils.forceArray(a), rulesMatcherUtils.forceArray(c))
|
|
268
|
-
.length
|
|
269
|
-
),
|
|
303
|
+
$in: (a, b) => includesWithSemanticEquality(a, b),
|
|
304
|
+
|
|
305
|
+
$nin: (a, b) => !includesWithSemanticEquality(a, b),
|
|
270
306
|
|
|
271
307
|
$all: (a, b) =>
|
|
272
|
-
rulesMatcherUtils
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
(
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
308
|
+
rulesMatcherUtils.forceArray(b).every((candidate) =>
|
|
309
|
+
rulesMatcherUtils
|
|
310
|
+
.forceArray(a)
|
|
311
|
+
.some((value) =>
|
|
312
|
+
rulesMatcherUtils.forceArray(candidate).some((item) => areSemanticallyEqual(value, item))
|
|
313
|
+
)
|
|
314
|
+
),
|
|
279
315
|
|
|
280
316
|
$size: (a, b) => Array.isArray(a) && a.length === parseFloat(b),
|
|
281
317
|
|
|
282
318
|
$regex: (a, b, opt) =>
|
|
283
319
|
rulesMatcherUtils
|
|
284
320
|
.forceArray(b)
|
|
285
|
-
.some((c) => (c instanceof RegExp ? c.test(a) : new RegExp(c, opt).test(a)))
|
|
321
|
+
.some((c) => (c instanceof RegExp ? c.test(a) : new RegExp(c, opt).test(a))),
|
|
322
|
+
|
|
323
|
+
'%stringToOid': (a, b) => {
|
|
324
|
+
const converted = toObjectIdHex(b)
|
|
325
|
+
return converted !== null && areSemanticallyEqual(a, converted)
|
|
326
|
+
},
|
|
327
|
+
|
|
328
|
+
'%oidToString': (a, b) => {
|
|
329
|
+
const converted = toObjectIdHex(b)
|
|
330
|
+
return converted !== null && areSemanticallyEqual(a, converted)
|
|
331
|
+
}
|
|
286
332
|
}
|
|
287
333
|
|
|
288
334
|
// export default operators
|