Merge PR #528 into 13.0

Signed-off-by pedrobaeza
pull/532/head
OCA-git-bot 2021-08-04 17:12:29 +00:00
commit d51766e1f3
6 changed files with 96 additions and 15 deletions

View File

@ -13,7 +13,7 @@
"license": "AGPL-3",
"installable": True,
"depends": ["web_editor"],
"external_dependencies": {"bin": ["/usr/bin/java"]},
"external_dependencies": {"python": ["endesive", "cryptography"]},
"data": [
"data/defaults.xml",
"security/ir.model.access.csv",

View File

@ -10,6 +10,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
<field name="name">Test OCA certificate</field>
<field name="path">test.p12</field>
<field name="password_file">test.passwd</field>
<field name="signing_method">java</field>
<field name="model_id" ref="base.model_res_partner" />
<field name="allow_only_one" eval="True" />
<field

View File

@ -3,6 +3,7 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import base64
import datetime
import logging
import os
import subprocess
@ -10,6 +11,10 @@ import tempfile
import time
from contextlib import closing
from cryptography.hazmat import backends
from cryptography.hazmat.primitives.serialization import pkcs12
from endesive import pdf
from odoo import _, models
from odoo.exceptions import AccessError, UserError
from odoo.tools.safe_eval import safe_eval
@ -120,28 +125,67 @@ class IrActionsReport(models.Model):
jar = "{}/../static/jar/jPdfSign.jar".format(me)
return "{} {} {} {}".format(java_bin, java_param, jar, opts)
def _get_endesive_params(self, certificate):
date = datetime.datetime.utcnow() - datetime.timedelta(hours=12)
date = date.strftime("D:%Y%m%d%H%M%S+00'00'")
return {
"sigflags": 3,
"sigpage": 0,
"sigbutton": False,
"contact": certificate.endesive_certificate_mail,
"location": certificate.endesive_certificate_location,
"signingdate": date.encode(),
"reason": certificate.endesive_certificate_reason,
"signature": "",
"signaturebox": (0, 0, 0, 0),
"text": {"fontsize": 0},
}
def _signer_endesive(self, params, p12filepath, pdfpath, pdfsigned, passwd):
stringpassword = ""
with open(passwd, "r") as pw:
for line in pw:
stringpassword += line.rstrip()
password = stringpassword.encode("utf-8")
with open(p12filepath, "rb") as fp:
p12 = pkcs12.load_key_and_certificates(
fp.read(), password, backends.default_backend()
)
with open(pdfpath, "rb") as fh:
datau = fh.read()
datas = pdf.cms.sign(datau, params, p12[0], p12[1], p12[2], "sha256")
with open(pdfsigned, "wb") as res:
res.write(datau)
res.write(datas)
return pdfsigned
def pdf_sign(self, pdf, certificate):
pdfsigned = pdf + ".signed.pdf"
p12 = _normalize_filepath(certificate.path)
passwd = _normalize_filepath(certificate.password_file)
if not (p12 and passwd):
method_used = certificate.signing_method
if not (p12 or passwd):
raise UserError(
_("Signing report (PDF): " "Certificate or password file not found")
)
signer_opts = '"{}" "{}" "{}" "{}"'.format(p12, pdf, pdfsigned, passwd)
signer = self._signer_bin(signer_opts)
process = subprocess.Popen(
signer, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True
)
out, err = process.communicate()
if process.returncode:
raise UserError(
_(
"Signing report (PDF): jPdfSign failed (error code: %s). "
"Message: %s. Output: %s"
)
% (process.returncode, err, out)
if method_used == "java":
signer_opts = '"{}" "{}" "{}" "{}"'.format(p12, pdf, pdfsigned, passwd)
signer = self._signer_bin(signer_opts)
process = subprocess.Popen(
signer, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True
)
out, err = process.communicate()
if process.returncode:
raise UserError(
_(
"Signing report (PDF): jPdfSign failed (error code: %s). "
"Message: %s. Output: %s"
)
% (process.returncode, err, out)
)
elif method_used == "endesive":
params = self._get_endesive_params(certificate)
self._signer_endesive(params, p12, pdf, pdfsigned, passwd)
return pdfsigned
def render_qweb_pdf(self, res_ids=None, data=None):

View File

@ -52,3 +52,20 @@ class ReportCertificate(models.Model):
required=True,
default=_default_company,
)
signing_method = fields.Selection(
selection=[("java", "Java"), ("endesive", "Endesive")],
default="java",
string="Signing Method",
required=True,
)
endesive_certificate_mail = fields.Char(
string="Signature e-mail",
help="E-mail address to include in PDF digital signature.",
)
endesive_certificate_location = fields.Char(
string="Signature location",
help="Location to include in digital signature (typically, a city name). ",
)
endesive_certificate_reason = fields.Char(
string="Signature reason", help="Reason text to include in digital signature.",
)

View File

@ -22,6 +22,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
<field name="path" />
<field name="password_file" />
<field name="model_id" />
<field name="signing_method" />
</group>
<group>
<field name="domain" />
@ -33,6 +34,22 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
groups="base.group_multi_company"
/>
</group>
<group
attrs="{'invisible': [('signing_method', '!=', 'endesive')]}"
>
<field
name="endesive_certificate_mail"
attrs="{'required': [('signing_method', '=', 'endesive')]}"
/>
<field
name="endesive_certificate_location"
attrs="{'required': [('signing_method', '=', 'endesive')]}"
/>
<field
name="endesive_certificate_reason"
attrs="{'required': [('signing_method', '=', 'endesive')]}"
/>
</group>
</group>
</sheet>
</form>

View File

@ -1,3 +1,5 @@
py3o.template
py3o.formats
genshi>=0.7
cryptography
endesive