mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-27 11:37:59 -06:00
M6: Extract, Split and Combine write no Password-field values either (#3926)
CodeRabbit on #3943: Extract Pages copies the fields of the pages it takes, and write_new (Combine, Extract, Split, Create) wrote that copy without the writable() boundary saves use, so the new file kept a typed Password value. write_unchecked, which write_new and Split's size measuring both go through, now writes the sanitized copy. The other write_full/write_incremental calls in the engine build in-memory bytes (display, previews, the working copy, print rasters), not files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
509b5d5cf3
commit
048cf14d31
@@ -4915,9 +4915,12 @@ impl Session {
|
||||
}
|
||||
|
||||
/// [`Self::write_new`] without the check, for bytes nobody writes: measuring a part's size.
|
||||
/// Like a save, a new file never carries a typed Password-field value (#3926): Extract and
|
||||
/// Split copy the fields of the pages they take.
|
||||
fn write_unchecked(&self, doc: &pdfcraft_cos::Document) -> Result<Arc<Vec<u8>>, EditError> {
|
||||
let opts = SaveOptions { mod_date: self.now().map(pdfcraft_cos::pdf_date), ..SaveOptions::default() };
|
||||
write_full(doc, &opts).map(Arc::new).map_err(|e| EditError::Write(e.to_string()))
|
||||
let doc = writable(doc)?;
|
||||
write_full(&doc, &opts).map(Arc::new).map_err(|e| EditError::Write(e.to_string()))
|
||||
}
|
||||
|
||||
/// Whether a changed document still needs a recovery snapshot. This does not consume it.
|
||||
|
||||
@@ -2042,7 +2042,8 @@ fn appears_in_pdf(bytes: &Arc<Vec<u8>>, needle: &str) -> bool {
|
||||
}
|
||||
|
||||
/// #3926: a value typed into a text field with the Password flag stays in the open document but
|
||||
/// is written to no file: Save, a full rewrite, Reduce File Size or a recovery snapshot. ISO
|
||||
/// is written to no file: Save, a full rewrite, Reduce File Size, a recovery snapshot, or a new
|
||||
/// file made from its pages (Extract, Split, Combine). ISO
|
||||
/// 32000-2 §12.7.5.3, Table 231, note to the Password flag: PDF processors should never store
|
||||
/// the value in the PDF file.
|
||||
#[test]
|
||||
@@ -2065,6 +2066,15 @@ fn password_field_values_are_kept_in_memory_but_written_to_no_file() {
|
||||
let snaps = s.autosave_snapshots();
|
||||
assert_eq!(snaps.len(), 1);
|
||||
assert!(!appears_in_pdf(&snaps[0].bytes, "hunter2"), "the recovery snapshot");
|
||||
// New files built from its pages too (#3943 review): Extract copies the fields of the pages it
|
||||
// takes, and Split writes each part the same way.
|
||||
let extracted = s.extract(id, &[0]).unwrap();
|
||||
assert!(!appears_in_pdf(&extracted, "hunter2"), "Extract Pages");
|
||||
assert!(appears_in_pdf(&extracted, "*******"), "the extracted page keeps the masked appearance");
|
||||
for (_, _, part) in s.split_by_size(id, 1).unwrap() {
|
||||
assert!(!appears_in_pdf(&part, "hunter2"), "Split");
|
||||
}
|
||||
assert!(!appears_in_pdf(&s.combine(&[("form.pdf".into(), s.get(id).unwrap().bytes.clone())]).unwrap(), "hunter2"), "Combine");
|
||||
// Reopened, the field is empty, as in any reader.
|
||||
let mut t = Session::new();
|
||||
let reopened = t.open("saved.pdf", None, saved, None).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user