create-fluxstack 1.4.0 → 1.5.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.
Files changed (55) hide show
  1. package/.env.example +8 -1
  2. package/CRYPTO-AUTH-MIDDLEWARE-GUIDE.md +475 -0
  3. package/CRYPTO-AUTH-MIDDLEWARES.md +473 -0
  4. package/CRYPTO-AUTH-USAGE.md +491 -0
  5. package/EXEMPLO-ROTA-PROTEGIDA.md +347 -0
  6. package/QUICK-START-CRYPTO-AUTH.md +221 -0
  7. package/app/client/src/App.tsx +4 -1
  8. package/app/client/src/pages/CryptoAuthPage.tsx +394 -0
  9. package/app/server/index.ts +4 -0
  10. package/app/server/routes/crypto-auth-demo.routes.ts +167 -0
  11. package/app/server/routes/example-with-crypto-auth.routes.ts +235 -0
  12. package/app/server/routes/exemplo-posts.routes.ts +161 -0
  13. package/app/server/routes/index.ts +5 -1
  14. package/config/index.ts +9 -1
  15. package/core/cli/generators/index.ts +5 -2
  16. package/core/cli/generators/plugin.ts +580 -0
  17. package/core/cli/generators/template-engine.ts +5 -0
  18. package/core/cli/index.ts +88 -3
  19. package/core/cli/plugin-discovery.ts +33 -12
  20. package/core/framework/server.ts +10 -0
  21. package/core/plugins/dependency-manager.ts +89 -22
  22. package/core/plugins/index.ts +4 -0
  23. package/core/plugins/manager.ts +3 -2
  24. package/core/plugins/module-resolver.ts +216 -0
  25. package/core/plugins/registry.ts +28 -1
  26. package/core/utils/logger/index.ts +4 -0
  27. package/core/utils/version.ts +1 -1
  28. package/create-fluxstack.ts +117 -8
  29. package/fluxstack.config.ts +253 -114
  30. package/package.json +117 -117
  31. package/plugins/crypto-auth/README.md +722 -172
  32. package/plugins/crypto-auth/ai-context.md +1282 -0
  33. package/plugins/crypto-auth/cli/make-protected-route.command.ts +383 -0
  34. package/plugins/crypto-auth/client/CryptoAuthClient.ts +136 -159
  35. package/plugins/crypto-auth/client/components/AuthProvider.tsx +35 -94
  36. package/plugins/crypto-auth/client/components/LoginButton.tsx +36 -53
  37. package/plugins/crypto-auth/client/components/ProtectedRoute.tsx +17 -37
  38. package/plugins/crypto-auth/client/components/index.ts +1 -4
  39. package/plugins/crypto-auth/client/index.ts +1 -1
  40. package/plugins/crypto-auth/config/index.ts +34 -0
  41. package/plugins/crypto-auth/index.ts +84 -152
  42. package/plugins/crypto-auth/package.json +65 -64
  43. package/plugins/crypto-auth/server/AuthMiddleware.ts +19 -75
  44. package/plugins/crypto-auth/server/CryptoAuthService.ts +60 -167
  45. package/plugins/crypto-auth/server/index.ts +15 -2
  46. package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +65 -0
  47. package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +26 -0
  48. package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +76 -0
  49. package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +45 -0
  50. package/plugins/crypto-auth/server/middlewares/helpers.ts +140 -0
  51. package/plugins/crypto-auth/server/middlewares/index.ts +22 -0
  52. package/plugins/crypto-auth/server/middlewares.ts +19 -0
  53. package/test-crypto-auth.ts +101 -0
  54. package/plugins/crypto-auth/client/components/SessionInfo.tsx +0 -242
  55. package/plugins/crypto-auth/plugin.json +0 -29
@@ -1,238 +1,788 @@
1
- # FluxStack Crypto Auth Plugin
1
+ # 🔐 FluxStack Crypto Auth Plugin
2
2
 
3
- Plugin de autenticação criptográfica baseado em Ed25519 para FluxStack.
3
+ Sistema de autenticação baseado em criptografia **Ed25519** para FluxStack. Autenticação stateless sem sessões, usando assinaturas criptográficas.
4
4
 
5
- ## Características
5
+ ## 📋 Índice
6
6
 
7
- - 🔐 **Zero-friction auth** - Sem cadastros, senhas ou emails
8
- - **Criptografia Ed25519** - Assinatura criptográfica de todas as requisições
9
- - 🌐 **Cross-platform** - Funciona em qualquer ambiente JavaScript
10
- - 💾 **Stateless backend** - Não precisa de banco para autenticação
11
- - 🎨 **Componentes React** - Componentes prontos para uso
12
- - **Integração FluxStack** - Plugin nativo do FluxStack
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)
13
18
 
