From 6edb93d5afd57c1778f6032b6751b8d316ca93d1 Mon Sep 17 00:00:00 2001 From: mkelvers Date: Sat, 27 Jun 2026 21:05:09 +0200 Subject: [PATCH] feat: add HTTPS-aware session cookie helpers --- internal/auth/cookie.go | 58 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 internal/auth/cookie.go diff --git a/internal/auth/cookie.go b/internal/auth/cookie.go new file mode 100644 index 00000000..3fca0226 --- /dev/null +++ b/internal/auth/cookie.go @@ -0,0 +1,58 @@ +package auth + +import ( + "net/http" + "strings" + + "mal/internal/domain" + + "github.com/gin-gonic/gin" +) + +const sessionCookieName = "session_id" + +func setSessionCookie(c *gin.Context, value string, maxAge int) { + http.SetCookie(c.Writer, &http.Cookie{ + Name: sessionCookieName, + Value: value, + Path: "/", + MaxAge: maxAge, + Secure: isHTTPSRequest(c.Request), + HttpOnly: true, + SameSite: http.SameSiteLaxMode, + }) +} + +func setPersistentSessionCookie(c *gin.Context, value string) { + setSessionCookie(c, value, int(domain.SessionLifetime.Seconds())) +} + +func clearSessionCookie(c *gin.Context) { + setSessionCookie(c, "", -1) +} + +func isHTTPSRequest(r *http.Request) bool { + if r.TLS != nil { + return true + } + + proto := r.Header.Get("X-Forwarded-Proto") + if i := strings.IndexByte(proto, ','); i >= 0 { + proto = proto[:i] + } + if strings.EqualFold(strings.TrimSpace(proto), "https") { + return true + } + + forwarded := r.Header.Values("Forwarded") + for _, value := range forwarded { + for _, part := range strings.Split(value, ";") { + key, val, ok := strings.Cut(strings.TrimSpace(part), "=") + if ok && strings.EqualFold(key, "proto") && strings.EqualFold(strings.Trim(val, `"`), "https") { + return true + } + } + } + + return false +}