create-fluxstack 1.0.21 → 1.1.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 (31) hide show
  1. package/app/server/live/register-components.ts +6 -26
  2. package/core/build/bundler.ts +53 -5
  3. package/core/build/flux-plugins-generator.ts +315 -0
  4. package/core/build/index.ts +1 -3
  5. package/core/build/live-components-generator.ts +231 -0
  6. package/core/build/optimizer.ts +2 -54
  7. package/core/cli/index.ts +2 -1
  8. package/core/config/env.ts +3 -1
  9. package/core/config/schema.ts +0 -3
  10. package/core/framework/server.ts +33 -1
  11. package/core/plugins/built-in/static/index.ts +24 -10
  12. package/core/plugins/built-in/vite/index.ts +92 -56
  13. package/core/plugins/manager.ts +51 -8
  14. package/core/utils/helpers.ts +9 -3
  15. package/fluxstack.config.ts +4 -10
  16. package/package.json +4 -3
  17. package/plugins/crypto-auth/README.md +238 -0
  18. package/plugins/crypto-auth/client/CryptoAuthClient.ts +325 -0
  19. package/plugins/crypto-auth/client/components/AuthProvider.tsx +190 -0
  20. package/plugins/crypto-auth/client/components/LoginButton.tsx +155 -0
  21. package/plugins/crypto-auth/client/components/ProtectedRoute.tsx +109 -0
  22. package/plugins/crypto-auth/client/components/SessionInfo.tsx +242 -0
  23. package/plugins/crypto-auth/client/components/index.ts +15 -0
  24. package/plugins/crypto-auth/client/index.ts +12 -0
  25. package/plugins/crypto-auth/index.ts +230 -0
  26. package/plugins/crypto-auth/package.json +65 -0
  27. package/plugins/crypto-auth/plugin.json +29 -0
  28. package/plugins/crypto-auth/server/AuthMiddleware.ts +237 -0
  29. package/plugins/crypto-auth/server/CryptoAuthService.ts +293 -0
  30. package/plugins/crypto-auth/server/index.ts +9 -0
  31. package/vite.config.ts +16 -0
