92 lines
3.2 KiB
Python
92 lines
3.2 KiB
Python
import pytest
|
|
from cryptography.fernet import Fernet
|
|
|
|
from infrasynth.shared.crypto import decrypt, encrypt, generate_key, rotate_keys
|
|
|
|
|
|
class TestEncryptDecrypt:
|
|
def test_roundtrip(self):
|
|
token = encrypt("hello-world")
|
|
assert decrypt(token) == "hello-world"
|
|
|
|
def test_different_plaintexts(self):
|
|
for text in ["a", "hello", "data with spaces", "12345", ""]:
|
|
assert decrypt(encrypt(text)) == text
|
|
|
|
def test_encrypted_values_differ(self):
|
|
t1 = encrypt("same")
|
|
t2 = encrypt("same")
|
|
assert t1 != t2
|
|
|
|
def test_decrypt_invalid_token(self):
|
|
with pytest.raises(ValueError, match="Invalid Fernet token"):
|
|
decrypt("invalid-token-here")
|
|
|
|
def test_decrypt_garbage(self):
|
|
with pytest.raises(ValueError, match="Invalid Fernet token"):
|
|
decrypt("AAAA")
|
|
|
|
def test_decrypt_empty_string(self):
|
|
with pytest.raises(ValueError, match="Invalid Fernet token"):
|
|
decrypt("")
|
|
|
|
|
|
class TestGenerateKey:
|
|
def test_generates_string(self):
|
|
key = generate_key()
|
|
assert isinstance(key, str)
|
|
assert len(key) > 0
|
|
|
|
def test_keys_are_unique(self):
|
|
keys = {generate_key() for _ in range(10)}
|
|
assert len(keys) == 10
|
|
|
|
def test_key_is_valid_fernet_key(self):
|
|
key = generate_key()
|
|
Fernet(key.encode())
|
|
|
|
|
|
class TestRotateKeys:
|
|
def _encrypt_with_key(self, key: str, value: str) -> str:
|
|
f = Fernet(key.encode())
|
|
return f.encrypt(value.encode()).decode()
|
|
|
|
def test_rotate_single_token(self):
|
|
old_key = generate_key()
|
|
new_key = generate_key()
|
|
token = self._encrypt_with_key(old_key, "secret-value")
|
|
rotated = rotate_keys(old_key, new_key, [token])
|
|
assert len(rotated) == 1
|
|
assert rotated[0] != token
|
|
f = Fernet(new_key.encode())
|
|
assert f.decrypt(rotated[0].encode()).decode() == "secret-value"
|
|
|
|
def test_rotate_multiple_tokens(self):
|
|
old_key = generate_key()
|
|
new_key = generate_key()
|
|
values = [f"value-{i}" for i in range(5)]
|
|
tokens = [self._encrypt_with_key(old_key, v) for v in values]
|
|
rotated = rotate_keys(old_key, new_key, tokens)
|
|
assert len(rotated) == 5
|
|
f = Fernet(new_key.encode())
|
|
for plaintext, cipher in zip(values, rotated):
|
|
assert f.decrypt(cipher.encode()).decode() == plaintext
|
|
|
|
def test_rotate_with_same_key(self):
|
|
key = generate_key()
|
|
token = self._encrypt_with_key(key, "persistent")
|
|
rotated = rotate_keys(key, key, [token])
|
|
assert len(rotated) == 1
|
|
assert rotated[0] != token
|
|
f = Fernet(key.encode())
|
|
assert f.decrypt(rotated[0].encode()).decode() == "persistent"
|
|
|
|
def test_rotate_preserves_all_values(self):
|
|
old_key = generate_key()
|
|
new_key = generate_key()
|
|
values = ["keep-me-safe", "another-value", "123"]
|
|
tokens = [self._encrypt_with_key(old_key, v) for v in values]
|
|
rotated = rotate_keys(old_key, new_key, tokens)
|
|
f = Fernet(new_key.encode())
|
|
for original, cipher in zip(values, rotated):
|
|
assert f.decrypt(cipher.encode()).decode() == original
|