Commit Graph
702 Commits
Author SHA1 Message Date
JMR-devandClaude Opus 4.8 411dd306dc Target auto-release at the current repo
The packaging workflow pushed alpha releases to noDRM/DeDRM_tools_autorelease
using secrets.AUTORELEASE_KEY, which only exists on the upstream repo. On a
fork the secret is empty, so the "Delete older auto-releases" step failed with
"no GITHUB_TOKEN found", and even with a token a fork cannot publish into
noDRM's release repo.

Point the release at ${{ github.repository }} and use the built-in
secrets.GITHUB_TOKEN (scoped to the current repo) with contents: write
permission, so each fork publishes its own alpha release with no PAT required.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 10:17:45 -05:00
Jason Ross 0fcd81e325 Merge pull request #1 from JMR-dev/fix-patch-deps
Modernize tooling: drop Python 2, Poetry deps, tests, and CI
2026-06-24 10:10:42 -05:00
JMR-devandClaude Opus 4.8 c467fcea9b Modernize and pin packaging workflow
Rename main.yml to release.yml to reflect that it packages the plugin and
publishes the auto-release. Name the job and the previously unnamed step,
strip trailing whitespace, and pin every action to a commit SHA (with a
version comment) at its latest release:

- actions/checkout v2 -> v7.0.0
- actions/upload-artifact v4 -> v7.0.1
- dev-drprasad/delete-older-releases v0.2.1 -> v0.3.4
- softprops/action-gh-release v1 -> v3.0.1

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 09:53:44 -05:00
JMR-devandClaude Opus 4.8 f2950501cf Add PR test workflow
Run the pytest suite on pull requests to master across Python 3.9, 3.11
and 3.13 (the last exercises the legacy-cgi backport), installing
dependencies with Poetry. Actions are pinned to commit SHAs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 09:52:33 -05:00
JMR-devandClaude Opus 4.8 d407298be4 Update tests for shared helpers and fix test nits
- Cover the new utilities helpers (unpad, crc32, checksumPid type
  preservation, pidFromSerial, safe_join) and drop the now-redundant
  per-module crc32 tests.
- Rename test_unpad_removes_pkcs7_padding to reflect that unpad only
  trusts the trailing pad-length byte rather than validating PKCS#7.
- Replace the KOBO_HASH_KEYS change-detector with a test that documents
  the intentional value pin and checks the ASCII-salt contract.
- Note kgenpids' hybrid import in the test-loader docstring.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 09:18:01 -05:00
JMR-devandClaude Opus 4.8 bb96fe90ac Deduplicate PID/unpad helpers and generalize the Topaz path fix
Move the copies of unpad, crc32, checksumPid and pidFromSerial that were
scattered across the plugin into utilities.py, and add a shared safe_join
that generalizes the Topaz extraction path-traversal fix.

- unpad: adobekey, ineptepub and ineptpdf import the shared helper. The
  four bare-script key tools keep their local copies since they run
  without a package context.
- checksumPid is type-preserving (bytes for kgenpids/kindlepid, str for
  mobidedrm) so every call site keeps its exact behavior.
- kgenpids falls back to an absolute import because it is imported
  top-level by the worker modules.
- topazextract.extractFiles uses safe_join; genbook is unchanged as it
  only handles already-sanitized names.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 09:17:48 -05:00
JMR-devandClaude Opus 4.8 1ca134f5c3 Remove dead pure-Python AES implementation
aescbc.py provided a pure-Python Rijndael/AES-CBC fallback consumed only
by alfcrypto.AES_CBC, whose sole caller (kindlekey's macOS
CryptUnprotectData) never assigns self.crp and so raised AttributeError
before reaching it. The live crypto path uses Cryptodome, so delete the
dead module and the unused wrapper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 09:17:37 -05:00
JMR-devandClaude Opus 4.8 d6418996dd Harden tests flagged in code review
Strengthen weak-assertion / false-confidence tests:

  - test_alfcrypto: replace the tautological ctx_init determinism check
    with an independent golden vector, and add a golden Topaz decrypt
    vector that does not rely on the test's own inverse helper (so a
    systematic cipher bug is caught, not just round-trip symmetry). Pin
    the PC1 bad-key assertion to match="Bad key length", and load
    alfcrypto via the dedrm package so the test exercises the same module
    object that topazextract/mobidedrm import.
  - test_mobidedrm: pin the PC1 bad-key assertion to the guard message.
  - test_topazextract: make the path-traversal regression rely on the
    depth-independent positive oracle (the sanitised file must land inside
    outdir, which fails against the pre-fix code) plus an exact-contents
    check, instead of brittle parent-path negatives.
  - test_erdr2pml: narrow the import skip to only the missing-cgi case so
    a genuinely broken module fails loudly instead of silently skipping.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 20:35:21 -05:00
JMR-devandClaude Opus 4.8 ae2231727f Fix Python 3 correctness bugs found in code review
Fix str/bytes and leftover-py2 defects across the plugin, several on live
decryption paths:

  - erdr2pml.py: getText() footnote/sidebar handling mixed a bytes
    accumulator with str literals and called ord() on a bytes element,
    crashing on eReader/.pdb books that contain footnotes or sidebars.
  - ion.py: readdecimal() did `[ord(x) for x in self.read(...)]` over
    bytes (ord(int)), crashing KFX decryption on Ion DECIMAL values;
    printlob() had the same ord()-over-bytes in its debug path.
  - zipfilerugged.py: `isinstance(file, unicode)` raised NameError when a
    file-like object (not a path string) was passed to the ZipFile.
  - utilities.py: SafeUnbuffered.write referenced the undefined `unicode`
    (same fix already applied to the obok copy).
  - ineptpdf.py: ord(bookkey[0]) over an int in an error-diagnostic print.
  - epubfontdecrypt.py: removed a dead py2 itertools.izip fallback.
  - convert2xml.py: escapestr did bytes.replace(str, ...).
  - kgenpids.py: decode() built a str result then += bytes.

Cleanups from the earlier shim removal: drop now-unused `import sys`
(alfcrypto, utilities, kgenpids); unicode_argv returns list(sys.argv) so
callers can't mutate the process-global sys.argv.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 20:35:11 -05:00
JMR-devandClaude Opus 4.8 15592b84c8 Make legacy-cgi a runtime dependency
erdr2pml (eReader/.pdb support) imports the stdlib `cgi` module at
runtime, which was removed in Python 3.13. Having legacy-cgi only in the
dev group meant eReader decryption would break on a 3.13+ runtime that
installed just the main dependencies. Move it to the main dependency
group, scoped with a `python >= 3.13` marker so it is installed only
where the stdlib module is gone (3.8-3.12 keep using the stdlib `cgi`).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 20:15:36 -05:00
JMR-devandClaude Opus 4.8 9b93b5b789 Add legacy-cgi dev dep and expand erdr2pml tests
erdr2pml imports the stdlib `cgi` module, removed in Python 3.13, so its
tests were skipped on modern interpreters. Add the `legacy-cgi` backport
as a dev dependency so the module imports, and flesh out its tests:
deXOR involution, fixKey known vector / length, cleanPML high-ASCII
escaping, and sanitizeFileName separator/colon/control-char/angle-bracket
handling. The skip guard is kept as a safety net for environments without
the backport.

Suite is now 44 passing, 0 skipped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 20:13:26 -05:00
JMR-devandClaude Opus 4.8 ba96df081f Add pytest suite for both plugins
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>
2026-06-22 20:08:03 -05:00
JMR-devandClaude Opus 4.8 38dedea32b Fix invalid string escape sequences
Python 3.12+ emits SyntaxWarning for unrecognised backslash escapes (and
these will eventually become SyntaxErrors). Convert the affected string
literals to raw strings so the escapes are explicit:

  - scriptinterface.py: filename filter regexes (\.der, \.b64, ...).
  - obok.py: MAC-address detection regexes (\s, \-) and the title
    sanitiser ([^\s\w]).
  - flatxml2svg.py: the emitted JavaScript snippet contains \? and \d but
    also a trailing newline, so the regex part is made a raw string and
    the "\n" is concatenated separately.

