Files
lpra/internal/server/agents.go
T
redtea 3dde07f403 feat: terminal as a chosen OS user, create users from the panel (0.0.2)
- agent reports the OS user it runs as (enroll + poll header)
- per-machine terminal user on the edit page; defaults to the agent's own user (root on Linux)
- create a new user from the panel: name, password, optional sudo group
- show the reason in the terminal when a shell fails to start
- bump version to 0.0.2
2026-10-13 01:28:57 +03:00

64 lines
1.5 KiB
Go

package server
import (
"net/http"
"strings"
)
// authenticateAgent resolves the agent identified by the Bearer token on the
// request, verifying the token against the stored hash in constant time.
// Returns nil if authentication fails.
func (s *Server) authenticateAgent(r *http.Request) *Agent {
id := r.Header.Get("X-Agent-Id")
token := bearerToken(r)
if id == "" || token == "" {
return nil
}
a, err := s.db.GetAgent(id)
if err != nil || a == nil {
return nil
}
if !constantTimeEqual(a.TokenHash, hashToken(token)) {
return nil
}
return a
}
func bearerToken(r *http.Request) string {
h := r.Header.Get("Authorization")
if strings.HasPrefix(h, "Bearer ") {
return strings.TrimPrefix(h, "Bearer ")
}
return ""
}
// enroll creates a new agent record for a valid enroll secret and returns the
// generated id plus a one-time plaintext token (only the hash is stored).
func (s *Server) enroll(name, hostname, os, arch, version, runUser string) (id, token string, err error) {
id = randToken()[:16]
token = randToken()
a := Agent{
ID: id,
Name: firstNonEmpty(name, hostname, id),
Hostname: hostname,
OS: os,
Arch: arch,
Version: version,
RunUser: runUser,
TokenHash: hashToken(token),
}
if err = s.db.CreateAgent(a); err != nil {
return "", "", err
}
return id, token, nil
}
func firstNonEmpty(vals ...string) string {
for _, v := range vals {
if strings.TrimSpace(v) != "" {
return v
}
}
return ""
}