@dudousxd/nestjs-authz 0.2.0 → 0.4.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/CHANGELOG.md +84 -0
- package/dist/can-endpoint.controller.d.ts +39 -0
- package/dist/can-endpoint.controller.d.ts.map +1 -0
- package/dist/can-endpoint.controller.js +97 -0
- package/dist/can-endpoint.controller.js.map +1 -0
- package/dist/decorator/roles.decorator.d.ts +15 -0
- package/dist/decorator/roles.decorator.d.ts.map +1 -0
- package/dist/decorator/roles.decorator.js +19 -0
- package/dist/decorator/roles.decorator.js.map +1 -0
- package/dist/diagnostics.d.ts +42 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +68 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/gate.d.ts +42 -1
- package/dist/gate.d.ts.map +1 -1
- package/dist/gate.js +116 -12
- package/dist/gate.js.map +1 -1
- package/dist/guard/roles.guard.d.ts +21 -0
- package/dist/guard/roles.guard.d.ts.map +1 -0
- package/dist/guard/roles.guard.js +50 -0
- package/dist/guard/roles.guard.js.map +1 -0
- package/dist/index.d.ts +10 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/module.d.ts +13 -0
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +48 -2
- package/dist/module.js.map +1 -1
- package/dist/permission-provider.d.ts +2 -0
- package/dist/permission-provider.d.ts.map +1 -1
- package/dist/policy-registry.d.ts +21 -0
- package/dist/policy-registry.d.ts.map +1 -1
- package/dist/policy-registry.js +42 -0
- package/dist/policy-registry.js.map +1 -1
- package/dist/role-provider.d.ts +40 -0
- package/dist/role-provider.d.ts.map +1 -0
- package/dist/role-provider.js +32 -0
- package/dist/role-provider.js.map +1 -0
- package/dist/tokens.d.ts +29 -0
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +29 -0
- package/dist/tokens.js.map +1 -1
- package/dist/types.d.ts +67 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/policy-registry.js
CHANGED
|
@@ -41,6 +41,48 @@ let PolicyRegistry = class PolicyRegistry {
|
|
|
41
41
|
all() {
|
|
42
42
|
return [...this.byResource.values()];
|
|
43
43
|
}
|
|
44
|
+
/** All registered resource classes (insertion order). */
|
|
45
|
+
resources() {
|
|
46
|
+
return [...this.byResource.keys()];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Enumerate the CLASS-LEVEL ability method names declared on each registered
|
|
50
|
+
* policy, keyed by resource class. Used by integrations that pre-resolve a
|
|
51
|
+
* user's class-level abilities (e.g. to share them as Inertia props).
|
|
52
|
+
*
|
|
53
|
+
* Walks the policy prototype chain and collects own function-valued members,
|
|
54
|
+
* excluding `constructor` and the reserved `before` hook. Inherited Object
|
|
55
|
+
* members are skipped.
|
|
56
|
+
*
|
|
57
|
+
* Only methods that take NO resource instance are included — heuristically,
|
|
58
|
+
* arity `<= 1` (just `user`, e.g. `create(user)` / `viewAny(user)`). An
|
|
59
|
+
* instance method like `update(user, post)` is excluded: dispatching it
|
|
60
|
+
* against the resource CLASS would call it with the class constructor as
|
|
61
|
+
* `post` and write a bogus class-level verdict.
|
|
62
|
+
*/
|
|
63
|
+
classAbilities() {
|
|
64
|
+
const out = [];
|
|
65
|
+
for (const [resource, policy] of this.byResource) {
|
|
66
|
+
const abilities = new Set();
|
|
67
|
+
let proto = Object.getPrototypeOf(policy);
|
|
68
|
+
while (proto && proto !== Object.prototype) {
|
|
69
|
+
for (const name of Object.getOwnPropertyNames(proto)) {
|
|
70
|
+
if (name === 'constructor' || name === 'before')
|
|
71
|
+
continue;
|
|
72
|
+
const member = policy[name];
|
|
73
|
+
// Class-level abilities take only `user` (arity <= 1). A method that
|
|
74
|
+
// also declares a resource param (arity >= 2) is instance-scoped and
|
|
75
|
+
// must not be dispatched against the class.
|
|
76
|
+
if (typeof member === 'function' && member.length <= 1) {
|
|
77
|
+
abilities.add(name);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
proto = Object.getPrototypeOf(proto);
|
|
81
|
+
}
|
|
82
|
+
out.push({ resource, abilities: [...abilities] });
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
44
86
|
};
|
|
45
87
|
PolicyRegistry = __decorate([
|
|
46
88
|
Injectable()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy-registry.js","sourceRoot":"","sources":["../src/policy-registry.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AAGrE;;;GAGG;AAEI,IAAM,cAAc,GAApB,MAAM,cAAc;IACR,UAAU,GAAG,IAAI,GAAG,EAAiC,CAAC;IAEvE;;;OAGG;IACH,QAAQ,CAAC,MAAsB;QAC7B,MAAM,QAAQ,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,EAAE,IAAI,IAAI,QAAQ,CAAC;YAClD,MAAM,IAAI,2BAA2B,CAAC,IAAI,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;IAED,wEAAwE;IACxE,WAAW,CAAC,QAAuB;QACjC,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACvC,CAAC;IAED,+EAA+E;IAC/E,WAAW,CAAC,QAAgB;QAC1B,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,WAA4B,CAAC,CAAC;IACpE,CAAC;IAED,+DAA+D;IAC/D,GAAG,CAAC,QAAuB;QACzB,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACvC,CAAC;IAED,2DAA2D;IAC3D,GAAG;QACD,OAAO,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IACvC,CAAC;CACF,CAAA;
|
|
1
|
+
{"version":3,"file":"policy-registry.js","sourceRoot":"","sources":["../src/policy-registry.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AAGrE;;;GAGG;AAEI,IAAM,cAAc,GAApB,MAAM,cAAc;IACR,UAAU,GAAG,IAAI,GAAG,EAAiC,CAAC;IAEvE;;;OAGG;IACH,QAAQ,CAAC,MAAsB;QAC7B,MAAM,QAAQ,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,EAAE,IAAI,IAAI,QAAQ,CAAC;YAClD,MAAM,IAAI,2BAA2B,CAAC,IAAI,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;IAED,wEAAwE;IACxE,WAAW,CAAC,QAAuB;QACjC,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACvC,CAAC;IAED,+EAA+E;IAC/E,WAAW,CAAC,QAAgB;QAC1B,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,WAA4B,CAAC,CAAC;IACpE,CAAC;IAED,+DAA+D;IAC/D,GAAG,CAAC,QAAuB;QACzB,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACvC,CAAC;IAED,2DAA2D;IAC3D,GAAG;QACD,OAAO,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IACvC,CAAC;IAED,yDAAyD;IACzD,SAAS;QACP,OAAO,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,cAAc;QACZ,MAAM,GAAG,GAA4D,EAAE,CAAC;QACxE,KAAK,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACjD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;YACpC,IAAI,KAAK,GAAkB,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YACzD,OAAO,KAAK,IAAI,KAAK,KAAK,MAAM,CAAC,SAAS,EAAE,CAAC;gBAC3C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;oBACrD,IAAI,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,QAAQ;wBAAE,SAAS;oBAC1D,MAAM,MAAM,GAAI,MAAkC,CAAC,IAAI,CAAC,CAAC;oBACzD,qEAAqE;oBACrE,qEAAqE;oBACrE,4CAA4C;oBAC5C,IAAI,OAAO,MAAM,KAAK,UAAU,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;wBACvD,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBACtB,CAAC;gBACH,CAAC;gBACD,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YACvC,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF,CAAA;AA9EY,cAAc;IAD1B,UAAU,EAAE;GACA,cAAc,CA8E1B"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { User } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Optional seam that lets a persisted RBAC layer supply a user's roles.
|
|
4
|
+
*
|
|
5
|
+
* This mirrors {@link PermissionProvider} but for COARSE, role-based checks
|
|
6
|
+
* (`gate.hasRole('teacher')`, `@Roles('admin')`). The core does NOT implement
|
|
7
|
+
* this — `@dudousxd/nestjs-authz-typeorm` (and the other RBAC adapters) provide an
|
|
8
|
+
* implementation and register it under the shared {@link ROLE_PROVIDER} token.
|
|
9
|
+
* When no provider is registered the default {@link RoleResolver} (reading roles
|
|
10
|
+
* off the user object) is the only source.
|
|
11
|
+
*
|
|
12
|
+
* `user` is the current user (whatever the app's auth layer produced; `undefined`
|
|
13
|
+
* when anonymous). Return the role names the user holds — an empty array (or
|
|
14
|
+
* nullish) contributes no roles. When both this provider and the default resolver
|
|
15
|
+
* yield roles, the Gate takes their UNION.
|
|
16
|
+
*/
|
|
17
|
+
export interface RoleProvider {
|
|
18
|
+
getRoles(user: User): string[] | undefined | Promise<string[] | undefined>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Strategy that derives a user's roles from the user object itself, with ZERO RBAC
|
|
22
|
+
* tables. The {@link defaultRoleResolver} reads `user.roles` (`string[]`) OR
|
|
23
|
+
* `user.role` (`string | string[]`) and normalizes both to a `string[]`. Apps that
|
|
24
|
+
* already carry a role on the user thus get role-checks for free; an app that needs
|
|
25
|
+
* a different shape overrides it via `AuthzModule.forRoot({ resolveRoles })`.
|
|
26
|
+
*/
|
|
27
|
+
export type RoleResolver = (user: User) => string[] | undefined | Promise<string[] | undefined>;
|
|
28
|
+
/**
|
|
29
|
+
* Default {@link RoleResolver}: read roles directly off the user object.
|
|
30
|
+
*
|
|
31
|
+
* - `user.roles` is a `string[]` → used as-is.
|
|
32
|
+
* - `user.role` is a `string` → wrapped to `[role]`.
|
|
33
|
+
* - `user.role` is a `string[]` → used as-is.
|
|
34
|
+
* - neither present (or anonymous) → `[]` (no roles).
|
|
35
|
+
*
|
|
36
|
+
* Non-string entries are filtered out so a malformed field can never leak a
|
|
37
|
+
* truthy match.
|
|
38
|
+
*/
|
|
39
|
+
export declare function defaultRoleResolver(user: User): string[];
|
|
40
|
+
//# sourceMappingURL=role-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role-provider.d.ts","sourceRoot":"","sources":["../src/role-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;CAC5E;AAED;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,EAAE,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;AAEhG;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,CAaxD"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default {@link RoleResolver}: read roles directly off the user object.
|
|
3
|
+
*
|
|
4
|
+
* - `user.roles` is a `string[]` → used as-is.
|
|
5
|
+
* - `user.role` is a `string` → wrapped to `[role]`.
|
|
6
|
+
* - `user.role` is a `string[]` → used as-is.
|
|
7
|
+
* - neither present (or anonymous) → `[]` (no roles).
|
|
8
|
+
*
|
|
9
|
+
* Non-string entries are filtered out so a malformed field can never leak a
|
|
10
|
+
* truthy match.
|
|
11
|
+
*/
|
|
12
|
+
export function defaultRoleResolver(user) {
|
|
13
|
+
if (user == null || typeof user !== 'object')
|
|
14
|
+
return [];
|
|
15
|
+
const u = user;
|
|
16
|
+
const out = [];
|
|
17
|
+
if (Array.isArray(u.roles)) {
|
|
18
|
+
for (const r of u.roles)
|
|
19
|
+
if (typeof r === 'string')
|
|
20
|
+
out.push(r);
|
|
21
|
+
}
|
|
22
|
+
if (typeof u.role === 'string') {
|
|
23
|
+
out.push(u.role);
|
|
24
|
+
}
|
|
25
|
+
else if (Array.isArray(u.role)) {
|
|
26
|
+
for (const r of u.role)
|
|
27
|
+
if (typeof r === 'string')
|
|
28
|
+
out.push(r);
|
|
29
|
+
}
|
|
30
|
+
return out;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=role-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role-provider.js","sourceRoot":"","sources":["../src/role-provider.ts"],"names":[],"mappings":"AA8BA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAU;IAC5C,IAAI,IAAI,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IACxD,MAAM,CAAC,GAAG,IAA2C,CAAC;IACtD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK;YAAE,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC/B,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;QACjC,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI;YAAE,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/tokens.d.ts
CHANGED
|
@@ -2,10 +2,27 @@
|
|
|
2
2
|
export declare const AUTHZ_MODULE_OPTIONS: unique symbol;
|
|
3
3
|
/** Injection token for the optional {@link ResourceResolver} registered by the app. */
|
|
4
4
|
export declare const RESOURCE_RESOLVER: unique symbol;
|
|
5
|
+
/**
|
|
6
|
+
* Injection token holding the optional resource-loader map consulted by the opt-in
|
|
7
|
+
* `POST /authz/can` endpoint to rehydrate a `{ type, id }` shim into the REAL entity
|
|
8
|
+
* instance before authorizing — so an instance-bound `@Policy` matches by constructor.
|
|
9
|
+
*
|
|
10
|
+
* Resolves to a `ResourceLoaderMap` (`Record<type, (id) => instance | Promise<instance>>`)
|
|
11
|
+
* keyed by the resource `type` name the client/codegen emits. Populated from the
|
|
12
|
+
* `resourceLoaders` forRoot option; an adapter MAY also bind this token to register
|
|
13
|
+
* loaders, mirroring the {@link PERMISSION_PROVIDER}/{@link ROLE_PROVIDER} seam.
|
|
14
|
+
*
|
|
15
|
+
* Shared via `Symbol.for(key)` (global registry) so an external package binding this
|
|
16
|
+
* same key resolves to the SAME symbol instance. Consulted with `@Optional()` — absent
|
|
17
|
+
* or empty, the endpoint behaves exactly as before (class-level / ad-hoc only).
|
|
18
|
+
*/
|
|
19
|
+
export declare const RESOURCE_HYDRATOR: unique symbol;
|
|
5
20
|
/** Metadata key for `@Policy(Resource)` — stores the resource class on the policy. */
|
|
6
21
|
export declare const POLICY_RESOURCE_METADATA = "nestjs-authz:policy-resource";
|
|
7
22
|
/** Metadata key for `@Can(ability, Resource?)` — stores the ability descriptor on a route. */
|
|
8
23
|
export declare const CAN_METADATA = "nestjs-authz:can";
|
|
24
|
+
/** Metadata key for `@Roles(...roles)` — stores the allowed role names on a route. */
|
|
25
|
+
export declare const ROLES_METADATA = "nestjs-authz:roles";
|
|
9
26
|
/**
|
|
10
27
|
* Cross-lib injection token for an optional {@link PermissionProvider} — the seam the
|
|
11
28
|
* RBAC adapter (`@dudousxd/nestjs-authz-typeorm`) registers so that a model-less,
|
|
@@ -18,6 +35,18 @@ export declare const CAN_METADATA = "nestjs-authz:can";
|
|
|
18
35
|
* as before (backward-compatible: unknown abilities still throw).
|
|
19
36
|
*/
|
|
20
37
|
export declare const PERMISSION_PROVIDER: unique symbol;
|
|
38
|
+
/**
|
|
39
|
+
* Cross-lib injection token for an optional {@link RoleProvider} — the seam an RBAC
|
|
40
|
+
* adapter (`@dudousxd/nestjs-authz-typeorm`) registers so coarse role-checks
|
|
41
|
+
* (`gate.hasRole('teacher')`, `@Roles('admin')`) consult a persisted role store.
|
|
42
|
+
*
|
|
43
|
+
* Like {@link PERMISSION_PROVIDER}, it shares the global symbol registry via
|
|
44
|
+
* `Symbol.for(key)` so an RBAC package registering this same key resolves to the
|
|
45
|
+
* SAME symbol instance without importing core internals. Consulted with
|
|
46
|
+
* `@Optional()`: when absent, only the default {@link RoleResolver} (roles read off
|
|
47
|
+
* the user object) supplies roles. When BOTH yield roles, the Gate unions them.
|
|
48
|
+
*/
|
|
49
|
+
export declare const ROLE_PROVIDER: unique symbol;
|
|
21
50
|
/**
|
|
22
51
|
* Cross-lib injection token for the current-request context accessor, owned by
|
|
23
52
|
* `@dudousxd/nestjs-context`. We do NOT import nestjs-context — instead we share
|
package/dist/tokens.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,eAAO,MAAM,oBAAoB,eAA+C,CAAC;AAEjF,uFAAuF;AACvF,eAAO,MAAM,iBAAiB,eAAyD,CAAC;AAExF,sFAAsF;AACtF,eAAO,MAAM,wBAAwB,iCAAiC,CAAC;AAEvE,8FAA8F;AAC9F,eAAO,MAAM,YAAY,qBAAqB,CAAC;AAE/C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,eAA2D,CAAC;AAE5F;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,eAAkD,CAAC"}
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,eAAO,MAAM,oBAAoB,eAA+C,CAAC;AAEjF,uFAAuF;AACvF,eAAO,MAAM,iBAAiB,eAAyD,CAAC;AAExF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,eAAyD,CAAC;AAExF,sFAAsF;AACtF,eAAO,MAAM,wBAAwB,iCAAiC,CAAC;AAEvE,8FAA8F;AAC9F,eAAO,MAAM,YAAY,qBAAqB,CAAC;AAE/C,sFAAsF;AACtF,eAAO,MAAM,cAAc,uBAAuB,CAAC;AAEnD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,eAA2D,CAAC;AAE5F;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,eAAqD,CAAC;AAEhF;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,eAAkD,CAAC"}
|
package/dist/tokens.js
CHANGED
|
@@ -2,10 +2,27 @@
|
|
|
2
2
|
export const AUTHZ_MODULE_OPTIONS = Symbol.for('@dudousxd/nestjs-authz:options');
|
|
3
3
|
/** Injection token for the optional {@link ResourceResolver} registered by the app. */
|
|
4
4
|
export const RESOURCE_RESOLVER = Symbol.for('@dudousxd/nestjs-authz:resource-resolver');
|
|
5
|
+
/**
|
|
6
|
+
* Injection token holding the optional resource-loader map consulted by the opt-in
|
|
7
|
+
* `POST /authz/can` endpoint to rehydrate a `{ type, id }` shim into the REAL entity
|
|
8
|
+
* instance before authorizing — so an instance-bound `@Policy` matches by constructor.
|
|
9
|
+
*
|
|
10
|
+
* Resolves to a `ResourceLoaderMap` (`Record<type, (id) => instance | Promise<instance>>`)
|
|
11
|
+
* keyed by the resource `type` name the client/codegen emits. Populated from the
|
|
12
|
+
* `resourceLoaders` forRoot option; an adapter MAY also bind this token to register
|
|
13
|
+
* loaders, mirroring the {@link PERMISSION_PROVIDER}/{@link ROLE_PROVIDER} seam.
|
|
14
|
+
*
|
|
15
|
+
* Shared via `Symbol.for(key)` (global registry) so an external package binding this
|
|
16
|
+
* same key resolves to the SAME symbol instance. Consulted with `@Optional()` — absent
|
|
17
|
+
* or empty, the endpoint behaves exactly as before (class-level / ad-hoc only).
|
|
18
|
+
*/
|
|
19
|
+
export const RESOURCE_HYDRATOR = Symbol.for('@dudousxd/nestjs-authz:resource-hydrator');
|
|
5
20
|
/** Metadata key for `@Policy(Resource)` — stores the resource class on the policy. */
|
|
6
21
|
export const POLICY_RESOURCE_METADATA = 'nestjs-authz:policy-resource';
|
|
7
22
|
/** Metadata key for `@Can(ability, Resource?)` — stores the ability descriptor on a route. */
|
|
8
23
|
export const CAN_METADATA = 'nestjs-authz:can';
|
|
24
|
+
/** Metadata key for `@Roles(...roles)` — stores the allowed role names on a route. */
|
|
25
|
+
export const ROLES_METADATA = 'nestjs-authz:roles';
|
|
9
26
|
/**
|
|
10
27
|
* Cross-lib injection token for an optional {@link PermissionProvider} — the seam the
|
|
11
28
|
* RBAC adapter (`@dudousxd/nestjs-authz-typeorm`) registers so that a model-less,
|
|
@@ -18,6 +35,18 @@ export const CAN_METADATA = 'nestjs-authz:can';
|
|
|
18
35
|
* as before (backward-compatible: unknown abilities still throw).
|
|
19
36
|
*/
|
|
20
37
|
export const PERMISSION_PROVIDER = Symbol.for('@dudousxd/nestjs-authz:permission-provider');
|
|
38
|
+
/**
|
|
39
|
+
* Cross-lib injection token for an optional {@link RoleProvider} — the seam an RBAC
|
|
40
|
+
* adapter (`@dudousxd/nestjs-authz-typeorm`) registers so coarse role-checks
|
|
41
|
+
* (`gate.hasRole('teacher')`, `@Roles('admin')`) consult a persisted role store.
|
|
42
|
+
*
|
|
43
|
+
* Like {@link PERMISSION_PROVIDER}, it shares the global symbol registry via
|
|
44
|
+
* `Symbol.for(key)` so an RBAC package registering this same key resolves to the
|
|
45
|
+
* SAME symbol instance without importing core internals. Consulted with
|
|
46
|
+
* `@Optional()`: when absent, only the default {@link RoleResolver} (roles read off
|
|
47
|
+
* the user object) supplies roles. When BOTH yield roles, the Gate unions them.
|
|
48
|
+
*/
|
|
49
|
+
export const ROLE_PROVIDER = Symbol.for('@dudousxd/nestjs-authz:role-provider');
|
|
21
50
|
/**
|
|
22
51
|
* Cross-lib injection token for the current-request context accessor, owned by
|
|
23
52
|
* `@dudousxd/nestjs-context`. We do NOT import nestjs-context — instead we share
|
package/dist/tokens.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;AAEjF,uFAAuF;AACvF,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;AAExF,sFAAsF;AACtF,MAAM,CAAC,MAAM,wBAAwB,GAAG,8BAA8B,CAAC;AAEvE,8FAA8F;AAC9F,MAAM,CAAC,MAAM,YAAY,GAAG,kBAAkB,CAAC;AAE/C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;AAE5F;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;AAEjF,uFAAuF;AACvF,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;AAExF;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;AAExF,sFAAsF;AACtF,MAAM,CAAC,MAAM,wBAAwB,GAAG,8BAA8B,CAAC;AAEvE,8FAA8F;AAC9F,MAAM,CAAC,MAAM,YAAY,GAAG,kBAAkB,CAAC;AAE/C,sFAAsF;AACtF,MAAM,CAAC,MAAM,cAAc,GAAG,oBAAoB,CAAC;AAEnD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;AAE5F;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;AAEhF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -31,6 +31,18 @@ export type PolicyInstance = Record<string, unknown> & {
|
|
|
31
31
|
* An ad-hoc gate: a model-less ability resolved by name via `gate.define`.
|
|
32
32
|
*/
|
|
33
33
|
export type GateFn = (user: User, resource?: Resource) => boolean | Promise<boolean>;
|
|
34
|
+
/**
|
|
35
|
+
* A resource loader: turns an `id` into the REAL entity instance for a resource
|
|
36
|
+
* `type`. Used by the opt-in `POST /authz/can` endpoint to rehydrate the client's
|
|
37
|
+
* `{ type, id }` shim before authorizing, so an instance-bound `@Policy` matches by
|
|
38
|
+
* constructor. Returning nullish signals "not found" (the endpoint denies). May be async.
|
|
39
|
+
*/
|
|
40
|
+
export type ResourceLoader = (id: string | number) => unknown | Promise<unknown>;
|
|
41
|
+
/**
|
|
42
|
+
* Resource loaders keyed by the resource `type` name as emitted by the client/codegen
|
|
43
|
+
* (e.g. `'Post'`). See {@link AuthzModuleOptions.resourceLoaders}.
|
|
44
|
+
*/
|
|
45
|
+
export type ResourceLoaderMap = Record<string, ResourceLoader>;
|
|
34
46
|
/**
|
|
35
47
|
* Global super-admin before-hook. Runs before any policy/gate; truthy → allow.
|
|
36
48
|
* `void`/`undefined`/`false` falls through to normal resolution.
|
|
@@ -69,6 +81,19 @@ export interface AuthzModuleOptions {
|
|
|
69
81
|
* you pass directly and never invokes this hook.
|
|
70
82
|
*/
|
|
71
83
|
resolveUser?: (ref: UserRef) => User | undefined | Promise<User | undefined>;
|
|
84
|
+
/**
|
|
85
|
+
* Override the default {@link RoleResolver} used by coarse role-checks
|
|
86
|
+
* (`gate.hasRole('teacher')`, `@Roles('admin')`). The default reads `user.roles`
|
|
87
|
+
* (`string[]`) OR `user.role` (`string | string[]`) off the user object, so
|
|
88
|
+
* role-checks work with ZERO RBAC tables. Provide this to derive roles from a
|
|
89
|
+
* different shape. When the optional `ROLE_PROVIDER` seam is ALSO registered, the
|
|
90
|
+
* Gate unions both sources' roles.
|
|
91
|
+
*
|
|
92
|
+
* On the context path the resolver receives whatever the context produced (the
|
|
93
|
+
* raw {@link UserRef} unless `resolveUser` hydrated the entity); on the explicit
|
|
94
|
+
* `gate.forUser(entity)` path it receives exactly what you passed.
|
|
95
|
+
*/
|
|
96
|
+
resolveRoles?: (user: User) => string[] | undefined | Promise<string[] | undefined>;
|
|
72
97
|
/**
|
|
73
98
|
* Override the default {@link ResourceResolver} used to load an instance for
|
|
74
99
|
* `@Can(ability, Resource)` routes. Defaults to {@link IdParamResourceResolver}
|
|
@@ -83,6 +108,35 @@ export interface AuthzModuleOptions {
|
|
|
83
108
|
* is supplied.
|
|
84
109
|
*/
|
|
85
110
|
idParam?: string;
|
|
111
|
+
/**
|
|
112
|
+
* Opt-in `POST /authz/can` fallback endpoint. **Off by default.** When enabled,
|
|
113
|
+
* registers a controller that runs `gate.allows(ability, resource?)` for the
|
|
114
|
+
* current (context) user and returns `{ allowed: boolean }`. This is the
|
|
115
|
+
* last-resort path the codegen-emitted `can()` helper targets.
|
|
116
|
+
*
|
|
117
|
+
* - `true` → mount at the default path `authz/can`.
|
|
118
|
+
* - `string` → mount at that path (e.g. `'api/authz/can'`).
|
|
119
|
+
* - `false`/omitted → no endpoint is registered.
|
|
120
|
+
*
|
|
121
|
+
* Prefer the no-request paths (shared Inertia props, per-resource `can` maps)
|
|
122
|
+
* — this endpoint exists only for abilities not already hydrated on the client.
|
|
123
|
+
*/
|
|
124
|
+
canEndpoint?: boolean | string;
|
|
125
|
+
/**
|
|
126
|
+
* Resource loaders keyed by the resource `type` name the client/codegen emits
|
|
127
|
+
* (e.g. `'Post'`). They close the per-instance gap in the {@link canEndpoint}
|
|
128
|
+
* fallback: when the endpoint receives `{ ability, resource: { type, id } }` and a
|
|
129
|
+
* loader is registered for `type`, it `await`s `loader(id)` and authorizes the REAL
|
|
130
|
+
* entity — so an instance-bound `@Policy` matches by constructor and its method runs
|
|
131
|
+
* with the loaded resource. A loader returning nullish is treated as "not found"
|
|
132
|
+
* (the endpoint denies). Types WITHOUT a loader keep the prior behavior (class-level
|
|
133
|
+
* / ad-hoc only; a resource-bound ability still denies). Opt-in: unset → unchanged.
|
|
134
|
+
*
|
|
135
|
+
* ```ts
|
|
136
|
+
* resourceLoaders: { Post: (id) => postRepo.findOneBy({ id: Number(id) }) }
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
resourceLoaders?: ResourceLoaderMap;
|
|
86
140
|
}
|
|
87
141
|
export interface AuthzModuleOptionsFactory {
|
|
88
142
|
createAuthzOptions(): Promise<AuthzModuleOptions> | AuthzModuleOptions;
|
|
@@ -93,5 +147,18 @@ export interface AuthzModuleAsyncOptions {
|
|
|
93
147
|
useClass?: Type<AuthzModuleOptionsFactory>;
|
|
94
148
|
useFactory?: (...args: unknown[]) => Promise<AuthzModuleOptions> | AuthzModuleOptions;
|
|
95
149
|
inject?: unknown[];
|
|
150
|
+
/**
|
|
151
|
+
* Opt-in `POST /authz/can` fallback endpoint (see {@link AuthzModuleOptions.canEndpoint}).
|
|
152
|
+
* Declared statically here because controllers are registered at module-definition
|
|
153
|
+
* time, before the async options factory resolves. Off by default.
|
|
154
|
+
*/
|
|
155
|
+
canEndpoint?: boolean | string;
|
|
156
|
+
/**
|
|
157
|
+
* Resource loaders for the {@link canEndpoint} fallback
|
|
158
|
+
* (see {@link AuthzModuleOptions.resourceLoaders}). May also be returned from the
|
|
159
|
+
* async options factory; either way the endpoint reads them from the resolved
|
|
160
|
+
* options, so this declaration is for the rarer case of supplying them statically.
|
|
161
|
+
*/
|
|
162
|
+
resourceLoaders?: ResourceLoaderMap;
|
|
96
163
|
}
|
|
97
164
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC;AAE9B;;;GAGG;AACH,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC;AAE3B;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,QAAQ,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAE3F;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,KACZ,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;AAExD,4EAA4E;AAC5E,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IACrD,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,QAAQ,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAErF;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAC3B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,KACZ,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;AAExD,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;IACvC;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC;IAC7E;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|