diff --git a/config/users.go b/config/users.go index f9f7d80..0d5e2dc 100644 --- a/config/users.go +++ b/config/users.go @@ -43,6 +43,7 @@ type User struct { Name string Salt []byte Password []byte + SessionKey []byte Permissions Permission } @@ -82,6 +83,7 @@ func (a *UserManager) load() error { return err } + dirty := false hasAdmin := false for i := range settings.Users { u := settings.Users[i] @@ -89,6 +91,18 @@ func (a *UserManager) load() error { if u.Has(PermissionAdmin) { hasAdmin = true } + if u.SessionKey == nil { + key, err := a.randomBytes() + if err != nil { + return err + } + u.SessionKey = key + dirty = true + } + } + + if dirty { + _ = a.save("System", "Migration: adding session keys") } if len(a.users) > 0 && !hasAdmin { @@ -212,7 +226,7 @@ func (a *UserManager) canRemoveAdmin(user *User) bool { return false } -func (a *UserManager) generateSalt() ([]byte, error) { +func (a *UserManager) randomBytes() ([]byte, error) { res := make([]byte, 16) n, err := rand.Read(res) @@ -224,7 +238,7 @@ func (a *UserManager) generateSalt() ([]byte, error) { } func (a *UserManager) setPassword(u *User, password string) error { - salt, err := a.generateSalt() + salt, err := a.randomBytes() if err != nil { return err } @@ -235,7 +249,13 @@ func (a *UserManager) setPassword(u *User, password string) error { return err } + key, err := a.randomBytes() + if err != nil { + return err + } + u.Salt = salt u.Password = hash + u.SessionKey = key return nil } diff --git a/handlers_session.go b/handlers_session.go index ab05f5d..4fd69a7 100644 --- a/handlers_session.go +++ b/handlers_session.go @@ -2,6 +2,7 @@ package main import ( "context" + "fmt" "log" "net/http" @@ -10,15 +11,18 @@ import ( ) const ( - sessionName = "wiki" - sessionUserKey = "user" - sessionNoticeKey = "notice" - sessionErrorKey = "error" + sessionName = "wiki" + sessionUserKey = "user" + sessionSessionKey = "session" + sessionNoticeKey = "notice" + sessionErrorKey = "error" contextUserKey = "user" contextErrorKey = "error" contextNoticeKey = "notice" contextSessionKey = "session" + + sessionKeyFormat = "wiki:%x" ) type UserProvider interface { @@ -33,7 +37,9 @@ func SessionHandler(up UserProvider, store sessions.Store) func(http.Handler) ht if username, ok := s.Values[sessionUserKey]; ok { user := up.User(username.(string)) if user != nil { - request = request.WithContext(context.WithValue(request.Context(), contextUserKey, user)) + if key := s.Values[sessionSessionKey]; fmt.Sprintf(sessionKeyFormat, user.SessionKey) == key { + request = request.WithContext(context.WithValue(request.Context(), contextUserKey, user)) + } } } diff --git a/handlers_user.go b/handlers_user.go index 7b87568..db774b9 100644 --- a/handlers_user.go +++ b/handlers_user.go @@ -57,6 +57,7 @@ func LoginHandler(auth Authenticator) http.HandlerFunc { putSessionKey(writer, request, sessionErrorKey, fmt.Sprintf("Failed to login: %v", err)) } else { putSessionKey(writer, request, sessionUserKey, user.Name) + putSessionKey(writer, request, sessionSessionKey, fmt.Sprintf(sessionKeyFormat, user.SessionKey)) } writer.Header().Set("location", redirect) writer.WriteHeader(http.StatusSeeOther) @@ -199,6 +200,7 @@ func ModifyAccountHandler(pu PasswordUpdater) http.HandlerFunc { putSessionKey(writer, request, sessionErrorKey, fmt.Sprintf("Unable to set password: %v", err)) } else { putSessionKey(writer, request, sessionNoticeKey, "Your password has been updated") + putSessionKey(writer, request, sessionSessionKey, fmt.Sprintf(sessionKeyFormat, user.SessionKey)) } } else { writer.WriteHeader(http.StatusBadRequest)