return(firstByte,1)#the 1 is the length of the varint
iffirstByte==253:
a,=unpack('>H',data[1:3])
return(a,3)
# encodes 253 to 65535
iflen(data)<3:
raisevarintDecodeError('The first byte of this varint as an integer is %s but the total length is only %s. It needs to be at least 3.'%(firstByte,len(data)))
encodedValue,=unpack('>H',data[1:3])
ifencodedValue<253:
raisevarintDecodeError('This varint does not encode the value with the lowest possible number of bytes.')
return(encodedValue,3)
iffirstByte==254:
a,=unpack('>I',data[1:5])
return(a,5)
# encodes 65536 to 4294967295
iflen(data)<5:
raisevarintDecodeError('The first byte of this varint as an integer is %s but the total length is only %s. It needs to be at least 5.'%(firstByte,len(data)))
encodedValue,=unpack('>I',data[1:5])
ifencodedValue<65536:
raisevarintDecodeError('This varint does not encode the value with the lowest possible number of bytes.')
return(encodedValue,5)
iffirstByte==255:
a,=unpack('>Q',data[1:9])
return(a,9)
# encodes 4294967296 to 18446744073709551615
iflen(data)<9:
raisevarintDecodeError('The first byte of this varint as an integer is %s but the total length is only %s. It needs to be at least 9.'%(firstByte,len(data)))
encodedValue,=unpack('>Q',data[1:9])
ifencodedValue<4294967296:
raisevarintDecodeError('This varint does not encode the value with the lowest possible number of bytes.')
QMessageBox.about(self,_translate("MainWindow","Message too long"),_translate(
"MainWindow","The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending.").arg(len(message)-(2**18-500)))
return
ifself.ui.radioButtonSpecific.isChecked():# To send a message to specific people (rather than broadcast)
toAddressesList=[s.strip()
forsintoAddresses.replace(',',';').split(';')]
@ -1873,6 +1884,9 @@ class MyForm(QtGui.QMainWindow):
elifstatus=='ripetoolong':
self.statusBar().showMessage(_translate(
"MainWindow","Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance.").arg(toAddress))
elifstatus=='varintmalformed':
self.statusBar().showMessage(_translate(
"MainWindow","Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance.").arg(toAddress))
else:
self.statusBar().showMessage(_translate(
"MainWindow","Error: Something is wrong with the address %1.").arg(toAddress))
@ -2211,10 +2225,10 @@ class MyForm(QtGui.QMainWindow):
fromsubprocessimportcall# used when the API must execute an outside program
from pyelliptic.opensslimportOpenSSL
import traceback
frompyelliptic.opensslimportOpenSSL
importhighlevelcrypto
fromaddressesimport*
importhelper_generic
@ -51,18 +52,23 @@ class objectProcessor(threading.Thread):
whileTrue:
objectType,data=shared.objectProcessorQueue.get()
ifobjectType=='getpubkey':
self.processgetpubkey(data)
elifobjectType=='pubkey':
self.processpubkey(data)
elifobjectType=='msg':
self.processmsg(data)
elifobjectType=='broadcast':
self.processbroadcast(data)
elifobjectType=='checkShutdownVariable':# is more of a command, not an object type. Is used to get this thread past the queue.get() so that it will check the shutdown variable.
pass
else:
logger.critical('Error! Bug! The class_objectProcessor was passed an object type it doesn\'t recognize: %s'%str(objectType))
try:
ifobjectType==0:# getpubkey
self.processgetpubkey(data)
elifobjectType==1:#pubkey
self.processpubkey(data)
elifobjectType==2:#msg
self.processmsg(data)
elifobjectType==3:#broadcast
self.processbroadcast(data)
elifobjectType=='checkShutdownVariable':# is more of a command, not an object type. Is used to get this thread past the queue.get() so that it will check the shutdown variable.
pass
else:
logger.critical('Error! Bug! The class_objectProcessor was passed an object type it doesn\'t recognize: %s'%str(objectType))
exceptvarintDecodeErrorase:
logger.debug("There was a problem with a varint while processing an object. Some details: %s"%e)
exceptExceptionase:
logger.critical("Critical error within objectProcessorThread: \n%s"%traceback.format_exc())
withshared.objectProcessorQueueSizeLock:
shared.objectProcessorQueueSize-=len(data)# We maintain objectProcessorQueueSize so that we will slow down requesting objects if too much data accumulates in the queue.
@ -83,17 +89,7 @@ class objectProcessor(threading.Thread):
@ -147,7 +143,7 @@ class objectProcessor(threading.Thread):
myAddress,'lastpubkeysendtime'))
except:
lastPubkeySendTime=0
iflastPubkeySendTime>time.time()-shared.lengthOfTimeToHoldOnToAllPubkeys:# If the last time we sent our pubkey was more recent than 28 days ago...
iflastPubkeySendTime>time.time()-2419200:# If the last time we sent our pubkey was more recent than 28 days ago...
logger.info('Found getpubkey-requested-item in my list of EC hashes BUT we already sent it recently. Ignoring request. The lastPubkeySendTime is: %s'%lastPubkeySendTime)
return
logger.info('Found getpubkey-requested-hash in my list of EC hashes. Telling Worker thread to do the POW for a pubkey message and send it out.')
@ -166,17 +162,8 @@ class objectProcessor(threading.Thread):
sqlExecute('UPDATE sent SET status=? WHERE ackdata=?',
'ackreceived',data[readPosition:])
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(data[readPosition:],tr.translateText("MainWindow",'Acknowledgement of the message received. %1').arg(l10n.formatTimestamp()))))
'ackreceived',data[-32:])
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(data[-32:],tr.translateText("MainWindow",'Acknowledgement of the message received. %1').arg(l10n.formatTimestamp()))))
return
else:
logger.info('This was NOT an acknowledgement bound for me.')
@ -430,17 +378,35 @@ class objectProcessor(threading.Thread):
# This is not an acknowledgement bound for me. See if it is a message
# bound for me by trying to decrypt it with my private keys.
# This can be simplified quite a bit after 1416175200: # Sun, 16 Nov 2014 22:00:00 GMT
toRipe=key# This is the RIPE hash of my pubkeys. We need this below to compare to the destination_ripe included in the encrypted data.
initialDecryptionSuccessful=True
logger.info('EC decryption successful using key associated with ripe hash: %s'%key.encode('hex'))
logger.info('EC decryption successful using key associated with ripe hash: %s. msg did NOT specify version.'%key.encode('hex'))
# We didn't bypass a msg version above as it is commented out.
# But the decryption was successful. Which means that there
# wasn't a msg version byte include in this msg.
msgObjectContainedVersion=False
break
exceptExceptionaserr:
pass
# print 'cryptorObject.decrypt Exception:', err
# What if a client sent us a msg with
# a msg version included? We didn't bypass it above. So
# let's try to decrypt the msg assuming that it is present.
try:
decryptedData=cryptorObject.decrypt(data[readPosition+1:])# notice that we offset by 1 byte compared to the attempt above.
toRipe=key# This is the RIPE hash of my pubkeys. We need this below to compare to the destination_ripe included in the encrypted data.
initialDecryptionSuccessful=True
logger.info('EC decryption successful using key associated with ripe hash: %s. msg DID specifiy version.'%key.encode('hex'))
# There IS a msg version byte include in this msg.
msgObjectContainedVersion=True
break
exceptExceptionaserr:
pass
ifnotinitialDecryptionSuccessful:
# This is not a message bound for me.
logger.info('Length of time program spent failing to decrypt this message: %s seconds.'%(time.time()-messageProcessingStartTime,))
@ -450,12 +416,15 @@ class objectProcessor(threading.Thread):
toAddress=shared.myAddressesByHash[
toRipe]# Look up my address based on the RIPE hash.
readPosition=0
messageVersion,messageVersionLength=decodeVarint(
decryptedData[readPosition:readPosition+10])
readPosition+=messageVersionLength
ifmessageVersion!=1:
logger.info('Cannot understand message versions other than one. Ignoring message.')
return
ifnotmsgObjectContainedVersion:# by which I mean "if the msg object didn't have the msg version outside of the encryption". This confusingness will be removed after the protocol v3 upgrade period.
logger.debug('As a matter of intellectual curiosity, here is the Bitcoin address associated with the keys owned by the other person: %s ..and here is the testnet address: %s. The other person must take their private signing key from Bitmessage and import it into Bitcoin (or a service like Blockchain.info) for it to be of any use. Do not use this unless you know what you are doing.'%
logger.debug('Cannot decode incoming broadcast versions higher than 3. Assuming the sender isn\'t being silly, you should upgrade Bitmessage because this message shall be ignored.')
ifbroadcastVersion<1orbroadcastVersion>5:
logger.info('Cannot decode incoming broadcast versions higher than 5. Assuming the sender isn\'t being silly, you should upgrade Bitmessage because this message shall be ignored.')
return
ifbroadcastVersion==1:
beginningOfPubkeyPosition=readPosition# used when we add the pubkey to our pubkey table
beginningOfPubkeyPosition=readPosition# used when we add the pubkey to our pubkey table. This variable can be disposed of after the protocol v3 upgrade period because it will necessarily be at the beginning of the decryptedData; ie it will definitely equal 0
logger.info('Cannot decode senderAddressVersion less than 4 for broadcast version number 3. Assuming the sender isn\'t being silly, you should upgrade Bitmessage because this message shall be ignored.')
logger.info('Cannot decode senderAddressVersion less than 4 for broadcast version number 3 or 4. Assuming the sender isn\'t being silly, you should upgrade Bitmessage because this message shall be ignored.')
return
readPosition+=sendersAddressVersionLength
sendersStream,sendersStreamLength=decodeVarint(
@ -1067,14 +915,14 @@ class objectProcessor(threading.Thread):
# This thread is created either by the synSenderThread(for outgoing
# connections) or the singleListenerThread(for incoming connections).
@ -117,7 +117,7 @@ class receiveDataThread(threading.Thread):
ifmagic!=0xE9BEB4D9:
self.data=""
return
ifpayloadLength>20000000:
ifpayloadLength>2**18:# 256 KiB
logger.info('The incoming message, which we have not yet download, is too large. Ignoring it. (unfortunately there is no way to tell the other node to stop sending it except to disconnect.) Message size: %s'%payloadLength)