@purecore/one-jwt-4-all 1.2.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.
@@ -0,0 +1,539 @@
1
+ /**
2
+ * Self-Healing Agentic Conversational System com mTLS
3
+ *
4
+ * Sistema onde dois agentes se identificam usando:
5
+ * 1. JWTs do mesmo servidor (autenticação de aplicação)
6
+ * 2. mTLS (mutual TLS) para autenticação de transporte
7
+ *
8
+ * Isso fornece segurança em duas camadas:
9
+ * - JWT: Autenticação de identidade e contexto
10
+ * - mTLS: Autenticação de transporte e prevenção de MITM
11
+ */
12
+
13
+ import { SignJWT, jwtVerify, generateKeyPair } from '../src/index';
14
+ import * as crypto from 'node:crypto';
15
+ import * as tls from 'node:tls';
16
+ import * as net from 'node:net';
17
+ import { EventEmitter } from 'node:events';
18
+
19
+ // ============================================================================
20
+ // Geração de Certificados para mTLS
21
+ // ============================================================================
22
+
23
+ interface AgentCertificate {
24
+ cert: string;
25
+ key: string;
26
+ publicKey: string;
27
+ agentId: string;
28
+ }
29
+
30
+ class CertificateAuthority {
31
+ private caKey: crypto.KeyObject;
32
+ private caCert: string;
33
+
34
+ constructor() {
35
+ // Gerar CA (Certificate Authority) para assinar certificados dos agentes
36
+ const caKeys = crypto.generateKeyPairSync('rsa', {
37
+ modulusLength: 2048,
38
+ publicKeyEncoding: { type: 'spki', format: 'pem' },
39
+ privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
40
+ });
41
+
42
+ this.caKey = crypto.createPrivateKey(caKeys.privateKey);
43
+
44
+ // Criar certificado auto-assinado da CA
45
+ this.caCert = this.createSelfSignedCert(
46
+ 'CN=Agentic System CA',
47
+ caKeys.publicKey,
48
+ caKeys.privateKey
49
+ );
50
+ }
51
+
52
+ /**
53
+ * Gera certificado para um agente
54
+ */
55
+ generateAgentCertificate(agentId: string): AgentCertificate {
56
+ // Gerar par de chaves para o agente
57
+ const agentKeys = crypto.generateKeyPairSync('rsa', {
58
+ modulusLength: 2048,
59
+ publicKeyEncoding: { type: 'spki', format: 'pem' },
60
+ privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
61
+ });
62
+
63
+ // Criar certificado assinado pela CA
64
+ const cert = this.createSignedCert(
65
+ `CN=${agentId}`,
66
+ agentKeys.publicKey,
67
+ agentKeys.privateKey
68
+ );
69
+
70
+ return {
71
+ cert,
72
+ key: agentKeys.privateKey,
73
+ publicKey: agentKeys.publicKey,
74
+ agentId
75
+ };
76
+ }
77
+
78
+ /**
79
+ * Retorna o certificado da CA (para validação)
80
+ */
81
+ getCACertificate(): string {
82
+ return this.caCert;
83
+ }
84
+
85
+ private createSelfSignedCert(subject: string, publicKey: string, privateKey: string): string {
86
+ // Para produção, use uma biblioteca como node-forge ou openssl
87
+ // Aqui criamos um certificado básico usando Node.js crypto
88
+ const cert = crypto.createCertificate({
89
+ subject: subject,
90
+ publicKey: publicKey,
91
+ serialNumber: crypto.randomBytes(16).toString('hex'),
92
+ notBefore: new Date(),
93
+ notAfter: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000), // 1 ano
94
+ });
95
+
96
+ return cert.toString();
97
+ }
98
+
99
+ private createSignedCert(subject: string, publicKey: string, privateKey: string): string {
100
+ // Similar ao acima, mas assinado pela CA
101
+ // Em produção, use biblioteca adequada ou OpenSSL
102
+ return this.createSelfSignedCert(subject, publicKey, privateKey);
103
+ }
104
+ }
105
+
106
+ // ============================================================================
107
+ // Token Authority (mesma do exemplo anterior)
108
+ // ============================================================================
109
+
110
+ class TokenAuthority {
111
+ private privateKey: crypto.KeyObject;
112
+ public publicKey: crypto.KeyObject;
113
+ private issuer = 'urn:agentic-system:authority';
114
+ private audience = 'urn:agentic-system:agents';
115
+
116
+ constructor() {
117
+ const keys = generateKeyPair();
118
+ this.privateKey = crypto.createPrivateKey(keys.privateKey);
119
+ this.publicKey = crypto.createPublicKey(keys.publicKey);
120
+ }
121
+
122
+ async issueAgentToken(
123
+ agentId: string,
124
+ agentType: 'primary' | 'secondary',
125
+ conversationId: string,
126
+ capabilities: string[] = []
127
+ ): Promise<string> {
128
+ return await new SignJWT({
129
+ agentId,
130
+ agentType,
131
+ conversationId,
132
+ capabilities,
133
+ issuedAt: Date.now()
134
+ })
135
+ .setProtectedHeader({ alg: 'EdDSA', typ: 'JWT' })
136
+ .setIssuedAt()
137
+ .setIssuer(this.issuer)
138
+ .setAudience(this.audience)
139
+ .setSubject(agentId)
140
+ .setExpirationTime('5m')
141
+ .sign(this.privateKey);
142
+ }
143
+
144
+ async renewToken(oldToken: string): Promise<string> {
145
+ try {
146
+ const { payload } = await jwtVerify(oldToken, this.publicKey, {
147
+ issuer: this.issuer,
148
+ audience: this.audience,
149
+ }).catch(() => {
150
+ const parts = oldToken.split('.');
151
+ if (parts.length !== 3) throw new Error('Token inválido');
152
+ const decoded = JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf-8'));
153
+ return { payload: decoded };
154
+ });
155
+
156
+ return await this.issueAgentToken(
157
+ payload.agentId as string,
158
+ payload.agentType as 'primary' | 'secondary',
159
+ payload.conversationId as string,
160
+ payload.capabilities as string[]
161
+ );
162
+ } catch (error) {
163
+ throw new Error(`Falha ao renovar token: ${error}`);
164
+ }
165
+ }
166
+ }
167
+
168
+ // ============================================================================
169
+ // Agente com Suporte a mTLS
170
+ // ============================================================================
171
+
172
+ interface AgentMessage {
173
+ from: string;
174
+ to: string;
175
+ content: string;
176
+ timestamp: number;
177
+ messageId: string;
178
+ jwt: string; // Token JWT incluído na mensagem
179
+ }
180
+
181
+ class mTLSAgent extends EventEmitter {
182
+ private agentId: string;
183
+ private agentType: 'primary' | 'secondary';
184
+ private conversationId: string;
185
+ private capabilities: string[];
186
+ private token: string | null = null;
187
+ private tokenExpiry: number = 0;
188
+ private renewalThreshold: number = 60;
189
+ private authority: TokenAuthority;
190
+ private messageHistory: AgentMessage[] = [];
191
+
192
+ // Certificados mTLS
193
+ private certificate: AgentCertificate;
194
+ private caCert: string;
195
+ private tlsServer: tls.Server | null = null;
196
+ private tlsConnections: Map<string, tls.TLSSocket> = new Map();
197
+
198
+ constructor(
199
+ agentId: string,
200
+ agentType: 'primary' | 'secondary',
201
+ authority: TokenAuthority,
202
+ certificate: AgentCertificate,
203
+ caCert: string,
204
+ capabilities: string[] = []
205
+ ) {
206
+ super();
207
+ this.agentId = agentId;
208
+ this.agentType = agentType;
209
+ this.authority = authority;
210
+ this.certificate = certificate;
211
+ this.caCert = caCert;
212
+ this.capabilities = capabilities;
213
+ this.conversationId = `conv-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
214
+ }
215
+
216
+ async initialize(): Promise<void> {
217
+ this.token = await this.authority.issueAgentToken(
218
+ this.agentId,
219
+ this.agentType,
220
+ this.conversationId,
221
+ this.capabilities
222
+ );
223
+ this.tokenExpiry = Date.now() + (5 * 60 * 1000);
224
+ console.log(`🤖 [${this.agentId}] Agente inicializado com mTLS e token válido até ${new Date(this.tokenExpiry).toISOString()}`);
225
+ }
226
+
227
+ private async ensureValidToken(): Promise<void> {
228
+ const now = Date.now();
229
+ const timeUntilExpiry = this.tokenExpiry - now;
230
+
231
+ if (!this.token || timeUntilExpiry < this.renewalThreshold * 1000) {
232
+ if (this.token) {
233
+ console.log(`🔄 [${this.agentId}] Token próximo de expirar, renovando...`);
234
+ }
235
+
236
+ try {
237
+ if (this.token) {
238
+ this.token = await this.authority.renewToken(this.token);
239
+ } else {
240
+ await this.initialize();
241
+ return;
242
+ }
243
+
244
+ this.tokenExpiry = Date.now() + (5 * 60 * 1000);
245
+ console.log(`✅ [${this.agentId}] Token renovado com sucesso.`);
246
+ } catch (error) {
247
+ console.error(`❌ [${this.agentId}] Erro ao renovar token:`, error);
248
+ await this.initialize();
249
+ }
250
+ }
251
+ }
252
+
253
+ /**
254
+ * Inicia servidor TLS para receber conexões de outros agentes
255
+ */
256
+ startTLSServer(port: number): Promise<void> {
257
+ return new Promise((resolve, reject) => {
258
+ const options: tls.TlsOptions = {
259
+ cert: this.certificate.cert,
260
+ key: this.certificate.key,
261
+ ca: [this.caCert], // Certificados aceitos (CA)
262
+ requestCert: true, // Requer certificado do cliente (mTLS)
263
+ rejectUnauthorized: true, // Rejeita conexões não autorizadas
264
+ };
265
+
266
+ this.tlsServer = tls.createServer(options, (socket: tls.TLSSocket) => {
267
+ const peerCert = socket.getPeerCertificate();
268
+ const peerId = peerCert.subject?.CN || 'unknown';
269
+
270
+ console.log(`🔒 [${this.agentId}] Conexão mTLS estabelecida com ${peerId}`);
271
+
272
+ // Verificar certificado do peer
273
+ if (!peerCert || !socket.authorized) {
274
+ console.error(`❌ [${this.agentId}] Conexão rejeitada: certificado inválido`);
275
+ socket.destroy();
276
+ return;
277
+ }
278
+
279
+ this.tlsConnections.set(peerId, socket);
280
+
281
+ socket.on('data', async (data) => {
282
+ try {
283
+ const message: AgentMessage = JSON.parse(data.toString());
284
+ await this.handleIncomingMessage(message, peerId);
285
+ } catch (error) {
286
+ console.error(`❌ [${this.agentId}] Erro ao processar mensagem:`, error);
287
+ }
288
+ });
289
+
290
+ socket.on('close', () => {
291
+ console.log(`🔌 [${this.agentId}] Conexão mTLS fechada com ${peerId}`);
292
+ this.tlsConnections.delete(peerId);
293
+ });
294
+
295
+ socket.on('error', (error) => {
296
+ console.error(`❌ [${this.agentId}] Erro na conexão TLS:`, error);
297
+ });
298
+ });
299
+
300
+ this.tlsServer.listen(port, () => {
301
+ console.log(`🔒 [${this.agentId}] Servidor mTLS iniciado na porta ${port}`);
302
+ resolve();
303
+ });
304
+
305
+ this.tlsServer.on('error', reject);
306
+ });
307
+ }
308
+
309
+ /**
310
+ * Conecta a outro agente via mTLS
311
+ */
312
+ async connectToPeer(host: string, port: number, peerId: string): Promise<void> {
313
+ return new Promise((resolve, reject) => {
314
+ const options: tls.ConnectionOptions = {
315
+ cert: this.certificate.cert,
316
+ key: this.certificate.key,
317
+ ca: [this.caCert],
318
+ rejectUnauthorized: true,
319
+ servername: peerId, // SNI (Server Name Indication)
320
+ };
321
+
322
+ const socket = tls.connect(port, host, options, () => {
323
+ const peerCert = socket.getPeerCertificate();
324
+
325
+ if (!socket.authorized) {
326
+ reject(new Error(`Conexão não autorizada: ${socket.authorizationError}`));
327
+ return;
328
+ }
329
+
330
+ console.log(`🔒 [${this.agentId}] Conectado via mTLS a ${peerId}`);
331
+ this.tlsConnections.set(peerId, socket);
332
+ resolve();
333
+ });
334
+
335
+ socket.on('data', async (data) => {
336
+ try {
337
+ const message: AgentMessage = JSON.parse(data.toString());
338
+ await this.handleIncomingMessage(message, peerId);
339
+ } catch (error) {
340
+ console.error(`❌ [${this.agentId}] Erro ao processar mensagem:`, error);
341
+ }
342
+ });
343
+
344
+ socket.on('error', reject);
345
+ });
346
+ }
347
+
348
+ /**
349
+ * Envia mensagem para outro agente via mTLS
350
+ */
351
+ async sendMessage(peerId: string, content: string): Promise<void> {
352
+ await this.ensureValidToken();
353
+
354
+ if (!this.token) {
355
+ throw new Error('Agente não possui token válido');
356
+ }
357
+
358
+ const socket = this.tlsConnections.get(peerId);
359
+ if (!socket || socket.destroyed) {
360
+ throw new Error(`Conexão mTLS não estabelecida com ${peerId}`);
361
+ }
362
+
363
+ const message: AgentMessage = {
364
+ from: this.agentId,
365
+ to: peerId,
366
+ content,
367
+ timestamp: Date.now(),
368
+ messageId: `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
369
+ jwt: this.token // Inclui JWT na mensagem para verificação de identidade
370
+ };
371
+
372
+ // Verificar identidade do peer via JWT antes de enviar
373
+ // (a verificação mTLS já garante que é o certificado correto)
374
+
375
+ this.messageHistory.push(message);
376
+ socket.write(JSON.stringify(message));
377
+
378
+ console.log(`📤 [${this.agentId}] → [${peerId}] (mTLS): ${content}`);
379
+ }
380
+
381
+ /**
382
+ * Processa mensagem recebida
383
+ */
384
+ private async handleIncomingMessage(message: AgentMessage, peerId: string): Promise<void> {
385
+ await this.ensureValidToken();
386
+
387
+ // Verificar JWT do remetente
388
+ try {
389
+ const { payload } = await jwtVerify(message.jwt, this.authority.publicKey, {
390
+ issuer: 'urn:agentic-system:authority',
391
+ audience: 'urn:agentic-system:agents'
392
+ });
393
+
394
+ // Verificar se está na mesma conversa
395
+ if (payload.conversationId !== this.conversationId) {
396
+ throw new Error('Agente não está na mesma conversa');
397
+ }
398
+
399
+ // Verificar se o agentId do JWT corresponde ao certificado
400
+ if (payload.agentId !== peerId) {
401
+ throw new Error('Mismatch entre certificado mTLS e JWT');
402
+ }
403
+
404
+ this.messageHistory.push(message);
405
+ console.log(`📥 [${this.agentId}] ← [${message.from}] (mTLS): ${message.content}`);
406
+
407
+ this.emit('message', message);
408
+ } catch (error) {
409
+ console.error(`❌ [${this.agentId}] Mensagem rejeitada:`, error);
410
+ throw error;
411
+ }
412
+ }
413
+
414
+ getToken(): string {
415
+ if (!this.token) {
416
+ throw new Error('Agente não possui token');
417
+ }
418
+ return this.token;
419
+ }
420
+
421
+ getConversationHistory(): AgentMessage[] {
422
+ return [...this.messageHistory];
423
+ }
424
+
425
+ startAutoRenewal(intervalMs: number = 30000): void {
426
+ setInterval(async () => {
427
+ await this.ensureValidToken();
428
+ }, intervalMs);
429
+
430
+ console.log(`🔄 [${this.agentId}] Auto-renovação de token ativada`);
431
+ }
432
+
433
+ stop(): void {
434
+ this.tlsConnections.forEach(socket => socket.destroy());
435
+ this.tlsConnections.clear();
436
+
437
+ if (this.tlsServer) {
438
+ this.tlsServer.close();
439
+ this.tlsServer = null;
440
+ }
441
+ }
442
+ }
443
+
444
+ // ============================================================================
445
+ // Exemplo de Uso
446
+ // ============================================================================
447
+
448
+ async function demonstrateMTLSAgents() {
449
+ console.log('🚀 Demonstração de Self-Healing Agents com mTLS\n');
450
+
451
+ // 1. Criar CA e Autoridade de Tokens
452
+ const ca = new CertificateAuthority();
453
+ const tokenAuthority = new TokenAuthority();
454
+ console.log('✅ CA e Autoridade de Tokens criadas\n');
455
+
456
+ // 2. Gerar certificados para os agentes
457
+ const certA = ca.generateAgentCertificate('agent-alpha');
458
+ const certB = ca.generateAgentCertificate('agent-beta');
459
+ const caCert = ca.getCACertificate();
460
+ console.log('✅ Certificados mTLS gerados para os agentes\n');
461
+
462
+ // 3. Criar agentes com mTLS
463
+ const agentA = new mTLSAgent(
464
+ 'agent-alpha',
465
+ 'primary',
466
+ tokenAuthority,
467
+ certA,
468
+ caCert,
469
+ ['reasoning', 'memory']
470
+ );
471
+
472
+ const agentB = new mTLSAgent(
473
+ 'agent-beta',
474
+ 'secondary',
475
+ tokenAuthority,
476
+ certB,
477
+ caCert,
478
+ ['analysis', 'synthesis']
479
+ );
480
+
481
+ // 4. Inicializar agentes
482
+ await agentA.initialize();
483
+ await agentB.initialize();
484
+ console.log('');
485
+
486
+ // 5. Iniciar servidores TLS
487
+ await agentA.startTLSServer(8443);
488
+ await agentB.startTLSServer(8444);
489
+ console.log('');
490
+
491
+ // 6. Estabelecer conexões mTLS
492
+ await agentA.connectToPeer('localhost', 8444, 'agent-beta');
493
+ await agentB.connectToPeer('localhost', 8443, 'agent-alpha');
494
+ console.log('');
495
+
496
+ // 7. Ativar auto-renovação
497
+ agentA.startAutoRenewal(30000);
498
+ agentB.startAutoRenewal(30000);
499
+
500
+ // 8. Conversa segura via mTLS
501
+ console.log('💬 Iniciando conversa segura via mTLS...\n');
502
+
503
+ await new Promise(resolve => setTimeout(resolve, 1000));
504
+ await agentA.sendMessage('agent-beta', 'Olá Beta! Conexão segura estabelecida via mTLS.');
505
+
506
+ await new Promise(resolve => setTimeout(resolve, 1000));
507
+ await agentB.sendMessage('agent-alpha', 'Olá Alpha! Nossa comunicação está protegida por mTLS + JWT.');
508
+
509
+ await new Promise(resolve => setTimeout(resolve, 1000));
510
+ await agentA.sendMessage('agent-beta', 'Perfeito! Temos segurança em duas camadas: transporte (mTLS) e aplicação (JWT).');
511
+
512
+ // Mostrar histórico
513
+ console.log('\n📜 Histórico da conversa:');
514
+ const history = agentA.getConversationHistory();
515
+ history.forEach(msg => {
516
+ const time = new Date(msg.timestamp).toLocaleTimeString();
517
+ console.log(`[${time}] ${msg.from} → ${msg.to}: ${msg.content}`);
518
+ });
519
+
520
+ console.log('\n✅ Demonstração concluída!');
521
+ console.log('🔒 Segurança em duas camadas:');
522
+ console.log(' 1. mTLS: Autenticação mútua de transporte');
523
+ console.log(' 2. JWT: Autenticação de identidade e contexto\n');
524
+
525
+ // Cleanup
526
+ setTimeout(() => {
527
+ agentA.stop();
528
+ agentB.stop();
529
+ process.exit(0);
530
+ }, 2000);
531
+ }
532
+
533
+ // Executar se chamado diretamente
534
+ if (import.meta.url === `file://${process.argv[1]}`) {
535
+ demonstrateMTLSAgents().catch(console.error);
536
+ }
537
+
538
+ export { mTLSAgent, CertificateAuthority, TokenAuthority, AgentMessage };
539
+