jellyfin-kodi/resources/lib/UserClient.py
xnappo 4f46debd31 Revert parental control - breaking change
I don't have any restrictions set up and this completely breaks the
addon for me...
2015-05-12 22:24:18 -05:00

388 lines
No EOL
13 KiB
Python

#################################################################################################
# UserClient thread
#################################################################################################
import xbmc
import xbmcgui
import xbmcaddon
import xbmcvfs
import threading
import hashlib
import json as json
import KodiMonitor
import Utils as utils
from ClientInformation import ClientInformation
from DownloadUtils import DownloadUtils
class UserClient(threading.Thread):
# Borg - multiple instances, shared state
_shared_state = {}
clientInfo = ClientInformation()
doUtils = DownloadUtils()
KodiMonitor = KodiMonitor.Kodi_Monitor()
addonName = clientInfo.getAddonName()
addonId = clientInfo.getAddonId()
addon = xbmcaddon.Addon(id=addonId)
WINDOW = xbmcgui.Window(10000)
stopClient = False
logLevel = 0
auth = True
retry = 0
currUser = None
currUserId = None
currServer = None
currToken = None
HasAccess = True
AdditionalUser = []
def __init__(self, *args):
self.__dict__ = self._shared_state
threading.Thread.__init__(self, *args)
def logMsg(self, msg, lvl=1):
className = self.__class__.__name__
utils.logMsg("%s %s" % (self.addonName, className), str(msg), int(lvl))
def getUsername(self):
addon = xbmcaddon.Addon(id=self.addonId)
username = addon.getSetting('username')
if (username == ""):
self.logMsg("No username saved.", 2)
return ""
return username
def getLogLevel(self):
logLevel = int(self.addon.getSetting('logLevel'))
return logLevel
def getUserId(self):
username = self.getUsername()
w_userId = self.WINDOW.getProperty('userId%s' % username)
s_userId = self.addon.getSetting('userId%s' % username)
# Verify the window property
if (w_userId != ""):
self.logMsg("Returning userId from WINDOW for username: %s UserId: %s" % (username, w_userId), 2)
return w_userId
# Verify the settings
elif (s_userId != ""):
self.logMsg("Returning userId from SETTINGS for username: %s userId: %s" % (username, s_userId), 2)
return s_userId
# No userId found
else:
self.logMsg("No userId saved for username: %s." % username)
return
def getServer(self, prefix=True):
# For https support
addon = xbmcaddon.Addon(id=self.addonId)
HTTPS = addon.getSetting('https')
host = addon.getSetting('ipaddress')
port = addon.getSetting('port')
server = host + ":" + port
if host == "":
self.logMsg("No server information saved.", 2)
return ""
# If https is true
if prefix and (HTTPS == "true"):
server = "https://%s" % server
return server
# If https is false
elif prefix and (HTTPS == "false"):
server = "http://%s" % server
return server
# If only the host:port is required
elif (prefix == False):
return server
def getToken(self):
username = self.getUsername()
w_token = self.WINDOW.getProperty('accessToken%s' % username)
s_token = self.addon.getSetting('accessToken')
# Verify the window property
if (w_token != ""):
self.logMsg("Returning accessToken from WINDOW for username: %s accessToken: %s" % (username, w_token), 2)
return w_token
# Verify the settings
elif (s_token != ""):
self.logMsg("Returning accessToken from SETTINGS for username: %s accessToken: %s" % (username, s_token), 2)
self.WINDOW.setProperty('accessToken%s' % username, s_token)
return s_token
else:
self.logMsg("No token found.")
return ""
def getSSLverify(self):
# Verify host certificate
s_sslverify = self.addon.getSetting('sslverify')
if s_sslverify == "true":
return True
else:
return False
def getSSL(self):
# Client side certificate
s_cert = self.addon.getSetting('sslcert')
if s_cert == "None":
return None
else:
return s_cert
def getPublicUsers(self):
server = self.getServer()
# Get public Users
url = "%s/mediabrowser/Users/Public?format=json" % server
result = self.doUtils.downloadUrl(url, authenticate=False)
users = []
if (result != ""):
users = result
else:
# Server connection failed
return False
return users
def hasAccess(self):
url = "{server}/mediabrowser/Users"
result = self.doUtils.downloadUrl(url)
if result is False:
# Access is restricted
self.logMsg("Access is restricted.")
self.HasAccess = False
return
if self.WINDOW.getProperty("Server_status") == "restricted":
self.logMsg("Access is granted.")
self.HasAccess = True
self.WINDOW.setProperty("Server_status", "")
xbmcgui.Dialog().notification("Emby server", "Access is enabled.")
return
def loadCurrUser(self):
WINDOW = self.WINDOW
doUtils = self.doUtils
username = self.getUsername()
# Only to be used if token exists
self.currUserId = self.getUserId()
self.currServer = self.getServer()
self.currToken = self.getToken()
self.ssl = self.getSSLverify()
self.sslcert = self.getSSL()
# Set to windows property
WINDOW.setProperty("currUser", username)
WINDOW.setProperty("accessToken%s" % username, self.currToken)
WINDOW.setProperty("server%s" % username, self.currServer)
WINDOW.setProperty("server_%s" % username, self.getServer(prefix=False))
WINDOW.setProperty("userId%s" % username, self.currUserId)
# Set DownloadUtils values
doUtils.setUsername(username)
doUtils.setUserId(self.currUserId)
doUtils.setServer(self.currServer)
doUtils.setToken(self.currToken)
doUtils.setSSL(self.ssl, self.sslcert)
# Start DownloadUtils session
doUtils.startSession()
self.currUser = username
def authenticate(self):
WINDOW = self.WINDOW
addon = self.addon
username = self.getUsername()
server = self.getServer()
addondir = xbmc.translatePath(self.addon.getAddonInfo('profile'))
hasSettings = xbmcvfs.exists("%ssettings.xml" % addondir)
# If there's no settings.xml
if (hasSettings == 0):
self.logMsg("No settings.xml found.")
self.auth = False
return
# If no user information
if (server == "") or (username == ""):
self.logMsg("Missing server information.")
self.auth = False
return
# If there's a token
if (self.getToken() != ""):
self.loadCurrUser()
self.logMsg("Current user: %s" % self.currUser, 0)
self.logMsg("Current userId: %s" % self.currUserId, 0)
self.logMsg("Current accessToken: %s" % self.currToken, 0)
# parental control - let's verify if access is restricted
self.hasAccess()
return
users = self.getPublicUsers()
password = ""
# Find user in list
for user in users:
name = user[u'Name']
userHasPassword = False
if (unicode(username, 'utf-8') in name):
# Verify if user has a password
if (user.get("HasPassword") == True):
userHasPassword = True
# If user has password
if (userHasPassword):
password = xbmcgui.Dialog().input("Enter password for user: %s" % username, option=xbmcgui.ALPHANUM_HIDE_INPUT)
# If password dialog is cancelled
if (password == ""):
self.logMsg("No password entered.", 0)
self.WINDOW.setProperty("Server_status", "Stop")
self.auth = False
return
break
else:
# Manual login, user is hidden
password = xbmcgui.Dialog().input("Enter password for user: %s" % username, option=xbmcgui.ALPHANUM_HIDE_INPUT)
sha1 = hashlib.sha1(password)
sha1 = sha1.hexdigest()
# Authenticate username and password
url = "%s/mediabrowser/Users/AuthenticateByName?format=json" % server
data = {'username': username, 'password': sha1}
self.logMsg(data, 2)
result = self.doUtils.downloadUrl(url, postBody=data, type="POST", authenticate=False)
accessToken = None
try:
self.logMsg("Auth_Reponse: %s" % result, 1)
accessToken = result[u'AccessToken']
except:
pass
if (result != None and accessToken != None):
self.currUser = username
userId = result[u'User'][u'Id']
addon.setSetting("accessToken", accessToken)
addon.setSetting("userId%s" % username, userId)
self.logMsg("User Authenticated: %s" % accessToken)
self.loadCurrUser()
self.WINDOW.setProperty("Server_status", "")
self.retry = 0
return
else:
self.logMsg("User authentication failed.")
addon.setSetting("accessToken", "")
addon.setSetting("userId%s" % username, "")
xbmcgui.Dialog().ok("Error connecting", "Invalid username or password.")
# Give two attempts at entering password
self.retry += 1
if self.retry == 2:
self.logMsg("Too many retries. You can retry by selecting the option in the addon settings.")
self.WINDOW.setProperty("Server_status", "Stop")
xbmcgui.Dialog().ok("Error connecting", "Failed to authenticate too many times. You can retry by selecting the option in the addon settings.")
self.auth = False
return
def resetClient(self):
if (self.currToken != None):
# In case of 401, removed saved token
self.addon.setSetting("accessToken%s" % self.currUser, "")
self.WINDOW.setProperty("accessToken%s" % self.currUser, "")
self.currToken = None
self.logMsg("User token has been removed.", 1)
self.auth = True
self.currUser = None
return
def run(self):
self.logMsg("|---- Starting UserClient ----|", 0)
while not self.KodiMonitor.abortRequested():
# Get the latest addon settings
self.addon = xbmcaddon.Addon(id=self.addonId)
if (self.WINDOW.getProperty("Server_status") != ""):
status = self.WINDOW.getProperty("Server_status")
if status == "restricted":
# Parental control is restricting access
self.HasAccess = False
elif status == "401":
self.WINDOW.setProperty("Server_status", "Auth")
# Revoked token
self.resetClient()
if self.auth and (self.currUser == None):
status = self.WINDOW.getProperty("Server_status")
if (status == "") or (status == "Auth"):
self.auth = False
self.authenticate()
if (self.auth == False) and (self.currUser == None):
# Only if there's information found to login
server = self.getServer()
username = self.getUsername()
status = self.WINDOW.getProperty("Server_status")
# If user didn't enter a password when prompted
if status == "Stop":
pass
elif (server != "") and (username != ""):
self.logMsg("Server found: %s" % server)
self.logMsg("Username found: %s" % username)
self.auth = True
# If stopping the client didn't work
if self.stopClient == True:
break
if self.KodiMonitor.waitForAbort(1):
# Abort was requested while waiting. We should exit
break
self.logMsg("|---- UserClient Stopped ----|", 0)
def stopClient(self):
# As last resort
self.stopClient = True