mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-04-02 22:28:51 +00:00
70 lines
2.8 KiB
Python
70 lines
2.8 KiB
Python
import hmac
|
|
import pickle
|
|
from hashlib import sha256
|
|
|
|
import pytest
|
|
from django.test import override_settings
|
|
|
|
from paperless.celery import HMAC_SIZE
|
|
from paperless.celery import signed_pickle_dumps
|
|
from paperless.celery import signed_pickle_loads
|
|
|
|
|
|
class TestSignedPickleSerializer:
|
|
def test_roundtrip_simple_types(self):
|
|
"""Signed pickle can round-trip basic JSON-like types."""
|
|
for obj in [42, "hello", [1, 2, 3], {"key": "value"}, None, True]:
|
|
assert signed_pickle_loads(signed_pickle_dumps(obj)) == obj
|
|
|
|
def test_roundtrip_complex_types(self):
|
|
"""Signed pickle can round-trip types that JSON cannot."""
|
|
from pathlib import Path
|
|
|
|
obj = {"path": Path("/tmp/test"), "data": {1, 2, 3}}
|
|
result = signed_pickle_loads(signed_pickle_dumps(obj))
|
|
assert result["path"] == Path("/tmp/test")
|
|
assert result["data"] == {1, 2, 3}
|
|
|
|
def test_tampered_data_rejected(self):
|
|
"""Flipping a byte in the data portion causes HMAC failure."""
|
|
payload = signed_pickle_dumps({"task": "test"})
|
|
tampered = bytearray(payload)
|
|
tampered[-1] ^= 0xFF
|
|
with pytest.raises(ValueError, match="HMAC verification failed"):
|
|
signed_pickle_loads(bytes(tampered))
|
|
|
|
def test_tampered_signature_rejected(self):
|
|
"""Flipping a byte in the signature portion causes HMAC failure."""
|
|
payload = signed_pickle_dumps({"task": "test"})
|
|
tampered = bytearray(payload)
|
|
tampered[0] ^= 0xFF
|
|
with pytest.raises(ValueError, match="HMAC verification failed"):
|
|
signed_pickle_loads(bytes(tampered))
|
|
|
|
def test_truncated_payload_rejected(self):
|
|
"""A payload shorter than HMAC_SIZE is rejected."""
|
|
with pytest.raises(ValueError, match="too short"):
|
|
signed_pickle_loads(b"\x00" * (HMAC_SIZE - 1))
|
|
|
|
def test_empty_payload_rejected(self):
|
|
with pytest.raises(ValueError, match="too short"):
|
|
signed_pickle_loads(b"")
|
|
|
|
@override_settings(SECRET_KEY="different-secret-key")
|
|
def test_wrong_secret_key_rejected(self):
|
|
"""A message signed with one key cannot be loaded with another."""
|
|
original_key = b"test-secret-key-do-not-use-in-production"
|
|
obj = {"task": "test"}
|
|
data = pickle.dumps(obj, protocol=pickle.HIGHEST_PROTOCOL)
|
|
signature = hmac.new(original_key, data, sha256).digest()
|
|
payload = signature + data
|
|
with pytest.raises(ValueError, match="HMAC verification failed"):
|
|
signed_pickle_loads(payload)
|
|
|
|
def test_forged_pickle_rejected(self):
|
|
"""A raw pickle payload (no signature) is rejected."""
|
|
raw_pickle = pickle.dumps({"task": "test"})
|
|
# Raw pickle won't have a valid HMAC prefix
|
|
with pytest.raises(ValueError, match="HMAC verification failed"):
|
|
signed_pickle_loads(b"\x00" * HMAC_SIZE + raw_pickle)
|