Files
summercms/modules/cabana/csrf.go
Jakub Zych 5e50b166ef refactor(10.2-01): nest framework packages under modules
- Move remaining beach packages and embedded admin assets\n- Rewrite framework, example, build, and gate paths
2026-09-28 02:21:02 +02:00

46 lines
1.2 KiB
Go

package cabana
import (
"net/http"
"strings"
)
const (
// requestedWithHeader is the custom header the admin SPA sends on every
// request. A cross-site form or navigation cannot set it, and a
// cross-origin fetch that sets it needs a CORS preflight the admin API
// never answers (D-19).
requestedWithHeader = "X-Requested-With"
requestedWithAjax = "XMLHttpRequest"
)
// requireAjax refuses a state-changing admin request that is not
// Bearer-authenticated and does not carry X-Requested-With: XMLHttpRequest.
// It runs before the wrapped handler, so a refused request is never decoded,
// never looks up a controller and never reaches the database. The response
// uses the fixed D-10 code forbidden.
func requireAjax(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if !csrfSafe(r) {
WriteError(w, http.StatusForbidden, "forbidden", msgForbidden)
return
}
next(w, r)
}
}
func csrfSafe(r *http.Request) bool {
switch r.Method {
case http.MethodGet, http.MethodHead, http.MethodOptions:
return true
}
if bearerToken(r) != "" {
return true
}
return isAjax(r)
}
func isAjax(r *http.Request) bool {
return strings.TrimSpace(r.Header.Get(requestedWithHeader)) == requestedWithAjax
}