@jantstack/adonis-authz 1.0.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/LICENSE +21 -0
- package/README.md +138 -0
- package/build/commands/main.d.ts +7 -0
- package/build/commands/main.d.ts.map +1 -0
- package/build/commands/main.js +7 -0
- package/build/commands/main.js.map +1 -0
- package/build/commands/openfga_import.d.ts +28 -0
- package/build/commands/openfga_import.d.ts.map +1 -0
- package/build/commands/openfga_import.js +74 -0
- package/build/commands/openfga_import.js.map +1 -0
- package/build/commands/openfga_provision.d.ts +27 -0
- package/build/commands/openfga_provision.d.ts.map +1 -0
- package/build/commands/openfga_provision.js +73 -0
- package/build/commands/openfga_provision.js.map +1 -0
- package/build/configure.d.ts +10 -0
- package/build/configure.d.ts.map +1 -0
- package/build/configure.js +43 -0
- package/build/configure.js.map +1 -0
- package/build/index.d.ts +21 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +18 -0
- package/build/index.js.map +1 -0
- package/build/providers/authz_provider.d.ts +17 -0
- package/build/providers/authz_provider.d.ts.map +1 -0
- package/build/providers/authz_provider.js +21 -0
- package/build/providers/authz_provider.js.map +1 -0
- package/build/services/main.d.ts +10 -0
- package/build/services/main.d.ts.map +1 -0
- package/build/services/main.js +13 -0
- package/build/services/main.js.map +1 -0
- package/build/src/catalog.d.ts +3 -0
- package/build/src/catalog.d.ts.map +1 -0
- package/build/src/catalog.js +97 -0
- package/build/src/catalog.js.map +1 -0
- package/build/src/define_config.d.ts +53 -0
- package/build/src/define_config.d.ts.map +1 -0
- package/build/src/define_config.js +4 -0
- package/build/src/define_config.js.map +1 -0
- package/build/src/drivers/database_driver.d.ts +48 -0
- package/build/src/drivers/database_driver.d.ts.map +1 -0
- package/build/src/drivers/database_driver.js +260 -0
- package/build/src/drivers/database_driver.js.map +1 -0
- package/build/src/drivers/openfga_driver.d.ts +107 -0
- package/build/src/drivers/openfga_driver.d.ts.map +1 -0
- package/build/src/drivers/openfga_driver.js +450 -0
- package/build/src/drivers/openfga_driver.js.map +1 -0
- package/build/src/manager.d.ts +29 -0
- package/build/src/manager.d.ts.map +1 -0
- package/build/src/manager.js +79 -0
- package/build/src/manager.js.map +1 -0
- package/build/src/middleware/app_access_middleware.d.ts +23 -0
- package/build/src/middleware/app_access_middleware.d.ts.map +1 -0
- package/build/src/middleware/app_access_middleware.js +53 -0
- package/build/src/middleware/app_access_middleware.js.map +1 -0
- package/build/src/models/authz_assignment.d.ts +166 -0
- package/build/src/models/authz_assignment.d.ts.map +1 -0
- package/build/src/models/authz_assignment.js +60 -0
- package/build/src/models/authz_assignment.js.map +1 -0
- package/build/src/models/authz_deny.d.ts +161 -0
- package/build/src/models/authz_deny.d.ts.map +1 -0
- package/build/src/models/authz_deny.js +50 -0
- package/build/src/models/authz_deny.js.map +1 -0
- package/build/src/models/authz_permission.d.ts +159 -0
- package/build/src/models/authz_permission.d.ts.map +1 -0
- package/build/src/models/authz_permission.js +42 -0
- package/build/src/models/authz_permission.js.map +1 -0
- package/build/src/models/authz_role.d.ts +166 -0
- package/build/src/models/authz_role.d.ts.map +1 -0
- package/build/src/models/authz_role.js +66 -0
- package/build/src/models/authz_role.js.map +1 -0
- package/build/src/models/authz_role_permission.d.ts +155 -0
- package/build/src/models/authz_role_permission.d.ts.map +1 -0
- package/build/src/models/authz_role_permission.js +35 -0
- package/build/src/models/authz_role_permission.js.map +1 -0
- package/build/src/testing/contract.d.ts +27 -0
- package/build/src/testing/contract.d.ts.map +1 -0
- package/build/src/testing/contract.js +211 -0
- package/build/src/testing/contract.js.map +1 -0
- package/build/src/testing/main.d.ts +11 -0
- package/build/src/testing/main.d.ts.map +1 -0
- package/build/src/testing/main.js +10 -0
- package/build/src/testing/main.js.map +1 -0
- package/build/src/traits/authz_scopes.d.ts +21 -0
- package/build/src/traits/authz_scopes.d.ts.map +1 -0
- package/build/src/traits/authz_scopes.js +45 -0
- package/build/src/traits/authz_scopes.js.map +1 -0
- package/build/src/traits/has_uuid.d.ts +151 -0
- package/build/src/traits/has_uuid.d.ts.map +1 -0
- package/build/src/traits/has_uuid.js +38 -0
- package/build/src/traits/has_uuid.js.map +1 -0
- package/build/src/types.d.ts +153 -0
- package/build/src/types.d.ts.map +1 -0
- package/build/src/types.js +38 -0
- package/build/src/types.js.map +1 -0
- package/build/stubs/config/app_acl.stub +81 -0
- package/build/stubs/config/authorization.stub +74 -0
- package/build/stubs/main.d.ts +3 -0
- package/build/stubs/main.d.ts.map +1 -0
- package/build/stubs/main.js +3 -0
- package/build/stubs/main.js.map +1 -0
- package/build/stubs/migration.stub +124 -0
- package/package.json +94 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jose Tenorio
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# @jantstack/adonis-authz
|
|
2
|
+
|
|
3
|
+
Driver-based **authorization engine for AdonisJS 7 + Lucid**: hierarchical scopes with downward-only inheritance, explicit denies that always win, expiring assignments and polymorphic holders — behind a single contract, so the backend is a config choice, not an architectural commitment.
|
|
4
|
+
|
|
5
|
+
Ships two drivers that pass **the same executable contract suite**:
|
|
6
|
+
|
|
7
|
+
- **`database`** (default) — self-contained, engine-agnostic SQL over its own `authz_*` tables. Zero extra infrastructure.
|
|
8
|
+
- **`openfga`** — facts live in an [OpenFGA](https://openfga.dev) server (Zanzibar model); the catalog and your scope hierarchy stay local, so switching drivers is a facts migration, not a rewrite.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import authorization from '@jantstack/adonis-authz/services/main'
|
|
12
|
+
import { APP_SCOPE } from '@jantstack/adonis-authz'
|
|
13
|
+
|
|
14
|
+
await authorization.grant({ type: 'users', uuid }, 'support', APP_SCOPE, {
|
|
15
|
+
expiresAt: new Date(Date.now() + 30 * 86_400_000),
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
await authorization.authorize({ type: 'users', uuid }, 'audit:read', APP_SCOPE) // → boolean
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm i @jantstack/adonis-authz
|
|
25
|
+
node ace configure @jantstack/adonis-authz
|
|
26
|
+
node ace migration:run
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`configure` registers the provider, the commands and the `appAccess` middleware, defines the env variables, and **publishes into your project** what belongs to you: the migration for the `authz_*` tables and two config files (`config/authorization.ts` for drivers, `config/app_acl.ts` for your role catalog).
|
|
30
|
+
|
|
31
|
+
For the OpenFGA driver, also install its SDK (optional peer): `npm i @openfga/sdk`.
|
|
32
|
+
|
|
33
|
+
## Semantics (what every driver guarantees)
|
|
34
|
+
|
|
35
|
+
1. **Hierarchical scopes, inheritance only downward.** A grant on a scope authorizes on that scope and all its descendants — never on siblings or ancestors. The engine only reserves the root (`app`); every other level is yours, declared by the `resolveAncestors` resolver you inject.
|
|
36
|
+
2. **Explicit deny wins.** A deny anywhere in the scope chain blocks the permission even if a role grants it. Removing the deny restores it.
|
|
37
|
+
3. **Expiry is observable.** An assignment past its `expiresAt` grants nothing — enforced in SQL by the `database` driver and by an FGA *condition* in `openfga`, so no scheduler is needed.
|
|
38
|
+
4. **Polymorphic holders.** Users, admins, API integrations — any model with a morph name. Two holders with the same uuid and different type never cross.
|
|
39
|
+
5. **Deny by default.** Unknown permission, role without it, or no valid assignment → `false`. `authorize()` never throws.
|
|
40
|
+
6. **Idempotent writes.** Re-granting doesn't duplicate (it refreshes the expiry); re-revoking is a safe no-op.
|
|
41
|
+
|
|
42
|
+
These aren't prose promises: they're `tests/…` cases in the contract suite below.
|
|
43
|
+
|
|
44
|
+
## Your domain stays yours
|
|
45
|
+
|
|
46
|
+
Nothing about your model is hardcoded. Three seams:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
// config/authorization.ts (published by configure)
|
|
50
|
+
export default defineConfig({
|
|
51
|
+
default: env.get('AUTHZ_DRIVER', 'database'),
|
|
52
|
+
|
|
53
|
+
// 1. Your guards → FGA types (only the openfga driver uses this)
|
|
54
|
+
holderTypes: { users: 'user', admins: 'admin', integrations: 'integration' },
|
|
55
|
+
|
|
56
|
+
drivers: {
|
|
57
|
+
// 2. Your scope tree: organization → unit, project → site, whatever
|
|
58
|
+
database: () => new DatabaseAuthorizationDriver({ resolveAncestors }),
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
// 3. Your side-effects on every write (audit, events, notifications)
|
|
62
|
+
hooks: { onWrite: (event) => audit(event) },
|
|
63
|
+
})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`ScopeType` is an open `string`, so define your own union for type safety and let `resolveAncestors` describe the tree. The engine never queries your tables.
|
|
67
|
+
|
|
68
|
+
## Enforcing in routes
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
router
|
|
72
|
+
.get('/admin/audit-log', [AuditLogsController, 'index'])
|
|
73
|
+
.use(middleware.appAccess({ permission: 'audit:read' }))
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The middleware resolves the authenticated holder from its morph name and asks the engine. Identity decides *what you may do*; if you also issue scoped API tokens, that's an orthogonal check — the token narrows, it never widens.
|
|
77
|
+
|
|
78
|
+
## The catalog
|
|
79
|
+
|
|
80
|
+
Roles and permissions are config-driven and synced idempotently:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
// config/app_acl.ts
|
|
84
|
+
permissions: [{ slug: 'audit:read' }, { slug: 'admin:manage' }],
|
|
85
|
+
roles: [{ slug: 'superadmin', rank: 100, permissions: '*' }],
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { syncAuthzCatalog } from '@jantstack/adonis-authz'
|
|
90
|
+
await syncAuthzCatalog(appAclCatalog()) // additive, safe to re-run
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`rank` is metadata for *your* assignment policy ("nobody grants a role at or above their own rank"). The engine stores it; enforcing a privilege ceiling is a decision only your domain can make — the engine is mechanism, not policy.
|
|
94
|
+
|
|
95
|
+
## Custom drivers, judged by the same suite
|
|
96
|
+
|
|
97
|
+
Implement `AuthorizationDriver`, register its factory, and prove it:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { runAuthorizationDriverContract } from '@jantstack/adonis-authz/testing'
|
|
101
|
+
|
|
102
|
+
runAuthorizationDriverContract({
|
|
103
|
+
name: 'my-driver',
|
|
104
|
+
makeDriver: () => new MyDriver(),
|
|
105
|
+
seedCatalog: (catalog) => syncAuthzCatalog(catalog),
|
|
106
|
+
cleanup: () => wipeEverything(),
|
|
107
|
+
})
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
A driver that passes honors the semantics above, so call-sites never change when you swap backends.
|
|
111
|
+
|
|
112
|
+
## OpenFGA tooling
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
node ace openfga:provision # creates a store + writes the model from your holderTypes
|
|
116
|
+
node ace openfga:import --dry-run # copies assignments/denies from the database driver
|
|
117
|
+
node ace openfga:import
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The import **copies**, it doesn't move: your `authz_*` tables stay intact, so rolling back is setting `AUTHZ_DRIVER=database` again.
|
|
121
|
+
|
|
122
|
+
## Compatibility
|
|
123
|
+
|
|
124
|
+
| | |
|
|
125
|
+
|---|---|
|
|
126
|
+
| Node | ≥ 20.6 |
|
|
127
|
+
| AdonisJS | ^7 (peer) · Lucid ^22 (peer) |
|
|
128
|
+
| OpenFGA SDK | ^0.9 (optional peer, only for that driver) |
|
|
129
|
+
| Databases | PostgreSQL, MySQL, SQLite |
|
|
130
|
+
| Module format | ESM only |
|
|
131
|
+
|
|
132
|
+
## Scope and maintenance
|
|
133
|
+
|
|
134
|
+
Extracted from the [adonis7-base](https://github.com/JantStack/adonis7-base) chassis, where it runs in production-shaped projects. Maintained according to that chassis's needs.
|
|
135
|
+
|
|
136
|
+
## License
|
|
137
|
+
|
|
138
|
+
MIT
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comandos ace del paquete. Se registran con:
|
|
3
|
+
* node ace configure @jantstack/adonis-authz
|
|
4
|
+
*/
|
|
5
|
+
export { default as OpenFgaProvision } from './openfga_provision.js';
|
|
6
|
+
export { default as OpenFgaImport } from './openfga_import.js';
|
|
7
|
+
//# sourceMappingURL=main.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../commands/main.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACpE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comandos ace del paquete. Se registran con:
|
|
3
|
+
* node ace configure @jantstack/adonis-authz
|
|
4
|
+
*/
|
|
5
|
+
export { default as OpenFgaProvision } from './openfga_provision.js';
|
|
6
|
+
export { default as OpenFgaImport } from './openfga_import.js';
|
|
7
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../commands/main.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACpE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { BaseCommand } from '@adonisjs/core/ace';
|
|
2
|
+
import { CommandOptions } from '@adonisjs/core/types/ace';
|
|
3
|
+
/**
|
|
4
|
+
* Migra los HECHOS del driver `database` a un store OpenFGA: copia las
|
|
5
|
+
* asignaciones vigentes (authz_assignments) y los denies (authz_denies)
|
|
6
|
+
* como tuples. El catálogo y la jerarquía no migran: son metadata local
|
|
7
|
+
* para ambos drivers.
|
|
8
|
+
*
|
|
9
|
+
* Proceso completo database → openfga:
|
|
10
|
+
* 1. Levantar el servidor (profile openfga del compose).
|
|
11
|
+
* 2. node ace openfga:provision → store + model (ids al .env)
|
|
12
|
+
* 3. node ace openfga:import [--dry-run] → copia los hechos
|
|
13
|
+
* 4. AUTHZ_DRIVER=openfga + reiniciar api/worker.
|
|
14
|
+
*
|
|
15
|
+
* Idempotente (re-ejecutar no duplica) y no destructivo (las tablas
|
|
16
|
+
* locales quedan intactas → rollback = volver a AUTHZ_DRIVER=database).
|
|
17
|
+
*/
|
|
18
|
+
export default class OpenFgaImport extends BaseCommand {
|
|
19
|
+
static commandName: string;
|
|
20
|
+
static description: string;
|
|
21
|
+
static options: CommandOptions;
|
|
22
|
+
url: string | undefined;
|
|
23
|
+
storeId: string | undefined;
|
|
24
|
+
modelId: string | undefined;
|
|
25
|
+
dryRun: boolean | undefined;
|
|
26
|
+
run(): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=openfga_import.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openfga_import.d.ts","sourceRoot":"","sources":["../../commands/openfga_import.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAS,MAAM,oBAAoB,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAEzD;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,WAAW;IACpD,MAAM,CAAC,WAAW,SAAmB;IACrC,MAAM,CAAC,WAAW,SAAgF;IAElG,MAAM,CAAC,OAAO,EAAE,cAAc,CAE7B;IAGO,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;IAGvB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAG3B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAG3B,MAAM,EAAE,OAAO,GAAG,SAAS,CAAA;IAE7B,GAAG;CA+BV"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { BaseCommand, flags } from '@adonisjs/core/ace';
|
|
11
|
+
/**
|
|
12
|
+
* Migra los HECHOS del driver `database` a un store OpenFGA: copia las
|
|
13
|
+
* asignaciones vigentes (authz_assignments) y los denies (authz_denies)
|
|
14
|
+
* como tuples. El catálogo y la jerarquía no migran: son metadata local
|
|
15
|
+
* para ambos drivers.
|
|
16
|
+
*
|
|
17
|
+
* Proceso completo database → openfga:
|
|
18
|
+
* 1. Levantar el servidor (profile openfga del compose).
|
|
19
|
+
* 2. node ace openfga:provision → store + model (ids al .env)
|
|
20
|
+
* 3. node ace openfga:import [--dry-run] → copia los hechos
|
|
21
|
+
* 4. AUTHZ_DRIVER=openfga + reiniciar api/worker.
|
|
22
|
+
*
|
|
23
|
+
* Idempotente (re-ejecutar no duplica) y no destructivo (las tablas
|
|
24
|
+
* locales quedan intactas → rollback = volver a AUTHZ_DRIVER=database).
|
|
25
|
+
*/
|
|
26
|
+
export default class OpenFgaImport extends BaseCommand {
|
|
27
|
+
static commandName = 'openfga:import';
|
|
28
|
+
static description = 'Copy authz facts (assignments/denies) from the database driver into OpenFGA';
|
|
29
|
+
static options = {
|
|
30
|
+
startApp: true,
|
|
31
|
+
};
|
|
32
|
+
async run() {
|
|
33
|
+
const config = this.app.config.get('authorization');
|
|
34
|
+
const apiUrl = this.url ?? config?.openfga?.url;
|
|
35
|
+
const storeId = this.storeId ?? config?.openfga?.storeId;
|
|
36
|
+
if (!apiUrl || !storeId) {
|
|
37
|
+
this.logger.error('Faltan la URL o el store: --url/--store-id o OPENFGA_URL/OPENFGA_STORE_ID (ver openfga:provision)');
|
|
38
|
+
this.exitCode = 1;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const { importAuthzFactsToOpenFga } = await import('../src/drivers/openfga_driver.js');
|
|
42
|
+
const holderTypes = config?.holderTypes ?? {};
|
|
43
|
+
const result = await importAuthzFactsToOpenFga({
|
|
44
|
+
apiUrl,
|
|
45
|
+
storeId,
|
|
46
|
+
modelId: this.modelId ?? config?.openfga?.modelId,
|
|
47
|
+
dryRun: this.dryRun ?? false,
|
|
48
|
+
holderTypes,
|
|
49
|
+
});
|
|
50
|
+
const verb = result.dryRun ? 'Se escribirían' : 'Escritos';
|
|
51
|
+
this.logger.success(`${verb} ${result.assignments} assignments y ${result.denies} denies ` +
|
|
52
|
+
`(${result.skippedExpired} asignaciones ya expiradas omitidas).`);
|
|
53
|
+
if (!result.dryRun) {
|
|
54
|
+
this.logger.log('Siguiente paso: AUTHZ_DRIVER=openfga y reiniciar api/worker.');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
__decorate([
|
|
59
|
+
flags.string({ description: 'OpenFGA API URL (defaults to OPENFGA_URL)' }),
|
|
60
|
+
__metadata("design:type", Object)
|
|
61
|
+
], OpenFgaImport.prototype, "url", void 0);
|
|
62
|
+
__decorate([
|
|
63
|
+
flags.string({ alias: 's', description: 'Store id (defaults to OPENFGA_STORE_ID)' }),
|
|
64
|
+
__metadata("design:type", Object)
|
|
65
|
+
], OpenFgaImport.prototype, "storeId", void 0);
|
|
66
|
+
__decorate([
|
|
67
|
+
flags.string({ description: 'Model id (defaults to OPENFGA_MODEL_ID)' }),
|
|
68
|
+
__metadata("design:type", Object)
|
|
69
|
+
], OpenFgaImport.prototype, "modelId", void 0);
|
|
70
|
+
__decorate([
|
|
71
|
+
flags.boolean({ description: 'Count what would be written, without writing' }),
|
|
72
|
+
__metadata("design:type", Object)
|
|
73
|
+
], OpenFgaImport.prototype, "dryRun", void 0);
|
|
74
|
+
//# sourceMappingURL=openfga_import.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openfga_import.js","sourceRoot":"","sources":["../../commands/openfga_import.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAGvD;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,WAAW;IACpD,MAAM,CAAC,WAAW,GAAG,gBAAgB,CAAA;IACrC,MAAM,CAAC,WAAW,GAAG,6EAA6E,CAAA;IAElG,MAAM,CAAC,OAAO,GAAmB;QAC/B,QAAQ,EAAE,IAAI;KACf,CAAA;IAcD,KAAK,CAAC,GAAG;QACP,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,eAAe,CAAQ,CAAA;QAC1D,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,MAAM,EAAE,OAAO,EAAE,GAAG,CAAA;QAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,MAAM,EAAE,OAAO,EAAE,OAAO,CAAA;QACxD,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,mGAAmG,CACpG,CAAA;YACD,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAA;YACjB,OAAM;QACR,CAAC;QAED,MAAM,EAAE,yBAAyB,EAAE,GAAG,MAAM,MAAM,CAAC,kCAAkC,CAAC,CAAA;QACtF,MAAM,WAAW,GAAG,MAAM,EAAE,WAAW,IAAI,EAAE,CAAA;QAC7C,MAAM,MAAM,GAAG,MAAM,yBAAyB,CAAC;YAC7C,MAAM;YACN,OAAO;YACP,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,MAAM,EAAE,OAAO,EAAE,OAAO;YACjD,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,KAAK;YAC5B,WAAW;SACZ,CAAC,CAAA;QAEF,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,UAAU,CAAA;QAC1D,IAAI,CAAC,MAAM,CAAC,OAAO,CACjB,GAAG,IAAI,IAAI,MAAM,CAAC,WAAW,kBAAkB,MAAM,CAAC,MAAM,UAAU;YACpE,IAAI,MAAM,CAAC,cAAc,uCAAuC,CACnE,CAAA;QACD,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACnB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAA;QACjF,CAAC;IACH,CAAC;;AAzCO;IADP,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,2CAA2C,EAAE,CAAC;;0CAC5C;AAGvB;IADP,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,yCAAyC,EAAE,CAAC;;8CAClD;AAG3B;IADP,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,yCAAyC,EAAE,CAAC;;8CACtC;AAG3B;IADP,KAAK,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,8CAA8C,EAAE,CAAC;;6CAC5C"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { BaseCommand } from '@adonisjs/core/ace';
|
|
2
|
+
import { CommandOptions } from '@adonisjs/core/types/ace';
|
|
3
|
+
/**
|
|
4
|
+
* Provisiona OpenFGA para el driver `openfga` del motor de autorización:
|
|
5
|
+
* crea un store y escribe el authorization model del chasis. Imprime los
|
|
6
|
+
* ids para el .env (OPENFGA_STORE_ID / OPENFGA_MODEL_ID).
|
|
7
|
+
*
|
|
8
|
+
* Idempotencia: cada ejecución crea un store NUEVO (los stores son baratos y
|
|
9
|
+
* aislados); re-ejecutar sobre un store existente no es necesario salvo que
|
|
10
|
+
* cambie el modelo — en ese caso usar --store-id para escribir un model nuevo
|
|
11
|
+
* versionado sobre el mismo store.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* node ace openfga:provision # usa OPENFGA_URL del .env
|
|
15
|
+
* node ace openfga:provision --url http://openfga:8080
|
|
16
|
+
* node ace openfga:provision --store-id 01H... # nuevo model en store existente
|
|
17
|
+
*/
|
|
18
|
+
export default class OpenFgaProvision extends BaseCommand {
|
|
19
|
+
static commandName: string;
|
|
20
|
+
static description: string;
|
|
21
|
+
static options: CommandOptions;
|
|
22
|
+
url: string | undefined;
|
|
23
|
+
storeId: string | undefined;
|
|
24
|
+
name: string | undefined;
|
|
25
|
+
run(): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=openfga_provision.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openfga_provision.d.ts","sourceRoot":"","sources":["../../commands/openfga_provision.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAS,MAAM,oBAAoB,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAEzD;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,WAAW;IACvD,MAAM,CAAC,WAAW,SAAsB;IACxC,MAAM,CAAC,WAAW,SAAoE;IAEtF,MAAM,CAAC,OAAO,EAAE,cAAc,CAE7B;IAGO,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;IAGvB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAG3B,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IAE1B,GAAG;CAqCV"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { BaseCommand, flags } from '@adonisjs/core/ace';
|
|
11
|
+
/**
|
|
12
|
+
* Provisiona OpenFGA para el driver `openfga` del motor de autorización:
|
|
13
|
+
* crea un store y escribe el authorization model del chasis. Imprime los
|
|
14
|
+
* ids para el .env (OPENFGA_STORE_ID / OPENFGA_MODEL_ID).
|
|
15
|
+
*
|
|
16
|
+
* Idempotencia: cada ejecución crea un store NUEVO (los stores son baratos y
|
|
17
|
+
* aislados); re-ejecutar sobre un store existente no es necesario salvo que
|
|
18
|
+
* cambie el modelo — en ese caso usar --store-id para escribir un model nuevo
|
|
19
|
+
* versionado sobre el mismo store.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* node ace openfga:provision # usa OPENFGA_URL del .env
|
|
23
|
+
* node ace openfga:provision --url http://openfga:8080
|
|
24
|
+
* node ace openfga:provision --store-id 01H... # nuevo model en store existente
|
|
25
|
+
*/
|
|
26
|
+
export default class OpenFgaProvision extends BaseCommand {
|
|
27
|
+
static commandName = 'openfga:provision';
|
|
28
|
+
static description = 'Create an OpenFGA store + write the chassis authorization model';
|
|
29
|
+
static options = {
|
|
30
|
+
startApp: false,
|
|
31
|
+
};
|
|
32
|
+
async run() {
|
|
33
|
+
const config = this.app.config.get('authorization');
|
|
34
|
+
const apiUrl = this.url ?? config?.openfga?.url;
|
|
35
|
+
if (!apiUrl) {
|
|
36
|
+
this.logger.error('Falta la URL del servidor: --url o `openfga.url` en config/authorization.ts');
|
|
37
|
+
this.exitCode = 1;
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const { OpenFgaClient } = await import('@openfga/sdk');
|
|
41
|
+
const { openFgaAuthorizationModel, provisionOpenFgaStore } = await import('../src/drivers/openfga_driver.js');
|
|
42
|
+
// Los holders del consumidor viven en SU config, no en el paquete.
|
|
43
|
+
const holderTypes = config?.holderTypes ?? {};
|
|
44
|
+
if (this.storeId) {
|
|
45
|
+
const client = new OpenFgaClient({ apiUrl, storeId: this.storeId });
|
|
46
|
+
const model = await client.writeAuthorizationModel(openFgaAuthorizationModel(holderTypes));
|
|
47
|
+
this.logger.success('Nuevo authorization model escrito en el store existente.');
|
|
48
|
+
this.logger.log(`OPENFGA_STORE_ID=${this.storeId}`);
|
|
49
|
+
this.logger.log(`OPENFGA_MODEL_ID=${model.authorization_model_id}`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// El paquete no lee env: el default APP_NAME se resuelve aquí (chasis).
|
|
53
|
+
const { storeId, modelId } = await provisionOpenFgaStore(apiUrl, this.name ?? config?.openfga?.storeName ?? this.app.appName, holderTypes);
|
|
54
|
+
this.logger.success('Store + authorization model provisionados.');
|
|
55
|
+
this.logger.log('Añade al .env (junto a AUTHZ_DRIVER=openfga):');
|
|
56
|
+
this.logger.log(`OPENFGA_URL=${apiUrl}`);
|
|
57
|
+
this.logger.log(`OPENFGA_STORE_ID=${storeId}`);
|
|
58
|
+
this.logger.log(`OPENFGA_MODEL_ID=${modelId}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
__decorate([
|
|
62
|
+
flags.string({ description: 'OpenFGA API URL (defaults to OPENFGA_URL)' }),
|
|
63
|
+
__metadata("design:type", Object)
|
|
64
|
+
], OpenFgaProvision.prototype, "url", void 0);
|
|
65
|
+
__decorate([
|
|
66
|
+
flags.string({ alias: 's', description: 'Write a new model into an EXISTING store' }),
|
|
67
|
+
__metadata("design:type", Object)
|
|
68
|
+
], OpenFgaProvision.prototype, "storeId", void 0);
|
|
69
|
+
__decorate([
|
|
70
|
+
flags.string({ description: 'Store name when creating one (default: APP_NAME del entorno)' }),
|
|
71
|
+
__metadata("design:type", Object)
|
|
72
|
+
], OpenFgaProvision.prototype, "name", void 0);
|
|
73
|
+
//# sourceMappingURL=openfga_provision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openfga_provision.js","sourceRoot":"","sources":["../../commands/openfga_provision.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAGvD;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,WAAW;IACvD,MAAM,CAAC,WAAW,GAAG,mBAAmB,CAAA;IACxC,MAAM,CAAC,WAAW,GAAG,iEAAiE,CAAA;IAEtF,MAAM,CAAC,OAAO,GAAmB;QAC/B,QAAQ,EAAE,KAAK;KAChB,CAAA;IAWD,KAAK,CAAC,GAAG;QACP,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,eAAe,CAAQ,CAAA;QAC1D,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,MAAM,EAAE,OAAO,EAAE,GAAG,CAAA;QAC/C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,6EAA6E,CAAC,CAAA;YAChG,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAA;YACjB,OAAM;QACR,CAAC;QAED,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAA;QACtD,MAAM,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,GAAG,MAAM,MAAM,CACvE,kCAAkC,CACnC,CAAA;QACD,mEAAmE;QACnE,MAAM,WAAW,GAAG,MAAM,EAAE,WAAW,IAAI,EAAE,CAAA;QAE7C,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAA;YACnE,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAC,CAAA;YAC1F,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,0DAA0D,CAAC,CAAA;YAC/E,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,oBAAoB,IAAI,CAAC,OAAO,EAAE,CAAC,CAAA;YACnD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,oBAAoB,KAAK,CAAC,sBAAsB,EAAE,CAAC,CAAA;YACnE,OAAM;QACR,CAAC;QAED,wEAAwE;QACxE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,qBAAqB,CACtD,MAAM,EACN,IAAI,CAAC,IAAI,IAAI,MAAM,EAAE,OAAO,EAAE,SAAS,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAC3D,WAAW,CACZ,CAAA;QACD,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,4CAA4C,CAAC,CAAA;QACjE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAA;QAChE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,eAAe,MAAM,EAAE,CAAC,CAAA;QACxC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAA;QAC9C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAA;IAChD,CAAC;;AA5CO;IADP,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,2CAA2C,EAAE,CAAC;;6CAC5C;AAGvB;IADP,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,0CAA0C,EAAE,CAAC;;iDACnD;AAG3B;IADP,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,8DAA8D,EAAE,CAAC;;8CAC9D"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type Configure from '@adonisjs/core/commands/configure';
|
|
2
|
+
/**
|
|
3
|
+
* `node ace configure @jantstack/adonis-authz`
|
|
4
|
+
*
|
|
5
|
+
* Registra el provider, los comandos y el middleware, define las variables
|
|
6
|
+
* de entorno y PUBLICA en el proyecto lo que es suyo: la migración de las
|
|
7
|
+
* tablas `authz_*` y los dos configs (drivers + catálogo del nivel app).
|
|
8
|
+
*/
|
|
9
|
+
export declare function configure(command: Configure): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=configure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../configure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,mCAAmC,CAAA;AAG9D;;;;;;GAMG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,SAAS,iBAuCjD"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { stubsRoot } from './stubs/main.js';
|
|
2
|
+
/**
|
|
3
|
+
* `node ace configure @jantstack/adonis-authz`
|
|
4
|
+
*
|
|
5
|
+
* Registra el provider, los comandos y el middleware, define las variables
|
|
6
|
+
* de entorno y PUBLICA en el proyecto lo que es suyo: la migración de las
|
|
7
|
+
* tablas `authz_*` y los dos configs (drivers + catálogo del nivel app).
|
|
8
|
+
*/
|
|
9
|
+
export async function configure(command) {
|
|
10
|
+
const codemods = await command.createCodemods();
|
|
11
|
+
await codemods.updateRcFile((rcFile) => {
|
|
12
|
+
rcFile
|
|
13
|
+
.addProvider('@jantstack/adonis-authz/authz_provider')
|
|
14
|
+
.addCommand('@jantstack/adonis-authz/commands');
|
|
15
|
+
});
|
|
16
|
+
await codemods.registerMiddleware('named', [
|
|
17
|
+
{
|
|
18
|
+
name: 'appAccess',
|
|
19
|
+
path: '@jantstack/adonis-authz/app_access_middleware',
|
|
20
|
+
},
|
|
21
|
+
]);
|
|
22
|
+
await codemods.defineEnvVariables({ AUTHZ_DRIVER: 'database' });
|
|
23
|
+
await codemods.defineEnvValidations({
|
|
24
|
+
variables: {
|
|
25
|
+
AUTHZ_DRIVER: `Env.schema.string.optional()`,
|
|
26
|
+
OPENFGA_URL: `Env.schema.string.optional({ format: 'url', tld: false })`,
|
|
27
|
+
OPENFGA_STORE_ID: `Env.schema.string.optional()`,
|
|
28
|
+
OPENFGA_MODEL_ID: `Env.schema.string.optional()`,
|
|
29
|
+
},
|
|
30
|
+
leadingComment: 'Variables de @jantstack/adonis-authz',
|
|
31
|
+
});
|
|
32
|
+
await codemods.makeUsingStub(stubsRoot, 'config/authorization.stub', {});
|
|
33
|
+
await codemods.makeUsingStub(stubsRoot, 'config/app_acl.stub', {});
|
|
34
|
+
await codemods.makeUsingStub(stubsRoot, 'migration.stub', {
|
|
35
|
+
migration: {
|
|
36
|
+
folder: 'database/migrations',
|
|
37
|
+
fileName: `${new Date().getTime()}_create_authz_tables.ts`,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
command.logger.success('Autorización configurada.');
|
|
41
|
+
command.logger.info('Siguiente paso: node ace migration:run');
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=configure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configure.js","sourceRoot":"","sources":["../configure.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAkB;IAChD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,cAAc,EAAE,CAAA;IAE/C,MAAM,QAAQ,CAAC,YAAY,CAAC,CAAC,MAAW,EAAE,EAAE;QAC1C,MAAM;aACH,WAAW,CAAC,wCAAwC,CAAC;aACrD,UAAU,CAAC,kCAAkC,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;IAEF,MAAM,QAAQ,CAAC,kBAAkB,CAAC,OAAO,EAAE;QACzC;YACE,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,+CAA+C;SACtD;KACF,CAAC,CAAA;IAEF,MAAM,QAAQ,CAAC,kBAAkB,CAAC,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,CAAA;IAC/D,MAAM,QAAQ,CAAC,oBAAoB,CAAC;QAClC,SAAS,EAAE;YACT,YAAY,EAAE,8BAA8B;YAC5C,WAAW,EAAE,2DAA2D;YACxE,gBAAgB,EAAE,8BAA8B;YAChD,gBAAgB,EAAE,8BAA8B;SACjD;QACD,cAAc,EAAE,sCAAsC;KACvD,CAAC,CAAA;IAEF,MAAM,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,2BAA2B,EAAE,EAAE,CAAC,CAAA;IACxE,MAAM,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,qBAAqB,EAAE,EAAE,CAAC,CAAA;IAElE,MAAM,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,gBAAgB,EAAE;QACxD,SAAS,EAAE;YACT,MAAM,EAAE,qBAAqB;YAC7B,QAAQ,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,yBAAyB;SAC3D;KACF,CAAC,CAAA;IAEF,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAA;IACnD,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAA;AAC/D,CAAC"}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entrada pública del paquete.
|
|
3
|
+
* import { AuthorizationManager, APP_SCOPE } from '@jantstack/adonis-authz'
|
|
4
|
+
*/
|
|
5
|
+
export { AuthorizationManager } from './src/manager.js';
|
|
6
|
+
export { defineConfig } from './src/define_config.js';
|
|
7
|
+
export type { AuthorizationConfig } from './src/define_config.js';
|
|
8
|
+
export { syncAuthzCatalog } from './src/catalog.js';
|
|
9
|
+
export { DatabaseAuthorizationDriver, APP_SCOPE_DB_UUID } from './src/drivers/database_driver.js';
|
|
10
|
+
export { OpenFgaAuthorizationDriver, openFgaAuthorizationModel, provisionOpenFgaStore, importAuthzFactsToOpenFga, } from './src/drivers/openfga_driver.js';
|
|
11
|
+
export type { HolderTypeMap, OpenFgaDriverOptions } from './src/drivers/openfga_driver.js';
|
|
12
|
+
export { APP_SCOPE, APP_SCOPE_TYPE } from './src/types.js';
|
|
13
|
+
export type { AuthorizationDriver, AuthorizationDriverFactory, AuthzWriteEvent, CatalogRoleSpec, CatalogSpec, GrantOptions, ScopeAncestorsResolver, ScopeRef, ScopeType, SubjectRef, } from './src/types.js';
|
|
14
|
+
export { default as AuthzRole } from './src/models/authz_role.js';
|
|
15
|
+
export { default as AuthzPermission } from './src/models/authz_permission.js';
|
|
16
|
+
export { default as AuthzRolePermission } from './src/models/authz_role_permission.js';
|
|
17
|
+
export { default as AuthzAssignment } from './src/models/authz_assignment.js';
|
|
18
|
+
export { default as AuthzDeny } from './src/models/authz_deny.js';
|
|
19
|
+
export { withAuthzScopes } from './src/traits/authz_scopes.js';
|
|
20
|
+
export { hasUuid } from './src/traits/has_uuid.js';
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACrD,YAAY,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAEnD,OAAO,EAAE,2BAA2B,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAA;AACjG,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,EACzB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,iCAAiC,CAAA;AACxC,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAA;AAE1F,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC1D,YAAY,EACV,mBAAmB,EACnB,0BAA0B,EAC1B,eAAe,EACf,eAAe,EACf,WAAW,EACX,YAAY,EACZ,sBAAsB,EACtB,QAAQ,EACR,SAAS,EACT,UAAU,GACX,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,4BAA4B,CAAA;AACjE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,kCAAkC,CAAA;AAC7E,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,uCAAuC,CAAA;AACtF,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,kCAAkC,CAAA;AAC7E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,4BAA4B,CAAA;AAEjE,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA"}
|
package/build/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entrada pública del paquete.
|
|
3
|
+
* import { AuthorizationManager, APP_SCOPE } from '@jantstack/adonis-authz'
|
|
4
|
+
*/
|
|
5
|
+
export { AuthorizationManager } from './src/manager.js';
|
|
6
|
+
export { defineConfig } from './src/define_config.js';
|
|
7
|
+
export { syncAuthzCatalog } from './src/catalog.js';
|
|
8
|
+
export { DatabaseAuthorizationDriver, APP_SCOPE_DB_UUID } from './src/drivers/database_driver.js';
|
|
9
|
+
export { OpenFgaAuthorizationDriver, openFgaAuthorizationModel, provisionOpenFgaStore, importAuthzFactsToOpenFga, } from './src/drivers/openfga_driver.js';
|
|
10
|
+
export { APP_SCOPE, APP_SCOPE_TYPE } from './src/types.js';
|
|
11
|
+
export { default as AuthzRole } from './src/models/authz_role.js';
|
|
12
|
+
export { default as AuthzPermission } from './src/models/authz_permission.js';
|
|
13
|
+
export { default as AuthzRolePermission } from './src/models/authz_role_permission.js';
|
|
14
|
+
export { default as AuthzAssignment } from './src/models/authz_assignment.js';
|
|
15
|
+
export { default as AuthzDeny } from './src/models/authz_deny.js';
|
|
16
|
+
export { withAuthzScopes } from './src/traits/authz_scopes.js';
|
|
17
|
+
export { hasUuid } from './src/traits/has_uuid.js';
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAErD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAEnD,OAAO,EAAE,2BAA2B,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAA;AACjG,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,EACzB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,iCAAiC,CAAA;AAGxC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAc1D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,4BAA4B,CAAA;AACjE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,kCAAkC,CAAA;AAC7E,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,uCAAuC,CAAA;AACtF,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,kCAAkC,CAAA;AAC7E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,4BAA4B,CAAA;AAEjE,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ApplicationService } from '@adonisjs/core/types';
|
|
2
|
+
import { AuthorizationManager } from '../src/manager.js';
|
|
3
|
+
declare module '@adonisjs/core/types' {
|
|
4
|
+
interface ContainerBindings {
|
|
5
|
+
'authz.manager': AuthorizationManager;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Registra el manager de autorización como singleton del contenedor,
|
|
10
|
+
* construido desde `config/authorization.ts` de la aplicación.
|
|
11
|
+
*/
|
|
12
|
+
export default class AuthzProvider {
|
|
13
|
+
protected app: ApplicationService;
|
|
14
|
+
constructor(app: ApplicationService);
|
|
15
|
+
register(): void;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=authz_provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authz_provider.d.ts","sourceRoot":"","sources":["../../providers/authz_provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAExD,OAAO,QAAQ,sBAAsB,CAAC;IACpC,UAAiB,iBAAiB;QAChC,eAAe,EAAE,oBAAoB,CAAA;KACtC;CACF;AAED;;;GAGG;AACH,MAAM,CAAC,OAAO,OAAO,aAAa;IACpB,SAAS,CAAC,GAAG,EAAE,kBAAkB;gBAAvB,GAAG,EAAE,kBAAkB;IAE7C,QAAQ;CAWT"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { AuthorizationManager } from '../src/manager.js';
|
|
2
|
+
/**
|
|
3
|
+
* Registra el manager de autorización como singleton del contenedor,
|
|
4
|
+
* construido desde `config/authorization.ts` de la aplicación.
|
|
5
|
+
*/
|
|
6
|
+
export default class AuthzProvider {
|
|
7
|
+
app;
|
|
8
|
+
constructor(app) {
|
|
9
|
+
this.app = app;
|
|
10
|
+
}
|
|
11
|
+
register() {
|
|
12
|
+
this.app.container.singleton('authz.manager', async () => {
|
|
13
|
+
const config = this.app.config.get('authorization');
|
|
14
|
+
if (!config) {
|
|
15
|
+
throw new Error('Falta config/authorization.ts — ejecuta: node ace configure @jantstack/adonis-authz');
|
|
16
|
+
}
|
|
17
|
+
return new AuthorizationManager(config);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=authz_provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authz_provider.js","sourceRoot":"","sources":["../../providers/authz_provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAQxD;;;GAGG;AACH,MAAM,CAAC,OAAO,OAAO,aAAa;IACV;IAAtB,YAAsB,GAAuB;QAAvB,QAAG,GAAH,GAAG,CAAoB;IAAG,CAAC;IAEjD,QAAQ;QACN,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE;YACvD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,eAAe,CAAQ,CAAA;YAC1D,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CACb,qFAAqF,CACtF,CAAA;YACH,CAAC;YACD,OAAO,IAAI,oBAAoB,CAAC,MAAM,CAAC,CAAA;QACzC,CAAC,CAAC,CAAA;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AuthorizationManager } from '../src/manager.js';
|
|
2
|
+
/**
|
|
3
|
+
* Singleton del manager, resuelto del contenedor cuando la app ha booteado.
|
|
4
|
+
*
|
|
5
|
+
* import authorization from '@jantstack/adonis-authz/services/main'
|
|
6
|
+
* await authorization.authorize(subject, 'audit:read', APP_SCOPE)
|
|
7
|
+
*/
|
|
8
|
+
declare let authorization: AuthorizationManager;
|
|
9
|
+
export { authorization as default };
|
|
10
|
+
//# sourceMappingURL=main.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../services/main.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAE7D;;;;;GAKG;AACH,QAAA,IAAI,aAAa,EAAE,oBAAoB,CAAA;AAMvC,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import app from '@adonisjs/core/services/app';
|
|
2
|
+
/**
|
|
3
|
+
* Singleton del manager, resuelto del contenedor cuando la app ha booteado.
|
|
4
|
+
*
|
|
5
|
+
* import authorization from '@jantstack/adonis-authz/services/main'
|
|
6
|
+
* await authorization.authorize(subject, 'audit:read', APP_SCOPE)
|
|
7
|
+
*/
|
|
8
|
+
let authorization;
|
|
9
|
+
await app.booted(async () => {
|
|
10
|
+
authorization = await app.container.make('authz.manager');
|
|
11
|
+
});
|
|
12
|
+
export { authorization as default };
|
|
13
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../services/main.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,6BAA6B,CAAA;AAG7C;;;;;GAKG;AACH,IAAI,aAAmC,CAAA;AAEvC,MAAM,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;IAC1B,aAAa,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;AAC3D,CAAC,CAAC,CAAA;AAEF,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/catalog.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AA+B7C,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAwE1E"}
|