@memberjunction/generic-database-provider 6.1.0-edge.6 → 6.1.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/DatabaseWellKnownUserSource.d.ts +48 -0
- package/dist/DatabaseWellKnownUserSource.d.ts.map +1 -0
- package/dist/DatabaseWellKnownUserSource.js +101 -0
- package/dist/DatabaseWellKnownUserSource.js.map +1 -0
- package/dist/GenericDatabaseProvider.d.ts +45 -3
- package/dist/GenericDatabaseProvider.d.ts.map +1 -1
- package/dist/GenericDatabaseProvider.js +251 -21
- package/dist/GenericDatabaseProvider.js.map +1 -1
- package/dist/SystemUserFieldAccessCheck.d.ts +64 -0
- package/dist/SystemUserFieldAccessCheck.d.ts.map +1 -0
- package/dist/SystemUserFieldAccessCheck.js +137 -0
- package/dist/SystemUserFieldAccessCheck.js.map +1 -0
- package/dist/UserCache.d.ts.map +1 -1
- package/dist/UserCache.js +2 -2
- package/dist/UserCache.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/queryPagingEngine.d.ts +19 -0
- package/dist/queryPagingEngine.d.ts.map +1 -1
- package/dist/queryPagingEngine.js +45 -0
- package/dist/queryPagingEngine.js.map +1 -1
- package/dist/systemUser.d.ts +27 -0
- package/dist/systemUser.d.ts.map +1 -0
- package/dist/systemUser.js +29 -0
- package/dist/systemUser.js.map +1 -0
- package/dist/systemUserFieldAccess.d.ts +114 -0
- package/dist/systemUserFieldAccess.d.ts.map +1 -0
- package/dist/systemUserFieldAccess.js +198 -0
- package/dist/systemUserFieldAccess.js.map +1 -0
- package/package.json +14 -14
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Keeping the MJ system user's own field access intact, now that field-level
|
|
3
|
+
* security has no runtime exemption for anybody.
|
|
4
|
+
*
|
|
5
|
+
* ## Why this file exists
|
|
6
|
+
*
|
|
7
|
+
* The system user is the account the server runs its own work as. It pre-warms the shared engine
|
|
8
|
+
* caches at startup, and in task mode (job and agent runners) engines instead load on first touch,
|
|
9
|
+
* so whichever caller gets there first configures the engine for the whole process. Those caches
|
|
10
|
+
* are process-wide. A system user that cannot read a column therefore does not just fail its own
|
|
11
|
+
* query — it leaves a partially loaded record in a cache every later user reads, with nothing at
|
|
12
|
+
* the point of failure pointing back at the permission row that caused it.
|
|
13
|
+
*
|
|
14
|
+
* Field security deliberately has **no exempt user** at runtime: `GetUserFieldPermissions` has no
|
|
15
|
+
* identity branch at all, and the system user's access comes from ordinary `Allow` rows that
|
|
16
|
+
* snapshot initialization writes for the standard roles it holds. That is a better design — an
|
|
17
|
+
* administrator can see the rows and reason about them, where a code bypass is invisible exactly
|
|
18
|
+
* where access is decided. But it moves the burden here: something has to stop those rows being
|
|
19
|
+
* taken away.
|
|
20
|
+
*
|
|
21
|
+
* ## Why "does this rule contain a Deny?" is not enough
|
|
22
|
+
*
|
|
23
|
+
* Whether a change restricts a user is a property of the **aggregate across every role they
|
|
24
|
+
* hold**, never of one rule in isolation. Three ways to lock the system user out without writing
|
|
25
|
+
* a single `Deny`:
|
|
26
|
+
*
|
|
27
|
+
* 1. set `ReadAccess = 'No Access'` on each of its roles in turn — every save individually
|
|
28
|
+
* harmless, the last one leaves no `Allow` standing;
|
|
29
|
+
* 2. delete its roles' `Allow` rows;
|
|
30
|
+
* 3. reach either state through direct SQL, which no entity-layer guard sees at all.
|
|
31
|
+
*
|
|
32
|
+
* So the save-time guard evaluates the **projected aggregate** — the rules as they would stand
|
|
33
|
+
* after the proposed change — and {@link FindSystemUserFieldAccessViolations} sweeps for state
|
|
34
|
+
* that got there by some other route.
|
|
35
|
+
*
|
|
36
|
+
* @module @memberjunction/generic-database-provider
|
|
37
|
+
*/
|
|
38
|
+
import { EntityFieldInfo, UserInfo, } from '@memberjunction/core';
|
|
39
|
+
import { UUIDsEqual } from '@memberjunction/global';
|
|
40
|
+
import { UserCache } from './UserCache.js';
|
|
41
|
+
/**
|
|
42
|
+
* Why a proposed field-permission state would leave the MJ system user short of its entity-level
|
|
43
|
+
* access, or null when it would not.
|
|
44
|
+
*
|
|
45
|
+
* Callers pass the rules **as they would be after** their change — with the edited row's new
|
|
46
|
+
* values substituted, or the deleted row removed. Classifying the changed row on its own cannot
|
|
47
|
+
* answer this question; see the module comment.
|
|
48
|
+
*
|
|
49
|
+
* Answers null (permits the change) in three cases, each deliberate:
|
|
50
|
+
*
|
|
51
|
+
* - **No system user resolves.** A cold `UserCache` is the normal state during a process's own
|
|
52
|
+
* bootstrap. Blocking an administrator on missing state would be worse than the risk, and
|
|
53
|
+
* {@link FindSystemUserFieldAccessViolations} runs at startup precisely to catch whatever slips
|
|
54
|
+
* through here.
|
|
55
|
+
* - **The field is unrestrictable.** Primary keys, `__mj_` columns and the security-configuration
|
|
56
|
+
* entities are forced open by the aggregation regardless of any row, so no rule about them can
|
|
57
|
+
* restrict anyone.
|
|
58
|
+
* - **The system user has no entity-level read.** It is already denied one level up, where the
|
|
59
|
+
* entity permission check has no exemption either, so field rules change nothing for it here.
|
|
60
|
+
*
|
|
61
|
+
* Note this does NOT gate on `EnableFieldLevelSecurity`. Rules on a disabled entity are dormant
|
|
62
|
+
* rather than gone — disabling deliberately preserves them — so gating would leave a three-step
|
|
63
|
+
* hole: disable, strip the system user's rows, re-enable.
|
|
64
|
+
*
|
|
65
|
+
* @param entity the entity the field belongs to
|
|
66
|
+
* @param field the field whose rules are changing
|
|
67
|
+
* @param projectedRules every rule that would bind to this field after the change
|
|
68
|
+
*/
|
|
69
|
+
export function SystemUserFieldAccessLossReason(entity, field, projectedRules) {
|
|
70
|
+
if (!entity || !field) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
const systemUser = resolveSystemUser();
|
|
74
|
+
if (!systemUser) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
if (field.IsUnrestrictableField || field.IsOnUnrestrictableEntity) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const lost = lostVerb(entity, field, projectedRules, systemUser);
|
|
81
|
+
if (!lost) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
return (`This change would leave the MJ system user unable to ${lost} field '${field.Name}' on ` +
|
|
85
|
+
`'${entity.Name}'. The server runs background work as that account and shares one engine cache ` +
|
|
86
|
+
`across all users, so restricting it would let partially loaded records reach everyone. ` +
|
|
87
|
+
`Field security has no exempt user — the system user's access comes from these rows — so at ` +
|
|
88
|
+
`least one role it holds must keep 'Allow' here. Apply this rule to a different role, or ` +
|
|
89
|
+
`remove the role from the system user first.`);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Every field on an FLS-enabled entity that the system user cannot fully use.
|
|
93
|
+
*
|
|
94
|
+
* The backstop for state the save-time guard never saw: direct SQL, a migration, or a save made
|
|
95
|
+
* while the user cache was cold. Walks loaded metadata only — no queries — and skips entities with
|
|
96
|
+
* field security switched off, which is nearly all of them.
|
|
97
|
+
*
|
|
98
|
+
* @param provider the provider whose metadata to walk
|
|
99
|
+
* @param systemUser the account to check; defaults to the user cache's system user
|
|
100
|
+
* @param options optional projection — see {@link SystemUserFieldAccessSweepOptions}
|
|
101
|
+
*/
|
|
102
|
+
export function FindSystemUserFieldAccessViolations(provider, systemUser, options = {}) {
|
|
103
|
+
const resolved = systemUser ?? resolveSystemUser();
|
|
104
|
+
if (!provider || !resolved) {
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
const user = options.WithoutRoleID ? projectUserWithoutRole(resolved, options.WithoutRoleID) : resolved;
|
|
108
|
+
const violations = [];
|
|
109
|
+
for (const entity of provider.Entities ?? []) {
|
|
110
|
+
if (!entity.EnableFieldLevelSecurity) {
|
|
111
|
+
continue; // dormant rules cannot restrict anything
|
|
112
|
+
}
|
|
113
|
+
for (const field of entity.Fields) {
|
|
114
|
+
if (field.IsUnrestrictableField || field.IsOnUnrestrictableEntity) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const lost = lostVerb(entity, field, field.FieldPermissions, user);
|
|
118
|
+
if (lost) {
|
|
119
|
+
violations.push({ EntityName: entity.Name, FieldName: field.Name, Verb: lost });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return violations;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Which verb the system user would lose relative to its ENTITY-level access, or null.
|
|
127
|
+
*
|
|
128
|
+
* Compared against the entity-level ceiling rather than against "all three verbs" on purpose. The
|
|
129
|
+
* snapshot mirrors entity permissions, so a role holding only entity read legitimately produces
|
|
130
|
+
* `Allow / No Access / No Access`. Demanding update and create unconditionally would make that
|
|
131
|
+
* ordinary, correct state look like a violation and refuse the very rows the guard exists to
|
|
132
|
+
* protect.
|
|
133
|
+
*/
|
|
134
|
+
function lostVerb(entity, field, rules, systemUser) {
|
|
135
|
+
const entityAccess = entity.GetUserPermisions(systemUser);
|
|
136
|
+
if (!entityAccess?.CanRead) {
|
|
137
|
+
return null; // already denied one level up; field rules add nothing
|
|
138
|
+
}
|
|
139
|
+
const after = EntityFieldInfo.AggregateFieldRulesForUser(rules, systemUser);
|
|
140
|
+
if (!after.CanRead) {
|
|
141
|
+
return 'read';
|
|
142
|
+
}
|
|
143
|
+
// A read-only field cannot be written through the API by ANY user — it is excluded from the
|
|
144
|
+
// generated create input and from the update SET list — so the write verbs decide nothing on
|
|
145
|
+
// it and their absence costs the system user nothing. Reconciliation deliberately authors
|
|
146
|
+
// `No Access` there rather than an inert `Allow`; without this the guard would read that as
|
|
147
|
+
// lost access and report every joined display column on an FLS-enabled entity as a violation.
|
|
148
|
+
if (field.ReadOnly) {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
if (entityAccess.CanUpdate && !after.CanUpdate) {
|
|
152
|
+
return 'update';
|
|
153
|
+
}
|
|
154
|
+
if (entityAccess.CanCreate && !after.CanCreate) {
|
|
155
|
+
return 'create';
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Whether the MJ system user holds the given role.
|
|
161
|
+
*
|
|
162
|
+
* The cheap pre-check for the save-time guard. Field aggregation only ever consults rules bound to
|
|
163
|
+
* a role the user holds, so a change to any other role's rule provably cannot move the system
|
|
164
|
+
* user's access — which lets callers skip the work of projecting and re-aggregating for the
|
|
165
|
+
* overwhelming majority of permission edits.
|
|
166
|
+
*
|
|
167
|
+
* False on a cold cache, matching {@link SystemUserFieldAccessLossReason}'s posture: with no system
|
|
168
|
+
* user to reason about there is nothing to protect, and the startup sweep is the backstop.
|
|
169
|
+
*/
|
|
170
|
+
export function SystemUserHoldsRole(roleID) {
|
|
171
|
+
if (!roleID) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
const systemUser = resolveSystemUser();
|
|
175
|
+
return !!systemUser?.UserRoles?.some(ur => UUIDsEqual(ur.RoleID, roleID));
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* A copy of the user holding every role except `roleID`.
|
|
179
|
+
*
|
|
180
|
+
* `UserRoles` is a read-only accessor over a private backing field, so this rebuilds through the
|
|
181
|
+
* constructor rather than mutating. `copyInitData` skips accessors (it only assigns own
|
|
182
|
+
* properties), and the constructor then seeds the backing field from `initData.UserRoles` — so the
|
|
183
|
+
* filtered list is what the projection ends up holding.
|
|
184
|
+
*/
|
|
185
|
+
function projectUserWithoutRole(user, roleID) {
|
|
186
|
+
// No provider: `UserInfo` only stores it for lookups this projection never performs, and the
|
|
187
|
+
// aggregation reads nothing but `UserRoles`.
|
|
188
|
+
return new UserInfo(undefined, {
|
|
189
|
+
...user,
|
|
190
|
+
UserRoles: (user.UserRoles ?? []).filter(ur => !UUIDsEqual(ur.RoleID, roleID)),
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
/** The system user, or null when the cache is cold. Never throws. */
|
|
194
|
+
function resolveSystemUser() {
|
|
195
|
+
const user = UserCache.Instance?.GetSystemUser?.();
|
|
196
|
+
return user?.UserRoles?.length ? user : null;
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=systemUserFieldAccess.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"systemUserFieldAccess.js","sourceRoot":"","sources":["../src/systemUserFieldAccess.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/generic-database-provider",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "6.1.0
|
|
4
|
+
"version": "6.1.0",
|
|
5
5
|
"description": "Shared database provider logic for MemberJunction — intermediate base class between DatabaseProviderBase and platform-specific providers",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -16,19 +16,19 @@
|
|
|
16
16
|
"vitest": "^3.1.1"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@memberjunction/actions": "6.1.0
|
|
20
|
-
"@memberjunction/actions-base": "6.1.0
|
|
21
|
-
"@memberjunction/ai-vectors-memory": "6.1.0
|
|
22
|
-
"@memberjunction/aiengine": "6.1.0
|
|
23
|
-
"@memberjunction/core": "6.1.0
|
|
24
|
-
"@memberjunction/core-entities": "6.1.0
|
|
25
|
-
"@memberjunction/encryption": "6.1.0
|
|
26
|
-
"@memberjunction/geo-core": "6.1.0
|
|
27
|
-
"@memberjunction/global": "6.1.0
|
|
28
|
-
"@memberjunction/query-processor": "6.1.0
|
|
29
|
-
"@memberjunction/sql-dialect": "6.1.0
|
|
30
|
-
"@memberjunction/sql-parser": "6.1.0
|
|
31
|
-
"@memberjunction/queue": "6.1.0
|
|
19
|
+
"@memberjunction/actions": "6.1.0",
|
|
20
|
+
"@memberjunction/actions-base": "6.1.0",
|
|
21
|
+
"@memberjunction/ai-vectors-memory": "6.1.0",
|
|
22
|
+
"@memberjunction/aiengine": "6.1.0",
|
|
23
|
+
"@memberjunction/core": "6.1.0",
|
|
24
|
+
"@memberjunction/core-entities": "6.1.0",
|
|
25
|
+
"@memberjunction/encryption": "6.1.0",
|
|
26
|
+
"@memberjunction/geo-core": "6.1.0",
|
|
27
|
+
"@memberjunction/global": "6.1.0",
|
|
28
|
+
"@memberjunction/query-processor": "6.1.0",
|
|
29
|
+
"@memberjunction/sql-dialect": "6.1.0",
|
|
30
|
+
"@memberjunction/sql-parser": "6.1.0",
|
|
31
|
+
"@memberjunction/queue": "6.1.0",
|
|
32
32
|
"sql-formatter": "^15.7.0",
|
|
33
33
|
"uuid": "^13.0.0"
|
|
34
34
|
},
|