create-fluxstack 1.4.1 → 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 (51) 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/plugin.ts +324 -34
  16. package/core/cli/generators/template-engine.ts +5 -0
  17. package/core/cli/plugin-discovery.ts +33 -12
  18. package/core/framework/server.ts +10 -0
  19. package/core/plugins/dependency-manager.ts +89 -22
  20. package/core/plugins/index.ts +4 -0
  21. package/core/plugins/manager.ts +3 -2
  22. package/core/plugins/module-resolver.ts +216 -0
  23. package/core/plugins/registry.ts +28 -1
  24. package/core/utils/logger/index.ts +4 -0
  25. package/fluxstack.config.ts +253 -114
  26. package/package.json +117 -117
  27. package/plugins/crypto-auth/README.md +722 -172
  28. package/plugins/crypto-auth/ai-context.md +1282 -0
  29. package/plugins/crypto-auth/cli/make-protected-route.command.ts +383 -0
  30. package/plugins/crypto-auth/client/CryptoAuthClient.ts +136 -159
  31. package/plugins/crypto-auth/client/components/AuthProvider.tsx +35 -94
  32. package/plugins/crypto-auth/client/components/LoginButton.tsx +36 -53
  33. package/plugins/crypto-auth/client/components/ProtectedRoute.tsx +17 -37
  34. package/plugins/crypto-auth/client/components/index.ts +1 -4
  35. package/plugins/crypto-auth/client/index.ts +1 -1
  36. package/plugins/crypto-auth/config/index.ts +34 -0
  37. package/plugins/crypto-auth/index.ts +84 -152
  38. package/plugins/crypto-auth/package.json +65 -64
  39. package/plugins/crypto-auth/server/AuthMiddleware.ts +19 -75
  40. package/plugins/crypto-auth/server/CryptoAuthService.ts +60 -167
  41. package/plugins/crypto-auth/server/index.ts +15 -2
  42. package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +65 -0
  43. package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +26 -0
  44. package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +76 -0
  45. package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +45 -0
  46. package/plugins/crypto-auth/server/middlewares/helpers.ts +140 -0
  47. package/plugins/crypto-auth/server/middlewares/index.ts +22 -0
  48. package/plugins/crypto-auth/server/middlewares.ts +19 -0
  49. package/test-crypto-auth.ts +101 -0
  50. package/plugins/crypto-auth/client/components/SessionInfo.tsx +0 -242
  51. package/plugins/crypto-auth/plugin.json +0 -29
package/.env.example CHANGED
@@ -27,4 +27,11 @@ LOG_LEVEL=info
27
27
 
28
28
  # Build Configuration
29
29
  BUILD_TARGET=bun
