use pdf_oxide::editor::{
DocumentEditor, EditableDocument, EncryptionAlgorithm, EncryptionConfig, Permissions,
SaveOptions,
};
use pdf_oxide::writer::{DocumentBuilder, DocumentMetadata, PageSize};
use std::fs;
use tempfile::tempdir;
fn read_file_as_string(path: &std::path::Path) -> String {
let bytes = fs::read(path).unwrap();
String::from_utf8_lossy(&bytes).to_string()
}
fn create_test_pdf_with_content(path: &str, content: &str) -> std::io::Result<()> {
let mut builder = DocumentBuilder::new();
builder = builder.metadata(
DocumentMetadata::new()
.title("Encryption Test Document")
.author("pdf_oxide"),
);
{
let page = builder.page(PageSize::Letter);
page.at(72.0, 720.0).text(content).done();
}
let pdf_bytes = builder.build().expect("Failed to build test PDF");
fs::write(path, pdf_bytes)
}
mod encryption_config_tests {
use super::*;
#[test]
fn test_encryption_config_builder() {
let config = EncryptionConfig::new("user", "owner");
assert_eq!(config.user_password, "user");
assert_eq!(config.owner_password, "owner");
assert_eq!(config.algorithm, EncryptionAlgorithm::Aes256); }
#[test]
fn test_encryption_config_with_algorithm() {
let config =
EncryptionConfig::new("user", "owner").with_algorithm(EncryptionAlgorithm::Aes128);
assert_eq!(config.algorithm, EncryptionAlgorithm::Aes128);
}
#[test]
fn test_encryption_config_with_permissions() {
let perms = Permissions::read_only();
let config = EncryptionConfig::new("user", "owner").with_permissions(perms.clone());
assert!(!config.permissions.print);
assert!(!config.permissions.modify);
assert!(!config.permissions.copy);
assert!(config.permissions.accessibility); }
#[test]
fn test_permissions_all() {
let perms = Permissions::all();
assert!(perms.print);
assert!(perms.print_high_quality);
assert!(perms.modify);
assert!(perms.copy);
assert!(perms.annotate);
assert!(perms.fill_forms);
assert!(perms.accessibility);
assert!(perms.assemble);
}
#[test]
fn test_permissions_read_only() {
let perms = Permissions::read_only();
assert!(!perms.print);
assert!(!perms.print_high_quality);
assert!(!perms.modify);
assert!(!perms.copy);
assert!(!perms.annotate);
assert!(!perms.fill_forms);
assert!(perms.accessibility); assert!(!perms.assemble);
}
#[test]
fn test_permissions_to_bits() {
let perms = Permissions::all();
let bits = perms.to_bits();
assert!(bits & (1 << 2) != 0); assert!(bits & (1 << 3) != 0); assert!(bits & (1 << 4) != 0); assert!(bits & (1 << 5) != 0); assert!(bits & (1 << 8) != 0); assert!(bits & (1 << 9) != 0); assert!(bits & (1 << 10) != 0); assert!(bits & (1 << 11) != 0); }
#[test]
fn test_permissions_to_bits_read_only() {
let perms = Permissions::read_only();
let bits = perms.to_bits();
assert!(bits & (1 << 2) == 0); assert!(bits & (1 << 3) == 0); assert!(bits & (1 << 4) == 0); assert!(bits & (1 << 5) == 0); assert!(bits & (1 << 9) != 0); }
}
mod save_options_encryption_tests {
use super::*;
#[test]
fn test_save_options_with_encryption() {
let config = EncryptionConfig::new("user123", "owner456");
let options = SaveOptions::with_encryption(config);
assert!(options.encryption.is_some());
let enc = options.encryption.unwrap();
assert_eq!(enc.user_password, "user123");
assert_eq!(enc.owner_password, "owner456");
}
}
mod aes256_encryption_tests {
use super::*;
#[test]
fn test_encrypt_pdf_aes256() {
let dir = tempdir().unwrap();
let input_path = dir.path().join("input.pdf");
let output_path = dir.path().join("encrypted.pdf");
create_test_pdf_with_content(
input_path.to_str().unwrap(),
"Secret document content for AES-256 test",
)
.unwrap();
let mut editor = DocumentEditor::open(&input_path).unwrap();
let config = EncryptionConfig::new("userpass", "ownerpass")
.with_algorithm(EncryptionAlgorithm::Aes256)
.with_permissions(Permissions::all());
let options = SaveOptions::with_encryption(config);
editor.save_with_options(&output_path, options).unwrap();
assert!(output_path.exists());
let input_bytes = fs::read(&input_path).unwrap();
let output_bytes = fs::read(&output_path).unwrap();
assert_ne!(input_bytes, output_bytes);
let output_str = read_file_as_string(&output_path);
assert!(output_str.contains("/Encrypt"));
assert!(output_str.contains("/V 5")); }
#[test]
fn test_encrypt_pdf_aes256_structure() {
let dir = tempdir().unwrap();
let input_path = dir.path().join("input.pdf");
let encrypted_path = dir.path().join("encrypted.pdf");
create_test_pdf_with_content(input_path.to_str().unwrap(), "AES-256 structure test")
.unwrap();
let mut editor = DocumentEditor::open(&input_path).unwrap();
let config = EncryptionConfig::new("user256", "owner256")
.with_algorithm(EncryptionAlgorithm::Aes256);
editor
.save_with_options(&encrypted_path, SaveOptions::with_encryption(config))
.unwrap();
let output_str = read_file_as_string(&encrypted_path);
assert!(output_str.contains("/Encrypt"));
assert!(output_str.contains("/Filter /Standard"));
assert!(output_str.contains("/V 5")); assert!(output_str.contains("/R 6")); assert!(output_str.contains("/O ")); assert!(output_str.contains("/U ")); assert!(output_str.contains("/P ")); }
}
mod aes128_encryption_tests {
use super::*;
#[test]
fn test_encrypt_pdf_aes128() {
let dir = tempdir().unwrap();
let input_path = dir.path().join("input.pdf");
let output_path = dir.path().join("encrypted_aes128.pdf");
create_test_pdf_with_content(input_path.to_str().unwrap(), "AES-128 test content").unwrap();
let mut editor = DocumentEditor::open(&input_path).unwrap();
let config =
EncryptionConfig::new("user", "owner").with_algorithm(EncryptionAlgorithm::Aes128);
editor
.save_with_options(&output_path, SaveOptions::with_encryption(config))
.unwrap();
assert!(output_path.exists());
let output_str = read_file_as_string(&output_path);
assert!(output_str.contains("/Encrypt"));
assert!(output_str.contains("/V 4")); assert!(output_str.contains("/R 4")); }
}
mod rc4_encryption_tests {
use super::*;
#[test]
fn test_encrypt_pdf_rc4_128() {
let dir = tempdir().unwrap();
let input_path = dir.path().join("input.pdf");
let output_path = dir.path().join("encrypted_rc4_128.pdf");
create_test_pdf_with_content(input_path.to_str().unwrap(), "RC4-128 test content").unwrap();
let mut editor = DocumentEditor::open(&input_path).unwrap();
let config =
EncryptionConfig::new("user", "owner").with_algorithm(EncryptionAlgorithm::Rc4_128);
editor
.save_with_options(&output_path, SaveOptions::with_encryption(config))
.unwrap();
assert!(output_path.exists());
let output_str = read_file_as_string(&output_path);
assert!(output_str.contains("/Encrypt"));
assert!(output_str.contains("/V 2")); assert!(output_str.contains("/R 3")); }
#[test]
fn test_encrypt_pdf_rc4_40() {
let dir = tempdir().unwrap();
let input_path = dir.path().join("input.pdf");
let output_path = dir.path().join("encrypted_rc4_40.pdf");
create_test_pdf_with_content(input_path.to_str().unwrap(), "RC4-40 test content").unwrap();
let mut editor = DocumentEditor::open(&input_path).unwrap();
let config =
EncryptionConfig::new("user", "owner").with_algorithm(EncryptionAlgorithm::Rc4_40);
editor
.save_with_options(&output_path, SaveOptions::with_encryption(config))
.unwrap();
assert!(output_path.exists());
let output_str = read_file_as_string(&output_path);
assert!(output_str.contains("/Encrypt"));
assert!(output_str.contains("/V 1")); assert!(output_str.contains("/R 2")); }
}
mod permission_tests {
use super::*;
#[test]
fn test_encrypt_pdf_read_only_permissions() {
let dir = tempdir().unwrap();
let input_path = dir.path().join("input.pdf");
let output_path = dir.path().join("readonly.pdf");
create_test_pdf_with_content(input_path.to_str().unwrap(), "Read-only document").unwrap();
let mut editor = DocumentEditor::open(&input_path).unwrap();
let config =
EncryptionConfig::new("user", "owner").with_permissions(Permissions::read_only());
editor
.save_with_options(&output_path, SaveOptions::with_encryption(config))
.unwrap();
assert!(output_path.exists());
let output_bytes = fs::read(&output_path).unwrap();
let output_str = String::from_utf8_lossy(&output_bytes);
assert!(output_str.contains("/P"));
}
#[test]
fn test_encrypt_pdf_custom_permissions() {
let dir = tempdir().unwrap();
let input_path = dir.path().join("input.pdf");
let output_path = dir.path().join("custom_perms.pdf");
create_test_pdf_with_content(input_path.to_str().unwrap(), "Custom permissions test")
.unwrap();
let mut editor = DocumentEditor::open(&input_path).unwrap();
let perms = Permissions {
print: true,
print_high_quality: true,
modify: false,
copy: true,
annotate: false,
fill_forms: false,
accessibility: true,
assemble: false,
};
let config = EncryptionConfig::new("user", "owner").with_permissions(perms);
editor
.save_with_options(&output_path, SaveOptions::with_encryption(config))
.unwrap();
assert!(output_path.exists());
}
}
mod empty_password_tests {
use super::*;
#[test]
fn test_encrypt_with_empty_user_password_creates_valid_pdf() {
let dir = tempdir().unwrap();
let input_path = dir.path().join("input.pdf");
let output_path = dir.path().join("owner_only.pdf");
create_test_pdf_with_content(input_path.to_str().unwrap(), "Owner password only test")
.unwrap();
let mut editor = DocumentEditor::open(&input_path).unwrap();
let config =
EncryptionConfig::new("", "ownerpass").with_permissions(Permissions::read_only());
editor
.save_with_options(&output_path, SaveOptions::with_encryption(config))
.unwrap();
assert!(output_path.exists());
let output_str = read_file_as_string(&output_path);
assert!(output_str.contains("/Encrypt"));
assert!(output_str.contains("/O ")); assert!(output_str.contains("/U ")); assert!(output_str.contains("/P ")); }
}
mod api_encryption_tests {
use super::*;
use pdf_oxide::api::Pdf;
#[test]
fn test_pdf_api_save_encrypted() {
let dir = tempdir().unwrap();
let input_path = dir.path().join("input.pdf");
let output_path = dir.path().join("encrypted_api.pdf");
create_test_pdf_with_content(input_path.to_str().unwrap(), "API encryption test").unwrap();
let mut pdf = Pdf::open(&input_path).unwrap();
pdf.save_encrypted(&output_path, "user", "owner").unwrap();
assert!(output_path.exists());
let output_str = read_file_as_string(&output_path);
assert!(output_str.contains("/Encrypt"));
}
#[test]
fn test_pdf_api_save_with_encryption_config() {
let dir = tempdir().unwrap();
let input_path = dir.path().join("input.pdf");
let output_path = dir.path().join("encrypted_config.pdf");
create_test_pdf_with_content(input_path.to_str().unwrap(), "Config encryption test")
.unwrap();
let mut pdf = Pdf::open(&input_path).unwrap();
let config = EncryptionConfig::new("myuser", "myowner")
.with_algorithm(EncryptionAlgorithm::Aes128)
.with_permissions(Permissions::all());
pdf.save_with_encryption(&output_path, config).unwrap();
assert!(output_path.exists());
let output_str = read_file_as_string(&output_path);
assert!(output_str.contains("/Encrypt"));
assert!(output_str.contains("/V 4")); }
#[test]
fn test_pdf_api_save_encrypted_with_empty_password() {
let dir = tempdir().unwrap();
let input_path = dir.path().join("input.pdf");
let output_path = dir.path().join("encrypted_empty.pdf");
create_test_pdf_with_content(input_path.to_str().unwrap(), "API empty password test")
.unwrap();
let mut pdf = Pdf::open(&input_path).unwrap();
pdf.save_encrypted(&output_path, "", "owner").unwrap();
assert!(output_path.exists());
let output_str = read_file_as_string(&output_path);
assert!(output_str.contains("/Encrypt"));
}
}