@fiado/type-kit 3.70.0 → 3.72.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/_test_/unit/cognitoBackofficeConnector/dtos/CreateUserRequest.test.ts +13 -0
- package/_test_/unit/platformRbac/dtos/effectivePermissions.test.ts +22 -0
- package/_test_/unit/platformRbac/enums/__snapshots__/permissionBits.test.ts.snap +98 -0
- package/_test_/unit/platformRbac/enums/permissionBits.test.ts +36 -0
- package/bin/cognitoBackofficeConnector/dtos/CreateUserRequest.d.ts +2 -2
- package/bin/cognitoBackofficeConnector/dtos/CreateUserRequest.js +2 -2
- package/bin/platformRbac/dtos/AuthContext.d.ts +6 -0
- package/bin/platformRbac/dtos/CreateTenantRequest.d.ts +2 -0
- package/bin/platformRbac/dtos/CreateTenantRequest.js +7 -0
- package/bin/platformRbac/dtos/EffectivePermissionsResponse.d.ts +8 -0
- package/bin/platformRbac/dtos/EffectivePermissionsResponse.js +2 -0
- package/bin/platformRbac/enums/Permission.d.ts +37 -1
- package/bin/platformRbac/enums/Permission.js +164 -2
- package/bin/platformRbac/enums/TokenValidationMode.d.ts +13 -0
- package/bin/platformRbac/enums/TokenValidationMode.js +17 -0
- package/bin/platformRbac/index.d.ts +3 -1
- package/bin/platformRbac/index.js +9 -4
- package/package.json +1 -1
- package/src/cognitoBackofficeConnector/dtos/CreateUserRequest.ts +5 -2
- package/src/platformRbac/dtos/AuthContext.ts +6 -0
- package/src/platformRbac/dtos/CreateTenantRequest.ts +3 -1
- package/src/platformRbac/dtos/EffectivePermissionsResponse.ts +9 -0
- package/src/platformRbac/enums/Permission.ts +160 -1
- package/src/platformRbac/enums/TokenValidationMode.ts +13 -0
- package/src/platformRbac/index.ts +12 -4
|
@@ -38,6 +38,19 @@ describe('CreateUserRequest', () => {
|
|
|
38
38
|
expect(errors.some(e => e.property === 'tenantId')).toBe(true);
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
+
// userPoolId + region pasan a ser OPCIONALES: el front del alta de usuario PLATFORM deja de
|
|
42
|
+
// mandarlos y el backend (platform-rbac-business) los resuelve de la config del tenant 'platform'.
|
|
43
|
+
// Quedan en el DTO por compatibilidad con los demás callers del connector que SÍ los proveen.
|
|
44
|
+
it('valida sin userPoolId ni region (alta platform — el backend los resuelve)', async () => {
|
|
45
|
+
const dto = plainToInstance(CreateUserRequest, {
|
|
46
|
+
email: 'user@acme.com',
|
|
47
|
+
tenantId: 'platform',
|
|
48
|
+
});
|
|
49
|
+
const errors = await validate(dto);
|
|
50
|
+
expect(errors.some(e => e.property === 'userPoolId')).toBe(false);
|
|
51
|
+
expect(errors.some(e => e.property === 'region')).toBe(false);
|
|
52
|
+
});
|
|
53
|
+
|
|
41
54
|
it('preserva los campos opcionales legítimos', async () => {
|
|
42
55
|
const dto = plainToInstance(CreateUserRequest, {
|
|
43
56
|
...valid,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import type { AuthContext, EffectivePermissionsResponse } from '../../../../src/platformRbac/index';
|
|
3
|
+
|
|
4
|
+
it('AuthContext acepta los campos opcionales del token-as-cache', () => {
|
|
5
|
+
const ctx: AuthContext = {
|
|
6
|
+
cognitoSub: 's',
|
|
7
|
+
tenantId: 't',
|
|
8
|
+
email: 'e',
|
|
9
|
+
roleAssignments: [],
|
|
10
|
+
permissions: [],
|
|
11
|
+
resolvedAt: 'now',
|
|
12
|
+
permBits: 'AAA',
|
|
13
|
+
permVer: 1,
|
|
14
|
+
permsEpoch: 3,
|
|
15
|
+
};
|
|
16
|
+
expect(ctx.permVer).toBe(1);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('EffectivePermissionsResponse tiene permissions + roleAssignments + epoch', () => {
|
|
20
|
+
const r: EffectivePermissionsResponse = { permissions: [], roleAssignments: [], permsEpoch: 0 };
|
|
21
|
+
expect(r.permsEpoch).toBe(0);
|
|
22
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
|
2
|
+
|
|
3
|
+
exports[`PERMISSION_BIT_ORDER PERMS_VERSION es número estable 1`] = `4037934643`;
|
|
4
|
+
|
|
5
|
+
exports[`PERMISSION_BIT_ORDER append-only: snapshot del ORDEN COMPLETO (rompe ante cualquier reorden/inserción) 1`] = `
|
|
6
|
+
[
|
|
7
|
+
"rbac.catalog.manage",
|
|
8
|
+
"platform.tenant.create",
|
|
9
|
+
"platform.tenant.list",
|
|
10
|
+
"platform.tenant.view",
|
|
11
|
+
"platform.tenant.update",
|
|
12
|
+
"platform.tenant.suspend",
|
|
13
|
+
"platform.tenant.activate",
|
|
14
|
+
"platform.tenant.admin.replace",
|
|
15
|
+
"platform.cognito.pool.manage",
|
|
16
|
+
"platform.cognito.pool.list",
|
|
17
|
+
"platform.user.create",
|
|
18
|
+
"platform.user.list",
|
|
19
|
+
"platform.user.view",
|
|
20
|
+
"platform.user.update",
|
|
21
|
+
"platform.user.disable",
|
|
22
|
+
"platform.user.enable",
|
|
23
|
+
"platform.user.delete",
|
|
24
|
+
"platform.role.create",
|
|
25
|
+
"platform.role.list",
|
|
26
|
+
"platform.role.update",
|
|
27
|
+
"platform.role.delete",
|
|
28
|
+
"platform.audit.view",
|
|
29
|
+
"tenant.user.create",
|
|
30
|
+
"tenant.user.create.lateral",
|
|
31
|
+
"tenant.user.read",
|
|
32
|
+
"tenant.user.status",
|
|
33
|
+
"tenant.user.list",
|
|
34
|
+
"tenant.user.view",
|
|
35
|
+
"tenant.user.update",
|
|
36
|
+
"tenant.user.disable",
|
|
37
|
+
"tenant.user.enable",
|
|
38
|
+
"tenant.user.delete",
|
|
39
|
+
"tenant.user.mfa.reset",
|
|
40
|
+
"tenant.user.password.reset",
|
|
41
|
+
"tenant.role.create",
|
|
42
|
+
"tenant.role.list",
|
|
43
|
+
"tenant.role.update",
|
|
44
|
+
"tenant.role.delete",
|
|
45
|
+
"tenant.role.view",
|
|
46
|
+
"tenant.role.assign",
|
|
47
|
+
"tenant.role.revoke",
|
|
48
|
+
"tenant.security.policy.view",
|
|
49
|
+
"tenant.security.policy.manage",
|
|
50
|
+
"tenant.branding.manage",
|
|
51
|
+
"tenant.audit.view",
|
|
52
|
+
"retail.user.create",
|
|
53
|
+
"retail.user.create.lateral",
|
|
54
|
+
"retail.user.read",
|
|
55
|
+
"retail.user.update",
|
|
56
|
+
"retail.user.status",
|
|
57
|
+
"retail.user.delete",
|
|
58
|
+
"retail.user.password.reset",
|
|
59
|
+
"retail.user.mfa.reset",
|
|
60
|
+
"retail.product.create",
|
|
61
|
+
"retail.product.list",
|
|
62
|
+
"retail.product.view",
|
|
63
|
+
"retail.product.update",
|
|
64
|
+
"retail.product.delete",
|
|
65
|
+
"retail.product.mdm_config",
|
|
66
|
+
"retail.inventory.list",
|
|
67
|
+
"retail.inventory.view",
|
|
68
|
+
"retail.inventory.update",
|
|
69
|
+
"retail.sale.create",
|
|
70
|
+
"retail.sale.list",
|
|
71
|
+
"retail.sale.cancel",
|
|
72
|
+
"retail.store.manage",
|
|
73
|
+
"retail.retailer.manage",
|
|
74
|
+
"lend.credit.create",
|
|
75
|
+
"lend.credit.list",
|
|
76
|
+
"lend.credit.view",
|
|
77
|
+
"lend.credit.update",
|
|
78
|
+
"lend.credit.liquidate",
|
|
79
|
+
"lend.credit.restructure",
|
|
80
|
+
"lend.payment.apply",
|
|
81
|
+
"lend.payment.list",
|
|
82
|
+
"lend.payment.reverse",
|
|
83
|
+
"lend.installment.view",
|
|
84
|
+
"mdm.device.enroll",
|
|
85
|
+
"mdm.device.release",
|
|
86
|
+
"mdm.device.archive",
|
|
87
|
+
"mdm.device.deactivate",
|
|
88
|
+
"mdm.device.lock.manual",
|
|
89
|
+
"mdm.device.unlock.manual",
|
|
90
|
+
"mdm.device.pin_unlock",
|
|
91
|
+
"mdm.device.extend_validity",
|
|
92
|
+
"mdm.device.notify",
|
|
93
|
+
"mdm.device.status.view",
|
|
94
|
+
"mdm.operation_log.view",
|
|
95
|
+
"mdm.test",
|
|
96
|
+
"pay.transaction.view",
|
|
97
|
+
]
|
|
98
|
+
`;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Permission,
|
|
3
|
+
PERMISSION_BIT_ORDER,
|
|
4
|
+
PERMS_VERSION,
|
|
5
|
+
permissionsToBits,
|
|
6
|
+
bitsToPermissions,
|
|
7
|
+
} from '../../../../src/platformRbac/enums/Permission';
|
|
8
|
+
|
|
9
|
+
describe('PERMISSION_BIT_ORDER', () => {
|
|
10
|
+
it('contiene TODOS los valores del enum Permission', () => {
|
|
11
|
+
const enumVals = Object.values(Permission) as string[];
|
|
12
|
+
expect([...PERMISSION_BIT_ORDER].sort()).toEqual([...enumVals].sort());
|
|
13
|
+
});
|
|
14
|
+
it('append-only: snapshot del ORDEN COMPLETO (rompe ante cualquier reorden/inserción)', () => {
|
|
15
|
+
// Snapshot del array entero, NO un prefijo: un reorden del índice 11+ o una inserción
|
|
16
|
+
// intermedia desalinea todos los tokens emitidos. Si esto rompe, fue intencional → -u consciente.
|
|
17
|
+
expect(PERMISSION_BIT_ORDER).toMatchSnapshot();
|
|
18
|
+
});
|
|
19
|
+
it('PERMS_VERSION es número estable', () => {
|
|
20
|
+
expect(typeof PERMS_VERSION).toBe('number');
|
|
21
|
+
expect(PERMS_VERSION).toMatchSnapshot();
|
|
22
|
+
});
|
|
23
|
+
it('round-trip permisos ↔ bits', () => {
|
|
24
|
+
const perms = [
|
|
25
|
+
PERMISSION_BIT_ORDER[0],
|
|
26
|
+
PERMISSION_BIT_ORDER[5],
|
|
27
|
+
PERMISSION_BIT_ORDER[PERMISSION_BIT_ORDER.length - 1],
|
|
28
|
+
];
|
|
29
|
+
const bits = permissionsToBits(perms);
|
|
30
|
+
expect(typeof bits).toBe('string');
|
|
31
|
+
expect(new Set(bitsToPermissions(bits))).toEqual(new Set(perms));
|
|
32
|
+
});
|
|
33
|
+
it('bitsToPermissions tolera basura → []', () => {
|
|
34
|
+
expect(bitsToPermissions('')).toEqual([]);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -17,14 +17,14 @@ class CreateUserRequest {
|
|
|
17
17
|
exports.CreateUserRequest = CreateUserRequest;
|
|
18
18
|
__decorate([
|
|
19
19
|
(0, class_transformer_1.Expose)(),
|
|
20
|
+
(0, class_validator_1.IsOptional)(),
|
|
20
21
|
(0, class_validator_1.IsString)(),
|
|
21
|
-
(0, class_validator_1.IsNotEmpty)(),
|
|
22
22
|
__metadata("design:type", String)
|
|
23
23
|
], CreateUserRequest.prototype, "userPoolId", void 0);
|
|
24
24
|
__decorate([
|
|
25
25
|
(0, class_transformer_1.Expose)(),
|
|
26
|
+
(0, class_validator_1.IsOptional)(),
|
|
26
27
|
(0, class_validator_1.IsString)(),
|
|
27
|
-
(0, class_validator_1.IsNotEmpty)(),
|
|
28
28
|
__metadata("design:type", String)
|
|
29
29
|
], CreateUserRequest.prototype, "region", void 0);
|
|
30
30
|
__decorate([
|
|
@@ -18,4 +18,10 @@ export interface AuthContext {
|
|
|
18
18
|
permissions: Permission[];
|
|
19
19
|
resolvedAt: string;
|
|
20
20
|
issuer?: string;
|
|
21
|
+
/** Bitset base64url de permisos efectivos (token-as-cache). Ausente → fallback al resolver/claim. */
|
|
22
|
+
permBits?: string;
|
|
23
|
+
/** Versión del catálogo (PERMS_VERSION) con la que se construyó permBits. */
|
|
24
|
+
permVer?: number;
|
|
25
|
+
/** Epoch de permisos del tenant al momento de emitir el token. */
|
|
26
|
+
permsEpoch?: number;
|
|
21
27
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TokenValidationMode } from '../enums/TokenValidationMode';
|
|
1
2
|
/**
|
|
2
3
|
* Input del POST backoffice de creación de tenant (F-11 — onboarding de tenant en SureKeep).
|
|
3
4
|
* Consumido por el controller `backofficeCreateTenant` del platform-rbac-business y, a futuro,
|
|
@@ -14,4 +15,5 @@ export declare class CreateTenantRequest {
|
|
|
14
15
|
region: string;
|
|
15
16
|
mfaRequired?: boolean;
|
|
16
17
|
passwordMinLength?: number;
|
|
18
|
+
tokenValidationMode?: TokenValidationMode;
|
|
17
19
|
}
|
|
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.CreateTenantRequest = void 0;
|
|
13
13
|
const class_transformer_1 = require("class-transformer");
|
|
14
14
|
const class_validator_1 = require("class-validator");
|
|
15
|
+
const TokenValidationMode_1 = require("../enums/TokenValidationMode");
|
|
15
16
|
/**
|
|
16
17
|
* Input del POST backoffice de creación de tenant (F-11 — onboarding de tenant en SureKeep).
|
|
17
18
|
* Consumido por el controller `backofficeCreateTenant` del platform-rbac-business y, a futuro,
|
|
@@ -66,3 +67,9 @@ __decorate([
|
|
|
66
67
|
(0, class_validator_1.Min)(8),
|
|
67
68
|
__metadata("design:type", Number)
|
|
68
69
|
], CreateTenantRequest.prototype, "passwordMinLength", void 0);
|
|
70
|
+
__decorate([
|
|
71
|
+
(0, class_transformer_1.Expose)(),
|
|
72
|
+
(0, class_validator_1.IsOptional)(),
|
|
73
|
+
(0, class_validator_1.IsEnum)(TokenValidationMode_1.TokenValidationMode),
|
|
74
|
+
__metadata("design:type", String)
|
|
75
|
+
], CreateTenantRequest.prototype, "tokenValidationMode", void 0);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Permission } from '../enums/Permission';
|
|
2
|
+
import type { RoleAssignmentInfo } from './RoleAssignmentInfo';
|
|
3
|
+
/** Respuesta de platform-rbac-business /internal/effective-permissions (consumida por jwt-inyector). */
|
|
4
|
+
export interface EffectivePermissionsResponse {
|
|
5
|
+
permissions: Permission[];
|
|
6
|
+
roleAssignments: RoleAssignmentInfo[];
|
|
7
|
+
permsEpoch: number;
|
|
8
|
+
}
|
|
@@ -6,7 +6,25 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Copy-paste literal de los valores del spec (DEC-003).
|
|
8
8
|
* Convención: `<category>.<resource>.<action>` (snake_case en action si multi-palabra).
|
|
9
|
-
*
|
|
9
|
+
*
|
|
10
|
+
* ⚠️ ESTE ES EL CATÁLOGO GLOBAL Y ÚNICO. Todo permiso del sistema vive acá. Los tenants
|
|
11
|
+
* NO inventan permisos: cada `tenantType` arma su lista (techo) ELIGIENDO de este catálogo
|
|
12
|
+
* (`TenantTypePermissionCatalog_GT` en platform-rbac-business, DEC-062), y cada tenant arma
|
|
13
|
+
* sus roles combinando esos permisos. El vocabulario es global; lo que varía por tenant es
|
|
14
|
+
* QUÉ permisos usa, no CUÁLES existen.
|
|
15
|
+
*
|
|
16
|
+
* ⚠️⚠️ AL AGREGAR / QUITAR / RENOMBRAR UN PERMISO — PROCEDIMIENTO OBLIGATORIO:
|
|
17
|
+
* 1. Agregar el valor a ESTE enum.
|
|
18
|
+
* 2. Agregarlo TAMBIÉN al FINAL de `PERMISSION_BIT_ORDER` (abajo) — append-only, NUNCA en
|
|
19
|
+
* el medio ni reordenando: ese array define el bit de cada permiso en el token (bitset).
|
|
20
|
+
* Reordenar/insertar en medio desalinea TODOS los tokens ya emitidos (escalada/pérdida
|
|
21
|
+
* de permisos silenciosa). Un permiso deprecado CONSERVA su posición (no se borra del array).
|
|
22
|
+
* 3. Recién entonces un `tenantType` puede incluirlo en su lista. Un permiso que NO esté en
|
|
23
|
+
* este enum + bit-order NO tiene bit → no viaja en el token (el gateway-adapter no lo ve).
|
|
24
|
+
* 4. `PERMS_VERSION` (hash del orden) cambia solo → bump minor del type-kit + redeploy de
|
|
25
|
+
* consumers (jwt-inyector-trigger, gateway-adapter, platform-rbac-business). Tokens viejos
|
|
26
|
+
* caen al fallback (resolver DDB) hasta refrescar — by-design, no rompe.
|
|
27
|
+
* El test `permissionBits.test.ts` falla si el enum y `PERMISSION_BIT_ORDER` se desincronizan.
|
|
10
28
|
*
|
|
11
29
|
* Coexiste con módulo `rbac/` oficial cuando yhonhansen publique componente 01 — TD-RBAC-002.
|
|
12
30
|
*/
|
|
@@ -102,3 +120,21 @@ export declare enum Permission {
|
|
|
102
120
|
MDM_TEST = "mdm.test",
|
|
103
121
|
PAY_TRANSACTION_VIEW = "pay.transaction.view"
|
|
104
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* Orden CANÓNICO y APPEND-ONLY de los permisos para el bitset del token.
|
|
125
|
+
* Índice de cada permiso = su posición de bit. NUNCA reordenar ni borrar:
|
|
126
|
+
* deprecados CONSERVAN su posición; los nuevos van SIEMPRE al final.
|
|
127
|
+
* Derivado explícitamente (no Object.values, frágil ante edición del enum).
|
|
128
|
+
*
|
|
129
|
+
* ⚠️ Si agregás un permiso al enum `Permission` (arriba), agregalo TAMBIÉN acá, AL FINAL.
|
|
130
|
+
* Ver el procedimiento completo en el JSDoc del enum `Permission`. El test
|
|
131
|
+
* `permissionBits.test.ts` rompe si esto y el enum no coinciden, y el snapshot del orden
|
|
132
|
+
* completo rompe si reordenás (guard anti-desalineamiento de tokens emitidos).
|
|
133
|
+
*/
|
|
134
|
+
export declare const PERMISSION_BIT_ORDER: readonly Permission[];
|
|
135
|
+
/** Versión del catálogo = hash del orden. Cambia solo si el orden cambia. */
|
|
136
|
+
export declare const PERMS_VERSION: number;
|
|
137
|
+
/** Comprime un set de permisos a bitset base64url. */
|
|
138
|
+
export declare function permissionsToBits(perms: readonly Permission[]): string;
|
|
139
|
+
/** Decodifica un bitset base64url a la lista de permisos. Tolerante a basura → []. */
|
|
140
|
+
export declare function bitsToPermissions(bits: string): Permission[];
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Permission = void 0;
|
|
3
|
+
exports.PERMS_VERSION = exports.PERMISSION_BIT_ORDER = exports.Permission = void 0;
|
|
4
|
+
exports.permissionsToBits = permissionsToBits;
|
|
5
|
+
exports.bitsToPermissions = bitsToPermissions;
|
|
4
6
|
/**
|
|
5
7
|
* Catálogo universal de permisos del sistema RBAC Fiado.
|
|
6
8
|
*
|
|
@@ -9,7 +11,25 @@ exports.Permission = void 0;
|
|
|
9
11
|
*
|
|
10
12
|
* Copy-paste literal de los valores del spec (DEC-003).
|
|
11
13
|
* Convención: `<category>.<resource>.<action>` (snake_case en action si multi-palabra).
|
|
12
|
-
*
|
|
14
|
+
*
|
|
15
|
+
* ⚠️ ESTE ES EL CATÁLOGO GLOBAL Y ÚNICO. Todo permiso del sistema vive acá. Los tenants
|
|
16
|
+
* NO inventan permisos: cada `tenantType` arma su lista (techo) ELIGIENDO de este catálogo
|
|
17
|
+
* (`TenantTypePermissionCatalog_GT` en platform-rbac-business, DEC-062), y cada tenant arma
|
|
18
|
+
* sus roles combinando esos permisos. El vocabulario es global; lo que varía por tenant es
|
|
19
|
+
* QUÉ permisos usa, no CUÁLES existen.
|
|
20
|
+
*
|
|
21
|
+
* ⚠️⚠️ AL AGREGAR / QUITAR / RENOMBRAR UN PERMISO — PROCEDIMIENTO OBLIGATORIO:
|
|
22
|
+
* 1. Agregar el valor a ESTE enum.
|
|
23
|
+
* 2. Agregarlo TAMBIÉN al FINAL de `PERMISSION_BIT_ORDER` (abajo) — append-only, NUNCA en
|
|
24
|
+
* el medio ni reordenando: ese array define el bit de cada permiso en el token (bitset).
|
|
25
|
+
* Reordenar/insertar en medio desalinea TODOS los tokens ya emitidos (escalada/pérdida
|
|
26
|
+
* de permisos silenciosa). Un permiso deprecado CONSERVA su posición (no se borra del array).
|
|
27
|
+
* 3. Recién entonces un `tenantType` puede incluirlo en su lista. Un permiso que NO esté en
|
|
28
|
+
* este enum + bit-order NO tiene bit → no viaja en el token (el gateway-adapter no lo ve).
|
|
29
|
+
* 4. `PERMS_VERSION` (hash del orden) cambia solo → bump minor del type-kit + redeploy de
|
|
30
|
+
* consumers (jwt-inyector-trigger, gateway-adapter, platform-rbac-business). Tokens viejos
|
|
31
|
+
* caen al fallback (resolver DDB) hasta refrescar — by-design, no rompe.
|
|
32
|
+
* El test `permissionBits.test.ts` falla si el enum y `PERMISSION_BIT_ORDER` se desincronizan.
|
|
13
33
|
*
|
|
14
34
|
* Coexiste con módulo `rbac/` oficial cuando yhonhansen publique componente 01 — TD-RBAC-002.
|
|
15
35
|
*/
|
|
@@ -135,3 +155,145 @@ var Permission;
|
|
|
135
155
|
// ====================================================
|
|
136
156
|
Permission["PAY_TRANSACTION_VIEW"] = "pay.transaction.view";
|
|
137
157
|
})(Permission || (exports.Permission = Permission = {}));
|
|
158
|
+
/**
|
|
159
|
+
* Orden CANÓNICO y APPEND-ONLY de los permisos para el bitset del token.
|
|
160
|
+
* Índice de cada permiso = su posición de bit. NUNCA reordenar ni borrar:
|
|
161
|
+
* deprecados CONSERVAN su posición; los nuevos van SIEMPRE al final.
|
|
162
|
+
* Derivado explícitamente (no Object.values, frágil ante edición del enum).
|
|
163
|
+
*
|
|
164
|
+
* ⚠️ Si agregás un permiso al enum `Permission` (arriba), agregalo TAMBIÉN acá, AL FINAL.
|
|
165
|
+
* Ver el procedimiento completo en el JSDoc del enum `Permission`. El test
|
|
166
|
+
* `permissionBits.test.ts` rompe si esto y el enum no coinciden, y el snapshot del orden
|
|
167
|
+
* completo rompe si reordenás (guard anti-desalineamiento de tokens emitidos).
|
|
168
|
+
*/
|
|
169
|
+
exports.PERMISSION_BIT_ORDER = [
|
|
170
|
+
Permission.RBAC_CATALOG_MANAGE,
|
|
171
|
+
Permission.PLATFORM_TENANT_CREATE,
|
|
172
|
+
Permission.PLATFORM_TENANT_LIST,
|
|
173
|
+
Permission.PLATFORM_TENANT_VIEW,
|
|
174
|
+
Permission.PLATFORM_TENANT_UPDATE,
|
|
175
|
+
Permission.PLATFORM_TENANT_SUSPEND,
|
|
176
|
+
Permission.PLATFORM_TENANT_ACTIVATE,
|
|
177
|
+
Permission.PLATFORM_TENANT_ADMIN_REPLACE,
|
|
178
|
+
Permission.PLATFORM_COGNITO_POOL_MANAGE,
|
|
179
|
+
Permission.PLATFORM_COGNITO_POOL_LIST,
|
|
180
|
+
Permission.PLATFORM_USER_CREATE,
|
|
181
|
+
Permission.PLATFORM_USER_LIST,
|
|
182
|
+
Permission.PLATFORM_USER_VIEW,
|
|
183
|
+
Permission.PLATFORM_USER_UPDATE,
|
|
184
|
+
Permission.PLATFORM_USER_DISABLE,
|
|
185
|
+
Permission.PLATFORM_USER_ENABLE,
|
|
186
|
+
Permission.PLATFORM_USER_DELETE,
|
|
187
|
+
Permission.PLATFORM_ROLE_CREATE,
|
|
188
|
+
Permission.PLATFORM_ROLE_LIST,
|
|
189
|
+
Permission.PLATFORM_ROLE_UPDATE,
|
|
190
|
+
Permission.PLATFORM_ROLE_DELETE,
|
|
191
|
+
Permission.PLATFORM_AUDIT_VIEW,
|
|
192
|
+
Permission.TENANT_USER_CREATE,
|
|
193
|
+
Permission.TENANT_USER_CREATE_LATERAL,
|
|
194
|
+
Permission.TENANT_USER_READ,
|
|
195
|
+
Permission.TENANT_USER_STATUS,
|
|
196
|
+
Permission.TENANT_USER_LIST,
|
|
197
|
+
Permission.TENANT_USER_VIEW,
|
|
198
|
+
Permission.TENANT_USER_UPDATE,
|
|
199
|
+
Permission.TENANT_USER_DISABLE,
|
|
200
|
+
Permission.TENANT_USER_ENABLE,
|
|
201
|
+
Permission.TENANT_USER_DELETE,
|
|
202
|
+
Permission.TENANT_USER_MFA_RESET,
|
|
203
|
+
Permission.TENANT_USER_PASSWORD_RESET,
|
|
204
|
+
Permission.TENANT_ROLE_CREATE,
|
|
205
|
+
Permission.TENANT_ROLE_LIST,
|
|
206
|
+
Permission.TENANT_ROLE_UPDATE,
|
|
207
|
+
Permission.TENANT_ROLE_DELETE,
|
|
208
|
+
Permission.TENANT_ROLE_VIEW,
|
|
209
|
+
Permission.TENANT_ROLE_ASSIGN,
|
|
210
|
+
Permission.TENANT_ROLE_REVOKE,
|
|
211
|
+
Permission.TENANT_SECURITY_POLICY_VIEW,
|
|
212
|
+
Permission.TENANT_SECURITY_POLICY_MANAGE,
|
|
213
|
+
Permission.TENANT_BRANDING_MANAGE,
|
|
214
|
+
Permission.TENANT_AUDIT_VIEW,
|
|
215
|
+
Permission.RETAIL_USER_CREATE,
|
|
216
|
+
Permission.RETAIL_USER_CREATE_LATERAL,
|
|
217
|
+
Permission.RETAIL_USER_READ,
|
|
218
|
+
Permission.RETAIL_USER_UPDATE,
|
|
219
|
+
Permission.RETAIL_USER_STATUS,
|
|
220
|
+
Permission.RETAIL_USER_DELETE,
|
|
221
|
+
Permission.RETAIL_USER_PASSWORD_RESET,
|
|
222
|
+
Permission.RETAIL_USER_MFA_RESET,
|
|
223
|
+
Permission.RETAIL_PRODUCT_CREATE,
|
|
224
|
+
Permission.RETAIL_PRODUCT_LIST,
|
|
225
|
+
Permission.RETAIL_PRODUCT_VIEW,
|
|
226
|
+
Permission.RETAIL_PRODUCT_UPDATE,
|
|
227
|
+
Permission.RETAIL_PRODUCT_DELETE,
|
|
228
|
+
Permission.RETAIL_PRODUCT_MDM_CONFIG,
|
|
229
|
+
Permission.RETAIL_INVENTORY_LIST,
|
|
230
|
+
Permission.RETAIL_INVENTORY_VIEW,
|
|
231
|
+
Permission.RETAIL_INVENTORY_UPDATE,
|
|
232
|
+
Permission.RETAIL_SALE_CREATE,
|
|
233
|
+
Permission.RETAIL_SALE_LIST,
|
|
234
|
+
Permission.RETAIL_SALE_CANCEL,
|
|
235
|
+
Permission.RETAIL_STORE_MANAGE,
|
|
236
|
+
Permission.RETAIL_RETAILER_MANAGE,
|
|
237
|
+
Permission.LEND_CREDIT_CREATE,
|
|
238
|
+
Permission.LEND_CREDIT_LIST,
|
|
239
|
+
Permission.LEND_CREDIT_VIEW,
|
|
240
|
+
Permission.LEND_CREDIT_UPDATE,
|
|
241
|
+
Permission.LEND_CREDIT_LIQUIDATE,
|
|
242
|
+
Permission.LEND_CREDIT_RESTRUCTURE,
|
|
243
|
+
Permission.LEND_PAYMENT_APPLY,
|
|
244
|
+
Permission.LEND_PAYMENT_LIST,
|
|
245
|
+
Permission.LEND_PAYMENT_REVERSE,
|
|
246
|
+
Permission.LEND_INSTALLMENT_VIEW,
|
|
247
|
+
Permission.MDM_DEVICE_ENROLL,
|
|
248
|
+
Permission.MDM_DEVICE_RELEASE,
|
|
249
|
+
Permission.MDM_DEVICE_ARCHIVE,
|
|
250
|
+
Permission.MDM_DEVICE_DEACTIVATE,
|
|
251
|
+
Permission.MDM_DEVICE_LOCK_MANUAL,
|
|
252
|
+
Permission.MDM_DEVICE_UNLOCK_MANUAL,
|
|
253
|
+
Permission.MDM_DEVICE_PIN_UNLOCK,
|
|
254
|
+
Permission.MDM_DEVICE_EXTEND_VALIDITY,
|
|
255
|
+
Permission.MDM_DEVICE_NOTIFY,
|
|
256
|
+
Permission.MDM_DEVICE_STATUS_VIEW,
|
|
257
|
+
Permission.MDM_OPERATION_LOG_VIEW,
|
|
258
|
+
Permission.MDM_TEST,
|
|
259
|
+
Permission.PAY_TRANSACTION_VIEW,
|
|
260
|
+
];
|
|
261
|
+
function djb2(input) {
|
|
262
|
+
let h = 5381;
|
|
263
|
+
for (let i = 0; i < input.length; i++)
|
|
264
|
+
h = ((h << 5) + h + input.charCodeAt(i)) >>> 0;
|
|
265
|
+
return h;
|
|
266
|
+
}
|
|
267
|
+
/** Versión del catálogo = hash del orden. Cambia solo si el orden cambia. */
|
|
268
|
+
exports.PERMS_VERSION = djb2(exports.PERMISSION_BIT_ORDER.join('|'));
|
|
269
|
+
const BIT_INDEX = new Map(exports.PERMISSION_BIT_ORDER.map((p, i) => [p, i]));
|
|
270
|
+
/** Comprime un set de permisos a bitset base64url. */
|
|
271
|
+
function permissionsToBits(perms) {
|
|
272
|
+
const bytes = new Uint8Array(Math.ceil(exports.PERMISSION_BIT_ORDER.length / 8));
|
|
273
|
+
for (const p of perms) {
|
|
274
|
+
const idx = BIT_INDEX.get(p);
|
|
275
|
+
if (idx === undefined)
|
|
276
|
+
continue;
|
|
277
|
+
bytes[idx >> 3] |= 1 << (idx & 7);
|
|
278
|
+
}
|
|
279
|
+
return Buffer.from(bytes).toString('base64url');
|
|
280
|
+
}
|
|
281
|
+
/** Decodifica un bitset base64url a la lista de permisos. Tolerante a basura → []. */
|
|
282
|
+
function bitsToPermissions(bits) {
|
|
283
|
+
if (typeof bits !== 'string' || bits.length === 0)
|
|
284
|
+
return [];
|
|
285
|
+
let bytes;
|
|
286
|
+
try {
|
|
287
|
+
bytes = Buffer.from(bits, 'base64url');
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
return [];
|
|
291
|
+
}
|
|
292
|
+
const out = [];
|
|
293
|
+
for (let i = 0; i < exports.PERMISSION_BIT_ORDER.length; i++) {
|
|
294
|
+
const byte = bytes[i >> 3] ?? 0;
|
|
295
|
+
if (byte & (1 << (i & 7)))
|
|
296
|
+
out.push(exports.PERMISSION_BIT_ORDER[i]);
|
|
297
|
+
}
|
|
298
|
+
return out;
|
|
299
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Modo de validación de tokens por tenant (DEC-RBAC-002 del rbac-authorizer-trigger).
|
|
3
|
+
* Persistido como atributo no-key en PlatformTenantConfig_GT. Los valores string SON el
|
|
4
|
+
* contrato: el authorizer los espeja con un tipo local (no depende de type-kit, DT-7).
|
|
5
|
+
* - OFFLINE: solo firma (JWKS) + permsEpoch. Default. No pega a Cognito.
|
|
6
|
+
* - ONLINE_PREFERRED: AdminGetUser; negativo definitivo → Deny; fallo de infra → cae a offline.
|
|
7
|
+
* - ONLINE_STRICT: AdminGetUser; negativo definitivo O fallo de infra → Deny (fail-closed, regulado).
|
|
8
|
+
*/
|
|
9
|
+
export declare enum TokenValidationMode {
|
|
10
|
+
OFFLINE = "offline",
|
|
11
|
+
ONLINE_PREFERRED = "online_preferred",
|
|
12
|
+
ONLINE_STRICT = "online_strict"
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TokenValidationMode = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Modo de validación de tokens por tenant (DEC-RBAC-002 del rbac-authorizer-trigger).
|
|
6
|
+
* Persistido como atributo no-key en PlatformTenantConfig_GT. Los valores string SON el
|
|
7
|
+
* contrato: el authorizer los espeja con un tipo local (no depende de type-kit, DT-7).
|
|
8
|
+
* - OFFLINE: solo firma (JWKS) + permsEpoch. Default. No pega a Cognito.
|
|
9
|
+
* - ONLINE_PREFERRED: AdminGetUser; negativo definitivo → Deny; fallo de infra → cae a offline.
|
|
10
|
+
* - ONLINE_STRICT: AdminGetUser; negativo definitivo O fallo de infra → Deny (fail-closed, regulado).
|
|
11
|
+
*/
|
|
12
|
+
var TokenValidationMode;
|
|
13
|
+
(function (TokenValidationMode) {
|
|
14
|
+
TokenValidationMode["OFFLINE"] = "offline";
|
|
15
|
+
TokenValidationMode["ONLINE_PREFERRED"] = "online_preferred";
|
|
16
|
+
TokenValidationMode["ONLINE_STRICT"] = "online_strict";
|
|
17
|
+
})(TokenValidationMode || (exports.TokenValidationMode = TokenValidationMode = {}));
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
export { Permission } from './enums/Permission';
|
|
1
|
+
export { Permission, PERMISSION_BIT_ORDER, PERMS_VERSION, permissionsToBits, bitsToPermissions, } from './enums/Permission';
|
|
2
2
|
export { PermissionScope } from './enums/PermissionScope';
|
|
3
3
|
export { PermissionCategory } from './enums/PermissionCategory';
|
|
4
4
|
export type { AuthContext } from './dtos/AuthContext';
|
|
5
5
|
export type { RoleAssignmentInfo } from './dtos/RoleAssignmentInfo';
|
|
6
6
|
export type { PermissionMeta } from './dtos/PermissionMeta';
|
|
7
|
+
export type { EffectivePermissionsResponse } from './dtos/EffectivePermissionsResponse';
|
|
7
8
|
export * from './enums/MfaMethodEnum';
|
|
9
|
+
export * from './enums/TokenValidationMode';
|
|
8
10
|
export * from './enums/ChallengeNameEnum';
|
|
9
11
|
export * from './auth/DefineNextChallengeRequest';
|
|
10
12
|
export * from './auth/DefineNextChallengeResponse';
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
// del platform-rbac-business documenta la migración futura de los 4 símbolos cross-cutting
|
|
6
6
|
// (Permission, PermissionScope, AuthContext, RoleAssignmentInfo) de aquí a `rbac/`.
|
|
7
7
|
//
|
|
8
|
-
//
|
|
9
|
-
// EffectivePermissionsResponse
|
|
10
|
-
//
|
|
8
|
+
// Los DTOs propios del rbac-business se van agregando a medida que los flujos los necesitan.
|
|
9
|
+
// EffectivePermissionsResponse ya vive acá (lo consume jwt-inyector vía /internal/effective-permissions).
|
|
10
|
+
// Otros DTOs aún pendientes se sumarán cuando los managers que los consumen se implementen.
|
|
11
11
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
12
|
if (k2 === undefined) k2 = k;
|
|
13
13
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -23,9 +23,13 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
23
23
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.scopeRankOrder = exports.tableSuffixForLevel = exports.levelsOf = exports.TENANT_TYPES = exports.TenantType = exports.AuthorizeDenyReason = exports.PermissionCategory = exports.PermissionScope = exports.Permission = void 0;
|
|
26
|
+
exports.scopeRankOrder = exports.tableSuffixForLevel = exports.levelsOf = exports.TENANT_TYPES = exports.TenantType = exports.AuthorizeDenyReason = exports.PermissionCategory = exports.PermissionScope = exports.bitsToPermissions = exports.permissionsToBits = exports.PERMS_VERSION = exports.PERMISSION_BIT_ORDER = exports.Permission = void 0;
|
|
27
27
|
var Permission_1 = require("./enums/Permission");
|
|
28
28
|
Object.defineProperty(exports, "Permission", { enumerable: true, get: function () { return Permission_1.Permission; } });
|
|
29
|
+
Object.defineProperty(exports, "PERMISSION_BIT_ORDER", { enumerable: true, get: function () { return Permission_1.PERMISSION_BIT_ORDER; } });
|
|
30
|
+
Object.defineProperty(exports, "PERMS_VERSION", { enumerable: true, get: function () { return Permission_1.PERMS_VERSION; } });
|
|
31
|
+
Object.defineProperty(exports, "permissionsToBits", { enumerable: true, get: function () { return Permission_1.permissionsToBits; } });
|
|
32
|
+
Object.defineProperty(exports, "bitsToPermissions", { enumerable: true, get: function () { return Permission_1.bitsToPermissions; } });
|
|
29
33
|
var PermissionScope_1 = require("./enums/PermissionScope");
|
|
30
34
|
Object.defineProperty(exports, "PermissionScope", { enumerable: true, get: function () { return PermissionScope_1.PermissionScope; } });
|
|
31
35
|
var PermissionCategory_1 = require("./enums/PermissionCategory");
|
|
@@ -33,6 +37,7 @@ Object.defineProperty(exports, "PermissionCategory", { enumerable: true, get: fu
|
|
|
33
37
|
// Fase 1 — Custom Auth Challenge (Email OTP + TOTP) + MFA self-service.
|
|
34
38
|
// Class values (no type-only) — los DTOs llevan decoradores class-validator y se hidratan con plainToInstance en runtime.
|
|
35
39
|
__exportStar(require("./enums/MfaMethodEnum"), exports);
|
|
40
|
+
__exportStar(require("./enums/TokenValidationMode"), exports);
|
|
36
41
|
__exportStar(require("./enums/ChallengeNameEnum"), exports);
|
|
37
42
|
__exportStar(require("./auth/DefineNextChallengeRequest"), exports);
|
|
38
43
|
__exportStar(require("./auth/DefineNextChallengeResponse"), exports);
|
package/package.json
CHANGED
|
@@ -2,8 +2,11 @@ import { Expose } from 'class-transformer';
|
|
|
2
2
|
import { IsBoolean, IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
|
3
3
|
|
|
4
4
|
export class CreateUserRequest {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
// userPoolId + region son OPCIONALES: el alta de usuario PLATFORM ya no los manda desde el front
|
|
6
|
+
// (el backend platform-rbac-business los resuelve de la config del tenant 'platform'). Se conservan
|
|
7
|
+
// en el DTO porque los demás callers del connector SÍ los proveen.
|
|
8
|
+
@Expose() @IsOptional() @IsString() userPoolId?: string;
|
|
9
|
+
@Expose() @IsOptional() @IsString() region?: string;
|
|
7
10
|
@Expose() @IsEmail() email!: string;
|
|
8
11
|
@Expose() @IsOptional() @IsString() displayName?: string;
|
|
9
12
|
@Expose() @IsString() @IsNotEmpty() tenantId!: string;
|
|
@@ -19,4 +19,10 @@ export interface AuthContext {
|
|
|
19
19
|
permissions: Permission[];
|
|
20
20
|
resolvedAt: string;
|
|
21
21
|
issuer?: string;
|
|
22
|
+
/** Bitset base64url de permisos efectivos (token-as-cache). Ausente → fallback al resolver/claim. */
|
|
23
|
+
permBits?: string;
|
|
24
|
+
/** Versión del catálogo (PERMS_VERSION) con la que se construyó permBits. */
|
|
25
|
+
permVer?: number;
|
|
26
|
+
/** Epoch de permisos del tenant al momento de emitir el token. */
|
|
27
|
+
permsEpoch?: number;
|
|
22
28
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Expose } from 'class-transformer';
|
|
2
|
-
import { IsBoolean, IsEmail, IsInt, IsOptional, IsString, Matches, Min } from 'class-validator';
|
|
2
|
+
import { IsBoolean, IsEmail, IsEnum, IsInt, IsOptional, IsString, Matches, Min } from 'class-validator';
|
|
3
|
+
import { TokenValidationMode } from '../enums/TokenValidationMode';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Input del POST backoffice de creación de tenant (F-11 — onboarding de tenant en SureKeep).
|
|
@@ -17,4 +18,5 @@ export class CreateTenantRequest {
|
|
|
17
18
|
@Expose() @IsString() region!: string;
|
|
18
19
|
@Expose() @IsOptional() @IsBoolean() mfaRequired?: boolean;
|
|
19
20
|
@Expose() @IsOptional() @IsInt() @Min(8) passwordMinLength?: number;
|
|
21
|
+
@Expose() @IsOptional() @IsEnum(TokenValidationMode) tokenValidationMode?: TokenValidationMode;
|
|
20
22
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Permission } from '../enums/Permission';
|
|
2
|
+
import type { RoleAssignmentInfo } from './RoleAssignmentInfo';
|
|
3
|
+
|
|
4
|
+
/** Respuesta de platform-rbac-business /internal/effective-permissions (consumida por jwt-inyector). */
|
|
5
|
+
export interface EffectivePermissionsResponse {
|
|
6
|
+
permissions: Permission[];
|
|
7
|
+
roleAssignments: RoleAssignmentInfo[];
|
|
8
|
+
permsEpoch: number;
|
|
9
|
+
}
|
|
@@ -6,7 +6,25 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Copy-paste literal de los valores del spec (DEC-003).
|
|
8
8
|
* Convención: `<category>.<resource>.<action>` (snake_case en action si multi-palabra).
|
|
9
|
-
*
|
|
9
|
+
*
|
|
10
|
+
* ⚠️ ESTE ES EL CATÁLOGO GLOBAL Y ÚNICO. Todo permiso del sistema vive acá. Los tenants
|
|
11
|
+
* NO inventan permisos: cada `tenantType` arma su lista (techo) ELIGIENDO de este catálogo
|
|
12
|
+
* (`TenantTypePermissionCatalog_GT` en platform-rbac-business, DEC-062), y cada tenant arma
|
|
13
|
+
* sus roles combinando esos permisos. El vocabulario es global; lo que varía por tenant es
|
|
14
|
+
* QUÉ permisos usa, no CUÁLES existen.
|
|
15
|
+
*
|
|
16
|
+
* ⚠️⚠️ AL AGREGAR / QUITAR / RENOMBRAR UN PERMISO — PROCEDIMIENTO OBLIGATORIO:
|
|
17
|
+
* 1. Agregar el valor a ESTE enum.
|
|
18
|
+
* 2. Agregarlo TAMBIÉN al FINAL de `PERMISSION_BIT_ORDER` (abajo) — append-only, NUNCA en
|
|
19
|
+
* el medio ni reordenando: ese array define el bit de cada permiso en el token (bitset).
|
|
20
|
+
* Reordenar/insertar en medio desalinea TODOS los tokens ya emitidos (escalada/pérdida
|
|
21
|
+
* de permisos silenciosa). Un permiso deprecado CONSERVA su posición (no se borra del array).
|
|
22
|
+
* 3. Recién entonces un `tenantType` puede incluirlo en su lista. Un permiso que NO esté en
|
|
23
|
+
* este enum + bit-order NO tiene bit → no viaja en el token (el gateway-adapter no lo ve).
|
|
24
|
+
* 4. `PERMS_VERSION` (hash del orden) cambia solo → bump minor del type-kit + redeploy de
|
|
25
|
+
* consumers (jwt-inyector-trigger, gateway-adapter, platform-rbac-business). Tokens viejos
|
|
26
|
+
* caen al fallback (resolver DDB) hasta refrescar — by-design, no rompe.
|
|
27
|
+
* El test `permissionBits.test.ts` falla si el enum y `PERMISSION_BIT_ORDER` se desincronizan.
|
|
10
28
|
*
|
|
11
29
|
* Coexiste con módulo `rbac/` oficial cuando yhonhansen publique componente 01 — TD-RBAC-002.
|
|
12
30
|
*/
|
|
@@ -137,3 +155,144 @@ export enum Permission {
|
|
|
137
155
|
// ====================================================
|
|
138
156
|
PAY_TRANSACTION_VIEW = 'pay.transaction.view',
|
|
139
157
|
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Orden CANÓNICO y APPEND-ONLY de los permisos para el bitset del token.
|
|
161
|
+
* Índice de cada permiso = su posición de bit. NUNCA reordenar ni borrar:
|
|
162
|
+
* deprecados CONSERVAN su posición; los nuevos van SIEMPRE al final.
|
|
163
|
+
* Derivado explícitamente (no Object.values, frágil ante edición del enum).
|
|
164
|
+
*
|
|
165
|
+
* ⚠️ Si agregás un permiso al enum `Permission` (arriba), agregalo TAMBIÉN acá, AL FINAL.
|
|
166
|
+
* Ver el procedimiento completo en el JSDoc del enum `Permission`. El test
|
|
167
|
+
* `permissionBits.test.ts` rompe si esto y el enum no coinciden, y el snapshot del orden
|
|
168
|
+
* completo rompe si reordenás (guard anti-desalineamiento de tokens emitidos).
|
|
169
|
+
*/
|
|
170
|
+
export const PERMISSION_BIT_ORDER: readonly Permission[] = [
|
|
171
|
+
Permission.RBAC_CATALOG_MANAGE,
|
|
172
|
+
Permission.PLATFORM_TENANT_CREATE,
|
|
173
|
+
Permission.PLATFORM_TENANT_LIST,
|
|
174
|
+
Permission.PLATFORM_TENANT_VIEW,
|
|
175
|
+
Permission.PLATFORM_TENANT_UPDATE,
|
|
176
|
+
Permission.PLATFORM_TENANT_SUSPEND,
|
|
177
|
+
Permission.PLATFORM_TENANT_ACTIVATE,
|
|
178
|
+
Permission.PLATFORM_TENANT_ADMIN_REPLACE,
|
|
179
|
+
Permission.PLATFORM_COGNITO_POOL_MANAGE,
|
|
180
|
+
Permission.PLATFORM_COGNITO_POOL_LIST,
|
|
181
|
+
Permission.PLATFORM_USER_CREATE,
|
|
182
|
+
Permission.PLATFORM_USER_LIST,
|
|
183
|
+
Permission.PLATFORM_USER_VIEW,
|
|
184
|
+
Permission.PLATFORM_USER_UPDATE,
|
|
185
|
+
Permission.PLATFORM_USER_DISABLE,
|
|
186
|
+
Permission.PLATFORM_USER_ENABLE,
|
|
187
|
+
Permission.PLATFORM_USER_DELETE,
|
|
188
|
+
Permission.PLATFORM_ROLE_CREATE,
|
|
189
|
+
Permission.PLATFORM_ROLE_LIST,
|
|
190
|
+
Permission.PLATFORM_ROLE_UPDATE,
|
|
191
|
+
Permission.PLATFORM_ROLE_DELETE,
|
|
192
|
+
Permission.PLATFORM_AUDIT_VIEW,
|
|
193
|
+
Permission.TENANT_USER_CREATE,
|
|
194
|
+
Permission.TENANT_USER_CREATE_LATERAL,
|
|
195
|
+
Permission.TENANT_USER_READ,
|
|
196
|
+
Permission.TENANT_USER_STATUS,
|
|
197
|
+
Permission.TENANT_USER_LIST,
|
|
198
|
+
Permission.TENANT_USER_VIEW,
|
|
199
|
+
Permission.TENANT_USER_UPDATE,
|
|
200
|
+
Permission.TENANT_USER_DISABLE,
|
|
201
|
+
Permission.TENANT_USER_ENABLE,
|
|
202
|
+
Permission.TENANT_USER_DELETE,
|
|
203
|
+
Permission.TENANT_USER_MFA_RESET,
|
|
204
|
+
Permission.TENANT_USER_PASSWORD_RESET,
|
|
205
|
+
Permission.TENANT_ROLE_CREATE,
|
|
206
|
+
Permission.TENANT_ROLE_LIST,
|
|
207
|
+
Permission.TENANT_ROLE_UPDATE,
|
|
208
|
+
Permission.TENANT_ROLE_DELETE,
|
|
209
|
+
Permission.TENANT_ROLE_VIEW,
|
|
210
|
+
Permission.TENANT_ROLE_ASSIGN,
|
|
211
|
+
Permission.TENANT_ROLE_REVOKE,
|
|
212
|
+
Permission.TENANT_SECURITY_POLICY_VIEW,
|
|
213
|
+
Permission.TENANT_SECURITY_POLICY_MANAGE,
|
|
214
|
+
Permission.TENANT_BRANDING_MANAGE,
|
|
215
|
+
Permission.TENANT_AUDIT_VIEW,
|
|
216
|
+
Permission.RETAIL_USER_CREATE,
|
|
217
|
+
Permission.RETAIL_USER_CREATE_LATERAL,
|
|
218
|
+
Permission.RETAIL_USER_READ,
|
|
219
|
+
Permission.RETAIL_USER_UPDATE,
|
|
220
|
+
Permission.RETAIL_USER_STATUS,
|
|
221
|
+
Permission.RETAIL_USER_DELETE,
|
|
222
|
+
Permission.RETAIL_USER_PASSWORD_RESET,
|
|
223
|
+
Permission.RETAIL_USER_MFA_RESET,
|
|
224
|
+
Permission.RETAIL_PRODUCT_CREATE,
|
|
225
|
+
Permission.RETAIL_PRODUCT_LIST,
|
|
226
|
+
Permission.RETAIL_PRODUCT_VIEW,
|
|
227
|
+
Permission.RETAIL_PRODUCT_UPDATE,
|
|
228
|
+
Permission.RETAIL_PRODUCT_DELETE,
|
|
229
|
+
Permission.RETAIL_PRODUCT_MDM_CONFIG,
|
|
230
|
+
Permission.RETAIL_INVENTORY_LIST,
|
|
231
|
+
Permission.RETAIL_INVENTORY_VIEW,
|
|
232
|
+
Permission.RETAIL_INVENTORY_UPDATE,
|
|
233
|
+
Permission.RETAIL_SALE_CREATE,
|
|
234
|
+
Permission.RETAIL_SALE_LIST,
|
|
235
|
+
Permission.RETAIL_SALE_CANCEL,
|
|
236
|
+
Permission.RETAIL_STORE_MANAGE,
|
|
237
|
+
Permission.RETAIL_RETAILER_MANAGE,
|
|
238
|
+
Permission.LEND_CREDIT_CREATE,
|
|
239
|
+
Permission.LEND_CREDIT_LIST,
|
|
240
|
+
Permission.LEND_CREDIT_VIEW,
|
|
241
|
+
Permission.LEND_CREDIT_UPDATE,
|
|
242
|
+
Permission.LEND_CREDIT_LIQUIDATE,
|
|
243
|
+
Permission.LEND_CREDIT_RESTRUCTURE,
|
|
244
|
+
Permission.LEND_PAYMENT_APPLY,
|
|
245
|
+
Permission.LEND_PAYMENT_LIST,
|
|
246
|
+
Permission.LEND_PAYMENT_REVERSE,
|
|
247
|
+
Permission.LEND_INSTALLMENT_VIEW,
|
|
248
|
+
Permission.MDM_DEVICE_ENROLL,
|
|
249
|
+
Permission.MDM_DEVICE_RELEASE,
|
|
250
|
+
Permission.MDM_DEVICE_ARCHIVE,
|
|
251
|
+
Permission.MDM_DEVICE_DEACTIVATE,
|
|
252
|
+
Permission.MDM_DEVICE_LOCK_MANUAL,
|
|
253
|
+
Permission.MDM_DEVICE_UNLOCK_MANUAL,
|
|
254
|
+
Permission.MDM_DEVICE_PIN_UNLOCK,
|
|
255
|
+
Permission.MDM_DEVICE_EXTEND_VALIDITY,
|
|
256
|
+
Permission.MDM_DEVICE_NOTIFY,
|
|
257
|
+
Permission.MDM_DEVICE_STATUS_VIEW,
|
|
258
|
+
Permission.MDM_OPERATION_LOG_VIEW,
|
|
259
|
+
Permission.MDM_TEST,
|
|
260
|
+
Permission.PAY_TRANSACTION_VIEW,
|
|
261
|
+
] as const;
|
|
262
|
+
|
|
263
|
+
function djb2(input: string): number {
|
|
264
|
+
let h = 5381;
|
|
265
|
+
for (let i = 0; i < input.length; i++) h = ((h << 5) + h + input.charCodeAt(i)) >>> 0;
|
|
266
|
+
return h;
|
|
267
|
+
}
|
|
268
|
+
/** Versión del catálogo = hash del orden. Cambia solo si el orden cambia. */
|
|
269
|
+
export const PERMS_VERSION: number = djb2(PERMISSION_BIT_ORDER.join('|'));
|
|
270
|
+
|
|
271
|
+
const BIT_INDEX: ReadonlyMap<Permission, number> = new Map(PERMISSION_BIT_ORDER.map((p, i) => [p, i]));
|
|
272
|
+
|
|
273
|
+
/** Comprime un set de permisos a bitset base64url. */
|
|
274
|
+
export function permissionsToBits(perms: readonly Permission[]): string {
|
|
275
|
+
const bytes = new Uint8Array(Math.ceil(PERMISSION_BIT_ORDER.length / 8));
|
|
276
|
+
for (const p of perms) {
|
|
277
|
+
const idx = BIT_INDEX.get(p);
|
|
278
|
+
if (idx === undefined) continue;
|
|
279
|
+
bytes[idx >> 3] |= 1 << (idx & 7);
|
|
280
|
+
}
|
|
281
|
+
return Buffer.from(bytes).toString('base64url');
|
|
282
|
+
}
|
|
283
|
+
/** Decodifica un bitset base64url a la lista de permisos. Tolerante a basura → []. */
|
|
284
|
+
export function bitsToPermissions(bits: string): Permission[] {
|
|
285
|
+
if (typeof bits !== 'string' || bits.length === 0) return [];
|
|
286
|
+
let bytes: Buffer;
|
|
287
|
+
try {
|
|
288
|
+
bytes = Buffer.from(bits, 'base64url');
|
|
289
|
+
} catch {
|
|
290
|
+
return [];
|
|
291
|
+
}
|
|
292
|
+
const out: Permission[] = [];
|
|
293
|
+
for (let i = 0; i < PERMISSION_BIT_ORDER.length; i++) {
|
|
294
|
+
const byte = bytes[i >> 3] ?? 0;
|
|
295
|
+
if (byte & (1 << (i & 7))) out.push(PERMISSION_BIT_ORDER[i]);
|
|
296
|
+
}
|
|
297
|
+
return out;
|
|
298
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Modo de validación de tokens por tenant (DEC-RBAC-002 del rbac-authorizer-trigger).
|
|
3
|
+
* Persistido como atributo no-key en PlatformTenantConfig_GT. Los valores string SON el
|
|
4
|
+
* contrato: el authorizer los espeja con un tipo local (no depende de type-kit, DT-7).
|
|
5
|
+
* - OFFLINE: solo firma (JWKS) + permsEpoch. Default. No pega a Cognito.
|
|
6
|
+
* - ONLINE_PREFERRED: AdminGetUser; negativo definitivo → Deny; fallo de infra → cae a offline.
|
|
7
|
+
* - ONLINE_STRICT: AdminGetUser; negativo definitivo O fallo de infra → Deny (fail-closed, regulado).
|
|
8
|
+
*/
|
|
9
|
+
export enum TokenValidationMode {
|
|
10
|
+
OFFLINE = 'offline',
|
|
11
|
+
ONLINE_PREFERRED = 'online_preferred',
|
|
12
|
+
ONLINE_STRICT = 'online_strict',
|
|
13
|
+
}
|
|
@@ -4,21 +4,29 @@
|
|
|
4
4
|
// del platform-rbac-business documenta la migración futura de los 4 símbolos cross-cutting
|
|
5
5
|
// (Permission, PermissionScope, AuthContext, RoleAssignmentInfo) de aquí a `rbac/`.
|
|
6
6
|
//
|
|
7
|
-
//
|
|
8
|
-
// EffectivePermissionsResponse
|
|
9
|
-
//
|
|
7
|
+
// Los DTOs propios del rbac-business se van agregando a medida que los flujos los necesitan.
|
|
8
|
+
// EffectivePermissionsResponse ya vive acá (lo consume jwt-inyector vía /internal/effective-permissions).
|
|
9
|
+
// Otros DTOs aún pendientes se sumarán cuando los managers que los consumen se implementen.
|
|
10
10
|
|
|
11
|
-
export {
|
|
11
|
+
export {
|
|
12
|
+
Permission,
|
|
13
|
+
PERMISSION_BIT_ORDER,
|
|
14
|
+
PERMS_VERSION,
|
|
15
|
+
permissionsToBits,
|
|
16
|
+
bitsToPermissions,
|
|
17
|
+
} from './enums/Permission';
|
|
12
18
|
export { PermissionScope } from './enums/PermissionScope';
|
|
13
19
|
export { PermissionCategory } from './enums/PermissionCategory';
|
|
14
20
|
|
|
15
21
|
export type { AuthContext } from './dtos/AuthContext';
|
|
16
22
|
export type { RoleAssignmentInfo } from './dtos/RoleAssignmentInfo';
|
|
17
23
|
export type { PermissionMeta } from './dtos/PermissionMeta';
|
|
24
|
+
export type { EffectivePermissionsResponse } from './dtos/EffectivePermissionsResponse';
|
|
18
25
|
|
|
19
26
|
// Fase 1 — Custom Auth Challenge (Email OTP + TOTP) + MFA self-service.
|
|
20
27
|
// Class values (no type-only) — los DTOs llevan decoradores class-validator y se hidratan con plainToInstance en runtime.
|
|
21
28
|
export * from './enums/MfaMethodEnum';
|
|
29
|
+
export * from './enums/TokenValidationMode';
|
|
22
30
|
export * from './enums/ChallengeNameEnum';
|
|
23
31
|
export * from './auth/DefineNextChallengeRequest';
|
|
24
32
|
export * from './auth/DefineNextChallengeResponse';
|