14
- ## Instalação
19
+ ---
15
20
 
16
- ```bash
17
- # O plugin já está incluído na pasta plugins/
18
- # Apenas habilite no fluxstack.config.ts
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))
19
58
  ```
20
59
 
21
- ## Configuração
60
+ ### 2. **Cliente Assina Cada Requisição**
22
61
 
23
- No seu `fluxstack.config.ts`:
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`**
24
113
 
25
114
  ```typescript
26
- export const config: FluxStackConfig = {
27
- // ... outras configurações
28
-
115
+ import { cryptoAuthPlugin } from './plugins/crypto-auth'
116
+
117
+ export default defineConfig({
29
118
  plugins: {
30
- enabled: ['crypto-auth'],
119
+ enabled: [
120
+ cryptoAuthPlugin
121
+ ],
31
122
  config: {
32
123
  'crypto-auth': {
33
124
  enabled: true,
34
- sessionTimeout: 1800000, // 30 minutos
35
125
  maxTimeDrift: 300000, // 5 minutos
36
126
  adminKeys: [
37
- 'sua_chave_publica_admin_aqui'
38
- ],
39
- protectedRoutes: [
40
- '/api/admin/*',
41
- '/api/protected/*'
42
- ],
43
- publicRoutes: [
44
- '/api/auth/*',
45
- '/api/health',
46
- '/api/docs'
127
+ 'a1b2c3d4e5f6...', // Chaves públicas de admins (hex 64 chars)
128
+ 'f6e5d4c3b2a1...'
47
129
  ],
48
130
  enableMetrics: true
49
131
  }
50
132
  }
51
133
  }
52
- }
134
+ })
53
135
  ```
54
136
 
55
- ## Uso no Frontend
137
+ ### 2. **Variáveis de Ambiente (Opcional)**
56
138
 
57
- ### 1. Configurar o Provider
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
+ ```
58
146
 
59
- ```tsx
60
- import React from 'react'
61
- import { AuthProvider } from '@/plugins/crypto-auth/client'
147
+ ---
62
148
 
63
- function App() {
64
- return (
65
- <AuthProvider
66
- config={{
67
- apiBaseUrl: 'http://localhost:3000',
68
- storage: 'localStorage'
69
- }}
70
- onAuthChange={(isAuth, session) => {
71
- console.log('Auth changed:', isAuth, session)
72
- }}
73
- >
74
- <YourApp />
75
- </AuthProvider>
76
- )
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
77
159
  }
78
160
  ```
79
161
 
80
- ### 2. Usar o Hook de Autenticação
81
-
82
- ```tsx
83
- import React from 'react'
84
- import { useAuth } from '@/plugins/crypto-auth/client'
85
-
86
- function Dashboard() {
87
- const {
88
- isAuthenticated,
89
- isAdmin,
90
- permissions,
91
- login,
92
- logout,
93
- client
94
- } = useAuth()
95
-
96
- const handleApiCall = async () => {
97
- try {
98
- const response = await client.fetch('/api/protected/data')
99
- const data = await response.json()
100
- console.log(data)
101
- } catch (error) {
102
- console.error('Erro na API:', error)
103
- }
104
- }
162
+ ### Valores Padrão
105
163
 
106
- if (!isAuthenticated) {
107
- return <button onClick={login}>Entrar</button>
108
- }
109
-
110
- return (
111
- <div>
112
- <h1>Dashboard {isAdmin && '(Admin)'}</h1>
113
- <p>Permissões: {permissions.join(', ')}</p>
114
- <button onClick={handleApiCall}>Chamar API</button>
115
- <button onClick={logout}>Sair</button>
116
- </div>
117
- )
164
+ ```typescript
165
+ {
166
+ enabled: true,
167
+ maxTimeDrift: 300000, // 5 minutos
168
+ adminKeys: [],
169
+ enableMetrics: true
118
170
  }
119
171
  ```
120
172
 
121
- ### 3. Componentes Prontos
122
-
123
- ```tsx
124
- import React from 'react'
125
- import {
126
- LoginButton,
127
- ProtectedRoute,
128
- SessionInfo
129
- } from '@/plugins/crypto-auth/client'
130
-
131
- function MyApp() {
132
- return (
133
- <div>
134
- {/* Botão de login/logout */}
135
- <LoginButton
136
- onLogin={(session) => console.log('Logado:', session)}
137
- onLogout={() => console.log('Deslogado')}
138
- showPermissions={true}
139
- />
140
-
141
- {/* Rota protegida */}
142
- <ProtectedRoute requireAdmin={true}>
143
- <AdminPanel />
144
- </ProtectedRoute>
145
-
146
- {/* Informações da sessão */}
147
- <SessionInfo
148
- showPrivateKey={false}
149
- compact={true}
150
- />
151
- </div>
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
+ })
152
231
  )
