def setLabel(self, label=None): """Set label""" super(MessageList_AddressWidget, self).setLabel(label) if label is not None: return newLabel = self.address queryreturn = None if self.type in (AccountMixin.NORMAL, AccountMixin.CHAN, AccountMixin.MAILINGLIST): try: newLabel = unicode(BMConfigParser().get(self.address, 'label'), 'utf-8', 'ignore') except: queryreturn = sqlQuery( '''select label from addressbook where address=?''', self.address) elif self.type == AccountMixin.SUBSCRIPTION: queryreturn = sqlQuery( '''select label from subscriptions where address=?''', self.address) if queryreturn: for row in queryreturn: newLabel = unicode(row[0], 'utf-8', 'ignore') self.label = newLabel
def HandleListAddressBookEntries(self, params): if len(params) == 1: label, = params label = self._decode(label, "base64") queryreturn = sqlQuery( "SELECT label, address from addressbook WHERE label = ?", label) elif len(params) > 1: raise APIError(0, "Too many paremeters, max 1") else: queryreturn = sqlQuery("SELECT label, address from addressbook") data = '{"addresses":[' for row in queryreturn: label, address = row label = shared.fixPotentiallyInvalidUTF8Data(label) if len(data) > 20: data += ',' data += json.dumps( { 'label': base64.b64encode(label), 'address': address }, indent=4, separators=(',', ': ')) data += ']}' return data
def doCleanShutdown(): state.shutdown = 1 #Used to tell proof of work worker threads and the objectProcessorThread to exit. objectProcessorQueue.put(('checkShutdownVariable', 'no data')) for thread in threading.enumerate(): if thread.isAlive() and isinstance(thread, StoppableThread): thread.stopThread() UISignalQueue.put( ('updateStatusBar', 'Saving the knownNodes list of peers to disk...')) logger.info('Saving knownNodes list of peers to disk') saveKnownNodes() logger.info('Done saving knownNodes list of peers to disk') UISignalQueue.put(('updateStatusBar', 'Done saving the knownNodes list of peers to disk.')) logger.info('Flushing inventory in memory out to disk...') UISignalQueue.put(( 'updateStatusBar', 'Flushing inventory in memory out to disk. This should normally only take a second...' )) Inventory().flush() # Verify that the objectProcessor has finished exiting. It should have incremented the # shutdown variable from 1 to 2. This must finish before we command the sqlThread to exit. while state.shutdown == 1: time.sleep(.1) # This one last useless query will guarantee that the previous flush committed and that the # objectProcessorThread committed before we close the program. sqlQuery('SELECT address FROM subscriptions') logger.info('Finished flushing inventory.') sqlStoredProcedure('exit') # Wait long enough to guarantee that any running proof of work worker threads will check the # shutdown variable and exit. If the main thread closes before they do then they won't stop. time.sleep(.25) for thread in threading.enumerate(): if thread is not threading.currentThread() and isinstance( thread, StoppableThread): logger.debug("Waiting for thread %s", thread.name) thread.join() # flush queued for queue in (workerQueue, UISignalQueue, addressGeneratorQueue, objectProcessorQueue): while True: try: queue.get(False) queue.task_done() except Queue.Empty: break if shared.thisapp.daemon: logger.info('Clean shutdown complete.') shared.thisapp.cleanup() os._exit(0) else: logger.info('Core shutdown complete.') for thread in threading.enumerate(): logger.debug("Thread %s still running", thread.name)
def setLabel(self, label=None): newLabel = self.address if label is None: queryreturn = None if self.type in (AccountMixin.NORMAL, AccountMixin.CHAN, AccountMixin.MAILINGLIST): try: newLabel = unicode( BMConfigParser().get(self.address, 'label'), 'utf-8', 'ignore') except: queryreturn = sqlQuery( '''select label from addressbook where address=?''', self.address) elif self.type == AccountMixin.SUBSCRIPTION: queryreturn = sqlQuery( '''select label from subscriptions where address=?''', self.address) if queryreturn is not None: if queryreturn != []: for row in queryreturn: newLabel = unicode(row[0], 'utf-8', 'ignore') else: newLabel = label if hasattr(self, 'label') and newLabel == self.label: return self.label = newLabel
def defaultLabel(self): queryreturn = None retval = None if self.type in (AccountMixin.NORMAL, AccountMixin.CHAN, AccountMixin.MAILINGLIST): try: retval = unicode(BMConfigParser().get(self.address, 'label'), 'utf-8') except Exception as e: queryreturn = sqlQuery( '''select label from addressbook where address=?''', self.address) elif self.type == AccountMixin.SUBSCRIPTION: queryreturn = sqlQuery( '''select label from subscriptions where address=?''', self.address) if queryreturn is not None: if queryreturn != []: for row in queryreturn: retval, = row retval = unicode(retval, 'utf-8') elif self.address is None or self.type == AccountMixin.ALL: return unicode( str(QtGui.QApplication.translate("MainWindow", "All accounts")), 'utf-8') if retval is None: return unicode(self.address, 'utf-8') else: return retval
def rerenderBlackWhiteList(self): tabs = self.parent().parent() if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': tabs.setTabText(tabs.indexOf(self), _translate('blacklist', 'Blacklist')) else: tabs.setTabText(tabs.indexOf(self), _translate('blacklist', 'Whitelist')) self.tableWidgetBlacklist.setRowCount(0) listType = BMConfigParser().get('bitmessagesettings', 'blackwhitelist') if listType == 'black': queryreturn = sqlQuery('''SELECT label, address, enabled FROM blacklist''') else: queryreturn = sqlQuery('''SELECT label, address, enabled FROM whitelist''') self.tableWidgetBlacklist.setSortingEnabled(False) for row in queryreturn: label, address, enabled = row self.tableWidgetBlacklist.insertRow(0) newItem = QtGui.QTableWidgetItem(unicode(label, 'utf-8')) if not enabled: newItem.setTextColor(QtGui.QColor(128, 128, 128)) newItem.setIcon(avatarize(address)) self.tableWidgetBlacklist.setItem(0, 0, newItem) newItem = QtGui.QTableWidgetItem(address) newItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) if not enabled: newItem.setTextColor(QtGui.QColor(128, 128, 128)) self.tableWidgetBlacklist.setItem(0, 1, newItem) self.tableWidgetBlacklist.setSortingEnabled(True)
def getSortedSubscriptions(count=False): queryreturn = sqlQuery( 'SELECT label, address, enabled FROM subscriptions ORDER BY label COLLATE NOCASE ASC' ) ret = {} for row in queryreturn: label, address, enabled = row ret[address] = {} ret[address]["inbox"] = {} ret[address]["inbox"]['label'] = label ret[address]["inbox"]['enabled'] = enabled ret[address]["inbox"]['count'] = 0 if count: queryreturn = sqlQuery( '''SELECT fromaddress, folder, count(msgid) as cnt FROM inbox, subscriptions ON subscriptions.address = inbox.fromaddress WHERE read = 0 AND toaddress = ? GROUP BY inbox.fromaddress, folder''', str_broadcast_subscribers) for row in queryreturn: address, folder, cnt = row if not folder in ret[address]: ret[address][folder] = { 'label': ret[address]['inbox']['label'], 'enabled': ret[address]['inbox']['enabled'] } ret[address][folder]['count'] = cnt return ret
def getSortedSubscriptions(count=False): """ Actually return a grouped dictionary rather than a sorted list :param count: Whether to count messages for each fromaddress in the inbox :type count: bool, default False :retuns: dict keys are addresses, values are dicts containing settings :rtype: dict, default {} """ queryreturn = sqlQuery( 'SELECT label, address, enabled FROM subscriptions ORDER BY label COLLATE NOCASE ASC' ) ret = {} for row in queryreturn: label, address, enabled = row ret[address] = {} ret[address]["inbox"] = {} ret[address]["inbox"]['label'] = label ret[address]["inbox"]['enabled'] = enabled ret[address]["inbox"]['count'] = 0 if count: queryreturn = sqlQuery( '''SELECT fromaddress, folder, count(msgid) as cnt FROM inbox, subscriptions ON subscriptions.address = inbox.fromaddress WHERE read = 0 AND toaddress = ? GROUP BY inbox.fromaddress, folder''', str_broadcast_subscribers) for row in queryreturn: address, folder, cnt = row if folder not in ret[address]: ret[address][folder] = { 'label': ret[address]['inbox']['label'], 'enabled': ret[address]['inbox']['enabled'] } ret[address][folder]['count'] = cnt return ret
def recgetdata(self, data): numberOfRequestedInventoryItems, lengthOfVarint = decodeVarint( data[:10]) if len(data) < lengthOfVarint + (32 * numberOfRequestedInventoryItems): return for i in xrange(numberOfRequestedInventoryItems): hash = data[lengthOfVarint + ( i * 32):32 + lengthOfVarint + (i * 32)] shared.numberOfInventoryLookupsPerformed += 1 shared.inventoryLock.acquire() if hash in shared.inventory: objectType, streamNumber, payload, expiresTime, tag = shared.inventory[hash] shared.inventoryLock.release() self.sendObject(payload) else: shared.inventoryLock.release() queryreturn = sqlQuery( '''select payload from inventory where hash=? and expirestime>=?''', hash, int(time.time())) if queryreturn != []: for row in queryreturn: payload, = row self.sendObject(payload) else: pass
def getStatusByAck(ackdata): query = sqlQuery("SELECT status FROM sent WHERE ackdata=? LIMIT 0,1", ackdata) if not len(query) == 0: return query[0][0] else: return "not found"
def sendBigInv(self): # Select all hashes for objects in this stream. queryreturn = sqlQuery( '''SELECT hash FROM inventory WHERE expirestime>? and streamnumber=?''', int(time.time()), self.streamNumber) bigInvList = {} for row in queryreturn: hash, = row if hash not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware: bigInvList[hash] = 0 # We also have messages in our inventory in memory (which is a python # dictionary). Let's fetch those too. with shared.inventoryLock: for hash, storedValue in shared.inventory.items(): if hash not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware: objectType, streamNumber, payload, expiresTime, tag = storedValue if streamNumber == self.streamNumber and expiresTime > int( time.time()): bigInvList[hash] = 0 numberOfObjectsInInvMessage = 0 payload = '' # Now let us start appending all of these hashes together. They will be # sent out in a big inv message to our new peer. for hash, storedValue in bigInvList.items(): payload += hash numberOfObjectsInInvMessage += 1 if numberOfObjectsInInvMessage == 50000: # We can only send a max of 50000 items per inv message but we may have more objects to advertise. They must be split up into multiple inv messages. self.sendinvMessageToJustThisOnePeer( numberOfObjectsInInvMessage, payload) payload = '' numberOfObjectsInInvMessage = 0 if numberOfObjectsInInvMessage > 0: self.sendinvMessageToJustThisOnePeer(numberOfObjectsInInvMessage, payload)
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") try: unicode(label, 'utf-8') except: 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. queryreturn = sqlQuery("SELECT * FROM subscriptions WHERE address=?", address) if queryreturn != []: raise APIError(16, 'You are already subscribed to that address.') sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", label, address, True) shared.reloadBroadcastSendersForWhichImWatching() queues.UISignalQueue.put(('rerenderMessagelistFromLabels', '')) queues.UISignalQueue.put(('rerenderSubscriptions', '')) return 'Added subscription.'
def HandleGetAllInboxMessages(self, params): queryreturn = sqlQuery( "SELECT msgid, toaddress, fromaddress, subject, received, message," " encodingtype, read FROM inbox where folder='inbox'" " ORDER BY received") data = '{"inboxMessages":[' for row in queryreturn: msgid, toAddress, fromAddress, subject, received, message, \ encodingtype, read = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' 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=(',', ': ')) data += ']}' return data
def recgetdata(self, data): numberOfRequestedInventoryItems, lengthOfVarint = decodeVarint( data[:10]) if len(data) < lengthOfVarint + (32 * numberOfRequestedInventoryItems): print 'getdata message does not contain enough data. Ignoring.' return for i in xrange(numberOfRequestedInventoryItems): hash = data[lengthOfVarint + ( i * 32):32 + lengthOfVarint + (i * 32)] with shared.printLock: print 'received getdata request for item:', hash.encode('hex') shared.numberOfInventoryLookupsPerformed += 1 shared.inventoryLock.acquire() if hash in shared.inventory: objectType, streamNumber, payload, expiresTime, tag = shared.inventory[hash] shared.inventoryLock.release() self.sendObject(payload) else: shared.inventoryLock.release() queryreturn = sqlQuery( '''select payload from inventory where hash=? and expirestime>=?''', hash, int(time.time())) if queryreturn != []: for row in queryreturn: payload, = row self.sendObject(payload) else: logger.warning('%s asked for an object with a getdata which is not in either our memory inventory or our SQL inventory. We probably cleaned it out after advertising it but before they got around to asking for it.' % (self.peer,))
def HandleGetAllSentMessages(self, params): queryreturn = sqlQuery( "SELECT msgid, toaddress, fromaddress, subject, lastactiontime," " message, encodingtype, status, ackdata FROM sent" " WHERE folder='sent' ORDER BY lastactiontime") data = '{"sentMessages":[' for row in queryreturn: msgid, toAddress, fromAddress, subject, lastactiontime, message, \ encodingtype, status, ackdata = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' 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=(',', ': ')) data += ']}' return data
def reloadBroadcastSendersForWhichImWatching(): broadcastSendersForWhichImWatching.clear() MyECSubscriptionCryptorObjects.clear() queryreturn = sqlQuery('SELECT address FROM subscriptions where enabled=1') logger.debug('reloading subscriptions...') for row in queryreturn: address, = row # status _, addressVersionNumber, streamNumber, hash = decodeAddress(address) if addressVersionNumber == 2: broadcastSendersForWhichImWatching[hash] = 0 # Now, for all addresses, even version 2 addresses, # we should create Cryptor objects in a dictionary which we will # use to attempt to decrypt encrypted broadcast messages. if addressVersionNumber <= 3: privEncryptionKey = hashlib.sha512( encodeVarint(addressVersionNumber) + encodeVarint(streamNumber) + hash).digest()[:32] MyECSubscriptionCryptorObjects[hash] = \ highlevelcrypto.makeCryptor(hexlify(privEncryptionKey)) else: doubleHashOfAddressData = hashlib.sha512( hashlib.sha512( encodeVarint(addressVersionNumber) + encodeVarint(streamNumber) + hash).digest()).digest() tag = doubleHashOfAddressData[32:] privEncryptionKey = doubleHashOfAddressData[:32] MyECSubscriptionCryptorObjects[tag] = \ highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))
def recgetdata(self, data): numberOfRequestedInventoryItems, lengthOfVarint = decodeVarint( data[:10]) if len(data) < lengthOfVarint + (32 * numberOfRequestedInventoryItems): logger.debug( 'getdata message does not contain enough data. Ignoring.') return for i in xrange(numberOfRequestedInventoryItems): hash = data[lengthOfVarint + (i * 32):32 + lengthOfVarint + (i * 32)] logger.debug('received getdata request for item:' + hash.encode('hex')) shared.numberOfInventoryLookupsPerformed += 1 shared.inventoryLock.acquire() if hash in shared.inventory: objectType, streamNumber, payload, expiresTime, tag = shared.inventory[ hash] shared.inventoryLock.release() self.sendObject(payload) else: shared.inventoryLock.release() queryreturn = sqlQuery( '''select payload from inventory where hash=? and expirestime>=?''', hash, int(time.time())) if queryreturn != []: for row in queryreturn: payload, = row self.sendObject(payload) else: logger.warning( '%s asked for an object with a getdata which is not in either our memory inventory or our SQL inventory. We probably cleaned it out after advertising it but before they got around to asking for it.' % (self.peer, ))
def HandleInboxMessagesByReceiver(self, params): if len(params) == 0: raise APIError(0, 'I need parameters!') toAddress = params[0] queryreturn = sqlQuery( "SELECT msgid, toaddress, fromaddress, subject, received, message," " encodingtype FROM inbox WHERE folder='inbox' AND toAddress=?", toAddress) data = '{"inboxMessages":[' for row in queryreturn: msgid, toAddress, fromAddress, subject, received, message, \ encodingtype = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' 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=(',', ': ')) data += ']}' return data
def HandleGetSentMessagesByAckData(self, params): if len(params) == 0: raise APIError(0, 'I need parameters!') ackData = self._decode(params[0], "hex") queryreturn = sqlQuery( "SELECT msgid, toaddress, fromaddress, subject, lastactiontime," " message, encodingtype, status, ackdata FROM sent" " WHERE ackdata=?", ackData) data = '{"sentMessage":[' for row in queryreturn: msgid, toAddress, fromAddress, subject, lastactiontime, message, \ encodingtype, status, ackdata = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) 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=(',', ': ')) data += ']}' return data
def isAddressInMyAddressBookSubscriptionsListOrWhitelist(address): if isAddressInMyAddressBook(address): return True queryreturn = sqlQuery( '''SELECT address FROM whitelist where address=?''' ''' and enabled = '1' ''', address) if queryreturn != []: return True queryreturn = sqlQuery( '''select address from subscriptions where address=?''' ''' and enabled = '1' ''', address) if queryreturn != []: return True return False
def sendBigInv(self): # Select all hashes for objects in this stream. queryreturn = sqlQuery( '''SELECT hash FROM inventory WHERE expirestime>? and streamnumber=?''', int(time.time()), self.streamNumber) bigInvList = {} for row in queryreturn: hash, = row if hash not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware: bigInvList[hash] = 0 # We also have messages in our inventory in memory (which is a python # dictionary). Let's fetch those too. with shared.inventoryLock: for hash, storedValue in shared.inventory.items(): if hash not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware: objectType, streamNumber, payload, expiresTime, tag = storedValue if streamNumber == self.streamNumber and expiresTime > int(time.time()): bigInvList[hash] = 0 numberOfObjectsInInvMessage = 0 payload = '' # Now let us start appending all of these hashes together. They will be # sent out in a big inv message to our new peer. for hash, storedValue in bigInvList.items(): payload += hash numberOfObjectsInInvMessage += 1 if numberOfObjectsInInvMessage == 50000: # We can only send a max of 50000 items per inv message but we may have more objects to advertise. They must be split up into multiple inv messages. self.sendinvMessageToJustThisOnePeer( numberOfObjectsInInvMessage, payload) payload = '' numberOfObjectsInInvMessage = 0 if numberOfObjectsInInvMessage > 0: self.sendinvMessageToJustThisOnePeer( numberOfObjectsInInvMessage, payload)
def getLabel(self, address=None): """Get a label for this bitmessage account""" if address is None: address = self.address label = BMConfigParser().safeGet(address, 'label', address) queryreturn = sqlQuery( '''select label from addressbook where address=?''', address) if queryreturn != []: for row in queryreturn: label, = row else: queryreturn = sqlQuery( '''select label from subscriptions where address=?''', address) if queryreturn != []: for row in queryreturn: label, = row return label
def checkAddressBook(myapp): sqlExecute('DELETE from addressbook WHERE address=?', OLD_SUPPORT_ADDRESS) queryreturn = sqlQuery('SELECT * FROM addressbook WHERE address=?', SUPPORT_ADDRESS) if queryreturn == []: sqlExecute('INSERT INTO addressbook VALUES (?,?)', SUPPORT_LABEL.toUtf8(), SUPPORT_ADDRESS) myapp.rerenderAddressBook()
def __getitem__(self, hash): with self.lock: if hash in self._inventory: return self._inventory[hash] rows = sqlQuery('SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE hash=?', hash) if not rows: raise KeyError(hash) return self.InventoryItem(*rows[0])
def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, what=None, unreadOnly=False): if what is not None and what != "": what = "%" + what + "%" if where == search_translate("MainWindow", "To"): where = "toaddress" elif where == search_translate("MainWindow", "From"): where = "fromaddress" elif where == search_translate("MainWindow", "Subject"): where = "subject" elif where == search_translate("MainWindow", "Message"): where = "message" else: where = "toaddress || fromaddress || subject || message" else: what = None if folder == "sent": sqlStatementBase = ''' SELECT toaddress, fromaddress, subject, status, ackdata, lastactiontime FROM sent ''' else: sqlStatementBase = '''SELECT folder, msgid, toaddress, fromaddress, subject, received, read FROM inbox ''' sqlStatementParts = [] sqlArguments = [] if account is not None: if xAddress == 'both': sqlStatementParts.append("(fromaddress = ? OR toaddress = ?)") sqlArguments.append(account) sqlArguments.append(account) else: sqlStatementParts.append(xAddress + " = ? ") sqlArguments.append(account) if folder is not None: if folder == "new": folder = "inbox" unreadOnly = True sqlStatementParts.append("folder = ? ") sqlArguments.append(folder) else: sqlStatementParts.append("folder != ?") sqlArguments.append("trash") if what is not None: sqlStatementParts.append("%s LIKE ?" % (where)) sqlArguments.append(what) if unreadOnly: sqlStatementParts.append("read = 0") if len(sqlStatementParts) > 0: sqlStatementBase += "WHERE " + " AND ".join(sqlStatementParts) if folder == "sent": sqlStatementBase += " ORDER BY lastactiontime" return sqlQuery(sqlStatementBase, sqlArguments)
def getLabel(self, address=None): if address is None: address = self.address label = address if BMConfigParser().has_section(address): label = BMConfigParser().get(address, 'label') queryreturn = sqlQuery( '''select label from addressbook where address=?''', address) if queryreturn != []: for row in queryreturn: label, = row else: queryreturn = sqlQuery( '''select label from subscriptions where address=?''', address) if queryreturn != []: for row in queryreturn: label, = row return label
def _getLabel(self): queryreturn = sqlQuery( '''select label from subscriptions where address=?''', self.address) if queryreturn != []: for row in queryreturn: retval, = row return unicode(retval, 'utf-8', 'ignore') return unicode(self.address, 'utf-8')
def HandleGetInboxMessageById(self, params): if len(params) == 0: raise APIError(0, 'I need parameters!') elif len(params) == 1: msgid = self._decode(params[0], "hex") elif len(params) >= 2: msgid = self._decode(params[0], "hex") readStatus = params[1] if not isinstance(readStatus, bool): raise APIError( 23, 'Bool expected in readStatus, saw %s instead.' % type(readStatus)) queryreturn = sqlQuery("SELECT read FROM inbox WHERE msgid=?", msgid) # UPDATE is slow, only update if status is different if queryreturn != [] and (queryreturn[0][0] == 1) != readStatus: sqlExecute("UPDATE inbox set read = ? WHERE msgid=?", readStatus, msgid) queues.UISignalQueue.put(('changedInboxUnread', None)) queryreturn = sqlQuery( "SELECT msgid, toaddress, fromaddress, subject, received, message," " encodingtype, read FROM inbox WHERE msgid=?", msgid) data = '{"inboxMessage":[' for row in queryreturn: msgid, toAddress, fromAddress, subject, received, message, \ encodingtype, read = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) 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=(',', ': ')) data += ']}' return data
def has_pubkey_for(address, decodedAddress): # Can return True or False # If we need the public key for our own address or a chan, # we can compute it from the private key if shared.config.has_section(address): return True # This is not an address where we know the private key. # See if we already have the public key in our database: _, toAddressVersion, toStreamNumber, toRipe = decodedAddress queryReturn = sqlQuery( "SELECT hash FROM pubkeys WHERE hash=? AND addressversion=?", toRipe, toAddressVersion) if queryReturn != []: return True if toAddressVersion >= 4: # If we are trying to send to address version >= 4 then the needed pubkey might be encrypted in the inventory. # If we have it we'll need to decrypt it and put it in the pubkeys table. _, toTag = compute_priv_encryption_key_and_tag(toAddressVersion, toStreamNumber, toRipe) queryreturn = sqlQuery( '''SELECT payload FROM inventory WHERE objecttype='pubkey' and tag=? ''', toTag) if queryreturn != []: # if there was a pubkey in our inventory with the correct tag, we need to try to decrypt it. for row in queryreturn: data, = row if shared.decryptAndCheckPubkeyPayload( data, address) == 'successful': return True with shared.inventoryLock: for hash, storedValue in shared.inventory.items(): objectType, streamNumber, payload, receivedTime, tag = storedValue if objectType == 'pubkey' and tag == toTag: result = shared.decryptAndCheckPubkeyPayload( payload, address ) #if valid, this function also puts it in the pubkeys table. if result == 'successful': return True # We don't have the public key in our database. return False
def __contains__(self, hash_): with self.lock: if hash_ in self._objects: return True rows = sqlQuery('SELECT streamnumber FROM inventory WHERE hash=?', sqlite3.Binary(hash_)) if not rows: return False self._objects[hash_] = rows[0][0] return True
def isAddressInMyAddressBookSubscriptionsListOrWhitelist(address): """ Am I subscribed to this address, is it in my addressbook or whitelist? """ if isAddressInMyAddressBook(address): return True queryreturn = sqlQuery( '''SELECT address FROM whitelist where address=?''' ''' and enabled = '1' ''', address) if queryreturn != []: return True queryreturn = sqlQuery( '''select address from subscriptions where address=?''' ''' and enabled = '1' ''', address) if queryreturn != []: return True return False
def click_pushButtonAddBlacklist(self): self.NewBlacklistDialogInstance = AddAddressDialog(self) if self.NewBlacklistDialogInstance.exec_(): if self.NewBlacklistDialogInstance.labelAddressCheck.text() == \ _translate("MainWindow", "Address is valid."): address = addBMIfNotPresent( str(self.NewBlacklistDialogInstance.lineEditAddress.text()) ) # First we must check to see if the address is already in the # address book. The user cannot add it again or else it will # cause problems when updating and deleting the entry. t = (address, ) if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': sql = '''select * from blacklist where address=?''' else: sql = '''select * from whitelist where address=?''' queryreturn = sqlQuery(sql, *t) if queryreturn == []: self.tableWidgetBlacklist.setSortingEnabled(False) self.tableWidgetBlacklist.insertRow(0) newItem = QtGui.QTableWidgetItem( unicode( self.NewBlacklistDialogInstance.lineEditLabel.text( ).toUtf8(), 'utf-8')) newItem.setIcon(avatarize(address)) self.tableWidgetBlacklist.setItem(0, 0, newItem) newItem = QtGui.QTableWidgetItem(address) newItem.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.tableWidgetBlacklist.setItem(0, 1, newItem) self.tableWidgetBlacklist.setSortingEnabled(True) t = (str(self.NewBlacklistDialogInstance.lineEditLabel. text().toUtf8()), address, True) if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': sql = '''INSERT INTO blacklist VALUES (?,?,?)''' else: sql = '''INSERT INTO whitelist VALUES (?,?,?)''' sqlExecute(sql, *t) else: UISignalQueue.put( ('updateStatusBar', _translate( "MainWindow", "Error: You cannot add the same address to your" " list twice. Perhaps rename the existing one" " if you want."))) else: UISignalQueue.put( ('updateStatusBar', _translate( "MainWindow", "The address you entered was invalid. Ignoring it.")))
def has_pubkey_for(address, decodedAddress): # Can return True or False # If we need the public key for our own address or a chan, # we can compute it from the private key if shared.config.has_section( address ): return True # This is not an address where we know the private key. # See if we already have the public key in our database: _, toAddressVersion, toStreamNumber, toRipe = decodedAddress queryReturn = sqlQuery( "SELECT hash FROM pubkeys WHERE hash=? AND addressversion=?", toRipe, toAddressVersion) if queryReturn != []: return True if toAddressVersion >= 4: # If we are trying to send to address version >= 4 then the needed pubkey might be encrypted in the inventory. # If we have it we'll need to decrypt it and put it in the pubkeys table. _, toTag = compute_priv_encryption_key_and_tag(toAddressVersion, toStreamNumber, toRipe) queryreturn = sqlQuery( '''SELECT payload FROM inventory WHERE objecttype='pubkey' and tag=? ''', toTag) if queryreturn != []: # if there was a pubkey in our inventory with the correct tag, we need to try to decrypt it. for row in queryreturn: data, = row if shared.decryptAndCheckPubkeyPayload(data, address) == 'successful': return True with shared.inventoryLock: for hash, storedValue in shared.inventory.items(): objectType, streamNumber, payload, receivedTime, tag = storedValue if objectType == 'pubkey' and tag == toTag: result = shared.decryptAndCheckPubkeyPayload(payload, address) #if valid, this function also puts it in the pubkeys table. if result == 'successful': return True # We don't have the public key in our database. return False
def connectToStream(streamNumber): shared.streamsInWhichIAmParticipating[streamNumber] = 'no data' selfInitiatedConnections[streamNumber] = {} shared.inventorySets[streamNumber] = set() queryData = sqlQuery('''SELECT hash FROM inventory WHERE streamnumber=?''', streamNumber) for row in queryData: shared.inventorySets[streamNumber].add(row[0]) if sys.platform[0:3] == 'win': maximumNumberOfHalfOpenConnections = 9 else: maximumNumberOfHalfOpenConnections = 32 for i in range(maximumNumberOfHalfOpenConnections): a = outgoingSynSender() a.setup(streamNumber, selfInitiatedConnections) a.start()
def connectToStream(streamNumber): shared.streamsInWhichIAmParticipating[streamNumber] = "no data" selfInitiatedConnections[streamNumber] = {} shared.inventorySets[streamNumber] = set() queryData = sqlQuery("""SELECT hash FROM inventory WHERE streamnumber=?""", streamNumber) for row in queryData: shared.inventorySets[streamNumber].add(row[0]) if isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections(): # Some XP and Vista systems can only have 10 outgoing connections at a time. maximumNumberOfHalfOpenConnections = 9 else: maximumNumberOfHalfOpenConnections = 64 for i in range(maximumNumberOfHalfOpenConnections): a = outgoingSynSender() a.setup(streamNumber, selfInitiatedConnections) a.start()
def connect_to_stream(stream_number): shared.streamsInWhichIAmParticipating[stream_number] = 'no data' self_initiated_connections[stream_number] = {} shared.inventorySets[stream_number] = set() query_data = sqlQuery('''SELECT hash FROM inventory WHERE streamnumber=?''', stream_number) for row in query_data: shared.inventorySets[stream_number].add(row[0]) if isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections(): # Some XP and Vista systems can only have 10 outgoing connections at a time. maximum_number_of_half_open_connections = 9 else: maximum_number_of_half_open_connections = 64 for i in range(maximum_number_of_half_open_connections): a = outgoingSynSender() a.setup(stream_number, self_initiated_connections) a.start()
def click_pushButtonAddBlacklist(self): self.NewBlacklistDialogInstance = AddAddressDialog(self) if self.NewBlacklistDialogInstance.exec_(): if self.NewBlacklistDialogInstance.ui.labelAddressCheck.text() == _translate("MainWindow", "Address is valid."): address = addBMIfNotPresent(str( self.NewBlacklistDialogInstance.ui.lineEditAddress.text())) # First we must check to see if the address is already in the # address book. The user cannot add it again or else it will # cause problems when updating and deleting the entry. t = (address,) if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': sql = '''select * from blacklist where address=?''' else: sql = '''select * from whitelist where address=?''' queryreturn = sqlQuery(sql,*t) if queryreturn == []: self.tableWidgetBlacklist.setSortingEnabled(False) self.tableWidgetBlacklist.insertRow(0) newItem = QtGui.QTableWidgetItem(unicode( self.NewBlacklistDialogInstance.ui.newAddressLabel.text().toUtf8(), 'utf-8')) newItem.setIcon(avatarize(address)) self.tableWidgetBlacklist.setItem(0, 0, newItem) newItem = QtGui.QTableWidgetItem(address) newItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.tableWidgetBlacklist.setItem(0, 1, newItem) self.tableWidgetBlacklist.setSortingEnabled(True) t = (str(self.NewBlacklistDialogInstance.ui.newAddressLabel.text().toUtf8()), address, True) if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': sql = '''INSERT INTO blacklist VALUES (?,?,?)''' else: sql = '''INSERT INTO whitelist VALUES (?,?,?)''' sqlExecute(sql, *t) else: self.statusBar().showMessage(_translate( "MainWindow", "Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want.")) else: self.statusBar().showMessage(_translate( "MainWindow", "The address you entered was invalid. Ignoring it."))
def get_pubkey_for(address, decodedAddress=None): """ Retrieve public key for an address. Provide the decodedAddress if you already have it. No need to decode it more than once. Returns None if pubkey not found, otherwise the following tuple: ( pubEncryptionKey, pubSigningKey, requiredAvgPOWNonceTrialsPerByte, requiredPayloadLengthExtraBytes, behaviourBitfield ) The keys returned are in binary format. """ # Can return None, "mobile-user-disallowed", or # ( pubEncryptionKeyBase256, pubsigningKeyBase256, # requiredAverageProofOfWorkNonceTrialsPerByte, # requiredPayloadLengthExtraBytes, # behaviourBitfield ) if decodedAddress is None: decodedAddress = shared.decodeAddress( address ) requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes # If we need the public key for our own address or a chan, # we can compute it from the private key if shared.config.has_section( address ): try: privSigningKeyBase58 = shared.config.get( address, 'privsigningkey') privEncryptionKeyBase58 = shared.config.get( address, 'privencryptionkey') except: debug.logger.error( tr.translateText("MainWindow", "Error! Could not find sender address (your address) in the keys.dat file." ) ) return None privSigningKeyHex = shared.decodeWalletImportFormat( privSigningKeyBase58).encode('hex') privEncryptionKeyHex = shared.decodeWalletImportFormat( privEncryptionKeyBase58).encode('hex') pubSigningKey = highlevelcrypto.privToPub( privSigningKeyHex).decode('hex')[1:] pubEncryptionKey = highlevelcrypto.privToPub( privEncryptionKeyHex).decode('hex')[1:] return ( pubEncryptionKey, pubSigningKey, requiredAverageProofOfWorkNonceTrialsPerByte, requiredPayloadLengthExtraBytes, "\x00\x00\x00\x01" ) # This is not an address where we know the private key. # See if we already have the public key in our database: _, addressVersion, streamNumber, ripe = decodedAddress queryReturn = sqlQuery( "SELECT transmitdata FROM pubkeys WHERE hash=? AND addressversion=?", ripe, addressVersion) if queryReturn != []: pubkeyPayload = queryReturn[0][0] return decode_pubkey_payload( pubkeyPayload, addressVersion ) # The pubkey message is stored the way we originally received it # which means that we need to read beyond things like the nonce and # time to get to the actual public keys. # We don't have the public key in our database. return None
def _handle_request(self, method, params): if method == 'helloWorld': (a, b) = params return a + '-' + b elif method == 'add': (a, b) = params return a + b elif method == 'statusBar': message, = params shared.UISignalQueue.put(('updateStatusBar', message)) elif method == 'listAddresses' or method == 'listAddresses2': data = '{"addresses":[' configSections = shared.config.sections() for addressInKeysFile in configSections: if addressInKeysFile != 'bitmessagesettings': status, addressVersionNumber, streamNumber, hash01 = decodeAddress( addressInKeysFile) if len(data) > 20: data += ',' if shared.config.has_option(addressInKeysFile, 'chan'): chan = shared.config.getboolean(addressInKeysFile, 'chan') else: chan = False label = shared.config.get(addressInKeysFile, 'label') if method == 'listAddresses2': label = label.encode('base64') data += json.dumps({'label': label, 'address': addressInKeysFile, 'stream': streamNumber, 'enabled': shared.config.getboolean(addressInKeysFile, 'enabled'), 'chan': chan}, indent=4, separators=(',', ': ')) data += ']}' return data elif method == 'listAddressBookEntries' or method == 'listAddressbook': # the listAddressbook alias should be removed eventually. queryreturn = sqlQuery('''SELECT label, address from addressbook''') data = '{"addresses":[' for row in queryreturn: label, address = row label = shared.fixPotentiallyInvalidUTF8Data(label) if len(data) > 20: data += ',' data += json.dumps({'label':label.encode('base64'), 'address': address}, indent=4, separators=(',', ': ')) data += ']}' return data elif method == 'addAddressBookEntry' or method == 'addAddressbook': # the addAddressbook alias should be deleted eventually. 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) queryreturn = sqlQuery("SELECT address FROM addressbook WHERE address=?", address) if queryreturn != []: raise APIError(16, 'You already have this address in your address book.') sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address) shared.UISignalQueue.put(('rerenderInboxFromLabels','')) shared.UISignalQueue.put(('rerenderSentToLabels','')) shared.UISignalQueue.put(('rerenderAddressBook','')) return "Added address %s to address book" % address elif method == 'deleteAddressBookEntry' or method == 'deleteAddressbook': # The deleteAddressbook alias should be deleted eventually. 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) shared.UISignalQueue.put(('rerenderInboxFromLabels','')) shared.UISignalQueue.put(('rerenderSentToLabels','')) shared.UISignalQueue.put(('rerenderAddressBook','')) return "Deleted address book entry for %s if it existed" % address elif method == 'createRandomAddress': if len(params) == 0: raise APIError(0, 'I need parameters!') elif len(params) == 1: label, = params eighteenByteRipe = False nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 2: label, eighteenByteRipe = params nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 3: label, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 4: label, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params nonceTrialsPerByte = int( shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = int( shared.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) 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.') shared.apiAddressGeneratorReturnQueue.queue.clear() streamNumberForAddress = 1 shared.addressGeneratorQueue.put(( 'createRandomAddress', 4, streamNumberForAddress, label, 1, "", eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes)) return shared.apiAddressGeneratorReturnQueue.get() elif method == 'createDeterministicAddresses': if len(params) == 0: raise APIError(0, 'I need parameters!') elif len(params) == 1: passphrase, = params numberOfAddresses = 1 addressVersionNumber = 0 streamNumber = 0 eighteenByteRipe = False nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 2: passphrase, numberOfAddresses = params addressVersionNumber = 0 streamNumber = 0 eighteenByteRipe = False nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 3: passphrase, numberOfAddresses, addressVersionNumber = params streamNumber = 0 eighteenByteRipe = False nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 4: passphrase, numberOfAddresses, addressVersionNumber, streamNumber = params eighteenByteRipe = False nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 5: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe = params nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 6: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 7: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params nonceTrialsPerByte = int( shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = int( shared.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) else: raise APIError(0, 'Too many parameters!') if len(passphrase) == 0: raise APIError(1, 'The specified passphrase is blank.') if not isinstance(eighteenByteRipe, bool): raise APIError(23, 'Bool expected in eighteenByteRipe, saw %s instead' % type(eighteenByteRipe)) passphrase = self._decode(passphrase, "base64") if addressVersionNumber == 0: # 0 means "just use the proper addressVersionNumber" addressVersionNumber = 4 if addressVersionNumber != 3 and addressVersionNumber != 4: raise APIError(2,'The address version number currently must be 3, 4, or 0 (which means auto-select). ' + addressVersionNumber + ' isn\'t supported.') if streamNumber == 0: # 0 means "just use the most available stream" streamNumber = 1 if streamNumber != 1: raise APIError(3,'The stream number must be 1 (or 0 which means auto-select). Others aren\'t supported.') if numberOfAddresses == 0: raise APIError(4, 'Why would you ask me to generate 0 addresses for you?') if numberOfAddresses > 999: 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.') shared.apiAddressGeneratorReturnQueue.queue.clear() logger.debug('Requesting that the addressGenerator create %s addresses.', numberOfAddresses) shared.addressGeneratorQueue.put( ('createDeterministicAddresses', addressVersionNumber, streamNumber, 'unused API address', numberOfAddresses, passphrase, eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes)) data = '{"addresses":[' queueReturn = shared.apiAddressGeneratorReturnQueue.get() for item in queueReturn: if len(data) > 20: data += ',' data += "\"" + item + "\"" data += ']}' return data elif method == 'getDeterministicAddress': 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: raise APIError(2, 'The address version number currently must be 3 or 4. ' + addressVersionNumber + ' isn\'t supported.') if streamNumber != 1: raise APIError(3, ' The stream number must be 1. Others aren\'t supported.') shared.apiAddressGeneratorReturnQueue.queue.clear() logger.debug('Requesting that the addressGenerator create %s addresses.', numberOfAddresses) shared.addressGeneratorQueue.put( ('getDeterministicAddress', addressVersionNumber, streamNumber, 'unused API address', numberOfAddresses, passphrase, eighteenByteRipe)) 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] 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.') #TODO: this variable is not used to anything createdAddress = addressGeneratorReturnValue[0] # in case we ever want it for anything. 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) 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': queryreturn = sqlQuery( '''SELECT msgid, toaddress, fromaddress, subject, received, message, encodingtype, read FROM inbox where folder='inbox' ORDER BY received''') data = '{"inboxMessages":[' for row in queryreturn: msgid, toAddress, fromAddress, subject, received, message, encodingtype, read = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' data += json.dumps({'msgid': msgid.encode('hex'), 'toAddress': toAddress, 'fromAddress': fromAddress, 'subject': subject.encode( 'base64'), 'message': message.encode('base64'), 'encodingType': encodingtype, 'receivedTime': received, 'read': read}, indent=4, separators=(',', ': ')) data += ']}' return data elif method == 'getAllInboxMessageIds' or method == 'getAllInboxMessageIDs': queryreturn = sqlQuery( '''SELECT msgid FROM inbox where folder='inbox' ORDER BY received''') data = '{"inboxMessageIds":[' for row in queryreturn: msgid = row[0] if len(data) > 25: data += ',' data += json.dumps({'msgid': msgid.encode('hex')}, indent=4, separators=(',', ': ')) data += ']}' return data elif method == 'getInboxMessageById' or method == 'getInboxMessageByID': if len(params) == 0: raise APIError(0, 'I need parameters!') elif len(params) == 1: msgid = self._decode(params[0], "hex") elif len(params) >= 2: msgid = self._decode(params[0], "hex") readStatus = params[1] if not isinstance(readStatus, bool): raise APIError(23, 'Bool expected in readStatus, saw %s instead.' % type(readStatus)) queryreturn = sqlQuery('''SELECT read FROM inbox WHERE msgid=?''', msgid) # UPDATE is slow, only update if status is different if queryreturn != [] and (queryreturn[0][0] == 1) != readStatus: sqlExecute('''UPDATE inbox set read = ? WHERE msgid=?''', readStatus, msgid) shared.UISignalQueue.put(('changedInboxUnread', None)) queryreturn = sqlQuery('''SELECT msgid, toaddress, fromaddress, subject, received, message, encodingtype, read FROM inbox WHERE msgid=?''', msgid) data = '{"inboxMessage":[' for row in queryreturn: msgid, toAddress, fromAddress, subject, received, message, encodingtype, read = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) data += json.dumps({'msgid':msgid.encode('hex'), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'receivedTime':received, 'read': read}, indent=4, separators=(',', ': ')) data += ']}' return data elif method == 'getAllSentMessages': queryreturn = sqlQuery('''SELECT msgid, toaddress, fromaddress, subject, lastactiontime, message, encodingtype, status, ackdata FROM sent where folder='sent' ORDER BY lastactiontime''') data = '{"sentMessages":[' for row in queryreturn: msgid, toAddress, fromAddress, subject, lastactiontime, message, encodingtype, status, ackdata = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' data += json.dumps({'msgid':msgid.encode('hex'), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':ackdata.encode('hex')}, indent=4, separators=(',', ': ')) data += ']}' return data elif method == 'getAllSentMessageIds' or method == 'getAllSentMessageIDs': queryreturn = sqlQuery('''SELECT msgid FROM sent where folder='sent' ORDER BY lastactiontime''') data = '{"sentMessageIds":[' for row in queryreturn: msgid = row[0] if len(data) > 25: data += ',' data += json.dumps({'msgid':msgid.encode('hex')}, indent=4, separators=(',', ': ')) data += ']}' return data elif method == 'getInboxMessagesByReceiver' or method == 'getInboxMessagesByAddress': #after some time getInboxMessagesByAddress should be removed if len(params) == 0: raise APIError(0, 'I need parameters!') toAddress = params[0] queryreturn = sqlQuery('''SELECT msgid, toaddress, fromaddress, subject, received, message, encodingtype FROM inbox WHERE folder='inbox' AND toAddress=?''', toAddress) data = '{"inboxMessages":[' for row in queryreturn: msgid, toAddress, fromAddress, subject, received, message, encodingtype = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' data += json.dumps({'msgid':msgid.encode('hex'), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'receivedTime':received}, indent=4, separators=(',', ': ')) data += ']}' return data elif method == 'getSentMessageById' or method == 'getSentMessageByID': if len(params) == 0: raise APIError(0, 'I need parameters!') msgid = self._decode(params[0], "hex") queryreturn = sqlQuery('''SELECT msgid, toaddress, fromaddress, subject, lastactiontime, message, encodingtype, status, ackdata FROM sent WHERE msgid=?''', msgid) data = '{"sentMessage":[' for row in queryreturn: msgid, toAddress, fromAddress, subject, lastactiontime, message, encodingtype, status, ackdata = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) data += json.dumps({'msgid':msgid.encode('hex'), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':ackdata.encode('hex')}, indent=4, separators=(',', ': ')) data += ']}' return data elif method == 'getSentMessagesByAddress' or method == 'getSentMessagesBySender': if len(params) == 0: raise APIError(0, 'I need parameters!') fromAddress = params[0] queryreturn = sqlQuery('''SELECT msgid, toaddress, fromaddress, subject, lastactiontime, message, encodingtype, status, ackdata FROM sent WHERE folder='sent' AND fromAddress=? ORDER BY lastactiontime''', fromAddress) data = '{"sentMessages":[' for row in queryreturn: msgid, toAddress, fromAddress, subject, lastactiontime, message, encodingtype, status, ackdata = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' data += json.dumps({'msgid':msgid.encode('hex'), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':ackdata.encode('hex')}, indent=4, separators=(',', ': ')) data += ']}' return data elif method == 'getSentMessageByAckData': if len(params) == 0: raise APIError(0, 'I need parameters!') ackData = self._decode(params[0], "hex") queryreturn = sqlQuery('''SELECT msgid, toaddress, fromaddress, subject, lastactiontime, message, encodingtype, status, ackdata FROM sent WHERE ackdata=?''', ackData) data = '{"sentMessage":[' for row in queryreturn: msgid, toAddress, fromAddress, subject, lastactiontime, message, encodingtype, status, ackdata = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) data += json.dumps({'msgid':msgid.encode('hex'), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':ackdata.encode('hex')}, indent=4, separators=(',', ': ')) data += ']}' return data elif method == 'trashMessage': 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).' elif method == 'trashInboxMessage': 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).' elif method == 'trashSentMessage': 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).' elif method == 'trashSentMessageByAckData': # 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") sqlExecute('''UPDATE sent SET folder='trash' WHERE ackdata=?''', ackdata) return 'Trashed sent message (assuming message existed).' elif method == 'sendMessage': if len(params) == 0: raise APIError(0, 'I need parameters!') elif len(params) == 4: toAddress, fromAddress, subject, message = params encodingType = 2 elif len(params) == 5: toAddress, fromAddress, subject, message, encodingType = params if encodingType != 2: raise APIError(6, 'The encoding type must be 2 because that is the only one this program currently supports.') subject = self._decode(subject, "base64") message = self._decode(message, "base64") toAddress = addBMIfNotPresent(toAddress) fromAddress = addBMIfNotPresent(fromAddress) status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(toAddress) self._verifyAddress(fromAddress) try: fromAddressEnabled = shared.config.getboolean( fromAddress, 'enabled') except: raise APIError(13, 'Could not find your fromAddress in the keys.dat file.') if not fromAddressEnabled: raise APIError(14, 'Your fromAddress is disabled. Cannot send.') ackdata = OpenSSL.rand(32) t = ('', toAddress, toRipe, fromAddress, subject, message, ackdata, int( time.time()), 'msgqueued', 1, 1, 'sent', 2) helper_sent.insert(t) toLabel = '' queryreturn = sqlQuery('''select label from addressbook where address=?''', toAddress) if queryreturn != []: for row in queryreturn: toLabel, = row # apiSignalQueue.put(('displayNewSentMessage',(toAddress,toLabel,fromAddress,subject,message,ackdata))) shared.UISignalQueue.put(('displayNewSentMessage', ( toAddress, toLabel, fromAddress, subject, message, ackdata))) shared.workerQueue.put(('sendmessage', toAddress)) return ackdata.encode('hex') elif method == 'sendBroadcast': if len(params) == 0: raise APIError(0, 'I need parameters!') if len(params) == 3: fromAddress, subject, message = params encodingType = 2 elif len(params) == 4: fromAddress, subject, message, encodingType = params if encodingType != 2: raise APIError(6, 'The encoding type must be 2 because that is the only one this program currently supports.') subject = self._decode(subject, "base64") message = self._decode(message, "base64") fromAddress = addBMIfNotPresent(fromAddress) self._verifyAddress(fromAddress) try: fromAddressEnabled = shared.config.getboolean( fromAddress, 'enabled') except: raise APIError(13, 'could not find your fromAddress in the keys.dat file.') ackdata = OpenSSL.rand(32) toAddress = '[Broadcast subscribers]' ripe = '' t = ('', toAddress, ripe, fromAddress, subject, message, ackdata, int( time.time()), 'broadcastqueued', 1, 1, 'sent', 2) helper_sent.insert(t) toLabel = '[Broadcast subscribers]' shared.UISignalQueue.put(('displayNewSentMessage', ( toAddress, toLabel, fromAddress, subject, message, ackdata))) shared.workerQueue.put(('sendbroadcast', '')) return ackdata.encode('hex') elif method == 'getStatus': if len(params) != 1: raise APIError(0, 'I need one parameter!') ackdata, = params if len(ackdata) != 64: raise APIError(15, 'The length of ackData should be 32 bytes (encoded in hex thus 64 characters).') ackdata = self._decode(ackdata, "hex") queryreturn = sqlQuery( '''SELECT status FROM sent where ackdata=?''', ackdata) if queryreturn == []: return 'notfound' for row in queryreturn: status, = row return status elif method == 'addSubscription': 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") try: unicode(label, 'utf-8') except: 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. queryreturn = sqlQuery('''select * from subscriptions where address=?''', address) if queryreturn != []: raise APIError(16, 'You are already subscribed to that address.') sqlExecute('''INSERT INTO subscriptions VALUES (?,?,?)''',label, address, True) shared.reloadBroadcastSendersForWhichImWatching() shared.UISignalQueue.put(('rerenderInboxFromLabels', '')) shared.UISignalQueue.put(('rerenderSubscriptions', '')) return 'Added subscription.' elif method == 'deleteSubscription': 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() shared.UISignalQueue.put(('rerenderInboxFromLabels', '')) shared.UISignalQueue.put(('rerenderSubscriptions', '')) return 'Deleted subscription if it existed.' elif method == 'listSubscriptions': queryreturn = sqlQuery('''SELECT label, address, enabled FROM subscriptions''') data = '{"subscriptions":[' for row in queryreturn: label, address, enabled = row label = shared.fixPotentiallyInvalidUTF8Data(label) if len(data) > 20: data += ',' data += json.dumps({'label':label.encode('base64'), 'address': address, 'enabled': enabled == 1}, indent=4, separators=(',',': ')) data += ']}' return data elif method == 'disseminatePreEncryptedMsg': # 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. if len(params) != 3: raise APIError(0, 'I need 3 parameter!') encryptedPayload, requiredAverageProofOfWorkNonceTrialsPerByte, requiredPayloadLengthExtraBytes = params encryptedPayload = self._decode(encryptedPayload, "hex") # Let us do the POW and attach it to the front target = 2**64 / ((len(encryptedPayload)+requiredPayloadLengthExtraBytes+8) * requiredAverageProofOfWorkNonceTrialsPerByte) with shared.printLock: print '(For msg message via API) Doing proof of work. Total required difficulty:', float(requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte, 'Required small message difficulty:', float(requiredPayloadLengthExtraBytes) / shared.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: pass encryptedPayload = pack('>Q', nonce) + encryptedPayload toStreamNumber = decodeVarint(encryptedPayload[16:26])[0] inventoryHash = calculateInventoryHash(encryptedPayload) objectType = 'msg' shared.inventory[inventoryHash] = ( objectType, toStreamNumber, encryptedPayload, int(time.time()),'') shared.inventorySets[toStreamNumber].add(inventoryHash) with shared.printLock: print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', inventoryHash.encode('hex') shared.broadcastToSendDataQueues(( toStreamNumber, 'advertiseobject', inventoryHash)) elif method == 'disseminatePubkey': # 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. if len(params) != 1: raise APIError(0, 'I need 1 parameter!') payload, = params payload = self._decode(payload, "hex") # Let us do the POW target = 2 ** 64 / ((len(payload) + shared.networkDefaultPayloadLengthExtraBytes + 8) * shared.networkDefaultProofOfWorkNonceTrialsPerByte) 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 pubkeyReadPosition = 8 # bypass the nonce if payload[pubkeyReadPosition:pubkeyReadPosition+4] == '\x00\x00\x00\x00': # if this pubkey uses 8 byte time pubkeyReadPosition += 8 else: pubkeyReadPosition += 4 addressVersion, addressVersionLength = decodeVarint(payload[pubkeyReadPosition:pubkeyReadPosition+10]) pubkeyReadPosition += addressVersionLength pubkeyStreamNumber = decodeVarint(payload[pubkeyReadPosition:pubkeyReadPosition+10])[0] inventoryHash = calculateInventoryHash(payload) objectType = 'pubkey' #todo: support v4 pubkeys shared.inventory[inventoryHash] = ( objectType, pubkeyStreamNumber, payload, int(time.time()),'') shared.inventorySets[pubkeyStreamNumber].add(inventoryHash) with shared.printLock: print 'broadcasting inv within API command disseminatePubkey with hash:', inventoryHash.encode('hex') shared.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) elif method == 'getMessageDataByDestinationHash' or method == 'getMessageDataByDestinationTag': # 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: raise APIError(19, 'The length of hash should be 32 bytes (encoded in hex thus 64 characters).') 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( '''SELECT hash, payload FROM inventory WHERE tag = '' and objecttype = 'msg' ; ''') with SqlBulkExecute() as sql: for row in queryreturn: hash01, payload = row readPosition = 16 # Nonce length + time length readPosition += decodeVarint(payload[readPosition:readPosition+10])[1] # Stream Number length t = (payload[readPosition:readPosition+32],hash01) sql.execute('''UPDATE inventory SET tag=? WHERE hash=?; ''', *t) queryreturn = sqlQuery('''SELECT payload FROM inventory WHERE tag = ?''', requestedHash) data = '{"receivedMessageDatas":[' for row in queryreturn: payload, = row if len(data) > 25: data += ',' data += json.dumps({'data':payload.encode('hex')}, indent=4, separators=(',', ': ')) data += ']}' return data elif method == 'getPubkeyByHash': # Method will eventually be used by a particular Android app to # retrieve pubkeys. Please do not yet add this to the api docs. if len(params) != 1: raise APIError(0, 'I need 1 parameter!') requestedHash, = params if len(requestedHash) != 40: raise APIError(19, 'The length of hash should be 20 bytes (encoded in hex thus 40 characters).') requestedHash = self._decode(requestedHash, "hex") queryreturn = sqlQuery('''SELECT transmitdata FROM pubkeys WHERE hash = ? ; ''', requestedHash) data = '{"pubkey":[' for row in queryreturn: transmitdata, = row data += json.dumps({'data':transmitdata.encode('hex')}, indent=4, separators=(',', ': ')) data += ']}' return data elif method == 'clientStatus': if len(shared.connectedHostsList) == 0: networkStatus = 'notConnected' elif len(shared.connectedHostsList) > 0 and not shared.clientHasReceivedIncomingConnections: networkStatus = 'connectedButHaveNotReceivedIncomingConnections' else: 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=(',', ': ')) elif method == 'decodeAddress': # 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) return json.dumps({'status':status, 'addressVersion':addressVersion, 'streamNumber':streamNumber, 'ripe':ripe.encode('base64')}, indent=4, separators=(',', ': ')) else: raise APIError(20, 'Invalid method: %s' % method)
def _handle_request(self, method, params): if method == 'add': (a, b) = params return a + b # Commands for disseminating msgs, getpubkeys, and pubkeys elif method == 'disseminateMsg': self.checkParameters(params, 1) payload, = params payloadBytes = payload.decode('hex') if (shared.checkAndShareObjectWithPeers(payloadBytes) > 0): return 'Message disseminated successfully' else: return 'Message dissemination failed' elif method == 'disseminatePubkey': self.checkParameters(params, 1) payload, = params payloadBytes = payload.decode('hex') if (shared.checkAndShareObjectWithPeers(payloadBytes) > 0): return 'Pubkey disseminated successfully' else: return 'Pubkey dissemination failed' elif method == 'disseminateGetpubkey': self.checkParameters(params, 1) payload, = params payloadBytes = payload.decode('hex') if (shared.checkAndShareObjectWithPeers(payloadBytes) > 0): return 'Getpubkey disseminated successfully' else: return 'Getpubkey dissemination failed' # Commands for requesting msgs and pubkeys elif method == 'requestPubkey': ''' Check the supplied parameters ''' if len(params) != 2: raise APIError(0, 'I need 2 parameters!') identifierHex, addressVersion = params ''' Check that the address version and requested tag are valid ''' if addressVersion < 1: raise APIError(2, 'The address version cannot be less than 1') elif addressVersion > 4: raise APIError(3, 'Address versions above 4 are currently not supported') elif addressVersion < 4: # For pubkeys of address versions 1-3 if len(identifierHex) != 40: raise APIError(4, 'The length of identifier (the ripe hash of the pubkey) should be 20 bytes (encoded in hex and thus 40 characters).') else: # For pubkeys of address version 4 if len(identifierHex) != 64: raise APIError(5, 'The length of identifier (the tag of the pubkey) should be 32 bytes (encoded in hex and thus 64 characters).') ''' Now attempt to retrieve the pubkey using the given identifier ''' requestedTag = self._decode(identifierHex, "hex") queryReturn = sqlQuery('''SELECT payload FROM inventory WHERE objecttype=1 and tag=? ''', requestedTag) if queryReturn != []: payload = queryReturn[0] if len(payload) <= self.MAX_PAYLOAD_SIZE_TO_RETURN: return self.outputQueryReturn("pubkeyPayload", queryReturn) else: raise APIError(6, 'The requested object was found, but its payload is above the maximum size limit. The size of the object payload is ' + str(len(payload))) else: # We had no success looking in the sql inventory. Let's look through the memory inventory. with shared.inventoryLock: for hash, storedValue in shared.inventory.items(): objectType, streamNumber, payload, expiresTime, tag, receivedTime = storedValue if objectType == self.OBJECT_TYPE_PUBKEY and tag == requestedTag: if len(payload) <= self.MAX_PAYLOAD_SIZE_TO_RETURN: return self.outputPayload("pubkeyPayload", payload) else: raise APIError(6, 'The requested object was found, but its payload is above the maximum size limit. The size of the object payload is ' + str(len(payload))) else: return 'No pubkeys found' elif method == 'checkForNewMsgs': self.checkParameters(params, 3) streamNumber, receivedSinceTime, receivedBeforeTime = params queryReturn = sqlQuery('''SELECT payload FROM inventory WHERE objecttype=2 and streamnumber=? and receivedTime>? and receivedTime<? ''', streamNumber, receivedSinceTime, receivedBeforeTime) output = [] if queryReturn != []: output = self.addQueryReturnToOutput(output, queryReturn) # Now let us search through the objects stored in memory with shared.inventoryLock: for hash, storedValue in shared.inventory.items(): objectType, streamNumber, payload, expiresTime, tag, receivedTime = storedValue if objectType == self.OBJECT_TYPE_MSG and receivedTime > receivedSinceTime and receivedTime < receivedBeforeTime: if len(payload) <= self.MAX_PAYLOAD_SIZE_TO_RETURN: output = self.addPayloadToOutput(output, payload) if output == []: return 'No msgs found' else: return self.outputAsJSON('msgPayloads', output)