jellyfin-kodi/resources/lib/userclient.py
angelblue05 bec267bfe4 Update ssl
Allow to disable verification for self signed cert.
2018-06-10 16:43:23 -05:00

312 lines
9.9 KiB
Python

# -*- coding: utf-8 -*-
##################################################################################################
import json
import logging
import threading
import xbmc
import xbmcgui
import artwork
import connectmanager
import downloadutils
import read_embyserver as embyserver
from utils import window, settings, language as lang
##################################################################################################
log = logging.getLogger("EMBY."+__name__)
##################################################################################################
class UserClient(threading.Thread):
_shared_state = {} # Borg
_stop_thread = False
_user = None
_server = None
_auth = True
_has_access = True
def __init__(self):
self.__dict__ = self._shared_state
self.doutils = downloadutils.DownloadUtils()
self.emby = embyserver.Read_EmbyServer()
self.connectmanager = connectmanager.ConnectManager()
threading.Thread.__init__(self)
@classmethod
def get_username(cls):
return settings('username') or settings('connectUsername') or None
def get_user(self, data=None):
if data is not None:
self._user = data
self._set_user_server()
return self._user
def get_server_details(self):
return self._server
@classmethod
def get_server(cls):
return settings('server') or None
def verify_server(self):
try:
url = "%s/emby/system/info/public?format=json" % self.get_server() # tried system/public but can't get reliable response from the server?
self.doutils.downloadUrl(url, authenticate=False)
return True
except Exception as error:
# Server connection failed
return False
@classmethod
def get_ssl(cls):
"""
Returns boolean value or path to certificate
True: Verify ssl
False: Don't verify connection
"""
return settings('sslverify') == "true"
def get_access(self):
if not self._has_access:
self._set_access()
return self._has_access
def _set_access(self):
try:
self.doutils.downloadUrl("{server}/emby/Users?format=json")
except Exception as error:
if self._has_access and "restricted" in error:
self._has_access = False
log.info("access is restricted")
else:
if not self._has_access:
self._has_access = True
window('emby_serverStatus', clear=True)
log.info("access is granted")
xbmcgui.Dialog().notification(lang(29999), lang(33007))
@classmethod
def get_userid(cls):
###$ Begin migration $###
if settings('userId') == "":
settings('userId', value=settings('userId%s' % settings('username')))
log.info("userid migration completed")
###$ End migration $###
return settings('userId') or None
@classmethod
def get_token(cls):
###$ Begin migration $###
if settings('token') == "":
settings('token', value=settings('accessToken'))
log.info("token migration completed")
###$ End migration $###
return settings('token') or None
def _set_user_server(self):
user = self.doutils.downloadUrl("{server}/emby/Users/{UserId}?format=json")
settings('username', value=user['Name'])
self._user = user
window('emby.userinfo.json', user)
if "PrimaryImageTag" in self._user:
window('EmbyUserImage',
value=artwork.Artwork().get_user_artwork(self._user['Id'], 'Primary'))
self._server = self.doutils.downloadUrl("{server}/emby/System/Configuration?format=json")
settings('markPlayed', value=str(self._server['MaxResumePct']))
def _authenticate(self):
if not self.get_server() or not self.get_username():
log.info('missing server or user information')
self._auth = False
elif self.get_token():
try:
self._load_user()
except Exception as error:
if "401" in error:
log.info("token is invalid")
self._reset_client()
else:
log.info("current user: %s", self.get_username())
log.info("current userid: %s", self.get_userid())
log.debug("current token: %s", self.get_token())
return
##### AUTHENTICATE USER #####
server = self.get_server()
username = self.get_username().decode('utf-8')
try:
user = self.connectmanager.login_manual(server, username)
except RuntimeError:
window('emby_serverStatus', value="stop")
self._auth = False
return
else:
log.info("user: %s", user)
settings('username', value=user['User']['Name'])
settings('token', value=user['AccessToken'])
settings('userId', value=user['User']['Id'])
xbmcgui.Dialog().notification(lang(29999),
"%s %s!" % (lang(33000), username))
self._load_user(authenticated=True)
window('emby_serverStatus', clear=True)
def _load_user(self, authenticated=False):
doutils = self.doutils
userid = self.get_userid()
server = self.get_server()
token = self.get_token()
# Set properties
# TODO: Remove old reference once code converted
window('emby_currUser', value=userid)
window('emby_server%s' % userid, value=server)
window('emby_accessToken%s' % userid, value=token)
server_json = {
'UserId': userid,
'Server': server,
'ServerId': settings('serverId'),
'Token': token,
'SSL': self.get_ssl()
}
# Set downloadutils.py values
doutils.set_session(**server_json)
# Test the validity of the current token
if not authenticated:
try:
self.doutils.downloadUrl("{server}/emby/Users/{UserId}?format=json")
except Exception as error:
if "401" in error:
# Token is not longer valid
raise
# verify user access
self._set_access()
# Start downloadutils.py session
doutils.start_session()
# Set _user and _server
self._set_user_server()
def post_capabilities(self):
log.info("post capabilities")
self.doutils.post_capabilities()
def load_connect_servers(self):
# Set connect servers
if not settings('connectUsername'):
return
servers = self.connectmanager.get_connect_servers()
added_servers = []
for server in servers:
if server['Id'] != settings('serverId'):
# TODO: SSL setup
self.doutils.add_server(server, False)
added_servers.append(server['Id'])
# Set properties
log.info(added_servers)
window('emby_servers.json', value=added_servers)
def _reset_client(self):
log.info("reset UserClient authentication")
settings('accessToken', value="")
window('emby_accessToken', clear=True)
log.info("user token revoked.")
self._user = None
self.auth = None
current_state = self.connectmanager.get_state()
for server in current_state['Servers']:
if server['Id'] == settings('serverId'):
# Update token
server['AccessToken'] = None
self.connectmanager.update_token(server)
def run(self):
monitor = xbmc.Monitor()
log.warn("----====# Starting UserClient #====----")
while not self._stop_thread:
status = window('emby_serverStatus')
if status:
# Verify the connection status to server
if status == "restricted":
# Parental control is restricting access
self._has_access = False
elif status == "401":
# Unauthorized access, revoke token
window('emby_serverStatus', value="auth")
self._reset_client()
if self._auth and self._user is None:
# Try to authenticate user
status = window('emby_serverStatus')
if not status or status == "auth":
# Set auth flag because we no longer need
# to authenticate the user
self._auth = False
self._authenticate()
if not self._auth and self._user is None:
# If authenticate failed.
server = self.get_server()
username = self.get_username()
status = window('emby_serverStatus')
# The status Stop is for when user cancelled password dialog.
if server and username and status != "stop":
# Only if there's information found to login
log.info("Server found: %s", server)
log.info("Username found: %s", username)
self._auth = True
if monitor.waitForAbort(2):
# Abort was requested while waiting. We should exit
break
self.doutils.stop_session()
log.warn("#====---- UserClient Stopped ----====#")
def stop_client(self):
self._stop_thread = True