Remove ed25519, add pynacl, documentation updates and preparation for PyPI
This commit is contained in:
parent
f000e564f9
commit
fff2d3e244
24 changed files with 404 additions and 82 deletions
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
__author__ = 'Miroslav Shubernetskiy | Keaton Brown'
|
||||
__email__ = 'miroslav@miki725.com | kii-chan@tutanota.com'
|
||||
__version__ = '0.1.0'
|
||||
__author__ = 'Keaton Brown'
|
||||
__email__ = 'kii-chan@tutanota.com'
|
||||
__version__ = '0.2.0'
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
from collections import OrderedDict
|
||||
import os
|
||||
|
||||
import ed25519
|
||||
from nacl import signing
|
||||
from nacl.exceptions import BadSignatureError
|
||||
from django.utils.crypto import constant_time_compare, salted_hmac
|
||||
|
||||
from .utils import Base64, Encoder
|
||||
|
@ -89,6 +90,8 @@ class Ed25519(object):
|
|||
def __init__(self, public_key, private_key, msg):
|
||||
self.public_key = public_key
|
||||
self.private_key = private_key
|
||||
if private_key and type(private_key) == bytes:
|
||||
self.private_key = private_key[:32]
|
||||
self.msg = msg
|
||||
|
||||
def is_signature_valid(self, other_signature):
|
||||
|
@ -101,10 +104,10 @@ class Ed25519(object):
|
|||
Boolean indicating whether validation has succeeded.
|
||||
"""
|
||||
try:
|
||||
vk = ed25519.VerifyingKey(self.public_key)
|
||||
vk.verify(other_signature, self.msg)
|
||||
vk = signing.VerifyKey(self.public_key)
|
||||
vk.verify(self.msg, other_signature)
|
||||
return True
|
||||
except (AssertionError, ed25519.BadSignatureError):
|
||||
except (AssertionError, BadSignatureError) as e:
|
||||
return False
|
||||
|
||||
def sign_data(self):
|
||||
|
@ -116,8 +119,8 @@ class Ed25519(object):
|
|||
bytes
|
||||
ed25519 signature
|
||||
"""
|
||||
sk = ed25519.SigningKey(self.private_key)
|
||||
return sk.sign(self.msg)
|
||||
sk = signing.SigningKey(self.private_key)
|
||||
return sk.sign(self.msg).signature
|
||||
|
||||
|
||||
def generate_randomness(size=32):
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
{% load static %}
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>{% block title %}SQRL Test{% endblock %}</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header>
|
||||
{% block header %}
|
||||
<div>SQRL Test Server</div>
|
||||
<nav>
|
||||
{% if user.is_authenticated %}
|
||||
Logged in as {{ user.username }}
|
||||
{% endif %}
|
||||
<ul>
|
||||
{% if user.is_authenticated %}
|
||||
<li>
|
||||
<a href="{% url 'logout' %}">Log out</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'sqrl:manage' %}">Manage SQRL</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li>
|
||||
<a href="{% url 'sqrl:login' %}">Log In</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endblock %}
|
||||
</header>
|
||||
|
||||
<div id="content">
|
||||
{% block content %}
|
||||
{% endblock content %}
|
||||
</div>
|
||||
|
||||
{% block scripts %}
|
||||
{% endblock %}
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -12,7 +12,7 @@
|
|||
</p>
|
||||
|
||||
{% sqrl as sqrl_session %}
|
||||
{% sqrl_login_dropin sqrl_session login %}
|
||||
{% sqrl_login_dropin sqrl_session "sqrl:login" %}
|
||||
{% endblock %}
|
||||
|
||||
{% comment %}
|
||||
|
@ -23,5 +23,6 @@ All necessary data should already be in the context.
|
|||
|
||||
Please note again that this template is for SQRL-exclusive logins.
|
||||
If you would like to add SQRL login to an existing login page,
|
||||
you should rather adjust that template as it is probably way more involved.
|
||||
you should rather adjust that template as it is probably way more involved
|
||||
to add that here.
|
||||
{% endcomment %}
|
||||
|
|
|
@ -15,7 +15,7 @@ def sqrl(context):
|
|||
|
||||
|
||||
@register.inclusion_tag('sqrl/sqrl-dropin.html')
|
||||
def sqrl_login_dropin(sqrl_session, redir=""):
|
||||
def sqrl_login_dropin(sqrl_session, redir="sqrl:login"):
|
||||
"""
|
||||
Creates a drop-in SQRL element in your template pages.
|
||||
Add it to your login template to make it SQRL-aware.
|
||||
|
|
|
@ -4,7 +4,8 @@ from collections import OrderedDict
|
|||
from django.conf import settings
|
||||
import os
|
||||
|
||||
import ed25519
|
||||
from nacl import signing
|
||||
from nacl.exceptions import BadSignatureError
|
||||
import mock
|
||||
|
||||
from ..crypto import HMAC, Ed25519, generate_randomness
|
||||
|
@ -111,11 +112,11 @@ class TestEd25519(unittest.TestCase):
|
|||
b'\x97\x145\x90N[\xb9\xfc\x8e\x8a\x9e\xd2=\xad\x84\xcd\xf1\x93\x06'
|
||||
)
|
||||
|
||||
@mock.patch('ed25519.SigningKey')
|
||||
@mock.patch('nacl.signing.SigningKey')
|
||||
def test_sign_data_mock(self, mock_signing_key):
|
||||
signature = self.sig.sign_data()
|
||||
|
||||
self.assertEqual(signature, mock_signing_key.return_value.sign.return_value)
|
||||
self.assertEqual(signature, mock_signing_key.return_value.sign.return_value.signature)
|
||||
mock_signing_key.assert_called_once_with(self.sig.private_key)
|
||||
mock_signing_key.return_value.sign.assert_called_once_with(self.sig.msg)
|
||||
|
||||
|
@ -125,17 +126,17 @@ class TestEd25519(unittest.TestCase):
|
|||
self.assertTrue(self.sig.is_signature_valid(signature))
|
||||
self.assertFalse(self.sig.is_signature_valid(b'a' + signature[:-1]))
|
||||
|
||||
@mock.patch('ed25519.VerifyingKey')
|
||||
@mock.patch('nacl.signing.VerifyKey')
|
||||
def test_is_signature_mock(self, mock_verifying_key):
|
||||
is_valid = self.sig.is_signature_valid(mock.sentinel.signature)
|
||||
|
||||
self.assertTrue(is_valid)
|
||||
mock_verifying_key.assert_called_once_with(self.sig.public_key)
|
||||
mock_verifying_key.return_value.verify.assert_called_once_with(
|
||||
mock.sentinel.signature, self.data
|
||||
self.data, mock.sentinel.signature
|
||||
)
|
||||
|
||||
@mock.patch('ed25519.VerifyingKey')
|
||||
@mock.patch('nacl.signing.VerifyKey')
|
||||
def test_is_signature_mock_assertion_error(self, mock_verifying_key):
|
||||
mock_verifying_key.return_value.verify.side_effect = AssertionError
|
||||
|
||||
|
@ -144,19 +145,19 @@ class TestEd25519(unittest.TestCase):
|
|||
self.assertFalse(is_valid)
|
||||
mock_verifying_key.assert_called_once_with(self.sig.public_key)
|
||||
mock_verifying_key.return_value.verify.assert_called_once_with(
|
||||
mock.sentinel.signature, self.data
|
||||
self.data, mock.sentinel.signature
|
||||
)
|
||||
|
||||
@mock.patch('ed25519.VerifyingKey')
|
||||
def test_is_signature_mock_bas_signature_error(self, mock_verifying_key):
|
||||
mock_verifying_key.return_value.verify.side_effect = ed25519.BadSignatureError
|
||||
@mock.patch('nacl.signing.VerifyKey')
|
||||
def test_is_signature_mock_bad_signature_error(self, mock_verifying_key):
|
||||
mock_verifying_key.return_value.verify.side_effect = BadSignatureError
|
||||
|
||||
is_valid = self.sig.is_signature_valid(mock.sentinel.signature)
|
||||
|
||||
self.assertFalse(is_valid)
|
||||
mock_verifying_key.assert_called_once_with(self.sig.public_key)
|
||||
mock_verifying_key.return_value.verify.assert_called_once_with(
|
||||
mock.sentinel.signature, self.data
|
||||
self.data, mock.sentinel.signature
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import unittest
|
||||
from collections import OrderedDict
|
||||
|
||||
import ed25519
|
||||
from nacl import signing
|
||||
import mock
|
||||
from django import forms, test
|
||||
from django.contrib.auth import SESSION_KEY, get_user_model
|
||||
|
@ -19,9 +19,10 @@ TESTING_MODULE = 'sqrl.forms'
|
|||
|
||||
class TestRequestForm(test.TestCase):
|
||||
def get_key_pair(self):
|
||||
signing_key, verifying_key = ed25519.create_keypair()
|
||||
signing_key = signing_key.to_bytes()
|
||||
verifying_key = verifying_key.to_bytes()
|
||||
signing_key = signing.SigningKey.generate()
|
||||
verifying_key = signing_key.verify_key
|
||||
signing_key = signing_key._signing_key
|
||||
verifying_key = verifying_key._key
|
||||
|
||||
return signing_key, verifying_key
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ class TestSQRLStatusView(test.TestCase):
|
|||
|
||||
def test_get_success_url_complete_registration(self):
|
||||
self.view.request.GET['url'] = '?next={}'.format(reverse('sqrl:login'))
|
||||
self.view.request.user.is_authenticated.return_value = False
|
||||
self.view.request.user.is_authenticated = False
|
||||
self.view.request.session = {SQRL_IDENTITY_SESSION_KEY: ''}
|
||||
|
||||
self.assertEqual(
|
||||
|
|
|
@ -16,7 +16,7 @@ urlpatterns = [
|
|||
path("auth/", SQRLAuthView.as_view(), name="auth"),
|
||||
path("login/", SQRLLoginView.as_view(), name="login"),
|
||||
path("manage/", SQRLIdentityManagementView.as_view(), name='manage'),
|
||||
path("register/",SQRLCompleteRegistrationView.as_view(), name='complete-registration'),
|
||||
path("register/", SQRLCompleteRegistrationView.as_view(), name='complete-registration'),
|
||||
re_path(r"^status/(?P<transaction>[A-Za-z0-9_-]{43})/$", SQRLStatusView.as_view(), name='status'),
|
||||
path('admin/sqrl_manage/', AdminSiteSQRLIdentityManagementView.as_view(), name='admin-sqrl_manage'),
|
||||
]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue