@stoker-platform/utils 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/src/access/collection.d.ts +9 -0
- package/lib/src/access/collection.js +59 -0
- package/lib/src/access/document.d.ts +3 -0
- package/lib/src/access/document.js +191 -0
- package/lib/src/access/getCollectionRestrictions.d.ts +7 -0
- package/lib/src/access/getCollectionRestrictions.js +71 -0
- package/lib/src/access/getRecordSubcollections.d.ts +2 -0
- package/lib/src/access/getRecordSubcollections.js +15 -0
- package/lib/src/access/getRelatedCollections.d.ts +2 -0
- package/lib/src/access/getRelatedCollections.js +24 -0
- package/lib/src/access/hasDependencyAccess.d.ts +2 -0
- package/lib/src/access/hasDependencyAccess.js +24 -0
- package/lib/src/access/isPaginationEnabled.d.ts +2 -0
- package/lib/src/access/isPaginationEnabled.js +35 -0
- package/lib/src/access/permissions.d.ts +2 -0
- package/lib/src/access/permissions.js +543 -0
- package/lib/src/access/read/getOne.d.ts +2 -0
- package/lib/src/access/read/getOne.js +19 -0
- package/lib/src/access/read/getSome.d.ts +2 -0
- package/lib/src/access/read/getSome.js +21 -0
- package/lib/src/access/roleHasOperationAccess.d.ts +2 -0
- package/lib/src/access/roleHasOperationAccess.js +7 -0
- package/lib/src/access/write/addRecord.d.ts +2 -0
- package/lib/src/access/write/addRecord.js +40 -0
- package/lib/src/access/write/deleteRecord.d.ts +2 -0
- package/lib/src/access/write/deleteRecord.js +26 -0
- package/lib/src/access/write/updateRecord.d.ts +2 -0
- package/lib/src/access/write/updateRecord.js +61 -0
- package/lib/src/getConfigValue.d.ts +12 -0
- package/lib/src/getConfigValue.js +83 -0
- package/lib/src/getCustomization.d.ts +4 -0
- package/lib/src/getCustomization.js +29 -0
- package/lib/src/getFieldCustomization.d.ts +7 -0
- package/lib/src/getFieldCustomization.js +3 -0
- package/lib/src/main.d.ts +60 -0
- package/lib/src/main.js +60 -0
- package/lib/src/operations/addInitialValues.d.ts +2 -0
- package/lib/src/operations/addInitialValues.js +27 -0
- package/lib/src/operations/addLowercaseFields.d.ts +2 -0
- package/lib/src/operations/addLowercaseFields.js +12 -0
- package/lib/src/operations/addRelationArrays.d.ts +2 -0
- package/lib/src/operations/addRelationArrays.js +60 -0
- package/lib/src/operations/addSystemFields.d.ts +2 -0
- package/lib/src/operations/addSystemFields.js +17 -0
- package/lib/src/operations/getDateRange.d.ts +5 -0
- package/lib/src/operations/getDateRange.js +56 -0
- package/lib/src/operations/getExtendedSchema.d.ts +2 -0
- package/lib/src/operations/getExtendedSchema.js +23 -0
- package/lib/src/operations/getFinalRecord.d.ts +1 -0
- package/lib/src/operations/getFinalRecord.js +11 -0
- package/lib/src/operations/getInputSchema.d.ts +15 -0
- package/lib/src/operations/getInputSchema.js +352 -0
- package/lib/src/operations/getLowercaseFields.d.ts +2 -0
- package/lib/src/operations/getLowercaseFields.js +15 -0
- package/lib/src/operations/getSingleFieldRelations.d.ts +2 -0
- package/lib/src/operations/getSingleFieldRelations.js +27 -0
- package/lib/src/operations/getZodSchema.d.ts +15 -0
- package/lib/src/operations/getZodSchema.js +303 -0
- package/lib/src/operations/isDeleteSentinel.d.ts +1 -0
- package/lib/src/operations/isDeleteSentinel.js +4 -0
- package/lib/src/operations/isSortingEnabled.d.ts +2 -0
- package/lib/src/operations/isSortingEnabled.js +7 -0
- package/lib/src/operations/isValidUniqueFieldValue.d.ts +1 -0
- package/lib/src/operations/isValidUniqueFieldValue.js +25 -0
- package/lib/src/operations/parseDate.d.ts +1 -0
- package/lib/src/operations/parseDate.js +4 -0
- package/lib/src/operations/prepareDenormalized.d.ts +8 -0
- package/lib/src/operations/prepareDenormalized.js +312 -0
- package/lib/src/operations/removeDeleteSentinels.d.ts +2 -0
- package/lib/src/operations/removeDeleteSentinels.js +15 -0
- package/lib/src/operations/removeDeletedFields.d.ts +2 -0
- package/lib/src/operations/removeDeletedFields.js +14 -0
- package/lib/src/operations/removeEmptyStrings.d.ts +2 -0
- package/lib/src/operations/removeEmptyStrings.js +14 -0
- package/lib/src/operations/removePrivateFields.d.ts +2 -0
- package/lib/src/operations/removePrivateFields.js +14 -0
- package/lib/src/operations/removeUndefined.d.ts +2 -0
- package/lib/src/operations/removeUndefined.js +14 -0
- package/lib/src/operations/retryOperation.d.ts +1 -0
- package/lib/src/operations/retryOperation.js +21 -0
- package/lib/src/operations/runHooks.d.ts +17 -0
- package/lib/src/operations/runHooks.js +18 -0
- package/lib/src/operations/sanitizeDownloadFilename.d.ts +1 -0
- package/lib/src/operations/sanitizeDownloadFilename.js +18 -0
- package/lib/src/operations/sanitizeEmailInput.d.ts +5 -0
- package/lib/src/operations/sanitizeEmailInput.js +73 -0
- package/lib/src/operations/updateFieldReference.d.ts +2 -0
- package/lib/src/operations/updateFieldReference.js +14 -0
- package/lib/src/operations/validateRecord.d.ts +2 -0
- package/lib/src/operations/validateRecord.js +18 -0
- package/lib/src/operations/validateStorageName.d.ts +1 -0
- package/lib/src/operations/validateStorageName.js +19 -0
- package/lib/src/schema/getAccessFields.d.ts +2 -0
- package/lib/src/schema/getAccessFields.js +62 -0
- package/lib/src/schema/getCollection.d.ts +2 -0
- package/lib/src/schema/getCollection.js +3 -0
- package/lib/src/schema/getDependencyFields.d.ts +6 -0
- package/lib/src/schema/getDependencyFields.js +22 -0
- package/lib/src/schema/getField.d.ts +2 -0
- package/lib/src/schema/getField.js +3 -0
- package/lib/src/schema/getFieldNames.d.ts +2 -0
- package/lib/src/schema/getFieldNames.js +3 -0
- package/lib/src/schema/getIndexFields.d.ts +9 -0
- package/lib/src/schema/getIndexFields.js +184 -0
- package/lib/src/schema/getInverseRelationType.d.ts +1 -0
- package/lib/src/schema/getInverseRelationType.js +15 -0
- package/lib/src/schema/getPathCollections.d.ts +2 -0
- package/lib/src/schema/getPathCollections.js +12 -0
- package/lib/src/schema/getRecordSystemFields.d.ts +2 -0
- package/lib/src/schema/getRecordSystemFields.js +11 -0
- package/lib/src/schema/getRelationLists.d.ts +5 -0
- package/lib/src/schema/getRelationLists.js +13 -0
- package/lib/src/schema/getSubcollections.d.ts +2 -0
- package/lib/src/schema/getSubcollections.js +9 -0
- package/lib/src/schema/getSystemFieldsSchema.d.ts +2 -0
- package/lib/src/schema/getSystemFieldsSchema.js +52 -0
- package/lib/src/schema/isDependencyField.d.ts +2 -0
- package/lib/src/schema/isDependencyField.js +18 -0
- package/lib/src/schema/isIncludedField.d.ts +2 -0
- package/lib/src/schema/isIncludedField.js +18 -0
- package/lib/src/schema/isRelationField.d.ts +2 -0
- package/lib/src/schema/isRelationField.js +3 -0
- package/lib/src/schema/system-fields.d.ts +2 -0
- package/lib/src/schema/system-fields.js +13 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +35 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CollectionField, CollectionPermissions, CollectionSchema, StokerPermissions } from "@stoker-platform/types";
|
|
2
|
+
export declare const collectionAuthAccess: (permissions: CollectionPermissions) => boolean;
|
|
3
|
+
export declare const collectionAccess: (operation: "Read" | "Create" | "Update" | "Delete", permissions: CollectionPermissions) => boolean | undefined;
|
|
4
|
+
export declare const collectionSomeWriteAccess: (permissions: CollectionPermissions) => boolean | undefined;
|
|
5
|
+
export declare const collectionAllWriteAccess: (permissions: CollectionPermissions) => boolean | undefined;
|
|
6
|
+
export declare const privateFieldAccess: (field: CollectionField, permissions?: StokerPermissions) => boolean | undefined;
|
|
7
|
+
export declare const restrictCreateAccess: (field: CollectionField, permissions?: StokerPermissions) => boolean;
|
|
8
|
+
export declare const restrictUpdateAccess: (field: CollectionField, permissions?: StokerPermissions) => boolean;
|
|
9
|
+
export declare const canUpdateField: (collection: CollectionSchema, field: CollectionField, permissions: StokerPermissions) => boolean | undefined;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export const collectionAuthAccess = (permissions) => {
|
|
2
|
+
return !!permissions.auth;
|
|
3
|
+
};
|
|
4
|
+
export const collectionAccess = (operation, permissions) => {
|
|
5
|
+
if (permissions?.operations) {
|
|
6
|
+
return permissions.operations.includes(operation);
|
|
7
|
+
}
|
|
8
|
+
return;
|
|
9
|
+
};
|
|
10
|
+
export const collectionSomeWriteAccess = (permissions) => {
|
|
11
|
+
if (permissions?.operations) {
|
|
12
|
+
return permissions.operations.some((operation) => operation === "Create" || operation === "Update" || operation === "Delete");
|
|
13
|
+
}
|
|
14
|
+
return;
|
|
15
|
+
};
|
|
16
|
+
export const collectionAllWriteAccess = (permissions) => {
|
|
17
|
+
if (permissions?.operations) {
|
|
18
|
+
return permissions.operations.every((operation) => operation === "Create" || operation === "Update" || operation === "Delete");
|
|
19
|
+
}
|
|
20
|
+
return;
|
|
21
|
+
};
|
|
22
|
+
export const privateFieldAccess = (field, permissions) => {
|
|
23
|
+
if (!permissions)
|
|
24
|
+
return true;
|
|
25
|
+
if (!permissions.Role)
|
|
26
|
+
return false;
|
|
27
|
+
return field.access?.includes(permissions.Role);
|
|
28
|
+
};
|
|
29
|
+
export const restrictCreateAccess = (field, permissions) => {
|
|
30
|
+
if (field.restrictCreate === true)
|
|
31
|
+
return false;
|
|
32
|
+
else if (permissions && typeof field.restrictCreate === "object") {
|
|
33
|
+
if (!permissions.Role)
|
|
34
|
+
return false;
|
|
35
|
+
return field.restrictCreate?.includes(permissions.Role);
|
|
36
|
+
}
|
|
37
|
+
return true;
|
|
38
|
+
};
|
|
39
|
+
export const restrictUpdateAccess = (field, permissions) => {
|
|
40
|
+
if (field.restrictUpdate === true)
|
|
41
|
+
return false;
|
|
42
|
+
else if (permissions && typeof field.restrictUpdate === "object") {
|
|
43
|
+
if (!permissions.Role)
|
|
44
|
+
return false;
|
|
45
|
+
return field.restrictUpdate?.includes(permissions.Role);
|
|
46
|
+
}
|
|
47
|
+
return true;
|
|
48
|
+
};
|
|
49
|
+
export const canUpdateField = (collection, field, permissions) => {
|
|
50
|
+
const { labels } = collection;
|
|
51
|
+
return (permissions.collections &&
|
|
52
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
53
|
+
collectionAccess("Update", permissions.collections[labels.collection]) &&
|
|
54
|
+
(!field.access || privateFieldAccess(field, permissions)) &&
|
|
55
|
+
restrictUpdateAccess(field, permissions) &&
|
|
56
|
+
!(collection.auth &&
|
|
57
|
+
!permissions.collections?.[labels.collection].auth &&
|
|
58
|
+
["Enabled", "Role", "Name", "Email", "Photo_URL"].includes(field.name)));
|
|
59
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { CollectionSchema, CollectionsSchema, StokerPermissions, StokerRecord } from "@stoker-platform/types";
|
|
2
|
+
export declare const documentAccess: (operation: "Read" | "Create" | "Update" | "Delete", collectionSchema: CollectionSchema, schema: CollectionsSchema, userId: string, permissions: StokerPermissions, record: StokerRecord) => boolean;
|
|
3
|
+
export declare const dependencyAccess: (collectionSchema: CollectionSchema, schema: CollectionsSchema, userId: string, permissions: StokerPermissions, record: StokerRecord) => boolean;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { getField } from "../schema/getField.js";
|
|
2
|
+
import { collectionAccess } from "./collection.js";
|
|
3
|
+
import { getAttributeRestrictions, getEntityRestrictions, getEntityParentFilters, } from "../access/getCollectionRestrictions.js";
|
|
4
|
+
import { hasDependencyAccess } from "./hasDependencyAccess.js";
|
|
5
|
+
const filterAccess = (operation, collectionSchema, schema, userId, permissions, record) => {
|
|
6
|
+
const { fields } = collectionSchema;
|
|
7
|
+
const collectionPermissions = permissions.collections?.[collectionSchema.labels.collection];
|
|
8
|
+
let granted = true;
|
|
9
|
+
if (!collectionPermissions) {
|
|
10
|
+
granted = false;
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const hasAttributeRestrictions = getAttributeRestrictions(collectionSchema, permissions);
|
|
14
|
+
const hasEntityRestrictions = getEntityRestrictions(collectionSchema, permissions);
|
|
15
|
+
const hasEntityParentFilters = getEntityParentFilters(collectionSchema, schema, permissions);
|
|
16
|
+
hasAttributeRestrictions
|
|
17
|
+
?.filter((attributeRestriction) => attributeRestriction.type === "Record_Owner")
|
|
18
|
+
.forEach((attributeRestriction) => {
|
|
19
|
+
if ("operations" in attributeRestriction &&
|
|
20
|
+
attributeRestriction.operations &&
|
|
21
|
+
!attributeRestriction.operations.includes(operation))
|
|
22
|
+
return;
|
|
23
|
+
if (record.Created_By !== userId)
|
|
24
|
+
granted = false;
|
|
25
|
+
});
|
|
26
|
+
hasAttributeRestrictions
|
|
27
|
+
?.filter((attributeRestriction) => attributeRestriction.type === "Record_User")
|
|
28
|
+
.forEach((attributeRestriction) => {
|
|
29
|
+
if ("operations" in attributeRestriction &&
|
|
30
|
+
attributeRestriction.operations &&
|
|
31
|
+
!attributeRestriction.operations.includes(operation))
|
|
32
|
+
return;
|
|
33
|
+
const field = getField(fields, attributeRestriction.collectionField);
|
|
34
|
+
if (!record[`${field.name}_Array`]?.includes(permissions.Doc_ID))
|
|
35
|
+
granted = false;
|
|
36
|
+
});
|
|
37
|
+
hasAttributeRestrictions
|
|
38
|
+
?.filter((attributeRestriction) => attributeRestriction.type === "Record_Property")
|
|
39
|
+
.forEach((attributeRestriction) => {
|
|
40
|
+
if ("operations" in attributeRestriction &&
|
|
41
|
+
attributeRestriction.operations &&
|
|
42
|
+
!attributeRestriction.operations.includes(operation))
|
|
43
|
+
return;
|
|
44
|
+
const field = getField(fields, attributeRestriction.propertyField);
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
46
|
+
const recordPropertyRole = attributeRestriction.roles.find((role) => role.role === permissions.Role);
|
|
47
|
+
if (field.type === "Array") {
|
|
48
|
+
if (!recordPropertyRole.values?.some((value) => record[field.name].includes(value)))
|
|
49
|
+
granted = false;
|
|
50
|
+
}
|
|
51
|
+
else if (!recordPropertyRole.values?.includes(record[field.name]))
|
|
52
|
+
granted = false;
|
|
53
|
+
});
|
|
54
|
+
let individualEntityRestrictionPassed = true;
|
|
55
|
+
let hasIndividualEntityRestriction = false;
|
|
56
|
+
hasEntityRestrictions
|
|
57
|
+
?.filter((entityRestriction) => entityRestriction.type === "Individual")
|
|
58
|
+
.forEach(() => {
|
|
59
|
+
hasIndividualEntityRestriction = true;
|
|
60
|
+
if (!collectionPermissions.individualEntities?.includes(record.id))
|
|
61
|
+
individualEntityRestrictionPassed = false;
|
|
62
|
+
});
|
|
63
|
+
let parentEntityRestrictionPassed = true;
|
|
64
|
+
let hasParentEntityRestriction = false;
|
|
65
|
+
hasEntityRestrictions
|
|
66
|
+
?.filter((entityRestriction) => entityRestriction.type === "Parent")
|
|
67
|
+
.forEach((entityRestriction) => {
|
|
68
|
+
hasParentEntityRestriction = true;
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
70
|
+
const field = getField(fields, entityRestriction.collectionField);
|
|
71
|
+
if (!collectionPermissions.parentEntities?.some((entity) => record[`${field.name}_Array`].includes(entity)))
|
|
72
|
+
parentEntityRestrictionPassed = false;
|
|
73
|
+
});
|
|
74
|
+
hasEntityRestrictions
|
|
75
|
+
?.filter((entityRestriction) => entityRestriction.type === "Parent_Property")
|
|
76
|
+
.forEach((entityRestriction) => {
|
|
77
|
+
hasParentEntityRestriction = true;
|
|
78
|
+
const collectionField = getField(fields, entityRestriction.collectionField);
|
|
79
|
+
const propertyField = getField(fields, entityRestriction.propertyField);
|
|
80
|
+
if (!Object.entries(collectionPermissions.parentPropertyEntities || {}).some((property) => {
|
|
81
|
+
const [propertyKey, entities] = property;
|
|
82
|
+
return (propertyKey === record[propertyField.name] &&
|
|
83
|
+
record[`${collectionField.name}_Array`].some((entity) => entities.includes(entity)));
|
|
84
|
+
}))
|
|
85
|
+
parentEntityRestrictionPassed = false;
|
|
86
|
+
});
|
|
87
|
+
if (hasIndividualEntityRestriction && hasParentEntityRestriction) {
|
|
88
|
+
if (!(individualEntityRestrictionPassed || parentEntityRestrictionPassed)) {
|
|
89
|
+
granted = false;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else if (!individualEntityRestrictionPassed || !parentEntityRestrictionPassed) {
|
|
94
|
+
granted = false;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
let individualParentFilterPassed = true;
|
|
98
|
+
let hasIndividualParentFilter = false;
|
|
99
|
+
hasEntityParentFilters
|
|
100
|
+
?.filter((entityParentFilter) => entityParentFilter.parentFilter.type === "Individual")
|
|
101
|
+
.forEach((entityParentFilter) => {
|
|
102
|
+
hasIndividualParentFilter = true;
|
|
103
|
+
const { parentFilter } = entityParentFilter;
|
|
104
|
+
const collectionField = getField(fields, parentFilter.collectionField);
|
|
105
|
+
const parentCollectionPermissions = permissions.collections?.[collectionField.collection];
|
|
106
|
+
if (!parentCollectionPermissions) {
|
|
107
|
+
granted = false;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (!parentCollectionPermissions.individualEntities?.some((entity) => record[`${collectionField.name}_Array`].includes(entity)))
|
|
111
|
+
individualParentFilterPassed = false;
|
|
112
|
+
});
|
|
113
|
+
let parentParentFilterPassed = true;
|
|
114
|
+
let hasParentParentFilter = false;
|
|
115
|
+
hasEntityParentFilters
|
|
116
|
+
?.filter((entityParentFilter) => entityParentFilter.parentFilter.type === "Parent")
|
|
117
|
+
.forEach((entityParentFilter) => {
|
|
118
|
+
hasParentParentFilter = true;
|
|
119
|
+
const { parentFilter } = entityParentFilter;
|
|
120
|
+
const collectionField = getField(fields, parentFilter.collectionField);
|
|
121
|
+
const parentCollectionField = getField(fields, parentFilter.parentCollectionField);
|
|
122
|
+
const parentCollectionPermissions = permissions.collections?.[collectionField.collection];
|
|
123
|
+
if (!parentCollectionPermissions) {
|
|
124
|
+
granted = false;
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (!parentCollectionPermissions.parentEntities?.some((entity) => record[`${parentCollectionField.name}_Array`].includes(entity)))
|
|
128
|
+
parentParentFilterPassed = false;
|
|
129
|
+
});
|
|
130
|
+
hasEntityParentFilters
|
|
131
|
+
?.filter((entityParentFilter) => entityParentFilter.parentFilter.type === "Parent_Property")
|
|
132
|
+
.forEach((entityParentFilter) => {
|
|
133
|
+
hasParentParentFilter = true;
|
|
134
|
+
const { parentFilter } = entityParentFilter;
|
|
135
|
+
const collectionField = getField(fields, parentFilter.collectionField);
|
|
136
|
+
const parentPropertyField = getField(fields, parentFilter.parentPropertyField);
|
|
137
|
+
const parentCollectionField = getField(fields, parentFilter.parentCollectionField);
|
|
138
|
+
const parentCollectionPermissions = permissions.collections?.[collectionField.collection];
|
|
139
|
+
if (!parentCollectionPermissions) {
|
|
140
|
+
granted = false;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (!Object.entries(parentCollectionPermissions.parentPropertyEntities || {}).some((property) => {
|
|
144
|
+
const [propertyKey, entities] = property;
|
|
145
|
+
return (propertyKey === record[parentPropertyField.name] &&
|
|
146
|
+
record[`${parentCollectionField.name}_Array`].some((entity) => entities.includes(entity)));
|
|
147
|
+
}))
|
|
148
|
+
parentParentFilterPassed = false;
|
|
149
|
+
});
|
|
150
|
+
if (hasIndividualParentFilter && hasParentParentFilter) {
|
|
151
|
+
if (!(individualParentFilterPassed || parentParentFilterPassed)) {
|
|
152
|
+
granted = false;
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else if (!individualParentFilterPassed || !parentParentFilterPassed) {
|
|
157
|
+
granted = false;
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
return granted;
|
|
161
|
+
};
|
|
162
|
+
export const documentAccess = (operation, collectionSchema, schema, userId, permissions, record) => {
|
|
163
|
+
const { labels } = collectionSchema;
|
|
164
|
+
const collectionPermissions = permissions.collections?.[labels.collection];
|
|
165
|
+
let granted = true;
|
|
166
|
+
if (!collectionPermissions || !permissions.Role) {
|
|
167
|
+
granted = false;
|
|
168
|
+
return granted;
|
|
169
|
+
}
|
|
170
|
+
if (!collectionAccess(operation, collectionPermissions))
|
|
171
|
+
granted = false;
|
|
172
|
+
const hasEntityRestrictions = getEntityRestrictions(collectionSchema, permissions);
|
|
173
|
+
const hasIndividualEntityRestriction = hasEntityRestrictions?.filter((entityRestriction) => entityRestriction.type === "Individual").length > 0;
|
|
174
|
+
if (operation === "Create" && hasIndividualEntityRestriction)
|
|
175
|
+
granted = false;
|
|
176
|
+
if (!filterAccess(operation, collectionSchema, schema, userId, permissions, record))
|
|
177
|
+
granted = false;
|
|
178
|
+
return granted;
|
|
179
|
+
};
|
|
180
|
+
export const dependencyAccess = (collectionSchema, schema, userId, permissions, record) => {
|
|
181
|
+
let granted = true;
|
|
182
|
+
if (!permissions.Role) {
|
|
183
|
+
granted = false;
|
|
184
|
+
return granted;
|
|
185
|
+
}
|
|
186
|
+
if (hasDependencyAccess(collectionSchema, schema, permissions).length === 0)
|
|
187
|
+
granted = false;
|
|
188
|
+
if (!filterAccess("Read", collectionSchema, schema, userId, permissions, record))
|
|
189
|
+
granted = false;
|
|
190
|
+
return granted;
|
|
191
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { AttributeRestriction, CollectionSchema, CollectionsSchema, EntityParentFilter, EntityRestriction, StokerPermissions } from "@stoker-platform/types";
|
|
2
|
+
export declare const getAttributeRestrictions: (collection: CollectionSchema, permissions: StokerPermissions) => AttributeRestriction[];
|
|
3
|
+
export declare const getEntityRestrictions: (collection: CollectionSchema, permissions: StokerPermissions) => EntityRestriction[];
|
|
4
|
+
export declare const getEntityParentFilters: (collection: CollectionSchema, schema: CollectionsSchema, permissions: StokerPermissions) => {
|
|
5
|
+
parentFilter: EntityParentFilter;
|
|
6
|
+
parentRestriction: EntityRestriction;
|
|
7
|
+
}[];
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { getField } from "../schema/getField.js";
|
|
2
|
+
import { isRelationField } from "../schema/isRelationField.js";
|
|
3
|
+
export const getAttributeRestrictions = (collection, permissions) => {
|
|
4
|
+
const restrictionKeys = {
|
|
5
|
+
Record_Owner: "recordOwner",
|
|
6
|
+
Record_User: "recordUser",
|
|
7
|
+
Record_Property: "recordProperty",
|
|
8
|
+
};
|
|
9
|
+
const restrictions = [];
|
|
10
|
+
const { labels, access } = collection;
|
|
11
|
+
const { attributeRestrictions } = access;
|
|
12
|
+
const collectionPermissions = permissions.collections?.[labels.collection];
|
|
13
|
+
attributeRestrictions?.forEach((attributeRestriction) => {
|
|
14
|
+
if ("roles" in attributeRestriction) {
|
|
15
|
+
attributeRestriction.roles.forEach((role) => {
|
|
16
|
+
const permissionRestriction = collectionPermissions?.[restrictionKeys[attributeRestriction.type]];
|
|
17
|
+
if (role.role === permissions.Role && (!role.assignable || permissionRestriction?.active))
|
|
18
|
+
restrictions.push(attributeRestriction);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
return restrictions;
|
|
23
|
+
};
|
|
24
|
+
export const getEntityRestrictions = (collection, permissions) => {
|
|
25
|
+
const restrictions = [];
|
|
26
|
+
const { labels, access } = collection;
|
|
27
|
+
const { entityRestrictions } = access;
|
|
28
|
+
const collectionPermissions = permissions.collections?.[labels.collection];
|
|
29
|
+
entityRestrictions?.restrictions?.forEach((entityRestriction) => {
|
|
30
|
+
if ("roles" in entityRestriction) {
|
|
31
|
+
entityRestriction.roles.forEach((role) => {
|
|
32
|
+
if (role.role === permissions.Role &&
|
|
33
|
+
(!entityRestrictions.assignable?.includes(permissions.Role) ||
|
|
34
|
+
collectionPermissions?.restrictEntities))
|
|
35
|
+
restrictions.push(entityRestriction);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
return restrictions;
|
|
40
|
+
};
|
|
41
|
+
export const getEntityParentFilters = (collection, schema, permissions) => {
|
|
42
|
+
const parentFilters = [];
|
|
43
|
+
const { access } = collection;
|
|
44
|
+
const { entityRestrictions } = access;
|
|
45
|
+
entityRestrictions?.parentFilters?.forEach((entityParentFilter) => {
|
|
46
|
+
if (!entityParentFilter.roles.some((role) => role.role === permissions.Role))
|
|
47
|
+
return;
|
|
48
|
+
const collectionField = entityParentFilter.collectionField;
|
|
49
|
+
const collectionFieldSchema = getField(collection.fields, collectionField);
|
|
50
|
+
if (!isRelationField(collectionFieldSchema))
|
|
51
|
+
throw new Error("PERMISSION_DENIED");
|
|
52
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
53
|
+
const parentPermissions = permissions.collections?.[collectionFieldSchema.collection];
|
|
54
|
+
const parentCollection = schema.collections[collectionFieldSchema.collection];
|
|
55
|
+
const parentEntityRestrictions = parentCollection.access.entityRestrictions;
|
|
56
|
+
if (!parentEntityRestrictions)
|
|
57
|
+
throw new Error("PERMISSION_DENIED");
|
|
58
|
+
const parentRestriction = parentEntityRestrictions.restrictions?.find((restriction) => restriction.type === entityParentFilter.type &&
|
|
59
|
+
restriction.roles.some((role) => role.role === permissions.Role));
|
|
60
|
+
if (!parentRestriction)
|
|
61
|
+
throw new Error("PERMISSION_DENIED");
|
|
62
|
+
parentRestriction.roles.forEach((role) => {
|
|
63
|
+
if (role.role === permissions.Role &&
|
|
64
|
+
(!parentEntityRestrictions.assignable?.includes(permissions.Role) ||
|
|
65
|
+
parentPermissions?.restrictEntities)) {
|
|
66
|
+
parentFilters.push({ parentFilter: entityParentFilter, parentRestriction });
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
return parentFilters;
|
|
71
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { collectionAccess } from "./collection.js";
|
|
2
|
+
export const getRecordSubcollections = (collectionSchema, schema, permissions) => {
|
|
3
|
+
const { labels } = collectionSchema;
|
|
4
|
+
const subcollections = [];
|
|
5
|
+
for (const collection of Object.values(schema.collections)) {
|
|
6
|
+
const collectionPermissions = permissions?.collections?.[collection.labels.collection];
|
|
7
|
+
if (!collectionPermissions)
|
|
8
|
+
continue;
|
|
9
|
+
if (collection.parentCollection === labels.collection &&
|
|
10
|
+
(!permissions || collectionAccess("Read", collectionPermissions))) {
|
|
11
|
+
subcollections.push(collection);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return subcollections;
|
|
15
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { isRelationField } from "../schema/isRelationField.js";
|
|
2
|
+
import { collectionAccess, privateFieldAccess } from "../access/collection.js";
|
|
3
|
+
import { hasDependencyAccess } from "./hasDependencyAccess.js";
|
|
4
|
+
export const getRelatedCollections = (collectionSchema, schema, permissions) => {
|
|
5
|
+
const relatedCollections = [];
|
|
6
|
+
for (const field of collectionSchema.fields) {
|
|
7
|
+
if (isRelationField(field)) {
|
|
8
|
+
if (field.access && (!permissions || !privateFieldAccess(field, permissions)))
|
|
9
|
+
continue;
|
|
10
|
+
const relatedCollection = schema.collections[field.collection];
|
|
11
|
+
if (!relatedCollection)
|
|
12
|
+
continue;
|
|
13
|
+
const relatedCollectionPermissions = permissions?.collections?.[field.collection];
|
|
14
|
+
if (!relatedCollectionPermissions)
|
|
15
|
+
continue;
|
|
16
|
+
if (!permissions ||
|
|
17
|
+
collectionAccess("Read", relatedCollectionPermissions) ||
|
|
18
|
+
hasDependencyAccess(collectionSchema, schema, permissions)) {
|
|
19
|
+
relatedCollections.push(field.collection);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return Array.from(new Set(relatedCollections));
|
|
24
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { privateFieldAccess } from "./collection.js";
|
|
2
|
+
import { isRelationField } from "../schema/isRelationField.js";
|
|
3
|
+
export const hasDependencyAccess = (collection, schema, permissions) => {
|
|
4
|
+
const collections = Object.values(schema.collections);
|
|
5
|
+
const { labels } = collection;
|
|
6
|
+
const hasDependencyAccess = [];
|
|
7
|
+
for (const collectionSchema of collections) {
|
|
8
|
+
const { fields: dependencyFields } = collectionSchema;
|
|
9
|
+
for (const field of dependencyFields) {
|
|
10
|
+
if (field.access && !privateFieldAccess(field, permissions))
|
|
11
|
+
continue;
|
|
12
|
+
if (!permissions.Role)
|
|
13
|
+
continue;
|
|
14
|
+
if (isRelationField(field) && field.collection === labels.collection && field.dependencyFields) {
|
|
15
|
+
for (const dependencyField of field.dependencyFields) {
|
|
16
|
+
const existingField = hasDependencyAccess.find((field) => field.field === dependencyField.field);
|
|
17
|
+
if (!existingField && dependencyField.roles.includes(permissions.Role))
|
|
18
|
+
hasDependencyAccess.push(dependencyField);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return hasDependencyAccess;
|
|
24
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { getField } from "../schema/getField.js";
|
|
2
|
+
import { isRelationField } from "../schema/isRelationField.js";
|
|
3
|
+
export const isPaginationEnabled = (role, collectionSchema, schema) => {
|
|
4
|
+
const { access } = collectionSchema;
|
|
5
|
+
const { entityRestrictions } = access;
|
|
6
|
+
if (entityRestrictions?.restrictions) {
|
|
7
|
+
for (const restriction of entityRestrictions.restrictions) {
|
|
8
|
+
if (restriction.roles?.some((accessRole) => accessRole.role === role)) {
|
|
9
|
+
if (!("singleQuery" in restriction && restriction.singleQuery)) {
|
|
10
|
+
return `${restriction.type} entity restriction`;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
if (entityRestrictions?.parentFilters) {
|
|
16
|
+
for (const parentFilter of entityRestrictions.parentFilters) {
|
|
17
|
+
if (!parentFilter.roles.some((accessRole) => accessRole.role === role))
|
|
18
|
+
continue;
|
|
19
|
+
const collectionFieldSchema = getField(collectionSchema.fields, parentFilter.collectionField);
|
|
20
|
+
if (!isRelationField(collectionFieldSchema))
|
|
21
|
+
throw new Error("PERMISSION_DENIED");
|
|
22
|
+
const parentCollection = schema.collections[collectionFieldSchema.collection];
|
|
23
|
+
const parentRestriction = parentCollection.access.entityRestrictions?.restrictions?.find((restriction) => restriction.type === parentFilter.type &&
|
|
24
|
+
restriction.roles.some((accessRole) => accessRole.role === role));
|
|
25
|
+
if (!parentRestriction)
|
|
26
|
+
throw new Error("PERMISSION_DENIED");
|
|
27
|
+
if (parentRestriction.type !== parentFilter.type)
|
|
28
|
+
throw new Error("PERMISSION_DENIED");
|
|
29
|
+
if (!("singleQuery" in parentRestriction && parentRestriction.singleQuery)) {
|
|
30
|
+
return `${parentFilter.type} parent filter`;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { CollectionSchema, CollectionsSchema, StokerPermissions, StokerRecord } from "@stoker-platform/types";
|
|
2
|
+
export declare const permissionsWriteAccess: (operation: "create" | "update" | "delete", record: StokerRecord, docId: string, collectionSchema: CollectionSchema, schema: CollectionsSchema, currentUserId?: string, currentUserPermissions?: StokerPermissions, permissions?: StokerPermissions, originalPermissions?: StokerPermissions, originalRecord?: StokerRecord, userOperation?: string) => boolean;
|