API commands: createChan, joinChan, leaveChan, deleteAddress #535
|
@ -12,9 +12,10 @@ warrantless wiretapping programs.
|
||||||
|
|
||||||
Development
|
Development
|
||||||
----------
|
----------
|
||||||
If you plan to put a non-trivial amount of work into coding new features, it
|
Bitmessage is a collaborative project. You are welcome to submit pull requests
|
||||||
is recommended that you first solicit feedback on the DevTalk pseudo-mailing
|
although if you plan to put a non-trivial amount of work into coding new
|
||||||
list:
|
features, it is recommended that you first solicit feedback on the DevTalk
|
||||||
|
pseudo-mailing list:
|
||||||
BM-2D9QKN4teYRvoq2fyzpiftPh9WP9qggtzh
|
BM-2D9QKN4teYRvoq2fyzpiftPh9WP9qggtzh
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -139,7 +139,7 @@ def decodeAddress(address):
|
||||||
integer = decodeBase58(address)
|
integer = decodeBase58(address)
|
||||||
if integer == 0:
|
if integer == 0:
|
||||||
status = 'invalidcharacters'
|
status = 'invalidcharacters'
|
||||||
return status,0,0,0
|
return status,0,0,""
|
||||||
#after converting to hex, the string will be prepended with a 0x and appended with a L
|
#after converting to hex, the string will be prepended with a 0x and appended with a L
|
||||||
hexdata = hex(integer)[2:-1]
|
hexdata = hex(integer)[2:-1]
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@ def decodeAddress(address):
|
||||||
|
|
||||||
if checksum != sha.digest()[0:4]:
|
if checksum != sha.digest()[0:4]:
|
||||||
status = 'checksumfailed'
|
status = 'checksumfailed'
|
||||||
return status,0,0,0
|
return status,0,0,""
|
||||||
#else:
|
#else:
|
||||||
# print 'checksum PASSED'
|
# print 'checksum PASSED'
|
||||||
|
|
||||||
|
@ -172,11 +172,11 @@ def decodeAddress(address):
|
||||||
if addressVersionNumber > 4:
|
if addressVersionNumber > 4:
|
||||||
print 'cannot decode address version numbers this high'
|
print 'cannot decode address version numbers this high'
|
||||||
status = 'versiontoohigh'
|
status = 'versiontoohigh'
|
||||||
return status,0,0,0
|
return status,0,0,""
|
||||||
elif addressVersionNumber == 0:
|
elif addressVersionNumber == 0:
|
||||||
print 'cannot decode address version numbers of zero.'
|
print 'cannot decode address version numbers of zero.'
|
||||||
status = 'versiontoohigh'
|
status = 'versiontoohigh'
|
||||||
return status,0,0,0
|
return status,0,0,""
|
||||||
|
|
||||||
streamNumber, bytesUsedByStreamNumber = decodeVarint(data[bytesUsedByVersionNumber:])
|
streamNumber, bytesUsedByStreamNumber = decodeVarint(data[bytesUsedByVersionNumber:])
|
||||||
#print streamNumber
|
#print streamNumber
|
||||||
|
@ -191,16 +191,16 @@ def decodeAddress(address):
|
||||||
elif len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]) == 18:
|
elif len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]) == 18:
|
||||||
return status,addressVersionNumber,streamNumber,'\x00\x00'+data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]
|
return status,addressVersionNumber,streamNumber,'\x00\x00'+data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]
|
||||||
elif len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]) < 18:
|
elif len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]) < 18:
|
||||||
return 'ripetooshort',0,0,0
|
return 'ripetooshort',0,0,""
|
||||||
elif len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]) > 20:
|
elif len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]) > 20:
|
||||||
return 'ripetoolong',0,0,0
|
return 'ripetoolong',0,0,""
|
||||||
else:
|
else:
|
||||||
return 'otherproblem',0,0,0
|
return 'otherproblem',0,0,""
|
||||||
elif addressVersionNumber == 4:
|
elif addressVersionNumber == 4:
|
||||||
if len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]) > 20:
|
if len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]) > 20:
|
||||||
return 'ripetoolong',0,0,0
|
return 'ripetoolong',0,0,""
|
||||||
elif len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]) < 4:
|
elif len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]) < 4:
|
||||||
return 'ripetooshort',0,0,0
|
return 'ripetooshort',0,0,""
|
||||||
else:
|
else:
|
||||||
x00string = '\x00' * (20 - len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]))
|
x00string = '\x00' * (20 - len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]))
|
||||||
return status,addressVersionNumber,streamNumber,x00string+data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]
|
return status,addressVersionNumber,streamNumber,x00string+data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]
|
||||||
|
|
|
@ -38,6 +38,8 @@ from debug import logger
|
||||||
import helper_bootstrap
|
import helper_bootstrap
|
||||||
import proofofwork
|
import proofofwork
|
||||||
|
|
||||||
|
str_chan = '[chan]'
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == 'darwin':
|
||||||
if float("{1}.{2}".format(*sys.version_info)) < 7.5:
|
if float("{1}.{2}".format(*sys.version_info)) < 7.5:
|
||||||
|
@ -150,8 +152,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
def _decode(self, text, decode_type):
|
def _decode(self, text, decode_type):
|
||||||
try:
|
try:
|
||||||
return text.decode(decode_type)
|
return text.decode(decode_type)
|
||||||
except TypeError as e:
|
except Exception as e:
|
||||||
raise APIError(22, "Decode error - " + str(e))
|
raise APIError(22, "Decode error - " + str(e) + ". Had trouble while decoding string: " + repr(text))
|
||||||
|
|
||||||
def _verifyAddress(self, address):
|
def _verifyAddress(self, address):
|
||||||
status, addressVersionNumber, streamNumber, ripe = decodeAddress(address)
|
status, addressVersionNumber, streamNumber, ripe = decodeAddress(address)
|
||||||
|
@ -387,6 +389,113 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
('getDeterministicAddress', addressVersionNumber,
|
('getDeterministicAddress', addressVersionNumber,
|
||||||
streamNumber, 'unused API address', numberOfAddresses, passphrase, eighteenByteRipe))
|
streamNumber, 'unused API address', numberOfAddresses, passphrase, eighteenByteRipe))
|
||||||
return shared.apiAddressGeneratorReturnQueue.get()
|
return shared.apiAddressGeneratorReturnQueue.get()
|
||||||
|
|
||||||
|
elif method == 'createChan':
|
||||||
|
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
|
||||||
|
shared.apiAddressGeneratorReturnQueue.queue.clear()
|
||||||
|
logger.debug('Requesting that the addressGenerator create chan %s.', passphrase)
|
||||||
|
shared.addressGeneratorQueue.put(('createChan', addressVersionNumber, streamNumber, label, passphrase))
|
||||||
|
queueReturn = shared.apiAddressGeneratorReturnQueue.get()
|
||||||
|
if len(queueReturn) == 0:
|
||||||
|
raise APIError(24, 'Chan address is already present.')
|
||||||
|
address = queueReturn[0]
|
||||||
|
|
||||||
|
#add address to addressbook
|
||||||
|
queryreturn = sqlQuery("SELECT address FROM addressbook WHERE address=?", address)
|
||||||
|
if queryreturn == []:
|
||||||
|
sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address)
|
||||||
|
shared.UISignalQueue.put(('rerenderInboxFromLabels',''))
|
||||||
|
shared.UISignalQueue.put(('rerenderSentToLabels',''))
|
||||||
|
shared.UISignalQueue.put(('rerenderAddressBook',''))
|
||||||
|
return address
|
||||||
|
elif method == 'joinChan':
|
||||||
|
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:
|
||||||
|
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)
|
||||||
|
|
||||||
|
status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(suppliedAddress)
|
||||||
|
suppliedAddress = addBMIfNotPresent(suppliedAddress)
|
||||||
|
shared.apiAddressGeneratorReturnQueue.queue.clear()
|
||||||
|
shared.addressGeneratorQueue.put(('joinChan', suppliedAddress, label, passphrase))
|
||||||
|
addressGeneratorReturnValue = shared.apiAddressGeneratorReturnQueue.get()
|
||||||
|
|
||||||
|
if addressGeneratorReturnValue == 'chan name does not match address':
|
||||||
|
raise APIError(18, 'Chan name does not match address.')
|
||||||
|
if len(addressGeneratorReturnValue) == 0:
|
||||||
|
raise APIError(24, 'Chan address is already present.')
|
||||||
|
createdAddress = addressGeneratorReturnValue[0]
|
||||||
|
#add address to addressbook
|
||||||
|
queryreturn = sqlQuery("SELECT address FROM addressbook WHERE address=?", createdAddress)
|
||||||
|
if queryreturn == []:
|
||||||
|
sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, createdAddress)
|
||||||
|
shared.UISignalQueue.put(('rerenderInboxFromLabels',''))
|
||||||
|
shared.UISignalQueue.put(('rerenderSentToLabels',''))
|
||||||
|
shared.UISignalQueue.put(('rerenderAddressBook',''))
|
||||||
|
return "success"
|
||||||
|
elif method == 'leaveChan':
|
||||||
|
if len(params) == 0:
|
||||||
|
raise APIError(0, 'I need parameters.')
|
||||||
|
elif len(params) == 1:
|
||||||
|
address, = params
|
||||||
|
status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address)
|
||||||
|
address = addBMIfNotPresent(address)
|
||||||
|
if not shared.config.has_section(address):
|
||||||
|
raise APIError(13, 'Could not find this address in your keys.dat file.')
|
||||||
|
if not shared.safeConfigGetBoolean(address, 'chan'):
|
||||||
|
raise APIError(25, 'Specified address is not a chan address. Use deleteAddress API call instead.')
|
||||||
|
shared.config.remove_section(address)
|
||||||
|
with open(shared.appdata + 'keys.dat', 'wb') as configfile:
|
||||||
|
shared.config.write(configfile)
|
||||||
|
sqlExecute('''DELETE FROM addressbook WHERE address=?''', address)
|
||||||
|
shared.UISignalQueue.put(('rerenderInboxFromLabels',''))
|
||||||
|
shared.UISignalQueue.put(('rerenderSentToLabels',''))
|
||||||
|
shared.UISignalQueue.put(('rerenderAddressBook',''))
|
||||||
|
return 'success'
|
||||||
|
|
||||||
|
elif method == 'deleteAddress':
|
||||||
|
if len(params) == 0:
|
||||||
|
raise APIError(0, 'I need parameters.')
|
||||||
|
elif len(params) == 1:
|
||||||
|
address, = params
|
||||||
|
status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address)
|
||||||
|
address = addBMIfNotPresent(address)
|
||||||
|
if not shared.config.has_section(address):
|
||||||
|
raise APIError(13, 'Could not find this address in your keys.dat file.')
|
||||||
|
shared.config.remove_section(address)
|
||||||
|
with open(shared.appdata + 'keys.dat', 'wb') as configfile:
|
||||||
|
shared.config.write(configfile)
|
||||||
|
shared.UISignalQueue.put(('rerenderInboxFromLabels',''))
|
||||||
|
shared.UISignalQueue.put(('rerenderSentToLabels',''))
|
||||||
|
shared.reloadMyAddressHashes()
|
||||||
|
return 'success'
|
||||||
|
|
||||||
elif method == 'getAllInboxMessages':
|
elif method == 'getAllInboxMessages':
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''SELECT msgid, toaddress, fromaddress, subject, received, message, encodingtype, read FROM inbox where folder='inbox' ORDER BY received''')
|
'''SELECT msgid, toaddress, fromaddress, subject, received, message, encodingtype, read FROM inbox where folder='inbox' ORDER BY received''')
|
||||||
|
@ -818,6 +927,15 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
else:
|
else:
|
||||||
networkStatus = 'connectedAndReceivingIncomingConnections'
|
networkStatus = 'connectedAndReceivingIncomingConnections'
|
||||||
return json.dumps({'networkConnections':len(shared.connectedHostsList),'numberOfMessagesProcessed':shared.numberOfMessagesProcessed, 'numberOfBroadcastsProcessed':shared.numberOfBroadcastsProcessed, 'numberOfPubkeysProcessed':shared.numberOfPubkeysProcessed, 'networkStatus':networkStatus, 'softwareName':'PyBitmessage','softwareVersion':shared.softwareVersion}, indent=4, separators=(',', ': '))
|
return json.dumps({'networkConnections':len(shared.connectedHostsList),'numberOfMessagesProcessed':shared.numberOfMessagesProcessed, 'numberOfBroadcastsProcessed':shared.numberOfBroadcastsProcessed, 'numberOfPubkeysProcessed':shared.numberOfPubkeysProcessed, 'networkStatus':networkStatus, 'softwareName':'PyBitmessage','softwareVersion':shared.softwareVersion}, indent=4, separators=(',', ': '))
|
||||||
|
elif method == 'decodeAddress':
|
||||||
|
#decode an address
|
||||||
|
if len(params) != 1:
|
||||||
|
raise APIError(0, 'I need 1 parameter!')
|
||||||
|
address, = params
|
||||||
|
status, addressVersion, streamNumber, ripe = decodeAddress(address)
|
||||||
|
return json.dumps({'status':status, 'addressVersion':addressVersion,
|
||||||
|
'streamNumber':streamNumber, 'ripe':ripe.encode('base64')}, indent=4,
|
||||||
|
separators=(',', ': '))
|
||||||
else:
|
else:
|
||||||
raise APIError(20, 'Invalid method: %s' % method)
|
raise APIError(20, 'Invalid method: %s' % method)
|
||||||
|
|
||||||
|
|
|
@ -315,10 +315,15 @@ class singleWorker(threading.Thread):
|
||||||
shared.broadcastToSendDataQueues((
|
shared.broadcastToSendDataQueues((
|
||||||
streamNumber, 'advertiseobject', inventoryHash))
|
streamNumber, 'advertiseobject', inventoryHash))
|
||||||
shared.UISignalQueue.put(('updateStatusBar', ''))
|
shared.UISignalQueue.put(('updateStatusBar', ''))
|
||||||
|
try:
|
||||||
shared.config.set(
|
shared.config.set(
|
||||||
myAddress, 'lastpubkeysendtime', str(int(time.time())))
|
myAddress, 'lastpubkeysendtime', str(int(time.time())))
|
||||||
with open(shared.appdata + 'keys.dat', 'wb') as configfile:
|
with open(shared.appdata + 'keys.dat', 'wb') as configfile:
|
||||||
shared.config.write(configfile)
|
shared.config.write(configfile)
|
||||||
|
except:
|
||||||
|
# The user deleted the address out of the keys.dat file before this
|
||||||
|
# finished.
|
||||||
|
pass
|
||||||
|
|
||||||
def sendBroadcast(self):
|
def sendBroadcast(self):
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
|
|
Reference in New Issue
Block a user