Index: keyring-5.3/keyring/backends/file.py =================================================================== --- keyring-5.3.orig/keyring/backends/file.py +++ keyring-5.3/keyring/backends/file.py @@ -9,6 +9,7 @@ import abc import time import logging import shutil +import glob from ..py27compat import configparser @@ -36,13 +37,6 @@ class FileBacked(object): """ return os.path.join(platform_.data_root(), self.filename) - @properties.NonDataProperty - def backup_file_path(self): - """ - The path to the file where passwords are stored. This property - may be overridden by the subclass or at the instance level. - """ - return os.path.join(platform_.data_root(), self.backup_filename) class BaseKeyring(FileBacked, KeyringBackend): """ @@ -91,15 +85,6 @@ class BaseKeyring(FileBacked, KeyringBac return password - def filecopy(self,src,dest): - """copy file src to dest with default buffer size - """ - with open(src, 'r') as f1: - with open(dest, 'w') as f2: - shutil.copyfileobj(f1,f2) - f2.flush() - - def set_password(self, service, username, password): """Write the password in the file. """ @@ -125,23 +110,7 @@ class BaseKeyring(FileBacked, KeyringBac config = configparser.RawConfigParser() config.read(self.file_path) except configparser.ParsingError as e: - logging.warning("set_password: keyring file corrupted, Reverting to Backup") - # Revert to the backup file (copy backup over current file) - try: - src = self.backup_file_path - dest = self.file_path - self.filecopy(src,dest) - except shutil.Error as e: - logging.warning("set_password: Revert from Backup failed. Error: %s" % e) - raise - # Load the keyring from the disk, if this fails exception is raised - try: - config = configparser.RawConfigParser() - config.read(self.file_path) - except: - e = sys.exc_info()[0] - logging.warning("set_password: Both keyring files are non useable. Error: %s" % e) - raise + logging.warning("set_password: keyring file corrupted") # Update the keyring with the password @@ -149,17 +118,15 @@ class BaseKeyring(FileBacked, KeyringBac config.add_section(service) config.set(service, username, password_base64) - # Make a back up of the keyring file here - try: - src = self.file_path - dest = self.backup_file_path - self.filecopy(src,dest) - except shutil.Error as e: - logging.warning("set_password: Backup failed. Error: %s" % e) - # Save the keyring back to the file - with open(self.file_path, 'w') as config_file: + storage_root = os.path.dirname(self.file_path) + tmpfile = "tmpfile.%s" % os.getpid() + with open(storage_root + "/" + tmpfile, 'w') as config_file: config.write(config_file) + # copy will overwrite but move will not + shutil.copy(storage_root + "/" + tmpfile,self.file_path) + # wipe out tmpfile here + os.remove(storage_root + "/" + tmpfile) @@ -203,8 +170,15 @@ class BaseKeyring(FileBacked, KeyringBac except configparser.NoSectionError: raise PasswordDeleteError("Password not found") # update the file - with open(self.file_path, 'w') as config_file: + storage_root = os.path.dirname(self.file_path) + tmpfile = "tmpfile.%s" % os.getpid() + with open(storage_root + "/" + tmpfile, 'w') as config_file: config.write(config_file) + # copy will overwrite but move will not + shutil.copy(storage_root + "/" + tmpfile,self.file_path) + # wipe out tmpfile + os.remove(storage_root + "/" + tmpfile) + class PlaintextKeyring(BaseKeyring): """Simple File Keyring with no encryption""" @@ -213,7 +187,6 @@ class PlaintextKeyring(BaseKeyring): "Applicable for all platforms, but not recommended" filename = 'keyring_pass.cfg' - backup_filename = 'crypted_pass_backup.cfg' def encrypt(self, password): """Directly return the password itself. @@ -267,7 +240,6 @@ class EncryptedKeyring(Encrypted, BaseKe """PyCrypto File Keyring""" filename = 'crypted_pass.cfg' - backup_filename = 'crypted_pass_backup.cfg' pw_prefix = 'pw:'.encode() @properties.ClassProperty @@ -326,27 +298,15 @@ class EncryptedKeyring(Encrypted, BaseKe escape_for_ini('password reference'), ) except (configparser.NoSectionError, configparser.NoOptionError): - # The current file doesn't have the keyring-setting, check the backup - if os.path.exists(self.backup_file_path): - config = configparser.RawConfigParser() - config.read(self.backup_file_path) - try: - config.get( - escape_for_ini('keyring-setting'), - escape_for_ini('password reference'), - ) - except (configparser.NoSectionError, configparser.NoOptionError): - return False - # backup file has it, let's use it - try: - src = self.backup_file_path - dest = self.file_path - shutil.copy(src,dest) - except shutil.Error as e: - logging.warning("Revert from Backup failed. Error: %s" % e) - return False - else: - return False + return False + + # remove any residual temporary files here + try: + for tmpfile in glob.glob(os.path.dirname(self.file_path) + "/" + "tmpfile.*"): + os.remove(tmpfile) + except: + logging.warning("_check_file: tmpfile removal failed") + return True