All changes are value-preserving (an unrecognised escape already evaluated
to the backslash plus the character); verified the emitted JS string and
the compiled regexes are unchanged, and that both plugins now compile with
zero SyntaxWarnings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 19:52:56 -05:00
JMR-devandClaude Opus 4.8 838700fbec Remove Python 2 compatibility shims
The plugins target calibre 5/6 (Python 3) and the Poetry environment
pins Python >=3.8, so the Python 2 fallbacks are dead code. This removes
them throughout both plugins (behaviour on Python 3 is unchanged):

  - Drop all `from __future__` imports.
  - Collapse `if sys.version_info[0] == 2: ... else: ...` blocks to their
    Python 3 branch (ineptpdf, mobidedrm, kindlekey, kgenpids, alfcrypto,
    erdr2pml, ineptepub, obok, and the various unpad() helpers, etc.).
  - Replace `_winreg` import fallbacks with plain `import winreg`, and
    delete the py2-only adobekey_winreg_unicode module (now unreferenced).
  - Drop py2 name shims: `unicode`/`unichr`, `.iteritems()`,
    `from StringIO import StringIO`, `htmlentitydefs` fallback, and the
    Windows CommandLineToArgvW dance in unicode_argv (py3 sys.argv is
    already Unicode on every platform).
  - Remove the "Calibre < 5" (py2) bugfix block from the compat header.

Verified: every .py file in both plugins still byte-compiles.

Scope: the maintained DeDRM_plugin and Obok_plugin only. The archival
standalone scripts under Other_Tools/ are left as historical snapshots.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 18:42:33 -05:00
JMR-devandClaude Opus 4.8 815c621f01 Manage dependencies with Poetry; drop abandoned pycrypto
Add a Poetry manifest (pyproject.toml) and lock file to manage the
development / standalone-CLI environment for the plugins. The plugins
themselves run inside calibre's bundled Python, so the project is set to
package-mode = false and the manifest documents the real third-party
dependency set rather than building a distributable package.

Declared dependencies:
  - pycryptodomex (>=3.20): maintained crypto library exposing the
    `Cryptodome` namespace that every crypto import already prefers. This
    replaces the abandoned pycrypto (unmaintained since 2014,
    CVE-2013-7459), which is no longer needed and is not declared.
  - lxml (>=5.0): EPUB/PDF/ADEPT XML handling.
  - apsw (>=3.46): optional `nook` group, only used by
    ignoblekeyWindowsStore.py for Nook Windows Store key extraction.

calibre/calibre_lzma/PyQt are supplied by the calibre runtime and the
Python <3.3 lzma fallbacks (backports.lzma, pylzma) are unnecessary on
the supported Python 3.8+ range, so none are declared.

Also update the stale PyCrypto install instructions in
ignoblekeyGenPassHash.py to point at the maintained pycryptodomex.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 18:27:43 -05:00
JMR-devandClaude Opus 4.8 768d49094c Fix path traversal in Topaz extraction (arbitrary file write)
The Topaz header record "tag" is read verbatim from the untrusted book
file by bookReadString() and then used unsanitized to build the output
filename in extractFiles(). A crafted tag such as "../../foo" let a
malicious .azw/Topaz file write attacker-controlled bytes outside the
extraction directory. The payload content requires no book key, since an
unencrypted record with compressedLength == 0 is returned raw.

