Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve views query #29

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
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
9 changes: 6 additions & 3 deletions .github/workflows/basic_checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ env:
jobs:
basic_checks:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: 3.7
python-version: ${{ matrix.python-version }}
- name: Install requirements
run: |
python setup.py install
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/run_tox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: |
3.7
Expand Down
8 changes: 5 additions & 3 deletions example/test_app/tests/test_current_platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ def setUp(self) -> None:
if not getattr(self, "assertEquals", None):
self.assertEquals = self.assertEqual

def check_platform(self,user_agent, platform):
request = self.request_factory.get('/', HTTP_USER_AGENT=user_agent)
self.assertEquals(get_current_platform(request), platform)
def check_platform(self, user_agent, platform):
request = self.request_factory.get("/", HTTP_USER_AGENT=user_agent)
self.assertEqual(get_current_platform(request), platform)

def test_mac(self):
self.check_platform("Mozilla/5.0 (Macintosh; Intel Mac OS X 13_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Safari/605.1.15","Apple")

def test_ios(self):
self.check_platform("Mozilla/5.0 (Macintosh; Intel Mac OS X 13_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Safari/605.1.15","Apple")

def test_ipad(self):
self.check_platform("Mozilla/5.0 (iPad; CPU OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1","Apple")

Expand Down
59 changes: 29 additions & 30 deletions example/test_app/tests/test_fido.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
from base64 import urlsafe_b64encode
from importlib import import_module

from django.http import HttpRequest
from django.test import RequestFactory,TransactionTestCase, Client
from django.test import RequestFactory, TransactionTestCase, Client
from django.urls import reverse

from django.conf import settings
Expand All @@ -15,17 +14,19 @@
def get_server_id(request):
return request.META["SERVER_NAME"] + "1"


def get_server_name(request):
return "MySite"

class test_fido(TransactionTestCase):

class TestFIDO(TransactionTestCase):
def setUp(self) -> None:
if not getattr(self,"assertEquals",None):
self.assertEquals = self.assertEqual
from django.contrib.auth import get_user_model
self.user_model = get_user_model()
if self.user_model.objects.filter(username="test").count()==0:
self.user = self.user_model.objects.create_user(username="test",password="test")
if not self.user_model.objects.filter(username="test").exists():
self.user = self.user_model.objects.create_user(username="test", password="test")
else:
self.user = self.user_model.objects.get(username="test")
self.client = Client()
Expand All @@ -40,32 +41,30 @@ def setUp(self) -> None:
self.client.post("/auth/login", {"username": "test", "password": "test", 'passkeys': ''})
self.factory = RequestFactory()


def test_key_reg(self):
self.client.post('auth/login',{"usernaame":"test","password":"test","passkeys":""})
self.client.post('auth/login', {"usernaame": "test", "password": "test", "passkeys": ""})
r = self.client.get(reverse('passkeys:reg_begin'))
self.assertEquals(r.status_code, 200)
self.assertEqual(r.status_code, 200)
j = json.loads(r.content)
j['publicKey']['challenge'] = j['publicKey']['challenge'].encode("ascii")
s = SoftWebauthnDevice()
res = s.create(j, "https://" + j["publicKey"]["rp"]["id"])
res["key_name"]="testKey"
res["key_name"] = "testKey"
u = reverse('passkeys:reg_complete')
r = self.client.post(u, data=json.dumps(res),headers={"USER_AGENT":""}, HTTP_USER_AGENT="", content_type="application/json")
r = self.client.post(u, data=json.dumps(res), headers={"USER_AGENT": ""}, HTTP_USER_AGENT="", content_type="application/json")
try:
j = json.loads(r.content)
except Exception:
raise AssertionError("Failed to get the required JSON after reg_completed")
self.assertTrue("status" in j)

self.assertEquals(j["status"], "OK")
self.assertEquals(UserPasskey.objects.latest('id').name, "testKey")
self.assertEqual(j["status"], "OK")
self.assertEqual(UserPasskey.objects.latest('id').name, "testKey")
return s


def test_auto_key_name(self):
r = self.client.get(reverse('passkeys:reg_begin'))
self.assertEquals(r.status_code, 200)
self.assertEqual(r.status_code, 200)
j = json.loads(r.content)
j['publicKey']['challenge'] = j['publicKey']['challenge'].encode("ascii")
s = SoftWebauthnDevice()
Expand All @@ -77,8 +76,8 @@ def test_auto_key_name(self):
except Exception:
raise AssertionError("Failed to get the required JSON after reg_completed")
self.assertTrue("status" in j)
self.assertEquals(j["status"], "OK")
self.assertEquals(UserPasskey.objects.latest('id').name,"Apple")
self.assertEqual(j["status"], "OK")
self.assertEqual(UserPasskey.objects.latest('id').name, "Apple")
return s

def test_error_when_no_session(self):
Expand All @@ -92,35 +91,35 @@ def test_error_when_no_session(self):
except Exception:
raise AssertionError("Failed to get the required JSON after reg_completed")
self.assertTrue("status" in j)
self.assertEquals(j["status"], "ERR")
self.assertEquals(j["message"], "FIDO Status can't be found, please try again")
self.assertEqual(j["status"], "ERR")
self.assertEqual(j["message"], "FIDO Status can't be found, please try again")

def test_passkey_login(self):
authenticator = self.test_key_reg()
self.client.get('/auth/logout')
r = self.client.get(reverse('passkeys:auth_begin'))
self.assertEquals(r.status_code, 200)
self.assertEqual(r.status_code, 200)
j = json.loads(r.content)
j['publicKey']['challenge'] = j['publicKey']['challenge'].encode("ascii")

res = authenticator.get(j, "https://" + j["publicKey"]["rpId"])
u = reverse('login')
self.client.post(u, {'passkeys': json.dumps(res), "username": "", "password": ""},headers={"USER_AGENT":""}, HTTP_USER_AGENT="")
self.assertTrue(self.client.session.get('_auth_user_id',False))
self.assertTrue(self.client.session.get("passkey",{}).get("passkey",False))
self.assertEquals(self.client.session.get("passkey",{}).get("name"),"testKey")
self.client.post(u, {'passkeys': json.dumps(res), "username": "", "password": ""}, headers={"USER_AGENT": ""}, HTTP_USER_AGENT="")
self.assertTrue(self.client.session.get('_auth_user_id', False))
self.assertTrue(self.client.session.get("passkey", {}).get("passkey", False))
self.assertEqual(self.client.session.get("passkey", {}).get("name"), "testKey")

def test_base_username(self):
authenticator = self.test_key_reg()
self.client.get('/auth/logout')
session = self.session
session["base_username"]= "test"
session["base_username"] = "test"
session.save(must_create=True)
self.client.cookies["sessionid"] = session.session_key
r = self.client.get(reverse('passkeys:auth_begin'))
self.assertEquals(r.status_code, 200)
self.assertEqual(r.status_code, 200)
j = json.loads(r.content)
self.assertEquals(j['publicKey']['allowCredentials'][0]['id'],urlsafe_b64encode(authenticator.credential_id).decode("utf8").strip('='))
self.assertEqual(j['publicKey']['allowCredentials'][0]['id'], urlsafe_b64encode(authenticator.credential_id).decode("utf8").strip('='))

def test_passkey_login_no_session(self):
pass
Expand All @@ -130,14 +129,14 @@ def test_server_id_callable(self):
from test_app.tests.test_fido import get_server_id
settings.FIDO_SERVER_ID = get_server_id
r = self.client.get(reverse('passkeys:auth_begin'))
self.assertEquals(r.status_code, 200)
self.assertEqual(r.status_code, 200)
j = json.loads(r.content)
self.assertEquals(j['publicKey']['rpId'],'testserver1')
self.assertEqual(j['publicKey']['rpId'],'testserver1')

def test_server_name_callable(self):
from test_app.tests.test_fido import get_server_name
settings.FIDO_SERVER_NAME = get_server_name
r = self.client.get(reverse('passkeys:reg_begin'))
self.assertEquals(r.status_code, 200)
self.assertEqual(r.status_code, 200)
j = json.loads(r.content)
self.assertEquals(j['publicKey']['rp']["name"],'MySite')
self.assertEqual(j['publicKey']['rp']["name"], 'MySite')
29 changes: 15 additions & 14 deletions example/test_app/tests/test_passkeys.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,43 @@
from django.test import RequestFactory,TransactionTestCase, Client
from django.test import RequestFactory, TransactionTestCase, Client

class test_passkeys(TransactionTestCase):

class TestPasskeys(TransactionTestCase):
def setUp(self) -> None:
from django.contrib.auth import get_user_model
if not getattr(self, "assertEquals", None):
self.assertEquals = self.assertEqual

self.user_model = get_user_model()
self.user = self.user_model.objects.create_user(username="test",password="test")
self.user = self.user_model.objects.create_user(username="test", password="test")
self.client = Client()
self.factory = RequestFactory()

def test_raiseException(self):
from django.contrib.auth import authenticate
try:
authenticate(request=None,username="test",password="test")
authenticate(request=None, username="test", password="test")
self.assertFalse(True)
except Exception as e:
self.assertEquals(str(e),"request is required for passkeys.backend.PasskeyModelBackend")
self.assertEqual(str(e), "request is required for passkeys.backend.PasskeyModelBackend")

def test_not_add_passkeys_field(self):
request = self.factory.post("/auth/login",{"username":"","password":""})
request = self.factory.post("/auth/login", {"username": "", "password": ""})
from django.contrib.auth import authenticate
try:
user = authenticate(request=request,username="",password="")
user = authenticate(request=request, username="", password="")
self.assertFalse(True)
except Exception as e:
self.assertEquals(str(e),"Can't find 'passkeys' key in request.POST, did you add the hidden input?")
self.assertEqual(str(e), "Can't find 'passkeys' key in request.POST, did you add the hidden input?")

