[MIG] report_qweb_signer: Migration to 14.0 updating java's lib for visible signatures

pull/534/head
Omar (Comunitea) 2021-08-30 20:57:09 +02:00
parent 0809bb7109
commit 54bf4b0ef3
15 changed files with 55 additions and 29 deletions

View File

@ -6,7 +6,7 @@
{ {
"name": "Qweb PDF reports signer", "name": "Qweb PDF reports signer",
"summary": "Sign Qweb PDFs usign a PKCS#12 certificate", "summary": "Sign Qweb PDFs usign a PKCS#12 certificate",
"version": "13.0.2.0.0", "version": "14.0.1.0.0",
"category": "Reporting", "category": "Reporting",
"website": "https://github.com/OCA/reporting-engine", "website": "https://github.com/OCA/reporting-engine",
"author": "Tecnativa, " "Odoo Community Association (OCA)", "author": "Tecnativa, " "Odoo Community Association (OCA)",

View File

@ -2,6 +2,10 @@
<odoo> <odoo>
<record model="ir.config_parameter" id="report_qweb_signer_java_param"> <record model="ir.config_parameter" id="report_qweb_signer_java_param">
<field name="key">report_qweb_signer.java_parameters</field> <field name="key">report_qweb_signer.java_parameters</field>
<field name="value">-Xms4M -Xmx4M -XX:CompressedClassSpaceSize=256m</field> <field name="value">-Xms16M -Xmx16M -XX:CompressedClassSpaceSize=256m</field>
</record>
<record model="ir.config_parameter" id="report_qweb_signer_java_position_param">
<field name="key">report_qweb_signer.java_position_parameters</field>
<field name="value">-llx 400 -lly 820 -urx 600 -ury 100 -fs 8</field>
</record> </record>
</odoo> </odoo>

View File

@ -33,14 +33,16 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
</t> </t>
</t> </t>
</template> </template>
<report <record id="partner_demo_report" model="ir.actions.report">
id="partner_demo_report" <field name="name">Test PDF certificate</field>
model="res.partner" <field name="model">res.partner</field>
string="Test PDF certificate" <field name="report_type">qweb-pdf</field>
report_type="qweb-pdf" <field name="report_name">report_qweb_signer.report_partner_demo</field>
name="report_qweb_signer.report_partner_demo" <field
file="report_qweb_signer.report_partner_demo" name="attachment"
attachment_use="True" >'test_' + (object.name or '').replace(' ', '_').lower() + '.pdf'</field>
attachment="'test_' + (object.name or '').replace(' ', '_').lower() + '.pdf'" <field name="attachment_use">True</field>
/> <field name="binding_model_id" ref="base.model_res_partner" />
<field name="binding_type">report</field>
</record>
</odoo> </odoo>

View File

@ -8,7 +8,6 @@ import logging
import os import os
import subprocess import subprocess
import tempfile import tempfile
import time
from contextlib import closing from contextlib import closing
from cryptography.hazmat import backends from cryptography.hazmat import backends
@ -17,7 +16,7 @@ from endesive import pdf
from odoo import _, models from odoo import _, models
from odoo.exceptions import AccessError, UserError from odoo.exceptions import AccessError, UserError
from odoo.tools.safe_eval import safe_eval from odoo.tools.safe_eval import safe_eval, time
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@ -122,8 +121,13 @@ class IrActionsReport(models.Model):
irc_param = self.env["ir.config_parameter"].sudo() irc_param = self.env["ir.config_parameter"].sudo()
java_bin = "java -jar" java_bin = "java -jar"
java_param = irc_param.get_param("report_qweb_signer.java_parameters") java_param = irc_param.get_param("report_qweb_signer.java_parameters")
jar = "{}/../static/jar/jPdfSign.jar".format(me) java_position_param = irc_param.get_param(
return "{} {} {} {}".format(java_bin, java_param, jar, opts) "report_qweb_signer.java_position_parameters"
)
jar = "{}/../static/jar/JSignPdf.jar".format(me)
return "{} {} {} {} {}".format(
java_bin, java_param, jar, opts, java_position_param
)
def _get_endesive_params(self, certificate): def _get_endesive_params(self, certificate):
date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) date = datetime.datetime.utcnow() - datetime.timedelta(hours=12)
@ -160,7 +164,7 @@ class IrActionsReport(models.Model):
return pdfsigned return pdfsigned
def pdf_sign(self, pdf, certificate): def pdf_sign(self, pdf, certificate):
pdfsigned = pdf + ".signed.pdf" pdfsigned = pdf[:-4] + "_signed.pdf"
p12 = _normalize_filepath(certificate.path) p12 = _normalize_filepath(certificate.path)
passwd = _normalize_filepath(certificate.password_file) passwd = _normalize_filepath(certificate.password_file)
method_used = certificate.signing_method method_used = certificate.signing_method
@ -169,7 +173,12 @@ class IrActionsReport(models.Model):
_("Signing report (PDF): " "Certificate or password file not found") _("Signing report (PDF): " "Certificate or password file not found")
) )
if method_used == "java": if method_used == "java":
signer_opts = '"{}" "{}" "{}" "{}"'.format(p12, pdf, pdfsigned, passwd) passwd_f = open(passwd, "tr")
passwd = passwd_f.read().strip()
passwd_f.close()
signer_opts = ' "{}" -ksf "{}" -ksp "{}" -V -d "/tmp"'.format(
pdf, p12, passwd
)
signer = self._signer_bin(signer_opts) signer = self._signer_bin(signer_opts)
process = subprocess.Popen( process = subprocess.Popen(
signer, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True signer, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True
@ -188,7 +197,7 @@ class IrActionsReport(models.Model):
self._signer_endesive(params, p12, pdf, pdfsigned, passwd) self._signer_endesive(params, p12, pdf, pdfsigned, passwd)
return pdfsigned return pdfsigned
def render_qweb_pdf(self, res_ids=None, data=None): def _render_qweb_pdf(self, res_ids=None, data=None):
certificate = self._certificate_get(res_ids) certificate = self._certificate_get(res_ids)
if certificate and certificate.attachment: if certificate and certificate.attachment:
signed_content = self._attach_signed_read(res_ids, certificate) signed_content = self._attach_signed_read(res_ids, certificate)
@ -199,7 +208,7 @@ class IrActionsReport(models.Model):
res_ids, res_ids,
) )
return signed_content, "pdf" return signed_content, "pdf"
content, ext = super(IrActionsReport, self).render_qweb_pdf(res_ids, data) content, ext = super(IrActionsReport, self)._render_qweb_pdf(res_ids, data)
if certificate: if certificate:
# Creating temporary origin PDF # Creating temporary origin PDF
pdf_fd, pdf = tempfile.mkstemp(suffix=".pdf", prefix="report.tmp.") pdf_fd, pdf = tempfile.mkstemp(suffix=".pdf", prefix="report.tmp.")
@ -220,7 +229,7 @@ class IrActionsReport(models.Model):
for fname in (pdf, signed): for fname in (pdf, signed):
try: try:
os.unlink(fname) os.unlink(fname)
except (OSError, IOError): except OSError:
_logger.error("Error when trying to remove file %s", fname) _logger.error("Error when trying to remove file %s", fname)
if certificate.attachment: if certificate.attachment:
self._attach_signed_write(res_ids, certificate, content) self._attach_signed_write(res_ids, certificate, content)

