v0.324.0: the database password comes back with the data (R-1106, R-127b, R-926); restic 0.19.1 (R-1107); R-1108, R-1065, R-1017; dashboard hardening (R-983, R-976)
gates / gates (push) Successful in 44s

This commit is contained in:
2026-10-16 22:46:00 +02:00
parent 00a0d91976
commit f75b3aa778
212 changed files with 2414 additions and 398 deletions
+47 -2
View File
@@ -1,8 +1,9 @@
// Package family is the household's family list for the permanent family gate (`09` §3 decisions 63, 64; R-780).
//
// Each family member has their OWN name and password (never the dashboard's); the household's dashboard admin adds,
// resets and removes them. A member who signs in gets a SESSION (30 days). Every app cookie the gate mints names the
// session, so the gate asks this store on every request: a removed member, a reset password (the member's generation
// resets and removes them. A member who signs in gets a SESSION (30 days). Every app cookie the gate mints carries a
// token derived from the session for that app (never the session id itself, R-976), so the gate asks this store on
// every request (Find): a removed member, a reset password (the member's generation
// moves on) or a logout (the session is deleted) ends every app's access at the next request.
//
// A session with Member "" is the HOUSEHOLD's: minted when the dashboard's own session vouched for the browser (the
@@ -312,6 +313,50 @@ func (s *Store) Valid(id string) (Session, bool) {
return se, true
}
// Find returns the first session that match accepts and that still holds (the same test as Valid). It lets a caller
// look a session up by something DERIVED from its id — the per-app token the family gate puts in an app's cookie
// (R-976) — without that id ever leaving the dashboard host.
func (s *Store) Find(match func(id string) bool) (Session, bool) {
if s == nil || match == nil {
return Session{}, false
}
s.mu.Lock()
var found string
for id := range s.sessions {
if match(id) {
found = id
break
}
}
s.mu.Unlock()
if found == "" {
return Session{}, false
}
return s.Valid(found)
}
// EndAll deletes every session — every member's and the household's — and keeps the members (R-976: a dashboard
// password change or reset ends every way into the family apps; members sign in again with their own passwords).
// It returns how many sessions it ended.
func (s *Store) EndAll() (int, error) {
if s == nil {
return 0, nil
}
s.mu.Lock()
defer s.mu.Unlock()
n := len(s.sessions)
if n == 0 {
return 0, nil
}
// Ended in memory even when the save fails: an ending is never undone because a disk write failed (the caller
// logs the error; the sessions stay ended until a restart would read the old file back).
s.sessions = map[string]Session{}
if err := s.saveLocked(); err != nil {
return n, err
}
return n, nil
}
// EndSession deletes a session (logout). Unknown ids are not an error.
func (s *Store) EndSession(id string) error {
if s == nil {