cookie ready

This commit is contained in:
2026-05-13 22:34:11 +02:00
parent 8c4e664ca8
commit 1b53c1c199
16 changed files with 798 additions and 146 deletions
+34 -108
View File
@@ -3,7 +3,6 @@ package middleware
import (
"context"
"fmt"
"hash/crc32"
"net/http"
"strconv"
"strings"
@@ -26,6 +25,10 @@ type SessionCookieNameResolver interface {
ResolveCookieName(ctx context.Context, req *http.Request) (string, error)
}
type SessionCookiePathResolver interface {
ResolveCookiePath(ctx context.Context, req *http.Request) (string, error)
}
type LanguageResolver interface {
ResolveLanguageID(ctx context.Context, req *http.Request, fallback int64) int64
}
@@ -38,6 +41,7 @@ func Session(cfg psconfig.Config, codec pscookie.Codec, initializer AnonymousSes
ownership := cfg.ParseRouteOwnership()
expiryRefresher, _ := initializer.(SessionExpiryRefresher)
cookieNameResolver, _ := initializer.(SessionCookieNameResolver)
cookiePathResolver, _ := initializer.(SessionCookiePathResolver)
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
@@ -82,6 +86,16 @@ func Session(cfg psconfig.Config, codec pscookie.Codec, initializer AnonymousSes
applyRequestMarket(session, requestMarketSelection(c.Request()))
}
if ownedRoute && shouldSetSessionCookie(rawCookie, session) {
cookiePath := "/"
if cookiePathResolver != nil {
resolvedCookiePath, err := cookiePathResolver.ResolveCookiePath(c.Request().Context(), c.Request())
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("prestashop cookie path resolution failed: %v", err))
}
if strings.TrimSpace(resolvedCookiePath) != "" {
cookiePath = resolvedCookiePath
}
}
if expiryRefresher != nil {
if err := expiryRefresher.RefreshExpiry(c.Request().Context(), session); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("prestashop session expiry refresh failed: %v", err))
@@ -92,7 +106,7 @@ func Session(cfg psconfig.Config, codec pscookie.Codec, initializer AnonymousSes
return echo.NewHTTPError(http.StatusInternalServerError, "prestashop cookie encode failed")
}
session.RawCookie = encoded
setPrestaShopCookie(c.Request(), c.Response(), session, cookieName, encoded)
setPrestaShopCookie(c.Request(), c.Response(), session, cookieName, encoded, cookiePath)
if redirectURL, ok := clearMarketSelectionURL(c.Request()); ok {
return c.Redirect(http.StatusSeeOther, redirectURL)
}
@@ -153,20 +167,7 @@ func cookiePrefix(configuredName string) string {
}
func shouldBootstrapAnonymousSession(rawCookie string, session *pscookie.SessionContext) bool {
if session == nil {
return true
}
if rawCookie == "" {
return true
}
if session.IsLoggedIn {
return false
}
return session.GuestID == nil ||
session.CurrencyID == nil ||
session.LanguageID == nil ||
session.Values["id_connections"] == "" ||
session.Values["iso_code_country"] == ""
return session == nil || rawCookie == ""
}
func shouldSetSessionCookie(rawCookie string, session *pscookie.SessionContext) bool {
@@ -195,15 +196,9 @@ func applyRequestLanguage(session *pscookie.SessionContext, languageID int64) {
session.LanguageID = int64Ptr(languageID)
session.Values["id_lang"] = value
session.Values["id_language"] = value
session.OrderedKeys = ensureOrderedKey(session.OrderedKeys, "id_lang", 1)
session.OrderedKeys = ensureOrderedKey(session.OrderedKeys, "id_language", 3)
if !session.IsLoggedIn {
if checksum := anonymousSessionChecksum(session, languageID); checksum != "" {
session.Values["checksum"] = checksum
session.OrderedKeys = ensureOrderedKey(session.OrderedKeys, "checksum", len(session.OrderedKeys))
}
}
session.OrderedKeys = appendOrderedKeyIfMissing(session.OrderedKeys, "id_lang")
session.OrderedKeys = appendOrderedKeyIfMissing(session.OrderedKeys, "id_language")
session.OrderedKeys = moveOrderedKeyToEnd(session.OrderedKeys, "checksum")
session.Plaintext = ""
session.RawCookie = ""
@@ -235,18 +230,9 @@ func applyRequestMarket(session *pscookie.SessionContext, selection marketSelect
session.CurrencyID = int64Ptr(selection.CurrencyID)
session.Values["iso_code_country"] = selection.CountryISO
session.Values["id_currency"] = strconv.FormatInt(selection.CurrencyID, 10)
delete(session.Values, "id_country")
session.OrderedKeys = ensureOrderedKey(session.OrderedKeys, "iso_code_country", 4)
session.OrderedKeys = removeOrderedKey(session.OrderedKeys, "id_country")
session.OrderedKeys = ensureOrderedKey(session.OrderedKeys, "id_currency", 5)
if !session.IsLoggedIn {
trimAnonymousCookieValues(session)
session.OrderedKeys = ensureOrderedKey(session.OrderedKeys, "id_guest", 6)
session.OrderedKeys = ensureOrderedKey(session.OrderedKeys, "id_connections", 7)
session.OrderedKeys = removeOrderedKey(session.OrderedKeys, "checksum")
session.OrderedKeys = ensureOrderedKey(session.OrderedKeys, "checksum", len(session.OrderedKeys))
}
session.OrderedKeys = appendOrderedKeyIfMissing(session.OrderedKeys, "iso_code_country")
session.OrderedKeys = appendOrderedKeyIfMissing(session.OrderedKeys, "id_currency")
session.OrderedKeys = moveOrderedKeyToEnd(session.OrderedKeys, "checksum")
session.Plaintext = ""
session.RawCookie = ""
@@ -259,91 +245,28 @@ func sessionLanguageID(session *pscookie.SessionContext) int64 {
return *session.LanguageID
}
func anonymousSessionChecksum(session *pscookie.SessionContext, languageID int64) string {
if session == nil || session.Values == nil {
return ""
}
guestID, _ := strconv.ParseInt(session.Values["id_guest"], 10, 64)
connectionID, _ := strconv.ParseInt(session.Values["id_connections"], 10, 64)
currencyID, _ := strconv.ParseInt(session.Values["id_currency"], 10, 64)
shopID, _ := strconv.ParseInt(session.Values["id_shop"], 10, 64)
if guestID == 0 || connectionID == 0 || currencyID == 0 {
return ""
}
buf := make([]byte, 0, 32)
for _, value := range []int64{guestID, connectionID, languageID, currencyID, shopID} {
buf = strconv.AppendInt(buf, value, 10)
buf = append(buf, '|')
}
return strconv.FormatUint(uint64(crc32.ChecksumIEEE(buf)), 10)
}
func ensureOrderedKey(keys []string, key string, index int) []string {
func appendOrderedKeyIfMissing(keys []string, key string) []string {
for i, existing := range keys {
if existing != key {
continue
}
if i == index || index >= len(keys) {
if i >= 0 {
return keys
}
keys = append(keys[:i], keys[i+1:]...)
break
}
if index < 0 {
index = 0
}
if index >= len(keys) {
return append(keys, key)
}
keys = append(keys, "")
copy(keys[index+1:], keys[index:])
keys[index] = key
return keys
return append(keys, key)
}
func removeOrderedKey(keys []string, key string) []string {
func moveOrderedKeyToEnd(keys []string, key string) []string {
for i, existing := range keys {
if existing == key {
return append(keys[:i], keys[i+1:]...)
keys = append(keys[:i], keys[i+1:]...)
return append(keys, key)
}
}
return keys
}
func trimAnonymousCookieValues(session *pscookie.SessionContext) {
if session == nil || session.Values == nil {
return
}
allowed := map[string]struct{}{
"date_add": {},
"id_lang": {},
"id_language": {},
"iso_code_country": {},
"id_currency": {},
"id_guest": {},
"id_connections": {},
"checksum": {},
}
for key := range session.Values {
if _, ok := allowed[key]; !ok {
delete(session.Values, key)
}
}
filtered := make([]string, 0, len(session.OrderedKeys))
for _, key := range session.OrderedKeys {
if _, ok := allowed[key]; ok {
filtered = append(filtered, key)
}
}
session.OrderedKeys = filtered
}
func int64Ptr(value int64) *int64 {
if value == 0 {
return nil
@@ -413,13 +336,16 @@ func clearMarketSelectionURL(req *http.Request) (string, bool) {
return cleanPath, true
}
func setPrestaShopCookie(req *http.Request, res *echo.Response, session *pscookie.SessionContext, name, value string) {
func setPrestaShopCookie(req *http.Request, res *echo.Response, session *pscookie.SessionContext, name, value, path string) {
maxAge := 1
if session != nil && session.ExpiresAt != nil {
maxAge = int(session.ExpiresAt.UTC().Unix())
}
if strings.TrimSpace(path) == "" {
path = "/"
}
header := fmt.Sprintf("%s=%s; path=/; max-age=%d; HttpOnly; SameSite=Lax", name, value, maxAge)
header := fmt.Sprintf("%s=%s; path=%s; max-age=%d; HttpOnly; SameSite=Lax", name, value, path, maxAge)
if requestCookieSecure(req) {
header += "; Secure"
}