diff --git a/src/addresses.py b/src/addresses.py index 0d3d4400ee..fb86d40c9e 100644 --- a/src/addresses.py +++ b/src/addresses.py @@ -274,69 +274,3 @@ def addBMIfNotPresent(address): """Prepend BM- to an address if it doesn't already have it""" address = str(address).strip() return address if address[:3] == 'BM-' else 'BM-' + address - - -# TODO: make test case -if __name__ == "__main__": - from pyelliptic import arithmetic - - print( - '\nLet us make an address from scratch. Suppose we generate two' - ' random 32 byte values and call the first one the signing key' - ' and the second one the encryption key:' - ) - privateSigningKey = \ - '93d0b61371a54b53df143b954035d612f8efa8a3ed1cf842c2186bfd8f876665' - privateEncryptionKey = \ - '4b0b73a54e19b059dc274ab69df095fe699f43b17397bca26fdf40f4d7400a3a' - print( - '\nprivateSigningKey = %s\nprivateEncryptionKey = %s' % - (privateSigningKey, privateEncryptionKey) - ) - print( - '\nNow let us convert them to public keys by doing' - ' an elliptic curve point multiplication.' - ) - publicSigningKey = arithmetic.privtopub(privateSigningKey) - publicEncryptionKey = arithmetic.privtopub(privateEncryptionKey) - print( - '\npublicSigningKey = %s\npublicEncryptionKey = %s' % - (publicSigningKey, publicEncryptionKey) - ) - - print( - '\nNotice that they both begin with the \\x04 which specifies' - ' the encoding type. This prefix is not send over the wire.' - ' You must strip if off before you send your public key across' - ' the wire, and you must add it back when you receive a public key.' - ) - - publicSigningKeyBinary = \ - arithmetic.changebase(publicSigningKey, 16, 256, minlen=64) - publicEncryptionKeyBinary = \ - arithmetic.changebase(publicEncryptionKey, 16, 256, minlen=64) - - ripe = hashlib.new('ripemd160') - sha = hashlib.new('sha512') - sha.update(publicSigningKeyBinary + publicEncryptionKeyBinary) - - ripe.update(sha.digest()) - addressVersionNumber = 2 - streamNumber = 1 - print( - '\nRipe digest that we will encode in the address: %s' % - hexlify(ripe.digest()) - ) - returnedAddress = \ - encodeAddress(addressVersionNumber, streamNumber, ripe.digest()) - print('Encoded address: %s' % returnedAddress) - status, addressVersionNumber, streamNumber, data = \ - decodeAddress(returnedAddress) - print( - '\nAfter decoding address:\n\tStatus: %s' - '\n\taddressVersionNumber %s' - '\n\tstreamNumber %s' - '\n\tlength of data (the ripe hash): %s' - '\n\tripe data: %s' % - (status, addressVersionNumber, streamNumber, len(data), hexlify(data)) - ) diff --git a/src/api.py b/src/api.py index 70da0cdafe..446c6ae429 100644 --- a/src/api.py +++ b/src/api.py @@ -27,6 +27,7 @@ import shared import shutdown import state +import threads from addresses import ( addBMIfNotPresent, calculateInventoryHash, @@ -1206,7 +1207,7 @@ def HandleDisseminatePreEncryptedMsg(self, params): len(encryptedPayload) + requiredPayloadLengthExtraBytes + 8 ) * requiredAverageProofOfWorkNonceTrialsPerByte ) - with shared.printLock: + with threads.printLock: print( '(For msg message via API) Doing proof of work.' 'Total required difficulty:', @@ -1221,7 +1222,7 @@ def HandleDisseminatePreEncryptedMsg(self, params): powStartTime = time.time() initialHash = hashlib.sha512(encryptedPayload).digest() trialValue, nonce = proofofwork.run(target, initialHash) - with shared.printLock: + with threads.printLock: print '(For msg message via API) Found proof of work', trialValue, 'Nonce:', nonce try: print( @@ -1240,7 +1241,7 @@ def HandleDisseminatePreEncryptedMsg(self, params): objectType, toStreamNumber, encryptedPayload, int(time.time()) + TTL, '' ) - with shared.printLock: + with threads.printLock: print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', hexlify(inventoryHash) queues.invQueue.put((toStreamNumber, inventoryHash)) @@ -1294,7 +1295,7 @@ def HandleDissimatePubKey(self, params): Inventory()[inventoryHash] = ( objectType, pubkeyStreamNumber, payload, int(time.time()) + TTL, '' ) - with shared.printLock: + with threads.printLock: print 'broadcasting inv within API command disseminatePubkey with hash:', hexlify(inventoryHash) queues.invQueue.put((pubkeyStreamNumber, inventoryHash)) @@ -1347,15 +1348,15 @@ def HandleClientStatus(self, params): connections_num = len(network.stats.connectedHostsList()) if connections_num == 0: networkStatus = 'notConnected' - elif shared.clientHasReceivedIncomingConnections: + elif state.clientHasReceivedIncomingConnections: networkStatus = 'connectedAndReceivingIncomingConnections' else: networkStatus = 'connectedButHaveNotReceivedIncomingConnections' return json.dumps({ 'networkConnections': connections_num, - 'numberOfMessagesProcessed': shared.numberOfMessagesProcessed, - 'numberOfBroadcastsProcessed': shared.numberOfBroadcastsProcessed, - 'numberOfPubkeysProcessed': shared.numberOfPubkeysProcessed, + 'numberOfMessagesProcessed': state.numberOfMessagesProcessed, + 'numberOfBroadcastsProcessed': state.numberOfBroadcastsProcessed, + 'numberOfPubkeysProcessed': state.numberOfPubkeysProcessed, 'networkStatus': networkStatus, 'softwareName': 'PyBitmessage', 'softwareVersion': softwareVersion diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index d8daeef703..17dba22baf 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -24,6 +24,7 @@ import queues import shared import shutdown +import state from addresses import addBMIfNotPresent, decodeAddress from bmconfigparser import BMConfigParser @@ -274,11 +275,11 @@ def drawtab(stdscr): # Uptime and processing data stdscr.addstr(6, 35, "Since startup on " + l10n.formatTimestamp(startuptime, False)) stdscr.addstr(7, 40, "Processed " + str( - shared.numberOfMessagesProcessed).ljust(4) + " person-to-person messages.") + state.numberOfMessagesProcessed).ljust(4) + " person-to-person messages.") stdscr.addstr(8, 40, "Processed " + str( - shared.numberOfBroadcastsProcessed).ljust(4) + " broadcast messages.") + state.numberOfBroadcastsProcessed).ljust(4) + " broadcast messages.") stdscr.addstr(9, 40, "Processed " + str( - shared.numberOfPubkeysProcessed).ljust(4) + " public keys.") + state.numberOfPubkeysProcessed).ljust(4) + " public keys.") # Inventory data stdscr.addstr(11, 35, "Inventory lookups per second: " + str(inventorydata).ljust(3)) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index d6cb289b34..2a279acaca 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -38,9 +38,7 @@ from bmconfigparser import BMConfigParser from debug import logger # this should go before any threads from helper_startup import ( - isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections, - start_proxyconfig -) + adjustHalfOpenConnectionsLimit, start_proxyconfig) from inventory import Inventory from knownnodes import readKnownNodes # Network objects and threads @@ -51,30 +49,8 @@ from singleinstance import singleinstance # Synchronous threads from threads import ( - set_thread_name, addressGenerator, objectProcessor, singleCleaner, - singleWorker, sqlThread -) - - -def connectToStream(streamNumber): - """Connect to a stream""" - state.streamsInWhichIAmParticipating.append(streamNumber) - - if isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections(): - # Some XP and Vista systems can only have 10 outgoing connections - # at a time. - state.maximumNumberOfHalfOpenConnections = 9 - else: - state.maximumNumberOfHalfOpenConnections = 64 - try: - # don't overload Tor - if BMConfigParser().get( - 'bitmessagesettings', 'socksproxytype') != 'none': - state.maximumNumberOfHalfOpenConnections = 4 - except: - pass - - BMConnectionPool().connectToStream(streamNumber) + set_thread_name, printLock, + addressGenerator, objectProcessor, singleCleaner, singleWorker, sqlThread) def _fixSocket(): @@ -157,7 +133,7 @@ def signal_handler(signum, frame): logger.error("Got signal %i", signum) # there are possible non-UI variants to run bitmessage # which should shutdown especially test-mode - if shared.thisapp.daemon or not state.enableGUI: + if state.thisapp.daemon or not state.enableGUI: shutdown.doCleanShutdown() else: print('# Thread: %s(%d)' % (thread.name, thread.ident)) @@ -175,6 +151,7 @@ def start(self): """Start main application""" # pylint: disable=too-many-statements,too-many-branches,too-many-locals _fixSocket() + adjustHalfOpenConnectionsLimit() config = BMConfigParser() daemon = config.safeGetBoolean('bitmessagesettings', 'daemon') @@ -233,10 +210,10 @@ def start(self): ' \'-c\' as a commandline argument.' ) # is the application already running? If yes then exit. - shared.thisapp = singleinstance("", daemon) + state.thisapp = singleinstance("", daemon) if daemon: - with shared.printLock: + with printLock: print('Running as a daemon. Send TERM signal to end.') self.daemonize() @@ -333,7 +310,7 @@ def start(self): # start network components if networking is enabled if state.enableNetwork: start_proxyconfig() - BMConnectionPool() + BMConnectionPool().connectToStream(1) asyncoreThread = BMNetworkThread() asyncoreThread.daemon = True asyncoreThread.start() @@ -357,8 +334,6 @@ def start(self): state.uploadThread.daemon = True state.uploadThread.start() - connectToStream(1) - if config.safeGetBoolean('bitmessagesettings', 'upnp'): import upnp upnpThread = upnp.uPnPThread() @@ -413,7 +388,7 @@ def daemonize(): try: if os.fork(): # unlock - shared.thisapp.cleanup() + state.thisapp.cleanup() # wait until grandchild ready while True: time.sleep(1) @@ -423,7 +398,7 @@ def daemonize(): pass else: parentPid = os.getpid() - shared.thisapp.lock() # relock + state.thisapp.lock() # relock os.umask(0) try: @@ -434,7 +409,7 @@ def daemonize(): try: if os.fork(): # unlock - shared.thisapp.cleanup() + state.thisapp.cleanup() # wait until child ready while True: time.sleep(1) @@ -443,8 +418,8 @@ def daemonize(): # fork not implemented pass else: - shared.thisapp.lock() # relock - shared.thisapp.lockPid = None # indicate we're the final child + state.thisapp.lock() # relock + state.thisapp.lockPid = None # indicate we're the final child sys.stdout.flush() sys.stderr.flush() if not sys.platform.startswith('win'): @@ -483,7 +458,7 @@ def usage(): @staticmethod def stop(): """Stop main application""" - with shared.printLock: + with printLock: print('Stopping Bitmessage Deamon.') shutdown.doCleanShutdown() diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 440d36b205..bf3918829a 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -7,6 +7,7 @@ import os import random import string +import subprocess import sys import textwrap import threading @@ -17,10 +18,11 @@ from PyQt4 import QtCore, QtGui from PyQt4.QtNetwork import QLocalSocket, QLocalServer +import shared +import state from debug import logger from tr import _translate from addresses import decodeAddress, addBMIfNotPresent -import shared from bitmessageui import Ui_MainWindow from bmconfigparser import BMConfigParser import namecoin @@ -47,7 +49,6 @@ from proofofwork import getPowType import queues import shutdown -import state from statusbar import BMStatusBar import sound # This is needed for tray icon @@ -72,6 +73,15 @@ def powQueueSize(): return queue_len +def openKeysFile(): + """Open keys file with an external editor""" + keysfile = os.path.join(state.appdata, 'keys.dat') + if 'linux' in sys.platform: + subprocess.call(["xdg-open", keysfile]) + elif sys.platform.startswith('win'): + os.startfile(keysfile) # pylint: disable=no-member + + class MyForm(settingsmixin.SMainWindow): # the maximum frequency of message sounds in seconds @@ -730,9 +740,6 @@ def __init__(self, parent=None): QtCore.QObject.connect(self.pushButtonStatusIcon, QtCore.SIGNAL( "clicked()"), self.click_pushButtonStatusIcon) - self.numberOfMessagesProcessed = 0 - self.numberOfBroadcastsProcessed = 0 - self.numberOfPubkeysProcessed = 0 self.unreadCount = 0 # Set the icon sizes for the identicons @@ -1546,7 +1553,7 @@ def click_actionManageKeys(self): reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Open keys.dat?"), _translate( "MainWindow", "You may manage your keys by editing the keys.dat file stored in\n %1 \nIt is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.)").arg(state.appdata), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: - shared.openKeysFile() + openKeysFile() # menu button 'delete all treshed messages' def click_actionDeleteAllTrashedMessages(self): @@ -1668,7 +1675,7 @@ def setStatusIcon(self, color): if color == 'red': self.pushButtonStatusIcon.setIcon( QtGui.QIcon(":/newPrefix/images/redicon.png")) - shared.statusIconColor = 'red' + state.statusIconColor = 'red' # if the connection is lost then show a notification if self.connected and _notifications_enabled: self.notifierShow( @@ -1694,7 +1701,7 @@ def setStatusIcon(self, color): self.statusbar.clearMessage() self.pushButtonStatusIcon.setIcon( QtGui.QIcon(":/newPrefix/images/yellowicon.png")) - shared.statusIconColor = 'yellow' + state.statusIconColor = 'yellow' # if a new connection has been established then show a notification if not self.connected and _notifications_enabled: self.notifierShow( @@ -1712,7 +1719,7 @@ def setStatusIcon(self, color): self.statusbar.clearMessage() self.pushButtonStatusIcon.setIcon( QtGui.QIcon(":/newPrefix/images/greenicon.png")) - shared.statusIconColor = 'green' + state.statusIconColor = 'green' if not self.connected and _notifications_enabled: self.notifierShow( 'Bitmessage', @@ -2119,7 +2126,7 @@ def click_pushButtonSend(self): "MainWindow", "Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version.").arg(toAddress).arg(str(streamNumber))) continue self.statusbar.clearMessage() - if shared.statusIconColor == 'red': + if state.statusIconColor == 'red': self.updateStatusBar(_translate( "MainWindow", "Warning: You are currently not connected." @@ -2632,7 +2639,7 @@ def quit(self): elif reply == QtGui.QMessageBox.Cancel: return - if shared.statusIconColor == 'red' and not BMConfigParser().safeGetBoolean( + if state.statusIconColor == 'red' and not BMConfigParser().safeGetBoolean( 'bitmessagesettings', 'dontconnect'): reply = QtGui.QMessageBox.question( self, _translate("MainWindow", "Not connected"), @@ -2660,7 +2667,7 @@ def quit(self): if waitForConnection: self.updateStatusBar(_translate( "MainWindow", "Waiting for network connection...")) - while shared.statusIconColor == 'red': + while state.statusIconColor == 'red': time.sleep(0.5) QtCore.QCoreApplication.processEvents( QtCore.QEventLoop.AllEvents, 1000 diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index 6fbf5df63a..59b97f77ec 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -11,7 +11,7 @@ import knownnodes import l10n import network.stats -import shared +import state import widgets from inventory import Inventory from network import BMConnectionPool @@ -108,7 +108,7 @@ def updateNumberOfMessagesProcessed(self): "Processed %n person-to-person message(s).", None, QtCore.QCoreApplication.CodecForTr, - shared.numberOfMessagesProcessed)) + state.numberOfMessagesProcessed)) def updateNumberOfBroadcastsProcessed(self): """Update the counter for the number of processed broadcasts""" @@ -119,7 +119,7 @@ def updateNumberOfBroadcastsProcessed(self): "Processed %n broadcast message(s).", None, QtCore.QCoreApplication.CodecForTr, - shared.numberOfBroadcastsProcessed)) + state.numberOfBroadcastsProcessed)) def updateNumberOfPubkeysProcessed(self): """Update the counter for the number of processed pubkeys""" @@ -130,7 +130,7 @@ def updateNumberOfPubkeysProcessed(self): "Processed %n public key(s).", None, QtCore.QCoreApplication.CodecForTr, - shared.numberOfPubkeysProcessed)) + state.numberOfPubkeysProcessed)) def updateNumberOfBytes(self): """ @@ -225,9 +225,9 @@ def updateNetworkStatusTab(self, outbound, add, destination): # FYI: The 'singlelistener' thread sets the icon color to green when it # receives an incoming connection, meaning that the user's firewall is # configured correctly. - if self.tableWidgetConnectionCount.rowCount() and shared.statusIconColor == 'red': + if self.tableWidgetConnectionCount.rowCount() and state.statusIconColor == 'red': self.window().setStatusIcon('yellow') - elif self.tableWidgetConnectionCount.rowCount() == 0 and shared.statusIconColor != "red": + elif self.tableWidgetConnectionCount.rowCount() == 0 and state.statusIconColor != "red": self.window().setStatusIcon('red') # timer driven diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index bab27fbba0..1f650fe74c 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -11,7 +11,6 @@ import openclpow import paths import queues -import shared import state import tempfile import widgets @@ -338,7 +337,7 @@ def accept(self): proxytype_index = self.comboBoxProxyType.currentIndex() if proxytype_index == 0: - if self._proxy_type and shared.statusIconColor != 'red': + if self._proxy_type and state.statusIconColor != 'red': self.net_restart_needed = True elif self.comboBoxProxyType.currentText() != self._proxy_type: self.net_restart_needed = True @@ -482,7 +481,7 @@ def accept(self): # default behavior. The input is blank/blank self.config.set('bitmessagesettings', 'stopresendingafterxdays', '') self.config.set('bitmessagesettings', 'stopresendingafterxmonths', '') - shared.maximumLengthOfTimeToBotherResendingMessages = float('inf') + state.maximumLengthOfTimeToBotherResendingMessages = float('inf') stopResendingDefaults = True try: @@ -497,9 +496,9 @@ def accept(self): months = 0.0 if days >= 0 and months >= 0 and not stopResendingDefaults: - shared.maximumLengthOfTimeToBotherResendingMessages = \ + state.maximumLengthOfTimeToBotherResendingMessages = \ days * 24 * 60 * 60 + months * 60 * 60 * 24 * 365 / 12 - if shared.maximumLengthOfTimeToBotherResendingMessages < 432000: + if state.maximumLengthOfTimeToBotherResendingMessages < 432000: # If the time period is less than 5 hours, we give # zero values to all fields. No message will be sent again. QtGui.QMessageBox.about( @@ -516,7 +515,7 @@ def accept(self): 'bitmessagesettings', 'stopresendingafterxdays', '0') self.config.set( 'bitmessagesettings', 'stopresendingafterxmonths', '0') - shared.maximumLengthOfTimeToBotherResendingMessages = 0.0 + state.maximumLengthOfTimeToBotherResendingMessages = 0.0 else: self.config.set( 'bitmessagesettings', 'stopresendingafterxdays', str(days)) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 824580c250..f435d8d48e 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -140,9 +140,9 @@ def checkackdata(data): # bypass nonce and time, retain object type/version/stream + body readPosition = 16 - if data[readPosition:] in shared.ackdataForWhichImWatching: + if data[readPosition:] in state.ackdataForWhichImWatching: logger.info('This object is an acknowledgement bound for me.') - del shared.ackdataForWhichImWatching[data[readPosition:]] + del state.ackdataForWhichImWatching[data[readPosition:]] sqlExecute( 'UPDATE sent SET status=?, lastactiontime=?' ' WHERE ackdata=?', @@ -286,7 +286,7 @@ def processgetpubkey(data): def processpubkey(self, data): """Process a pubkey object""" pubkeyProcessingStartTime = time.time() - shared.numberOfPubkeysProcessed += 1 + state.numberOfPubkeysProcessed += 1 queues.UISignalQueue.put(( 'updateNumberOfPubkeysProcessed', 'no data')) readPosition = 20 # bypass the nonce, time, and object type @@ -459,7 +459,7 @@ def processpubkey(self, data): def processmsg(self, data): """Process a message object""" messageProcessingStartTime = time.time() - shared.numberOfMessagesProcessed += 1 + state.numberOfMessagesProcessed += 1 queues.UISignalQueue.put(( 'updateNumberOfMessagesProcessed', 'no data')) readPosition = 20 # bypass the nonce, time, and object type @@ -808,7 +808,7 @@ def processmsg(self, data): def processbroadcast(self, data): """Process a broadcast object""" messageProcessingStartTime = time.time() - shared.numberOfBroadcastsProcessed += 1 + state.numberOfBroadcastsProcessed += 1 queues.UISignalQueue.put(( 'updateNumberOfBroadcastsProcessed', 'no data')) inventoryHash = calculateInventoryHash(data) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index b9fe3d1c2c..e322574ed0 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -25,7 +25,6 @@ import knownnodes import queues -import shared import state import tr from bmconfigparser import BMConfigParser @@ -34,6 +33,13 @@ from network import BMConnectionPool, StoppableThread +#: Equals 4 weeks. You could make this longer if you want +#: but making it shorter would not be advisable because +#: there is a very small possibility that it could keep you +#: from obtaining a needed pubkey for a period of time. +lengthOfTimeToHoldOnToAllPubkeys = 2419200 + + class singleCleaner(StoppableThread): """The singleCleaner thread class""" name = "singleCleaner" @@ -44,7 +50,7 @@ def run(self): # pylint: disable=too-many-branches gc.disable() timeWeLastClearedInventoryAndPubkeysTables = 0 try: - shared.maximumLengthOfTimeToBotherResendingMessages = ( + state.maximumLengthOfTimeToBotherResendingMessages = ( float(BMConfigParser().get( 'bitmessagesettings', 'stopresendingafterxdays')) * 24 * 60 * 60 @@ -56,7 +62,7 @@ def run(self): # pylint: disable=too-many-branches # Either the user hasn't set stopresendingafterxdays and # stopresendingafterxmonths yet or the options are missing # from the config file. - shared.maximumLengthOfTimeToBotherResendingMessages = float('inf') + state.maximumLengthOfTimeToBotherResendingMessages = float('inf') # initial wait if state.shutdown == 0: @@ -74,7 +80,7 @@ def run(self): # pylint: disable=too-many-branches # queue which will never be handled by a UI. We should clear it to # save memory. # FIXME redundant? - if shared.thisapp.daemon or not state.enableGUI: + if state.thisapp.daemon or not state.enableGUI: queues.UISignalQueue.queue.clear() if timeWeLastClearedInventoryAndPubkeysTables < \ int(time.time()) - 7380: @@ -84,7 +90,7 @@ def run(self): # pylint: disable=too-many-branches # pubkeys sqlExecute( "DELETE FROM pubkeys WHERE time?)", int(time.time()), int(time.time()) - - shared.maximumLengthOfTimeToBotherResendingMessages + - state.maximumLengthOfTimeToBotherResendingMessages ) for row in queryreturn: if len(row) < 2: @@ -131,7 +137,8 @@ def run(self): # pylint: disable=too-many-branches ' is full. Bitmessage will now exit.'), True) )) - if shared.thisapp.daemon or not state.enableGUI: + # FIXME redundant? + if state.thisapp.daemon or not state.enableGUI: os._exit(1) # inv/object tracking diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 6d7514d46f..6e2522d8be 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -94,25 +94,25 @@ def run(self): hexlify(privEncryptionKey)) ) - # Initialize the shared.ackdataForWhichImWatching data structure + # Initialize the state.ackdataForWhichImWatching data structure queryreturn = sqlQuery( '''SELECT ackdata FROM sent WHERE status = 'msgsent' ''') for row in queryreturn: ackdata, = row self.logger.info('Watching for ackdata %s', hexlify(ackdata)) - shared.ackdataForWhichImWatching[ackdata] = 0 + state.ackdataForWhichImWatching[ackdata] = 0 # Fix legacy (headerless) watched ackdata to include header - for oldack in shared.ackdataForWhichImWatching: + for oldack in state.ackdataForWhichImWatching: if len(oldack) == 32: # attach legacy header, always constant (msg/1/1) newack = '\x00\x00\x00\x02\x01\x01' + oldack - shared.ackdataForWhichImWatching[newack] = 0 + state.ackdataForWhichImWatching[newack] = 0 sqlExecute( 'UPDATE sent SET ackdata=? WHERE ackdata=?', newack, oldack ) - del shared.ackdataForWhichImWatching[oldack] + del state.ackdataForWhichImWatching[oldack] # give some time for the GUI to start # before we start on existing POW tasks. @@ -864,7 +864,7 @@ def sendMsg(self): # if we aren't sending this to ourselves or a chan if not BMConfigParser().has_section(toaddress): - shared.ackdataForWhichImWatching[ackdata] = 0 + state.ackdataForWhichImWatching[ackdata] = 0 queues.UISignalQueue.put(( 'updateSentItemStatusByAckdata', ( ackdata, diff --git a/src/helper_startup.py b/src/helper_startup.py index 9711c33917..fcd12aa4de 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -276,19 +276,28 @@ def updateConfig(): config.save() -def isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections(): - """Check for (mainly XP and Vista) limitations""" +def adjustHalfOpenConnectionsLimit(): + """Check and satisfy half-open connections limit (mainly XP and Vista)""" + if BMConfigParser().safeGet( + 'bitmessagesettings', 'socksproxytype', 'none') != 'none': + state.maximumNumberOfHalfOpenConnections = 4 + return + + is_limited = False try: if sys.platform[0:3] == "win": + # Some XP and Vista systems can only have 10 outgoing + # connections at a time. VER_THIS = StrictVersion(platform.version()) - return ( + is_limited = ( StrictVersion("5.1.2600") <= VER_THIS and StrictVersion("6.0.6000") >= VER_THIS ) - return False - except Exception: + except ValueError: pass + state.maximumNumberOfHalfOpenConnections = 9 if is_limited else 64 + def start_proxyconfig(): """Check socksproxytype and start any proxy configuration plugin""" diff --git a/src/highlevelcrypto.py b/src/highlevelcrypto.py index f392fe4af9..f89a31c8c0 100644 --- a/src/highlevelcrypto.py +++ b/src/highlevelcrypto.py @@ -2,8 +2,8 @@ High level cryptographic functions based on `.pyelliptic` OpenSSL bindings. .. note:: - Upstream pyelliptic was upgraded from SHA1 to SHA256 for signing. - We must upgrade PyBitmessage gracefully. + Upstream pyelliptic was upgraded from SHA1 to SHA256 for signing. We must + `upgrade PyBitmessage gracefully. `_ `More discussion. `_ """ @@ -68,7 +68,7 @@ def sign(msg, hexPrivkey): "digestalg" setting """ digestAlg = BMConfigParser().safeGet( - 'bitmessagesettings', 'digestalg', 'sha1') + 'bitmessagesettings', 'digestalg', 'sha256') if digestAlg == "sha1": # SHA1, this will eventually be deprecated return makeCryptor(hexPrivkey).sign( diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 6264191dbb..77eb58e418 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -87,6 +87,7 @@ def establishedConnections(self): def connectToStream(self, streamNumber): """Connect to a bitmessage stream""" self.streams.append(streamNumber) + state.streamsInWhichIAmParticipating.append(streamNumber) def getConnectionByAddr(self, addr): """ diff --git a/src/network/tcp.py b/src/network/tcp.py index d611b1caf7..18fd2e1a7b 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -14,7 +14,6 @@ import helper_random import knownnodes import protocol -import shared import state from bmconfigparser import BMConfigParser from helper_random import randomBytes @@ -34,6 +33,9 @@ logger = logging.getLogger('default') +maximumAgeOfNodesThatIAdvertiseToOthers = 10800 #: Equals three hours + + class TCPConnection(BMProto, TLSDispatcher): # pylint: disable=too-many-instance-attributes """ @@ -136,7 +138,7 @@ def state_connection_fully_established(self): def set_connection_fully_established(self): """Initiate inventory synchronisation.""" if not self.isOutbound and not self.local: - shared.clientHasReceivedIncomingConnections = True + state.clientHasReceivedIncomingConnections = True UISignalQueue.put(('setStatusIcon', 'green')) UISignalQueue.put( ('updateNetworkStatusTab', ( @@ -170,7 +172,7 @@ def sendAddr(self): filtered = [ (k, v) for k, v in nodes.iteritems() if v["lastseen"] > int(time.time()) - - shared.maximumAgeOfNodesThatIAdvertiseToOthers and + maximumAgeOfNodesThatIAdvertiseToOthers and v["rating"] >= 0 and len(k.host) <= 22 ] # sent 250 only if the remote isn't interested in it diff --git a/src/shared.py b/src/shared.py index beed52ed67..3a6fbc31df 100644 --- a/src/shared.py +++ b/src/shared.py @@ -13,7 +13,6 @@ import stat import subprocess import sys -import threading from binascii import hexlify # Project imports. @@ -27,19 +26,6 @@ from pyelliptic import arithmetic -verbose = 1 -# This is obsolete with the change to protocol v3 -# but the singleCleaner thread still hasn't been updated -# so we need this a little longer. -maximumAgeOfAnObjectThatIAmWillingToAccept = 216000 -# Equals 4 weeks. You could make this longer if you want -# but making it shorter would not be advisable because -# there is a very small possibility that it could keep you -# from obtaining a needed pubkey for a period of time. -lengthOfTimeToHoldOnToAllPubkeys = 2419200 -maximumAgeOfNodesThatIAdvertiseToOthers = 10800 # Equals three hours - - myECCryptorObjects = {} MyECSubscriptionCryptorObjects = {} # The key in this dictionary is the RIPE hash which is encoded @@ -48,19 +34,6 @@ # The key in this dictionary is the tag generated from the address. myAddressesByTag = {} broadcastSendersForWhichImWatching = {} -printLock = threading.Lock() -statusIconColor = 'red' - -thisapp = None # singleton lock instance - -ackdataForWhichImWatching = {} -# used by API command clientStatus -clientHasReceivedIncomingConnections = False -numberOfMessagesProcessed = 0 -numberOfBroadcastsProcessed = 0 -numberOfPubkeysProcessed = 0 - -maximumLengthOfTimeToBotherResendingMessages = 0 def isAddressInMyAddressBook(address): @@ -280,11 +253,3 @@ def fixSensitiveFilePermissions(filename, hasEnabledKeys): except Exception: logger.exception('Keyfile permissions could not be fixed.') raise - - -def openKeysFile(): - """Open keys file with an external editor""" - if 'linux' in sys.platform: - subprocess.call(["xdg-open", state.appdata + 'keys.dat']) - else: - os.startfile(state.appdata + 'keys.dat') diff --git a/src/shutdown.py b/src/shutdown.py index dbc2af04e4..819aa2dab6 100644 --- a/src/shutdown.py +++ b/src/shutdown.py @@ -4,7 +4,6 @@ import threading import time -import shared import state from debug import logger from helper_sql import sqlQuery, sqlStoredProcedure @@ -80,9 +79,9 @@ def doCleanShutdown(): except Queue.Empty: break - if shared.thisapp.daemon or not state.enableGUI: # ..fixme:: redundant? + if state.thisapp.daemon or not state.enableGUI: logger.info('Clean shutdown complete.') - shared.thisapp.cleanup() + state.thisapp.cleanup() os._exit(0) # pylint: disable=protected-access else: logger.info('Core shutdown complete.') diff --git a/src/state.py b/src/state.py index 58e1106a70..8bfaf7b98c 100644 --- a/src/state.py +++ b/src/state.py @@ -39,6 +39,8 @@ maximumNumberOfHalfOpenConnections = 0 +maximumLengthOfTimeToBotherResendingMessages = 0 + invThread = None addrThread = None downloadThread = None @@ -55,3 +57,21 @@ kivy = False association = '' + +clientHasReceivedIncomingConnections = False +"""used by API command clientStatus""" + +numberOfMessagesProcessed = 0 +numberOfBroadcastsProcessed = 0 +numberOfPubkeysProcessed = 0 + +statusIconColor = 'red' +""" +GUI status icon color +.. note:: bad style, refactor it +""" + +ackdataForWhichImWatching = {} + +thisapp = None +"""Singleton instance""" diff --git a/src/tests/test_crypto.py b/src/tests/test_crypto.py index b7eb717795..b53105cb2d 100644 --- a/src/tests/test_crypto.py +++ b/src/tests/test_crypto.py @@ -6,6 +6,7 @@ import unittest from abc import ABCMeta, abstractmethod from binascii import hexlify, unhexlify +from pybitmessage.pyelliptic import arithmetic try: from Crypto.Hash import RIPEMD @@ -20,8 +21,13 @@ sample_pubencryptionkey = unhexlify( '044597d59177fc1d89555d38915f581b5ff2286b39d022ca0283d2bdd5c36be5d3c' 'e7b9b97792327851a562752e4b79475d1f51f5a71352482b241227f45ed36a9') - +sample_privatesigningkey = \ + '93d0b61371a54b53df143b954035d612f8efa8a3ed1cf842c2186bfd8f876665' +sample_privateencryptionkey = \ + '4b0b73a54e19b059dc274ab69df095fe699f43b17397bca26fdf40f4d7400a3a' sample_ripe = '003cd097eb7f35c87b5dc8b4538c22cb55312a9f' +# stream: 1, version: 2 +sample_address = 'BM-onkVu1KKL2UaUss5Upg9vXmqd3esTmV79' _sha = hashlib.new('sha512') _sha.update(sample_pubsigningkey + sample_pubencryptionkey) @@ -59,3 +65,34 @@ class TestCrypto(RIPEMD160TestCase, unittest.TestCase): @staticmethod def _hashdigest(data): return RIPEMD.RIPEMD160Hash(data).digest() + + +class TestAddresses(unittest.TestCase): + """Test addresses manipulations""" + def test_privtopub(self): + """Generate public keys and check the result""" + self.assertEqual( + arithmetic.privtopub(sample_privatesigningkey), + hexlify(sample_pubsigningkey) + ) + self.assertEqual( + arithmetic.privtopub(sample_privateencryptionkey), + hexlify(sample_pubencryptionkey) + ) + + def test_address(self): + """Create address and check the result""" + from pybitmessage import addresses + from pybitmessage.fallback import RIPEMD160Hash + + sha = hashlib.new('sha512') + sha.update(sample_pubsigningkey + sample_pubencryptionkey) + ripe_hash = RIPEMD160Hash(sha.digest()).digest() + self.assertEqual(ripe_hash, unhexlify(sample_ripe)) + + self.assertEqual( + addresses.encodeAddress(2, 1, ripe_hash), sample_address) + + self.assertEqual( + addresses.decodeAddress(sample_address), + ('success', 2, 1, ripe_hash)) diff --git a/src/threads.py b/src/threads.py index b7471508dc..ac8bf7a6d5 100644 --- a/src/threads.py +++ b/src/threads.py @@ -40,7 +40,9 @@ def _thread_name_hack(self): threading.Thread._Thread__bootstrap = _thread_name_hack +printLock = threading.Lock() + __all__ = [ "addressGenerator", "objectProcessor", "singleCleaner", "singleWorker", - "sqlThread" + "sqlThread", "printLock" ]