@aooth/arbac-moost 0.1.56 → 0.1.58
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/index.d.mts +17 -1
- package/dist/index.mjs +54 -4
- package/package.json +10 -10
package/dist/index.d.mts
CHANGED
|
@@ -170,7 +170,23 @@ interface MetaVisibility {
|
|
|
170
170
|
alwaysVisible: ReadonlySet<string>;
|
|
171
171
|
/** Relation names granted via `with.<name>` (see {@link collectWithGrantNames}). */
|
|
172
172
|
withGrants: ReadonlySet<string>;
|
|
173
|
+
/**
|
|
174
|
+
* Fields the principal's WRITE scopes allow (union of `allowedFields`, or
|
|
175
|
+
* `"all"` for an unrestricted write grant). A field that is writable but not
|
|
176
|
+
* read-visible is NOT pruned from `/meta` — it survives with a `db.writeOnly`
|
|
177
|
+
* stamp (type only; rows/projections never carry it), so generic forms and
|
|
178
|
+
* client preflight validators can still SET sealed fields (e.g. credentials
|
|
179
|
+
* behind a read projection). Absent → nothing extra survives.
|
|
180
|
+
*/
|
|
181
|
+
writable?: ReadonlySet<string> | "all";
|
|
173
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* Union of write-scope `allowedFields`; `"all"` for field-unrestricted write
|
|
185
|
+
* access. Mirrors `prepareScopeOverlay`: the whitelist exists only when at
|
|
186
|
+
* least one scope carries an `allowedFields` array — scoped-but-unlisted
|
|
187
|
+
* writes are field-unrestricted.
|
|
188
|
+
*/
|
|
189
|
+
declare function collectWritableFields(scopes: ArbacDbScope[], unrestricted: boolean): ReadonlySet<string> | "all" | undefined;
|
|
174
190
|
/**
|
|
175
191
|
* Whether a flattened dot-path field exists for this principal. A path under
|
|
176
192
|
* a `with`-granted relation passes unconditionally — the sub-scope governs
|
|
@@ -247,4 +263,4 @@ declare function applyArbacMetaOverlay(meta: TMetaResponse, alwaysVisible: Reado
|
|
|
247
263
|
*/
|
|
248
264
|
declare class MoostArbac<TUserAttrs extends object, TScope extends object> extends Arbac$1<TUserAttrs, TScope> {}
|
|
249
265
|
//#endregion
|
|
250
|
-
export { type AoothArbacClaims, Arbac, ArbacAction, ArbacAuthorize, ArbacDbScope, ArbacResource, ArbacUserProvider, ArbacUserProviderToken, AsArbacDbController, AsArbacDbReadableController, type ControlGate, type ControlsOf, MetaVisibility, MoostArbac, type NavRelationKey, type NavTarget, type OwnFieldKey, type ProjectionOf, type TArbacCompiledRule, type TArbacEvalResult, TArbacMeta, type TArbacRole, type TArbacRoleForResource, type TArbacRule, applyAllowedFieldsAndSet, applyArbacMetaOverlay, arbacAuthorizeInterceptor, arbacPatternToRegex, collectWithGrantNames, conjoinArbacDbScopes, enforceControlsPolicy, extractUsedControlValues, getArbacMate, isMetaFieldVisible, isScopedFieldVisible, metaAlwaysVisibleFields, pruneMetaByVisibility, unionScopeProjection, useArbac };
|
|
266
|
+
export { type AoothArbacClaims, Arbac, ArbacAction, ArbacAuthorize, ArbacDbScope, ArbacResource, ArbacUserProvider, ArbacUserProviderToken, AsArbacDbController, AsArbacDbReadableController, type ControlGate, type ControlsOf, MetaVisibility, MoostArbac, type NavRelationKey, type NavTarget, type OwnFieldKey, type ProjectionOf, type TArbacCompiledRule, type TArbacEvalResult, TArbacMeta, type TArbacRole, type TArbacRoleForResource, type TArbacRule, applyAllowedFieldsAndSet, applyArbacMetaOverlay, arbacAuthorizeInterceptor, arbacPatternToRegex, collectWithGrantNames, collectWritableFields, conjoinArbacDbScopes, enforceControlsPolicy, extractUsedControlValues, getArbacMate, isMetaFieldVisible, isScopedFieldVisible, metaAlwaysVisibleFields, pruneMetaByVisibility, unionScopeProjection, useArbac };
|
package/dist/index.mjs
CHANGED
|
@@ -263,6 +263,33 @@ function collectWithGrantNames(scopes) {
|
|
|
263
263
|
for (const s of scopes) if (s.with) for (const name of Object.keys(s.with)) out.add(name);
|
|
264
264
|
return out;
|
|
265
265
|
}
|
|
266
|
+
/** Exact-or-ancestor membership: `credit.credentials.user` matches a `credit.credentials` grant. */
|
|
267
|
+
function isPathWritable(path, writable) {
|
|
268
|
+
if (!writable) return false;
|
|
269
|
+
if (writable === "all") return true;
|
|
270
|
+
if (writable.has(path)) return true;
|
|
271
|
+
let pos = path.length;
|
|
272
|
+
while ((pos = path.lastIndexOf(".", pos - 1)) !== -1) if (writable.has(path.slice(0, pos))) return true;
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Union of write-scope `allowedFields`; `"all"` for field-unrestricted write
|
|
277
|
+
* access. Mirrors `prepareScopeOverlay`: the whitelist exists only when at
|
|
278
|
+
* least one scope carries an `allowedFields` array — scoped-but-unlisted
|
|
279
|
+
* writes are field-unrestricted.
|
|
280
|
+
*/
|
|
281
|
+
function collectWritableFields(scopes, unrestricted) {
|
|
282
|
+
if (unrestricted) return "all";
|
|
283
|
+
if (scopes.length === 0) return void 0;
|
|
284
|
+
const out = /* @__PURE__ */ new Set();
|
|
285
|
+
let sawWhitelist = false;
|
|
286
|
+
for (const s of scopes) if (Array.isArray(s.allowedFields)) {
|
|
287
|
+
sawWhitelist = true;
|
|
288
|
+
for (const f of s.allowedFields) out.add(f);
|
|
289
|
+
}
|
|
290
|
+
if (!sawWhitelist) return "all";
|
|
291
|
+
return out.size > 0 ? out : void 0;
|
|
292
|
+
}
|
|
266
293
|
/**
|
|
267
294
|
* Whether a flattened dot-path field exists for this principal. A path under
|
|
268
295
|
* a `with`-granted relation passes unconditionally — the sub-scope governs
|
|
@@ -295,6 +322,12 @@ function isMetaFieldVisible(path, vis) {
|
|
|
295
322
|
function pruneMetaByVisibility(meta, vis) {
|
|
296
323
|
const fields = {};
|
|
297
324
|
for (const [path, fieldMeta] of Object.entries(meta.fields)) if (isMetaFieldVisible(path, vis)) fields[path] = fieldMeta;
|
|
325
|
+
else if (isPathWritable(path, vis.writable)) fields[path] = {
|
|
326
|
+
...fieldMeta,
|
|
327
|
+
writeOnly: true,
|
|
328
|
+
filterable: false,
|
|
329
|
+
sortable: false
|
|
330
|
+
};
|
|
298
331
|
const relationNames = new Set(meta.relations.map((r) => r.name));
|
|
299
332
|
const relations = meta.relations.filter((r) => isMetaFieldVisible(r.name, vis));
|
|
300
333
|
const out = {
|
|
@@ -325,7 +358,16 @@ function pruneSerializedType(node, basePath, vis, relationNames) {
|
|
|
325
358
|
if (isMetaFieldVisible(name, vis)) props[name] = prop;
|
|
326
359
|
continue;
|
|
327
360
|
}
|
|
328
|
-
if (!isMetaFieldVisible(path, vis))
|
|
361
|
+
if (!isMetaFieldVisible(path, vis)) {
|
|
362
|
+
if (isPathWritable(path, vis.writable)) props[name] = {
|
|
363
|
+
...prop,
|
|
364
|
+
metadata: {
|
|
365
|
+
...prop.metadata,
|
|
366
|
+
"db.writeOnly": true
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
329
371
|
props[name] = pruneSerializedType(prop, path, vis, relationNames);
|
|
330
372
|
}
|
|
331
373
|
return {
|
|
@@ -451,10 +493,17 @@ async function applyArbacMetaOverlay(meta, alwaysVisible) {
|
|
|
451
493
|
crud: filteredCrud
|
|
452
494
|
};
|
|
453
495
|
let readUnrestricted = false;
|
|
496
|
+
let writeUnrestricted = false;
|
|
454
497
|
const readScopes = [];
|
|
498
|
+
const writeScopes = [];
|
|
455
499
|
for (let i = 0; i < crudKeys.length; i++) {
|
|
456
|
-
if (!crudResults[i].allowed
|
|
500
|
+
if (!crudResults[i].allowed) continue;
|
|
457
501
|
const scopes = crudResults[i].scopes;
|
|
502
|
+
if (WRITE_CRUD_OPS.has(crudKeys[i])) {
|
|
503
|
+
if (!scopes || scopes.length === 0) writeUnrestricted = true;
|
|
504
|
+
else writeScopes.push(...scopes);
|
|
505
|
+
continue;
|
|
506
|
+
}
|
|
458
507
|
if (!scopes || scopes.length === 0) readUnrestricted = true;
|
|
459
508
|
else readScopes.push(...scopes);
|
|
460
509
|
}
|
|
@@ -463,7 +512,8 @@ async function applyArbacMetaOverlay(meta, alwaysVisible) {
|
|
|
463
512
|
if (allowed) overlaid = pruneMetaByVisibility(overlaid, {
|
|
464
513
|
allowed,
|
|
465
514
|
alwaysVisible,
|
|
466
|
-
withGrants: collectWithGrantNames(readScopes)
|
|
515
|
+
withGrants: collectWithGrantNames(readScopes),
|
|
516
|
+
writable: collectWritableFields(writeScopes, writeUnrestricted)
|
|
467
517
|
});
|
|
468
518
|
}
|
|
469
519
|
return overlaid;
|
|
@@ -871,4 +921,4 @@ let AsArbacDbReadableController = class AsArbacDbReadableController extends AsDb
|
|
|
871
921
|
};
|
|
872
922
|
AsArbacDbReadableController = __decorate([Inherit()], AsArbacDbReadableController);
|
|
873
923
|
//#endregion
|
|
874
|
-
export { Arbac, ArbacAction, ArbacAuthorize, ArbacResource, ArbacUserProvider, ArbacUserProviderToken, AsArbacDbController, AsArbacDbReadableController, MoostArbac, applyAllowedFieldsAndSet, applyArbacMetaOverlay, arbacAuthorizeInterceptor, arbacPatternToRegex, collectWithGrantNames, conjoinArbacDbScopes, enforceControlsPolicy, extractUsedControlValues, getArbacMate, isMetaFieldVisible, isScopedFieldVisible, metaAlwaysVisibleFields, pruneMetaByVisibility, unionScopeProjection, useArbac };
|
|
924
|
+
export { Arbac, ArbacAction, ArbacAuthorize, ArbacResource, ArbacUserProvider, ArbacUserProviderToken, AsArbacDbController, AsArbacDbReadableController, MoostArbac, applyAllowedFieldsAndSet, applyArbacMetaOverlay, arbacAuthorizeInterceptor, arbacPatternToRegex, collectWithGrantNames, collectWritableFields, conjoinArbacDbScopes, enforceControlsPolicy, extractUsedControlValues, getArbacMate, isMetaFieldVisible, isScopedFieldVisible, metaAlwaysVisibleFields, pruneMetaByVisibility, unionScopeProjection, useArbac };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aooth/arbac-moost",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.58",
|
|
4
4
|
"description": "Moost RBAC integration for aoothjs (migrated from @moostjs/arbac)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"abac",
|
|
@@ -60,16 +60,16 @@
|
|
|
60
60
|
"access": "public"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@aooth/arbac": "0.1.
|
|
64
|
-
"@aooth/
|
|
65
|
-
"@aooth/
|
|
63
|
+
"@aooth/arbac": "0.1.58",
|
|
64
|
+
"@aooth/user": "0.1.58",
|
|
65
|
+
"@aooth/arbac-core": "0.1.58"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
68
|
"@atscript/core": "^0.1.85",
|
|
69
|
-
"@atscript/db": "^0.1.
|
|
70
|
-
"@atscript/db-sql-tools": "^0.1.
|
|
71
|
-
"@atscript/db-sqlite": "^0.1.
|
|
72
|
-
"@atscript/moost-db": "^0.1.
|
|
69
|
+
"@atscript/db": "^0.1.124",
|
|
70
|
+
"@atscript/db-sql-tools": "^0.1.124",
|
|
71
|
+
"@atscript/db-sqlite": "^0.1.124",
|
|
72
|
+
"@atscript/moost-db": "^0.1.124",
|
|
73
73
|
"@atscript/typescript": "^0.1.85",
|
|
74
74
|
"@moostjs/event-http": "^0.6.33",
|
|
75
75
|
"@types/better-sqlite3": "^7.6.13",
|
|
@@ -78,8 +78,8 @@
|
|
|
78
78
|
"unplugin-atscript": "^0.1.85"
|
|
79
79
|
},
|
|
80
80
|
"peerDependencies": {
|
|
81
|
-
"@atscript/db": "^0.1.
|
|
82
|
-
"@atscript/moost-db": "^0.1.
|
|
81
|
+
"@atscript/db": "^0.1.124",
|
|
82
|
+
"@atscript/moost-db": "^0.1.124",
|
|
83
83
|
"@atscript/typescript": "^0.1.85",
|
|
84
84
|
"@moostjs/event-http": "^0.6.33",
|
|
85
85
|
"@wooksjs/event-core": "^0.7.21",
|