diff --git a/jrnl/EncryptedJournal.py b/jrnl/EncryptedJournal.py index 3d4c8ba2..7f27e297 100644 --- a/jrnl/EncryptedJournal.py +++ b/jrnl/EncryptedJournal.py @@ -26,7 +26,12 @@ class EncryptedJournal(Journal.Journal): super(EncryptedJournal, self).__init__(name, **kwargs) 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: journal_encrypted = f.read() @@ -36,7 +41,8 @@ class EncryptedJournal(Journal.Journal): return Fernet(key).decrypt(journal_encrypted).decode('utf-8') except (InvalidToken, IndexError): return None - + if password: + return validate_password(password) return util.get_password(keychain=self.name, validator=validate_password) def _store(self, filename, text): diff --git a/jrnl/cli.py b/jrnl/cli.py index 529d46e6..7407f836 100644 --- a/jrnl/cli.py +++ b/jrnl/cli.py @@ -153,7 +153,7 @@ def run(manual_args=None): util.prnt(u"Journals defined in {}".format(install.CONFIG_FILE_PATH)) ml = min(max(len(k) for k in config['journals']), 20) 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) log.debug('Using configuration "%s"', config) diff --git a/jrnl/install.py b/jrnl/install.py index cfab2051..dac80700 100644 --- a/jrnl/install.py +++ b/jrnl/install.py @@ -63,7 +63,7 @@ def upgrade_config(config): for key in missing_keys: config[key] = default_config[key] 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): diff --git a/jrnl/upgrade.py b/jrnl/upgrade.py index 7af969bc..b8941c5b 100644 --- a/jrnl/upgrade.py +++ b/jrnl/upgrade.py @@ -12,8 +12,6 @@ from cryptography.fernet import Fernet def upgrade_encrypted_journal(filename, key_plain): """Decrypts a journal in memory using the jrnl 1.x encryption scheme and returns it in plain text.""" - util.prompt("UPGRADING JOURNAL") - print "UPGRADING SHIT", filename, key_plain with open(filename) as f: iv_cipher = f.read() iv, cipher = iv_cipher[:16], iv_cipher[16:] @@ -27,10 +25,8 @@ def upgrade_encrypted_journal(filename, key_plain): else: unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder() plain = unpadder.update(plain_padded) + unpadder.finalize() - except IndexError: - print "UH NO" + except ValueError: return None - print "PLain", plain key = EncryptedJournal.make_key(key_plain) journal = Fernet(key).encrypt(plain) with open(filename, 'w') as f: @@ -40,17 +36,27 @@ def upgrade_encrypted_journal(filename, key_plain): def upgrade_jrnl_if_necessary(config_path): with open(config_path) as f: - config = f.read() - if not config.strip().startswith("{"): + config_file = f.read() + if not config_file.strip().startswith("{"): return config = util.load_config(config_path) - 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. - If you choose to proceed, you will not be able to use your journals with - older versions of jrnl anymore.""".format(__version__)) + util.prompt("""Welcome to jrnl {}. + +It looks like you've been using an older version of jrnl until now. That's +okay - jrnl will now upgrade your configuration and journal files. Afterwards +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 = {} plain_journals = {} @@ -66,13 +72,14 @@ def upgrade_jrnl_if_necessary(config_path): else: plain_journals[journal] = journal_conf 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(): - util.prompt(" {:20} -> {}".format(journal, path)) + util.prompt(" {:{pad}} -> {}".format(journal, path, pad=longest_journal_name)) 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(): - util.prompt(" {:20} -> {}".format(journal, path)) + util.prompt(" {:{pad}} -> {}".format(journal, path, pad=longest_journal_name)) cont = util.yesno("Continue upgrading jrnl?", default=False) if not cont: @@ -82,3 +89,9 @@ def upgrade_jrnl_if_necessary(config_path): for journal, path in encrypted_journals.items(): util.prompt("Enter password for {} journal (stored in {}).".format(journal, path)) 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))