From 602b3f3d39db29fbcd90e3f734bdcc73e67f175d Mon Sep 17 00:00:00 2001 From: Ivan Yelizariev Date: Mon, 23 Jan 2023 12:12:23 +0000 Subject: [PATCH] [FIX] account: prevent reading fake binary fields over rpc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since Odoo 16 [1] account module uses some non-storable computed Binary fields to compute and access structured data. Those data is not transformed into binary data and is not supposed to be used outside of server environment. There are still use cases when ORM tries to process such fields as normal Binary fields. For example, on using export wizard [2]. This commit fixes similar problem on reading `account.move{.line}` records via rpc. STEPS: create `account.move` record and read it via an RPC call [3] ``` account_move_id = 666 models.execute_kw(db, uid, password, 'account.move', 'read', [account_move_id]) ``` SOLUTION 1. Add missing `exportable=False` to the fake Binary fields 2. Block access to such fields via method `check_field_access_rights` [1]: https://github.com/odoo/odoo/commit/d8d47f9ff8554f4b39487fd2f13c153c7d6f958d [2]: https://github.com/odoo/odoo/commit/c925ecb2a22750524020f0d111888fd76eedb0cb [3]: https://www.odoo.com/documentation/16.0/developer/api/external_api.html opw-3099975 closes odoo/odoo#134164 X-original-commit: 5193d145b96e34ef1e754b8421cccd8c9dab99e7 Signed-off-by: William André (wan) --- addons/account/models/account_move.py | 13 ++++++++++--- addons/account/models/account_move_line.py | 17 ++++++++++++----- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index d54c13f436e..5f956c33116 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -292,7 +292,7 @@ class AccountMove(models.Model): compute='_compute_invoice_payment_term_id', store=True, readonly=False, precompute=True, check_company=True, ) - needed_terms = fields.Binary(compute='_compute_needed_terms') + needed_terms = fields.Binary(compute='_compute_needed_terms', exportable=False) needed_terms_dirty = fields.Boolean(compute='_compute_needed_terms') tax_calculation_rounding_method = fields.Selection( related='company_id.tax_calculation_rounding_method', @@ -488,7 +488,7 @@ class AccountMove(models.Model): help='Use this field to encode the total amount of the invoice.\n' 'Odoo will automatically create one invoice line with default values to match it.', ) - quick_encoding_vals = fields.Binary(compute='_compute_quick_encoding_vals') + quick_encoding_vals = fields.Binary(compute='_compute_quick_encoding_vals', exportable=False) # === Misc Information === # narration = fields.Html( @@ -580,7 +580,7 @@ class AccountMove(models.Model): need_cancel_request = fields.Boolean(compute='_compute_need_cancel_request') # used to display the various dates and amount dues on the invoice's PDF - payment_term_details = fields.Binary(compute="_compute_payment_term_details") + payment_term_details = fields.Binary(compute="_compute_payment_term_details", exportable=False) show_payment_term_details = fields.Boolean(compute="_compute_show_payment_term_details") show_discount_details = fields.Boolean(compute="_compute_show_payment_term_details") @@ -2340,6 +2340,13 @@ class AccountMove(models.Model): # LOW-LEVEL METHODS # ------------------------------------------------------------------------- + def check_field_access_rights(self, operation, field_names): + result = super().check_field_access_rights(operation, field_names) + if not field_names: + weirdos = ['needed_terms', 'quick_encoding_vals', 'payment_term_details'] + result = [fname for fname in result if fname not in weirdos] + return result + def copy_data(self, default=None): data_list = super().copy_data(default) for move, data in zip(self, data_list): diff --git a/addons/account/models/account_move_line.py b/addons/account/models/account_move_line.py index 84a645306ba..8e586903a5d 100644 --- a/addons/account/models/account_move_line.py +++ b/addons/account/models/account_move_line.py @@ -354,12 +354,12 @@ class AccountMoveLine(models.Model): related='company_id.tax_calculation_rounding_method', string='Tax calculation rounding method', readonly=True) # === Invoice sync fields === # - term_key = fields.Binary(compute='_compute_term_key') - tax_key = fields.Binary(compute='_compute_tax_key') - compute_all_tax = fields.Binary(compute='_compute_all_tax') + term_key = fields.Binary(compute='_compute_term_key', exportable=False) + tax_key = fields.Binary(compute='_compute_tax_key', exportable=False) + compute_all_tax = fields.Binary(compute='_compute_all_tax', exportable=False) compute_all_tax_dirty = fields.Boolean(compute='_compute_all_tax') - epd_key = fields.Binary(compute='_compute_epd_key') - epd_needed = fields.Binary(compute='_compute_epd_needed') + epd_key = fields.Binary(compute='_compute_epd_key', exportable=False) + epd_needed = fields.Binary(compute='_compute_epd_needed', exportable=False) epd_dirty = fields.Boolean(compute='_compute_epd_needed') # === Analytic fields === # @@ -1262,6 +1262,13 @@ class AccountMoveLine(models.Model): # ------------------------------------------------------------------------- # CRUD/ORM # ------------------------------------------------------------------------- + def check_field_access_rights(self, operation, field_names): + result = super().check_field_access_rights(operation, field_names) + if not fields: + weirdos = ['term_key', 'tax_key', 'compute_all_tax', 'epd_key', 'epd_needed'] + result = [fname for fname in result if fname not in weirdos] + return result + def invalidate_model(self, fnames=None, flush=True): # Invalidate cache of related moves if fnames is None or 'move_id' in fnames: