The CORS middleware let every origin make credentialed requests, so a page on another subdomain of the server's domain could read and act as the signed-in user. Nothing needs cross-origin access, so the middleware and the go-chi/cors dependency go. A test checks that a request from another origin and a preflight get no Access-Control-Allow-* headers. Model: opus-5-5
This commit is contained in:
1 parent
f42c6214a0
commit
3587ce92cd
6 files changed
+74
-39
No files matched your search
@@ -12,7 +12,6 @@ import (
|
||||
|
||||
basicauth "github.com/99designs/basicauth-go"
|
||||
chimw "github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/go-chi/cors"
|
||||
metrics "github.com/slok/go-http-metrics/metrics/prometheus"
|
||||
ghmm "github.com/slok/go-http-metrics/middleware"
|
||||
"github.com/slok/go-http-metrics/middleware/std"
|
||||
@@ -24,8 +23,6 @@ import (
|
||||
"sneak.berlin/go/neoirc/internal/logger"
|
||||
)
|
||||
|
||||
const corsMaxAge = 300
|
||||
|
||||
// Params defines the dependencies for creating Middleware.
|
||||
type Params struct {
|
||||
fx.In
|
||||
@@ -200,28 +197,6 @@ func (mware *Middleware) Logging() func(http.Handler) http.Handler {
|
||||
}
|
||||
}
|
||||
|
||||
// CORS returns middleware that handles Cross-Origin Resource Sharing.
|
||||
// AllowCredentials is true so browsers include cookies in
|
||||
// cross-origin API requests.
|
||||
func (mware *Middleware) CORS() func(http.Handler) http.Handler {
|
||||
return cors.Handler(cors.Options{ //nolint:exhaustruct // optional fields
|
||||
AllowOriginFunc: func(
|
||||
_ *http.Request, _ string,
|
||||
) bool {
|
||||
return true
|
||||
},
|
||||
AllowedMethods: []string{
|
||||
"GET", "POST", "PUT", "DELETE", "OPTIONS",
|
||||
},
|
||||
AllowedHeaders: []string{
|
||||
"Accept", "Content-Type", "X-CSRF-Token",
|
||||
},
|
||||
ExposedHeaders: []string{"Link"},
|
||||
AllowCredentials: true,
|
||||
MaxAge: corsMaxAge,
|
||||
})
|
||||
}
|
||||
|
||||
// Metrics returns middleware that records HTTP metrics.
|
||||
func (mware *Middleware) Metrics() func(http.Handler) http.Handler {
|
||||
metricsMiddleware := ghmm.New(ghmm.Config{ //nolint:exhaustruct // optional fields
|
||||
|
||||
@@ -30,7 +30,6 @@ func (srv *Server) SetupRoutes() {
|
||||
srv.router.Use(srv.mw.Metrics())
|
||||
}
|
||||
|
||||
srv.router.Use(srv.mw.CORS())
|
||||
srv.router.Use(srv.mw.CSP())
|
||||
srv.router.Use(middleware.Timeout(routeTimeout))
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -188,6 +189,70 @@ func TestServeAfterStopDoesNotStopApp(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestNoCrossOriginAccess checks that the server allows no
|
||||
// cross-origin requests: neither a request from another origin
|
||||
// nor a preflight gets Access-Control-Allow-Origin or
|
||||
// Access-Control-Allow-Credentials, and a preflight gets 405
|
||||
// like any other OPTIONS request.
|
||||
func TestNoCrossOriginAccess(t *testing.T) {
|
||||
var srv *server.Server
|
||||
|
||||
startApp(t, fx.Populate(&srv))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
method string
|
||||
requestMethod string
|
||||
status int
|
||||
}{
|
||||
{
|
||||
name: "request",
|
||||
method: http.MethodGet,
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "preflight",
|
||||
method: http.MethodOptions,
|
||||
requestMethod: http.MethodPost,
|
||||
status: http.StatusMethodNotAllowed,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
request := httptest.NewRequestWithContext(
|
||||
t.Context(), test.method,
|
||||
"http://chat.example.com/api/v1/server", nil,
|
||||
)
|
||||
request.Header.Set("Origin", "http://blog.example.com")
|
||||
|
||||
if test.requestMethod != "" {
|
||||
request.Header.Set(
|
||||
"Access-Control-Request-Method", test.requestMethod,
|
||||
)
|
||||
}
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
srv.ServeHTTP(recorder, request)
|
||||
|
||||
if recorder.Code != test.status {
|
||||
t.Errorf("status %d, want %d", recorder.Code, test.status)
|
||||
}
|
||||
|
||||
for _, header := range []string{
|
||||
"Access-Control-Allow-Origin",
|
||||
"Access-Control-Allow-Credentials",
|
||||
} {
|
||||
value := recorder.Header().Get(header)
|
||||
if value != "" {
|
||||
t.Errorf("%s is %q, want none", header, value)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// startApp starts the app newApp builds, with the HTTP port
|
||||
// set to 0, so the system gives the server a free port.
|
||||
func startApp(
|
||||
|
||||
Reference in new issue
Block a user