View File

@ -31,9 +31,11 @@ class ReportCertificate(models.Model):
required=True, required=True,
comodel_name="ir.model", comodel_name="ir.model",
help="Model where apply this certificate", help="Model where apply this certificate",
ondelete="cascade",
) )
domain = fields.Char( domain = fields.Char(
string="Domain", help="Domain for filtering if sign or not the document", string="Domain",
help="Domain for filtering if sign or not the document",
) )
allow_only_one = fields.Boolean( allow_only_one = fields.Boolean(
string="Allow only one document", string="Allow only one document",
@ -67,5 +69,6 @@ class ReportCertificate(models.Model):
help="Location to include in digital signature (typically, a city name). ", help="Location to include in digital signature (typically, a city name). ",
) )
endesive_certificate_reason = fields.Char( endesive_certificate_reason = fields.Char(
string="Signature reason", help="Reason text to include in digital signature.", string="Signature reason",
help="Reason text to include in digital signature.",
) )

View File

@ -5,3 +5,5 @@
* Pedro M. Baeza * Pedro M. Baeza
* Jairo Llopis * Jairo Llopis
* David Vidal * David Vidal
* Santi Argüeso <santi@comunitea.com>
* Omar Castiñeira <omar@comunitea.com>

View File

@ -1,9 +1,7 @@
External utilities External utilities
++++++++++++++++++ ++++++++++++++++++
* iText v1.4.8: © 2000-2006, Paulo Soares, Bruno Lowagie and others - License `MPL <http://www.mozilla.org/MPL>`__ or `LGPL2 <http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html>`__ - http://sourceforge.net/projects/itext * JSignPdf: © Josef Cacek - License `MPL <http://www.mozilla.org/MPL>`__ or `LGPL2 <http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html>`__ - http://jsignpdf.sourceforge.net/
* jPdfSign: © 2006 Jan Peter Stotz - License `MPL <http://www.mozilla.org/MPL>`__ or `LGPL2 <http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html>`__ (inherited from iText) - http://private.sit.fraunhofer.de/~stotz/software/jpdfsign
* Modified jPdfSign: © 2015 Antonio Espinosa - License `MPL <http://www.mozilla.org/MPL>`__ or `LGPL2 <http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html>`__ (inherited from iText) - static/src/java/JPdfSign.java
Icon Icon
++++ ++++

