Inherited APIError from xmlrpclib.Fault.
From now on any errors are raised.
This commit is contained in:
parent
25abf66f1d
commit
2142888cbe
91
src/api.py
91
src/api.py
|
@ -20,6 +20,7 @@ import time
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer
|
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer
|
||||||
from struct import pack
|
from struct import pack
|
||||||
|
import xmlrpclib
|
||||||
|
|
||||||
import defaults
|
import defaults
|
||||||
import helper_inbox
|
import helper_inbox
|
||||||
|
@ -49,16 +50,10 @@ str_chan = '[chan]'
|
||||||
str_broadcast_subscribers = '[Broadcast subscribers]'
|
str_broadcast_subscribers = '[Broadcast subscribers]'
|
||||||
|
|
||||||
|
|
||||||
class APIError(Exception):
|
class APIError(xmlrpclib.Fault):
|
||||||
"""APIError exception class"""
|
"""APIError exception class"""
|
||||||
|
|
||||||
def __init__(self, error_number, error_message):
|
|
||||||
super(APIError, self).__init__()
|
|
||||||
self.error_number = error_number
|
|
||||||
self.error_message = error_message
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "API Error %04i: %s" % (self.error_number, self.error_message)
|
return "API Error %04i: %s" % (self.faultCode, self.faultString)
|
||||||
|
|
||||||
|
|
||||||
class StoppableXMLRPCServer(SimpleXMLRPCServer):
|
class StoppableXMLRPCServer(SimpleXMLRPCServer):
|
||||||
|
@ -107,7 +102,7 @@ class singleAPI(StoppableThread):
|
||||||
(BMConfigParser().get(
|
(BMConfigParser().get(
|
||||||
'bitmessagesettings', 'apiinterface'),
|
'bitmessagesettings', 'apiinterface'),
|
||||||
port),
|
port),
|
||||||
MySimpleXMLRPCRequestHandler, True, True)
|
BMXMLRPCRequestHandler, True, True)
|
||||||
except socket.error as e:
|
except socket.error as e:
|
||||||
if e.errno in (errno.EADDRINUSE, errno.WSAEADDRINUSE):
|
if e.errno in (errno.EADDRINUSE, errno.WSAEADDRINUSE):
|
||||||
continue
|
continue
|
||||||
|
@ -146,6 +141,7 @@ class CommandHandler(type):
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
result = super(CommandHandler, mcs).__new__(
|
result = super(CommandHandler, mcs).__new__(
|
||||||
mcs, name, bases, namespace)
|
mcs, name, bases, namespace)
|
||||||
|
result.config = BMConfigParser()
|
||||||
result._handlers = {}
|
result._handlers = {}
|
||||||
for func in namespace.values():
|
for func in namespace.values():
|
||||||
try:
|
try:
|
||||||
|
@ -162,9 +158,15 @@ class command(object):
|
||||||
self.aliases = aliases
|
self.aliases = aliases
|
||||||
|
|
||||||
def __call__(self, func):
|
def __call__(self, func):
|
||||||
|
if BMConfigParser().safeGet(
|
||||||
|
'bitmessagesettings', 'apivariant') == 'legacy':
|
||||||
def wrapper(*args):
|
def wrapper(*args):
|
||||||
# return json.dumps(func(*args), indent=4)
|
result = func(*args)
|
||||||
return func(*args)
|
return result if isinstance(result, (int, str)) \
|
||||||
|
else json.dumps(result, indent=4)
|
||||||
|
wrapper.__doc__ = func.__doc__
|
||||||
|
else:
|
||||||
|
wrapper = func
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
wrapper._cmd = self.aliases
|
wrapper._cmd = self.aliases
|
||||||
return wrapper
|
return wrapper
|
||||||
|
@ -175,7 +177,7 @@ class command(object):
|
||||||
# Modified by Jonathan Warren (Atheros).
|
# Modified by Jonathan Warren (Atheros).
|
||||||
# Further modified by the Bitmessage developers
|
# Further modified by the Bitmessage developers
|
||||||
# http://code.activestate.com/recipes/501148
|
# http://code.activestate.com/recipes/501148
|
||||||
class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler, object):
|
class BMXMLRPCRequestHandler(SimpleXMLRPCRequestHandler, object):
|
||||||
"""The main API handler"""
|
"""The main API handler"""
|
||||||
__metaclass__ = CommandHandler
|
__metaclass__ = CommandHandler
|
||||||
|
|
||||||
|
@ -253,9 +255,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler, object):
|
||||||
encstr = self.headers.get('Authorization').split()[1]
|
encstr = self.headers.get('Authorization').split()[1]
|
||||||
emailid, password = encstr.decode('base64').split(':')
|
emailid, password = encstr.decode('base64').split(':')
|
||||||
return (
|
return (
|
||||||
emailid == BMConfigParser().get(
|
emailid == self.config.get(
|
||||||
'bitmessagesettings', 'apiusername') and
|
'bitmessagesettings', 'apiusername')
|
||||||
password == BMConfigParser().get(
|
and password == self.config.get(
|
||||||
'bitmessagesettings', 'apipassword')
|
'bitmessagesettings', 'apipassword')
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
@ -274,7 +276,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler, object):
|
||||||
return base64.b64decode(text)
|
return base64.b64decode(text)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise APIError(
|
raise APIError(
|
||||||
22, "Decode error - %s. Had trouble while decoding string: %r"
|
22, 'Decode error - %s. Had trouble while decoding string: %r'
|
||||||
% (e, text)
|
% (e, text)
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
@ -359,17 +361,17 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler, object):
|
||||||
@command('listAddresses', 'listAddresses2')
|
@command('listAddresses', 'listAddresses2')
|
||||||
def HandleListAddresses(self):
|
def HandleListAddresses(self):
|
||||||
data = []
|
data = []
|
||||||
for address in BMConfigParser().addresses():
|
for address in self.config.addresses():
|
||||||
streamNumber = decodeAddress(address)[2]
|
streamNumber = decodeAddress(address)[2]
|
||||||
label = BMConfigParser().get(address, 'label')
|
label = self.config.get(address, 'label')
|
||||||
if self._method == 'listAddresses2':
|
if self._method == 'listAddresses2':
|
||||||
label = base64.b64encode(label)
|
label = base64.b64encode(label)
|
||||||
data.append({
|
data.append({
|
||||||
'label': label,
|
'label': label,
|
||||||
'address': address,
|
'address': address,
|
||||||
'stream': streamNumber,
|
'stream': streamNumber,
|
||||||
'enabled': BMConfigParser().safeGetBoolean(address, 'enabled'),
|
'enabled': self.config.safeGetBoolean(address, 'enabled'),
|
||||||
'chan': BMConfigParser().safeGetBoolean(address, 'chan')
|
'chan': self.config.safeGetBoolean(address, 'chan')
|
||||||
})
|
})
|
||||||
return {'addresses': data}
|
return {'addresses': data}
|
||||||
|
|
||||||
|
@ -426,12 +428,12 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler, object):
|
||||||
):
|
):
|
||||||
"""Handle a request to create a random address"""
|
"""Handle a request to create a random address"""
|
||||||
|
|
||||||
nonceTrialsPerByte = BMConfigParser().get(
|
nonceTrialsPerByte = self.config.get(
|
||||||
'bitmessagesettings', 'defaultnoncetrialsperbyte'
|
'bitmessagesettings', 'defaultnoncetrialsperbyte'
|
||||||
) if not totalDifficulty else int(
|
) if not totalDifficulty else int(
|
||||||
defaults.networkDefaultProofOfWorkNonceTrialsPerByte *
|
defaults.networkDefaultProofOfWorkNonceTrialsPerByte *
|
||||||
totalDifficulty)
|
totalDifficulty)
|
||||||
payloadLengthExtraBytes = BMConfigParser().get(
|
payloadLengthExtraBytes = self.config.get(
|
||||||
'bitmessagesettings', 'defaultpayloadlengthextrabytes'
|
'bitmessagesettings', 'defaultpayloadlengthextrabytes'
|
||||||
) if not smallMessageDifficulty else int(
|
) if not smallMessageDifficulty else int(
|
||||||
defaults.networkDefaultPayloadLengthExtraBytes *
|
defaults.networkDefaultPayloadLengthExtraBytes *
|
||||||
|
@ -464,12 +466,12 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler, object):
|
||||||
"""Handle a request to create a deterministic address"""
|
"""Handle a request to create a deterministic address"""
|
||||||
# pylint: disable=too-many-branches, too-many-statements
|
# pylint: disable=too-many-branches, too-many-statements
|
||||||
|
|
||||||
nonceTrialsPerByte = BMConfigParser().get(
|
nonceTrialsPerByte = self.config.get(
|
||||||
'bitmessagesettings', 'defaultnoncetrialsperbyte'
|
'bitmessagesettings', 'defaultnoncetrialsperbyte'
|
||||||
) if not totalDifficulty else int(
|
) if not totalDifficulty else int(
|
||||||
defaults.networkDefaultProofOfWorkNonceTrialsPerByte *
|
defaults.networkDefaultProofOfWorkNonceTrialsPerByte *
|
||||||
totalDifficulty)
|
totalDifficulty)
|
||||||
payloadLengthExtraBytes = BMConfigParser().get(
|
payloadLengthExtraBytes = self.config.get(
|
||||||
'bitmessagesettings', 'defaultpayloadlengthextrabytes'
|
'bitmessagesettings', 'defaultpayloadlengthextrabytes'
|
||||||
) if not smallMessageDifficulty else int(
|
) if not smallMessageDifficulty else int(
|
||||||
defaults.networkDefaultPayloadLengthExtraBytes *
|
defaults.networkDefaultPayloadLengthExtraBytes *
|
||||||
|
@ -612,16 +614,16 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler, object):
|
||||||
"""Handle a request to leave a chan"""
|
"""Handle a request to leave a chan"""
|
||||||
self._verifyAddress(address)
|
self._verifyAddress(address)
|
||||||
address = addBMIfNotPresent(address)
|
address = addBMIfNotPresent(address)
|
||||||
if not BMConfigParser().safeGetBoolean(address, 'chan'):
|
if not self.config.safeGetBoolean(address, 'chan'):
|
||||||
raise APIError(
|
raise APIError(
|
||||||
25, 'Specified address is not a chan address.'
|
25, 'Specified address is not a chan address.'
|
||||||
' Use deleteAddress API call instead.')
|
' Use deleteAddress API call instead.')
|
||||||
try:
|
try:
|
||||||
BMConfigParser().remove_section(address)
|
self.config.remove_section(address)
|
||||||
except ConfigParser.NoSectionError:
|
except ConfigParser.NoSectionError:
|
||||||
raise APIError(
|
raise APIError(
|
||||||
13, 'Could not find this address in your keys.dat file.')
|
13, 'Could not find this address in your keys.dat file.')
|
||||||
BMConfigParser().save()
|
self.config.save()
|
||||||
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
||||||
queues.UISignalQueue.put(('rerenderMessagelistToLabels', ''))
|
queues.UISignalQueue.put(('rerenderMessagelistToLabels', ''))
|
||||||
return "success"
|
return "success"
|
||||||
|
@ -632,11 +634,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler, object):
|
||||||
self._verifyAddress(address)
|
self._verifyAddress(address)
|
||||||
address = addBMIfNotPresent(address)
|
address = addBMIfNotPresent(address)
|
||||||
try:
|
try:
|
||||||
BMConfigParser().remove_section(address)
|
self.config.remove_section(address)
|
||||||
except ConfigParser.NoSectionError:
|
except ConfigParser.NoSectionError:
|
||||||
raise APIError(
|
raise APIError(
|
||||||
13, 'Could not find this address in your keys.dat file.')
|
13, 'Could not find this address in your keys.dat file.')
|
||||||
BMConfigParser().save()
|
self.config.save()
|
||||||
queues.UISignalQueue.put(('writeNewAddressToTable', ('', '', '')))
|
queues.UISignalQueue.put(('writeNewAddressToTable', ('', '', '')))
|
||||||
shared.reloadMyAddressHashes()
|
shared.reloadMyAddressHashes()
|
||||||
return "success"
|
return "success"
|
||||||
|
@ -829,7 +831,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler, object):
|
||||||
streamNumber, toRipe = self._verifyAddress(toAddress)[2:]
|
streamNumber, toRipe = self._verifyAddress(toAddress)[2:]
|
||||||
self._verifyAddress(fromAddress)
|
self._verifyAddress(fromAddress)
|
||||||
try:
|
try:
|
||||||
fromAddressEnabled = BMConfigParser().getboolean(
|
fromAddressEnabled = self.config.getboolean(
|
||||||
fromAddress, 'enabled')
|
fromAddress, 'enabled')
|
||||||
except BaseException:
|
except BaseException:
|
||||||
raise APIError(
|
raise APIError(
|
||||||
|
@ -837,7 +839,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler, object):
|
||||||
if not fromAddressEnabled:
|
if not fromAddressEnabled:
|
||||||
raise APIError(14, 'Your fromAddress is disabled. Cannot send.')
|
raise APIError(14, 'Your fromAddress is disabled. Cannot send.')
|
||||||
|
|
||||||
stealthLevel = BMConfigParser().safeGetInt(
|
stealthLevel = self.config.safeGetInt(
|
||||||
'bitmessagesettings', 'ackstealthlevel')
|
'bitmessagesettings', 'ackstealthlevel')
|
||||||
ackdata = genAckPayload(streamNumber, stealthLevel)
|
ackdata = genAckPayload(streamNumber, stealthLevel)
|
||||||
|
|
||||||
|
@ -892,10 +894,10 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler, object):
|
||||||
fromAddress = addBMIfNotPresent(fromAddress)
|
fromAddress = addBMIfNotPresent(fromAddress)
|
||||||
self._verifyAddress(fromAddress)
|
self._verifyAddress(fromAddress)
|
||||||
try:
|
try:
|
||||||
BMConfigParser().getboolean(fromAddress, 'enabled')
|
self.config.getboolean(fromAddress, 'enabled')
|
||||||
except BaseException:
|
except BaseException:
|
||||||
raise APIError(
|
raise APIError(
|
||||||
13, 'could not find your fromAddress in the keys.dat file.')
|
13, 'Could not find your fromAddress in the keys.dat file.')
|
||||||
streamNumber = decodeAddress(fromAddress)[2]
|
streamNumber = decodeAddress(fromAddress)[2]
|
||||||
ackdata = genAckPayload(streamNumber, 0)
|
ackdata = genAckPayload(streamNumber, 0)
|
||||||
toAddress = str_broadcast_subscribers
|
toAddress = str_broadcast_subscribers
|
||||||
|
@ -1186,20 +1188,20 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler, object):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise APIError(20, 'Invalid method: %s' % method)
|
raise APIError(20, 'Invalid method: %s' % method)
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
msg = "Unexpected internal error: %s" % e
|
msg = 'Unexpected API Failure - %s' % e
|
||||||
if 'argument' not in str(e):
|
if 'argument' not in str(e):
|
||||||
raise APIError(0, msg)
|
raise APIError(0, msg)
|
||||||
argcount = len(params)
|
argcount = len(params)
|
||||||
maxcount = func.func_code.co_argcount
|
maxcount = func.func_code.co_argcount
|
||||||
if argcount > maxcount:
|
if argcount > maxcount:
|
||||||
msg = (
|
msg = (
|
||||||
"Command %s takes at most %s parameters (%s given)" %
|
'Command %s takes at most %s parameters (%s given)' %
|
||||||
(method, maxcount, argcount))
|
(method, maxcount, argcount))
|
||||||
else:
|
else:
|
||||||
mincount = maxcount - len(func.func_defaults or [])
|
mincount = maxcount - len(func.func_defaults or [])
|
||||||
if argcount < mincount:
|
if argcount < mincount:
|
||||||
msg = (
|
msg = (
|
||||||
"Command %s takes at least %s parameters (%s given)" %
|
'Command %s takes at least %s parameters (%s given)' %
|
||||||
(method, mincount, argcount))
|
(method, mincount, argcount))
|
||||||
raise APIError(0, msg)
|
raise APIError(0, msg)
|
||||||
finally:
|
finally:
|
||||||
|
@ -1212,16 +1214,27 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler, object):
|
||||||
validuser = self.APIAuthenticateClient()
|
validuser = self.APIAuthenticateClient()
|
||||||
if not validuser:
|
if not validuser:
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
# ProtocolError?
|
||||||
return "RPC Username or password incorrect or HTTP header lacks authentication at all."
|
return "RPC Username or password incorrect or HTTP header lacks authentication at all."
|
||||||
|
|
||||||
|
_fault = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return self._handle_request(method, params)
|
return self._handle_request(method, params)
|
||||||
except APIError as e:
|
except APIError as e:
|
||||||
return str(e)
|
_fault = e
|
||||||
except varintDecodeError as e:
|
except varintDecodeError as e:
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
return "API Error 0026: Data contains a malformed varint. Some details: %s" % e
|
_fault = APIError(
|
||||||
|
26, 'Data contains a malformed varint. Some details: %s' %
|
||||||
|
e)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(e)
|
logger.exception(e)
|
||||||
|
_fault = APIError(21, 'Unexpected API Failure - %s' % e)
|
||||||
|
|
||||||
return "API Error 0021: Unexpected API Failure - %s" % e
|
if _fault:
|
||||||
|
if self.config.safeGet(
|
||||||
|
'bitmessagesettings', 'apivariant') == 'legacy':
|
||||||
|
return str(_fault)
|
||||||
|
else:
|
||||||
|
raise _fault # pylint: disable=raising-bad-type
|
||||||
|
|
|
@ -188,6 +188,8 @@ class Main(object):
|
||||||
'bitmessagesettings', 'apiusername', 'username')
|
'bitmessagesettings', 'apiusername', 'username')
|
||||||
config.set(
|
config.set(
|
||||||
'bitmessagesettings', 'apipassword', 'password')
|
'bitmessagesettings', 'apipassword', 'password')
|
||||||
|
config.set(
|
||||||
|
'bitmessagesettings', 'apivariant', 'legacy')
|
||||||
config.set(
|
config.set(
|
||||||
'bitmessagesettings', 'apinotifypath',
|
'bitmessagesettings', 'apinotifypath',
|
||||||
os.path.join(app_dir, 'tests', 'apinotify_handler.py')
|
os.path.join(app_dir, 'tests', 'apinotify_handler.py')
|
||||||
|
|
Loading…
Reference in New Issue
Block a user