mirror of
https://github.com/StarFleetCPTN/GoMFT.git
synced 2026-10-18 12:08:16 +02:00
feat: Implement storage provider management functionality
- Added new routes and handlers for managing storage providers, including creation, editing, and deletion. - Introduced a new StorageProvider form component for user input. - Enhanced the database schema to support storage provider references in transfer configurations. - Implemented encryption for sensitive fields in storage provider data. - Added tests for storage provider API endpoints and integration with the database. - Updated frontend components to support storage provider selection and testing.
This commit is contained in:
1 parent
88d0ac815a
commit
31871bd16e
59 files changed
+15842
-594
No files matched your search
@@ -0,0 +1,329 @@
|
||||
package encryption
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func setupCredentialEncryptor(t *testing.T) *CredentialEncryptor {
|
||||
encService := setupEncryptionService(t)
|
||||
credEncryptor, err := NewCredentialEncryptor(encService)
|
||||
require.NoError(t, err)
|
||||
return credEncryptor
|
||||
}
|
||||
|
||||
func TestNewCredentialEncryptor(t *testing.T) {
|
||||
t.Run("Valid encryption service", func(t *testing.T) {
|
||||
encService := setupEncryptionService(t)
|
||||
credEncryptor, err := NewCredentialEncryptor(encService)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, credEncryptor)
|
||||
})
|
||||
|
||||
t.Run("Nil encryption service", func(t *testing.T) {
|
||||
credEncryptor, err := NewCredentialEncryptor(nil)
|
||||
require.Error(t, err)
|
||||
assert.Nil(t, credEncryptor)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCredentialEncryptor_Encrypt(t *testing.T) {
|
||||
credEncryptor := setupCredentialEncryptor(t)
|
||||
|
||||
t.Run("Encrypt password", func(t *testing.T) {
|
||||
password := "securePassword123"
|
||||
encrypted, err := credEncryptor.EncryptPassword(password)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, strings.HasPrefix(encrypted, EncryptedPrefix))
|
||||
|
||||
// Check that we can decrypt it
|
||||
decrypted, err := credEncryptor.Decrypt(encrypted)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, password, decrypted)
|
||||
})
|
||||
|
||||
t.Run("Encrypt API key", func(t *testing.T) {
|
||||
apiKey := "api_12345678901234567890abcdef"
|
||||
encrypted, err := credEncryptor.EncryptAPIKey(apiKey)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, strings.HasPrefix(encrypted, EncryptedPrefix))
|
||||
|
||||
// Check that we can decrypt it
|
||||
decrypted, err := credEncryptor.Decrypt(encrypted)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, apiKey, decrypted)
|
||||
})
|
||||
|
||||
t.Run("Encrypt empty value", func(t *testing.T) {
|
||||
encrypted, err := credEncryptor.Encrypt("", TypePassword)
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, ErrEmptyCredential, err)
|
||||
assert.Empty(t, encrypted)
|
||||
})
|
||||
|
||||
t.Run("Encrypt value with invalid type", func(t *testing.T) {
|
||||
encrypted, err := credEncryptor.Encrypt("somevalue", "invalid_type")
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), ErrUnsupportedType.Error())
|
||||
assert.Empty(t, encrypted)
|
||||
})
|
||||
|
||||
t.Run("Password validation", func(t *testing.T) {
|
||||
shortPassword := "short"
|
||||
encrypted, err := credEncryptor.EncryptPassword(shortPassword)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "password too short")
|
||||
assert.Empty(t, encrypted)
|
||||
})
|
||||
|
||||
t.Run("API key validation", func(t *testing.T) {
|
||||
shortAPIKey := "short"
|
||||
encrypted, err := credEncryptor.EncryptAPIKey(shortAPIKey)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "too short")
|
||||
assert.Empty(t, encrypted)
|
||||
})
|
||||
|
||||
t.Run("Already encrypted value", func(t *testing.T) {
|
||||
password := "securePassword123"
|
||||
encrypted, err := credEncryptor.EncryptPassword(password)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Try to encrypt again
|
||||
doubleEncrypted, err := credEncryptor.Encrypt(encrypted, TypePassword)
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, ErrAlreadyEncrypted, err)
|
||||
assert.Empty(t, doubleEncrypted)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCredentialEncryptor_Decrypt(t *testing.T) {
|
||||
credEncryptor := setupCredentialEncryptor(t)
|
||||
|
||||
t.Run("Decrypt encrypted value", func(t *testing.T) {
|
||||
original := "securePassword123"
|
||||
encrypted, err := credEncryptor.EncryptPassword(original)
|
||||
require.NoError(t, err)
|
||||
|
||||
decrypted, err := credEncryptor.Decrypt(encrypted)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, original, decrypted)
|
||||
})
|
||||
|
||||
t.Run("Decrypt empty value", func(t *testing.T) {
|
||||
decrypted, err := credEncryptor.Decrypt("")
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, ErrEmptyCredential, err)
|
||||
assert.Empty(t, decrypted)
|
||||
})
|
||||
|
||||
t.Run("Decrypt non-encrypted value", func(t *testing.T) {
|
||||
decrypted, err := credEncryptor.Decrypt("notEncrypted")
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, ErrNotEncrypted, err)
|
||||
assert.Empty(t, decrypted)
|
||||
})
|
||||
|
||||
t.Run("Decrypt corrupted value", func(t *testing.T) {
|
||||
original := "securePassword123"
|
||||
encrypted, err := credEncryptor.EncryptPassword(original)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Remove the prefix for manipulation
|
||||
encryptedWithoutPrefix := strings.TrimPrefix(encrypted, EncryptedPrefix)
|
||||
|
||||
// Base64 decode the encrypted content
|
||||
decoded, err := base64.StdEncoding.DecodeString(encryptedWithoutPrefix)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Find position in the actual ciphertext (after the IV)
|
||||
if len(decoded) > 20 {
|
||||
// Corrupt a byte in the ciphertext portion (not in the IV)
|
||||
decoded[20] ^= 0xFF // Flip all bits in this byte
|
||||
|
||||
// Re-encode to base64
|
||||
corrupted := EncryptedPrefix + base64.StdEncoding.EncodeToString(decoded)
|
||||
|
||||
// This should fail to decrypt
|
||||
decrypted, err := credEncryptor.Decrypt(corrupted)
|
||||
require.Error(t, err, "Decryption should fail with corrupted data")
|
||||
assert.Empty(t, decrypted)
|
||||
} else {
|
||||
t.Skip("Encrypted data too short to corrupt properly")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestCredentialEncryptor_EncryptField(t *testing.T) {
|
||||
credEncryptor := setupCredentialEncryptor(t)
|
||||
|
||||
t.Run("Encrypt non-encrypted field", func(t *testing.T) {
|
||||
field := "securePassword123"
|
||||
encrypted, err := credEncryptor.EncryptField(field, TypePassword)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, strings.HasPrefix(encrypted, EncryptedPrefix))
|
||||
})
|
||||
|
||||
t.Run("Already encrypted field", func(t *testing.T) {
|
||||
original := "securePassword123"
|
||||
encrypted, err := credEncryptor.EncryptPassword(original)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Try to encrypt again using EncryptField
|
||||
result, err := credEncryptor.EncryptField(encrypted, TypePassword)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, encrypted, result, "EncryptField should return the already encrypted value")
|
||||
})
|
||||
|
||||
t.Run("Empty field", func(t *testing.T) {
|
||||
result, err := credEncryptor.EncryptField("", TypePassword)
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, result, "EncryptField should return empty for empty input")
|
||||
})
|
||||
}
|
||||
|
||||
func TestCredentialEncryptor_DecryptField(t *testing.T) {
|
||||
credEncryptor := setupCredentialEncryptor(t)
|
||||
|
||||
t.Run("Decrypt encrypted field", func(t *testing.T) {
|
||||
original := "securePassword123"
|
||||
encrypted, err := credEncryptor.EncryptPassword(original)
|
||||
require.NoError(t, err)
|
||||
|
||||
decrypted, err := credEncryptor.DecryptField(encrypted)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, original, decrypted)
|
||||
})
|
||||
|
||||
t.Run("Non-encrypted field", func(t *testing.T) {
|
||||
field := "plaintext"
|
||||
result, err := credEncryptor.DecryptField(field)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, field, result, "DecryptField should return non-encrypted value as is")
|
||||
})
|
||||
|
||||
t.Run("Empty field", func(t *testing.T) {
|
||||
result, err := credEncryptor.DecryptField("")
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, result, "DecryptField should return empty for empty input")
|
||||
})
|
||||
}
|
||||
|
||||
func TestSanitizeCredential(t *testing.T) {
|
||||
t.Run("Sanitize plaintext", func(t *testing.T) {
|
||||
original := "plainTextPassword123"
|
||||
sanitized := SanitizeCredential(original)
|
||||
assert.NotEqual(t, original, sanitized)
|
||||
assert.True(t, len(sanitized) < len(original))
|
||||
assert.Contains(t, sanitized, "...")
|
||||
})
|
||||
|
||||
t.Run("Sanitize encrypted value", func(t *testing.T) {
|
||||
credEncryptor := setupCredentialEncryptor(t)
|
||||
original := "securePassword123"
|
||||
encrypted, err := credEncryptor.EncryptPassword(original)
|
||||
require.NoError(t, err)
|
||||
|
||||
sanitized := SanitizeCredential(encrypted)
|
||||
assert.NotEqual(t, encrypted, sanitized)
|
||||
assert.True(t, strings.HasPrefix(sanitized, EncryptedPrefix))
|
||||
assert.Contains(t, sanitized, "...")
|
||||
})
|
||||
|
||||
t.Run("Sanitize empty value", func(t *testing.T) {
|
||||
sanitized := SanitizeCredential("")
|
||||
assert.Empty(t, sanitized)
|
||||
})
|
||||
|
||||
t.Run("Sanitize short value", func(t *testing.T) {
|
||||
sanitized := SanitizeCredential("short")
|
||||
assert.Equal(t, "****", sanitized)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRequiresEncryption(t *testing.T) {
|
||||
testCases := []struct {
|
||||
fieldName string
|
||||
requiresEncryption bool
|
||||
expectedType CredentialType
|
||||
}{
|
||||
{"password", true, TypePassword},
|
||||
{"userPassword", true, TypePassword},
|
||||
{"passwd", true, TypePassword},
|
||||
{"pwd", true, TypePassword},
|
||||
{"apiKey", true, TypeAPIKey},
|
||||
{"api_key", true, TypeAPIKey},
|
||||
{"secretKey", true, TypeSecretKey},
|
||||
{"secret_key", true, TypeSecretKey},
|
||||
{"accessToken", true, TypeAccessToken},
|
||||
{"access_token", true, TypeAccessToken},
|
||||
{"refreshToken", true, TypeRefreshToken},
|
||||
{"refresh_token", true, TypeRefreshToken},
|
||||
{"oauthToken", true, TypeOAuthToken},
|
||||
{"oauth_refresh_token", true, TypeOAuthToken},
|
||||
{"sshKey", true, TypeSSHKey},
|
||||
{"ssh_key", true, TypeSSHKey},
|
||||
{"privateKey", true, TypeSSHKey},
|
||||
{"private_key", true, TypeSSHKey},
|
||||
{"authToken", true, TypeGeneric},
|
||||
{"secret", true, TypeGeneric},
|
||||
{"key", true, TypeGeneric},
|
||||
{"token", true, TypeGeneric},
|
||||
{"username", false, ""},
|
||||
{"email", false, ""},
|
||||
{"address", false, ""},
|
||||
{"name", false, ""},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.fieldName, func(t *testing.T) {
|
||||
requires, credType := RequiresEncryption(tc.fieldName)
|
||||
assert.Equal(t, tc.requiresEncryption, requires)
|
||||
if tc.requiresEncryption {
|
||||
assert.Equal(t, tc.expectedType, credType)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetGlobalCredentialEncryptor(t *testing.T) {
|
||||
// Setup environment for global encryption service
|
||||
testEnvVar := DefaultKeyEnvVar
|
||||
validKey := make([]byte, AES256KeySize)
|
||||
for i := range validKey {
|
||||
validKey[i] = byte(i % 256)
|
||||
}
|
||||
validKeyBase64 := encodeBase64(validKey)
|
||||
|
||||
// Set a valid key in environment
|
||||
setenv(t, testEnvVar, validKeyBase64)
|
||||
|
||||
// Get global credential encryptor
|
||||
credEncryptor, err := GetGlobalCredentialEncryptor()
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, credEncryptor)
|
||||
|
||||
// Test that it works
|
||||
testValue := "testPassword123"
|
||||
encrypted, err := credEncryptor.EncryptPassword(testValue)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, strings.HasPrefix(encrypted, EncryptedPrefix))
|
||||
|
||||
decrypted, err := credEncryptor.Decrypt(encrypted)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testValue, decrypted)
|
||||
}
|
||||
|
||||
// Utility functions for testing
|
||||
|
||||
func encodeBase64(data []byte) string {
|
||||
return base64.StdEncoding.EncodeToString(data)
|
||||
}
|
||||
|
||||
func setenv(t *testing.T, key, value string) {
|
||||
t.Setenv(key, value)
|
||||
}
|
||||
Reference in new issue
Block a user