@jantstack/adonis-authz 1.1.0 → 2.4.0-alpha.1
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 +1 -1
- package/README.md +837 -51
- package/build/commands/authz_catalog_diff.d.ts +28 -0
- package/build/commands/authz_catalog_diff.d.ts.map +1 -0
- package/build/commands/authz_catalog_diff.js +67 -0
- package/build/commands/authz_catalog_diff.js.map +1 -0
- package/build/commands/authz_catalog_prune_orphans.d.ts +78 -0
- package/build/commands/authz_catalog_prune_orphans.d.ts.map +1 -0
- package/build/commands/authz_catalog_prune_orphans.js +136 -0
- package/build/commands/authz_catalog_prune_orphans.js.map +1 -0
- package/build/commands/authz_catalog_sync.d.ts +37 -0
- package/build/commands/authz_catalog_sync.d.ts.map +1 -0
- package/build/commands/authz_catalog_sync.js +81 -0
- package/build/commands/authz_catalog_sync.js.map +1 -0
- package/build/commands/authz_freeze.d.ts +44 -0
- package/build/commands/authz_freeze.d.ts.map +1 -0
- package/build/commands/authz_freeze.js +95 -0
- package/build/commands/authz_freeze.js.map +1 -0
- package/build/commands/authz_reconcile.d.ts +102 -0
- package/build/commands/authz_reconcile.d.ts.map +1 -0
- package/build/commands/authz_reconcile.js +294 -0
- package/build/commands/authz_reconcile.js.map +1 -0
- package/build/commands/authz_relations_reconcile.d.ts +73 -0
- package/build/commands/authz_relations_reconcile.d.ts.map +1 -0
- package/build/commands/authz_relations_reconcile.js +225 -0
- package/build/commands/authz_relations_reconcile.js.map +1 -0
- package/build/commands/authz_scopes_relay.d.ts +47 -0
- package/build/commands/authz_scopes_relay.d.ts.map +1 -0
- package/build/commands/authz_scopes_relay.js +141 -0
- package/build/commands/authz_scopes_relay.js.map +1 -0
- package/build/commands/authz_unfreeze.d.ts +37 -0
- package/build/commands/authz_unfreeze.d.ts.map +1 -0
- package/build/commands/authz_unfreeze.js +92 -0
- package/build/commands/authz_unfreeze.js.map +1 -0
- package/build/commands/main.d.ts +8 -1
- package/build/commands/main.d.ts.map +1 -1
- package/build/commands/main.js +8 -1
- package/build/commands/main.js.map +1 -1
- package/build/commands/openfga_provision.d.ts +46 -4
- package/build/commands/openfga_provision.d.ts.map +1 -1
- package/build/commands/openfga_provision.js +91 -7
- package/build/commands/openfga_provision.js.map +1 -1
- package/build/configure.d.ts +11 -0
- package/build/configure.d.ts.map +1 -1
- package/build/configure.js +37 -1
- package/build/configure.js.map +1 -1
- package/build/index.d.ts +75 -7
- package/build/index.d.ts.map +1 -1
- package/build/index.js +67 -5
- package/build/index.js.map +1 -1
- package/build/providers/authz_provider.d.ts +26 -2
- package/build/providers/authz_provider.d.ts.map +1 -1
- package/build/providers/authz_provider.js +48 -2
- package/build/providers/authz_provider.js.map +1 -1
- package/build/services/relations.d.ts +14 -0
- package/build/services/relations.d.ts.map +1 -0
- package/build/services/relations.js +17 -0
- package/build/services/relations.js.map +1 -0
- package/build/src/catalog/catalog.d.ts +289 -0
- package/build/src/catalog/catalog.d.ts.map +1 -0
- package/build/src/catalog/catalog.js +859 -0
- package/build/src/catalog/catalog.js.map +1 -0
- package/build/src/catalog/catalog_cache.d.ts +324 -0
- package/build/src/catalog/catalog_cache.d.ts.map +1 -0
- package/build/src/catalog/catalog_cache.js +666 -0
- package/build/src/catalog/catalog_cache.js.map +1 -0
- package/build/src/clock.d.ts +24 -0
- package/build/src/clock.d.ts.map +1 -0
- package/build/src/clock.js +7 -0
- package/build/src/clock.js.map +1 -0
- package/build/src/define_config.d.ts +201 -7
- package/build/src/define_config.d.ts.map +1 -1
- package/build/src/define_config.js.map +1 -1
- package/build/src/drivers/database_driver.d.ts +324 -15
- package/build/src/drivers/database_driver.d.ts.map +1 -1
- package/build/src/drivers/database_driver.js +1107 -128
- package/build/src/drivers/database_driver.js.map +1 -1
- package/build/src/drivers/database_relations_driver.d.ts +75 -0
- package/build/src/drivers/database_relations_driver.d.ts.map +1 -0
- package/build/src/drivers/database_relations_driver.js +450 -0
- package/build/src/drivers/database_relations_driver.js.map +1 -0
- package/build/src/drivers/openfga_driver.d.ts +963 -55
- package/build/src/drivers/openfga_driver.d.ts.map +1 -1
- package/build/src/drivers/openfga_driver.js +2693 -372
- package/build/src/drivers/openfga_driver.js.map +1 -1
- package/build/src/drivers/openfga_facts.d.ts +369 -0
- package/build/src/drivers/openfga_facts.d.ts.map +1 -0
- package/build/src/drivers/openfga_facts.js +813 -0
- package/build/src/drivers/openfga_facts.js.map +1 -0
- package/build/src/drivers/openfga_relations_driver.d.ts +120 -0
- package/build/src/drivers/openfga_relations_driver.d.ts.map +1 -0
- package/build/src/drivers/openfga_relations_driver.js +466 -0
- package/build/src/drivers/openfga_relations_driver.js.map +1 -0
- package/build/src/errors.d.ts +586 -0
- package/build/src/errors.d.ts.map +1 -1
- package/build/src/errors.js +583 -0
- package/build/src/errors.js.map +1 -1
- package/build/src/expiry.d.ts +27 -0
- package/build/src/expiry.d.ts.map +1 -0
- package/build/src/expiry.js +50 -0
- package/build/src/expiry.js.map +1 -0
- package/build/src/freeze.d.ts +120 -0
- package/build/src/freeze.d.ts.map +1 -0
- package/build/src/freeze.js +172 -0
- package/build/src/freeze.js.map +1 -0
- package/build/src/hierarchical_resolver.d.ts +56 -0
- package/build/src/hierarchical_resolver.d.ts.map +1 -0
- package/build/src/hierarchical_resolver.js +87 -0
- package/build/src/hierarchical_resolver.js.map +1 -0
- package/build/src/{middleware → http}/app_access_middleware.d.ts +8 -6
- package/build/src/http/app_access_middleware.d.ts.map +1 -0
- package/build/src/{middleware → http}/app_access_middleware.js +10 -26
- package/build/src/http/app_access_middleware.js.map +1 -0
- package/build/src/http/resource_access_middleware.d.ts +105 -0
- package/build/src/http/resource_access_middleware.d.ts.map +1 -0
- package/build/src/http/resource_access_middleware.js +81 -0
- package/build/src/http/resource_access_middleware.js.map +1 -0
- package/build/src/identity.d.ts +228 -0
- package/build/src/identity.d.ts.map +1 -0
- package/build/src/identity.js +457 -0
- package/build/src/identity.js.map +1 -0
- package/build/src/manager.d.ts +536 -7
- package/build/src/manager.d.ts.map +1 -1
- package/build/src/manager.js +2676 -23
- package/build/src/manager.js.map +1 -1
- package/build/src/memoize_ancestors.d.ts +23 -0
- package/build/src/memoize_ancestors.d.ts.map +1 -0
- package/build/src/memoize_ancestors.js +42 -0
- package/build/src/memoize_ancestors.js.map +1 -0
- package/build/src/models/authz_assignment.d.ts +11 -11
- package/build/src/models/authz_assignment.d.ts.map +1 -1
- package/build/src/models/authz_deny.d.ts +11 -11
- package/build/src/models/authz_deny.d.ts.map +1 -1
- package/build/src/models/authz_permission.d.ts +17 -11
- package/build/src/models/authz_permission.d.ts.map +1 -1
- package/build/src/models/authz_permission.js +4 -0
- package/build/src/models/authz_permission.js.map +1 -1
- package/build/src/models/authz_role.d.ts +19 -12
- package/build/src/models/authz_role.d.ts.map +1 -1
- package/build/src/models/authz_role.js +6 -1
- package/build/src/models/authz_role.js.map +1 -1
- package/build/src/models/authz_role_permission.d.ts +11 -11
- package/build/src/models/authz_role_permission.d.ts.map +1 -1
- package/build/src/openfga.d.ts +29 -0
- package/build/src/openfga.d.ts.map +1 -0
- package/build/src/openfga.js +26 -0
- package/build/src/openfga.js.map +1 -0
- package/build/src/reconcile.d.ts +37 -0
- package/build/src/reconcile.d.ts.map +1 -0
- package/build/src/reconcile.js +69 -0
- package/build/src/reconcile.js.map +1 -0
- package/build/src/relation_partition_trigger.d.ts +8 -0
- package/build/src/relation_partition_trigger.d.ts.map +1 -0
- package/build/src/relation_partition_trigger.js +85 -0
- package/build/src/relation_partition_trigger.js.map +1 -0
- package/build/src/relations/define_relations_config.d.ts +58 -0
- package/build/src/relations/define_relations_config.d.ts.map +1 -0
- package/build/src/relations/define_relations_config.js +144 -0
- package/build/src/relations/define_relations_config.js.map +1 -0
- package/build/src/relations/manager.d.ts +38 -0
- package/build/src/relations/manager.d.ts.map +1 -0
- package/build/src/relations/manager.js +156 -0
- package/build/src/relations/manager.js.map +1 -0
- package/build/src/relations/reconcile.d.ts +62 -0
- package/build/src/relations/reconcile.d.ts.map +1 -0
- package/build/src/relations/reconcile.js +138 -0
- package/build/src/relations/reconcile.js.map +1 -0
- package/build/src/relations_config_store.d.ts +22 -0
- package/build/src/relations_config_store.d.ts.map +1 -0
- package/build/src/relations_config_store.js +74 -0
- package/build/src/relations_config_store.js.map +1 -0
- package/build/src/scope_outbox.d.ts +69 -0
- package/build/src/scope_outbox.d.ts.map +1 -0
- package/build/src/scope_outbox.js +291 -0
- package/build/src/scope_outbox.js.map +1 -0
- package/build/src/shared/backend_guard.d.ts +106 -0
- package/build/src/shared/backend_guard.d.ts.map +1 -0
- package/build/src/shared/backend_guard.js +246 -0
- package/build/src/shared/backend_guard.js.map +1 -0
- package/build/src/shared/sql_expiry.d.ts +53 -0
- package/build/src/shared/sql_expiry.d.ts.map +1 -0
- package/build/src/shared/sql_expiry.js +66 -0
- package/build/src/shared/sql_expiry.js.map +1 -0
- package/build/src/sql_descendants.d.ts +97 -0
- package/build/src/sql_descendants.d.ts.map +1 -0
- package/build/src/sql_descendants.js +203 -0
- package/build/src/sql_descendants.js.map +1 -0
- package/build/src/testing/contract.d.ts +212 -7
- package/build/src/testing/contract.d.ts.map +1 -1
- package/build/src/testing/contract.js +3449 -24
- package/build/src/testing/contract.js.map +1 -1
- package/build/src/testing/main.d.ts +10 -2
- package/build/src/testing/main.d.ts.map +1 -1
- package/build/src/testing/main.js +5 -1
- package/build/src/testing/main.js.map +1 -1
- package/build/src/testing/migration_contract.d.ts +284 -0
- package/build/src/testing/migration_contract.d.ts.map +1 -0
- package/build/src/testing/migration_contract.js +586 -0
- package/build/src/testing/migration_contract.js.map +1 -0
- package/build/src/testing/relations_contract.d.ts +51 -0
- package/build/src/testing/relations_contract.d.ts.map +1 -0
- package/build/src/testing/relations_contract.js +654 -0
- package/build/src/testing/relations_contract.js.map +1 -0
- package/build/src/testing/relations_reconcile_contract.d.ts +24 -0
- package/build/src/testing/relations_reconcile_contract.d.ts.map +1 -0
- package/build/src/testing/relations_reconcile_contract.js +172 -0
- package/build/src/testing/relations_reconcile_contract.js.map +1 -0
- package/build/src/testing/scope_tree.d.ts +65 -0
- package/build/src/testing/scope_tree.d.ts.map +1 -0
- package/build/src/testing/scope_tree.js +145 -0
- package/build/src/testing/scope_tree.js.map +1 -0
- package/build/src/traits/authz_scopes.d.ts +30 -6
- package/build/src/traits/authz_scopes.d.ts.map +1 -1
- package/build/src/traits/authz_scopes.js +30 -18
- package/build/src/traits/authz_scopes.js.map +1 -1
- package/build/src/traits/has_uuid.d.ts +12 -12
- package/build/src/traits/has_uuid.d.ts.map +1 -1
- package/build/src/types.d.ts +1313 -28
- package/build/src/types.d.ts.map +1 -1
- package/build/src/types.js +20 -4
- package/build/src/types.js.map +1 -1
- package/build/stubs/config/app_acl.stub +4 -2
- package/build/stubs/config/authorization.stub +168 -14
- package/build/stubs/migration.stub +183 -13
- package/build/stubs/scopes_outbox_migration.stub +57 -0
- package/package.json +14 -7
- package/build/commands/openfga_import.d.ts +0 -28
- package/build/commands/openfga_import.d.ts.map +0 -1
- package/build/commands/openfga_import.js +0 -74
- package/build/commands/openfga_import.js.map +0 -1
- package/build/src/catalog.d.ts +0 -3
- package/build/src/catalog.d.ts.map +0 -1
- package/build/src/catalog.js +0 -103
- package/build/src/catalog.js.map +0 -1
- package/build/src/middleware/app_access_middleware.d.ts.map +0 -1
- package/build/src/middleware/app_access_middleware.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openfga_facts.js","sourceRoot":"","sources":["../../../src/drivers/openfga_facts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { RelObject, RelSubject, RelationObjectsPage, RelationSubjectsPage, RelationPage, RelationTuplePage, RelationsDriver, RelationsDriverCapabilities, RelationWriteOptions, ScopeRef } from '../types.js';
|
|
2
|
+
import type { HolderTypeMap } from './openfga_driver.js';
|
|
3
|
+
import type { RelationsConfig } from '../relations/define_relations_config.js';
|
|
4
|
+
export declare const DEFAULT_TIMEOUT_MS = 5000;
|
|
5
|
+
export interface OpenFgaRelationsDriverOptions {
|
|
6
|
+
apiUrl: string;
|
|
7
|
+
storeId: string;
|
|
8
|
+
/** Pin del model FUSIONADO; si se omite, FGA usa el último del store. */
|
|
9
|
+
modelId?: string;
|
|
10
|
+
/** Holders del consumidor: morph name → tipo FGA. El MISMO mapa del driver de roles. */
|
|
11
|
+
holderTypes: HolderTypeMap;
|
|
12
|
+
/** Deadline de cada llamada en ms (default 5000): vencido ⇒ 503. */
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
/** Consistencia pedida al servidor (default `higher_consistency`, como el driver de roles). */
|
|
15
|
+
consistency?: 'higher_consistency' | 'minimize_latency';
|
|
16
|
+
/**
|
|
17
|
+
* El tope de `ListObjects` del servidor (`OPENFGA_LIST_OBJECTS_MAX_RESULTS`).
|
|
18
|
+
* Default 1000 (el default de OpenFGA). Cuando `listObjects` recibe `>= este`
|
|
19
|
+
* resultados, señala `truncated: true`. Ponlo igual que el del servidor.
|
|
20
|
+
*/
|
|
21
|
+
listObjectsMaxResults?: number;
|
|
22
|
+
/** Dónde avisar de tuplas del store que el driver no puede parsear. */
|
|
23
|
+
logger?: {
|
|
24
|
+
warn(message: string): void;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export declare class OpenFgaRelationsDriver implements RelationsDriver {
|
|
28
|
+
#private;
|
|
29
|
+
/**
|
|
30
|
+
* Lo que declara (cada valor tiene su cara en `runRelationsDriverContract`):
|
|
31
|
+
* - `singleCheckRelations: true`: `check` es UN solo `Check` (el modelo
|
|
32
|
+
* resuelve includes + usersets del lado del servidor).
|
|
33
|
+
* - `listObjectsInherited: false`: `list*` no abren el subárbol de
|
|
34
|
+
* particiones (invariante 7); `ListObjects` sí resuelve la derivación del
|
|
35
|
+
* modelo (includes/usersets), que es «directos + derivados», no herencia
|
|
36
|
+
* de scopes.
|
|
37
|
+
* - `usersetSubjects: true`: `listSubjects` (`Read`) trae los usersets
|
|
38
|
+
* directos (`group#member`) junto con los holders.
|
|
39
|
+
* - `membersOfNative: false`: la membresía TRANSITIVA sería `ListUsers`, que
|
|
40
|
+
* trunca al tope del servidor; se declara 500 `E_AUTHZ_UNSUPPORTED`, jamás
|
|
41
|
+
* un userset enumerado a medias (par de `purgeRole` de la 3b).
|
|
42
|
+
* - `enumerateRelations: true` (4-5): es ORIGEN de `authz:reconcile` de
|
|
43
|
+
* relaciones — lee el store ENTERO (`Read({})`, la única forma de ver todo
|
|
44
|
+
* sin filtro por user u objeto: un `Read` por tipo-solo sin user es un 400)
|
|
45
|
+
* y devuelve SOLO las tuplas de relación de la partición (tipo declarado o
|
|
46
|
+
* `group`), descartando las de `facts` (scope/role/role_binding).
|
|
47
|
+
* - `listObjectsTruncation: true`: `ListObjects` trunca al tope del servidor
|
|
48
|
+
* y este driver lo SEÑALA (medido contra el `:8103` de tope 3).
|
|
49
|
+
*/
|
|
50
|
+
readonly capabilities: RelationsDriverCapabilities;
|
|
51
|
+
private readonly client;
|
|
52
|
+
readonly diagnostics: {
|
|
53
|
+
unparseableTuples: number;
|
|
54
|
+
};
|
|
55
|
+
constructor(config: RelationsConfig, options: OpenFgaRelationsDriverOptions);
|
|
56
|
+
relate(subject: RelSubject, relation: string, object: RelObject, partition: ScopeRef, _options?: RelationWriteOptions): Promise<void>;
|
|
57
|
+
unrelate(subject: RelSubject, relation: string, object: RelObject, partition: ScopeRef, _options?: RelationWriteOptions): Promise<void>;
|
|
58
|
+
/** `check` = UN solo `Check` (el modelo resuelve includes + usersets). */
|
|
59
|
+
check(subject: RelSubject, relation: string, object: RelObject, partition: ScopeRef): Promise<boolean>;
|
|
60
|
+
/**
|
|
61
|
+
* `listObjects` = `ListObjects` (resuelve includes + usersets del lado del
|
|
62
|
+
* servidor) + FILTRO por partición + señal de TRUNCADO. `ListObjects` corta
|
|
63
|
+
* al tope del servidor sin `continuation_token` ni bandera, así que el
|
|
64
|
+
* truncado se detecta comparando el número de resultados CRUDOS con el tope
|
|
65
|
+
* configurado (`listObjectsMaxResults`): `>= tope` ⇒ no se puede prometer la
|
|
66
|
+
* lista completa ⇒ `truncated: true`. El filtro por partición se aplica
|
|
67
|
+
* DESPUÉS (los ids llevan la partición), así que en un store con varias
|
|
68
|
+
* particiones el tope se consume entre todas — otra razón para señalar el
|
|
69
|
+
* truncado y no callar (documentado en el README).
|
|
70
|
+
*/
|
|
71
|
+
listObjects(subject: RelSubject, relation: string, objectType: string, partition: ScopeRef, _page?: RelationPage): Promise<RelationObjectsPage>;
|
|
72
|
+
/**
|
|
73
|
+
* `listSubjects` = `Read` por `(object, relation)` — hechos DIRECTOS del
|
|
74
|
+
* relation EXACTO (invariante 7): ni transitivo (eso es `membersOf`) ni
|
|
75
|
+
* derivado por includes. `usersetSubjects: true` ⇒ los usersets
|
|
76
|
+
* (`group#member`) salen junto con los holders.
|
|
77
|
+
*/
|
|
78
|
+
listSubjects(relation: string, object: RelObject, partition: ScopeRef, _page?: RelationPage): Promise<RelationSubjectsPage>;
|
|
79
|
+
/**
|
|
80
|
+
* **`membersOf` ⇒ 500 `E_AUTHZ_UNSUPPORTED`** (cara `whenFalse`): la
|
|
81
|
+
* membresía TRANSITIVA de un grupo sería `ListUsers`, que trunca al tope del
|
|
82
|
+
* servidor sin señal fiable. No hay userset transitivo enumerable aquí; se
|
|
83
|
+
* dice con 500 nombrándolo, jamás un userset a medias. Es el análogo del par
|
|
84
|
+
* `purgeRole` de la 3b. (El método existe en el prototipo para que el manager
|
|
85
|
+
* lo despache, pero la capacidad `membersOfNative: false` lo corta antes.)
|
|
86
|
+
*/
|
|
87
|
+
membersOf(): Promise<RelationSubjectsPage>;
|
|
88
|
+
/**
|
|
89
|
+
* **`enumerateRelations` — el ORIGEN de `authz:reconcile` de relaciones**
|
|
90
|
+
* (4-5). Lee el store ENTERO (`Read({})`) —la única forma de ver todo sin un
|
|
91
|
+
* filtro por `user` u `object`, que un `Read` por tipo-solo sin user
|
|
92
|
+
* rechazaría con 400— y devuelve SOLO las tuplas de relación de la partición
|
|
93
|
+
* pedida: tipo `group` o un tipo declarado en la config, DESCARTANDO las de
|
|
94
|
+
* `facts` (`scope`/`role`/`role_binding`, que no llevan la partición en el id
|
|
95
|
+
* con la forma `<key>|<uuid>` de relaciones —o cuyo tipo no está declarado—).
|
|
96
|
+
*
|
|
97
|
+
* `truncated`/paginación: `enumerateRelations` agota el `Read` (exhaustivo,
|
|
98
|
+
* como `listSubjects`/`purge*`), así que devuelve TODO en una página sin
|
|
99
|
+
* cursor —el reconcile itera hasta que no hay cursor—. Es el ORIGEN de una
|
|
100
|
+
* migración: una tupla que no llegara aquí desaparecería sin rastro.
|
|
101
|
+
*/
|
|
102
|
+
enumerateRelations(partition: ScopeRef, _page?: RelationPage): Promise<RelationTuplePage>;
|
|
103
|
+
/**
|
|
104
|
+
* Borra TODAS las tuplas del objeto (cualquier relación) y demuestra cero.
|
|
105
|
+
* Barre las DOS ortografías del uuid de partición (🟡2, paridad con
|
|
106
|
+
* `database`): un motor que funda `aaa…` con `aaa-…` dejaría la fila del
|
|
107
|
+
* alias concediendo tras una purga «exitosa». Si tras borrar quedan tuplas
|
|
108
|
+
* ⇒ 500 `E_AUTHZ_PURGE_INCOMPLETE`.
|
|
109
|
+
*/
|
|
110
|
+
purgeObject(object: RelObject, partition: ScopeRef): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Borra TODAS las tuplas cuyo SUJETO es este subject en la partición, en
|
|
113
|
+
* cualquier tipo de objeto declarado, y demuestra cero. `Read` exige un
|
|
114
|
+
* filtro de objeto (un `Read` solo por `user` es un 400 del servidor), así
|
|
115
|
+
* que se recorre cada tipo declarado (`group` + los del consumidor) con
|
|
116
|
+
* `Read({ user, object: '<type>:' })`.
|
|
117
|
+
*/
|
|
118
|
+
purgeSubject(subject: RelSubject, partition: ScopeRef): Promise<void>;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=openfga_relations_driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openfga_relations_driver.d.ts","sourceRoot":"","sources":["../../../src/drivers/openfga_relations_driver.ts"],"names":[],"mappings":"AAiDA,OAAO,KAAK,EACV,SAAS,EACT,UAAU,EACV,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EAEZ,iBAAiB,EACjB,eAAe,EACf,2BAA2B,EAC3B,oBAAoB,EACpB,QAAQ,EAET,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAExD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAA;AAE9E,eAAO,MAAM,kBAAkB,OAAQ,CAAA;AAgCvC,MAAM,WAAW,6BAA6B;IAC5C,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,wFAAwF;IACxF,WAAW,EAAE,aAAa,CAAA;IAC1B,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,+FAA+F;IAC/F,WAAW,CAAC,EAAE,oBAAoB,GAAG,kBAAkB,CAAA;IACvD;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,uEAAuE;IACvE,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;CACzC;AAED,qBAAa,sBAAuB,YAAW,eAAe;;IAC5D;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,QAAQ,CAAC,YAAY,EAAE,2BAA2B,CAOhD;IAEF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IASvC,QAAQ,CAAC,WAAW;;MAA2B;gBAEnC,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,6BAA6B;IA+GrE,MAAM,CACV,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,QAAQ,EACnB,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC,IAAI,CAAC;IAYV,QAAQ,CACZ,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,QAAQ,EACnB,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC,IAAI,CAAC;IAahB,0EAA0E;IACpE,KAAK,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAW5G;;;;;;;;;;OAUG;IACG,WAAW,CACf,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,QAAQ,EACnB,KAAK,CAAC,EAAE,YAAY,GACnB,OAAO,CAAC,mBAAmB,CAAC;IAuB/B;;;;;OAKG;IACG,YAAY,CAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,QAAQ,EACnB,KAAK,CAAC,EAAE,YAAY,GACnB,OAAO,CAAC,oBAAoB,CAAC;IAchC;;;;;;;OAOG;IACG,SAAS,IAAI,OAAO,CAAC,oBAAoB,CAAC;IAYhD;;;;;;;;;;;;;OAaG;IACG,kBAAkB,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA6B/F;;;;;;OAMG;IACG,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAUxE;;;;;;OAMG;IACG,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;CA+G5E"}
|
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Driver `openfga` del puerto `RelationsDriver` — ReBAC sobre el MISMO store y
|
|
3
|
+
* `modelId` que el driver `facts` de roles (Fase 4, lote 4-4).
|
|
4
|
+
*
|
|
5
|
+
* Store COMPARTIDO (decisión del dueño / juez §2): las relaciones ReBAC viven
|
|
6
|
+
* en el modelo FUSIONADO (`facts` + `group` + los tipos de objeto del
|
|
7
|
+
* consumidor), así que `relate`/`unrelate` son `Write`/delete de tuplas del
|
|
8
|
+
* mismo store, `check` es UN solo `Check` (el modelo resuelve includes +
|
|
9
|
+
* usersets del lado del servidor) y `list*` van por `ListObjects`/`Read`.
|
|
10
|
+
*
|
|
11
|
+
* **La partición va en el ID del objeto y del userset**, no en el modelo:
|
|
12
|
+
* `document:<scopeKey(partition)>|<uuid>`, `group:<scopeKey(partition)>|<uuid>#member`.
|
|
13
|
+
* El cruce de particiones se corta por comparación de string —aquí NO hay
|
|
14
|
+
* trigger como en `database`, así que F-05 (en el manager) + la comparación de
|
|
15
|
+
* string son la ÚNICA defensa de tenant—. El id lleva DOS `|` cuando la
|
|
16
|
+
* partición es un scope no-raíz (`document:unit|<partUuid>|<objUuid>`), así que
|
|
17
|
+
* el parseo es CANÓNICO desde la DERECHA (⚪5, el mismo cuidado que
|
|
18
|
+
* `parseBindingId`): partición = todo menos el ÚLTIMO segmento; el id del
|
|
19
|
+
* objeto es el último y no contiene `|`.
|
|
20
|
+
*
|
|
21
|
+
* **La frontera del 🔴 (F-05) NO vive aquí**: la cierra el `RelationsManager`
|
|
22
|
+
* ANTES de tocar el driver (un `object.type` no declarado ⇒ 422) junto con ⚪4
|
|
23
|
+
* (un tipo reservado no se puede declarar). Si a este driver se le llama en
|
|
24
|
+
* DIRECTO con `object.type: 'role_binding'` (la salida `manager.driver()`, de
|
|
25
|
+
* plataforma), compondría el id de un binding real y escalaría — por eso el
|
|
26
|
+
* caso-exploit del auditor se cierra en el manager, y el runner publica el
|
|
27
|
+
* caso para que un driver de terceros que no lo cumpla NO pase el contrato.
|
|
28
|
+
*
|
|
29
|
+
* Pureza: vive detrás del subpath `@jantstack/adonis-authz/openfga`
|
|
30
|
+
* (`src/openfga.ts`), como el driver `facts` de roles: es lo único que puede
|
|
31
|
+
* tocar `@openfga/sdk` (peer opcional). La abstracción no filtra: ningún error
|
|
32
|
+
* del SDK escapa (todo va por `#guard`, que clasifica a 503/timeout).
|
|
33
|
+
*/
|
|
34
|
+
import { OpenFgaClient, ConsistencyPreference, ClientWriteRequestOnMissingDeletes, ClientWriteRequestOnDuplicateWrites, } from '@openfga/sdk';
|
|
35
|
+
import { AuthorizationBackendError, AuthorizationBackendTimeoutError, InvalidIdentityError, PurgeIncompleteError, UnsupportedOperationError, } from '../errors.js';
|
|
36
|
+
import { assertScope, assertSubject, assertRelationId, scopeKey, scopeSpellings } from '../identity.js';
|
|
37
|
+
import { isRelUserset } from '../types.js';
|
|
38
|
+
import { assertFgaObjectId, FACTS_GROUP_TYPE } from './openfga_facts.js';
|
|
39
|
+
export const DEFAULT_TIMEOUT_MS = 5_000;
|
|
40
|
+
/** Tope de operaciones por `Write` en FGA (`exceeded_entity_limit` a partir de 100). */
|
|
41
|
+
const WRITE_BATCH_SIZE = 100;
|
|
42
|
+
/** Tamaño de página de `Read` (máximo del servidor). */
|
|
43
|
+
const READ_PAGE_SIZE = 100;
|
|
44
|
+
/**
|
|
45
|
+
* Cota de páginas de una enumeración por `Read`. Un `continuation_token` que
|
|
46
|
+
* no avanza (servidor roto, proxy, caché) sería un bucle que ningún deadline
|
|
47
|
+
* corta (el deadline es por llamada). Mismo patrón que el driver de roles.
|
|
48
|
+
*/
|
|
49
|
+
const MAX_READ_PAGES = 10_000;
|
|
50
|
+
/**
|
|
51
|
+
* El tope de `ListObjects` del servidor por defecto (`OPENFGA_LIST_OBJECTS_MAX_RESULTS`).
|
|
52
|
+
* `ListObjects` NO devuelve señal de truncado ni `continuation_token`: corta al
|
|
53
|
+
* tope y calla. La única forma honesta de detectar el corte es comparar el
|
|
54
|
+
* número de resultados con el tope CONFIGURADO del servidor —de ahí la opción
|
|
55
|
+
* `listObjectsMaxResults`—: si vuelven `>= tope`, no se puede prometer que la
|
|
56
|
+
* lista esté completa ⇒ `truncated: true` (lección S16/L0.7: nunca una lista
|
|
57
|
+
* parcial MUDA). Ponerlo por debajo del tope real del servidor daría un
|
|
58
|
+
* truncado FALSO (el servidor devolvió todo); por encima, se perdería el corte.
|
|
59
|
+
*/
|
|
60
|
+
const DEFAULT_LIST_OBJECTS_MAX = 1_000;
|
|
61
|
+
/** Ignora duplicados: las tuplas de relación no llevan condición (idénticas por construcción). */
|
|
62
|
+
const IGNORE_DUPLICATE_WRITES = {
|
|
63
|
+
conflict: { onDuplicateWrites: ClientWriteRequestOnDuplicateWrites.Ignore },
|
|
64
|
+
};
|
|
65
|
+
/** Ignora deletes de tuplas ya ausentes (re-unrelate no-op seguro, invariante 6). */
|
|
66
|
+
const IGNORE_MISSING_DELETES = {
|
|
67
|
+
conflict: { onMissingDeletes: ClientWriteRequestOnMissingDeletes.Ignore },
|
|
68
|
+
};
|
|
69
|
+
export class OpenFgaRelationsDriver {
|
|
70
|
+
/**
|
|
71
|
+
* Lo que declara (cada valor tiene su cara en `runRelationsDriverContract`):
|
|
72
|
+
* - `singleCheckRelations: true`: `check` es UN solo `Check` (el modelo
|
|
73
|
+
* resuelve includes + usersets del lado del servidor).
|
|
74
|
+
* - `listObjectsInherited: false`: `list*` no abren el subárbol de
|
|
75
|
+
* particiones (invariante 7); `ListObjects` sí resuelve la derivación del
|
|
76
|
+
* modelo (includes/usersets), que es «directos + derivados», no herencia
|
|
77
|
+
* de scopes.
|
|
78
|
+
* - `usersetSubjects: true`: `listSubjects` (`Read`) trae los usersets
|
|
79
|
+
* directos (`group#member`) junto con los holders.
|
|
80
|
+
* - `membersOfNative: false`: la membresía TRANSITIVA sería `ListUsers`, que
|
|
81
|
+
* trunca al tope del servidor; se declara 500 `E_AUTHZ_UNSUPPORTED`, jamás
|
|
82
|
+
* un userset enumerado a medias (par de `purgeRole` de la 3b).
|
|
83
|
+
* - `enumerateRelations: true` (4-5): es ORIGEN de `authz:reconcile` de
|
|
84
|
+
* relaciones — lee el store ENTERO (`Read({})`, la única forma de ver todo
|
|
85
|
+
* sin filtro por user u objeto: un `Read` por tipo-solo sin user es un 400)
|
|
86
|
+
* y devuelve SOLO las tuplas de relación de la partición (tipo declarado o
|
|
87
|
+
* `group`), descartando las de `facts` (scope/role/role_binding).
|
|
88
|
+
* - `listObjectsTruncation: true`: `ListObjects` trunca al tope del servidor
|
|
89
|
+
* y este driver lo SEÑALA (medido contra el `:8103` de tope 3).
|
|
90
|
+
*/
|
|
91
|
+
capabilities = Object.freeze({
|
|
92
|
+
singleCheckRelations: true,
|
|
93
|
+
listObjectsInherited: false,
|
|
94
|
+
usersetSubjects: true,
|
|
95
|
+
membersOfNative: false,
|
|
96
|
+
enumerateRelations: true,
|
|
97
|
+
listObjectsTruncation: true,
|
|
98
|
+
});
|
|
99
|
+
client;
|
|
100
|
+
#config;
|
|
101
|
+
#holderTypes;
|
|
102
|
+
#fgaToMorph;
|
|
103
|
+
#timeoutMs;
|
|
104
|
+
#consistency;
|
|
105
|
+
#listObjectsMax;
|
|
106
|
+
#logger;
|
|
107
|
+
diagnostics = { unparseableTuples: 0 };
|
|
108
|
+
constructor(config, options) {
|
|
109
|
+
this.#config = config;
|
|
110
|
+
this.#holderTypes = options.holderTypes;
|
|
111
|
+
this.#fgaToMorph = Object.fromEntries(Object.entries(options.holderTypes).map(([morph, fga]) => [fga, morph]));
|
|
112
|
+
this.#timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
113
|
+
this.#consistency =
|
|
114
|
+
options.consistency === 'minimize_latency'
|
|
115
|
+
? ConsistencyPreference.MinimizeLatency
|
|
116
|
+
: ConsistencyPreference.HigherConsistency;
|
|
117
|
+
this.#listObjectsMax = options.listObjectsMaxResults ?? DEFAULT_LIST_OBJECTS_MAX;
|
|
118
|
+
this.#logger = options.logger ?? console;
|
|
119
|
+
this.client = new OpenFgaClient({
|
|
120
|
+
apiUrl: options.apiUrl,
|
|
121
|
+
storeId: options.storeId,
|
|
122
|
+
authorizationModelId: options.modelId,
|
|
123
|
+
baseOptions: { timeout: this.#timeoutMs },
|
|
124
|
+
retryParams: { maxRetry: 0 },
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/* ── Clasificación de fallos (la abstracción no filtra) ─────────────────── */
|
|
128
|
+
async #guard(operation, fn) {
|
|
129
|
+
try {
|
|
130
|
+
return await fn();
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
// Un error del paquete (422/500 ya clasificado) se propaga tal cual.
|
|
134
|
+
if (error instanceof InvalidIdentityError || error instanceof PurgeIncompleteError)
|
|
135
|
+
throw error;
|
|
136
|
+
if (isTimeoutLike(error)) {
|
|
137
|
+
throw new AuthorizationBackendTimeoutError('openfga-relations', operation, this.#timeoutMs, error);
|
|
138
|
+
}
|
|
139
|
+
throw new AuthorizationBackendError('openfga-relations', operation, error);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/* ── Composición y parseo de ids (⚪5: partición por string en el id) ────── */
|
|
143
|
+
/** `<type>:<scopeKey(partition)>|<objectUuid>`. */
|
|
144
|
+
#objectId(objectType, partitionKey, objectUuid) {
|
|
145
|
+
// R-16 (defensa en profundidad, paridad con `database`): el `object.id` con
|
|
146
|
+
// la gramática estricta ANTES de componer. Un `|`/`#`/`:`/espacio dentro se
|
|
147
|
+
// escribía (solo se medía la longitud) y luego se perdía en el parseo por
|
|
148
|
+
// el último `|` —invisible en enumeración y `reconcile`—. `manager.driver()`
|
|
149
|
+
// salta el manager, así que el driver aplica la MISMA regla que él.
|
|
150
|
+
assertRelationId(`el id del objeto '${objectType}'`, objectUuid);
|
|
151
|
+
const id = `${objectType}:${partitionKey}|${objectUuid}`;
|
|
152
|
+
assertFgaObjectId(objectType, id);
|
|
153
|
+
return id;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* El `user` FGA de un sujeto: holder ⇒ `<fgaType>:<uuid>`; userset ⇒
|
|
157
|
+
* `<type>:<scopeKey(partition)>|<objUuid>#<relation>`. El userset comparte la
|
|
158
|
+
* partición de la tupla (el manager lo exige).
|
|
159
|
+
*/
|
|
160
|
+
#subjectUser(subject, partitionKey) {
|
|
161
|
+
if (isRelUserset(subject)) {
|
|
162
|
+
const object = this.#objectId(subject.object.type, partitionKey, subject.object.id);
|
|
163
|
+
return `${object}#${subject.relation}`;
|
|
164
|
+
}
|
|
165
|
+
const fgaType = this.#holderTypes[subject.type];
|
|
166
|
+
if (!fgaType) {
|
|
167
|
+
throw new InvalidIdentityError(`Holder type '${subject.type}' no está en holderTypes del driver openfga de relaciones ` +
|
|
168
|
+
`(declarados: ${Object.keys(this.#holderTypes).join(', ') || 'ninguno'}).`);
|
|
169
|
+
}
|
|
170
|
+
return `${fgaType}:${subject.uuid}`;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* **Parseo CANÓNICO del id de un objeto de relación** (⚪5): a partir de
|
|
174
|
+
* `<type>:<scopeKey>|<objUuid>`, separa `type` (antes del primer `:`),
|
|
175
|
+
* `partitionKey` (todo menos el ÚLTIMO segmento tras el `:`) y `objectUuid`
|
|
176
|
+
* (el último segmento, que no contiene `|`). Es el MISMO parseo-desde-la-
|
|
177
|
+
* derecha que `parseBindingId`: `lastIndexOf('|')` corta el objeto de la
|
|
178
|
+
* clave de partición (que tiene 1 parte `app` o 2 `<tipo>|<uuid>`). `null` si
|
|
179
|
+
* el id no tiene la forma que este driver escribe.
|
|
180
|
+
*/
|
|
181
|
+
#parseObjectId(fullId) {
|
|
182
|
+
const colon = fullId.indexOf(':');
|
|
183
|
+
if (colon <= 0)
|
|
184
|
+
return null;
|
|
185
|
+
const type = fullId.slice(0, colon);
|
|
186
|
+
const rest = fullId.slice(colon + 1);
|
|
187
|
+
const cut = rest.lastIndexOf('|');
|
|
188
|
+
if (cut < 0)
|
|
189
|
+
return null;
|
|
190
|
+
const partitionKey = rest.slice(0, cut);
|
|
191
|
+
const objectUuid = rest.slice(cut + 1);
|
|
192
|
+
if (!partitionKey || !objectUuid)
|
|
193
|
+
return null;
|
|
194
|
+
return { type, partitionKey, objectUuid };
|
|
195
|
+
}
|
|
196
|
+
/** Un `user` del store de vuelta a `RelSubject`: userset (`…#rel`) o holder (`<fga>:<uuid>`). */
|
|
197
|
+
#userToSubject(user) {
|
|
198
|
+
const hash = user.indexOf('#');
|
|
199
|
+
if (hash >= 0) {
|
|
200
|
+
const parsed = this.#parseObjectId(user.slice(0, hash));
|
|
201
|
+
const relation = user.slice(hash + 1);
|
|
202
|
+
if (!parsed || !relation)
|
|
203
|
+
return null;
|
|
204
|
+
return { object: { type: parsed.type, id: parsed.objectUuid }, relation };
|
|
205
|
+
}
|
|
206
|
+
const colon = user.indexOf(':');
|
|
207
|
+
if (colon <= 0)
|
|
208
|
+
return null;
|
|
209
|
+
const morph = this.#fgaToMorph[user.slice(0, colon)];
|
|
210
|
+
const uuid = user.slice(colon + 1);
|
|
211
|
+
if (!morph || !uuid || uuid === '*' || uuid.includes('|'))
|
|
212
|
+
return null;
|
|
213
|
+
return { type: morph, uuid };
|
|
214
|
+
}
|
|
215
|
+
/* ── Escrituras ─────────────────────────────────────────────────────────── */
|
|
216
|
+
async relate(subject, relation, object, partition, _options) {
|
|
217
|
+
assertScope(partition);
|
|
218
|
+
const partitionKey = scopeKey(partition);
|
|
219
|
+
const objectId = this.#objectId(object.type, partitionKey, object.id);
|
|
220
|
+
const user = this.#subjectUser(subject, partitionKey);
|
|
221
|
+
await this.#guard('relate', () =>
|
|
222
|
+
// Idempotente (invariante 6): un `Write` de una tupla que ya está es un
|
|
223
|
+
// duplicado idéntico (sin condición), así que se ignora.
|
|
224
|
+
this.client.write({ writes: [{ user, relation, object: objectId }] }, IGNORE_DUPLICATE_WRITES));
|
|
225
|
+
}
|
|
226
|
+
async unrelate(subject, relation, object, partition, _options) {
|
|
227
|
+
assertScope(partition);
|
|
228
|
+
const partitionKey = scopeKey(partition);
|
|
229
|
+
const objectId = this.#objectId(object.type, partitionKey, object.id);
|
|
230
|
+
const user = this.#subjectUser(subject, partitionKey);
|
|
231
|
+
await this.#guard('unrelate', () =>
|
|
232
|
+
// Re-unrelate no-op seguro: borrar una tupla ausente se ignora.
|
|
233
|
+
this.client.write({ deletes: [{ user, relation, object: objectId }] }, IGNORE_MISSING_DELETES));
|
|
234
|
+
}
|
|
235
|
+
/* ── Lecturas ───────────────────────────────────────────────────────────── */
|
|
236
|
+
/** `check` = UN solo `Check` (el modelo resuelve includes + usersets). */
|
|
237
|
+
async check(subject, relation, object, partition) {
|
|
238
|
+
assertScope(partition);
|
|
239
|
+
const partitionKey = scopeKey(partition);
|
|
240
|
+
const objectId = this.#objectId(object.type, partitionKey, object.id);
|
|
241
|
+
const user = this.#subjectUser(subject, partitionKey);
|
|
242
|
+
const response = await this.#guard('check', () => this.client.check({ user, relation, object: objectId }, { consistency: this.#consistency }));
|
|
243
|
+
return response.allowed === true;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* `listObjects` = `ListObjects` (resuelve includes + usersets del lado del
|
|
247
|
+
* servidor) + FILTRO por partición + señal de TRUNCADO. `ListObjects` corta
|
|
248
|
+
* al tope del servidor sin `continuation_token` ni bandera, así que el
|
|
249
|
+
* truncado se detecta comparando el número de resultados CRUDOS con el tope
|
|
250
|
+
* configurado (`listObjectsMaxResults`): `>= tope` ⇒ no se puede prometer la
|
|
251
|
+
* lista completa ⇒ `truncated: true`. El filtro por partición se aplica
|
|
252
|
+
* DESPUÉS (los ids llevan la partición), así que en un store con varias
|
|
253
|
+
* particiones el tope se consume entre todas — otra razón para señalar el
|
|
254
|
+
* truncado y no callar (documentado en el README).
|
|
255
|
+
*/
|
|
256
|
+
async listObjects(subject, relation, objectType, partition, _page) {
|
|
257
|
+
assertScope(partition);
|
|
258
|
+
const partitionKey = scopeKey(partition);
|
|
259
|
+
const user = this.#subjectUser(subject, partitionKey);
|
|
260
|
+
const response = await this.#guard('listObjects', () => this.client.listObjects({ user, relation, type: objectType }, { consistency: this.#consistency }));
|
|
261
|
+
const raw = response.objects ?? [];
|
|
262
|
+
const truncated = raw.length >= this.#listObjectsMax;
|
|
263
|
+
const objects = [];
|
|
264
|
+
for (const full of raw) {
|
|
265
|
+
const parsed = this.#parseObjectId(full);
|
|
266
|
+
if (!parsed || parsed.type !== objectType) {
|
|
267
|
+
this.#warnUnparseable('listObjects', full);
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
if (parsed.partitionKey !== partitionKey)
|
|
271
|
+
continue; // otra partición: no cruza
|
|
272
|
+
objects.push({ type: objectType, id: parsed.objectUuid });
|
|
273
|
+
}
|
|
274
|
+
objects.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
275
|
+
return truncated ? { objects, truncated: true } : { objects };
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* `listSubjects` = `Read` por `(object, relation)` — hechos DIRECTOS del
|
|
279
|
+
* relation EXACTO (invariante 7): ni transitivo (eso es `membersOf`) ni
|
|
280
|
+
* derivado por includes. `usersetSubjects: true` ⇒ los usersets
|
|
281
|
+
* (`group#member`) salen junto con los holders.
|
|
282
|
+
*/
|
|
283
|
+
async listSubjects(relation, object, partition, _page) {
|
|
284
|
+
assertScope(partition);
|
|
285
|
+
const partitionKey = scopeKey(partition);
|
|
286
|
+
const objectId = this.#objectId(object.type, partitionKey, object.id);
|
|
287
|
+
const tuples = await this.#readAll('listSubjects', { object: objectId, relation });
|
|
288
|
+
const subjects = [];
|
|
289
|
+
for (const t of tuples) {
|
|
290
|
+
const subject = this.#userToSubject(t.user);
|
|
291
|
+
if (subject)
|
|
292
|
+
subjects.push(subject);
|
|
293
|
+
else
|
|
294
|
+
this.#warnUnparseable('listSubjects', t.user);
|
|
295
|
+
}
|
|
296
|
+
return { subjects };
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* **`membersOf` ⇒ 500 `E_AUTHZ_UNSUPPORTED`** (cara `whenFalse`): la
|
|
300
|
+
* membresía TRANSITIVA de un grupo sería `ListUsers`, que trunca al tope del
|
|
301
|
+
* servidor sin señal fiable. No hay userset transitivo enumerable aquí; se
|
|
302
|
+
* dice con 500 nombrándolo, jamás un userset a medias. Es el análogo del par
|
|
303
|
+
* `purgeRole` de la 3b. (El método existe en el prototipo para que el manager
|
|
304
|
+
* lo despache, pero la capacidad `membersOfNative: false` lo corta antes.)
|
|
305
|
+
*/
|
|
306
|
+
async membersOf() {
|
|
307
|
+
throw new UnsupportedOperationError('membersOf', 'la membresía transitiva de un grupo', 'openfga', `En 'openfga' la transitiva sería 'ListUsers', que trunca al tope del servidor sin señal fiable. ` +
|
|
308
|
+
`Usa el driver 'database' (CTE recursiva) o 'listSubjects' para los hechos directos.`);
|
|
309
|
+
}
|
|
310
|
+
/* ── ORIGEN de reconcile (4-5): las tuplas de relación de la partición ──── */
|
|
311
|
+
/**
|
|
312
|
+
* **`enumerateRelations` — el ORIGEN de `authz:reconcile` de relaciones**
|
|
313
|
+
* (4-5). Lee el store ENTERO (`Read({})`) —la única forma de ver todo sin un
|
|
314
|
+
* filtro por `user` u `object`, que un `Read` por tipo-solo sin user
|
|
315
|
+
* rechazaría con 400— y devuelve SOLO las tuplas de relación de la partición
|
|
316
|
+
* pedida: tipo `group` o un tipo declarado en la config, DESCARTANDO las de
|
|
317
|
+
* `facts` (`scope`/`role`/`role_binding`, que no llevan la partición en el id
|
|
318
|
+
* con la forma `<key>|<uuid>` de relaciones —o cuyo tipo no está declarado—).
|
|
319
|
+
*
|
|
320
|
+
* `truncated`/paginación: `enumerateRelations` agota el `Read` (exhaustivo,
|
|
321
|
+
* como `listSubjects`/`purge*`), así que devuelve TODO en una página sin
|
|
322
|
+
* cursor —el reconcile itera hasta que no hay cursor—. Es el ORIGEN de una
|
|
323
|
+
* migración: una tupla que no llegara aquí desaparecería sin rastro.
|
|
324
|
+
*/
|
|
325
|
+
async enumerateRelations(partition, _page) {
|
|
326
|
+
assertScope(partition);
|
|
327
|
+
const partitionKey = scopeKey(partition);
|
|
328
|
+
const relationTypes = new Set([FACTS_GROUP_TYPE, ...this.#config.objectTypes.map((t) => t.type)]);
|
|
329
|
+
const all = await this.#readAll('enumerateRelations', {});
|
|
330
|
+
const tuples = [];
|
|
331
|
+
for (const key of all) {
|
|
332
|
+
const parsed = this.#parseObjectId(key.object);
|
|
333
|
+
// No es una tupla de relación (facts: scope/role/role_binding, o un tipo
|
|
334
|
+
// no declarado): no la migra este puerto.
|
|
335
|
+
if (!parsed || !relationTypes.has(parsed.type))
|
|
336
|
+
continue;
|
|
337
|
+
if (parsed.partitionKey !== partitionKey)
|
|
338
|
+
continue; // otra partición: no cruza
|
|
339
|
+
const subject = this.#userToSubject(key.user);
|
|
340
|
+
if (!subject) {
|
|
341
|
+
this.#warnUnparseable('enumerateRelations', key.user);
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
tuples.push({
|
|
345
|
+
subject,
|
|
346
|
+
relation: key.relation,
|
|
347
|
+
object: { type: parsed.type, id: parsed.objectUuid },
|
|
348
|
+
partition,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
return { tuples };
|
|
352
|
+
}
|
|
353
|
+
/* ── Purga (invariante 11): borra y DEMUESTRA cero, o lanza ─────────────── */
|
|
354
|
+
/**
|
|
355
|
+
* Borra TODAS las tuplas del objeto (cualquier relación) y demuestra cero.
|
|
356
|
+
* Barre las DOS ortografías del uuid de partición (🟡2, paridad con
|
|
357
|
+
* `database`): un motor que funda `aaa…` con `aaa-…` dejaría la fila del
|
|
358
|
+
* alias concediendo tras una purga «exitosa». Si tras borrar quedan tuplas
|
|
359
|
+
* ⇒ 500 `E_AUTHZ_PURGE_INCOMPLETE`.
|
|
360
|
+
*/
|
|
361
|
+
async purgeObject(object, partition) {
|
|
362
|
+
assertScope(partition);
|
|
363
|
+
const objectIds = this.#partitionSpellings(partition).map((key) => this.#objectId(object.type, key, object.id));
|
|
364
|
+
for (const objectId of objectIds) {
|
|
365
|
+
await this.#purgeByFilter('purgeObject', { object: objectId }, `objeto ${objectId}`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Borra TODAS las tuplas cuyo SUJETO es este subject en la partición, en
|
|
370
|
+
* cualquier tipo de objeto declarado, y demuestra cero. `Read` exige un
|
|
371
|
+
* filtro de objeto (un `Read` solo por `user` es un 400 del servidor), así
|
|
372
|
+
* que se recorre cada tipo declarado (`group` + los del consumidor) con
|
|
373
|
+
* `Read({ user, object: '<type>:' })`.
|
|
374
|
+
*/
|
|
375
|
+
async purgeSubject(subject, partition) {
|
|
376
|
+
assertScope(partition);
|
|
377
|
+
if (!isRelUserset(subject))
|
|
378
|
+
assertSubject(subject);
|
|
379
|
+
const partitionKeys = this.#partitionSpellings(partition);
|
|
380
|
+
const types = [FACTS_GROUP_TYPE, ...this.#config.objectTypes.map((t) => t.type)];
|
|
381
|
+
for (const partitionKey of partitionKeys) {
|
|
382
|
+
const user = this.#subjectUser(subject, partitionKey);
|
|
383
|
+
for (const type of types) {
|
|
384
|
+
await this.#purgeByFilter('purgeSubject', { user, object: `${type}:` }, `sujeto ${user} en '${type}'`);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
/** Lee por filtro, borra en lotes, y RE-LEE para demostrar cero (o lanza). */
|
|
389
|
+
async #purgeByFilter(operation, filter, what) {
|
|
390
|
+
const keys = await this.#readAll(operation, filter);
|
|
391
|
+
for (let i = 0; i < keys.length; i += WRITE_BATCH_SIZE) {
|
|
392
|
+
await this.#guard(operation, () => this.client.deleteTuples(keys.slice(i, i + WRITE_BATCH_SIZE).map((k) => ({ user: k.user, relation: k.relation, object: k.object })), IGNORE_MISSING_DELETES));
|
|
393
|
+
}
|
|
394
|
+
if (keys.length === 0)
|
|
395
|
+
return;
|
|
396
|
+
// Demostración de cero: re-lee tras borrar (invariante 11).
|
|
397
|
+
const residue = await this.#readAll(operation, filter);
|
|
398
|
+
if (residue.length > 0) {
|
|
399
|
+
throw new PurgeIncompleteError(`${operation}: quedan ${residue.length} tuplas de ${what} tras el borrado ` +
|
|
400
|
+
`(${residue.slice(0, 3).map((k) => `${k.user}#${k.relation}@${k.object}`).join('; ')}). ` +
|
|
401
|
+
`No se confirma la purga.`);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
/* ── Helpers ────────────────────────────────────────────────────────────── */
|
|
405
|
+
/** Las dos ortografías del uuid de partición, como claves de scope (🟡2). */
|
|
406
|
+
#partitionSpellings(partition) {
|
|
407
|
+
return [...new Set(scopeSpellings(partition).map((s) => scopeKey(s)))];
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* TODAS las tuplas que casan con el filtro, paginando `Read` hasta agotar el
|
|
411
|
+
* `continuation_token`. `Read` no tiene tope de resultados (a diferencia de
|
|
412
|
+
* `ListObjects`), así que es exhaustivo — por eso las purgas y `listSubjects`
|
|
413
|
+
* van por aquí, no por `ListObjects`.
|
|
414
|
+
*/
|
|
415
|
+
async #readAll(operation, filter) {
|
|
416
|
+
const keys = [];
|
|
417
|
+
let continuationToken;
|
|
418
|
+
const seenTokens = new Set();
|
|
419
|
+
let pages = 0;
|
|
420
|
+
do {
|
|
421
|
+
const response = await this.#guard(operation, () => this.client.read(filter, {
|
|
422
|
+
pageSize: READ_PAGE_SIZE,
|
|
423
|
+
continuationToken,
|
|
424
|
+
consistency: this.#consistency,
|
|
425
|
+
}));
|
|
426
|
+
pages += 1;
|
|
427
|
+
for (const tuple of response.tuples ?? []) {
|
|
428
|
+
const key = tuple?.key;
|
|
429
|
+
if (!key?.user || !key?.relation || !key?.object) {
|
|
430
|
+
this.#warnUnparseable(operation, JSON.stringify(key ?? null));
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
keys.push({ user: key.user, relation: key.relation, object: key.object });
|
|
434
|
+
}
|
|
435
|
+
continuationToken = response.continuation_token || undefined;
|
|
436
|
+
if (continuationToken) {
|
|
437
|
+
if (seenTokens.has(continuationToken)) {
|
|
438
|
+
throw new AuthorizationBackendError('openfga-relations', operation, new Error(`el continuation_token se repite (página ${pages}); el servidor no avanza`));
|
|
439
|
+
}
|
|
440
|
+
if (pages >= MAX_READ_PAGES) {
|
|
441
|
+
throw new AuthorizationBackendError('openfga-relations', operation, new Error(`más de ${MAX_READ_PAGES} páginas sin agotar el Read`));
|
|
442
|
+
}
|
|
443
|
+
seenTokens.add(continuationToken);
|
|
444
|
+
}
|
|
445
|
+
} while (continuationToken);
|
|
446
|
+
return keys;
|
|
447
|
+
}
|
|
448
|
+
#warnUnparseable(operation, detail) {
|
|
449
|
+
this.diagnostics.unparseableTuples += 1;
|
|
450
|
+
this.#logger.warn(`authz(openfga-relations): tupla no parseable en ${operation} (${detail}); ` +
|
|
451
|
+
`se ignora en la enumeración (total: ${this.diagnostics.unparseableTuples})`);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
/** ¿El error huele a timeout de red/axios? (mismo criterio que el driver de roles). */
|
|
455
|
+
function isTimeoutLike(error) {
|
|
456
|
+
let current = error;
|
|
457
|
+
for (let depth = 0; current && depth < 6; depth++) {
|
|
458
|
+
const code = String(current.code ?? '');
|
|
459
|
+
if (code === 'ECONNABORTED' || code === 'ETIMEDOUT' || /timeout/i.test(String(current.message ?? ''))) {
|
|
460
|
+
return true;
|
|
461
|
+
}
|
|
462
|
+
current = current.cause;
|
|
463
|
+
}
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
//# sourceMappingURL=openfga_relations_driver.js.map
|