forked from RocketChat/Rocket.Chat
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathisValidQuery.ts
More file actions
66 lines (56 loc) · 1.87 KB
/
isValidQuery.ts
File metadata and controls
66 lines (56 loc) · 1.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import { isRecord } from '@rocket.chat/tools';
import { removeDangerousProps } from './cleanQuery';
type Query = { [k: string]: any };
export const isValidQuery: {
(query: Query, allowedAttributes: string[], allowedOperations: string[]): boolean;
errors: string[];
} = Object.assign(
(query: Query, allowedAttributes: string[], allowedOperations: string[]): boolean => {
isValidQuery.errors = [];
// query is an object with null prototype, so it wont be instance of Object
if (!isRecord(query)) {
throw new Error('query must be an object');
}
return verifyQuery(query, allowedAttributes, allowedOperations);
},
{
errors: [],
},
);
const verifyQuery = (query: Query, allowedAttributes: string[], allowedOperations: string[], parent = ''): boolean => {
return Object.entries(removeDangerousProps({ ...query })).every(([key, value]) => {
const path = parent ? `${parent}.${key}` : key;
if (key.startsWith('$')) {
if (!allowedOperations.includes(key)) {
isValidQuery.errors.push(`Invalid operation: ${key}`);
return false;
}
if (Array.isArray(value)) {
return value.every((v) => verifyQuery(v, allowedAttributes, allowedOperations));
}
if (isRecord(value)) {
return verifyQuery(value, allowedAttributes, allowedOperations, path);
}
// handles primitive values (strings, numbers, booleans, etc.)
return true;
}
if (
!allowedAttributes.some((allowedAttribute) => {
if (allowedAttribute.endsWith('.*')) {
return path.startsWith(allowedAttribute.replace('.*', ''));
}
if (allowedAttribute.endsWith('*') && !allowedAttribute.endsWith('.*')) {
return true;
}
return path === allowedAttribute;
})
) {
isValidQuery.errors.push(`Invalid attribute: ${path}`);
return false;
}
if (isRecord(value)) {
return verifyQuery(value, allowedAttributes, allowedOperations, path);
}
return true;
});
};