refactor(auth): replace dashboard sessions with stateless tokens and session control (#6329)

* refactor(auth): replace dashboard sessions with stateless tokens

* feat(auth): harden session issuance and distributed enforcement

* fix(proxy): preserve trusted proxy compatibility defaults

* refactor: address dashboard auth review feedback

* refactor: remove classic frontend and flatten web app
This commit is contained in:
Calcium-Ion
2026-07-20 16:48:43 +08:00
committed by GitHub
parent 5a6c53d496
commit 31d70fca39
1605 changed files with 17511 additions and 147913 deletions
+37 -3
View File
@@ -2,11 +2,45 @@ package common
import (
"fmt"
"net"
"net/url"
"os"
"strings"
)
// NormalizeOrigin validates and canonicalizes a browser origin. Only an exact
// scheme/host/effective-port match is meaningful; paths and wildcards are not
// accepted for authentication cookie endpoints.
func NormalizeOrigin(raw string) (string, error) {
raw = strings.TrimSpace(raw)
if raw == "" || raw == "null" || strings.ContainsAny(raw, "\r\n") {
return "", fmt.Errorf("origin is empty or invalid")
}
parsedURL, err := url.Parse(raw)
if err != nil {
return "", fmt.Errorf("invalid origin: %w", err)
}
if parsedURL.Scheme != "http" && parsedURL.Scheme != "https" {
return "", fmt.Errorf("origin scheme must be http or https")
}
if parsedURL.Host == "" || parsedURL.User != nil || parsedURL.RawQuery != "" || parsedURL.Fragment != "" || (parsedURL.Path != "" && parsedURL.Path != "/") {
return "", fmt.Errorf("origin must contain only scheme and host")
}
hostname := strings.ToLower(parsedURL.Hostname())
if hostname == "" || strings.Contains(hostname, "*") {
return "", fmt.Errorf("origin host is empty")
}
port := parsedURL.Port()
normalizedHost := hostname
if strings.Contains(hostname, ":") {
normalizedHost = "[" + hostname + "]"
}
if port == "" || (parsedURL.Scheme == "http" && port == "80") || (parsedURL.Scheme == "https" && port == "443") {
return parsedURL.Scheme + "://" + normalizedHost, nil
}
return parsedURL.Scheme + "://" + net.JoinHostPort(hostname, port), nil
}
func InitSessionCookieSettings() error {
secureRaw := strings.TrimSpace(os.Getenv("SESSION_COOKIE_SECURE"))
trustedURLsRaw := strings.TrimSpace(os.Getenv("SESSION_COOKIE_TRUSTED_URL"))
@@ -35,14 +69,14 @@ func InitSessionCookieSettings() error {
if trustedURL == "" {
return fmt.Errorf("SESSION_COOKIE_TRUSTED_URL contains an empty URL")
}
parsedURL, err := url.Parse(trustedURL)
normalizedOrigin, err := NormalizeOrigin(trustedURL)
if err != nil {
return fmt.Errorf("invalid SESSION_COOKIE_TRUSTED_URL: %w", err)
}
if parsedURL.Scheme != "https" || parsedURL.Host == "" {
if !strings.HasPrefix(normalizedOrigin, "https://") {
return fmt.Errorf("SESSION_COOKIE_TRUSTED_URL must contain only https URLs with hosts")
}
SessionCookieTrustedURLs = append(SessionCookieTrustedURLs, trustedURL)
SessionCookieTrustedURLs = append(SessionCookieTrustedURLs, normalizedOrigin)
}
SessionCookieSecure = true