From 93854b3e9ed93eaca5de6d22e6e2a2631a188ea5 Mon Sep 17 00:00:00 2001
From: Kazuhiko SHIOZAKI <kazuhiko@nexedi.com>
Date: Fri, 7 Oct 2022 12:04:06 +0200
Subject: [PATCH] py2/py3: md5() argument should by byte.

---
 product/ERP5Form/CaptchaField.py           | 7 ++++---
 product/ERP5Form/CaptchasDotNet.py         | 3 ++-
 product/ERP5Form/Selection.py              | 5 +++--
 product/ERP5Form/Tool/SelectionTool.py     | 6 ++----
 product/ERP5Type/tests/ERP5TypeTestCase.py | 2 +-
 5 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/product/ERP5Form/CaptchaField.py b/product/ERP5Form/CaptchaField.py
index b1aadbfc7c..5f4c26bc0e 100644
--- a/product/ERP5Form/CaptchaField.py
+++ b/product/ERP5Form/CaptchaField.py
@@ -35,6 +35,7 @@ from Products.Formulator.Errors import ValidationError
 from Products.PageTemplates.PageTemplateFile import PageTemplateFile
 from AccessControl import ClassSecurityInfo
 from Products.ERP5Type.Globals import DTMLFile
+from Products.ERP5Type.Utils import str2bytes
 from Products.Formulator.TALESField import TALESField
 from . import CaptchasDotNet
 import string
@@ -75,7 +76,7 @@ class CaptchasDotNetProvider(object):
 
   def getHTML(self, field, captcha_key):
     image_generator = self.getImageGenerator(field)
-    return image_generator.image(captcha_key, "__captcha_" + md5(captcha_key).hexdigest())
+    return image_generator.image(captcha_key, "__captcha_" + md5(str2bytes(captcha_key)).hexdigest())
 
   # dynamic fields
   _dynamic_property_list = [dict(id='captcha_dot_net_client',
@@ -197,14 +198,14 @@ class CaptchaWidget(Widget.TextWidget):
     provider = CaptchaProviderFactory.getProvider(captcha_type)
     (captcha_key, captcha_answer) = provider.generate(field)
     portal_sessions = field.getPortalObject().portal_sessions
-    while not self.add_captcha(portal_sessions, md5(captcha_key).hexdigest(), captcha_answer):
+    while not self.add_captcha(portal_sessions, md5(str2bytes(captcha_key)).hexdigest(), captcha_answer):
       (captcha_key, captcha_answer) = provider.generate(field)
     captcha_field = provider.getHTML(field, captcha_key)
 
     key_field = Widget.render_element("input",
                                       type="hidden",
                                       name="__captcha_" + key + "__",
-                                      value=md5(captcha_key).hexdigest())
+                                      value=md5(str2bytes(captcha_key)).hexdigest())
     splitter = "<br />"
     answer = Widget.render_element("input",
                                    type="text",
diff --git a/product/ERP5Form/CaptchasDotNet.py b/product/ERP5Form/CaptchasDotNet.py
index 045b39c29a..565934dbe5 100644
--- a/product/ERP5Form/CaptchasDotNet.py
+++ b/product/ERP5Form/CaptchasDotNet.py
@@ -30,6 +30,7 @@
 
 from hashlib import md5
 import random
+from Products.ERP5Type.Utils import str2bytes
 
 class CaptchasDotNet:
     def __init__ (self, client, secret,
@@ -130,7 +131,7 @@ class CaptchasDotNet:
         encryption_base = self.__secret + random
         if (password_alphabet != "abcdefghijklmnopqrstuvwxyz") or (password_length != 6):
             encryption_base += ":" + password_alphabet + ":" + str(password_length)
-        digest = md5(encryption_base).digest()
+        digest = md5(str2bytes(encryption_base)).digest()
 
         # Compute password
         correct_password = ''
diff --git a/product/ERP5Form/Selection.py b/product/ERP5Form/Selection.py
index 388aca2936..4bbe6b0021 100644
--- a/product/ERP5Form/Selection.py
+++ b/product/ERP5Form/Selection.py
@@ -33,6 +33,7 @@ from Acquisition import aq_base
 from OFS.Traversable import Traversable
 from AccessControl import ClassSecurityInfo
 from Products.ERP5Type import Permissions as ERP5Permissions
+from Products.ERP5Type.Utils import str2bytes
 from Products.PythonScripts.Utility import allow_class
 from hashlib import md5
 
@@ -375,8 +376,8 @@ class Selection(Acquisition.Implicit, Traversable, Persistent):
 
     security.declarePublic('getAnonymousSelectionKey')
     def getAnonymousSelectionKey(self):
-        return md5(repr({k: v for k, v in six.iteritems(self.__dict__)
-                              if k != 'index'})).hexdigest()
+        return md5(str2bytes(repr({k: v for k, v in six.iteritems(self.__dict__)
+                                        if k != 'index'}))).hexdigest()
 
 InitializeClass(Selection)
 allow_class(Selection)
diff --git a/product/ERP5Form/Tool/SelectionTool.py b/product/ERP5Form/Tool/SelectionTool.py
index ec459dea08..12f38ef615 100644
--- a/product/ERP5Form/Tool/SelectionTool.py
+++ b/product/ERP5Form/Tool/SelectionTool.py
@@ -39,6 +39,7 @@ from ZTUtils import make_query
 from Products.ERP5Type.Tool.BaseTool import BaseTool
 from Products.ERP5Type import Permissions as ERP5Permissions
 from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
+from Products.ERP5Type.Utils import str2bytes
 from Products.ERP5Form import _dtmldir
 from Products.ERP5Form.Selection import Selection, DomainSelection
 from ZPublisher.HTTPRequest import FileUpload
@@ -1225,10 +1226,7 @@ class SelectionTool( BaseTool, SimpleItem ):
           return None
       # XXX To avoid the difference of the string representations of int and long,
       # convert each element to a string.
-      if six.PY3:
-          return md5(str(sorted(uid_list)).encode()).hexdigest()
-      else:
-          return md5(str(sorted(map(str, uid_list)))).hexdigest()
+      return md5(str2bytes(repr(sorted(str(e) for e in uid_list)))).hexdigest()
 
     # Related document searching
     security.declarePublic('viewSearchRelatedDocumentDialog')
diff --git a/product/ERP5Type/tests/ERP5TypeTestCase.py b/product/ERP5Type/tests/ERP5TypeTestCase.py
index 367e5e0366..c8a21cb2bf 100644
--- a/product/ERP5Type/tests/ERP5TypeTestCase.py
+++ b/product/ERP5Type/tests/ERP5TypeTestCase.py
@@ -943,7 +943,7 @@ class ERP5TypeCommandLineTestCase(ERP5TypeTestCaseMixin):
       forced_portal_id = os.environ.get('erp5_tests_portal_id')
       if forced_portal_id:
         return str(forced_portal_id)
-      m = md5(repr(self.getBusinessTemplateList()) + self.getTitle())
+      m = md5(str2bytes(repr(self.getBusinessTemplateList()) + self.getTitle()))
       return portal_name + '_' + m.hexdigest()
 
     def getPortal(self):
-- 
2.30.9