Files
ElyOffice/crates/ely-pdf-engine/tests/secure.rs
T

119 lines
4.8 KiB
Rust

//! Protected copies and what they allow (PDF-11).
use std::path::Path;
use ely_pdf_engine::{
Doc, Lock, Worker,
proto::may,
sample::{Extras, pdf_with},
};
fn worker() -> Worker {
Worker::spawn_from(Path::new(env!("CARGO_BIN_EXE_ely-pdf-worker"))).expect("the worker")
}
fn plain(dir: &Path) -> (Worker, Doc) {
let path = dir.join("doc.pdf");
std::fs::write(&path, pdf_with(&[(612.0, 792.0, &["Hello world"])], &[], &Extras::default())).expect("writes");
let mut worker = worker();
let doc = worker.open(&path).expect("opens").doc;
(worker, doc)
}
/// Writes a copy that opens with "user", allowing only `allow`.
fn locked(dir: &Path, allow: u32) -> std::path::PathBuf {
let (mut worker, doc) = plain(dir);
let out = dir.join("locked.pdf");
let lock = Lock { user: "user".into(), owner: "owner".into(), allow };
worker.protect(doc, &out, Some(&lock)).expect("protects");
out
}
#[test]
fn a_protected_copy_asks_and_holds_its_limits() {
let dir = tempfile::tempdir().expect("a temp dir");
let out = locked(dir.path(), may::PRINT);
let bytes = std::fs::read(&out).expect("reads");
assert!(bytes.windows(5).any(|w| w == b"AESV3"), "AES-256");
let mut worker = worker();
let opened = worker.open(&out).expect("opens");
assert!(opened.locked);
assert!(!worker.unlock(opened.doc, "wrong").expect("tries"));
assert!(worker.unlock(opened.doc, "user").expect("tries"));
let allowed = worker.permissions(opened.doc).expect("reads");
assert_eq!(allowed & (may::PRINT | may::COPY | may::EDIT | may::OWNER), may::PRINT);
let refused = worker.rotate_pages(opened.doc, &[0], 90).expect_err("refused");
assert_eq!(ely_pdf_engine::refused(&refused), Some("assemble"));
let text: String = worker.text(opened.doc, 0).expect("still reads").iter().map(|c| c.c).collect();
assert!(text.contains("Hello"));
}
#[test]
fn a_wrong_owner_password_keeps_access_and_the_right_one_lifts_limits() {
let dir = tempfile::tempdir().expect("a temp dir");
let out = locked(dir.path(), 0);
let mut worker = worker();
let doc = worker.open(&out).expect("opens").doc;
worker.unlock(doc, "user").expect("unlocks");
assert!(!worker.owner(doc, "nope").expect("tries"));
assert_eq!(worker.pages(doc).expect("still open"), 1);
assert!(worker.text(doc, 0).is_ok());
assert!(worker.owner(doc, "owner").expect("tries"));
assert_ne!(worker.permissions(doc).expect("reads") & may::OWNER, 0);
worker.rotate_pages(doc, &[0], 90).expect("allowed now");
}
#[test]
fn changing_protection_needs_the_owner() {
let dir = tempfile::tempdir().expect("a temp dir");
let out = locked(dir.path(), may::PRINT | may::COPY | may::EDIT);
let mut worker = worker();
let doc = worker.open(&out).expect("opens").doc;
worker.unlock(doc, "user").expect("unlocks");
let bare = dir.path().join("bare.pdf");
let refused = worker.protect(doc, &bare, None).expect_err("refused");
assert!(ely_pdf_engine::refused(&refused).is_some(), "refused: {refused}");
assert!(!bare.exists());
worker.owner(doc, "owner").expect("tries");
worker.protect(doc, &bare, None).expect("unprotects");
let mut other = self::worker();
assert!(!other.open(&bare).expect("opens").locked);
}
#[test]
fn an_owner_password_is_needed_and_must_differ() {
let dir = tempfile::tempdir().expect("a temp dir");
let (mut worker, doc) = plain(dir.path());
let out = dir.path().join("out.pdf");
for (user, owner) in [("a", ""), ("same", "same")] {
let lock = Lock { user: user.into(), owner: owner.into(), allow: 0 };
assert!(worker.protect(doc, &out, Some(&lock)).is_err(), "{user}/{owner}");
assert!(!out.exists());
}
}
#[test]
fn a_file_with_no_open_password_still_holds_limits() {
let dir = tempfile::tempdir().expect("a temp dir");
let (mut worker, doc) = plain(dir.path());
let out = dir.path().join("out.pdf");
let lock = Lock { user: String::new(), owner: "owner".into(), allow: may::PRINT };
worker.protect(doc, &out, Some(&lock)).expect("protects");
let mut other = self::worker();
let opened = other.open(&out).expect("opens");
assert!(!opened.locked);
let refused = other.annotate(opened.doc, &[]).expect_err("refused");
assert_eq!(ely_pdf_engine::refused(&refused), Some("annotate"));
}
#[test]
fn a_wrong_owner_try_on_aes_128_keeps_the_text_readable() {
let fixture = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../tests/fixtures/pdf/aes128.pdf");
let mut worker = worker();
let doc = worker.open(&fixture).expect("opens").doc;
assert!(worker.unlock(doc, "user").expect("tries"));
assert!(!worker.owner(doc, "nope").expect("tries"));
let text: String = worker.text(doc, 0).expect("reads").iter().map(|c| c.c).collect();
assert_eq!(text.trim(), "Hello");
}