auth, docs: a session from a longer window is cut; the remaining nits (audit A6, A7, A10, W7)
Security audit 2026-10-17, stage 6. A10: a session created under a longer PANEL_SESSION_IDLE_DAYS kept its old expiry after the setting was lowered (the renewal arithmetic took ExpiresAt minus the new window for the last renewal). Touch now cuts such a session to now plus the window at once. TestSessionMadeUnderALongerWindowIsCut. A6, A7, W7 - security.md now says what the code does, which is what it should do: a wrong method answers 405 with Allow from the router before the role is looked at (the routes are public source); the setup token is made anew at the first /setup/ request after expiry, a stranger's included, and logged where only the operator reads it; two GETs make what must exist, the server's own DKIM key on Settings and Health. README's local trial says the compose file is the hardened deployment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -98,8 +98,19 @@ func (s *sessionStore) Touch(token string) bool {
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
lastRenewal := row.ExpiresAt.Add(-s.idle)
|
||||
now := time.Now()
|
||||
// A session made under a longer PANEL_SESSION_IDLE_DAYS expires later
|
||||
// than today's window allows: it is cut to the window at once, rather
|
||||
// than keep the old expiry until it passes (security audit 2026-10-17,
|
||||
// A10).
|
||||
if row.ExpiresAt.After(now.Add(s.idle)) {
|
||||
if err := s.store.RenewSession(hash, now.Add(s.idle)); err != nil {
|
||||
logf("panel: session: shorten failed: %v", err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
lastRenewal := row.ExpiresAt.Add(-s.idle)
|
||||
if now.Sub(lastRenewal) < renewThreshold {
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user