@diister/quick-permission 0.9.0-beta.5
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/LICENSE +21 -0
- package/README.md +747 -0
- package/aggregation.ts +114 -0
- package/core/filtering.ts +70 -0
- package/core/matching.ts +82 -0
- package/core/merging.ts +143 -0
- package/dist/aggregation.d.ts +62 -0
- package/dist/aggregation.d.ts.map +1 -0
- package/dist/aggregation.js +97 -0
- package/dist/aggregation.js.map +1 -0
- package/dist/core/filtering.d.ts +35 -0
- package/dist/core/filtering.d.ts.map +1 -0
- package/dist/core/filtering.js +62 -0
- package/dist/core/filtering.js.map +1 -0
- package/dist/core/matching.d.ts +31 -0
- package/dist/core/matching.d.ts.map +1 -0
- package/dist/core/matching.js +75 -0
- package/dist/core/matching.js.map +1 -0
- package/dist/core/merging.d.ts +29 -0
- package/dist/core/merging.d.ts.map +1 -0
- package/dist/core/merging.js +124 -0
- package/dist/core/merging.js.map +1 -0
- package/dist/indirect-aggregation.d.ts +41 -0
- package/dist/indirect-aggregation.d.ts.map +1 -0
- package/dist/indirect-aggregation.js +185 -0
- package/dist/indirect-aggregation.js.map +1 -0
- package/dist/indirect-resource.d.ts +126 -0
- package/dist/indirect-resource.d.ts.map +1 -0
- package/dist/indirect-resource.js +109 -0
- package/dist/indirect-resource.js.map +1 -0
- package/dist/mod.d.ts +25 -0
- package/dist/mod.d.ts.map +1 -0
- package/dist/mod.js +25 -0
- package/dist/mod.js.map +1 -0
- package/dist/mongo-query.d.ts +38 -0
- package/dist/mongo-query.d.ts.map +1 -0
- package/dist/mongo-query.js +88 -0
- package/dist/mongo-query.js.map +1 -0
- package/dist/permission.d.ts +57 -0
- package/dist/permission.d.ts.map +1 -0
- package/dist/permission.js +60 -0
- package/dist/permission.js.map +1 -0
- package/dist/resource.d.ts +48 -0
- package/dist/resource.d.ts.map +1 -0
- package/dist/resource.js +298 -0
- package/dist/resource.js.map +1 -0
- package/dist/rules.d.ts +106 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +183 -0
- package/dist/rules.js.map +1 -0
- package/dist/sift/core.d.ts +104 -0
- package/dist/sift/core.d.ts.map +1 -0
- package/dist/sift/core.js +248 -0
- package/dist/sift/core.js.map +1 -0
- package/dist/sift/index.d.ts +10 -0
- package/dist/sift/index.d.ts.map +1 -0
- package/dist/sift/index.js +18 -0
- package/dist/sift/index.js.map +1 -0
- package/dist/sift/operations.d.ts +87 -0
- package/dist/sift/operations.d.ts.map +1 -0
- package/dist/sift/operations.js +257 -0
- package/dist/sift/operations.js.map +1 -0
- package/dist/sift/utils.d.ts +12 -0
- package/dist/sift/utils.d.ts.map +1 -0
- package/dist/sift/utils.js +80 -0
- package/dist/sift/utils.js.map +1 -0
- package/dist/system.d.ts +113 -0
- package/dist/system.d.ts.map +1 -0
- package/dist/system.js +712 -0
- package/dist/system.js.map +1 -0
- package/dist/target.d.ts +18 -0
- package/dist/target.d.ts.map +1 -0
- package/dist/target.js +41 -0
- package/dist/target.js.map +1 -0
- package/dist/types.d.ts +345 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/indirect-aggregation.ts +216 -0
- package/indirect-resource.ts +205 -0
- package/mod.ts +81 -0
- package/mongo-query.ts +94 -0
- package/package.json +58 -0
- package/permission.ts +88 -0
- package/resource.ts +352 -0
- package/rules.ts +241 -0
- package/sift/MIT-LICENSE.txt +20 -0
- package/sift/core.ts +551 -0
- package/sift/index.ts +62 -0
- package/sift/operations.ts +449 -0
- package/sift/utils.ts +96 -0
- package/system.ts +974 -0
- package/target.ts +84 -0
- package/types.ts +408 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `indirectResource` — déclaration d'une ressource atteignable via une
|
|
3
|
+
* jointure (DB-pushdown via aggregation pipeline). Pendant de `resource()`
|
|
4
|
+
* pour les cas où la donnée filtrante vit dans une autre collection (ou
|
|
5
|
+
* dans la même via un foreign field).
|
|
6
|
+
*
|
|
7
|
+
* Cas d'usage typique :
|
|
8
|
+
* - lister les `participant` qui ont une `org_membership` matching org=X
|
|
9
|
+
* - lister les `participant` dont l'`user` lié appartient à entreprise=Y
|
|
10
|
+
* - chaîner sur plusieurs niveaux (`participant → user → entreprise_member`)
|
|
11
|
+
*
|
|
12
|
+
* La méthode `.match()` retourne une `Rule` sentinelle (kind="indirect-match")
|
|
13
|
+
* que l'orchestrateur de `system.ts` détecte pour générer le pipeline
|
|
14
|
+
* d'aggregation correspondant — voir `indirect-aggregation.ts`.
|
|
15
|
+
*
|
|
16
|
+
* À la différence des ressources directes :
|
|
17
|
+
* - Pas de `fetch` ni de `dedupKey` : aucune donnée chargée à l'évaluation
|
|
18
|
+
* - Pas de rule `filter`/`include`/`require*` — uniquement `match` pour
|
|
19
|
+
* contribuer une contrainte au pipeline généré.
|
|
20
|
+
*/
|
|
21
|
+
import { defineRule } from "./rules.js";
|
|
22
|
+
import { evaluateSpec, validateSpec } from "./mongo-query.js";
|
|
23
|
+
/**
|
|
24
|
+
* Sentinelle dans `Rule.descriptor` pour qu'`system.ts` reconnaisse
|
|
25
|
+
* cette rule comme "indirect" et collecte la resource correspondante.
|
|
26
|
+
*
|
|
27
|
+
* Le champ est typé `unknown` côté `RuleDescriptor` parce que
|
|
28
|
+
* `[extra: string]: unknown` est la signature catch-all des descriptors —
|
|
29
|
+
* on cast à l'extraction.
|
|
30
|
+
*/
|
|
31
|
+
export const INDIRECT_RULE_KIND = "indirect-match";
|
|
32
|
+
export function indirectResource(spec) {
|
|
33
|
+
// Normalize `from`: a `Resource` (from `resource({...})`) has no `kind`
|
|
34
|
+
// field; we treat it as "direct". An `IndirectResource` has
|
|
35
|
+
// `kind: "indirect"` set by this very factory. Walking the chain in
|
|
36
|
+
// the orchestrator reads `from.kind` to know whether to descend.
|
|
37
|
+
const fromNormalized = {
|
|
38
|
+
id: spec.from.id,
|
|
39
|
+
kind: spec.from.kind === "indirect"
|
|
40
|
+
? "indirect"
|
|
41
|
+
: "direct",
|
|
42
|
+
};
|
|
43
|
+
const impl = {
|
|
44
|
+
id: spec.id,
|
|
45
|
+
kind: "indirect",
|
|
46
|
+
from: fromNormalized,
|
|
47
|
+
on: spec.on,
|
|
48
|
+
to: spec.to,
|
|
49
|
+
cardinality: spec.cardinality,
|
|
50
|
+
fetcher: spec.fetch,
|
|
51
|
+
cacheKeyForTarget(target) {
|
|
52
|
+
// Mirror of Resource.cacheKeyForTarget — the indirect's cache key
|
|
53
|
+
// is target-derived (typically by source dedup). Useful for
|
|
54
|
+
// `CanContext.preseed()` when the caller wants to inject joined
|
|
55
|
+
// docs already returned by a pipeline aggregation.
|
|
56
|
+
return `${spec.id}::${JSON.stringify(target)}`;
|
|
57
|
+
},
|
|
58
|
+
match() {
|
|
59
|
+
return defineRule({
|
|
60
|
+
kind: INDIRECT_RULE_KIND,
|
|
61
|
+
needs: [],
|
|
62
|
+
describe: () => ({ indirectResource: impl }),
|
|
63
|
+
check: (_data, _payload, ctx) => {
|
|
64
|
+
// Cap-mode : sentinelle. `system.ts` reads the descriptor and
|
|
65
|
+
// emits the pipeline via `buildAggregationStages`. The rule
|
|
66
|
+
// itself contributes nothing.
|
|
67
|
+
if (ctx.capability)
|
|
68
|
+
return { ok: true };
|
|
69
|
+
// Concrete mode without fetcher : sentinelle aussi (legacy).
|
|
70
|
+
if (!impl.fetcher)
|
|
71
|
+
return { ok: true };
|
|
72
|
+
// Concrete mode with fetcher : evaluate `grant.with[id]` spec
|
|
73
|
+
// against the joined docs. The engine already populated the
|
|
74
|
+
// joined docs in the context cache (see system.ts) — we just
|
|
75
|
+
// read them from `_indirectFetched` (an opaque per-rule pass).
|
|
76
|
+
// If no spec is set, the rule passes (the grant trusts the
|
|
77
|
+
// indirect resource without further check).
|
|
78
|
+
const spec = ctx.grant.with?.[impl.id];
|
|
79
|
+
if (spec === undefined)
|
|
80
|
+
return { ok: true };
|
|
81
|
+
if (typeof spec === "object" && spec !== null)
|
|
82
|
+
validateSpec(spec);
|
|
83
|
+
const joined = ctx._indirectFetched?.get(impl.id) ?? [];
|
|
84
|
+
const passes = joined.some((d) => evaluateSpec(spec, d));
|
|
85
|
+
return passes
|
|
86
|
+
? { ok: true }
|
|
87
|
+
: {
|
|
88
|
+
ok: false,
|
|
89
|
+
reason: `indirect[${impl.id}] no joined doc matches spec`,
|
|
90
|
+
};
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
return impl;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Extraction utilitaire pour `system.ts` : récupère la `IndirectResource`
|
|
99
|
+
* portée par une rule sentinelle, ou `null` si la rule n'en est pas une.
|
|
100
|
+
*/
|
|
101
|
+
export function extractIndirectResource(rule) {
|
|
102
|
+
if (rule.descriptor.kind !== INDIRECT_RULE_KIND)
|
|
103
|
+
return null;
|
|
104
|
+
const ref = rule.descriptor.indirectResource;
|
|
105
|
+
if (!ref || typeof ref !== "object")
|
|
106
|
+
return null;
|
|
107
|
+
return ref;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=indirect-resource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indirect-resource.js","sourceRoot":"","sources":["../indirect-resource.ts"],"names":[],"mappings":"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"}
|
package/dist/mod.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@diister/quick-permission` — API publique.
|
|
3
|
+
*
|
|
4
|
+
* Expose une primitive unique `defineRule({ needs, check })` autour de
|
|
5
|
+
* laquelle sont organisés les `Resource`, méthodes de sucre, et le moteur
|
|
6
|
+
* d'orchestration avec dedup par contexte.
|
|
7
|
+
*
|
|
8
|
+
* Cf. `docs/rfc-resource-pipe-api.md` pour la motivation, les décisions
|
|
9
|
+
* de design et le plan de migration.
|
|
10
|
+
*/
|
|
11
|
+
export { seg, target } from "./target.ts";
|
|
12
|
+
export type { AnySegment, AnyTarget, CanResult, FetchCtx, FilterContribution, Grant, IndirectResourceInfo, ListEntry, Permission, Resource, ResourceData, ResourcesData, Rule, RuleDescriptor, RuleResult, SegmentSpec, SerializableSegment, SerializableTarget, SpecToSegment, Subject, TargetArgs, TargetNone, TargetOptional, TargetPath, TargetRequired, TreeNode, } from "./types.ts";
|
|
13
|
+
export { resource } from "./resource.ts";
|
|
14
|
+
export { indirectResource } from "./indirect-resource.ts";
|
|
15
|
+
export type { IndirectResource, IndirectResourceJoin, } from "./indirect-resource.ts";
|
|
16
|
+
export type { AggregationStage } from "./indirect-aggregation.ts";
|
|
17
|
+
export { defineRule, inputMatch, matchPath, requireSelf } from "./rules.ts";
|
|
18
|
+
export type { DefineRuleOpts } from "./rules.ts";
|
|
19
|
+
export { intermediate, permission } from "./permission.ts";
|
|
20
|
+
export type { IntermediateBuilder, IntermediateConfig, PermissionBuilder, PermissionConfig, } from "./permission.ts";
|
|
21
|
+
export { createSystem } from "./system.ts";
|
|
22
|
+
export type { CanContext, Provider, ProviderFn, ProviderObject, System, } from "./system.ts";
|
|
23
|
+
export { applyFilter, pickFields } from "./core/filtering.ts";
|
|
24
|
+
export type { FilterSpec } from "./core/merging.ts";
|
|
25
|
+
//# sourceMappingURL=mod.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAG1C,YAAY,EACV,UAAU,EACV,SAAS,EACT,SAAS,EACT,QAAQ,EACR,kBAAkB,EAClB,KAAK,EACL,oBAAoB,EACpB,SAAS,EACT,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,aAAa,EACb,IAAI,EACJ,cAAc,EACd,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,OAAO,EACP,UAAU,EACV,UAAU,EACV,cAAc,EACd,UAAU,EACV,cAAc,EACd,QAAQ,GACT,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EACV,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAGlE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC5E,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC3D,YAAY,EACV,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EACV,UAAU,EACV,QAAQ,EACR,UAAU,EACV,cAAc,EACd,MAAM,GACP,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC9D,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/mod.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@diister/quick-permission` — API publique.
|
|
3
|
+
*
|
|
4
|
+
* Expose une primitive unique `defineRule({ needs, check })` autour de
|
|
5
|
+
* laquelle sont organisés les `Resource`, méthodes de sucre, et le moteur
|
|
6
|
+
* d'orchestration avec dedup par contexte.
|
|
7
|
+
*
|
|
8
|
+
* Cf. `docs/rfc-resource-pipe-api.md` pour la motivation, les décisions
|
|
9
|
+
* de design et le plan de migration.
|
|
10
|
+
*/
|
|
11
|
+
// ─── Targets ─────────────────────────────────────────────────────────────
|
|
12
|
+
export { seg, target } from "./target.js";
|
|
13
|
+
// ─── Resource factory + sugar methods ────────────────────────────────────
|
|
14
|
+
export { resource } from "./resource.js";
|
|
15
|
+
// ─── Indirect resource (JOIN-based, generates aggregation pipeline) ──────
|
|
16
|
+
export { indirectResource } from "./indirect-resource.js";
|
|
17
|
+
// ─── defineRule + standalone helpers ─────────────────────────────────────
|
|
18
|
+
export { defineRule, inputMatch, matchPath, requireSelf } from "./rules.js";
|
|
19
|
+
// ─── Permission builders ─────────────────────────────────────────────────
|
|
20
|
+
export { intermediate, permission } from "./permission.js";
|
|
21
|
+
// ─── System ──────────────────────────────────────────────────────────────
|
|
22
|
+
export { createSystem } from "./system.js";
|
|
23
|
+
// ─── Field-projection helpers (used outside permission checks too) ───────
|
|
24
|
+
export { applyFilter, pickFields } from "./core/filtering.js";
|
|
25
|
+
//# sourceMappingURL=mod.js.map
|
package/dist/mod.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.js","sourceRoot":"","sources":["../mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,4EAA4E;AAC5E,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAgC1C,4EAA4E;AAC5E,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,4EAA4E;AAC5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAO1D,4EAA4E;AAC5E,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG5E,4EAA4E;AAC5E,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAQ3D,4EAA4E;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAS3C,4EAA4E;AAC5E,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Évaluateur d'expressions style MongoDB query basé sur `sift`.
|
|
3
|
+
*
|
|
4
|
+
* Sift supporte ~100% du Mongo query language en pur JS. On délègue
|
|
5
|
+
* l'évaluation à sift mais on **valide la spec en amont** pour s'assurer
|
|
6
|
+
* qu'aucun opérateur dangereux n'est utilisé (`$where`, `$function`, etc.
|
|
7
|
+
* permettent de l'exécution de code arbitraire — interdits dans un grant
|
|
8
|
+
* qui peut venir de la DB).
|
|
9
|
+
*
|
|
10
|
+
* Whitelist :
|
|
11
|
+
* - Comparaisons : `$eq`, `$ne`, `$in`, `$nin`, `$gt`, `$gte`, `$lt`, `$lte`
|
|
12
|
+
* - Existence : `$exists`, `$type`
|
|
13
|
+
* - Logiques : `$and`, `$or`, `$nor`, `$not`
|
|
14
|
+
* - String : `$regex`, `$options`
|
|
15
|
+
* - Tableaux : `$all`, `$elemMatch`, `$size`
|
|
16
|
+
*
|
|
17
|
+
* Interdit (pas dans la whitelist, throw au boot ou au check) :
|
|
18
|
+
* - `$where`, `$function`, `$expr`, `$jsonSchema`, `$accumulator`
|
|
19
|
+
*
|
|
20
|
+
* La même spec sert à :
|
|
21
|
+
* 1. Évaluer en mémoire un document (per-doc check via sift)
|
|
22
|
+
* 2. Filtrer une collection MongoDB en pushdown (la spec EST déjà du Mongo)
|
|
23
|
+
*/
|
|
24
|
+
export type MongoSpec = Record<string, unknown>;
|
|
25
|
+
/**
|
|
26
|
+
* Vérifie récursivement qu'aucun opérateur non-whitelisté n'est présent
|
|
27
|
+
* dans la spec. Throw au premier opérateur interdit (`$where`, etc.).
|
|
28
|
+
*
|
|
29
|
+
* À appeler à la création du grant (validation côté API) ou au pire au
|
|
30
|
+
* check time, pour empêcher l'exécution de code arbitraire.
|
|
31
|
+
*/
|
|
32
|
+
export declare function validateSpec(spec: unknown, path?: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* Évalue une spec contre un document. La spec est validée d'abord pour
|
|
35
|
+
* rejeter tout opérateur non-whitelisté.
|
|
36
|
+
*/
|
|
37
|
+
export declare function evaluateSpec(spec: MongoSpec, doc: unknown): boolean;
|
|
38
|
+
//# sourceMappingURL=mongo-query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mongo-query.d.ts","sourceRoot":"","sources":["../mongo-query.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AA+BH,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,SAAM,GAAG,IAAI,CAqB5D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAInE"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Évaluateur d'expressions style MongoDB query basé sur `sift`.
|
|
3
|
+
*
|
|
4
|
+
* Sift supporte ~100% du Mongo query language en pur JS. On délègue
|
|
5
|
+
* l'évaluation à sift mais on **valide la spec en amont** pour s'assurer
|
|
6
|
+
* qu'aucun opérateur dangereux n'est utilisé (`$where`, `$function`, etc.
|
|
7
|
+
* permettent de l'exécution de code arbitraire — interdits dans un grant
|
|
8
|
+
* qui peut venir de la DB).
|
|
9
|
+
*
|
|
10
|
+
* Whitelist :
|
|
11
|
+
* - Comparaisons : `$eq`, `$ne`, `$in`, `$nin`, `$gt`, `$gte`, `$lt`, `$lte`
|
|
12
|
+
* - Existence : `$exists`, `$type`
|
|
13
|
+
* - Logiques : `$and`, `$or`, `$nor`, `$not`
|
|
14
|
+
* - String : `$regex`, `$options`
|
|
15
|
+
* - Tableaux : `$all`, `$elemMatch`, `$size`
|
|
16
|
+
*
|
|
17
|
+
* Interdit (pas dans la whitelist, throw au boot ou au check) :
|
|
18
|
+
* - `$where`, `$function`, `$expr`, `$jsonSchema`, `$accumulator`
|
|
19
|
+
*
|
|
20
|
+
* La même spec sert à :
|
|
21
|
+
* 1. Évaluer en mémoire un document (per-doc check via sift)
|
|
22
|
+
* 2. Filtrer une collection MongoDB en pushdown (la spec EST déjà du Mongo)
|
|
23
|
+
*/
|
|
24
|
+
import sift from "./sift/index.js";
|
|
25
|
+
const ALLOWED_OPERATORS = new Set([
|
|
26
|
+
// Comparison
|
|
27
|
+
"$eq",
|
|
28
|
+
"$ne",
|
|
29
|
+
"$in",
|
|
30
|
+
"$nin",
|
|
31
|
+
"$gt",
|
|
32
|
+
"$gte",
|
|
33
|
+
"$lt",
|
|
34
|
+
"$lte",
|
|
35
|
+
// Existence / type
|
|
36
|
+
"$exists",
|
|
37
|
+
"$type",
|
|
38
|
+
// Logical
|
|
39
|
+
"$and",
|
|
40
|
+
"$or",
|
|
41
|
+
"$nor",
|
|
42
|
+
"$not",
|
|
43
|
+
// String
|
|
44
|
+
"$regex",
|
|
45
|
+
"$options",
|
|
46
|
+
// Array
|
|
47
|
+
"$all",
|
|
48
|
+
"$elemMatch",
|
|
49
|
+
"$size",
|
|
50
|
+
]);
|
|
51
|
+
/**
|
|
52
|
+
* Vérifie récursivement qu'aucun opérateur non-whitelisté n'est présent
|
|
53
|
+
* dans la spec. Throw au premier opérateur interdit (`$where`, etc.).
|
|
54
|
+
*
|
|
55
|
+
* À appeler à la création du grant (validation côté API) ou au pire au
|
|
56
|
+
* check time, pour empêcher l'exécution de code arbitraire.
|
|
57
|
+
*/
|
|
58
|
+
export function validateSpec(spec, path = "$") {
|
|
59
|
+
if (spec === null || typeof spec !== "object")
|
|
60
|
+
return;
|
|
61
|
+
if (Array.isArray(spec)) {
|
|
62
|
+
// A `for` loop, not `forEach`: the arrow's implicit return handed back
|
|
63
|
+
// validateSpec's value, which the iteration then discarded.
|
|
64
|
+
for (const [i, item] of spec.entries()) {
|
|
65
|
+
validateSpec(item, `${path}[${i}]`);
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
for (const [key, value] of Object.entries(spec)) {
|
|
70
|
+
if (key.startsWith("$")) {
|
|
71
|
+
if (!ALLOWED_OPERATORS.has(key)) {
|
|
72
|
+
throw new Error(`Forbidden Mongo operator at ${path}: "${key}". ` +
|
|
73
|
+
`Allowed: ${[...ALLOWED_OPERATORS].join(", ")}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
validateSpec(value, `${path}.${key}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Évalue une spec contre un document. La spec est validée d'abord pour
|
|
81
|
+
* rejeter tout opérateur non-whitelisté.
|
|
82
|
+
*/
|
|
83
|
+
export function evaluateSpec(spec, doc) {
|
|
84
|
+
validateSpec(spec);
|
|
85
|
+
// deno-lint-ignore no-explicit-any
|
|
86
|
+
return sift(spec)(doc);
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=mongo-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mongo-query.js","sourceRoot":"","sources":["../mongo-query.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,IAAI,MAAM,iBAAiB,CAAC;AAEnC,MAAM,iBAAiB,GAAwB,IAAI,GAAG,CAAC;IACrD,aAAa;IACb,KAAK;IACL,KAAK;IACL,KAAK;IACL,MAAM;IACN,KAAK;IACL,MAAM;IACN,KAAK;IACL,MAAM;IACN,mBAAmB;IACnB,SAAS;IACT,OAAO;IACP,UAAU;IACV,MAAM;IACN,KAAK;IACL,MAAM;IACN,MAAM;IACN,SAAS;IACT,QAAQ;IACR,UAAU;IACV,QAAQ;IACR,MAAM;IACN,YAAY;IACZ,OAAO;CACR,CAAC,CAAC;AAIH;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,IAAa,EAAE,IAAI,GAAG,GAAG;IACpD,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO;IACtD,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,uEAAuE;QACvE,4DAA4D;QAC5D,KAAK,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YACvC,YAAY,CAAC,IAAI,EAAE,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;QACtC,CAAC;QACD,OAAO;IACT,CAAC;IACD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAc,CAAC,EAAE,CAAC;QAC1D,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAChC,MAAM,IAAI,KAAK,CACb,+BAA+B,IAAI,MAAM,GAAG,KAAK;oBAC/C,YAAY,CAAC,GAAG,iBAAiB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAClD,CAAC;YACJ,CAAC;QACH,CAAC;QACD,YAAY,CAAC,KAAK,EAAE,GAAG,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAe,EAAE,GAAY;IACxD,YAAY,CAAC,IAAI,CAAC,CAAC;IACnB,mCAAmC;IACnC,OAAQ,IAAY,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builder de permission pour resource-pipe.
|
|
3
|
+
*
|
|
4
|
+
* API en deux étapes (`permission(opts).rules([])`), même justification que
|
|
5
|
+
* `library/permission.ts` (cf. RFC declarative §"Décision two-call").
|
|
6
|
+
*
|
|
7
|
+
* Différence majeure vs l'API declarative actuelle : pas de slot `fetch` au
|
|
8
|
+
* niveau permission. Les fetches sont déclarés au niveau des `Resource`s
|
|
9
|
+
* que les rules consomment via `needs`.
|
|
10
|
+
*/
|
|
11
|
+
import type { AnyTarget, Grant, Permission, Rule } from "./types.ts";
|
|
12
|
+
export type PermissionConfig<TMeta> = {
|
|
13
|
+
readonly metadata?: TMeta;
|
|
14
|
+
readonly target: AnyTarget;
|
|
15
|
+
};
|
|
16
|
+
export type PermissionBuilder<TMeta> = {
|
|
17
|
+
rules(rules: readonly Rule[]): Permission<TMeta>;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Déclare une permission "feuille" (vérifiable directement via `can()`).
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* "users.read": permission({
|
|
24
|
+
* metadata: { description: "Lire un user" },
|
|
25
|
+
* target: target.required("user"),
|
|
26
|
+
* }).rules([
|
|
27
|
+
* userOf.match(),
|
|
28
|
+
* userOf.filter(),
|
|
29
|
+
* ]),
|
|
30
|
+
*/
|
|
31
|
+
export declare function permission<TMeta = unknown>(config: PermissionConfig<TMeta>): PermissionBuilder<TMeta>;
|
|
32
|
+
export type IntermediateConfig<TMeta> = {
|
|
33
|
+
readonly metadata?: TMeta;
|
|
34
|
+
readonly target: AnyTarget;
|
|
35
|
+
/** Expand un grant sur cette intermediate en N grants sur les enfants. */
|
|
36
|
+
readonly expandsTo: (grant: Grant) => readonly Grant[];
|
|
37
|
+
};
|
|
38
|
+
export type IntermediateBuilder<TMeta> = {
|
|
39
|
+
/** Optionnellement attacher des rules au niveau intermediate. */
|
|
40
|
+
rules(rules: readonly Rule[]): Permission<TMeta>;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Déclare une permission "intermediate" (macro qui s'expand en grants
|
|
44
|
+
* enfants au moment du check).
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* "users.manage": intermediate({
|
|
48
|
+
* target: target.required("user"),
|
|
49
|
+
* expandsTo: (grant) => [
|
|
50
|
+
* { ...grant, key: "users.read" },
|
|
51
|
+
* { ...grant, key: "users.update" },
|
|
52
|
+
* { ...grant, key: "users.delete" },
|
|
53
|
+
* ],
|
|
54
|
+
* }).rules([]),
|
|
55
|
+
*/
|
|
56
|
+
export declare function intermediate<TMeta = unknown>(config: IntermediateConfig<TMeta>): IntermediateBuilder<TMeta>;
|
|
57
|
+
//# sourceMappingURL=permission.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission.d.ts","sourceRoot":"","sources":["../permission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAErE,MAAM,MAAM,gBAAgB,CAAC,KAAK,IAAI;IACpC,QAAQ,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,iBAAiB,CAAC,KAAK,IAAI;IACrC,KAAK,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;CAClD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,KAAK,GAAG,OAAO,EACxC,MAAM,EAAE,gBAAgB,CAAC,KAAK,CAAC,GAC9B,iBAAiB,CAAC,KAAK,CAAC,CAU1B;AAED,MAAM,MAAM,kBAAkB,CAAC,KAAK,IAAI;IACtC,QAAQ,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,SAAS,KAAK,EAAE,CAAC;CACxD,CAAC;AAEF,MAAM,MAAM,mBAAmB,CAAC,KAAK,IAAI;IACvC,iEAAiE;IACjE,KAAK,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;CAClD,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,KAAK,GAAG,OAAO,EAC1C,MAAM,EAAE,kBAAkB,CAAC,KAAK,CAAC,GAChC,mBAAmB,CAAC,KAAK,CAAC,CAW5B"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builder de permission pour resource-pipe.
|
|
3
|
+
*
|
|
4
|
+
* API en deux étapes (`permission(opts).rules([])`), même justification que
|
|
5
|
+
* `library/permission.ts` (cf. RFC declarative §"Décision two-call").
|
|
6
|
+
*
|
|
7
|
+
* Différence majeure vs l'API declarative actuelle : pas de slot `fetch` au
|
|
8
|
+
* niveau permission. Les fetches sont déclarés au niveau des `Resource`s
|
|
9
|
+
* que les rules consomment via `needs`.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Déclare une permission "feuille" (vérifiable directement via `can()`).
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* "users.read": permission({
|
|
16
|
+
* metadata: { description: "Lire un user" },
|
|
17
|
+
* target: target.required("user"),
|
|
18
|
+
* }).rules([
|
|
19
|
+
* userOf.match(),
|
|
20
|
+
* userOf.filter(),
|
|
21
|
+
* ]),
|
|
22
|
+
*/
|
|
23
|
+
export function permission(config) {
|
|
24
|
+
return {
|
|
25
|
+
rules(rules) {
|
|
26
|
+
return {
|
|
27
|
+
metadata: config.metadata,
|
|
28
|
+
target: config.target,
|
|
29
|
+
rules,
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Déclare une permission "intermediate" (macro qui s'expand en grants
|
|
36
|
+
* enfants au moment du check).
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* "users.manage": intermediate({
|
|
40
|
+
* target: target.required("user"),
|
|
41
|
+
* expandsTo: (grant) => [
|
|
42
|
+
* { ...grant, key: "users.read" },
|
|
43
|
+
* { ...grant, key: "users.update" },
|
|
44
|
+
* { ...grant, key: "users.delete" },
|
|
45
|
+
* ],
|
|
46
|
+
* }).rules([]),
|
|
47
|
+
*/
|
|
48
|
+
export function intermediate(config) {
|
|
49
|
+
return {
|
|
50
|
+
rules(rules) {
|
|
51
|
+
return {
|
|
52
|
+
metadata: config.metadata,
|
|
53
|
+
target: config.target,
|
|
54
|
+
rules,
|
|
55
|
+
expandsTo: config.expandsTo,
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=permission.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission.js","sourceRoot":"","sources":["../permission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAaH;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU,CACxB,MAA+B;IAE/B,OAAO;QACL,KAAK,CAAC,KAAK;YACT,OAAO;gBACL,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,KAAK;aACN,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAcD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAiC;IAEjC,OAAO;QACL,KAAK,CAAC,KAAK;YACT,OAAO;gBACL,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,KAAK;gBACL,SAAS,EAAE,MAAM,CAAC,SAAS;aAC5B,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Resource` : source de donnée fetchable, dédupliquée par contexte.
|
|
3
|
+
*
|
|
4
|
+
* Une Resource est conçue pour être déclarée une fois dans son domaine
|
|
5
|
+
* (`userOf`, `expositionInfoOf`, etc.) et réutilisée entre permissions.
|
|
6
|
+
* Le moteur dédup les fetches au sein d'un context via `(id, dedupKey)`.
|
|
7
|
+
*
|
|
8
|
+
* Les méthodes `match`/`filter`/`includes`/`require*` sont du sucre :
|
|
9
|
+
* elles produisent des Rule via `defineRule`, avec la resource comme need.
|
|
10
|
+
*
|
|
11
|
+
* ─── Capability-mode contract ────────────────────────────────────────────
|
|
12
|
+
* A request target containing a wildcard (`"*"` or `"xxx:*"`) is a capability
|
|
13
|
+
* query — "can the subject act on ANY resource of this shape?". The engine
|
|
14
|
+
* skips resource fetches in this mode (no concrete resource to fetch). Each
|
|
15
|
+
* rule must declare what it does when its data is unavailable:
|
|
16
|
+
*
|
|
17
|
+
* match : silent-pass (cannot verify spec against absent data),
|
|
18
|
+
* but exposes the spec as a constraint for DB pushdown.
|
|
19
|
+
* filter : silent-pass — no projection happens; `output.data`
|
|
20
|
+
* stays undefined.
|
|
21
|
+
* includes : deny — membership cannot be checked without the resource.
|
|
22
|
+
* requireTruthy : deny — no value to test for truthiness.
|
|
23
|
+
* requireOwner : deny — no owner field to compare.
|
|
24
|
+
* requireMembership: deny — no membership list to scan.
|
|
25
|
+
* requireCustom : deny — predicate cannot run without `data`.
|
|
26
|
+
*
|
|
27
|
+
* Pure rules (no `needs`) like `matchPath` and `requireSelf` are unaffected:
|
|
28
|
+
* they read `ctx.target` / `ctx.subject` only.
|
|
29
|
+
*/
|
|
30
|
+
import type { FetchCtx, Grant, Resource } from "./types.ts";
|
|
31
|
+
/**
|
|
32
|
+
* Crée une Resource. À utiliser une fois par entité de domaine, partagée
|
|
33
|
+
* entre toutes les permissions qui la consomment.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* const userOf = resource({
|
|
37
|
+
* id: "user",
|
|
38
|
+
* fetch: ({ target }) => usersRepo.findById(target[0] as string),
|
|
39
|
+
* dedupKey: ({ target }) => target[0] as string,
|
|
40
|
+
* });
|
|
41
|
+
*/
|
|
42
|
+
export declare function resource<T>(opts: {
|
|
43
|
+
readonly id: string;
|
|
44
|
+
readonly fetch: (ctx: FetchCtx) => T | Promise<T>;
|
|
45
|
+
readonly activeWhen?: (grant: Grant) => boolean;
|
|
46
|
+
readonly dedupKey?: (ctx: FetchCtx) => string;
|
|
47
|
+
}): Resource<T>;
|
|
48
|
+
//# sourceMappingURL=resource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../resource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAQ,MAAM,YAAY,CAAC;AA0SlE;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAClD,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC;IAChD,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,MAAM,CAAC;CAC/C,GAAG,QAAQ,CAAC,CAAC,CAAC,CAOd"}
|