gogcli/internal/tracking/crypto_test.go
2026-04-28 10:22:55 +01:00

145 lines
3.2 KiB
Go

package tracking
import (
"encoding/base64"
"testing"
"time"
)
func TestEncryptDecryptRoundTrip(t *testing.T) {
key, err := GenerateKey()
if err != nil {
t.Fatalf("GenerateKey failed: %v", err)
}
payload := &PixelPayload{
Recipient: "test@example.com",
SubjectHash: "abc123",
SentAt: time.Now().Unix(),
}
encrypted, err := Encrypt(payload, key)
if err != nil {
t.Fatalf("Encrypt failed: %v", err)
}
decrypted, err := Decrypt(encrypted, key)
if err != nil {
t.Fatalf("Decrypt failed: %v", err)
}
if decrypted.Recipient != payload.Recipient {
t.Errorf("Recipient mismatch: got %q, want %q", decrypted.Recipient, payload.Recipient)
}
if decrypted.SubjectHash != payload.SubjectHash {
t.Errorf("SubjectHash mismatch: got %q, want %q", decrypted.SubjectHash, payload.SubjectHash)
}
if decrypted.SentAt != payload.SentAt {
t.Errorf("SentAt mismatch: got %d, want %d", decrypted.SentAt, payload.SentAt)
}
}
func TestEncryptProducesURLSafeOutput(t *testing.T) {
key, _ := GenerateKey()
payload := &PixelPayload{
Recipient: "test@example.com",
SubjectHash: "abc123",
SentAt: time.Now().Unix(),
}
encrypted, err := Encrypt(payload, key)
if err != nil {
t.Fatalf("Encrypt failed: %v", err)
}
// URL-safe base64 should not contain +, /, or =
for _, c := range encrypted {
if c == '+' || c == '/' || c == '=' {
t.Errorf("Output contains non-URL-safe character: %c", c)
}
}
}
func TestDecryptWithWrongKeyFails(t *testing.T) {
key1, _ := GenerateKey()
key2, _ := GenerateKey()
payload := &PixelPayload{
Recipient: "test@example.com",
SubjectHash: "abc123",
SentAt: time.Now().Unix(),
}
encrypted, _ := Encrypt(payload, key1)
_, err := Decrypt(encrypted, key2)
if err == nil {
t.Error("Expected error when decrypting with wrong key")
}
}
func TestEncryptWithVersionDecryptsWithActiveKeys(t *testing.T) {
oldKey, _ := GenerateKey()
newKey, _ := GenerateKey()
payload := &PixelPayload{
Recipient: "test@example.com",
SubjectHash: "abc123",
SentAt: time.Now().Unix(),
}
encrypted, err := EncryptWithVersion(payload, newKey, 2)
if err != nil {
t.Fatalf("EncryptWithVersion failed: %v", err)
}
raw, err := base64.RawURLEncoding.DecodeString(encrypted)
if err != nil {
t.Fatalf("decode encrypted blob: %v", err)
}
if got := int(raw[0]); got != 2 {
t.Fatalf("version prefix = %d, want 2", got)
}
decrypted, err := DecryptWithKeys(encrypted, map[int]string{
1: oldKey,
2: newKey,
})
if err != nil {
t.Fatalf("DecryptWithKeys failed: %v", err)
}
if *decrypted != *payload {
t.Fatalf("decrypted payload = %#v, want %#v", decrypted, payload)
}
}
func TestDecryptWithKeysAcceptsLegacyBlobs(t *testing.T) {
oldKey, _ := GenerateKey()
newKey, _ := GenerateKey()
payload := &PixelPayload{
Recipient: "test@example.com",
SubjectHash: "abc123",
SentAt: time.Now().Unix(),
}
encrypted, err := Encrypt(payload, oldKey)
if err != nil {
t.Fatalf("Encrypt failed: %v", err)
}
decrypted, err := DecryptWithKeys(encrypted, map[int]string{
1: oldKey,
2: newKey,
})
if err != nil {
t.Fatalf("DecryptWithKeys legacy failed: %v", err)
}
if *decrypted != *payload {
t.Fatalf("decrypted payload = %#v, want %#v", decrypted, payload)
}
}