237 lines
11 KiB
Python
237 lines
11 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
"""
|
||
|
|
||
|
Copyright (C) 2017-2018 plugin.video.youtube
|
||
|
|
||
|
SPDX-License-Identifier: GPL-2.0-only
|
||
|
See LICENSES/GPL-2.0-only for more information.
|
||
|
"""
|
||
|
|
||
|
from base64 import b64decode
|
||
|
from hashlib import md5
|
||
|
from ...kodion.json_store import APIKeyStore, LoginTokenStore
|
||
|
from ...kodion import Context as __Context
|
||
|
from ... import key_sets
|
||
|
|
||
|
DEFAULT_SWITCH = 1
|
||
|
|
||
|
__context = __Context(plugin_id='plugin.video.youtube')
|
||
|
__settings = __context.get_settings()
|
||
|
|
||
|
|
||
|
class APICheck(object):
|
||
|
|
||
|
def __init__(self, context, settings):
|
||
|
self._context = context
|
||
|
self._settings = settings
|
||
|
self._ui = context.get_ui()
|
||
|
self._api_jstore = APIKeyStore()
|
||
|
self._json_api = self._api_jstore.get_data()
|
||
|
self._am_jstore = LoginTokenStore()
|
||
|
self._json_am = self._am_jstore.get_data()
|
||
|
self.changed = False
|
||
|
|
||
|
self._on_init()
|
||
|
|
||
|
def _on_init(self):
|
||
|
self._json_api = self._api_jstore.get_data()
|
||
|
|
||
|
j_key = self._json_api['keys']['personal'].get('api_key', '')
|
||
|
j_id = self._json_api['keys']['personal'].get('client_id', '')
|
||
|
j_secret = self._json_api['keys']['personal'].get('client_secret', '')
|
||
|
|
||
|
if j_key and j_id and j_secret:
|
||
|
# users are now pasting keys into api_keys.json
|
||
|
# try stripping whitespace and .apps.googleusercontent.com from keys and saving the result if they differ
|
||
|
stripped_key, stripped_id, stripped_secret = self._strip_api_keys(j_key, j_id, j_secret)
|
||
|
if stripped_key and stripped_id and stripped_secret:
|
||
|
if (j_key != stripped_key) or (j_id != stripped_id) or (j_secret != stripped_secret):
|
||
|
self._json_api['keys']['personal'] = {'api_key': stripped_key, 'client_id': stripped_id, 'client_secret': stripped_secret}
|
||
|
self._api_jstore.save(self._json_api)
|
||
|
|
||
|
original_key = self._settings.get_string('youtube.api.key')
|
||
|
original_id = self._settings.get_string('youtube.api.id')
|
||
|
original_secret = self._settings.get_string('youtube.api.secret')
|
||
|
if original_key and original_id and original_secret:
|
||
|
own_key, own_id, own_secret = self._strip_api_keys(original_key, original_id, original_secret)
|
||
|
if own_key and own_id and own_secret:
|
||
|
if (original_key != own_key) or (original_id != own_id) or (original_secret != own_secret):
|
||
|
self._settings.set_string('youtube.api.key', own_key)
|
||
|
self._settings.set_string('youtube.api.id', own_id)
|
||
|
self._settings.set_string('youtube.api.secret', own_secret)
|
||
|
|
||
|
if (j_key != own_key) or (j_id != own_id) or (j_secret != own_secret):
|
||
|
self._json_api['keys']['personal'] = {'api_key': own_key, 'client_id': own_id, 'client_secret': own_secret}
|
||
|
self._api_jstore.save(self._json_api)
|
||
|
|
||
|
self._json_api = self._api_jstore.get_data()
|
||
|
j_key = self._json_api['keys']['personal'].get('api_key', '')
|
||
|
j_id = self._json_api['keys']['personal'].get('client_id', '')
|
||
|
j_secret = self._json_api['keys']['personal'].get('client_secret', '')
|
||
|
|
||
|
if not original_key or not original_id or not original_secret and (j_key and j_secret and j_id):
|
||
|
self._settings.set_string('youtube.api.key', j_key)
|
||
|
self._settings.set_string('youtube.api.id', j_id)
|
||
|
self._settings.set_string('youtube.api.secret', j_secret)
|
||
|
|
||
|
switch = self.get_current_switch()
|
||
|
user = self.get_current_user()
|
||
|
|
||
|
access_token = self._settings.get_string('kodion.access_token', '')
|
||
|
refresh_token = self._settings.get_string('kodion.refresh_token', '')
|
||
|
token_expires = self._settings.get_int('kodion.access_token.expires', -1)
|
||
|
last_hash = self._settings.get_string('youtube.api.last.hash', '')
|
||
|
if not self._json_am['access_manager']['users'].get(user, {}).get('access_token') or \
|
||
|
not self._json_am['access_manager']['users'].get(user, {}).get('refresh_token'):
|
||
|
if access_token and refresh_token:
|
||
|
self._json_am['access_manager']['users'][user]['access_token'] = access_token
|
||
|
self._json_am['access_manager']['users'][user]['refresh_token'] = refresh_token
|
||
|
self._json_am['access_manager']['users'][user]['token_expires'] = token_expires
|
||
|
if switch == 'own':
|
||
|
own_key_hash = self._get_key_set_hash('own')
|
||
|
if last_hash == self._get_key_set_hash('own', True) or \
|
||
|
last_hash == own_key_hash:
|
||
|
self._json_am['access_manager']['users'][user]['last_key_hash'] = own_key_hash
|
||
|
self._am_jstore.save(self._json_am)
|
||
|
if access_token or refresh_token or last_hash:
|
||
|
self._settings.set_string('kodion.access_token', '')
|
||
|
self._settings.set_string('kodion.refresh_token', '')
|
||
|
self._settings.set_int('kodion.access_token.expires', -1)
|
||
|
self._settings.set_string('youtube.api.last.hash', '')
|
||
|
|
||
|
updated_hash = self._api_keys_changed(switch)
|
||
|
if updated_hash:
|
||
|
self._context.log_warning('User: |%s| Switching API key set to |%s|' % (user, switch))
|
||
|
self._json_am['access_manager']['users'][user]['last_key_hash'] = updated_hash
|
||
|
self._am_jstore.save(self._json_am)
|
||
|
self._context.log_debug('API key set changed: Signing out')
|
||
|
self._context.execute('RunPlugin(plugin://plugin.video.youtube/sign/out/?confirmed=true)')
|
||
|
else:
|
||
|
self._context.log_debug('User: |%s| Using API key set: |%s|' % (user, switch))
|
||
|
|
||
|
def get_current_switch(self):
|
||
|
return 'own'
|
||
|
|
||
|
def get_current_user(self):
|
||
|
self._json_am = self._am_jstore.get_data()
|
||
|
return self._json_am['access_manager'].get('current_user', '0')
|
||
|
|
||
|
def has_own_api_keys(self):
|
||
|
self._json_api = self._api_jstore.get_data()
|
||
|
own_key = self._json_api['keys']['personal']['api_key']
|
||
|
own_id = self._json_api['keys']['personal']['client_id']
|
||
|
own_secret = self._json_api['keys']['personal']['client_secret']
|
||
|
return False if not own_key or \
|
||
|
not own_id or \
|
||
|
not own_secret else True
|
||
|
|
||
|
def get_api_keys(self, switch):
|
||
|
self._json_api = self._api_jstore.get_data()
|
||
|
if switch == 'youtube-tv':
|
||
|
api_key = b64decode(key_sets['youtube-tv']['key']).decode('utf-8'),
|
||
|
client_id = u''.join([b64decode(key_sets['youtube-tv']['id']).decode('utf-8'), u'.apps.googleusercontent.com'])
|
||
|
client_secret = b64decode(key_sets['youtube-tv']['secret']).decode('utf-8')
|
||
|
elif switch == 'developer':
|
||
|
self._json_api = self._api_jstore.get_data()
|
||
|
return self._json_api['keys']['developer']
|
||
|
elif switch == 'own':
|
||
|
api_key = self._json_api['keys']['personal']['api_key']
|
||
|
client_id = u''.join([self._json_api['keys']['personal']['client_id'], u'.apps.googleusercontent.com'])
|
||
|
client_secret = self._json_api['keys']['personal']['client_secret']
|
||
|
else:
|
||
|
api_key = b64decode(key_sets['provided'][switch]['key']).decode('utf-8')
|
||
|
client_id = u''.join([b64decode(key_sets['provided'][switch]['id']).decode('utf-8'), u'.apps.googleusercontent.com'])
|
||
|
client_secret = b64decode(key_sets['provided'][switch]['secret']).decode('utf-8')
|
||
|
return api_key, client_id, client_secret
|
||
|
|
||
|
def _api_keys_changed(self, switch):
|
||
|
self._json_am = self._am_jstore.get_data()
|
||
|
user = self.get_current_user()
|
||
|
last_set_hash = self._json_am['access_manager']['users'].get(user, {}).get('last_key_hash', '')
|
||
|
current_set_hash = self._get_key_set_hash(switch)
|
||
|
if last_set_hash != current_set_hash:
|
||
|
self.changed = True
|
||
|
return current_set_hash
|
||
|
else:
|
||
|
self.changed = False
|
||
|
return None
|
||
|
|
||
|
def _get_key_set_hash(self, switch, old=False):
|
||
|
api_key, client_id, client_secret = self.get_api_keys(switch)
|
||
|
if old and switch == 'own':
|
||
|
client_id = client_id.replace(u'.apps.googleusercontent.com', u'')
|
||
|
m = md5()
|
||
|
m.update(api_key.encode('utf-8'))
|
||
|
m.update(client_id.encode('utf-8'))
|
||
|
m.update(client_secret.encode('utf-8'))
|
||
|
|
||
|
return m.hexdigest()
|
||
|
|
||
|
def _strip_api_keys(self, api_key, client_id, client_secret):
|
||
|
|
||
|
stripped_key = ''.join(api_key.split())
|
||
|
stripped_id = ''.join(client_id.replace('.apps.googleusercontent.com', '').split())
|
||
|
stripped_secret = ''.join(client_secret.split())
|
||
|
|
||
|
if api_key != stripped_key:
|
||
|
if stripped_key not in api_key:
|
||
|
self._context.log_debug('Personal API setting: |Key| Skipped: potentially mangled by stripping')
|
||
|
return_key = api_key
|
||
|
else:
|
||
|
self._context.log_debug('Personal API setting: |Key| had whitespace removed')
|
||
|
return_key = stripped_key
|
||
|
else:
|
||
|
return_key = api_key
|
||
|
|
||
|
if client_id != stripped_id:
|
||
|
if stripped_id not in client_id:
|
||
|
self._context.log_debug('Personal API setting: |Id| Skipped: potentially mangled by stripping')
|
||
|
return_id = client_id
|
||
|
else:
|
||
|
googleusercontent = ''
|
||
|
if '.apps.googleusercontent.com' in client_id:
|
||
|
googleusercontent = ' and .apps.googleusercontent.com'
|
||
|
self._context.log_debug('Personal API setting: |Id| had whitespace%s removed' % googleusercontent)
|
||
|
return_id = stripped_id
|
||
|
else:
|
||
|
return_id = client_id
|
||
|
|
||
|
if client_secret != stripped_secret:
|
||
|
if stripped_secret not in client_secret:
|
||
|
self._context.log_debug('Personal API setting: |Secret| Skipped: potentially mangled by stripping')
|
||
|
return_secret = client_secret
|
||
|
else:
|
||
|
self._context.log_debug('Personal API setting: |Secret| had whitespace removed')
|
||
|
return_secret = stripped_secret
|
||
|
else:
|
||
|
return_secret = client_secret
|
||
|
|
||
|
return return_key, return_id, return_secret
|
||
|
|
||
|
|
||
|
notification_data = {'use_httpd': (__settings.use_dash_videos() and
|
||
|
__settings.use_dash()) or
|
||
|
(__settings.api_config_page()),
|
||
|
'httpd_port': __settings.httpd_port(),
|
||
|
'whitelist': __settings.httpd_whitelist(),
|
||
|
'httpd_address': __settings.httpd_listen()
|
||
|
}
|
||
|
|
||
|
__context.send_notification('check_settings', notification_data)
|
||
|
|
||
|
_api_check = APICheck(__context, __settings)
|
||
|
|
||
|
keys_changed = _api_check.changed
|
||
|
current_user = _api_check.get_current_user()
|
||
|
|
||
|
api = dict()
|
||
|
youtube_tv = dict()
|
||
|
|
||
|
_current_switch = _api_check.get_current_switch()
|
||
|
|
||
|
api['key'], api['id'], api['secret'] = _api_check.get_api_keys(_current_switch)
|
||
|
|
||
|
youtube_tv['key'], youtube_tv['id'], youtube_tv['secret'] = _api_check.get_api_keys('youtube-tv')
|
||
|
|
||
|
developer_keys = _api_check.get_api_keys('developer')
|