Users, with their own settings, and a list of where each is signed in
The login is a user name and a password. The old single password becomes the account named after the OS user on first boot, along with its sessions and the machine-wide look. Settings gains Users (add, remove, reset a password — your own password confirms) and Sessions (device, IP, last seen; revoke one or sign out everywhere else). Theme, accents and the dashboard layout follow the account; the refresh rate, graph history and alerts stay the machine's. Pairing a machine takes a user on it. Log lines name the actor. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
db214ebc2b
commit
2b54a06821
+53
-8
@@ -16,14 +16,59 @@ type Terminal struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// Session is one signed-in browser. The map key is the cookie's token; ID is what the
|
||||
// UI sees and revokes by, so a session list never shows a usable token.
|
||||
type Session struct {
|
||||
ID string `json:"id"`
|
||||
User string `json:"user"`
|
||||
Expires time.Time `json:"expires"`
|
||||
Created time.Time `json:"created,omitempty"`
|
||||
LastSeen time.Time `json:"last_seen,omitempty"`
|
||||
IP string `json:"ip,omitempty"`
|
||||
Agent string `json:"agent,omitempty"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON also reads the pre-users form, a bare expiry time: such a session has no
|
||||
// user yet; the server gives it to the migrated first account.
|
||||
func (s *Session) UnmarshalJSON(b []byte) error {
|
||||
if len(b) > 0 && b[0] == '"' {
|
||||
return json.Unmarshal(b, &s.Expires)
|
||||
}
|
||||
type plain Session
|
||||
return json.Unmarshal(b, (*plain)(s))
|
||||
}
|
||||
|
||||
// UserState is what follows an account rather than the machine: how the console looks
|
||||
// to that person and how their dashboard is laid out.
|
||||
type UserState struct {
|
||||
Dashboard json.RawMessage `json:"dashboard,omitempty"` // layout prefs, opaque to the server
|
||||
UI json.RawMessage `json:"ui,omitempty"` // theme, accents; opaque to the server
|
||||
}
|
||||
|
||||
type State struct {
|
||||
Terminals []Terminal `json:"terminals"`
|
||||
Sessions map[string]time.Time `json:"sessions"` // token -> expiry
|
||||
Dashboard json.RawMessage `json:"dashboard,omitempty"` // UI layout prefs, opaque to the server
|
||||
UI json.RawMessage `json:"ui,omitempty"` // theme etc., opaque to the server
|
||||
Alerts json.RawMessage `json:"alerts,omitempty"` // rules, channels and recent events (internal/api/alerts.go)
|
||||
SamplerMs int `json:"sampler_ms,omitempty"` // how often this machine samples; the hub keeps every machine on the console's refresh rate
|
||||
HistorySec int `json:"history_sec,omitempty"` // how far back the graphs reach; the hub keeps every machine on the same one
|
||||
Terminals []Terminal `json:"terminals"`
|
||||
Sessions map[string]Session `json:"sessions"` // token -> session
|
||||
Users map[string]*UserState `json:"users,omitempty"`
|
||||
// Dashboard and UI are the pre-users machine-wide prefs; on first boot with users they
|
||||
// move to the first account. Kept so an old state file still reads.
|
||||
Dashboard json.RawMessage `json:"dashboard,omitempty"`
|
||||
UI json.RawMessage `json:"ui,omitempty"`
|
||||
Alerts json.RawMessage `json:"alerts,omitempty"` // rules, channels and recent events (internal/api/alerts.go)
|
||||
SamplerMs int `json:"sampler_ms,omitempty"` // how often this machine samples; the hub keeps every machine on the console's refresh rate
|
||||
HistorySec int `json:"history_sec,omitempty"` // how far back the graphs reach; the hub keeps every machine on the same one
|
||||
}
|
||||
|
||||
// UserState returns the prefs of an account, making an empty one if needed.
|
||||
func (st *State) UserState(name string) *UserState {
|
||||
if st.Users == nil {
|
||||
st.Users = map[string]*UserState{}
|
||||
}
|
||||
u := st.Users[name]
|
||||
if u == nil {
|
||||
u = &UserState{}
|
||||
st.Users[name] = u
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
type Store struct {
|
||||
@@ -48,7 +93,7 @@ func Open(path string) (*Store, error) {
|
||||
}
|
||||
}
|
||||
if s.state.Sessions == nil {
|
||||
s.state.Sessions = map[string]time.Time{}
|
||||
s.state.Sessions = map[string]Session{}
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user