mirror of https://github.com/usememos/memos
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
60 lines
2.1 KiB
Go
60 lines
2.1 KiB
Go
package server
|
|
|
|
import (
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/labstack/echo/v5"
|
|
"github.com/labstack/echo/v5/middleware"
|
|
|
|
"github.com/usememos/memos/internal/profile"
|
|
)
|
|
|
|
func newCORSMiddleware(profile *profile.Profile) echo.MiddlewareFunc {
|
|
return middleware.CORSWithConfig(middleware.CORSConfig{
|
|
// The API is open to any origin so that token-authenticated clients
|
|
// (Access Token V2 / PAT in the Authorization header) can call it from
|
|
// anywhere. Credentials — i.e. the SameSite=Lax refresh-token cookie — are
|
|
// granted only to trusted origins (same host or the configured InstanceURL).
|
|
//
|
|
// AllowCredentials stays false here on purpose: the per-origin
|
|
// Access-Control-Allow-Credentials header is set inside the func below.
|
|
// Do NOT switch this to AllowCredentials:true — emitting that header for
|
|
// every reflected origin would let a malicious same-site subdomain read the
|
|
// cookie-authenticated /auth/refresh response and steal an access token.
|
|
AllowCredentials: false,
|
|
UnsafeAllowOriginFunc: func(c *echo.Context, origin string) (string, bool, error) {
|
|
// Never reflect the opaque "null" origin (sandboxed iframes, file://).
|
|
if origin == "null" {
|
|
return "", false, nil
|
|
}
|
|
// Trusted origins additionally get credentialed (cookie) access.
|
|
if isAllowedCORSOrigin(profile, c.Request().Host, origin) {
|
|
c.Response().Header().Set(echo.HeaderAccessControlAllowCredentials, "true")
|
|
}
|
|
// Reflect every origin; only trusted ones carry the credentials header.
|
|
return origin, true, nil
|
|
},
|
|
})
|
|
}
|
|
|
|
func isAllowedCORSOrigin(profile *profile.Profile, requestHost, origin string) bool {
|
|
originURL, err := url.Parse(origin)
|
|
if err != nil || originURL.Scheme == "" || originURL.Host == "" {
|
|
return false
|
|
}
|
|
|
|
if strings.EqualFold(originURL.Host, requestHost) {
|
|
return true
|
|
}
|
|
|
|
if profile == nil || profile.InstanceURL == "" {
|
|
return false
|
|
}
|
|
instanceURL, err := url.Parse(profile.InstanceURL)
|
|
if err != nil || instanceURL.Scheme == "" || instanceURL.Host == "" {
|
|
return false
|
|
}
|
|
return strings.EqualFold(originURL.Scheme, instanceURL.Scheme) && strings.EqualFold(originURL.Host, instanceURL.Host)
|
|
}
|