Skip to content

fix(cli): info, text, render and audit take the owner password of R2–R4 files - #2825

Open
enesoglu wants to merge 1 commit into
storytold:mainfrom
enesoglu:claude/fix/2670-cli-owner-password
Open

enesoglu wants to merge 1 commit into
storytold:mainfrom
enesoglu:claude/fix/2670-cli-owner-password

Conversation

@enesoglu

@enesoglu enesoglu commented Oct 16, 2026 •

Copy link
Copy Markdown

What this changes

pdfcraft-cli info, text, render and audit now accept the owner password of revision 2–4 files (RC4-40, RC4-128, AES-128), as run doc_open already 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::open works 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 to inspect and PageRenderer.

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::open and the new function share one helper (recovered_render_password), so there is one source of truth. The CLI uses it for inspect/PageRenderer only. The engine session and the cos document still get the typed password, so the owner password still lifts copy restrictions in text.

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
  • clippy with -D warnings on the crates I changed (cargo clippy -p pdfcraft-cli -p pdfcraft-engine -j 4 --all-targets -- -D warnings)
  • tests pass on the crates I changed (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) and cargo xtask parity (exit 0)

Tests.

  • apps/pdfcraft-cli/tests/owner_password.rs (end-to-end, the built binary): info, text, render and audit with the owner password on RC4-40, RC4-128, AES-128 and AES-256 files; the user password still works; a wrong password still fails. text with the user password still refuses copying, because the file allows nothing. audit places 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.rs reverted, all four CLI tests fail:

Rc4_40 with "owner": pdfcraft-cli: the password is incorrect
Rc4_40: pdfcraft-cli: /tmp/.../audit-Rc4_40.pdf: the password is incorrect
Rc4_40: pdfcraft-cli: the document could not be parsed          (render)
Rc4_40: pdfcraft-cli: text: the password is incorrect
test result: FAILED. 0 passed; 4 failed

With the fix restored: test result: ok. 4 passed; 0 failed.

Never-crash

  • No new unwrap/expect/panic!/unreachable!/todo! outside tests
  • No indexing or slicing with input-derived positions; no new arithmetic or allocations sized by input
  • No unsafe
  • (no crash fixed here) — the new cos parse in render_password_for runs inside the engine's guard, and any failure falls back to the typed password

Provenance

  • No asset from an Adobe product, and no Adobe icon recreated, traced or imitated
  • No font files committed here
  • No GPL/AGPL code copied in
  • Behaviour comes from the specification (ISO 32000-2 Algorithm 7, already implemented in pdfcraft-crypt) and the issue's black-box report, not from reading another implementation's source
  • No new assets

Security

  • --root confinement unchanged (no path handling touched)
  • MCP and the UI control channel untouched
  • No new outbound network access

Parity and reach

  • parity/acrobat-features.toml: core.owner-password-unlock cites the new tests, and its notes say the CLI takes either password; "Not yet: an automation tool to unlock an open document" still stands
  • Reachable headlessly: doc_open already accepted the owner password; this brings the CLI subcommands in line with it

Anything a reviewer should look at first

  • render_password_for parses the document with pdfcraft-cos one extra time per CLI call, but only when --password is 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 in vendor/README.md and docs/gaps.md gap 2). The engine already treats the renderer's limitation this way in Session::open.
  • The UI's other direct renderer calls (combine thumbnails, print, etc.) use doc.password, which Session::open already sets to the render password. The parity note 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

…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
@enesoglu enesoglu changed the title fix(cli): info, text, render and audit take the owner password of R2–… fix(cli): info, text, render and audit take the owner password of R2–R4 files Oct 16, 2026

@ahmadmuj ahmadmuj left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants