jrnl/jrnl/encryption/BasePasswordEncryption.py
Jonathan Wren fcc8d8e3fa
Rework Encryption to enable future support of other encryption methods (#1602)
- initial pass through to rework encryption into separate module
- little more cleanup
- rename function, fix some linting issues
- more cleaning
- fix password bug in encryption
- fix linting issue
- more cleanup
- move prompt into prompt.py
- more cleanup
- update the upgrade process for new encryption classes
- general cleanup
- turn into enum instead of strings
- store status code so tests don't fail
- standardize the load and store methods in journals
- get rid of old PlainJournal class
- typing cleanup
- more cleanup
- format
- fix linting issue
- Fix obscure Windows line ending issue with decode
  See https://bugs.python.org/issue40863
- fix for python 3.11
- add more typing
- don't use class variables because that's not what we want
- fix more type hints
- jrnlv1 encryption doesn't support encryption anymore (it's deprecated)
- keep logic for password attemps inside the class that uses it
- take out old line of code
- add some more logging
- update logging statements
- clean up logging statements
- run linters
- fix typo
- 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>
2022-11-19 13:39:39 -08:00

81 lines
2.4 KiB
Python

# Copyright © 2012-2022 jrnl contributors
# License: https://www.gnu.org/licenses/gpl-3.0.html
import logging
from jrnl.encryption.BaseEncryption import BaseEncryption
from jrnl.exception import JrnlException
from jrnl.keyring import get_keyring_password
from jrnl.messages import Message
from jrnl.messages import MsgStyle
from jrnl.messages import MsgText
from jrnl.prompt import create_password
from jrnl.prompt import prompt_password
class BasePasswordEncryption(BaseEncryption):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
logging.debug("start")
self._attempts: int = 0
self._max_attempts: int = 3
self._password: str = ""
self._check_keyring: bool = True
@property
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
@password.setter
def password(self, value: str) -> None:
self._password = value
def clear(self):
self.password = None
self.check_keyring = False
def encrypt(self, text: str) -> bytes:
logging.debug("encrypting")
if not self.password:
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)
def decrypt(self, text: bytes) -> str:
logging.debug("decrypting")
if not self.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:
self._prompt_password()
return result
def _prompt_password(self) -> None:
if self._attempts >= self._max_attempts:
raise JrnlException(
Message(MsgText.PasswordMaxTriesExceeded, MsgStyle.ERROR)
)
first_try = self._attempts == 0
self.password = prompt_password(first_try=first_try)
self._attempts += 1