From 481a00dc4b82bc1b2cbbd6079a147fe230ac57bd Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 15 May 2017 17:27:24 +0200 Subject: [PATCH] [FIX] P3: hash/hmac payload must be bytes --- addons/hw_escpos/escpos/escpos.py | 2 +- addons/mail/models/mail_thread.py | 2 +- addons/mass_mailing/models/mass_mailing.py | 2 +- addons/payment/models/payment_acquirer.py | 2 +- addons/payment_adyen/models/payment.py | 2 +- addons/payment_authorize/models/payment.py | 2 +- addons/payment_authorize/tests/test_authorize.py | 2 +- addons/payment_payumoney/models/payment.py | 2 +- addons/payment_sips/models/payment.py | 2 +- addons/web_editor/models/ir_qweb.py | 2 +- addons/website/models/website.py | 2 +- addons/website_forum/models/res_users.py | 5 +++-- addons/website_mail/controllers/main.py | 1 - addons/website_mail_channel/models/mail_channel.py | 2 +- odoo/addons/base/ir/ir_attachment.py | 4 ++-- odoo/addons/base/ir/ir_config_parameter.py | 4 ++-- odoo/addons/base/ir/ir_http.py | 6 +++--- odoo/addons/base/ir/ir_qweb/assetsbundle.py | 2 +- odoo/addons/base/res/res_partner.py | 2 +- odoo/addons/base/tests/test_translate.py | 2 ++ odoo/http.py | 4 ++-- odoo/osv/expression.py | 2 +- 22 files changed, 29 insertions(+), 27 deletions(-) diff --git a/addons/hw_escpos/escpos/escpos.py b/addons/hw_escpos/escpos/escpos.py index f076778ca9c..7159ac3b31e 100644 --- a/addons/hw_escpos/escpos/escpos.py +++ b/addons/hw_escpos/escpos/escpos.py @@ -433,7 +433,7 @@ class Escpos: print('print_b64_img') - id = md5(img).digest() + id = md5(img.encode('utf-8')).digest() if id not in self.img_cache: print('not in cache') diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index bc7b1d1072d..8dfe1ef452c 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -570,7 +570,7 @@ class MailThread(models.AbstractModel): def _generate_notification_token(self, base_link, params): secret = self.env['ir.config_parameter'].sudo().get_param('database.secret') token = '%s?%s' % (base_link, ' '.join('%s=%s' % (key, params[key]) for key in sorted(params))) - hm = hmac.new(str(secret), token, hashlib.sha1).hexdigest() + hm = hmac.new(secret.encode('utf-8'), token.encode('utf-8'), hashlib.sha1).hexdigest() return hm @api.multi diff --git a/addons/mass_mailing/models/mass_mailing.py b/addons/mass_mailing/models/mass_mailing.py index 44993bdc907..a10e6143c89 100644 --- a/addons/mass_mailing/models/mass_mailing.py +++ b/addons/mass_mailing/models/mass_mailing.py @@ -430,7 +430,7 @@ class MassMailing(models.Model): secret = self.env["ir.config_parameter"].sudo().get_param( "database.secret") token = (self.env.cr.dbname, self.id, int(res_id), tools.ustr(email)) - return hmac.new(str(secret), repr(token), hashlib.sha512).hexdigest() + return hmac.new(secret.encode('utf-8'), repr(token).encode('utf-8'), hashlib.sha512).hexdigest() def _compute_next_departure(self): cron_next_call = self.env.ref('mass_mailing.ir_cron_mass_mailing_queue').sudo().nextcall diff --git a/addons/payment/models/payment_acquirer.py b/addons/payment/models/payment_acquirer.py index 623676c7a9c..909536ac95c 100644 --- a/addons/payment/models/payment_acquirer.py +++ b/addons/payment/models/payment_acquirer.py @@ -583,7 +583,7 @@ class PaymentTransaction(models.Model): token = '%s%s%s' % (self.callback_model_id.model, self.callback_res_id, self.sudo().callback_method) - return hmac.new(str(secret), token, hashlib.sha256).hexdigest() + return hmac.new(secret.encode('utf-8'), token.encode('utf-8'), hashlib.sha256).hexdigest() # -------------------------------------------------- # FORM RELATED METHODS diff --git a/addons/payment_adyen/models/payment.py b/addons/payment_adyen/models/payment.py index 87e51e619cb..787160fd1ea 100644 --- a/addons/payment_adyen/models/payment.py +++ b/addons/payment_adyen/models/payment.py @@ -54,7 +54,7 @@ class AcquirerAdyen(models.Model): escapeVal(v) for v in chain(pycompat.keys(parms), pycompat.values(parms)) ) - hm = hmac.new(hmac_key, signing_string, hashlib.sha256) + hm = hmac.new(hmac_key, signing_string.encode('utf-8'), hashlib.sha256) return base64.b64encode(hm.digest()) assert inout in ('in', 'out') diff --git a/addons/payment_authorize/models/payment.py b/addons/payment_authorize/models/payment.py index bfc5bfd569a..caa15732e15 100644 --- a/addons/payment_authorize/models/payment.py +++ b/addons/payment_authorize/models/payment.py @@ -54,7 +54,7 @@ class PaymentAcquirerAuthorize(models.Model): values['x_fp_timestamp'], values['x_amount'], values['x_currency_code']]) - return hmac.new(str(values['x_trans_key']), data, hashlib.md5).hexdigest() + return hmac.new(values['x_trans_key'].encode('utf-8'), data.encode('utf-8'), hashlib.md5).hexdigest() @api.multi def authorize_form_generate_values(self, values): diff --git a/addons/payment_authorize/tests/test_authorize.py b/addons/payment_authorize/tests/test_authorize.py index 668e17d0562..6d3f4244583 100644 --- a/addons/payment_authorize/tests/test_authorize.py +++ b/addons/payment_authorize/tests/test_authorize.py @@ -39,7 +39,7 @@ class AuthorizeForm(AuthorizeCommon): values['x_fp_timestamp'], values['x_amount'], ]) + '^' - return hmac.new(str(values['x_trans_key']), data, hashlib.md5).hexdigest() + return hmac.new(values['x_trans_key'].encode('utf-8'), data.encode('utf-8'), hashlib.md5).hexdigest() def test_10_Authorize_form_render(self): self.assertEqual(self.authorize.environment, 'test', 'test without test environment') diff --git a/addons/payment_payumoney/models/payment.py b/addons/payment_payumoney/models/payment.py index 243ef5cef53..cbda9e64527 100644 --- a/addons/payment_payumoney/models/payment.py +++ b/addons/payment_payumoney/models/payment.py @@ -49,7 +49,7 @@ class PaymentAcquirerPayumoney(models.Model): sign = ''.join('%s|' % (values.get(k) or '') for k in keys) sign = self.payumoney_merchant_salt + sign + self.payumoney_merchant_key - shasign = hashlib.sha512(sign).hexdigest() + shasign = hashlib.sha512(sign.encode('utf-8')).hexdigest() return shasign @api.multi diff --git a/addons/payment_sips/models/payment.py b/addons/payment_sips/models/payment.py index f01c59d1880..a6c9b390eae 100644 --- a/addons/payment_sips/models/payment.py +++ b/addons/payment_sips/models/payment.py @@ -66,7 +66,7 @@ class AcquirerSips(models.Model): if self.environment == 'prod': key = getattr(self, 'sips_secret') - shasign = sha256(data + key) + shasign = sha256((data + key).encode('utf-8')) return shasign.hexdigest() @api.multi diff --git a/addons/web_editor/models/ir_qweb.py b/addons/web_editor/models/ir_qweb.py index 4b1cd512e06..f4a25a8b990 100644 --- a/addons/web_editor/models/ir_qweb.py +++ b/addons/web_editor/models/ir_qweb.py @@ -315,7 +315,7 @@ class Image(models.AbstractModel): if max_width or max_height: max_size = '%sx%s' % (max_width, max_height) - sha = hashlib.sha1(getattr(record, '__last_update')).hexdigest()[0:7] + sha = hashlib.sha1(getattr(record, '__last_update').encode('utf-8')).hexdigest()[0:7] max_size = '' if max_size is None else '/%s' % max_size src = '/web/image/%s/%s/%s%s?unique=%s' % (record._name, record.id, field_name, max_size, sha) diff --git a/addons/website/models/website.py b/addons/website/models/website.py index c46e3c2a327..fd6ee0f2841 100644 --- a/addons/website/models/website.py +++ b/addons/website/models/website.py @@ -584,7 +584,7 @@ class Website(models.Model): def image_url(self, record, field, size=None): """ Returns a local url that points to the image field of a given browse record. """ sudo_record = record.sudo() - sha = hashlib.sha1(getattr(sudo_record, '__last_update')).hexdigest()[0:7] + sha = hashlib.sha1(getattr(sudo_record, '__last_update').encode('utf-8')).hexdigest()[0:7] size = '' if size is None else '/%s' % size return '/web/image/%s/%s/%s%s?unique=%s' % (record._name, record.id, field, size, sha) diff --git a/addons/website_forum/models/res_users.py b/addons/website_forum/models/res_users.py index 9d22ee3c9d8..054e3a4d56a 100644 --- a/addons/website_forum/models/res_users.py +++ b/addons/website_forum/models/res_users.py @@ -66,11 +66,12 @@ class Users(models.Model): and is a hash based on a (secret) uuid generated by the forum module, the user_id, the email and currently the day (to be updated if necessary). """ forum_uuid = self.env['ir.config_parameter'].sudo().get_param('website_forum.uuid') - return hashlib.sha256('%s-%s-%s-%s' % ( + return hashlib.sha256((u'%s-%s-%s-%s' % ( datetime.now().replace(hour=0, minute=0, second=0, microsecond=0), forum_uuid, user_id, - email)).hexdigest() + email + )).encode('utf-8')).hexdigest() @api.one def send_forum_validation_email(self, forum_id=None): diff --git a/addons/website_mail/controllers/main.py b/addons/website_mail/controllers/main.py index c10525fd5e0..ab42fb5c3b5 100644 --- a/addons/website_mail/controllers/main.py +++ b/addons/website_mail/controllers/main.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. - from werkzeug.exceptions import NotFound, Forbidden from odoo import http diff --git a/addons/website_mail_channel/models/mail_channel.py b/addons/website_mail_channel/models/mail_channel.py index 519dfe7afc6..79c6cc27287 100644 --- a/addons/website_mail_channel/models/mail_channel.py +++ b/addons/website_mail_channel/models/mail_channel.py @@ -68,4 +68,4 @@ class MailGroup(models.Model): str(self.id), str(partner_id), action]) - return hmac.new(secret.encode('utf-8'), data).hexdigest() + return hmac.new(secret.encode('utf-8'), data.encode('utf-8')).hexdigest() diff --git a/odoo/addons/base/ir/ir_attachment.py b/odoo/addons/base/ir/ir_attachment.py index f40d842c4f9..8032878d061 100644 --- a/odoo/addons/base/ir/ir_attachment.py +++ b/odoo/addons/base/ir/ir_attachment.py @@ -195,7 +195,7 @@ class IrAttachment(models.Model): for attach in self: # compute the fields that depend on datas value = attach.datas - bin_data = value and base64.b64decode(value) or '' + bin_data = base64.b64decode(value) if value else b'' vals = { 'file_size': len(bin_data), 'checksum': self._compute_checksum(bin_data), @@ -220,7 +220,7 @@ class IrAttachment(models.Model): :param bin_data : datas in its binary form """ # an empty file has a checksum too (for caching) - return hashlib.sha1(bin_data or '').hexdigest() + return hashlib.sha1(bin_data or b'').hexdigest() def _compute_mimetype(self, values): """ compute the mimetype of the given values diff --git a/odoo/addons/base/ir/ir_config_parameter.py b/odoo/addons/base/ir/ir_config_parameter.py index 8e4ea20b5a5..833185d8d67 100644 --- a/odoo/addons/base/ir/ir_config_parameter.py +++ b/odoo/addons/base/ir/ir_config_parameter.py @@ -16,8 +16,8 @@ _logger = logging.getLogger(__name__) A dictionary holding some configuration parameters to be initialized when the database is created. """ _default_parameters = { - "database.secret": lambda: str(uuid.uuid4()), - "database.uuid": lambda: str(uuid.uuid1()), + "database.secret": lambda: pycompat.text_type(uuid.uuid4()), + "database.uuid": lambda: pycompat.text_type(uuid.uuid1()), "database.create_date": fields.Datetime.now, "web.base.url": lambda: "http://localhost:%s" % config.get('xmlrpc_port'), } diff --git a/odoo/addons/base/ir/ir_http.py b/odoo/addons/base/ir/ir_http.py index 83231ebc3e6..392cf27d4a1 100644 --- a/odoo/addons/base/ir/ir_http.py +++ b/odoo/addons/base/ir/ir_http.py @@ -125,7 +125,7 @@ class IrHttp(models.AbstractModel): attach = env['ir.attachment'].search_read(domain, fields) if attach: wdate = attach[0]['__last_update'] - datas = attach[0]['datas'] or '' + datas = attach[0]['datas'] or b'' name = attach[0]['name'] checksum = attach[0]['checksum'] or hashlib.sha1(datas).hexdigest() @@ -288,7 +288,7 @@ class IrHttp(models.AbstractModel): if module_resource_path.startswith(module_path): with open(module_resource_path, 'rb') as f: content = base64.b64encode(f.read()) - last_update = str(os.path.getmtime(module_resource_path)) + last_update = pycompat.text_type(os.path.getmtime(module_resource_path)) if not module_resource_path: module_resource_path = obj.url @@ -324,7 +324,7 @@ class IrHttp(models.AbstractModel): # cache etag = bool(request) and request.httprequest.headers.get('If-None-Match') - retag = '"%s"' % hashlib.md5(last_update).hexdigest() + retag = '"%s"' % hashlib.md5(last_update.encode('utf-8')).hexdigest() status = status or (304 if etag == retag else 200) headers.append(('ETag', retag)) headers.append(('Cache-Control', 'max-age=%s' % (STATIC_CACHE if unique else 0))) diff --git a/odoo/addons/base/ir/ir_qweb/assetsbundle.py b/odoo/addons/base/ir/ir_qweb/assetsbundle.py index 24bc9bea492..fcf9abe4d5d 100644 --- a/odoo/addons/base/ir/ir_qweb/assetsbundle.py +++ b/odoo/addons/base/ir/ir_qweb/assetsbundle.py @@ -149,7 +149,7 @@ class AssetsBundle(object): Not really a full checksum. We compute a SHA1 on the rendered bundle + max linked files last_modified date """ - check = json.dumps(self.files) + ",".join(self.remains) + str(self.last_modified) + check = json.dumps(self.files) + b",".join(self.remains) + self.last_modified.encode('utf-8') return hashlib.sha1(check).hexdigest() def clean_attachments(self, type): diff --git a/odoo/addons/base/res/res_partner.py b/odoo/addons/base/res/res_partner.py index 5b73d6848cd..7873dfda525 100644 --- a/odoo/addons/base/res/res_partner.py +++ b/odoo/addons/base/res/res_partner.py @@ -665,7 +665,7 @@ class Partner(models.Model): return partners.id or self.name_create(email)[0] def _get_gravatar_image(self, email): - email_hash = hashlib.md5(email.lower()).hexdigest() + email_hash = hashlib.md5(email.lower().encode('utf-8')).hexdigest() url = "https://www.gravatar.com/avatar/" + email_hash try: res = requests.get(url, params={'d': '404', 's': '128'}, timeout=5) diff --git a/odoo/addons/base/tests/test_translate.py b/odoo/addons/base/tests/test_translate.py index 6d54a0b7886..19405c3145d 100644 --- a/odoo/addons/base/tests/test_translate.py +++ b/odoo/addons/base/tests/test_translate.py @@ -9,6 +9,8 @@ from odoo.tests.common import TransactionCase class TranslationToolsTestCase(unittest.TestCase): + def assertItemsEqual(self, a, b, msg=None): + self.assertEqual(sorted(a), sorted(b), msg) def test_quote_unquote(self): diff --git a/odoo/http.py b/odoo/http.py index 941fae06fe2..1f8af2e8b9f 100644 --- a/odoo/http.py +++ b/odoo/http.py @@ -392,7 +392,7 @@ class WebRequest(object): msg = '%s%s' % (token, max_ts) secret = self.env['ir.config_parameter'].sudo().get_param('database.secret') assert secret, "CSRF protection requires a configured database secret" - hm = hmac.new(str(secret), msg, hashlib.sha1).hexdigest() + hm = hmac.new(secret.encode('ascii'), msg.encode('utf-8'), hashlib.sha1).hexdigest() return '%so%s' % (hm, max_ts) def validate_csrf(self, csrf): @@ -416,7 +416,7 @@ class WebRequest(object): msg = '%s%s' % (token, max_ts) secret = self.env['ir.config_parameter'].sudo().get_param('database.secret') assert secret, "CSRF protection requires a configured database secret" - hm_expected = hmac.new(str(secret), msg, hashlib.sha1).hexdigest() + hm_expected = hmac.new(secret.encode('ascii'), msg.encode('utf-8'), hashlib.sha1).hexdigest() return consteq(hm, hm_expected) def route(route=None, **kw): diff --git a/odoo/osv/expression.py b/odoo/osv/expression.py index 761b9bef4fe..1f55f58600a 100644 --- a/odoo/osv/expression.py +++ b/odoo/osv/expression.py @@ -337,7 +337,7 @@ def generate_table_alias(src_table_alias, joined_tables=[]): # We have to fit a crc32 hash and one underscore # into a 63 character alias. The remaining space we can use to add # a human readable prefix. - alias_hash = hex(crc32(alias))[2:] + alias_hash = hex(crc32(alias.encode('utf-8')))[2:].decode('utf-8') ALIAS_PREFIX_LENGTH = 63 - len(alias_hash) - 1 alias = "%s_%s" % ( alias[:ALIAS_PREFIX_LENGTH], alias_hash)