create-fluxstack 1.5.0 → 1.5.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 (50) hide show
  1. package/.env.example +1 -8
  2. package/app/client/src/App.tsx +1 -4
  3. package/app/server/index.ts +0 -4
  4. package/app/server/routes/index.ts +1 -5
  5. package/config/index.ts +1 -9
  6. package/core/cli/generators/plugin.ts +34 -324
  7. package/core/cli/generators/template-engine.ts +0 -5
  8. package/core/cli/plugin-discovery.ts +12 -33
  9. package/core/framework/server.ts +0 -10
  10. package/core/plugins/dependency-manager.ts +22 -89
  11. package/core/plugins/index.ts +0 -4
  12. package/core/plugins/manager.ts +2 -3
  13. package/core/plugins/registry.ts +1 -28
  14. package/core/utils/logger/index.ts +0 -4
  15. package/core/utils/version.ts +1 -1
  16. package/fluxstack.config.ts +114 -253
  17. package/package.json +117 -117
  18. package/CRYPTO-AUTH-MIDDLEWARE-GUIDE.md +0 -475
  19. package/CRYPTO-AUTH-MIDDLEWARES.md +0 -473
  20. package/CRYPTO-AUTH-USAGE.md +0 -491
  21. package/EXEMPLO-ROTA-PROTEGIDA.md +0 -347
  22. package/QUICK-START-CRYPTO-AUTH.md +0 -221
  23. package/app/client/src/pages/CryptoAuthPage.tsx +0 -394
  24. package/app/server/routes/crypto-auth-demo.routes.ts +0 -167
  25. package/app/server/routes/example-with-crypto-auth.routes.ts +0 -235
  26. package/app/server/routes/exemplo-posts.routes.ts +0 -161
  27. package/core/plugins/module-resolver.ts +0 -216
  28. package/plugins/crypto-auth/README.md +0 -788
  29. package/plugins/crypto-auth/ai-context.md +0 -1282
  30. package/plugins/crypto-auth/cli/make-protected-route.command.ts +0 -383
  31. package/plugins/crypto-auth/client/CryptoAuthClient.ts +0 -302
  32. package/plugins/crypto-auth/client/components/AuthProvider.tsx +0 -131
  33. package/plugins/crypto-auth/client/components/LoginButton.tsx +0 -138
  34. package/plugins/crypto-auth/client/components/ProtectedRoute.tsx +0 -89
  35. package/plugins/crypto-auth/client/components/index.ts +0 -12
  36. package/plugins/crypto-auth/client/index.ts +0 -12
  37. package/plugins/crypto-auth/config/index.ts +0 -34
  38. package/plugins/crypto-auth/index.ts +0 -162
  39. package/plugins/crypto-auth/package.json +0 -66
  40. package/plugins/crypto-auth/server/AuthMiddleware.ts +0 -181
  41. package/plugins/crypto-auth/server/CryptoAuthService.ts +0 -186
  42. package/plugins/crypto-auth/server/index.ts +0 -22
  43. package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +0 -65
  44. package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +0 -26
  45. package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +0 -76
  46. package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +0 -45
  47. package/plugins/crypto-auth/server/middlewares/helpers.ts +0 -140
  48. package/plugins/crypto-auth/server/middlewares/index.ts +0 -22
  49. package/plugins/crypto-auth/server/middlewares.ts +0 -19
  50. package/test-crypto-auth.ts +0 -101
