1mod acro_form;
2mod byte_range;
3mod digitally_sign;
4mod error;
5mod image_insert;
6mod image_insert_to_page;
7mod image_xobject;
8mod lopdf_utils;
9mod pdf_object;
10mod rectangle;
11mod signature_image;
12mod signature_info;
13mod user_signature_info;
14
15use acro_form::AcroForm;
16use byte_range::ByteRange;
17use image_insert::InsertImage;
18use image_insert_to_page::InsertImageToPage;
19use lopdf::{
20 content::{Content, Operation},
21 Document, IncrementalDocument, Object, ObjectId,
22};
23use pdf_object::PdfObjectDeref;
24use std::collections::HashMap;
25use std::{fs::File, path::Path};
26
27pub use error::Error;
28pub use lopdf;
29pub use user_signature_info::{UserFormSignatureInfo, UserSignatureInfo};
30
31#[derive(Debug, Clone)]
33pub struct PDFSigningDocument {
34 raw_document: IncrementalDocument,
35 file_name: String,
36 image_signature_object_id: HashMap<String, ObjectId>,
39
40 acro_form: Option<Vec<AcroForm>>,
41}
42
43impl PDFSigningDocument {
44 fn new(raw_document: IncrementalDocument, file_name: String) -> Self {
45 PDFSigningDocument {
46 raw_document,
47 file_name,
48 image_signature_object_id: HashMap::new(),
49 acro_form: None,
50 }
51 }
52
53 pub fn copy_from(&mut self, other: Self) {
54 self.raw_document = other.raw_document;
55 self.file_name = other.file_name;
56 self.acro_form = other.acro_form;
59 }
60
61 pub fn read_from<R: std::io::Read>(reader: R, file_name: String) -> Result<Self, Error> {
62 let raw_doc = IncrementalDocument::load_from(reader)?;
63 Ok(Self::new(raw_doc, file_name))
64 }
65
66 pub fn read<P: AsRef<Path>>(path: P, file_name: String) -> Result<Self, Error> {
67 let raw_doc = IncrementalDocument::load(path)?;
68 Ok(Self::new(raw_doc, file_name))
69 }
70
71 pub fn load_all(&mut self) -> Result<(), Error> {
72 self.load_acro_form()
73 }
74
75 pub fn load_acro_form(&mut self) -> Result<(), Error> {
76 if self.acro_form.is_none() {
77 self.acro_form = Some(AcroForm::load_all_forms(
78 self.raw_document.get_prev_documents(),
79 )?);
80 } else {
81 log::info!("Already Loaded Acro Form.");
82 }
83 Ok(())
84 }
85
86 pub fn save_document<P: AsRef<Path>>(&self, path: P) -> Result<File, Error> {
88 let mut raw_document = self.raw_document.clone();
90 raw_document.new_document.compress();
91 Ok(raw_document.save(path)?)
92 }
93
94 pub fn write_document<W: std::io::Write>(&self, target: &mut W) -> Result<(), Error> {
96 let mut raw_document = self.raw_document.clone();
98 raw_document.new_document.compress();
99 raw_document.save_to(target)?;
100 Ok(())
101 }
102
103 pub fn get_incr_document_ref(&self) -> &IncrementalDocument {
104 &self.raw_document
105 }
106
107 pub fn get_prev_document_ref(&self) -> &Document {
108 self.raw_document.get_prev_documents()
109 }
110
111 pub fn get_new_document_ref(&self) -> &Document {
112 &self.raw_document.new_document
113 }
114
115 pub fn sign_document(
116 &mut self,
117 users_signature_info: Vec<UserSignatureInfo>,
118 ) -> Result<Vec<u8>, Error> {
119 self.load_all()?;
120 self.raw_document.new_document.version = "1.5".to_owned();
122
123 let mut acro_forms = self.acro_form.clone();
125 let mut last_binary_pdf = None;
126
127 let mut form_field_current = acro_forms.as_ref().and_then(|list| list.first().cloned());
129 let mut form_field_index = 0;
130
131 let users_signature_info_map: HashMap<String, UserSignatureInfo> = users_signature_info
133 .iter()
134 .map(|info| (info.user_id.clone(), info.clone()))
135 .collect();
136
137 let mut loop_counter: u16 = 0;
140 while let Some(form_field) = form_field_current {
142 loop_counter += 1;
143 if loop_counter >= 10000 {
144 log::error!(
145 "Infinite loop detected and prevented. Please check file: `{}`.",
146 self.file_name
147 );
148 break;
149 }
150 if !form_field.is_empty_signature() {
152 form_field_index += 1;
154 form_field_current = acro_forms
155 .as_ref()
156 .and_then(|list| list.get(form_field_index).cloned());
157 continue;
159 }
160
161 let pdf_document_user_info_opt =
173 self.add_signature_images(form_field, &users_signature_info_map)?;
174
175 if let Some((pdf_document_image, user_form_info)) = pdf_document_user_info_opt {
177 let user_info = users_signature_info_map
179 .get(&user_form_info.user_id)
180 .ok_or_else(|| Error::Other("User was not found".to_owned()))?;
181
182 let new_binary_pdf = pdf_document_image.digitally_sign_document(user_info)?;
183 self.copy_from(Self::read_from(
185 &*new_binary_pdf,
186 pdf_document_image.file_name,
187 )?);
188 self.load_all()?;
189 self.raw_document.new_document.version = "1.5".to_owned();
190 acro_forms = self.acro_form.clone();
191 last_binary_pdf = Some(new_binary_pdf);
193 form_field_index = 0;
195 } else {
196 form_field_index += 1;
198 }
199
200 form_field_current = acro_forms
202 .as_ref()
203 .and_then(|list| list.get(form_field_index).cloned());
204 }
205
206 match last_binary_pdf {
207 Some(last_binary_pdf) => Ok(last_binary_pdf),
208 None => {
209 Ok(self.raw_document.get_prev_documents_bytes().to_vec())
211 }
212 }
213 }
214
215 }
237
238impl InsertImage for PDFSigningDocument {
239 fn add_object<T: Into<Object>>(&mut self, object: T) -> ObjectId {
240 self.raw_document.new_document.add_object(object)
241 }
242}
243
244impl InsertImageToPage for PDFSigningDocument {
245 fn add_xobject<N: Into<Vec<u8>>>(
246 &mut self,
247 page_id: ObjectId,
248 xobject_name: N,
249 xobject_id: ObjectId,
250 ) -> Result<(), Error> {
251 Ok(self
252 .raw_document
253 .add_xobject(page_id, xobject_name, xobject_id)?)
254 }
255
256 fn opt_clone_object_to_new_document(&mut self, object_id: ObjectId) -> Result<(), Error> {
257 Ok(self
258 .raw_document
259 .opt_clone_object_to_new_document(object_id)?)
260 }
261
262 fn add_to_page_content(
263 &mut self,
264 page_id: ObjectId,
265 content: Content<Vec<Operation>>,
266 ) -> Result<(), Error> {
267 Ok(self
268 .raw_document
269 .new_document
270 .add_to_page_content(page_id, content)?)
271 }
272}