168 lines
6.3 KiB
Python
168 lines
6.3 KiB
Python
|
try:
|
||
|
import http.client as httplib
|
||
|
except ImportError:
|
||
|
import httplib
|
||
|
try:
|
||
|
import urllib.parse as urlparse
|
||
|
except ImportError:
|
||
|
import urlparse
|
||
|
|
||
|
import logging
|
||
|
import requests
|
||
|
import os
|
||
|
import base64
|
||
|
import json
|
||
|
|
||
|
from lbrynet.lbrynet_daemon.auth.util import load_api_keys, APIKey, API_KEY_NAME
|
||
|
from lbrynet.conf import API_INTERFACE, API_ADDRESS, API_PORT
|
||
|
from lbrynet.lbrynet_daemon.LBRYDaemon import log_dir as DATA_DIR
|
||
|
|
||
|
log = logging.getLogger(__name__)
|
||
|
USER_AGENT = "AuthServiceProxy/0.1"
|
||
|
HTTP_TIMEOUT = 30
|
||
|
|
||
|
|
||
|
class JSONRPCException(Exception):
|
||
|
def __init__(self, rpc_error):
|
||
|
Exception.__init__(self)
|
||
|
self.error = rpc_error
|
||
|
|
||
|
|
||
|
class LBRYAPIClient(object):
|
||
|
__api_token = None
|
||
|
|
||
|
def __init__(self, key_name=None, key=None, pw_path=None, timeout=HTTP_TIMEOUT, connection=None, count=0,
|
||
|
service=None, cookies=None, auth=None, url=None, login_url=None):
|
||
|
self.__api_key_name = API_KEY_NAME if not key_name else key_name
|
||
|
self.__api_token = key
|
||
|
self.__pw_path = os.path.join(DATA_DIR, ".api_keys") if not pw_path else pw_path
|
||
|
self.__service_name = service
|
||
|
|
||
|
if not key:
|
||
|
keys = load_api_keys(self.__pw_path)
|
||
|
api_key = keys.get(self.__api_key_name, False)
|
||
|
self.__api_token = api_key['token']
|
||
|
self.__api_key_obj = api_key
|
||
|
else:
|
||
|
self.__api_key_obj = APIKey({'token': key})
|
||
|
|
||
|
if login_url is None:
|
||
|
self.__service_url = "http://%s:%s@%s:%i/%s" % (self.__api_key_name, self.__api_token,
|
||
|
API_INTERFACE, API_PORT, API_ADDRESS)
|
||
|
else:
|
||
|
self.__service_url = login_url
|
||
|
|
||
|
self.__id_count = count
|
||
|
|
||
|
if auth is None and connection is None and cookies is None and url is None:
|
||
|
self.__url = urlparse.urlparse(self.__service_url)
|
||
|
(user, passwd) = (self.__url.username, self.__url.password)
|
||
|
try:
|
||
|
user = user.encode('utf8')
|
||
|
except AttributeError:
|
||
|
pass
|
||
|
try:
|
||
|
passwd = passwd.encode('utf8')
|
||
|
except AttributeError:
|
||
|
pass
|
||
|
authpair = user + b':' + passwd
|
||
|
self.__auth_header = b'Basic ' + base64.b64encode(authpair)
|
||
|
|
||
|
self.__conn = requests.Session()
|
||
|
self.__conn.auth = (user, passwd)
|
||
|
|
||
|
req = requests.Request(method='POST',
|
||
|
url=self.__service_url,
|
||
|
auth=self.__conn.auth,
|
||
|
headers={'Host': self.__url.hostname,
|
||
|
'User-Agent': USER_AGENT,
|
||
|
'Authorization': self.__auth_header,
|
||
|
'Content-type': 'application/json'},)
|
||
|
r = req.prepare()
|
||
|
http_response = self.__conn.send(r)
|
||
|
cookies = http_response.cookies
|
||
|
self.__cookies = cookies
|
||
|
# print "Logged in"
|
||
|
|
||
|
uid = cookies.get('TWISTED_SESSION')
|
||
|
api_key = APIKey.new(seed=uid)
|
||
|
# print "Created temporary api key"
|
||
|
|
||
|
self.__api_token = api_key.token()
|
||
|
self.__api_key_obj = api_key
|
||
|
else:
|
||
|
self.__auth_header = auth
|
||
|
self.__conn = connection
|
||
|
self.__cookies = cookies
|
||
|
self.__url = url
|
||
|
|
||
|
if cookies.get("secret", False):
|
||
|
self.__api_token = cookies.get("secret")
|
||
|
self.__api_key_obj = APIKey({'name': self.__api_key_name, 'token': self.__api_token})
|
||
|
|
||
|
|
||
|
def __getattr__(self, name):
|
||
|
if name.startswith('__') and name.endswith('__'):
|
||
|
# Python internal stuff
|
||
|
raise AttributeError
|
||
|
if self.__service_name is not None:
|
||
|
name = "%s.%s" % (self.__service_name, name)
|
||
|
return LBRYAPIClient(key_name=self.__api_key_name,
|
||
|
key=self.__api_token,
|
||
|
connection=self.__conn,
|
||
|
service=name,
|
||
|
count=self.__id_count,
|
||
|
cookies=self.__cookies,
|
||
|
auth=self.__auth_header,
|
||
|
url=self.__url,
|
||
|
login_url=self.__service_url)
|
||
|
|
||
|
def __call__(self, *args):
|
||
|
self.__id_count += 1
|
||
|
pre_auth_postdata = {'version': '1.1',
|
||
|
'method': self.__service_name,
|
||
|
'params': args,
|
||
|
'id': self.__id_count}
|
||
|
to_auth = str(pre_auth_postdata['method']).encode('hex') + str(pre_auth_postdata['id']).encode('hex')
|
||
|
token = self.__api_key_obj.get_hmac(to_auth.decode('hex'))
|
||
|
pre_auth_postdata.update({'hmac': token})
|
||
|
postdata = json.dumps(pre_auth_postdata)
|
||
|
service_url = self.__service_url
|
||
|
auth_header = self.__auth_header
|
||
|
cookies = self.__cookies
|
||
|
host = self.__url.hostname
|
||
|
|
||
|
req = requests.Request(method='POST',
|
||
|
url=service_url,
|
||
|
data=postdata,
|
||
|
headers={'Host': host,
|
||
|
'User-Agent': USER_AGENT,
|
||
|
'Authorization': auth_header,
|
||
|
'Content-type': 'application/json'},
|
||
|
cookies=cookies)
|
||
|
r = req.prepare()
|
||
|
http_response = self.__conn.send(r)
|
||
|
self.__cookies = http_response.cookies
|
||
|
headers = http_response.headers
|
||
|
next_secret = headers.get('Next-Secret', False)
|
||
|
|
||
|
if next_secret:
|
||
|
cookies.update({'secret': next_secret})
|
||
|
|
||
|
# print "Postdata: %s" % postdata
|
||
|
if http_response is None:
|
||
|
raise JSONRPCException({
|
||
|
'code': -342, 'message': 'missing HTTP response from server'})
|
||
|
|
||
|
# print "-----\n%s\n------" % http_response.text
|
||
|
http_response.raise_for_status()
|
||
|
|
||
|
response = http_response.json()
|
||
|
|
||
|
if response['error'] is not None:
|
||
|
raise JSONRPCException(response['error'])
|
||
|
elif 'result' not in response:
|
||
|
raise JSONRPCException({
|
||
|
'code': -343, 'message': 'missing JSON-RPC result'})
|
||
|
else:
|
||
|
return response['result']
|