pdf_signing/
lib.rs

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/// The whole PDF document. This struct only loads part of the document on demand.
32#[derive(Debug, Clone)]
33pub struct PDFSigningDocument {
34    raw_document: IncrementalDocument,
35    file_name: String,
36    /// Link between the image name saved and the objectId of the image.
37    /// This is used to reduce the amount of copies of the images in the pdf file.
38    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        // Do not replace `image_signature_object_id`
57        // We want to keep this so we can do optimization.
58        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    /// Save document to file
87    pub fn save_document<P: AsRef<Path>>(&self, path: P) -> Result<File, Error> {
88        // Create clone so we can compress the clone, not the original.
89        let mut raw_document = self.raw_document.clone();
90        raw_document.new_document.compress();
91        Ok(raw_document.save(path)?)
92    }
93
94    /// Write document to Writer or buffer
95    pub fn write_document<W: std::io::Write>(&self, target: &mut W) -> Result<(), Error> {
96        // Create clone so we can compress the clone, not the original.
97        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        // Set PDF version, version 1.5 is the minimum version required.
121        self.raw_document.new_document.version = "1.5".to_owned();
122
123        // loop over AcroForm elements
124        let mut acro_forms = self.acro_form.clone();
125        let mut last_binary_pdf = None;
126
127        // Take the first form field (if there is any)
128        let mut form_field_current = acro_forms.as_ref().and_then(|list| list.first().cloned());
129        let mut form_field_index = 0;
130
131        // Covert `Vec<UserSignatureInfo>` to `HashMap<String, UserSignatureInfo>`
132        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        // Make sure we never end up in an infinite loop, should not happen.
138        // But better safe then sorry.
139        let mut loop_counter: u16 = 0;
140        // Loop over all the form fields and sign them one by one.
141        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            // Check if it is a signature and it is already signed.
151            if !form_field.is_empty_signature() {
152                // Go to next form field if pdf did not change
153                form_field_index += 1;
154                form_field_current = acro_forms
155                    .as_ref()
156                    .and_then(|list| list.get(form_field_index).cloned());
157                // Go back to start of while loop
158                continue;
159            }
160
161            // TODO: Debug code, can be removed
162            // if form_field_index == 1 {
163            //     form_field_index += 1;
164            //     form_field_current = acro_forms
165            //         .as_ref()
166            //         .and_then(|list| list.get(form_field_index).cloned());
167            //     continue;
168            // }
169
170            // Update pdf (when nothing else is incorrect)
171            // Insert signature images into pdf itself.
172            let pdf_document_user_info_opt =
173                self.add_signature_images(form_field, &users_signature_info_map)?;
174
175            // PDF has been updated, now we need to digitally sign it.
176            if let Some((pdf_document_image, user_form_info)) = pdf_document_user_info_opt {
177                // Digitally sign the document using a cert.
178                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                // Reload file
184                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                // Set as return value
192                last_binary_pdf = Some(new_binary_pdf);
193                // Reset form field index
194                form_field_index = 0;
195            } else {
196                // Go to next form field because pdf did not change
197                form_field_index += 1;
198            }
199
200            // Load next form field (or set to `0` depending on index.)
201            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                // No signing done, so just return initial document.
210                Ok(self.raw_document.get_prev_documents_bytes().to_vec())
211            }
212        }
213    }
214
215    // pub fn add_signature_to_form<R: Read>(
216    //     &mut self,
217    //     image_reader: R,
218    //     image_name: &str,
219    //     page_id: ObjectId,
220    //     form_id: ObjectId,
221    // ) -> Result<ObjectId, Error> {
222    //     let rect = Rectangle::get_rectangle_from_signature(form_id, &self.raw_document)?;
223    //     let image_object_id_opt = self.image_signature_object_id.get(image_name).cloned();
224    //     Ok(if let Some(image_object_id) = image_object_id_opt {
225    //         // Image was already added so we can reuse it.
226    //         self.add_image_to_page_only(image_object_id, image_name, page_id, rect)?
227    //     } else {
228    //         // Image was not added already so we need to add it in full
229    //         let image_object_id = self.add_image(image_reader, image_name, page_id, rect)?;
230    //         // Add signature to map
231    //         self.image_signature_object_id
232    //             .insert(image_name.to_owned(), image_object_id);
233    //         image_object_id
234    //     })
235    // }
236}
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}