@cargolift-cdi/lib-common 0.0.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.
Files changed (68) hide show
  1. package/LICENSE +9 -0
  2. package/README.jwt-logger-context.md +44 -0
  3. package/README.md +232 -0
  4. package/dist/auth/api-client.decorator.d.ts +2 -0
  5. package/dist/auth/api-client.decorator.js +4 -0
  6. package/dist/auth/api-client.decorator.js.map +1 -0
  7. package/dist/auth/auth.guard.d.ts +13 -0
  8. package/dist/auth/auth.guard.js +95 -0
  9. package/dist/auth/auth.guard.js.map +1 -0
  10. package/dist/auth/auth.module.d.ts +2 -0
  11. package/dist/auth/auth.module.js +19 -0
  12. package/dist/auth/auth.module.js.map +1 -0
  13. package/dist/auth/jwt-verifier.service.d.ts +22 -0
  14. package/dist/auth/jwt-verifier.service.js +164 -0
  15. package/dist/auth/jwt-verifier.service.js.map +1 -0
  16. package/dist/auth/roles.decorator.d.ts +2 -0
  17. package/dist/auth/roles.decorator.js +4 -0
  18. package/dist/auth/roles.decorator.js.map +1 -0
  19. package/dist/auth/user.decorator.d.ts +1 -0
  20. package/dist/auth/user.decorator.js +6 -0
  21. package/dist/auth/user.decorator.js.map +1 -0
  22. package/dist/errors/application.error.d.ts +7 -0
  23. package/dist/errors/application.error.js +12 -0
  24. package/dist/errors/application.error.js.map +1 -0
  25. package/dist/errors/base.error.d.ts +22 -0
  26. package/dist/errors/base.error.js +37 -0
  27. package/dist/errors/base.error.js.map +1 -0
  28. package/dist/errors/business.error.d.ts +7 -0
  29. package/dist/errors/business.error.js +12 -0
  30. package/dist/errors/business.error.js.map +1 -0
  31. package/dist/errors/invalid-payload-business.error.d.ts +7 -0
  32. package/dist/errors/invalid-payload-business.error.js +10 -0
  33. package/dist/errors/invalid-payload-business.error.js.map +1 -0
  34. package/dist/errors/invalid-schema-validation.error.d.ts +9 -0
  35. package/dist/errors/invalid-schema-validation.error.js +8 -0
  36. package/dist/errors/invalid-schema-validation.error.js.map +1 -0
  37. package/dist/errors/not-found-business.error.d.ts +7 -0
  38. package/dist/errors/not-found-business.error.js +20 -0
  39. package/dist/errors/not-found-business.error.js.map +1 -0
  40. package/dist/filters/api-exceptions.filter.d.ts +8 -0
  41. package/dist/filters/api-exceptions.filter.js +113 -0
  42. package/dist/filters/api-exceptions.filter.js.map +1 -0
  43. package/dist/index.d.ts +16 -0
  44. package/dist/index.js +17 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/logger/app-logger.module.d.ts +13 -0
  47. package/dist/logger/app-logger.module.js +42 -0
  48. package/dist/logger/app-logger.module.js.map +1 -0
  49. package/dist/logger/app-logger.token.d.ts +1 -0
  50. package/dist/logger/app-logger.token.js +2 -0
  51. package/dist/logger/app-logger.token.js.map +1 -0
  52. package/dist/logger/logger.async-context.d.ts +10 -0
  53. package/dist/logger/logger.async-context.js +20 -0
  54. package/dist/logger/logger.async-context.js.map +1 -0
  55. package/dist/logger/logger.module.d.ts +2 -0
  56. package/dist/logger/logger.module.js +19 -0
  57. package/dist/logger/logger.module.js.map +1 -0
  58. package/dist/logger/logger.service.d.ts +27 -0
  59. package/dist/logger/logger.service.js +275 -0
  60. package/dist/logger/logger.service.js.map +1 -0
  61. package/dist/middleware/api-logger.middleware.d.ts +8 -0
  62. package/dist/middleware/api-logger.middleware.js +83 -0
  63. package/dist/middleware/api-logger.middleware.js.map +1 -0
  64. package/dist/tsconfig.tsbuildinfo +1 -0
  65. package/dist/util/payload.util.d.ts +4 -0
  66. package/dist/util/payload.util.js +34 -0
  67. package/dist/util/payload.util.js.map +1 -0
  68. package/package.json +38 -0
