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,181 +0,0 @@
1
- /**
2
- * Middleware de Autenticação Simplificado
3
- * Apenas valida autenticação - routing é feito pelos middlewares Elysia
4
- */
5
-
6
- import type { RequestContext } from '../../../core/plugins/types'
7
- import type { CryptoAuthService } from './CryptoAuthService'
8
-
9
- export interface Logger {
10
- debug(message: string, meta?: any): void
11
- info(message: string, meta?: any): void
12
- warn(message: string, meta?: any): void
13
- error(message: string, meta?: any): void
14
- }
15
-
16
- export interface AuthMiddlewareConfig {
17
- logger?: Logger
18
- }
19
-
20
- export interface AuthMiddlewareResult {
21
- success: boolean
22
- error?: string
23
- user?: {
24
- publicKey: string
25
- isAdmin: boolean
26
- permissions: string[]
27
- }
28
- }
29
-
30
- export class AuthMiddleware {
31
- private authService: CryptoAuthService
32
- private logger?: Logger
33
-
34
- constructor(authService: CryptoAuthService, config: AuthMiddlewareConfig = {}) {
35
- this.authService = authService
36
- this.logger = config.logger
37
- }
38
-
39
- /**
40
- * Autenticar requisição (sem path matching - é responsabilidade dos middlewares Elysia)
41
- */
42
- async authenticate(context: RequestContext): Promise<AuthMiddlewareResult> {
43
- const path = context.path
44
- const method = context.method
45
-
46
- // Extrair headers de autenticação
47
- const authHeaders = this.extractAuthHeaders(context.headers)
48
- if (!authHeaders) {
49
- this.logger?.warn("Headers de autenticação ausentes", {
50
- path,
51
- method,
52
- headers: Object.keys(context.headers)
53
- })
54
-
55
- return {
56
- success: false,
57
- error: "Headers de autenticação obrigatórios"
58
- }
59
- }
60
-
61
- // Validar assinatura da requisição
62
- try {
63
- const validationResult = await this.authService.validateRequest({
64
- publicKey: authHeaders.publicKey,
65
- timestamp: authHeaders.timestamp,
66
- nonce: authHeaders.nonce,
67
- signature: authHeaders.signature,
68
- message: this.buildMessage(context)
69
- })
70
-
71
- if (!validationResult.success) {
72
- this.logger?.warn("Falha na validação da assinatura", {
73
- path,
74
- method,
75
- publicKey: authHeaders.publicKey.substring(0, 8) + "...",
76
- error: validationResult.error
77
- })
78
-
79
- return {
80
- success: false,
81
- error: validationResult.error
82
- }
83
- }
84
-
85
- this.logger?.debug("Requisição autenticada com sucesso", {
86
- path,
87
- method,
88
- publicKey: authHeaders.publicKey.substring(0, 8) + "...",
89
- isAdmin: validationResult.user?.isAdmin
90
- })
91
-
92
- return {
93
- success: true,
94
- user: validationResult.user
95
- }
96
- } catch (error) {
97
- this.logger?.error("Erro durante autenticação", {
98
- path,
99
- method,
100
- error
101
- })
102
-
103
- return {
104
- success: false,
105
- error: "Erro interno de autenticação"
106
- }
107
- }
108
- }
109
-
110
- /**
111
- * Extrair headers de autenticação
112
- */
113
- private extractAuthHeaders(headers: Record<string, string>): {
114
- publicKey: string
115
- timestamp: number
116
- nonce: string
117
- signature: string
118
- } | null {
119
- const publicKey = headers['x-public-key']
120
- const timestampStr = headers['x-timestamp']
121
- const nonce = headers['x-nonce']
122
- const signature = headers['x-signature']
123
-
124
- if (!publicKey || !timestampStr || !nonce || !signature) {
125
- return null
126
- }
127
-
128
- const timestamp = parseInt(timestampStr, 10)
129
- if (isNaN(timestamp)) {
130
- return null
131
- }
132
-
133
- return {
134
- publicKey,
135
- timestamp,
136
- nonce,
137
- signature
138
- }
139
- }
140
-
141
- /**
142
- * Construir mensagem para assinatura
143
- */
144
- private buildMessage(context: RequestContext): string {
145
- // Incluir método, path e body (se houver) na mensagem
146
- let message = `${context.method}:${context.path}`
147
-
148
- if (context.body && typeof context.body === 'string') {
149
- message += `:${context.body}`
150
- } else if (context.body && typeof context.body === 'object') {
151
- message += `:${JSON.stringify(context.body)}`
152
- }
153
-
154
- return message
155
- }
156
-
157
- /**
158
- * Verificar se usuário tem permissão
159
- */
160
- hasPermission(user: any, requiredPermission: string): boolean {
161
- if (!user || !user.permissions) {
162
- return false
163
- }
164
-
165
- return user.permissions.includes(requiredPermission) || user.permissions.includes('admin')
166
- }
167
-
168
- /**
169
- * Verificar se usuário é admin
170
- */
171
- isAdmin(user: any): boolean {
172
- return user && user.isAdmin === true
173
- }
174
-
175
- /**
176
- * Obter estatísticas do serviço de autenticação
177
- */
178
- getStats() {
179
- return this.authService.getStats()
180
- }
181
- }
@@ -1,186 +0,0 @@
1
- /**
2
- * Serviço de Autenticação Criptográfica
3
- * Implementa autenticação baseada em Ed25519 - SEM SESSÕES
4
- * Cada requisição é validada pela assinatura da chave pública
5
- */
6
-
7
- import { ed25519 } from '@noble/curves/ed25519'
8
- import { sha256 } from '@noble/hashes/sha256'
9
- import { hexToBytes } from '@noble/hashes/utils'
10
-
11
- export interface Logger {
12
- debug(message: string, meta?: any): void
13
- info(message: string, meta?: any): void
14
- warn(message: string, meta?: any): void
15
- error(message: string, meta?: any): void
16
- }
17
-
18
- export interface AuthResult {
19
- success: boolean
20
- error?: string
21
- user?: {
22
- publicKey: string
23
- isAdmin: boolean
24
- permissions: string[]
25
- }
26
- }
27
-
28
- export interface CryptoAuthConfig {
29
- maxTimeDrift: number
30
- adminKeys: string[]
31
- logger?: Logger
32
- }
33
-
34
- export class CryptoAuthService {
35
- private config: CryptoAuthConfig
36
- private logger?: Logger
37
- private usedNonces: Map<string, number> = new Map() // Para prevenir replay attacks
38
-
39
- constructor(config: CryptoAuthConfig) {
40
- this.config = config
41
- this.logger = config.logger
42
-
43
- // Limpar nonces antigos a cada 5 minutos
44
- setInterval(() => {
45
- this.cleanupOldNonces()
46
- }, 5 * 60 * 1000)
47
- }
48
-
49
- /**
50
- * Validar assinatura de requisição
51
- * PRINCIPAL: Valida se assinatura é válida para a chave pública fornecida
52
- */
53
- async validateRequest(data: {
54
- publicKey: string
55
- timestamp: number
56
- nonce: string
57
- signature: string
58
- message?: string
59
- }): Promise<AuthResult> {
60
- try {
61
- const { publicKey, timestamp, nonce, signature, message = "" } = data
62
-
63
- // Validar chave pública
64
- if (!this.isValidPublicKey(publicKey)) {
65
- return {
66
- success: false,
67
- error: "Chave pública inválida"
68
- }
69
- }
70
-
71
- // Verificar drift de tempo (previne replay de requisições antigas)
72
- const now = Date.now()
73
- const timeDrift = Math.abs(now - timestamp)
74
- if (timeDrift > this.config.maxTimeDrift) {
75
- return {
76
- success: false,
77
- error: "Timestamp inválido ou expirado"
78
- }
79
- }
80
-
81
- // Verificar nonce (previne replay attacks)
82
- const nonceKey = `${publicKey}:${nonce}`
83
- if (this.usedNonces.has(nonceKey)) {
84
- return {
85
- success: false,
86
- error: "Nonce já utilizado (possível replay attack)"
87
- }
88
- }
89
-
90
- // Construir mensagem para verificação
91
- const messageToVerify = `${publicKey}:${timestamp}:${nonce}:${message}`
92
- const messageHash = sha256(new TextEncoder().encode(messageToVerify))
93
-
94
- // Verificar assinatura usando chave pública
95
- const publicKeyBytes = hexToBytes(publicKey)
96
- const signatureBytes = hexToBytes(signature)
97
-
98
- const isValidSignature = ed25519.verify(signatureBytes, messageHash, publicKeyBytes)
99
-
100
- if (!isValidSignature) {
101
- this.logger?.warn("Assinatura inválida", {
102
- publicKey: publicKey.substring(0, 8) + "..."
103
- })
104
- return {
105
- success: false,
106
- error: "Assinatura inválida"
107
- }
108
- }
109
-
110
- // Marcar nonce como usado
111
- this.usedNonces.set(nonceKey, timestamp)
112
-
113
- // Verificar se é admin
114
- const isAdmin = this.config.adminKeys.includes(publicKey)
115
- const permissions = isAdmin ? ['admin', 'read', 'write', 'delete'] : ['read']
116
-
117
- this.logger?.debug("Requisição autenticada", {
118
- publicKey: publicKey.substring(0, 8) + "...",
119
- isAdmin,
120
- permissions
121
- })
122
-
123
- return {
124
- success: true,
125
- user: {
126
- publicKey,
127
- isAdmin,
128
- permissions
129
- }
130
- }
131
- } catch (error) {
132
- this.logger?.error("Erro ao validar requisição", { error })
133
- return {
134
- success: false,
135
- error: "Erro interno ao validar requisição"
136
- }
137
- }
138
- }
139
-
140
- /**
141
- * Verificar se uma chave pública é válida
142
- */
143
- private isValidPublicKey(publicKey: string): boolean {
144
- try {
145
- if (publicKey.length !== 64) {
146
- return false
147
- }
148
-
149
- const bytes = hexToBytes(publicKey)
150
- return bytes.length === 32
151
- } catch {
152
- return false
153
- }
154
- }
155
-
156
- /**
157
- * Limpar nonces antigos (previne crescimento infinito da memória)
158
- */
159
- private cleanupOldNonces(): void {
160
- const now = Date.now()
161
- const maxAge = this.config.maxTimeDrift * 2 // Dobro do tempo máximo permitido
162
- let cleanedCount = 0
163
-
164
- for (const [nonceKey, timestamp] of this.usedNonces.entries()) {
165
- if (now - timestamp > maxAge) {
166
- this.usedNonces.delete(nonceKey)
167
- cleanedCount++
168
- }
169
- }
170
-
171
- if (cleanedCount > 0) {
172
- this.logger?.debug(`Limpeza de nonces: ${cleanedCount} nonces antigos removidos`)
173
- }
174
- }
175
-
176
- /**
177
- * Obter estatísticas do serviço
178
- */
179
- getStats() {
180
- return {
181
- usedNoncesCount: this.usedNonces.size,
182
- adminKeys: this.config.adminKeys.length,
183
- maxTimeDrift: this.config.maxTimeDrift
184
- }
185
- }
186
- }
@@ -1,22 +0,0 @@
1
- /**
2
- * Exportações do servidor de autenticação
3
- */
4
-
5
- export { CryptoAuthService } from './CryptoAuthService'
6
- export type { AuthResult, CryptoAuthConfig } from './CryptoAuthService'
7
-
8
- export { AuthMiddleware } from './AuthMiddleware'
9
- export type { AuthMiddlewareConfig, AuthMiddlewareResult } from './AuthMiddleware'
10
-
11
- // Middlewares Elysia
12
- export {
13
- cryptoAuthRequired,
14
- cryptoAuthAdmin,
15
- cryptoAuthPermissions,
16
- cryptoAuthOptional,
17
- getCryptoAuthUser,
18
- isCryptoAuthAuthenticated,
19
- isCryptoAuthAdmin,
20
- hasCryptoAuthPermission
21
- } from './middlewares'
22
- export type { CryptoAuthUser, CryptoAuthMiddlewareOptions } from './middlewares'
@@ -1,65 +0,0 @@
1
- /**
2
- * Middleware que REQUER privilégios de administrador
3
- * Bloqueia requisições não autenticadas (401) ou sem privilégios admin (403)
4
- */
5
-
6
- import { Elysia } from 'elysia'
7
- import { createGuard } from '@/core/server/middleware/elysia-helpers'
8
- import type { Logger } from '@/core/utils/logger'
9
- import { validateAuthSync, type CryptoAuthUser } from './helpers'
10
-
11
- export interface CryptoAuthMiddlewareOptions {
12
- logger?: Logger
13
- }
14
-
15
- export const cryptoAuthAdmin = (options: CryptoAuthMiddlewareOptions = {}) => {
16
- return new Elysia({ name: 'crypto-auth-admin' })
17
- .derive(async ({ request }) => {
18
- const result = await validateAuthSync(request as Request, options.logger)
19
-
20
- if (result.success && result.user) {
21
- ;(request as any).user = result.user
22
- }
23
-
24
- return {}
25
- })
26
- .use(
27
- createGuard({
28
- name: 'crypto-auth-admin-check',
29
- check: ({ request }) => {
30
- const user = (request as any).user as CryptoAuthUser | undefined
31
- return user && user.isAdmin
32
- },
33
- onFail: (set, { request }) => {
34
- const user = (request as any).user as CryptoAuthUser | undefined
35
-
36
- if (!user) {
37
- set.status = 401
38
- return {
39
- error: {
40
- message: 'Authentication required',
41
- code: 'CRYPTO_AUTH_REQUIRED',
42
- statusCode: 401
43
- }
44
- }
45
- }
46
-
47
- options.logger?.warn('Admin access denied', {
48
- publicKey: user.publicKey.substring(0, 8) + '...',
49
- permissions: user.permissions
50
- })
51
-
52
- set.status = 403
53
- return {
54
- error: {
55
- message: 'Admin privileges required',
56
- code: 'ADMIN_REQUIRED',
57
- statusCode: 403,
58
- yourPermissions: user.permissions
59
- }
60
- }
61
- }
62
- })
63
- )
64
- .as('plugin')
65
- }
@@ -1,26 +0,0 @@
1
- /**
2
- * Middleware OPCIONAL - adiciona user se autenticado, mas não requer
3
- * Não bloqueia requisições não autenticadas - permite acesso público
4
- */
5
-
6
- import { Elysia } from 'elysia'
7
- import type { Logger } from '@/core/utils/logger'
8
- import { validateAuthSync } from './helpers'
9
-
10
- export interface CryptoAuthMiddlewareOptions {
11
- logger?: Logger
12
- }
13
-
14
- export const cryptoAuthOptional = (options: CryptoAuthMiddlewareOptions = {}) => {
15
- return new Elysia({ name: 'crypto-auth-optional' })
16
- .derive(async ({ request }) => {
17
- const result = await validateAuthSync(request as Request, options.logger)
18
-
19
- if (result.success && result.user) {
20
- ;(request as any).user = result.user
21
- }
22
-
23
- return {}
24
- })
25
- .as('plugin')
26
- }
@@ -1,76 +0,0 @@
1
- /**
2
- * Middleware que REQUER permissões específicas
3
- * Bloqueia requisições sem as permissões necessárias (403)
4
- */
5
-
6
- import { Elysia } from 'elysia'
7
- import { createGuard } from '@/core/server/middleware/elysia-helpers'
8
- import type { Logger } from '@/core/utils/logger'
9
- import { validateAuthSync, type CryptoAuthUser } from './helpers'
10
-
11
- export interface CryptoAuthMiddlewareOptions {
12
- logger?: Logger
13
- }
14
-
15
- export const cryptoAuthPermissions = (
16
- requiredPermissions: string[],
17
- options: CryptoAuthMiddlewareOptions = {}
18
- ) => {
19
- return new Elysia({ name: 'crypto-auth-permissions' })
20
- .derive(async ({ request }) => {
21
- const result = await validateAuthSync(request as Request, options.logger)
22
-
23
- if (result.success && result.user) {
24
- ;(request as any).user = result.user
25
- }
26
-
27
- return {}
28
- })
29
- .use(
30
- createGuard({
31
- name: 'crypto-auth-permissions-check',
32
- check: ({ request }) => {
33
- const user = (request as any).user as CryptoAuthUser | undefined
34
-
35
- if (!user) return false
36
-
37
- const userPermissions = user.permissions
38
- return requiredPermissions.every(
39
- perm => userPermissions.includes(perm) || userPermissions.includes('admin')
40
- )
41
- },
42
- onFail: (set, { request }) => {
43
- const user = (request as any).user as CryptoAuthUser | undefined
44
-
45
- if (!user) {
46
- set.status = 401
47
- return {
48
- error: {
49
- message: 'Authentication required',
50
- code: 'CRYPTO_AUTH_REQUIRED',
51
- statusCode: 401
52
- }
53
- }
54
- }
55
-
56
- options.logger?.warn('Permission denied', {
57
- publicKey: user.publicKey.substring(0, 8) + '...',
58
- required: requiredPermissions,
59
- has: user.permissions
60
- })
61
-
62
- set.status = 403
63
- return {
64
- error: {
65
- message: 'Insufficient permissions',
66
- code: 'PERMISSION_DENIED',
67
- statusCode: 403,
68
- required: requiredPermissions,
69
- yours: user.permissions
70
- }
71
- }
72
- }
73
- })
74
- )
75
- .as('plugin')
76
- }
@@ -1,45 +0,0 @@
1
- /**
2
- * Middleware que REQUER autenticação
3
- * Bloqueia requisições não autenticadas com 401
4
- */
5
-
6
- import { Elysia } from 'elysia'
7
- import { createGuard } from '@/core/server/middleware/elysia-helpers'
8
- import type { Logger } from '@/core/utils/logger'
9
- import { validateAuthSync } from './helpers'
10
-
11
- export interface CryptoAuthMiddlewareOptions {
12
- logger?: Logger
13
- }
14
-
15
- export const cryptoAuthRequired = (options: CryptoAuthMiddlewareOptions = {}) => {
16
- return new Elysia({ name: 'crypto-auth-required' })
17
- .derive(async ({ request }) => {
18
- const result = await validateAuthSync(request as Request, options.logger)
19
-
20
- if (result.success && result.user) {
21
- ;(request as any).user = result.user
22
- }
23
-
24
- return {}
25
- })
26
- .use(
27
- createGuard({
28
- name: 'crypto-auth-check',
29
- check: ({ request }) => {
30
- return !!(request as any).user
31
- },
32
- onFail: (set) => {
33
- set.status = 401
34
- return {
35
- error: {
36
- message: 'Authentication required',
37
- code: 'CRYPTO_AUTH_REQUIRED',
38
- statusCode: 401
39
- }
40
- }
41
- }
42
- })
43
- )
44
- .as('plugin')
45
- }