@aooth/arbac-moost 0.2.3 → 0.2.4
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.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as AoothArbacClaims, t as ArbacUserProvider } from "../user.provider-
|
|
1
|
+
import { r as AoothArbacClaims, t as ArbacUserProvider } from "../user.provider-D0cJ_iMd.mjs";
|
|
2
2
|
import { TAtscriptAnnotatedType, TAtscriptTypeObject, TMetadataMap, TValidatorOptions, Validator } from "@atscript/typescript/utils";
|
|
3
3
|
import { AoothUserCredentials } from "@aooth/user/atscript-db/model.as";
|
|
4
4
|
/**
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { _ as ProjectionOf, a as conjoinArbacDbScopes, b as TArbacMeta, c as ArbacDbScope, d as extractUsedControlValues, f as applyAllowedFieldsAndSet, g as OwnFieldKey, h as NavTarget, i as ConjoinArbacDbScopesOptions, l as AsArbacDbController, m as NavRelationKey, n as ArbacUserProviderToken, o as RefForeignKey, p as ControlsOf, r as AoothArbacClaims, s as RefTableSource, t as ArbacUserProvider, u as enforceControlsPolicy, v as ARBAC_DELEGATED_AUTH, x as getArbacMate, y as ArbacDelegatedAuth } from "./user.provider-
|
|
1
|
+
import { _ as ProjectionOf, a as conjoinArbacDbScopes, b as TArbacMeta, c as ArbacDbScope, d as extractUsedControlValues, f as applyAllowedFieldsAndSet, g as OwnFieldKey, h as NavTarget, i as ConjoinArbacDbScopesOptions, l as AsArbacDbController, m as NavRelationKey, n as ArbacUserProviderToken, o as RefForeignKey, p as ControlsOf, r as AoothArbacClaims, s as RefTableSource, t as ArbacUserProvider, u as enforceControlsPolicy, v as ARBAC_DELEGATED_AUTH, x as getArbacMate, y as ArbacDelegatedAuth } from "./user.provider-D0cJ_iMd.mjs";
|
|
2
2
|
import { Arbac, Arbac as Arbac$1, TArbacCompiledRule, TArbacEvalResult, TArbacEvalResult as TArbacEvalResult$1, TArbacRole, TArbacRoleForResource, TArbacRule, arbacPatternToRegex } from "@aooth/arbac-core";
|
|
3
3
|
import { ControlGate, ControlGate as ControlGate$1, TProjection, TScopeFieldRules, TScopeFilter, conjoinScopeFilters } from "@aooth/arbac";
|
|
4
|
-
import { TAuthGuardDef } from "@moostjs/event-http";
|
|
4
|
+
import { HttpError, TAuthGuardDef } from "@moostjs/event-http";
|
|
5
5
|
import { EventContext } from "@wooksjs/event-core";
|
|
6
6
|
import { FilterExpr, TDbRemoveGuardContext, TDbWriteCheckContext, TDbWriteGuardContext, TDeleteOptions, TMetaResponse, TRowResolveOptions, TWriteOptions, UniqueryControls } from "@atscript/db";
|
|
7
7
|
import { AsDbReadableController, AsJsonValueHelpController, AsValueHelpController, TDbActionScopeContext, TDbControlsType, TDbIndexFieldPaths, TDbRequestContext, ValueHelpSelect } from "@atscript/moost-db";
|
|
@@ -615,9 +615,41 @@ export declare function isScopedFieldVisible(scopes: ArbacDbScope[], path: strin
|
|
|
615
615
|
* caller's readable rows match the query; the action itself is authorized
|
|
616
616
|
* by its source controller on every batch.
|
|
617
617
|
*
|
|
618
|
+
* A read endpoint (`query`, `pages`, `geo`, `one`) under a moost-db write
|
|
619
|
+
* handler (`insert`, `update`, `replace`, `remove`, `removeComposite`) is
|
|
620
|
+
* served only inside {@link readBackUnderReadGrant} (since 0.2.4), under the
|
|
621
|
+
* read grant it installs — otherwise a 403, never the write grant. moost-db's
|
|
622
|
+
* insert read-back (`Prefer: return=representation`) then answers the plain
|
|
623
|
+
* insert result.
|
|
624
|
+
*
|
|
618
625
|
* @since 0.1.72
|
|
619
626
|
*/
|
|
620
627
|
export declare function prepareArbacRequest(ctx: TDbRequestContext, readable?: VisibilityTableSource): Promise<void>;
|
|
628
|
+
/**
|
|
629
|
+
* Read back the row `id` after a write, exactly as `GET /one/:id` would
|
|
630
|
+
* answer the caller (since 0.2.4) — the body of
|
|
631
|
+
* `AsArbacDbController._readRepresentation`, and the way for a write handler
|
|
632
|
+
* override to answer the written row:
|
|
633
|
+
*
|
|
634
|
+
* ```ts
|
|
635
|
+
* await super.update(payload);
|
|
636
|
+
* return readBackUnderReadGrant(id, () => this.getOne(String(id), ""));
|
|
637
|
+
* ```
|
|
638
|
+
*
|
|
639
|
+
* `read` calls the controller's `/one` handler: `getOne` for a scalar `id`,
|
|
640
|
+
* `getOneComposite` for a key object. The caller's grant on that handler is
|
|
641
|
+
* evaluated (its `@ArbacResource` / `@ArbacAction`, credential attenuation
|
|
642
|
+
* included) and installed as the request's scopes while `read` runs — its
|
|
643
|
+
* row filter, projection and controls apply, and an overridden handler body
|
|
644
|
+
* runs too — then the write's scopes are restored.
|
|
645
|
+
*
|
|
646
|
+
* Answers `undefined` instead of the row when: the caller has no grant on
|
|
647
|
+
* that handler; the handler carries method-level interceptors (they would
|
|
648
|
+
* not run on a direct call); `read` answers or throws an `HttpError` (e.g.
|
|
649
|
+
* the row is outside the read filter → 404); or anything else fails (logged
|
|
650
|
+
* as a warning, never answered — the write is already committed).
|
|
651
|
+
*/
|
|
652
|
+
export declare function readBackUnderReadGrant<R>(id: unknown, read: () => Promise<R>): Promise<Exclude<R, HttpError> | undefined>;
|
|
621
653
|
/**
|
|
622
654
|
* `authorizeForm` for the ARBAC DB controllers: a form is served iff the
|
|
623
655
|
* caller may run at least one of the actions that take it as input — each
|
package/dist/index.mjs
CHANGED
|
@@ -21,6 +21,15 @@ function getOrCreate(map, key, create) {
|
|
|
21
21
|
function hasSelfOrAncestor(set, path) {
|
|
22
22
|
return set.has(path) || findAncestorInSet(path, set) !== void 0;
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* A key object (a composite id, read by `getOneComposite`) — a plain object.
|
|
26
|
+
* A class instance such as a MongoDB `ObjectId` is a scalar id: `String(id)`.
|
|
27
|
+
*/
|
|
28
|
+
function isKeyObject(id) {
|
|
29
|
+
if (id === null || typeof id !== "object") return false;
|
|
30
|
+
const proto = Object.getPrototypeOf(id);
|
|
31
|
+
return proto === Object.prototype || proto === null;
|
|
32
|
+
}
|
|
24
33
|
/** A patch (`update` / `updateMany`) — only the keys it carries are written. */
|
|
25
34
|
function isPatchAction(action) {
|
|
26
35
|
return action === "update" || action === "updateMany";
|
|
@@ -2603,10 +2612,11 @@ function cachedRequestScopes() {
|
|
|
2603
2612
|
*/
|
|
2604
2613
|
async function resolveRequestScopes() {
|
|
2605
2614
|
const ctx = current();
|
|
2615
|
+
const prior = resolved();
|
|
2616
|
+
if (prior?.readBack) return prior.scopes;
|
|
2606
2617
|
const arbac = useArbac(ctx);
|
|
2607
2618
|
const cachedScopes = arbac.getScopes();
|
|
2608
2619
|
const fromInterceptor = cachedScopes && scopesOwnedBy(cachedScopes, arbac.resource, arbac.action) ? cachedScopes : void 0;
|
|
2609
|
-
const prior = resolved();
|
|
2610
2620
|
if (prior && prior.resource === arbac.resource && prior.action === arbac.action && prior.source === fromInterceptor) return prior.scopes;
|
|
2611
2621
|
const scopes = normalizeScopes(fromInterceptor !== void 0 ? {
|
|
2612
2622
|
allowed: true,
|
|
@@ -2684,6 +2694,13 @@ function isScopedFieldVisible(scopes, path, source) {
|
|
|
2684
2694
|
* caller's readable rows match the query; the action itself is authorized
|
|
2685
2695
|
* by its source controller on every batch.
|
|
2686
2696
|
*
|
|
2697
|
+
* A read endpoint (`query`, `pages`, `geo`, `one`) under a moost-db write
|
|
2698
|
+
* handler (`insert`, `update`, `replace`, `remove`, `removeComposite`) is
|
|
2699
|
+
* served only inside {@link readBackUnderReadGrant} (since 0.2.4), under the
|
|
2700
|
+
* read grant it installs — otherwise a 403, never the write grant. moost-db's
|
|
2701
|
+
* insert read-back (`Prefer: return=representation`) then answers the plain
|
|
2702
|
+
* insert result.
|
|
2703
|
+
*
|
|
2687
2704
|
* @since 0.1.72
|
|
2688
2705
|
*/
|
|
2689
2706
|
async function prepareArbacRequest(ctx, readable) {
|
|
@@ -2695,10 +2712,67 @@ async function prepareArbacRequest(ctx, readable) {
|
|
|
2695
2712
|
await authorizeDelegatedQueryTarget();
|
|
2696
2713
|
return;
|
|
2697
2714
|
}
|
|
2715
|
+
if (READ_ENDPOINTS.has(ctx.endpoint) && !resolved()?.readBack && underWriteHandler()) {
|
|
2716
|
+
const { resource, action } = useArbac();
|
|
2717
|
+
throw insufficientPrivileges(resource, action);
|
|
2718
|
+
}
|
|
2698
2719
|
const scopes = await resolveRequestScopes();
|
|
2699
2720
|
if (ctx.endpoint === "insert" && ctx.onConflict === "ignore") resolved().insertIgnore = true;
|
|
2700
2721
|
if (READ_ENDPOINTS.has(ctx.endpoint)) enforceRelationGates(await resolveRequestRelations(scopes, ctx.controls, readable, ctx.filter), visibilityFor(scopes, readable));
|
|
2701
2722
|
}
|
|
2723
|
+
/** moost-db's write handler methods — a read under one of them must be a read-back. */
|
|
2724
|
+
const WRITE_HANDLERS = new Set([...WRITE_CRUD_OPS].flatMap((op) => DB_CRUD_HANDLERS[op]));
|
|
2725
|
+
function underWriteHandler() {
|
|
2726
|
+
const method = useControllerContext().getMethod();
|
|
2727
|
+
return method !== void 0 && WRITE_HANDLERS.has(method);
|
|
2728
|
+
}
|
|
2729
|
+
/**
|
|
2730
|
+
* Read back the row `id` after a write, exactly as `GET /one/:id` would
|
|
2731
|
+
* answer the caller (since 0.2.4) — the body of
|
|
2732
|
+
* `AsArbacDbController._readRepresentation`, and the way for a write handler
|
|
2733
|
+
* override to answer the written row:
|
|
2734
|
+
*
|
|
2735
|
+
* ```ts
|
|
2736
|
+
* await super.update(payload);
|
|
2737
|
+
* return readBackUnderReadGrant(id, () => this.getOne(String(id), ""));
|
|
2738
|
+
* ```
|
|
2739
|
+
*
|
|
2740
|
+
* `read` calls the controller's `/one` handler: `getOne` for a scalar `id`,
|
|
2741
|
+
* `getOneComposite` for a key object. The caller's grant on that handler is
|
|
2742
|
+
* evaluated (its `@ArbacResource` / `@ArbacAction`, credential attenuation
|
|
2743
|
+
* included) and installed as the request's scopes while `read` runs — its
|
|
2744
|
+
* row filter, projection and controls apply, and an overridden handler body
|
|
2745
|
+
* runs too — then the write's scopes are restored.
|
|
2746
|
+
*
|
|
2747
|
+
* Answers `undefined` instead of the row when: the caller has no grant on
|
|
2748
|
+
* that handler; the handler carries method-level interceptors (they would
|
|
2749
|
+
* not run on a direct call); `read` answers or throws an `HttpError` (e.g.
|
|
2750
|
+
* the row is outside the read filter → 404); or anything else fails (logged
|
|
2751
|
+
* as a warning, never answered — the write is already committed).
|
|
2752
|
+
*/
|
|
2753
|
+
async function readBackUnderReadGrant(id, read) {
|
|
2754
|
+
const ctx = current();
|
|
2755
|
+
const prior = resolved();
|
|
2756
|
+
if (!prior) return void 0;
|
|
2757
|
+
try {
|
|
2758
|
+
const instance = useControllerContext(ctx).getController();
|
|
2759
|
+
const method = isKeyObject(id) ? "getOneComposite" : "getOne";
|
|
2760
|
+
if (getMoostMate().read(instance, method)?.interceptors?.length) return void 0;
|
|
2761
|
+
const ids = resolveHandlerArbacIds(instance, method);
|
|
2762
|
+
const [outcome] = await evaluateHandlerOutcomes([ids]);
|
|
2763
|
+
const scopes = normalizeScopes(outcome);
|
|
2764
|
+
if (!scopes) return void 0;
|
|
2765
|
+
storeResolved(ctx, ids, void 0, scopes);
|
|
2766
|
+
ctx.get(requestScopesKey).readBack = true;
|
|
2767
|
+
const row = await read();
|
|
2768
|
+
return row instanceof HttpError ? void 0 : row;
|
|
2769
|
+
} catch (error) {
|
|
2770
|
+
if (!(error instanceof HttpError)) useLogger("arbac", ctx).warn(`Read-back of the written row failed: ${String(error)}`);
|
|
2771
|
+
return;
|
|
2772
|
+
} finally {
|
|
2773
|
+
ctx.set(requestScopesKey, prior);
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2702
2776
|
/**
|
|
2703
2777
|
* `authorizeForm` for the ARBAC DB controllers: a form is served iff the
|
|
2704
2778
|
* caller may run at least one of the actions that take it as input — each
|
|
@@ -3205,6 +3279,15 @@ let AsArbacDbController = class AsArbacDbController extends AsDbController {
|
|
|
3205
3279
|
return prepareArbacRequest(ctx, this.readable);
|
|
3206
3280
|
}
|
|
3207
3281
|
/**
|
|
3282
|
+
* The read-back of `Prefer: return=representation` on `POST /` (since
|
|
3283
|
+
* 0.2.4; opt in with `returnRepresentation()`): this controller's own
|
|
3284
|
+
* `/one` handler under the caller's grant on it — see
|
|
3285
|
+
* {@link readBackUnderReadGrant}.
|
|
3286
|
+
*/
|
|
3287
|
+
_readRepresentation(id) {
|
|
3288
|
+
return readBackUnderReadGrant(id, () => isKeyObject(id) ? this.getOneComposite(textKey(id), "") : this.getOne(String(id), ""));
|
|
3289
|
+
}
|
|
3290
|
+
/**
|
|
3208
3291
|
* The request filter ∧ the union of the scopes' `filter`s. Computed
|
|
3209
3292
|
* synchronously, but typed with moost-db's async-capable contract
|
|
3210
3293
|
* (`FilterExpr | Promise<FilterExpr>`) so a subclass may override it
|
|
@@ -3392,6 +3475,10 @@ let AsArbacDbController = class AsArbacDbController extends AsDbController {
|
|
|
3392
3475
|
}
|
|
3393
3476
|
};
|
|
3394
3477
|
AsArbacDbController = __decorate([Inherit()], AsArbacDbController);
|
|
3478
|
+
/** A key object as `GET /one?…` receives it — every value as text. */
|
|
3479
|
+
function textKey(id) {
|
|
3480
|
+
return Object.fromEntries(Object.entries(id).map(([k, v]) => [k, String(v)]));
|
|
3481
|
+
}
|
|
3395
3482
|
const preservedFieldsCache = /* @__PURE__ */ new WeakMap();
|
|
3396
3483
|
/**
|
|
3397
3484
|
* Test-friendly internal helper — exported for unit tests and helper
|
|
@@ -3813,4 +3900,4 @@ async function useArbacDbScope() {
|
|
|
3813
3900
|
})
|
|
3814
3901
|
};
|
|
3815
3902
|
}
|
|
3816
|
-
export { ARBAC_DELEGATED_AUTH, Arbac, ArbacAction, ArbacAuthorize, ArbacResource, ArbacUserProvider, ArbacUserProviderToken, AsArbacDbController, AsArbacDbReadableController, AsArbacJsonValueHelpController, AsArbacValueHelpController, MoostArbac, applyAllowedFieldsAndSet, applyArbacControls, applyArbacMetaOverlay, applyArbacProjection, applyArbacRelationScopes, arbacActionRowScope, arbacAllowedActions, arbacAuthorizeInterceptor, arbacPatternToRegex, arbacRelationFilter, arbacRowFilter, authorizeArbacForm, buildScopeVisibility, cachedRequestScopes, checkArbacWrite, collectMethodNames, collectWithGrantNames, collectWritableFields, conjoinArbacDbScopes, conjoinScopeFilters, enforceControlsPolicy, extractUsedControlValues, getArbacMate, getArbacScopes, guardArbacRemove, guardArbacWrite, isMetaFieldVisible, isScopedFieldVisible, metaAlwaysVisibleFields, prepareArbacRequest, pruneMetaByVisibility, registerArbacDbTarget, requestFieldVisible, requireRequestScopes, resolveHandlerArbacIds, resolveRequestScopes, unionScopeProjection, useArbac, useArbacDbScope };
|
|
3903
|
+
export { ARBAC_DELEGATED_AUTH, Arbac, ArbacAction, ArbacAuthorize, ArbacResource, ArbacUserProvider, ArbacUserProviderToken, AsArbacDbController, AsArbacDbReadableController, AsArbacJsonValueHelpController, AsArbacValueHelpController, MoostArbac, applyAllowedFieldsAndSet, applyArbacControls, applyArbacMetaOverlay, applyArbacProjection, applyArbacRelationScopes, arbacActionRowScope, arbacAllowedActions, arbacAuthorizeInterceptor, arbacPatternToRegex, arbacRelationFilter, arbacRowFilter, authorizeArbacForm, buildScopeVisibility, cachedRequestScopes, checkArbacWrite, collectMethodNames, collectWithGrantNames, collectWritableFields, conjoinArbacDbScopes, conjoinScopeFilters, enforceControlsPolicy, extractUsedControlValues, getArbacMate, getArbacScopes, guardArbacRemove, guardArbacWrite, isMetaFieldVisible, isScopedFieldVisible, metaAlwaysVisibleFields, prepareArbacRequest, pruneMetaByVisibility, readBackUnderReadGrant, registerArbacDbTarget, requestFieldVisible, requireRequestScopes, resolveHandlerArbacIds, resolveRequestScopes, unionScopeProjection, useArbac, useArbacDbScope };
|
|
@@ -268,6 +268,13 @@ declare class AsArbacDbController<T extends TAtscriptAnnotatedType = TAtscriptAn
|
|
|
268
268
|
* is resolved for the requested relations.
|
|
269
269
|
*/
|
|
270
270
|
protected prepareRequest(ctx: TDbRequestContext): Promise<void>;
|
|
271
|
+
/**
|
|
272
|
+
* The read-back of `Prefer: return=representation` on `POST /` (since
|
|
273
|
+
* 0.2.4; opt in with `returnRepresentation()`): this controller's own
|
|
274
|
+
* `/one` handler under the caller's grant on it — see
|
|
275
|
+
* {@link readBackUnderReadGrant}.
|
|
276
|
+
*/
|
|
277
|
+
protected _readRepresentation(id: unknown): Promise<TAtscriptDataType<T> | undefined>;
|
|
271
278
|
/**
|
|
272
279
|
* The request filter ∧ the union of the scopes' `filter`s. Computed
|
|
273
280
|
* synchronously, but typed with moost-db's async-capable contract
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aooth/arbac-moost",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Moost RBAC integration for aoothjs (migrated from @moostjs/arbac)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"abac",
|
|
@@ -61,16 +61,16 @@
|
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@uniqu/core": "^0.2.0",
|
|
64
|
-
"@aooth/arbac": "0.2.
|
|
65
|
-
"@aooth/user": "0.2.
|
|
66
|
-
"@aooth/arbac-core": "0.2.
|
|
64
|
+
"@aooth/arbac": "0.2.4",
|
|
65
|
+
"@aooth/user": "0.2.4",
|
|
66
|
+
"@aooth/arbac-core": "0.2.4"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@atscript/core": "^0.2.4",
|
|
70
|
-
"@atscript/db": "^0.1.
|
|
71
|
-
"@atscript/db-sql-tools": "^0.1.
|
|
72
|
-
"@atscript/db-sqlite": "^0.1.
|
|
73
|
-
"@atscript/moost-db": "^0.1.
|
|
70
|
+
"@atscript/db": "^0.1.169",
|
|
71
|
+
"@atscript/db-sql-tools": "^0.1.169",
|
|
72
|
+
"@atscript/db-sqlite": "^0.1.169",
|
|
73
|
+
"@atscript/moost-db": "^0.1.169",
|
|
74
74
|
"@atscript/typescript": "^0.2.4",
|
|
75
75
|
"@moostjs/event-http": "^0.7.2",
|
|
76
76
|
"@types/better-sqlite3": "^7.6.13",
|
|
@@ -78,8 +78,8 @@
|
|
|
78
78
|
"unplugin-atscript": "^0.2.4"
|
|
79
79
|
},
|
|
80
80
|
"peerDependencies": {
|
|
81
|
-
"@atscript/db": "^0.1.
|
|
82
|
-
"@atscript/moost-db": "^0.1.
|
|
81
|
+
"@atscript/db": "^0.1.169",
|
|
82
|
+
"@atscript/moost-db": "^0.1.169",
|
|
83
83
|
"@atscript/typescript": "^0.2.4",
|
|
84
84
|
"@moostjs/event-http": "^0.7.2",
|
|
85
85
|
"@wooksjs/event-core": "^0.8.0",
|