2016-05-01 08:34:04 +02:00
# Copyright (c) 2012-2016 Jonathan Warren
2018-04-08 17:28:08 +02:00
# Copyright (c) 2012-2018 The Bitmessage developers
2014-01-13 01:56:30 +01:00
2018-04-08 17:28:08 +02:00
"""
2014-01-13 01:56:30 +01:00
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
2015-03-21 12:53:09 +01:00
( https : / / bitmessage . org / wiki / Daemon ) then run bitmessagemain . py .
2014-01-13 01:56:30 +01:00
"""
2017-06-03 02:53:13 +02:00
import base64
2018-06-28 15:09:23 +02:00
import errno
2018-04-08 17:28:08 +02:00
import hashlib
2014-01-13 01:56:30 +01:00
import json
2018-06-28 15:09:23 +02:00
import random # nosec
import socket
import subprocess
import threading
2018-04-08 17:28:08 +02:00
import time
2017-06-03 02:53:13 +02:00
from binascii import hexlify , unhexlify
2018-04-08 17:28:08 +02:00
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler , SimpleXMLRPCServer
from struct import pack
2014-01-13 01:56:30 +01:00
import shared
2018-04-08 17:28:08 +02:00
from addresses import (
decodeAddress , addBMIfNotPresent , decodeVarint ,
2018-04-10 09:14:32 +02:00
calculateInventoryHash , varintDecodeError )
2017-02-22 09:34:54 +01:00
from bmconfigparser import BMConfigParser
2017-02-08 20:37:42 +01:00
import defaults
2014-01-13 01:56:30 +01:00
import helper_inbox
import helper_sent
2018-06-28 15:09:23 +02:00
import helper_threading
2014-01-13 01:56:30 +01:00
2017-01-11 17:00:00 +01:00
import state
2017-02-08 13:41:56 +01:00
import queues
2017-08-21 10:39:03 +02:00
import shutdown
2017-06-09 10:07:51 +02:00
import network . stats
2014-01-13 01:56:30 +01:00
# Classes
2018-04-10 09:14:32 +02:00
from helper_sql import sqlQuery , sqlExecute , SqlBulkExecute , sqlStoredProcedure
2017-09-30 11:19:44 +02:00
from helper_ackPayload import genAckPayload
2014-01-13 01:56:30 +01:00
from debug import logger
2017-01-10 21:17:25 +01:00
from inventory import Inventory
2017-01-11 14:27:19 +01:00
from version import softwareVersion
2014-01-13 01:56:30 +01:00
# Helper Functions
import proofofwork
str_chan = ' [chan] '
class APIError ( Exception ) :
def __init__ ( self , error_number , error_message ) :
super ( APIError , self ) . __init__ ( )
self . error_number = error_number
self . error_message = error_message
2018-04-08 17:28:08 +02:00
2014-01-13 01:56:30 +01:00
def __str__ ( self ) :
return " API Error %04i : %s " % ( self . error_number , self . error_message )
2015-11-24 01:55:17 +01:00
class StoppableXMLRPCServer ( SimpleXMLRPCServer ) :
2017-08-09 17:29:23 +02:00
allow_reuse_address = True
2015-11-24 01:55:17 +01:00
def serve_forever ( self ) :
2017-01-14 23:20:15 +01:00
while state . shutdown == 0 :
2015-11-24 01:55:17 +01:00
self . handle_request ( )
2018-06-28 15:09:23 +02:00
# This thread, of which there is only one, runs the API.
class singleAPI ( threading . Thread , helper_threading . StoppableThread ) :
2018-09-05 12:56:06 +02:00
""" API thread """
2018-06-28 15:09:23 +02:00
def __init__ ( self ) :
threading . Thread . __init__ ( self , name = " singleAPI " )
self . initStop ( )
def stopThread ( self ) :
super ( singleAPI , self ) . stopThread ( )
s = socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
try :
s . connect ( (
BMConfigParser ( ) . get ( ' bitmessagesettings ' , ' apiinterface ' ) ,
BMConfigParser ( ) . getint ( ' bitmessagesettings ' , ' apiport ' )
) )
s . shutdown ( socket . SHUT_RDWR )
s . close ( )
except :
pass
def run ( self ) :
port = BMConfigParser ( ) . getint ( ' bitmessagesettings ' , ' apiport ' )
try :
2018-09-05 12:56:06 +02:00
getattr ( errno , ' WSAEADDRINUSE ' )
except AttributeError :
2018-06-28 15:09:23 +02:00
errno . WSAEADDRINUSE = errno . EADDRINUSE
for attempt in range ( 50 ) :
try :
if attempt > 0 :
port = random . randint ( 32767 , 65535 )
se = StoppableXMLRPCServer (
( BMConfigParser ( ) . get (
' bitmessagesettings ' , ' apiinterface ' ) ,
port ) ,
MySimpleXMLRPCRequestHandler , True , True )
except socket . error as e :
if e . errno in ( errno . EADDRINUSE , errno . WSAEADDRINUSE ) :
continue
else :
if attempt > 0 :
BMConfigParser ( ) . set (
" bitmessagesettings " , " apiport " , str ( port ) )
BMConfigParser ( ) . save ( )
break
se . register_introspection_functions ( )
apiNotifyPath = BMConfigParser ( ) . safeGet (
' bitmessagesettings ' , ' apinotifypath ' )
if apiNotifyPath :
logger . info ( ' Trying to call %s ' , apiNotifyPath )
try :
subprocess . call ( [ apiNotifyPath , " startingUp " ] )
except OSError :
logger . warning (
' Failed to call %s , removing apinotifypath setting ' ,
apiNotifyPath )
BMConfigParser ( ) . remove_option (
' bitmessagesettings ' , ' apinotifypath ' )
se . serve_forever ( )
2014-01-13 01:56:30 +01:00
# This is one of several classes that constitute the API
2018-04-08 17:28:08 +02:00
# This class was written by Vaibhav Bhatia.
# Modified by Jonathan Warren (Atheros).
2014-01-13 01:56:30 +01:00
# http://code.activestate.com/recipes/501148-xmlrpc-serverclient-which-does-cookie-handling-and/
class MySimpleXMLRPCRequestHandler ( SimpleXMLRPCRequestHandler ) :
2018-09-05 12:56:06 +02:00
""" The main API handler """
2014-01-13 01:56:30 +01:00
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 ( ) :
self . report_404 ( )
return
try :
# Get arguments by reading body of request.
# We read this in chunks to avoid straining
# socket.read(); around the 10 or 15Mb mark, some platforms
# begin to have problems (bug #792570).
max_chunk_size = 10 * 1024 * 1024
size_remaining = int ( self . headers [ " content-length " ] )
L = [ ]
while size_remaining :
chunk_size = min ( size_remaining , max_chunk_size )
L . append ( self . rfile . read ( chunk_size ) )
size_remaining - = len ( L [ - 1 ] )
data = ' ' . join ( L )
# In previous versions of SimpleXMLRPCServer, _dispatch
# could be overridden in this class, instead of in
# 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 (
data , getattr ( self , ' _dispatch ' , None )
)
except : # This should only happen if the module is buggy
# internal error, report as HTTP server error
self . send_response ( 500 )
self . end_headers ( )
else :
# got a valid XML RPC response
self . send_response ( 200 )
self . send_header ( " Content-type " , " text/xml " )
self . send_header ( " Content-length " , str ( len ( response ) ) )
# HACK :start -> sends cookies here
if self . cookies :
for cookie in self . cookies :
self . send_header ( ' Set-Cookie ' , cookie . output ( header = ' ' ) )
# HACK :end
self . end_headers ( )
self . wfile . write ( response )
# shut down the connection
self . wfile . flush ( )
self . connection . shutdown ( 1 )
def APIAuthenticateClient ( self ) :
if ' Authorization ' in self . headers :
# handle Basic authentication
2018-04-08 17:28:08 +02:00
enctype , encstr = self . headers . get ( ' Authorization ' ) . split ( )
emailid , password = encstr . decode ( ' base64 ' ) . split ( ' : ' )
return (
emailid ==
BMConfigParser ( ) . get ( ' bitmessagesettings ' , ' apiusername ' )
and password ==
BMConfigParser ( ) . get ( ' bitmessagesettings ' , ' apipassword ' )
)
2014-01-13 01:56:30 +01:00
else :
2018-04-08 17:28:08 +02:00
logger . warning (
' Authentication failed because header lacks '
' Authentication field ' )
2014-01-13 01:56:30 +01:00
time . sleep ( 2 )
return False
return False
def _decode ( self , text , decode_type ) :
try :
2017-06-03 02:53:13 +02:00
if decode_type == ' hex ' :
return unhexlify ( text )
elif decode_type == ' base64 ' :
return base64 . b64decode ( text )
2014-01-13 01:56:30 +01:00
except Exception as e :
2018-04-08 17:28:08 +02:00
raise APIError (
22 , " Decode error - %s . Had trouble while decoding string: %r "
% ( e , text )
)
2014-01-13 01:56:30 +01:00
def _verifyAddress ( self , address ) :
2018-04-08 17:28:08 +02:00
status , addressVersionNumber , streamNumber , ripe = \
decodeAddress ( address )
2014-01-13 01:56:30 +01:00
if status != ' success ' :
2018-04-08 17:28:08 +02:00
logger . warning (
' API Error 0007: Could not decode address %s . Status: %s . ' ,
address , status
)
2014-01-13 01:56:30 +01:00
if status == ' checksumfailed ' :
raise APIError ( 8 , ' Checksum failed for address: ' + address )
if status == ' invalidcharacters ' :
raise APIError ( 9 , ' Invalid characters in address: ' + address )
if status == ' versiontoohigh ' :
2018-04-08 17:28:08 +02:00
raise APIError (
10 ,
' Address version number too high (or zero) in address: '
+ address
)
2014-08-27 09:14:32 +02:00
if status == ' varintmalformed ' :
raise APIError ( 26 , ' Malformed varint in address: ' + address )
2018-04-08 17:28:08 +02:00
raise APIError (
7 , ' Could not decode address: %s : %s ' % ( address , status ) )
2014-01-13 01:56:30 +01:00
if addressVersionNumber < 2 or addressVersionNumber > 4 :
2018-04-08 17:28:08 +02:00
raise APIError (
11 , ' The address version number currently must be 2, 3 or 4. '
' Others aren \' t supported. Check the address. '
)
2014-01-13 01:56:30 +01:00
if streamNumber != 1 :
2018-04-08 17:28:08 +02:00
raise APIError (
12 , ' The stream number must be 1. Others aren \' t supported. '
' Check the address. '
)
2014-01-13 01:56:30 +01:00
return ( status , addressVersionNumber , streamNumber , ripe )
2018-04-08 17:28:08 +02:00
# Request Handlers
2015-09-28 20:55:40 +02:00
def HandleListAddresses ( self , method ) :
data = ' { " addresses " :[ '
2017-05-15 12:18:07 +02:00
for addressInKeysFile in BMConfigParser ( ) . addresses ( ) :
status , addressVersionNumber , streamNumber , hash01 = decodeAddress (
addressInKeysFile )
if len ( data ) > 20 :
data + = ' , '
if BMConfigParser ( ) . has_option ( addressInKeysFile , ' chan ' ) :
chan = BMConfigParser ( ) . getboolean ( addressInKeysFile , ' chan ' )
else :
chan = False
label = BMConfigParser ( ) . get ( addressInKeysFile , ' label ' )
if method == ' listAddresses2 ' :
2017-06-03 02:53:13 +02:00
label = base64 . b64encode ( label )
2018-04-08 17:28:08 +02:00
data + = json . dumps ( {
' label ' : label ,
' address ' : addressInKeysFile ,
' stream ' : streamNumber ,
' enabled ' :
BMConfigParser ( ) . getboolean ( addressInKeysFile , ' enabled ' ) ,
' chan ' : chan
} , indent = 4 , separators = ( ' , ' , ' : ' ) )
2015-03-21 12:53:09 +01:00
data + = ' ]} '
return data
def HandleListAddressBookEntries ( self , params ) :
2015-09-28 20:55:40 +02:00
if len ( params ) == 1 :
label , = params
label = self . _decode ( label , " base64 " )
2018-04-08 17:28:08 +02:00
queryreturn = sqlQuery (
" SELECT label, address from addressbook WHERE label = ? " ,
label )
2015-09-28 20:55:40 +02:00
elif len ( params ) > 1 :
raise APIError ( 0 , " Too many paremeters, max 1 " )
else :
2018-04-08 17:28:08 +02:00
queryreturn = sqlQuery ( " SELECT label, address from addressbook " )
2015-03-21 12:53:09 +01:00
data = ' { " addresses " :[ '
for row in queryreturn :
label , address = row
label = shared . fixPotentiallyInvalidUTF8Data ( label )
if len ( data ) > 20 :
data + = ' , '
2018-04-08 17:28:08 +02:00
data + = json . dumps ( {
' label ' : base64 . b64encode ( label ) ,
' address ' : address } , indent = 4 , separators = ( ' , ' , ' : ' ) )
2015-03-21 12:53:09 +01:00
data + = ' ]} '
return data
def HandleAddAddressBookEntry ( self , params ) :
if len ( params ) != 2 :
raise APIError ( 0 , " I need label and address " )
address , label = params
label = self . _decode ( label , " base64 " )
address = addBMIfNotPresent ( address )
self . _verifyAddress ( address )
2018-04-08 17:28:08 +02:00
queryreturn = sqlQuery (
" SELECT address FROM addressbook WHERE address=? " , address )
2015-03-21 12:53:09 +01:00
if queryreturn != [ ] :
2018-04-08 17:28:08 +02:00
raise APIError (
16 , ' You already have this address in your address book. ' )
2015-03-21 12:53:09 +01:00
sqlExecute ( " INSERT INTO addressbook VALUES(?,?) " , label , address )
2018-04-08 17:28:08 +02:00
queues . UISignalQueue . put ( ( ' rerenderMessagelistFromLabels ' , ' ' ) )
queues . UISignalQueue . put ( ( ' rerenderMessagelistToLabels ' , ' ' ) )
queues . UISignalQueue . put ( ( ' rerenderAddressBook ' , ' ' ) )
2015-03-21 12:53:09 +01:00
return " Added address %s to address book " % address
def HandleDeleteAddressBookEntry ( self , params ) :
if len ( params ) != 1 :
raise APIError ( 0 , " I need an address " )
address , = params
address = addBMIfNotPresent ( address )
self . _verifyAddress ( address )
sqlExecute ( ' DELETE FROM addressbook WHERE address=? ' , address )
2018-04-08 17:28:08 +02:00
queues . UISignalQueue . put ( ( ' rerenderMessagelistFromLabels ' , ' ' ) )
queues . UISignalQueue . put ( ( ' rerenderMessagelistToLabels ' , ' ' ) )
queues . UISignalQueue . put ( ( ' rerenderAddressBook ' , ' ' ) )
2015-03-21 12:53:09 +01:00
return " Deleted address book entry for %s if it existed " % address
def HandleCreateRandomAddress ( self , params ) :
if len ( params ) == 0 :
raise APIError ( 0 , ' I need parameters! ' )
elif len ( params ) == 1 :
label , = params
eighteenByteRipe = False
2017-01-11 14:27:19 +01:00
nonceTrialsPerByte = BMConfigParser ( ) . get (
2015-03-21 12:53:09 +01:00
' bitmessagesettings ' , ' defaultnoncetrialsperbyte ' )
2017-01-11 14:27:19 +01:00
payloadLengthExtraBytes = BMConfigParser ( ) . get (
2015-03-21 12:53:09 +01:00
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
elif len ( params ) == 2 :
label , eighteenByteRipe = params
2017-01-11 14:27:19 +01:00
nonceTrialsPerByte = BMConfigParser ( ) . get (
2015-03-21 12:53:09 +01:00
' bitmessagesettings ' , ' defaultnoncetrialsperbyte ' )
2017-01-11 14:27:19 +01:00
payloadLengthExtraBytes = BMConfigParser ( ) . get (
2015-03-21 12:53:09 +01:00
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
elif len ( params ) == 3 :
label , eighteenByteRipe , totalDifficulty = params
nonceTrialsPerByte = int (
2018-04-08 17:28:08 +02:00
defaults . networkDefaultProofOfWorkNonceTrialsPerByte
* totalDifficulty )
2017-01-11 14:27:19 +01:00
payloadLengthExtraBytes = BMConfigParser ( ) . get (
2015-03-21 12:53:09 +01:00
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
elif len ( params ) == 4 :
2018-04-08 17:28:08 +02:00
label , eighteenByteRipe , totalDifficulty , \
smallMessageDifficulty = params
2015-03-21 12:53:09 +01:00
nonceTrialsPerByte = int (
2018-04-08 17:28:08 +02:00
defaults . networkDefaultProofOfWorkNonceTrialsPerByte
* totalDifficulty )
2015-03-21 12:53:09 +01:00
payloadLengthExtraBytes = int (
2018-04-08 17:28:08 +02:00
defaults . networkDefaultPayloadLengthExtraBytes
* smallMessageDifficulty )
2015-03-21 12:53:09 +01:00
else :
raise APIError ( 0 , ' Too many parameters! ' )
label = self . _decode ( label , " base64 " )
try :
unicode ( label , ' utf-8 ' )
except :
raise APIError ( 17 , ' Label is not valid UTF-8 data. ' )
2017-02-08 13:41:56 +01:00
queues . apiAddressGeneratorReturnQueue . queue . clear ( )
2015-03-21 12:53:09 +01:00
streamNumberForAddress = 1
2017-02-08 13:41:56 +01:00
queues . addressGeneratorQueue . put ( (
2018-04-08 17:28:08 +02:00
' createRandomAddress ' , 4 , streamNumberForAddress , label , 1 , " " ,
eighteenByteRipe , nonceTrialsPerByte , payloadLengthExtraBytes
) )
2017-02-08 13:41:56 +01:00
return queues . apiAddressGeneratorReturnQueue . get ( )
2015-03-21 12:53:09 +01:00
def HandleCreateDeterministicAddresses ( self , params ) :
if len ( params ) == 0 :
raise APIError ( 0 , ' I need parameters! ' )
elif len ( params ) == 1 :
passphrase , = params
2014-01-13 01:56:30 +01:00
numberOfAddresses = 1
2015-03-21 12:53:09 +01:00
addressVersionNumber = 0
streamNumber = 0
2015-03-21 12:45:56 +01:00
eighteenByteRipe = False
2017-01-11 14:27:19 +01:00
nonceTrialsPerByte = BMConfigParser ( ) . get (
2015-03-21 12:53:09 +01:00
' bitmessagesettings ' , ' defaultnoncetrialsperbyte ' )
2017-01-11 14:27:19 +01:00
payloadLengthExtraBytes = BMConfigParser ( ) . get (
2015-03-21 12:53:09 +01:00
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
elif len ( params ) == 2 :
passphrase , numberOfAddresses = params
addressVersionNumber = 0
streamNumber = 0
eighteenByteRipe = False
2017-01-11 14:27:19 +01:00
nonceTrialsPerByte = BMConfigParser ( ) . get (
2015-03-21 12:53:09 +01:00
' bitmessagesettings ' , ' defaultnoncetrialsperbyte ' )
2017-01-11 14:27:19 +01:00
payloadLengthExtraBytes = BMConfigParser ( ) . get (
2015-03-21 12:53:09 +01:00
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
elif len ( params ) == 3 :
passphrase , numberOfAddresses , addressVersionNumber = params
streamNumber = 0
eighteenByteRipe = False
2017-01-11 14:27:19 +01:00
nonceTrialsPerByte = BMConfigParser ( ) . get (
2015-03-21 12:53:09 +01:00
' bitmessagesettings ' , ' defaultnoncetrialsperbyte ' )
2017-01-11 14:27:19 +01:00
payloadLengthExtraBytes = BMConfigParser ( ) . get (
2015-03-21 12:53:09 +01:00
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
elif len ( params ) == 4 :
2018-04-08 17:28:08 +02:00
passphrase , numberOfAddresses , addressVersionNumber , \
streamNumber = params
2015-03-21 12:53:09 +01:00
eighteenByteRipe = False
2017-01-11 14:27:19 +01:00
nonceTrialsPerByte = BMConfigParser ( ) . get (
2015-03-21 12:53:09 +01:00
' bitmessagesettings ' , ' defaultnoncetrialsperbyte ' )
2017-01-11 14:27:19 +01:00
payloadLengthExtraBytes = BMConfigParser ( ) . get (
2015-03-21 12:53:09 +01:00
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
elif len ( params ) == 5 :
2018-04-08 17:28:08 +02:00
passphrase , numberOfAddresses , addressVersionNumber , \
streamNumber , eighteenByteRipe = params
2017-01-11 14:27:19 +01:00
nonceTrialsPerByte = BMConfigParser ( ) . get (
2015-03-21 12:53:09 +01:00
' bitmessagesettings ' , ' defaultnoncetrialsperbyte ' )
2017-01-11 14:27:19 +01:00
payloadLengthExtraBytes = BMConfigParser ( ) . get (
2015-03-21 12:53:09 +01:00
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
elif len ( params ) == 6 :
2018-04-08 17:28:08 +02:00
passphrase , numberOfAddresses , addressVersionNumber , \
streamNumber , eighteenByteRipe , totalDifficulty = params
2015-03-21 12:53:09 +01:00
nonceTrialsPerByte = int (
2018-04-08 17:28:08 +02:00
defaults . networkDefaultProofOfWorkNonceTrialsPerByte
* totalDifficulty )
2017-01-11 14:27:19 +01:00
payloadLengthExtraBytes = BMConfigParser ( ) . get (
2015-03-21 12:53:09 +01:00
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
elif len ( params ) == 7 :
2018-04-08 17:28:08 +02:00
passphrase , numberOfAddresses , addressVersionNumber , \
streamNumber , eighteenByteRipe , totalDifficulty , \
smallMessageDifficulty = params
2015-03-21 12:53:09 +01:00
nonceTrialsPerByte = int (
2018-04-08 17:28:08 +02:00
defaults . networkDefaultProofOfWorkNonceTrialsPerByte
* totalDifficulty )
2015-03-21 12:53:09 +01:00
payloadLengthExtraBytes = int (
2018-04-08 17:28:08 +02:00
defaults . networkDefaultPayloadLengthExtraBytes
* smallMessageDifficulty )
2015-03-21 12:53:09 +01:00
else :
raise APIError ( 0 , ' Too many parameters! ' )
if len ( passphrase ) == 0 :
raise APIError ( 1 , ' The specified passphrase is blank. ' )
if not isinstance ( eighteenByteRipe , bool ) :
2018-04-08 17:28:08 +02:00
raise APIError (
23 , ' Bool expected in eighteenByteRipe, saw %s instead ' %
type ( eighteenByteRipe ) )
2015-03-21 12:53:09 +01:00
passphrase = self . _decode ( passphrase , " base64 " )
2018-04-08 17:28:08 +02:00
# 0 means "just use the proper addressVersionNumber"
if addressVersionNumber == 0 :
2014-01-13 01:56:30 +01:00
addressVersionNumber = 4
2015-03-21 12:53:09 +01:00
if addressVersionNumber != 3 and addressVersionNumber != 4 :
2018-04-08 17:28:08 +02:00
raise APIError (
2 , ' The address version number currently must be 3, 4, or 0 '
' (which means auto-select). %i isn \' t supported. ' %
addressVersionNumber )
2015-03-21 12:53:09 +01:00
if streamNumber == 0 : # 0 means "just use the most available stream"
2014-01-13 01:56:30 +01:00
streamNumber = 1
2015-03-21 12:53:09 +01:00
if streamNumber != 1 :
2018-04-08 17:28:08 +02:00
raise APIError (
3 , ' The stream number must be 1 (or 0 which means '
' auto-select). Others aren \' t supported. ' )
2015-03-21 12:53:09 +01:00
if numberOfAddresses == 0 :
2018-04-08 17:28:08 +02:00
raise APIError (
4 , ' Why would you ask me to generate 0 addresses for you? ' )
2015-03-21 12:53:09 +01:00
if numberOfAddresses > 999 :
2018-04-08 17:28:08 +02:00
raise APIError (
5 , ' You have (accidentally?) specified too many addresses to '
' make. Maximum 999. This check only exists to prevent '
' mischief; if you really want to create more addresses than '
' this, contact the Bitmessage developers and we can modify '
' the check or you can do it yourself by searching the source '
' code for this message. ' )
2017-02-08 13:41:56 +01:00
queues . apiAddressGeneratorReturnQueue . queue . clear ( )
2018-04-08 17:28:08 +02:00
logger . debug (
' Requesting that the addressGenerator create %s addresses. ' ,
numberOfAddresses )
queues . addressGeneratorQueue . put ( (
' createDeterministicAddresses ' , addressVersionNumber , streamNumber ,
' unused API address ' , numberOfAddresses , passphrase ,
eighteenByteRipe , nonceTrialsPerByte , payloadLengthExtraBytes
) )
2015-03-21 12:53:09 +01:00
data = ' { " addresses " :[ '
2017-02-08 13:41:56 +01:00
queueReturn = queues . apiAddressGeneratorReturnQueue . get ( )
2015-03-21 12:53:09 +01:00
for item in queueReturn :
if len ( data ) > 20 :
data + = ' , '
data + = " \" " + item + " \" "
data + = ' ]} '
return data
def HandleGetDeterministicAddress ( self , params ) :
if len ( params ) != 3 :
raise APIError ( 0 , ' I need exactly 3 parameters. ' )
passphrase , addressVersionNumber , streamNumber = params
numberOfAddresses = 1
eighteenByteRipe = False
if len ( passphrase ) == 0 :
raise APIError ( 1 , ' The specified passphrase is blank. ' )
passphrase = self . _decode ( passphrase , " base64 " )
if addressVersionNumber != 3 and addressVersionNumber != 4 :
2018-04-08 17:28:08 +02:00
raise APIError (
2 , ' The address version number currently must be 3 or 4. %i '
' isn \' t supported. ' % addressVersionNumber )
2015-03-21 12:53:09 +01:00
if streamNumber != 1 :
2018-04-08 17:28:08 +02:00
raise APIError (
3 , ' The stream number must be 1. Others aren \' t supported. ' )
2017-02-08 13:41:56 +01:00
queues . apiAddressGeneratorReturnQueue . queue . clear ( )
2018-04-08 17:28:08 +02:00
logger . debug (
' Requesting that the addressGenerator create %s addresses. ' ,
numberOfAddresses )
queues . addressGeneratorQueue . put ( (
' getDeterministicAddress ' , addressVersionNumber , streamNumber ,
' unused API address ' , numberOfAddresses , passphrase ,
eighteenByteRipe
) )
2017-02-08 13:41:56 +01:00
return queues . apiAddressGeneratorReturnQueue . get ( )
2015-03-21 12:53:09 +01:00
2015-09-28 20:55:40 +02:00
def HandleCreateChan ( self , params ) :
if len ( params ) == 0 :
raise APIError ( 0 , ' I need parameters. ' )
elif len ( params ) == 1 :
passphrase , = params
passphrase = self . _decode ( passphrase , " base64 " )
if len ( passphrase ) == 0 :
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 :
label = str_chan + ' ' + repr ( passphrase )
addressVersionNumber = 4
streamNumber = 1
2017-02-08 13:41:56 +01:00
queues . apiAddressGeneratorReturnQueue . queue . clear ( )
2018-04-08 17:28:08 +02:00
logger . debug (
' Requesting that the addressGenerator create chan %s . ' , passphrase )
queues . addressGeneratorQueue . put ( (
' createChan ' , addressVersionNumber , streamNumber , label ,
passphrase , True
) )
2017-02-08 13:41:56 +01:00
queueReturn = queues . apiAddressGeneratorReturnQueue . get ( )
2015-09-28 20:55:40 +02:00
if len ( queueReturn ) == 0 :
raise APIError ( 24 , ' Chan address is already present. ' )
address = queueReturn [ 0 ]
return address
def HandleJoinChan ( self , params ) :
if len ( params ) < 2 :
raise APIError ( 0 , ' I need two parameters. ' )
elif len ( params ) == 2 :
2018-04-08 17:28:08 +02:00
passphrase , suppliedAddress = params
2015-09-28 20:55:40 +02:00
passphrase = self . _decode ( passphrase , " base64 " )
if len ( passphrase ) == 0 :
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 :
label = str_chan + ' ' + repr ( passphrase )
2018-04-08 17:28:08 +02:00
status , addressVersionNumber , streamNumber , toRipe = \
self . _verifyAddress ( suppliedAddress )
2015-09-28 20:55:40 +02:00
suppliedAddress = addBMIfNotPresent ( suppliedAddress )
2017-02-08 13:41:56 +01:00
queues . apiAddressGeneratorReturnQueue . queue . clear ( )
2018-04-08 17:28:08 +02:00
queues . addressGeneratorQueue . put ( (
' joinChan ' , suppliedAddress , label , passphrase , True
) )
addressGeneratorReturnValue = \
queues . apiAddressGeneratorReturnQueue . get ( )
2015-09-28 20:55:40 +02:00
2018-04-08 17:28:08 +02:00
if addressGeneratorReturnValue [ 0 ] == \
' chan name does not match address ' :
2015-09-28 20:55:40 +02:00
raise APIError ( 18 , ' Chan name does not match address. ' )
if len ( addressGeneratorReturnValue ) == 0 :
raise APIError ( 24 , ' Chan address is already present. ' )
2018-04-08 17:28:08 +02:00
# TODO: this variable is not used to anything
# in case we ever want it for anything.
# createdAddress = addressGeneratorReturnValue[0]
2015-09-28 20:55:40 +02:00
return " success "
def HandleLeaveChan ( self , params ) :
if len ( params ) == 0 :
raise APIError ( 0 , ' I need parameters. ' )
elif len ( params ) == 1 :
address , = params
2018-04-08 17:28:08 +02:00
status , addressVersionNumber , streamNumber , toRipe = \
self . _verifyAddress ( address )
2015-09-28 20:55:40 +02:00
address = addBMIfNotPresent ( address )
2017-01-11 14:27:19 +01:00
if not BMConfigParser ( ) . has_section ( address ) :
2018-04-08 17:28:08 +02:00
raise APIError (
13 , ' Could not find this address in your keys.dat file. ' )
2017-01-11 14:27:19 +01:00
if not BMConfigParser ( ) . safeGetBoolean ( address , ' chan ' ) :
2018-04-08 17:28:08 +02:00
raise APIError (
25 , ' Specified address is not a chan address. '
' Use deleteAddress API call instead. ' )
2017-01-11 14:27:19 +01:00
BMConfigParser ( ) . remove_section ( address )
2017-01-11 17:00:00 +01:00
with open ( state . appdata + ' keys.dat ' , ' wb ' ) as configfile :
2017-01-11 14:27:19 +01:00
BMConfigParser ( ) . write ( configfile )
2015-09-28 20:55:40 +02:00
return ' success '
def HandleDeleteAddress ( self , params ) :
if len ( params ) == 0 :
raise APIError ( 0 , ' I need parameters. ' )
elif len ( params ) == 1 :
address , = params
2018-04-08 17:28:08 +02:00
status , addressVersionNumber , streamNumber , toRipe = \
self . _verifyAddress ( address )
2015-09-28 20:55:40 +02:00
address = addBMIfNotPresent ( address )
2017-01-11 14:27:19 +01:00
if not BMConfigParser ( ) . has_section ( address ) :
2018-04-08 17:28:08 +02:00
raise APIError (
13 , ' Could not find this address in your keys.dat file. ' )
2017-01-11 14:27:19 +01:00
BMConfigParser ( ) . remove_section ( address )
2017-01-11 17:00:00 +01:00
with open ( state . appdata + ' keys.dat ' , ' wb ' ) as configfile :
2017-01-11 14:27:19 +01:00
BMConfigParser ( ) . write ( configfile )
2018-04-08 17:28:08 +02:00
queues . UISignalQueue . put ( ( ' rerenderMessagelistFromLabels ' , ' ' ) )
queues . UISignalQueue . put ( ( ' rerenderMessagelistToLabels ' , ' ' ) )
2015-09-28 20:55:40 +02:00
shared . reloadMyAddressHashes ( )
return ' success '
def HandleGetAllInboxMessages ( self , params ) :
queryreturn = sqlQuery (
2018-04-08 17:28:08 +02:00
" SELECT msgid, toaddress, fromaddress, subject, received, message, "
" encodingtype, read FROM inbox where folder= ' inbox ' "
" ORDER BY received "
)
2015-09-28 20:55:40 +02:00
data = ' { " inboxMessages " :[ '
for row in queryreturn :
2018-04-08 17:28:08 +02:00
msgid , toAddress , fromAddress , subject , received , message , \
encodingtype , read = row
2015-09-28 20:55:40 +02:00
subject = shared . fixPotentiallyInvalidUTF8Data ( subject )
message = shared . fixPotentiallyInvalidUTF8Data ( message )
if len ( data ) > 25 :
data + = ' , '
2018-04-08 17:28:08 +02:00
data + = json . dumps ( {
' msgid ' : hexlify ( msgid ) ,
' toAddress ' : toAddress ,
' fromAddress ' : fromAddress ,
' subject ' : base64 . b64encode ( subject ) ,
' message ' : base64 . b64encode ( message ) ,
' encodingType ' : encodingtype ,
' receivedTime ' : received ,
' read ' : read } , indent = 4 , separators = ( ' , ' , ' : ' ) )
2015-09-28 20:55:40 +02:00
data + = ' ]} '
return data
def HandleGetAllInboxMessageIds ( self , params ) :
queryreturn = sqlQuery (
2018-04-08 17:28:08 +02:00
" SELECT msgid FROM inbox where folder= ' inbox ' ORDER BY received " )
2015-09-28 20:55:40 +02:00
data = ' { " inboxMessageIds " :[ '
for row in queryreturn :
msgid = row [ 0 ]
if len ( data ) > 25 :
data + = ' , '
2018-04-08 17:28:08 +02:00
data + = json . dumps (
{ ' msgid ' : hexlify ( msgid ) } , indent = 4 , separators = ( ' , ' , ' : ' ) )
2015-09-28 20:55:40 +02:00
data + = ' ]} '
return data
def HandleGetInboxMessageById ( self , params ) :
if len ( params ) == 0 :
raise APIError ( 0 , ' I need parameters! ' )
elif len ( params ) == 1 :
2015-03-21 12:45:56 +01:00
msgid = self . _decode ( params [ 0 ] , " hex " )
2015-03-21 12:53:09 +01:00
elif len ( params ) > = 2 :
msgid = self . _decode ( params [ 0 ] , " hex " )
readStatus = params [ 1 ]
if not isinstance ( readStatus , bool ) :
2018-04-08 17:28:08 +02:00
raise APIError (
23 , ' Bool expected in readStatus, saw %s instead. ' %
type ( readStatus ) )
queryreturn = sqlQuery (
" SELECT read FROM inbox WHERE msgid=? " , msgid )
2015-03-21 12:53:09 +01:00
# UPDATE is slow, only update if status is different
if queryreturn != [ ] and ( queryreturn [ 0 ] [ 0 ] == 1 ) != readStatus :
2018-04-08 17:28:08 +02:00
sqlExecute (
" UPDATE inbox set read = ? WHERE msgid=? " ,
readStatus , msgid )
2017-02-08 13:41:56 +01:00
queues . UISignalQueue . put ( ( ' changedInboxUnread ' , None ) )
2018-04-08 17:28:08 +02:00
queryreturn = sqlQuery (
" SELECT msgid, toaddress, fromaddress, subject, received, message, "
" encodingtype, read FROM inbox WHERE msgid=? " , msgid
)
2015-03-21 12:53:09 +01:00
data = ' { " inboxMessage " :[ '
for row in queryreturn :
2018-04-08 17:28:08 +02:00
msgid , toAddress , fromAddress , subject , received , message , \
encodingtype , read = row
2015-03-21 12:53:09 +01:00
subject = shared . fixPotentiallyInvalidUTF8Data ( subject )
message = shared . fixPotentiallyInvalidUTF8Data ( message )
2018-04-08 17:28:08 +02:00
data + = json . dumps ( {
' msgid ' : hexlify ( msgid ) ,
' toAddress ' : toAddress ,
' fromAddress ' : fromAddress ,
' subject ' : base64 . b64encode ( subject ) ,
' message ' : base64 . b64encode ( message ) ,
' encodingType ' : encodingtype ,
' receivedTime ' : received ,
' read ' : read } , indent = 4 , separators = ( ' , ' , ' : ' ) )
2014-01-13 01:56:30 +01:00
data + = ' ]} '
return data
2015-03-21 12:53:09 +01:00
def HandleGetAllSentMessages ( self , params ) :
2018-04-08 17:28:08 +02:00
queryreturn = sqlQuery (
" SELECT msgid, toaddress, fromaddress, subject, lastactiontime, "
" message, encodingtype, status, ackdata FROM sent "
" WHERE folder= ' sent ' ORDER BY lastactiontime "
)
2015-03-21 12:53:09 +01:00
data = ' { " sentMessages " :[ '
for row in queryreturn :
2018-04-08 17:28:08 +02:00
msgid , toAddress , fromAddress , subject , lastactiontime , message , \
encodingtype , status , ackdata = row
2015-03-21 12:53:09 +01:00
subject = shared . fixPotentiallyInvalidUTF8Data ( subject )
message = shared . fixPotentiallyInvalidUTF8Data ( message )
if len ( data ) > 25 :
data + = ' , '
2018-04-08 17:28:08 +02:00
data + = json . dumps ( {
' msgid ' : hexlify ( msgid ) ,
' toAddress ' : toAddress ,
' fromAddress ' : fromAddress ,
' subject ' : base64 . b64encode ( subject ) ,
' message ' : base64 . b64encode ( message ) ,
' encodingType ' : encodingtype ,
' lastActionTime ' : lastactiontime ,
' status ' : status ,
' ackData ' : hexlify ( ackdata ) } , indent = 4 , separators = ( ' , ' , ' : ' ) )
2015-03-21 12:53:09 +01:00
data + = ' ]} '
return data
def HandleGetAllSentMessageIds ( self , params ) :
2018-04-08 17:28:08 +02:00
queryreturn = sqlQuery (
" SELECT msgid FROM sent where folder= ' sent ' "
" ORDER BY lastactiontime "
)
2015-03-21 12:53:09 +01:00
data = ' { " sentMessageIds " :[ '
for row in queryreturn :
msgid = row [ 0 ]
if len ( data ) > 25 :
data + = ' , '
2018-04-08 17:28:08 +02:00
data + = json . dumps (
{ ' msgid ' : hexlify ( msgid ) } , indent = 4 , separators = ( ' , ' , ' : ' ) )
2015-03-21 12:53:09 +01:00
data + = ' ]} '
return data
def HandleInboxMessagesByReceiver ( self , params ) :
if len ( params ) == 0 :
raise APIError ( 0 , ' I need parameters! ' )
toAddress = params [ 0 ]
2018-04-08 17:28:08 +02:00
queryreturn = sqlQuery (
" SELECT msgid, toaddress, fromaddress, subject, received, message, "
" encodingtype FROM inbox WHERE folder= ' inbox ' AND toAddress=? " ,
toAddress )
2015-03-21 12:53:09 +01:00
data = ' { " inboxMessages " :[ '
for row in queryreturn :
2018-04-08 17:28:08 +02:00
msgid , toAddress , fromAddress , subject , received , message , \
encodingtype = row
2015-03-21 12:53:09 +01:00
subject = shared . fixPotentiallyInvalidUTF8Data ( subject )
message = shared . fixPotentiallyInvalidUTF8Data ( message )
if len ( data ) > 25 :
data + = ' , '
2018-04-08 17:28:08 +02:00
data + = json . dumps ( {
' msgid ' : hexlify ( msgid ) ,
' toAddress ' : toAddress ,
' fromAddress ' : fromAddress ,
' subject ' : base64 . b64encode ( subject ) ,
' message ' : base64 . b64encode ( message ) ,
' encodingType ' : encodingtype ,
' receivedTime ' : received } , indent = 4 , separators = ( ' , ' , ' : ' ) )
2015-03-21 12:53:09 +01:00
data + = ' ]} '
return data
def HandleGetSentMessageById ( self , params ) :
if len ( params ) == 0 :
raise APIError ( 0 , ' I need parameters! ' )
msgid = self . _decode ( params [ 0 ] , " hex " )
2018-04-08 17:28:08 +02:00
queryreturn = sqlQuery (
" SELECT msgid, toaddress, fromaddress, subject, lastactiontime, "
" message, encodingtype, status, ackdata FROM sent WHERE msgid=? " ,
msgid
)
2015-03-21 12:53:09 +01:00
data = ' { " sentMessage " :[ '
for row in queryreturn :
2018-04-08 17:28:08 +02:00
msgid , toAddress , fromAddress , subject , lastactiontime , message , \
encodingtype , status , ackdata = row
2015-03-21 12:53:09 +01:00
subject = shared . fixPotentiallyInvalidUTF8Data ( subject )
message = shared . fixPotentiallyInvalidUTF8Data ( message )
2018-04-08 17:28:08 +02:00
data + = json . dumps ( {
' msgid ' : hexlify ( msgid ) ,
' toAddress ' : toAddress ,
' fromAddress ' : fromAddress ,
' subject ' : base64 . b64encode ( subject ) ,
' message ' : base64 . b64encode ( message ) ,
' encodingType ' : encodingtype ,
' lastActionTime ' : lastactiontime ,
' status ' : status ,
' ackData ' : hexlify ( ackdata ) } , indent = 4 , separators = ( ' , ' , ' : ' ) )
2014-01-13 01:56:30 +01:00
data + = ' ]} '
return data
2015-03-21 12:53:09 +01:00
def HandleGetSentMessagesByAddress ( self , params ) :
if len ( params ) == 0 :
raise APIError ( 0 , ' I need parameters! ' )
fromAddress = params [ 0 ]
2018-04-08 17:28:08 +02:00
queryreturn = sqlQuery (
" SELECT msgid, toaddress, fromaddress, subject, lastactiontime, "
" message, encodingtype, status, ackdata FROM sent "
" WHERE folder= ' sent ' AND fromAddress=? ORDER BY lastactiontime " ,
fromAddress
)
2015-03-21 12:53:09 +01:00
data = ' { " sentMessages " :[ '
for row in queryreturn :
2018-04-08 17:28:08 +02:00
msgid , toAddress , fromAddress , subject , lastactiontime , message , \
encodingtype , status , ackdata = row
2015-03-21 12:53:09 +01:00
subject = shared . fixPotentiallyInvalidUTF8Data ( subject )
message = shared . fixPotentiallyInvalidUTF8Data ( message )
if len ( data ) > 25 :
data + = ' , '
2018-04-08 17:28:08 +02:00
data + = json . dumps ( {
' msgid ' : hexlify ( msgid ) ,
' toAddress ' : toAddress ,
' fromAddress ' : fromAddress ,
' subject ' : base64 . b64encode ( subject ) ,
' message ' : base64 . b64encode ( message ) ,
' encodingType ' : encodingtype ,
' lastActionTime ' : lastactiontime ,
' status ' : status ,
' ackData ' : hexlify ( ackdata ) } , indent = 4 , separators = ( ' , ' , ' : ' ) )
2015-03-21 12:53:09 +01:00
data + = ' ]} '
return data
def HandleGetSentMessagesByAckData ( self , params ) :
if len ( params ) == 0 :
raise APIError ( 0 , ' I need parameters! ' )
ackData = self . _decode ( params [ 0 ] , " hex " )
2018-04-08 17:28:08 +02:00
queryreturn = sqlQuery (
" SELECT msgid, toaddress, fromaddress, subject, lastactiontime, "
" message, encodingtype, status, ackdata FROM sent "
" WHERE ackdata=? " , ackData
)
2015-03-21 12:53:09 +01:00
data = ' { " sentMessage " :[ '
for row in queryreturn :
2018-04-08 17:28:08 +02:00
msgid , toAddress , fromAddress , subject , lastactiontime , message , \
encodingtype , status , ackdata = row
2015-03-21 12:53:09 +01:00
subject = shared . fixPotentiallyInvalidUTF8Data ( subject )
message = shared . fixPotentiallyInvalidUTF8Data ( message )
2018-04-08 17:28:08 +02:00
data + = json . dumps ( {
' msgid ' : hexlify ( msgid ) ,
' toAddress ' : toAddress ,
' fromAddress ' : fromAddress ,
' subject ' : base64 . b64encode ( subject ) ,
' message ' : base64 . b64encode ( message ) ,
' encodingType ' : encodingtype ,
' lastActionTime ' : lastactiontime ,
' status ' : status ,
' ackData ' : hexlify ( ackdata ) } , indent = 4 , separators = ( ' , ' , ' : ' ) )
2015-03-21 12:53:09 +01:00
data + = ' ]} '
return data
def HandleTrashMessage ( self , params ) :
if len ( params ) == 0 :
raise APIError ( 0 , ' I need parameters! ' )
msgid = self . _decode ( params [ 0 ] , " hex " )
# Trash if in inbox table
helper_inbox . trash ( msgid )
# Trash if in sent table
sqlExecute ( ''' UPDATE sent SET folder= ' trash ' WHERE msgid=? ''' , msgid )
return ' Trashed message (assuming message existed). '
def HandleTrashInboxMessage ( self , params ) :
if len ( params ) == 0 :
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 :
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 :
raise APIError ( 0 , ' I need parameters! ' )
elif len ( params ) == 4 :
toAddress , fromAddress , subject , message = params
encodingType = 2
2018-04-10 09:14:32 +02:00
TTL = 4 * 24 * 60 * 60
2015-03-21 12:53:09 +01:00
elif len ( params ) == 5 :
toAddress , fromAddress , subject , message , encodingType = params
2018-04-10 09:14:32 +02:00
TTL = 4 * 24 * 60 * 60
2015-07-15 17:56:24 +02:00
elif len ( params ) == 6 :
2018-04-08 17:28:08 +02:00
toAddress , fromAddress , subject , message , encodingType , TTL = \
params
2017-04-30 10:39:48 +02:00
if encodingType not in [ 2 , 3 ] :
raise APIError ( 6 , ' The encoding type must be 2 or 3. ' )
2015-03-21 12:53:09 +01:00
subject = self . _decode ( subject , " base64 " )
message = self . _decode ( message , " base64 " )
if len ( subject + message ) > ( 2 * * 18 - 500 ) :
raise APIError ( 27 , ' Message is too long. ' )
2018-04-10 09:14:32 +02:00
if TTL < 60 * 60 :
TTL = 60 * 60
if TTL > 28 * 24 * 60 * 60 :
TTL = 28 * 24 * 60 * 60
2015-03-21 12:53:09 +01:00
toAddress = addBMIfNotPresent ( toAddress )
fromAddress = addBMIfNotPresent ( fromAddress )
2018-04-08 17:28:08 +02:00
status , addressVersionNumber , streamNumber , toRipe = \
self . _verifyAddress ( toAddress )
2015-03-21 12:53:09 +01:00
self . _verifyAddress ( fromAddress )
try :
2017-01-11 14:27:19 +01:00
fromAddressEnabled = BMConfigParser ( ) . getboolean (
2015-03-21 12:53:09 +01:00
fromAddress , ' enabled ' )
except :
2018-04-08 17:28:08 +02:00
raise APIError (
13 , ' Could not find your fromAddress in the keys.dat file. ' )
2015-03-21 12:53:09 +01:00
if not fromAddressEnabled :
raise APIError ( 14 , ' Your fromAddress is disabled. Cannot send. ' )
2018-04-08 17:28:08 +02:00
stealthLevel = BMConfigParser ( ) . safeGetInt (
' bitmessagesettings ' , ' ackstealthlevel ' )
2017-09-30 11:19:44 +02:00
ackdata = genAckPayload ( streamNumber , stealthLevel )
2015-03-21 12:53:09 +01:00
2018-04-08 17:28:08 +02:00
t = ( ' ' ,
toAddress ,
toRipe ,
fromAddress ,
subject ,
message ,
ackdata ,
2018-04-10 09:14:32 +02:00
int ( time . time ( ) ) , # sentTime (this won't change)
int ( time . time ( ) ) , # lastActionTime
2018-04-08 17:28:08 +02:00
0 ,
' msgqueued ' ,
0 ,
' sent ' ,
2 ,
2015-07-15 17:56:24 +02:00
TTL )
2015-03-21 12:53:09 +01:00
helper_sent . insert ( t )
toLabel = ' '
2018-04-08 17:28:08 +02:00
queryreturn = sqlQuery (
" SELECT label FROM addressbook WHERE address=? " , toAddress )
2015-03-21 12:53:09 +01:00
if queryreturn != [ ] :
for row in queryreturn :
toLabel , = row
# apiSignalQueue.put(('displayNewSentMessage',(toAddress,toLabel,fromAddress,subject,message,ackdata)))
2017-02-08 13:41:56 +01:00
queues . UISignalQueue . put ( ( ' displayNewSentMessage ' , (
2015-03-21 12:53:09 +01:00
toAddress , toLabel , fromAddress , subject , message , ackdata ) ) )
2017-02-08 13:41:56 +01:00
queues . workerQueue . put ( ( ' sendmessage ' , toAddress ) )
2015-03-21 12:53:09 +01:00
2016-03-23 23:26:57 +01:00
return hexlify ( ackdata )
2015-03-21 12:53:09 +01:00
def HandleSendBroadcast ( self , params ) :
if len ( params ) == 0 :
raise APIError ( 0 , ' I need parameters! ' )
if len ( params ) == 3 :
fromAddress , subject , message = params
encodingType = 2
2018-04-10 09:14:32 +02:00
TTL = 4 * 24 * 60 * 60
2015-03-21 12:53:09 +01:00
elif len ( params ) == 4 :
fromAddress , subject , message , encodingType = params
2018-04-10 09:14:32 +02:00
TTL = 4 * 24 * 60 * 60
2015-07-15 17:56:24 +02:00
elif len ( params ) == 5 :
fromAddress , subject , message , encodingType , TTL = params
2017-05-27 07:48:29 +02:00
if encodingType not in [ 2 , 3 ] :
raise APIError ( 6 , ' The encoding type must be 2 or 3. ' )
2015-03-21 12:53:09 +01:00
subject = self . _decode ( subject , " base64 " )
message = self . _decode ( message , " base64 " )
if len ( subject + message ) > ( 2 * * 18 - 500 ) :
raise APIError ( 27 , ' Message is too long. ' )
2018-04-10 09:14:32 +02:00
if TTL < 60 * 60 :
TTL = 60 * 60
if TTL > 28 * 24 * 60 * 60 :
TTL = 28 * 24 * 60 * 60
2015-03-21 12:53:09 +01:00
fromAddress = addBMIfNotPresent ( fromAddress )
self . _verifyAddress ( fromAddress )
try :
2018-04-08 17:28:08 +02:00
BMConfigParser ( ) . getboolean ( fromAddress , ' enabled ' )
2015-03-21 12:53:09 +01:00
except :
2018-04-08 17:28:08 +02:00
raise APIError (
13 , ' could not find your fromAddress in the keys.dat file. ' )
2018-04-10 09:14:32 +02:00
streamNumber = decodeAddress ( fromAddress ) [ 2 ]
2017-09-30 11:19:44 +02:00
ackdata = genAckPayload ( streamNumber , 0 )
2015-03-21 12:53:09 +01:00
toAddress = ' [Broadcast subscribers] '
ripe = ' '
2018-04-10 09:14:32 +02:00
t = ( ' ' ,
toAddress ,
ripe ,
fromAddress ,
subject ,
message ,
ackdata ,
int ( time . time ( ) ) , # sentTime (this doesn't change)
int ( time . time ( ) ) , # lastActionTime
0 ,
' broadcastqueued ' ,
0 ,
' sent ' ,
2 ,
2015-07-15 17:56:24 +02:00
TTL )
2015-03-21 12:53:09 +01:00
helper_sent . insert ( t )
toLabel = ' [Broadcast subscribers] '
2017-02-08 13:41:56 +01:00
queues . UISignalQueue . put ( ( ' displayNewSentMessage ' , (
2015-03-21 12:53:09 +01:00
toAddress , toLabel , fromAddress , subject , message , ackdata ) ) )
2017-02-08 13:41:56 +01:00
queues . workerQueue . put ( ( ' sendbroadcast ' , ' ' ) )
2015-03-21 12:53:09 +01:00
2016-03-23 23:26:57 +01:00
return hexlify ( ackdata )
2015-03-21 12:53:09 +01:00
def HandleGetStatus ( self , params ) :
if len ( params ) != 1 :
raise APIError ( 0 , ' I need one parameter! ' )
ackdata , = params
2018-05-05 14:38:05 +02:00
if len ( ackdata ) < 76 :
2018-05-06 13:06:44 +02:00
# The length of ackData should be at least 38 bytes (76 hex digits)
raise APIError ( 15 , ' Invalid ackData object size. ' )
2015-03-21 12:53:09 +01:00
ackdata = self . _decode ( ackdata , " hex " )
queryreturn = sqlQuery (
2018-04-08 17:28:08 +02:00
" SELECT status FROM sent where ackdata=? " , ackdata )
2015-03-21 12:53:09 +01:00
if queryreturn == [ ] :
return ' notfound '
for row in queryreturn :
status , = row
return status
def HandleAddSubscription ( self , params ) :
if len ( params ) == 0 :
raise APIError ( 0 , ' I need parameters! ' )
if len ( params ) == 1 :
address , = params
label = ' '
if len ( params ) == 2 :
address , label = params
label = self . _decode ( label , " base64 " )
2014-01-13 01:56:30 +01:00
try :
2015-03-21 12:53:09 +01:00
unicode ( label , ' utf-8 ' )
2014-01-13 01:56:30 +01:00
except :
2015-03-21 12:53:09 +01:00
raise APIError ( 17 , ' Label is not valid UTF-8 data. ' )
if len ( params ) > 2 :
raise APIError ( 0 , ' I need either 1 or 2 parameters! ' )
address = addBMIfNotPresent ( address )
self . _verifyAddress ( address )
# First we must check to see if the address is already in the
# subscriptions list.
2018-04-08 17:28:08 +02:00
queryreturn = sqlQuery (
" SELECT * FROM subscriptions WHERE address=? " , address )
2015-03-21 12:53:09 +01:00
if queryreturn != [ ] :
raise APIError ( 16 , ' You are already subscribed to that address. ' )
2018-04-08 17:28:08 +02:00
sqlExecute (
" INSERT INTO subscriptions VALUES (?,?,?) " , label , address , True )
2015-03-21 12:53:09 +01:00
shared . reloadBroadcastSendersForWhichImWatching ( )
2017-02-08 13:41:56 +01:00
queues . UISignalQueue . put ( ( ' rerenderMessagelistFromLabels ' , ' ' ) )
queues . UISignalQueue . put ( ( ' rerenderSubscriptions ' , ' ' ) )
2015-03-21 12:53:09 +01:00
return ' Added subscription. '
def HandleDeleteSubscription ( self , params ) :
if len ( params ) != 1 :
raise APIError ( 0 , ' I need 1 parameter! ' )
address , = params
address = addBMIfNotPresent ( address )
sqlExecute ( ''' DELETE FROM subscriptions WHERE address=? ''' , address )
shared . reloadBroadcastSendersForWhichImWatching ( )
2017-02-08 13:41:56 +01:00
queues . UISignalQueue . put ( ( ' rerenderMessagelistFromLabels ' , ' ' ) )
queues . UISignalQueue . put ( ( ' rerenderSubscriptions ' , ' ' ) )
2015-03-21 12:53:09 +01:00
return ' Deleted subscription if it existed. '
def ListSubscriptions ( self , params ) :
2018-04-08 17:28:08 +02:00
queryreturn = sqlQuery (
" SELECT label, address, enabled FROM subscriptions " )
2017-06-03 02:53:13 +02:00
data = { ' subscriptions ' : [ ] }
2015-03-21 12:53:09 +01:00
for row in queryreturn :
label , address , enabled = row
label = shared . fixPotentiallyInvalidUTF8Data ( label )
2018-04-08 17:28:08 +02:00
data [ ' subscriptions ' ] . append ( {
' label ' : base64 . b64encode ( label ) ,
' address ' : address ,
' enabled ' : enabled == 1
} )
return json . dumps ( data , indent = 4 , separators = ( ' , ' , ' : ' ) )
2015-03-21 12:53:09 +01:00
def HandleDisseminatePreEncryptedMsg ( self , params ) :
2018-04-08 17:28:08 +02:00
# 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
# to the rest of the Bitmessage network as if it had generated
# the message itself. Please do not yet add this to the api doc.
2015-03-21 12:53:09 +01:00
if len ( params ) != 3 :
raise APIError ( 0 , ' I need 3 parameter! ' )
2018-04-08 17:28:08 +02:00
encryptedPayload , requiredAverageProofOfWorkNonceTrialsPerByte , \
requiredPayloadLengthExtraBytes = params
2015-03-21 12:53:09 +01:00
encryptedPayload = self . _decode ( encryptedPayload , " hex " )
# Let us do the POW and attach it to the front
2018-04-08 17:28:08 +02:00
target = 2 * * 64 / (
( len ( encryptedPayload ) + requiredPayloadLengthExtraBytes + 8 )
* requiredAverageProofOfWorkNonceTrialsPerByte )
2015-03-21 12:53:09 +01:00
with shared . printLock :
2017-02-08 20:37:42 +01:00
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
2015-03-21 12:53:09 +01:00
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
2014-01-13 01:56:30 +01:00
try :
2015-03-21 12:53:09 +01:00
print ' POW took ' , int ( time . time ( ) - powStartTime ) , ' seconds. ' , nonce / ( time . time ( ) - powStartTime ) , ' nonce trials per second. '
2014-01-13 01:56:30 +01:00
except :
2015-03-21 12:53:09 +01:00
pass
encryptedPayload = pack ( ' >Q ' , nonce ) + encryptedPayload
toStreamNumber = decodeVarint ( encryptedPayload [ 16 : 26 ] ) [ 0 ]
inventoryHash = calculateInventoryHash ( encryptedPayload )
objectType = 2
TTL = 2.5 * 24 * 60 * 60
2017-01-10 21:17:25 +01:00
Inventory ( ) [ inventoryHash ] = (
2018-04-08 17:28:08 +02:00
objectType , toStreamNumber , encryptedPayload ,
int ( time . time ( ) ) + TTL , ' '
)
2015-03-21 12:53:09 +01:00
with shared . printLock :
2016-03-23 23:26:57 +01:00
print ' Broadcasting inv for msg(API disseminatePreEncryptedMsg command): ' , hexlify ( inventoryHash )
2017-08-09 17:36:52 +02:00
queues . invQueue . put ( ( toStreamNumber , inventoryHash ) )
2015-03-21 12:53:09 +01:00
def HandleTrashSentMessageByAckDAta ( self , params ) :
# This API method should only be used when msgid is not available
if len ( params ) == 0 :
raise APIError ( 0 , ' I need parameters! ' )
ackdata = self . _decode ( params [ 0 ] , " hex " )
2018-04-08 17:28:08 +02:00
sqlExecute ( " UPDATE sent SET folder= ' trash ' WHERE ackdata=? " , ackdata )
2015-03-21 12:53:09 +01:00
return ' Trashed sent message (assuming message existed). '
def HandleDissimatePubKey ( self , params ) :
2018-04-08 17:28:08 +02:00
# 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
# of the Bitmessage network as if it had generated the pubkey object
# itself. Please do not yet add this to the api doc.
2015-03-21 12:53:09 +01:00
if len ( params ) != 1 :
raise APIError ( 0 , ' I need 1 parameter! ' )
payload , = params
payload = self . _decode ( payload , " hex " )
# Let us do the POW
2018-04-08 17:28:08 +02:00
target = 2 * * 64 / (
( len ( payload ) + defaults . networkDefaultPayloadLengthExtraBytes
+ 8 ) * defaults . networkDefaultProofOfWorkNonceTrialsPerByte )
2015-03-21 12:53:09 +01:00
print ' (For pubkey message via API) Doing proof of work... '
initialHash = hashlib . sha512 ( payload ) . digest ( )
trialValue , nonce = proofofwork . run ( target , initialHash )
print ' (For pubkey message via API) Found proof of work ' , trialValue , ' Nonce: ' , nonce
payload = pack ( ' >Q ' , nonce ) + payload
2018-04-08 17:28:08 +02:00
pubkeyReadPosition = 8 # bypass the nonce
if payload [ pubkeyReadPosition : pubkeyReadPosition + 4 ] == \
' \x00 \x00 \x00 \x00 ' : # if this pubkey uses 8 byte time
2015-03-21 12:53:09 +01:00
pubkeyReadPosition + = 8
else :
pubkeyReadPosition + = 4
2018-04-08 17:28:08 +02:00
addressVersion , addressVersionLength = decodeVarint (
payload [ pubkeyReadPosition : pubkeyReadPosition + 10 ] )
2015-03-21 12:53:09 +01:00
pubkeyReadPosition + = addressVersionLength
2018-04-08 17:28:08 +02:00
pubkeyStreamNumber = decodeVarint (
payload [ pubkeyReadPosition : pubkeyReadPosition + 10 ] ) [ 0 ]
2015-03-21 12:53:09 +01:00
inventoryHash = calculateInventoryHash ( payload )
2018-04-08 17:28:08 +02:00
objectType = 1 # TODO: support v4 pubkeys
2015-03-21 12:53:09 +01:00
TTL = 28 * 24 * 60 * 60
2017-01-10 21:17:25 +01:00
Inventory ( ) [ inventoryHash ] = (
2018-04-08 17:28:08 +02:00
objectType , pubkeyStreamNumber , payload , int ( time . time ( ) ) + TTL , ' '
)
2015-03-21 12:53:09 +01:00
with shared . printLock :
2016-03-23 23:26:57 +01:00
print ' broadcasting inv within API command disseminatePubkey with hash: ' , hexlify ( inventoryHash )
2017-08-09 17:36:52 +02:00
queues . invQueue . put ( ( pubkeyStreamNumber , inventoryHash ) )
2015-03-21 12:53:09 +01:00
def HandleGetMessageDataByDestinationHash ( self , params ) :
# Method will eventually be used by a particular Android app to
# select relevant messages. Do not yet add this to the api
# doc.
if len ( params ) != 1 :
raise APIError ( 0 , ' I need 1 parameter! ' )
requestedHash , = params
if len ( requestedHash ) != 32 :
2018-04-08 17:28:08 +02:00
raise APIError (
19 , ' The length of hash should be 32 bytes (encoded in hex '
' thus 64 characters). ' )
2015-03-21 12:53:09 +01:00
requestedHash = self . _decode ( requestedHash , " hex " )
# This is not a particularly commonly used API function. Before we
# use it we'll need to fill out a field in our inventory database
# which is blank by default (first20bytesofencryptedmessage).
queryreturn = sqlQuery (
2018-04-08 17:28:08 +02:00
" SELECT hash, payload FROM inventory WHERE tag = ' ' "
" and objecttype = 2 " )
2015-03-21 12:53:09 +01:00
with SqlBulkExecute ( ) as sql :
2014-01-13 01:56:30 +01:00
for row in queryreturn :
2015-09-28 20:55:40 +02:00
hash01 , payload = row
2018-04-08 17:28:08 +02:00
readPosition = 16 # Nonce length + time length
# Stream Number length
readPosition + = decodeVarint (
payload [ readPosition : readPosition + 10 ] ) [ 1 ]
t = ( payload [ readPosition : readPosition + 32 ] , hash01 )
sql . execute ( " UPDATE inventory SET tag=? WHERE hash=? " , * t )
2015-09-28 20:55:40 +02:00
2018-04-08 17:28:08 +02:00
queryreturn = sqlQuery (
" SELECT payload FROM inventory WHERE tag = ? " , requestedHash )
2015-09-28 20:55:40 +02:00
data = ' { " receivedMessageDatas " :[ '
for row in queryreturn :
payload , = row
if len ( data ) > 25 :
data + = ' , '
2018-04-08 17:28:08 +02:00
data + = json . dumps (
{ ' data ' : hexlify ( payload ) } , indent = 4 , separators = ( ' , ' , ' : ' ) )
2015-09-28 20:55:40 +02:00
data + = ' ]} '
return data
def HandleClientStatus ( self , params ) :
2017-06-10 10:08:40 +02:00
if len ( network . stats . connectedHostsList ( ) ) == 0 :
2015-09-28 20:55:40 +02:00
networkStatus = ' notConnected '
2018-04-08 17:28:08 +02:00
elif len ( network . stats . connectedHostsList ( ) ) > 0 \
and not shared . clientHasReceivedIncomingConnections :
2015-09-28 20:55:40 +02:00
networkStatus = ' connectedButHaveNotReceivedIncomingConnections '
else :
networkStatus = ' connectedAndReceivingIncomingConnections '
2018-04-08 17:28:08 +02:00
return json . dumps ( {
' networkConnections ' : len ( network . stats . connectedHostsList ( ) ) ,
' numberOfMessagesProcessed ' : shared . numberOfMessagesProcessed ,
' numberOfBroadcastsProcessed ' : shared . numberOfBroadcastsProcessed ,
' numberOfPubkeysProcessed ' : shared . numberOfPubkeysProcessed ,
' networkStatus ' : networkStatus ,
' softwareName ' : ' PyBitmessage ' ,
' softwareVersion ' : softwareVersion
} , indent = 4 , separators = ( ' , ' , ' : ' ) )
2015-09-28 20:55:40 +02:00
def HandleDecodeAddress ( self , params ) :
# Return a meaningful decoding of an address.
if len ( params ) != 1 :
raise APIError ( 0 , ' I need 1 parameter! ' )
address , = params
status , addressVersion , streamNumber , ripe = decodeAddress ( address )
2018-04-08 17:28:08 +02:00
return json . dumps ( {
' status ' : status ,
' addressVersion ' : addressVersion ,
' streamNumber ' : streamNumber ,
' ripe ' : base64 . b64encode ( ripe )
} , indent = 4 , separators = ( ' , ' , ' : ' ) )
2015-09-28 20:55:40 +02:00
def HandleHelloWorld ( self , params ) :
2018-04-08 17:28:08 +02:00
a , b = params
2015-09-28 20:55:40 +02:00
return a + ' - ' + b
def HandleAdd ( self , params ) :
2018-04-08 17:28:08 +02:00
a , b = params
2015-09-28 20:55:40 +02:00
return a + b
def HandleStatusBar ( self , params ) :
message , = params
2017-02-08 13:41:56 +01:00
queues . UISignalQueue . put ( ( ' updateStatusBar ' , message ) )
2015-09-28 20:55:40 +02:00
def HandleDeleteAndVacuum ( self , params ) :
2017-08-22 13:49:27 +02:00
if not params :
sqlStoredProcedure ( ' deleteandvacuume ' )
return ' done '
2015-09-28 20:55:40 +02:00
2017-08-21 10:39:03 +02:00
def HandleShutdown ( self , params ) :
2017-08-22 13:49:27 +02:00
if not params :
shutdown . doCleanShutdown ( )
return ' done '
2017-08-21 10:39:03 +02:00
2015-09-28 20:55:40 +02:00
handlers = { }
handlers [ ' helloWorld ' ] = HandleHelloWorld
handlers [ ' add ' ] = HandleAdd
handlers [ ' statusBar ' ] = HandleStatusBar
handlers [ ' listAddresses ' ] = HandleListAddresses
2018-04-08 17:28:08 +02:00
handlers [ ' listAddressBookEntries ' ] = HandleListAddressBookEntries
# the listAddressbook alias should be removed eventually.
handlers [ ' listAddressbook ' ] = HandleListAddressBookEntries
2015-09-28 20:55:40 +02:00
handlers [ ' addAddressBookEntry ' ] = HandleAddAddressBookEntry
2018-04-08 17:28:08 +02:00
# the addAddressbook alias should be deleted eventually.
handlers [ ' addAddressbook ' ] = HandleAddAddressBookEntry
2015-09-28 20:55:40 +02:00
handlers [ ' deleteAddressBookEntry ' ] = HandleDeleteAddressBookEntry
2018-04-08 17:28:08 +02:00
# The deleteAddressbook alias should be deleted eventually.
handlers [ ' deleteAddressbook ' ] = HandleDeleteAddressBookEntry
2015-09-28 20:55:40 +02:00
handlers [ ' createRandomAddress ' ] = HandleCreateRandomAddress
2018-04-08 17:28:08 +02:00
handlers [ ' createDeterministicAddresses ' ] = \
HandleCreateDeterministicAddresses
2015-09-28 20:55:40 +02:00
handlers [ ' getDeterministicAddress ' ] = HandleGetDeterministicAddress
handlers [ ' createChan ' ] = HandleCreateChan
handlers [ ' joinChan ' ] = HandleJoinChan
handlers [ ' leaveChan ' ] = HandleLeaveChan
handlers [ ' deleteAddress ' ] = HandleDeleteAddress
handlers [ ' getAllInboxMessages ' ] = HandleGetAllInboxMessages
handlers [ ' getAllInboxMessageIds ' ] = HandleGetAllInboxMessageIds
handlers [ ' getAllInboxMessageIDs ' ] = HandleGetAllInboxMessageIds
handlers [ ' getInboxMessageById ' ] = HandleGetInboxMessageById
handlers [ ' getInboxMessageByID ' ] = HandleGetInboxMessageById
handlers [ ' getAllSentMessages ' ] = HandleGetAllSentMessages
handlers [ ' getAllSentMessageIds ' ] = HandleGetAllSentMessageIds
handlers [ ' getAllSentMessageIDs ' ] = HandleGetAllSentMessageIds
handlers [ ' getInboxMessagesByReceiver ' ] = HandleInboxMessagesByReceiver
2018-04-08 17:28:08 +02:00
# after some time getInboxMessagesByAddress should be removed
handlers [ ' getInboxMessagesByAddress ' ] = HandleInboxMessagesByReceiver
2015-09-28 20:55:40 +02:00
handlers [ ' getSentMessageById ' ] = HandleGetSentMessageById
handlers [ ' getSentMessageByID ' ] = HandleGetSentMessageById
handlers [ ' getSentMessagesByAddress ' ] = HandleGetSentMessagesByAddress
handlers [ ' getSentMessagesBySender ' ] = HandleGetSentMessagesByAddress
handlers [ ' getSentMessageByAckData ' ] = HandleGetSentMessagesByAckData
handlers [ ' trashMessage ' ] = HandleTrashMessage
handlers [ ' trashInboxMessage ' ] = HandleTrashInboxMessage
handlers [ ' trashSentMessage ' ] = HandleTrashSentMessage
handlers [ ' trashSentMessageByAckData ' ] = HandleTrashSentMessageByAckDAta
handlers [ ' sendMessage ' ] = HandleSendMessage
handlers [ ' sendBroadcast ' ] = HandleSendBroadcast
handlers [ ' getStatus ' ] = HandleGetStatus
handlers [ ' addSubscription ' ] = HandleAddSubscription
handlers [ ' deleteSubscription ' ] = HandleDeleteSubscription
handlers [ ' listSubscriptions ' ] = ListSubscriptions
handlers [ ' disseminatePreEncryptedMsg ' ] = HandleDisseminatePreEncryptedMsg
handlers [ ' disseminatePubkey ' ] = HandleDissimatePubKey
2018-04-08 17:28:08 +02:00
handlers [ ' getMessageDataByDestinationHash ' ] = \
HandleGetMessageDataByDestinationHash
handlers [ ' getMessageDataByDestinationTag ' ] = \
HandleGetMessageDataByDestinationHash
2015-09-28 20:55:40 +02:00
handlers [ ' clientStatus ' ] = HandleClientStatus
handlers [ ' decodeAddress ' ] = HandleDecodeAddress
handlers [ ' deleteAndVacuum ' ] = HandleDeleteAndVacuum
2017-08-21 10:39:03 +02:00
handlers [ ' shutdown ' ] = HandleShutdown
2015-09-28 20:55:40 +02:00
def _handle_request ( self , method , params ) :
2018-04-08 17:28:08 +02:00
if method not in self . handlers :
2014-01-13 01:56:30 +01:00
raise APIError ( 20 , ' Invalid method: %s ' % method )
2018-04-08 17:28:08 +02:00
return self . handlers [ method ] ( self , params )
2014-01-13 01:56:30 +01:00
def _dispatch ( self , method , params ) :
self . cookies = [ ]
validuser = self . APIAuthenticateClient ( )
if not validuser :
time . sleep ( 2 )
return " RPC Username or password incorrect or HTTP header lacks authentication at all. "
try :
return self . _handle_request ( method , params )
except APIError as e :
return str ( e )
2014-08-27 09:14:32 +02:00
except varintDecodeError as e :
logger . error ( e )
2014-08-28 01:17:47 +02:00
return " API Error 0026: Data contains a malformed varint. Some details: %s " % e
2014-01-13 01:56:30 +01:00
except Exception as e :
logger . exception ( e )
2018-04-08 17:28:08 +02:00
return " API Error 0021: Unexpected API Failure - %s " % e