Files
1Panel/agent/utils/terminal/registry.go

98 lines
1.9 KiB
Go

package terminal
import (
"errors"
"sort"
"sync"
)
// sessions is the process wide registry of live sessions, keyed by id.
// Open stores, Close deletes.
var sessions sync.Map
var errSessionNotFound = errors.New("terminal session not found")
const (
HeaderUserID = "X-Panel-User-ID"
HeaderAuthSessionID = "X-Panel-Auth-Session-ID"
)
type Identity struct {
UserID string
AuthSessionID string
}
func (i Identity) Valid() bool {
return i.UserID != "" && i.AuthSessionID != ""
}
func registerSession(s *Session) {
sessions.Store(s.ID, s)
}
func unregisterSession(s *Session) {
sessions.CompareAndDelete(s.ID, s)
}
func Lookup(id string, identity Identity) (*Session, bool) {
if !identity.Valid() {
return nil, false
}
v, ok := sessions.Load(id)
if !ok {
return nil, false
}
s := v.(*Session)
if s.UserID != identity.UserID || s.AuthSessionID != identity.AuthSessionID {
return nil, false
}
return s, true
}
func List(identity Identity) []Info {
if !identity.Valid() {
return nil
}
var out []Info
sessions.Range(func(_, v any) bool {
s := v.(*Session)
if s.UserID == identity.UserID && s.AuthSessionID == identity.AuthSessionID {
out = append(out, s.Info())
}
return true
})
sort.Slice(out, func(i, j int) bool { return out[i].CreatedAt.Before(out[j].CreatedAt) })
return out
}
func CloseSession(id string, identity Identity) error {
s, ok := Lookup(id, identity)
if !ok {
return errSessionNotFound
}
s.Close()
return nil
}
func Revoke(scope, userID, authSessionID string) int {
closed := 0
sessions.Range(func(_, v any) bool {
s := v.(*Session)
match := false
switch scope {
case "auth_session":
match = userID != "" && authSessionID != "" && s.UserID == userID && s.AuthSessionID == authSessionID
case "user":
match = userID != "" && s.UserID == userID
case "all":
match = true
}
if match {
closed++
s.Close()
}
return true
})
return closed
}