Add a pytest suite covering the pure logic of the DeDRM and Obok plugins.
Because the plugins normally run inside calibre and use intra-package
imports, tests/dedrm_test_utils.py sets up an import shim (plugin dirs on
sys.path, a minimal calibre stub, and a synthetic `dedrm` package) so the
modules can be imported and exercised standalone.
Coverage:
- alfcrypto: PC1 and Topaz cipher round-trips, PBKDF2 vs hashlib.
- kgenpids / kindlepid: PID encoding, bit-field extraction, device-PID
and serial-PID known vectors, CRC32.
- mobidedrm: PC1 round-trip, trailing-data sizing, bad-key handling.
- ineptpdf / ineptepub: nunpack and PKCS7 unpad.
- topazextract: encoded number/string parsing, plus a regression test
that a malicious header tag ("../../evil") cannot escape the output
directory (covers the path-traversal fix).
- obok: unpad, hash-key table, SafeUnbuffered str/bytes handling.
- utilities / argv_utils: uStrCmp normalisation, unicode_argv.
- erdr2pml: deXOR/sanitiseFileName, skipped on Python 3.13+ where the
module's `cgi` import is unavailable.
Run with `poetry install` then `poetry run pytest`. 36 pass, 2 skip on
Python 3.13+.
Note: this surfaced two dead-code modules that are broken on Python 3
(aescbc's pure-Python AES and kgenpids.decode, neither on a live path,
since the real crypto goes through pycryptodome); left as-is here.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
34 lines
992 B
Python
34 lines
992 B
Python
"""Tests for erdr2pml helpers.
|
|
|
|
erdr2pml imports the stdlib ``cgi`` module, which was removed in Python 3.13.
|
|
On such interpreters the whole module is unimportable, so these tests are
|
|
skipped (calibre currently ships Python 3.8-3.11, where they run).
|
|
"""
|
|
|
|
import pytest
|
|
|
|
import dedrm_test_utils as U
|
|
|
|
try:
|
|
erdr2pml = U.load("erdr2pml", package="dedrm")
|
|
_skip_reason = None
|
|
except Exception as exc: # pragma: no cover - depends on interpreter version
|
|
erdr2pml = None
|
|
_skip_reason = "erdr2pml not importable: {0}".format(exc)
|
|
|
|
pytestmark = pytest.mark.skipif(erdr2pml is None, reason=_skip_reason or "")
|
|
|
|
|
|
def test_dexor_is_involutive():
|
|
table = bytes(range(7, 7 + 16))
|
|
text = b"some secret payload!"
|
|
once = erdr2pml.deXOR(text, 0, table)
|
|
assert once != text
|
|
assert erdr2pml.deXOR(once, 0, table) == text
|
|
|
|
|
|
def test_sanitize_filename_strips_separators():
|
|
name = erdr2pml.sanitizeFileName("a/b\\c")
|
|
assert "/" not in name
|
|
assert "\\" not in name
|