0.2.40
This commit is contained in:
@@ -17,13 +17,13 @@ import (
|
||||
const (
|
||||
installerCookieName = "memby_installer"
|
||||
installerSessionTTL = 30 * time.Minute
|
||||
adminSessionTTL = 12 * time.Hour
|
||||
installerDeviceID = "memby-web-installer"
|
||||
installerDeviceName = "Memby Web Installer"
|
||||
|
||||
// installerRenewWithin is how close to expiry a session must be before an operator's
|
||||
// own request re-issues it. Half the TTL, so a cookie is rewritten at most once every
|
||||
// fifteen minutes rather than on every request of a working session.
|
||||
installerRenewWithin = installerSessionTTL / 2
|
||||
// adminRenewWithin is how close to expiry a session must be before an operator's own
|
||||
// request re-issues it. Half the TTL avoids rewriting the cookie on every request.
|
||||
adminRenewWithin = adminSessionTTL / 2
|
||||
)
|
||||
|
||||
func (s *Server) installerSecret() []byte {
|
||||
@@ -45,8 +45,12 @@ func (s *Server) signInstallerValue(purpose string, payload []byte) []byte {
|
||||
}
|
||||
|
||||
func (s *Server) newInstallerSession() (string, error) {
|
||||
return s.newBrowserSession(installerSessionTTL)
|
||||
}
|
||||
|
||||
func (s *Server) newBrowserSession(ttl time.Duration) (string, error) {
|
||||
payload := make([]byte, 8+16)
|
||||
binary.BigEndian.PutUint64(payload[:8], uint64(time.Now().Add(installerSessionTTL).Unix()))
|
||||
binary.BigEndian.PutUint64(payload[:8], uint64(time.Now().Add(ttl).Unix()))
|
||||
if _, err := rand.Read(payload[8:]); err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -79,7 +83,7 @@ func (s *Server) installerSessionExpiry(r *http.Request) (time.Time, bool) {
|
||||
}
|
||||
expires := int64(binary.BigEndian.Uint64(payload[:8]))
|
||||
now := time.Now().Unix()
|
||||
if expires <= now || expires > now+int64(installerSessionTTL/time.Second)+60 {
|
||||
if expires <= now || expires > now+int64(adminSessionTTL/time.Second)+60 {
|
||||
return time.Time{}, false
|
||||
}
|
||||
return time.Unix(expires, 0), true
|
||||
@@ -90,31 +94,35 @@ func (s *Server) validInstallerSession(r *http.Request) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
// renewInstallerSession slides a valid session's expiry forward. The TTL was absolute and
|
||||
// renewAdminSession slides a valid session's expiry forward. The TTL was absolute and
|
||||
// nothing extended it, so an operator working the admin console was signed out from under
|
||||
// themselves after thirty minutes and the page's poll became a permanent "invalid admin
|
||||
// themselves and the page's poll became a permanent "invalid admin
|
||||
// token" banner with no sign-in to return to. Callers must only reach here for a request
|
||||
// an operator actually made — see operatorPresent — or an abandoned tab's own polling
|
||||
// would keep the session alive indefinitely, which is what the TTL exists to stop.
|
||||
func (s *Server) renewInstallerSession(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Server) renewAdminSession(w http.ResponseWriter, r *http.Request) {
|
||||
expires, ok := s.installerSessionExpiry(r)
|
||||
if !ok || time.Until(expires) > installerRenewWithin {
|
||||
if !ok || time.Until(expires) > adminRenewWithin {
|
||||
return
|
||||
}
|
||||
session, err := s.newInstallerSession()
|
||||
session, err := s.newBrowserSession(adminSessionTTL)
|
||||
if err != nil {
|
||||
s.loggerFor(r.Context()).Error("installer session renewal failed", "error", err)
|
||||
return
|
||||
}
|
||||
s.setInstallerCookie(w, session)
|
||||
s.setBrowserSessionCookie(w, session, adminSessionTTL)
|
||||
}
|
||||
|
||||
func (s *Server) setInstallerCookie(w http.ResponseWriter, value string) {
|
||||
s.setBrowserSessionCookie(w, value, installerSessionTTL)
|
||||
}
|
||||
|
||||
func (s *Server) setBrowserSessionCookie(w http.ResponseWriter, value string, ttl time.Duration) {
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: installerCookieName,
|
||||
Value: value,
|
||||
Path: "/",
|
||||
MaxAge: int(installerSessionTTL / time.Second),
|
||||
MaxAge: int(ttl / time.Second),
|
||||
HttpOnly: true,
|
||||
Secure: true,
|
||||
SameSite: http.SameSiteStrictMode,
|
||||
@@ -210,13 +218,17 @@ func (s *Server) handleInstallLogin(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
session, err := s.newInstallerSession()
|
||||
ttl := installerSessionTTL
|
||||
if strings.HasPrefix(next, "/admin/") {
|
||||
ttl = adminSessionTTL
|
||||
}
|
||||
session, err := s.newBrowserSession(ttl)
|
||||
if err != nil {
|
||||
s.loggerFor(r.Context()).Error("installer session generation failed", "error", err)
|
||||
writeError(w, http.StatusInternalServerError, "could not start installer session")
|
||||
return
|
||||
}
|
||||
s.setInstallerCookie(w, session)
|
||||
s.setBrowserSessionCookie(w, session, ttl)
|
||||
http.Redirect(w, r, next, http.StatusSeeOther)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user