From 18ba16ad66aed4eb048840881000de5b599f0c17 Mon Sep 17 00:00:00 2001 From: Greg Bodnar Date: Sat, 3 Aug 2019 16:48:10 +1200 Subject: [PATCH 1/4] Add failing test for configuring an encrypted journal --- features/data/configs/multiple.yaml | 3 +++ features/multiple_journals.feature | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/features/data/configs/multiple.yaml b/features/data/configs/multiple.yaml index 1bbb872f..2e282232 100644 --- a/features/data/configs/multiple.yaml +++ b/features/data/configs/multiple.yaml @@ -9,6 +9,9 @@ journals: ideas: features/journals/nothing.journal simple: features/journals/simple.journal work: features/journals/work.journal + new_encrypted: + encrypt: true + journal: features/journals/new_encrypted.journal linewrap: 80 password: '' tagsymbols: '@' diff --git a/features/multiple_journals.feature b/features/multiple_journals.feature index fb26eef8..af032b03 100644 --- a/features/multiple_journals.feature +++ b/features/multiple_journals.feature @@ -39,3 +39,8 @@ Feature: Multiple journals Given we use the config "bug343.yaml" When we run "jrnl a long day in the office" Then we should see the message "No default journal configured" + + 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" + Then journal "new_encrypted" should have 1 entry From da62e542458dd12e8de0e0d45d73e23b5c14d6be Mon Sep 17 00:00:00 2001 From: Greg Bodnar Date: Sun, 4 Aug 2019 08:40:15 +1200 Subject: [PATCH 2/4] Overload open for EncryptedJournal This avoids the execution path that calls EncryptedJournal._create() without a password parameter. It results in duplication of code that requests and stores a password, which should be factored out in a subsequent change. --- jrnl/EncryptedJournal.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/jrnl/EncryptedJournal.py b/jrnl/EncryptedJournal.py index a29db554..9a1822e0 100644 --- a/jrnl/EncryptedJournal.py +++ b/jrnl/EncryptedJournal.py @@ -5,7 +5,13 @@ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes import hashlib from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from cryptography.hazmat.backends import default_backend +import sys +import os import base64 +import getpass +import logging + +log = logging.getLogger() def make_key(password): @@ -27,6 +33,33 @@ class EncryptedJournal(Journal.Journal): super(EncryptedJournal, self).__init__(name, **kwargs) self.config['encrypt'] = True + def open(self, filename=None): + """Opens the journal file defined in the config and parses it into a list of Entries. + Entries have the form (date, title, body).""" + filename = filename or self.config['journal'] + + if not os.path.exists(filename): + password = getpass.getpass("Enter password for new journal: ") + if password: + if util.yesno("Do you want to store the password in your keychain?", default=True): + util.set_keychain(self.name, password) + else: + util.set_keychain(self.name, None) + self.config['password'] = password + text = "" + self._store(filename, text) + util.prompt("[Journal '{0}' created at {1}]".format(self.name, filename)) + else: + util.prompt("No password supplied for encrypted journal") + sys.exit(1) + else: + text = self._load(filename) + self.entries = self._parse(text) + self.sort() + log.debug("opened %s with %d entries", self.__class__.__name__, len(self)) + return self + + 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 From 02f853b5455f51d3196c718846c2e2bd0af9561e Mon Sep 17 00:00:00 2001 From: Greg Bodnar Date: Sun, 4 Aug 2019 08:44:17 +1200 Subject: [PATCH 3/4] Modify test to test for returned strings The entered string for the password is not being used by the test and I don't understand why. --- features/multiple_journals.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/multiple_journals.feature b/features/multiple_journals.feature index af032b03..1d4943ee 100644 --- a/features/multiple_journals.feature +++ b/features/multiple_journals.feature @@ -42,5 +42,5 @@ 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" - Then journal "new_encrypted" should have 1 entry + When we run "jrnl new_encrypted Adding first entry" and enter "these three eyes" + Then we should see the message "Journal 'new_encrypted' created" From 290bb96daab4d71713286aeb68a49e6ad17e32e3 Mon Sep 17 00:00:00 2001 From: Greg Bodnar Date: Sun, 4 Aug 2019 13:21:40 +1200 Subject: [PATCH 4/4] Use util wrapper for getpass This allows for tests to run without prompting for user input. --- jrnl/EncryptedJournal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jrnl/EncryptedJournal.py b/jrnl/EncryptedJournal.py index 9a1822e0..a83651e4 100644 --- a/jrnl/EncryptedJournal.py +++ b/jrnl/EncryptedJournal.py @@ -39,7 +39,7 @@ class EncryptedJournal(Journal.Journal): filename = filename or self.config['journal'] if not os.path.exists(filename): - password = getpass.getpass("Enter password for new journal: ") + password = util.getpass("Enter password for new journal: ") if password: if util.yesno("Do you want to store the password in your keychain?", default=True): util.set_keychain(self.name, password)