Skip to content

Commit

Permalink
split keys.reset into keys.reset and keys.reset_and_delete_keys
Browse files Browse the repository at this point in the history
  • Loading branch information
erikvw committed Mar 19, 2024
1 parent ef959bb commit 23471d7
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 64 deletions.
57 changes: 31 additions & 26 deletions django_crypto_fields/keys/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def __init__(self, verbose: bool = None):
self.aes_modes_supported = None
self.path = KeyPath().path
self.template = get_template(self.path, self.key_prefix)
self.files = get_filenames(self.path, self.key_prefix)
self.filenames = get_filenames(self.path, self.key_prefix)
self.initialize()

def initialize(self):
Expand Down Expand Up @@ -78,20 +78,22 @@ def initialize(self):
self.load_keys()
self.rsa_modes_supported = sorted([k for k in self.keys[RSA]])
self.aes_modes_supported = sorted([k for k in self.keys[AES]])
write_msg(self.verbose, " Done loading encryption keys\n")

def reset(self, delete_all_keys: str = None, verbose: bool = None):
"""Use with extreme care!"""
verbose = self.verbose if verbose is None else verbose
def reset(self):
"""For use in tests."""
self.keys = deepcopy(self.template)
self.loaded = False
if delete_all_keys == "delete_all_keys":
write_msg(verbose, style.ERROR(" * Deleting encryption keys\n"))
for file in encryption_keys.files:
try:
Path(file).unlink()
except FileNotFoundError:
pass

def reset_and_delete_keys(self, verbose: bool | None = None):
"""For use in tests.
Use with extreme care!
"""
verbose = self.verbose if verbose is None else verbose
self.reset()
write_msg(verbose, style.ERROR(" * Deleting encryption keys\n"))
for filename in self.filenames:
Path(filename).unlink(missing_ok=True)

def get(self, k: str):
return self.keys.get(k)
Expand All @@ -106,13 +108,15 @@ def create(self) -> None:
self._create_rsa()
self._create_aes()
self._create_salt()
write_msg(self.verbose, " Done generating new encryption keys.\n")
write_msg(self.verbose, f" Your new encryption keys are in {self.path}.\n")
write_msg(self.verbose, style.ERROR(" DON'T FORGET TO BACKUP YOUR NEW KEYS!!\n"))
write_msg(self.verbose, f" Your new encryption keys are in {self.path}.\n")
write_msg(self.verbose, style.ERROR(" DON'T FORGET TO BACKUP YOUR NEW KEYS!!\n"))
write_msg(self.verbose, " Done generating new encryption keys.\n")

def load_keys(self) -> None:
"""Loads all keys defined in self.filenames."""
write_msg(self.verbose, f" * loading keys from {self.path}\n")
write_msg(
self.verbose, style.WARNING(f" * Loading encryption keys from {self.path}\n")
)
if self.loaded:
raise DjangoCryptoFieldsKeysAlreadyLoaded(
f"Encryption keys have already been loaded. Path='{self.path}'."
Expand All @@ -121,20 +125,21 @@ def load_keys(self) -> None:
self.load_aes_keys()
self.load_salt_keys()
self.loaded = True
write_msg(self.verbose, " Done loading encryption keys\n")

def load_rsa_keys(self) -> None:
"""Loads RSA keys into _keys."""
for access_mode, keys in self.keys[RSA].items():
for key in keys:
write_msg(self.verbose, f" * loading {RSA}.{access_mode}.{key} ...\r")
write_msg(self.verbose, f" - loading {RSA}.{access_mode}.{key} ...\r")
path = Path(self.keys[RSA][access_mode][key])
with path.open(mode="rb") as f:
rsa_key = RSA_PUBLIC_KEY.importKey(f.read())
rsa_key = PKCS1_OAEP.new(rsa_key)
self.keys[RSA][access_mode][key] = rsa_key
self.update_rsa_key_info(rsa_key, access_mode)
setattr(self, RSA + "_" + access_mode + "_" + key + "_key", rsa_key)
write_msg(self.verbose, f" * loading {RSA}.{access_mode}.{key} ... Done.\n")
write_msg(self.verbose, f" - loading {RSA}.{access_mode}.{key} ... Done.\n")

def load_aes_keys(self) -> None:
"""Decrypts and loads AES keys into _keys.
Expand All @@ -143,7 +148,7 @@ def load_aes_keys(self) -> None:
"""
key = PRIVATE
for access_mode in self.keys[AES]:
write_msg(self.verbose, f" * loading {AES}.{access_mode} ...\r")
write_msg(self.verbose, f" - loading {AES}.{access_mode} ...\r")
rsa_key = self.keys[RSA][access_mode][key]
try:
path = Path(self.keys[AES][access_mode][key])
Expand All @@ -153,19 +158,19 @@ def load_aes_keys(self) -> None:
aes_key = rsa_key.decrypt(f.read())
self.keys[AES][access_mode][key] = aes_key
setattr(self, AES + "_" + access_mode + "_" + key + "_key", aes_key)
write_msg(self.verbose, f" * loading {AES}.{access_mode} ... Done.\n")
write_msg(self.verbose, f" - loading {AES}.{access_mode} ... Done.\n")

def load_salt_keys(self) -> None:
"""Decrypts and loads salt keys into _keys."""
for access_mode in self.keys[SALT]:
write_msg(self.verbose, f" * loading {SALT}.{access_mode} ...\r")
write_msg(self.verbose, f" - loading {SALT}.{access_mode} ...\r")
attr = SALT + "_" + access_mode + "_" + PRIVATE
rsa_key = self.keys[RSA][access_mode][PRIVATE]
path = Path(self.keys[SALT][access_mode][PRIVATE])
with path.open(mode="rb") as f:
salt = rsa_key.decrypt(f.read())
setattr(self, attr, salt)
write_msg(self.verbose, f" * loading {SALT}.{access_mode} ... Done.\n")
write_msg(self.verbose, f" - loading {SALT}.{access_mode} ... Done.\n")

def update_rsa_key_info(self, rsa_key, access_mode: str) -> None:
"""Stores info about the RSA key."""
Expand All @@ -189,11 +194,11 @@ def _create_rsa(self) -> None:
try:
with path.open(mode="xb") as f1:
f1.write(pub.exportKey("PEM"))
write_msg(self.verbose, f" - Created new RSA {access_mode} key {path}\n")
write_msg(self.verbose, f" - Created new RSA {access_mode} key {path}\n")
path = Path(self.keys.get(RSA).get(access_mode).get(PRIVATE))
with open(path, "xb") as f2:
f2.write(key.exportKey("PEM"))
write_msg(self.verbose, f" - Created new RSA {access_mode} key {path}\n")
write_msg(self.verbose, f" - Created new RSA {access_mode} key {path}\n")
except FileExistsError as e:
raise DjangoCryptoFieldsKeyError(f"RSA key already exists. Got {e}")

Expand All @@ -207,7 +212,7 @@ def _create_aes(self) -> None:
path = Path(self.keys.get(AES).get(access_mode).get(PRIVATE))
with path.open(mode="xb") as f:
f.write(rsa_key.encrypt(aes_key))
write_msg(self.verbose, f" - Created new AES {access_mode} key {path}\n")
write_msg(self.verbose, f" - Created new AES {access_mode} key {path}\n")

def _create_salt(self) -> None:
"""Creates a salt and RSA encrypts it."""
Expand All @@ -219,7 +224,7 @@ def _create_salt(self) -> None:
path = Path(self.keys.get(SALT).get(access_mode).get(PRIVATE))
with path.open(mode="xb") as f:
f.write(rsa_key.encrypt(salt))
write_msg(self.verbose, f" - Created new salt {access_mode} key {path}\n")
write_msg(self.verbose, f" - Created new salt {access_mode} key {path}\n")


encryption_keys = Keys()
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
path,date
/Users/erikvw/source/edc_source/django-crypto-fields/django_crypto_fields/tests/crypto_keys,2024-03-19 02:51:34.544731+00:00
/Users/erikvw/source/edc_source/django-crypto-fields/django_crypto_fields/tests/crypto_keys,2024-03-19 03:29:04.747127+00:00
10 changes: 2 additions & 8 deletions django_crypto_fields/tests/tests/test_cryptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,12 @@

class TestCryptor(TestCase):
def setUp(self):
try:
encryption_keys.reset(delete_all_keys="delete_all_keys", verbose=False)
except FileNotFoundError:
pass
encryption_keys.reset_and_delete_keys(verbose=False)
encryption_keys.verbose = False
encryption_keys.initialize()

def tearDown(self):
try:
encryption_keys.reset(delete_all_keys="delete_all_keys", verbose=False)
except FileNotFoundError:
pass
encryption_keys.reset_and_delete_keys(verbose=False)

def test_mode_support(self):
self.assertEqual(encryption_keys.rsa_modes_supported, [LOCAL_MODE, RESTRICTED_MODE])
Expand Down
10 changes: 2 additions & 8 deletions django_crypto_fields/tests/tests/test_field_cryptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,12 @@

class TestFieldCryptor(TestCase):
def setUp(self):
try:
encryption_keys.reset(delete_all_keys="delete_all_keys", verbose=False)
except FileNotFoundError:
pass
encryption_keys.reset_and_delete_keys(verbose=False)
encryption_keys.verbose = False
encryption_keys.initialize()

def tearDown(self):
try:
encryption_keys.reset(delete_all_keys="delete_all_keys", verbose=False)
except FileNotFoundError:
pass
encryption_keys.reset_and_delete_keys(verbose=False)

def test_can_verify_hash_as_none(self):
field_cryptor = FieldCryptor(RSA, LOCAL_MODE)
Expand Down
20 changes: 7 additions & 13 deletions django_crypto_fields/tests/tests/test_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,26 @@

class TestKeyCreator(TestCase):
def setUp(self):
try:
encryption_keys.reset(delete_all_keys="delete_all_keys", verbose=False)
except FileNotFoundError:
pass
encryption_keys.reset_and_delete_keys(verbose=False)
encryption_keys.verbose = False
encryption_keys.initialize()

def tearDown(self):
try:
encryption_keys.reset(delete_all_keys="delete_all_keys", verbose=False)
except FileNotFoundError:
pass
encryption_keys.reset_and_delete_keys(verbose=False)

@override_settings(DJANGO_CRYPTO_FIELDS_KEY_PATH=mkdtemp())
def test_keys_do_not_exist(self):
encryption_keys.verbose = False
encryption_keys.reset(delete_all_keys="delete_all_keys")
for file in encryption_keys.files:
encryption_keys.reset_and_delete_keys()
for file in encryption_keys.filenames:
self.assertFalse(Path(file).exists())

@override_settings(DJANGO_CRYPTO_FIELDS_KEY_PATH=mkdtemp())
def test_keys_exist(self):
encryption_keys.reset(delete_all_keys="delete_all_keys", verbose=False)
encryption_keys.reset_and_delete_keys(verbose=False)
encryption_keys.verbose = False
encryption_keys.initialize()
for file in encryption_keys.files:
for file in encryption_keys.filenames:
self.assertTrue(Path(file).exists())

@override_settings(DEBUG=False, DJANGO_CRYPTO_FIELDS_KEY_PATH="/blah/blah/blah/blah")
Expand Down Expand Up @@ -79,7 +73,7 @@ def test_invalid_production_path_raises(self):
)
def test_create_keys_does_not_overwrite_production_keys(self):
keys = Keys(verbose=False)
keys.reset(verbose=False)
keys.reset()
self.assertRaises(DjangoCryptoFieldsKeyAlreadyExist, keys.create)

@override_settings(
Expand Down
10 changes: 2 additions & 8 deletions django_crypto_fields/tests/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,12 @@
class TestModels(TestCase):

def setUp(self):
try:
encryption_keys.reset(delete_all_keys="delete_all_keys", verbose=False)
except FileNotFoundError:
pass
encryption_keys.reset_and_delete_keys(verbose=False)
encryption_keys.verbose = False
encryption_keys.initialize()

def tearDown(self):
try:
encryption_keys.reset(delete_all_keys="delete_all_keys", verbose=False)
except FileNotFoundError:
pass
encryption_keys.reset_and_delete_keys(verbose=False)

def test_encrypt_rsa(self):
"""Assert deconstruct."""
Expand Down

0 comments on commit 23471d7

Please sign in to comment.