30
- BUILD_OUTDIR=dist
30
+ BUILD_OUTDIR=dist
31
+
32
+ # Crypto Auth Plugin
33
+ CRYPTO_AUTH_ENABLED=true
34
+ CRYPTO_AUTH_MAX_TIME_DRIFT=300000
35
+ # Adicione chaves públicas de admin separadas por vírgula (64 chars hex cada)
36
+ CRYPTO_AUTH_ADMIN_KEYS=
37
+ CRYPTO_AUTH_ENABLE_METRICS=true
@@ -0,0 +1,475 @@
1
+ # 🔐 Crypto Auth - Guia de Middlewares
2
+
3
+ > **✅ Nova Abordagem**: Middlewares declarativos - sem necessidade de configurar listas de paths!
4
+
5
+ ## 📖 **Visão Geral**
6
+
7
+ O plugin Crypto Auth agora usa **middlewares Elysia nativos** aplicados diretamente nas rotas. Isso torna o código mais limpo, explícito e fácil de manter.
8
+
9
+ ## 🚀 **Quick Start**
10
+
11
+ ### **1. Configuração Simplificada**
12
+
13
+ ```typescript
14
+ // fluxstack.config.ts
15
+ plugins: {
16
+ enabled: ['crypto-auth'],
17
+ config: {
18
+ 'crypto-auth': {
19
+ enabled: true,
20
+ maxTimeDrift: 300000, // 5 minutos
21
+ adminKeys: [
22
+ 'abc123def456...' // Chaves públicas dos admins
23
+ ],
24
+ enableMetrics: true
25
+ }
26
+ }
27
+ }
28
+ ```
29
+
30
+ **✅ Removido**: `protectedRoutes` e `publicRoutes`
31
+ **✅ Novo**: Middlewares aplicados diretamente nas rotas
32
+
33
+ ---
34
+
35
+ ## 🔌 **Middlewares Disponíveis**
36
+
37
+ ### **1. `cryptoAuthRequired()` - Requer Autenticação**
38
+
39
+ Bloqueia a rota se não houver assinatura válida.
40
+
41
+ ```typescript
42
+ import { cryptoAuthRequired, getCryptoAuthUser } from '@/plugins/crypto-auth/server'
43
+ import { Elysia } from 'elysia'
44
+
45
+ export const protectedRoutes = new Elysia()
46
+ .use(cryptoAuthRequired()) // ⚡ Middleware aplicado
47
+
48
+ .get('/profile', ({ request }) => {
49
+ const user = getCryptoAuthUser(request)! // Garantido que existe
50
+ return {
51
+ publicKey: user.publicKey,
52
+ isAdmin: user.isAdmin
53
+ }
54
+ })
55
+ ```
56
+
57
+ **Response se não autenticado (401):**
58
+ ```json
59
+ {
60
+ "error": {
61
+ "message": "Authentication required",
62
+ "code": "CRYPTO_AUTH_REQUIRED",
63
+ "statusCode": 401
64
+ }
65
+ }
66
+ ```
67
+
68
+ ---
69
+
70
+ ### **2. `cryptoAuthAdmin()` - Requer Admin**
71
+
72
+ Bloqueia a rota se não for administrador.
73
+
74
+ ```typescript
75
+ import { cryptoAuthAdmin } from '@/plugins/crypto-auth/server'
76
+
77
+ export const adminRoutes = new Elysia()
78
+ .use(cryptoAuthAdmin()) // ⚡ Requer admin
79
+
80
+ .delete('/users/:id', ({ params, request }) => {
81
+ const user = getCryptoAuthUser(request)! // Garantido admin
82
+ return {
83
+ deleted: params.id,
84
+ by: user.publicKey
85
+ }
86
+ })
87
+ ```
88
+
89
+ **Response se não for admin (403):**
90
+ ```json
91
+ {
92
+ "error": {
93
+ "message": "Admin privileges required",
94
+ "code": "ADMIN_REQUIRED",
95
+ "statusCode": 403,
96
+ "yourPermissions": ["user", "read"]
97
+ }
98
+ }
99
+ ```
100
+
101
+ ---
102
+
103
+ ### **3. `cryptoAuthPermissions([...])` - Requer Permissões**
104
+
105
+ Bloqueia se não tiver as permissões específicas.
106
+
107
+ ```typescript
108
+ import { cryptoAuthPermissions } from '@/plugins/crypto-auth/server'
109
+
110
+ export const writeRoutes = new Elysia()
111
+ .use(cryptoAuthPermissions(['write', 'edit'])) // ⚡ Requer ambas
112
+
113
+ .post('/posts', ({ body }) => {
114
+ return { created: body }
115
+ })
116
+ ```
117
+
118
+ **Response se sem permissão (403):**
119
+ ```json
120
+ {
121
+ "error": {
122
+ "message": "Insufficient permissions",
123
+ "code": "PERMISSION_DENIED",
124
+ "statusCode": 403,
125
+ "required": ["write", "edit"],
126
+ "yours": ["read"]
127
+ }
128
+ }
129
+ ```
130
+
131
+ ---
132
+
133
+ ### **4. `cryptoAuthOptional()` - Autenticação Opcional**
134
+
135
+ Não bloqueia, mas adiciona `user` se autenticado.
136
+
137
+ ```typescript
138
+ import { cryptoAuthOptional, getCryptoAuthUser } from '@/plugins/crypto-auth/server'
139
+
140
+ export const feedRoutes = new Elysia()
141
+ .use(cryptoAuthOptional()) // ⚡ Opcional
142
+
143
+ .get('/posts', ({ request }) => {
144
+ const user = getCryptoAuthUser(request) // Pode ser null
145
+
146
+ return {
147
+ posts: getPosts(),
148
+ personalizedFor: user ? user.publicKey : 'anonymous'
149
+ }
150
+ })
151
+ ```
152
+
153
+ ---
154
+
155
+ ## 🎯 **Padrões de Uso**
156
+
157
+ ### **Padrão 1: Grupo de Rotas Protegidas**
158
+
159
+ ```typescript
160
+ import { Elysia } from 'elysia'
161
+ import { cryptoAuthRequired } from '@/plugins/crypto-auth/server'
162
+
163
+ export const apiRoutes = new Elysia({ prefix: '/api' })
164
+
165
+ // Rotas públicas
166
+ .get('/health', () => ({ status: 'ok' }))
167
+ .get('/docs', () => ({ version: '1.0.0' }))
168
+
169
+ // Grupo protegido
170
+ .group('/users', (app) => app
171
+ .use(cryptoAuthRequired()) // ⚡ Todas as rotas do grupo requerem auth
172
+
173
+ .get('/', ({ request }) => {
174
+ const user = getCryptoAuthUser(request)!
175
+ return { users: getUsers(user.publicKey) }
176
+ })
177
+
178
+ .post('/', ({ body }) => {
179
+ return { created: body }
180
+ })
181
+ )
182
+ ```
183
+
184
+ ---
185
+
186
+ ### **Padrão 2: Mix de Permissões no Mesmo Grupo**
187
+
188
+ ```typescript
189
+ export const postsRoutes = new Elysia({ prefix: '/api/posts' })
190
+
191
+ // Leitura: apenas auth
192
+ .group('', (app) => app
193
+ .use(cryptoAuthRequired())
194
+
195
+ .get('/', () => ({ posts: [] }))
196
+ .get('/:id', ({ params }) => ({ post: params.id }))
197
+ )
198
+
199
+ // Escrita: auth + permissão write
200
+ .group('', (app) => app
201
+ .use(cryptoAuthPermissions(['write']))
202
+
203
+ .post('/', ({ body }) => ({ created: body }))
204
+ .put('/:id', ({ params, body }) => ({ updated: params.id }))
205
+ )
206
+
207
+ // Deleção: só admin
208
+ .group('', (app) => app
209
+ .use(cryptoAuthAdmin())
210
+
211
+ .delete('/:id', ({ params }) => ({ deleted: params.id }))
212
+ )
213
+ ```
214
+
215
+ ---
216
+
217
+ ### **Padrão 3: Auth Opcional com Comportamento Diferente**
218
+
219
+ ```typescript
220
+ import { cryptoAuthOptional, getCryptoAuthUser, isCryptoAuthAdmin } from '@/plugins/crypto-auth/server'
221
+
222
+ export const contentRoutes = new Elysia({ prefix: '/api/content' })
223
+ .use(cryptoAuthOptional()) // ⚡ Auth opcional para todas
224
+
225
+ .get('/articles/:id', ({ request, params }) => {
226
+ const user = getCryptoAuthUser(request)
227
+ const isAdmin = isCryptoAuthAdmin(request)
228
+ const article = getArticle(params.id)
229
+
230
+ return {
231
+ ...article,
232
+ premium: user ? article.premiumContent : '[Premium - Login Required]',
233
+ canEdit: isAdmin,
234
+ canComment: !!user
235
+ }
236
+ })
237
+ ```
238
+
239
+ ---
240
+
241
+ ## 🛠️ **Helpers Disponíveis**
242
+
243
+ ### **`getCryptoAuthUser(request)`**
244
+
245
+ Retorna o usuário autenticado ou `null`.
246
+
247
+ ```typescript
248
+ import { getCryptoAuthUser } from '@/plugins/crypto-auth/server'
249
+
250
+ .get('/me', ({ request }) => {
251
+ const user = getCryptoAuthUser(request)
252
+
253
+ if (!user) {
254
+ return { error: 'Not authenticated' }
255
+ }
256
+
257
+ return { user }
258
+ })
259
+ ```
260
+
261
+ ---
262
+
263
+ ### **`isCryptoAuthAuthenticated(request)`**
264
+
265
+ Verifica se está autenticado.
266
+
267
+ ```typescript
268
+ import { isCryptoAuthAuthenticated } from '@/plugins/crypto-auth/server'
269
+
270
+ .get('/status', ({ request }) => {
271
+ return {
272
+ authenticated: isCryptoAuthAuthenticated(request)
273
+ }
274
+ })
275
+ ```
276
+
277
+ ---
278
+
279
+ ### **`isCryptoAuthAdmin(request)`**
280
+
281
+ Verifica se é admin.
282
+
283
+ ```typescript
284
+ import { isCryptoAuthAdmin } from '@/plugins/crypto-auth/server'
285
+
286
+ .get('/posts/:id', ({ request, params }) => {
287
+ const post = getPost(params.id)
288
+
289
+ return {
290
+ ...post,
291
+ canEdit: isCryptoAuthAdmin(request)
292
+ }
293
+ })
294
+ ```
295
+
296
+ ---
297
+
298
+ ### **`hasCryptoAuthPermission(request, permission)`**
299
+
300
+ Verifica permissão específica.
301
+
302
+ ```typescript
303
+ import { hasCryptoAuthPermission } from '@/plugins/crypto-auth/server'
304
+
305
+ .post('/posts/:id/publish', ({ request, params }) => {
306
+ if (!hasCryptoAuthPermission(request, 'publish')) {
307
+ return { error: 'Permission denied' }
308
+ }
309
+
310
+ return publishPost(params.id)
311
+ })
312
+ ```
313
+
314
+ ---
315
+
316
+ ## 📋 **Estrutura do User**
317
+
318
+ ```typescript
319
+ interface CryptoAuthUser {
320
+ publicKey: string // Chave pública Ed25519 (hex)
321
+ isAdmin: boolean // Se está na lista adminKeys
322
+ permissions: string[] // ['read', 'write', 'admin', ...]
323
+ }
324
+ ```
325
+
326
+ **Como o `isAdmin` é determinado:**
327
+ ```typescript
328
+ // Plugin verifica se a publicKey está em adminKeys
329
+ const isAdmin = config.adminKeys.includes(user.publicKey)
330
+ ```
331
+
332
+ ---
333
+
334
+ ## 🔄 **Migrando da Abordagem Antiga**
335
+
336
+ ### **❌ Antes (listas de paths)**
337
+
338
+ ```typescript
339
+ // fluxstack.config.ts
340
+ plugins: {
341
+ config: {
342
+ 'crypto-auth': {
343
+ protectedRoutes: ['/api/users/*', '/api/admin/*'],
344
+ publicRoutes: ['/api/health', '/api/docs']
345
+ }
346
+ }
347
+ }
348
+
349
+ // Rotas (sem controle explícito)
350
+ export const routes = new Elysia()
351
+ .get('/api/users', handler) // Protegido pelo plugin
352
+ ```
353
+
354
+ ### **✅ Agora (middlewares declarativos)**
355
+
356
+ ```typescript
357
+ // fluxstack.config.ts
358
+ plugins: {
359
+ config: {
360
+ 'crypto-auth': {
361
+ adminKeys: ['abc123...']
362
+ // Sem protectedRoutes/publicRoutes!
363
+ }
364
+ }
365
+ }
366
+
367
+ // Rotas (controle explícito)
368
+ import { cryptoAuthRequired } from '@/plugins/crypto-auth/server'
369
+
370
+ export const routes = new Elysia()
371
+ .get('/health', handler) // ✅ Público explicitamente
372
+
373
+ .group('/users', (app) => app
374
+ .use(cryptoAuthRequired()) // ✅ Protegido explicitamente
375
+ .get('/', handler)
376
+ )
377
+ ```
378
+
379
+ ---
380
+
381
+ ## 🎯 **Vantagens da Nova Abordagem**
382
+
383
+ | Aspecto | Antes | Agora |
384
+ |---------|-------|-------|
385
+ | **Clareza** | Rotas implicitamente protegidas | ✅ Explícito no código |
386
+ | **Manutenção** | Editar config + rotas | ✅ Editar apenas rotas |
387
+ | **Type Safety** | Sem garantia de user | ✅ TypeScript sabe que user existe |
388
+ | **Flexibilidade** | Apenas on/off | ✅ Permissões, admin, opcional |
389
+ | **Debugging** | Difícil rastrear proteção | ✅ Fácil ver middleware aplicado |
390
+
391
+ ---
392
+
393
+ ## 🧪 **Testando**
394
+
395
+ ### **Rota Pública**
396
+ ```bash
397
+ curl http://localhost:3000/api/crypto-auth/public
398
+ # ✅ 200 OK - sem headers
399
+ ```
400
+
401
+ ### **Rota Protegida (sem auth)**
402
+ ```bash
403
+ curl http://localhost:3000/api/crypto-auth/protected
404
+ # ❌ 401 Unauthorized
405
+ ```
406
+
407
+ ### **Rota Protegida (com auth)**
408
+ ```bash
409
+ curl http://localhost:3000/api/crypto-auth/protected \
410
+ -H "x-public-key: abc123..." \
411
+ -H "x-timestamp: 1234567890" \
412
+ -H "x-nonce: xyz789" \
413
+ -H "x-signature: def456..."
414
+ # ✅ 200 OK
415
+ ```
416
+
417
+ ### **Rota Admin (sem ser admin)**
418
+ ```bash
419
+ curl http://localhost:3000/api/crypto-auth/admin \
420
+ -H "x-public-key: user123..." \
421
+ -H "x-signature: ..."
422
+ # ❌ 403 Forbidden - "Admin privileges required"
423
+ ```
424
+
425
+ ---
426
+
427
+ ## 📚 **Exemplos Completos**
428
+
429
+ Veja exemplos práticos em:
430
+ - `app/server/routes/crypto-auth-demo.routes.ts` - Rotas de demonstração
431
+ - `plugins/crypto-auth/server/middlewares.ts` - Implementação dos middlewares
432
+
433
+ ---
434
+
435
+ ## 🆘 **Troubleshooting**
436
+
437
+ ### **Erro: "CryptoAuthService not initialized"**
438
+
439
+ **Causa**: Plugin não está carregado.
440
+
441
+ **Solução**:
442
+ ```typescript
443
+ // fluxstack.config.ts
444
+ plugins: {
445
+ enabled: ['crypto-auth'], // ✅ Adicione aqui
446
+ }
447
+ ```
448
+
449
+ ### **User sempre null**
450
+
451
+ **Causa**: Não está usando o middleware.
452
+
453
+ **Solução**:
454
+ ```typescript
455
+ // ❌ Errado
456
+ .get('/protected', ({ request }) => {
457
+ const user = getCryptoAuthUser(request) // null
458
+ })
459
+
460
+ // ✅ Correto
461
+ .use(cryptoAuthRequired())
462
+ .get('/protected', ({ request }) => {
463
+ const user = getCryptoAuthUser(request)! // Garantido
464
+ })
465
+ ```
466
+
467
+ ### **403 ao invés de 401**
468
+
469
+ **Causa**: Usuário autenticado mas sem permissão.
470
+
471
+ **Solução**: Verificar se `adminKeys` ou permissões estão corretas.
472
+
473
+ ---
474
+
475
+ **✅ Pronto!** Agora você tem controle total e explícito sobre quais rotas são protegidas, sem precisar configurar listas de paths!