89 lines
2.5 KiB
Go
89 lines
2.5 KiB
Go
package middleware
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
// CorsMiddleware — browser CORS for Harbor Desk FE.
|
|
// Note: cannot combine Access-Control-Allow-Origin: * with Allow-Credentials: true
|
|
// (browsers reject). FE uses Bearer token (no cookies), so no credentials header.
|
|
type CorsMiddleware struct {
|
|
allowedOrigins map[string]struct{}
|
|
}
|
|
|
|
func NewCorsMiddleware(origins []string) *CorsMiddleware {
|
|
allowed := make(map[string]struct{}, len(origins))
|
|
for _, origin := range origins {
|
|
origin = strings.TrimRight(strings.TrimSpace(origin), "/")
|
|
if origin != "" {
|
|
allowed[origin] = struct{}{}
|
|
}
|
|
}
|
|
return &CorsMiddleware{allowedOrigins: allowed}
|
|
}
|
|
|
|
func (m *CorsMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
if !m.setHeader(w, r) {
|
|
writeOriginDenied(w)
|
|
return
|
|
}
|
|
if r.Method == http.MethodOptions {
|
|
w.WriteHeader(http.StatusNoContent)
|
|
return
|
|
}
|
|
next(w, r)
|
|
}
|
|
}
|
|
|
|
func (m *CorsMiddleware) Handler() http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if !m.setHeader(w, r) {
|
|
writeOriginDenied(w)
|
|
return
|
|
}
|
|
if r.Method == http.MethodOptions {
|
|
w.WriteHeader(http.StatusNoContent)
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusNotFound)
|
|
})
|
|
}
|
|
|
|
func writeOriginDenied(w http.ResponseWriter) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusForbidden)
|
|
_ = json.NewEncoder(w).Encode(map[string]any{
|
|
"code": 403003, "message": "origin is not allowed", "data": nil, "error": nil,
|
|
})
|
|
}
|
|
|
|
func (m *CorsMiddleware) setHeader(w http.ResponseWriter, r *http.Request) bool {
|
|
origin := strings.TrimRight(strings.TrimSpace(r.Header.Get("Origin")), "/")
|
|
if origin != "" {
|
|
if _, ok := m.allowedOrigins[origin]; !ok {
|
|
return false
|
|
}
|
|
w.Header().Set("Access-Control-Allow-Origin", origin)
|
|
appendVary(w, "Origin")
|
|
}
|
|
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Request-Id, device_id")
|
|
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH")
|
|
w.Header().Set("Access-Control-Max-Age", "600")
|
|
w.Header().Set("Access-Control-Expose-Headers", "Content-Length, Content-Type")
|
|
return true
|
|
}
|
|
|
|
func appendVary(w http.ResponseWriter, value string) {
|
|
for _, existing := range w.Header().Values("Vary") {
|
|
for _, part := range strings.Split(existing, ",") {
|
|
if strings.EqualFold(strings.TrimSpace(part), value) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
w.Header().Add("Vary", value)
|
|
}
|