package util import ( "crypto/aes" "crypto/cipher" "encoding/base64" "os" "pocketbase/util" "testing" "github.com/pocketbase/pocketbase/tools/security" ) func TestLooksLikeEncrypted(t *testing.T) { // Sub-test for non-base64 input. t.Run("NonBase64", func(t *testing.T) { if util.LooksLikeEncrypted("not a base64 string!") { t.Errorf("Expected false for non-base64 input") } }) // Sub-test for an empty string. t.Run("EmptyString", func(t *testing.T) { if util.LooksLikeEncrypted("") { t.Errorf("Expected false for empty string") } }) // Create a dummy byte slice to determine the nonce size using a dummy 32-byte key. dummyKey := make([]byte, 32) block, err := aes.NewCipher(dummyKey) if err != nil { t.Fatalf("Failed to create dummy cipher: %v", err) } gcm, err := cipher.NewGCM(block) if err != nil { t.Fatalf("Failed to create dummy GCM: %v", err) } nonceSize := gcm.NonceSize() minSize := nonceSize + 16 // Sub-test for data length less than nonce+16 bytes. t.Run("ShortData", func(t *testing.T) { shortData := make([]byte, minSize-1) encodedShort := base64.StdEncoding.EncodeToString(shortData) if util.LooksLikeEncrypted(encodedShort) { t.Errorf("Expected false for data length < nonce+16, got true") } }) // Sub-test for data length exactly equal to nonce+16 bytes. t.Run("ExactData", func(t *testing.T) { exactData := make([]byte, minSize) encodedExact := base64.StdEncoding.EncodeToString(exactData) if !util.LooksLikeEncrypted(encodedExact) { t.Errorf("Expected true for data length == nonce+16") } }) // Sub-test for data length greater than nonce+16 bytes. t.Run("LongData", func(t *testing.T) { longData := make([]byte, minSize+10) encodedLong := base64.StdEncoding.EncodeToString(longData) if !util.LooksLikeEncrypted(encodedLong) { t.Errorf("Expected true for data length > nonce+16") } }) } func TestCanDecryptSecret(t *testing.T) { // Sub-test: When POCKETBASE_ENCRYPTION_KEY is not set. t.Run("NoEncryptionKey", func(t *testing.T) { os.Unsetenv("POCKETBASE_ENCRYPTION_KEY") if util.CanDecryptSecret("anyciphertext") { t.Errorf("Expected false when POCKETBASE_ENCRYPTION_KEY is not set") } }) // Set a valid 32-byte key (for AES-256). encryptionKey := "0123456789abcdef0123456789abcdef" // exactly 32 bytes os.Setenv("POCKETBASE_ENCRYPTION_KEY", encryptionKey) // Cleanup environment variable after the test. t.Cleanup(func() { os.Unsetenv("POCKETBASE_ENCRYPTION_KEY") }) // Sub-test: Valid ciphertext should return true. t.Run("ValidCiphertext", func(t *testing.T) { plaintext := "my secret message" // Cast plaintext to []byte as required by security.Encrypt. ciphertext, err := security.Encrypt([]byte(plaintext), encryptionKey) if err != nil { t.Fatalf("Failed to encrypt secret: %v", err) } if !util.CanDecryptSecret(ciphertext) { t.Errorf("Expected true for valid ciphertext with correct key") } }) // Sub-test: Invalid ciphertext should return false. t.Run("InvalidCiphertext", func(t *testing.T) { invalidCiphertext := "invalid_ciphertext" if util.CanDecryptSecret(invalidCiphertext) { t.Errorf("Expected false for invalid ciphertext") } }) }