1use super::objects::PdfDictionary;
7use super::{ParseError, ParseResult};
8use crate::encryption::{EncryptionKey, Permissions, StandardSecurityHandler, UserPassword};
9use crate::objects::ObjectId;
10
11#[derive(Debug, Clone)]
13pub struct EncryptionInfo {
14 pub filter: String,
16 pub v: i32,
18 pub r: i32,
20 pub o: Vec<u8>,
22 pub u: Vec<u8>,
24 pub p: i32,
26 pub length: Option<i32>,
28}
29
30pub struct EncryptionHandler {
32 encryption_info: EncryptionInfo,
34 security_handler: StandardSecurityHandler,
36 encryption_key: Option<EncryptionKey>,
38 file_id: Option<Vec<u8>>,
40}
41
42impl EncryptionHandler {
43 pub fn new(encrypt_dict: &PdfDictionary, file_id: Option<Vec<u8>>) -> ParseResult<Self> {
45 let encryption_info = Self::parse_encryption_dict(encrypt_dict)?;
46
47 let security_handler = match encryption_info.r {
49 2 => StandardSecurityHandler::rc4_40bit(),
50 3 | 4 => StandardSecurityHandler::rc4_128bit(),
51 5 => StandardSecurityHandler::aes_256_r5(),
52 6 => StandardSecurityHandler::aes_256_r6(),
53 _ => {
54 return Err(ParseError::SyntaxError {
55 position: 0,
56 message: format!("Encryption revision {} not supported", encryption_info.r),
57 });
58 }
59 };
60
61 Ok(Self {
62 encryption_info,
63 security_handler,
64 encryption_key: None,
65 file_id,
66 })
67 }
68
69 fn parse_encryption_dict(dict: &PdfDictionary) -> ParseResult<EncryptionInfo> {
71 let filter = dict
73 .get("Filter")
74 .and_then(|obj| obj.as_name())
75 .map(|name| name.0.as_str())
76 .ok_or_else(|| ParseError::MissingKey("Filter".to_string()))?;
77
78 if filter != "Standard" {
79 return Err(ParseError::SyntaxError {
80 position: 0,
81 message: format!("Encryption filter '{filter}' not supported"),
82 });
83 }
84
85 let v = dict
87 .get("V")
88 .and_then(|obj| obj.as_integer())
89 .map(|i| i as i32)
90 .unwrap_or(0);
91
92 let r = dict
94 .get("R")
95 .and_then(|obj| obj.as_integer())
96 .map(|i| i as i32)
97 .ok_or_else(|| ParseError::MissingKey("R".to_string()))?;
98
99 let o = dict
101 .get("O")
102 .and_then(|obj| obj.as_string())
103 .ok_or_else(|| ParseError::MissingKey("O".to_string()))?
104 .as_bytes()
105 .to_vec();
106
107 let u = dict
109 .get("U")
110 .and_then(|obj| obj.as_string())
111 .ok_or_else(|| ParseError::MissingKey("U".to_string()))?
112 .as_bytes()
113 .to_vec();
114
115 let p = dict
117 .get("P")
118 .and_then(|obj| obj.as_integer())
119 .map(|i| i as i32)
120 .ok_or_else(|| ParseError::MissingKey("P".to_string()))?;
121
122 let length = dict
124 .get("Length")
125 .and_then(|obj| obj.as_integer())
126 .map(|i| i as i32);
127
128 Ok(EncryptionInfo {
129 filter: filter.to_string(),
130 v,
131 r,
132 o,
133 u,
134 p,
135 length,
136 })
137 }
138
139 pub fn detect_encryption(trailer: &PdfDictionary) -> bool {
141 trailer.contains_key("Encrypt")
142 }
143
144 pub fn unlock_with_user_password(&mut self, password: &str) -> ParseResult<bool> {
146 let user_password = UserPassword(password.to_string());
147
148 let permissions = Permissions::from_bits(self.encryption_info.p as u32);
150 let computed_u = self
151 .security_handler
152 .compute_user_hash(
153 &user_password,
154 &self.encryption_info.o,
155 permissions,
156 self.file_id.as_deref(),
157 )
158 .map_err(|e| ParseError::SyntaxError {
159 position: 0,
160 message: format!("Failed to compute user hash: {e}"),
161 })?;
162
163 let comparison_length = if self.encryption_info.r >= 3 { 16 } else { 32 };
165 let matches =
166 computed_u[..comparison_length] == self.encryption_info.u[..comparison_length];
167
168 if matches {
169 let key = self
171 .security_handler
172 .compute_encryption_key(
173 &user_password,
174 &self.encryption_info.o,
175 permissions,
176 self.file_id.as_deref(),
177 )
178 .map_err(|e| ParseError::SyntaxError {
179 position: 0,
180 message: format!("Failed to compute encryption key: {e}"),
181 })?;
182 self.encryption_key = Some(key);
183 }
184
185 Ok(matches)
186 }
187
188 pub fn unlock_with_owner_password(&mut self, password: &str) -> ParseResult<bool> {
190 self.unlock_with_user_password(password)
196 }
197
198 pub fn try_empty_password(&mut self) -> ParseResult<bool> {
200 self.unlock_with_user_password("")
201 }
202
203 pub fn is_unlocked(&self) -> bool {
205 self.encryption_key.is_some()
206 }
207
208 pub fn encryption_key(&self) -> Option<&EncryptionKey> {
210 self.encryption_key.as_ref()
211 }
212
213 pub fn decrypt_string(&self, data: &[u8], obj_id: &ObjectId) -> ParseResult<Vec<u8>> {
215 match &self.encryption_key {
216 Some(key) => Ok(self.security_handler.decrypt_string(data, key, obj_id)),
217 None => Err(ParseError::EncryptionNotSupported),
218 }
219 }
220
221 pub fn decrypt_stream(&self, data: &[u8], obj_id: &ObjectId) -> ParseResult<Vec<u8>> {
223 match &self.encryption_key {
224 Some(key) => Ok(self.security_handler.decrypt_stream(data, key, obj_id)),
225 None => Err(ParseError::EncryptionNotSupported),
226 }
227 }
228
229 pub fn algorithm_info(&self) -> String {
231 match (
232 self.encryption_info.r,
233 self.encryption_info.length.unwrap_or(40),
234 ) {
235 (2, _) => "RC4 40-bit".to_string(),
236 (3, len) => format!("RC4 {len}-bit"),
237 (4, len) => format!("RC4 {len}-bit with metadata control"),
238 (5, _) => "AES-256 (Revision 5)".to_string(),
239 (6, _) => "AES-256 (Revision 6, Unicode passwords)".to_string(),
240 (r, len) => format!("Unknown revision {r} with {len}-bit key"),
241 }
242 }
243
244 pub fn permissions(&self) -> Permissions {
246 Permissions::from_bits(self.encryption_info.p as u32)
247 }
248
249 pub fn encrypt_strings(&self) -> bool {
251 true
253 }
254
255 pub fn encrypt_streams(&self) -> bool {
257 true
259 }
260
261 pub fn encrypt_metadata(&self) -> bool {
263 true
266 }
267}
268
269#[derive(Debug)]
271pub enum PasswordResult {
272 Success,
274 Rejected,
276 Cancelled,
278}
279
280pub trait PasswordProvider {
282 fn prompt_user_password(&self) -> ParseResult<Option<String>>;
284
285 fn prompt_owner_password(&self) -> ParseResult<Option<String>>;
287}
288
289pub struct ConsolePasswordProvider;
291
292impl PasswordProvider for ConsolePasswordProvider {
293 fn prompt_user_password(&self) -> ParseResult<Option<String>> {
294 println!("PDF is encrypted. Enter user password (or press Enter for empty password):");
295
296 let mut input = String::new();
297 std::io::stdin()
298 .read_line(&mut input)
299 .map_err(|e| ParseError::SyntaxError {
300 position: 0,
301 message: format!("Failed to read password: {e}"),
302 })?;
303
304 input.truncate(input.trim_end().len());
306 Ok(Some(input))
307 }
308
309 fn prompt_owner_password(&self) -> ParseResult<Option<String>> {
310 println!("User password failed. Enter owner password:");
311
312 let mut input = String::new();
313 std::io::stdin()
314 .read_line(&mut input)
315 .map_err(|e| ParseError::SyntaxError {
316 position: 0,
317 message: format!("Failed to read password: {e}"),
318 })?;
319
320 input.truncate(input.trim_end().len());
322 Ok(Some(input))
323 }
324}
325
326pub struct InteractiveDecryption<P: PasswordProvider> {
328 password_provider: P,
329}
330
331impl<P: PasswordProvider> InteractiveDecryption<P> {
332 pub fn new(password_provider: P) -> Self {
334 Self { password_provider }
335 }
336
337 pub fn unlock_pdf(&self, handler: &mut EncryptionHandler) -> ParseResult<PasswordResult> {
339 if handler.try_empty_password()? {
341 return Ok(PasswordResult::Success);
342 }
343
344 if let Some(password) = self.password_provider.prompt_user_password()? {
346 if handler.unlock_with_user_password(&password)? {
347 return Ok(PasswordResult::Success);
348 }
349 } else {
350 return Ok(PasswordResult::Cancelled);
351 }
352
353 if let Some(password) = self.password_provider.prompt_owner_password()? {
355 if handler.unlock_with_owner_password(&password)? {
356 return Ok(PasswordResult::Success);
357 }
358 } else {
359 return Ok(PasswordResult::Cancelled);
360 }
361
362 Ok(PasswordResult::Rejected)
363 }
364}
365
366#[cfg(test)]
367mod tests {
368 use super::*;
369 use crate::parser::objects::{PdfDictionary, PdfName, PdfObject, PdfString};
370
371 fn create_test_encryption_dict() -> PdfDictionary {
372 let mut dict = PdfDictionary::new();
373 dict.insert(
374 "Filter".to_string(),
375 PdfObject::Name(PdfName("Standard".to_string())),
376 );
377 dict.insert("V".to_string(), PdfObject::Integer(1));
378 dict.insert("R".to_string(), PdfObject::Integer(2));
379 dict.insert(
380 "O".to_string(),
381 PdfObject::String(PdfString::new(vec![0u8; 32])),
382 );
383 dict.insert(
384 "U".to_string(),
385 PdfObject::String(PdfString::new(vec![0u8; 32])),
386 );
387 dict.insert("P".to_string(), PdfObject::Integer(-4));
388 dict
389 }
390
391 #[test]
392 fn test_encryption_detection() {
393 let mut trailer = PdfDictionary::new();
394 assert!(!EncryptionHandler::detect_encryption(&trailer));
395
396 trailer.insert("Encrypt".to_string(), PdfObject::Reference(1, 0));
397 assert!(EncryptionHandler::detect_encryption(&trailer));
398 }
399
400 #[test]
401 fn test_encryption_info_parsing() {
402 let dict = create_test_encryption_dict();
403 let info = EncryptionHandler::parse_encryption_dict(&dict).unwrap();
404
405 assert_eq!(info.filter, "Standard");
406 assert_eq!(info.v, 1);
407 assert_eq!(info.r, 2);
408 assert_eq!(info.o.len(), 32);
409 assert_eq!(info.u.len(), 32);
410 assert_eq!(info.p, -4);
411 }
412
413 #[test]
414 fn test_encryption_handler_creation() {
415 let dict = create_test_encryption_dict();
416 let handler = EncryptionHandler::new(&dict, None).unwrap();
417
418 assert_eq!(handler.encryption_info.r, 2);
419 assert!(!handler.is_unlocked());
420 assert_eq!(handler.algorithm_info(), "RC4 40-bit");
421 }
422
423 #[test]
424 fn test_empty_password_attempt() {
425 let dict = create_test_encryption_dict();
426 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
427
428 let result = handler.try_empty_password().unwrap();
430 assert!(!result);
431 assert!(!handler.is_unlocked());
432 }
433
434 #[test]
435 fn test_permissions() {
436 let dict = create_test_encryption_dict();
437 let handler = EncryptionHandler::new(&dict, None).unwrap();
438
439 let permissions = handler.permissions();
440 assert!(permissions.bits() != 0);
442 }
443
444 #[test]
445 fn test_encryption_flags() {
446 let dict = create_test_encryption_dict();
447 let handler = EncryptionHandler::new(&dict, None).unwrap();
448
449 assert!(handler.encrypt_strings());
450 assert!(handler.encrypt_streams());
451 assert!(handler.encrypt_metadata());
452 }
453
454 #[test]
455 fn test_decrypt_without_key() {
456 let dict = create_test_encryption_dict();
457 let handler = EncryptionHandler::new(&dict, None).unwrap();
458
459 let obj_id = ObjectId::new(1, 0);
460 let result = handler.decrypt_string(b"test", &obj_id);
461 assert!(result.is_err());
462 }
463
464 #[test]
465 fn test_unsupported_filter() {
466 let mut dict = PdfDictionary::new();
467 dict.insert(
468 "Filter".to_string(),
469 PdfObject::Name(PdfName("UnsupportedFilter".to_string())),
470 );
471 dict.insert("R".to_string(), PdfObject::Integer(2));
472 dict.insert(
473 "O".to_string(),
474 PdfObject::String(PdfString::new(vec![0u8; 32])),
475 );
476 dict.insert(
477 "U".to_string(),
478 PdfObject::String(PdfString::new(vec![0u8; 32])),
479 );
480 dict.insert("P".to_string(), PdfObject::Integer(-4));
481
482 let result = EncryptionHandler::new(&dict, None);
483 assert!(result.is_err());
484 }
485
486 #[test]
487 fn test_unsupported_revision() {
488 let mut dict = create_test_encryption_dict();
489 dict.insert("R".to_string(), PdfObject::Integer(99)); let result = EncryptionHandler::new(&dict, None);
492 assert!(result.is_err());
493 }
494
495 #[test]
496 fn test_missing_required_keys() {
497 let test_cases = vec![
498 ("Filter", PdfObject::Name(PdfName("Standard".to_string()))),
499 ("R", PdfObject::Integer(2)),
500 ("O", PdfObject::String(PdfString::new(vec![0u8; 32]))),
501 ("U", PdfObject::String(PdfString::new(vec![0u8; 32]))),
502 ("P", PdfObject::Integer(-4)),
503 ];
504
505 for (skip_key, _) in test_cases {
506 let mut dict = create_test_encryption_dict();
507 dict.0.remove(&PdfName(skip_key.to_string()));
508
509 let result = EncryptionHandler::parse_encryption_dict(&dict);
510 assert!(result.is_err(), "Should fail when {skip_key} is missing");
511 }
512 }
513
514 struct MockPasswordProvider {
516 user_password: Option<String>,
517 owner_password: Option<String>,
518 }
519
520 impl PasswordProvider for MockPasswordProvider {
521 fn prompt_user_password(&self) -> ParseResult<Option<String>> {
522 Ok(self.user_password.clone())
523 }
524
525 fn prompt_owner_password(&self) -> ParseResult<Option<String>> {
526 Ok(self.owner_password.clone())
527 }
528 }
529
530 #[test]
531 fn test_interactive_decryption_cancelled() {
532 let provider = MockPasswordProvider {
533 user_password: None,
534 owner_password: None,
535 };
536
537 let decryption = InteractiveDecryption::new(provider);
538 let dict = create_test_encryption_dict();
539 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
540
541 let result = decryption.unlock_pdf(&mut handler).unwrap();
542 matches!(result, PasswordResult::Cancelled);
543 }
544
545 #[test]
546 fn test_interactive_decryption_rejected() {
547 let provider = MockPasswordProvider {
548 user_password: Some("wrong_password".to_string()),
549 owner_password: Some("also_wrong".to_string()),
550 };
551
552 let decryption = InteractiveDecryption::new(provider);
553 let dict = create_test_encryption_dict();
554 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
555
556 let result = decryption.unlock_pdf(&mut handler).unwrap();
557 matches!(result, PasswordResult::Rejected);
558 }
559
560 #[test]
563 fn test_malformed_encryption_dictionary_invalid_types() {
564 let mut dict = PdfDictionary::new();
566 dict.insert("Filter".to_string(), PdfObject::Integer(123)); dict.insert("R".to_string(), PdfObject::Integer(2));
568 dict.insert(
569 "O".to_string(),
570 PdfObject::String(PdfString::new(vec![0u8; 32])),
571 );
572 dict.insert(
573 "U".to_string(),
574 PdfObject::String(PdfString::new(vec![0u8; 32])),
575 );
576 dict.insert("P".to_string(), PdfObject::Integer(-4));
577
578 let result = EncryptionHandler::parse_encryption_dict(&dict);
579 assert!(result.is_err());
580
581 let mut dict = create_test_encryption_dict();
583 dict.insert(
584 "R".to_string(),
585 PdfObject::Name(PdfName("not_a_number".to_string())),
586 );
587 let result = EncryptionHandler::parse_encryption_dict(&dict);
588 assert!(result.is_err());
589 }
590
591 #[test]
592 fn test_encryption_dictionary_edge_values() {
593 let mut dict = create_test_encryption_dict();
595 dict.insert("R".to_string(), PdfObject::Integer(0)); let result = EncryptionHandler::new(&dict, None);
597 assert!(result.is_err());
598
599 let mut dict = create_test_encryption_dict();
601 dict.insert("R".to_string(), PdfObject::Integer(-1));
602 let result = EncryptionHandler::new(&dict, None);
603 assert!(result.is_err());
604
605 let mut dict = create_test_encryption_dict();
607 dict.insert("R".to_string(), PdfObject::Integer(1000));
608 let result = EncryptionHandler::new(&dict, None);
609 assert!(result.is_err());
610 }
611
612 #[test]
613 fn test_encryption_dictionary_invalid_hash_lengths() {
614 let mut dict = create_test_encryption_dict();
616 dict.insert(
617 "O".to_string(),
618 PdfObject::String(PdfString::new(vec![0u8; 16])),
619 ); let result = EncryptionHandler::parse_encryption_dict(&dict);
621 assert!(result.is_ok());
623
624 let mut dict = create_test_encryption_dict();
626 dict.insert(
627 "U".to_string(),
628 PdfObject::String(PdfString::new(vec![0u8; 64])),
629 ); let result = EncryptionHandler::parse_encryption_dict(&dict);
631 assert!(result.is_ok());
632
633 let mut dict = create_test_encryption_dict();
635 dict.insert("O".to_string(), PdfObject::String(PdfString::new(vec![])));
636 dict.insert("U".to_string(), PdfObject::String(PdfString::new(vec![])));
637 let result = EncryptionHandler::parse_encryption_dict(&dict);
638 assert!(result.is_ok());
639 }
640
641 #[test]
642 fn test_encryption_with_different_key_lengths() {
643 let mut dict = create_test_encryption_dict();
645 dict.insert("R".to_string(), PdfObject::Integer(2));
646 let handler = EncryptionHandler::new(&dict, None).unwrap();
647 assert_eq!(handler.algorithm_info(), "RC4 40-bit");
648
649 let mut dict = create_test_encryption_dict();
651 dict.insert("R".to_string(), PdfObject::Integer(3));
652 dict.insert("Length".to_string(), PdfObject::Integer(128));
653 let handler = EncryptionHandler::new(&dict, None).unwrap();
654 assert_eq!(handler.algorithm_info(), "RC4 128-bit");
655
656 let mut dict = create_test_encryption_dict();
658 dict.insert("R".to_string(), PdfObject::Integer(4));
659 dict.insert("Length".to_string(), PdfObject::Integer(128));
660 let handler = EncryptionHandler::new(&dict, None).unwrap();
661 assert_eq!(
662 handler.algorithm_info(),
663 "RC4 128-bit with metadata control"
664 );
665
666 let mut dict = create_test_encryption_dict();
668 dict.insert("R".to_string(), PdfObject::Integer(5));
669 dict.insert("V".to_string(), PdfObject::Integer(5));
670 let handler = EncryptionHandler::new(&dict, None).unwrap();
671 assert_eq!(handler.algorithm_info(), "AES-256 (Revision 5)");
672
673 let mut dict = create_test_encryption_dict();
675 dict.insert("R".to_string(), PdfObject::Integer(6));
676 dict.insert("V".to_string(), PdfObject::Integer(5));
677 let handler = EncryptionHandler::new(&dict, None).unwrap();
678 assert_eq!(
679 handler.algorithm_info(),
680 "AES-256 (Revision 6, Unicode passwords)"
681 );
682 }
683
684 #[test]
685 fn test_file_id_handling() {
686 let dict = create_test_encryption_dict();
687
688 let file_id = Some(b"test_file_id_12345678".to_vec());
690 let handler = EncryptionHandler::new(&dict, file_id.clone()).unwrap();
691 assert_eq!(handler.file_id, file_id);
693
694 let handler = EncryptionHandler::new(&dict, None).unwrap();
696 assert_eq!(handler.file_id, None);
697
698 let empty_file_id = Some(vec![]);
700 let handler = EncryptionHandler::new(&dict, empty_file_id.clone()).unwrap();
701 assert_eq!(handler.file_id, empty_file_id);
702 }
703
704 #[test]
705 fn test_permissions_edge_cases() {
706 let permission_values = vec![0, -1, -4, -44, -100, i32::MAX, i32::MIN];
708
709 for p_value in permission_values {
710 let mut dict = create_test_encryption_dict();
711 dict.insert("P".to_string(), PdfObject::Integer(p_value as i64));
712 let handler = EncryptionHandler::new(&dict, None).unwrap();
713
714 let permissions = handler.permissions();
715 assert_eq!(permissions.bits(), p_value as u32);
716 }
717 }
718
719 #[test]
720 fn test_decrypt_with_different_object_ids() {
721 let dict = create_test_encryption_dict();
722 let handler = EncryptionHandler::new(&dict, None).unwrap();
723 let test_data = b"test data";
724
725 let object_ids = vec![
727 ObjectId::new(1, 0),
728 ObjectId::new(999, 0),
729 ObjectId::new(1, 999),
730 ObjectId::new(u32::MAX, u16::MAX),
731 ];
732
733 for obj_id in object_ids {
734 let result = handler.decrypt_string(test_data, &obj_id);
735 assert!(result.is_err());
736
737 let result = handler.decrypt_stream(test_data, &obj_id);
738 assert!(result.is_err());
739 }
740 }
741
742 #[test]
743 fn test_password_scenarios_comprehensive() {
744 let dict = create_test_encryption_dict();
745 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
746
747 let test_passwords = vec![
749 "".to_string(), " ".to_string(), " ".to_string(), "password".to_string(), "Password123!@#".to_string(), "a".repeat(32), "a".repeat(50), "unicode_ñáéíóú".to_string(), "pass\nwith\nnewlines".to_string(), "pass\twith\ttabs".to_string(), "pass with spaces".to_string(), "🔐🗝️📄".to_string(), ];
762
763 for password in test_passwords {
764 let result = handler.unlock_with_user_password(&password);
766 assert!(result.is_ok());
767 assert!(!result.unwrap());
768
769 let result = handler.unlock_with_owner_password(&password);
770 assert!(result.is_ok());
771 assert!(!result.unwrap());
772 }
773 }
774
775 #[test]
776 fn test_encryption_handler_thread_safety_simulation() {
777 let dict = create_test_encryption_dict();
779 let handler = EncryptionHandler::new(&dict, None).unwrap();
780
781 for _ in 0..100 {
783 assert!(!handler.is_unlocked());
784 assert_eq!(handler.algorithm_info(), "RC4 40-bit");
785 assert!(handler.encrypt_strings());
786 assert!(handler.encrypt_streams());
787 assert!(handler.encrypt_metadata());
788 }
789 }
790
791 #[test]
792 fn test_encryption_state_transitions() {
793 let dict = create_test_encryption_dict();
794 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
795
796 assert!(!handler.is_unlocked());
798
799 let result = handler.try_empty_password().unwrap();
801 assert!(!result);
802 assert!(!handler.is_unlocked());
803
804 let result = handler.unlock_with_user_password("test").unwrap();
806 assert!(!result);
807 assert!(!handler.is_unlocked());
808
809 let result = handler.unlock_with_owner_password("test").unwrap();
811 assert!(!result);
812 assert!(!handler.is_unlocked());
813
814 assert!(!handler.is_unlocked());
816 }
817
818 #[test]
819 fn test_interactive_decryption_edge_cases() {
820 let provider = MockPasswordProvider {
822 user_password: None,
823 owner_password: None,
824 };
825
826 let decryption = InteractiveDecryption::new(provider);
827 let dict = create_test_encryption_dict();
828 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
829
830 let result = decryption.unlock_pdf(&mut handler).unwrap();
831 matches!(result, PasswordResult::Cancelled);
832
833 let provider = MockPasswordProvider {
835 user_password: Some("".to_string()),
836 owner_password: Some("".to_string()),
837 };
838
839 let decryption = InteractiveDecryption::new(provider);
840 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
841
842 let result = decryption.unlock_pdf(&mut handler).unwrap();
843 matches!(result, PasswordResult::Rejected);
844 }
845
846 struct EdgeCasePasswordProvider {
848 call_count: std::cell::RefCell<usize>,
849 passwords: Vec<Option<String>>,
850 }
851
852 impl EdgeCasePasswordProvider {
853 fn new(passwords: Vec<Option<String>>) -> Self {
854 Self {
855 call_count: std::cell::RefCell::new(0),
856 passwords,
857 }
858 }
859 }
860
861 impl PasswordProvider for EdgeCasePasswordProvider {
862 fn prompt_user_password(&self) -> ParseResult<Option<String>> {
863 let mut count = self.call_count.borrow_mut();
864 if *count < self.passwords.len() {
865 let result = self.passwords[*count].clone();
866 *count += 1;
867 Ok(result)
868 } else {
869 Ok(None)
870 }
871 }
872
873 fn prompt_owner_password(&self) -> ParseResult<Option<String>> {
874 self.prompt_user_password()
875 }
876 }
877
878 #[test]
879 fn test_interactive_decryption_with_sequence() {
880 let passwords = vec![
881 Some("first_attempt".to_string()),
882 Some("second_attempt".to_string()),
883 None, ];
885
886 let provider = EdgeCasePasswordProvider::new(passwords);
887 let decryption = InteractiveDecryption::new(provider);
888 let dict = create_test_encryption_dict();
889 let mut handler = EncryptionHandler::new(&dict, None).unwrap();
890
891 let result = decryption.unlock_pdf(&mut handler).unwrap();
892 matches!(result, PasswordResult::Cancelled);
893 }
894}