@dudousxd/nestjs-authz-prisma 0.5.1 → 0.7.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 +52 -0
- package/README.md +84 -10
- package/dist/authz-rbac.module.d.ts +17 -0
- package/dist/authz-rbac.module.d.ts.map +1 -1
- package/dist/authz-rbac.module.js +51 -9
- package/dist/authz-rbac.module.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/prisma-authz.store.d.ts +42 -17
- package/dist/prisma-authz.store.d.ts.map +1 -1
- package/dist/prisma-authz.store.js +103 -39
- package/dist/prisma-authz.store.js.map +1 -1
- package/dist/prisma-client.d.ts +10 -1
- package/dist/prisma-client.d.ts.map +1 -1
- package/dist/prisma-client.js +3 -1
- package/dist/prisma-client.js.map +1 -1
- package/dist/tenancy.d.ts +100 -0
- package/dist/tenancy.d.ts.map +1 -0
- package/dist/tenancy.js +128 -0
- package/dist/tenancy.js.map +1 -0
- package/package.json +11 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,57 @@
|
|
|
1
1
|
# @dudousxd/nestjs-authz-prisma
|
|
2
2
|
|
|
3
|
+
## 0.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Back on the 0.x line. The 1.x and 2.x versions were published by accident: a release-tooling peer cascade bumped this package to a major, not an API decision. 0.7.0 contains everything those versions shipped (console `authorize` support, tenancy, Node 24+ `engines`) with no other change. Upgrade from 1.x/2.x to 0.7.0; those versions are deprecated.
|
|
8
|
+
|
|
9
|
+
## 2.0.0
|
|
10
|
+
|
|
11
|
+
### Major Changes
|
|
12
|
+
|
|
13
|
+
- [#74](https://github.com/DavideCarvalho/nestjs-authz/pull/74) [`35421dc`](https://github.com/DavideCarvalho/nestjs-authz/commit/35421dc5b09bd271d5087d26e8536191ef6ba342) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - **Breaking:** require Node.js 24 or newer (`engines.node` is now `>=24`; it was `>=22`, and `>=20` for `-client` and `-react`). CI tests on Node 24 and 26. No API changes: see the Upgrading page in the docs.
|
|
14
|
+
|
|
15
|
+
## 1.1.1
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- [#73](https://github.com/DavideCarvalho/nestjs-authz/pull/73) [`9fd6787`](https://github.com/DavideCarvalho/nestjs-authz/commit/9fd6787307361b8552236a833d969fa041a46bca) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Fix the `$queryRaw` permission fast path: it is now called on the client instead of detached from it. A real `PrismaClient` threw on the unbound call, so every permission check silently fell back to the three-query path.
|
|
20
|
+
|
|
21
|
+
## 1.1.0
|
|
22
|
+
|
|
23
|
+
### Minor Changes
|
|
24
|
+
|
|
25
|
+
- [#72](https://github.com/DavideCarvalho/nestjs-authz/pull/72) [`58a5d72`](https://github.com/DavideCarvalho/nestjs-authz/commit/58a5d72d2964a7cfae9cbfe8506526c8518ba30a) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Tenancy for the RBAC modules, following the `@dudousxd/nestjs-context` tenancy switch.
|
|
26
|
+
|
|
27
|
+
- New `tenancy` option (`'inherit' | false | { enabled?, kinds?, nullRows?, roles? }`, default `'inherit'`). With context tenancy on, permission and role checks are scoped to the request's tenant from `Context.setTenant`. A request with no tenant, inside `Context.allTenants()`, or outside a request sees global assignments only. `kinds` limits the tenant kinds this module honours. With tenancy off nothing changes.
|
|
28
|
+
- `tenancy.roles` maps the caller's role inside the tenant (`tenant.role`) to authz roles that apply in that tenant only, e.g. `{ owner: 'org_admin' }`.
|
|
29
|
+
- New `tenant` resolver option, `(user) => tenantId | null | undefined`: an explicit tenant that wins over the context.
|
|
30
|
+
- MikroORM and Prisma can now store tenant-scoped role assignments like Drizzle and TypeORM: `assignRole`, `removeRole` and `setUserRoles` take `{ tenantId }`, and the read methods take a tenant scope. MikroORM: build the entities with `createAuthzEntitySchemas({}, { tenantScoped: true })`. Prisma: add `tenantId String @default("")` to `UserRole` and its `@@id`, then pass `tenantScoped: true`. Without that, every assignment stays global.
|
|
31
|
+
|
|
32
|
+
## 1.0.0
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- Updated dependencies [[`750a6b3`](https://github.com/DavideCarvalho/nestjs-authz/commit/750a6b3f80deea3803dec8df5f9f8cf67a046ac1)]:
|
|
37
|
+
- @dudousxd/nestjs-authz@0.10.0
|
|
38
|
+
|
|
39
|
+
## 0.6.0
|
|
40
|
+
|
|
41
|
+
### Minor Changes
|
|
42
|
+
|
|
43
|
+
- [#67](https://github.com/DavideCarvalho/nestjs-authz/pull/67) [`32e967f`](https://github.com/DavideCarvalho/nestjs-authz/commit/32e967ffbcd68a97e8effc77af9c16bbbafdc918) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Run on `@dudousxd/nestjs-authz` 0.9 and `@nestjs/authorization`: persisted roles and
|
|
44
|
+
permissions now guard routes through the official guard as the core's `RolePolicy` /
|
|
45
|
+
`PermissionPolicy` (`@Roles('editor')`, `@Permission('posts.publish')`), and the guard and the
|
|
46
|
+
handler's `Gate` calls share one permission and role fetch per request. The store API
|
|
47
|
+
(role sources, admin management, tenant-scoped roles where supported) and `AuthzRbacModule`
|
|
48
|
+
are unchanged. A persisted permission named like a policy ability no longer bypasses that
|
|
49
|
+
policy (see the core changeset). Requires NestJS 12, `@nestjs/authorization` ^0.1.3 and Node 22+.
|
|
50
|
+
|
|
51
|
+
### Patch Changes
|
|
52
|
+
|
|
53
|
+
- [#67](https://github.com/DavideCarvalho/nestjs-authz/pull/67) [`32e967f`](https://github.com/DavideCarvalho/nestjs-authz/commit/32e967ffbcd68a97e8effc77af9c16bbbafdc918) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Fix packages that could be published without files their `exports` point to. `tsc` builds no longer use a `.tsbuildinfo` that can outlive `dist/` and skip emitting files. A new `check:exports` step (also `prepack`) fails the release if any `exports`/`main`/`types` path is missing.
|
|
54
|
+
|
|
3
55
|
## 0.5.1
|
|
4
56
|
|
|
5
57
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @dudousxd/nestjs-authz-prisma
|
|
2
2
|
|
|
3
3
|
Prisma RBAC persistence for [`@dudousxd/nestjs-authz`](https://github.com/DavideCarvalho/nestjs-authz) —
|
|
4
|
-
roles
|
|
4
|
+
roles and permissions for the official `@nestjs/authorization` policies, with **zero connection ownership** (your app owns the
|
|
5
5
|
`PrismaClient`; this package never opens a connection and never imports `@prisma/client`).
|
|
6
6
|
|
|
7
7
|
This is the Prisma sibling of `@dudousxd/nestjs-authz-typeorm`: identical store surface and
|
|
@@ -10,7 +10,7 @@ This is the Prisma sibling of `@dudousxd/nestjs-authz-typeorm`: identical store
|
|
|
10
10
|
## Install
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
pnpm add @dudousxd/nestjs-authz-prisma @dudousxd/nestjs-authz
|
|
13
|
+
pnpm add @dudousxd/nestjs-authz-prisma @dudousxd/nestjs-authz @nestjs/authorization
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
No `@prisma/client` is required by this package — it depends only on the structural
|
|
@@ -92,16 +92,30 @@ AuthzRbacModule.forRootAsync({
|
|
|
92
92
|
});
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
-
Once wired,
|
|
95
|
+
Once wired, persisted roles and permissions guard routes through the official
|
|
96
|
+
`@nestjs/authorization` guard, as the core's `RolePolicy` / `PermissionPolicy`:
|
|
96
97
|
|
|
97
98
|
```ts
|
|
98
|
-
await store.givePermissionToRole('editor', 'posts
|
|
99
|
+
await store.givePermissionToRole('editor', 'posts.*');
|
|
99
100
|
await store.assignRole({ type: 'user', id: 7 }, 'editor');
|
|
100
101
|
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
@Permission('posts.publish') // posts.* grants it
|
|
103
|
+
@Can(PermissionPolicy, 'has', permission('posts.publish')) // the same, spelled out
|
|
104
|
+
@Roles('editor') // @Can(RolePolicy, 'has', roles('editor'))
|
|
103
105
|
```
|
|
104
106
|
|
|
107
|
+
and in services, through the `Gate`:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
gate.forUser(user).allows('posts.publish'); // true (PERMISSION_PROVIDER seam)
|
|
111
|
+
gate.forUser(user).allows(PermissionPolicy, 'has', 'posts.publish');
|
|
112
|
+
gate.forUser(user).hasRole('editor'); // true (ROLE_PROVIDER seam)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The user is the one the official guard reads (`AuthorizationModule.forRoot({ getUser })`,
|
|
116
|
+
default `request.user`), mapped to a store ref with `userRefFrom` (default `{ type, id }` or
|
|
117
|
+
`{ id }`).
|
|
118
|
+
|
|
105
119
|
## Role sources (manual vs SSO/SCIM)
|
|
106
120
|
|
|
107
121
|
Every role assignment records a `source`. It defaults to `'manual'`, so existing calls and existing
|
|
@@ -171,10 +185,70 @@ await store.listRoleAssignments({ user: { type: 'user', id: 7 } });
|
|
|
171
185
|
await store.removeUser({ type: 'user', id: 7 });
|
|
172
186
|
```
|
|
173
187
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
nothing. Without `roleSources: true` every row
|
|
177
|
-
`source` matches nothing.
|
|
188
|
+
`tenantId` filters: omitted = every tenant, `null` = global assignments only, a string = that
|
|
189
|
+
tenant's scoped assignments only. Without `tenantScoped: true` (below) every row has
|
|
190
|
+
`tenantId: null`, so a tenant id string matches nothing. Without `roleSources: true` every row
|
|
191
|
+
is `'manual'`, so filtering by another `source` matches nothing.
|
|
192
|
+
|
|
193
|
+
## Tenant-scoped roles
|
|
194
|
+
|
|
195
|
+
Tenant-scoped assignments are opt-in. Add the column to `UserRole` and its `@@id`, then run
|
|
196
|
+
`prisma migrate dev` (existing rows get `''`, a global assignment):
|
|
197
|
+
|
|
198
|
+
```prisma
|
|
199
|
+
model UserRole {
|
|
200
|
+
userType String
|
|
201
|
+
userId String
|
|
202
|
+
roleId String
|
|
203
|
+
tenantId String @default("")
|
|
204
|
+
|
|
205
|
+
@@id([userType, userId, roleId, tenantId])
|
|
206
|
+
@@index([userType, userId])
|
|
207
|
+
@@map("authz_user_role")
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Then turn it on: `new PrismaAuthzStore(prisma, { tenantScoped: true })`, or
|
|
212
|
+
`AuthzRbacModule.forRoot({ client: prisma, tenantScoped: true })`.
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
await store.assignRole(user, 'editor', { tenantId: 'acme' }); // only inside acme
|
|
216
|
+
await store.assignRole(user, 'viewer'); // everywhere
|
|
217
|
+
await store.getRolesForUser(user, { tenantId: 'acme' }); // ['editor', 'viewer']
|
|
218
|
+
await store.getRolesForUser(user); // ['viewer']
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
`removeRole` and `setUserRoles` take the same `{ tenantId }` (omitted = the global
|
|
222
|
+
assignments). Without `tenantScoped`, every assignment is global and reads ignore the tenant.
|
|
223
|
+
`assignRole` and `setUserRoles` with a `tenantId` throw; `removeRole` with one does nothing,
|
|
224
|
+
since there is no tenant assignment to remove.
|
|
225
|
+
|
|
226
|
+
## Tenancy
|
|
227
|
+
|
|
228
|
+
The RBAC module reads the tenant only when tenancy is on: turn it on with
|
|
229
|
+
`ContextModule.forRoot({ tenancy: { enabled: true } })` in `@dudousxd/nestjs-context`. Checks
|
|
230
|
+
are then scoped to the request's tenant from `Context.setTenant(...)`.
|
|
231
|
+
A request with no tenant, or inside `Context.allTenants()`, sees global assignments only.
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
AuthzRbacModule.forRoot({
|
|
235
|
+
client: prisma,
|
|
236
|
+
tenantScoped: true,
|
|
237
|
+
tenancy: {
|
|
238
|
+
kinds: ['organization'], // optional: tenant kinds this module honours
|
|
239
|
+
roles: { owner: 'org_admin', member: 'org_member' }, // optional: tenant.role → authz roles in that tenant
|
|
240
|
+
},
|
|
241
|
+
tenant: (user) => (user as { orgId?: string }).orgId, // optional: an explicit tenant wins over the context
|
|
242
|
+
});
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
`tenancy` defaults to `'inherit'` (follow the context switch); `false` keeps this module out.
|
|
246
|
+
Roles mapped with `roles` apply only inside that tenant and only to the context's current user.
|
|
247
|
+
The `tenant` resolver returns a tenant id, `null` for the global scope, or `undefined` to fall
|
|
248
|
+
back to the context.
|
|
249
|
+
|
|
250
|
+
With tenancy on and without `tenantScoped`, every assignment is global, so only `roles` and the
|
|
251
|
+
`tenant` resolver change what a check sees.
|
|
178
252
|
|
|
179
253
|
## License
|
|
180
254
|
|
|
@@ -2,6 +2,7 @@ import type { UserRef } from '@dudousxd/nestjs-authz/store-kit';
|
|
|
2
2
|
import { type DynamicModule } from '@nestjs/common';
|
|
3
3
|
import { PrismaAuthzStore } from './prisma-authz.store.js';
|
|
4
4
|
import { type PrismaAuthzClientLike } from './prisma-client.js';
|
|
5
|
+
import { type AuthzTenancyOption, type TenantResolver } from './tenancy.js';
|
|
5
6
|
/** Injection token holding the {@link PrismaAuthzStore} the RBAC module manages. */
|
|
6
7
|
export declare const AUTHZ_RBAC_STORE: unique symbol;
|
|
7
8
|
/** Injection token holding the resolved {@link AuthzRbacModuleOptions}. */
|
|
@@ -30,11 +31,27 @@ export interface AuthzRbacModuleOptions {
|
|
|
30
31
|
* `source` column on `UserRole`. Only used when the module builds the store from `client`.
|
|
31
32
|
*/
|
|
32
33
|
roleSources?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Tenant-scoped role assignments (see {@link PrismaAuthzStoreOptions.tenantScoped}); requires
|
|
36
|
+
* the `tenantId` column on `UserRole`. Only used when the module builds the store from `client`.
|
|
37
|
+
*/
|
|
38
|
+
tenantScoped?: boolean;
|
|
33
39
|
/**
|
|
34
40
|
* Derive a {@link UserRef} from the Gate's current user. Defaults to
|
|
35
41
|
* {@link defaultUserRefMapper} (`{ type, id }` or `{ id }`).
|
|
36
42
|
*/
|
|
37
43
|
userRefFrom?: UserRefMapper;
|
|
44
|
+
/**
|
|
45
|
+
* Tenancy, from `@dudousxd/nestjs-context`. `'inherit'` (default) follows `ContextModule`'s
|
|
46
|
+
* `tenancy.enabled`; with it on, checks are scoped to the context tenant. The object form adds
|
|
47
|
+
* `kinds` and `roles` (map the caller's `tenant.role` to authz roles in that tenant).
|
|
48
|
+
*/
|
|
49
|
+
tenancy?: AuthzTenancyOption;
|
|
50
|
+
/**
|
|
51
|
+
* Explicit tenant for a check, from the user being checked. Wins over the context: return a
|
|
52
|
+
* tenant id, `null` for the global scope, or `undefined` to fall back to the context.
|
|
53
|
+
*/
|
|
54
|
+
tenant?: TenantResolver;
|
|
38
55
|
}
|
|
39
56
|
export interface AuthzRbacModuleAsyncOptions {
|
|
40
57
|
imports?: unknown[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authz-rbac.module.d.ts","sourceRoot":"","sources":["../src/authz-rbac.module.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"authz-rbac.module.d.ts","sourceRoot":"","sources":["../src/authz-rbac.module.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAChE,OAAO,EACL,KAAK,aAAa,EAQnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAiB,KAAK,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EACL,KAAK,kBAAkB,EAIvB,KAAK,cAAc,EAEpB,MAAM,cAAc,CAAC;AAEtB,oFAAoF;AACpF,eAAO,MAAM,gBAAgB,eAAoD,CAAC;AAClF,2EAA2E;AAC3E,eAAO,MAAM,kBAAkB,eAAsD,CAAC;AAEtF;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,GAAG,SAAS,CAAC;AAEnE,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,oFAAoF;IACpF,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,aAAa,CAAC;IAC5B;;;;OAIG;IACH,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B;;;OAGG;IACH,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;IACnB,UAAU,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,sBAAsB,CAAC,GAAG,sBAAsB,CAAC;CAC9F;AAED,qFAAqF;AACrF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,CAOvE;AA0ID;;;;;;GAMG;AACH,qBACa,eAAe;IAC1B,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,sBAAsB,GAAG,aAAa;IAa9D,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,2BAA2B,GAAG,aAAa;IAsBxE,OAAO,CAAC,MAAM,CAAC,eAAe;CAS/B"}
|
|
@@ -11,9 +11,11 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
11
11
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
12
|
};
|
|
13
13
|
var AuthzRbacModule_1;
|
|
14
|
-
import { PERMISSION_PROVIDER, ROLE_PROVIDER, } from '@dudousxd/nestjs-authz';
|
|
14
|
+
import { CONTEXT_ACCESSOR, PERMISSION_PROVIDER, ROLE_PROVIDER, } from '@dudousxd/nestjs-authz';
|
|
15
15
|
import { Inject, Injectable, Module, Optional, } from '@nestjs/common';
|
|
16
|
+
import { ModuleRef } from '@nestjs/core';
|
|
16
17
|
import { PrismaAuthzStore } from './prisma-authz.store.js';
|
|
18
|
+
import { rbacTenant, } from './tenancy.js';
|
|
17
19
|
/** Injection token holding the {@link PrismaAuthzStore} the RBAC module manages. */
|
|
18
20
|
export const AUTHZ_RBAC_STORE = Symbol.for('@dudousxd/nestjs-authz-prisma:store');
|
|
19
21
|
/** Injection token holding the resolved {@link AuthzRbacModuleOptions}. */
|
|
@@ -35,7 +37,10 @@ function resolveStore(options) {
|
|
|
35
37
|
if (options.store)
|
|
36
38
|
return options.store;
|
|
37
39
|
if (options.client) {
|
|
38
|
-
return new PrismaAuthzStore(options.client,
|
|
40
|
+
return new PrismaAuthzStore(options.client, {
|
|
41
|
+
...(options.roleSources ? { roleSources: true } : {}),
|
|
42
|
+
...(options.tenantScoped ? { tenantScoped: true } : {}),
|
|
43
|
+
});
|
|
39
44
|
}
|
|
40
45
|
throw new Error('AuthzRbacModule (prisma): provide either `store` or `client` in the options.');
|
|
41
46
|
}
|
|
@@ -46,13 +51,27 @@ function resolveStore(options) {
|
|
|
46
51
|
*/
|
|
47
52
|
let RbacPermissionProvider = class RbacPermissionProvider {
|
|
48
53
|
options;
|
|
54
|
+
context;
|
|
55
|
+
moduleRef;
|
|
49
56
|
// `getPermissions` lists every grant `hasPermission` can find, for any resource.
|
|
50
57
|
exhaustivePermissions = true;
|
|
51
58
|
store;
|
|
52
|
-
|
|
59
|
+
contextCache = { resolved: false, value: undefined };
|
|
60
|
+
constructor(options, context, moduleRef) {
|
|
53
61
|
this.options = options;
|
|
62
|
+
this.context = context;
|
|
63
|
+
this.moduleRef = moduleRef;
|
|
54
64
|
this.store = resolveStore(options);
|
|
55
65
|
}
|
|
66
|
+
tenant(user, ref) {
|
|
67
|
+
return rbacTenant(this.options, user, ref, this.context, this.moduleRef, this.contextCache, false);
|
|
68
|
+
}
|
|
69
|
+
/** The permissions `tenancy.roles` grants through the caller's role in the tenant. */
|
|
70
|
+
async tenantRolePermissions(roles) {
|
|
71
|
+
if (roles.length === 0)
|
|
72
|
+
return [];
|
|
73
|
+
return Object.values(await this.store.getRolePermissions(roles)).flat();
|
|
74
|
+
}
|
|
56
75
|
// The core `PermissionProvider` interface passes an optional `resource` (3rd
|
|
57
76
|
// arg); it is intentionally ignored here. RBAC grants are model-less,
|
|
58
77
|
// named-ability grants (the Laravel/spatie `Gate::before` grant), so the
|
|
@@ -62,7 +81,10 @@ let RbacPermissionProvider = class RbacPermissionProvider {
|
|
|
62
81
|
const ref = map(user);
|
|
63
82
|
if (ref === undefined)
|
|
64
83
|
return undefined;
|
|
65
|
-
|
|
84
|
+
const tenant = this.tenant(user, ref);
|
|
85
|
+
if (await this.store.userHasPermission(ref, permission, tenant.scope))
|
|
86
|
+
return true;
|
|
87
|
+
return (await this.tenantRolePermissions(tenant.roles)).includes(permission);
|
|
66
88
|
}
|
|
67
89
|
// Expose the user's full granted permission set so the core can apply
|
|
68
90
|
// Laravel/spatie-style wildcard matching (a granted `posts.*` satisfies a check
|
|
@@ -72,13 +94,20 @@ let RbacPermissionProvider = class RbacPermissionProvider {
|
|
|
72
94
|
const ref = map(user);
|
|
73
95
|
if (ref === undefined)
|
|
74
96
|
return undefined;
|
|
75
|
-
|
|
97
|
+
const tenant = this.tenant(user, ref);
|
|
98
|
+
const own = await this.store.getPermissionsForUser(ref, tenant.scope);
|
|
99
|
+
if (tenant.roles.length === 0)
|
|
100
|
+
return own;
|
|
101
|
+
return [...new Set([...own, ...(await this.tenantRolePermissions(tenant.roles))])];
|
|
76
102
|
}
|
|
77
103
|
};
|
|
78
104
|
RbacPermissionProvider = __decorate([
|
|
79
105
|
Injectable(),
|
|
80
106
|
__param(0, Inject(AUTHZ_RBAC_OPTIONS)),
|
|
81
|
-
|
|
107
|
+
__param(1, Optional()),
|
|
108
|
+
__param(1, Inject(CONTEXT_ACCESSOR)),
|
|
109
|
+
__param(2, Optional()),
|
|
110
|
+
__metadata("design:paramtypes", [Object, Object, ModuleRef])
|
|
82
111
|
], RbacPermissionProvider);
|
|
83
112
|
/**
|
|
84
113
|
* The RBAC {@link RoleProvider} the Gate consults (via the shared {@link ROLE_PROVIDER}
|
|
@@ -88,23 +117,36 @@ RbacPermissionProvider = __decorate([
|
|
|
88
117
|
*/
|
|
89
118
|
let RbacRoleProvider = class RbacRoleProvider {
|
|
90
119
|
options;
|
|
120
|
+
context;
|
|
121
|
+
moduleRef;
|
|
91
122
|
store;
|
|
92
|
-
|
|
123
|
+
contextCache = { resolved: false, value: undefined };
|
|
124
|
+
constructor(options, context, moduleRef) {
|
|
93
125
|
this.options = options;
|
|
126
|
+
this.context = context;
|
|
127
|
+
this.moduleRef = moduleRef;
|
|
94
128
|
this.store = resolveStore(options);
|
|
95
129
|
}
|
|
130
|
+
tenant(user, ref) {
|
|
131
|
+
return rbacTenant(this.options, user, ref, this.context, this.moduleRef, this.contextCache, false);
|
|
132
|
+
}
|
|
96
133
|
async getRoles(user) {
|
|
97
134
|
const map = this.options.userRefFrom ?? defaultUserRefMapper;
|
|
98
135
|
const ref = map(user);
|
|
99
136
|
if (ref === undefined)
|
|
100
137
|
return undefined;
|
|
101
|
-
|
|
138
|
+
const tenant = this.tenant(user, ref);
|
|
139
|
+
const own = await this.store.getRolesForUser(ref, tenant.scope);
|
|
140
|
+
return tenant.roles.length === 0 ? own : [...new Set([...own, ...tenant.roles])];
|
|
102
141
|
}
|
|
103
142
|
};
|
|
104
143
|
RbacRoleProvider = __decorate([
|
|
105
144
|
Injectable(),
|
|
106
145
|
__param(0, Inject(AUTHZ_RBAC_OPTIONS)),
|
|
107
|
-
|
|
146
|
+
__param(1, Optional()),
|
|
147
|
+
__param(1, Inject(CONTEXT_ACCESSOR)),
|
|
148
|
+
__param(2, Optional()),
|
|
149
|
+
__metadata("design:paramtypes", [Object, Object, ModuleRef])
|
|
108
150
|
], RbacRoleProvider);
|
|
109
151
|
/**
|
|
110
152
|
* Runs `ensureSchema` on bootstrap when `autoCreateSchema` is enabled. For Prisma this is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authz-rbac.module.js","sourceRoot":"","sources":["../src/authz-rbac.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,OAAO,EACL,mBAAmB,EAEnB,aAAa,GAEd,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAEL,MAAM,EACN,UAAU,EACV,MAAM,EAEN,QAAQ,GAGT,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"authz-rbac.module.js","sourceRoot":"","sources":["../src/authz-rbac.module.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { PRISMA_AUTHZ_STORE_OPTIONS, PRISMA_CLIENT, type PrismaAuthzClientLike, type PrismaAuthzStoreOptions, type PrismaModelDelegate, } from './prisma-client.js';
|
|
2
|
-
export { PrismaAuthzStore } from './prisma-authz.store.js';
|
|
3
|
-
export type { RoleAssignment, RoleAssignmentFilter, RoleSourceOptions, UserAuthz, UserRoleAssignment, } from './prisma-authz.store.js';
|
|
2
|
+
export { GLOBAL_TENANT, PrismaAuthzStore } from './prisma-authz.store.js';
|
|
3
|
+
export type { RoleAssignment, RoleAssignmentFilter, RoleSourceOptions, TenantScope, UserAuthz, UserRoleAssignment, } from './prisma-authz.store.js';
|
|
4
4
|
export { AUTHZ_RBAC_OPTIONS, AUTHZ_RBAC_STORE, AuthzRbacModule, defaultUserRefMapper, } from './authz-rbac.module.js';
|
|
5
5
|
export type { AuthzRbacModuleAsyncOptions, AuthzRbacModuleOptions, UserRefMapper, } from './authz-rbac.module.js';
|
|
6
|
+
export type { AuthzTenancyOption, TenantResolver } from './tenancy.js';
|
|
6
7
|
export type { UserRef, UserRefInput } from '@dudousxd/nestjs-authz/store-kit';
|
|
7
8
|
export { applyScope, compileScope } from './scope.js';
|
|
8
9
|
export type { PrismaWhere, ScopeResolver } from './scope.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,aAAa,EACb,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,aAAa,EACb,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC1E,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,iBAAiB,EACjB,WAAW,EACX,SAAS,EACT,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,2BAA2B,EAC3B,sBAAsB,EACtB,aAAa,GACd,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACvE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { PRISMA_AUTHZ_STORE_OPTIONS, PRISMA_CLIENT, } from './prisma-client.js';
|
|
2
|
-
export { PrismaAuthzStore } from './prisma-authz.store.js';
|
|
2
|
+
export { GLOBAL_TENANT, PrismaAuthzStore } from './prisma-authz.store.js';
|
|
3
3
|
export { AUTHZ_RBAC_OPTIONS, AUTHZ_RBAC_STORE, AuthzRbacModule, defaultUserRefMapper, } from './authz-rbac.module.js';
|
|
4
4
|
export { applyScope, compileScope } from './scope.js';
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,aAAa,GAId,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,aAAa,GAId,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAS1E,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAQhC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import { type RoleAssignment, type RoleAssignmentFilter, type UserAuthz, type UserRef, type UserRoleAssignment } from '@dudousxd/nestjs-authz/store-kit';
|
|
2
2
|
import { type PrismaAuthzClientLike, type PrismaAuthzStoreOptions } from './prisma-client.js';
|
|
3
3
|
export type { RoleAssignment, RoleAssignmentFilter, UserAuthz, UserRoleAssignment };
|
|
4
|
-
/**
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Optional tenant scope for a query. Omitted → the GLOBAL scope (only global assignments; a
|
|
6
|
+
* tenant-scoped role never leaks into an unscoped check). With a `tenantId`, global assignments
|
|
7
|
+
* AND that tenant's apply. Needs `tenantScoped: true`; without it every assignment is global.
|
|
8
|
+
*/
|
|
9
|
+
export interface TenantScope {
|
|
10
|
+
tenantId?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Assignment source (default `'manual'`, needs `roleSources: true`) and tenant (needs
|
|
14
|
+
* `tenantScoped: true`) for role mutations — see `setUserRoles`.
|
|
15
|
+
*/
|
|
16
|
+
export interface RoleSourceOptions extends TenantScope {
|
|
6
17
|
source?: string;
|
|
7
18
|
}
|
|
19
|
+
/** The tenant id of a GLOBAL role assignment (applies in every tenant). */
|
|
20
|
+
export declare const GLOBAL_TENANT = "";
|
|
8
21
|
/**
|
|
9
22
|
* Prisma-backed RBAC store. Receives the app-owned Prisma client via the
|
|
10
23
|
* {@link PRISMA_CLIENT} DI token — NO internal connection ownership, NO `@prisma/client`
|
|
@@ -22,6 +35,12 @@ export declare class PrismaAuthzStore {
|
|
|
22
35
|
* `{}` otherwise (legacy schema without the column) — where a non-default source is an error.
|
|
23
36
|
*/
|
|
24
37
|
private sourceField;
|
|
38
|
+
/** The `tenantId` value of a written assignment (`{}` without `tenantScoped`). */
|
|
39
|
+
private tenantField;
|
|
40
|
+
/** Assignments visible in a scope: global ones, plus the tenant's own when one is given. */
|
|
41
|
+
private tenantWhere;
|
|
42
|
+
/** The public `tenantId` of a stored row: `null` for a global assignment. */
|
|
43
|
+
private static rowTenant;
|
|
25
44
|
/**
|
|
26
45
|
* No-op: Prisma is schema-first / consumer-managed. Declare the RBAC models in your
|
|
27
46
|
* `schema.prisma` (see {@link PrismaAuthzClientLike}) and apply them with
|
|
@@ -68,7 +87,9 @@ export declare class PrismaAuthzStore {
|
|
|
68
87
|
assignRole(user: UserRef, roleName: string, opts?: RoleSourceOptions): Promise<void>;
|
|
69
88
|
/**
|
|
70
89
|
* Remove a role from a user. No-op if the role or assignment is absent. With `{ source }` only
|
|
71
|
-
* that source's assignment goes; without it, the role is removed from every source.
|
|
90
|
+
* that source's assignment goes; without it, the role is removed from every source. With
|
|
91
|
+
* `tenantScoped`, `{ tenantId }` removes the assignment in that tenant and omitting it removes
|
|
92
|
+
* the global one.
|
|
72
93
|
*/
|
|
73
94
|
removeRole(user: UserRef, roleName: string, opts?: RoleSourceOptions): Promise<void>;
|
|
74
95
|
/**
|
|
@@ -76,18 +97,23 @@ export declare class PrismaAuthzStore {
|
|
|
76
97
|
* `roleNames` — e.g. an SSO/SCIM sync calls `setUserRoles(user, mappedRoles, { source: 'sso' })`
|
|
77
98
|
* on every login; other sources' assignments are untouched. Roles are created by name when
|
|
78
99
|
* missing. Atomic when the client has `$transaction`. Without `roleSources: true` there is only
|
|
79
|
-
* one (implicit manual) source, so this replaces ALL of the user's roles.
|
|
100
|
+
* one (implicit manual) source, so this replaces ALL of the user's roles. With `tenantScoped` it
|
|
101
|
+
* replaces the assignments of one tenant (`{ tenantId }`), or the global ones when omitted.
|
|
80
102
|
*/
|
|
81
103
|
setUserRoles(user: UserRef, roleNames: readonly string[], opts?: RoleSourceOptions): Promise<void>;
|
|
82
|
-
/**
|
|
83
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Every role assignment of a user visible in a tenant scope (global ones always; the tenant's
|
|
106
|
+
* own with `{ tenantId }`), one entry per `(role, source, tenant)`.
|
|
107
|
+
*/
|
|
108
|
+
getRoleAssignments(user: UserRef, scope?: TenantScope): Promise<RoleAssignment[]>;
|
|
84
109
|
/**
|
|
85
110
|
* Raw role-assignment rows for admin listings — e.g. who holds a role (`{ role: 'admin' }`) or
|
|
86
111
|
* a user's assignments with their sources (`{ user }`). `role` accepts one name or a list;
|
|
87
112
|
* `user` and `source` narrow further. Ordered by `(userType, userId, role, source)`.
|
|
88
113
|
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
114
|
+
* `tenantId`: omitted = no tenant filter; `null` = global assignments only; a string = exactly
|
|
115
|
+
* that tenant's scoped assignments. Without `tenantScoped: true` every row is global
|
|
116
|
+
* (`tenantId: null`), so a tenant id string matches nothing.
|
|
91
117
|
* Without `roleSources: true` every row is `'manual'`, so another `source` matches nothing.
|
|
92
118
|
*/
|
|
93
119
|
listRoleAssignments(filter?: RoleAssignmentFilter): Promise<UserRoleAssignment[]>;
|
|
@@ -96,8 +122,8 @@ export declare class PrismaAuthzStore {
|
|
|
96
122
|
* Roles and permissions are kept. (This adapter has no direct user permissions.)
|
|
97
123
|
*/
|
|
98
124
|
removeUser(user: UserRef): Promise<void>;
|
|
99
|
-
/** The role names a user holds. */
|
|
100
|
-
getRolesForUser(user: UserRef): Promise<string[]>;
|
|
125
|
+
/** The role names a user holds, in a tenant scope (see {@link TenantScope}). */
|
|
126
|
+
getRolesForUser(user: UserRef, scope?: TenantScope): Promise<string[]>;
|
|
101
127
|
/**
|
|
102
128
|
* The flattened, distinct permission names a user has via their roles.
|
|
103
129
|
*
|
|
@@ -107,12 +133,11 @@ export declare class PrismaAuthzStore {
|
|
|
107
133
|
*
|
|
108
134
|
* Fast path: when the injected client exposes `$queryRaw`, assemble the set in a
|
|
109
135
|
* SINGLE database round-trip via one JOIN (3 round-trips → 1). On ANY failure
|
|
110
|
-
* (
|
|
111
|
-
* quoting, etc.) it degrades to {@link getPermissionsViaDelegates}, so correctness
|
|
136
|
+
* (custom `@@map` table names, non-Postgres identifier quoting, etc.) it degrades to {@link getPermissionsViaDelegates}, so correctness
|
|
112
137
|
* is preserved everywhere and only the common (Postgres + documented schema) case
|
|
113
138
|
* gets the speedup.
|
|
114
139
|
*/
|
|
115
|
-
getPermissionsForUser(user: UserRef): Promise<string[]>;
|
|
140
|
+
getPermissionsForUser(user: UserRef, scope?: TenantScope): Promise<string[]>;
|
|
116
141
|
/**
|
|
117
142
|
* The original three-query implementation (userRole → rolePermission → permission),
|
|
118
143
|
* returning the same deduped permission-name set as {@link getPermissionsForUser}.
|
|
@@ -120,9 +145,9 @@ export declare class PrismaAuthzStore {
|
|
|
120
145
|
* fast path throws.
|
|
121
146
|
*/
|
|
122
147
|
private getPermissionsViaDelegates;
|
|
123
|
-
/** A user's roles + effective permissions in one shot. */
|
|
124
|
-
getUserAuthz(user: UserRef): Promise<UserAuthz>;
|
|
125
|
-
/** True when the user holds `permission` through any of their roles. */
|
|
126
|
-
userHasPermission(user: UserRef, permission: string): Promise<boolean>;
|
|
148
|
+
/** A user's roles + effective permissions in one shot, in a tenant scope. */
|
|
149
|
+
getUserAuthz(user: UserRef, scope?: TenantScope): Promise<UserAuthz>;
|
|
150
|
+
/** True when the user holds `permission` through any of their roles, in a tenant scope. */
|
|
151
|
+
userHasPermission(user: UserRef, permission: string, scope?: TenantScope): Promise<boolean>;
|
|
127
152
|
}
|
|
128
153
|
//# sourceMappingURL=prisma-authz.store.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prisma-authz.store.d.ts","sourceRoot":"","sources":["../src/prisma-authz.store.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,SAAS,EACd,KAAK,OAAO,EACZ,KAAK,kBAAkB,EAIxB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC7B,MAAM,oBAAoB,CAAC;AAI5B,YAAY,EAAE,cAAc,EAAE,oBAAoB,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC;AAEpF,
|
|
1
|
+
{"version":3,"file":"prisma-authz.store.d.ts","sourceRoot":"","sources":["../src/prisma-authz.store.ts"],"names":[],"mappings":"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"}
|