From 7897d8a8ad87c0bb26bb8156ba09fc9fab62f565 Mon Sep 17 00:00:00 2001 From: Frédéric Guillot Date: Mon, 21 Jan 2019 20:21:05 -0800 Subject: Handle the case when application session is expired and not user session --- model/app_session.go | 2 +- storage/session.go | 48 ++++++++++++++++++++++++++++++++++++------------ ui/middleware.go | 23 ++++++++++++++++------- ui/session/session.go | 16 ++++++++-------- ui/ui.go | 2 +- 5 files changed, 62 insertions(+), 29 deletions(-) diff --git a/model/app_session.go b/model/app_session.go index 6a1f6ff..ad4db3b 100644 --- a/model/app_session.go +++ b/model/app_session.go @@ -18,7 +18,7 @@ type SessionData struct { FlashMessage string `json:"flash_message"` FlashErrorMessage string `json:"flash_error_message"` Language string `json:"language"` - Theme string `json:"Theme"` + Theme string `json:"theme"` PocketRequestToken string `json:"pocket_request_token"` } diff --git a/storage/session.go b/storage/session.go index 4139684..8c1f615 100644 --- a/storage/session.go +++ b/storage/session.go @@ -12,24 +12,48 @@ import ( "miniflux.app/model" ) -// CreateSession creates a new session. -func (s *Storage) CreateSession() (*model.Session, error) { +// CreateAppSessionWithUserPrefs creates a new application session with the given user preferences. +func (s *Storage) CreateAppSessionWithUserPrefs(userID int64) (*model.Session, error) { + user, err := s.UserByID(userID) + if err != nil { + return nil, err + } + session := model.Session{ - ID: crypto.GenerateRandomString(32), - Data: &model.SessionData{CSRF: crypto.GenerateRandomString(64)}, + ID: crypto.GenerateRandomString(32), + Data: &model.SessionData{ + CSRF: crypto.GenerateRandomString(64), + Theme: user.Theme, + Language: user.Language, + }, } - query := "INSERT INTO sessions (id, data) VALUES ($1, $2)" - _, err := s.db.Exec(query, session.ID, session.Data) + return s.createAppSession(&session) +} + +// CreateAppSession creates a new application session. +func (s *Storage) CreateAppSession() (*model.Session, error) { + session := model.Session{ + ID: crypto.GenerateRandomString(32), + Data: &model.SessionData{ + CSRF: crypto.GenerateRandomString(64), + }, + } + + return s.createAppSession(&session) +} + +func (s *Storage) createAppSession(session *model.Session) (*model.Session, error) { + _, err := s.db.Exec(`INSERT INTO sessions (id, data) VALUES ($1, $2)`, session.ID, session.Data) if err != nil { - return nil, fmt.Errorf("unable to create session: %v", err) + return nil, fmt.Errorf("unable to create app session: %v", err) } - return &session, nil + return session, nil } -// UpdateSessionField updates only one session field. -func (s *Storage) UpdateSessionField(sessionID, field string, value interface{}) error { +// UpdateAppSessionField updates only one session field. +func (s *Storage) UpdateAppSessionField(sessionID, field string, value interface{}) error { query := `UPDATE sessions SET data = jsonb_set(data, '{%s}', to_jsonb($1::text), true) WHERE id=$2` @@ -42,8 +66,8 @@ func (s *Storage) UpdateSessionField(sessionID, field string, value interface{}) return nil } -// Session returns the given session. -func (s *Storage) Session(id string) (*model.Session, error) { +// AppSession returns the given session. +func (s *Storage) AppSession(id string) (*model.Session, error) { var session model.Session query := "SELECT id, data FROM sessions WHERE id=$1" diff --git a/ui/middleware.go b/ui/middleware.go index 237432a..81fb3a5 100644 --- a/ui/middleware.go +++ b/ui/middleware.go @@ -61,12 +61,21 @@ func (m *middleware) handleAppSession(next http.Handler) http.Handler { session := m.getAppSessionValueFromCookie(r) if session == nil { - logger.Debug("[UI:AppSession] Session not found") - - session, err = m.store.CreateSession() - if err != nil { - html.ServerError(w, r, err) - return + if (request.IsAuthenticated(r)) { + userID := request.UserID(r) + logger.Debug("[UI:AppSession] Cookie expired but user #%d is logged: creating a new session", userID) + session, err = m.store.CreateAppSessionWithUserPrefs(userID) + if err != nil { + html.ServerError(w, r, err) + return + } + } else { + logger.Debug("[UI:AppSession] Session not found, creating a new one") + session, err = m.store.CreateAppSession() + if err != nil { + html.ServerError(w, r, err) + return + } } http.SetCookie(w, cookie.New(cookie.CookieSessionID, session.ID, m.cfg.IsHTTPS, m.cfg.BasePath())) @@ -104,7 +113,7 @@ func (m *middleware) getAppSessionValueFromCookie(r *http.Request) *model.Sessio return nil } - session, err := m.store.Session(cookieValue) + session, err := m.store.AppSession(cookieValue) if err != nil { logger.Error("[UI:AppSession] %v", err) return nil diff --git a/ui/session/session.go b/ui/session/session.go index 2351866..0874f92 100644 --- a/ui/session/session.go +++ b/ui/session/session.go @@ -18,49 +18,49 @@ type Session struct { // NewOAuth2State generates a new OAuth2 state and stores the value into the database. func (s *Session) NewOAuth2State() string { state := crypto.GenerateRandomString(32) - s.store.UpdateSessionField(s.sessionID, "oauth2_state", state) + s.store.UpdateAppSessionField(s.sessionID, "oauth2_state", state) return state } // NewFlashMessage creates a new flash message. func (s *Session) NewFlashMessage(message string) { - s.store.UpdateSessionField(s.sessionID, "flash_message", message) + s.store.UpdateAppSessionField(s.sessionID, "flash_message", message) } // FlashMessage returns the current flash message if any. func (s *Session) FlashMessage(message string) string { if message != "" { - s.store.UpdateSessionField(s.sessionID, "flash_message", "") + s.store.UpdateAppSessionField(s.sessionID, "flash_message", "") } return message } // NewFlashErrorMessage creates a new flash error message. func (s *Session) NewFlashErrorMessage(message string) { - s.store.UpdateSessionField(s.sessionID, "flash_error_message", message) + s.store.UpdateAppSessionField(s.sessionID, "flash_error_message", message) } // FlashErrorMessage returns the last flash error message if any. func (s *Session) FlashErrorMessage(message string) string { if message != "" { - s.store.UpdateSessionField(s.sessionID, "flash_error_message", "") + s.store.UpdateAppSessionField(s.sessionID, "flash_error_message", "") } return message } // SetLanguage updates the language field in session. func (s *Session) SetLanguage(language string) { - s.store.UpdateSessionField(s.sessionID, "language", language) + s.store.UpdateAppSessionField(s.sessionID, "language", language) } // SetTheme updates the theme field in session. func (s *Session) SetTheme(theme string) { - s.store.UpdateSessionField(s.sessionID, "theme", theme) + s.store.UpdateAppSessionField(s.sessionID, "theme", theme) } // SetPocketRequestToken updates Pocket Request Token. func (s *Session) SetPocketRequestToken(requestToken string) { - s.store.UpdateSessionField(s.sessionID, "pocket_request_token", requestToken) + s.store.UpdateAppSessionField(s.sessionID, "pocket_request_token", requestToken) } // New returns a new session handler. diff --git a/ui/ui.go b/ui/ui.go index 91d4783..71bbe69 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -22,8 +22,8 @@ func Serve(router *mux.Router, cfg *config.Config, store *storage.Storage, pool handler := &handler{router, cfg, store, template.NewEngine(cfg, router), pool, feedHandler} uiRouter := router.NewRoute().Subrouter() - uiRouter.Use(middleware.handleAppSession) uiRouter.Use(middleware.handleUserSession) + uiRouter.Use(middleware.handleAppSession) // Static assets. uiRouter.HandleFunc("/stylesheets/{name}.css", handler.showStylesheet).Name("stylesheet").Methods("GET") -- cgit v1.2.3