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,788 +0,0 @@
1
- # 🔐 FluxStack Crypto Auth Plugin
2
-
3
- Sistema de autenticação baseado em criptografia **Ed25519** para FluxStack. Autenticação stateless sem sessões, usando assinaturas criptográficas.
4
-
5
- ## 📋 Índice
6
-
7
- - [O Que É](#-o-que-é)
8
- - [Como Funciona](#-como-funciona)
9
- - [Instalação](#-instalação)
10
- - [Configuração](#️-configuração)
11
- - [Uso Básico](#-uso-básico)
12
- - [CLI Commands](#-cli-commands)
13
- - [Middlewares Disponíveis](#-middlewares-disponíveis)
14
- - [Helpers e Utilitários](#-helpers-e-utilitários)
15
- - [Fluxo de Autenticação](#-fluxo-de-autenticação)
16
- - [Segurança](#-segurança)
17
- - [Troubleshooting](#-troubleshooting)
18
-
19
- ---
20
-
21
- ## 🎯 O Que É
22
-
23
- **Crypto Auth** é um plugin de autenticação que usa **assinaturas digitais Ed25519** ao invés de sessões tradicionais.
24
-
25
- ### ✨ Principais Características
26
-
27
- - ✅ **Stateless**: Sem sessões, sem armazenamento de tokens
28
- - ✅ **Zero Trust**: Cada requisição é validada independentemente
29
- - ✅ **Ed25519**: Criptografia de curva elíptica (rápida e segura)
30
- - ✅ **Anti-Replay**: Proteção contra replay attacks com timestamps e nonces
31
- - ✅ **Admin Support**: Sistema de permissões com chaves administrativas
32
- - ✅ **TypeScript**: Totalmente tipado
33
- - ✅ **CLI Integration**: Geração automática de rotas protegidas
34
-
35
- ### 🔄 Diferenças vs. Auth Tradicional
36
-
37
- | Característica | Auth Tradicional | Crypto Auth |
38
- |----------------|------------------|-------------|
39
- | **Armazenamento** | Sessões no servidor | Nenhum |
40
- | **Escalabilidade** | Limitada (sessões) | Infinita (stateless) |
41
- | **Segurança** | Token JWT ou session | Assinatura Ed25519 |
42
- | **Chave privada** | Armazenada no servidor | **NUNCA** sai do cliente |
43
- | **Performance** | Depende do DB/cache | Ultra-rápida (validação local) |
44
-
45
- ---
46
-
47
- ## 🔬 Como Funciona
48
-
49
- ### 1. **Cliente Gera Par de Chaves (Uma Vez)**
50
-
51
- ```typescript
52
- // No navegador (usando TweetNaCl ou similar)
53
- const keypair = nacl.sign.keyPair()
54
-
55
- // Armazenar no localStorage (chave privada NUNCA sai do navegador)
56
- localStorage.setItem('privateKey', toHex(keypair.secretKey))
57
- localStorage.setItem('publicKey', toHex(keypair.publicKey))
58
- ```
59
-
60
- ### 2. **Cliente Assina Cada Requisição**
61
-
62
- ```typescript
63
- // Para cada request
64
- const timestamp = Date.now()
65
- const nonce = generateRandomNonce()
66
- const message = `${timestamp}:${nonce}:${requestBody}`
67
-
68
- // Assinar com chave privada
69
- const signature = nacl.sign.detached(message, privateKey)
70
-
71
- // Enviar headers
72
- headers = {
73
- 'x-public-key': publicKeyHex,
74
- 'x-timestamp': timestamp,
75
- 'x-nonce': nonce,
76
- 'x-signature': toHex(signature)
77
- }
78
- ```
79
-
80
- ### 3. **Servidor Valida Assinatura**
81
-
82
- ```typescript
83
- // Plugin valida automaticamente
84
- const isValid = nacl.sign.detached.verify(
85
- message,
86
- signature,
87
- publicKey
88
- )
89
-
90
- if (!isValid) {
91
- throw new Error('Invalid signature')
92
- }
93
-
94
- // Verificar timestamp (previne replay attacks)
95
- if (Math.abs(Date.now() - timestamp) > maxTimeDrift) {
96
- throw new Error('Timestamp expired')
97
- }
98
- ```
99
-
100
- ### 4. **Sem Armazenamento de Estado**
101
-
102
- - ✅ Servidor valida usando **apenas** a chave pública enviada
103
- - ✅ Nenhuma sessão ou token armazenado
104
- - ✅ Cada requisição é independente
105
-
106
- ---
107
-
108
- ## 📦 Instalação
109
-
110
- O plugin já vem incluído no FluxStack. Para habilitá-lo:
111
-
112
- ### 1. **Adicionar ao `fluxstack.config.ts`**
113
-
114
- ```typescript
115
- import { cryptoAuthPlugin } from './plugins/crypto-auth'
116
-
117
- export default defineConfig({
118
- plugins: {
119
- enabled: [
120
- cryptoAuthPlugin
121
- ],
122
- config: {
123
- 'crypto-auth': {
124
- enabled: true,
125
- maxTimeDrift: 300000, // 5 minutos
126
- adminKeys: [
127
- 'a1b2c3d4e5f6...', // Chaves públicas de admins (hex 64 chars)
128
- 'f6e5d4c3b2a1...'
129
- ],
130
- enableMetrics: true
131
- }
132
- }
133
- }
134
- })
135
- ```
136
-
137
- ### 2. **Variáveis de Ambiente (Opcional)**
138
-
139
- ```bash
140
- # .env
141
- CRYPTO_AUTH_ENABLED=true
142
- CRYPTO_AUTH_MAX_TIME_DRIFT=300000
143
- CRYPTO_AUTH_ADMIN_KEYS=a1b2c3d4e5f6...,f6e5d4c3b2a1...
144
- CRYPTO_AUTH_ENABLE_METRICS=true
145
- ```
146
-
147
- ---
148
-
149
- ## ⚙️ Configuração
150
-
151
- ### Schema de Configuração
152
-
153
- ```typescript
154
- {
155
- enabled: boolean // Habilitar/desabilitar plugin
156
- maxTimeDrift: number // Máximo drift de tempo (ms) - previne replay
157
- adminKeys: string[] // Chaves públicas de administradores
158
- enableMetrics: boolean // Habilitar logs de métricas
159
- }
160
- ```
161
-
162
- ### Valores Padrão
163
-
164
- ```typescript
165
- {
166
- enabled: true,
167
- maxTimeDrift: 300000, // 5 minutos
168
- adminKeys: [],
169
- enableMetrics: true
170
- }
171
- ```
172
-
173
- ---
174
-
175
- ## 🚀 Uso Básico
176
-
177
- ### Opção 1: CLI (Recomendado)
178
-
179
- ```bash
180
- # Criar rota com auth obrigatória
181
- bun flux crypto-auth:make:route users
182
-
183
- # Criar rota admin-only
184
- bun flux crypto-auth:make:route admin-panel --auth admin
185
-
186
- # Criar rota com auth opcional
187
- bun flux crypto-auth:make:route blog --auth optional
188
-
189
- # Criar rota pública
190
- bun flux crypto-auth:make:route public-api --auth public
191
- ```
192
-
193
- ### Opção 2: Manual
194
-
195
- ```typescript
196
- // app/server/routes/users.routes.ts
197
- import { Elysia, t } from 'elysia'
198
- import { cryptoAuthRequired, getCryptoAuthUser } from '@/plugins/crypto-auth/server'
199
-
200
- export const usersRoutes = new Elysia({ prefix: '/users' })
201
-
202
- // ========================================
203
- // 🔒 ROTAS PROTEGIDAS
204
- // ========================================
205
- .guard({}, (app) =>
206
- app.use(cryptoAuthRequired())
207
-
208
- .get('/', ({ request }) => {
209
- const user = getCryptoAuthUser(request)!
210
-
211
- return {
212
- message: 'Lista de usuários',
213
- authenticatedAs: user.publicKey.substring(0, 8) + '...',
214
- isAdmin: user.isAdmin
215
- }
216
- })
217
-
218
- .post('/', ({ request, body }) => {
219
- const user = getCryptoAuthUser(request)!
220
-
221
- return {
222
- message: 'Usuário criado',
223
- createdBy: user.publicKey.substring(0, 8) + '...'
224
- }
225
- }, {
226
- body: t.Object({
227
- name: t.String(),
228
- email: t.String()
229
- })
230
- })
231
- )
232
- ```
233
-
234
- ### Registrar Rotas
235
-
236
- ```typescript
237
- // app/server/routes/index.ts
238
- import { usersRoutes } from './users.routes'
239
-
240
- export const apiRoutes = new Elysia({ prefix: '/api' })
241
- .use(usersRoutes)
242
- ```
243
-
244
- ---
245
-
246
- ## 🎛️ CLI Commands
247
-
248
- ### `crypto-auth:make:route`
249
-
250
- Gera arquivos de rotas com proteção crypto-auth automaticamente.
251
-
252
- #### **Sintaxe**
253
-
254
- ```bash
255
- bun flux crypto-auth:make:route <name> [options]
256
- ```
257
-
258
- #### **Argumentos**
259
-
260
- - `name` - Nome da rota (ex: posts, users, admin)
261
-
262
- #### **Opções**
263
-
264
- - `--auth, -a` - Tipo de autenticação (required, admin, optional, public)
265
- - `--output, -o` - Diretório de saída (padrão: app/server/routes)
266
- - `--force, -f` - Sobrescrever arquivo existente
267
-
268
- #### **Exemplos**
269
-
270
- ```bash
271
- # Rota com auth obrigatória
272
- bun flux crypto-auth:make:route posts
273
-
274
- # Rota admin-only com output customizado
275
- bun flux crypto-auth:make:route admin --auth admin --output src/routes
276
-
277
- # Forçar sobrescrita
278
- bun flux crypto-auth:make:route users --force
279
- ```
280
-
281
- #### **Templates Gerados**
282
-
283
- | Tipo | Descrição | Rotas Geradas |
284
- |------|-----------|---------------|
285
- | `required` | Auth obrigatória | GET, POST, PUT, DELETE (CRUD completo) |
286
- | `admin` | Apenas admins | GET, POST, DELETE |
287
- | `optional` | Auth opcional | GET (lista), GET (detalhes com conteúdo extra) |
288
- | `public` | Sem auth | GET (lista), GET (detalhes) |
289
-
290
- ---
291
-
292
- ## 🛡️ Middlewares Disponíveis
293
-
294
- ### 1. `cryptoAuthRequired()`
295
-
296
- Autenticação **obrigatória**. Bloqueia requisições não autenticadas.
297
-
298
- ```typescript
299
- import { cryptoAuthRequired, getCryptoAuthUser } from '@/plugins/crypto-auth/server'
300
-
301
- .guard({}, (app) =>
302
- app.use(cryptoAuthRequired())
303
- .get('/protected', ({ request }) => {
304
- const user = getCryptoAuthUser(request)! // ✅ Sempre existe
305
- return { user }
306
- })
307
- )
308
- ```
309
-
310
- **Comportamento:**
311
- - ✅ Requisição autenticada → Prossegue
312
- - ❌ Requisição não autenticada → `401 Unauthorized`
313
-
314
- ---
315
-
316
- ### 2. `cryptoAuthAdmin()`
317
-
318
- Apenas **administradores**. Valida se a chave pública está em `adminKeys`.
319
-
320
- ```typescript
321
- import { cryptoAuthAdmin, getCryptoAuthUser } from '@/plugins/crypto-auth/server'
322
-
323
- .guard({}, (app) =>
324
- app.use(cryptoAuthAdmin())
325
- .delete('/delete/:id', ({ request }) => {
326
- const user = getCryptoAuthUser(request)! // ✅ Sempre admin
327
- return { message: 'Deletado' }
328
- })
329
- )
330
- ```
331
-
332
- **Comportamento:**
333
- - ✅ Chave pública está em `adminKeys` → Prossegue
334
- - ❌ Não é admin → `403 Forbidden`
335
- - ❌ Não autenticado → `401 Unauthorized`
336
-
337
- ---
338
-
339
- ### 3. `cryptoAuthOptional()`
340
-
341
- Autenticação **opcional**. Não bloqueia, mas identifica usuários autenticados.
342
-
343
- ```typescript
344
- import { cryptoAuthOptional, getCryptoAuthUser } from '@/plugins/crypto-auth/server'
345
-
346
- .guard({}, (app) =>
347
- app.use(cryptoAuthOptional())
348
- .get('/feed', ({ request }) => {
349
- const user = getCryptoAuthUser(request) // ⚠️ Pode ser null
350
-
351
- if (user) {
352
- return {
353
- message: 'Feed personalizado',
354
- recommendations: [...],
355
- user: user.publicKey.substring(0, 8) + '...'
356
- }
357
- }
358
-
359
- return {
360
- message: 'Feed público',
361
- trending: [...]
362
- }
363
- })
364
- )
365
- ```
366
-
367
- **Comportamento:**
368
- - ✅ Requisição autenticada → `user` disponível
369
- - ✅ Requisição não autenticada → `user = null`, requisição prossegue
370
-
371
- ---
372
-
373
- ### 4. `cryptoAuthPermissions(permissions: string[])`
374
-
375
- Valida **permissões customizadas**.
376
-
377
- ```typescript
378
- import { cryptoAuthPermissions, getCryptoAuthUser } from '@/plugins/crypto-auth/server'
379
-
380
- .guard({}, (app) =>
381
- app.use(cryptoAuthPermissions(['write', 'delete']))
382
- .put('/edit/:id', ({ request }) => {
383
- const user = getCryptoAuthUser(request)! // ✅ Tem as permissões
384
- return { message: 'Editado' }
385
- })
386
- )
387
- ```
388
-
389
- **Comportamento:**
390
- - ✅ Usuário tem todas as permissões → Prossegue
391
- - ❌ Falta alguma permissão → `403 Forbidden`
392
-
393
- > **Nota**: Sistema de permissões requer extensão customizada. Por padrão, apenas `isAdmin` é verificado.
394
-
395
- ---
396
-
397
- ## 🔧 Helpers e Utilitários
398
-
399
- ### `getCryptoAuthUser(request)`
400
-
401
- Retorna o usuário autenticado ou `null`.
402
-
403
- ```typescript
404
- import { getCryptoAuthUser } from '@/plugins/crypto-auth/server'
405
-
406
- .get('/profile', ({ request }) => {
407
- const user = getCryptoAuthUser(request)
408
-
409
- if (!user) {
410
- return { error: 'Not authenticated' }
411
- }
412
-
413
- return {
414
- publicKey: user.publicKey,
415
- isAdmin: user.isAdmin
416
- }
417
- })
418
- ```
419
-
420
- **Retorno:**
421
- ```typescript
422
- {
423
- publicKey: string // Chave pública do usuário (hex)
424
- isAdmin: boolean // Se é administrador
425
- } | null
426
- ```
427
-
428
- ---
429
-
430
- ### `isCryptoAuthAuthenticated(request)`
431
-
432
- Verifica se a requisição está autenticada.
433
-
434
- ```typescript
435
- import { isCryptoAuthAuthenticated } from '@/plugins/crypto-auth/server'
436
-
437
- .get('/status', ({ request }) => {
438
- const isAuth = isCryptoAuthAuthenticated(request)
439
-
440
- return {
441
- authenticated: isAuth,
442
- message: isAuth ? 'Você está logado' : 'Você não está logado'
443
- }
444
- })
445
- ```
446
-
447
- **Retorno:** `boolean`
448
-
449
- ---
450
-
451
- ### `isCryptoAuthAdmin(request)`
452
-
453
- Verifica se o usuário é administrador.
454
-
455
- ```typescript
456
- import { isCryptoAuthAdmin } from '@/plugins/crypto-auth/server'
457
-
458
- .get('/admin-check', ({ request }) => {
459
- const isAdmin = isCryptoAuthAdmin(request)
460
-
461
- return {
462
- isAdmin,
463
- access: isAdmin ? 'granted' : 'denied'
464
- }
465
- })
466
- ```
467
-
468
- **Retorno:** `boolean`
469
-
470
- ---
471
-
472
- ### `hasCryptoAuthPermission(request, permission)`
473
-
474
- Verifica se o usuário tem uma permissão específica.
475
-
476
- ```typescript
477
- import { hasCryptoAuthPermission } from '@/plugins/crypto-auth/server'
478
-
479
- .get('/can-delete', ({ request }) => {
480
- const canDelete = hasCryptoAuthPermission(request, 'delete')
481
-
482
- return { canDelete }
483
- })
484
- ```
485
-
486
- **Retorno:** `boolean`
487
-
488
- ---
489
-
490
- ## 🔄 Fluxo de Autenticação
491
-
492
- ### Diagrama Completo
493
-
494
- ```
495
- ┌─────────────┐ ┌─────────────┐
496
- │ Cliente │ │ Servidor │
497
- │ (Browser) │ │ (Elysia) │
498
- └──────┬──────┘ └──────┬──────┘
499
- │ │
500
- │ 1. Gera par de chaves Ed25519 (uma vez) │
501
- │ privateKey, publicKey │
502
- │ localStorage.setItem(...) │
503
- │ │
504
- │ 2. Para cada request: │
505
- │ - timestamp = Date.now() │
506
- │ - nonce = random() │
507
- │ - message = `${timestamp}:${nonce}:${body}` │
508
- │ - signature = sign(message, privateKey) │
509
- │ │
510
- │ 3. Envia request com headers │
511
- │────────────────────────────────────────────────>│
512
- │ x-public-key: <publicKey> │
513
- │ x-timestamp: <timestamp> │
514
- │ x-nonce: <nonce> │
515
- │ x-signature: <signature> │
516
- │ │
517
- │ │ 4. Middleware valida:
518
- │ │ - Reconstrói message
519
- │ │ - verify(message, signature, publicKey)
520
- │ │ - Verifica timestamp
521
- │ │ - Verifica se é admin (se necessário)
522
- │ │
523
- │ 5a. ✅ Válido │
524
- │<────────────────────────────────────────────────│
525
- │ 200 OK { data: ... } │
526
- │ │
527
- │ 5b. ❌ Inválido │
528
- │<────────────────────────────────────────────────│
529
- │ 401 Unauthorized { error: ... } │
530
- │ │
531
- ```
532
-
533
- ---
534
-
535
- ## 🔒 Segurança
536
-
537
- ### ✅ Proteções Implementadas
538
-
539
- 1. **Anti-Replay Attacks**
540
- - Timestamp validation (maxTimeDrift)
541
- - Nonce único por requisição
542
- - Assinatura inclui timestamp + nonce
543
-
544
- 2. **Stateless Security**
545
- - Sem sessões (não há o que roubar)
546
- - Chave privada **NUNCA** sai do cliente
547
- - Validação criptográfica a cada request
548
-
549
- 3. **Admin Protection**
550
- - Lista whitelist de chaves públicas administrativas
551
- - Validação dupla (auth + isAdmin)
552
-
553
- 4. **Type Safety**
554
- - TypeScript completo
555
- - Validação de schemas com TypeBox
556
-
557
- ### ⚠️ Considerações de Segurança
558
-
559
- 1. **HTTPS Obrigatório**
560
- ```typescript
561
- // Sempre use HTTPS em produção
562
- if (process.env.NODE_ENV === 'production' && !request.url.startsWith('https')) {
563
- throw new Error('HTTPS required')
564
- }
565
- ```
566
-
567
- 2. **Rotação de Chaves**
568
- ```typescript
569
- // Cliente deve permitir rotação de chaves
570
- function rotateKeys() {
571
- const newKeypair = nacl.sign.keyPair()
572
- // Migrar dados assinados com chave antiga
573
- // Atualizar localStorage
574
- }
575
- ```
576
-
577
- 3. **Rate Limiting**
578
- ```typescript
579
- // Adicionar rate limiting para prevenir brute force
580
- import { rateLimit } from '@/plugins/rate-limit'
581
-
582
- .use(rateLimit({ max: 100, window: '15m' }))
583
- .use(cryptoAuthRequired())
584
- ```
585
-
586
- 4. **Admin Keys em Ambiente**
587
- ```bash
588
- # .env
589
- CRYPTO_AUTH_ADMIN_KEYS=key1,key2,key3
590
- ```
591
-
592
- ---
593
-
594
- ## 🧪 Troubleshooting
595
-
596
- ### ❌ Erro: "Authentication required"
597
-
598
- **Problema**: Requisição sem headers de autenticação.
599
-
600
- **Solução**:
601
- ```typescript
602
- // Cliente deve enviar headers
603
- headers: {
604
- 'x-public-key': publicKeyHex,
605
- 'x-timestamp': Date.now().toString(),
606
- 'x-nonce': generateNonce(),
607
- 'x-signature': signatureHex
608
- }
609
- ```
610
-
611
- ---
612
-
613
- ### ❌ Erro: "Invalid signature"
614
-
615
- **Problema**: Assinatura não corresponde à mensagem.
616
-
617
- **Causas comuns**:
618
- 1. Chave privada incorreta
619
- 2. Mensagem reconstruída diferente
620
- 3. Ordem dos campos alterada
621
-
622
- **Solução**:
623
- ```typescript
624
- // Garantir ordem exata dos campos
625
- const message = `${timestamp}:${nonce}:${JSON.stringify(body)}`
626
- ```
627
-
628
- ---
629
-
630
- ### ❌ Erro: "Timestamp drift too large"
631
-
632
- **Problema**: Diferença entre timestamp do cliente e servidor excede `maxTimeDrift`.
633
-
634
- **Solução**:
635
- ```typescript
636
- // Sincronizar relógio do cliente com servidor
637
- const serverTime = await fetch('/api/time').then(r => r.json())
638
- const timeDrift = Date.now() - serverTime.timestamp
639
- // Ajustar timestamps futuros
640
- ```
641
-
642
- ---
643
-
644
- ### ❌ Erro: "Admin access required"
645
-
646
- **Problema**: Usuário não está na lista de `adminKeys`.
647
-
648
- **Solução**:
649
- ```typescript
650
- // Adicionar chave pública ao config
651
- {
652
- 'crypto-auth': {
653
- adminKeys: [
654
- 'a1b2c3d4e5f6...', // Sua chave pública
655
- ]
656
- }
657
- }
658
- ```
659
-
660
- ---
661
-
662
- ### 🔍 Debug Mode
663
-
664
- Habilitar logs detalhados:
665
-
666
- ```typescript
667
- // fluxstack.config.ts
668
- {
669
- 'crypto-auth': {
670
- enableMetrics: true
671
- }
672
- }
673
- ```
674
-
675
- Verificar logs:
676
- ```bash
677
- # Requisições autenticadas
678
- Requisição autenticada {
679
- publicKey: "a1b2c3d4...",
680
- isAdmin: false,
681
- path: "/api/users",
682
- method: "GET"
683
- }
684
-
685
- # Falhas de autenticação
686
- Falha na autenticação {
687
- error: "Invalid signature",
688
- path: "/api/users",
689
- method: "POST"
690
- }
691
- ```
692
-
693
- ---
694
-
695
- ## 📚 Recursos Adicionais
696
-
697
- ### Documentação Relacionada
698
-
699
- - [`QUICK-START-CRYPTO-AUTH.md`](../../QUICK-START-CRYPTO-AUTH.md) - Início rápido em 5 minutos
700
- - [`EXEMPLO-ROTA-PROTEGIDA.md`](../../EXEMPLO-ROTA-PROTEGIDA.md) - Tutorial passo-a-passo
701
- - [`CRYPTO-AUTH-MIDDLEWARE-GUIDE.md`](../../CRYPTO-AUTH-MIDDLEWARE-GUIDE.md) - Referência de middlewares
702
-
703
- ### Bibliotecas Cliente Recomendadas
704
-
705
- - **JavaScript/TypeScript**: [TweetNaCl.js](https://github.com/dchest/tweetnacl-js)
706
- - **React**: [@stablelib/ed25519](https://github.com/StableLib/stablelib)
707
-
708
- ### Exemplo de Cliente
709
-
710
- ```typescript
711
- // client-auth.ts
712
- import nacl from 'tweetnacl'
713
- import { encodeHex, decodeHex } from 'tweetnacl-util'
714
-
715
- export class CryptoAuthClient {
716
- private privateKey: Uint8Array
717
- private publicKey: Uint8Array
718
-
719
- constructor() {
720
- // Carregar ou gerar chaves
721
- const stored = localStorage.getItem('cryptoAuthKeys')
722
-
723
- if (stored) {
724
- const keys = JSON.parse(stored)
725
- this.privateKey = decodeHex(keys.privateKey)
726
- this.publicKey = decodeHex(keys.publicKey)
727
- } else {
728
- const keypair = nacl.sign.keyPair()
729
- this.privateKey = keypair.secretKey
730
- this.publicKey = keypair.publicKey
731
-
732
- localStorage.setItem('cryptoAuthKeys', JSON.stringify({
733
- privateKey: encodeHex(keypair.secretKey),
734
- publicKey: encodeHex(keypair.publicKey)
735
- }))
736
- }
737
- }
738
-
739
- async fetch(url: string, options: RequestInit = {}) {
740
- const timestamp = Date.now().toString()
741
- const nonce = encodeHex(nacl.randomBytes(16))
742
- const body = options.body || ''
743
-
744
- const message = `${timestamp}:${nonce}:${body}`
745
- const signature = nacl.sign.detached(
746
- new TextEncoder().encode(message),
747
- this.privateKey
748
- )
749
-
750
- const headers = {
751
- ...options.headers,
752
- 'x-public-key': encodeHex(this.publicKey),
753
- 'x-timestamp': timestamp,
754
- 'x-nonce': nonce,
755
- 'x-signature': encodeHex(signature)
756
- }
757
-
758
- return fetch(url, { ...options, headers })
759
- }
760
-
761
- getPublicKey() {
762
- return encodeHex(this.publicKey)
763
- }
764
- }
765
-
766
- // Uso
767
- const authClient = new CryptoAuthClient()
768
- const response = await authClient.fetch('/api/users', {
769
- method: 'POST',
770
- body: JSON.stringify({ name: 'João' })
771
- })
772
- ```
773
-
774
- ---
775
-
776
- ## 🤝 Contribuindo
777
-
778
- Para reportar bugs ou sugerir melhorias, abra uma issue no repositório do FluxStack.
779
-
780
- ---
781
-
782
- ## 📄 Licença
783
-
784
- Este plugin é parte do FluxStack e segue a mesma licença do framework.
785
-
786
- ---
787
-
788
- **Desenvolvido com ❤️ pela FluxStack Team**