Merge branch 'main' into avm99963-monorail

Merged commit 34d8229ae2b51fb1a15bd208e6fe6185c94f6266

GitOrigin-RevId: 7ee0917f93a577e475f8e09526dd144d245593f4
diff --git a/framework/xsrf.py b/framework/xsrf.py
index 75581ef..bc5ae33 100644
--- a/framework/xsrf.py
+++ b/framework/xsrf.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Utility routines for avoiding cross-site-request-forgery."""
 from __future__ import print_function
@@ -9,12 +8,12 @@
 from __future__ import absolute_import
 
 import base64
+import hashlib
 import hmac
-import logging
+import six
 import time
 
 # This is a file in the top-level directory that you must edit before deploying
-import settings
 from framework import framework_constants
 from services import secrets_svc
 
@@ -43,7 +42,7 @@
 XHR_SERVLET_PATH = 'xhr'
 
 
-DELIMITER = ':'
+DELIMITER = b':'
 
 
 def GenerateToken(user_id, servlet_path, token_time=None):
@@ -63,16 +62,16 @@
     ValueError: if the XSRF secret was not configured.
   """
   token_time = token_time or int(time.time())
-  digester = hmac.new(secrets_svc.GetXSRFKey())
-  digester.update(str(user_id))
+  digester = hmac.new(secrets_svc.GetXSRFKey(), digestmod=hashlib.md5)
+  digester.update(six.ensure_binary(str(user_id)))
   digester.update(DELIMITER)
-  digester.update(servlet_path)
+  digester.update(six.ensure_binary(servlet_path))
   digester.update(DELIMITER)
-  digester.update(str(token_time))
+  digester.update(six.ensure_binary(str(token_time)))
   digest = digester.digest()
 
-  token = base64.urlsafe_b64encode('%s%s%d' % (digest, DELIMITER, token_time))
-  return token
+  token = base64.urlsafe_b64encode(b'%s%s%d' % (digest, DELIMITER, token_time))
+  return six.ensure_str(token)
 
 
 def ValidateToken(
@@ -91,7 +90,7 @@
     raise TokenIncorrect('missing token')
 
   try:
-    decoded = base64.urlsafe_b64decode(str(token))
+    decoded = base64.urlsafe_b64decode(six.ensure_binary(token))
     token_time = int(decoded.split(DELIMITER)[-1])
   except (TypeError, ValueError):
     raise TokenIncorrect('could not decode token')
@@ -104,8 +103,14 @@
 
   # Perform constant time comparison to avoid timing attacks
   different = 0
+  # In Python 3, zip(bytes, bytes) gives ints, but in Python 2,
+  # zip(str, str) gives strs. We need to call ord() in Python 2 only.
+  if isinstance(token, six.string_types):
+    token = list(map(ord, token))
+  if isinstance(expected_token, six.string_types):
+    expected_token = list(map(ord, expected_token))
   for x, y in zip(token, expected_token):
-    different |= ord(x) ^ ord(y)
+    different |= x ^ y
   if different:
     raise TokenIncorrect(
         'presented token does not match expected token: %r != %r' % (