package/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ Licença MIT
2
+
3
+ Copyright (c) 2025 Cargolift
4
+
5
+ A permissão é concedida, gratuitamente, a qualquer pessoa que obtenha uma cópia deste software e dos arquivos de documentação associados (o "Software"), para lidar com o Software sem restrições, incluindo, sem limitação, os direitos de usar, copiar, modificar, mesclar, publicar, distribuir, sublicenciar e/ou vender cópias do Software, e permitir que pessoas a quem o Software é fornecido o façam, sujeito às seguintes condições:
6
+
7
+ O aviso de copyright acima e este aviso de permissão devem ser incluídos em todas as cópias ou partes substanciais do Software.
8
+
9
+ O SOFTWARE É FORNECIDO "NO ESTADO EM QUE SE ENCONTRA", SEM GARANTIA DE QUALQUER TIPO, EXPRESSA OU IMPLÍCITA, INCLUINDO, MAS NÃO SE LIMITANDO ÀS GARANTIAS DE COMERCIALIZAÇÃO, ADEQUAÇÃO A UM DETERMINADO FIM E NÃO VIOLAÇÃO. EM NENHUMA HIPÓTESE OS AUTORES OU DETENTORES DOS DIREITOS AUTORAIS SERÃO RESPONSÁVEIS POR QUALQUER REIVINDICAÇÃO, DANO OU OUTRA RESPONSABILIDADE, SEJA EM UMA AÇÃO DE CONTRATO, DELITO OU DE OUTRA FORMA, DECORRENTE DE, FORA DE OU EM CONEXÃO COM O SOFTWARE OU O USO OU OUTRAS NEGOCIAÇÕES NO SOFTWARE.
@@ -0,0 +1,44 @@
1
+ # Enriquecimento de LoggerContext com dados do JWT
2
+
3
+ ## Objetivo
4
+ Propagar informações de usuário (id, name, email, ip, user-agent, aplicação de origem) extraídas do token JWT para:
5
+ - Contexto de logs (LoggerContextService)
6
+ - Envelope de mensagens publicadas (IntegrationEventPublisher / RabbitMQPublisherService)
7
+
8
+ ## Fluxo Implementado
9
+ 1. Middleware `APILoggerMiddleware` inicializa o contexto de log por requisição (correlation_id, trace básico, application.function via URL, etc).
10
+ 2. Guard `AuthGuard` valida o token e agora enriquece o contexto via `logger.updateSource()`, mesclando:
11
+ - `user_name` => preferred_username | username | name
12
+ - `user_id` => sub
13
+ - `user_email`=> email
14
+ - `application` => azp | aud
15
+ - `ip` e `user_agent` (cabecalhos / request)
16
+ 3. Controller dispara `IntegrationEventPublisher.publish()`, que:
17
+ - Obtém `ctx = logger.getContext()`
18
+ - Mescla `ctx.source` + `opts.envelope.source` + fallback (ip/user_agent) para construir `envelope.source`
19
+ - Publica headers padronizados: `x-correlation-id`, `x-trace`, `x-source`
20
+
21
+ ## Ponto de Extensão
22
+ Se quiser acrescentar campos customizados (ex: filial, tenant_id):
23
+ ```ts
24
+ this.logger.updateSource({ tenant_id: payload?.tenant_id });
25
+ ```
26
+
27
+ ## Boas Práticas
28
+ - Evitar sobrescrever `source` inteiro; sempre usar `updateSource` para merge incremental.
29
+ - Caso haja Interceptor para métricas, pode ler `logger.getContext().source.user_id` sem recompor payload.
30
+ - Em chamadas internas (sem HTTP), pode-se chamar manualmente:
31
+ ```ts
32
+ this.logger.updateSource({ application: 'internal-task-runner' });
33
+ ```
34
+
35
+ ## Erros/Edge Cases
36
+ - Se o middleware não rodar (ex: rota sem HTTP padrão), o guard ainda enriquece parcialmente o contexto.
37
+ - Campos ausentes no token não sobrescrevem os já registrados.
38
+ - `ip` extraído de `x-forwarded-for` (primeiro IP) se existir.
39
+
40
+ ## Alternativas Consideradas
41
+ - Interceptor global pós-guard (maior latência e ordem de execução mais complexa).
42
+ - Decorator por controller (repetitivo e sujeito a esquecimento).
43
+
44
+ A abordagem atual centraliza a responsabilidade de *enriquecimento* no mesmo ponto da *autenticação*, garantindo consistência.
package/README.md ADDED
@@ -0,0 +1,232 @@
1
+ # @cargolift-cdi/common
2
+
3
+ Utilidades comuns e padronização de erros para projetos Cargolift CDI (NestJS).
4
+
5
+ Este pacote provê:
6
+ - Classes de erro de domínio (BusinessError) com código, dados adicionais e causa encadeada
7
+ - Filtro global de exceções para APIs (APIExceptionsFilter) já integrado ao util-logger
8
+
9
+
10
+ ## Instalação
11
+
12
+ Requisitos:
13
+ - Node.js LTS (18+) e npm
14
+ - Peer dependency: `@nestjs/common@^11`
15
+
16
+ Instale:
17
+
18
+ ```cmd
19
+ npm i @cargolift-cdi/common
20
+ ```
21
+
22
+ O pacote depende de `@cargolift-cdi/util-logger` (instalado automaticamente).
23
+
24
+
25
+ ## Uso rápido
26
+
27
+ ### 1) Aplicar o filtro global de exceções (NestJS)
28
+
29
+ ```ts
30
+ import { NestFactory } from '@nestjs/core';
31
+ import { AppModule } from './app.module';
32
+ import { APIExceptionsFilter } from '@cargolift-cdi/common';
33
+ import { LoggerContextService } from '@cargolift-cdi/util-logger';
34
+
35
+ async function bootstrap() {
36
+ const app = await NestFactory.create(AppModule, { bufferLogs: true });
37
+
38
+ // Usa o LoggerContextService já registrado no container
39
+ const logger = app.get(LoggerContextService);
40
+ app.useGlobalFilters(new APIExceptionsFilter(logger));
41
+
42
+ await app.listen(3000);
43
+ }
44
+
45
+ bootstrap();
46
+ ```
47
+
48
+ O filtro padroniza o payload de erro, enriquece logs com `correlation_id` e trata mensagens conhecidas (ex.: erros de rede).
49
+
50
+ Alternativa: registrar via provider global (APP_FILTER):
51
+
52
+ ```ts
53
+ import { Module } from '@nestjs/common';
54
+ import { APP_FILTER } from '@nestjs/core';
55
+ import { APIExceptionsFilter } from '@cargolift-cdi/common';
56
+ // Certifique-se de que o LoggerContextService esteja disponível no container
57
+ import { LoggerContextService } from '@cargolift-cdi/util-logger';
58
+
59
+ @Module({
60
+ providers: [
61
+ LoggerContextService, // ou importe o módulo que o fornece, se existir
62
+ { provide: APP_FILTER, useClass: APIExceptionsFilter },
63
+ ],
64
+ })
65
+ export class AppModule {}
66
+ ```
67
+
68
+ ### 2) Lançar erros de negócio no seu código
69
+
70
+ ```ts
71
+ import { NotFoundBusinessError, GenericBusinessError } from '@cargolift-cdi/common';
72
+
73
+ // Recurso não encontrado
74
+ throw new NotFoundBusinessError('Order', '12345');
75
+
76
+ // Erro de negócio genérico com código e dados extras
77
+ throw new GenericBusinessError('Falha no provedor', {
78
+ code: 'PAYMENT_PROVIDER_ERROR',
79
+ data: { context: 'Pagamento', errorCode: 'PX-999', provider: 'AcmePay' },
80
+ });
81
+ ```
82
+
83
+
84
+ ## API pública (exportada por `index`)
85
+
86
+ - `BusinessError` (abstrata)
87
+ - Base para erros de domínio. Suporta `code?: string`, `data?: Record<string, unknown>`, `cause?: unknown` e serialização segura via `toJSON()`.
88
+ - `GenericBusinessError`
89
+ - Erro de negócio genérico (mensagem padrão "Generic Business error" quando não informada). Útil para normalizar exceções desconhecidas.
90
+ - `NotFoundBusinessError`
91
+ - Especialização para recursos não encontrados: construtor `(resourceType: string, resourceId: string|number, message?, options?)`.
92
+ - `APIExceptionsFilter` (NestJS)
93
+ - Filtro global de exceções. Decide tipo do erro (business/application), aplica códigos padrão e registra logs estruturados via `LoggerContextService`.
94
+
95
+ Observação: existem classes internas adicionais (ex.: `ApplicationError`, `GenericApplicationError`) que podem evoluir; utilize apenas a API pública acima para evitar quebras.
96
+
97
+ ## Contexto de Logs com AsyncLocalStorage (v2)
98
+
99
+ A partir da versão que introduz esta seção, o `LoggerContextService` passou a ser singleton (escopo DEFAULT) e o isolamento por requisição/mensagem é garantido via `AsyncLocalStorage`.
100
+
101
+ Benefícios:
102
+ - Menos alocações de instâncias (melhor para alto throughput)
103
+ - Propagação automática de contexto por callbacks/promises sem passar manualmente
104
+ - Publishers/clients apenas usam `logger.getContext()`
105
+
106
+ Helpers exportados:
107
+ ```ts
108
+ import { runWithLoggerContext, getLoggerContext, updateLoggerContext } from '@cargolift-cdi/common';
109
+
110
+ runWithLoggerContext({ correlation_id: 'abc' }, () => {
111
+ // Tudo aqui dentro (e awaits) mantém o contexto
112
+ });
113
+ ```
114
+
115
+ Fluxo HTTP (middleware `APILoggerMiddleware`):
116
+ 1. Abre `runWithLoggerContext({})`
117
+ 2. Chama `logger.setContextRequest(req)` (gera/propaga `correlation_id` e `trace`)
118
+ 3. Todos os logs subsequentes compartilham o mesmo contexto
119
+
120
+ Fluxo RabbitMQ (consumer):
121
+ 1. Cria um child logger a partir dos headers da mensagem (`childFromRabbit`)
122
+ 2. Semeia o ALS com `runWithLoggerContext(child.getContext(), processMessage)`
123
+ 3. Dentro do processamento usa-se o `logger` base normalmente
124
+
125
+ Caso precise anexar dados adicionais no meio da execução:
126
+ ```ts
127
+ updateLoggerContext({ caller_info: { type: 'user', id: 'u-1' } });
128
+ ```
129
+
130
+ Se um log for emitido fora de um escopo ALS (ex.: antes de bootstrap), o logger ainda funcionará, porém sem `correlation_id` fixo (um novo poderá ser gerado quando o contexto for definido).
131
+
132
+
133
+
134
+ ## Detalhes das classes
135
+
136
+ ### BusinessError
137
+
138
+ Contrato básico:
139
+ - `name: string` — Nome da classe (ex.: `NotFoundBusinessError`)
140
+ - `message?: string` — Mensagem humana
141
+ - `code?: string` — Ex.: `BUSINESS_RESOURCE_NOT_FOUND`, `INVALID_PAYLOAD`
142
+ - `data?: Record<string, unknown>` — Dados serializáveis extras
143
+ - `cause?: unknown` — Erro original para encadeamento
144
+ - `toJSON()` — Retorna objeto serializável, inclusive com `stack` enumerável e `cause` segura
145
+
146
+ `BusinessErrorOptions`:
147
+ ```ts
148
+ type BusinessErrorOptions = {
149
+ code?: string;
150
+ cause?: unknown;
151
+ data?: Record<string, unknown>;
152
+ };
153
+ ```
154
+
155
+ ### NotFoundBusinessError
156
+
157
+ - Código padrão: `BUSINESS_RESOURCE_NOT_FOUND`
158
+ - `data`: `{ resourceType: string, resourceId: string|number }`
159
+
160
+ ### GenericBusinessError
161
+
162
+ - Código padrão: `BUSINESS_ERROR`
163
+ - Permite enviar `data` adicional e causa original (`cause`).
164
+
165
+ ### APIExceptionsFilter
166
+
167
+ - Inspeciona exceções do NestJS (`HttpException`) e erros comuns de infraestrutura (ex.: `ECONNREFUSED`, `ETIMEDOUT`)
168
+ - Cria/propaga `correlation_id` no contexto de log
169
+ - Resposta JSON padrão:
170
+
171
+ ```json
172
+ {
173
+ "message": "<mensagem>",
174
+ "error": {
175
+ "statusCode": 500,
176
+ "timestamp": "2025-01-01T00:00:00.000Z",
177
+ "path": "/rota",
178
+ "errorCode": "INTERNAL_ERROR"
179
+ }
180
+ }
181
+ ```
182
+
183
+
184
+ # App Logger (Global)
185
+ Use AppLoggerModule para configurar um log global com contexto.
186
+
187
+ ```ts
188
+ import { AppLoggerModule, APP_LOGGER, LoggerContextService } from '@cargolift-cdi/common';
189
+
190
+ @Module({
191
+ imports: [
192
+ AppLoggerModule.forRoot({
193
+ application: {
194
+ name: 'middleware-esb',
195
+ function: 'service',
196
+ },
197
+ }),
198
+ ],
199
+ })
200
+ export class AppModule {}
201
+
202
+ @Injectable()
203
+ export class SomeService {
204
+ constructor(@Inject(APP_LOGGER) private readonly appLogger: LoggerContextService) {}
205
+
206
+ doStuff() {
207
+ this.appLogger.log('App level log');
208
+ }
209
+ }
210
+ ```
211
+
212
+ Notes:
213
+ - Este log possui um contexto único; não chame `setContext`.
214
+ - Para logs por mensagem/requisição , use a versão de escopo TRANSIENT `LoggerContextService` e chame `setContextRabbitMQ`/`setContextRequest`.
215
+
216
+
217
+
218
+ ## Scripts do projeto
219
+
220
+ - `npm run build` — Compila TypeScript para `dist/`
221
+ - `npm publish` — Publica (executa `build` no `prepublishOnly`)
222
+
223
+
224
+ ## Contribuição
225
+
226
+ - Abra issues e PRs no GitHub: https://github.com/cargolift-cdi/common
227
+ - Padrões: TypeScript, NestJS 11, commits claros, linters/formatters do seu editor
228
+
229
+
230
+ ## Licença
231
+
232
+ MIT © Cargolift CDI
@@ -0,0 +1,2 @@
1
+ export declare const API_CLIENT_ID_KEY = "api_client_id";
2
+ export declare const ApiClient: (clientId: string) => import("@nestjs/common").CustomDecorator<string>;
@@ -0,0 +1,4 @@
1
+ import { SetMetadata } from '@nestjs/common';
2
+ export const API_CLIENT_ID_KEY = 'api_client_id';
3
+ export const ApiClient = (clientId) => SetMetadata(API_CLIENT_ID_KEY, clientId);
4
+ //# sourceMappingURL=api-client.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.decorator.js","sourceRoot":"","sources":["../../src/auth/api-client.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,CAAC,MAAM,iBAAiB,GAAG,eAAe,CAAC;AACjD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,QAAgB,EAAE,EAAE,CAAC,WAAW,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { CanActivate, ExecutionContext } from "@nestjs/common";
2
+ import { Reflector } from "@nestjs/core";
3
+ import { JwtVerifierService } from "./jwt-verifier.service.js";
4
+ import { LoggerContextService } from "../logger/logger.service.js";
5
+ export declare class AuthGuard implements CanActivate {
6
+ private readonly jwtVerifier;
7
+ private readonly reflector;
8
+ private readonly logger;
9
+ constructor(jwtVerifier: JwtVerifierService, reflector: Reflector, logger: LoggerContextService);
10
+ private baseClientId;
11
+ private resolveApiClientId;
12
+ canActivate(context: ExecutionContext): Promise<boolean>;
13
+ }
@@ -0,0 +1,95 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Injectable, UnauthorizedException, ForbiddenException, InternalServerErrorException } from "@nestjs/common";
11
+ import { Reflector } from "@nestjs/core";
12
+ import { JwtVerifierService } from "./jwt-verifier.service.js";
13
+ import { LoggerContextService } from "../logger/logger.service.js";
14
+ import { ROLES_KEY } from "./roles.decorator.js";
15
+ import { API_CLIENT_ID_KEY } from "./api-client.decorator.js";
16
+ let AuthGuard = class AuthGuard {
17
+ constructor(jwtVerifier, reflector, logger) {
18
+ this.jwtVerifier = jwtVerifier;
19
+ this.reflector = reflector;
20
+ this.logger = logger;
21
+ }
22
+ baseClientId() {
23
+ return process.env.KEYCLOAK_AUDIENCE || "api.util";
24
+ }
25
+ resolveApiClientId(context, payload) {
26
+ const decorated = this.reflector.getAllAndOverride(API_CLIENT_ID_KEY, [context.getHandler(), context.getClass()]);
27
+ if (decorated)
28
+ return decorated;
29
+ if (payload?.aud && typeof payload.aud === "string")
30
+ return payload.aud;
31
+ return this.baseClientId();
32
+ }
33
+ async canActivate(context) {
34
+ let request;
35
+ try {
36
+ request = context.switchToHttp().getRequest();
37
+ }
38
+ catch (e) {
39
+ throw new InternalServerErrorException("Erro ao obter dados de autorização da requisição: " + e.message);
40
+ }
41
+ const auth = request.headers["authorization"] || request.headers["Authorization"];
42
+ if (!auth || typeof auth !== "string" || !auth.startsWith("Bearer ")) {
43
+ throw new UnauthorizedException("Autorização ausente ou inválida");
44
+ }
45
+ const token = auth.substring("Bearer ".length).trim();
46
+ let payload;
47
+ try {
48
+ payload = await this.jwtVerifier.verify(token);
49
+ }
50
+ catch (e) {
51
+ throw new UnauthorizedException("Falha ao obter autorização: " + (e.message || "Token inválido"));
52
+ }
53
+ request.user = payload;
54
+ try {
55
+ const ip = payload?.clientAddress ||
56
+ request.headers["x-forwarded-for"]?.split(",")[0]?.trim() ||
57
+ request.ip ||
58
+ request.connection?.remoteAddress ||
59
+ undefined;
60
+ const userAgent = request.headers["user-agent"];
61
+ const username = payload?.preferred_username || payload?.username || payload?.name;
62
+ const email = payload?.email;
63
+ const userId = payload?.sub;
64
+ this.logger.updateSource({
65
+ ip: ip,
66
+ user_agent: userAgent,
67
+ user_email: email,
68
+ user_id: userId,
69
+ user_name: username,
70
+ application: payload?.azp || payload?.aud,
71
+ });
72
+ }
73
+ catch {
74
+ }
75
+ const requiredRoles = this.reflector.getAllAndOverride(ROLES_KEY, [context.getHandler(), context.getClass()]);
76
+ if (!requiredRoles || requiredRoles.length === 0) {
77
+ return true;
78
+ }
79
+ const apiClientId = this.resolveApiClientId(context, payload);
80
+ const roles = payload?.resource_access?.[apiClientId]?.roles || [];
81
+ const missing = requiredRoles.filter((r) => !roles.includes(r));
82
+ if (missing.length > 0) {
83
+ throw new ForbiddenException(`Sem permissão para acessar este recurso. Cliente: ${apiClientId}, regra: ${missing.join(", ")}`);
84
+ }
85
+ return true;
86
+ }
87
+ };
88
+ AuthGuard = __decorate([
89
+ Injectable(),
90
+ __metadata("design:paramtypes", [JwtVerifierService,
91
+ Reflector,
92
+ LoggerContextService])
93
+ ], AuthGuard);
94
+ export { AuthGuard };
95
+ //# sourceMappingURL=auth.guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.guard.js","sourceRoot":"","sources":["../../src/auth/auth.guard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare class AuthModule {
2
+ }
@@ -0,0 +1,19 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Module } from '@nestjs/common';
8
+ import { JwtVerifierService } from './jwt-verifier.service.js';
9
+ import { AuthGuard } from './auth.guard.js';
10
+ let AuthModule = class AuthModule {
11
+ };
12
+ AuthModule = __decorate([
13
+ Module({
14
+ providers: [JwtVerifierService, AuthGuard],
15
+ exports: [JwtVerifierService, AuthGuard],
16
+ })
17
+ ], AuthModule);
18
+ export { AuthModule };
19
+ //# sourceMappingURL=auth.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../../src/auth/auth.module.ts"],"names":[],"mappings":";;;;;;AACA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAMrC,IAAM,UAAU,GAAhB,MAAM,UAAU;CAAG,CAAA;AAAb,UAAU;IAJtB,MAAM,CAAC;QACN,SAAS,EAAE,CAAC,kBAAkB,EAAE,SAAS,CAAC;QAC1C,OAAO,EAAE,CAAC,kBAAkB,EAAE,SAAS,CAAC;KACzC,CAAC;GACW,UAAU,CAAG"}
@@ -0,0 +1,22 @@
1
+ import { OnModuleInit } from '@nestjs/common';
2
+ import { LoggerContextService } from '../logger/logger.service.js';
3
+ export declare class JwtVerifierService implements OnModuleInit {
4
+ private readonly logger;
5
+ private openIdConfig?;
6
+ private keyCache;
7
+ private configFetchedAt?;
8
+ constructor(logger: LoggerContextService);
9
+ private readonly CONFIG_TTL_MS;
10
+ private readonly KEY_TTL_MS;
11
+ private get issuer();
12
+ private get audience();
13
+ private get wellKnownUrl();
14
+ private fetchOpenIdConfig;
15
+ private fetchJwks;
16
+ private getKeyByKid;
17
+ private parseJwt;
18
+ private verifySignatureRS256;
19
+ private assertClaims;
20
+ verify(token: string): Promise<any>;
21
+ onModuleInit(): Promise<void>;
22
+ }
@@ -0,0 +1,164 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Injectable } from '@nestjs/common';
11
+ import { createPublicKey, createVerify } from 'crypto';
12
+ import { LoggerContextService } from '../logger/logger.service.js';
13
+ function base64urlDecode(input) {
14
+ input = input.replace(/-/g, '+').replace(/_/g, '/');
15
+ const pad = input.length % 4;
16
+ if (pad)
17
+ input += '='.repeat(4 - pad);
18
+ return Buffer.from(input, 'base64');
19
+ }
20
+ let JwtVerifierService = class JwtVerifierService {
21
+ constructor(logger) {
22
+ this.logger = logger;
23
+ this.keyCache = new Map();
24
+ this.CONFIG_TTL_MS = 60_000;
25
+ this.KEY_TTL_MS = 10 * 60_000;
26
+ }
27
+ get issuer() {
28
+ return process.env.KEYCLOAK_ISSUER;
29
+ }
30
+ get audience() {
31
+ return process.env.KEYCLOAK_AUDIENCE;
32
+ }
33
+ get wellKnownUrl() {
34
+ const baseUrl = process.env.KEYCLOAK_BASE_URL;
35
+ const realm = process.env.KEYCLOAK_REALM;
36
+ return `${baseUrl}/realms/${realm}/.well-known/openid-configuration`;
37
+ }
38
+ async fetchOpenIdConfig() {
39
+ const now = Date.now();
40
+ if (this.openIdConfig && this.configFetchedAt && now - this.configFetchedAt < this.CONFIG_TTL_MS) {
41
+ return this.openIdConfig;
42
+ }
43
+ const res = await fetch(this.wellKnownUrl, { method: 'GET' }).catch(err => {
44
+ throw new Error(`Falha ao buscar configuração OpenID (${err.message})`);
45
+ });
46
+ if (!res.ok) {
47
+ throw new Error(`Falha ao carregar configuração OpenID: ${res.status}`);
48
+ }
49
+ const json = await res.json();
50
+ this.openIdConfig = { issuer: json.issuer, jwks_uri: json.jwks_uri };
51
+ this.configFetchedAt = now;
52
+ return this.openIdConfig;
53
+ }
54
+ async fetchJwks() {
55
+ const { jwks_uri } = await this.fetchOpenIdConfig();
56
+ const res = await fetch(jwks_uri, { method: 'GET' }).catch(err => {
57
+ throw new Error(`Falha ao buscar JWKS (${err.message})`);
58
+ });
59
+ if (!res.ok) {
60
+ throw new Error(`Falha ao carregar JWKS: ${res.status}`);
61
+ }
62
+ return res.json();
63
+ }
64
+ async getKeyByKid(kid) {
65
+ const now = Date.now();
66
+ const cached = this.keyCache.get(kid);
67
+ if (cached && now - cached.fetchedAt < this.KEY_TTL_MS) {
68
+ return cached.key;
69
+ }
70
+ const jwks = await this.fetchJwks();
71
+ const jwk = jwks.keys.find(k => k.kid === kid);
72
+ if (!jwk) {
73
+ throw new Error(`Chave com kid ${kid} não encontrada no JWKS`);
74
+ }
75
+ const key = createPublicKey({ key: jwk, format: 'jwk' });
76
+ this.keyCache.set(kid, { key, fetchedAt: now });
77
+ return key;
78
+ }
79
+ parseJwt(token) {
80
+ const parts = token.split('.');
81
+ if (parts.length !== 3)
82
+ throw new Error('Invalid JWT format');
83
+ const [encodedHeader, encodedPayload, encodedSig] = parts;
84
+ const header = JSON.parse(base64urlDecode(encodedHeader).toString('utf8'));
85
+ const payload = JSON.parse(base64urlDecode(encodedPayload).toString('utf8'));
86
+ const signature = base64urlDecode(encodedSig);
87
+ const signingInput = `${encodedHeader}.${encodedPayload}`;
88
+ return { header, payload, signature, signingInput };
89
+ }
90
+ verifySignatureRS256(signingInput, signature, publicKey) {
91
+ const verifier = createVerify('RSA-SHA256');
92
+ verifier.update(signingInput);
93
+ verifier.end();
94
+ return verifier.verify(publicKey, signature);
95
+ }
96
+ assertClaims(payload) {
97
+ const now = Math.floor(Date.now() / 1000);
98
+ if (typeof payload.exp === 'number' && now >= payload.exp) {
99
+ throw new Error('Token expirado');
100
+ }
101
+ if (typeof payload.nbf === 'number' && now < payload.nbf) {
102
+ throw new Error('Token ainda não válido (nbf)');
103
+ }
104
+ if (this.issuer && payload.iss !== this.issuer) {
105
+ throw new Error(`Invalid issuer: expected ${this.issuer}`);
106
+ }
107
+ if (this.audience) {
108
+ const aud = payload.aud;
109
+ const ok = aud === this.audience ||
110
+ (Array.isArray(aud) && aud.includes(this.audience));
111
+ if (!ok)
112
+ throw new Error(`Invalid audience, expected ${this.audience}`);
113
+ }
114
+ }
115
+ async verify(token) {
116
+ const { header, payload, signature, signingInput } = this.parseJwt(token);
117
+ if (header.alg !== 'RS256') {
118
+ throw new Error(`Unsupported alg: ${header.alg}`);
119
+ }
120
+ if (!header.kid) {
121
+ throw new Error('JWT missing kid');
122
+ }
123
+ const key = await this.getKeyByKid(header.kid);
124
+ const valid = this.verifySignatureRS256(signingInput, signature, key);
125
+ if (!valid)
126
+ throw new Error('Token com assinatura inválida');
127
+ this.assertClaims(payload);
128
+ return payload;
129
+ }
130
+ async onModuleInit() {
131
+ try {
132
+ if (!process.env.KEYCLOAK_BASE_URL || !process.env.KEYCLOAK_REALM) {
133
+ this.logger.warn('JWT verifier warmup skipped: KEYCLOAK environment variables not fully set');
134
+ return;
135
+ }
136
+ await this.fetchOpenIdConfig();
137
+ const jwks = await this.fetchJwks();
138
+ const now = Date.now();
139
+ let loaded = 0;
140
+ for (const jwk of jwks.keys) {
141
+ if (!jwk.kid)
142
+ continue;
143
+ try {
144
+ const key = createPublicKey({ key: jwk, format: 'jwk' });
145
+ this.keyCache.set(jwk.kid, { key, fetchedAt: now });
146
+ loaded++;
147
+ }
148
+ catch (e) {
149
+ this.logger.warn(`Falha ao preparar chave kid=${jwk.kid}: ${e.message}`);
150
+ }
151
+ }
152
+ this.logger.log(`JWT verifier warmup concluído: ${loaded} chave(s) em cache`);
153
+ }
154
+ catch (e) {
155
+ this.logger.warn(`JWT verifier warmup falhou: ${e.message}`);
156
+ }
157
+ }
158
+ };
159
+ JwtVerifierService = __decorate([
160
+ Injectable(),
161
+ __metadata("design:paramtypes", [LoggerContextService])
162
+ ], JwtVerifierService);
163
+ export { JwtVerifierService };
164
+ //# sourceMappingURL=jwt-verifier.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt-verifier.service.js","sourceRoot":"","sources":["../../src/auth/jwt-verifier.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const ROLES_KEY = "required_roles";
2
+ export declare const RequireRoles: (...roles: string[]) => import("@nestjs/common").CustomDecorator<string>;
@@ -0,0 +1,4 @@
1
+ import { SetMetadata } from '@nestjs/common';
2
+ export const ROLES_KEY = 'required_roles';
3
+ export const RequireRoles = (...roles) => SetMetadata(ROLES_KEY, roles);
4
+ //# sourceMappingURL=roles.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roles.decorator.js","sourceRoot":"","sources":["../../src/auth/roles.decorator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,CAAC,MAAM,SAAS,GAAG,gBAAgB,CAAC;AAC1C,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAG,KAAe,EAAE,EAAE,CAAC,WAAW,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC"}