A PDF protected with only a permissions (owner) password opens without
asking, restricted, and nothing let the user enter that password
afterwards: the security notice only led to a read-only Security tab and
the hint said to reopen the file with the password, which the app had no
way to do (#995, #1077).
Now the security notice and Document Properties > Security offer Unlock...,
and Change settings / Remove security on a restricted document ask for the
permissions password first and then carry on, as Acrobat does. The open
password is refused there.
- crypt: SecurityHandler::authenticate_owner accepts only the owner
password and refuses a different file key.
- cos: Document::unlock upgrades the open document in place; owner and user
passwords unlock the same file key, so nothing is decoded again.
- engine: Session::unlock (not an edit: no undo step, not marked unsaved)
also unlocks the undo and redo states and reopens saves as owner;
Document::can_unlock, EditError::WrongPassword, command protect.unlock.
- ui: the permissions password prompt shares the open prompt's modal; the
notice and Security tab get Unlock...; the disabled-command hints no
longer point at reopening the file.
- i18n: the new strings in all 15 full catalogs (catalog hashes updated).
Tests cover crypt, cos and engine (all four algorithms, wrong and open
passwords, undo, redo, save, removing security afterwards) and the UI
(notice flow, Remove security asking first).
Closes#995Closes#1077
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* M9: sign and timestamp encrypted documents
Signing a password-protected PDF failed with "not supported: signing
encrypted documents". The writer encrypted every string, including the
signature's /Contents placeholder, which the signer patches in place
after hashing.
- cos: a signature dictionary's /Contents is never encrypted or
decrypted (ISO 32000-2 §7.6.2), identified by /Type /Sig|/DocTimeStamp
or by /Contents + /ByteRange. Existing signatures in encrypted files
now read their real CMS and survive rewrites of their dictionary.
- sign: the blanket refusal is replaced by the document's permissions
(Table 22) when opened with the user password: existing fields and
document timestamps need fill-forms, new fields need annotate +
modify, certifying needs modify. Refusals name the permissions
password.
- Tests for all four algorithms, counter-signing, tampering,
permissions, document timestamps and the sign_document tool; parity
entry sign.encrypted-documents; ROADMAP log.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Hadi Chokr <hadichokr@icloud.com>
* M9: signing an encrypted document waits for a pending security change to be saved
Otherwise the incremental save becomes a full rewrite that applies or removes protection while
signing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Signed-off-by: Hadi Chokr <hadichokr@icloud.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
The app, crates, binaries, bundle id, packaging, icons, screenshots and docs are now
PdfCraft / pdfcraft (repo storytold/pdfcraft). On first launch the desktop app moves the
PrintCraft settings and crash-recovery folders to the new name, and both apps read settings
saved under the old storage key, so upgrades keep recent files, preferences and unsaved work.
The signing test fixtures keep their PrintCraft subject names (they are binary).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>