diff --git a/src/api.py b/src/api.py index fa2a126a..0493ecb7 100644 --- a/src/api.py +++ b/src/api.py @@ -1,12 +1,19 @@ +# pylint: disable=too-many-locals,too-many-lines,no-self-use,too-many-public-methods,too-many-branches +# pylint: disable=too-many-statements +""" +src/api.py +========== + # Copyright (c) 2012-2016 Jonathan Warren # Copyright (c) 2012-2018 The Bitmessage developers -""" This is not what you run to run the Bitmessage API. Instead, enable the API ( https://bitmessage.org/wiki/API ) and optionally enable daemon mode ( https://bitmessage.org/wiki/Daemon ) then run bitmessagemain.py. """ +from __future__ import absolute_import + import base64 import errno import hashlib @@ -20,35 +27,31 @@ from binascii import hexlify, unhexlify from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer from struct import pack -import shared -from addresses import ( - decodeAddress, addBMIfNotPresent, decodeVarint, - calculateInventoryHash, varintDecodeError) -from bmconfigparser import BMConfigParser +from version import softwareVersion + import defaults import helper_inbox import helper_sent import helper_threading - -import state -import queues -import shutdown import network.stats - -# Classes -from helper_sql import sqlQuery, sqlExecute, SqlBulkExecute, sqlStoredProcedure -from helper_ackPayload import genAckPayload -from debug import logger -from inventory import Inventory -from version import softwareVersion - -# Helper Functions import proofofwork +import queues +import shared +import shutdown +import state +from addresses import addBMIfNotPresent, calculateInventoryHash, decodeAddress, decodeVarint, varintDecodeError +from bmconfigparser import BMConfigParser +from debug import logger +from helper_ackPayload import genAckPayload +from helper_sql import SqlBulkExecute, sqlExecute, sqlQuery, sqlStoredProcedure +from inventory import Inventory str_chan = '[chan]' class APIError(Exception): + """APIError exception class""" + def __init__(self, error_number, error_message): super(APIError, self).__init__() self.error_number = error_number @@ -59,9 +62,12 @@ class APIError(Exception): class StoppableXMLRPCServer(SimpleXMLRPCServer): + """A SimpleXMLRPCServer that honours state.shutdown""" allow_reuse_address = True def serve_forever(self): + """Start the SimpleXMLRPCServer""" + # pylint: disable=arguments-differ while state.shutdown == 0: self.handle_request() @@ -83,7 +89,7 @@ class singleAPI(threading.Thread, helper_threading.StoppableThread): )) s.shutdown(socket.SHUT_RDWR) s.close() - except: + except BaseException: pass def run(self): @@ -129,19 +135,24 @@ class singleAPI(threading.Thread, helper_threading.StoppableThread): se.serve_forever() -# This is one of several classes that constitute the API -# This class was written by Vaibhav Bhatia. -# Modified by Jonathan Warren (Atheros). -# http://code.activestate.com/recipes/501148-xmlrpc-serverclient-which-does-cookie-handling-and/ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): - """The main API handler""" - def do_POST(self): - # Handles the HTTP POST request. - # Attempts to interpret all HTTP POST requests as XML-RPC calls, - # which are forwarded to the server's _dispatch method for handling. + """ + This is one of several classes that constitute the API - # Note: this method is the same as in SimpleXMLRPCRequestHandler, - # just hacked to handle cookies + This class was written by Vaibhav Bhatia. Modified by Jonathan Warren (Atheros). + http://code.activestate.com/recipes/501148-xmlrpc-serverclient-which-does-cookie-handling-and/ + """ + + def do_POST(self): + """ + Handles the HTTP POST request. + + Attempts to interpret all HTTP POST requests as XML-RPC calls, + which are forwarded to the server's _dispatch method for handling. + + Note: this method is the same as in SimpleXMLRPCRequestHandler, + just hacked to handle cookies + """ # Check that the path is legal if not self.is_rpc_path_valid(): @@ -167,10 +178,10 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): # SimpleXMLRPCDispatcher. To maintain backwards compatibility, # check to see if a subclass implements _dispatch and dispatch # using that method if present. - response = self.server._marshaled_dispatch( + response = self.server._marshaled_dispatch( # pylint: disable=protected-access data, getattr(self, '_dispatch', None) ) - except: # This should only happen if the module is buggy + except BaseException: # This should only happen if the module is buggy # internal error, report as HTTP server error self.send_response(500) self.end_headers() @@ -194,22 +205,21 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): self.connection.shutdown(1) def APIAuthenticateClient(self): + """Predicate to check for valid API credentials in the request header""" + if 'Authorization' in self.headers: # handle Basic authentication - enctype, encstr = self.headers.get('Authorization').split() + _, encstr = self.headers.get('Authorization').split() emailid, password = encstr.decode('base64').split(':') return ( - emailid == - BMConfigParser().get('bitmessagesettings', 'apiusername') - and password == - BMConfigParser().get('bitmessagesettings', 'apipassword') + emailid == BMConfigParser().get('bitmessagesettings', 'apiusername') and + password == BMConfigParser().get('bitmessagesettings', 'apipassword') ) else: logger.warning( 'Authentication failed because header lacks' ' Authentication field') time.sleep(2) - return False return False @@ -224,6 +234,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 22, "Decode error - %s. Had trouble while decoding string: %r" % (e, text) ) + return None def _verifyAddress(self, address): status, addressVersionNumber, streamNumber, ripe = \ @@ -239,15 +250,10 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): if status == 'invalidcharacters': raise APIError(9, 'Invalid characters in address: ' + address) if status == 'versiontoohigh': - raise APIError( - 10, - 'Address version number too high (or zero) in address: ' - + address - ) + raise APIError(10, 'Address version number too high (or zero) in address: ' + address) if status == 'varintmalformed': raise APIError(26, 'Malformed varint in address: ' + address) - raise APIError( - 7, 'Could not decode address: %s : %s' % (address, status)) + raise APIError(7, 'Could not decode address: %s : %s' % (address, status)) if addressVersionNumber < 2 or addressVersionNumber > 4: raise APIError( 11, 'The address version number currently must be 2, 3 or 4.' @@ -264,9 +270,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): # Request Handlers def HandleListAddresses(self, method): + """Handle a request to list addresses""" + data = '{"addresses":[' for addressInKeysFile in BMConfigParser().addresses(): - status, addressVersionNumber, streamNumber, hash01 = decodeAddress( + status, addressVersionNumber, streamNumber, hash01 = decodeAddress( # pylint: disable=unused-variable addressInKeysFile) if len(data) > 20: data += ',' @@ -284,11 +292,13 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 'enabled': BMConfigParser().getboolean(addressInKeysFile, 'enabled'), 'chan': chan - }, indent=4, separators=(',', ': ')) + }, indent=4, separators=(',', ': ')) data += ']}' return data def HandleListAddressBookEntries(self, params): + """Handle a request to list address book entries""" + if len(params) == 1: label, = params label = self._decode(label, "base64") @@ -312,6 +322,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return data def HandleAddAddressBookEntry(self, params): + """Handle a request to add an address book entry""" + if len(params) != 2: raise APIError(0, "I need label and address") address, label = params @@ -331,6 +343,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return "Added address %s to address book" % address def HandleDeleteAddressBookEntry(self, params): + """Handle a request to delete an address book entry""" + if len(params) != 1: raise APIError(0, "I need an address") address, = params @@ -343,8 +357,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return "Deleted address book entry for %s if it existed" % address def HandleCreateRandomAddress(self, params): - if len(params) == 0: + """Handle a request to create a random address""" + + if not params: raise APIError(0, 'I need parameters!') + elif len(params) == 1: label, = params eighteenByteRipe = False @@ -361,25 +378,22 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): elif len(params) == 3: label, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte - * totalDifficulty) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 4: label, eighteenByteRipe, totalDifficulty, \ smallMessageDifficulty = params nonceTrialsPerByte = int( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte - * totalDifficulty) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = int( - defaults.networkDefaultPayloadLengthExtraBytes - * smallMessageDifficulty) + defaults.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) else: raise APIError(0, 'Too many parameters!') label = self._decode(label, "base64") try: unicode(label, 'utf-8') - except: + except BaseException: raise APIError(17, 'Label is not valid UTF-8 data.') queues.apiAddressGeneratorReturnQueue.queue.clear() streamNumberForAddress = 1 @@ -390,8 +404,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return queues.apiAddressGeneratorReturnQueue.get() def HandleCreateDeterministicAddresses(self, params): - if len(params) == 0: + """Handle a request to create a deterministic address""" + + if not params: raise APIError(0, 'I need parameters!') + elif len(params) == 1: passphrase, = params numberOfAddresses = 1 @@ -402,6 +419,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 2: passphrase, numberOfAddresses = params addressVersionNumber = 0 @@ -411,6 +429,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 3: passphrase, numberOfAddresses, addressVersionNumber = params streamNumber = 0 @@ -419,6 +438,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 4: passphrase, numberOfAddresses, addressVersionNumber, \ streamNumber = params @@ -427,6 +447,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 5: passphrase, numberOfAddresses, addressVersionNumber, \ streamNumber, eighteenByteRipe = params @@ -434,27 +455,26 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 6: passphrase, numberOfAddresses, addressVersionNumber, \ streamNumber, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte - * totalDifficulty) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 7: passphrase, numberOfAddresses, addressVersionNumber, \ streamNumber, eighteenByteRipe, totalDifficulty, \ smallMessageDifficulty = params nonceTrialsPerByte = int( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte - * totalDifficulty) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = int( - defaults.networkDefaultPayloadLengthExtraBytes - * smallMessageDifficulty) + defaults.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) else: raise APIError(0, 'Too many parameters!') - if len(passphrase) == 0: + if not passphrase: raise APIError(1, 'The specified passphrase is blank.') if not isinstance(eighteenByteRipe, bool): raise APIError( @@ -505,12 +525,14 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return data def HandleGetDeterministicAddress(self, params): + """Handle a request to get a deterministic address""" + if len(params) != 3: raise APIError(0, 'I need exactly 3 parameters.') passphrase, addressVersionNumber, streamNumber = params numberOfAddresses = 1 eighteenByteRipe = False - if len(passphrase) == 0: + if not passphrase: raise APIError(1, 'The specified passphrase is blank.') passphrase = self._decode(passphrase, "base64") if addressVersionNumber != 3 and addressVersionNumber != 4: @@ -532,19 +554,23 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return queues.apiAddressGeneratorReturnQueue.get() def HandleCreateChan(self, params): - if len(params) == 0: + """Handle a request to create a chan""" + + if not params: raise APIError(0, 'I need parameters.') + elif len(params) == 1: passphrase, = params passphrase = self._decode(passphrase, "base64") - if len(passphrase) == 0: + + if not passphrase: raise APIError(1, 'The specified passphrase is blank.') # It would be nice to make the label the passphrase but it is # possible that the passphrase contains non-utf-8 characters. try: unicode(passphrase, 'utf-8') label = str_chan + ' ' + passphrase - except: + except BaseException: label = str_chan + ' ' + repr(passphrase) addressVersionNumber = 4 @@ -557,29 +583,31 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): passphrase, True )) queueReturn = queues.apiAddressGeneratorReturnQueue.get() - if len(queueReturn) == 0: + if not queueReturn: raise APIError(24, 'Chan address is already present.') address = queueReturn[0] return address def HandleJoinChan(self, params): + """Handle a request to join a chan""" + if len(params) < 2: raise APIError(0, 'I need two parameters.') elif len(params) == 2: passphrase, suppliedAddress = params passphrase = self._decode(passphrase, "base64") - if len(passphrase) == 0: + if not passphrase: raise APIError(1, 'The specified passphrase is blank.') # It would be nice to make the label the passphrase but it is # possible that the passphrase contains non-utf-8 characters. try: unicode(passphrase, 'utf-8') label = str_chan + ' ' + passphrase - except: + except BaseException: label = str_chan + ' ' + repr(passphrase) - status, addressVersionNumber, streamNumber, toRipe = \ - self._verifyAddress(suppliedAddress) + status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress( # pylint: disable=unused-variable + suppliedAddress) suppliedAddress = addBMIfNotPresent(suppliedAddress) queues.apiAddressGeneratorReturnQueue.queue.clear() queues.addressGeneratorQueue.put(( @@ -591,20 +619,19 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): if addressGeneratorReturnValue[0] == \ 'chan name does not match address': raise APIError(18, 'Chan name does not match address.') - if len(addressGeneratorReturnValue) == 0: + if not addressGeneratorReturnValue: raise APIError(24, 'Chan address is already present.') - # TODO: this variable is not used to anything - # in case we ever want it for anything. - # createdAddress = addressGeneratorReturnValue[0] return "success" def HandleLeaveChan(self, params): - if len(params) == 0: + """Handle a request to leave a chan""" + + if not params: raise APIError(0, 'I need parameters.') elif len(params) == 1: address, = params - status, addressVersionNumber, streamNumber, toRipe = \ - self._verifyAddress(address) + # pylint: disable=unused-variable + status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address) address = addBMIfNotPresent(address) if not BMConfigParser().has_section(address): raise APIError( @@ -619,12 +646,14 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return 'success' def HandleDeleteAddress(self, params): - if len(params) == 0: + """Handle a request to delete an address""" + + if not params: raise APIError(0, 'I need parameters.') elif len(params) == 1: address, = params - status, addressVersionNumber, streamNumber, toRipe = \ - self._verifyAddress(address) + # pylint: disable=unused-variable + status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address) address = addBMIfNotPresent(address) if not BMConfigParser().has_section(address): raise APIError( @@ -637,7 +666,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): shared.reloadMyAddressHashes() return 'success' - def HandleGetAllInboxMessages(self, params): + def HandleGetAllInboxMessages(self, params): # pylint: disable=unused-argument + """Handle a request to get all inbox messages""" + queryreturn = sqlQuery( "SELECT msgid, toaddress, fromaddress, subject, received, message," " encodingtype, read FROM inbox where folder='inbox'" @@ -663,7 +694,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): data += ']}' return data - def HandleGetAllInboxMessageIds(self, params): + def HandleGetAllInboxMessageIds(self, params): # pylint: disable=unused-argument + """Handle a request to get all inbox message IDs""" + queryreturn = sqlQuery( "SELECT msgid FROM inbox where folder='inbox' ORDER BY received") data = '{"inboxMessageIds":[' @@ -677,7 +710,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return data def HandleGetInboxMessageById(self, params): - if len(params) == 0: + """Handle a request to get an inbox messsage by ID""" + + if not params: raise APIError(0, 'I need parameters!') elif len(params) == 1: msgid = self._decode(params[0], "hex") @@ -718,7 +753,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): data += ']}' return data - def HandleGetAllSentMessages(self, params): + def HandleGetAllSentMessages(self, params): # pylint: disable=unused-argument + """Handle a request to get all sent messages""" + queryreturn = sqlQuery( "SELECT msgid, toaddress, fromaddress, subject, lastactiontime," " message, encodingtype, status, ackdata FROM sent" @@ -745,7 +782,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): data += ']}' return data - def HandleGetAllSentMessageIds(self, params): + def HandleGetAllSentMessageIds(self, params): # pylint: disable=unused-argument + """Handle a request to get all sent message IDs""" + queryreturn = sqlQuery( "SELECT msgid FROM sent where folder='sent'" " ORDER BY lastactiontime" @@ -761,7 +800,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return data def HandleInboxMessagesByReceiver(self, params): - if len(params) == 0: + """Handle a request to get inbox messages by receiver""" + + if not params: raise APIError(0, 'I need parameters!') toAddress = params[0] queryreturn = sqlQuery( @@ -788,7 +829,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return data def HandleGetSentMessageById(self, params): - if len(params) == 0: + """Handle a request to get a sent message by ID""" + + if not params: raise APIError(0, 'I need parameters!') msgid = self._decode(params[0], "hex") queryreturn = sqlQuery( @@ -816,7 +859,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return data def HandleGetSentMessagesByAddress(self, params): - if len(params) == 0: + """Handle a request to get sent messages by address""" + + if not params: raise APIError(0, 'I need parameters!') fromAddress = params[0] queryreturn = sqlQuery( @@ -828,7 +873,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): data = '{"sentMessages":[' for row in queryreturn: msgid, toAddress, fromAddress, subject, lastactiontime, message, \ - encodingtype, status, ackdata = row + encodingtype, status, ackdata = row # pylint: disable=unused-variable subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: @@ -847,7 +892,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return data def HandleGetSentMessagesByAckData(self, params): - if len(params) == 0: + """Handle a request to get sent messages by ack data""" + + if not params: raise APIError(0, 'I need parameters!') ackData = self._decode(params[0], "hex") queryreturn = sqlQuery( @@ -875,7 +922,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return data def HandleTrashMessage(self, params): - if len(params) == 0: + """Handle a request to trash a message by ID""" + + if not params: raise APIError(0, 'I need parameters!') msgid = self._decode(params[0], "hex") @@ -886,32 +935,42 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return 'Trashed message (assuming message existed).' def HandleTrashInboxMessage(self, params): - if len(params) == 0: + """Handle a request to trash an inbox message by ID""" + + if not params: raise APIError(0, 'I need parameters!') msgid = self._decode(params[0], "hex") helper_inbox.trash(msgid) return 'Trashed inbox message (assuming message existed).' def HandleTrashSentMessage(self, params): - if len(params) == 0: + """Handle a request to trash a sent message by ID""" + + if not params: raise APIError(0, 'I need parameters!') msgid = self._decode(params[0], "hex") sqlExecute('''UPDATE sent SET folder='trash' WHERE msgid=?''', msgid) return 'Trashed sent message (assuming message existed).' def HandleSendMessage(self, params): - if len(params) == 0: + """Handle a request to send a message""" + + if not params: raise APIError(0, 'I need parameters!') + elif len(params) == 4: toAddress, fromAddress, subject, message = params encodingType = 2 TTL = 4 * 24 * 60 * 60 + elif len(params) == 5: toAddress, fromAddress, subject, message, encodingType = params TTL = 4 * 24 * 60 * 60 + elif len(params) == 6: toAddress, fromAddress, subject, message, encodingType, TTL = \ params + if encodingType not in [2, 3]: raise APIError(6, 'The encoding type must be 2 or 3.') subject = self._decode(subject, "base64") @@ -924,13 +983,14 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): TTL = 28 * 24 * 60 * 60 toAddress = addBMIfNotPresent(toAddress) fromAddress = addBMIfNotPresent(fromAddress) + # pylint: disable=unused-variable status, addressVersionNumber, streamNumber, toRipe = \ self._verifyAddress(toAddress) self._verifyAddress(fromAddress) try: fromAddressEnabled = BMConfigParser().getboolean( fromAddress, 'enabled') - except: + except BaseException: raise APIError( 13, 'Could not find your fromAddress in the keys.dat file.') if not fromAddressEnabled: @@ -963,7 +1023,6 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): if queryreturn != []: for row in queryreturn: toLabel, = row - # apiSignalQueue.put(('displayNewSentMessage',(toAddress,toLabel,fromAddress,subject,message,ackdata))) queues.UISignalQueue.put(('displayNewSentMessage', ( toAddress, toLabel, fromAddress, subject, message, ackdata))) @@ -972,19 +1031,25 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return hexlify(ackdata) def HandleSendBroadcast(self, params): - if len(params) == 0: + """Handle a request to send a broadcast message""" + + if not params: raise APIError(0, 'I need parameters!') + if len(params) == 3: fromAddress, subject, message = params encodingType = 2 TTL = 4 * 24 * 60 * 60 + elif len(params) == 4: fromAddress, subject, message, encodingType = params TTL = 4 * 24 * 60 * 60 elif len(params) == 5: fromAddress, subject, message, encodingType, TTL = params + if encodingType not in [2, 3]: raise APIError(6, 'The encoding type must be 2 or 3.') + subject = self._decode(subject, "base64") message = self._decode(message, "base64") if len(subject + message) > (2 ** 18 - 500): @@ -997,7 +1062,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): self._verifyAddress(fromAddress) try: BMConfigParser().getboolean(fromAddress, 'enabled') - except: + except BaseException: raise APIError( 13, 'could not find your fromAddress in the keys.dat file.') streamNumber = decodeAddress(fromAddress)[2] @@ -1030,6 +1095,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return hexlify(ackdata) def HandleGetStatus(self, params): + """Handle a request to get the status of a sent message""" + if len(params) != 1: raise APIError(0, 'I need one parameter!') ackdata, = params @@ -1046,7 +1113,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return status def HandleAddSubscription(self, params): - if len(params) == 0: + """Handle a request to add a subscription""" + + if not params: raise APIError(0, 'I need parameters!') if len(params) == 1: address, = params @@ -1056,7 +1125,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): label = self._decode(label, "base64") try: unicode(label, 'utf-8') - except: + except BaseException: raise APIError(17, 'Label is not valid UTF-8 data.') if len(params) > 2: raise APIError(0, 'I need either 1 or 2 parameters!') @@ -1076,6 +1145,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return 'Added subscription.' def HandleDeleteSubscription(self, params): + """Handle a request to delete a subscription""" + if len(params) != 1: raise APIError(0, 'I need 1 parameter!') address, = params @@ -1086,7 +1157,10 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): queues.UISignalQueue.put(('rerenderSubscriptions', '')) return 'Deleted subscription if it existed.' - def ListSubscriptions(self, params): + def ListSubscriptions(self, params): # pylint: disable=unused-argument + """Handle a request to list susbcriptions""" + + # pylint: disable=unused-variable queryreturn = sqlQuery( "SELECT label, address, enabled FROM subscriptions") data = {'subscriptions': []} @@ -1101,6 +1175,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return json.dumps(data, indent=4, separators=(',', ': ')) def HandleDisseminatePreEncryptedMsg(self, params): + """Handle a request to disseminate an encrypted message""" + # The device issuing this command to PyBitmessage supplies a msg # object that has already been encrypted but which still needs the POW # to be done. PyBitmessage accepts this msg object and sends it out @@ -1113,18 +1189,30 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): encryptedPayload = self._decode(encryptedPayload, "hex") # Let us do the POW and attach it to the front target = 2**64 / ( - (len(encryptedPayload) + requiredPayloadLengthExtraBytes + 8) - * requiredAverageProofOfWorkNonceTrialsPerByte) + ( + len(encryptedPayload) + requiredPayloadLengthExtraBytes + 8 + ) * requiredAverageProofOfWorkNonceTrialsPerByte + ) with shared.printLock: - print '(For msg message via API) Doing proof of work. Total required difficulty:', float(requiredAverageProofOfWorkNonceTrialsPerByte) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte, 'Required small message difficulty:', float(requiredPayloadLengthExtraBytes) / defaults.networkDefaultPayloadLengthExtraBytes + print( + '(For msg message via API) Doing proof of work. Total required difficulty:', + float( + requiredAverageProofOfWorkNonceTrialsPerByte + ) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte, + 'Required small message difficulty:', + float(requiredPayloadLengthExtraBytes) / defaults.networkDefaultPayloadLengthExtraBytes, + ) powStartTime = time.time() initialHash = hashlib.sha512(encryptedPayload).digest() trialValue, nonce = proofofwork.run(target, initialHash) with shared.printLock: print '(For msg message via API) Found proof of work', trialValue, 'Nonce:', nonce try: - print 'POW took', int(time.time() - powStartTime), 'seconds.', nonce / (time.time() - powStartTime), 'nonce trials per second.' - except: + print( + 'POW took', int(time.time() - powStartTime), 'seconds.', + nonce / (time.time() - powStartTime), 'nonce trials per second.', + ) + except BaseException: pass encryptedPayload = pack('>Q', nonce) + encryptedPayload toStreamNumber = decodeVarint(encryptedPayload[16:26])[0] @@ -1140,14 +1228,18 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): queues.invQueue.put((toStreamNumber, inventoryHash)) def HandleTrashSentMessageByAckDAta(self, params): + """Handle a request to trash a sent message by ackdata""" + # This API method should only be used when msgid is not available - if len(params) == 0: + if not params: raise APIError(0, 'I need parameters!') ackdata = self._decode(params[0], "hex") sqlExecute("UPDATE sent SET folder='trash' WHERE ackdata=?", ackdata) return 'Trashed sent message (assuming message existed).' - def HandleDissimatePubKey(self, params): + def HandleDissimatePubKey(self, params): # pylint: disable=unused-argument + """Handle a request to disseminate a public key""" + # The device issuing this command to PyBitmessage supplies a pubkey # object to be disseminated to the rest of the Bitmessage network. # PyBitmessage accepts this pubkey object and sends it out to the rest @@ -1159,9 +1251,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): payload = self._decode(payload, "hex") # Let us do the POW - target = 2 ** 64 / ( - (len(payload) + defaults.networkDefaultPayloadLengthExtraBytes - + 8) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte) + target = 2 ** 64 / (( + len(payload) + defaults.networkDefaultPayloadLengthExtraBytes + 8 + ) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte) print '(For pubkey message via API) Doing proof of work...' initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -1169,18 +1261,19 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): payload = pack('>Q', nonce) + payload pubkeyReadPosition = 8 # bypass the nonce - if payload[pubkeyReadPosition:pubkeyReadPosition+4] == \ + if payload[pubkeyReadPosition:pubkeyReadPosition + 4] == \ '\x00\x00\x00\x00': # if this pubkey uses 8 byte time pubkeyReadPosition += 8 else: pubkeyReadPosition += 4 + # pylint: disable=unused-variable addressVersion, addressVersionLength = decodeVarint( - payload[pubkeyReadPosition:pubkeyReadPosition+10]) + payload[pubkeyReadPosition:pubkeyReadPosition + 10]) pubkeyReadPosition += addressVersionLength pubkeyStreamNumber = decodeVarint( - payload[pubkeyReadPosition:pubkeyReadPosition+10])[0] + payload[pubkeyReadPosition:pubkeyReadPosition + 10])[0] inventoryHash = calculateInventoryHash(payload) - objectType = 1 # TODO: support v4 pubkeys + objectType = 1 # .. todo::: support v4 pubkeys TTL = 28 * 24 * 60 * 60 Inventory()[inventoryHash] = ( objectType, pubkeyStreamNumber, payload, int(time.time()) + TTL, '' @@ -1190,6 +1283,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): queues.invQueue.put((pubkeyStreamNumber, inventoryHash)) def HandleGetMessageDataByDestinationHash(self, params): + """Handle a request to get message data by destination hash""" + # Method will eventually be used by a particular Android app to # select relevant messages. Do not yet add this to the api # doc. @@ -1214,8 +1309,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): readPosition = 16 # Nonce length + time length # Stream Number length readPosition += decodeVarint( - payload[readPosition:readPosition+10])[1] - t = (payload[readPosition:readPosition+32], hash01) + payload[readPosition:readPosition + 10])[1] + t = (payload[readPosition:readPosition + 32], hash01) sql.execute("UPDATE inventory SET tag=? WHERE hash=?", *t) queryreturn = sqlQuery( @@ -1230,10 +1325,12 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): data += ']}' return data - def HandleClientStatus(self, params): - if len(network.stats.connectedHostsList()) == 0: + def HandleClientStatus(self, params): # pylint: disable=unused-argument + """Handle a request to get the status of the client""" + + if network.stats.connectedHostsList(): networkStatus = 'notConnected' - elif len(network.stats.connectedHostsList()) > 0 \ + elif not network.stats.connectedHostsList() \ and not shared.clientHasReceivedIncomingConnections: networkStatus = 'connectedButHaveNotReceivedIncomingConnections' else: @@ -1246,9 +1343,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 'networkStatus': networkStatus, 'softwareName': 'PyBitmessage', 'softwareVersion': softwareVersion - }, indent=4, separators=(',', ': ')) + }, indent=4, separators=(',', ': ')) def HandleDecodeAddress(self, params): + """Handle a request to decode an address""" + # Return a meaningful decoding of an address. if len(params) != 1: raise APIError(0, 'I need 1 parameter!') @@ -1259,29 +1358,41 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 'addressVersion': addressVersion, 'streamNumber': streamNumber, 'ripe': base64.b64encode(ripe) - }, indent=4, separators=(',', ': ')) + }, indent=4, separators=(',', ': ')) def HandleHelloWorld(self, params): + """Test two string params""" + a, b = params return a + '-' + b def HandleAdd(self, params): + """Test two numeric params""" + a, b = params return a + b def HandleStatusBar(self, params): + """Handle a request to update the status bar""" + message, = params queues.UISignalQueue.put(('updateStatusBar', message)) def HandleDeleteAndVacuum(self, params): + """Handle a request to run the deleteandvacuum stored procedure""" + if not params: sqlStoredProcedure('deleteandvacuume') return 'done' + return None def HandleShutdown(self, params): + """Handle a request to huutdown the client""" + if not params: shutdown.doCleanShutdown() return 'done' + return None handlers = {} handlers['helloWorld'] = HandleHelloWorld @@ -1348,6 +1459,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return self.handlers[method](self, params) def _dispatch(self, method, params): + # pylint: disable=attribute-defined-outside-init self.cookies = [] validuser = self.APIAuthenticateClient() diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 22c38a62..3a3db962 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -1,6 +1,9 @@ # -*- coding: utf-8 -*- # pylint: disable=too-many-instance-attributes,too-many-locals,too-many-statements,attribute-defined-outside-init """ +src/bitmessageqt/settings.py +============================ + Form implementation generated from reading ui file 'settings.ui' Created: Thu Dec 25 23:21:20 2014 @@ -9,8 +12,6 @@ Created: Thu Dec 25 23:21:20 2014 WARNING! All changes made in this file will be lost! """ -from __future__ import absolute_import - from sys import platform from PyQt4 import QtCore, QtGui @@ -18,7 +19,6 @@ from PyQt4 import QtCore, QtGui from . import bitmessage_icons_rc # pylint: disable=unused-import from .languagebox import LanguageBox - try: _fromUtf8 = QtCore.QString.fromUtf8 except AttributeError: