@ -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 network . stats
import proofofwork
import queues
import shared
import shutdown
import network . stats
# Classes
from helper_sql import sqlQuery , sqlExecute , SqlBulkExecute , sqlStoredProcedure
from helper_ackPayload import genAckPayload
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
from version import softwareVersion
# Helper Functions
import proofofwork
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 """
"""
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 /
"""
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.
"""
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
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 ( )