diff --git a/src/api.py b/src/api.py index cd3a8962..945e269b 100644 --- a/src/api.py +++ b/src/api.py @@ -431,8 +431,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 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) + shared.writeKeysFile() return 'success' elif method == 'deleteAddress': @@ -445,8 +444,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 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.writeKeysFile() shared.UISignalQueue.put(('rerenderInboxFromLabels','')) shared.UISignalQueue.put(('rerenderSentToLabels','')) shared.reloadMyAddressHashes() diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index 91e72355..a4546c08 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -471,15 +471,13 @@ def handlech(c, stdscr): label = t shared.config.set(a, "label", label) # Write config - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() addresses[addrcur][0] = label elif t == "4": # Enable address a = addresses[addrcur][2] shared.config.set(a, "enabled", "true") # Set config # Write config - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() # Change color if shared.safeConfigGetBoolean(a, 'chan'): addresses[addrcur][3] = 9 # orange @@ -494,16 +492,14 @@ def handlech(c, stdscr): shared.config.set(a, "enabled", "false") # Set config addresses[addrcur][3] = 8 # Set color to gray # Write config - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() addresses[addrcur][1] = False shared.reloadMyAddressHashes() # Reload address hashes elif t == "6": # Delete address r, t = d.inputbox("Type in \"I want to delete this address\"", width=50) if r == d.DIALOG_OK and t == "I want to delete this address": shared.config.remove_section(addresses[addrcur][2]) - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() del addresses[addrcur] elif t == "7": # Special address behavior a = addresses[addrcur][2] @@ -534,8 +530,7 @@ def handlech(c, stdscr): shared.config.set(a, "mailinglistname", mn) addresses[addrcur][3] = 6 # Set color to magenta # Write config - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() elif menutab == 5: d.set_background_title("Subscriptions Dialog Box") r, t = d.menu("Do what with subscription to \""+subscriptions[subcur][0]+"\"?", diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 9952caf8..95eb7d12 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -458,8 +458,7 @@ class MyForm(QtGui.QMainWindow): self, 'Message', displayMsg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: shared.config.remove_section(addressInKeysFile) - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() # Configure Bitmessage to start on startup (or remove the # configuration) based on the setting in the keys.dat file @@ -1332,7 +1331,7 @@ class MyForm(QtGui.QMainWindow): 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(shared.appdata), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: - self.openKeysFile() + shared.openKeysFile() def click_actionDeleteAllTrashedMessages(self): if QtGui.QMessageBox.question(self, _translate("MainWindow", "Delete trash?"), _translate("MainWindow", "Are you sure you want to delete all trashed messages?"), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) == QtGui.QMessageBox.No: @@ -1419,17 +1418,10 @@ class MyForm(QtGui.QMainWindow): if self.connectDialogInstance.exec_(): if self.connectDialogInstance.ui.radioButtonConnectNow.isChecked(): shared.config.remove_option('bitmessagesettings', 'dontconnect') - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() else: self.click_actionSettings() - def openKeysFile(self): - if 'linux' in sys.platform: - subprocess.call(["xdg-open", shared.appdata + 'keys.dat']) - else: - os.startfile(shared.appdata + 'keys.dat') - def changeEvent(self, event): if event.type() == QtCore.QEvent.WindowStateChange: if self.windowState() & QtCore.Qt.WindowMinimized: @@ -2414,8 +2406,7 @@ class MyForm(QtGui.QMainWindow): # shared.config.set('bitmessagesettings', 'maxcores', # str(self.settingsDialogInstance.ui.comboBoxMaxCores.currentText())) - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() if 'win32' in sys.platform or 'win64' in sys.platform: # Auto-startup for Windows @@ -2435,8 +2426,7 @@ class MyForm(QtGui.QMainWindow): if shared.appdata != '' and self.settingsDialogInstance.ui.checkBoxPortableMode.isChecked(): # If we are NOT using portable mode now but the user selected that we should... # Write the keys.dat file to disk in the new location sqlStoredProcedure('movemessagstoprog') - with open('keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() # Write the knownnodes.dat file to disk in the new location shared.knownNodesLock.acquire() output = open('knownnodes.dat', 'wb') @@ -2460,8 +2450,7 @@ class MyForm(QtGui.QMainWindow): os.makedirs(shared.appdata) sqlStoredProcedure('movemessagstoappdata') # Write the keys.dat file to disk in the new location - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() # Write the knownnodes.dat file to disk in the new location shared.knownNodesLock.acquire() output = open(shared.appdata + 'knownnodes.dat', 'wb') @@ -2480,8 +2469,7 @@ class MyForm(QtGui.QMainWindow): def click_radioButtonBlacklist(self): if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'white': shared.config.set('bitmessagesettings', 'blackwhitelist', 'black') - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() # self.ui.tableWidgetBlacklist.clearContents() self.ui.tableWidgetBlacklist.setRowCount(0) self.loadBlackWhiteList() @@ -2490,8 +2478,7 @@ class MyForm(QtGui.QMainWindow): def click_radioButtonWhitelist(self): if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': shared.config.set('bitmessagesettings', 'blackwhitelist', 'white') - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() # self.ui.tableWidgetBlacklist.clearContents() self.ui.tableWidgetBlacklist.setRowCount(0) self.loadBlackWhiteList() @@ -2563,8 +2550,7 @@ class MyForm(QtGui.QMainWindow): shared.config.set(str(addressAtCurrentRow), 'mailinglistname', str( self.dialog.ui.lineEditMailingListName.text().toUtf8())) self.ui.tableWidgetYourIdentities.item(currentRow, 1).setTextColor(QtGui.QColor(137, 04, 177)) # magenta - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() self.rerenderInboxToLabels() def click_NewAddressDialog(self): @@ -3066,8 +3052,7 @@ class MyForm(QtGui.QMainWindow): addressAtCurrentRow = str( self.ui.tableWidgetYourIdentities.item(currentRow, 1).text()) shared.config.set(addressAtCurrentRow, 'enabled', 'true') - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() self.ui.tableWidgetYourIdentities.item( currentRow, 0).setTextColor(QApplication.palette().text().color()) self.ui.tableWidgetYourIdentities.item( @@ -3093,8 +3078,7 @@ class MyForm(QtGui.QMainWindow): currentRow, 2).setTextColor(QtGui.QColor(128, 128, 128)) if shared.safeConfigGetBoolean(addressAtCurrentRow, 'mailinglist'): self.ui.tableWidgetYourIdentities.item(currentRow, 1).setTextColor(QtGui.QColor(137, 04, 177)) # magenta - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() shared.reloadMyAddressHashes() def on_action_YourIdentitiesClipboard(self): @@ -3291,8 +3275,7 @@ class MyForm(QtGui.QMainWindow): currentRow, 1).text() shared.config.set(str(addressAtCurrentRow), 'label', str( self.ui.tableWidgetYourIdentities.item(currentRow, 0).text().toUtf8())) - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() self.rerenderComboBoxSendFrom() # self.rerenderInboxFromLabels() self.rerenderInboxToLabels() diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index 2e215606..1a3ff5bc 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -129,8 +129,7 @@ class addressGenerator(threading.Thread): address, 'privSigningKey', privSigningKeyWIF) shared.config.set( address, 'privEncryptionKey', privEncryptionKeyWIF) - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() # The API and the join and create Chan functionality # both need information back from the address generator. @@ -244,8 +243,7 @@ class addressGenerator(threading.Thread): address, 'privSigningKey', privSigningKeyWIF) shared.config.set( address, 'privEncryptionKey', privEncryptionKeyWIF) - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() shared.UISignalQueue.put(('writeNewAddressToTable', ( label, address, str(streamNumber)))) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 4a88f6c0..5fe85d6d 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -150,8 +150,7 @@ class singleWorker(threading.Thread): try: shared.config.set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() except: # The user deleted the address out of the keys.dat file before this # finished. @@ -248,8 +247,7 @@ class singleWorker(threading.Thread): try: shared.config.set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() except: # The user deleted the address out of the keys.dat file before this # finished. @@ -345,8 +343,7 @@ class singleWorker(threading.Thread): try: shared.config.set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() except Exception as err: logger.error('Error: Couldn\'t add the lastpubkeysendtime to the keys.dat file. Error message: %s' % err) diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 24e9b59a..4eadc6f0 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -91,8 +91,6 @@ class sqlThread(threading.Thread): shared.config.set('bitmessagesettings', 'sockslisten', 'false') shared.config.set('bitmessagesettings', 'keysencrypted', 'false') shared.config.set('bitmessagesettings', 'messagesencrypted', 'false') - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) # People running earlier versions of PyBitmessage do not have the # usedpersonally field in their pubkeys table. Let's add it. @@ -103,8 +101,6 @@ class sqlThread(threading.Thread): self.conn.commit() shared.config.set('bitmessagesettings', 'settingsversion', '3') - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) # People running earlier versions of PyBitmessage do not have the # encodingtype field in their inbox and sent tables or the read field @@ -138,6 +134,7 @@ class sqlThread(threading.Thread): shared.config.set( 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', '0') shared.config.set('bitmessagesettings', 'settingsversion', '6') + # From now on, let us keep a 'version' embedded in the messages.dat # file so that when we make changes to the database, the database # version we are on can stay embedded in the messages.dat file. Let us @@ -281,10 +278,7 @@ class sqlThread(threading.Thread): 'bitmessagesettings', 'stopresendingafterxdays', '') shared.config.set( 'bitmessagesettings', 'stopresendingafterxmonths', '') - #shared.config.set( shared.config.set('bitmessagesettings', 'settingsversion', '8') - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) # Add a new table: objectprocessorqueue with which to hold objects # that have yet to be processed if the user shuts down Bitmessage. @@ -344,10 +338,8 @@ class sqlThread(threading.Thread): shared.config.set('bitmessagesettings', 'maxdownloadrate', '0') shared.config.set('bitmessagesettings', 'maxuploadrate', '0') shared.config.set('bitmessagesettings', 'settingsversion', '10') - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) - - + shared.writeKeysFile() + # The format of data stored in the pubkeys table has changed. Let's # clear it, and the pubkeys from inventory, so that they'll be re-downloaded. item = '''SELECT value FROM settings WHERE key='version';''' diff --git a/src/helper_startup.py b/src/helper_startup.py index d192070f..c71ee436 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -133,8 +133,7 @@ def loadConfig(): os.makedirs(shared.appdata) if not sys.platform.startswith('win'): os.umask(0o077) - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + shared.writeKeysFile() _loadTrustedPeer() diff --git a/src/shared.py b/src/shared.py index f31683ed..df37c1b4 100644 --- a/src/shared.py +++ b/src/shared.py @@ -18,6 +18,8 @@ import sys import stat import threading import time +import shutil # used for moving the data folder and copying keys.dat +import datetime from os import path, environ from struct import Struct import traceback @@ -838,4 +840,22 @@ def _checkAndShareBroadcastWithPeers(data): shared.objectProcessorQueueSize += len(data) objectProcessorQueue.put((objectType,data)) +def openKeysFile(): + if 'linux' in sys.platform: + subprocess.call(["xdg-open", shared.appdata + 'keys.dat']) + else: + os.startfile(shared.appdata + 'keys.dat') + +def writeKeysFile(): + fileName = shared.appdata + 'keys.dat' + fileNameBak = fileName + "." + datetime.datetime.now().strftime("%Y%j%H%M%S%f") + '.bak' + # create a backup copy to prevent the accidental loss due to the disk write failure + shutil.copyfile(fileName, fileNameBak) + # write the file + with open(fileName, 'wb') as configfile: + shared.config.write(configfile) + # delete a backup + os.remove(fileNameBak) + +helper_startup.loadConfig() from debug import logger