Make backup of config when upgrading

Fixes #307
This commit is contained in:
Manuel Ebert 2015-04-04 18:36:34 +11:00
parent 2615070df0
commit c0ec95679b
4 changed files with 39 additions and 20 deletions

View file

@ -26,7 +26,12 @@ class EncryptedJournal(Journal.Journal):
super(EncryptedJournal, self).__init__(name, **kwargs) super(EncryptedJournal, self).__init__(name, **kwargs)
self.config['encrypt'] = True self.config['encrypt'] = True
def _load(self, filename): def _load(self, filename, password=None):
"""Loads an encrypted journal from a file and tries to decrypt it.
If password is not provided, will look for password in the keychain
and otherwise ask the user to enter a password up to three times.
If the password is provided but wrong (or corrupt), this will simply
return None."""
with open(filename) as f: with open(filename) as f:
journal_encrypted = f.read() journal_encrypted = f.read()
@ -36,7 +41,8 @@ class EncryptedJournal(Journal.Journal):
return Fernet(key).decrypt(journal_encrypted).decode('utf-8') return Fernet(key).decrypt(journal_encrypted).decode('utf-8')
except (InvalidToken, IndexError): except (InvalidToken, IndexError):
return None return None
if password:
return validate_password(password)
return util.get_password(keychain=self.name, validator=validate_password) return util.get_password(keychain=self.name, validator=validate_password)
def _store(self, filename, text): def _store(self, filename, text):

View file

@ -153,7 +153,7 @@ def run(manual_args=None):
util.prnt(u"Journals defined in {}".format(install.CONFIG_FILE_PATH)) util.prnt(u"Journals defined in {}".format(install.CONFIG_FILE_PATH))
ml = min(max(len(k) for k in config['journals']), 20) ml = min(max(len(k) for k in config['journals']), 20)
for journal, cfg in config['journals'].items(): for journal, cfg in config['journals'].items():
print " * {:{}} -> {}".format(journal, ml, cfg['journal'] if isinstance(cfg, dict) else cfg) print(" * {:{}} -> {}".format(journal, ml, cfg['journal'] if isinstance(cfg, dict) else cfg))
sys.exit(0) sys.exit(0)
log.debug('Using configuration "%s"', config) log.debug('Using configuration "%s"', config)

View file

@ -63,7 +63,7 @@ def upgrade_config(config):
for key in missing_keys: for key in missing_keys:
config[key] = default_config[key] config[key] = default_config[key]
save_config(config) save_config(config)
print("[.jrnl_conf updated to newest version]") print("[.jrnl_conf updated to newest version at {}]".format(CONFIG_FILE_PATH))
def save_config(config): def save_config(config):

View file

@ -12,8 +12,6 @@ from cryptography.fernet import Fernet
def upgrade_encrypted_journal(filename, key_plain): def upgrade_encrypted_journal(filename, key_plain):
"""Decrypts a journal in memory using the jrnl 1.x encryption scheme """Decrypts a journal in memory using the jrnl 1.x encryption scheme
and returns it in plain text.""" and returns it in plain text."""
util.prompt("UPGRADING JOURNAL")
print "UPGRADING SHIT", filename, key_plain
with open(filename) as f: with open(filename) as f:
iv_cipher = f.read() iv_cipher = f.read()
iv, cipher = iv_cipher[:16], iv_cipher[16:] iv, cipher = iv_cipher[:16], iv_cipher[16:]
@ -27,10 +25,8 @@ def upgrade_encrypted_journal(filename, key_plain):
else: else:
unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder() unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
plain = unpadder.update(plain_padded) + unpadder.finalize() plain = unpadder.update(plain_padded) + unpadder.finalize()
except IndexError: except ValueError:
print "UH NO"
return None return None
print "PLain", plain
key = EncryptedJournal.make_key(key_plain) key = EncryptedJournal.make_key(key_plain)
journal = Fernet(key).encrypt(plain) journal = Fernet(key).encrypt(plain)
with open(filename, 'w') as f: with open(filename, 'w') as f:
@ -40,17 +36,27 @@ def upgrade_encrypted_journal(filename, key_plain):
def upgrade_jrnl_if_necessary(config_path): def upgrade_jrnl_if_necessary(config_path):
with open(config_path) as f: with open(config_path) as f:
config = f.read() config_file = f.read()
if not config.strip().startswith("{"): if not config_file.strip().startswith("{"):
return return
config = util.load_config(config_path) config = util.load_config(config_path)
util.prompt("""Welcome to jrnl {} util.prompt("""Welcome to jrnl {}.
jrnl will now upgrade your configuration and journal files.
Please note that jrnl 1.x is NOT forward compatible with this version of jrnl. It looks like you've been using an older version of jrnl until now. That's
If you choose to proceed, you will not be able to use your journals with okay - jrnl will now upgrade your configuration and journal files. Afterwards
older versions of jrnl anymore.""".format(__version__)) you can enjoy all of the great new features that come with jrnl 2:
- Support for storing your journal in multiple files
- Faster reading and writing for large journals
- New encryption back-end that makes installing jrnl much easier
- Tons of bug fixes
Please note that jrnl 1.x is NOT forward compatible with this version of jrnl.
If you choose to proceed, you will not be able to use your journals with
older versions of jrnl anymore.
""".format(__version__))
encrypted_journals = {} encrypted_journals = {}
plain_journals = {} plain_journals = {}
@ -66,13 +72,14 @@ def upgrade_jrnl_if_necessary(config_path):
else: else:
plain_journals[journal] = journal_conf plain_journals[journal] = journal_conf
if encrypted_journals: if encrypted_journals:
util.prompt("Following encrypted journals will be upgraded to jrnl {}:".format(__version__)) longest_journal_name = max([len(journal) for journal in config['journals']])
util.prompt("\nFollowing encrypted journals will be upgraded to jrnl {}:".format(__version__))
for journal, path in encrypted_journals.items(): for journal, path in encrypted_journals.items():
util.prompt(" {:20} -> {}".format(journal, path)) util.prompt(" {:{pad}} -> {}".format(journal, path, pad=longest_journal_name))
if plain_journals: if plain_journals:
util.prompt("Following plain text journals will be not be touched:") util.prompt("\nFollowing plain text journals will be not be touched:")
for journal, path in plain_journals.items(): for journal, path in plain_journals.items():
util.prompt(" {:20} -> {}".format(journal, path)) util.prompt(" {:{pad}} -> {}".format(journal, path, pad=longest_journal_name))
cont = util.yesno("Continue upgrading jrnl?", default=False) cont = util.yesno("Continue upgrading jrnl?", default=False)
if not cont: if not cont:
@ -82,3 +89,9 @@ def upgrade_jrnl_if_necessary(config_path):
for journal, path in encrypted_journals.items(): for journal, path in encrypted_journals.items():
util.prompt("Enter password for {} journal (stored in {}).".format(journal, path)) util.prompt("Enter password for {} journal (stored in {}).".format(journal, path))
util.get_password(keychain=journal, validator=lambda pwd: upgrade_encrypted_journal(path, pwd)) util.get_password(keychain=journal, validator=lambda pwd: upgrade_encrypted_journal(path, pwd))
with open(config_path + ".backup", 'w') as config_backup:
config_backup.write(config_file)
util.prompt("""\n\nYour old config has been backed up to {}.backup.
We're all done here and you can start enjoying jrnl 2.""".format(config_path))