fix: 2026-06-04 audit pass — README, USB pack, multi-area fixes
WS ticket dashboard auth, builder universal signing/size limits/fusion obfuscation/dropper bundles, Path Tracer WireGuard topology, SessionGate degraded mode and download timeouts, server bootstrap (data dir, cloudflared dedupe, config port precedence), agent mesh/miner/spread fixes. README refreshed; usb bundle repacked; PROBLEMS.md audit log updated.
This commit is contained in:
54
server/internal/api/ws_ticket.go
Normal file
54
server/internal/api/ws_ticket.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const wsTicketTTL = 2 * time.Minute
|
||||
|
||||
type wsTicketEntry struct {
|
||||
Username string
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
|
||||
var (
|
||||
wsTicketMu sync.Mutex
|
||||
wsTickets = map[string]wsTicketEntry{}
|
||||
)
|
||||
|
||||
// issueWSTicket mints a one-time, short-lived dashboard WebSocket credential.
|
||||
func issueWSTicket(username string) string {
|
||||
b := make([]byte, 24)
|
||||
_, _ = rand.Read(b)
|
||||
ticket := hex.EncodeToString(b)
|
||||
wsTicketMu.Lock()
|
||||
wsTickets[ticket] = wsTicketEntry{Username: username, ExpiresAt: time.Now().Add(wsTicketTTL)}
|
||||
if len(wsTickets) > 512 {
|
||||
now := time.Now()
|
||||
for k, v := range wsTickets {
|
||||
if now.After(v.ExpiresAt) {
|
||||
delete(wsTickets, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
wsTicketMu.Unlock()
|
||||
return ticket
|
||||
}
|
||||
|
||||
// consumeWSTicket validates and invalidates a ticket (one-time use).
|
||||
func consumeWSTicket(ticket string) (string, bool) {
|
||||
wsTicketMu.Lock()
|
||||
defer wsTicketMu.Unlock()
|
||||
entry, ok := wsTickets[ticket]
|
||||
if !ok || time.Now().After(entry.ExpiresAt) {
|
||||
if ok {
|
||||
delete(wsTickets, ticket)
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
delete(wsTickets, ticket)
|
||||
return entry.Username, true
|
||||
}
|
||||
Reference in New Issue
Block a user