@@ -0,0 +1,293 @@
1
+ /**
2
+ * Serviço de Autenticação Criptográfica
3
+ * Implementa autenticação baseada em Ed25519
4
+ */
5
+
6
+ import { ed25519 } from '@noble/curves/ed25519'
7
+ import { sha256 } from '@noble/hashes/sha256'
8
+ import { bytesToHex, hexToBytes } from '@noble/hashes/utils'
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 SessionData {
17
+ sessionId: string
18
+ publicKey: string
19
+ createdAt: Date
20
+ lastUsed: Date
21
+ isAdmin: boolean
22
+ permissions: string[]
23
+ }
24
+
25
+ export interface AuthResult {
26
+ success: boolean
27
+ sessionId?: string
28
+ error?: string
29
+ user?: {
30
+ sessionId: string
31
+ isAdmin: boolean
32
+ isSuperAdmin: boolean
33
+ permissions: string[]
34
+ }
35
+ }
36
+
37
+ export interface CryptoAuthConfig {
38
+ sessionTimeout: number
39
+ maxTimeDrift: number
40
+ adminKeys: string[]
41
+ logger?: Logger
42
+ }
43
+
44
+ export class CryptoAuthService {
45
+ private sessions: Map<string, SessionData> = new Map()
46
+ private config: CryptoAuthConfig
47
+ private logger?: Logger
48
+
49
+ constructor(config: CryptoAuthConfig) {
50
+ this.config = config
51
+ this.logger = config.logger
52
+
53
+ // Limpar sessões expiradas a cada 5 minutos
54
+ setInterval(() => {
55
+ this.cleanupExpiredSessions()
56
+ }, 5 * 60 * 1000)
57
+ }
58
+
59
+ /**
60
+ * Inicializar uma nova sessão
61
+ */
62
+ async initializeSession(data: { publicKey?: string }): Promise<AuthResult> {
63
+ try {
64
+ let publicKey: string
65
+
66
+ if (data.publicKey) {
67
+ // Validar chave pública fornecida
68
+ if (!this.isValidPublicKey(data.publicKey)) {
69
+ return {
70
+ success: false,
71
+ error: "Chave pública inválida"
72
+ }
73
+ }
74
+ publicKey = data.publicKey
75
+ } else {
76
+ // Gerar novo par de chaves
77
+ const privateKey = ed25519.utils.randomPrivateKey()
78
+ publicKey = bytesToHex(ed25519.getPublicKey(privateKey))
79
+ }
80
+
81
+ const sessionId = publicKey
82
+ const isAdmin = this.config.adminKeys.includes(publicKey)
83
+
84
+ const sessionData: SessionData = {
85
+ sessionId,
86
+ publicKey,
87
+ createdAt: new Date(),
88
+ lastUsed: new Date(),
89
+ isAdmin,
90
+ permissions: isAdmin ? ['admin', 'read', 'write'] : ['read']
91
+ }
92
+
93
+ this.sessions.set(sessionId, sessionData)
94
+
95
+ this.logger?.info("Nova sessão inicializada", {
96
+ sessionId: sessionId.substring(0, 8) + "...",
97
+ isAdmin,
98
+ permissions: sessionData.permissions
99
+ })
100
+
101
+ return {
102
+ success: true,
103
+ sessionId,
104
+ user: {
105
+ sessionId,
106
+ isAdmin,
107
+ isSuperAdmin: isAdmin,
108
+ permissions: sessionData.permissions
109
+ }
110
+ }
111
+ } catch (error) {
112
+ this.logger?.error("Erro ao inicializar sessão", { error })
113
+ return {
114
+ success: false,
115
+ error: "Erro interno ao inicializar sessão"
116
+ }
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Validar uma sessão com assinatura
122
+ */
123
+ async validateSession(data: {
124
+ sessionId: string
125
+ timestamp: number
126
+ nonce: string
127
+ signature: string
128
+ message?: string
129
+ }): Promise<AuthResult> {
130
+ try {
131
+ const { sessionId, timestamp, nonce, signature, message = "" } = data
132
+
133
+ // Verificar se a sessão existe
134
+ const session = this.sessions.get(sessionId)
135
+ if (!session) {
136
+ return {
137
+ success: false,
138
+ error: "Sessão não encontrada"
139
+ }
140
+ }
141
+
142
+ // Verificar se a sessão não expirou
143
+ const now = Date.now()
144
+ const sessionAge = now - session.lastUsed.getTime()
145
+ if (sessionAge > this.config.sessionTimeout) {
146
+ this.sessions.delete(sessionId)
147
+ return {
148
+ success: false,
149
+ error: "Sessão expirada"
150
+ }
151
+ }
152
+
153
+ // Verificar drift de tempo
154
+ const timeDrift = Math.abs(now - timestamp)
155
+ if (timeDrift > this.config.maxTimeDrift) {
156
+ return {
157
+ success: false,
158
+ error: "Timestamp inválido"
159
+ }
160
+ }
161
+
162
+ // Construir mensagem para verificação
163
+ const messageToVerify = `${sessionId}:${timestamp}:${nonce}:${message}`
164
+ const messageHash = sha256(new TextEncoder().encode(messageToVerify))
165
+
166
+ // Verificar assinatura
167
+ const publicKeyBytes = hexToBytes(session.publicKey)
168
+ const signatureBytes = hexToBytes(signature)
169
+
170
+ const isValidSignature = ed25519.verify(signatureBytes, messageHash, publicKeyBytes)
171
+
172
+ if (!isValidSignature) {
173
+ return {
174
+ success: false,
175
+ error: "Assinatura inválida"
176
+ }
177
+ }
178
+
179
+ // Atualizar último uso da sessão
180
+ session.lastUsed = new Date()
181
+
182
+ return {
183
+ success: true,
184
+ sessionId,
185
+ user: {
186
+ sessionId,
187
+ isAdmin: session.isAdmin,
188
+ isSuperAdmin: session.isAdmin,
189
+ permissions: session.permissions
190
+ }
191
+ }
192
+ } catch (error) {
193
+ this.logger?.error("Erro ao validar sessão", { error })
194
+ return {
195
+ success: false,
196
+ error: "Erro interno ao validar sessão"
197
+ }
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Obter informações da sessão
203
+ */
204
+ async getSessionInfo(sessionId: string): Promise<SessionData | null> {
205
+ const session = this.sessions.get(sessionId)
206
+ if (!session) {
207
+ return null
208
+ }
209
+
210
+ // Verificar se não expirou
211
+ const now = Date.now()
212
+ const sessionAge = now - session.lastUsed.getTime()
213
+ if (sessionAge > this.config.sessionTimeout) {
214
+ this.sessions.delete(sessionId)
215
+ return null
216
+ }
217
+
218
+ return { ...session }
219
+ }
220
+
221
+ /**
222
+ * Destruir uma sessão
223
+ */
224
+ async destroySession(sessionId: string): Promise<void> {
225
+ this.sessions.delete(sessionId)
226
+ this.logger?.info("Sessão destruída", {
227
+ sessionId: sessionId.substring(0, 8) + "..."
228
+ })
229
+ }
230
+
231
+ /**
232
+ * Verificar se uma chave pública é válida
233
+ */
234
+ private isValidPublicKey(publicKey: string): boolean {
235
+ try {
236
+ if (publicKey.length !== 64) {
237
+ return false
238
+ }
239
+
240
+ const bytes = hexToBytes(publicKey)
241
+ return bytes.length === 32
242
+ } catch {
243
+ return false
244
+ }
245
+ }
246
+
247
+ /**
248
+ * Limpar sessões expiradas
249
+ */
250
+ private cleanupExpiredSessions(): void {
251
+ const now = Date.now()
252
+ let cleanedCount = 0
253
+
254
+ for (const [sessionId, session] of this.sessions.entries()) {
255
+ const sessionAge = now - session.lastUsed.getTime()
256
+ if (sessionAge > this.config.sessionTimeout) {
257
+ this.sessions.delete(sessionId)
258
+ cleanedCount++
259
+ }
260
+ }
261
+
262
+ if (cleanedCount > 0) {
263
+ this.logger?.debug(`Limpeza de sessões: ${cleanedCount} sessões expiradas removidas`)
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Obter estatísticas das sessões
269
+ */
270
+ getStats() {
271
+ const now = Date.now()
272
+ let activeSessions = 0
273
+ let adminSessions = 0
274
+
275
+ for (const session of this.sessions.values()) {
276
+ const sessionAge = now - session.lastUsed.getTime()
277
+ if (sessionAge <= this.config.sessionTimeout) {
278
+ activeSessions++
279
+ if (session.isAdmin) {
280
+ adminSessions++
281
+ }
282
+ }
283
+ }
284
+
285
+ return {
286
+ totalSessions: this.sessions.size,
287
+ activeSessions,
288
+ adminSessions,
289
+ sessionTimeout: this.config.sessionTimeout,
290
+ adminKeys: this.config.adminKeys.length
291
+ }
292
+ }
293
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Exportações do servidor de autenticação
3
+ */
4
+
5
+ export { CryptoAuthService } from './CryptoAuthService'
6
+ export type { SessionData, AuthResult, CryptoAuthConfig } from './CryptoAuthService'
7
+
8
+ export { AuthMiddleware } from './AuthMiddleware'
9
+ export type { AuthMiddlewareConfig, AuthMiddlewareResult } from './AuthMiddleware'
package/vite.config.ts CHANGED
@@ -23,6 +23,22 @@ export default defineConfig({
23
23
  },
24
24
  })
25
25
  ],
26
+ define: {
27
+ __DEFINES__: JSON.stringify({}),
28
+ global: 'globalThis',
29
+ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
30
+ __HMR_CONFIG_NAME__: JSON.stringify('vite.config.ts'),
31
+ __BASE__: JSON.stringify('/'),
32
+ __SERVER_HOST__: JSON.stringify('localhost'),
33
+ __HMR_PROTOCOL__: JSON.stringify('ws'),
34
+ __HMR_PORT__: JSON.stringify(5173),
35
+ __HMR_HOSTNAME__: JSON.stringify('localhost'),
36
+ __HMR_BASE__: JSON.stringify('/'),
37
+ __HMR_DIRECT_TARGET__: JSON.stringify('localhost:5173'),
38
+ __HMR_ENABLE_OVERLAY__: JSON.stringify(true),
39
+ __HMR_TIMEOUT__: JSON.stringify(30000),
40
+ __WS_TOKEN__: JSON.stringify(''),
41
+ },
26
42
  root: 'app/client',
27
43
  server: {
28
44
  port: 5173,