@stoker-platform/utils 0.5.77 → 0.5.79
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 +4 -4
- package/lib/src/access/collection.js +28 -18
- package/lib/src/access/document.d.ts +1 -1
- package/lib/src/access/document.js +2 -2
- package/lib/src/access/fieldAccess.d.ts +8 -0
- package/lib/src/access/fieldAccess.js +78 -0
- package/lib/src/access/getRelatedCollections.d.ts +1 -1
- package/lib/src/access/getRelatedCollections.js +3 -3
- package/lib/src/access/hasDependencyAccess.d.ts +1 -1
- package/lib/src/access/hasDependencyAccess.js +2 -2
- package/lib/src/access/write/addRecord.d.ts +1 -1
- package/lib/src/access/write/addRecord.js +3 -3
- package/lib/src/access/write/updateRecord.d.ts +1 -1
- package/lib/src/access/write/updateRecord.js +3 -3
- package/lib/src/main.d.ts +2 -1
- package/lib/src/main.js +2 -1
- package/lib/src/operations/addInitialValues.d.ts +2 -2
- package/lib/src/operations/addInitialValues.js +4 -3
- package/lib/src/operations/prepareDenormalized.js +91 -1
- package/lib/src/schema/getIndexFields.d.ts +3 -0
- package/lib/src/schema/getIndexFields.js +79 -13
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -3,7 +3,7 @@ export declare const collectionAuthAccess: (permissions: CollectionPermissions)
|
|
|
3
3
|
export declare const collectionAccess: (operation: "Read" | "Create" | "Update" | "Delete", permissions: CollectionPermissions) => boolean | undefined;
|
|
4
4
|
export declare const collectionSomeWriteAccess: (permissions: CollectionPermissions) => boolean | undefined;
|
|
5
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;
|
|
6
|
+
export declare const privateFieldAccess: (field: CollectionField, permissions?: StokerPermissions, collection?: CollectionSchema, claims?: Record<string, unknown>) => boolean | undefined;
|
|
7
|
+
export declare const restrictCreateAccess: (field: CollectionField, permissions?: StokerPermissions, collectionName?: string, claims?: Record<string, unknown>) => boolean;
|
|
8
|
+
export declare const restrictUpdateAccess: (field: CollectionField, permissions?: StokerPermissions, collectionName?: string, claims?: Record<string, unknown>) => boolean;
|
|
9
|
+
export declare const canUpdateField: (collection: CollectionSchema, field: CollectionField, permissions: StokerPermissions, claims: Record<string, unknown>) => boolean | undefined;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { evaluateFieldAccessCondition, fieldAccessGroupAccess, isFieldAccessGroupReference } from "./fieldAccess.js";
|
|
1
2
|
export const collectionAuthAccess = (permissions) => {
|
|
2
3
|
return !!permissions.auth;
|
|
3
4
|
};
|
|
@@ -19,44 +20,53 @@ export const collectionAllWriteAccess = (permissions) => {
|
|
|
19
20
|
}
|
|
20
21
|
return;
|
|
21
22
|
};
|
|
22
|
-
export const privateFieldAccess = (field, permissions) => {
|
|
23
|
+
export const privateFieldAccess = (field, permissions, collection, claims) => {
|
|
23
24
|
if (!permissions)
|
|
24
25
|
return true;
|
|
25
26
|
if (!permissions.Role)
|
|
26
27
|
return false;
|
|
28
|
+
if (isFieldAccessGroupReference(field.access)) {
|
|
29
|
+
if (!collection || !claims)
|
|
30
|
+
return false;
|
|
31
|
+
return fieldAccessGroupAccess(field, collection, permissions, claims);
|
|
32
|
+
}
|
|
27
33
|
return field.access?.includes(permissions.Role);
|
|
28
34
|
};
|
|
29
|
-
|
|
30
|
-
if (
|
|
31
|
-
return true;
|
|
32
|
-
if (!permissions.Role)
|
|
33
|
-
return false;
|
|
34
|
-
if (field.restrictCreate === true)
|
|
35
|
+
const restrictWriteAccess = (restriction, permissions, collectionName, claims) => {
|
|
36
|
+
if (restriction === true)
|
|
35
37
|
return false;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
if (Array.isArray(restriction)) {
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
40
|
+
return restriction.includes(permissions.Role);
|
|
41
|
+
}
|
|
42
|
+
if (typeof restriction === "object" && restriction !== null) {
|
|
43
|
+
if (!collectionName || !claims)
|
|
44
|
+
return false;
|
|
45
|
+
return evaluateFieldAccessCondition(restriction, collectionName, permissions, claims);
|
|
38
46
|
}
|
|
39
47
|
return true;
|
|
40
48
|
};
|
|
41
|
-
export const
|
|
49
|
+
export const restrictCreateAccess = (field, permissions, collectionName, claims) => {
|
|
42
50
|
if (!permissions)
|
|
43
51
|
return true;
|
|
44
52
|
if (!permissions.Role)
|
|
45
53
|
return false;
|
|
46
|
-
|
|
54
|
+
return restrictWriteAccess(field.restrictCreate, permissions, collectionName, claims);
|
|
55
|
+
};
|
|
56
|
+
export const restrictUpdateAccess = (field, permissions, collectionName, claims) => {
|
|
57
|
+
if (!permissions)
|
|
58
|
+
return true;
|
|
59
|
+
if (!permissions.Role)
|
|
47
60
|
return false;
|
|
48
|
-
|
|
49
|
-
return field.restrictUpdate?.includes(permissions.Role);
|
|
50
|
-
}
|
|
51
|
-
return true;
|
|
61
|
+
return restrictWriteAccess(field.restrictUpdate, permissions, collectionName, claims);
|
|
52
62
|
};
|
|
53
|
-
export const canUpdateField = (collection, field, permissions) => {
|
|
63
|
+
export const canUpdateField = (collection, field, permissions, claims) => {
|
|
54
64
|
const { labels } = collection;
|
|
55
65
|
return (permissions.collections &&
|
|
56
66
|
// eslint-disable-next-line security/detect-object-injection
|
|
57
67
|
collectionAccess("Update", permissions.collections[labels.collection]) &&
|
|
58
|
-
(!field.access || privateFieldAccess(field, permissions)) &&
|
|
59
|
-
restrictUpdateAccess(field, permissions) &&
|
|
68
|
+
(!field.access || privateFieldAccess(field, permissions, collection, claims)) &&
|
|
69
|
+
restrictUpdateAccess(field, permissions, labels.collection, claims) &&
|
|
60
70
|
!(collection.auth &&
|
|
61
71
|
!permissions.collections?.[labels.collection].auth &&
|
|
62
72
|
["Enabled", "Role", "Name", "Email", "Photo_URL"].includes(field.name)));
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { CollectionSchema, CollectionsSchema, StokerPermissions, StokerRecord } from "@stoker-platform/types";
|
|
2
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;
|
|
3
|
+
export declare const dependencyAccess: (collectionSchema: CollectionSchema, schema: CollectionsSchema, userId: string, permissions: StokerPermissions, record: StokerRecord, claims: Record<string, unknown>) => boolean;
|
|
@@ -177,13 +177,13 @@ export const documentAccess = (operation, collectionSchema, schema, userId, perm
|
|
|
177
177
|
granted = false;
|
|
178
178
|
return granted;
|
|
179
179
|
};
|
|
180
|
-
export const dependencyAccess = (collectionSchema, schema, userId, permissions, record) => {
|
|
180
|
+
export const dependencyAccess = (collectionSchema, schema, userId, permissions, record, claims) => {
|
|
181
181
|
let granted = true;
|
|
182
182
|
if (!permissions.Role) {
|
|
183
183
|
granted = false;
|
|
184
184
|
return granted;
|
|
185
185
|
}
|
|
186
|
-
if (hasDependencyAccess(collectionSchema, schema, permissions).length === 0)
|
|
186
|
+
if (hasDependencyAccess(collectionSchema, schema, permissions, claims).length === 0)
|
|
187
187
|
granted = false;
|
|
188
188
|
if (!filterAccess("Read", collectionSchema, schema, userId, permissions, record, true))
|
|
189
189
|
granted = false;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CollectionField, CollectionSchema, FieldAccessCondition, FieldAccessGroupReference, StokerPermissions, StokerRole } from "@stoker-platform/types";
|
|
2
|
+
export declare const isFieldAccessGroupReference: (access?: StokerRole[] | FieldAccessGroupReference) => access is FieldAccessGroupReference;
|
|
3
|
+
export declare const getFieldAccessRoles: (access?: StokerRole[] | FieldAccessGroupReference) => StokerRole[] | undefined;
|
|
4
|
+
export declare const fieldRoleProjectionAccess: (field: CollectionField, role: StokerRole) => boolean;
|
|
5
|
+
export declare const getFieldAccessGroupCondition: (field: CollectionField, collection: CollectionSchema) => FieldAccessCondition | undefined;
|
|
6
|
+
export declare const getFieldAccessGroupFields: (collection: CollectionSchema) => Record<string, CollectionField[]>;
|
|
7
|
+
export declare const evaluateFieldAccessCondition: (condition: FieldAccessCondition, collectionName: string, permissions?: StokerPermissions, claims?: Record<string, unknown>) => boolean;
|
|
8
|
+
export declare const fieldAccessGroupAccess: (field: CollectionField, collection: CollectionSchema, permissions: StokerPermissions, claims: Record<string, unknown>) => boolean;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export const isFieldAccessGroupReference = (access) => {
|
|
2
|
+
return !!access && !Array.isArray(access);
|
|
3
|
+
};
|
|
4
|
+
export const getFieldAccessRoles = (access) => {
|
|
5
|
+
return Array.isArray(access) ? access : undefined;
|
|
6
|
+
};
|
|
7
|
+
export const fieldRoleProjectionAccess = (field, role) => {
|
|
8
|
+
if (!field.access)
|
|
9
|
+
return true;
|
|
10
|
+
if (isFieldAccessGroupReference(field.access))
|
|
11
|
+
return false;
|
|
12
|
+
return field.access.includes(role);
|
|
13
|
+
};
|
|
14
|
+
export const getFieldAccessGroupCondition = (field, collection) => {
|
|
15
|
+
if (!isFieldAccessGroupReference(field.access))
|
|
16
|
+
return;
|
|
17
|
+
return collection.fieldAccessGroups?.[field.access.group];
|
|
18
|
+
};
|
|
19
|
+
export const getFieldAccessGroupFields = (collection) => {
|
|
20
|
+
const groups = {};
|
|
21
|
+
Object.keys(collection.fieldAccessGroups || {}).forEach((key) => {
|
|
22
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
23
|
+
groups[key] = [];
|
|
24
|
+
});
|
|
25
|
+
collection.fields.forEach((field) => {
|
|
26
|
+
if (isFieldAccessGroupReference(field.access)) {
|
|
27
|
+
const { group } = field.access;
|
|
28
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
29
|
+
if (groups[group])
|
|
30
|
+
groups[group].push(field);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return groups;
|
|
34
|
+
};
|
|
35
|
+
export const evaluateFieldAccessCondition = (condition, collectionName, permissions, claims) => {
|
|
36
|
+
if (!permissions)
|
|
37
|
+
return true;
|
|
38
|
+
if (permissions.Role && !condition.applicableRoles.includes(permissions.Role))
|
|
39
|
+
return false;
|
|
40
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
41
|
+
const collectionPermissions = permissions.collections?.[collectionName];
|
|
42
|
+
const checks = [];
|
|
43
|
+
if (condition.collectionAuth !== undefined) {
|
|
44
|
+
checks.push(!!collectionPermissions?.auth === condition.collectionAuth);
|
|
45
|
+
}
|
|
46
|
+
if (condition.roles) {
|
|
47
|
+
checks.push(!!permissions.Role && condition.roles.includes(permissions.Role));
|
|
48
|
+
}
|
|
49
|
+
if (condition.claims) {
|
|
50
|
+
checks.push(Object.entries(condition.claims).every(([claim, expected]) => {
|
|
51
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
52
|
+
let value = claims?.[claim];
|
|
53
|
+
if (value === undefined && claim === "role")
|
|
54
|
+
value = permissions.Role;
|
|
55
|
+
if (Array.isArray(expected))
|
|
56
|
+
return expected.some((item) => item === value);
|
|
57
|
+
return value === expected;
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
if (condition.restrictions) {
|
|
61
|
+
const { recordOwner, recordUser, recordProperty, restrictEntities } = condition.restrictions;
|
|
62
|
+
checks.push((recordOwner === undefined || !!collectionPermissions?.recordOwner?.active === recordOwner) &&
|
|
63
|
+
(recordUser === undefined || !!collectionPermissions?.recordUser?.active === recordUser) &&
|
|
64
|
+
(recordProperty === undefined || !!collectionPermissions?.recordProperty?.active === recordProperty) &&
|
|
65
|
+
(restrictEntities === undefined || !!collectionPermissions?.restrictEntities === restrictEntities));
|
|
66
|
+
}
|
|
67
|
+
if (checks.length === 0)
|
|
68
|
+
return false;
|
|
69
|
+
if (condition.match === "all")
|
|
70
|
+
return checks.every(Boolean);
|
|
71
|
+
return checks.some(Boolean);
|
|
72
|
+
};
|
|
73
|
+
export const fieldAccessGroupAccess = (field, collection, permissions, claims) => {
|
|
74
|
+
const condition = getFieldAccessGroupCondition(field, collection);
|
|
75
|
+
if (!condition)
|
|
76
|
+
return false;
|
|
77
|
+
return evaluateFieldAccessCondition(condition, collection.labels.collection, permissions, claims);
|
|
78
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { CollectionSchema, CollectionsSchema, StokerPermissions } from "@stoker-platform/types";
|
|
2
|
-
export declare const getRelatedCollections: (collectionSchema: CollectionSchema, schema: CollectionsSchema, permissions?: StokerPermissions) => string[];
|
|
2
|
+
export declare const getRelatedCollections: (collectionSchema: CollectionSchema, schema: CollectionsSchema, permissions?: StokerPermissions, claims?: Record<string, unknown>) => string[];
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { isRelationField } from "../schema/isRelationField.js";
|
|
2
2
|
import { collectionAccess, privateFieldAccess } from "../access/collection.js";
|
|
3
3
|
import { hasDependencyAccess } from "./hasDependencyAccess.js";
|
|
4
|
-
export const getRelatedCollections = (collectionSchema, schema, permissions) => {
|
|
4
|
+
export const getRelatedCollections = (collectionSchema, schema, permissions, claims) => {
|
|
5
5
|
const relatedCollections = [];
|
|
6
6
|
for (const field of collectionSchema.fields) {
|
|
7
7
|
if (isRelationField(field)) {
|
|
8
|
-
if (field.access && (!permissions || !privateFieldAccess(field, permissions)))
|
|
8
|
+
if (field.access && (!permissions || !privateFieldAccess(field, permissions, collectionSchema, claims)))
|
|
9
9
|
continue;
|
|
10
10
|
const relatedCollection = schema.collections[field.collection];
|
|
11
11
|
if (!relatedCollection)
|
|
@@ -15,7 +15,7 @@ export const getRelatedCollections = (collectionSchema, schema, permissions) =>
|
|
|
15
15
|
continue;
|
|
16
16
|
if (!permissions ||
|
|
17
17
|
collectionAccess("Read", relatedCollectionPermissions) ||
|
|
18
|
-
hasDependencyAccess(collectionSchema, schema, permissions)) {
|
|
18
|
+
hasDependencyAccess(collectionSchema, schema, permissions, claims ?? {})) {
|
|
19
19
|
relatedCollections.push(field.collection);
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { CollectionSchema, CollectionsSchema, DependencyField, StokerPermissions } from "@stoker-platform/types";
|
|
2
|
-
export declare const hasDependencyAccess: (collection: CollectionSchema, schema: CollectionsSchema, permissions: StokerPermissions) => DependencyField[];
|
|
2
|
+
export declare const hasDependencyAccess: (collection: CollectionSchema, schema: CollectionsSchema, permissions: StokerPermissions, claims: Record<string, unknown>) => DependencyField[];
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { privateFieldAccess } from "./collection.js";
|
|
2
2
|
import { isRelationField } from "../schema/isRelationField.js";
|
|
3
|
-
export const hasDependencyAccess = (collection, schema, permissions) => {
|
|
3
|
+
export const hasDependencyAccess = (collection, schema, permissions, claims) => {
|
|
4
4
|
const collections = Object.values(schema.collections);
|
|
5
5
|
const { labels } = collection;
|
|
6
6
|
const hasDependencyAccess = [];
|
|
7
7
|
for (const collectionSchema of collections) {
|
|
8
8
|
const { fields: dependencyFields } = collectionSchema;
|
|
9
9
|
for (const field of dependencyFields) {
|
|
10
|
-
if (field.access && !privateFieldAccess(field, permissions))
|
|
10
|
+
if (field.access && !privateFieldAccess(field, permissions, collectionSchema, claims))
|
|
11
11
|
continue;
|
|
12
12
|
if (!permissions.Role)
|
|
13
13
|
continue;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { CollectionSchema, CollectionsSchema, StokerPermissions, StokerRecord } from "@stoker-platform/types";
|
|
2
|
-
export declare const addRecordAccessControl: (record: StokerRecord, docId: string, collectionSchema: CollectionSchema, schema: CollectionsSchema, currentUserId?: string, currentUserPermissions?: StokerPermissions, permissions?: StokerPermissions) => void;
|
|
2
|
+
export declare const addRecordAccessControl: (record: StokerRecord, docId: string, collectionSchema: CollectionSchema, schema: CollectionsSchema, currentUserId?: string, currentUserPermissions?: StokerPermissions, permissions?: StokerPermissions, claims?: Record<string, unknown>) => void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { collectionAccess, collectionAuthAccess, privateFieldAccess, restrictCreateAccess } from "../collection.js";
|
|
2
2
|
import { documentAccess } from "../document.js";
|
|
3
3
|
import { permissionsWriteAccess } from "../permissions.js";
|
|
4
|
-
export const addRecordAccessControl = (record, docId, collectionSchema, schema, currentUserId, currentUserPermissions, permissions) => {
|
|
4
|
+
export const addRecordAccessControl = (record, docId, collectionSchema, schema, currentUserId, currentUserPermissions, permissions, claims) => {
|
|
5
5
|
const { labels, fields } = collectionSchema;
|
|
6
6
|
// eslint-disable-next-line security/detect-object-injection
|
|
7
7
|
const collectionPermissions = currentUserPermissions?.collections?.[labels.collection];
|
|
@@ -27,11 +27,11 @@ export const addRecordAccessControl = (record, docId, collectionSchema, schema,
|
|
|
27
27
|
for (const field of fields) {
|
|
28
28
|
const value = record[field.name];
|
|
29
29
|
if (field.access) {
|
|
30
|
-
if (!privateFieldAccess(field, currentUserPermissions) && value !== undefined) {
|
|
30
|
+
if (!privateFieldAccess(field, currentUserPermissions, collectionSchema, claims) && value !== undefined) {
|
|
31
31
|
granted = false;
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
-
if (value !== undefined && !restrictCreateAccess(field, currentUserPermissions))
|
|
34
|
+
if (value !== undefined && !restrictCreateAccess(field, currentUserPermissions, labels.collection, claims))
|
|
35
35
|
granted = false;
|
|
36
36
|
}
|
|
37
37
|
if (!granted)
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { CollectionSchema, CollectionsSchema, StokerPermissions, StokerRecord } from "@stoker-platform/types";
|
|
2
|
-
export declare const updateRecordAccessControl: (partial: StokerRecord, originalRecord: StokerRecord, docId: string, collectionSchema: CollectionSchema, schema: CollectionsSchema, currentUserId?: string, currentUserPermissions?: StokerPermissions, userOperation?: string, permissions?: StokerPermissions, originalPermissions?: StokerPermissions | undefined) => void;
|
|
2
|
+
export declare const updateRecordAccessControl: (partial: StokerRecord, originalRecord: StokerRecord, docId: string, collectionSchema: CollectionSchema, schema: CollectionsSchema, currentUserId?: string, currentUserPermissions?: StokerPermissions, userOperation?: string, permissions?: StokerPermissions, originalPermissions?: StokerPermissions | undefined, claims?: Record<string, unknown>) => void;
|
|
@@ -2,7 +2,7 @@ import { collectionAccess, collectionAuthAccess, privateFieldAccess, restrictUpd
|
|
|
2
2
|
import { documentAccess } from "../document.js";
|
|
3
3
|
import { permissionsWriteAccess } from "../permissions.js";
|
|
4
4
|
import { removeDeleteSentinels } from "../../operations/removeDeleteSentinels.js";
|
|
5
|
-
export const updateRecordAccessControl = (partial, originalRecord, docId, collectionSchema, schema, currentUserId, currentUserPermissions, userOperation, permissions, originalPermissions) => {
|
|
5
|
+
export const updateRecordAccessControl = (partial, originalRecord, docId, collectionSchema, schema, currentUserId, currentUserPermissions, userOperation, permissions, originalPermissions, claims) => {
|
|
6
6
|
const { labels, fields } = collectionSchema;
|
|
7
7
|
// eslint-disable-next-line security/detect-object-injection
|
|
8
8
|
const collectionPermissions = currentUserPermissions?.collections?.[labels.collection];
|
|
@@ -50,12 +50,12 @@ export const updateRecordAccessControl = (partial, originalRecord, docId, collec
|
|
|
50
50
|
for (const field of fields) {
|
|
51
51
|
const value = partial[field.name];
|
|
52
52
|
if (field.access) {
|
|
53
|
-
if (!privateFieldAccess(field, currentUserPermissions) && value !== undefined) {
|
|
53
|
+
if (!privateFieldAccess(field, currentUserPermissions, collectionSchema, claims) && value !== undefined) {
|
|
54
54
|
errorDetails = `Authenticated user does not have access to field ${field.name}`;
|
|
55
55
|
granted = false;
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
if (value !== undefined && !restrictUpdateAccess(field, currentUserPermissions)) {
|
|
58
|
+
if (value !== undefined && !restrictUpdateAccess(field, currentUserPermissions, labels.collection, claims)) {
|
|
59
59
|
errorDetails = `Authenticated user does not have Update access to field ${field.name}`;
|
|
60
60
|
granted = false;
|
|
61
61
|
}
|
package/lib/src/main.d.ts
CHANGED
|
@@ -20,7 +20,8 @@ export { getCollection } from "./schema/getCollection.js";
|
|
|
20
20
|
export { getDependencyFields } from "./schema/getDependencyFields.js";
|
|
21
21
|
export { getField } from "./schema/getField.js";
|
|
22
22
|
export { getFieldNames } from "./schema/getFieldNames.js";
|
|
23
|
-
export { getRoleFields, getDependencyAccessFields, getDependencyIndexFields, getRoleGroups, getRoleGroup, getRoleExcludedFields, getUserRoleGroups, getAllRoleGroups, } from "./schema/getIndexFields.js";
|
|
23
|
+
export { getRoleFields, getDependencyAccessFields, getDependencyIndexFields, getFieldAccessGroupIndexFields, getFieldAccessGroupRoles, getFieldAccessGroupKey, getRoleGroups, getRoleGroup, getRoleExcludedFields, getUserRoleGroups, getAllRoleGroups, } from "./schema/getIndexFields.js";
|
|
24
|
+
export { isFieldAccessGroupReference, getFieldAccessRoles, fieldRoleProjectionAccess, getFieldAccessGroupCondition, getFieldAccessGroupFields, evaluateFieldAccessCondition, fieldAccessGroupAccess, } from "./access/fieldAccess.js";
|
|
24
25
|
export { getAccessFields } from "./schema/getAccessFields.js";
|
|
25
26
|
export { getSystemFieldsSchema } from "./schema/getSystemFieldsSchema.js";
|
|
26
27
|
export { isRelationField } from "./schema/isRelationField.js";
|
package/lib/src/main.js
CHANGED
|
@@ -20,7 +20,8 @@ export { getCollection } from "./schema/getCollection.js";
|
|
|
20
20
|
export { getDependencyFields } from "./schema/getDependencyFields.js";
|
|
21
21
|
export { getField } from "./schema/getField.js";
|
|
22
22
|
export { getFieldNames } from "./schema/getFieldNames.js";
|
|
23
|
-
export { getRoleFields, getDependencyAccessFields, getDependencyIndexFields, getRoleGroups, getRoleGroup, getRoleExcludedFields, getUserRoleGroups, getAllRoleGroups, } from "./schema/getIndexFields.js";
|
|
23
|
+
export { getRoleFields, getDependencyAccessFields, getDependencyIndexFields, getFieldAccessGroupIndexFields, getFieldAccessGroupRoles, getFieldAccessGroupKey, getRoleGroups, getRoleGroup, getRoleExcludedFields, getUserRoleGroups, getAllRoleGroups, } from "./schema/getIndexFields.js";
|
|
24
|
+
export { isFieldAccessGroupReference, getFieldAccessRoles, fieldRoleProjectionAccess, getFieldAccessGroupCondition, getFieldAccessGroupFields, evaluateFieldAccessCondition, fieldAccessGroupAccess, } from "./access/fieldAccess.js";
|
|
24
25
|
export { getAccessFields } from "./schema/getAccessFields.js";
|
|
25
26
|
export { getSystemFieldsSchema } from "./schema/getSystemFieldsSchema.js";
|
|
26
27
|
export { isRelationField } from "./schema/isRelationField.js";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { CollectionSchema, CollectionCustomization,
|
|
2
|
-
export declare const addInitialValues: (data: StokerRecord, collectionSchema: CollectionSchema, customization: CollectionCustomization,
|
|
1
|
+
import { CollectionSchema, CollectionCustomization, StokerPermissions, StokerRecord } from "@stoker-platform/types";
|
|
2
|
+
export declare const addInitialValues: (data: StokerRecord, collectionSchema: CollectionSchema, customization: CollectionCustomization, permissions?: StokerPermissions, claims?: Record<string, unknown>) => Promise<void>;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import { privateFieldAccess } from "../access/collection.js";
|
|
1
2
|
import { tryPromise } from "../getConfigValue.js";
|
|
2
3
|
import { getField } from "../schema/getField.js";
|
|
3
4
|
import { isRelationField } from "../schema/isRelationField.js";
|
|
4
5
|
import { getLowercaseFields } from "./getLowercaseFields.js";
|
|
5
|
-
export const addInitialValues = async (data, collectionSchema, customization,
|
|
6
|
+
export const addInitialValues = async (data, collectionSchema, customization, permissions, claims) => {
|
|
6
7
|
const { fields } = collectionSchema;
|
|
7
8
|
for (const field of customization.fields) {
|
|
8
9
|
const fieldSchema = getField(fields, field.name);
|
|
9
10
|
if (field.custom?.initialValue !== undefined &&
|
|
10
|
-
!
|
|
11
|
+
(!fieldSchema.access || privateFieldAccess(fieldSchema, permissions, collectionSchema, claims || {}))) {
|
|
11
12
|
data[field.name] = await tryPromise(field.custom.initialValue, [data]);
|
|
12
13
|
const lowercaseFields = getLowercaseFields(collectionSchema, [fieldSchema]);
|
|
13
14
|
if (lowercaseFields.size === 1) {
|
|
@@ -16,7 +17,7 @@ export const addInitialValues = async (data, collectionSchema, customization, ro
|
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
19
|
for (const field of fields) {
|
|
19
|
-
if (!
|
|
20
|
+
if (!field.access || privateFieldAccess(field, permissions, collectionSchema, claims || {})) {
|
|
20
21
|
if ("autoIncrement" in field && field.autoIncrement && !data[field.name]) {
|
|
21
22
|
data[field.name] = "Pending";
|
|
22
23
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isRelationField } from "../schema/isRelationField.js";
|
|
2
|
-
import { getDependencyIndexFields, getRoleExcludedFields } from "../schema/getIndexFields.js";
|
|
2
|
+
import { getDependencyIndexFields, getFieldAccessGroupIndexFields, getFieldAccessGroupKey, getRoleExcludedFields, } from "../schema/getIndexFields.js";
|
|
3
|
+
import { getFieldAccessGroupFields } from "../access/fieldAccess.js";
|
|
3
4
|
import { isDependencyField } from "../schema/isDependencyField.js";
|
|
4
5
|
import { getFieldNames } from "../schema/getFieldNames.js";
|
|
5
6
|
import { getField } from "../schema/getField.js";
|
|
@@ -65,6 +66,48 @@ options, allRoleGroups, arrayUnion, arrayRemove, deleteField, dependencyRef, uni
|
|
|
65
66
|
}
|
|
66
67
|
});
|
|
67
68
|
const roleGroups = allRoleGroups[collectionSchema.labels.collection];
|
|
69
|
+
const fieldAccessGroups = getFieldAccessGroupFields(collectionSchema);
|
|
70
|
+
Object.entries(fieldAccessGroups).forEach(([groupKey, groupFields]) => {
|
|
71
|
+
if (groupFields.length === 0)
|
|
72
|
+
return;
|
|
73
|
+
for (const roleGroup of roleGroups) {
|
|
74
|
+
const overlayFieldsSchema = getFieldAccessGroupIndexFields(groupKey, collectionSchema, roleGroup);
|
|
75
|
+
if (overlayFieldsSchema.length === 0)
|
|
76
|
+
continue;
|
|
77
|
+
const overlayKey = getFieldAccessGroupKey(groupKey, roleGroup.key);
|
|
78
|
+
const overlayRecord = {};
|
|
79
|
+
overlayFieldsSchema.forEach((overlayField) => {
|
|
80
|
+
const names = [
|
|
81
|
+
overlayField.name,
|
|
82
|
+
`${overlayField.name}_Array`,
|
|
83
|
+
`${overlayField.name}_Single`,
|
|
84
|
+
`${overlayField.name}_Lowercase`,
|
|
85
|
+
];
|
|
86
|
+
names.forEach((name) => {
|
|
87
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
88
|
+
if (record[name] !== undefined)
|
|
89
|
+
overlayRecord[name] = record[name];
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
if (operation === "create") {
|
|
93
|
+
overlayRecord.Collection_Path ||= path;
|
|
94
|
+
overlayRecord.Collection_Path_String = path.join("/");
|
|
95
|
+
batch.set(privateRef(overlayKey), overlayRecord);
|
|
96
|
+
if (batchSize)
|
|
97
|
+
batchSize.size++;
|
|
98
|
+
}
|
|
99
|
+
if (operation === "update" && Object.keys(overlayRecord).length > 0) {
|
|
100
|
+
batch.update(privateRef(overlayKey), overlayRecord);
|
|
101
|
+
if (batchSize)
|
|
102
|
+
batchSize.size++;
|
|
103
|
+
}
|
|
104
|
+
if (operation === "delete") {
|
|
105
|
+
batch.delete(privateRef(overlayKey));
|
|
106
|
+
if (batchSize)
|
|
107
|
+
batchSize.size++;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
});
|
|
68
111
|
for (const group of roleGroups) {
|
|
69
112
|
const excludedFields = getRoleExcludedFields(group, collectionSchema);
|
|
70
113
|
const recordToUpdate = { ...record };
|
|
@@ -110,6 +153,18 @@ options, allRoleGroups, arrayUnion, arrayRemove, deleteField, dependencyRef, uni
|
|
|
110
153
|
batchSize++;
|
|
111
154
|
}
|
|
112
155
|
}
|
|
156
|
+
const fieldAccessGroups = getFieldAccessGroupFields(targetSchema);
|
|
157
|
+
for (const [groupKey, groupFields] of Object.entries(fieldAccessGroups)) {
|
|
158
|
+
if (groupFields.length === 0)
|
|
159
|
+
continue;
|
|
160
|
+
for (const roleGroup of targetRoleGroups) {
|
|
161
|
+
const overlayIndexFields = getFieldAccessGroupIndexFields(groupKey, targetSchema, roleGroup);
|
|
162
|
+
if (overlayIndexFields.some((overlayField) => overlayField.name === targetField.name) &&
|
|
163
|
+
isRelationField(targetField)) {
|
|
164
|
+
batchSize++;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
113
168
|
return batchSize;
|
|
114
169
|
};
|
|
115
170
|
const deleteFields = (field, targetSchema, targetField, id, relationPath) => {
|
|
@@ -142,6 +197,19 @@ options, allRoleGroups, arrayUnion, arrayRemove, deleteField, dependencyRef, uni
|
|
|
142
197
|
batch.update(twoWayPrivateRef(field, group.key, id), fieldUpdate);
|
|
143
198
|
}
|
|
144
199
|
}
|
|
200
|
+
const fieldAccessGroups = getFieldAccessGroupFields(targetSchema);
|
|
201
|
+
for (const [groupKey, groupFields] of Object.entries(fieldAccessGroups)) {
|
|
202
|
+
if (groupFields.length === 0)
|
|
203
|
+
continue;
|
|
204
|
+
for (const roleGroup of targetRoleGroups) {
|
|
205
|
+
const overlayIndexFields = getFieldAccessGroupIndexFields(groupKey, targetSchema, roleGroup);
|
|
206
|
+
const overlayKey = getFieldAccessGroupKey(groupKey, roleGroup.key);
|
|
207
|
+
if (overlayIndexFields.some((overlayField) => overlayField.name === targetField.name) &&
|
|
208
|
+
isRelationField(targetField)) {
|
|
209
|
+
batch.update(twoWayPrivateRef(field, overlayKey, id), fieldUpdate);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
145
213
|
};
|
|
146
214
|
if (operation === "delete")
|
|
147
215
|
return;
|
|
@@ -246,6 +314,28 @@ options, allRoleGroups, arrayUnion, arrayRemove, deleteField, dependencyRef, uni
|
|
|
246
314
|
}
|
|
247
315
|
}
|
|
248
316
|
}
|
|
317
|
+
const fieldAccessGroups = getFieldAccessGroupFields(targetSchema);
|
|
318
|
+
for (const [groupKey, groupFields] of Object.entries(fieldAccessGroups)) {
|
|
319
|
+
if (groupFields.length === 0)
|
|
320
|
+
continue;
|
|
321
|
+
for (const roleGroup of targetRoleGroups) {
|
|
322
|
+
const overlayIndexFields = getFieldAccessGroupIndexFields(groupKey, targetSchema, roleGroup);
|
|
323
|
+
const overlayKey = getFieldAccessGroupKey(groupKey, roleGroup.key);
|
|
324
|
+
if (overlayIndexFields.some((overlayField) => overlayField.name === targetField.name)) {
|
|
325
|
+
const overlayFieldUpdate = { ...fieldUpdate };
|
|
326
|
+
Object.keys(systemFields).forEach((systemField) => {
|
|
327
|
+
if (overlayIndexFields.some((overlayField) => overlayField.name === systemField)) {
|
|
328
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
329
|
+
overlayFieldUpdate[systemField] = systemFields[systemField];
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
if (Object.keys(overlayFieldUpdate).length > 0) {
|
|
333
|
+
batch.update(twoWayPrivateRef(field, overlayKey, id), overlayFieldUpdate);
|
|
334
|
+
batchSize.size++;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
249
339
|
}
|
|
250
340
|
}
|
|
251
341
|
}
|
|
@@ -2,6 +2,9 @@ import type { CollectionField, CollectionSchema, CollectionsSchema, StokerPermis
|
|
|
2
2
|
export declare const getRoleFields: (collection: CollectionSchema, role: StokerRole) => CollectionField[];
|
|
3
3
|
export declare const getDependencyAccessFields: (field: CollectionField, collection: CollectionSchema, schema: CollectionsSchema) => CollectionField[];
|
|
4
4
|
export declare const getDependencyIndexFields: (field: CollectionField, collection: CollectionSchema, schema: CollectionsSchema) => CollectionField[];
|
|
5
|
+
export declare const getFieldAccessGroupRoles: (groupKey: string, collection: CollectionSchema, roleGroup: RoleGroup) => string[];
|
|
6
|
+
export declare const getFieldAccessGroupKey: (groupKey: string, roleGroupKey: string) => string;
|
|
7
|
+
export declare const getFieldAccessGroupIndexFields: (groupKey: string, collection: CollectionSchema, roleGroup: RoleGroup) => CollectionField[];
|
|
5
8
|
export declare const getRoleGroups: (collection: CollectionSchema, schema: CollectionsSchema) => Set<RoleGroup>;
|
|
6
9
|
export declare const getRoleGroup: (role: StokerRole, collection: CollectionSchema, schema: CollectionsSchema) => RoleGroup | undefined;
|
|
7
10
|
export declare const getRoleExcludedFields: (roleGroup: RoleGroup, collection: CollectionSchema) => CollectionField[];
|