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.
- package/.env.example +1 -8
- package/app/client/src/App.tsx +1 -4
- package/app/server/index.ts +0 -4
- package/app/server/routes/index.ts +1 -5
- package/config/index.ts +1 -9
- package/core/cli/generators/plugin.ts +34 -324
- package/core/cli/generators/template-engine.ts +0 -5
- package/core/cli/plugin-discovery.ts +12 -33
- package/core/framework/server.ts +0 -10
- package/core/plugins/dependency-manager.ts +22 -89
- package/core/plugins/index.ts +0 -4
- package/core/plugins/manager.ts +2 -3
- package/core/plugins/registry.ts +1 -28
- package/core/utils/logger/index.ts +0 -4
- package/core/utils/version.ts +1 -1
- package/fluxstack.config.ts +114 -253
- package/package.json +117 -117
- package/CRYPTO-AUTH-MIDDLEWARE-GUIDE.md +0 -475
- package/CRYPTO-AUTH-MIDDLEWARES.md +0 -473
- package/CRYPTO-AUTH-USAGE.md +0 -491
- package/EXEMPLO-ROTA-PROTEGIDA.md +0 -347
- package/QUICK-START-CRYPTO-AUTH.md +0 -221
- package/app/client/src/pages/CryptoAuthPage.tsx +0 -394
- package/app/server/routes/crypto-auth-demo.routes.ts +0 -167
- package/app/server/routes/example-with-crypto-auth.routes.ts +0 -235
- package/app/server/routes/exemplo-posts.routes.ts +0 -161
- package/core/plugins/module-resolver.ts +0 -216
- package/plugins/crypto-auth/README.md +0 -788
- package/plugins/crypto-auth/ai-context.md +0 -1282
- package/plugins/crypto-auth/cli/make-protected-route.command.ts +0 -383
- package/plugins/crypto-auth/client/CryptoAuthClient.ts +0 -302
- package/plugins/crypto-auth/client/components/AuthProvider.tsx +0 -131
- package/plugins/crypto-auth/client/components/LoginButton.tsx +0 -138
- package/plugins/crypto-auth/client/components/ProtectedRoute.tsx +0 -89
- package/plugins/crypto-auth/client/components/index.ts +0 -12
- package/plugins/crypto-auth/client/index.ts +0 -12
- package/plugins/crypto-auth/config/index.ts +0 -34
- package/plugins/crypto-auth/index.ts +0 -162
- package/plugins/crypto-auth/package.json +0 -66
- package/plugins/crypto-auth/server/AuthMiddleware.ts +0 -181
- package/plugins/crypto-auth/server/CryptoAuthService.ts +0 -186
- package/plugins/crypto-auth/server/index.ts +0 -22
- package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +0 -65
- package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +0 -26
- package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +0 -76
- package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +0 -45
- package/plugins/crypto-auth/server/middlewares/helpers.ts +0 -140
- package/plugins/crypto-auth/server/middlewares/index.ts +0 -22
- package/plugins/crypto-auth/server/middlewares.ts +0 -19
- 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
|
-
}
|