View File

@ -1,5 +1,4 @@
* When signing multiple documents (if 'Allow only one document' is disable) * When signing multiple documents (if 'Allow only one document' is disable)
then 'Save as attachment' is not applied and signed result is not then 'Save as attachment' is not applied and signed result is not
saved as attachment. saved as attachment.
* To have a visible signature through an image embedded in the resulting PDF.
* Add tests. * Add tests.

Binary file not shown.

View File

@ -13,7 +13,7 @@ class TestReportQwebSigner(HttpCase):
).with_context(force_report_rendering=True) ).with_context(force_report_rendering=True)
def test_report_qweb_signer(self): def test_report_qweb_signer(self):
self.report.render_qweb_pdf(self.partner.ids) self.report._render_qweb_pdf(self.partner.ids)
# Reprint again for taking the PDF from attachment # Reprint again for taking the PDF from attachment
IrAttachment = self.env["ir.attachment"] IrAttachment = self.env["ir.attachment"]
domain = [ domain = [
@ -21,6 +21,6 @@ class TestReportQwebSigner(HttpCase):
("res_model", "=", self.partner._name), ("res_model", "=", self.partner._name),
] ]
num_attachments = IrAttachment.search_count(domain) num_attachments = IrAttachment.search_count(domain)
self.report.render_qweb_pdf(self.partner.ids) self.report._render_qweb_pdf(self.partner.ids)
num_attachments_after = IrAttachment.search_count(domain) num_attachments_after = IrAttachment.search_count(domain)
self.assertEqual(num_attachments, num_attachments_after) self.assertEqual(num_attachments, num_attachments_after)

View File

@ -1,4 +1,6 @@
# generated from manifests external_dependencies # generated from manifests external_dependencies
cryptography
endesive
lxml lxml
PyPDF2 PyPDF2
xlrd xlrd

View File

@ -0,0 +1 @@
../../../../report_qweb_signer

View File

@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)