def test_username_password_failed_login(self):
self.client.post("/auth/login",{"username":"test","password":"test123",'passkeys':''})
self.assertFalse(self.client.session.get('_auth_user_id',False))
self.client.post("/auth/login", {"username": "test", "password": "test123", "passkeys": ""})
self.assertFalse(self.client.session.get('_auth_user_id', False))

def test_username_password_login(self):
self.client.post("/auth/login",{"username":"test","password":"test",'passkeys':''})
self.assertTrue(self.client.session.get('_auth_user_id',False))
self.client.post("/auth/login", {"username": "test", "password": "test", "passkeys": ""})
self.assertTrue(self.client.session.get('_auth_user_id', False))
self.assertFalse(self.client.session.get('passkey', {}).get('passkey', False))

def test_no_data(self):
self.client.post("/auth/login",{"username":"","password":"",'passkeys':''})
self.assertFalse(self.client.session.get('_auth_user_id',False))
self.client.post("/auth/login", {"username": "", "password": "", "passkeys": ""})
self.assertFalse(self.client.session.get('_auth_user_id', False))
18 changes: 9 additions & 9 deletions example/test_app/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
from django.urls import reverse

from passkeys.models import UserPasskey
from .test_fido import test_fido
from .test_fido import TestFIDO as test_fido

class test_views(TransactionTestCase):

class TestViews(TransactionTestCase):

def setUp(self) -> None:
from django.contrib.auth import get_user_model
Expand All @@ -18,11 +19,11 @@ def setUp(self) -> None:
test = test_fido()
test.setUp()
self.authenticator = test.test_key_reg()
self.client.post("/auth/login", {"username": "test", "password": "test", 'passkeys': ''})
self.client.post("/auth/login", {"username": "test", "password": "test", "passkeys": ""})
self.user = self.user_model.objects.get(username="test")

def test_disabling_key(self):
key =UserPasskey.objects.filter(user=self.user).latest('id')
key = UserPasskey.objects.filter(user=self.user).latest('id')
self.client.get(reverse('passkeys:toggle') + "?id=" + str(key.id))
self.assertFalse(UserPasskey.objects.get(id=key.id).enabled)

Expand All @@ -32,7 +33,7 @@ def test_disabling_key(self):
def test_deleting_key(self):
key = UserPasskey.objects.filter(user=self.user).latest('id')
self.client.get(reverse('passkeys:delKey') + "?id=" + str(key.id))
self.assertEquals(UserPasskey.objects.filter(id=key.id).count(), 0)
self.assertFalse(UserPasskey.objects.filter(id=key.id).exists())

def test_wrong_ownership(self):
test = test_fido()
Expand All @@ -42,8 +43,7 @@ def test_wrong_ownership(self):
self.user = self.user_model.objects.create_user(username="test2", password="test2")
self.client.post("/auth/login", {"username": "test2", "password": "test2", 'passkeys': ''})
r = self.client.get(reverse('passkeys:delKey') + "?id="+str(key.id))
self.assertEquals(r.status_code, 403)
self.assertEquals(r.content,b"Error: You own this token so you can't delete it")
self.assertEqual(r.status_code, 404)
r = self.client.get(reverse('passkeys:toggle') + "?id=" + str(key.id))
self.assertEquals(r.status_code, 403)
self.assertEquals(r.content, b"Error: You own this token so you can't toggle it")
self.assertEqual(r.status_code, 403)
self.assertEqual(r.content, b"Error: You own this token so you can't toggle it")
32 changes: 15 additions & 17 deletions passkeys/views.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseForbidden
from django.shortcuts import get_object_or_404, render

from .models import UserPasskey


@login_required
def index(request,enroll=False): # noqa
keys = UserPasskey.objects.filter(user=request.user) # pragma: no cover
return render(request,'PassKeys.html',{"keys":keys,"enroll":enroll}) # pragma: no cover
def index(request, enroll=False): # noqa
keys = UserPasskey.objects.filter(user=request.user) # pragma: no cover
return render(request, "PassKeys.html", {"keys": keys, "enroll": enroll}) # pragma: no cover


@login_required
def delKey(request):
key=UserPasskey.objects.get(id=request.GET["id"])
if key.user.pk == request.user.pk:
key.delete()
return HttpResponse("Deleted Successfully")
return HttpResponse("Error: You own this token so you can't delete it", status=403)
key = get_object_or_404(UserPasskey, id=request.GET["id"], user=request.user)
key.delete()
return HttpResponse("Deleted Successfully")


@login_required
def toggleKey(request):
id=request.GET["id"]
q=UserPasskey.objects.filter(user=request.user, id=id)
if q.count()==1:
key=q[0]
key.enabled=not key.enabled
key.save()
key = UserPasskey.objects.filter(id=request.GET["id"], user=request.user).first()
if key is not None:
key.enabled = not key.enabled
key.save(update_fields=["enabled"])
return HttpResponse("OK")
return HttpResponse("Error: You own this token so you can't toggle it", status=403)
return HttpResponseForbidden("Error: You own this token so you can't toggle it")

Choose a reason for hiding this comment

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

I think this should be "You don't own [...]".