1
0
Fork 0
mirror of https://github.com/miniflux/v2.git synced 2025-06-27 16:36:00 +00:00

Store tokens in database instead of cookie

This commit is contained in:
Frédéric Guillot 2017-12-01 21:51:22 -08:00
parent 7cecdbb856
commit 1a90c059e7
11 changed files with 160 additions and 58 deletions

View file

@ -82,7 +82,7 @@ func (c *Context) UserLanguage() string {
// CsrfToken returns the current CSRF token.
func (c *Context) CsrfToken() string {
if v := c.request.Context().Value(middleware.CsrfContextKey); v != nil {
if v := c.request.Context().Value(middleware.TokenContextKey); v != nil {
return v.(string)
}

View file

@ -21,6 +21,6 @@ var (
// IsAuthenticatedContextKey is the context key used to store the authentication flag.
IsAuthenticatedContextKey = &contextKey{"IsAuthenticated"}
// CsrfContextKey is the context key used to store CSRF token.
CsrfContextKey = &contextKey{"CSRF"}
// TokenContextKey is the context key used to store CSRF token.
TokenContextKey = &contextKey{"CSRF"}
)

View file

@ -1,50 +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"
"log"
"net/http"
"github.com/miniflux/miniflux2/helper"
)
// Csrf is a middleware that handle CSRF tokens.
func Csrf(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var csrfToken string
csrfCookie, err := r.Cookie("csrfToken")
if err == http.ErrNoCookie || csrfCookie.Value == "" {
csrfToken = helper.GenerateRandomString(64)
cookie := &http.Cookie{
Name: "csrfToken",
Value: csrfToken,
Path: "/",
Secure: r.URL.Scheme == "https",
HttpOnly: true,
}
http.SetCookie(w, cookie)
} else {
csrfToken = csrfCookie.Value
}
ctx := r.Context()
ctx = context.WithValue(ctx, CsrfContextKey, csrfToken)
w.Header().Add("Vary", "Cookie")
isTokenValid := csrfToken == r.FormValue("csrf") || csrfToken == r.Header.Get("X-Csrf-Token")
if r.Method == "POST" && !isTokenValid {
log.Println("[Middleware:CSRF] Invalid or missing CSRF token!")
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Invalid or missing CSRF token!"))
} else {
next.ServeHTTP(w, r.WithContext(ctx))
}
})
}

View file

@ -0,0 +1,81 @@
// 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"
"log"
"net/http"
"github.com/miniflux/miniflux2/model"
"github.com/miniflux/miniflux2/storage"
)
// TokenMiddleware represents a token middleware.
type TokenMiddleware struct {
store *storage.Storage
}
// Handler execute the middleware.
func (t *TokenMiddleware) Handler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var err error
token := t.getTokenValueFromCookie(r)
if token == nil {
log.Println("[Middleware:Token] Token not found")
token, err = t.store.CreateToken()
if err != nil {
log.Println(err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
cookie := &http.Cookie{
Name: "tokenID",
Value: token.ID,
Path: "/",
Secure: r.URL.Scheme == "https",
HttpOnly: true,
}
http.SetCookie(w, cookie)
} else {
log.Println("[Middleware:Token]", token)
}
isTokenValid := token.Value == r.FormValue("csrf") || token.Value == r.Header.Get("X-Csrf-Token")
if r.Method == "POST" && !isTokenValid {
log.Println("[Middleware:CSRF] Invalid or missing CSRF token!")
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Invalid or missing CSRF token!"))
} else {
ctx := r.Context()
ctx = context.WithValue(ctx, TokenContextKey, token.Value)
next.ServeHTTP(w, r.WithContext(ctx))
}
})
}
func (t *TokenMiddleware) getTokenValueFromCookie(r *http.Request) *model.Token {
tokenCookie, err := r.Cookie("tokenID")
if err == http.ErrNoCookie {
return nil
}
token, err := t.store.Token(tokenCookie.Value)
if err != nil {
log.Println(err)
return nil
}
return token
}
// NewTokenMiddleware returns a new TokenMiddleware.
func NewTokenMiddleware(s *storage.Storage) *TokenMiddleware {
return &TokenMiddleware{store: s}
}

View file

@ -37,7 +37,7 @@ func getRoutes(cfg *config.Config, store *storage.Storage, feedHandler *feed.Han
uiHandler := core.NewHandler(store, router, templateEngine, translator, middleware.NewChain(
middleware.NewSessionMiddleware(store, router).Handler,
middleware.Csrf,
middleware.NewTokenMiddleware(store).Handler,
))
router.Handle("/v1/users", apiHandler.Use(apiController.CreateUser)).Methods("POST")