153
- }
154
232
  ```
155
233
 
156
- ### 4. HOC para Proteção
234
+ ### Registrar Rotas
157
235
 
158
- ```tsx
159
- import { withAuth } from '@/plugins/crypto-auth/client'
236
+ ```typescript
237
+ // app/server/routes/index.ts
238
+ import { usersRoutes } from './users.routes'
160
239
 
161
- const AdminComponent = () => <div>Área Admin</div>
240
+ export const apiRoutes = new Elysia({ prefix: '/api' })
241
+ .use(usersRoutes)
242
+ ```
162
243
 
163
- // Proteger componente
164
- const ProtectedAdmin = withAuth(AdminComponent, {
165
- requireAdmin: true,
166
- requiredPermissions: ['admin']
167
- })
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]
168
256
  ```
169
257
 
170
- ## Uso no Backend
258
+ #### **Argumentos**
171
259
 
172
- O plugin automaticamente:
260
+ - `name` - Nome da rota (ex: posts, users, admin)
173
261
 
174
- - Registra rotas de autenticação em `/api/auth/*`
175
- - Aplica middleware de autenticação nas rotas protegidas
176
- - Valida assinaturas Ed25519 em cada requisição
177
- - Gerencia sessões em memória
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
+ ```
178
280
 
179
- ### Rotas Automáticas
281
+ #### **Templates Gerados**
180
282
 
181
- - `POST /api/auth/session/init` - Inicializar sessão
182
- - `POST /api/auth/session/validate` - Validar sessão
183
- - `GET /api/auth/session/info` - Informações da sessão
184
- - `POST /api/auth/session/logout` - Encerrar sessão
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) |
185
289
 
186
- ### Acessar Usuário nas Rotas
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`.
187
319
 
188
320
  ```typescript
189
- // Em suas rotas FluxStack
190
- app.get('/api/protected/data', ({ user }) => {
191
- // user estará disponível se autenticado
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
+
192
409
  if (!user) {
193
- return { error: 'Não autenticado' }
410
+ return { error: 'Not authenticated' }
194
411
  }
195
-
412
+
196
413
  return {
197
- message: 'Dados protegidos',
198
- user: {
199
- sessionId: user.sessionId,
200
- isAdmin: user.isAdmin,
201
- permissions: user.permissions
202
- }
414
+ publicKey: user.publicKey,
415
+ isAdmin: user.isAdmin
203
416
  }
204
417
  })
205
418
  ```
206
419
 
207
- ## Como Funciona
420
+ **Retorno:**
421
+ ```typescript
422
+ {
423
+ publicKey: string // Chave pública do usuário (hex)
424
+ isAdmin: boolean // Se é administrador
425
+ } | null
426
+ ```
208
427
 
209
- 1. **Cliente gera** par de chaves Ed25519 automaticamente
210
- 2. **Session ID** = chave pública (64 chars hex)
211
- 3. **Todas as requisições** são assinadas com a chave privada
212
- 4. **Backend valida** a assinatura Ed25519 em cada request
213
- 5. **Admin access** via chaves públicas autorizadas
428
+ ---
214
429
 
215
- ## Segurança
430
+ ### `isCryptoAuthAuthenticated(request)`
216
431
 
217
- - Assinatura Ed25519 em todas as requisições
218
- - ✅ Nonce para prevenir replay attacks
219
- - ✅ Validação de timestamp (5 min máximo)
220
- - ✅ Timeout de sessões (30 min padrão)
221
- - ✅ Chaves privadas nunca saem do cliente
222
- - ✅ Stateless - sem dependência de banco de dados
432
+ Verifica se a requisição está autenticada.
223
433
 
224
- ## Desenvolvimento
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
+ ```
225
610
 
226
- Para desenvolver o plugin:
611
+ ---
227
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:
228
676
  ```bash
229
- # Instalar dependências
230
- npm install @noble/curves @noble/hashes
677
+ # Requisições autenticadas
678
+ Requisição autenticada {
679
+ publicKey: "a1b2c3d4...",
680
+ isAdmin: false,
681
+ path: "/api/users",
682
+ method: "GET"
683
+ }
231
684
 
232
- # Para desenvolvimento com React
233
- npm install --save-dev @types/react react
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
+ })
234
772
  ```
235
773
 
236
- ## Licença
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
+ ---
237
787
 
238
- MIT
788
+ **Desenvolvido com ❤️ pela FluxStack Team**