create-fluxstack 1.15.0 → 1.17.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/CHANGELOG.md +80 -0
- package/LLMD/INDEX.md +4 -3
- package/LLMD/resources/live-binary-delta.md +507 -0
- package/LLMD/resources/live-components.md +1 -0
- package/LLMD/resources/live-rooms.md +731 -333
- package/app/client/src/App.tsx +23 -14
- package/app/client/src/components/AppLayout.tsx +4 -4
- package/app/client/src/live/AuthDemo.tsx +4 -4
- package/app/client/src/live/PingPongDemo.tsx +199 -0
- package/app/client/src/live/RoomChatDemo.tsx +187 -22
- package/app/client/src/live/SharedCounterDemo.tsx +142 -0
- package/app/server/live/LivePingPong.ts +61 -0
- package/app/server/live/LiveRoomChat.ts +106 -38
- package/app/server/live/LiveSharedCounter.ts +73 -0
- package/app/server/live/rooms/ChatRoom.ts +68 -0
- package/app/server/live/rooms/CounterRoom.ts +51 -0
- package/app/server/live/rooms/DirectoryRoom.ts +42 -0
- package/app/server/live/rooms/PingRoom.ts +40 -0
- package/core/build/bundler.ts +40 -26
- package/core/build/flux-plugins-generator.ts +325 -325
- package/core/build/index.ts +92 -21
- package/core/cli/command-registry.ts +44 -46
- package/core/cli/commands/build.ts +11 -6
- package/core/cli/commands/create.ts +7 -5
- package/core/cli/commands/dev.ts +6 -5
- package/core/cli/commands/help.ts +3 -2
- package/core/cli/commands/make-plugin.ts +8 -7
- package/core/cli/commands/plugin-add.ts +60 -43
- package/core/cli/commands/plugin-deps.ts +73 -57
- package/core/cli/commands/plugin-list.ts +44 -41
- package/core/cli/commands/plugin-remove.ts +33 -22
- package/core/cli/generators/component.ts +770 -769
- package/core/cli/generators/controller.ts +9 -8
- package/core/cli/generators/index.ts +148 -146
- package/core/cli/generators/interactive.ts +228 -227
- package/core/cli/generators/plugin.ts +11 -10
- package/core/cli/generators/prompts.ts +83 -82
- package/core/cli/generators/route.ts +7 -6
- package/core/cli/generators/service.ts +10 -9
- package/core/cli/generators/template-engine.ts +2 -1
- package/core/cli/generators/types.ts +7 -7
- package/core/cli/generators/utils.ts +191 -191
- package/core/cli/index.ts +9 -8
- package/core/cli/plugin-discovery.ts +2 -2
- package/core/client/hooks/useAuth.ts +48 -48
- package/core/client/index.ts +0 -16
- package/core/client/standalone.ts +18 -17
- package/core/client/state/createStore.ts +192 -192
- package/core/client/state/index.ts +14 -14
- package/core/config/index.ts +1 -0
- package/core/framework/client.ts +131 -131
- package/core/framework/index.ts +7 -7
- package/core/framework/server.ts +72 -112
- package/core/framework/types.ts +2 -2
- package/core/plugins/built-in/live-components/commands/create-live-component.ts +6 -3
- package/core/plugins/built-in/monitoring/index.ts +110 -68
- package/core/plugins/built-in/static/index.ts +2 -2
- package/core/plugins/built-in/swagger/index.ts +9 -9
- package/core/plugins/built-in/vite/index.ts +3 -3
- package/core/plugins/built-in/vite/vite-dev.ts +3 -3
- package/core/plugins/config.ts +50 -47
- package/core/plugins/discovery.ts +10 -4
- package/core/plugins/executor.ts +2 -2
- package/core/plugins/index.ts +206 -203
- package/core/plugins/manager.ts +21 -20
- package/core/plugins/registry.ts +76 -12
- package/core/plugins/types.ts +14 -14
- package/core/server/framework.ts +3 -189
- package/core/server/live/auto-generated-components.ts +11 -35
- package/core/server/live/index.ts +41 -36
- package/core/server/live/websocket-plugin.ts +48 -3
- package/core/server/middleware/elysia-helpers.ts +16 -15
- package/core/server/middleware/errorHandling.ts +14 -14
- package/core/server/middleware/index.ts +31 -31
- package/core/server/plugins/database.ts +181 -180
- package/core/server/plugins/static-files-plugin.ts +4 -3
- package/core/server/plugins/swagger.ts +11 -8
- package/core/server/rooms/RoomBroadcaster.ts +11 -10
- package/core/server/rooms/RoomSystem.ts +14 -11
- package/core/server/services/BaseService.ts +7 -7
- package/core/server/services/ServiceContainer.ts +5 -5
- package/core/server/services/index.ts +8 -8
- package/core/templates/create-project.ts +28 -27
- package/core/testing/index.ts +9 -9
- package/core/testing/setup.ts +73 -73
- package/core/types/api.ts +168 -168
- package/core/types/config.ts +5 -5
- package/core/types/index.ts +1 -1
- package/core/types/plugin.ts +2 -2
- package/core/types/types.ts +3 -3
- package/core/utils/build-logger.ts +324 -324
- package/core/utils/config-schema.ts +480 -480
- package/core/utils/env.ts +10 -8
- package/core/utils/errors/codes.ts +114 -114
- package/core/utils/errors/handlers.ts +30 -20
- package/core/utils/errors/index.ts +54 -46
- package/core/utils/errors/middleware.ts +113 -113
- package/core/utils/helpers.ts +19 -16
- package/core/utils/logger/colors.ts +114 -114
- package/core/utils/logger/config.ts +2 -2
- package/core/utils/logger/formatter.ts +82 -82
- package/core/utils/logger/group-logger.ts +101 -101
- package/core/utils/logger/index.ts +13 -3
- package/core/utils/logger/startup-banner.ts +2 -2
- package/core/utils/logger/winston-logger.ts +152 -152
- package/core/utils/monitoring/index.ts +211 -211
- package/core/utils/sync-version.ts +67 -66
- package/core/utils/version.ts +1 -1
- package/package.json +11 -6
- package/playwright-report/index.html +85 -0
- package/playwright.config.ts +31 -0
- package/plugins/crypto-auth/client/CryptoAuthClient.ts +302 -302
- package/plugins/crypto-auth/client/components/index.ts +11 -11
- package/plugins/crypto-auth/client/index.ts +11 -11
- package/plugins/crypto-auth/package.json +65 -65
- package/plugins/crypto-auth/server/CryptoAuthService.ts +185 -185
- package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +6 -5
- package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +6 -5
- package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +3 -3
- package/plugins/crypto-auth/server/middlewares/index.ts +22 -22
- package/plugins/crypto-auth/server/middlewares.ts +19 -19
- package/tsconfig.json +4 -1
- package/vite.config.ts +13 -0
- package/app/client/.live-stubs/LiveAdminPanel.js +0 -5
- package/app/client/.live-stubs/LiveChat.js +0 -7
- package/app/client/.live-stubs/LiveCounter.js +0 -9
- package/app/client/.live-stubs/LiveForm.js +0 -11
- package/app/client/.live-stubs/LiveLocalCounter.js +0 -8
- package/app/client/.live-stubs/LiveRoomChat.js +0 -10
- package/app/client/.live-stubs/LiveTodoList.js +0 -9
- package/app/client/.live-stubs/LiveUpload.js +0 -15
- package/app/client/src/live/ChatDemo.tsx +0 -107
- package/app/client/src/live/LiveDebuggerPanel.tsx +0 -779
- package/app/client/src/live/TodoListDemo.tsx +0 -158
- package/app/server/live/LiveChat.ts +0 -78
- package/app/server/live/LiveTodoList.ts +0 -110
- package/app/server/live/register-components.ts +0 -19
- package/core/build/live-components-generator.ts +0 -312
- package/core/client/components/LiveDebugger.tsx +0 -1324
- package/core/live/ComponentRegistry.ts +0 -403
- package/core/live/types.ts +0 -241
- package/workspace.json +0 -6
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@fluxstack/crypto-auth-plugin",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "Plugin de autenticação criptográfica Ed25519 para FluxStack",
|
|
5
|
-
"main": "index.ts",
|
|
6
|
-
"types": "index.ts",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": {
|
|
9
|
-
"import": "./index.ts",
|
|
10
|
-
"types": "./index.ts"
|
|
11
|
-
},
|
|
12
|
-
"./client": {
|
|
13
|
-
"import": "./client/index.ts",
|
|
14
|
-
"types": "./client/index.ts"
|
|
15
|
-
},
|
|
16
|
-
"./server": {
|
|
17
|
-
"import": "./server/index.ts",
|
|
18
|
-
"types": "./server/index.ts"
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
"keywords": [
|
|
22
|
-
"fluxstack",
|
|
23
|
-
"plugin",
|
|
24
|
-
"authentication",
|
|
25
|
-
"ed25519",
|
|
26
|
-
"cryptography",
|
|
27
|
-
"security",
|
|
28
|
-
"react",
|
|
29
|
-
"typescript"
|
|
30
|
-
],
|
|
31
|
-
"author": "FluxStack Team",
|
|
32
|
-
"license": "MIT",
|
|
33
|
-
"peerDependencies": {
|
|
34
|
-
"react": ">=16.8.0"
|
|
35
|
-
},
|
|
36
|
-
"peerDependenciesMeta": {
|
|
37
|
-
"react": {
|
|
38
|
-
"optional": true
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
"dependencies": {
|
|
42
|
-
"@noble/curves": "1.2.0",
|
|
43
|
-
"@noble/hashes": "1.3.2"
|
|
44
|
-
},
|
|
45
|
-
"devDependencies": {
|
|
46
|
-
"@types/react": "^18.0.0",
|
|
47
|
-
"typescript": "^5.0.0"
|
|
48
|
-
},
|
|
49
|
-
"fluxstack": {
|
|
50
|
-
"plugin": true,
|
|
51
|
-
"version": "^1.0.0",
|
|
52
|
-
"hooks": [
|
|
53
|
-
"setup",
|
|
54
|
-
"onServerStart",
|
|
55
|
-
"onRequest",
|
|
56
|
-
"onResponse"
|
|
57
|
-
],
|
|
58
|
-
"category": "auth",
|
|
59
|
-
"tags": [
|
|
60
|
-
"authentication",
|
|
61
|
-
"ed25519",
|
|
62
|
-
"cryptography",
|
|
63
|
-
"security"
|
|
64
|
-
]
|
|
65
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@fluxstack/crypto-auth-plugin",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Plugin de autenticação criptográfica Ed25519 para FluxStack",
|
|
5
|
+
"main": "index.ts",
|
|
6
|
+
"types": "index.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./index.ts",
|
|
10
|
+
"types": "./index.ts"
|
|
11
|
+
},
|
|
12
|
+
"./client": {
|
|
13
|
+
"import": "./client/index.ts",
|
|
14
|
+
"types": "./client/index.ts"
|
|
15
|
+
},
|
|
16
|
+
"./server": {
|
|
17
|
+
"import": "./server/index.ts",
|
|
18
|
+
"types": "./server/index.ts"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"fluxstack",
|
|
23
|
+
"plugin",
|
|
24
|
+
"authentication",
|
|
25
|
+
"ed25519",
|
|
26
|
+
"cryptography",
|
|
27
|
+
"security",
|
|
28
|
+
"react",
|
|
29
|
+
"typescript"
|
|
30
|
+
],
|
|
31
|
+
"author": "FluxStack Team",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"react": ">=16.8.0"
|
|
35
|
+
},
|
|
36
|
+
"peerDependenciesMeta": {
|
|
37
|
+
"react": {
|
|
38
|
+
"optional": true
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@noble/curves": "1.2.0",
|
|
43
|
+
"@noble/hashes": "1.3.2"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/react": "^18.0.0",
|
|
47
|
+
"typescript": "^5.0.0"
|
|
48
|
+
},
|
|
49
|
+
"fluxstack": {
|
|
50
|
+
"plugin": true,
|
|
51
|
+
"version": "^1.0.0",
|
|
52
|
+
"hooks": [
|
|
53
|
+
"setup",
|
|
54
|
+
"onServerStart",
|
|
55
|
+
"onRequest",
|
|
56
|
+
"onResponse"
|
|
57
|
+
],
|
|
58
|
+
"category": "auth",
|
|
59
|
+
"tags": [
|
|
60
|
+
"authentication",
|
|
61
|
+
"ed25519",
|
|
62
|
+
"cryptography",
|
|
63
|
+
"security"
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
66
|
}
|
|
@@ -1,186 +1,186 @@
|
|
|
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
|
-
}
|
|
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
186
|
}
|
|
@@ -24,17 +24,18 @@ export const cryptoAuthAdmin = (options: CryptoAuthMiddlewareOptions = {}) => {
|
|
|
24
24
|
return {}
|
|
25
25
|
})
|
|
26
26
|
.use(
|
|
27
|
-
createGuard({
|
|
27
|
+
createGuard<{ request: Request & { user?: CryptoAuthUser } }>({
|
|
28
28
|
name: 'crypto-auth-admin-check',
|
|
29
29
|
check: ({ request }) => {
|
|
30
|
-
const user =
|
|
30
|
+
const user = request.user
|
|
31
31
|
return !!(user && user.isAdmin)
|
|
32
32
|
},
|
|
33
33
|
onFail: (set, { request }) => {
|
|
34
|
-
const user =
|
|
34
|
+
const user = request.user
|
|
35
|
+
const s = set as { status: number }
|
|
35
36
|
|
|
36
37
|
if (!user) {
|
|
37
|
-
|
|
38
|
+
s.status = 401
|
|
38
39
|
return {
|
|
39
40
|
error: {
|
|
40
41
|
message: 'Authentication required',
|
|
@@ -49,7 +50,7 @@ export const cryptoAuthAdmin = (options: CryptoAuthMiddlewareOptions = {}) => {
|
|
|
49
50
|
permissions: user.permissions
|
|
50
51
|
})
|
|
51
52
|
|
|
52
|
-
|
|
53
|
+
s.status = 403
|
|
53
54
|
return {
|
|
54
55
|
error: {
|
|
55
56
|
message: 'Admin privileges required',
|
|
@@ -27,10 +27,10 @@ export const cryptoAuthPermissions = (
|
|
|
27
27
|
return {}
|
|
28
28
|
})
|
|
29
29
|
.use(
|
|
30
|
-
createGuard({
|
|
30
|
+
createGuard<{ request: Request & { user?: CryptoAuthUser } }>({
|
|
31
31
|
name: 'crypto-auth-permissions-check',
|
|
32
32
|
check: ({ request }) => {
|
|
33
|
-
const user =
|
|
33
|
+
const user = request.user
|
|
34
34
|
|
|
35
35
|
if (!user) return false
|
|
36
36
|
|
|
@@ -40,10 +40,11 @@ export const cryptoAuthPermissions = (
|
|
|
40
40
|
)
|
|
41
41
|
},
|
|
42
42
|
onFail: (set, { request }) => {
|
|
43
|
-
const user =
|
|
43
|
+
const user = request.user
|
|
44
|
+
const s = set as { status: number }
|
|
44
45
|
|
|
45
46
|
if (!user) {
|
|
46
|
-
|
|
47
|
+
s.status = 401
|
|
47
48
|
return {
|
|
48
49
|
error: {
|
|
49
50
|
message: 'Authentication required',
|
|
@@ -59,7 +60,7 @@ export const cryptoAuthPermissions = (
|
|
|
59
60
|
has: user.permissions
|
|
60
61
|
})
|
|
61
62
|
|
|
62
|
-
|
|
63
|
+
s.status = 403
|
|
63
64
|
return {
|
|
64
65
|
error: {
|
|
65
66
|
message: 'Insufficient permissions',
|
|
@@ -24,13 +24,13 @@ export const cryptoAuthRequired = (options: CryptoAuthMiddlewareOptions = {}) =>
|
|
|
24
24
|
return {}
|
|
25
25
|
})
|
|
26
26
|
.use(
|
|
27
|
-
createGuard({
|
|
27
|
+
createGuard<{ request: Request & { user?: unknown } }>({
|
|
28
28
|
name: 'crypto-auth-check',
|
|
29
29
|
check: ({ request }) => {
|
|
30
|
-
return !!
|
|
30
|
+
return !!request.user
|
|
31
31
|
},
|
|
32
32
|
onFail: (set) => {
|
|
33
|
-
set.status = 401
|
|
33
|
+
(set as { status: number }).status = 401
|
|
34
34
|
return {
|
|
35
35
|
error: {
|
|
36
36
|
message: 'Authentication required',
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Crypto Auth Middlewares
|
|
3
|
-
* Exports centralizados de todos os middlewares
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// Middlewares
|
|
7
|
-
export { cryptoAuthRequired } from './cryptoAuthRequired'
|
|
8
|
-
export { cryptoAuthAdmin } from './cryptoAuthAdmin'
|
|
9
|
-
export { cryptoAuthOptional } from './cryptoAuthOptional'
|
|
10
|
-
export { cryptoAuthPermissions } from './cryptoAuthPermissions'
|
|
11
|
-
|
|
12
|
-
// Helpers
|
|
13
|
-
export {
|
|
14
|
-
getCryptoAuthUser,
|
|
15
|
-
isCryptoAuthAuthenticated,
|
|
16
|
-
isCryptoAuthAdmin,
|
|
17
|
-
hasCryptoAuthPermission,
|
|
18
|
-
type CryptoAuthUser
|
|
19
|
-
} from './helpers'
|
|
20
|
-
|
|
21
|
-
// Types
|
|
22
|
-
export type { CryptoAuthMiddlewareOptions } from './cryptoAuthRequired'
|
|
1
|
+
/**
|
|
2
|
+
* Crypto Auth Middlewares
|
|
3
|
+
* Exports centralizados de todos os middlewares
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Middlewares
|
|
7
|
+
export { cryptoAuthRequired } from './cryptoAuthRequired'
|
|
8
|
+
export { cryptoAuthAdmin } from './cryptoAuthAdmin'
|
|
9
|
+
export { cryptoAuthOptional } from './cryptoAuthOptional'
|
|
10
|
+
export { cryptoAuthPermissions } from './cryptoAuthPermissions'
|
|
11
|
+
|
|
12
|
+
// Helpers
|
|
13
|
+
export {
|
|
14
|
+
getCryptoAuthUser,
|
|
15
|
+
isCryptoAuthAuthenticated,
|
|
16
|
+
isCryptoAuthAdmin,
|
|
17
|
+
hasCryptoAuthPermission,
|
|
18
|
+
type CryptoAuthUser
|
|
19
|
+
} from './helpers'
|
|
20
|
+
|
|
21
|
+
// Types
|
|
22
|
+
export type { CryptoAuthMiddlewareOptions } from './cryptoAuthRequired'
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Crypto Auth Middlewares
|
|
3
|
-
* Middlewares Elysia para autenticação criptográfica
|
|
4
|
-
*
|
|
5
|
-
* Uso:
|
|
6
|
-
* ```typescript
|
|
7
|
-
* import { cryptoAuthRequired, cryptoAuthAdmin } from '@/plugins/crypto-auth/server'
|
|
8
|
-
*
|
|
9
|
-
* export const myRoutes = new Elysia()
|
|
10
|
-
* .use(cryptoAuthRequired())
|
|
11
|
-
* .get('/protected', ({ request }) => {
|
|
12
|
-
* const user = getCryptoAuthUser(request)
|
|
13
|
-
* return { user }
|
|
14
|
-
* })
|
|
15
|
-
* ```
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
// Re-export tudo do módulo middlewares
|
|
19
|
-
export * from './middlewares/index'
|
|
1
|
+
/**
|
|
2
|
+
* Crypto Auth Middlewares
|
|
3
|
+
* Middlewares Elysia para autenticação criptográfica
|
|
4
|
+
*
|
|
5
|
+
* Uso:
|
|
6
|
+
* ```typescript
|
|
7
|
+
* import { cryptoAuthRequired, cryptoAuthAdmin } from '@/plugins/crypto-auth/server'
|
|
8
|
+
*
|
|
9
|
+
* export const myRoutes = new Elysia()
|
|
10
|
+
* .use(cryptoAuthRequired())
|
|
11
|
+
* .get('/protected', ({ request }) => {
|
|
12
|
+
* const user = getCryptoAuthUser(request)
|
|
13
|
+
* return { user }
|
|
14
|
+
* })
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
// Re-export tudo do módulo middlewares
|
|
19
|
+
export * from './middlewares/index'
|