Repository navigation
feat(pdf): tell locked PDFs apart from damaged ones - #27
Merged
Merged
Conversation
pdf-lib refuses to load an encrypted PDF, and stripPdf caught that with every
other load failure, so a locked file was called damaged ("unreadable: pdf").
Two real ones in the week of 1 Nov 2026 may have been this.
stripPdf now loads with ignoreEncryption (only to look, never to edit) and
throws Locked. The standard security handler's own check, run with an empty
password, says whether the file opens freely (an owner password guards edits)
or needs a password to open. Nothing is decrypted: only /ID and /Encrypt are
read, and the standard leaves those in the clear.
The card says the file is locked instead of unreadable. When it needs a
password, it links SanctumPDF's unlock tool, which takes the password and
also runs in the browser. Permission-only locks get no link, because that
tool needs a password and those files have none to give.
Telemetry: "locked: pdf password|permissions|unknown" replaces
"unreadable: pdf" for these files, and a new unlock_link_clicked event
counts link clicks.
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.
Summary
An encrypted PDF used to be reported as damaged. Now it's reported as locked, the card says how it's locked, and for either kind of lock the card links SanctumPDF's in-browser unlock tool. A lock MetaStrip can't classify gets no link.
pdf-lock.tsimplements ISO 32000 algorithms 2, 4 and 5 (RC4/MD5, revisions 2 to 4) and 2.B (AES-256, revisions 5 and 6, using Web Crypto). Nothing is decrypted: it reads only/IDand/Encrypt, which the standard leaves in the clear.Telemetry: for these files,
file_failedreasons change fromunreadable: pdftolocked: pdf password|permissions|unknown. The newunlock_link_clicked {lock}event counts clicks on the link.Evidence
unreadable: pdfwith the message "It may be damaged…".After: 341 tests pass (15 new). The new tests use 13 real encrypted PDFs made with qpdf 12.4: revisions 2, 3, 4 and 6, with and without object streams, plus R4 with clear metadata. They also cover a non-standard handler. Each test fails on
main.file_failedreason islocked: pdf password, and clicking the link sendsunlock_link_clicked lock=password.locked: pdf permissions. It reads the same at 390 px.failure_report_clicked.https://sanctumpdf.com/unlock-pdf?utm_source=metastrip&utm_medium=referral&utm_campaign=locked_pdfreturns 200.Merge Danger
Merge order: merge lars-1987/sanctumpdf#1 first and let it deploy. Until it's live, SanctumPDF still disables its button with a blank password, so the link for editing-locked PDFs would lead to a dead end.
Door: two-way
Blast Radius: PDFs
Only encrypted PDFs take the new path; every other PDF loads exactly as before, since
ignoreEncryptionchanges nothing for an unencrypted file. If the check itself throws, the file is still reported as locked (unknown), never as a crash. Weekly reviews must countlocked: pdf%alongsideunreadable: pdffrom now on.