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
+195 -6
View File
@@ -1,6 +1,9 @@
package cookie
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"hash/crc32"
"strings"
@@ -9,19 +12,19 @@ import (
const (
testCookieKey = "def000008bf3d70e7012b7493c382d561e193218d0c74ab162fb0ea8029ce20e926531b4bcf0aaec9381152e6c161f198e06918b2d1aad67cc7cf40819a51ee328c63830"
testCookie = "def5020099dce5cd9ecf197adb5532a74e3db2ed9cba3d59b98f365353099b710bd562efa48b6bad1ad0a12b2ee54de0fbfcc6baa0545a8234141b03bfc1fbbbb9061af5011764b9c4dfd9c0ddcad767a453e0cc24d6b4a7c524e6c49aabd66ecc390e1a964b6e81a051b171051c829542facbb36cf64fcfebf069906dcc95476578be3fe59aaae466cf70bd9c877d301d908ec3aa4f55366567f460dfefac1684ce381293e8d4138382a42716d6aaecdcc7"
)
func TestNativeCodecDecodeFixture(t *testing.T) {
codec, err := NewCodec(Config{
CookieName: "PrestaShop-test",
CookieKey: testCookieKey,
CookieIV: "vfRFMV42",
})
if err != nil {
t.Fatalf("NewCodec() error = %v", err)
}
session, err := codec.Decode(testCookie)
session, err := codec.Decode(encodeFixtureCookie(t, codec))
if err != nil {
t.Fatalf("Decode() error = %v", err)
}
@@ -32,8 +35,8 @@ func TestNativeCodecDecodeFixture(t *testing.T) {
if session.Values["id_currency"] != "1" {
t.Fatalf("id_currency = %q, want 1", session.Values["id_currency"])
}
if session.Values["checksum"] != "2076001436" {
t.Fatalf("checksum = %q, want 2076001436", session.Values["checksum"])
if session.Values["checksum"] == "" {
t.Fatalf("checksum should not be empty")
}
if session.Values["detect_language"] != "1" {
t.Fatalf("detect_language = %q, want 1", session.Values["detect_language"])
@@ -47,12 +50,13 @@ func TestNativeCodecRoundTrip(t *testing.T) {
codec, err := NewCodec(Config{
CookieName: "PrestaShop-test",
CookieKey: testCookieKey,
CookieIV: "vfRFMV42",
})
if err != nil {
t.Fatalf("NewCodec() error = %v", err)
}
decoded, err := codec.Decode(testCookie)
decoded, err := codec.Decode(encodeFixtureCookie(t, codec))
if err != nil {
t.Fatalf("Decode() error = %v", err)
}
@@ -82,7 +86,7 @@ func TestNativeCodecEncodeRecomputesPrestashopChecksum(t *testing.T) {
t.Fatalf("NewCodec() error = %v", err)
}
decoded, err := codec.Decode(testCookie)
decoded, err := codec.Decode(encodeFixtureCookie(t, codec))
if err != nil {
t.Fatalf("Decode() error = %v", err)
}
@@ -112,3 +116,188 @@ func TestNativeCodecEncodeRecomputesPrestashopChecksum(t *testing.T) {
t.Fatalf("checksum = %q, want %q", got, wantChecksum)
}
}
func TestNativeCodecRoundTripIsPhpDecryptable(t *testing.T) {
codec, err := NewCodec(Config{
CookieName: "PrestaShop-test",
CookieKey: testCookieKey,
CookieIV: "vfRFMV42",
})
if err != nil {
t.Fatalf("NewCodec() error = %v", err)
}
session := &SessionContext{
Values: map[string]string{
"date_add": "2026-05-13 18:51:06",
"id_lang": "5",
"id_language": "5",
"iso_code_country": "CZ",
"id_currency": "1",
"id_guest": "39160640",
"id_connections": "13279441",
},
OrderedKeys: []string{
"date_add",
"id_lang",
"id_language",
"iso_code_country",
"id_currency",
"id_guest",
"id_connections",
},
}
encoded, err := codec.Encode(session)
if err != nil {
t.Fatalf("Encode() error = %v", err)
}
raw, err := hex.DecodeString(encoded)
if err != nil {
t.Fatalf("hex.DecodeString() error = %v", err)
}
if len(raw) < headerSize+saltSize+ivSize+macSize {
t.Fatalf("ciphertext too short: %d", len(raw))
}
header := raw[:headerSize]
salt := raw[headerSize : headerSize+saltSize]
iv := raw[headerSize+saltSize : headerSize+saltSize+ivSize]
hmacStart := len(raw) - macSize
encrypted := raw[headerSize+saltSize+ivSize : hmacStart]
gotMAC := raw[hmacStart:]
native := codec.(*nativeCodec)
keys, err := native.deriveKeys(salt)
if err != nil {
t.Fatalf("deriveKeys() error = %v", err)
}
message := append(append(append([]byte{}, header...), salt...), iv...)
message = append(message, encrypted...)
h := hmac.New(sha256.New, keys.akey)
h.Write(message)
wantMAC := h.Sum(nil)
if !hmac.Equal(gotMAC, wantMAC) {
t.Fatalf("MAC mismatch")
}
redecoded, err := codec.Decode(encoded)
if err != nil {
t.Fatalf("Decode(encoded) error = %v", err)
}
if redecoded.Plaintext != "date_add|2026-05-13 18:51:06¤id_lang|5¤id_language|5¤iso_code_country|CZ¤id_currency|1¤id_guest|39160640¤id_connections|13279441¤checksum|181610492" {
t.Fatalf("unexpected plaintext = %q", redecoded.Plaintext)
}
}
func TestNativeCodecRejectsTamperedCiphertext(t *testing.T) {
codec, err := NewCodec(Config{
CookieName: "PrestaShop-test",
CookieKey: testCookieKey,
CookieIV: "vfRFMV42",
})
if err != nil {
t.Fatalf("NewCodec() error = %v", err)
}
decoded, err := codec.Decode(encodeFixtureCookie(t, codec))
if err != nil {
t.Fatalf("Decode() error = %v", err)
}
encoded, err := codec.Encode(decoded)
if err != nil {
t.Fatalf("Encode() error = %v", err)
}
raw, err := hex.DecodeString(encoded)
if err != nil {
t.Fatalf("hex.DecodeString() error = %v", err)
}
raw[len(raw)-1] ^= 0x01
tampered := hex.EncodeToString(raw)
if _, err := codec.Decode(tampered); err == nil {
t.Fatalf("Decode(tampered) error = nil, want integrity failure")
}
}
func TestNativeCodecRejectsTamperedPlaintextChecksum(t *testing.T) {
codec, err := NewCodec(Config{
CookieName: "PrestaShop-test",
CookieKey: testCookieKey,
CookieIV: "vfRFMV42",
})
if err != nil {
t.Fatalf("NewCodec() error = %v", err)
}
native := codec.(*nativeCodec)
plaintext := "date_add|2026-05-13 18:51:06¤id_lang|5¤id_language|5¤iso_code_country|CZ¤id_currency|9¤id_guest|39160640¤id_connections|13279441¤checksum|181610492"
encoded, err := native.encryptInternal(plaintext)
if err != nil {
t.Fatalf("encryptInternal() error = %v", err)
}
if _, err := codec.Decode(encoded); err == nil {
t.Fatalf("Decode() error = nil, want checksum mismatch")
}
}
func TestSerializeCookieValuesMatchesPrestashopChecksumFormula(t *testing.T) {
values := map[string]string{
"date_add": "2026-05-13 18:51:06",
"id_lang": "5",
"id_language": "5",
"iso_code_country": "CZ",
"id_currency": "1",
"id_guest": "39160640",
"id_connections": "13279441",
"checksum": "stale",
}
orderedKeys := []string{
"date_add",
"id_lang",
"id_language",
"iso_code_country",
"id_currency",
"id_guest",
"id_connections",
"checksum",
}
got := serializeCookieValues(values, orderedKeys, "vfRFMV42")
want := "date_add|2026-05-13 18:51:06¤id_lang|5¤id_language|5¤iso_code_country|CZ¤id_currency|1¤id_guest|39160640¤id_connections|13279441¤checksum|181610492"
if got != want {
t.Fatalf("serializeCookieValues() = %q, want %q", got, want)
}
}
func encodeFixtureCookie(t *testing.T, codec Codec) string {
t.Helper()
session := &SessionContext{
Values: map[string]string{
"id_lang": "1",
"id_cart": "",
"id_language": "1",
"detect_language": "1",
"id_currency": "1",
},
OrderedKeys: []string{
"id_lang",
"id_cart",
"id_language",
"detect_language",
"id_currency",
},
}
encoded, err := codec.Encode(session)
if err != nil {
t.Fatalf("Encode() error = %v", err)
}
return encoded
}