Merge pull request #703 from croneter/fix-websocket

Allow websocket redirects. Never allow insecure HTTPs connections for Kodi Leia
This commit is contained in:
croneter 2019-02-05 18:59:04 +01:00 committed by GitHub
commit d8770603ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 51 additions and 16 deletions

View file

@ -105,6 +105,19 @@ class WebSocketTimeoutException(WebSocketException):
pass pass
class WebsocketRedirect(WebSocketException):
"""
WebsocketRedirect will be raised if a status code 301 is returned
The Exception will be instantiated with a dict containing all response
headers; which should contain the redirect address under the key 'location'
Access the headers via the attribute headers
"""
def __init__(self, headers):
self.headers = headers
super(WebsocketRedirect, self).__init__()
DEFAULT_TIMEOUT = None DEFAULT_TIMEOUT = None
TRACE_ENABLED = False TRACE_ENABLED = False
@ -162,10 +175,10 @@ def _parse_url(url):
port = parsed.port port = parsed.port
is_secure = False is_secure = False
if scheme == "ws": if scheme == "ws" or scheme == 'http':
if not port: if not port:
port = 80 port = 80
elif scheme == "wss": elif scheme == "wss" or scheme == 'https':
is_secure = True is_secure = True
if not port: if not port:
port = 443 port = 443
@ -500,6 +513,9 @@ class WebSocket(object):
LOG.debug("-----------------------") LOG.debug("-----------------------")
status, resp_headers = self._read_headers() status, resp_headers = self._read_headers()
if status == 301:
# Redirect
raise WebsocketRedirect(resp_headers)
if status != 101: if status != 101:
self.close() self.close()
raise WebSocketException("Handshake Status %d" % status) raise WebSocketException("Handshake Status %d" % status)

View file

@ -18,6 +18,7 @@ class WebSocket(backgroundthread.KillableThread):
def __init__(self): def __init__(self):
self.ws = None self.ws = None
self.redirect_uri = None
super(WebSocket, self).__init__() super(WebSocket, self).__init__()
def process(self, opcode, message): def process(self, opcode, message):
@ -91,6 +92,16 @@ class WebSocket(backgroundthread.KillableThread):
self.__class__.__name__) self.__class__.__name__)
self.ws = None self.ws = None
app.APP.monitor.waitForAbort(1) app.APP.monitor.waitForAbort(1)
except websocket.WebsocketRedirect as e:
LOG.info('301 redirect detected')
self.redirect_uri = e.headers.get('location', e.headers.get('Location'))
if self.redirect_uri:
self.redirect_uri.decode('utf-8')
counter += 1
if counter >= 10:
LOG.info('%s: Repeated WebsocketRedirect detected. Stopping now',
self.__class__.__name__)
break
except websocket.WebSocketException as e: except websocket.WebSocketException as e:
LOG.info('%s: WebSocketException: %s', LOG.info('%s: WebSocketException: %s',
self.__class__.__name__, e) self.__class__.__name__, e)
@ -141,18 +152,22 @@ class PMS_Websocket(WebSocket):
app.SYNC.background_sync_disabled) app.SYNC.background_sync_disabled)
def getUri(self): def getUri(self):
server = app.CONN.server if self.redirect_uri:
# Get the appropriate prefix for the websocket uri = self.redirect_uri
if server.startswith('https'): self.redirect_uri = None
server = "wss%s" % server[5:]
else: else:
server = "ws%s" % server[4:] server = app.CONN.server
uri = "%s/:/websockets/notifications" % server # Get the appropriate prefix for the websocket
# Need to use plex.tv token, if any. NOT user token if server.startswith('https'):
if app.ACCOUNT.plex_token: server = "wss%s" % server[5:]
uri += '?X-Plex-Token=%s' % app.ACCOUNT.plex_token else:
server = "ws%s" % server[4:]
uri = "%s/:/websockets/notifications" % server
# Need to use plex.tv token, if any. NOT user token
if app.ACCOUNT.plex_token:
uri += '?X-Plex-Token=%s' % app.ACCOUNT.plex_token
sslopt = {} sslopt = {}
if utils.settings('sslverify') == "false": if v.KODIVERSION == 17 and utils.settings('sslverify') == "false":
sslopt["cert_reqs"] = CERT_NONE sslopt["cert_reqs"] = CERT_NONE
LOG.debug("%s: Uri: %s, sslopt: %s", LOG.debug("%s: Uri: %s, sslopt: %s",
self.__class__.__name__, uri, sslopt) self.__class__.__name__, uri, sslopt)
@ -209,10 +224,14 @@ class Alexa_Websocket(WebSocket):
app.ACCOUNT.restricted_user) app.ACCOUNT.restricted_user)
def getUri(self): def getUri(self):
uri = ('wss://pubsub.plex.tv/sub/websockets/%s/%s?X-Plex-Token=%s' if self.redirect_uri:
% (app.ACCOUNT.plex_user_id, uri = self.redirect_uri
v.PKC_MACHINE_IDENTIFIER, self.redirect_uri = None
app.ACCOUNT.plex_token)) else:
uri = ('wss://pubsub.plex.tv/sub/websockets/%s/%s?X-Plex-Token=%s'
% (app.ACCOUNT.plex_user_id,
v.PKC_MACHINE_IDENTIFIER,
app.ACCOUNT.plex_token))
sslopt = {} sslopt = {}
LOG.debug("%s: Uri: %s, sslopt: %s", LOG.debug("%s: Uri: %s, sslopt: %s",
self.__class__.__name__, uri, sslopt) self.__class__.__name__, uri, sslopt)