package services import ( "encoding/base64" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestNewCryptoService_InvalidKey(t *testing.T) { _, err := NewCryptoService([]byte("short")) require.Error(t, err) assert.Contains(t, err.Error(), "32 bytes") } func TestNewCryptoService_ValidKey(t *testing.T) { key := make([]byte, 32) for i := range key { key[i] = byte(i) } svc, err := NewCryptoService(key) require.NoError(t, err) assert.NotNil(t, svc) } func TestCryptoService_EncryptDecrypt_Roundtrip(t *testing.T) { key := make([]byte, 32) for i := range key { key[i] = byte(i) } svc, err := NewCryptoService(key) require.NoError(t, err) plaintext := []byte("sensitive-oauth-token-value") enc, err := svc.Encrypt(plaintext) require.NoError(t, err) assert.NotEqual(t, plaintext, enc) assert.NotEmpty(t, enc) dec, err := svc.Decrypt(enc) require.NoError(t, err) assert.Equal(t, plaintext, dec) } func TestCryptoService_EncryptDecrypt_DifferentEachTime(t *testing.T) { key := make([]byte, 32) for i := range key { key[i] = byte(i) } svc, err := NewCryptoService(key) require.NoError(t, err) plaintext := []byte("token") enc1, err := svc.Encrypt(plaintext) require.NoError(t, err) enc2, err := svc.Encrypt(plaintext) require.NoError(t, err) assert.NotEqual(t, enc1, enc2, "encryption should be non-deterministic (random nonce)") dec1, err := svc.Decrypt(enc1) require.NoError(t, err) dec2, err := svc.Decrypt(enc2) require.NoError(t, err) assert.Equal(t, plaintext, dec1) assert.Equal(t, plaintext, dec2) } func TestCryptoService_EncryptString_DecryptString_Roundtrip(t *testing.T) { key := make([]byte, 32) for i := range key { key[i] = byte(i) } svc, err := NewCryptoService(key) require.NoError(t, err) plaintext := "my-access-token-123" enc, err := svc.EncryptString(plaintext) require.NoError(t, err) assert.True(t, strings.HasPrefix(enc, EncryptedTokenPrefix())) assert.NotEqual(t, plaintext, enc) dec, err := svc.DecryptString(enc) require.NoError(t, err) assert.Equal(t, plaintext, dec) } func TestCryptoService_DecryptString_Plaintext(t *testing.T) { key := make([]byte, 32) for i := range key { key[i] = byte(i) } svc, err := NewCryptoService(key) require.NoError(t, err) // Legacy plaintext (no prefix) -> returned as-is plain := "legacy-token" dec, err := svc.DecryptString(plain) require.NoError(t, err) assert.Equal(t, plain, dec) } func TestCryptoService_DecryptString_Empty(t *testing.T) { key := make([]byte, 32) svc, err := NewCryptoService(key) require.NoError(t, err) dec, err := svc.DecryptString("") require.NoError(t, err) assert.Empty(t, dec) } func TestCryptoService_EncryptString_Empty(t *testing.T) { key := make([]byte, 32) svc, err := NewCryptoService(key) require.NoError(t, err) enc, err := svc.EncryptString("") require.NoError(t, err) assert.Empty(t, enc) } func TestCryptoService_Decrypt_ModifiedCiphertext(t *testing.T) { key := make([]byte, 32) for i := range key { key[i] = byte(i) } svc, err := NewCryptoService(key) require.NoError(t, err) enc, err := svc.Encrypt([]byte("token")) require.NoError(t, err) enc[20] ^= 0xff // flip a byte _, err = svc.Decrypt(enc) require.Error(t, err) } func TestNewCryptoServiceFromBase64(t *testing.T) { key := make([]byte, 32) for i := range key { key[i] = byte(i) } keyB64 := base64.RawStdEncoding.EncodeToString(key) svc, err := NewCryptoServiceFromBase64(keyB64) require.NoError(t, err) assert.NotNil(t, svc) enc, err := svc.EncryptString("test") require.NoError(t, err) dec, err := svc.DecryptString(enc) require.NoError(t, err) assert.Equal(t, "test", dec) } func TestNewCryptoServiceFromBase64_Empty(t *testing.T) { _, err := NewCryptoServiceFromBase64("") require.Error(t, err) }