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
gates / gates (push) Successful in 44s
This commit is contained in:
@@ -53,10 +53,11 @@ const (
|
||||
)
|
||||
|
||||
type gateState struct {
|
||||
once sync.Once
|
||||
key []byte
|
||||
mu sync.Mutex
|
||||
used map[string]time.Time // token nonces already swapped, until they expire
|
||||
once sync.Once
|
||||
keyMu sync.RWMutex // guards key: rotateGateKey replaces it while requests read it
|
||||
key []byte
|
||||
mu sync.Mutex
|
||||
used map[string]time.Time // token nonces already swapped, until they expire
|
||||
}
|
||||
|
||||
// gateKey loads the gate's HMAC key from the data dir, or makes one. No data dir → a key for this run only.
|
||||
@@ -82,9 +83,41 @@ func (s *Server) gateKey() []byte {
|
||||
}
|
||||
}
|
||||
})
|
||||
s.gate.keyMu.RLock()
|
||||
defer s.gate.keyMu.RUnlock()
|
||||
return s.gate.key
|
||||
}
|
||||
|
||||
// rotateGateKey replaces the gate's key (R-976, v0.324.0). Every cookie and token the key signed stops opening
|
||||
// anything at once: each setup-gate pass, each family app cookie, each sign-in token in flight. The household's
|
||||
// browser passes again through its dashboard session. The new key is saved tmp+rename; when that fails the old file
|
||||
// is REMOVED, so a restart makes a fresh key rather than bringing the old one — and every cookie it signed — back.
|
||||
func (s *Server) rotateGateKey() {
|
||||
s.gateKey()
|
||||
k := make([]byte, 32)
|
||||
_, _ = rand.Read(k)
|
||||
s.gate.keyMu.Lock()
|
||||
s.gate.key = k
|
||||
s.gate.keyMu.Unlock()
|
||||
if s.cfg == nil || s.cfg.Paths.DataDir == "" {
|
||||
return
|
||||
}
|
||||
p := filepath.Join(s.cfg.Paths.DataDir, "setup-gate.key")
|
||||
tmp := p + ".tmp"
|
||||
err := os.WriteFile(tmp, []byte(hex.EncodeToString(k)), 0o600)
|
||||
if err == nil {
|
||||
err = os.Rename(tmp, p)
|
||||
}
|
||||
if err != nil {
|
||||
_ = os.Remove(tmp)
|
||||
if rerr := os.Remove(p); rerr != nil && !os.IsNotExist(rerr) {
|
||||
s.logger.Printf("[ERROR] [web] gate key: the new key could not be saved (%v) and the old one could not be removed (%v) — a restart would accept passes signed before the password change", err, rerr)
|
||||
return
|
||||
}
|
||||
s.logger.Printf("[WARN] [web] gate key: the new key could not be saved (%v) — the old one was removed, so a restart makes a fresh key", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) gateMAC(parts ...string) string {
|
||||
m := hmac.New(sha256.New, s.gateKey())
|
||||
m.Write([]byte(strings.Join(parts, "\x00")))
|
||||
|
||||
Reference in New Issue
Block a user