diff options
Diffstat (limited to 'middleware')
-rw-r--r-- | middleware/app_session.go | 29 | ||||
-rw-r--r-- | middleware/basic_auth.go | 14 | ||||
-rw-r--r-- | middleware/common_headers.go | 25 | ||||
-rw-r--r-- | middleware/fever.go | 12 | ||||
-rw-r--r-- | middleware/logging.go | 1 | ||||
-rw-r--r-- | middleware/user_session.go | 15 |
6 files changed, 61 insertions, 35 deletions
diff --git a/middleware/app_session.go b/middleware/app_session.go index 525cd661..e898ee34 100644 --- a/middleware/app_session.go +++ b/middleware/app_session.go @@ -6,9 +6,12 @@ package middleware import ( "context" + "errors" "net/http" "github.com/miniflux/miniflux/http/cookie" + "github.com/miniflux/miniflux/http/request" + "github.com/miniflux/miniflux/http/response/html" "github.com/miniflux/miniflux/logger" "github.com/miniflux/miniflux/model" ) @@ -17,20 +20,21 @@ import ( func (m *Middleware) AppSession(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var err error - session := m.getSessionValueFromCookie(r) + session := m.getAppSessionValueFromCookie(r) if session == nil { - logger.Debug("[Middleware:Session] Session not found") + logger.Debug("[Middleware:AppSession] Session not found") + session, err = m.store.CreateSession() if err != nil { - logger.Error("[Middleware:Session] %v", err) - http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + logger.Error("[Middleware:AppSession] %v", err) + html.ServerError(w, err) return } http.SetCookie(w, cookie.New(cookie.CookieSessionID, session.ID, m.cfg.IsHTTPS, m.cfg.BasePath())) } else { - logger.Debug("[Middleware:Session] %s", session) + logger.Debug("[Middleware:AppSession] %s", session) } if r.Method == "POST" { @@ -38,9 +42,8 @@ func (m *Middleware) AppSession(next http.Handler) http.Handler { headerValue := r.Header.Get("X-Csrf-Token") if session.Data.CSRF != formValue && session.Data.CSRF != headerValue { - logger.Error(`[Middleware:Session] Invalid or missing CSRF token: Form="%s", Header="%s"`, formValue, headerValue) - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("Invalid or missing CSRF session!")) + logger.Error(`[Middleware:AppSession] Invalid or missing CSRF token: Form="%s", Header="%s"`, formValue, headerValue) + html.BadRequest(w, errors.New("invalid or missing CSRF")) return } } @@ -56,15 +59,15 @@ func (m *Middleware) AppSession(next http.Handler) http.Handler { }) } -func (m *Middleware) getSessionValueFromCookie(r *http.Request) *model.Session { - sessionCookie, err := r.Cookie(cookie.CookieSessionID) - if err == http.ErrNoCookie { +func (m *Middleware) getAppSessionValueFromCookie(r *http.Request) *model.Session { + cookieValue := request.Cookie(r, cookie.CookieSessionID) + if cookieValue == "" { return nil } - session, err := m.store.Session(sessionCookie.Value) + session, err := m.store.Session(cookieValue) if err != nil { - logger.Error("[Middleware:Session] %v", err) + logger.Error("[Middleware:AppSession] %v", err) return nil } diff --git a/middleware/basic_auth.go b/middleware/basic_auth.go index 9d7a4b2d..edea3338 100644 --- a/middleware/basic_auth.go +++ b/middleware/basic_auth.go @@ -8,6 +8,7 @@ import ( "context" "net/http" + "github.com/miniflux/miniflux/http/response/json" "github.com/miniflux/miniflux/logger" ) @@ -15,35 +16,30 @@ import ( func (m *Middleware) BasicAuth(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`) - errorResponse := `{"error_message": "Not Authorized"}` username, password, authOK := r.BasicAuth() if !authOK { logger.Debug("[Middleware:BasicAuth] No authentication headers sent") - w.WriteHeader(http.StatusUnauthorized) - w.Write([]byte(errorResponse)) + json.Unauthorized(w) return } if err := m.store.CheckPassword(username, password); err != nil { logger.Info("[Middleware:BasicAuth] Invalid username or password: %s", username) - w.WriteHeader(http.StatusUnauthorized) - w.Write([]byte(errorResponse)) + json.Unauthorized(w) return } user, err := m.store.UserByUsername(username) if err != nil { logger.Error("[Middleware:BasicAuth] %v", err) - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(errorResponse)) + json.ServerError(w, err) return } if user == nil { logger.Info("[Middleware:BasicAuth] User not found: %s", username) - w.WriteHeader(http.StatusUnauthorized) - w.Write([]byte(errorResponse)) + json.Unauthorized(w) return } diff --git a/middleware/common_headers.go b/middleware/common_headers.go new file mode 100644 index 00000000..bdec580c --- /dev/null +++ b/middleware/common_headers.go @@ -0,0 +1,25 @@ +// Copyright 2018 Frédéric Guillot. All rights reserved. +// Use of this source code is governed by the Apache 2.0 +// license that can be found in the LICENSE file. + +package middleware + +import ( + "net/http" +) + +// CommonHeaders sends common HTTP headers. +func (m *Middleware) CommonHeaders(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-XSS-Protection", "1; mode=block") + w.Header().Set("X-Content-Type-Options", "nosniff") + w.Header().Set("X-Frame-Options", "DENY") + w.Header().Set("Content-Security-Policy", "default-src 'self'; img-src *; media-src *; frame-src *; child-src *") + + if m.cfg.IsHTTPS && m.cfg.HasHSTS() { + w.Header().Set("Strict-Transport-Security", "max-age=31536000") + } + + next.ServeHTTP(w, r) + }) +} diff --git a/middleware/fever.go b/middleware/fever.go index c9765fe5..78217e4a 100644 --- a/middleware/fever.go +++ b/middleware/fever.go @@ -8,27 +8,25 @@ import ( "context" "net/http" + "github.com/miniflux/miniflux/http/response/json" "github.com/miniflux/miniflux/logger" ) // FeverAuth handles Fever API authentication. func (m *Middleware) FeverAuth(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - logger.Debug("[Middleware:Fever]") - apiKey := r.FormValue("api_key") + user, err := m.store.UserByFeverToken(apiKey) if err != nil { - logger.Error("[Fever] %v", err) - w.Header().Set("Content-Type", "application/json") - w.Write([]byte(`{"api_version": 3, "auth": 0}`)) + logger.Error("[Middleware:Fever] %v", err) + json.OK(w, map[string]int{"api_version": 3, "auth": 0}) return } if user == nil { logger.Info("[Middleware:Fever] Fever authentication failure") - w.Header().Set("Content-Type", "application/json") - w.Write([]byte(`{"api_version": 3, "auth": 0}`)) + json.OK(w, map[string]int{"api_version": 3, "auth": 0}) return } diff --git a/middleware/logging.go b/middleware/logging.go index 6fc506a3..a6c141b5 100644 --- a/middleware/logging.go +++ b/middleware/logging.go @@ -8,6 +8,7 @@ import ( "net/http" "github.com/miniflux/miniflux/logger" + "github.com/tomasen/realip" ) diff --git a/middleware/user_session.go b/middleware/user_session.go index 2cb9f8a9..b27858fc 100644 --- a/middleware/user_session.go +++ b/middleware/user_session.go @@ -9,6 +9,8 @@ import ( "net/http" "github.com/miniflux/miniflux/http/cookie" + "github.com/miniflux/miniflux/http/request" + "github.com/miniflux/miniflux/http/response" "github.com/miniflux/miniflux/http/route" "github.com/miniflux/miniflux/logger" "github.com/miniflux/miniflux/model" @@ -19,17 +21,18 @@ import ( // UserSession handles the user session middleware. func (m *Middleware) UserSession(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - session := m.getSessionFromCookie(r) + session := m.getUserSessionFromCookie(r) if session == nil { logger.Debug("[Middleware:UserSession] Session not found") if m.isPublicRoute(r) { next.ServeHTTP(w, r) } else { - http.Redirect(w, r, route.Path(m.router, "login"), http.StatusFound) + response.Redirect(w, r, route.Path(m.router, "login")) } } else { logger.Debug("[Middleware:UserSession] %s", session) + ctx := r.Context() ctx = context.WithValue(ctx, UserIDContextKey, session.UserID) ctx = context.WithValue(ctx, IsAuthenticatedContextKey, true) @@ -58,13 +61,13 @@ func (m *Middleware) isPublicRoute(r *http.Request) bool { } } -func (m *Middleware) getSessionFromCookie(r *http.Request) *model.UserSession { - sessionCookie, err := r.Cookie(cookie.CookieUserSessionID) - if err == http.ErrNoCookie { +func (m *Middleware) getUserSessionFromCookie(r *http.Request) *model.UserSession { + cookieValue := request.Cookie(r, cookie.CookieUserSessionID) + if cookieValue == "" { return nil } - session, err := m.store.UserSessionByToken(sessionCookie.Value) + session, err := m.store.UserSessionByToken(cookieValue) if err != nil { logger.Error("[Middleware:UserSession] %v", err) return nil |