create-fluxstack 1.12.0 → 1.13.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.
- package/LLMD/INDEX.md +8 -1
- package/LLMD/agent.md +867 -0
- package/LLMD/config/environment-vars.md +30 -0
- package/LLMD/resources/live-auth.md +447 -0
- package/LLMD/resources/live-components.md +79 -21
- package/LLMD/resources/live-logging.md +158 -0
- package/LLMD/resources/live-upload.md +1 -1
- package/LLMD/resources/rest-auth.md +290 -0
- package/README.md +520 -340
- package/app/client/src/App.tsx +11 -0
- package/app/client/src/components/AppLayout.tsx +1 -0
- package/app/client/src/live/AuthDemo.tsx +332 -0
- package/app/client/src/live/RoomChatDemo.tsx +24 -105
- package/app/server/auth/AuthManager.ts +213 -0
- package/app/server/auth/DevAuthProvider.ts +66 -0
- package/app/server/auth/HashManager.ts +123 -0
- package/app/server/auth/JWTAuthProvider.example.ts +101 -0
- package/app/server/auth/RateLimiter.ts +106 -0
- package/app/server/auth/contracts.ts +192 -0
- package/app/server/auth/guards/SessionGuard.ts +167 -0
- package/app/server/auth/guards/TokenGuard.ts +202 -0
- package/app/server/auth/index.ts +174 -0
- package/app/server/auth/middleware.ts +163 -0
- package/app/server/auth/providers/InMemoryProvider.ts +162 -0
- package/app/server/auth/sessions/SessionManager.ts +164 -0
- package/app/server/cache/CacheManager.ts +81 -0
- package/app/server/cache/MemoryDriver.ts +112 -0
- package/app/server/cache/contracts.ts +49 -0
- package/app/server/cache/index.ts +42 -0
- package/app/server/index.ts +14 -0
- package/app/server/live/LiveAdminPanel.ts +173 -0
- package/app/server/live/LiveCounter.ts +1 -0
- package/app/server/live/LiveLocalCounter.ts +13 -8
- package/app/server/live/LiveProtectedChat.ts +150 -0
- package/app/server/live/LiveRoomChat.ts +45 -203
- package/app/server/routes/auth.routes.ts +278 -0
- package/app/server/routes/index.ts +2 -0
- package/config/index.ts +8 -0
- package/config/system/auth.config.ts +49 -0
- package/config/system/session.config.ts +33 -0
- package/core/client/LiveComponentsProvider.tsx +76 -5
- package/core/client/components/Live.tsx +2 -1
- package/core/client/hooks/useLiveComponent.ts +47 -4
- package/core/client/index.ts +2 -1
- package/core/framework/server.ts +36 -4
- package/core/plugins/built-in/live-components/commands/create-live-component.ts +15 -8
- package/core/plugins/built-in/monitoring/index.ts +10 -3
- package/core/plugins/built-in/vite/index.ts +95 -18
- package/core/plugins/config.ts +5 -4
- package/core/plugins/discovery.ts +11 -2
- package/core/plugins/manager.ts +11 -5
- package/core/plugins/module-resolver.ts +1 -1
- package/core/plugins/registry.ts +53 -25
- package/core/server/live/ComponentRegistry.ts +79 -24
- package/core/server/live/LiveComponentPerformanceMonitor.ts +9 -8
- package/core/server/live/LiveLogger.ts +111 -0
- package/core/server/live/LiveRoomManager.ts +5 -4
- package/core/server/live/StateSignature.ts +644 -643
- package/core/server/live/auth/LiveAuthContext.ts +71 -0
- package/core/server/live/auth/LiveAuthManager.ts +304 -0
- package/core/server/live/auth/index.ts +19 -0
- package/core/server/live/auth/types.ts +179 -0
- package/core/server/live/auto-generated-components.ts +8 -2
- package/core/server/live/index.ts +16 -0
- package/core/server/live/websocket-plugin.ts +92 -16
- package/core/templates/create-project.ts +0 -3
- package/core/types/types.ts +133 -13
- package/core/utils/index.ts +17 -17
- package/core/utils/logger/index.ts +5 -2
- package/core/utils/version.ts +1 -1
- package/package.json +1 -8
- package/plugins/crypto-auth/index.ts +6 -0
- package/plugins/crypto-auth/server/CryptoAuthLiveProvider.ts +58 -0
- package/plugins/crypto-auth/server/index.ts +24 -21
- package/rest-tests/README.md +57 -0
- package/rest-tests/auth-token.http +113 -0
- package/rest-tests/auth.http +112 -0
- package/rest-tests/rooms-token.http +69 -0
- package/rest-tests/users-token.http +62 -0
- package/.dockerignore +0 -81
- package/Dockerfile +0 -70
- package/LIVE_COMPONENTS_REVIEW.md +0 -781
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// 🔒 FluxStack Live Components - Auth Context Implementation
|
|
2
|
+
|
|
3
|
+
import type { LiveAuthContext, LiveAuthUser } from './types'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Contexto de autenticação para usuários autenticados.
|
|
7
|
+
* Fornece helpers type-safe para verificação de roles e permissões.
|
|
8
|
+
*
|
|
9
|
+
* Usado internamente pelo framework - devs acessam via this.$auth no LiveComponent.
|
|
10
|
+
*/
|
|
11
|
+
export class AuthenticatedContext implements LiveAuthContext {
|
|
12
|
+
readonly authenticated = true
|
|
13
|
+
readonly user: LiveAuthUser
|
|
14
|
+
readonly token?: string
|
|
15
|
+
readonly authenticatedAt: number
|
|
16
|
+
|
|
17
|
+
constructor(user: LiveAuthUser, token?: string) {
|
|
18
|
+
this.user = user
|
|
19
|
+
this.token = token
|
|
20
|
+
this.authenticatedAt = Date.now()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
hasRole(role: string): boolean {
|
|
24
|
+
return this.user.roles?.includes(role) ?? false
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
hasAnyRole(roles: string[]): boolean {
|
|
28
|
+
if (!this.user.roles?.length) return false
|
|
29
|
+
return roles.some(role => this.user.roles!.includes(role))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
hasAllRoles(roles: string[]): boolean {
|
|
33
|
+
if (!this.user.roles?.length) return roles.length === 0
|
|
34
|
+
return roles.every(role => this.user.roles!.includes(role))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
hasPermission(permission: string): boolean {
|
|
38
|
+
return this.user.permissions?.includes(permission) ?? false
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
hasAllPermissions(permissions: string[]): boolean {
|
|
42
|
+
if (!this.user.permissions?.length) return permissions.length === 0
|
|
43
|
+
return permissions.every(perm => this.user.permissions!.includes(perm))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
hasAnyPermission(permissions: string[]): boolean {
|
|
47
|
+
if (!this.user.permissions?.length) return false
|
|
48
|
+
return permissions.some(perm => this.user.permissions!.includes(perm))
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Contexto para usuários não autenticados (guest).
|
|
54
|
+
* Retornado quando nenhuma credencial é fornecida ou quando a auth falha.
|
|
55
|
+
*/
|
|
56
|
+
export class AnonymousContext implements LiveAuthContext {
|
|
57
|
+
readonly authenticated = false
|
|
58
|
+
readonly user = undefined
|
|
59
|
+
readonly token = undefined
|
|
60
|
+
readonly authenticatedAt = undefined
|
|
61
|
+
|
|
62
|
+
hasRole(): boolean { return false }
|
|
63
|
+
hasAnyRole(): boolean { return false }
|
|
64
|
+
hasAllRoles(): boolean { return false }
|
|
65
|
+
hasPermission(): boolean { return false }
|
|
66
|
+
hasAllPermissions(): boolean { return false }
|
|
67
|
+
hasAnyPermission(): boolean { return false }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Singleton para contextos anônimos (evita criar objetos desnecessários) */
|
|
71
|
+
export const ANONYMOUS_CONTEXT = new AnonymousContext()
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
// 🔒 FluxStack Live Components - Auth Manager
|
|
2
|
+
//
|
|
3
|
+
// Gerencia providers de autenticação e executa verificações de auth.
|
|
4
|
+
// Singleton global usado pelo ComponentRegistry e WebSocket plugin.
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
LiveAuthProvider,
|
|
8
|
+
LiveAuthCredentials,
|
|
9
|
+
LiveAuthContext,
|
|
10
|
+
LiveComponentAuth,
|
|
11
|
+
LiveActionAuth,
|
|
12
|
+
LiveAuthResult,
|
|
13
|
+
} from './types'
|
|
14
|
+
import { AuthenticatedContext, ANONYMOUS_CONTEXT } from './LiveAuthContext'
|
|
15
|
+
|
|
16
|
+
export class LiveAuthManager {
|
|
17
|
+
private providers = new Map<string, LiveAuthProvider>()
|
|
18
|
+
private defaultProviderName?: string
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Registra um provider de autenticação.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* liveAuthManager.register(new JWTAuthProvider({ secret: 'my-secret' }))
|
|
25
|
+
* liveAuthManager.register(new CryptoAuthProvider())
|
|
26
|
+
*/
|
|
27
|
+
register(provider: LiveAuthProvider): void {
|
|
28
|
+
this.providers.set(provider.name, provider)
|
|
29
|
+
|
|
30
|
+
// Primeiro provider registrado é o default
|
|
31
|
+
if (!this.defaultProviderName) {
|
|
32
|
+
this.defaultProviderName = provider.name
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
console.log(`🔒 Live Auth provider registered: ${provider.name}`)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Remove um provider de autenticação.
|
|
40
|
+
*/
|
|
41
|
+
unregister(name: string): void {
|
|
42
|
+
this.providers.delete(name)
|
|
43
|
+
if (this.defaultProviderName === name) {
|
|
44
|
+
this.defaultProviderName = this.providers.keys().next().value
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Define o provider padrão para autenticação.
|
|
50
|
+
*/
|
|
51
|
+
setDefault(name: string): void {
|
|
52
|
+
if (!this.providers.has(name)) {
|
|
53
|
+
throw new Error(`Auth provider '${name}' not registered`)
|
|
54
|
+
}
|
|
55
|
+
this.defaultProviderName = name
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Retorna true se há pelo menos um provider registrado.
|
|
60
|
+
*/
|
|
61
|
+
hasProviders(): boolean {
|
|
62
|
+
return this.providers.size > 0
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Retorna o provider padrão ou undefined se nenhum registrado.
|
|
67
|
+
*/
|
|
68
|
+
getDefaultProvider(): LiveAuthProvider | undefined {
|
|
69
|
+
if (!this.defaultProviderName) return undefined
|
|
70
|
+
return this.providers.get(this.defaultProviderName)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Autentica credenciais usando o provider especificado, ou tenta todos os providers.
|
|
75
|
+
* Retorna ANONYMOUS_CONTEXT se nenhuma credencial é fornecida ou nenhum provider existe.
|
|
76
|
+
*/
|
|
77
|
+
async authenticate(
|
|
78
|
+
credentials: LiveAuthCredentials,
|
|
79
|
+
providerName?: string
|
|
80
|
+
): Promise<LiveAuthContext> {
|
|
81
|
+
// Sem credenciais = anônimo
|
|
82
|
+
if (!credentials || Object.keys(credentials).every(k => !credentials[k])) {
|
|
83
|
+
return ANONYMOUS_CONTEXT
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Sem providers = anônimo (auth não está configurada)
|
|
87
|
+
if (this.providers.size === 0) {
|
|
88
|
+
return ANONYMOUS_CONTEXT
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Se provider específico solicitado, usar apenas ele
|
|
92
|
+
if (providerName) {
|
|
93
|
+
const provider = this.providers.get(providerName)
|
|
94
|
+
if (!provider) {
|
|
95
|
+
console.warn(`🔒 Auth provider '${providerName}' not found`)
|
|
96
|
+
return ANONYMOUS_CONTEXT
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
const context = await provider.authenticate(credentials)
|
|
100
|
+
return context || ANONYMOUS_CONTEXT
|
|
101
|
+
} catch (error: any) {
|
|
102
|
+
console.error(`🔒 Auth failed via '${providerName}':`, error.message)
|
|
103
|
+
return ANONYMOUS_CONTEXT
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Tentar todos os providers (default primeiro, depois os outros)
|
|
108
|
+
const providersToTry: LiveAuthProvider[] = []
|
|
109
|
+
|
|
110
|
+
// Default provider primeiro
|
|
111
|
+
if (this.defaultProviderName) {
|
|
112
|
+
const defaultProvider = this.providers.get(this.defaultProviderName)
|
|
113
|
+
if (defaultProvider) providersToTry.push(defaultProvider)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Adicionar outros providers
|
|
117
|
+
for (const [name, provider] of this.providers) {
|
|
118
|
+
if (name !== this.defaultProviderName) {
|
|
119
|
+
providersToTry.push(provider)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Tentar cada provider
|
|
124
|
+
for (const provider of providersToTry) {
|
|
125
|
+
try {
|
|
126
|
+
const context = await provider.authenticate(credentials)
|
|
127
|
+
if (context && context.authenticated) {
|
|
128
|
+
console.log(`🔒 Authenticated via provider: ${provider.name}`)
|
|
129
|
+
return context
|
|
130
|
+
}
|
|
131
|
+
} catch (error: any) {
|
|
132
|
+
// Silently continue to next provider
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return ANONYMOUS_CONTEXT
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Verifica se o contexto de auth atende aos requisitos do componente.
|
|
141
|
+
* Usado pelo ComponentRegistry antes de montar um componente.
|
|
142
|
+
*/
|
|
143
|
+
authorizeComponent(
|
|
144
|
+
authContext: LiveAuthContext,
|
|
145
|
+
authConfig: LiveComponentAuth | undefined
|
|
146
|
+
): LiveAuthResult {
|
|
147
|
+
// Sem config de auth = permitido
|
|
148
|
+
if (!authConfig) {
|
|
149
|
+
return { allowed: true }
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Auth required?
|
|
153
|
+
if (authConfig.required && !authContext.authenticated) {
|
|
154
|
+
return {
|
|
155
|
+
allowed: false,
|
|
156
|
+
reason: 'Authentication required'
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Verificar roles (OR logic - qualquer role basta)
|
|
161
|
+
if (authConfig.roles?.length) {
|
|
162
|
+
if (!authContext.authenticated) {
|
|
163
|
+
return {
|
|
164
|
+
allowed: false,
|
|
165
|
+
reason: `Authentication required. Roles needed: ${authConfig.roles.join(', ')}`
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (!authContext.hasAnyRole(authConfig.roles)) {
|
|
169
|
+
return {
|
|
170
|
+
allowed: false,
|
|
171
|
+
reason: `Insufficient roles. Required one of: ${authConfig.roles.join(', ')}`
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Verificar permissions (AND logic - todas devem estar presentes)
|
|
177
|
+
if (authConfig.permissions?.length) {
|
|
178
|
+
if (!authContext.authenticated) {
|
|
179
|
+
return {
|
|
180
|
+
allowed: false,
|
|
181
|
+
reason: `Authentication required. Permissions needed: ${authConfig.permissions.join(', ')}`
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (!authContext.hasAllPermissions(authConfig.permissions)) {
|
|
185
|
+
return {
|
|
186
|
+
allowed: false,
|
|
187
|
+
reason: `Insufficient permissions. Required all: ${authConfig.permissions.join(', ')}`
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return { allowed: true }
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Verifica se o contexto de auth permite executar uma action específica.
|
|
197
|
+
* Usado pelo ComponentRegistry antes de executar uma action.
|
|
198
|
+
*/
|
|
199
|
+
async authorizeAction(
|
|
200
|
+
authContext: LiveAuthContext,
|
|
201
|
+
componentName: string,
|
|
202
|
+
action: string,
|
|
203
|
+
actionAuth: LiveActionAuth | undefined,
|
|
204
|
+
providerName?: string
|
|
205
|
+
): Promise<LiveAuthResult> {
|
|
206
|
+
// Sem config de auth para esta action = permitido
|
|
207
|
+
if (!actionAuth) {
|
|
208
|
+
return { allowed: true }
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Verificar roles (OR logic)
|
|
212
|
+
if (actionAuth.roles?.length) {
|
|
213
|
+
if (!authContext.authenticated) {
|
|
214
|
+
return {
|
|
215
|
+
allowed: false,
|
|
216
|
+
reason: `Authentication required for action '${action}'`
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (!authContext.hasAnyRole(actionAuth.roles)) {
|
|
220
|
+
return {
|
|
221
|
+
allowed: false,
|
|
222
|
+
reason: `Insufficient roles for action '${action}'. Required one of: ${actionAuth.roles.join(', ')}`
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Verificar permissions (AND logic)
|
|
228
|
+
if (actionAuth.permissions?.length) {
|
|
229
|
+
if (!authContext.authenticated) {
|
|
230
|
+
return {
|
|
231
|
+
allowed: false,
|
|
232
|
+
reason: `Authentication required for action '${action}'`
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (!authContext.hasAllPermissions(actionAuth.permissions)) {
|
|
236
|
+
return {
|
|
237
|
+
allowed: false,
|
|
238
|
+
reason: `Insufficient permissions for action '${action}'. Required all: ${actionAuth.permissions.join(', ')}`
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Verificar via provider customizado (se implementado)
|
|
244
|
+
const name = providerName || this.defaultProviderName
|
|
245
|
+
if (name) {
|
|
246
|
+
const provider = this.providers.get(name)
|
|
247
|
+
if (provider?.authorizeAction) {
|
|
248
|
+
const allowed = await provider.authorizeAction(authContext, componentName, action)
|
|
249
|
+
if (!allowed) {
|
|
250
|
+
return {
|
|
251
|
+
allowed: false,
|
|
252
|
+
reason: `Action '${action}' denied by auth provider '${name}'`
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return { allowed: true }
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Verifica se o contexto de auth permite entrar em uma sala.
|
|
263
|
+
*/
|
|
264
|
+
async authorizeRoom(
|
|
265
|
+
authContext: LiveAuthContext,
|
|
266
|
+
roomId: string,
|
|
267
|
+
providerName?: string
|
|
268
|
+
): Promise<LiveAuthResult> {
|
|
269
|
+
const name = providerName || this.defaultProviderName
|
|
270
|
+
if (!name) return { allowed: true }
|
|
271
|
+
|
|
272
|
+
const provider = this.providers.get(name)
|
|
273
|
+
if (!provider?.authorizeRoom) return { allowed: true }
|
|
274
|
+
|
|
275
|
+
try {
|
|
276
|
+
const allowed = await provider.authorizeRoom(authContext, roomId)
|
|
277
|
+
if (!allowed) {
|
|
278
|
+
return {
|
|
279
|
+
allowed: false,
|
|
280
|
+
reason: `Access to room '${roomId}' denied by auth provider '${name}'`
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return { allowed: true }
|
|
284
|
+
} catch (error: any) {
|
|
285
|
+
return {
|
|
286
|
+
allowed: false,
|
|
287
|
+
reason: `Room authorization error: ${error.message}`
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Retorna informações sobre os providers registrados.
|
|
294
|
+
*/
|
|
295
|
+
getInfo(): { providers: string[]; defaultProvider?: string } {
|
|
296
|
+
return {
|
|
297
|
+
providers: Array.from(this.providers.keys()),
|
|
298
|
+
defaultProvider: this.defaultProviderName,
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** Instância global do auth manager */
|
|
304
|
+
export const liveAuthManager = new LiveAuthManager()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// 🔒 FluxStack Live Components - Auth System Exports
|
|
2
|
+
|
|
3
|
+
// Types
|
|
4
|
+
export type {
|
|
5
|
+
LiveAuthCredentials,
|
|
6
|
+
LiveAuthUser,
|
|
7
|
+
LiveAuthContext,
|
|
8
|
+
LiveAuthProvider,
|
|
9
|
+
LiveComponentAuth,
|
|
10
|
+
LiveActionAuth,
|
|
11
|
+
LiveActionAuthMap,
|
|
12
|
+
LiveAuthResult,
|
|
13
|
+
} from './types'
|
|
14
|
+
|
|
15
|
+
// Context implementations
|
|
16
|
+
export { AuthenticatedContext, AnonymousContext, ANONYMOUS_CONTEXT } from './LiveAuthContext'
|
|
17
|
+
|
|
18
|
+
// Manager (singleton)
|
|
19
|
+
export { LiveAuthManager, liveAuthManager } from './LiveAuthManager'
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
// 🔒 FluxStack Live Components - Authentication Types
|
|
2
|
+
//
|
|
3
|
+
// Sistema declarativo de autenticação para Live Components.
|
|
4
|
+
// Permite que devs configurem auth por componente e por action.
|
|
5
|
+
//
|
|
6
|
+
// Uso no componente:
|
|
7
|
+
// class AdminChat extends LiveComponent<State> {
|
|
8
|
+
// static auth: LiveComponentAuth = {
|
|
9
|
+
// required: true,
|
|
10
|
+
// roles: ['admin', 'moderator'],
|
|
11
|
+
// }
|
|
12
|
+
//
|
|
13
|
+
// static actionAuth: LiveActionAuthMap = {
|
|
14
|
+
// deleteMessage: { permissions: ['chat.admin'] },
|
|
15
|
+
// sendMessage: { permissions: ['chat.write'] },
|
|
16
|
+
// }
|
|
17
|
+
// }
|
|
18
|
+
|
|
19
|
+
// ===== Credenciais enviadas pelo cliente =====
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Credenciais enviadas pelo cliente durante a autenticação WebSocket.
|
|
23
|
+
* Extensível para suportar qualquer estratégia de auth (JWT, API key, crypto, etc.)
|
|
24
|
+
*/
|
|
25
|
+
export interface LiveAuthCredentials {
|
|
26
|
+
/** JWT ou token opaco */
|
|
27
|
+
token?: string
|
|
28
|
+
/** Chave pública (para crypto-auth) */
|
|
29
|
+
publicKey?: string
|
|
30
|
+
/** Assinatura (para crypto-auth) */
|
|
31
|
+
signature?: string
|
|
32
|
+
/** Timestamp da assinatura */
|
|
33
|
+
timestamp?: number
|
|
34
|
+
/** Nonce anti-replay */
|
|
35
|
+
nonce?: string
|
|
36
|
+
/** Campos adicionais para providers customizados */
|
|
37
|
+
[key: string]: unknown
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ===== Usuário autenticado =====
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Informações do usuário autenticado.
|
|
44
|
+
* Retornado pelo LiveAuthProvider após validação.
|
|
45
|
+
*/
|
|
46
|
+
export interface LiveAuthUser {
|
|
47
|
+
/** Identificador único do usuário */
|
|
48
|
+
id: string
|
|
49
|
+
/** Roles atribuídas ao usuário (ex: 'admin', 'moderator') */
|
|
50
|
+
roles?: string[]
|
|
51
|
+
/** Permissões granulares (ex: 'chat.write', 'chat.admin') */
|
|
52
|
+
permissions?: string[]
|
|
53
|
+
/** Campos adicionais (nome, email, etc.) */
|
|
54
|
+
[key: string]: unknown
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ===== Contexto de autenticação =====
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Contexto de autenticação disponível dentro do LiveComponent via this.$auth.
|
|
61
|
+
* Fornece helpers para verificação de roles e permissões.
|
|
62
|
+
*/
|
|
63
|
+
export interface LiveAuthContext {
|
|
64
|
+
/** Se o usuário está autenticado */
|
|
65
|
+
readonly authenticated: boolean
|
|
66
|
+
/** Dados do usuário (undefined se não autenticado) */
|
|
67
|
+
readonly user?: LiveAuthUser
|
|
68
|
+
/** Token original usado para autenticação */
|
|
69
|
+
readonly token?: string
|
|
70
|
+
/** Timestamp de quando a autenticação ocorreu */
|
|
71
|
+
readonly authenticatedAt?: number
|
|
72
|
+
|
|
73
|
+
/** Verifica se o usuário possui uma role específica */
|
|
74
|
+
hasRole(role: string): boolean
|
|
75
|
+
/** Verifica se o usuário possui QUALQUER uma das roles */
|
|
76
|
+
hasAnyRole(roles: string[]): boolean
|
|
77
|
+
/** Verifica se o usuário possui TODAS as roles */
|
|
78
|
+
hasAllRoles(roles: string[]): boolean
|
|
79
|
+
/** Verifica se o usuário possui uma permissão específica */
|
|
80
|
+
hasPermission(permission: string): boolean
|
|
81
|
+
/** Verifica se o usuário possui TODAS as permissões */
|
|
82
|
+
hasAllPermissions(permissions: string[]): boolean
|
|
83
|
+
/** Verifica se o usuário possui QUALQUER uma das permissões */
|
|
84
|
+
hasAnyPermission(permissions: string[]): boolean
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ===== Provider de autenticação =====
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Interface para implementação de estratégias de autenticação.
|
|
91
|
+
* Cada provider implementa sua própria lógica de validação.
|
|
92
|
+
*
|
|
93
|
+
* Exemplos: JWTAuthProvider, CryptoAuthProvider, SessionAuthProvider
|
|
94
|
+
*/
|
|
95
|
+
export interface LiveAuthProvider {
|
|
96
|
+
/** Nome único do provider (ex: 'jwt', 'crypto', 'session') */
|
|
97
|
+
readonly name: string
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Valida credenciais e retorna contexto de autenticação.
|
|
101
|
+
* Retorna null se as credenciais forem inválidas.
|
|
102
|
+
*/
|
|
103
|
+
authenticate(credentials: LiveAuthCredentials): Promise<LiveAuthContext | null>
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* (Opcional) Autorização customizada por action.
|
|
107
|
+
* Retorna true se o usuário pode executar a action.
|
|
108
|
+
* Se não implementado, usa a lógica padrão de roles/permissions.
|
|
109
|
+
*/
|
|
110
|
+
authorizeAction?(
|
|
111
|
+
context: LiveAuthContext,
|
|
112
|
+
componentName: string,
|
|
113
|
+
action: string
|
|
114
|
+
): Promise<boolean>
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* (Opcional) Autorização customizada por sala.
|
|
118
|
+
* Retorna true se o usuário pode entrar na sala.
|
|
119
|
+
*/
|
|
120
|
+
authorizeRoom?(
|
|
121
|
+
context: LiveAuthContext,
|
|
122
|
+
roomId: string
|
|
123
|
+
): Promise<boolean>
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ===== Configuração de auth no componente =====
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Configuração de autenticação declarativa no LiveComponent.
|
|
130
|
+
* Definida como propriedade estática na classe.
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* class ProtectedChat extends LiveComponent<State> {
|
|
134
|
+
* static auth: LiveComponentAuth = {
|
|
135
|
+
* required: true,
|
|
136
|
+
* roles: ['user'],
|
|
137
|
+
* permissions: ['chat.read'],
|
|
138
|
+
* }
|
|
139
|
+
* }
|
|
140
|
+
*/
|
|
141
|
+
export interface LiveComponentAuth {
|
|
142
|
+
/** Se autenticação é obrigatória para montar o componente. Default: false */
|
|
143
|
+
required?: boolean
|
|
144
|
+
/** Roles necessárias (lógica OR - qualquer uma das roles basta) */
|
|
145
|
+
roles?: string[]
|
|
146
|
+
/** Permissões necessárias (lógica AND - todas devem estar presentes) */
|
|
147
|
+
permissions?: string[]
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Configuração de auth por action individual.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* static actionAuth: LiveActionAuthMap = {
|
|
155
|
+
* deleteMessage: { permissions: ['chat.admin'] },
|
|
156
|
+
* banUser: { roles: ['admin'] },
|
|
157
|
+
* }
|
|
158
|
+
*/
|
|
159
|
+
export interface LiveActionAuth {
|
|
160
|
+
/** Roles necessárias para esta action (lógica OR) */
|
|
161
|
+
roles?: string[]
|
|
162
|
+
/** Permissões necessárias para esta action (lógica AND) */
|
|
163
|
+
permissions?: string[]
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Mapa de action name → configuração de auth */
|
|
167
|
+
export type LiveActionAuthMap = Record<string, LiveActionAuth>
|
|
168
|
+
|
|
169
|
+
// ===== Resultado de autorização =====
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Resultado de uma verificação de autorização.
|
|
173
|
+
*/
|
|
174
|
+
export interface LiveAuthResult {
|
|
175
|
+
/** Se a autorização foi bem-sucedida */
|
|
176
|
+
allowed: boolean
|
|
177
|
+
/** Motivo da negação (se allowed === false) */
|
|
178
|
+
reason?: string
|
|
179
|
+
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
// 🔥 Auto-generated Live Components Registration
|
|
2
2
|
// This file is automatically generated during build time - DO NOT EDIT MANUALLY
|
|
3
|
-
// Generated at: 2026-02-
|
|
3
|
+
// Generated at: 2026-02-17T00:55:07.182Z
|
|
4
4
|
|
|
5
|
+
import { LiveAdminPanel } from "@app/server/live/LiveAdminPanel"
|
|
5
6
|
import { LiveChat } from "@app/server/live/LiveChat"
|
|
6
7
|
import { LiveCounter } from "@app/server/live/LiveCounter"
|
|
7
8
|
import { LiveForm } from "@app/server/live/LiveForm"
|
|
8
9
|
import { LiveLocalCounter } from "@app/server/live/LiveLocalCounter"
|
|
10
|
+
import { LiveProtectedChat } from "@app/server/live/LiveProtectedChat"
|
|
9
11
|
import { LiveRoomChat } from "@app/server/live/LiveRoomChat"
|
|
10
12
|
import { LiveUpload } from "@app/server/live/LiveUpload"
|
|
11
13
|
import { componentRegistry } from "@core/server/live/ComponentRegistry"
|
|
@@ -14,14 +16,16 @@ import { componentRegistry } from "@core/server/live/ComponentRegistry"
|
|
|
14
16
|
function registerAllComponents() {
|
|
15
17
|
try {
|
|
16
18
|
// Auto-generated component registrations
|
|
19
|
+
componentRegistry.registerComponentClass('LiveAdminPanel', LiveAdminPanel)
|
|
17
20
|
componentRegistry.registerComponentClass('LiveChat', LiveChat)
|
|
18
21
|
componentRegistry.registerComponentClass('LiveCounter', LiveCounter)
|
|
19
22
|
componentRegistry.registerComponentClass('LiveForm', LiveForm)
|
|
20
23
|
componentRegistry.registerComponentClass('LiveLocalCounter', LiveLocalCounter)
|
|
24
|
+
componentRegistry.registerComponentClass('LiveProtectedChat', LiveProtectedChat)
|
|
21
25
|
componentRegistry.registerComponentClass('LiveRoomChat', LiveRoomChat)
|
|
22
26
|
componentRegistry.registerComponentClass('LiveUpload', LiveUpload)
|
|
23
27
|
|
|
24
|
-
console.log('📝 Live components registered successfully! (
|
|
28
|
+
console.log('📝 Live components registered successfully! (8 components)')
|
|
25
29
|
} catch (error) {
|
|
26
30
|
console.warn('⚠️ Error registering components:', error)
|
|
27
31
|
}
|
|
@@ -32,10 +36,12 @@ registerAllComponents()
|
|
|
32
36
|
|
|
33
37
|
// Export all components to ensure they're included in the bundle
|
|
34
38
|
export {
|
|
39
|
+
LiveAdminPanel,
|
|
35
40
|
LiveChat,
|
|
36
41
|
LiveCounter,
|
|
37
42
|
LiveForm,
|
|
38
43
|
LiveLocalCounter,
|
|
44
|
+
LiveProtectedChat,
|
|
39
45
|
LiveRoomChat,
|
|
40
46
|
LiveUpload
|
|
41
47
|
}
|
|
@@ -12,3 +12,19 @@ export { connectionManager } from './WebSocketConnectionManager'
|
|
|
12
12
|
export { fileUploadManager } from './FileUploadManager'
|
|
13
13
|
export { stateSignature } from './StateSignature'
|
|
14
14
|
export { performanceMonitor } from './LiveComponentPerformanceMonitor'
|
|
15
|
+
export { liveLog, liveWarn, registerComponentLogging, unregisterComponentLogging } from './LiveLogger'
|
|
16
|
+
export type { LiveLogCategory, LiveLogConfig } from './LiveLogger'
|
|
17
|
+
|
|
18
|
+
// 🔒 Auth system
|
|
19
|
+
export { liveAuthManager, LiveAuthManager } from './auth/LiveAuthManager'
|
|
20
|
+
export { AuthenticatedContext, AnonymousContext, ANONYMOUS_CONTEXT } from './auth/LiveAuthContext'
|
|
21
|
+
export type {
|
|
22
|
+
LiveAuthProvider,
|
|
23
|
+
LiveAuthCredentials,
|
|
24
|
+
LiveAuthUser,
|
|
25
|
+
LiveAuthContext,
|
|
26
|
+
LiveComponentAuth,
|
|
27
|
+
LiveActionAuth,
|
|
28
|
+
LiveActionAuthMap,
|
|
29
|
+
LiveAuthResult,
|
|
30
|
+
} from './auth/types'
|