Fix for new test from develop branch

There was a new test added for re-encrypting a journal. This updates the
refactor to match the old (previously untested) behavior of jrnl.

Co-authored-by: Micah Jerome Ellison <micah.jerome.ellison@gmail.com>
This commit is contained in:
Jonathan Wren 2022-11-05 18:43:39 -07:00
parent 12bcc644d8
commit 33b0de862f
No known key found for this signature in database
6 changed files with 75 additions and 16 deletions

View file

@ -107,13 +107,16 @@ def postconfig_encrypt(
) )
# If journal is encrypted, create new password # If journal is encrypted, create new password
logging.debug("Clearing encryption method...")
if journal.config["encrypt"] is True: if journal.config["encrypt"] is True:
logging.debug("Journal already encrypted. Re-encrypting...") logging.debug("Journal already encrypted. Re-encrypting...")
print(f"Journal {journal.name} is already encrypted. Create a new password.") print(f"Journal {journal.name} is already encrypted. Create a new password.")
journal.encryption_method.clear()
else:
journal.config["encrypt"] = True
journal.encryption_method = None
logging.debug("Clearing encryption method...")
journal.encryption_method = None
journal.config["encrypt"] = True
journal.write(args.filename) journal.write(args.filename)
print_msg( print_msg(

View file

@ -17,6 +17,9 @@ class BaseEncryption(ABC):
self._journal_name: str = journal_name self._journal_name: str = journal_name
self._config: dict = config self._config: dict = config
def clear(self) -> None:
pass
def encrypt(self, text: str) -> bytes: def encrypt(self, text: str) -> bytes:
logging.debug("encrypting") logging.debug("encrypting")
return self._encrypt(text) return self._encrypt(text)

View file

@ -19,30 +19,51 @@ class BasePasswordEncryption(BaseEncryption):
self._attempts: int = 0 self._attempts: int = 0
self._max_attempts: int = 3 self._max_attempts: int = 3
self._password: str = "" self._password: str = ""
self._check_keyring: bool = True
# Check keyring first for password.
# That way we'll have it.
if keyring_pw := get_keyring_password(self._journal_name):
self.password = keyring_pw
@property @property
def password(self) -> str: def check_keyring(self) -> bool:
return self._check_keyring
@check_keyring.setter
def check_keyring(self, value: bool) -> None:
self._check_keyring = value
@property
def password(self) -> str | None:
return self._password return self._password
@password.setter @password.setter
def password(self, value: str) -> None: def password(self, value: str) -> None:
self._password = value self._password = value
def clear(self):
self.password = None
self.check_keyring = False
def encrypt(self, text: str) -> bytes: def encrypt(self, text: str) -> bytes:
logging.debug("encrypting") logging.debug("encrypting")
if not self.password: if not self.password:
self.password = create_password(self._journal_name) if self.check_keyring and (
keyring_pw := get_keyring_password(self._journal_name)
):
self.password = keyring_pw
if not self.password:
self.password = create_password(self._journal_name)
return self._encrypt(text) return self._encrypt(text)
def decrypt(self, text: bytes) -> str: def decrypt(self, text: bytes) -> str:
logging.debug("decrypting") logging.debug("decrypting")
if not self.password: if not self.password:
self._prompt_password() if self.check_keyring and (
keyring_pw := get_keyring_password(self._journal_name)
):
self.password = keyring_pw
if not self.password:
self._prompt_password()
while (result := self._decrypt(text)) is None: while (result := self._decrypt(text)) is None:
self._prompt_password() self._prompt_password()

View file

@ -26,11 +26,15 @@ class Jrnlv2Encryption(BasePasswordEncryption):
return self._password return self._password
@password.setter @password.setter
def password(self, value): def password(self, value: str | None):
self._password = value self._password = value
self._make_key() self._make_key()
def _make_key(self) -> None: def _make_key(self) -> None:
if self._password is None:
# Password was removed after being set
self._key = None
return
password = self.password.encode(self._encoding) password = self.password.encode(self._encoding)
kdf = PBKDF2HMAC( kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(), algorithm=hashes.SHA256(),

View file

@ -48,6 +48,7 @@ Feature: Encrypting and decrypting journals
Scenario: Encrypt journal twice and get prompted each time Scenario: Encrypt journal twice and get prompted each time
Given we use the config "simple.yaml" Given we use the config "simple.yaml"
And we don't have a keyring
When we run "jrnl --encrypt" and enter When we run "jrnl --encrypt" and enter
swordfish swordfish
swordfish swordfish
@ -56,7 +57,26 @@ Feature: Encrypting and decrypting journals
And the output should contain "Journal encrypted" And the output should contain "Journal encrypted"
When we run "jrnl --encrypt" and enter When we run "jrnl --encrypt" and enter
swordfish swordfish
tuna
tuna
y
Then we should get no error
And the output should contain "Journal default is already encrypted. Create a new password."
And we should be prompted for a password
And the config for journal "default" should contain "encrypt: true"
Scenario: Encrypt journal twice and get prompted each time with keyring
Given we use the config "simple.yaml"
And we have a keyring
When we run "jrnl --encrypt" and enter
swordfish swordfish
swordfish
y
Then we should get no error
And the output should contain "Journal encrypted"
When we run "jrnl --encrypt" and enter
tuna
tuna
y y
Then we should get no error Then we should get no error
And the output should contain "Journal default is already encrypted. Create a new password." And the output should contain "Journal default is already encrypted. Create a new password."

View file

@ -17,6 +17,7 @@ from pytest_bdd.parsers import parse
from jrnl import __version__ from jrnl import __version__
from jrnl.time import __get_pdt_calendar from jrnl.time import __get_pdt_calendar
from tests.lib.fixtures import FailedKeyring from tests.lib.fixtures import FailedKeyring
from tests.lib.fixtures import NoKeyring
from tests.lib.fixtures import TestKeyring from tests.lib.fixtures import TestKeyring
from tests.lib.helpers import get_fixture from tests.lib.helpers import get_fixture
@ -67,13 +68,20 @@ def now_is_str(date_str, mock_factories):
) )
@given("we don't have a keyring", target_fixture="keyring")
def we_dont_have_keyring(keyring_type):
return NoKeyring()
@given("we have a keyring", target_fixture="keyring") @given("we have a keyring", target_fixture="keyring")
@given(parse("we have a {keyring_type} keyring"), target_fixture="keyring") @given(parse("we have a {keyring_type} keyring"), target_fixture="keyring")
def we_have_type_of_keyring(keyring_type): def we_have_type_of_keyring(keyring_type):
if keyring_type == "failed": match keyring_type:
return FailedKeyring() case "failed":
else: return FailedKeyring()
return TestKeyring()
case _:
return TestKeyring()
@given(parse('we use the config "{config_file}"'), target_fixture="config_path") @given(parse('we use the config "{config_file}"'), target_fixture="config_path")