1use crate::encryption::Permissions;
7use crate::error::{PdfError, Result};
8use std::sync::Mutex;
9
10#[derive(Debug, Clone, Copy, PartialEq)]
12pub enum PermissionOperation {
13 Print,
15 PrintHighQuality,
17 ModifyContents,
19 Copy,
21 ModifyAnnotations,
23 FillForms,
25 Accessibility,
27 Assemble,
29}
30
31impl PermissionOperation {
32 pub fn name(&self) -> &'static str {
34 match self {
35 PermissionOperation::Print => "Print",
36 PermissionOperation::PrintHighQuality => "Print High Quality",
37 PermissionOperation::ModifyContents => "Modify Contents",
38 PermissionOperation::Copy => "Copy",
39 PermissionOperation::ModifyAnnotations => "Modify Annotations",
40 PermissionOperation::FillForms => "Fill Forms",
41 PermissionOperation::Accessibility => "Accessibility",
42 PermissionOperation::Assemble => "Assemble",
43 }
44 }
45}
46
47#[derive(Debug, Clone)]
49pub struct PermissionCheckResult {
50 pub operation: PermissionOperation,
52 pub allowed: bool,
54 pub timestamp: std::time::SystemTime,
56 pub context: Option<String>,
58}
59
60pub type PermissionCallback = Box<dyn Fn(&PermissionCheckResult) + Send + Sync>;
62
63#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
65pub enum LogLevel {
66 Debug,
68 Info,
70 Warn,
72 Error,
74}
75
76#[derive(Debug, Clone)]
78pub struct PermissionEvent {
79 pub level: LogLevel,
81 pub operation: PermissionOperation,
83 pub allowed: bool,
85 pub timestamp: std::time::SystemTime,
87 pub message: String,
89}
90
91pub trait PermissionsValidator: Send + Sync {
93 fn validate(&self, operation: PermissionOperation) -> Result<bool>;
95
96 fn permissions(&self) -> Permissions;
98}
99
100pub struct RuntimePermissions {
102 permissions: Permissions,
104 callbacks: Vec<PermissionCallback>,
106 log_level: LogLevel,
108 event_log: Mutex<Vec<PermissionEvent>>,
110 enforce: bool,
112}
113
114impl RuntimePermissions {
115 pub fn new(permissions: Permissions) -> Self {
117 Self {
118 permissions,
119 callbacks: Vec::new(),
120 log_level: LogLevel::Info,
121 event_log: Mutex::new(Vec::new()),
122 enforce: true,
123 }
124 }
125
126 pub fn add_callback<F>(&mut self, callback: F)
128 where
129 F: Fn(&PermissionCheckResult) + Send + Sync + 'static,
130 {
131 self.callbacks.push(Box::new(callback));
132 }
133
134 pub fn set_log_level(&mut self, level: LogLevel) {
136 self.log_level = level;
137 }
138
139 pub fn set_enforce(&mut self, enforce: bool) {
141 self.enforce = enforce;
142 }
143
144 pub fn get_events(&self) -> Vec<PermissionEvent> {
146 self.event_log
147 .lock()
148 .map(|log| log.clone())
149 .unwrap_or_else(|_| Vec::new())
150 }
151
152 pub fn clear_events(&self) {
154 if let Ok(mut log) = self.event_log.lock() {
155 log.clear();
156 }
157 }
159
160 fn check_permission(&self, operation: PermissionOperation) -> bool {
162 if !self.enforce {
163 return true;
164 }
165
166 match operation {
167 PermissionOperation::Print => self.permissions.can_print(),
168 PermissionOperation::PrintHighQuality => self.permissions.can_print_high_quality(),
169 PermissionOperation::ModifyContents => self.permissions.can_modify_contents(),
170 PermissionOperation::Copy => self.permissions.can_copy(),
171 PermissionOperation::ModifyAnnotations => self.permissions.can_modify_annotations(),
172 PermissionOperation::FillForms => self.permissions.can_fill_forms(),
173 PermissionOperation::Accessibility => self.permissions.can_access_for_accessibility(),
174 PermissionOperation::Assemble => self.permissions.can_assemble(),
175 }
176 }
177
178 fn log_event(&self, operation: PermissionOperation, allowed: bool, message: String) {
180 let level = if allowed {
181 if self.log_level <= LogLevel::Debug {
182 LogLevel::Debug
183 } else {
184 LogLevel::Info
185 }
186 } else {
187 LogLevel::Warn
188 };
189
190 let event = PermissionEvent {
191 level,
192 operation,
193 allowed,
194 timestamp: std::time::SystemTime::now(),
195 message,
196 };
197
198 if level >= self.log_level {
199 if let Ok(mut log) = self.event_log.lock() {
200 log.push(event);
201 }
202 }
204 }
205
206 fn execute_callbacks(&self, result: &PermissionCheckResult) {
208 for callback in &self.callbacks {
209 callback(result);
210 }
211 }
212
213 fn validate_operation(
215 &self,
216 operation: PermissionOperation,
217 context: Option<String>,
218 ) -> Result<()> {
219 let allowed = self.check_permission(operation);
220
221 let result = PermissionCheckResult {
222 operation,
223 allowed,
224 timestamp: std::time::SystemTime::now(),
225 context: context.clone(),
226 };
227
228 self.execute_callbacks(&result);
230
231 let message = if let Some(ctx) = context {
233 format!(
234 "{} operation {} ({})",
235 operation.name(),
236 if allowed { "allowed" } else { "denied" },
237 ctx
238 )
239 } else {
240 format!(
241 "{} operation {}",
242 operation.name(),
243 if allowed { "allowed" } else { "denied" }
244 )
245 };
246 self.log_event(operation, allowed, message);
247
248 if allowed {
249 Ok(())
250 } else {
251 Err(PdfError::PermissionDenied(format!(
252 "Permission denied for {} operation",
253 operation.name()
254 )))
255 }
256 }
257
258 pub fn on_print(&self, context: Option<String>) -> Result<()> {
262 self.validate_operation(PermissionOperation::Print, context)
263 }
264
265 pub fn on_print_high_quality(&self, context: Option<String>) -> Result<()> {
267 self.validate_operation(PermissionOperation::PrintHighQuality, context)
268 }
269
270 pub fn on_modify(&self, context: Option<String>) -> Result<()> {
272 self.validate_operation(PermissionOperation::ModifyContents, context)
273 }
274
275 pub fn on_copy(&self, context: Option<String>) -> Result<()> {
277 self.validate_operation(PermissionOperation::Copy, context)
278 }
279
280 pub fn on_modify_annotations(&self, context: Option<String>) -> Result<()> {
282 self.validate_operation(PermissionOperation::ModifyAnnotations, context)
283 }
284
285 pub fn on_form_fill(&self, context: Option<String>) -> Result<()> {
287 self.validate_operation(PermissionOperation::FillForms, context)
288 }
289
290 pub fn on_accessibility(&self, context: Option<String>) -> Result<()> {
292 self.validate_operation(PermissionOperation::Accessibility, context)
293 }
294
295 pub fn on_assemble(&self, context: Option<String>) -> Result<()> {
297 self.validate_operation(PermissionOperation::Assemble, context)
298 }
299}
300
301impl PermissionsValidator for RuntimePermissions {
302 fn validate(&self, operation: PermissionOperation) -> Result<bool> {
303 Ok(self.check_permission(operation))
304 }
305
306 fn permissions(&self) -> Permissions {
307 self.permissions
308 }
309}
310
311pub struct RuntimePermissionsBuilder {
313 permissions: Permissions,
314 callbacks: Vec<PermissionCallback>,
315 log_level: LogLevel,
316 enforce: bool,
317}
318
319impl RuntimePermissionsBuilder {
320 pub fn new(permissions: Permissions) -> Self {
322 Self {
323 permissions,
324 callbacks: Vec::new(),
325 log_level: LogLevel::Info,
326 enforce: true,
327 }
328 }
329
330 pub fn with_callback<F>(mut self, callback: F) -> Self
332 where
333 F: Fn(&PermissionCheckResult) + Send + Sync + 'static,
334 {
335 self.callbacks.push(Box::new(callback));
336 self
337 }
338
339 pub fn with_log_level(mut self, level: LogLevel) -> Self {
341 self.log_level = level;
342 self
343 }
344
345 pub fn with_enforcement(mut self, enforce: bool) -> Self {
347 self.enforce = enforce;
348 self
349 }
350
351 pub fn build(self) -> RuntimePermissions {
353 let mut runtime = RuntimePermissions::new(self.permissions);
354 runtime.callbacks = self.callbacks;
355 runtime.log_level = self.log_level;
356 runtime.enforce = self.enforce;
357 runtime
358 }
359}
360
361#[cfg(test)]
362mod tests {
363 use super::*;
364 use std::sync::{Arc, Mutex};
365
366 #[test]
367 fn test_permission_operation_names() {
368 assert_eq!(PermissionOperation::Print.name(), "Print");
369 assert_eq!(
370 PermissionOperation::ModifyContents.name(),
371 "Modify Contents"
372 );
373 assert_eq!(PermissionOperation::Accessibility.name(), "Accessibility");
374 }
375
376 #[test]
377 fn test_runtime_permissions_allow() {
378 let perms = Permissions::all();
379 let runtime = RuntimePermissions::new(perms);
380
381 assert!(runtime.on_print(None).is_ok());
382 assert!(runtime.on_modify(None).is_ok());
383 assert!(runtime.on_copy(None).is_ok());
384 }
385
386 #[test]
387 fn test_runtime_permissions_deny() {
388 let perms = Permissions::new(); let runtime = RuntimePermissions::new(perms);
390
391 assert!(runtime.on_print(None).is_err());
392 assert!(runtime.on_modify(None).is_err());
393 assert!(runtime.on_copy(None).is_err());
394 }
395
396 #[test]
397 fn test_runtime_permissions_selective() {
398 let perms = *Permissions::new().set_print(true).set_copy(true);
399 let runtime = RuntimePermissions::new(perms);
400
401 assert!(runtime.on_print(None).is_ok());
402 assert!(runtime.on_copy(None).is_ok());
403 assert!(runtime.on_modify(None).is_err());
404 }
405
406 #[test]
407 fn test_enforcement_disabled() {
408 let perms = Permissions::new(); let mut runtime = RuntimePermissions::new(perms);
410 runtime.set_enforce(false);
411
412 assert!(runtime.on_print(None).is_ok());
414 assert!(runtime.on_modify(None).is_ok());
415 assert!(runtime.on_copy(None).is_ok());
416 }
417
418 #[test]
419 fn test_callbacks() {
420 let perms = *Permissions::new().set_print(true);
421 let mut runtime = RuntimePermissions::new(perms);
422
423 let callback_called = Arc::new(Mutex::new(false));
424 let callback_called_clone = callback_called.clone();
425
426 runtime.add_callback(move |result| {
427 assert_eq!(result.operation, PermissionOperation::Print);
428 assert!(result.allowed);
429 *callback_called_clone.lock().unwrap() = true;
430 });
431
432 runtime.on_print(None).unwrap();
433 assert!(*callback_called.lock().unwrap());
434 }
435
436 #[test]
437 fn test_multiple_callbacks() {
438 let perms = *Permissions::new().set_print(true);
439 let mut runtime = RuntimePermissions::new(perms);
440
441 let counter = Arc::new(Mutex::new(0));
442
443 for _ in 0..3 {
444 let counter_clone = counter.clone();
445 runtime.add_callback(move |_| {
446 *counter_clone.lock().unwrap() += 1;
447 });
448 }
449
450 runtime.on_print(None).unwrap();
451 assert_eq!(*counter.lock().unwrap(), 3);
452 }
453
454 #[test]
455 fn test_context_in_callback() {
456 let perms = *Permissions::new().set_copy(true);
457 let mut runtime = RuntimePermissions::new(perms);
458
459 let context_received = Arc::new(Mutex::new(String::new()));
460 let context_clone = context_received.clone();
461
462 runtime.add_callback(move |result| {
463 if let Some(ctx) = &result.context {
464 *context_clone.lock().unwrap() = ctx.clone();
465 }
466 });
467
468 runtime.on_copy(Some("Copying page 5".to_string())).unwrap();
469 assert_eq!(*context_received.lock().unwrap(), "Copying page 5");
470 }
471
472 #[test]
473 fn test_event_logging() {
474 let perms = *Permissions::new().set_print(true);
475 let mut runtime = RuntimePermissions::new(perms);
476 runtime.set_log_level(LogLevel::Debug);
477
478 runtime.on_print(Some("Test print".to_string())).unwrap();
479 let _ = runtime.on_modify(None); let events = runtime.get_events();
482 assert_eq!(events.len(), 2);
483
484 assert_eq!(events[0].operation, PermissionOperation::Print);
485 assert!(events[0].allowed);
486
487 assert_eq!(events[1].operation, PermissionOperation::ModifyContents);
488 assert!(!events[1].allowed);
489 }
490
491 #[test]
492 fn test_log_levels() {
493 let perms = Permissions::all();
494 let mut runtime = RuntimePermissions::new(perms);
495
496 runtime.set_log_level(LogLevel::Warn);
498
499 runtime.on_print(None).unwrap(); let mut runtime2 = RuntimePermissions::new(Permissions::new());
502 runtime2.set_log_level(LogLevel::Warn);
503 let _ = runtime2.on_print(None); assert_eq!(runtime.get_events().len(), 0);
506 assert_eq!(runtime2.get_events().len(), 1);
507 }
508
509 #[test]
510 fn test_clear_events() {
511 let perms = Permissions::all();
512 let runtime = RuntimePermissions::new(perms);
513
514 runtime.on_print(None).unwrap();
515 runtime.on_copy(None).unwrap();
516
517 assert!(runtime.get_events().len() >= 2);
518
519 runtime.clear_events();
520 assert_eq!(runtime.get_events().len(), 0);
521 }
522
523 #[test]
524 fn test_permissions_validator_trait() {
525 let perms = *Permissions::new().set_accessibility(true);
526 let runtime = RuntimePermissions::new(perms);
527
528 assert!(runtime
530 .validate(PermissionOperation::Accessibility)
531 .unwrap());
532 assert!(!runtime.validate(PermissionOperation::Print).unwrap());
533
534 let retrieved_perms = runtime.permissions();
535 assert!(retrieved_perms.can_access_for_accessibility());
536 assert!(!retrieved_perms.can_print());
537 }
538
539 #[test]
540 fn test_builder() {
541 let counter = Arc::new(Mutex::new(0));
542 let counter_clone = counter.clone();
543
544 let runtime = RuntimePermissionsBuilder::new(Permissions::all())
545 .with_callback(move |_| {
546 *counter_clone.lock().unwrap() += 1;
547 })
548 .with_log_level(LogLevel::Debug)
549 .with_enforcement(true)
550 .build();
551
552 runtime.on_print(None).unwrap();
553 assert_eq!(*counter.lock().unwrap(), 1);
554 assert_eq!(runtime.log_level, LogLevel::Debug);
555 }
556
557 #[test]
558 fn test_all_operations() {
559 let perms = Permissions::all();
560 let runtime = RuntimePermissions::new(perms);
561
562 assert!(runtime.on_print(None).is_ok());
564 assert!(runtime.on_print_high_quality(None).is_ok());
565 assert!(runtime.on_modify(None).is_ok());
566 assert!(runtime.on_copy(None).is_ok());
567 assert!(runtime.on_modify_annotations(None).is_ok());
568 assert!(runtime.on_form_fill(None).is_ok());
569 assert!(runtime.on_accessibility(None).is_ok());
570 assert!(runtime.on_assemble(None).is_ok());
571 }
572
573 #[test]
574 fn test_error_messages() {
575 let perms = Permissions::new();
576 let runtime = RuntimePermissions::new(perms);
577
578 let err = runtime.on_print(None).unwrap_err();
579 match err {
580 PdfError::PermissionDenied(msg) => {
581 assert!(msg.contains("Print"));
582 }
583 _ => panic!("Expected PermissionDenied error"),
584 }
585 }
586}