caerp-sign-pdf 2024.1.4__tar.gz → 2024.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (18) hide show
  1. caerp_sign_pdf-2024.2.1/CURRENT_VERSION +1 -0
  2. {caerp_sign_pdf-2024.1.4/src/caerp_sign_pdf.egg-info → caerp_sign_pdf-2024.2.1}/PKG-INFO +4 -2
  3. {caerp_sign_pdf-2024.1.4 → caerp_sign_pdf-2024.2.1}/src/caerp_sign_pdf/public.py +58 -34
  4. {caerp_sign_pdf-2024.1.4 → caerp_sign_pdf-2024.2.1/src/caerp_sign_pdf.egg-info}/PKG-INFO +5 -3
  5. caerp_sign_pdf-2024.1.4/CURRENT_VERSION +0 -1
  6. {caerp_sign_pdf-2024.1.4 → caerp_sign_pdf-2024.2.1}/LICENSE.txt +0 -0
  7. {caerp_sign_pdf-2024.1.4 → caerp_sign_pdf-2024.2.1}/MANIFEST.in +0 -0
  8. {caerp_sign_pdf-2024.1.4 → caerp_sign_pdf-2024.2.1}/README.rst +0 -0
  9. {caerp_sign_pdf-2024.1.4 → caerp_sign_pdf-2024.2.1}/requirements.txt +0 -0
  10. {caerp_sign_pdf-2024.1.4 → caerp_sign_pdf-2024.2.1}/setup.cfg +0 -0
  11. {caerp_sign_pdf-2024.1.4 → caerp_sign_pdf-2024.2.1}/setup.py +0 -0
  12. {caerp_sign_pdf-2024.1.4 → caerp_sign_pdf-2024.2.1}/src/caerp_sign_pdf/__init__.py +0 -0
  13. {caerp_sign_pdf-2024.1.4 → caerp_sign_pdf-2024.2.1}/src/caerp_sign_pdf/models.py +0 -0
  14. {caerp_sign_pdf-2024.1.4 → caerp_sign_pdf-2024.2.1}/src/caerp_sign_pdf.egg-info/SOURCES.txt +0 -0
  15. {caerp_sign_pdf-2024.1.4 → caerp_sign_pdf-2024.2.1}/src/caerp_sign_pdf.egg-info/dependency_links.txt +0 -0
  16. {caerp_sign_pdf-2024.1.4 → caerp_sign_pdf-2024.2.1}/src/caerp_sign_pdf.egg-info/not-zip-safe +0 -0
  17. {caerp_sign_pdf-2024.1.4 → caerp_sign_pdf-2024.2.1}/src/caerp_sign_pdf.egg-info/requires.txt +0 -0
  18. {caerp_sign_pdf-2024.1.4 → caerp_sign_pdf-2024.2.1}/src/caerp_sign_pdf.egg-info/top_level.txt +0 -0
@@ -0,0 +1 @@
1
+ 2024.2.1
@@ -1,12 +1,13 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: caerp_sign_pdf
3
- Version: 2024.1.4
3
+ Version: 2024.2.1
4
4
  Summary: caerp_sign_pdf
5
5
  Home-page: https://framagit.org/caerp/caerp_sign_pdf
6
6
  Author: Kilya
7
7
  Author-email: contact@kilya.net
8
8
  License: GPLv3
9
9
  Keywords: web wsgi bfg pylons pyramid caerp
10
+ Platform: UNKNOWN
10
11
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
11
12
  Classifier: Programming Language :: Python
12
13
  Classifier: Framework :: Pyramid
@@ -14,7 +15,6 @@ Classifier: Topic :: Internet :: WWW/HTTP
14
15
  Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
15
16
  Description-Content-Type: text/x-rst
16
17
  License-File: LICENSE.txt
17
- Requires-Dist: pyHanko[image-support,opentype,pkcs11,xmp]==0.25.1
18
18
 
19
19
  CAERP Sign PDF
20
20
  ======================================================
@@ -70,3 +70,5 @@ Sous linux la signature d'un document PDF peut être vérifiée facilement en li
70
70
 
71
71
  pdfsig <monfichierpdf.pdf>
72
72
 
73
+
74
+
@@ -1,14 +1,13 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  import logging
3
3
  import hashlib
