qcc/internal/server/session.go
Niko Marmeladkov 4f6310c2bb
Fix PoW auth bypass: verify against issued challenge, not new one
Store challenge from handleGetChallenge in session, then verify
against it in handleSolve. Previously a fresh challenge was
generated for verification, making auth trivially bypassable.
2026-06-30 13:47:17 +03:00

106 lines
1.8 KiB
Go

package server
import (
"sync"
"github.com/apernet/quic-go"
"github.com/niko/qcc/internal/auth"
"github.com/niko/qcc/internal/protocol"
"github.com/niko/qcc/internal/transport"
)
type Session struct {
mu sync.Mutex
conn *quic.Conn
stream *transport.Stream
authenticated bool
number string
pubKey [32]byte
certDER []byte
activeCallID uint64
lastChallenge *auth.PoWChallenge
}
func NewSession(conn *quic.Conn) *Session {
return &Session{
conn: conn,
}
}
func (s *Session) SetStream(st *transport.Stream) {
s.mu.Lock()
defer s.mu.Unlock()
s.stream = st
}
func (s *Session) Stream() protocol.FrameReadWriter {
s.mu.Lock()
defer s.mu.Unlock()
if s.stream == nil {
return nil
}
return s.stream
}
func (s *Session) Conn() *quic.Conn {
return s.conn
}
func (s *Session) Authenticate(number string, pubKey [32]byte, certDER []byte) {
s.mu.Lock()
defer s.mu.Unlock()
s.authenticated = true
s.number = number
s.pubKey = pubKey
s.certDER = certDER
}
func (s *Session) IsAuthenticated() bool {
s.mu.Lock()
defer s.mu.Unlock()
return s.authenticated
}
func (s *Session) Number() string {
s.mu.Lock()
defer s.mu.Unlock()
return s.number
}
func (s *Session) PubKey() [32]byte {
s.mu.Lock()
defer s.mu.Unlock()
return s.pubKey
}
func (s *Session) SetCallID(id uint64) {
s.mu.Lock()
defer s.mu.Unlock()
s.activeCallID = id
}
func (s *Session) CallID() uint64 {
s.mu.Lock()
defer s.mu.Unlock()
return s.activeCallID
}
func (s *Session) ClearCall() {
s.mu.Lock()
defer s.mu.Unlock()
s.activeCallID = 0
}
func (s *Session) SetChallenge(c *auth.PoWChallenge) {
s.mu.Lock()
defer s.mu.Unlock()
s.lastChallenge = c
}
func (s *Session) GetChallenge() *auth.PoWChallenge {
s.mu.Lock()
defer s.mu.Unlock()
return s.lastChallenge
}