mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-15 09:42:57 -07:00
Generate a unique token for each mobile device
This commit is contained in:
parent
5029b19d37
commit
08619244f0
6 changed files with 139 additions and 94 deletions
|
@ -2652,13 +2652,9 @@ $(document).ready(function() {
|
||||||
|
|
||||||
$('#api_key').click(function(){ $('#api_key').select() });
|
$('#api_key').click(function(){ $('#api_key').select() });
|
||||||
$("#generate_api").click(function() {
|
$("#generate_api").click(function() {
|
||||||
$.get('generateAPI',
|
$.get('generate_api_key',
|
||||||
function(data){
|
function (apikey) {
|
||||||
if (data.error != undefined) {
|
$('#api_key').val(apikey);
|
||||||
alert(data.error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$('#api_key').val(data);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3046,8 +3042,8 @@ $(document).ready(function() {
|
||||||
});
|
});
|
||||||
$('#api_qr_https').toggle(!(url.startsWith('https')));
|
$('#api_qr_https').toggle(!(url.startsWith('https')));
|
||||||
|
|
||||||
var token = Math.random().toString(36).substr(2, 20);
|
$.get('generate_api_key', { device: true }).then(function (token) {
|
||||||
var encoded_string = url + '|' + $('#api_key').val() + '|' + token;
|
var encoded_string = url + '|' + token;
|
||||||
$('#api_qr_string').html(encoded_string);
|
$('#api_qr_string').html(encoded_string);
|
||||||
$('#api_qr_code').empty().qrcode({
|
$('#api_qr_code').empty().qrcode({
|
||||||
text: encoded_string
|
text: encoded_string
|
||||||
|
@ -3079,8 +3075,19 @@ $(document).ready(function() {
|
||||||
})();
|
})();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
$('#api-qr-modal').on('hidden.bs.modal', function () {
|
$('#api-qr-modal').on('hidden.bs.modal', function () {
|
||||||
|
if (!(verifiedDevice)) {
|
||||||
|
$.ajax({
|
||||||
|
url: 'verify_mobile_device',
|
||||||
|
type: 'GET',
|
||||||
|
data: { cancel: true },
|
||||||
|
success: function(data) {
|
||||||
|
showMsg('<i class="fa fa-times"></i> ' + data.message, false, true, 5000, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
verifiedDevice = true;
|
verifiedDevice = true;
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ import activity_pinger
|
||||||
import config
|
import config
|
||||||
import database
|
import database
|
||||||
import logger
|
import logger
|
||||||
|
import mobile_app
|
||||||
import notification_handler
|
import notification_handler
|
||||||
import notifiers
|
import notifiers
|
||||||
import plextv
|
import plextv
|
||||||
|
@ -165,6 +166,7 @@ def initialize(config_file):
|
||||||
|
|
||||||
# Add notifier configs to logger blacklist
|
# Add notifier configs to logger blacklist
|
||||||
notifiers.blacklist_logger()
|
notifiers.blacklist_logger()
|
||||||
|
mobile_app.blacklist_logger()
|
||||||
|
|
||||||
# Check if PlexPy has a uuid
|
# Check if PlexPy has a uuid
|
||||||
if CONFIG.PMS_UUID == '' or not CONFIG.PMS_UUID:
|
if CONFIG.PMS_UUID == '' or not CONFIG.PMS_UUID:
|
||||||
|
|
|
@ -33,6 +33,7 @@ import plexpy
|
||||||
import config
|
import config
|
||||||
import database
|
import database
|
||||||
import logger
|
import logger
|
||||||
|
import mobile_app
|
||||||
import plextv
|
import plextv
|
||||||
import pmsconnect
|
import pmsconnect
|
||||||
|
|
||||||
|
@ -88,7 +89,9 @@ class API2:
|
||||||
elif 'apikey' not in kwargs:
|
elif 'apikey' not in kwargs:
|
||||||
self._api_msg = 'Parameter apikey is required'
|
self._api_msg = 'Parameter apikey is required'
|
||||||
|
|
||||||
elif kwargs.get('apikey', '') != plexpy.CONFIG.API_KEY:
|
elif (kwargs.get('apikey', '') != plexpy.CONFIG.API_KEY and
|
||||||
|
kwargs.get('apikey', '') != mobile_app.TEMP_DEVICE_TOKEN and
|
||||||
|
not mobile_app.get_mobile_device_by_token(kwargs.get('apikey', ''))):
|
||||||
self._api_msg = 'Invalid apikey'
|
self._api_msg = 'Invalid apikey'
|
||||||
|
|
||||||
elif 'cmd' not in kwargs:
|
elif 'cmd' not in kwargs:
|
||||||
|
@ -105,7 +108,9 @@ class API2:
|
||||||
# Allow override for the api.
|
# Allow override for the api.
|
||||||
self._api_out_type = kwargs.pop('out_type', 'json')
|
self._api_out_type = kwargs.pop('out_type', 'json')
|
||||||
|
|
||||||
if self._api_apikey == plexpy.CONFIG.API_KEY and plexpy.CONFIG.API_ENABLED and self._api_cmd in self._api_valid_methods:
|
if ((self._api_apikey == plexpy.CONFIG.API_KEY or
|
||||||
|
mobile_app.get_mobile_device_by_token(self._api_apikey)) and
|
||||||
|
plexpy.CONFIG.API_ENABLED and self._api_cmd in self._api_valid_methods):
|
||||||
self._api_authenticated = True
|
self._api_authenticated = True
|
||||||
self._api_msg = None
|
self._api_msg = None
|
||||||
self._api_kwargs = kwargs
|
self._api_kwargs = kwargs
|
||||||
|
@ -341,7 +346,7 @@ class API2:
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def register_device(self, device_id='', device_name='', device_token='', **kwargs):
|
def register_device(self, device_id='', device_name='', **kwargs):
|
||||||
""" Registers the PlexPy Android App for notifications.
|
""" Registers the PlexPy Android App for notifications.
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -350,7 +355,7 @@ class API2:
|
||||||
device_id (str): The OneSignal device id of the PlexPy Android App
|
device_id (str): The OneSignal device id of the PlexPy Android App
|
||||||
|
|
||||||
Optional parameters:
|
Optional parameters:
|
||||||
device_token (str): The device token to verify QR code scan
|
None
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
None
|
None
|
||||||
|
@ -366,28 +371,18 @@ class API2:
|
||||||
self._api_result_type = 'error'
|
self._api_result_type = 'error'
|
||||||
return
|
return
|
||||||
|
|
||||||
|
result = mobile_app.add_mobile_device(device_id=device_id,
|
||||||
|
device_name=device_name,
|
||||||
|
device_token=self._api_apikey)
|
||||||
|
|
||||||
db = database.MonitorDatabase()
|
if result:
|
||||||
|
|
||||||
keys = {'device_id': device_id}
|
|
||||||
values = {'device_name': device_name,
|
|
||||||
'device_token': device_token}
|
|
||||||
|
|
||||||
try:
|
|
||||||
result = db.upsert(table_name='mobile_devices', key_dict=keys, value_dict=values)
|
|
||||||
except Exception as e:
|
|
||||||
logger.warn(u"PlexPy APIv2 :: Failed to register mobile device in the database: %s." % e)
|
|
||||||
self._api_msg = 'Device registartion failed: database error.'
|
|
||||||
self._api_result_type = 'error'
|
|
||||||
return
|
|
||||||
|
|
||||||
if result == 'insert':
|
|
||||||
logger.info(u"PlexPy APIv2 :: Registered mobile device in the database: %s." % device_name)
|
|
||||||
else:
|
|
||||||
logger.debug(u"PlexPy APIv2 :: Re-registered mobile device in the database: %s." % device_name)
|
|
||||||
|
|
||||||
self._api_msg = 'Device registration successful.'
|
self._api_msg = 'Device registration successful.'
|
||||||
self._api_result_type = 'success'
|
self._api_result_type = 'success'
|
||||||
|
mobile_app.TEMP_DEVICE_TOKEN = None
|
||||||
|
else:
|
||||||
|
self._api_msg = 'Device registartion failed: database error.'
|
||||||
|
self._api_result_type = 'error'
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def _api_make_md(self):
|
def _api_make_md(self):
|
||||||
|
|
|
@ -19,6 +19,9 @@ import helpers
|
||||||
import logger
|
import logger
|
||||||
|
|
||||||
|
|
||||||
|
TEMP_DEVICE_TOKEN = None
|
||||||
|
|
||||||
|
|
||||||
def get_mobile_devices(device_id=None, device_token=None):
|
def get_mobile_devices(device_id=None, device_token=None):
|
||||||
where = where_id = where_token = ''
|
where = where_id = where_token = ''
|
||||||
args = []
|
args = []
|
||||||
|
@ -33,19 +36,57 @@ def get_mobile_devices(device_id=None, device_token=None):
|
||||||
args.append(device_token)
|
args.append(device_token)
|
||||||
where += ' AND '.join([w for w in [where_id, where_token] if w])
|
where += ' AND '.join([w for w in [where_id, where_token] if w])
|
||||||
|
|
||||||
monitor_db = database.MonitorDatabase()
|
db = database.MonitorDatabase()
|
||||||
result = monitor_db.select('SELECT * FROM mobile_devices %s' % where, args=args)
|
result = db.select('SELECT * FROM mobile_devices %s' % where, args=args)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def get_mobile_device_by_token(device_token=None):
|
||||||
|
if not device_token:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return get_mobile_devices(device_token=device_token)
|
||||||
|
|
||||||
|
|
||||||
|
def add_mobile_device(device_id=None, device_name=None, device_token=None):
|
||||||
|
db = database.MonitorDatabase()
|
||||||
|
|
||||||
|
keys = {'device_id': device_id}
|
||||||
|
values = {'device_name': device_name,
|
||||||
|
'device_token': device_token}
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = db.upsert(table_name='mobile_devices', key_dict=keys, value_dict=values)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warn(u"PlexPy MobileApp :: Failed to register mobile device in the database: %s." % e)
|
||||||
|
return
|
||||||
|
|
||||||
|
if result == 'insert':
|
||||||
|
logger.info(u"PlexPy MobileApp :: Registered mobile device '%s' in the database." % device_name)
|
||||||
|
else:
|
||||||
|
logger.debug(u"PlexPy MobileApp :: Re-registered mobile device '%s' in the database." % device_name)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def delete_mobile_device(device_id=None):
|
def delete_mobile_device(device_id=None):
|
||||||
monitor_db = database.MonitorDatabase()
|
db = database.MonitorDatabase()
|
||||||
|
|
||||||
if device_id:
|
if device_id:
|
||||||
logger.debug(u"PlexPy Notifiers :: Deleting device_id %s from the database." % device_id)
|
logger.debug(u"PlexPy MobileApp :: Deleting device_id %s from the database." % device_id)
|
||||||
result = monitor_db.action('DELETE FROM mobile_devices WHERE device_id = ?', args=[device_id])
|
result = db.action('DELETE FROM mobile_devices WHERE device_id = ?', args=[device_id])
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def blacklist_logger():
|
||||||
|
devices = get_mobile_devices()
|
||||||
|
|
||||||
|
blacklist = []
|
||||||
|
|
||||||
|
for d in devices:
|
||||||
|
blacklist.append(d['device_token'])
|
||||||
|
|
||||||
|
logger._BLACKLIST_WORDS.extend(blacklist)
|
||||||
|
|
|
@ -375,8 +375,8 @@ def get_notifiers(notifier_id=None, notify_action=None):
|
||||||
args.append(1)
|
args.append(1)
|
||||||
where += ' AND '.join([w for w in [where_id, where_action] if w])
|
where += ' AND '.join([w for w in [where_id, where_action] if w])
|
||||||
|
|
||||||
monitor_db = database.MonitorDatabase()
|
db = database.MonitorDatabase()
|
||||||
result = monitor_db.select('SELECT id, agent_id, agent_name, agent_label, friendly_name, %s FROM notifiers %s'
|
result = db.select('SELECT id, agent_id, agent_name, agent_label, friendly_name, %s FROM notifiers %s'
|
||||||
% (', '.join(notify_actions), where), args=args)
|
% (', '.join(notify_actions), where), args=args)
|
||||||
|
|
||||||
for item in result:
|
for item in result:
|
||||||
|
@ -386,11 +386,11 @@ def get_notifiers(notifier_id=None, notify_action=None):
|
||||||
|
|
||||||
|
|
||||||
def delete_notifier(notifier_id=None):
|
def delete_notifier(notifier_id=None):
|
||||||
monitor_db = database.MonitorDatabase()
|
db = database.MonitorDatabase()
|
||||||
|
|
||||||
if str(notifier_id).isdigit():
|
if str(notifier_id).isdigit():
|
||||||
logger.debug(u"PlexPy Notifiers :: Deleting notifier_id %s from the database." % notifier_id)
|
logger.debug(u"PlexPy Notifiers :: Deleting notifier_id %s from the database." % notifier_id)
|
||||||
result = monitor_db.action('DELETE FROM notifiers WHERE id = ?',
|
result = db.action('DELETE FROM notifiers WHERE id = ?',
|
||||||
args=[notifier_id])
|
args=[notifier_id])
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
|
@ -404,8 +404,8 @@ def get_notifier_config(notifier_id=None):
|
||||||
logger.error(u"PlexPy Notifiers :: Unable to retrieve notifier config: invalid notifier_id %s." % notifier_id)
|
logger.error(u"PlexPy Notifiers :: Unable to retrieve notifier config: invalid notifier_id %s." % notifier_id)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
monitor_db = database.MonitorDatabase()
|
db = database.MonitorDatabase()
|
||||||
result = monitor_db.select_single('SELECT * FROM notifiers WHERE id = ?',
|
result = db.select_single('SELECT * FROM notifiers WHERE id = ?',
|
||||||
args=[notifier_id])
|
args=[notifier_id])
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
|
@ -466,10 +466,10 @@ def add_notifier_config(agent_id=None, **kwargs):
|
||||||
values[a['name'] + '_subject'] = a['subject']
|
values[a['name'] + '_subject'] = a['subject']
|
||||||
values[a['name'] + '_body'] = a['body']
|
values[a['name'] + '_body'] = a['body']
|
||||||
|
|
||||||
monitor_db = database.MonitorDatabase()
|
db = database.MonitorDatabase()
|
||||||
try:
|
try:
|
||||||
monitor_db.upsert(table_name='notifiers', key_dict=keys, value_dict=values)
|
db.upsert(table_name='notifiers', key_dict=keys, value_dict=values)
|
||||||
notifier_id = monitor_db.last_insert_id()
|
notifier_id = db.last_insert_id()
|
||||||
logger.info(u"PlexPy Notifiers :: Added new notification agent: %s (notifier_id %s)." % (agent['label'], notifier_id))
|
logger.info(u"PlexPy Notifiers :: Added new notification agent: %s (notifier_id %s)." % (agent['label'], notifier_id))
|
||||||
return notifier_id
|
return notifier_id
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -514,9 +514,9 @@ def set_notifier_config(notifier_id=None, agent_id=None, **kwargs):
|
||||||
values.update(subject_text)
|
values.update(subject_text)
|
||||||
values.update(body_text)
|
values.update(body_text)
|
||||||
|
|
||||||
monitor_db = database.MonitorDatabase()
|
db = database.MonitorDatabase()
|
||||||
try:
|
try:
|
||||||
monitor_db.upsert(table_name='notifiers', key_dict=keys, value_dict=values)
|
db.upsert(table_name='notifiers', key_dict=keys, value_dict=values)
|
||||||
logger.info(u"PlexPy Notifiers :: Updated notification agent: %s (notifier_id %s)." % (agent['label'], notifier_id))
|
logger.info(u"PlexPy Notifiers :: Updated notification agent: %s (notifier_id %s)." % (agent['label'], notifier_id))
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -538,8 +538,8 @@ def send_notification(notifier_id=None, subject='', body='', notify_action='', *
|
||||||
|
|
||||||
|
|
||||||
def blacklist_logger():
|
def blacklist_logger():
|
||||||
monitor_db = database.MonitorDatabase()
|
db = database.MonitorDatabase()
|
||||||
notifiers = monitor_db.select('SELECT notifier_config FROM notifiers')
|
notifiers = db.select('SELECT notifier_config FROM notifiers')
|
||||||
|
|
||||||
blacklist = []
|
blacklist = []
|
||||||
blacklist_keys = [w.lstrip('_') for w in _BLACKLIST_KEYS]
|
blacklist_keys = [w.lstrip('_') for w in _BLACKLIST_KEYS]
|
||||||
|
@ -554,17 +554,6 @@ def blacklist_logger():
|
||||||
logger._BLACKLIST_WORDS.extend(blacklist)
|
logger._BLACKLIST_WORDS.extend(blacklist)
|
||||||
|
|
||||||
|
|
||||||
def delete_mobile_device(device_id=None):
|
|
||||||
monitor_db = database.MonitorDatabase()
|
|
||||||
|
|
||||||
if device_id:
|
|
||||||
logger.debug(u"PlexPy Notifiers :: Deleting device_id %s from the database." % device_id)
|
|
||||||
result = monitor_db.action('DELETE FROM mobile_devices WHERE device_id = ?', [device_id])
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class PrettyMetadata(object):
|
class PrettyMetadata(object):
|
||||||
def __init__(self, parameters):
|
def __init__(self, parameters):
|
||||||
self.parameters = parameters
|
self.parameters = parameters
|
||||||
|
@ -692,7 +681,7 @@ class ANDROIDAPP(Notifier):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Check mobile device is still registered
|
# Check mobile device is still registered
|
||||||
if self.config['device_id'] and not mobile_app.get_mobile_devices(device_id=self.config['device_id']):
|
if not mobile_app.get_mobile_devices(device_id=self.config['device_id']):
|
||||||
logger.warn(u"PlexPy Notifiers :: Unable to send Android app notification: device not registered.")
|
logger.warn(u"PlexPy Notifiers :: Unable to send Android app notification: device not registered.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -867,8 +856,8 @@ class BROWSER(Notifier):
|
||||||
if not self.config['enabled']:
|
if not self.config['enabled']:
|
||||||
return
|
return
|
||||||
|
|
||||||
monitor_db = database.MonitorDatabase()
|
db = database.MonitorDatabase()
|
||||||
result = monitor_db.select('SELECT subject_text, body_text FROM notify_log '
|
result = db.select('SELECT subject_text, body_text FROM notify_log '
|
||||||
'WHERE agent_id = 17 AND timestamp >= ? ',
|
'WHERE agent_id = 17 AND timestamp >= ? ',
|
||||||
args=[time.time() - 3])
|
args=[time.time() - 3])
|
||||||
|
|
||||||
|
|
|
@ -3204,9 +3204,14 @@ class WebInterface(object):
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@cherrypy.tools.json_out()
|
@cherrypy.tools.json_out()
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
def verify_mobile_device(self, device_token='', **kwargs):
|
def verify_mobile_device(self, device_token='', cancel=False, **kwargs):
|
||||||
result = mobile_app.get_mobile_devices(device_token=device_token)
|
if cancel == 'true':
|
||||||
|
mobile_app.TEMP_DEVICE_TOKEN = None
|
||||||
|
return {'result': 'error', 'message': 'Device registration cancelled.'}
|
||||||
|
|
||||||
|
result = mobile_app.get_mobile_device_by_token(device_token)
|
||||||
if result:
|
if result:
|
||||||
|
mobile_app.TEMP_DEVICE_TOKEN = None
|
||||||
return {'result': 'success', 'message': 'Device registered successfully.', 'data': result}
|
return {'result': 'success', 'message': 'Device registered successfully.', 'data': result}
|
||||||
else:
|
else:
|
||||||
return {'result': 'error', 'message': 'Device not registered.'}
|
return {'result': 'error', 'message': 'Device not registered.'}
|
||||||
|
@ -3421,10 +3426,16 @@ class WebInterface(object):
|
||||||
logger.warn(u"Unable to retrieve data for get_server_pref.")
|
logger.warn(u"Unable to retrieve data for get_server_pref.")
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
|
@cherrypy.tools.json_out()
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
def generateAPI(self, **kwargs):
|
def generate_api_key(self, device=None, **kwargs):
|
||||||
apikey = hashlib.sha224(str(random.getrandbits(256))).hexdigest()[0:32]
|
apikey = hashlib.sha224(str(random.getrandbits(256))).hexdigest()[0:32]
|
||||||
logger.info(u"New API key generated.")
|
logger.info(u"New API key generated.")
|
||||||
|
logger._BLACKLIST_WORDS.append(apikey)
|
||||||
|
|
||||||
|
if device == 'true':
|
||||||
|
mobile_app.TEMP_DEVICE_TOKEN = apikey
|
||||||
|
|
||||||
return apikey
|
return apikey
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue