""" tests/test_security_auth.py ============================ Unit tests for security/auth.py — JWT, bcrypt hashing, Fernet encryption. """ import time import pytest from jose import jwt, JWTError from security.auth import ( JWT_ALGORITHM, JWT_SECRET_KEY, create_jwt_token, decode_jwt_token, decrypt_data, encrypt_data, hash_password, verify_password, ) # --------------------------------------------------------------------------- # Password hashing (bcrypt) # --------------------------------------------------------------------------- class TestPasswordHashing: def test_hash_is_not_plaintext(self): hashed = hash_password("mysecret123") assert hashed != "mysecret123" assert hashed.startswith("$2b$") def test_verify_correct_password(self): hashed = hash_password("testpass") assert verify_password("testpass", hashed) is True def test_reject_wrong_password(self): hashed = hash_password("correct") assert verify_password("wrong", hashed) is False def test_different_hashes_for_same_password(self): """bcrypt uses a random salt, so two hashes of the same password differ.""" h1 = hash_password("same") h2 = hash_password("same") assert h1 != h2 # But both verify assert verify_password("same", h1) assert verify_password("same", h2) # --------------------------------------------------------------------------- # JWT tokens # --------------------------------------------------------------------------- class TestJWT: def test_create_and_decode(self): token = create_jwt_token({"sub": "alice"}) payload = decode_jwt_token(token) assert payload["sub"] == "alice" assert "exp" in payload def test_token_contains_custom_data(self): token = create_jwt_token({"sub": "bob", "role": "admin"}) payload = decode_jwt_token(token) assert payload["role"] == "admin" def test_expired_token_raises(self): from datetime import timedelta token = create_jwt_token( {"sub": "charlie"}, expires_delta=timedelta(seconds=-1) ) with pytest.raises(Exception): decode_jwt_token(token) def test_tampered_token_raises(self): token = create_jwt_token({"sub": "dave"}) # Tamper with the token tampered = token[:-5] + "XXXXX" with pytest.raises(Exception): decode_jwt_token(tampered) # --------------------------------------------------------------------------- # Fernet encryption (AES-256) # --------------------------------------------------------------------------- class TestFernetEncryption: def test_encrypt_decrypt_dict(self): data = {"scores": [0.5, 0.8], "timestamps": [1000.0, 2000.0]} encrypted = encrypt_data(data) assert isinstance(encrypted, str) assert encrypted != str(data) decrypted = decrypt_data(encrypted) assert decrypted == data def test_encrypt_decrypt_list(self): data = [[1000.0, 0.5], [2000.0, 0.8]] encrypted = encrypt_data(data) decrypted = decrypt_data(encrypted) assert decrypted == data def test_encrypted_is_not_plaintext(self): data = {"secret": "value"} encrypted = encrypt_data(data) assert "secret" not in encrypted assert "value" not in encrypted def test_decrypt_corrupted_returns_none(self): result = decrypt_data("not-a-valid-ciphertext") assert result is None def test_encrypt_empty_list(self): encrypted = encrypt_data([]) assert decrypt_data(encrypted) == []