|
|
|
@ -156,6 +156,10 @@ class singleWorker(threading.Thread):
|
|
|
|
|
# send messages to "ourselves".
|
|
|
|
|
def sendOutOrStoreMyV3Pubkey(self, hash):
|
|
|
|
|
myAddress = shared.myAddressesByHash[hash]
|
|
|
|
|
if shared.safeConfigGetBoolean(myAddress, 'chan'):
|
|
|
|
|
with shared.printLock:
|
|
|
|
|
print 'This is a chan address. Not sending pubkey.'
|
|
|
|
|
return
|
|
|
|
|
status, addressVersionNumber, streamNumber, hash = decodeAddress(
|
|
|
|
|
myAddress)
|
|
|
|
|
embeddedTime = int(time.time() + random.randrange(
|
|
|
|
@ -197,49 +201,39 @@ class singleWorker(threading.Thread):
|
|
|
|
|
payload += encodeVarint(len(signature))
|
|
|
|
|
payload += signature
|
|
|
|
|
|
|
|
|
|
if not shared.safeConfigGetBoolean(myAddress, 'chan'):
|
|
|
|
|
# Do the POW for this pubkey message
|
|
|
|
|
target = 2 ** 64 / ((len(payload) + shared.networkDefaultPayloadLengthExtraBytes +
|
|
|
|
|
8) * shared.networkDefaultProofOfWorkNonceTrialsPerByte)
|
|
|
|
|
print '(For pubkey message) Doing proof of work...'
|
|
|
|
|
initialHash = hashlib.sha512(payload).digest()
|
|
|
|
|
trialValue, nonce = proofofwork.run(target, initialHash)
|
|
|
|
|
print '(For pubkey message) Found proof of work', trialValue, 'Nonce:', nonce
|
|
|
|
|
# Do the POW for this pubkey message
|
|
|
|
|
target = 2 ** 64 / ((len(payload) + shared.networkDefaultPayloadLengthExtraBytes +
|
|
|
|
|
8) * shared.networkDefaultProofOfWorkNonceTrialsPerByte)
|
|
|
|
|
print '(For pubkey message) Doing proof of work...'
|
|
|
|
|
initialHash = hashlib.sha512(payload).digest()
|
|
|
|
|
trialValue, nonce = proofofwork.run(target, initialHash)
|
|
|
|
|
print '(For pubkey message) Found proof of work', trialValue, 'Nonce:', nonce
|
|
|
|
|
|
|
|
|
|
payload = pack('>Q', nonce) + payload
|
|
|
|
|
inventoryHash = calculateInventoryHash(payload)
|
|
|
|
|
objectType = 'pubkey'
|
|
|
|
|
shared.inventory[inventoryHash] = (
|
|
|
|
|
objectType, streamNumber, payload, embeddedTime,'')
|
|
|
|
|
shared.inventorySets[streamNumber].add(inventoryHash)
|
|
|
|
|
payload = pack('>Q', nonce) + payload
|
|
|
|
|
inventoryHash = calculateInventoryHash(payload)
|
|
|
|
|
objectType = 'pubkey'
|
|
|
|
|
shared.inventory[inventoryHash] = (
|
|
|
|
|
objectType, streamNumber, payload, embeddedTime,'')
|
|
|
|
|
shared.inventorySets[streamNumber].add(inventoryHash)
|
|
|
|
|
|
|
|
|
|
with shared.printLock:
|
|
|
|
|
print 'broadcasting inv with hash:', inventoryHash.encode('hex')
|
|
|
|
|
with shared.printLock:
|
|
|
|
|
print 'broadcasting inv with hash:', inventoryHash.encode('hex')
|
|
|
|
|
|
|
|
|
|
shared.broadcastToSendDataQueues((
|
|
|
|
|
streamNumber, 'advertiseobject', inventoryHash))
|
|
|
|
|
shared.UISignalQueue.put(('updateStatusBar', ''))
|
|
|
|
|
# If this is a chan address then we won't send out the pubkey over the
|
|
|
|
|
# network but rather will only store it in our pubkeys table so that
|
|
|
|
|
# we can send messages to "ourselves".
|
|
|
|
|
if shared.safeConfigGetBoolean(myAddress, 'chan'):
|
|
|
|
|
payload = '\x00' * 8 + payload # Attach a fake nonce on the front
|
|
|
|
|
# just so that it is in the correct format.
|
|
|
|
|
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?)''',
|
|
|
|
|
hash,
|
|
|
|
|
payload,
|
|
|
|
|
embeddedTime,
|
|
|
|
|
'yes')
|
|
|
|
|
shared.broadcastToSendDataQueues((
|
|
|
|
|
streamNumber, 'advertiseobject', inventoryHash))
|
|
|
|
|
shared.UISignalQueue.put(('updateStatusBar', ''))
|
|
|
|
|
shared.config.set(
|
|
|
|
|
myAddress, 'lastpubkeysendtime', str(int(time.time())))
|
|
|
|
|
with open(shared.appdata + 'keys.dat', 'wb') as configfile:
|
|
|
|
|
shared.config.write(configfile)
|
|
|
|
|
|
|
|
|
|
# If this isn't a chan address, this function assembles the pubkey data,
|
|
|
|
|
# does the necessary POW and sends it out. If it *is* a chan then it
|
|
|
|
|
# assembles the pubkey and stores is in the pubkey table so that we can
|
|
|
|
|
# send messages to "ourselves".
|
|
|
|
|
# does the necessary POW and sends it out.
|
|
|
|
|
def sendOutOrStoreMyV4Pubkey(self, myAddress):
|
|
|
|
|
if shared.safeConfigGetBoolean(myAddress, 'chan'):
|
|
|
|
|
with shared.printLock:
|
|
|
|
|
print 'This is a chan address. Not sending pubkey.'
|
|
|
|
|
return
|
|
|
|
|
status, addressVersionNumber, streamNumber, hash = decodeAddress(
|
|
|
|
|
myAddress)
|
|
|
|
|
embeddedTime = int(time.time() + random.randrange(
|
|
|
|
@ -284,52 +278,41 @@ class singleWorker(threading.Thread):
|
|
|
|
|
dataToEncrypt += encodeVarint(len(signature))
|
|
|
|
|
dataToEncrypt += signature
|
|
|
|
|
|
|
|
|
|
if not shared.safeConfigGetBoolean(myAddress, 'chan'):
|
|
|
|
|
# Let us encrypt the necessary data. We will use a hash of the data
|
|
|
|
|
# contained in an address as a decryption key. This way in order to
|
|
|
|
|
# read the public keys in a pubkey message, a node must know the address
|
|
|
|
|
# first. We'll also tag, unencrypted, the pubkey with part of the hash
|
|
|
|
|
# so that nodes know which pubkey object to try to decrypt when they
|
|
|
|
|
# want to send a message.
|
|
|
|
|
doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint(
|
|
|
|
|
addressVersionNumber) + encodeVarint(streamNumber) + hash).digest()).digest()
|
|
|
|
|
payload += doubleHashOfAddressData[32:] # the tag
|
|
|
|
|
privEncryptionKey = doubleHashOfAddressData[:32]
|
|
|
|
|
pubEncryptionKey = pointMult(privEncryptionKey)
|
|
|
|
|
payload += highlevelcrypto.encrypt(
|
|
|
|
|
dataToEncrypt, pubEncryptionKey.encode('hex'))
|
|
|
|
|
# Let us encrypt the necessary data. We will use a hash of the data
|
|
|
|
|
# contained in an address as a decryption key. This way in order to
|
|
|
|
|
# read the public keys in a pubkey message, a node must know the address
|
|
|
|
|
# first. We'll also tag, unencrypted, the pubkey with part of the hash
|
|
|
|
|
# so that nodes know which pubkey object to try to decrypt when they
|
|
|
|
|
# want to send a message.
|
|
|
|
|
doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint(
|
|
|
|
|
addressVersionNumber) + encodeVarint(streamNumber) + hash).digest()).digest()
|
|
|
|
|
payload += doubleHashOfAddressData[32:] # the tag
|
|
|
|
|
privEncryptionKey = doubleHashOfAddressData[:32]
|
|
|
|
|
pubEncryptionKey = pointMult(privEncryptionKey)
|
|
|
|
|
payload += highlevelcrypto.encrypt(
|
|
|
|
|
dataToEncrypt, pubEncryptionKey.encode('hex'))
|
|
|
|
|
|
|
|
|
|
# Do the POW for this pubkey message
|
|
|
|
|
target = 2 ** 64 / ((len(payload) + shared.networkDefaultPayloadLengthExtraBytes +
|
|
|
|
|
8) * shared.networkDefaultProofOfWorkNonceTrialsPerByte)
|
|
|
|
|
print '(For pubkey message) Doing proof of work...'
|
|
|
|
|
initialHash = hashlib.sha512(payload).digest()
|
|
|
|
|
trialValue, nonce = proofofwork.run(target, initialHash)
|
|
|
|
|
print '(For pubkey message) Found proof of work', trialValue, 'Nonce:', nonce
|
|
|
|
|
# Do the POW for this pubkey message
|
|
|
|
|
target = 2 ** 64 / ((len(payload) + shared.networkDefaultPayloadLengthExtraBytes +
|
|
|
|
|
8) * shared.networkDefaultProofOfWorkNonceTrialsPerByte)
|
|
|
|
|
print '(For pubkey message) Doing proof of work...'
|
|
|
|
|
initialHash = hashlib.sha512(payload).digest()
|
|
|
|
|
trialValue, nonce = proofofwork.run(target, initialHash)
|
|
|
|
|
print '(For pubkey message) Found proof of work', trialValue, 'Nonce:', nonce
|
|
|
|
|
|
|
|
|
|
payload = pack('>Q', nonce) + payload
|
|
|
|
|
inventoryHash = calculateInventoryHash(payload)
|
|
|
|
|
objectType = 'pubkey'
|
|
|
|
|
shared.inventory[inventoryHash] = (
|
|
|
|
|
objectType, streamNumber, payload, embeddedTime, doubleHashOfAddressData[32:])
|
|
|
|
|
shared.inventorySets[streamNumber].add(inventoryHash)
|
|
|
|
|
payload = pack('>Q', nonce) + payload
|
|
|
|
|
inventoryHash = calculateInventoryHash(payload)
|
|
|
|
|
objectType = 'pubkey'
|
|
|
|
|
shared.inventory[inventoryHash] = (
|
|
|
|
|
objectType, streamNumber, payload, embeddedTime, doubleHashOfAddressData[32:])
|
|
|
|
|
shared.inventorySets[streamNumber].add(inventoryHash)
|
|
|
|
|
|
|
|
|
|
with shared.printLock:
|
|
|
|
|
print 'broadcasting inv with hash:', inventoryHash.encode('hex')
|
|
|
|
|
with shared.printLock:
|
|
|
|
|
print 'broadcasting inv with hash:', inventoryHash.encode('hex')
|
|
|
|
|
|
|
|
|
|
shared.broadcastToSendDataQueues((
|
|
|
|
|
streamNumber, 'advertiseobject', inventoryHash))
|
|
|
|
|
shared.UISignalQueue.put(('updateStatusBar', ''))
|
|
|
|
|
# If this is a chan address then we won't send out the pubkey over the
|
|
|
|
|
# network but rather will only store it in our pubkeys table so that
|
|
|
|
|
# we can send messages to "ourselves".
|
|
|
|
|
if shared.safeConfigGetBoolean(myAddress, 'chan'):
|
|
|
|
|
|
|
|
|
|
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?)''',
|
|
|
|
|
hash,
|
|
|
|
|
dataToStoreInOurPubkeysTable,
|
|
|
|
|
embeddedTime,
|
|
|
|
|
'yes')
|
|
|
|
|
shared.broadcastToSendDataQueues((
|
|
|
|
|
streamNumber, 'advertiseobject', inventoryHash))
|
|
|
|
|
shared.UISignalQueue.put(('updateStatusBar', ''))
|
|
|
|
|
shared.config.set(
|
|
|
|
|
myAddress, 'lastpubkeysendtime', str(int(time.time())))
|
|
|
|
|
with open(shared.appdata + 'keys.dat', 'wb') as configfile:
|
|
|
|
@ -369,8 +352,6 @@ class singleWorker(threading.Thread):
|
|
|
|
|
pubEncryptionKey = highlevelcrypto.privToPub(
|
|
|
|
|
privEncryptionKeyHex).decode('hex')
|
|
|
|
|
|
|
|
|
|
print 'embedding pubEncryptionKey:', pubEncryptionKey.encode('hex')
|
|
|
|
|
|
|
|
|
|
payload = pack('>Q', (int(time.time()) + random.randrange(
|
|
|
|
|
-300, 300))) # the current time plus or minus five minutes
|
|
|
|
|
if addressVersionNumber <= 3:
|
|
|
|
@ -382,8 +363,6 @@ class singleWorker(threading.Thread):
|
|
|
|
|
doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint(
|
|
|
|
|
addressVersionNumber) + encodeVarint(streamNumber) + ripe).digest()).digest()
|
|
|
|
|
payload += doubleHashOfAddressData[32:] # the tag
|
|
|
|
|
print 'embeddedTag is', doubleHashOfAddressData[32:].encode('hex')
|
|
|
|
|
print 'embeddedTag is', repr(doubleHashOfAddressData[32:])
|
|
|
|
|
|
|
|
|
|
if addressVersionNumber <= 3:
|
|
|
|
|
dataToEncrypt = encodeVarint(2) # broadcast version
|
|
|
|
@ -458,8 +437,11 @@ class singleWorker(threading.Thread):
|
|
|
|
|
for row in queryreturn: # For each address to which we need to send a message, check to see if we have its pubkey already.
|
|
|
|
|
toaddress, = row
|
|
|
|
|
status, toAddressVersion, toStreamNumber, toRipe = decodeAddress(toaddress)
|
|
|
|
|
# If we are sending a message to ourselves or a chan then we won't need an entry in the pubkeys table; we can calculate the needed pubkey using the private keys in our keys.dat file.
|
|
|
|
|
if shared.config.has_section(toaddress):
|
|
|
|
|
continue
|
|
|
|
|
queryreturn = sqlQuery(
|
|
|
|
|
'''SELECT hash FROM pubkeys WHERE hash=? ''', toRipe)
|
|
|
|
|
'''SELECT hash FROM pubkeys WHERE hash=? AND addressversion=?''', toRipe, toAddressVersion)
|
|
|
|
|
if queryreturn != []: # If we have the needed pubkey in the pubkey table already, set the status to doingmsgpow (we'll do it further down)
|
|
|
|
|
sqlExecute(
|
|
|
|
|
'''UPDATE sent SET status='doingmsgpow' WHERE toaddress=? AND status='msgqueued' ''',
|
|
|
|
@ -523,130 +505,154 @@ class singleWorker(threading.Thread):
|
|
|
|
|
int(time.time()) - 2419200)
|
|
|
|
|
for row in queryreturn: # For each message we need to send..
|
|
|
|
|
toaddress, toripe, fromaddress, subject, message, ackdata, status = row
|
|
|
|
|
# There is a remote possibility that we may no longer have the
|
|
|
|
|
# recipient's pubkey. Let us make sure we still have it or else the
|
|
|
|
|
# sendMsg function will appear to freeze. This can happen if the
|
|
|
|
|
# user sends a message but doesn't let the POW function finish,
|
|
|
|
|
# then leaves their client off for a long time which could cause
|
|
|
|
|
# the needed pubkey to expire and be deleted.
|
|
|
|
|
queryreturn = sqlQuery(
|
|
|
|
|
'''SELECT hash FROM pubkeys WHERE hash=? ''',
|
|
|
|
|
toripe)
|
|
|
|
|
if queryreturn == [] and toripe not in shared.neededPubkeys:
|
|
|
|
|
# We no longer have the needed pubkey and we haven't requested
|
|
|
|
|
# it.
|
|
|
|
|
with shared.printLock:
|
|
|
|
|
sys.stderr.write(
|
|
|
|
|
'For some reason, the status of a message in our outbox is \'doingmsgpow\' even though we lack the pubkey. Here is the RIPE hash of the needed pubkey: %s\n' % toripe.encode('hex'))
|
|
|
|
|
|
|
|
|
|
sqlExecute(
|
|
|
|
|
'''UPDATE sent SET status='msgqueued' WHERE toaddress=? AND status='doingmsgpow' ''', toaddress)
|
|
|
|
|
shared.UISignalQueue.put(('updateSentItemStatusByHash', (
|
|
|
|
|
toripe, tr.translateText("MainWindow",'Sending a request for the recipient\'s encryption key.'))))
|
|
|
|
|
self.requestPubKey(toaddress)
|
|
|
|
|
continue
|
|
|
|
|
shared.ackdataForWhichImWatching[ackdata] = 0
|
|
|
|
|
toStatus, toAddressVersionNumber, toStreamNumber, toHash = decodeAddress(
|
|
|
|
|
toaddress)
|
|
|
|
|
fromStatus, fromAddressVersionNumber, fromStreamNumber, fromHash = decodeAddress(
|
|
|
|
|
fromaddress)
|
|
|
|
|
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (
|
|
|
|
|
ackdata, tr.translateText("MainWindow", "Looking up the receiver\'s public key"))))
|
|
|
|
|
with shared.printLock:
|
|
|
|
|
print 'Found a message in our database that needs to be sent with this pubkey.'
|
|
|
|
|
print 'First 150 characters of message:', repr(message[:150])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# mark the pubkey as 'usedpersonally' so that we don't ever delete
|
|
|
|
|
# it.
|
|
|
|
|
sqlExecute(
|
|
|
|
|
'''UPDATE pubkeys SET usedpersonally='yes' WHERE hash=?''',
|
|
|
|
|
toripe)
|
|
|
|
|
# Let us fetch the recipient's public key out of our database. If
|
|
|
|
|
# the required proof of work difficulty is too hard then we'll
|
|
|
|
|
# abort.
|
|
|
|
|
queryreturn = sqlQuery(
|
|
|
|
|
'SELECT transmitdata FROM pubkeys WHERE hash=?',
|
|
|
|
|
toripe)
|
|
|
|
|
if queryreturn == []:
|
|
|
|
|
with shared.printLock:
|
|
|
|
|
sys.stderr.write(
|
|
|
|
|
'(within sendMsg) The needed pubkey was not found. This should never happen. Aborting send.\n')
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
for row in queryreturn:
|
|
|
|
|
pubkeyPayload, = row
|
|
|
|
|
|
|
|
|
|
# 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.
|
|
|
|
|
if toAddressVersionNumber <= 3:
|
|
|
|
|
readPosition = 8 # to bypass the nonce
|
|
|
|
|
elif toAddressVersionNumber >= 4:
|
|
|
|
|
readPosition = 0 # the nonce is not included here so we don't need to skip over it.
|
|
|
|
|
pubkeyEmbeddedTime, = unpack(
|
|
|
|
|
'>I', pubkeyPayload[readPosition:readPosition + 4])
|
|
|
|
|
# This section is used for the transition from 32 bit time to 64
|
|
|
|
|
# bit time in the protocol.
|
|
|
|
|
if pubkeyEmbeddedTime == 0:
|
|
|
|
|
pubkeyEmbeddedTime, = unpack(
|
|
|
|
|
'>Q', pubkeyPayload[readPosition:readPosition + 8])
|
|
|
|
|
readPosition += 8
|
|
|
|
|
else:
|
|
|
|
|
readPosition += 4
|
|
|
|
|
readPosition += 1 # to bypass the address version whose length is definitely 1
|
|
|
|
|
streamNumber, streamNumberLength = decodeVarint(
|
|
|
|
|
pubkeyPayload[readPosition:readPosition + 10])
|
|
|
|
|
readPosition += streamNumberLength
|
|
|
|
|
behaviorBitfield = pubkeyPayload[readPosition:readPosition + 4]
|
|
|
|
|
# Mobile users may ask us to include their address's RIPE hash on a message
|
|
|
|
|
# unencrypted. Before we actually do it the sending human must check a box
|
|
|
|
|
# in the settings menu to allow it.
|
|
|
|
|
if shared.isBitSetWithinBitfield(behaviorBitfield,30): # if receiver is a mobile device who expects that their address RIPE is included unencrypted on the front of the message..
|
|
|
|
|
if not shared.safeConfigGetBoolean('bitmessagesettings','willinglysendtomobile'): # if we are Not willing to include the receiver's RIPE hash on the message..
|
|
|
|
|
logger.info('The receiver is a mobile user but the sender (you) has not selected that you are willing to send to mobiles. Aborting send.')
|
|
|
|
|
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow",'Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1').arg(unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(time.time()))),'utf-8')))))
|
|
|
|
|
# if the human changes their setting and then sends another message or restarts their client, this one will send at that time.
|
|
|
|
|
if not shared.config.has_section(toaddress):
|
|
|
|
|
# There is a remote possibility that we may no longer have the
|
|
|
|
|
# recipient's pubkey. Let us make sure we still have it or else the
|
|
|
|
|
# sendMsg function will appear to freeze. This can happen if the
|
|
|
|
|
# user sends a message but doesn't let the POW function finish,
|
|
|
|
|
# then leaves their client off for a long time which could cause
|
|
|
|
|
# the needed pubkey to expire and be deleted.
|
|
|
|
|
queryreturn = sqlQuery(
|
|
|
|
|
'''SELECT hash FROM pubkeys WHERE hash=? AND addressversion=?''',
|
|
|
|
|
toripe,
|
|
|
|
|
toAddressVersionNumber)
|
|
|
|
|
if queryreturn == [] and toripe not in shared.neededPubkeys:
|
|
|
|
|
# We no longer have the needed pubkey and we haven't requested
|
|
|
|
|
# it.
|
|
|
|
|
with shared.printLock:
|
|
|
|
|
sys.stderr.write(
|
|
|
|
|
'For some reason, the status of a message in our outbox is \'doingmsgpow\' even though we lack the pubkey. Here is the RIPE hash of the needed pubkey: %s\n' % toripe.encode('hex'))
|
|
|
|
|
sqlExecute(
|
|
|
|
|
'''UPDATE sent SET status='msgqueued' WHERE toaddress=? AND status='doingmsgpow' ''', toaddress)
|
|
|
|
|
shared.UISignalQueue.put(('updateSentItemStatusByHash', (
|
|
|
|
|
toripe, tr.translateText("MainWindow",'Sending a request for the recipient\'s encryption key.'))))
|
|
|
|
|
self.requestPubKey(toaddress)
|
|
|
|
|
continue
|
|
|
|
|
readPosition += 4 # to bypass the bitfield of behaviors
|
|
|
|
|
# pubSigningKeyBase256 =
|
|
|
|
|
# pubkeyPayload[readPosition:readPosition+64] #We don't use this
|
|
|
|
|
# key for anything here.
|
|
|
|
|
readPosition += 64
|
|
|
|
|
pubEncryptionKeyBase256 = pubkeyPayload[
|
|
|
|
|
readPosition:readPosition + 64]
|
|
|
|
|
readPosition += 64
|
|
|
|
|
|
|
|
|
|
# Let us fetch the amount of work required by the recipient.
|
|
|
|
|
if toAddressVersionNumber == 2:
|
|
|
|
|
shared.ackdataForWhichImWatching[ackdata] = 0
|
|
|
|
|
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (
|
|
|
|
|
ackdata, tr.translateText("MainWindow", "Looking up the receiver\'s public key"))))
|
|
|
|
|
with shared.printLock:
|
|
|
|
|
print 'Sending a message. First 150 characters of message:', repr(message[:150])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# mark the pubkey as 'usedpersonally' so that we don't ever delete
|
|
|
|
|
# it.
|
|
|
|
|
sqlExecute(
|
|
|
|
|
'''UPDATE pubkeys SET usedpersonally='yes' WHERE hash=? and addressversion=?''',
|
|
|
|
|
toripe,
|
|
|
|
|
toAddressVersionNumber)
|
|
|
|
|
# Let us fetch the recipient's public key out of our database. If
|
|
|
|
|
# the required proof of work difficulty is too hard then we'll
|
|
|
|
|
# abort.
|
|
|
|
|
queryreturn = sqlQuery(
|
|
|
|
|
'SELECT transmitdata FROM pubkeys WHERE hash=? and addressversion=?',
|
|
|
|
|
toripe,
|
|
|
|
|
toAddressVersionNumber)
|
|
|
|
|
if queryreturn == []:
|
|
|
|
|
with shared.printLock:
|
|
|
|
|
sys.stderr.write(
|
|
|
|
|
'(within sendMsg) The needed pubkey was not found. This should never happen. Aborting send.\n')
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
for row in queryreturn:
|
|
|
|
|
pubkeyPayload, = row
|
|
|
|
|
|
|
|
|
|
# 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.
|
|
|
|
|
if toAddressVersionNumber <= 3:
|
|
|
|
|
readPosition = 8 # to bypass the nonce
|
|
|
|
|
elif toAddressVersionNumber >= 4:
|
|
|
|
|
readPosition = 0 # the nonce is not included here so we don't need to skip over it.
|
|
|
|
|
pubkeyEmbeddedTime, = unpack(
|
|
|
|
|
'>I', pubkeyPayload[readPosition:readPosition + 4])
|
|
|
|
|
# This section is used for the transition from 32 bit time to 64
|
|
|
|
|
# bit time in the protocol.
|
|
|
|
|
if pubkeyEmbeddedTime == 0:
|
|
|
|
|
pubkeyEmbeddedTime, = unpack(
|
|
|
|
|
'>Q', pubkeyPayload[readPosition:readPosition + 8])
|
|
|
|
|
readPosition += 8
|
|
|
|
|
else:
|
|
|
|
|
readPosition += 4
|
|
|
|
|
readPosition += 1 # to bypass the address version whose length is definitely 1
|
|
|
|
|
streamNumber, streamNumberLength = decodeVarint(
|
|
|
|
|
pubkeyPayload[readPosition:readPosition + 10])
|
|
|
|
|
readPosition += streamNumberLength
|
|
|
|
|
behaviorBitfield = pubkeyPayload[readPosition:readPosition + 4]
|
|
|
|
|
# Mobile users may ask us to include their address's RIPE hash on a message
|
|
|
|
|
# unencrypted. Before we actually do it the sending human must check a box
|
|
|
|
|
# in the settings menu to allow it.
|
|
|
|
|
if shared.isBitSetWithinBitfield(behaviorBitfield,30): # if receiver is a mobile device who expects that their address RIPE is included unencrypted on the front of the message..
|
|
|
|
|
if not shared.safeConfigGetBoolean('bitmessagesettings','willinglysendtomobile'): # if we are Not willing to include the receiver's RIPE hash on the message..
|
|
|
|
|
logger.info('The receiver is a mobile user but the sender (you) has not selected that you are willing to send to mobiles. Aborting send.')
|
|
|
|
|
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow",'Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1').arg(unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(time.time()))),'utf-8')))))
|
|
|
|
|
# if the human changes their setting and then sends another message or restarts their client, this one will send at that time.
|
|
|
|
|
continue
|
|
|
|
|
readPosition += 4 # to bypass the bitfield of behaviors
|
|
|
|
|
# pubSigningKeyBase256 =
|
|
|
|
|
# pubkeyPayload[readPosition:readPosition+64] #We don't use this
|
|
|
|
|
# key for anything here.
|
|
|
|
|
readPosition += 64
|
|
|
|
|
pubEncryptionKeyBase256 = pubkeyPayload[
|
|
|
|
|
readPosition:readPosition + 64]
|
|
|
|
|
readPosition += 64
|
|
|
|
|
|
|
|
|
|
# Let us fetch the amount of work required by the recipient.
|
|
|
|
|
if toAddressVersionNumber == 2:
|
|
|
|
|
requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte
|
|
|
|
|
requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes
|
|
|
|
|
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (
|
|
|
|
|
ackdata, tr.translateText("MainWindow", "Doing work necessary to send message.\nThere is no required difficulty for version 2 addresses like this."))))
|
|
|
|
|
elif toAddressVersionNumber >= 3:
|
|
|
|
|
requiredAverageProofOfWorkNonceTrialsPerByte, varintLength = decodeVarint(
|
|
|
|
|
pubkeyPayload[readPosition:readPosition + 10])
|
|
|
|
|
readPosition += varintLength
|
|
|
|
|
requiredPayloadLengthExtraBytes, varintLength = decodeVarint(
|
|
|
|
|
pubkeyPayload[readPosition:readPosition + 10])
|
|
|
|
|
readPosition += varintLength
|
|
|
|
|
if requiredAverageProofOfWorkNonceTrialsPerByte < shared.networkDefaultProofOfWorkNonceTrialsPerByte: # We still have to meet a minimum POW difficulty regardless of what they say is allowed in order to get our message to propagate through the network.
|
|
|
|
|
requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte
|
|
|
|
|
if requiredPayloadLengthExtraBytes < shared.networkDefaultPayloadLengthExtraBytes:
|
|
|
|
|
requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes
|
|
|
|
|
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Doing work necessary to send message.\nReceiver\'s required difficulty: %1 and %2").arg(str(float(
|
|
|
|
|
requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes)))))
|
|
|
|
|
if status != 'forcepow':
|
|
|
|
|
if (requiredAverageProofOfWorkNonceTrialsPerByte > shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') and shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') != 0) or (requiredPayloadLengthExtraBytes > shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') and shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') != 0):
|
|
|
|
|
# The demanded difficulty is more than we are willing
|
|
|
|
|
# to do.
|
|
|
|
|
sqlExecute(
|
|
|
|
|
'''UPDATE sent SET status='toodifficult' WHERE ackdata=? ''',
|
|
|
|
|
ackdata)
|
|
|
|
|
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do.").arg(str(float(requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(
|
|
|
|
|
requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes)).arg(unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8')))))
|
|
|
|
|
continue
|
|
|
|
|
else: # if we are sending a message to ourselves or a chan..
|
|
|
|
|
with shared.printLock:
|
|
|
|
|
print 'Sending a message. First 150 characters of message:', repr(message[:150])
|
|
|
|
|
behaviorBitfield = '\x00\x00\x00\x01'
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
privEncryptionKeyBase58 = shared.config.get(
|
|
|
|
|
toaddress, 'privencryptionkey')
|
|
|
|
|
except Exception as err:
|
|
|
|
|
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow",'Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1').arg(unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(time.time()))),'utf-8')))))
|
|
|
|
|
with shared.printLock:
|
|
|
|
|
sys.stderr.write(
|
|
|
|
|
'Error within sendMsg. Could not read the keys from the keys.dat file for our own address. %s\n' % err)
|
|
|
|
|
continue
|
|
|
|
|
privEncryptionKeyHex = shared.decodeWalletImportFormat(
|
|
|
|
|
privEncryptionKeyBase58).encode('hex')
|
|
|
|
|
pubEncryptionKeyBase256 = highlevelcrypto.privToPub(
|
|
|
|
|
privEncryptionKeyHex).decode('hex')[1:]
|
|
|
|
|
requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte
|
|
|
|
|
requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes
|
|
|
|
|
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (
|
|
|
|
|
ackdata, tr.translateText("MainWindow", "Doing work necessary to send message.\nThere is no required difficulty for version 2 addresses like this."))))
|
|
|
|
|
elif toAddressVersionNumber >= 3:
|
|
|
|
|
requiredAverageProofOfWorkNonceTrialsPerByte, varintLength = decodeVarint(
|
|
|
|
|
pubkeyPayload[readPosition:readPosition + 10])
|
|
|
|
|
readPosition += varintLength
|
|
|
|
|
requiredPayloadLengthExtraBytes, varintLength = decodeVarint(
|
|
|
|
|
pubkeyPayload[readPosition:readPosition + 10])
|
|
|
|
|
readPosition += varintLength
|
|
|
|
|
if requiredAverageProofOfWorkNonceTrialsPerByte < shared.networkDefaultProofOfWorkNonceTrialsPerByte: # We still have to meet a minimum POW difficulty regardless of what they say is allowed in order to get our message to propagate through the network.
|
|
|
|
|
requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte
|
|
|
|
|
if requiredPayloadLengthExtraBytes < shared.networkDefaultPayloadLengthExtraBytes:
|
|
|
|
|
requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes
|
|
|
|
|
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Doing work necessary to send message.\nReceiver\'s required difficulty: %1 and %2").arg(str(float(
|
|
|
|
|
requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes)))))
|
|
|
|
|
if status != 'forcepow':
|
|
|
|
|
if (requiredAverageProofOfWorkNonceTrialsPerByte > shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') and shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') != 0) or (requiredPayloadLengthExtraBytes > shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') and shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') != 0):
|
|
|
|
|
# The demanded difficulty is more than we are willing
|
|
|
|
|
# to do.
|
|
|
|
|
sqlExecute(
|
|
|
|
|
'''UPDATE sent SET status='toodifficult' WHERE ackdata=? ''',
|
|
|
|
|
ackdata)
|
|
|
|
|
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do.").arg(str(float(requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(
|
|
|
|
|
requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes)).arg(unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8')))))
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
ackdata, tr.translateText("MainWindow", "Doing work necessary to send message."))))
|
|
|
|
|
|
|
|
|
|
embeddedTime = pack('>Q', (int(time.time()) + random.randrange(
|
|
|
|
|
-300, 300))) # the current time plus or minus five minutes. We will use this time both for our message and for the ackdata packed within our message.
|
|
|
|
@ -750,11 +756,11 @@ class singleWorker(threading.Thread):
|
|
|
|
|
payload += messageToTransmit
|
|
|
|
|
if shared.safeConfigGetBoolean(toaddress, 'chan'):
|
|
|
|
|
with shared.printLock:
|
|
|
|
|
print 'Not bothering to generate ackdata because we are sending to a chan.'
|
|
|
|
|
print 'Not bothering to include ackdata because we are sending to a chan.'
|
|
|
|
|
fullAckPayload = ''
|
|
|
|
|
elif not shared.isBitSetWithinBitfield(behaviorBitfield,31):
|
|
|
|
|
with shared.printLock:
|
|
|
|
|
print 'Not bothering to generate ackdata because the receiver said that they won\'t relay it anyway.'
|
|
|
|
|
print 'Not bothering to include ackdata because the receiver said that they won\'t relay it anyway.'
|
|
|
|
|
fullAckPayload = ''
|
|
|
|
|
else:
|
|
|
|
|
fullAckPayload = self.generateFullAckMessage(
|
|
|
|
@ -795,11 +801,11 @@ class singleWorker(threading.Thread):
|
|
|
|
|
shared.inventory[inventoryHash] = (
|
|
|
|
|
objectType, toStreamNumber, encryptedPayload, int(time.time()),'')
|
|
|
|
|
shared.inventorySets[toStreamNumber].add(inventoryHash)
|
|
|
|
|
if shared.safeConfigGetBoolean(toaddress, 'chan'):
|
|
|
|
|
if shared.config.has_section(toaddress):
|
|
|
|
|
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Message sent. Sent on %1").arg(unicode(
|
|
|
|
|
strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8')))))
|
|
|
|
|
else:
|
|
|
|
|
# not sending to a chan
|
|
|
|
|
# not sending to a chan or one of my addresses
|
|
|
|
|
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Message sent. Waiting on acknowledgement. Sent on %1").arg(unicode(
|
|
|
|
|
strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8')))))
|
|
|
|
|
print 'Broadcasting inv for my msg(within sendmsg function):', inventoryHash.encode('hex')
|
|
|
|
@ -808,7 +814,7 @@ class singleWorker(threading.Thread):
|
|
|
|
|
|
|
|
|
|
# Update the status of the message in the 'sent' table to have a
|
|
|
|
|
# 'msgsent' status or 'msgsentnoackexpected' status.
|
|
|
|
|
if shared.safeConfigGetBoolean(toaddress, 'chan'):
|
|
|
|
|
if not shared.config.has_section(toaddress):
|
|
|
|
|
newStatus = 'msgsentnoackexpected'
|
|
|
|
|
else:
|
|
|
|
|
newStatus = 'msgsent'
|
|
|
|
|