4
+ import subprocess
4
5
 
5
6
  from io import BytesIO
6
7
  from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter
7
- from pyhanko.pdf_utils.xref import ObjectHeaderReadError
8
8
  from pyhanko.sign import fields, signers
9
9
  from pyhanko.sign.general import SigningError
10
10
  from pyhanko.stamp import TextStampStyle
11
- from PyPDF4.pdf import PdfFileReader, PdfFileWriter
12
11
  from pyramid.httpexceptions import HTTPUnsupportedMediaType
13
12
 
14
13
  from caerp.views.files.controller import FileData
@@ -28,6 +27,10 @@ nouveau fichier PDF avant de le recharger."
28
27
 
29
28
 
30
29
  class SignPDFService(object):
30
+ """
31
+ The PDF digital signing service
32
+ """
33
+
31
34
  def __init__(self, context, request):
32
35
  self.context = context
33
36
  self.request = request
@@ -59,18 +62,44 @@ class SignPDFService(object):
59
62
  """
60
63
  return hashlib.md5(file_data.getvalue()).hexdigest()
61
64
 
62
- def _get_safe_pdf(self, file_data: BytesIO) -> str:
65
+ def _get_clean_pdf(self, file_data: BytesIO) -> BytesIO:
63
66
  """
64
- Create a new clean PDF buffer from the original
65
- to avoid some format errors
67
+ Create a new clean PDF buffer from the original to avoid format errors
66
68
  """
67
- writer = PdfFileWriter()
68
- reader = PdfFileReader(file_data, strict=False)
69
- num_pages = reader.getNumPages()
70
- for page in range(num_pages):
71
- writer.addPage(reader.getPage(page))
72
- writer.write(file_data)
73
- return file_data
69
+ logger.info(f"Cleaning PDF buffer...")
70
+ file_data.seek(0)
71
+ process = subprocess.Popen(
72
+ ["/usr/bin/pdftocairo", "-pdf", "-", "-"],
73
+ stdin=subprocess.PIPE,
74
+ stdout=subprocess.PIPE,
75
+ )
76
+ output = process.communicate(input=file_data.read())[0]
77
+ result = BytesIO()
78
+ result.write(output)
79
+ result.seek(0)
80
+ return result
81
+
82
+ def _get_pdf_stamp(self, display_stamp: bool) -> TextStampStyle:
83
+ """
84
+ Prepare physical stamp to apply on the PDF
85
+
86
+ :param bool display_stamp: Whether the stamp must be visible or not
87
+
88
+ :return TextStampStyle: The stamp object
89
+ """
90
+ stamp = None
91
+ if display_stamp:
92
+ stamp = TextStampStyle(
93
+ timestamp_format="%d/%m/%Y %H:%M:%S %Z",
94
+ stamp_text="Signé par: %(signer)s\nLe: %(ts)s",
95
+ border_width=2,
96
+ )
97
+ else:
98
+ stamp = TextStampStyle(
99
+ stamp_text="",
100
+ border_width=0,
101
+ )
102
+ return stamp
74
103
 
75
104
  def sign(
76
105
  self, pdf_data: FileData, node_id: int = None, with_stamp: bool = False
@@ -81,7 +110,8 @@ class SignPDFService(object):
81
110
 
82
111
  :param FileData pdf_data: The FileData object describing the PDF file
83
112
  :param int node_id: The related node's id if relevant
84
- :param bool with_stamp: whether we want a stamp on result file or not
113
+ :param bool with_stamp: Whether we want a printed stamp on result file or not
114
+
85
115
  :return bool: either the PDF has been signed or not
86
116
  """
87
117
 
@@ -89,7 +119,7 @@ class SignPDFService(object):
89
119
 
90
120
  # Check mimetype
91
121
  if not pdf_data.mimetype == "application/pdf":
92
- logger.warn("File is not a PDF, signing aborted")
122
+ logger.warning("File is not a PDF, signing aborted")
93
123
  return False
94
124
 
95
125
  # Load sign certificate
@@ -104,26 +134,18 @@ class SignPDFService(object):
104
134
  )
105
135
  raise Exception(ERROR_LOAD_CERTIFICATE_MSG)