Strip the record name to its basename before joining it to destdir so
traversal sequences (../, /, \) can no longer escape, and add an
abspath-based containment check as defense in depth.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 18:21:42 -05:00
NoDRM 7379b45319 Remove future import from ion.py 2024-11-10 20:15:33 +01:00
NoDRM bde82fd7ab Fix python2 support for ion.py 2024-11-10 16:10:29 +01:00
NoDRM de3d91f5e5 Don't repack EPUB if nothing has changed 2024-11-10 15:21:09 +01:00
NoDRM c5ee327a60 Add note about key import/export for K4PC in the help file (fixes #663) 2024-11-10 14:44:57 +01:00
NoDRM 501a1e6d31 Update obok readme to include wmic requirement (fixes #670) 2024-11-10 14:41:38 +01:00
NoDRM 815d86efe0 Update changelog 2024-11-10 14:36:27 +01:00
NoDRM 65646f4493 Fix CI 2024-11-10 14:25:35 +01:00
Josh Cotton 808dc7d29a Fix Obok import in Calibre flatpak by using /sys/class/net/IFACE/address instead of ip (#586)
Fix #585.
Use /sys/class/net/IFACE/address for the MAC address instead of the ip
command.
2024-11-10 13:14:59 +00:00
precondition 2cd2792306 Obok.py/action.py: invoke _() only once 2024-11-10 13:11:28 +00:00
precondition 2e53d70e88 Catch FileNotFoundError due to undownloaded ebooks 2024-11-10 13:11:28 +00:00
Ben Combee 05fff5217b Fix crash using bare sha1 symbol
Use sha1 from hashlib, as it isn't imported globally, fixed crash trying to decrypt a eReader PDB file
2024-11-10 13:10:11 +00:00
Martin Rys 34c4c067e8 DeDRM ion: Correctly throw last exception if decrypt fails 2024-11-10 13:09:45 +00:00
Martin Rys 195ea69537 DeDRM ion: Clean out errorneous whitespace and UTF8 definition from python 2 times 2024-11-10 13:09:45 +00:00
NoDRM 3373d93874 Add binascii import, fixes FileOpen #514 2024-03-15 13:13:45 +01:00
NoDRM bf2471e65b Update kfxdedrm as suggested in #440 2023-12-21 12:35:11 +01:00
NoDRM 5492dcdbf4 More FileOpen fixes 2023-12-21 11:57:39 +01:00
NoDRM 737d5e7f1e Bunch of updates for the FileOpen script 2023-12-03 10:45:09 +01:00
NoDRM e4e5808894 Fix file lock issue in androidkindlekey.py 2023-12-03 10:42:41 +01:00
NoDRM ef67dbd204 Fix more Py2/Py3 stuff 2023-08-06 15:49:52 +02:00
NoDRM 10b6caf9f5 Enable autorelease into 2nd repo 2023-08-03 21:53:16 +02:00
NoDRM 53996cf49c More Python2 fixes 2023-08-03 20:45:06 +02:00
NoDRM d388ae72fd More Py2 fixes 2023-08-03 20:14:33 +02:00
NoDRM bc089ee46d More Python2 bugfixes 2023-08-03 20:01:38 +02:00
NoDRM e509b7d520 Fix python2 issues in kgenpids and kindlekey 2023-08-03 11:26:05 +02:00
NoDRM e82d2b5c9c Fix PDF decryption for 256-bit AES with V=5 2023-08-02 18:13:42 +02:00
NoDRM 7f6dd84389 Fix PDF decryption of ancient 40-bit RC4 with R=2 2023-08-02 16:55:41 +02:00
NoDRM b9bad26d4b Prepare release candidate v10.0.9 2023-08-02 07:39:35 +02:00
NoDRM 2a1413297e Add warning to the standalone code 2023-08-02 07:30:39 +02:00
NoDRM 815f880e34 Disable auto-prerelease again (#358) 2023-06-25 18:51:46 +02:00
NoDRM 9ae77c438f Update CI to create an automatic beta release 2023-06-25 18:21:20 +02:00
Satsuoni abc5de018e Added several more scramble functions to Kindle decrypt 2023-06-25 16:38:55 +02:00
NoDRMandSatsuoni 133e67fa03 Added fix for padding being correct on accident
Co-authored-by: Satsuoni <satsuoni@hotmail.com>
2023-06-25 16:27:31 +02:00
NoDRM f86cff285b Fix python2 issues in Kindle and Nook code (#355) 2023-06-24 09:53:55 +02:00
NoDRM a553a71f45 Fix font decryption with multiple IDs (#347) 2023-06-23 19:44:24 +02:00