package auth import ( "net" "net/http" "strings" "time" "github.com/yusing/godoxy/internal/common" gperr "github.com/yusing/goutils/errs" strutils "github.com/yusing/goutils/strings" ) var ( ErrMissingSessionToken = gperr.New("missing session token") ErrInvalidSessionToken = gperr.New("invalid session token") ErrUserNotAllowed = gperr.New("user not allowed") ) func IsFrontend(r *http.Request) bool { return requestRemoteIP(r) == "127.0.0.1" } func requestRemoteIP(r *http.Request) string { ip, _, err := net.SplitHostPort(r.RemoteAddr) if err != nil { return "" } return ip } func requestHost(r *http.Request) string { // check if it's from backend if IsFrontend(r) { return r.Header.Get("X-Forwarded-Host") } return r.Host } // cookieDomain returns the fully qualified domain name of the request host // with subdomain stripped. // // If the request host does not have a subdomain, // an empty string is returned // // "abc.example.com" -> ".example.com" (cross subdomain) // "example.com" -> "" (same domain only) // "abc.localhost" -> ".localhost" // "abc.local" -> ".local" // "abc.internal" -> ".internal" func cookieDomain(r *http.Request) string { reqHost := requestHost(r) switch { case strings.HasSuffix(reqHost, ".internal"): return ".internal" case strings.HasSuffix(reqHost, ".localhost"): return ".localhost" case strings.HasSuffix(reqHost, ".local"): return ".local" } // if the host is an IP address, return an empty string { host, _, err := net.SplitHostPort(reqHost) if err != nil { host = reqHost } if net.ParseIP(host) != nil { return "" } } parts := strutils.SplitRune(reqHost, '.') if len(parts) < 2 { return "" } parts[0] = "" return strutils.JoinRune(parts, '.') } func SetTokenCookie(w http.ResponseWriter, r *http.Request, name, value string, ttl time.Duration) { http.SetCookie(w, &http.Cookie{ Name: name, Value: value, MaxAge: int(ttl.Seconds()), Domain: cookieDomain(r), HttpOnly: true, Secure: common.APIJWTSecure, SameSite: http.SameSiteLaxMode, Path: "/", }) } func ClearTokenCookie(w http.ResponseWriter, r *http.Request, name string) { http.SetCookie(w, &http.Cookie{ Name: name, Value: "", MaxAge: -1, Domain: cookieDomain(r), HttpOnly: true, Secure: common.APIJWTSecure, SameSite: http.SameSiteLaxMode, Path: "/", }) }