Repository navigation
Conversation
…R4 files `pdfcraft-cli info`, `text`, `render` and `audit` rejected the owner password of RC4-40, RC4-128 and AES-128 files with "the password is incorrect", while `run doc_open` accepted it (storytold#2670, item 8). The renderer authenticates only the user password of revisions 2–4. `Session::open` works around that by handing it the user password that owner authentication recovers, but the CLI passed the typed password straight to `inspect` and `PageRenderer`. `pdfcraft_engine::render_password_for` now gives any render path outside a session the password the renderer takes, sharing the recovery with `Session::open`. The CLI uses it for the renderer and keeps the typed password for the engine session and the cos document, so the owner password still lifts copy restrictions in `text`. Refs storytold#2670 (item 8 only). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013MW21PHkRQWs7ADnqBchWH
ahmadmuj
reviewed
Oct 16, 2026
ahmadmuj
left a comment
There was a problem hiding this comment.
Local checks pass for R2/R3/R4/AES-256, including exact text, metadata, audit bounds, decoded pixels and copy restrictions. Could the render test decode the PNG and check its dimensions and non-white pixels? The current header check also accepts a blank page. CI has no runs yet.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
pdfcraft-cli info,text,renderandauditnow accept the owner password of revision 2–4 files (RC4-40, RC4-128, AES-128), asrun doc_openalready did. Before, they failed with "the password is incorrect". This is item 8 of #2670 only; the other items are covered by #2799, #2789, #2744, #2687 and #2679 or remain open.Cause. The renderer (vendored hayro) authenticates only the user password of R2–R4 files.
Session::openworks around that by handing the renderer the user password that owner authentication recovers (pdfcraft-crypt, Algorithm 7). The CLI subcommands passed the typed password straight toinspectandPageRenderer.Fix. New
pdfcraft_engine::render_password_for(bytes, password)returns the password the renderer takes: the recovered user password for an R2–R4 owner password, otherwise the password as given.Session::openand the new function share one helper (recovered_render_password), so there is one source of truth. The CLI uses it forinspect/PageRendereronly. The engine session and the cos document still get the typed password, so the owner password still lifts copy restrictions intext.Refs #2670 (item 8 only — the issue covers several separate problems, so this PR does not close it).
How you verified it
cargo fmt --check-D warningson the crates I changed (cargo clippy -p pdfcraft-cli -p pdfcraft-engine -j 4 --all-targets -- -D warnings)cargo test -p pdfcraft-cli -j 4,cargo test -p pdfcraft-engine -j 4: all green)cargo xtask layers(OK, 37 crates),cargo xtask assets(ok) andcargo xtask parity(exit 0)Tests.
apps/pdfcraft-cli/tests/owner_password.rs(end-to-end, the built binary):info,text,renderandauditwith the owner password on RC4-40, RC4-128, AES-128 and AES-256 files; the user password still works; a wrong password still fails.textwith the user password still refuses copying, because the file allows nothing.auditplaces its finding at the right top-left rectangle.crates/engine/src/tests.rs::render_password_for_recovers_the_user_password_of_older_revisions(unit).Red before / green after: with only
apps/pdfcraft-cli/src/main.rsreverted, all four CLI tests fail:With the fix restored:
test result: ok. 4 passed; 0 failed.Never-crash
unwrap/expect/panic!/unreachable!/todo!outside testsunsaferender_password_forruns inside the engine'sguard, and any failure falls back to the typed passwordProvenance
pdfcraft-crypt) and the issue's black-box report, not from reading another implementation's sourceSecurity
--rootconfinement unchanged (no path handling touched)Parity and reach
parity/acrobat-features.toml:core.owner-password-unlockcites the new tests, and its notes say the CLI takes either password; "Not yet: an automation tool to unlock an open document" still standsdoc_openalready accepted the owner password; this brings the CLI subcommands in line with itAnything a reviewer should look at first
render_password_forparses the document withpdfcraft-cosone extra time per CLI call, but only when--passwordis given. I chose this over patching hayro-syntax to do Algorithm 7 itself. That would be the deeper fix, but it adds a vendored patch (and changes the patch counts invendor/README.mdanddocs/gaps.mdgap 2). The engine already treats the renderer's limitation this way inSession::open.doc.password, whichSession::openalready sets to the render password. Theparitynote about combine cards saying "No preview" for RC4 owner passwords (organize.combine) is a separate UI path that I did not touch.Prepared with Claude Code and checked against AGENTS.md and CLAUDE.md.
🤖 Generated with Claude Code