[tor-commits] [stem/master] Incorrect filesystem encoding broke latin-1 cookie path

atagar at torproject.org atagar at torproject.org
Sat Aug 22 22:51:08 UTC 2020


commit fbf16826124982add83312969e64ef6460571f2f
Author: Damian Johnson <atagar at torproject.org>
Date:   Sat Aug 22 15:48:47 2020 -0700

    Incorrect filesystem encoding broke latin-1 cookie path
    
    When a PROTOCOLINFO's authentication cookie path mismatches our filesystem
    encoding falling back to a couple common encodings (unicode and latin-1).
    
      https://github.com/torproject/stem/issues/57
---
 docs/change_log.rst                |  1 +
 stem/response/protocolinfo.py      | 16 ++++++++++++++--
 test/unit/response/protocolinfo.py | 17 +++++++++++++++++
 3 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/docs/change_log.rst b/docs/change_log.rst
index 59319e3c..abdbb0c9 100644
--- a/docs/change_log.rst
+++ b/docs/change_log.rst
@@ -58,6 +58,7 @@ The following are only available within Stem's `git repository
 
   * Socket based control connections often raised BrokenPipeError when closed
   * Added :func:`~stem.control.Controller.add_hidden_service_auth`, :func:`~stem.control.Controller.remove_hidden_service_auth`, and :func:`~stem.control.Controller.list_hidden_service_auth` to the :class:`~stem.control.Controller`
+  * Incorrect filesystem encoding broke latin-1 cookie path (:ticket:`57`)
 
  * **Descriptors**
 
diff --git a/stem/response/protocolinfo.py b/stem/response/protocolinfo.py
index c1387fab..65cb2d8c 100644
--- a/stem/response/protocolinfo.py
+++ b/stem/response/protocolinfo.py
@@ -108,8 +108,20 @@ class ProtocolInfoResponse(stem.response.ControlMessage):
         # parse optional COOKIEFILE mapping (quoted and can have escapes)
 
         if line.is_next_mapping('COOKIEFILE', True, True):
-          self.cookie_path = line._pop_mapping_bytes(True, True)[1].decode(sys.getfilesystemencoding())
-          self.cookie_path = stem.util.str_tools._to_unicode(self.cookie_path)  # normalize back to str
+          path = line._pop_mapping_bytes(True, True)[1]
+
+          # re-encode this path from our filesystem's encoding (with common
+          # fallbacks) to unicode
+
+          for encoding in set([sys.getfilesystemencoding(), 'utf-8', 'latin-1']):
+            try:
+              self.cookie_path = stem.util.str_tools._to_unicode(path.decode(encoding))
+              break
+            except ValueError:
+              pass
+
+          if self.cookie_path is None:
+            raise stem.ProtocolError("Cookie path '%s' mismatches our filesystem encoding (%s)" % (repr(path), sys.getfilesystemencoding()))
       elif line_type == 'VERSION':
         # Line format:
         #   VersionLine = "250-VERSION" SP "Tor=" TorVersion OptArguments CRLF
diff --git a/test/unit/response/protocolinfo.py b/test/unit/response/protocolinfo.py
index a71746c9..69c54413 100644
--- a/test/unit/response/protocolinfo.py
+++ b/test/unit/response/protocolinfo.py
@@ -56,6 +56,13 @@ RELATIVE_COOKIE_PATH = r"""250-PROTOCOLINFO 1
 
 EXPECTED_UNICODE_PATH = b"/home/user/\346\226\207\346\241\243/tor-browser_en-US/Browser/TorBrowser/Data/Tor/control_auth_cookie".decode('utf-8')
 
+LATIN_COOKIE_PATH = r"""250-PROTOCOLINFO 1
+250-AUTH METHODS=COOKIE,SAFECOOKIE COOKIEFILE="c:\\Drive-E\\Web\\Today\\ZeroNet-win-dist-win64 \341rv\355zt\373r\365 t\374k\366rf\372r\363g\351p\\ZeroNet-win-dist-win64\\core\\tools\\tor\\data\\control_auth_cookie"
+250-VERSION Tor="0.4.2.6"
+250 OK"""
+
+EXPECTED_LATIN_PATH = b"c:\\Drive-E\\Web\\Today\\ZeroNet-win-dist-win64 \341rv\355zt\373r\365 t\374k\366rf\372r\363g\351p\\ZeroNet-win-dist-win64\\core\\tools\\tor\\data\\control_auth_cookie".decode('latin-1')
+
 
 class TestProtocolInfoResponse(unittest.TestCase):
   def test_convert(self):
@@ -151,3 +158,13 @@ class TestProtocolInfoResponse(unittest.TestCase):
 
     control_message = ControlMessage.from_str(UNICODE_COOKIE_PATH, 'PROTOCOLINFO', normalize = True)
     self.assertEqual(EXPECTED_UNICODE_PATH, control_message.cookie_path)
+
+  @patch('sys.getfilesystemencoding', Mock(return_value = 'UTF-8'))
+  def test_latin_cookie_path(self):
+    """
+    Parse a latin-1 path when our filesystem is configured for unicode.
+    (:ticket:`57`)
+    """
+
+    control_message = ControlMessage.from_str(LATIN_COOKIE_PATH, 'PROTOCOLINFO', normalize = True)
+    self.assertEqual(EXPECTED_LATIN_PATH, control_message.cookie_path)



More information about the tor-commits mailing list