From 5a7d997da24ebac55a2bba8b801bcccfdeb42027 Mon Sep 17 00:00:00 2001 From: croneter Date: Fri, 13 Sep 2019 21:17:13 +0200 Subject: [PATCH] Correctly escape URLs for Direct Paths --- resources/lib/plex_api/media.py | 8 +------- resources/lib/service_entry.py | 1 + resources/lib/utils.py | 21 +++++++++++++++++++-- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/resources/lib/plex_api/media.py b/resources/lib/plex_api/media.py index b65b29a9..3c7bf72b 100644 --- a/resources/lib/plex_api/media.py +++ b/resources/lib/plex_api/media.py @@ -332,13 +332,7 @@ class Media(object): if path.startswith('\\\\'): path = 'smb:' + path.replace('\\', '/') if app.SYNC.escape_path: - try: - protocol, hostname, args = path.split(':', 2) - except ValueError: - pass - else: - args = utils.quote(args) - path = '%s:%s:%s' % (protocol, hostname, args) + path = utils.escape_path(path) if (app.SYNC.path_verified and not force_check) or omit_check: return path diff --git a/resources/lib/service_entry.py b/resources/lib/service_entry.py index e319d67a..c5f772ba 100644 --- a/resources/lib/service_entry.py +++ b/resources/lib/service_entry.py @@ -55,6 +55,7 @@ class Service(object): LOG.info("%s Version: %s", v.ADDON_NAME, v.ADDON_VERSION) LOG.info("PKC Direct Paths: %s", utils.settings('useDirectPaths') == '1') + LOG.info("Escape paths: %s", utils.settings('escapePath') == 'true') LOG.info("Synching Plex artwork to Kodi: %s", utils.settings('usePlexArtwork') == 'true') LOG.info("Number of sync threads: %s", diff --git a/resources/lib/utils.py b/resources/lib/utils.py index ad2d25ce..772441db 100644 --- a/resources/lib/utils.py +++ b/resources/lib/utils.py @@ -54,6 +54,8 @@ REGEX_MUSICPATH = re.compile(r'''^\^(.+)\$$''') # Grab Plex id from an URL-encoded string REGEX_PLEX_ID_FROM_URL = re.compile(r'''metadata%2F(\d+)''') +SAFE_URL_CHARACTERS = "%/:=&?~#+!$,;'@()*[]".encode('utf-8') + def garbageCollect(): gc.collect(2) @@ -373,6 +375,21 @@ def urlparse(url, scheme='', allow_fragments=True): return _urlparse.urlparse(url, scheme, allow_fragments) +def escape_path(path): + """ + Uses urllib.quote to escape to escape path [unicode]. See here for the + reasoning whether a character is safe or not and whether or not it should + be escaped: + https://bugs.python.org/issue918368 + Letters, digits, and the characters '_.-' are never quoted. Choosing the + "wrong" characters for a password for USERNAME:PASSWORD@host.com will get + you in trouble (e.g. '@') + Returns the escaped path as unicode + """ + return urllib.quote(path.encode('utf-8'), + safe=SAFE_URL_CHARACTERS).decode('utf-8') + + def quote(s, safe='/'): """ unicode-safe way to use urllib.quote(). Pass in either str or unicode @@ -380,7 +397,7 @@ def quote(s, safe='/'): """ if isinstance(s, unicode): s = s.encode('utf-8') - s = urllib.quote(s, safe) + s = urllib.quote(s, safe.encode('utf-8')) return s.decode('utf-8') @@ -391,7 +408,7 @@ def quote_plus(s, safe=''): """ if isinstance(s, unicode): s = s.encode('utf-8') - s = urllib.quote_plus(s, safe) + s = urllib.quote_plus(s, safe.encode('utf-8')) return s.decode('utf-8')