106
136
 
107
- # Prepare stamp (if needed)
108
- stamp = None
109
- if with_stamp:
110
- stamp = TextStampStyle(
111
- timestamp_format="%d/%m/%Y %H:%M:%S %Z",
112
- stamp_text="Signé par: %(signer)s\nLe: %(ts)s",
113
- border_width=2,
114
- )
115
- else:
116
- stamp = TextStampStyle(
117
- stamp_text="",
118
- border_width=0,
119
- )
137
+ # Clean PDF
138
+ try:
139
+ pdf_data.data = self._get_clean_pdf(pdf_data.data)
140
+ except Exception as error:
141
+ logger.error(f"Error while cleaning original PDF file : {error}")
142
+ raise HTTPUnsupportedMediaType(ERROR_PDF_FORMAT_MSG)
120
143
 
121
- # Open original PDF
144
+ # Open PDF
122
145
  try:
123
- pdf_data.data = self._get_safe_pdf(pdf_data.data)
124
146
  pdf_writer = IncrementalPdfFileWriter(pdf_data.data, strict=False)
125
147
  except Exception as error:
126
- logger.error(f"Error while opening original PDF file : {error}")
148
+ logger.error(f"Error while opening PDF file : {error}")
127
149
  raise HTTPUnsupportedMediaType(ERROR_PDF_FORMAT_MSG)
128
150
 
129
151
  # Add signature field on the PDF
@@ -135,10 +157,10 @@ class SignPDFService(object):
135
157
  ),
136
158
  )
137
159
  except SigningError:
138
- logger.warn("File is already signed, nothing to do")
160
+ logger.warning("File is already signed, nothing to do")
139
161
  return True
140
- except ObjectHeaderReadError as error:
141
- logger.error(f"Error while reading Xref header : {error}")
162
+ except Exception as error:
163
+ logger.error(f"Error while adding signature field : {error}")
142
164
  raise HTTPUnsupportedMediaType(ERROR_PDF_FORMAT_MSG)
143
165
 
144
166
  # Sign PDF
@@ -147,12 +169,14 @@ class SignPDFService(object):
147
169
  pdf_signer = signers.PdfSigner(
148
170
  meta,
149
171
  signer=signer,
150
- stamp_style=stamp,
172
+ stamp_style=self._get_pdf_stamp(with_stamp),
151
173
  )
152
174
  pdf_data.data = pdf_signer.sign_pdf(pdf_writer)
153
175
  except Exception as error:
154
176
  logger.error(f"Error while signing PDF file : {error}")
155
177
  raise HTTPUnsupportedMediaType(ERROR_PDF_FORMAT_MSG)
178
+
179
+ # Success
156
180
  logger.info(
157
181
  "File '{}' signed successfully by {} !".format(
158
182
  pdf_data.name, signer.subject_name
@@ -1,12 +1,13 @@
1
1
  Metadata-Version: 2.1
2
- Name: caerp_sign_pdf
3
- Version: 2024.1.4
2
+ Name: caerp-sign-pdf
3
+ Version: 2024.2.1
4
4
  Summary: caerp_sign_pdf
5
5
  Home-page: https://framagit.org/caerp/caerp_sign_pdf
6
6
  Author: Kilya
7
7
  Author-email: contact@kilya.net
8
8
  License: GPLv3
9
9
  Keywords: web wsgi bfg pylons pyramid caerp
10
+ Platform: UNKNOWN
10
11
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
11
12
  Classifier: Programming Language :: Python
12
13
  Classifier: Framework :: Pyramid
@@ -14,7 +15,6 @@ Classifier: Topic :: Internet :: WWW/HTTP
14
15
  Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
15
16
  Description-Content-Type: text/x-rst
16
17
  License-File: LICENSE.txt
17
- Requires-Dist: pyHanko[image-support,opentype,pkcs11,xmp]==0.25.1
18
18
 
19
19
  CAERP Sign PDF
20
20
  ======================================================
@@ -70,3 +70,5 @@ Sous linux la signature d'un document PDF peut être vérifiée facilement en li
70
70
 
71
71
  pdfsig <monfichierpdf.pdf>
72
72
 
73
+
74
+
@@ -1 +0,0 @@
1
- 2024.1.4