@@ -1,1282 +0,0 @@
1
- # 🔐 Crypto Auth Plugin - AI Context Documentation
2
-
3
- > **Plugin de Autenticação Criptográfica FluxStack**
4
- > Sistema de autenticação **STATELESS** baseado em assinaturas Ed25519
5
-
6
- ---
7
-
8
- ## 📖 Índice Rápido
9
-
10
- 1. [Overview e Conceitos](#overview-e-conceitos)
11
- 2. [Arquitetura do Sistema](#arquitetura-do-sistema)
12
- 3. [Fluxo de Autenticação](#fluxo-de-autenticação)
13
- 4. [Componentes Principais](#componentes-principais)
14
- 5. [Padrões e Boas Práticas](#padrões-e-boas-práticas)
15
- 6. [Troubleshooting](#troubleshooting)
16
- 7. [Exemplos de Uso](#exemplos-de-uso)
17
- 8. [Segurança](#segurança)
18
- 9. [Testes](#testes)
19
-
20
- ---
21
-
22
- ## 🎯 Overview e Conceitos
23
-
24
- ### O que é este plugin?
25
-
26
- Sistema de autenticação **SEM SESSÕES** que usa criptografia Ed25519 para validar requisições.
27
-
28
- ### Conceitos-chave
29
-
30
- **🚫 NÃO HÁ SESSÕES NO SERVIDOR**
31
- - Servidor NÃO armazena estado de autenticação
32
- - Cada requisição é validada independentemente
33
- - Chave pública identifica o usuário
34
-
35
- **🔑 Par de Chaves Ed25519**
36
- - **Chave Privada**: NUNCA sai do navegador, armazenada em localStorage
37
- - **Chave Pública**: Enviada em cada requisição, identifica o usuário
38
-
39
- **✍️ Assinatura Digital**
40
- - Cliente assina cada requisição com chave privada
41
- - Servidor valida assinatura usando chave pública recebida
42
- - Assinatura inclui: `publicKey:timestamp:nonce:message`
43
-
44
- **🛡️ Proteções**
45
- - **Replay Attack**: Nonces únicos impedem reutilização de assinaturas
46
- - **Time Drift**: Timestamps impedem requisições muito antigas (5 min)
47
- - **Man-in-the-Middle**: Assinaturas são únicas por requisição
48
-
49
- ---
50
-
51
- ## 🏗️ Arquitetura do Sistema
52
-
53
- ### Estrutura de Arquivos
54
-
55
- ```
56
- plugins/crypto-auth/
57
- ├── index.ts # Plugin principal e hooks
58
- ├── ai-context.md # Esta documentação
59
- ├── server/
60
- │ ├── index.ts # Exports do servidor
61
- │ ├── CryptoAuthService.ts # Validação de assinaturas
62
- │ └── AuthMiddleware.ts # Middleware de autenticação
63
- ├── client/
64
- │ ├── index.ts # Exports do cliente
65
- │ ├── CryptoAuthClient.ts # Cliente de autenticação
66
- │ └── components/
67
- │ └── AuthProvider.tsx # React Context Provider
68
- └── README.md # Documentação do usuário
69
- ```
70
-
71
- ### Fluxo de Dados
72
-
73
- ```
74
- ┌─────────────────────────────────────────────────────────────┐
75
- │ CLIENTE │
76
- ├─────────────────────────────────────────────────────────────┤
77
- │ 1. Gera par de chaves Ed25519 (local) │
78
- │ privateKey → NUNCA enviada │
79
- │ publicKey → Enviada em cada request │
80
- │ │
81
- │ 2. Para cada requisição: │
82
- │ - timestamp = Date.now() │
83
- │ - nonce = crypto.randomBytes(16) │
84
- │ - message = "GET:/api/users" │
85
- │ - fullMessage = publicKey:timestamp:nonce:message │
86
- │ - signature = sign(fullMessage, privateKey) │
87
- │ │
88
- │ 3. Headers enviados: │
89
- │ x-public-key: <publicKey> │
90
- │ x-timestamp: <timestamp> │
91
- │ x-nonce: <nonce> │
92
- │ x-signature: <signature> │
93
- └─────────────────────────────────────────────────────────────┘
94
-
95
- ┌─────────────────────────────────────────────────────────────┐
96
- │ SERVIDOR │
97
- ├─────────────────────────────────────────────────────────────┤
98
- │ 1. Plugin Hook onRequest │
99
- │ - AuthMiddleware.authenticate(context) │
100
- │ │
101
- │ 2. AuthMiddleware │
102
- │ - Extrai headers (public-key, timestamp, nonce, sig) │
103
- │ - Chama CryptoAuthService.validateRequest() │
104
- │ │
105
- │ 3. CryptoAuthService.validateRequest() │
106
- │ ✓ Valida formato da chave pública │
107
- │ ✓ Verifica time drift (< 5 min) │
108
- │ ✓ Verifica se nonce já foi usado │
109
- │ ✓ Reconstrói mensagem: publicKey:timestamp:nonce:message │
110
- │ ✓ Verifica assinatura: verify(signature, message, publicKey) │
111
- │ ✓ Marca nonce como usado │
112
- │ ✓ Retorna user: { publicKey, isAdmin, permissions } │
113
- │ │
114
- │ 4. Se válido: │
115
- │ - context.request.user = user │
116
- │ - Processa rota normalmente │
117
- │ │
118
- │ 5. Se inválido: │
119
- │ - context.handled = true │
120
- │ - context.response = 401 Unauthorized │
121
- │ - Rota NÃO é executada │
122
- └─────────────────────────────────────────────────────────────┘
123
- ```
124
-
125
- ---
126
-
127
- ## 🔄 Fluxo de Autenticação
128
-
129
- ### 1. Inicialização do Cliente
130
-
131
- ```typescript
132
- // Cliente inicializa automaticamente ou manualmente
133
- const client = new CryptoAuthClient({
134
- autoInit: true, // Gera chaves automaticamente
135
- storage: 'localStorage' // Onde armazenar chaves
136
- })
137
-
138
- // Se autoInit: true
139
- // → Verifica se já existem chaves no localStorage
140
- // → Se sim: carrega chaves existentes
141
- // → Se não: gera novo par de chaves
142
-
143
- // Chaves armazenadas em: localStorage['fluxstack_crypto_keys']
144
- // Formato: { publicKey, privateKey, createdAt }
145
- ```
146
-
147
- ### 2. Requisição Assinada
148
-
149
- ```typescript
150
- // Método automático (recomendado)
151
- const response = await client.fetch('/api/users')
152
-
153
- // O que acontece internamente:
154
- // 1. timestamp = Date.now()
155
- // 2. nonce = generateNonce() // 16 bytes aleatórios
156
- // 3. message = buildMessage('GET', '/api/users', null)
157
- // → "GET:/api/users"
158
- // 4. fullMessage = `${publicKey}:${timestamp}:${nonce}:${message}`
159
- // 5. messageHash = sha256(fullMessage)
160
- // 6. signature = ed25519.sign(messageHash, privateKey)
161
- // 7. Headers adicionados automaticamente
162
- ```
163
-
164
- ### 3. Validação no Servidor
165
-
166
- ```typescript
167
- // Plugin Hook onRequest (automático)
168
- onRequest: async (context) => {
169
- const authResult = await authMiddleware.authenticate(context)
170
-
171
- if (authResult.success) {
172
- // ✅ Usuário autenticado
173
- context.request.user = authResult.user
174
- // Rota é executada normalmente
175
- } else if (authResult.required) {
176
- // ❌ Falha na autenticação
177
- context.handled = true
178
- context.response = new Response(JSON.stringify({
179
- success: false,
180
- error: authResult.error
181
- }), { status: 401 })
182
- // Rota NÃO é executada
183
- }
184
- }
185
- ```
186
-
187
- ### 4. Acesso nas Rotas
188
-
189
- ```typescript
190
- // Rotas protegidas podem acessar user
191
- .get('/api/users', ({ request }) => {
192
- const user = (request as any).user
193
-
194
- return {
195
- user: {
196
- publicKey: user.publicKey,
197
- isAdmin: user.isAdmin,
198
- permissions: user.permissions
199
- }
200
- }
201
- })
202
- ```
203
-
204
- ---
205
-
206
- ## 🧩 Componentes Principais
207
-
208
- ### 1. CryptoAuthService (Backend)
209
-
210
- **Localização**: `plugins/crypto-auth/server/CryptoAuthService.ts`
211
-
212
- **Responsabilidades**:
213
- - Validar assinaturas Ed25519
214
- - Gerenciar nonces (prevenir replay attacks)
215
- - Verificar drift de tempo
216
- - Identificar usuários admin
217
-
218
- **Métodos Principais**:
219
-
220
- ```typescript
221
- class CryptoAuthService {
222
- // Validar uma requisição assinada
223
- async validateRequest(data: {
224
- publicKey: string
225
- timestamp: number
226
- nonce: string
227
- signature: string
228
- message?: string
229
- }): Promise<AuthResult>
230
-
231
- // Verificar se chave pública é válida (64 hex chars)
232
- private isValidPublicKey(publicKey: string): boolean
233
-
234
- // Limpar nonces antigos (executado a cada 5 min)
235
- private cleanupOldNonces(): void
236
-
237
- // Retornar estatísticas
238
- getStats(): { usedNonces: number; adminKeys: number }
239
- }
240
- ```
241
-
242
- **Estado Interno**:
243
- ```typescript
244
- private usedNonces: Map<string, number> // `${publicKey}:${nonce}` → timestamp
245
- ```
246
-
247
- **Importante**:
248
- - `usedNonces` é limpo automaticamente a cada 5 minutos
249
- - Nonces mais antigos que `maxTimeDrift * 2` são removidos
250
- - NÃO HÁ armazenamento de sessões!
251
-
252
- ---
253
-
254
- ### 2. AuthMiddleware (Backend)
255
-
256
- **Localização**: `plugins/crypto-auth/server/AuthMiddleware.ts`
257
-
258
- **Responsabilidades**:
259
- - Verificar se rota requer autenticação
260
- - Extrair headers de autenticação
261
- - Chamar CryptoAuthService para validar
262
- - Decidir se permite acesso
263
-
264
- **Métodos Principais**:
265
-
266
- ```typescript
267
- class AuthMiddleware {
268
- // Autenticar uma requisição
269
- async authenticate(context: RequestContext): Promise<{
270
- success: boolean
271
- required: boolean // Se autenticação é obrigatória
272
- error?: string
273
- user?: User
274
- }>
275
-
276
- // Verificar se rota está protegida
277
- private isProtectedRoute(path: string): boolean
278
-
279
- // Verificar se rota é pública
280
- private isPublicRoute(path: string): boolean
281
-
282
- // Extrair headers de auth
283
- private extractAuthHeaders(headers): AuthHeaders | null
284
-
285
- // Construir mensagem para validação
286
- private buildMessage(context: RequestContext): string
287
- }
288
- ```
289
-
290
- **Lógica de Decisão**:
291
- ```typescript
292
- // 1. Se rota pública → success: true, required: false
293
- // 2. Se rota protegida sem headers → success: false, required: true
294
- // 3. Se rota protegida com headers → valida assinatura
295
- // - Se válida → success: true, required: true, user: {...}
296
- // - Se inválida → success: false, required: true, error: "..."
297
- ```
298
-
299
- ---
300
-
301
- ### 3. CryptoAuthClient (Frontend)
302
-
303
- **Localização**: `plugins/crypto-auth/client/CryptoAuthClient.ts`
304
-
305
- **Responsabilidades**:
306
- - Gerar e gerenciar par de chaves
307
- - Assinar requisições automaticamente
308
- - Armazenar chaves em localStorage
309
-
310
- **Métodos Públicos**:
311
-
312
- ```typescript
313
- class CryptoAuthClient {
314
- // Inicializar (gerar ou carregar chaves)
315
- initialize(): KeyPair
316
-
317
- // Criar novo par de chaves
318
- createNewKeys(): KeyPair
319
-
320
- // Fazer requisição autenticada
321
- async fetch(url: string, options?: RequestInit): Promise<Response>
322
-
323
- // Obter chaves atuais
324
- getKeys(): KeyPair | null
325
-
326
- // Verificar se está inicializado
327
- isInitialized(): boolean
328
-
329
- // Limpar chaves (logout)
330
- clearKeys(): void
331
- }
332
- ```
333
-
334
- **Métodos Privados**:
335
-
336
- ```typescript
337
- // Assinar mensagem
338
- private signMessage(message: string, timestamp: number, nonce: string): string
339
-
340
- // Construir mensagem para assinar
341
- private buildMessage(method: string, url: string, body?: any): string
342
-
343
- // Gerar nonce aleatório
344
- private generateNonce(): string
345
-
346
- // Carregar chaves do storage
347
- private loadKeys(): KeyPair | null
348
-
349
- // Salvar chaves no storage
350
- private saveKeys(keys: KeyPair): void
351
- ```
352
-
353
- **Formato de Mensagem**:
354
- ```typescript
355
- // Para GET /api/users
356
- message = "GET:/api/users"
357
-
358
- // Para POST /api/users com body
359
- message = "POST:/api/users:{\"name\":\"João\"}"
360
-
361
- // Mensagem completa assinada
362
- fullMessage = `${publicKey}:${timestamp}:${nonce}:${message}`
363
- ```
364
-
365
- ---
366
-
367
- ### 4. AuthProvider (React Component)
368
-
369
- **Localização**: `plugins/crypto-auth/client/components/AuthProvider.tsx`
370
-
371
- **Responsabilidades**:
372
- - Prover contexto de autenticação via React Context
373
- - Gerenciar estado de chaves
374
- - Callbacks para eventos (onKeysChange, onError)
375
-
376
- **Interface**:
377
-
378
- ```typescript
379
- export interface AuthContextValue {
380
- client: CryptoAuthClient
381
- keys: KeyPair | null
382
- hasKeys: boolean
383
- isLoading: boolean
384
- error: string | null
385
- createKeys: () => void
386
- clearKeys: () => void
387
- }
388
-
389
- // Hook para usar o contexto
390
- export const useAuth = (): AuthContextValue
391
- ```
392
-
393
- **Uso**:
394
-
395
- ```tsx
396
- // Wrapper da aplicação
397
- <AuthProvider
398
- config={{ storage: 'localStorage' }}
399
- onKeysChange={(hasKeys, keys) => console.log('Keys changed')}
400
- onError={(error) => console.error(error)}
401
- >
402
- <App />
403
- </AuthProvider>
404
-
405
- // Dentro de componentes
406
- function MyComponent() {
407
- const { keys, hasKeys, createKeys, clearKeys } = useAuth()
408
-
409
- if (!hasKeys) {
410
- return <button onClick={createKeys}>Login</button>
411
- }
412
-
413
- return <button onClick={clearKeys}>Logout</button>
414
- }
415
- ```
416
-
417
- ---
418
-
419
- ### 5. Plugin Principal (index.ts)
420
-
421
- **Localização**: `plugins/crypto-auth/index.ts`
422
-
423
- **Responsabilidades**:
424
- - Definir schema de configuração
425
- - Hooks do plugin (setup, onRequest, onResponse, onServerStart)
426
- - Rotas de informação (/api/auth/info)
427
-
428
- **Configuração**:
429
-
430
- ```typescript
431
- defaultConfig: {
432
- enabled: true,
433
- maxTimeDrift: 300000, // 5 minutos em ms
434
- adminKeys: [], // Array de chaves públicas admin
435
- protectedRoutes: [
436
- "/api/admin/*",
437
- "/api/crypto-auth/protected",
438
- "/api/crypto-auth/admin"
439
- ],
440
- publicRoutes: [
441
- "/api/crypto-auth/public",
442
- "/api/health",
443
- "/api/docs",
444
- "/swagger"
445
- ],
446
- enableMetrics: true
447
- }
448
- ```
449
-
450
- **Hooks**:
451
-
452
- ```typescript
453
- // 1. setup - Inicialização
454
- setup: async (context) => {
455
- const authService = new CryptoAuthService(...)
456
- const authMiddleware = new AuthMiddleware(...)
457
-
458
- // Armazenar no global para acesso nos hooks
459
- (global as any).cryptoAuthService = authService
460
- (global as any).cryptoAuthMiddleware = authMiddleware
461
- }
462
-
463
- // 2. onRequest - Validar cada requisição
464
- onRequest: async (context) => {
465
- const authResult = await authMiddleware.authenticate(context)
466
-
467
- if (authResult.success) {
468
- context.request.user = authResult.user // ✅
469
- } else if (authResult.required) {
470
- context.handled = true // ❌
471
- context.response = new Response(...)
472
- }
473
- }
474
-
475
- // 3. onResponse - Métricas (opcional)
476
- onResponse: async (context) => {
477
- // Log de requisições autenticadas
478
- }
479
-
480
- // 4. onServerStart - Log de status
481
- onServerStart: async (context) => {
482
- logger.info("Crypto Auth plugin ativo")
483
- }
484
- ```
485
-
486
- ---
487
-
488
- ## 📋 Padrões e Boas Práticas
489
-
490
- ### ✅ Sempre Fazer
491
-
492
- 1. **Usar cliente nativo para requisições protegidas**
493
- ```typescript
494
- // ✅ Correto
495
- const response = await authClient.fetch('/api/protected')
496
-
497
- // ❌ Errado - não inclui assinatura
498
- const response = await fetch('/api/protected')
499
- ```
500
-
501
- 2. **Verificar se usuário está autenticado nas rotas**
502
- ```typescript
503
- // ✅ Correto
504
- .get('/api/users', ({ request }) => {
505
- const user = (request as any).user
506
- if (!user) {
507
- return { error: 'Unauthorized' }
508
- }
509
- // ...
510
- })
511
- ```
512
-
513
- 3. **Adicionar novas rotas protegidas na config**
514
- ```typescript
515
- // config/app.config.ts
516
- plugins: {
517
- config: {
518
- 'crypto-auth': {
519
- protectedRoutes: [
520
- "/api/admin/*",
521
- "/api/crypto-auth/protected",
522
- "/api/users/*" // ✅ Nova rota
523
- ]
524
- }
525
- }
526
- }
527
- ```
528
-
529
- 4. **Tratar erros de autenticação no frontend**
530
- ```typescript
531
- try {
532
- const response = await authClient.fetch('/api/protected')
533
- if (response.status === 401) {
534
- // Chaves inválidas, criar novas
535
- authClient.clearKeys()
536
- authClient.createNewKeys()
537
- }
538
- } catch (error) {
539
- console.error('Auth error:', error)
540
- }
541
- ```
542
-
543
- 5. **Verificar permissões de admin quando necessário**
544
- ```typescript
545
- .get('/api/admin/users', ({ request, set }) => {
546
- const user = (request as any).user
547
-
548
- if (!user?.isAdmin) {
549
- set.status = 403
550
- return { error: 'Admin access required' }
551
- }
552
-
553
- // Lógica admin
554
- })
555
- ```
556
-
557
- ---
558
-
559
- ### ❌ Nunca Fazer
560
-
561
- 1. **NÃO enviar chave privada ao servidor**
562
- ```typescript
563
- // ❌ NUNCA FAZER ISSO!
564
- await fetch('/api/register', {
565
- body: JSON.stringify({
566
- privateKey: keys.privateKey // PERIGO!
567
- })
568
- })
569
- ```
570
-
571
- 2. **NÃO armazenar sessões no servidor**
572
- ```typescript
573
- // ❌ Viola arquitetura stateless
574
- const sessions = new Map()
575
- sessions.set(publicKey, userData)
576
- ```
577
-
578
- 3. **NÃO confiar apenas na chave pública**
579
- ```typescript
580
- // ❌ Permite spoofing
581
- .get('/api/users', ({ headers }) => {
582
- const publicKey = headers['x-public-key']
583
- // FALTA: validar assinatura!
584
- })
585
-
586
- // ✅ Correto - middleware já validou
587
- .get('/api/users', ({ request }) => {
588
- const user = (request as any).user // Validado!
589
- })
590
- ```
591
-
592
- 4. **NÃO permitir timestamp muito antigo/futuro**
593
- ```typescript
594
- // ❌ Vulnerável a replay attack
595
- const maxTimeDrift = 24 * 60 * 60 * 1000 // 24 horas - MUITO!
596
-
597
- // ✅ Correto
598
- const maxTimeDrift = 5 * 60 * 1000 // 5 minutos
599
- ```
600
-
601
- 5. **NÃO reutilizar nonces**
602
- ```typescript
603
- // ❌ Cliente NÃO deve fazer isso
604
- const nonce = "fixed-nonce" // Sempre igual!
605
-
606
- // ✅ Correto
607
- const nonce = generateNonce() // Aleatório sempre
608
- ```
609
-
610
- ---
611
-
612
- ## 🔧 Troubleshooting
613
-
614
- ### Problema 1: "Assinatura inválida"
615
-
616
- **Sintomas**: Requisições retornam 401 com erro "Assinatura inválida"
617
-
618
- **Causas Possíveis**:
619
- 1. Chaves públicas/privadas não correspondem
620
- 2. Mensagem construída incorretamente
621
- 3. Timestamp/nonce diferentes no cliente e servidor
622
- 4. Corpo da requisição não incluído na assinatura
623
-
624
- **Debug**:
625
- ```typescript
626
- // No cliente - log mensagem assinada
627
- const fullMessage = `${publicKey}:${timestamp}:${nonce}:${message}`
628
- console.log('Client message:', fullMessage)
629
- console.log('Signature:', signature)
630
-
631
- // No servidor - log mensagem reconstruída
632
- const messageToVerify = `${publicKey}:${timestamp}:${nonce}:${message}`
633
- console.log('Server message:', messageToVerify)
634
- ```
635
-
636
- **Solução**:
637
- - Verificar se cliente e servidor constroem mensagem idêntica
638
- - Confirmar que timestamp e nonce estão sendo enviados corretamente
639
- - Para POST/PUT, verificar se body está sendo incluído na mensagem
640
-
641
- ---
642
-
643
- ### Problema 2: "Nonce já utilizado"
644
-
645
- **Sintomas**: Segunda requisição idêntica retorna 401
646
-
647
- **Causa**: Replay attack protection funcionando (comportamento esperado!)
648
-
649
- **Quando é bug**:
650
- - Se acontece com requisições DIFERENTES
651
- - Se nonce não está sendo gerado aleatoriamente
652
-
653
- **Debug**:
654
- ```typescript
655
- // Verificar geração de nonce
656
- console.log('Nonce 1:', generateNonce())
657
- console.log('Nonce 2:', generateNonce())
658
- // Devem ser SEMPRE diferentes!
659
- ```
660
-
661
- **Solução**:
662
- - Se está testando manualmente, gerar novo nonce a cada tentativa
663
- - Verificar que `crypto.randomBytes()` está funcionando
664
-
665
- ---
666
-
667
- ### Problema 3: "Timestamp inválido ou expirado"
668
-
669
- **Sintomas**: Requisições retornam 401 com erro de timestamp
670
-
671
- **Causas Possíveis**:
672
- 1. Relógio do cliente desincronizado
673
- 2. Requisição demorou muito para chegar ao servidor
674
- 3. `maxTimeDrift` configurado muito curto
675
-
676
- **Debug**:
677
- ```typescript
678
- const clientTime = Date.now()
679
- const serverTime = Date.now() // No servidor
680
- const drift = Math.abs(serverTime - clientTime)
681
- console.log('Time drift:', drift, 'ms')
682
- console.log('Max allowed:', maxTimeDrift, 'ms')
683
- ```
684
-
685
- **Solução**:
686
- - Sincronizar relógio do sistema
687
- - Aumentar `maxTimeDrift` se necessário (mas não muito!)
688
- - Verificar latência de rede
689
-
690
- ---
691
-
692
- ### Problema 4: "User undefined nas rotas"
693
-
694
- **Sintomas**: `request.user` é `undefined` mesmo com autenticação válida
695
-
696
- **Causa**: User não está sendo propagado corretamente do middleware
697
-
698
- **Debug**:
699
- ```typescript
700
- // No plugin index.ts - verificar hook onRequest
701
- if (authResult.success && authResult.user) {
702
- context.request.user = authResult.user // ✅ Deve estar aqui
703
- console.log('User set:', authResult.user)
704
- }
705
-
706
- // Na rota
707
- console.log('User received:', (request as any).user)
708
- ```
709
-
710
- **Solução**:
711
- - Verificar que `context.request.user` está sendo definido no hook
712
- - Confirmar que middleware está retornando `user` no authResult
713
-
714
- ---
715
-
716
- ### Problema 5: Rotas públicas retornando 401
717
-
718
- **Sintomas**: Rotas que deveriam ser públicas exigem autenticação
719
-
720
- **Causa**: Rota não está na lista de `publicRoutes`
721
-
722
- **Debug**:
723
- ```typescript
724
- // Verificar configuração
725
- console.log('Public routes:', config.publicRoutes)
726
- console.log('Request path:', context.path)
727
- console.log('Is public?:', isPublicRoute(context.path))
728
- ```
729
-
730
- **Solução**:
731
- ```typescript
732
- // config/app.config.ts
733
- plugins: {
734
- config: {
735
- 'crypto-auth': {
736
- publicRoutes: [
737
- "/api/health",
738
- "/api/docs",
739
- "/api/crypto-auth/public", // Adicionar rota
740
- "/swagger"
741
- ]
742
- }
743
- }
744
- }
745
- ```
746
-
747
- ---
748
-
749
- ## 💡 Exemplos de Uso
750
-
751
- ### Exemplo 1: Requisição Simples
752
-
753
- ```typescript
754
- // Cliente
755
- import { CryptoAuthClient } from '@/plugins/crypto-auth/client'
756
-
757
- const client = new CryptoAuthClient({ autoInit: true })
758
-
759
- // Fazer requisição protegida
760
- const response = await client.fetch('/api/users')
761
- const data = await response.json()
762
-
763
- console.log('Users:', data)
764
- ```
765
-
766
- ```typescript
767
- // Servidor - Rota
768
- .get('/api/users', ({ request }) => {
769
- const user = (request as any).user
770
-
771
- return {
772
- success: true,
773
- user: {
774
- publicKey: user.publicKey,
775
- isAdmin: user.isAdmin
776
- },
777
- users: [/* ... */]
778
- }
779
- })
780
- ```
781
-
782
- ---
783
-
784
- ### Exemplo 2: Requisição POST com Body
785
-
786
- ```typescript
787
- // Cliente
788
- const newUser = { name: 'João', email: 'joao@test.com' }
789
-
790
- const response = await client.fetch('/api/users', {
791
- method: 'POST',
792
- body: JSON.stringify(newUser)
793
- })
794
-
795
- const data = await response.json()
796
- ```
797
-
798
- ```typescript
799
- // Servidor
800
- .post('/api/users', async ({ request, body }) => {
801
- const user = (request as any).user
802
-
803
- // Body é assinado automaticamente
804
- const newUser = await createUser(body)
805
-
806
- return {
807
- success: true,
808
- user: newUser,
809
- authenticatedBy: user.publicKey
810
- }
811
- })
812
- ```
813
-
814
- ---
815
-
816
- ### Exemplo 3: Rota Admin
817
-
818
- ```typescript
819
- // Cliente
820
- const response = await client.fetch('/api/admin/stats')
821
-
822
- if (response.status === 403) {
823
- console.error('Você não é admin!')
824
- }
825
- ```
826
-
827
- ```typescript
828
- // Servidor
829
- .get('/api/admin/stats', ({ request, set }) => {
830
- const user = (request as any).user
831
-
832
- // Verificar permissões
833
- if (!user?.isAdmin) {
834
- set.status = 403
835
- return {
836
- success: false,
837
- error: 'Admin access required',
838
- yourPermissions: user?.permissions || []
839
- }
840
- }
841
-
842
- return {
843
- success: true,
844
- stats: {
845
- totalUsers: 100,
846
- activeUsers: 50
847
- }
848
- }
849
- })
850
- ```
851
-
852
- ---
853
-
854
- ### Exemplo 4: React Component com AuthProvider
855
-
856
- ```tsx
857
- import { useAuth } from '@/plugins/crypto-auth/client'
858
-
859
- function LoginButton() {
860
- const { keys, hasKeys, isLoading, createKeys, clearKeys } = useAuth()
861
-
862
- if (isLoading) {
863
- return <div>Carregando...</div>
864
- }
865
-
866
- if (!hasKeys) {
867
- return (
868
- <button onClick={createKeys}>
869
- Gerar Chaves de Autenticação
870
- </button>
871
- )
872
- }
873
-
874
- return (
875
- <div>
876
- <p>Autenticado: {keys.publicKey.substring(0, 16)}...</p>
877
- <button onClick={clearKeys}>Logout</button>
878
- </div>
879
- )
880
- }
881
-
882
- function ProtectedData() {
883
- const { client, hasKeys } = useAuth()
884
- const [data, setData] = useState(null)
885
-
886
- useEffect(() => {
887
- if (hasKeys) {
888
- client.fetch('/api/protected')
889
- .then(r => r.json())
890
- .then(setData)
891
- }
892
- }, [hasKeys])
893
-
894
- return <pre>{JSON.stringify(data, null, 2)}</pre>
895
- }
896
- ```
897
-
898
- ---
899
-
900
- ### Exemplo 5: Adicionar Chave Admin
901
-
902
- ```typescript
903
- // 1. Gerar chave pública de um usuário admin
904
- const adminClient = new CryptoAuthClient()
905
- const adminKeys = adminClient.createNewKeys()
906
- console.log('Admin Public Key:', adminKeys.publicKey)
907
-
908
- // 2. Adicionar na configuração
909
- // config/app.config.ts
910
- plugins: {
911
- config: {
912
- 'crypto-auth': {
913
- adminKeys: [
914
- "7443b54b3c8e2f1a9d5c6e4b2f8a1d3c9e5b7a2f4d8c1e6b3a9d5c7e2f4b8a1d"
915
- ]
916
- }
917
- }
918
- }
919
-
920
- // 3. Usuário com essa chave pública terá isAdmin: true
921
- const response = await adminClient.fetch('/api/admin/users')
922
- // ✅ Acesso permitido
923
- ```
924
-
925
- ---
926
-
927
- ## 🔒 Segurança
928
-
929
- ### Princípios de Segurança
930
-
931
- 1. **Zero Trust**
932
- - Servidor NUNCA confia apenas na chave pública
933
- - SEMPRE valida assinatura antes de processar requisição
934
-
935
- 2. **Defesa em Profundidade**
936
- - Validação de formato de chave
937
- - Verificação de timestamp
938
- - Proteção contra replay (nonces)
939
- - Assinatura criptográfica
940
-
941
- 3. **Least Privilege**
942
- - Usuários normais: apenas `read` permission
943
- - Admins: `admin`, `read`, `write`, `delete`
944
-
945
- ---
946
-
947
- ### Vetores de Ataque e Mitigações
948
-
949
- #### 1. Man-in-the-Middle (MITM)
950
-
951
- **Ataque**: Interceptar e modificar requisição
952
-
953
- **Mitigação**:
954
- - ✅ Assinatura detecta qualquer modificação
955
- - ✅ HTTPS obrigatório em produção
956
- - ✅ Chave privada nunca transmitida
957
-
958
- ```typescript
959
- // Atacante modifica mensagem
960
- Original: "GET:/api/users"
961
- Modificado: "GET:/api/admin/users"
962
-
963
- // Assinatura não corresponde → 401 Unauthorized
964
- ```
965
-
966
- ---
967
-
968
- #### 2. Replay Attack
969
-
970
- **Ataque**: Reutilizar requisição válida capturada
971
-
972
- **Mitigação**:
973
- - ✅ Nonces únicos por requisição
974
- - ✅ Timestamp expira em 5 minutos
975
- - ✅ Nonces armazenados até expiração
976
-
977
- ```typescript
978
- // Atacante captura requisição válida
979
- Request 1: nonce = "abc123" → ✅ 200 OK
980
-
981
- // Tenta reutilizar
982
- Request 2: nonce = "abc123" → ❌ 401 "Nonce já utilizado"
983
- ```
984
-
985
- ---
986
-
987
- #### 3. Brute Force de Chave Privada
988
-
989
- **Ataque**: Tentar adivinhar chave privada
990
-
991
- **Mitigação**:
992
- - ✅ Ed25519 com 256 bits de segurança
993
- - ✅ 2^256 combinações possíveis
994
- - ✅ Computacionalmente inviável
995
-
996
- ---
997
-
998
- #### 4. Key Theft (Roubo de Chave)
999
-
1000
- **Ataque**: Acessar localStorage e roubar chave privada
1001
-
1002
- **Mitigação**:
1003
- - ⚠️ Se atacante tem acesso ao localStorage, chave está comprometida
1004
- - ✅ Usar sempre HTTPS
1005
- - ✅ Implementar Content Security Policy
1006
- - ✅ XSS protection (sanitize inputs)
1007
-
1008
- **Procedimento de Resposta**:
1009
- ```typescript
1010
- // 1. Usuário reporta suspeita de roubo
1011
- // 2. Gerar novas chaves
1012
- client.clearKeys()
1013
- client.createNewKeys()
1014
-
1015
- // 3. Revogar chave antiga (se houver blacklist)
1016
- // 4. Notificar usuário
1017
- ```
1018
-
1019
- ---
1020
-
1021
- #### 5. Time Manipulation
1022
-
1023
- **Ataque**: Modificar relógio do sistema
1024
-
1025
- **Mitigação**:
1026
- - ✅ `maxTimeDrift` limita divergência a 5 minutos
1027
- - ✅ Servidor usa seu próprio timestamp como referência
1028
-
1029
- ```typescript
1030
- // Cliente com relógio 1 hora no futuro
1031
- clientTime: 2025-01-01 14:00:00
1032
- serverTime: 2025-01-01 13:00:00
1033
-
1034
- drift = 3600000ms > maxTimeDrift (300000ms)
1035
- → 401 "Timestamp inválido ou expirado"
1036
- ```
1037
-
1038
- ---
1039
-
1040
- ### Boas Práticas de Segurança
1041
-
1042
- 1. **Sempre usar HTTPS em produção**
1043
- ```typescript
1044
- // config/server.config.ts
1045
- if (process.env.NODE_ENV === 'production') {
1046
- config.enforceHTTPS = true
1047
- }
1048
- ```
1049
-
1050
- 2. **Rotacionar chaves periodicamente**
1051
- ```typescript
1052
- // A cada 30 dias, sugerir nova chave
1053
- const keyAge = Date.now() - keys.createdAt.getTime()
1054
- if (keyAge > 30 * 24 * 60 * 60 * 1000) {
1055
- showRotateKeyDialog()
1056
- }
1057
- ```
1058
-
1059
- 3. **Rate limiting em rotas sensíveis**
1060
- ```typescript
1061
- // Limitar tentativas de autenticação
1062
- const rateLimit = new Map()
1063
-
1064
- .post('/api/auth/verify', ({ headers }) => {
1065
- const publicKey = headers['x-public-key']
1066
- const attempts = rateLimit.get(publicKey) || 0
1067
-
1068
- if (attempts > 10) {
1069
- return { error: 'Too many attempts' }
1070
- }
1071
-
1072
- rateLimit.set(publicKey, attempts + 1)
1073
- })
1074
- ```
1075
-
1076
- 4. **Logging de eventos de segurança**
1077
- ```typescript
1078
- // Log failed auth attempts
1079
- if (!authResult.success) {
1080
- logger.warn('Failed authentication', {
1081
- publicKey: publicKey.substring(0, 8) + '...',
1082
- error: authResult.error,
1083
- ip: context.headers['x-forwarded-for'],
1084
- timestamp: new Date()
1085
- })
1086
- }
1087
- ```
1088
-
1089
- ---
1090
-
1091
- ## 🧪 Testes
1092
-
1093
- ### Teste Automatizado
1094
-
1095
- ```bash
1096
- # Executar script de teste
1097
- bun run test-crypto-auth.ts
1098
- ```
1099
-
1100
- **Saída Esperada**:
1101
- ```
1102
- 🔐 Testando Autenticação Criptográfica Ed25519
1103
-
1104
- 1️⃣ Gerando par de chaves Ed25519...
1105
- ✅ Chave pública: 7443b54b...
1106
- ✅ Chave privada: ******** (NUNCA enviar ao servidor!)
1107
-
1108
- 2️⃣ Preparando requisição assinada...
1109
- ✅ Mensagem construída
1110
-
1111
- 3️⃣ Assinando mensagem com chave privada...
1112
- ✅ Assinatura: e29d2819...
1113
-
1114
- 4️⃣ Enviando requisição ao servidor...
1115
- 📡 Status: 200
1116
- ✅ SUCESSO! Assinatura validada
1117
-
1118
- 5️⃣ Testando proteção contra replay attack...
1119
- 📡 Replay Status: 401
1120
- ✅ Proteção funcionando! Replay attack bloqueado
1121
- ```
1122
-
1123
- ---
1124
-
1125
- ### Teste Manual no Frontend
1126
-
1127
- 1. Abrir http://localhost:5173
1128
- 2. Navegar para "Crypto Auth Demo"
1129
- 3. Clicar em "Gerar Novo Par de Chaves"
1130
- 4. Verificar chaves exibidas
1131
- 5. Clicar em "GET /api/crypto-auth/public" → 200 OK
1132
- 6. Clicar em "GET /api/crypto-auth/protected" → 200 OK com dados
1133
- 7. Clicar em "Limpar Chaves"
1134
- 8. Clicar em "GET /api/crypto-auth/protected" → 401 Unauthorized
1135
-
1136
- ---
1137
-
1138
- ### Teste de Casos Edge
1139
-
1140
- ```typescript
1141
- // Teste 1: Timestamp muito antigo
1142
- const oldTimestamp = Date.now() - (10 * 60 * 1000) // 10 min atrás
1143
- // Esperado: 401 "Timestamp inválido"
1144
-
1145
- // Teste 2: Chave pública inválida
1146
- const invalidKey = "not-a-hex-string"
1147
- // Esperado: 401 "Chave pública inválida"
1148
-
1149
- // Teste 3: Assinatura incorreta
1150
- const wrongSignature = "0000000000000000000000000000000000000000"
1151
- // Esperado: 401 "Assinatura inválida"
1152
-
1153
- // Teste 4: Nonce reutilizado
1154
- const sameNonce = "abc123"
1155
- // Request 1: 200 OK
1156
- // Request 2: 401 "Nonce já utilizado"
1157
-
1158
- // Teste 5: Usuário não-admin tentando rota admin
1159
- // Esperado: 403 "Permissão negada"
1160
- ```
1161
-
1162
- ---
1163
-
1164
- ## 🔍 Debug e Logging
1165
-
1166
- ### Ativar Logs Detalhados
1167
-
1168
- ```typescript
1169
- // config/app.config.ts
1170
- plugins: {
1171
- config: {
1172
- 'crypto-auth': {
1173
- enableMetrics: true, // Ativa logs de métricas
1174
- logLevel: 'debug' // Nível de log
1175
- }
1176
- }
1177
- }
1178
- ```
1179
-
1180
- ### Logs Úteis
1181
-
1182
- ```typescript
1183
- // Cliente
1184
- console.log('Keys:', client.getKeys())
1185
- console.log('Is initialized:', client.isInitialized())
1186
-
1187
- // Middleware
1188
- logger.debug('Authenticating request', {
1189
- path: context.path,
1190
- method: context.method,
1191
- hasAuthHeaders: !!authHeaders
1192
- })
1193
-
1194
- // Service
1195
- logger.info('Request validated', {
1196
- publicKey: publicKey.substring(0, 8) + '...',
1197
- isAdmin,
1198
- permissions
1199
- })
1200
- ```
1201
-
1202
- ---
1203
-
1204
- ## 📚 Referências Técnicas
1205
-
1206
- ### Bibliotecas Utilizadas
1207
-
1208
- - **@noble/curves**: Implementação Ed25519
1209
- - **@noble/hashes**: SHA256 e utilitários
1210
-
1211
- ### Algoritmos
1212
-
1213
- - **Ed25519**: Curva elíptica para assinatura digital
1214
- - **SHA-256**: Hash da mensagem antes de assinar
1215
-
1216
- ### Padrões de Segurança
1217
-
1218
- - **NIST FIPS 186-5**: Digital Signature Standard
1219
- - **RFC 8032**: Edwards-Curve Digital Signature Algorithm (EdDSA)
1220
-
1221
- ---
1222
-
1223
- ## 🚀 Próximos Passos / Melhorias Futuras
1224
-
1225
- ### Funcionalidades Planejadas
1226
-
1227
- 1. **Key Rotation Automática**
1228
- - Sugerir rotação de chaves antigas
1229
- - Transição suave entre chaves
1230
-
1231
- 2. **Blacklist de Chaves**
1232
- - Revogar chaves comprometidas
1233
- - Armazenamento distribuído de revogações
1234
-
1235
- 3. **Multi-Device Support**
1236
- - Mesmo usuário, múltiplas chaves
1237
- - Sincronização de permissões
1238
-
1239
- 4. **Audit Log**
1240
- - Histórico de autenticações
1241
- - Análise de padrões suspeitos
1242
-
1243
- 5. **2FA Opcional**
1244
- - Adicionar segundo fator além da assinatura
1245
- - TOTP ou WebAuthn
1246
-
1247
- ---
1248
-
1249
- ## ✅ Checklist de Manutenção
1250
-
1251
- Ao modificar este plugin, verificar:
1252
-
1253
- - [ ] Testes automatizados passam (`bun run test-crypto-auth.ts`)
1254
- - [ ] Frontend funciona (http://localhost:5173 → Crypto Auth Demo)
1255
- - [ ] Replay attack protection ativo
1256
- - [ ] Timestamp validation funcionando
1257
- - [ ] User context propagado corretamente
1258
- - [ ] Rotas públicas acessíveis sem auth
1259
- - [ ] Rotas protegidas exigem autenticação
1260
- - [ ] Rotas admin verificam `isAdmin`
1261
- - [ ] Nonces sendo limpos periodicamente
1262
- - [ ] Logs de segurança sendo gerados
1263
- - [ ] Documentação atualizada (este arquivo!)
1264
-
1265
- ---
1266
-
1267
- ## 📞 Suporte
1268
-
1269
- **Logs importantes**: `plugins/crypto-auth/server/*.ts`
1270
- **Testes**: `test-crypto-auth.ts`
1271
- **Exemplos**: `app/client/src/pages/CryptoAuthPage.tsx`
1272
-
1273
- **Arquivos críticos** (não modificar sem entender):
1274
- - `CryptoAuthService.ts` - Validação de assinaturas
1275
- - `AuthMiddleware.ts` - Decisões de autenticação
1276
- - `CryptoAuthClient.ts` - Geração e assinatura
1277
-
1278
- ---
1279
-
1280
- **Última atualização**: Janeiro 2025
1281
- **Versão do Plugin**: 1.0.0
1282
- **Compatível com**: FluxStack v1.4.1+