aboutsummaryrefslogtreecommitdiffhomepage
path: root/http
diff options
context:
space:
mode:
authorGravatar Frédéric Guillot <fred@miniflux.net>2018-04-27 20:38:46 -0700
committerGravatar Frédéric Guillot <fred@miniflux.net>2018-04-27 20:38:46 -0700
commit6b360d08c1f6c8a6cd1b7608f7af734a3ceef8d7 (patch)
tree48352d35fa9f3559df05accf4ce4fce1672a2830 /http
parent322b265d7aec7731f7fa703c9a74ceb61ae73f3f (diff)
Use Gorilla middleware (refactoring)
Diffstat (limited to 'http')
-rw-r--r--http/handler/context.go2
-rw-r--r--http/handler/handler.go14
-rw-r--r--http/middleware/basic_auth.go72
-rw-r--r--http/middleware/context_keys.go49
-rw-r--r--http/middleware/fever.go57
-rw-r--r--http/middleware/middleware.go36
-rw-r--r--http/middleware/session.go85
-rw-r--r--http/middleware/user_session.go86
8 files changed, 5 insertions, 396 deletions
diff --git a/http/handler/context.go b/http/handler/context.go
index 35eb1ea..119a4d5 100644
--- a/http/handler/context.go
+++ b/http/handler/context.go
@@ -8,10 +8,10 @@ import (
"net/http"
"github.com/miniflux/miniflux/crypto"
- "github.com/miniflux/miniflux/http/middleware"
"github.com/miniflux/miniflux/http/route"
"github.com/miniflux/miniflux/locale"
"github.com/miniflux/miniflux/logger"
+ "github.com/miniflux/miniflux/middleware"
"github.com/miniflux/miniflux/model"
"github.com/miniflux/miniflux/storage"
diff --git a/http/handler/handler.go b/http/handler/handler.go
index d698b2e..b88a885 100644
--- a/http/handler/handler.go
+++ b/http/handler/handler.go
@@ -9,35 +9,30 @@ import (
"time"
"github.com/miniflux/miniflux/config"
- "github.com/miniflux/miniflux/http/middleware"
"github.com/miniflux/miniflux/locale"
- "github.com/miniflux/miniflux/logger"
"github.com/miniflux/miniflux/storage"
"github.com/miniflux/miniflux/template"
"github.com/miniflux/miniflux/timer"
"github.com/gorilla/mux"
- "github.com/tomasen/realip"
)
// ControllerFunc is an application HTTP handler.
type ControllerFunc func(ctx *Context, request *Request, response *Response)
-// Handler manages HTTP handlers and middlewares.
+// Handler manages HTTP handlers.
type Handler struct {
cfg *config.Config
store *storage.Storage
translator *locale.Translator
template *template.Engine
router *mux.Router
- middleware *middleware.Chain
}
// Use is a wrapper around an HTTP handler.
func (h *Handler) Use(f ControllerFunc) http.Handler {
- return h.middleware.WrapFunc(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer timer.ExecutionTime(time.Now(), r.URL.Path)
- logger.Debug("[HTTP] %s %s %s", realip.RealIP(r), r.Method, r.URL.Path)
if r.Header.Get("X-Forwarded-Proto") == "https" {
h.cfg.IsHTTPS = true
@@ -55,17 +50,16 @@ func (h *Handler) Use(f ControllerFunc) http.Handler {
}
f(ctx, request, response)
- }))
+ })
}
// NewHandler returns a new Handler.
-func NewHandler(cfg *config.Config, store *storage.Storage, router *mux.Router, template *template.Engine, translator *locale.Translator, middleware *middleware.Chain) *Handler {
+func NewHandler(cfg *config.Config, store *storage.Storage, router *mux.Router, template *template.Engine, translator *locale.Translator) *Handler {
return &Handler{
cfg: cfg,
store: store,
translator: translator,
router: router,
template: template,
- middleware: middleware,
}
}
diff --git a/http/middleware/basic_auth.go b/http/middleware/basic_auth.go
deleted file mode 100644
index 35a9f81..0000000
--- a/http/middleware/basic_auth.go
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2017 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 (
- "context"
- "net/http"
-
- "github.com/miniflux/miniflux/logger"
- "github.com/miniflux/miniflux/storage"
-)
-
-// BasicAuthMiddleware is the middleware for HTTP Basic authentication.
-type BasicAuthMiddleware struct {
- store *storage.Storage
-}
-
-// Handler executes the middleware.
-func (b *BasicAuthMiddleware) Handler(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))
- return
- }
-
- if err := b.store.CheckPassword(username, password); err != nil {
- logger.Info("[Middleware:BasicAuth] Invalid username or password: %s", username)
- w.WriteHeader(http.StatusUnauthorized)
- w.Write([]byte(errorResponse))
- return
- }
-
- user, err := b.store.UserByUsername(username)
- if err != nil {
- logger.Error("[Middleware:BasicAuth] %v", err)
- w.WriteHeader(http.StatusInternalServerError)
- w.Write([]byte(errorResponse))
- return
- }
-
- if user == nil {
- logger.Info("[Middleware:BasicAuth] User not found: %s", username)
- w.WriteHeader(http.StatusUnauthorized)
- w.Write([]byte(errorResponse))
- return
- }
-
- logger.Info("[Middleware:BasicAuth] User authenticated: %s", username)
- b.store.SetLastLogin(user.ID)
-
- ctx := r.Context()
- ctx = context.WithValue(ctx, UserIDContextKey, user.ID)
- ctx = context.WithValue(ctx, UserTimezoneContextKey, user.Timezone)
- ctx = context.WithValue(ctx, IsAdminUserContextKey, user.IsAdmin)
- ctx = context.WithValue(ctx, IsAuthenticatedContextKey, true)
-
- next.ServeHTTP(w, r.WithContext(ctx))
- })
-}
-
-// NewBasicAuthMiddleware returns a new BasicAuthMiddleware.
-func NewBasicAuthMiddleware(s *storage.Storage) *BasicAuthMiddleware {
- return &BasicAuthMiddleware{store: s}
-}
diff --git a/http/middleware/context_keys.go b/http/middleware/context_keys.go
deleted file mode 100644
index 887a90e..0000000
--- a/http/middleware/context_keys.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2017 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
-
-// ContextKey represents a context key.
-type ContextKey struct {
- name string
-}
-
-func (c ContextKey) String() string {
- return c.name
-}
-
-var (
- // UserIDContextKey is the context key used to store the user ID.
- UserIDContextKey = &ContextKey{"UserID"}
-
- // UserTimezoneContextKey is the context key used to store the user timezone.
- UserTimezoneContextKey = &ContextKey{"UserTimezone"}
-
- // IsAdminUserContextKey is the context key used to store the user role.
- IsAdminUserContextKey = &ContextKey{"IsAdminUser"}
-
- // IsAuthenticatedContextKey is the context key used to store the authentication flag.
- IsAuthenticatedContextKey = &ContextKey{"IsAuthenticated"}
-
- // UserSessionTokenContextKey is the context key used to store the user session ID.
- UserSessionTokenContextKey = &ContextKey{"UserSessionToken"}
-
- // UserLanguageContextKey is the context key to store user language.
- UserLanguageContextKey = &ContextKey{"UserLanguageContextKey"}
-
- // SessionIDContextKey is the context key used to store the session ID.
- SessionIDContextKey = &ContextKey{"SessionID"}
-
- // CSRFContextKey is the context key used to store CSRF token.
- CSRFContextKey = &ContextKey{"CSRF"}
-
- // OAuth2StateContextKey is the context key used to store OAuth2 state.
- OAuth2StateContextKey = &ContextKey{"OAuth2State"}
-
- // FlashMessageContextKey is the context key used to store a flash message.
- FlashMessageContextKey = &ContextKey{"FlashMessage"}
-
- // FlashErrorMessageContextKey is the context key used to store a flash error message.
- FlashErrorMessageContextKey = &ContextKey{"FlashErrorMessage"}
-)
diff --git a/http/middleware/fever.go b/http/middleware/fever.go
deleted file mode 100644
index 54eb0ca..0000000
--- a/http/middleware/fever.go
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2017 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 (
- "context"
- "net/http"
-
- "github.com/miniflux/miniflux/logger"
- "github.com/miniflux/miniflux/storage"
-)
-
-// FeverMiddleware is the middleware that handles Fever API.
-type FeverMiddleware struct {
- store *storage.Storage
-}
-
-// Handler executes the middleware.
-func (f *FeverMiddleware) Handler(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 := f.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}`))
- 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}`))
- return
- }
-
- logger.Info("[Middleware:Fever] User #%d is authenticated", user.ID)
- f.store.SetLastLogin(user.ID)
-
- ctx := r.Context()
- ctx = context.WithValue(ctx, UserIDContextKey, user.ID)
- ctx = context.WithValue(ctx, UserTimezoneContextKey, user.Timezone)
- ctx = context.WithValue(ctx, IsAdminUserContextKey, user.IsAdmin)
- ctx = context.WithValue(ctx, IsAuthenticatedContextKey, true)
-
- next.ServeHTTP(w, r.WithContext(ctx))
- })
-}
-
-// NewFeverMiddleware returns a new FeverMiddleware.
-func NewFeverMiddleware(s *storage.Storage) *FeverMiddleware {
- return &FeverMiddleware{store: s}
-}
diff --git a/http/middleware/middleware.go b/http/middleware/middleware.go
deleted file mode 100644
index 9853bc3..0000000
--- a/http/middleware/middleware.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2017 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"
-)
-
-// Middleware represents a HTTP middleware.
-type Middleware func(http.Handler) http.Handler
-
-// Chain handles a list of middlewares.
-type Chain struct {
- middlewares []Middleware
-}
-
-// Wrap adds a HTTP handler into the chain.
-func (m *Chain) Wrap(h http.Handler) http.Handler {
- for i := range m.middlewares {
- h = m.middlewares[len(m.middlewares)-1-i](h)
- }
-
- return h
-}
-
-// WrapFunc adds a HTTP handler function into the chain.
-func (m *Chain) WrapFunc(fn http.HandlerFunc) http.Handler {
- return m.Wrap(fn)
-}
-
-// NewChain returns a new Chain.
-func NewChain(middlewares ...Middleware) *Chain {
- return &Chain{append(([]Middleware)(nil), middlewares...)}
-}
diff --git a/http/middleware/session.go b/http/middleware/session.go
deleted file mode 100644
index 9b7dd86..0000000
--- a/http/middleware/session.go
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2017 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 (
- "context"
- "net/http"
-
- "github.com/miniflux/miniflux/config"
- "github.com/miniflux/miniflux/http/cookie"
- "github.com/miniflux/miniflux/logger"
- "github.com/miniflux/miniflux/model"
- "github.com/miniflux/miniflux/storage"
-)
-
-// SessionMiddleware represents a session middleware.
-type SessionMiddleware struct {
- cfg *config.Config
- store *storage.Storage
-}
-
-// Handler execute the middleware.
-func (s *SessionMiddleware) Handler(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- var err error
- session := s.getSessionValueFromCookie(r)
-
- if session == nil {
- logger.Debug("[Middleware:Session] Session not found")
- session, err = s.store.CreateSession()
- if err != nil {
- logger.Error("[Middleware:Session] %v", err)
- http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
- return
- }
-
- http.SetCookie(w, cookie.New(cookie.CookieSessionID, session.ID, s.cfg.IsHTTPS, s.cfg.BasePath()))
- } else {
- logger.Debug("[Middleware:Session] %s", session)
- }
-
- if r.Method == "POST" {
- formValue := r.FormValue("csrf")
- 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!"))
- return
- }
- }
-
- ctx := r.Context()
- ctx = context.WithValue(ctx, SessionIDContextKey, session.ID)
- ctx = context.WithValue(ctx, CSRFContextKey, session.Data.CSRF)
- ctx = context.WithValue(ctx, OAuth2StateContextKey, session.Data.OAuth2State)
- ctx = context.WithValue(ctx, FlashMessageContextKey, session.Data.FlashMessage)
- ctx = context.WithValue(ctx, FlashErrorMessageContextKey, session.Data.FlashErrorMessage)
- ctx = context.WithValue(ctx, UserLanguageContextKey, session.Data.Language)
- next.ServeHTTP(w, r.WithContext(ctx))
- })
-}
-
-func (s *SessionMiddleware) getSessionValueFromCookie(r *http.Request) *model.Session {
- sessionCookie, err := r.Cookie(cookie.CookieSessionID)
- if err == http.ErrNoCookie {
- return nil
- }
-
- session, err := s.store.Session(sessionCookie.Value)
- if err != nil {
- logger.Error("[Middleware:Session] %v", err)
- return nil
- }
-
- return session
-}
-
-// NewSessionMiddleware returns a new SessionMiddleware.
-func NewSessionMiddleware(cfg *config.Config, store *storage.Storage) *SessionMiddleware {
- return &SessionMiddleware{cfg, store}
-}
diff --git a/http/middleware/user_session.go b/http/middleware/user_session.go
deleted file mode 100644
index 820d093..0000000
--- a/http/middleware/user_session.go
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2017 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 (
- "context"
- "net/http"
-
- "github.com/miniflux/miniflux/http/cookie"
- "github.com/miniflux/miniflux/http/route"
- "github.com/miniflux/miniflux/logger"
- "github.com/miniflux/miniflux/model"
- "github.com/miniflux/miniflux/storage"
-
- "github.com/gorilla/mux"
-)
-
-// UserSessionMiddleware represents a user session middleware.
-type UserSessionMiddleware struct {
- store *storage.Storage
- router *mux.Router
-}
-
-// Handler execute the middleware.
-func (s *UserSessionMiddleware) Handler(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- session := s.getSessionFromCookie(r)
-
- if session == nil {
- logger.Debug("[Middleware:UserSession] Session not found")
- if s.isPublicRoute(r) {
- next.ServeHTTP(w, r)
- } else {
- http.Redirect(w, r, route.Path(s.router, "login"), http.StatusFound)
- }
- } else {
- logger.Debug("[Middleware:UserSession] %s", session)
- ctx := r.Context()
- ctx = context.WithValue(ctx, UserIDContextKey, session.UserID)
- ctx = context.WithValue(ctx, IsAuthenticatedContextKey, true)
- ctx = context.WithValue(ctx, UserSessionTokenContextKey, session.Token)
-
- next.ServeHTTP(w, r.WithContext(ctx))
- }
- })
-}
-
-func (s *UserSessionMiddleware) isPublicRoute(r *http.Request) bool {
- route := mux.CurrentRoute(r)
- switch route.GetName() {
- case "login",
- "checkLogin",
- "stylesheet",
- "javascript",
- "oauth2Redirect",
- "oauth2Callback",
- "appIcon",
- "favicon",
- "webManifest":
- return true
- default:
- return false
- }
-}
-
-func (s *UserSessionMiddleware) getSessionFromCookie(r *http.Request) *model.UserSession {
- sessionCookie, err := r.Cookie(cookie.CookieUserSessionID)
- if err == http.ErrNoCookie {
- return nil
- }
-
- session, err := s.store.UserSessionByToken(sessionCookie.Value)
- if err != nil {
- logger.Error("[Middleware:UserSession] %v", err)
- return nil
- }
-
- return session
-}
-
-// NewUserSessionMiddleware returns a new UserSessionMiddleware.
-func NewUserSessionMiddleware(s *storage.Storage, r *mux.Router) *UserSessionMiddleware {
- return &UserSessionMiddleware{store: s, router: r}
-}