@adonis-agora/agent 0.30.1 → 0.30.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/src/authz/agora-context.d.ts +22 -6
- package/dist/src/authz/agora-context.d.ts.map +1 -1
- package/dist/src/authz/agora-context.js +30 -0
- package/dist/src/authz/agora-context.js.map +1 -1
- package/dist/src/authz/authz-actor-resolver.d.ts.map +1 -1
- package/dist/src/authz/authz-actor-resolver.js +5 -6
- package/dist/src/authz/authz-actor-resolver.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @adonis-agora/agent
|
|
2
2
|
|
|
3
|
+
## 0.30.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#108](https://github.com/DavideCarvalho/adonis-agora-agent/pull/108) [`a99256b`](https://github.com/DavideCarvalho/adonis-agora-agent/commit/a99256b185ce1f4d653476d5b5d0fc675ad25c57) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Corrige `AuthzActorResolver` para ler `userRef`/`tenantId` do `@agora/context` como MÉTODOS, não como valores — bug que derrubava com 401 toda rota do agente atrás de authz
|
|
8
|
+
|
|
9
|
+
`@adonis-agora/context@0.6.1` publica no slot global `Symbol.for('@agora/context:accessor')` um accessor cujos campos são funções (`packages/core/src/accessor.ts`): `{ traceId(), tenantId(), userRef(), get() }`. `packages/adonis/src/authz/agora-context.ts` declarava `userRef`/`tenantId` como propriedades diretas, e `AuthzActorResolver.resolve()` lia `accessor?.userRef` como VALOR — contra o accessor real, isso é a própria função, `ref.id` é sempre `undefined`, e o resolver caía no ramo fail-closed ("no authenticated identity in @agora/context") em toda chamada. `tenantId` errava do outro lado, mais silenciosamente: uma função é truthy, então o escopo passado ao authz virava `{ tenantId: <function> }`.
|
|
10
|
+
|
|
11
|
+
Isso passou despercebido porque o spec do resolver montava um dublê com `userRef`/`tenantId` como valor — a forma que o resolver assumia, não a que `@adonis-agora/context` produz. Um dublê que não respeita o contrato do original testa uma fantasia.
|
|
12
|
+
|
|
13
|
+
**O que muda:**
|
|
14
|
+
|
|
15
|
+
- `AgoraContextAccessor` (em `agora-context.ts`) agora tipa `tenantId`/`userRef` como métodos (`() => T | undefined`), espelhando o contrato real do accessor.
|
|
16
|
+
- Duas novas funções, `userRefFromContext()` e `tenantIdFromContext()`, chamam esses métodos com segurança: toleram o campo não ser uma função (accessor parcial/mockado) e toleram o método lançar (fora de um contexto ativo) — em qualquer um dos dois casos degradam para `undefined` em vez de propagar, mantendo a postura fail-closed do chamador (`AuthzActorResolver` nunca fabrica identidade).
|
|
17
|
+
- `AuthzActorResolver.resolve()` passa a usar essas duas funções em vez de ler `accessor.userRef`/`accessor.tenantId` como propriedade.
|
|
18
|
+
- Specs de `authz-actor-resolver.spec.ts` e `agora-context.spec.ts` reescritos para mockar o accessor na forma real (métodos), com casos novos cobrindo: método ausente, método que lança, e `userRef()`/`tenantId()` retornando `undefined` fora de um contexto ativo.
|
|
19
|
+
|
|
20
|
+
Não há mudança de assinatura pública — `AuthzActorResolverConfig`, `authzActorResolver()` e o formato do `Actor` resolvido continuam os mesmos. Consumidores que hoje contornam este bug manualmente (lendo o accessor tolerando as duas formas) podem remover o contorno depois de atualizar.
|
|
21
|
+
|
|
3
22
|
## 0.30.1
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
|
@@ -7,18 +7,34 @@
|
|
|
7
7
|
/** The symbol slot the Agora context library writes its read accessor into. */
|
|
8
8
|
export declare const AGORA_CONTEXT_ACCESSOR: unique symbol;
|
|
9
9
|
/**
|
|
10
|
-
* The slice of the context accessor this package reads. `
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* The slice of the context accessor this package reads. `@adonis-agora/context`'s real accessor
|
|
11
|
+
* (`packages/core/src/accessor.ts`) publishes `tenantId` and `userRef` as METHODS — calling them
|
|
12
|
+
* returns the active value, or `undefined` outside a request/job. They are NOT plain properties;
|
|
13
|
+
* treating them as values (the mistake this file used to make) makes every field a truthy function
|
|
14
|
+
* reference instead of the data it holds. We never read `globalRoles` here — authz's
|
|
15
|
+
* `effectiveRoles` does that internally.
|
|
13
16
|
*/
|
|
14
17
|
export interface AgoraContextAccessor {
|
|
15
|
-
tenantId?: string;
|
|
16
|
-
userRef?: {
|
|
18
|
+
tenantId?: () => string | undefined;
|
|
19
|
+
userRef?: () => {
|
|
17
20
|
type?: string;
|
|
18
21
|
id?: string | number;
|
|
19
|
-
};
|
|
22
|
+
} | undefined;
|
|
20
23
|
get?: () => unknown;
|
|
21
24
|
}
|
|
22
25
|
/** Read the active Agora context accessor from the global slot, if present. */
|
|
23
26
|
export declare function readContextAccessor(): AgoraContextAccessor | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* The active caller's `userRef` from the Agora context, or `undefined` outside a context / when
|
|
29
|
+
* the accessor slot is absent.
|
|
30
|
+
*/
|
|
31
|
+
export declare function userRefFromContext(accessor?: AgoraContextAccessor | undefined): {
|
|
32
|
+
type?: string;
|
|
33
|
+
id?: string | number;
|
|
34
|
+
} | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* The active tenant id from the Agora context, or `undefined` outside a context / when unset /
|
|
37
|
+
* when the accessor slot is absent.
|
|
38
|
+
*/
|
|
39
|
+
export declare function tenantIdFromContext(accessor?: AgoraContextAccessor | undefined): string | undefined;
|
|
24
40
|
//# sourceMappingURL=agora-context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agora-context.d.ts","sourceRoot":"","sources":["../../../src/authz/agora-context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,+EAA+E;AAC/E,eAAO,MAAM,sBAAsB,eAAwC,CAAC;AAE5E
|
|
1
|
+
{"version":3,"file":"agora-context.d.ts","sourceRoot":"","sources":["../../../src/authz/agora-context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,+EAA+E;AAC/E,eAAO,MAAM,sBAAsB,eAAwC,CAAC;AAE5E;;;;;;;GAOG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACpE,GAAG,CAAC,EAAE,MAAM,OAAO,CAAC;CACrB;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,IAAI,oBAAoB,GAAG,SAAS,CAItE;AAiBD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,GAAE,oBAAoB,GAAG,SAAiC,GACjE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,GAAG,SAAS,CAErD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,GAAE,oBAAoB,GAAG,SAAiC,GACjE,MAAM,GAAG,SAAS,CAEpB"}
|
|
@@ -13,4 +13,34 @@ export function readContextAccessor() {
|
|
|
13
13
|
return undefined;
|
|
14
14
|
return slot;
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Call an accessor method safely: tolerates the method being absent (a partial/mocked accessor,
|
|
18
|
+
* or a slot that isn't the real `@adonis-agora/context` implementation) and tolerates it throwing.
|
|
19
|
+
* Degrades to `undefined` either way — this package never fabricates identity from a broken
|
|
20
|
+
* context, it just leaves the field empty and lets the caller fail closed.
|
|
21
|
+
*/
|
|
22
|
+
function readMethod(fn) {
|
|
23
|
+
if (typeof fn !== 'function')
|
|
24
|
+
return undefined;
|
|
25
|
+
try {
|
|
26
|
+
return fn();
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The active caller's `userRef` from the Agora context, or `undefined` outside a context / when
|
|
34
|
+
* the accessor slot is absent.
|
|
35
|
+
*/
|
|
36
|
+
export function userRefFromContext(accessor = readContextAccessor()) {
|
|
37
|
+
return readMethod(accessor?.userRef);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The active tenant id from the Agora context, or `undefined` outside a context / when unset /
|
|
41
|
+
* when the accessor slot is absent.
|
|
42
|
+
*/
|
|
43
|
+
export function tenantIdFromContext(accessor = readContextAccessor()) {
|
|
44
|
+
return readMethod(accessor?.tenantId);
|
|
45
|
+
}
|
|
16
46
|
//# sourceMappingURL=agora-context.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agora-context.js","sourceRoot":"","sources":["../../../src/authz/agora-context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,+EAA+E;AAC/E,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"agora-context.js","sourceRoot":"","sources":["../../../src/authz/agora-context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,+EAA+E;AAC/E,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;AAgB5E,+EAA+E;AAC/E,MAAM,UAAU,mBAAmB;IACjC,MAAM,IAAI,GAAI,UAAsC,CAAC,sBAAsB,CAAC,CAAC;IAC7E,IAAI,IAAI,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAC/D,OAAO,IAA4B,CAAC;AACtC,CAAC;AAED;;;;;GAKG;AACH,SAAS,UAAU,CAAI,EAAW;IAChC,IAAI,OAAO,EAAE,KAAK,UAAU;QAAE,OAAO,SAAS,CAAC;IAC/C,IAAI,CAAC;QACH,OAAQ,EAA0B,EAAE,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAAQ,GAAqC,mBAAmB,EAAE;IAElE,OAAO,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AACvC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAAQ,GAAqC,mBAAmB,EAAE;IAElE,OAAO,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authz-actor-resolver.d.ts","sourceRoot":"","sources":["../../../src/authz/authz-actor-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC5E;AAED,2EAA2E;AAC3E,MAAM,WAAW,wBAAwB;IACvC,wGAAwG;IACxG,KAAK,EAAE,oBAAoB,CAAC;CAC7B;AAED;;;;;;;;;;GAUG;AACH,qBAAa,kBAAmB,YAAW,aAAa;;IAGtD,YAAY,MAAM,EAAE,wBAAwB,EAE3C;IAEK,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"authz-actor-resolver.d.ts","sourceRoot":"","sources":["../../../src/authz/authz-actor-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC5E;AAED,2EAA2E;AAC3E,MAAM,WAAW,wBAAwB;IACvC,wGAAwG;IACxG,KAAK,EAAE,oBAAoB,CAAC;CAC7B;AAED;;;;;;;;;;GAUG;AACH,qBAAa,kBAAmB,YAAW,aAAa;;IAGtD,YAAY,MAAM,EAAE,wBAAwB,EAE3C;IAEK,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAoB3C;CACF;AAED,8CAA8C;AAC9C,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,wBAAwB,GAAG,aAAa,CAElF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readContextAccessor } from './agora-context.js';
|
|
1
|
+
import { readContextAccessor, tenantIdFromContext, userRefFromContext } from './agora-context.js';
|
|
2
2
|
/**
|
|
3
3
|
* An {@link ActorResolver} that reads the caller from the Agora context authkit populates
|
|
4
4
|
* (`userRef`, `tenantId`) and takes the caller's roles from authz (`effectiveRoles`). It ignores
|
|
@@ -17,20 +17,19 @@ export class AuthzActorResolver {
|
|
|
17
17
|
}
|
|
18
18
|
async resolve(_req) {
|
|
19
19
|
const accessor = readContextAccessor();
|
|
20
|
-
const ref = accessor
|
|
20
|
+
const ref = userRefFromContext(accessor);
|
|
21
21
|
if (ref?.id === undefined || ref.id === null || String(ref.id).length === 0) {
|
|
22
22
|
throw new Error('authzActorResolver: no authenticated identity in @agora/context. The agent route must ' +
|
|
23
23
|
'sit behind authkit auth middleware (which populates the context), with the ' +
|
|
24
24
|
'@adonis-agora/context provider registered.');
|
|
25
25
|
}
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
: undefined;
|
|
26
|
+
const tenantId = tenantIdFromContext(accessor);
|
|
27
|
+
const scope = tenantId ? { tenantId } : undefined;
|
|
29
28
|
const roles = await this.#authz.effectiveRoles(ref, scope);
|
|
30
29
|
return {
|
|
31
30
|
id: String(ref.id),
|
|
32
31
|
roles,
|
|
33
|
-
...(
|
|
32
|
+
...(tenantId ? { tenantRef: tenantId } : {}),
|
|
34
33
|
};
|
|
35
34
|
}
|
|
36
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authz-actor-resolver.js","sourceRoot":"","sources":["../../../src/authz/authz-actor-resolver.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"authz-actor-resolver.js","sourceRoot":"","sources":["../../../src/authz/authz-actor-resolver.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAkBlG;;;;;;;;;;GAUG;AACH,MAAM,OAAO,kBAAkB;IACpB,MAAM,CAAuB;IAEtC,YAAY,MAAgC;QAC1C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,IAAa;QACzB,MAAM,QAAQ,GAAG,mBAAmB,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QACzC,IAAI,GAAG,EAAE,EAAE,KAAK,SAAS,IAAI,GAAG,CAAC,EAAE,KAAK,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5E,MAAM,IAAI,KAAK,CACb,wFAAwF;gBACtF,6EAA6E;gBAC7E,4CAA4C,CAC/C,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAiC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAChF,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAE3D,OAAO;YACL,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YAClB,KAAK;YACL,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC7C,CAAC;IACJ,CAAC;CACF;AAED,8CAA8C;AAC9C,MAAM,UAAU,kBAAkB,CAAC,MAAgC;IACjE,OAAO,IAAI,kBAAkB,CAAC,MAAM,CAAC,CAAC;AACxC,CAAC"}
|
package/dist/src/index.d.ts
CHANGED
package/dist/src/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const VERSION = '0.30.
|
|
1
|
+
export const VERSION = '0.30.2';
|
|
2
2
|
// Re-export the configure hook from the package root so `node ace configure` finds it.
|
|
3
3
|
// AdonisJS imports the package MAIN and reads `configure` off the module namespace —
|
|
4
4
|
// the `./configure` subpath alone is never consulted.
|
package/package.json
CHANGED