SickGear/lib/imdbpie/auth.py

138 lines
4.5 KiB
Python

# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
import json
import requests
import tempfile
from datetime import datetime
try:
from base64 import encodebytes
except ImportError:
from base64 import encodestring as encodebytes
import diskcache
from dateutil.tz import tzutc
from dateutil.parser import parse
import boto.utils
from six.moves.urllib.parse import urlparse, parse_qs, quote
from boto import provider
from boto.connection import HTTPRequest
from boto.auth import HmacAuthV3HTTPHandler
from .constants import APP_KEY, HOST, USER_AGENT, BASE_URI
class ZuluHmacAuthV3HTTPHandler(HmacAuthV3HTTPHandler):
def sign_string(self, string_to_sign):
new_hmac = self._get_hmac()
new_hmac.update(string_to_sign)
return encodebytes(new_hmac.digest()).decode('utf-8').strip()
def headers_to_sign(self, http_request):
headers_to_sign = {'Host': self.host}
for name, value in http_request.headers.items():
lname = name.lower()
if lname.startswith('x-amz'):
headers_to_sign[name] = value
return headers_to_sign
def canonical_query_string(self, http_request):
if http_request.method == 'POST':
return ''
qs_parts = []
for param in sorted(http_request.params):
value = boto.utils.get_utf8_value(http_request.params[param])
param_ = quote(param, safe='-_.~')
value_ = quote(value, safe='-_.~')
qs_parts.append('{0}={1}'.format(param_, value_))
return '&'.join(qs_parts)
def string_to_sign(self, http_request):
headers_to_sign = self.headers_to_sign(http_request)
canonical_qs = self.canonical_query_string(http_request)
canonical_headers = self.canonical_headers(headers_to_sign)
string_to_sign = '\n'.join((
http_request.method,
http_request.path,
canonical_qs,
canonical_headers,
'',
http_request.body
))
return string_to_sign, headers_to_sign
def _get_credentials():
url = '{0}/authentication/credentials/temporary/ios82'.format(BASE_URI)
response = requests.post(
url, json={'appKey': APP_KEY}, headers={'User-Agent': USER_AGENT}
)
response.raise_for_status()
return json.loads(response.content.decode('utf8'))['resource']
class Auth(object):
SOON_EXPIRES_SECONDS = 60
_CREDS_STORAGE_KEY = 'imdbpie-credentials'
def __init__(self, creds=None):
self._cachedir = tempfile.gettempdir()
def _get_creds(self):
with diskcache.Cache(directory=self._cachedir) as cache:
return cache.get(self._CREDS_STORAGE_KEY)
def _set_creds(self, creds):
with diskcache.Cache(directory=self._cachedir) as cache:
cache[self._CREDS_STORAGE_KEY] = creds
return creds
def clear_cached_credentials(self):
with diskcache.Cache(directory=self._cachedir) as cache:
cache.delete(self._CREDS_STORAGE_KEY)
def _creds_soon_expiring(self):
creds = self._get_creds()
if not creds:
return creds, True
expires_at = parse(creds['expirationTimeStamp'])
now = datetime.now(tzutc())
if now < expires_at:
time_diff = expires_at - now
if time_diff.total_seconds() < self.SOON_EXPIRES_SECONDS:
# creds will soon expire, so renew them
return creds, True
return creds, False
else:
return creds, True
def get_auth_headers(self, url_path):
creds, soon_expires = self._creds_soon_expiring()
if soon_expires:
creds = self._set_creds(creds=_get_credentials())
handler = ZuluHmacAuthV3HTTPHandler(
host=HOST,
config={},
provider=provider.Provider(
name='aws',
access_key=creds['accessKeyId'],
secret_key=creds['secretAccessKey'],
security_token=creds['sessionToken'],
)
)
parsed_url = urlparse(url_path)
params = {
key: val[0] for key, val in parse_qs(parsed_url.query).items()
}
request = HTTPRequest(
method='GET', protocol='https', host=HOST,
port=443, path=parsed_url.path, auth_path=None, params=params,
headers={}, body=''
)
handler.add_auth(req=request)
headers = request.headers
headers['User-Agent'] = USER_AGENT
return headers