2020-03-19 16:45:31 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
""" AUTH API """
|
|
|
|
|
|
|
|
from __future__ import absolute_import, division, unicode_literals
|
|
|
|
|
|
|
|
import json
|
|
|
|
import logging
|
2020-04-01 11:01:22 +02:00
|
|
|
import os
|
2020-03-19 16:45:31 +01:00
|
|
|
import time
|
|
|
|
|
2020-04-01 12:42:04 +02:00
|
|
|
from resources.lib import kodiutils
|
2021-02-09 20:54:40 +01:00
|
|
|
from resources.lib.viervijfzes.aws.cognito_identity import CognitoIdentity
|
|
|
|
from resources.lib.viervijfzes.aws.cognito_idp import AuthenticationException, CognitoIdp, InvalidLoginException
|
|
|
|
from resources.lib.viervijfzes.aws.cognito_sync import CognitoSync
|
2020-03-19 16:45:31 +01:00
|
|
|
|
2020-10-26 10:25:57 +01:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
2020-03-19 16:45:31 +01:00
|
|
|
|
|
|
|
|
|
|
|
class AuthApi:
|
2021-02-01 08:53:13 +01:00
|
|
|
""" GoPlay Authentication API """
|
2020-03-19 16:45:31 +01:00
|
|
|
COGNITO_REGION = 'eu-west-1'
|
|
|
|
COGNITO_POOL_ID = 'eu-west-1_dViSsKM5Y'
|
|
|
|
COGNITO_CLIENT_ID = '6s1h851s8uplco5h6mqh1jac8m'
|
2021-02-09 20:54:40 +01:00
|
|
|
COGNITO_IDENTITY_POOL_ID = 'eu-west-1:8b7eb22c-cf61-43d5-a624-04b494867234'
|
2020-03-19 16:45:31 +01:00
|
|
|
|
|
|
|
TOKEN_FILE = 'auth-tokens.json'
|
|
|
|
|
2020-04-01 11:01:22 +02:00
|
|
|
def __init__(self, username, password, token_path):
|
2020-03-19 16:45:31 +01:00
|
|
|
""" Initialise object """
|
|
|
|
self._username = username
|
|
|
|
self._password = password
|
2020-04-01 11:01:22 +02:00
|
|
|
self._token_path = token_path
|
2020-03-19 16:45:31 +01:00
|
|
|
self._id_token = None
|
|
|
|
self._expiry = 0
|
|
|
|
self._refresh_token = None
|
|
|
|
|
2020-03-22 15:37:15 +01:00
|
|
|
# Load tokens from cache
|
|
|
|
try:
|
2020-07-09 10:16:45 +02:00
|
|
|
with open(os.path.join(self._token_path, self.TOKEN_FILE), 'r') as fdesc:
|
2020-03-25 08:08:15 +01:00
|
|
|
data_json = json.loads(fdesc.read())
|
2020-03-22 15:37:15 +01:00
|
|
|
self._id_token = data_json.get('id_token')
|
|
|
|
self._refresh_token = data_json.get('refresh_token')
|
|
|
|
self._expiry = int(data_json.get('expiry', 0))
|
|
|
|
except (IOError, TypeError, ValueError):
|
2020-05-11 14:12:13 +02:00
|
|
|
_LOGGER.warning('We could not use the cache since it is invalid or non-existent.')
|
2020-03-19 16:45:31 +01:00
|
|
|
|
|
|
|
def get_token(self):
|
|
|
|
""" Get a valid token """
|
|
|
|
now = int(time.time())
|
|
|
|
|
|
|
|
if self._id_token and self._expiry > now:
|
|
|
|
# We have a valid id token in memory, use it
|
2020-03-26 11:31:28 +01:00
|
|
|
_LOGGER.debug('Got an id token from memory')
|
2020-03-19 16:45:31 +01:00
|
|
|
return self._id_token
|
|
|
|
|
|
|
|
if self._refresh_token:
|
|
|
|
# We have a valid refresh token, use that to refresh our id token
|
|
|
|
# The refresh token is valid for 30 days. If this refresh fails, we just continue by logging in again.
|
2020-03-22 10:30:23 +01:00
|
|
|
_LOGGER.debug('Getting an id token by refreshing')
|
|
|
|
try:
|
|
|
|
self._id_token = self._refresh(self._refresh_token)
|
2020-03-19 16:45:31 +01:00
|
|
|
self._expiry = now + 3600
|
2020-03-25 08:08:15 +01:00
|
|
|
except (InvalidLoginException, AuthenticationException) as exc:
|
|
|
|
_LOGGER.error('Error logging in: %s', str(exc))
|
2020-03-22 10:30:23 +01:00
|
|
|
self._id_token = None
|
|
|
|
self._refresh_token = None
|
|
|
|
self._expiry = 0
|
|
|
|
# We continue by logging in with username and password
|
2020-03-19 16:45:31 +01:00
|
|
|
|
|
|
|
if not self._id_token:
|
|
|
|
# We have no tokens, or they are all invalid, do a login
|
2020-03-22 10:30:23 +01:00
|
|
|
_LOGGER.debug('Getting an id token by logging in')
|
2020-03-19 16:45:31 +01:00
|
|
|
id_token, refresh_token = self._authenticate(self._username, self._password)
|
|
|
|
self._id_token = id_token
|
|
|
|
self._refresh_token = refresh_token
|
|
|
|
self._expiry = now + 3600
|
|
|
|
|
2020-03-22 15:37:15 +01:00
|
|
|
# Store new tokens in cache
|
2020-04-01 11:01:22 +02:00
|
|
|
if not os.path.exists(self._token_path):
|
2020-11-28 17:13:21 +01:00
|
|
|
os.makedirs(self._token_path)
|
2020-07-09 10:16:45 +02:00
|
|
|
with open(os.path.join(self._token_path, self.TOKEN_FILE), 'w') as fdesc:
|
2020-03-22 15:37:15 +01:00
|
|
|
data = json.dumps(dict(
|
|
|
|
id_token=self._id_token,
|
|
|
|
refresh_token=self._refresh_token,
|
|
|
|
expiry=self._expiry,
|
|
|
|
))
|
2020-04-01 11:00:06 +02:00
|
|
|
fdesc.write(kodiutils.from_unicode(data))
|
2020-03-19 16:45:31 +01:00
|
|
|
|
|
|
|
return self._id_token
|
|
|
|
|
2020-04-01 11:01:22 +02:00
|
|
|
def clear_tokens(self):
|
2020-03-19 16:45:31 +01:00
|
|
|
""" Remove the cached tokens. """
|
2020-07-09 10:16:45 +02:00
|
|
|
if os.path.exists(os.path.join(self._token_path, AuthApi.TOKEN_FILE)):
|
|
|
|
os.unlink(os.path.join(self._token_path, AuthApi.TOKEN_FILE))
|
2020-03-19 16:45:31 +01:00
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _authenticate(username, password):
|
|
|
|
""" Authenticate with Amazon Cognito and fetch a refresh token and id token. """
|
2021-02-09 20:54:40 +01:00
|
|
|
idp_client = CognitoIdp(AuthApi.COGNITO_POOL_ID, AuthApi.COGNITO_CLIENT_ID)
|
|
|
|
return idp_client.authenticate(username, password)
|
2020-03-19 16:45:31 +01:00
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _refresh(refresh_token):
|
|
|
|
""" Use the refresh token to fetch a new id token. """
|
2021-02-09 20:54:40 +01:00
|
|
|
idp_client = CognitoIdp(AuthApi.COGNITO_POOL_ID, AuthApi.COGNITO_CLIENT_ID)
|
|
|
|
return idp_client.renew_token(refresh_token)
|
|
|
|
|
2021-02-11 18:25:51 +01:00
|
|
|
def get_dataset(self, dataset, key):
|
2021-02-09 20:54:40 +01:00
|
|
|
""" Fetch the value from the specified dataset. """
|
|
|
|
identity_client = CognitoIdentity(AuthApi.COGNITO_POOL_ID, AuthApi.COGNITO_IDENTITY_POOL_ID)
|
|
|
|
id_token = self.get_token()
|
|
|
|
identity_id = identity_client.get_id(id_token)
|
|
|
|
credentials = identity_client.get_credentials_for_identity(id_token, identity_id)
|
|
|
|
|
|
|
|
sync_client = CognitoSync(AuthApi.COGNITO_IDENTITY_POOL_ID, identity_id, credentials)
|
2021-02-11 18:25:51 +01:00
|
|
|
data, session_token, sync_count = sync_client.list_records(dataset, key)
|
2021-02-09 20:54:40 +01:00
|
|
|
|
|
|
|
sync_info = {
|
|
|
|
'identity_id': identity_id,
|
|
|
|
'credentials': credentials,
|
|
|
|
'session_token': session_token,
|
|
|
|
'sync_count': sync_count,
|
|
|
|
}
|
|
|
|
|
|
|
|
return data, sync_info
|
|
|
|
|
|
|
|
@staticmethod
|
2021-02-11 18:25:51 +01:00
|
|
|
def put_dataset(dataset, key, value, sync_info):
|
2021-02-09 20:54:40 +01:00
|
|
|
""" Store the value from the specified dataset. """
|
|
|
|
sync_client = CognitoSync(AuthApi.COGNITO_IDENTITY_POOL_ID, sync_info.get('identity_id'), sync_info.get('credentials'))
|
2021-02-11 18:25:51 +01:00
|
|
|
sync_client.update_records(dataset, key, value, sync_info.get('session_token'), sync_info.get('sync_count'))
|