Add NoCache middleware for authenticated pages (closes #61)
All checks were successful
check / check (push) Successful in 5s
All checks were successful
check / check (push) Successful in 5s
This commit is contained in:
@@ -265,6 +265,26 @@ func (s *Middleware) SecurityHeaders() func(http.Handler) http.Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NoCache returns middleware that instructs browsers and
|
||||||
|
// intermediary proxies not to cache the response. It sets
|
||||||
|
// Cache-Control: no-store and Pragma: no-cache (the latter for
|
||||||
|
// older HTTP/1.0 intermediaries). Apply it to authenticated pages
|
||||||
|
// so webhook configuration and captured event data are not stored
|
||||||
|
// by caches.
|
||||||
|
func (s *Middleware) NoCache() func(http.Handler) http.Handler {
|
||||||
|
return func(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(
|
||||||
|
w http.ResponseWriter,
|
||||||
|
r *http.Request,
|
||||||
|
) {
|
||||||
|
w.Header().Set("Cache-Control", "no-store")
|
||||||
|
w.Header().Set("Pragma", "no-cache")
|
||||||
|
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MaxBodySize returns middleware that limits the request body size
|
// MaxBodySize returns middleware that limits the request body size
|
||||||
// for POST requests. If the body exceeds the given limit in
|
// for POST requests. If the body exceeds the given limit in
|
||||||
// bytes, the server returns 413 Request Entity Too Large. This
|
// bytes, the server returns 413 Request Entity Too Large. This
|
||||||
|
|||||||
@@ -387,6 +387,45 @@ func TestRequireAuth_UnauthenticatedSession_RedirectsToLogin(
|
|||||||
assert.Equal(t, "/pages/login", w.Header().Get("Location"))
|
assert.Equal(t, "/pages/login", w.Header().Get("Location"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- NoCache Middleware Tests ---
|
||||||
|
|
||||||
|
func TestNoCache_SetsHeaders(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
m, _ := testMiddleware(t, config.EnvironmentDev)
|
||||||
|
|
||||||
|
var called bool
|
||||||
|
|
||||||
|
handler := m.NoCache()(http.HandlerFunc(
|
||||||
|
func(w http.ResponseWriter, _ *http.Request) {
|
||||||
|
called = true
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
|
req := httptest.NewRequestWithContext(
|
||||||
|
context.Background(),
|
||||||
|
http.MethodGet, "/sources", nil,
|
||||||
|
)
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
handler.ServeHTTP(w, req)
|
||||||
|
|
||||||
|
assert.True(
|
||||||
|
t, called,
|
||||||
|
"NoCache middleware should call the next handler",
|
||||||
|
)
|
||||||
|
assert.Equal(
|
||||||
|
t, "no-store",
|
||||||
|
w.Header().Get("Cache-Control"),
|
||||||
|
)
|
||||||
|
assert.Equal(
|
||||||
|
t, "no-cache",
|
||||||
|
w.Header().Get("Pragma"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// --- Helper Tests ---
|
// --- Helper Tests ---
|
||||||
|
|
||||||
func TestIpFromHostPort(t *testing.T) {
|
func TestIpFromHostPort(t *testing.T) {
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ func (s *Server) setupRoutes() {
|
|||||||
func (s *Server) setupPageRoutes() {
|
func (s *Server) setupPageRoutes() {
|
||||||
s.router.Route("/pages", func(r chi.Router) {
|
s.router.Route("/pages", func(r chi.Router) {
|
||||||
r.Use(s.mw.CSRF())
|
r.Use(s.mw.CSRF())
|
||||||
|
r.Use(s.mw.NoCache())
|
||||||
r.Use(s.mw.MaxBodySize(maxFormBodySize))
|
r.Use(s.mw.MaxBodySize(maxFormBodySize))
|
||||||
|
|
||||||
r.Group(func(r chi.Router) {
|
r.Group(func(r chi.Router) {
|
||||||
@@ -106,6 +107,7 @@ func (s *Server) setupPageRoutes() {
|
|||||||
func (s *Server) setupUserRoutes() {
|
func (s *Server) setupUserRoutes() {
|
||||||
s.router.Route("/user/{username}", func(r chi.Router) {
|
s.router.Route("/user/{username}", func(r chi.Router) {
|
||||||
r.Use(s.mw.CSRF())
|
r.Use(s.mw.CSRF())
|
||||||
|
r.Use(s.mw.NoCache())
|
||||||
r.Use(s.mw.RequireAuth())
|
r.Use(s.mw.RequireAuth())
|
||||||
r.Get("/", s.h.HandleProfile())
|
r.Get("/", s.h.HandleProfile())
|
||||||
})
|
})
|
||||||
@@ -114,6 +116,7 @@ func (s *Server) setupUserRoutes() {
|
|||||||
func (s *Server) setupSourceRoutes() {
|
func (s *Server) setupSourceRoutes() {
|
||||||
s.router.Route("/sources", func(r chi.Router) {
|
s.router.Route("/sources", func(r chi.Router) {
|
||||||
r.Use(s.mw.CSRF())
|
r.Use(s.mw.CSRF())
|
||||||
|
r.Use(s.mw.NoCache())
|
||||||
r.Use(s.mw.RequireAuth())
|
r.Use(s.mw.RequireAuth())
|
||||||
r.Use(s.mw.MaxBodySize(maxFormBodySize))
|
r.Use(s.mw.MaxBodySize(maxFormBodySize))
|
||||||
r.Get("/", s.h.HandleSourceList())
|
r.Get("/", s.h.HandleSourceList())
|
||||||
@@ -123,6 +126,7 @@ func (s *Server) setupSourceRoutes() {
|
|||||||
|
|
||||||
s.router.Route("/source/{sourceID}", func(r chi.Router) {
|
s.router.Route("/source/{sourceID}", func(r chi.Router) {
|
||||||
r.Use(s.mw.CSRF())
|
r.Use(s.mw.CSRF())
|
||||||
|
r.Use(s.mw.NoCache())
|
||||||
r.Use(s.mw.RequireAuth())
|
r.Use(s.mw.RequireAuth())
|
||||||
r.Use(s.mw.MaxBodySize(maxFormBodySize))
|
r.Use(s.mw.MaxBodySize(maxFormBodySize))
|
||||||
r.Get("/", s.h.HandleSourceDetail())
|
r.Get("/", s.h.HandleSourceDetail())
|
||||||
|
|||||||
Reference in New Issue
Block a user