From b19f18063980430875efcb14b129af4595c8a691 Mon Sep 17 00:00:00 2001 From: Peter Schmidbauer Date: Wed, 30 Oct 2019 21:27:23 +0100 Subject: [PATCH] add password confirmation dialog --- features/encryption.feature | 18 ++++++++++++++---- features/multiple_journals.feature | 7 ++++++- features/steps/core.py | 4 ++-- jrnl/EncryptedJournal.py | 2 +- jrnl/Journal.py | 2 +- jrnl/cli.py | 8 ++++---- jrnl/install.py | 4 ++-- jrnl/plugins/jrnl_importer.py | 2 +- jrnl/upgrade.py | 4 ++-- jrnl/util.py | 12 +++++++++--- 10 files changed, 42 insertions(+), 21 deletions(-) diff --git a/features/encryption.feature b/features/encryption.feature index e4b1cf01..e4b9a1e4 100644 --- a/features/encryption.feature +++ b/features/encryption.feature @@ -9,13 +9,18 @@ Given we use the config "encrypted.yaml" When we run "jrnl --decrypt" and enter "bad doggie no biscuit" Then the config for journal "default" should have "encrypt" set to "bool:False" - Then the output should contain "Journal decrypted" + Then we should see the message "Journal decrypted" and the journal should have 2 entries Scenario: Encrypting a journal Given we use the config "basic.yaml" - When we run "jrnl --encrypt" and enter "swordfish" and "n" - Then the output should contain "Journal encrypted" + When we run "jrnl --encrypt" and enter + """ + swordfish + swordfish + n + """ + Then we should see the message "Journal encrypted" and the config for journal "default" should have "encrypt" set to "bool:True" When we run "jrnl -n 1" and enter "swordfish" Then the output should contain "Password" @@ -23,7 +28,12 @@ Scenario: Storing a password in Keychain Given we use the config "multiple.yaml" - When we run "jrnl simple --encrypt" and enter "sabertooth" and "y" + When we run "jrnl simple --encrypt" and enter + """ + sabertooth + sabertooth + n + """ When we set the keychain password of "simple" to "sabertooth" Then the config for journal "simple" should have "encrypt" set to "bool:True" When we run "jrnl simple -n 1" diff --git a/features/multiple_journals.feature b/features/multiple_journals.feature index 1d4943ee..56c4b3a7 100644 --- a/features/multiple_journals.feature +++ b/features/multiple_journals.feature @@ -42,5 +42,10 @@ Feature: Multiple journals Scenario: Don't crash if no file exists for a configured encrypted journal Given we use the config "multiple.yaml" - When we run "jrnl new_encrypted Adding first entry" and enter "these three eyes" + When we run "jrnl new_encrypted Adding first entry" and enter + """ + these three eyes + these three eyes + n + """ Then we should see the message "Journal 'new_encrypted' created" diff --git a/features/steps/core.py b/features/steps/core.py index 943b7f40..d4e875ee 100644 --- a/features/steps/core.py +++ b/features/steps/core.py @@ -28,7 +28,7 @@ class TestKeyring(keyring.backend.KeyringBackend): def get_password(self, servicename, username): return self.keys[servicename].get(username) - def delete_password(self, servicename, username, password): + def delete_password(self, servicename, username): self.keys[servicename][username] = None @@ -93,7 +93,7 @@ def run_with_input(context, command, inputs1="", inputs2=""): text = iter((inputs1, inputs2)) if inputs1 else iter(context.text.split("\n")) args = ushlex(command)[1:] with patch("builtins.input", side_effect=_mock_input(text)) as mock_input: - with patch("jrnl.util.getpass", side_effect=_mock_getpass(text)) as mock_getpass: + with patch("jrnl.util.gp.getpass", side_effect=_mock_getpass(text)) as mock_getpass: with patch("sys.stdin.read", side_effect=text) as mock_read: try: cli.run(args or []) diff --git a/jrnl/EncryptedJournal.py b/jrnl/EncryptedJournal.py index 67345f45..525adc51 100644 --- a/jrnl/EncryptedJournal.py +++ b/jrnl/EncryptedJournal.py @@ -38,7 +38,7 @@ class EncryptedJournal(Journal.Journal): filename = filename or self.config['journal'] if not os.path.exists(filename): - password = util.getpass("Enter password for new journal: ") + password = util.create_password() if password: if util.yesno("Do you want to store the password in your keychain?", default=True): util.set_keychain(self.name, password) diff --git a/jrnl/Journal.py b/jrnl/Journal.py index 4b3f019d..35ae801e 100644 --- a/jrnl/Journal.py +++ b/jrnl/Journal.py @@ -71,7 +71,7 @@ class Journal: filename = filename or self.config['journal'] if not os.path.exists(filename): - print("[Journal '{0}' created at {1}]".format(self.name, filename)) + print("[Journal '{0}' created at {1}]".format(self.name, filename), file=sys.stderr) self._create(filename) text = self._load(filename) diff --git a/jrnl/cli.py b/jrnl/cli.py index ab9176ce..93d0aa66 100644 --- a/jrnl/cli.py +++ b/jrnl/cli.py @@ -79,7 +79,7 @@ def encrypt(journal, filename=None): """ Encrypt into new file. If filename is not set, we encrypt the journal file itself. """ from . import EncryptedJournal - journal.config['password'] = util.getpass("Enter new password: ") + journal.config['password'] = util.create_password() journal.config['encrypt'] = True new_journal = EncryptedJournal.EncryptedJournal(None, **journal.config) @@ -89,7 +89,7 @@ def encrypt(journal, filename=None): if util.yesno("Do you want to store the password in your keychain?", default=True): util.set_keychain(journal.name, journal.config['password']) - print("Journal encrypted to {0}.".format(filename or new_journal.config['journal'])) + print("Journal encrypted to {0}.".format(filename or new_journal.config['journal']), file=sys.stderr) def decrypt(journal, filename=None): @@ -100,7 +100,7 @@ def decrypt(journal, filename=None): new_journal = Journal.PlainJournal(filename, **journal.config) new_journal.entries = journal.entries new_journal.write(filename) - print("Journal decrypted to {0}.".format(filename or new_journal.config['journal'])) + print("Journal decrypted to {0}.".format(filename or new_journal.config['journal']), file=sys.stderr) def list_journals(config): @@ -199,7 +199,7 @@ def run(manual_args=None): raw = util.get_text_from_editor(config, template) else: try: - print("[Compose Entry; " + _exit_multiline_code + " to finish writing]\n") + print("[Compose Entry; " + _exit_multiline_code + " to finish writing]\n", file=sys.stderr) raw = sys.stdin.read() except KeyboardInterrupt: print("[Entry NOT saved to journal.]", file=sys.stderr) diff --git a/jrnl/install.py b/jrnl/install.py index defb7cee..08bb44dd 100644 --- a/jrnl/install.py +++ b/jrnl/install.py @@ -69,7 +69,7 @@ def upgrade_config(config): for key in missing_keys: config[key] = default_config[key] save_config(config) - print("[Configuration updated to newest version at {}]".format(CONFIG_FILE_PATH)) + print("[Configuration updated to newest version at {}]".format(CONFIG_FILE_PATH), file=sys.stderr) def save_config(config): @@ -139,7 +139,7 @@ def install(): else: util.set_keychain("default", None) EncryptedJournal._create(default_config['journals']['default'], password) - print("Journal will be encrypted.") + print("Journal will be encrypted.", file=sys.stderr) else: PlainJournal._create(default_config['journals']['default']) diff --git a/jrnl/plugins/jrnl_importer.py b/jrnl/plugins/jrnl_importer.py index a5b41049..1015c262 100644 --- a/jrnl/plugins/jrnl_importer.py +++ b/jrnl/plugins/jrnl_importer.py @@ -26,5 +26,5 @@ class JRNLImporter: sys.exit(0) journal.import_(other_journal_txt) new_cnt = len(journal.entries) - print("[{0} imported to {1} journal]".format(new_cnt - old_cnt, journal.name)) + print("[{0} imported to {1} journal]".format(new_cnt - old_cnt, journal.name), file=sys.stderr) journal.write() diff --git a/jrnl/upgrade.py b/jrnl/upgrade.py index f9452e03..1c9733c6 100644 --- a/jrnl/upgrade.py +++ b/jrnl/upgrade.py @@ -111,10 +111,10 @@ older versions of jrnl anymore. for j in all_journals: j.write() - print("\nUpgrading config...") + print("\nUpgrading config...", file=sys.stderr) backup(config_path) - print("\nWe're all done here and you can start enjoying jrnl 2.".format(config_path)) + print("\nWe're all done here and you can start enjoying jrnl 2.".format(config_path), file=sys.stderr) class UpgradeValidationException(Exception): """Raised when the contents of an upgraded journal do not match the old journal""" diff --git a/jrnl/util.py b/jrnl/util.py index 23e345cc..af050d8f 100644 --- a/jrnl/util.py +++ b/jrnl/util.py @@ -39,12 +39,18 @@ class UserAbort(Exception): pass -getpass = gp.getpass +def create_password(): + while True: + pw = gp.getpass("Enter password for new journal: ") + if pw == gp.getpass("Enter password again: "): + return pw + + gp.getpass("Passwords did not match, please try again") def get_password(validator, keychain=None, max_attempts=3): pwd_from_keychain = keychain and get_keychain(keychain) - password = pwd_from_keychain or getpass() + password = pwd_from_keychain or gp.getpass() result = validator(password) # Password is bad: if result is None and pwd_from_keychain: @@ -52,7 +58,7 @@ def get_password(validator, keychain=None, max_attempts=3): attempt = 1 while result is None and attempt < max_attempts: print("Wrong password, try again.", file=sys.stderr) - password = getpass() + password = gp.getpass() result = validator(password) attempt += 1 if result is not None: