Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ DJANGO_SETTINGS_MODULE=testproject.settings
STRIPE_SECRET_KEY="123"
STRIPE_WEBHOOK_SECRET="321"
BA_API_KEY_REQUEST_HEADER="HTTP_API_KEY"
# Dummy key for local development - generate real key with: python manage.py api_key --model baseapp_api_key.APIKey --generate_encryption_key
BA_API_KEY_ENCRYPTION_KEY="jCe8USiQJDatFT5T0WCIl86QBxYs0-Q7iDJQc77Dh7LR1VAnWW3PA9UyXK-V7LhFnKq9sLd3xDw5FTrrYYtj2Q=="
14 changes: 9 additions & 5 deletions baseapp_api_key/managers.py
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a ImproperlyConfigured exception would be more appropriate

Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ def encrypt(self, unencrypted_value: str | bytes, encryption_key: str | None = N
else:
raise TypeError("unencrypted_value must be str or bytes")

if not isinstance(encryption_key, str):
encryption_key = settings.BA_API_KEY_ENCRYPTION_KEY
encryption_key = self._get_encryption_key(encryption_key)
aessiv = AESSIV(base64.urlsafe_b64decode(encryption_key))
associated_data = []

Expand All @@ -87,9 +86,7 @@ def decrypt(self, encrypted_value: bytes, encryption_key: str | None = None) ->
Returns:
bytes: The decrypted value as str.
"""

if not isinstance(encryption_key, str):
encryption_key = settings.BA_API_KEY_ENCRYPTION_KEY
encryption_key = self._get_encryption_key(encryption_key)
aessiv = AESSIV(base64.urlsafe_b64decode(encryption_key))
associated_data = []

Expand Down Expand Up @@ -118,3 +115,10 @@ def rotate_encryption_key(self, encryption_key_old: str, encryption_key_new: str

def get_queryset(self, *args, **kwargs) -> models.QuerySet:
return super().get_queryset(*args, **kwargs).add_is_expired()

def _get_encryption_key(self, encryption_key: str | None = None) -> str:
if not isinstance(encryption_key, str):
if not settings.BA_API_KEY_ENCRYPTION_KEY:
raise ValueError("BA_API_KEY_ENCRYPTION_KEY is not set")
encryption_key = settings.BA_API_KEY_ENCRYPTION_KEY
return encryption_key
25 changes: 25 additions & 0 deletions baseapp_api_key/tests/unit/test_api_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,31 @@ def test_can_rotate_encryption_key(self):
):
APIKey.objects.decrypt(encrypted_value=api_key.encrypted_api_key)

def test_encrypt_raises_if_encryption_key_not_set(self):
with override_settings(BA_API_KEY_ENCRYPTION_KEY=None):
with self.assertRaises(ValueError) as excinfo:
APIKey.objects.encrypt("some-value")
assert "BA_API_KEY_ENCRYPTION_KEY is not set" in str(excinfo.exception)

def test_decrypt_raises_if_encryption_key_not_set(self):
with override_settings(BA_API_KEY_ENCRYPTION_KEY=None):
with self.assertRaises(ValueError) as excinfo:
APIKey.objects.decrypt(b"00")
assert "BA_API_KEY_ENCRYPTION_KEY is not set" in str(excinfo.exception)

def test_rotate_encryption_key_raises_if_encryption_key_not_set(self):
with override_settings(
BA_API_KEY_ENCRYPTION_KEY="jCe8USiQJDatFT5T0WCIl86QBxYs0-Q7iDJQc77Dh7LR1VAnWW3PA9UyXK-V7LhFnKq9sLd3xDw5FTrrYYtj2Q=="
):
f.APIKeyFactory()
with override_settings(BA_API_KEY_ENCRYPTION_KEY=None):
with self.assertRaises(ValueError) as excinfo:
APIKey.objects.rotate_encryption_key(
encryption_key_old=None,
encryption_key_new=None,
)
assert "BA_API_KEY_ENCRYPTION_KEY is not set" in str(excinfo.exception)


class TestAPIKeyAuthentication(APITestCase, URLPatternsTestCase):
class DummyViewSet(viewsets.GenericViewSet):
Expand Down
4 changes: 2 additions & 2 deletions testproject/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@
BASEAPP_REACTIONS_ENABLE_NOTIFICATIONS = False

# API Key
BA_API_KEY_REQUEST_HEADER = env("BA_API_KEY_REQUEST_HEADER")
BA_API_KEY_ENCRYPTION_KEY = env("BA_API_KEY_ENCRYPTION_KEY")
BA_API_KEY_REQUEST_HEADER = env("BA_API_KEY_REQUEST_HEADER", default="HTTP_API_KEY")
BA_API_KEY_ENCRYPTION_KEY = env("BA_API_KEY_ENCRYPTION_KEY", default=None)

# Graphene query optimizer
GRAPHQL_QUERY_OPTIMIZER = {
Expand Down
Loading