mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-15 01:32:57 -07:00
Add Plex OAuth to login page
This commit is contained in:
parent
b49e500221
commit
3bd1b03faf
4 changed files with 273 additions and 63 deletions
|
@ -3470,6 +3470,9 @@ a.no-highlight:hover {
|
||||||
max-width: 1170px;
|
max-width: 1170px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.login-body-container {
|
||||||
|
margin: 50px 0;
|
||||||
|
}
|
||||||
.login-container {
|
.login-container {
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
@ -3512,6 +3515,30 @@ a.no-highlight:hover {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.login-divider {
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 1px solid #555;
|
||||||
|
line-height: 0.1em;
|
||||||
|
margin: 50px auto;
|
||||||
|
max-width: 400px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.login-divider span {
|
||||||
|
background: #1f1f1f;
|
||||||
|
padding: 0 15px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.login-button-plex {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.login-button-plex button#sign-in-plex {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
.login-alert {
|
||||||
|
text-align: center;
|
||||||
|
padding: 8px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
#admin-login-modal .form-group label {
|
#admin-login-modal .form-group label {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: #999;
|
color: #999;
|
||||||
|
|
|
@ -32,20 +32,22 @@
|
||||||
<meta name="msapplication-config" content="${http_root}images/favicon/browserconfig.xml?v=2.0.5">
|
<meta name="msapplication-config" content="${http_root}images/favicon/browserconfig.xml?v=2.0.5">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body style="margin: 0; overflow: auto;">
|
||||||
<div class="body-container">
|
<div class="login-body-container">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="login-container">
|
<div class="login-container">
|
||||||
<div class="login-logo">
|
<div class="login-logo">
|
||||||
<img src="${http_root}images/logo-tautulli-100.png" height="100" alt="PlexPy">
|
<img src="${http_root}images/logo-tautulli-100.png" height="100" alt="PlexPy">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6 col-sm-offset-3">
|
||||||
|
<div id="sign-in-alert" class="alert alert-danger login-alert"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-6 col-sm-offset-3">
|
<div class="col-sm-6 col-sm-offset-3">
|
||||||
<form id="login-form">
|
<form id="login-form">
|
||||||
<div id="incorrect-login" class="alert alert-danger" style="text-align: center; padding: 8px; display: none;">
|
|
||||||
Incorrect username or password.
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="username" class="control-label">
|
<label for="username" class="control-label">
|
||||||
Username
|
Username
|
||||||
|
@ -69,6 +71,19 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="login-divider"><span>or</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6 col-sm-offset-3">
|
||||||
|
<div id="sign-in-plex-alert" class="alert alert-danger login-alert"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6 col-sm-offset-3 login-button-plex">
|
||||||
|
<button id="sign-in-plex" class="btn btn-bright login-button"><i class="fa fa-sign-in"></i> Sign In with Plex</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -78,25 +93,91 @@
|
||||||
<script>
|
<script>
|
||||||
$('#login-form').submit(function(event) {
|
$('#login-form').submit(function(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
$('#sign-in').prop('disabled', true).html('<i class="fa fa-refresh fa-spin"></i> Sign In');
|
signIn(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
function signIn(plex, token) {
|
||||||
|
$('.login-container button').prop('disabled', true);
|
||||||
|
if (plex) {
|
||||||
|
$('#sign-in-plex').html('<i class="fa fa-refresh fa-spin"></i> Sign In with Plex');
|
||||||
|
} else {
|
||||||
|
$('#sign-in').html('<i class="fa fa-refresh fa-spin"></i> Sign In');
|
||||||
|
}
|
||||||
|
|
||||||
|
const username = plex ? null : $('#username').val();
|
||||||
|
const password = plex ? null : $('#password').val();
|
||||||
|
const remember_me = $('#remember_me').is(':checked') ? '1' : '0';
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '${http_root}auth/signin',
|
url: '${http_root}auth/signin',
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
data: $(this).serialize(),
|
data: {
|
||||||
|
username: username,
|
||||||
|
password: password,
|
||||||
|
token: token,
|
||||||
|
remember_me: remember_me
|
||||||
|
},
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
statusCode: {
|
statusCode: {
|
||||||
200: function() {
|
200: function() {
|
||||||
window.location = "${redirect_uri or http_root}";
|
window.location = "${redirect_uri or http_root}";
|
||||||
},
|
},
|
||||||
401: function() {
|
401: function() {
|
||||||
$('#incorrect-login').show();
|
if (plex) {
|
||||||
$('#username').focus();
|
$('#sign-in-plex-alert').text('Invalid Plex Login.').show();
|
||||||
|
} else {
|
||||||
|
$('#sign-in-alert').text('Incorrect username or password.').show();
|
||||||
|
$('#username').focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
complete: function() {
|
complete: function() {
|
||||||
$('#sign-in').prop('disabled', false).html('<i class="fa fa-sign-in"></i> Sign In');
|
$('.login-container button').prop('disabled', false);
|
||||||
|
if (plex) {
|
||||||
|
$('#sign-in-plex').html('<i class="fa fa-sign-in"></i> Sign In with Plex');
|
||||||
|
} else {
|
||||||
|
$('#sign-in').html('<i class="fa fa-sign-in"></i> Sign In');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getPlexOAuthURL = function () {
|
||||||
|
var deferred = $.Deferred();
|
||||||
|
$.get('get_plex_oauth_url').then(function (data) {
|
||||||
|
deferred.resolve(data);
|
||||||
|
});
|
||||||
|
return deferred;
|
||||||
|
};
|
||||||
|
|
||||||
|
$('#sign-in-plex').click(function() {
|
||||||
|
getPlexOAuthURL().then(function (data) {
|
||||||
|
var url = data.url;
|
||||||
|
var pin = data.pin;
|
||||||
|
var polling = true;
|
||||||
|
|
||||||
|
window.open(url);
|
||||||
|
|
||||||
|
(function poll() {
|
||||||
|
setTimeout(function () {
|
||||||
|
$.ajax({
|
||||||
|
url: 'pin/' + pin,
|
||||||
|
success: function (data) {
|
||||||
|
if (data.result === 'success'){
|
||||||
|
polling = false;
|
||||||
|
signIn(true, data.token)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
complete: function () {
|
||||||
|
if (polling){
|
||||||
|
poll();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
timeout: 1000
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
})();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -226,6 +226,45 @@ class PlexTV(object):
|
||||||
|
|
||||||
return server_token
|
return server_token
|
||||||
|
|
||||||
|
def get_plextv_pin(self, pin='', output_format=''):
|
||||||
|
if pin:
|
||||||
|
uri = '/api/v2/pins/' + pin
|
||||||
|
request = self.request_handler.make_request(uri=uri,
|
||||||
|
request_type='GET',
|
||||||
|
output_format=output_format,
|
||||||
|
no_token=True)
|
||||||
|
else:
|
||||||
|
uri = '/api/v2/pins?strong=true'
|
||||||
|
request = self.request_handler.make_request(uri=uri,
|
||||||
|
request_type='POST',
|
||||||
|
output_format=output_format,
|
||||||
|
no_token=True)
|
||||||
|
return request
|
||||||
|
|
||||||
|
def get_pin(self, pin=''):
|
||||||
|
plextv_response = self.get_plextv_pin(pin=pin,
|
||||||
|
output_format='xml')
|
||||||
|
|
||||||
|
if plextv_response:
|
||||||
|
try:
|
||||||
|
xml_head = plextv_response.getElementsByTagName('pin')
|
||||||
|
if xml_head:
|
||||||
|
pin = {'id': xml_head[0].getAttribute('id'),
|
||||||
|
'code': xml_head[0].getAttribute('code'),
|
||||||
|
'token': xml_head[0].getAttribute('authToken')
|
||||||
|
}
|
||||||
|
return pin
|
||||||
|
else:
|
||||||
|
logger.warn(u"Tautulli PlexTV :: Could not get Plex authentication pin.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_pin: %s." % e)
|
||||||
|
return None
|
||||||
|
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
def get_plextv_user_data(self):
|
def get_plextv_user_data(self):
|
||||||
plextv_response = self.get_plex_auth(output_format='dict')
|
plextv_response = self.get_plex_auth(output_format='dict')
|
||||||
|
|
||||||
|
@ -819,3 +858,28 @@ class PlexTV(object):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_plex_account_details(self):
|
||||||
|
account_data = self.get_plextv_user_details(output_format='xml')
|
||||||
|
|
||||||
|
try:
|
||||||
|
xml_head = account_data.getElementsByTagName('user')
|
||||||
|
except Exception as e:
|
||||||
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_plex_account_details: %s." % e)
|
||||||
|
return None
|
||||||
|
|
||||||
|
for a in xml_head:
|
||||||
|
account_details = {"user_id": helpers.get_xml_attr(a, 'id'),
|
||||||
|
"username": helpers.get_xml_attr(a, 'username'),
|
||||||
|
"thumb": helpers.get_xml_attr(a, 'thumb'),
|
||||||
|
"email": helpers.get_xml_attr(a, 'email'),
|
||||||
|
"is_home_user": helpers.get_xml_attr(a, 'home'),
|
||||||
|
"is_restricted": helpers.get_xml_attr(a, 'restricted'),
|
||||||
|
"filter_all": helpers.get_xml_attr(a, 'filterAll'),
|
||||||
|
"filter_movies": helpers.get_xml_attr(a, 'filterMovies'),
|
||||||
|
"filter_tv": helpers.get_xml_attr(a, 'filterTelevision'),
|
||||||
|
"filter_music": helpers.get_xml_attr(a, 'filterMusic'),
|
||||||
|
"filter_photos": helpers.get_xml_attr(a, 'filterPhotos'),
|
||||||
|
"user_token": helpers.get_xml_attr(a, 'authToken')
|
||||||
|
}
|
||||||
|
return account_details
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
# Session tool to be loaded.
|
# Session tool to be loaded.
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import re
|
|
||||||
from urllib import quote, unquote
|
from urllib import quote, unquote
|
||||||
|
|
||||||
import cherrypy
|
import cherrypy
|
||||||
|
@ -37,17 +36,27 @@ JWT_ALGORITHM = 'HS256'
|
||||||
JWT_COOKIE_NAME = 'tautulli_token_'
|
JWT_COOKIE_NAME = 'tautulli_token_'
|
||||||
|
|
||||||
|
|
||||||
def user_login(username=None, password=None):
|
def user_login(username=None, password=None, token=None):
|
||||||
if not username or not password:
|
user_token = None
|
||||||
return None
|
user_id = None
|
||||||
|
|
||||||
# Try to login to Plex.tv to check if the user has a vaild account
|
# Try to login to Plex.tv to check if the user has a vaild account
|
||||||
plex_tv = PlexTV(username=username, password=password)
|
if username and password:
|
||||||
plex_user = plex_tv.get_token()
|
plex_tv = PlexTV(username=username, password=password)
|
||||||
if plex_user:
|
plex_user = plex_tv.get_token()
|
||||||
user_token = plex_user['auth_token']
|
if plex_user:
|
||||||
user_id = plex_user['user_id']
|
user_token = plex_user['auth_token']
|
||||||
|
user_id = plex_user['user_id']
|
||||||
|
elif token:
|
||||||
|
plex_tv = PlexTV(token=token)
|
||||||
|
plex_user = plex_tv.get_plex_account_details()
|
||||||
|
if plex_user:
|
||||||
|
user_token = token
|
||||||
|
user_id = plex_user['user_id']
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if user_token and user_id:
|
||||||
# Try to retrieve the user from the database.
|
# Try to retrieve the user from the database.
|
||||||
# Also make sure guest access is enabled for the user and the user is not deleted.
|
# Also make sure guest access is enabled for the user and the user is not deleted.
|
||||||
user_data = Users()
|
user_data = Users()
|
||||||
|
@ -57,7 +66,7 @@ def user_login(username=None, password=None):
|
||||||
return None
|
return None
|
||||||
elif plexpy.CONFIG.HTTP_PLEX_ADMIN and user_details['is_admin']:
|
elif plexpy.CONFIG.HTTP_PLEX_ADMIN and user_details['is_admin']:
|
||||||
# Plex admin login
|
# Plex admin login
|
||||||
return 'admin'
|
return user_details, 'admin'
|
||||||
elif not user_details['allow_guest'] or user_details['deleted_user']:
|
elif not user_details['allow_guest'] or user_details['deleted_user']:
|
||||||
# Guest access is disabled or the user is deleted.
|
# Guest access is disabled or the user is deleted.
|
||||||
return None
|
return None
|
||||||
|
@ -75,49 +84,64 @@ def user_login(username=None, password=None):
|
||||||
# Register the new user / update the access tokens.
|
# Register the new user / update the access tokens.
|
||||||
monitor_db = MonitorDatabase()
|
monitor_db = MonitorDatabase()
|
||||||
try:
|
try:
|
||||||
logger.debug(u"Tautulli WebAuth :: Regestering tokens for user '%s' in the database." % username)
|
logger.debug(u"Tautulli WebAuth :: Regestering tokens for user '%s' in the database."
|
||||||
result = monitor_db.action('UPDATE users SET user_token = ?, server_token = ? WHERE user_id = ?',
|
% user_details['username'])
|
||||||
[user_token, server_token, user_id])
|
result = monitor_db.action('UPDATE users SET server_token = ? WHERE user_id = ?',
|
||||||
|
[server_token, user_details['user_id']])
|
||||||
|
|
||||||
if result:
|
if result:
|
||||||
# Refresh the users list to make sure we have all the correct permissions.
|
# Refresh the users list to make sure we have all the correct permissions.
|
||||||
refresh_users()
|
refresh_users()
|
||||||
# Successful login
|
# Successful login
|
||||||
return 'guest'
|
return user_details, 'guest'
|
||||||
else:
|
else:
|
||||||
logger.warn(u"Tautulli WebAuth :: Unable to register user '%s' in database." % username)
|
logger.warn(u"Tautulli WebAuth :: Unable to register user '%s' in database."
|
||||||
|
% user_details['username'])
|
||||||
return None
|
return None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"Tautulli WebAuth :: Unable to register user '%s' in database: %s." % (username, e))
|
logger.warn(u"Tautulli WebAuth :: Unable to register user '%s' in database: %s."
|
||||||
|
% (user_details['username'], e))
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
logger.warn(u"Tautulli WebAuth :: Unable to retrieve Plex.tv server token for user '%s'." % username)
|
logger.warn(u"Tautulli WebAuth :: Unable to retrieve Plex.tv server token for user '%s'."
|
||||||
|
% user_details['username'])
|
||||||
return None
|
return None
|
||||||
else:
|
elif username:
|
||||||
logger.warn(u"Tautulli WebAuth :: Unable to retrieve Plex.tv user token for user '%s'." % username)
|
logger.warn(u"Tautulli WebAuth :: Unable to retrieve Plex.tv user token for user '%s'." % username)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return None
|
elif token:
|
||||||
|
logger.warn(u"Tautulli WebAuth :: Unable to retrieve Plex.tv user token for Plex OAuth.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def check_credentials(username, password, admin_login='0'):
|
def check_credentials(username=None, password=None, token=None, admin_login='0'):
|
||||||
"""Verifies credentials for username and password.
|
"""Verifies credentials for username and password.
|
||||||
Returns True and the user group on success or False and no user group"""
|
Returns True and the user group on success or False and no user group"""
|
||||||
|
|
||||||
if plexpy.CONFIG.HTTP_PASSWORD:
|
if username and password:
|
||||||
if plexpy.CONFIG.HTTP_HASHED_PASSWORD and \
|
if plexpy.CONFIG.HTTP_PASSWORD:
|
||||||
username == plexpy.CONFIG.HTTP_USERNAME and check_hash(password, plexpy.CONFIG.HTTP_PASSWORD):
|
user_details = {'user_id': None, 'username': username}
|
||||||
return True, 'tautulli admin'
|
|
||||||
elif not plexpy.CONFIG.HTTP_HASHED_PASSWORD and \
|
|
||||||
username == plexpy.CONFIG.HTTP_USERNAME and password == plexpy.CONFIG.HTTP_PASSWORD:
|
|
||||||
return True, 'tautulli admin'
|
|
||||||
|
|
||||||
if plexpy.CONFIG.HTTP_PLEX_ADMIN or (not admin_login == '1' and plexpy.CONFIG.ALLOW_GUEST_ACCESS):
|
if plexpy.CONFIG.HTTP_HASHED_PASSWORD and \
|
||||||
plex_login = user_login(username, password)
|
username == plexpy.CONFIG.HTTP_USERNAME and check_hash(password, plexpy.CONFIG.HTTP_PASSWORD):
|
||||||
if plex_login is not None:
|
return True, user_details, 'admin'
|
||||||
return True, plex_login
|
elif not plexpy.CONFIG.HTTP_HASHED_PASSWORD and \
|
||||||
|
username == plexpy.CONFIG.HTTP_USERNAME and password == plexpy.CONFIG.HTTP_PASSWORD:
|
||||||
|
return True, user_details, 'admin'
|
||||||
|
|
||||||
return False, None
|
if plexpy.CONFIG.HTTP_PLEX_ADMIN or (not admin_login == '1' and plexpy.CONFIG.ALLOW_GUEST_ACCESS):
|
||||||
|
plex_login = user_login(username=username, password=password)
|
||||||
|
if plex_login is not None:
|
||||||
|
return True, plex_login[0], plex_login[1]
|
||||||
|
|
||||||
|
elif token:
|
||||||
|
if plexpy.CONFIG.HTTP_PLEX_ADMIN or (not admin_login == '1' and plexpy.CONFIG.ALLOW_GUEST_ACCESS):
|
||||||
|
plex_login = user_login(token=token)
|
||||||
|
if plex_login is not None:
|
||||||
|
return True, plex_login[0], plex_login[1]
|
||||||
|
|
||||||
|
return False, None, None
|
||||||
|
|
||||||
|
|
||||||
def check_jwt_token():
|
def check_jwt_token():
|
||||||
|
@ -279,41 +303,33 @@ class AuthController(object):
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@cherrypy.tools.json_out()
|
@cherrypy.tools.json_out()
|
||||||
def signin(self, username=None, password=None, remember_me='0', admin_login='0', *args, **kwargs):
|
def signin(self, username=None, password=None, token=None, remember_me='0', admin_login='0', *args, **kwargs):
|
||||||
if cherrypy.request.method != 'POST':
|
if cherrypy.request.method != 'POST':
|
||||||
cherrypy.response.status = 405
|
cherrypy.response.status = 405
|
||||||
return {'status': 'error', 'message': 'Sign in using POST.'}
|
return {'status': 'error', 'message': 'Sign in using POST.'}
|
||||||
|
|
||||||
error_message = {'status': 'error', 'message': 'Incorrect username or password.'}
|
error_message = {'status': 'error', 'message': 'Invalid credentials.'}
|
||||||
|
|
||||||
valid_login, user_group = check_credentials(username, password, admin_login)
|
valid_login, user_details, user_group = check_credentials(username=username,
|
||||||
|
password=password,
|
||||||
|
token=token,
|
||||||
|
admin_login=admin_login)
|
||||||
|
|
||||||
if valid_login:
|
if valid_login:
|
||||||
if user_group == 'tautulli admin':
|
|
||||||
user_group = 'admin'
|
|
||||||
user_id = None
|
|
||||||
else:
|
|
||||||
if re.match(r"[^@]+@[^@]+\.[^@]+", username):
|
|
||||||
user_details = Users().get_details(email=username)
|
|
||||||
else:
|
|
||||||
user_details = Users().get_details(user=username)
|
|
||||||
|
|
||||||
user_id = user_details['user_id']
|
|
||||||
|
|
||||||
time_delta = timedelta(days=30) if remember_me == '1' else timedelta(minutes=60)
|
time_delta = timedelta(days=30) if remember_me == '1' else timedelta(minutes=60)
|
||||||
expiry = datetime.utcnow() + time_delta
|
expiry = datetime.utcnow() + time_delta
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
'user_id': user_id,
|
'user_id': user_details['user_id'],
|
||||||
'user': username,
|
'user': user_details['username'],
|
||||||
'user_group': user_group,
|
'user_group': user_group,
|
||||||
'exp': expiry
|
'exp': expiry
|
||||||
}
|
}
|
||||||
|
|
||||||
jwt_token = jwt.encode(payload, plexpy.CONFIG.JWT_SECRET, algorithm=JWT_ALGORITHM)
|
jwt_token = jwt.encode(payload, plexpy.CONFIG.JWT_SECRET, algorithm=JWT_ALGORITHM)
|
||||||
|
|
||||||
self.on_login(username=username,
|
self.on_login(username=user_details['username'],
|
||||||
user_id=user_id,
|
user_id=user_details['user_id'],
|
||||||
user_group=user_group,
|
user_group=user_group,
|
||||||
success=1)
|
success=1)
|
||||||
|
|
||||||
|
@ -326,14 +342,36 @@ class AuthController(object):
|
||||||
cherrypy.response.status = 200
|
cherrypy.response.status = 200
|
||||||
return {'status': 'success', 'token': jwt_token.decode('utf-8'), 'uuid': plexpy.CONFIG.PMS_UUID}
|
return {'status': 'success', 'token': jwt_token.decode('utf-8'), 'uuid': plexpy.CONFIG.PMS_UUID}
|
||||||
|
|
||||||
elif admin_login == '1':
|
elif admin_login == '1' and username:
|
||||||
self.on_login(username=username)
|
self.on_login(username=username)
|
||||||
logger.debug(u"Tautulli WebAuth :: Invalid admin login attempt from '%s'." % username)
|
logger.debug(u"Tautulli WebAuth :: Invalid admin login attempt from '%s'." % username)
|
||||||
cherrypy.response.status = 401
|
cherrypy.response.status = 401
|
||||||
return error_message
|
return error_message
|
||||||
|
|
||||||
else:
|
elif username:
|
||||||
self.on_login(username=username)
|
self.on_login(username=username)
|
||||||
logger.debug(u"Tautulli WebAuth :: Invalid login attempt from '%s'." % username)
|
logger.debug(u"Tautulli WebAuth :: Invalid user login attempt from '%s'." % username)
|
||||||
cherrypy.response.status = 401
|
cherrypy.response.status = 401
|
||||||
return error_message
|
return error_message
|
||||||
|
|
||||||
|
elif token:
|
||||||
|
logger.debug(u"Tautulli WebAuth :: Invalid Plex OAuth login attempt.")
|
||||||
|
cherrypy.response.status = 401
|
||||||
|
return error_message
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
@cherrypy.tools.json_out()
|
||||||
|
def get_plex_oauth_url(self, *args, **kwargs):
|
||||||
|
pin = PlexTV().get_pin()
|
||||||
|
oauth_url = 'https://app.plex.tv/auth/#!?clientID={}&code={}'.format(
|
||||||
|
plexpy.CONFIG.PMS_UUID, pin['code'])
|
||||||
|
return {'pin': pin['id'], 'url': oauth_url}
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
@cherrypy.tools.json_out()
|
||||||
|
def pin(self, pin=None, *args, **kwargs):
|
||||||
|
pin = PlexTV().get_pin(pin=pin)
|
||||||
|
if pin['token']:
|
||||||
|
return {'result': 'success', 'token': pin['token']}
|
||||||
|
else:
|
||||||
|
return {'result': 'polling'}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue