Skip to content

Commit

Permalink
linting
Browse files Browse the repository at this point in the history
  • Loading branch information
vegu committed Sep 18, 2024
1 parent 2136aa9 commit b0e78f9
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 36 deletions.
4 changes: 1 addition & 3 deletions src/django_security_keys/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ def authenticate(
if not username or not credential:
return

has_credentials = SecurityKey.credentials(
username, for_login=True
)
has_credentials = SecurityKey.credentials(username, for_login=True)

# no credential supplied

Expand Down
19 changes: 10 additions & 9 deletions src/django_security_keys/ext/two_factor/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import json
import time
from typing import Any

Expand All @@ -10,12 +11,13 @@
from django.http.response import HttpResponse, HttpResponseRedirect
from django.template.response import TemplateResponse
from django.views.generic import FormView
from webauthn.helpers import base64url_to_bytes

from django_security_keys.ext.two_factor import forms
from django_security_keys.ext.two_factor.forms import SecurityKeyDeviceValidation
from django_security_keys.models import SecurityKey, SecurityKeyDevice, UserHandle
import json
from webauthn.helpers import base64url_to_bytes


class DisableView(two_factor.views.DisableView):
def dispatch(self, *args: Any, **kwargs: Any) -> HttpResponse:
self.success_url = "/"
Expand All @@ -37,10 +39,7 @@ def has_security_key_step(self) -> bool:
if token_step_data:
return False

return (
len(SecurityKey.credentials(self.get_user().username))
> 0
)
return len(SecurityKey.credentials(self.get_user().username)) > 0

condition_dict = {
"backup": two_factor.views.LoginView.has_backup_step,
Expand Down Expand Up @@ -74,10 +73,12 @@ def attempt_passkey_auth(
try:
credential = request.POST.get("credential")
try:
user_handle = base64url_to_bytes(json.loads(credential)['response']['userHandle']).decode('utf-8')
user_handle = base64url_to_bytes(
json.loads(credential)["response"]["userHandle"]
).decode("utf-8")
username = UserHandle.objects.get(handle=user_handle).user.username
except:
raise Exception("Failed login using passkey")
except Exception as exc:
raise Exception(f"Failed login using passkey: {exc}")
# support passkey login using webauthn
if username and credential:
user = authenticate(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
from django.db import migrations, models


def migrate_passwordless_login_to_passkey_login(apps, schema_editor):
model = apps.get_model("django_security_keys", "SecurityKey")
try:
model._meta.get_field("updated").auto_now = False
for key in model.objects.all():
key.passkey_login = key.passwordless_login
key.save(update_fields=['passkey_login'])
key.save(update_fields=["passkey_login"])
finally:
model._meta.get_field("updated").auto_now = False


class Migration(migrations.Migration):

dependencies = [
Expand Down
24 changes: 14 additions & 10 deletions src/django_security_keys/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,14 +197,16 @@ def generate_registration(cls, user: User, session: SessionStore) -> str:
- `str` JSON string
"""
existing_credentials = SecurityKey.credentials(user.username,ignore_credential_filter=True)
existing_credentials = SecurityKey.credentials(
user.username, ignore_credential_filter=True
)
opts = webauthn.generate_registration_options(
rp_id=settings.WEBAUTHN_RP_ID,
rp_name=settings.WEBAUTHN_RP_NAME,
user_id=UserHandle.require_for_user(user).handle,
user_name=user.username,
attestation=getattr(settings, "WEBAUTHN_ATTESTATION", "none"),
exclude_credentials=existing_credentials
exclude_credentials=existing_credentials,
)

cls.set_challenge(session, opts.challenge)
Expand Down Expand Up @@ -282,10 +284,12 @@ def verify_registration(
SecurityKeyDevice.require_for_user(user)
return key


@classmethod
def credentials(
cls, username: User | str, for_login: bool = False, ignore_credential_filter = False
cls,
username: User | str,
for_login: bool = False,
ignore_credential_filter=False,
) -> list[PublicKeyCredentialDescriptor]:
"""
Returns a list of credentials for the specified username
Expand All @@ -305,8 +309,8 @@ def credentials(
"""

qset = cls.objects.filter(user__username=username)
# ignore credential_filter to get all credentials data
# example: used for excludeCredentials to prevent duplication of keys in 1 account in the same key
# ignore credential_filter to get all credentials data
# example: used for excludeCredentials to prevent duplication of keys in 1 account in the same key
if not ignore_credential_filter:
# if to be used for passkey login, exclude
# credentials that are not enabled for that.
Expand Down Expand Up @@ -338,12 +342,12 @@ def generate_authentication(
- `str` JSON
"""
options = {
"rp_id":settings.WEBAUTHN_RP_ID,
"rp_id": settings.WEBAUTHN_RP_ID,
}
if not for_login:
options.update({
"allow_credentials":cls.credentials(username, for_login=for_login)
})
options.update(
{"allow_credentials": cls.credentials(username, for_login=for_login)}
)
opts = webauthn.generate_authentication_options(**options)
cls.set_challenge(session, opts.challenge)
return webauthn.options_to_json(opts)
Expand Down
15 changes: 9 additions & 6 deletions src/django_security_keys/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import json
import traceback
from typing import Any

from django.conf import settings
Expand All @@ -14,11 +15,12 @@
from django.urls import reverse
from django.utils.http import url_has_allowed_host_and_scheme
from django.utils.translation import gettext_lazy as _
from webauthn.helpers import base64url_to_bytes

from django_security_keys.forms import LoginForm, RegisterKeyForm
from django_security_keys.models import SecurityKey, UserHandle
from django_security_keys.utils import convert_to_bool
from webauthn.helpers import base64url_to_bytes


def basic_logout(request: WSGIRequest) -> HttpResponseRedirect:
"""
Expand Down Expand Up @@ -51,13 +53,14 @@ def basic_login(request: WSGIRequest) -> HttpResponse | HttpResponseRedirect:
if credential and not (username or password):
# credential is set and not set username, password, check username in credential.response.userHandle
try:
user_handle = base64url_to_bytes(json.loads(credential)['response']['userHandle']).decode('utf-8')
user_handle = base64url_to_bytes(
json.loads(credential)["response"]["userHandle"]
).decode("utf-8")
username = UserHandle.objects.get(handle=user_handle).user.username
user = authenticate(
request, username=username, u2f_credential=credential
)
except:
import traceback
except Exception:
print(traceback.format_exc())
form.add_error("__all__", "Failed login using passkey")
else:
Expand Down Expand Up @@ -121,9 +124,9 @@ def request_authentication(request: WSGIRequest, **kwargs: Any) -> JsonResponse:
"""

username = request.POST.get("username")
for_login = convert_to_bool(request.POST.get("for_login",False))
for_login = convert_to_bool(request.POST.get("for_login", False))
if not for_login and not username:
return JsonResponse({"non_field_errors": _("No username supplied")}, status=403)
return JsonResponse({"non_field_errors": _("No username supplied")}, status=403)
return JsonResponse(
json.loads(
SecurityKey.generate_authentication(
Expand Down
8 changes: 4 additions & 4 deletions tests/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def invalid_test_credential():
def test_auth_credential():
return _test_auth_credential()


@pytest.fixture
def test_auth_credential_passkey():
return _test_auth_credential_passkey()
Expand Down Expand Up @@ -79,7 +80,7 @@ def security_key_passkey():


def _test_credential():
from django_security_keys.models import SecurityKey, UserHandle
from django_security_keys.models import SecurityKey

user = get_user_model().objects.create_user("bob", password="user")
session = SessionStore()
Expand Down Expand Up @@ -169,10 +170,9 @@ def _test_auth_credential_passkey():
),
)
UserHandle.objects.create(
user=user,
handle="xyW3XGlevvnRg2XgN7CeBuLKr_YJwmS2i_GM9eLt330"
user=user, handle="xyW3XGlevvnRg2XgN7CeBuLKr_YJwmS2i_GM9eLt330"
)

cred = json.dumps(
{
"id": "ZoIKP1JQvKdrYj1bTUPJ2eTUsbLeFkv-X5xJQNr4k6s",
Expand Down
4 changes: 1 addition & 3 deletions tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ def test_passkey_login_failure_invalid_signature(invalid_auth_credential):
SecurityKey.set_challenge(client_session, SecurityKey.get_challenge(session))
client_session.save()

response = c.post(
reverse("login"), {"credential": cred}
)
response = c.post(reverse("login"), {"credential": cred})

response = c.get(reverse("security-keys:manage-keys"))
assert "Your keys" not in response.content.decode("utf-8")
Expand Down

0 comments on commit b0e78f9

Please sign in to comment.