[IMP] add support for non-stored passphrase

This commit is contained in:
Luc De Meyer 2023-03-05 16:52:28 +01:00
parent 9c6c4e4d58
commit 6f3f825aa7
6 changed files with 87 additions and 39 deletions

View File

@ -3,7 +3,7 @@
{ {
"name": "EBICS banking protocol", "name": "EBICS banking protocol",
"version": "16.0.1.0.0", "version": "16.0.1.1.0",
"license": "LGPL-3", "license": "LGPL-3",
"author": "Noviat", "author": "Noviat",
"website": "https://www.noviat.com", "website": "https://www.noviat.com",

View File

@ -87,6 +87,16 @@ class EbicsUserID(models.Model):
ebics_keys_fn = fields.Char(compute="_compute_ebics_keys_fn") ebics_keys_fn = fields.Char(compute="_compute_ebics_keys_fn")
ebics_keys_found = fields.Boolean(compute="_compute_ebics_keys_found") ebics_keys_found = fields.Boolean(compute="_compute_ebics_keys_found")
ebics_passphrase = fields.Char(string="EBICS Passphrase") ebics_passphrase = fields.Char(string="EBICS Passphrase")
ebics_passphrase_store = fields.Boolean(
string="Store EBICS Passphrase",
default=True,
help="When you uncheck this option the passphrase to unlock "
"your private key will not be stored in the database. "
"We recommend to use this if you want to upload signed "
"payment orders via EBICS.\nYou will be prompted to enter the "
"passphrase for every EBICS transaction, hence do not uncheck this "
"option on a userid for automated EBICS downloads.",
)
ebics_ini_letter = fields.Binary( ebics_ini_letter = fields.Binary(
string="EBICS INI Letter", string="EBICS INI Letter",
readonly=True, readonly=True,
@ -195,7 +205,7 @@ class EbicsUserID(models.Model):
@api.constrains("ebics_passphrase") @api.constrains("ebics_passphrase")
def _check_ebics_passphrase(self): def _check_ebics_passphrase(self):
for rec in self: for rec in self:
if not rec.ebics_passphrase or len(rec.ebics_passphrase) < 8: if rec.ebics_passphrase and len(rec.ebics_passphrase) < 8:
raise UserError(_("The passphrase must be at least 8 characters long")) raise UserError(_("The passphrase must be at least 8 characters long"))
@api.onchange("ebics_version") @api.onchange("ebics_version")
@ -208,6 +218,11 @@ class EbicsUserID(models.Model):
if self.signature_class == "T": if self.signature_class == "T":
self.swift_3skey = False self.swift_3skey = False
@api.onchange("ebics_passphrase_store")
def _onchange_ebics_passphrase_store(self):
if not self.ebics_passphrase_store:
self.ebics_passphrase = False
@api.onchange("swift_3skey") @api.onchange("swift_3skey")
def _onchange_swift_3skey(self): def _onchange_swift_3skey(self):
if self.swift_3skey: if self.swift_3skey:

View File

@ -93,6 +93,16 @@
password="True" password="True"
attrs="{'required': [('state', '=', 'draft')]}" attrs="{'required': [('state', '=', 'draft')]}"
/> />
<field name="ebics_passphrase_store" />
<field name="active" />
</group>
<group name="main-right">
<field name="signature_class" />
<field
name="user_ids"
widget="many2many_tags"
options="{'no_create': True}"
/>
<field <field
name="swift_3skey" name="swift_3skey"
attrs="{'invisible': [('signature_class', '=', 'T')]}" attrs="{'invisible': [('signature_class', '=', 'T')]}"
@ -103,15 +113,6 @@
filename="swift_3skey_certificate_fn" filename="swift_3skey_certificate_fn"
attrs="{'invisible': [('swift_3skey', '=', False)], 'required': [('swift_3skey', '=', True)]}" attrs="{'invisible': [('swift_3skey', '=', False)], 'required': [('swift_3skey', '=', True)]}"
/> />
<field name="active" />
</group>
<group name="main-right">
<field name="signature_class" />
<field
name="user_ids"
widget="many2many_tags"
options="{'no_create': True}"
/>
<field name="ebics_key_x509" /> <field name="ebics_key_x509" />
</group> </group>
</group> </group>

View File

@ -62,6 +62,9 @@ class EbicsXfer(models.TransientModel):
comodel_name="ebics.userid", string="EBICS UserID" comodel_name="ebics.userid", string="EBICS UserID"
) )
ebics_passphrase = fields.Char(string="EBICS Passphrase") ebics_passphrase = fields.Char(string="EBICS Passphrase")
ebics_passphrase_stored = fields.Char(
string="EBICS Stored Passphrase", related="ebics_userid_id.ebics_passphrase"
)
date_from = fields.Date() date_from = fields.Date()
date_to = fields.Date() date_to = fields.Date()
upload_data = fields.Binary(string="File to Upload") upload_data = fields.Binary(string="File to Upload")
@ -108,7 +111,7 @@ class EbicsXfer(models.TransientModel):
@api.onchange("ebics_config_id") @api.onchange("ebics_config_id")
def _onchange_ebics_config_id(self): def _onchange_ebics_config_id(self):
ebics_userids = self.ebics_config_id.ebics_userid_ids ebics_userids = self.ebics_config_id.ebics_userid_ids
if self._context.get("ebics_download"): if self.env.context.get("ebics_download"):
download_formats = self.ebics_config_id.ebics_file_format_ids.filtered( download_formats = self.ebics_config_id.ebics_file_format_ids.filtered(
lambda r: r.type == "down" lambda r: r.type == "down"
) )
@ -425,9 +428,15 @@ class EbicsXfer(models.TransientModel):
def _setup_client(self): def _setup_client(self):
self.ebics_config_id._check_ebics_keys() self.ebics_config_id._check_ebics_keys()
passphrase = self._get_passphrase() passphrase = self._get_passphrase()
keyring = EbicsKeyRing( try:
keys=self.ebics_userid_id.ebics_keys_fn, passphrase=passphrase keyring = EbicsKeyRing(
) keys=self.ebics_userid_id.ebics_keys_fn, passphrase=passphrase
)
except (RuntimeError, ValueError) as err:
error = _("Error while accessing the EBICS Keys:")
error += "\n"
error += err.args[0]
raise UserError(error) from err
bank = EbicsBank( bank = EbicsBank(
keyring=keyring, keyring=keyring,
@ -437,11 +446,22 @@ class EbicsXfer(models.TransientModel):
if self.ebics_config_id.ebics_version == "H003": if self.ebics_config_id.ebics_version == "H003":
bank._order_number = self.ebics_config_id._get_order_number() bank._order_number = self.ebics_config_id._get_order_number()
user = EbicsUser( try:
keyring=keyring, user = EbicsUser(
partnerid=self.ebics_config_id.ebics_partner, keyring=keyring,
userid=self.ebics_userid_id.name, partnerid=self.ebics_config_id.ebics_partner,
) userid=self.ebics_userid_id.name,
)
except ValueError as err:
error = _("Error while accessing the EBICS UserID:")
error += "\n"
err_str = err.args[0]
error += err.args[0]
if err_str == "unknown key format":
error += "\n"
error += _("Doublecheck your EBICS Passphrase and UserID settings.")
raise UserError(error) from err
signature_class = ( signature_class = (
self.format_id.signature_class or self.ebics_userid_id.signature_class self.format_id.signature_class or self.ebics_userid_id.signature_class
) )
@ -460,24 +480,7 @@ class EbicsXfer(models.TransientModel):
return client return client
def _get_passphrase(self): def _get_passphrase(self):
passphrase = self.ebics_userid_id.ebics_passphrase return self.ebics_passphrase or self.ebics_userid_id.ebics_passphrase
if passphrase:
return passphrase
module = __name__.split("addons.")[1].split(".")[0]
passphrase_view = self.env.ref("%s.ebics_xfer_view_form_passphrase" % module)
return {
"name": _("EBICS file transfer"),
"res_id": self.id,
"view_type": "form",
"view_mode": "form",
"res_model": "ebics.xfer",
"view_id": passphrase_view.id,
"target": "new",
"context": self._context,
"type": "ir.actions.act_window",
}
def _file_format_methods(self): def _file_format_methods(self):
""" """

View File

@ -20,6 +20,13 @@
required="1" required="1"
options="{'no_create': True, 'no_open': True}" options="{'no_create': True, 'no_open': True}"
/> />
<field
name="ebics_passphrase"
password="True"
required="1"
attrs="{'invisible': [('ebics_passphrase_stored', '!=', False)]}"
/>
<field name="ebics_passphrase_stored" invisible="1" />
<field name="date_from" /> <field name="date_from" />
<field name="date_to" /> <field name="date_to" />
<field <field
@ -62,6 +69,13 @@
required="1" required="1"
options="{'no_create': True, 'no_open': True}" options="{'no_create': True, 'no_open': True}"
/> />
<field
name="ebics_passphrase"
password="True"
required="1"
attrs="{'invisible': [('ebics_passphrase_stored', '!=', False)]}"
/>
<field name="ebics_passphrase_stored" invisible="1" />
<separator string="Select your file :" colspan="2" /> <separator string="Select your file :" colspan="2" />
<field name="upload_data" filename="upload_fname" required="1" /> <field name="upload_data" filename="upload_fname" required="1" />
<field name="upload_fname" invisible="1" /> <field name="upload_fname" invisible="1" />

View File

@ -105,6 +105,15 @@ class EbicsBatchLog(models.Model):
) )
) )
continue continue
if not any(config.mapped("ebics_userid_ids.ebics_passphrase_store")):
import_dict["errors"].append(
err_msg
+ _(
"No EBICS UserID with stored passphrase found.\n"
"You should configure such a UserID for automated downloads."
)
)
continue
try: try:
with self.env.cr.savepoint(): with self.env.cr.savepoint():
ebics_file_ids += self._ebics_import( ebics_file_ids += self._ebics_import(
@ -146,6 +155,11 @@ class EbicsBatchLog(models.Model):
self.state = state self.state = state
def _ebics_import(self, config, date_from, date_to, import_dict): def _ebics_import(self, config, date_from, date_to, import_dict):
ebics_userids = config.ebics_userid_ids.filtered(
lambda r: r.ebics_passphrase_store
)
t_userids = ebics_userids.filtered(lambda r: r.signature_class == "T")
ebics_userid = t_userids and t_userids[0] or ebics_userids[0]
xfer_wiz = ( xfer_wiz = (
self.env["ebics.xfer"] self.env["ebics.xfer"]
.with_context(ebics_download=True) .with_context(ebics_download=True)
@ -158,8 +172,9 @@ class EbicsBatchLog(models.Model):
) )
) )
xfer_wiz._onchange_ebics_config_id() xfer_wiz._onchange_ebics_config_id()
xfer_wiz.ebics_userid_id = ebics_userid
res = xfer_wiz.ebics_download() res = xfer_wiz.ebics_download()
file_ids = res["context"].get("ebics_file_ids") file_ids = res["context"].get("ebics_file_ids", [])
if res["context"]["err_cnt"]: if res["context"]["err_cnt"]:
import_dict["errors"].append(xfer_wiz.note) import_dict["errors"].append(xfer_wiz.note)
return file_ids return file_ids