improve signed reads, crypto hardening, and scraper transport
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
"""enc:v2 envelope encryption (H4): roundtrip, legacy v1 compat, format checks."""
|
||||
import base64
|
||||
import hashlib
|
||||
|
||||
import pytest
|
||||
from cryptography.fernet import Fernet
|
||||
|
||||
from app.services import crypto
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _kek(monkeypatch):
|
||||
monkeypatch.setattr(crypto.settings, "encryption_key", "k" * 64)
|
||||
# Reset module caches so each test derives from the patched KEK.
|
||||
crypto._fernet_v1 = None
|
||||
crypto._fernet_v2_cache.clear()
|
||||
crypto._encrypt_salt = None
|
||||
yield
|
||||
crypto._fernet_v1 = None
|
||||
crypto._fernet_v2_cache.clear()
|
||||
crypto._encrypt_salt = None
|
||||
|
||||
|
||||
def test_v2_roundtrip():
|
||||
blob = crypto.encrypt_api_key("0x" + "ab" * 32)
|
||||
assert blob.startswith(crypto.ENC_PREFIX_V2)
|
||||
assert crypto.decrypt_api_key(blob) == "0x" + "ab" * 32
|
||||
assert crypto.is_current_format(blob)
|
||||
# Fits the hl_api_key String(256) column.
|
||||
assert len(blob) <= 256
|
||||
|
||||
|
||||
def test_v1_blob_still_decrypts():
|
||||
# Build a v1 blob exactly the way the legacy code did.
|
||||
digest = hashlib.sha256(("k" * 64).encode()).digest()
|
||||
f = Fernet(base64.urlsafe_b64encode(digest))
|
||||
blob = crypto.ENC_PREFIX_V1 + f.encrypt(b"secret-key").decode()
|
||||
assert not crypto.is_current_format(blob)
|
||||
assert crypto.decrypt_api_key(blob) == "secret-key"
|
||||
|
||||
|
||||
def test_wrong_kek_raises(monkeypatch):
|
||||
blob = crypto.encrypt_api_key("topsecret")
|
||||
monkeypatch.setattr(crypto.settings, "encryption_key", "x" * 64)
|
||||
crypto._fernet_v2_cache.clear()
|
||||
with pytest.raises(RuntimeError):
|
||||
crypto.decrypt_api_key(blob)
|
||||
|
||||
|
||||
def test_malformed_v2_raises():
|
||||
with pytest.raises(RuntimeError):
|
||||
crypto.decrypt_api_key(crypto.ENC_PREFIX_V2 + "no-salt-separator")
|
||||
|
||||
|
||||
def test_plaintext_refused_in_production(monkeypatch):
|
||||
monkeypatch.setattr(crypto.settings, "environment", "production")
|
||||
with pytest.raises(RuntimeError):
|
||||
crypto.decrypt_api_key("raw-plaintext-key")
|
||||
Reference in New Issue
Block a user