1use std::fmt;
4use std::io::BufRead;
5
6use age::secrecy::SecretString;
7
8use crate::builder;
9use crate::encryption;
10use crate::page::PageSize;
11
12#[derive(Debug)]
14pub enum PaperAgeError {
15 Encryption(String),
17 DocumentInit(String),
19 PdfCreation(String),
21}
22
23impl fmt::Display for PaperAgeError {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 match self {
26 PaperAgeError::Encryption(msg) => write!(f, "Encryption failed: {msg}"),
27 PaperAgeError::DocumentInit(msg) => write!(f, "Document initialization failed: {msg}"),
28 PaperAgeError::PdfCreation(msg) => write!(f, "PDF creation failed: {msg}"),
29 }
30 }
31}
32
33impl std::error::Error for PaperAgeError {}
34
35pub fn create_pdf(
72 title: String,
73 data: &mut dyn BufRead,
74 passphrase: &str,
75 notes_label: Option<String>,
76 skip_notes_line: Option<bool>,
77 page_size: Option<PageSize>,
78 grid: Option<bool>,
79) -> Result<Vec<u8>, PaperAgeError> {
80 let notes_label = notes_label.unwrap_or_else(|| "Passphrase:".to_string());
81 let skip_notes_line = skip_notes_line.unwrap_or(false);
82 let page_size = page_size.unwrap_or(PageSize::A4);
83 let grid = grid.unwrap_or(false);
84
85 let passphrase_secret = SecretString::from(passphrase.to_owned());
86
87 let (_plaintext_len, encrypted) = encryption::encrypt_plaintext(data, passphrase_secret)
88 .map_err(|e| PaperAgeError::Encryption(e.to_string()))?;
89
90 let pdf = builder::Document::new(title, page_size)
91 .map_err(|e| PaperAgeError::DocumentInit(e.to_string()))?;
92
93 let bytes = pdf
94 .create_pdf(grid, notes_label, skip_notes_line, encrypted)
95 .map_err(|e| PaperAgeError::PdfCreation(e.to_string()))?;
96
97 Ok(bytes)
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn test_create_pdf_defaults() {
106 let result = create_pdf(
107 "Test Document".to_string(),
108 &mut &b"hello world"[..],
109 "passphrase",
110 None,
111 None,
112 None,
113 None,
114 );
115 assert!(result.is_ok());
116 let bytes = result.unwrap();
117 assert!(!bytes.is_empty());
118 }
119
120 #[test]
121 fn test_create_pdf_with_options() {
122 let result = create_pdf(
123 "Custom Document".to_string(),
124 &mut &b"secret data"[..],
125 "hunter2",
126 Some("Recovery key:".to_string()),
127 Some(true),
128 Some(PageSize::Letter),
129 Some(true),
130 );
131 assert!(result.is_ok());
132 }
133
134 #[test]
135 fn test_create_pdf_empty_data() {
136 let result = create_pdf(
137 "Empty".to_string(),
138 &mut &b""[..],
139 "passphrase",
140 None,
141 None,
142 None,
143 None,
144 );
145 assert!(result.is_ok());
146 }
147
148 #[test]
149 fn test_error_display() {
150 assert_eq!(
151 PaperAgeError::Encryption("bad key".to_string()).to_string(),
152 "Encryption failed: bad key"
153 );
154 assert_eq!(
155 PaperAgeError::DocumentInit("missing font".to_string()).to_string(),
156 "Document initialization failed: missing font"
157 );
158 assert_eq!(
159 PaperAgeError::PdfCreation("QR too large".to_string()).to_string(),
160 "PDF creation failed: QR too large"
161 );
162 }
163}