ollie/cmd/toolsrv/internal/fs/state.go

104 lines
2.3 KiB
Go

// state.go - Server state management for toolsrv.
package fs
import (
"crypto/rand"
"encoding/hex"
"fmt"
"runtime"
"sync"
"ollie/cmd/toolsrv/internal/registry"
"ollie/virtfs"
)
// Server holds the state for the toolsrv 9P server.
type Server struct {
mu sync.RWMutex
secret string // set on first auth, verified on subsequent
token string // session token returned after auth
registry *registry.Registry // tool registry
yolo bool // skip sandbox
// Process management
Fs *State
}
// NewServer creates a new toolsrv server.
func NewServer() *Server {
return &Server{
Fs: NewState(""), // cwd set per-agent
}
}
// SetRegistry configures the tool registry.
func (s *Server) SetRegistry(r *registry.Registry) {
s.mu.Lock()
s.registry = r
s.Fs.SetRegistry(r)
s.mu.Unlock()
}
// SetYolo enables/disables sandbox bypass.
func (s *Server) SetYolo(yolo bool) {
s.mu.Lock()
s.yolo = yolo
s.Fs.SetYolo(yolo)
s.mu.Unlock()
}
// Authenticate handles secret verification.
// First call sets the secret; subsequent calls must match it.
// Returns (token, nil) on success, ("", error) on failure.
func (s *Server) Authenticate(clientSecret string) (string, error) {
s.mu.Lock()
defer s.mu.Unlock()
if s.secret == "" {
// First auth - set the secret
s.secret = clientSecret
s.token = randomToken()
return s.token, nil
}
// Subsequent auth - verify secret
if clientSecret != s.secret {
return "", fmt.Errorf("authentication failed")
}
return s.token, nil
}
// Token returns the current session token (empty if not authenticated).
func (s *Server) Token() string {
s.mu.RLock()
defer s.mu.RUnlock()
return s.token
}
// HostInfo returns platform info as key=value lines.
func (s *Server) HostInfo() string {
return fmt.Sprintf("platform=%s\narch=%s\n", runtime.GOOS, runtime.GOARCH)
}
// BuildTree creates the virtfs tree for this server.
func (s *Server) BuildTree() *virtfs.Tree {
return virtfs.BuildTree(Spec(s))
}
// GenerateSecret generates a random shared secret for toolsrv auth.
func GenerateSecret() (string, error) {
secret := make([]byte, 32)
if _, err := rand.Read(secret); err != nil {
return "", err
}
return hex.EncodeToString(secret), nil
}
func randomToken() string {
b := make([]byte, 16)
rand.Read(b)
return hex.EncodeToString(b)
}