diff --git a/backend/app/core/security.py b/backend/app/core/security.py index 8e88678..825fd28 100644 --- a/backend/app/core/security.py +++ b/backend/app/core/security.py @@ -8,7 +8,7 @@ from jose import JWTError, jwt from passlib.context import CryptContext from cryptography.fernet import Fernet from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2 +from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC import base64 from app.core.config import settings @@ -84,13 +84,13 @@ class CredentialEncryption: # Generate salt - in production, this should be unique per user if user_id is not None: # Per-user salt for production - salt = f'pop3_forwarder_user_{user_id}'.encode('utf-8')[:16].ljust(16, b'0') + salt = f'pop3fwd_usr_{user_id}'.encode('utf-8')[:16].ljust(16, b'\x00') else: # Default salt for system-wide operations (use with caution) salt = b'pop3_forwarder_0' # Derive a proper Fernet key from the provided key - kdf = PBKDF2( + kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, diff --git a/backend/requirements.txt b/backend/requirements.txt index 75c8520..fcaaa0c 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -56,6 +56,3 @@ faker==22.6.0 python-dotenv==1.0.0 schedule==1.2.0 tenacity==8.2.3 - -# Legacy support (for migration) -poplib3==0.0.4 diff --git a/backend/tests/unit/test_security.py b/backend/tests/unit/test_security.py index 2a6f246..b4c2d14 100644 --- a/backend/tests/unit/test_security.py +++ b/backend/tests/unit/test_security.py @@ -6,8 +6,7 @@ from app.core.security import ( get_password_hash, verify_password, create_access_token, - encrypt_password, - decrypt_password, + CredentialEncryption, ) @@ -60,7 +59,8 @@ class TestEncryption: password = "mailpassword123" user_id = 1 - encrypted = encrypt_password(password, user_id) + encryptor = CredentialEncryption(user_id=user_id) + encrypted = encryptor.encrypt(password) assert encrypted != password assert len(encrypted) > 50 @@ -70,8 +70,9 @@ class TestEncryption: password = "mailpassword123" user_id = 1 - encrypted = encrypt_password(password, user_id) - decrypted = decrypt_password(encrypted, user_id) + encryptor = CredentialEncryption(user_id=user_id) + encrypted = encryptor.encrypt(password) + decrypted = encryptor.decrypt(encrypted) assert decrypted == password @@ -81,15 +82,18 @@ class TestEncryption: user_id_1 = 1 user_id_2 = 2 - encrypted_1 = encrypt_password(password, user_id_1) - encrypted_2 = encrypt_password(password, user_id_2) + encryptor_1 = CredentialEncryption(user_id=user_id_1) + encryptor_2 = CredentialEncryption(user_id=user_id_2) + + encrypted_1 = encryptor_1.encrypt(password) + encrypted_2 = encryptor_2.encrypt(password) # Different users should produce different encrypted values assert encrypted_1 != encrypted_2 # But decryption should work correctly for each - assert decrypt_password(encrypted_1, user_id_1) == password - assert decrypt_password(encrypted_2, user_id_2) == password + assert encryptor_1.decrypt(encrypted_1) == password + assert encryptor_2.decrypt(encrypted_2) == password def test_decrypt_with_wrong_user_id_fails(self): """Test that decryption fails with wrong user ID""" @@ -97,7 +101,10 @@ class TestEncryption: user_id = 1 wrong_user_id = 2 - encrypted = encrypt_password(password, user_id) + encryptor = CredentialEncryption(user_id=user_id) + wrong_encryptor = CredentialEncryption(user_id=wrong_user_id) + + encrypted = encryptor.encrypt(password) with pytest.raises(Exception): - decrypt_password(encrypted, wrong_user_id) + wrong_encryptor.decrypt(encrypted)