From 8cb03ef5d40708bb875b1951d9b5851f857f25f6 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Fri, 19 Jan 2024 15:13:28 +0100 Subject: [PATCH 1/3] [IMP]account_ebics UI improvements --- account_ebics/__manifest__.py | 4 +- account_ebics/models/ebics_userid.py | 69 +++++++++++++--------- account_ebics/views/ebics_userid_views.xml | 20 ++++--- 3 files changed, 57 insertions(+), 36 deletions(-) diff --git a/account_ebics/__manifest__.py b/account_ebics/__manifest__.py index c737c4b..eba4c4c 100644 --- a/account_ebics/__manifest__.py +++ b/account_ebics/__manifest__.py @@ -1,9 +1,9 @@ -# Copyright 2009-2023 Noviat. +# Copyright 2009-2024 Noviat. # License LGPL-3 or later (http://www.gnu.org/licenses/lgpl). { "name": "EBICS banking protocol", - "version": "16.0.1.8.0", + "version": "16.0.1.9.0", "license": "LGPL-3", "author": "Noviat", "website": "https://www.noviat.com/", diff --git a/account_ebics/models/ebics_userid.py b/account_ebics/models/ebics_userid.py index d8e8ad1..f27e62e 100644 --- a/account_ebics/models/ebics_userid.py +++ b/account_ebics/models/ebics_userid.py @@ -1,4 +1,4 @@ -# Copyright 2009-2023 Noviat. +# Copyright 2009-2024 Noviat. # License LGPL-3 or later (http://www.gnu.org/licenses/lgpl). import base64 @@ -58,7 +58,10 @@ class EbicsUserID(models.Model): "The human user also can authorise orders.", ) ebics_config_id = fields.Many2one( - comodel_name="ebics.config", string="EBICS Configuration", ondelete="cascade" + comodel_name="ebics.config", + string="EBICS Configuration", + ondelete="cascade", + required=True, ) ebics_version = fields.Selection(related="ebics_config_id.ebics_version") user_ids = fields.Many2many( @@ -111,6 +114,9 @@ class EbicsUserID(models.Model): ebics_passphrase_invisible = fields.Boolean( compute="_compute_ebics_passphrase_view_modifiers" ) + ebics_passphrase_store_readonly = fields.Boolean( + compute="_compute_ebics_passphrase_view_modifiers" + ) ebics_sig_passphrase = fields.Char( string="EBICS Signature Passphrase", help="You can set here a different passphrase for the EBICS " @@ -146,6 +152,8 @@ class EbicsUserID(models.Model): # create self-signed X.509 certificates ebics_key_x509 = fields.Boolean( string="X509 support", + readonly=True, + states={"draft": [("readonly", False)]}, help="Set this flag in order to work with " "self-signed X.509 certificates", ) ebics_key_x509_dn_cn = fields.Char( @@ -203,7 +211,7 @@ class EbicsUserID(models.Model): help="Companies sharing this EBICS contract.", ) - @api.depends("name") + @api.depends("name", "ebics_config_id.ebics_keys") def _compute_ebics_keys_fn(self): for rec in self: keys_dir = rec.ebics_config_id.ebics_keys @@ -224,8 +232,10 @@ class EbicsUserID(models.Model): def _compute_ebics_passphrase_view_modifiers(self): for rec in self: rec.ebics_passphrase_invisible = False + rec.ebics_passphrase_store_readonly = True if rec.state == "draft": rec.ebics_passphrase_required = True + rec.ebics_passphrase_store_readonly = False elif rec.state == "init": rec.ebics_passphrase_invisible = True elif rec.state in ("get_bank_keys", "to_verify"): @@ -276,7 +286,18 @@ class EbicsUserID(models.Model): @api.onchange("ebics_passphrase_store") def _onchange_ebics_passphrase_store(self): - if not self.ebics_passphrase_store and self.state == "active_keys": + if self.ebics_passphrase_store: + # check passphrase before db store + keyring_params = { + "keys": self.ebics_keys_fn, + "passphrase": self.ebics_passphrase, + } + try: + # TODO: implement check passphrase logic + keyring = EbicsKeyRing(**keyring_params) # noqa: F841 + except Exception as err: + raise UserError(str(err)) from err + elif not self.ebics_passphrase_store and self.state != "draft": self.ebics_passphrase = False @api.onchange("swift_3skey") @@ -288,7 +309,9 @@ class EbicsUserID(models.Model): return self.write({"state": "draft"}) def set_to_active_keys(self): - return self.write({"state": "active_keys"}) + vals = {"state": "active_keys"} + self._update_passphrase_vals(vals) + return self.write(vals) def set_to_get_bank_keys(self): self.ensure_one() @@ -467,11 +490,7 @@ class EbicsUserID(models.Model): "ebics_ini_letter_fn": fn, "state": "init", } - # remove non-stored passphrases from db after successfull init_1 - if not self.ebics_passphrase_store: - vals.update["ebics_passphrase"] = False - if self.ebics_sig_passphrase: - vals.update["ebics_sig_passphrase"] = False + self._update_passphrase_vals(vals) return self.write(vals) def ebics_init_2(self): @@ -483,13 +502,7 @@ class EbicsUserID(models.Model): if self.state != "init": raise UserError(_("Set state to 'Initialisation'.")) vals = {"state": "get_bank_keys"} - # remove non-stored passphrases from db - # remark: this code is here for extra safety but shouldn't - # have any effect since passphrases are invisible in state "init" - if not self.ebics_passphrase_store: - vals.update["ebics_passphrase"] = False - if self.ebics_sig_passphrase: - vals.update["ebics_sig_passphrase"] = False + self._update_passphrase_vals(vals) return self.write(vals) def ebics_init_3(self): @@ -548,11 +561,7 @@ class EbicsUserID(models.Model): "ebics_public_bank_keys_fn": fn, "state": "to_verify", } - # remove non-stored passphrases from db - if not self.ebics_passphrase_store: - vals.update["ebics_passphrase"] = False - if self.ebics_sig_passphrase: - vals.update["ebics_sig_passphrase"] = False + self._update_passphrase_vals(vals) return self.write(vals) def ebics_init_4(self): @@ -575,11 +584,7 @@ class EbicsUserID(models.Model): ) bank.activate_keys() vals = {"state": "active_keys"} - # remove non-stored passphrases from db - if not self.ebics_passphrase_store: - vals.update["ebics_passphrase"] = False - if self.ebics_sig_passphrase: - vals.update["ebics_sig_passphrase"] = False + self._update_passphrase_vals(vals) return self.write(vals) def change_passphrase(self): @@ -597,3 +602,13 @@ class EbicsUserID(models.Model): "context": ctx, "type": "ir.actions.act_window", } + + def _update_passphrase_vals(self, vals): + """ + Remove non-stored passphrases from db after e.g. successfull init_1 + """ + if vals["state"] in ("init", "get_bank_keys", "to_verify", "active_keys"): + if not self.ebics_passphrase_store: + vals["ebics_passphrase"] = False + if self.ebics_sig_passphrase: + vals["ebics_sig_passphrase"] = False diff --git a/account_ebics/views/ebics_userid_views.xml b/account_ebics/views/ebics_userid_views.xml index 76c5021..f738293 100644 --- a/account_ebics/views/ebics_userid_views.xml +++ b/account_ebics/views/ebics_userid_views.xml @@ -82,13 +82,16 @@ /> - - - - - - + + + + + + + + + - + Date: Fri, 19 Jan 2024 15:17:57 +0100 Subject: [PATCH 2/3] [IMP]remove SWIFT 3Skey support from UI These fields should be restored after implementation of SWIFT SConnect. SWIFT 3Skey certificates can be imported into account_ebics and used for download purposes but there is little value in this. Hence it's better to remove it for the time being. --- account_ebics/views/ebics_userid_views.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/account_ebics/views/ebics_userid_views.xml b/account_ebics/views/ebics_userid_views.xml index f738293..10842f2 100644 --- a/account_ebics/views/ebics_userid_views.xml +++ b/account_ebics/views/ebics_userid_views.xml @@ -118,6 +118,7 @@ widget="many2many_tags" options="{'no_create': True}" /> + From f2a9af0debbaa5fa072269b6cbd28aa1b61df19c Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Sun, 21 Jan 2024 22:36:00 +0100 Subject: [PATCH 3/3] [IMP]account_ebics UI improvements --- account_ebics/models/ebics_userid.py | 33 +++++++++++++++++----------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/account_ebics/models/ebics_userid.py b/account_ebics/models/ebics_userid.py index f27e62e..beca448 100644 --- a/account_ebics/models/ebics_userid.py +++ b/account_ebics/models/ebics_userid.py @@ -284,21 +284,28 @@ class EbicsUserID(models.Model): if self.signature_class == "T": self.swift_3skey = False - @api.onchange("ebics_passphrase_store") + @api.onchange("ebics_passphrase_store", "ebics_passphrase") def _onchange_ebics_passphrase_store(self): if self.ebics_passphrase_store: - # check passphrase before db store - keyring_params = { - "keys": self.ebics_keys_fn, - "passphrase": self.ebics_passphrase, - } - try: - # TODO: implement check passphrase logic - keyring = EbicsKeyRing(**keyring_params) # noqa: F841 - except Exception as err: - raise UserError(str(err)) from err - elif not self.ebics_passphrase_store and self.state != "draft": - self.ebics_passphrase = False + if self.ebics_passphrase: + # check passphrase before db store + keyring_params = { + "keys": self.ebics_keys_fn, + "passphrase": self.ebics_passphrase, + } + keyring = EbicsKeyRing(**keyring_params) + try: + # fintech <= 7.4.3 does not have a call to check if a + # passphrase matches with the value stored in the keyfile. + # We get around this limitation as follows: + # Get user keys to check for valid passphrases + # It will raise a ValueError on invalid passphrases + keyring["#USER"] + except ValueError as err: # noqa: F841 + raise UserError(_("Passphrase mismatch.")) # noqa: B904 + else: + if self.state != "draft": + self.ebics_passphrase = False @api.onchange("swift_3skey") def _onchange_swift_3skey(self):