forked from GithubBackups/healthchecks
Add error handling on the client side, use Django form API
This commit is contained in:
parent
1eaa216d3a
commit
53688f1d87
@ -1,7 +1,11 @@
|
|||||||
|
import base64
|
||||||
from datetime import timedelta as td
|
from datetime import timedelta as td
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.auth import authenticate
|
from django.contrib.auth import authenticate
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from fido2.ctap2 import AttestationObject
|
||||||
|
from fido2.client import ClientData
|
||||||
from hc.api.models import TokenBucket
|
from hc.api.models import TokenBucket
|
||||||
|
|
||||||
|
|
||||||
@ -112,3 +116,23 @@ class ProjectNameForm(forms.Form):
|
|||||||
|
|
||||||
class TransferForm(forms.Form):
|
class TransferForm(forms.Form):
|
||||||
email = LowercaseEmailField()
|
email = LowercaseEmailField()
|
||||||
|
|
||||||
|
|
||||||
|
class AddCredentialForm(forms.Form):
|
||||||
|
name = forms.CharField(max_length=100, required=False)
|
||||||
|
client_data_json = forms.CharField(required=True)
|
||||||
|
attestation_object = forms.CharField(required=True)
|
||||||
|
|
||||||
|
def clean_client_data_json(self):
|
||||||
|
v = self.cleaned_data["client_data_json"]
|
||||||
|
binary = base64.b64decode(v.encode())
|
||||||
|
obj = ClientData(binary)
|
||||||
|
|
||||||
|
return obj
|
||||||
|
|
||||||
|
def clean_attestation_object(self):
|
||||||
|
v = self.cleaned_data["attestation_object"]
|
||||||
|
binary = base64.b64decode(v.encode())
|
||||||
|
obj = AttestationObject(binary)
|
||||||
|
|
||||||
|
return obj
|
||||||
|
@ -18,8 +18,6 @@ from django.utils.timezone import now
|
|||||||
from django.urls import resolve, Resolver404
|
from django.urls import resolve, Resolver404
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from django.views.decorators.http import require_POST
|
from django.views.decorators.http import require_POST
|
||||||
from fido2.client import ClientData
|
|
||||||
from fido2.ctap2 import AttestationObject
|
|
||||||
from fido2.server import Fido2Server
|
from fido2.server import Fido2Server
|
||||||
from fido2.webauthn import PublicKeyCredentialRpEntity
|
from fido2.webauthn import PublicKeyCredentialRpEntity
|
||||||
from fido2 import cbor
|
from fido2 import cbor
|
||||||
@ -559,18 +557,15 @@ def add_credential(request):
|
|||||||
# FIXME use HTTPS, remove the verify_origin hack
|
# FIXME use HTTPS, remove the verify_origin hack
|
||||||
server = Fido2Server(rp, verify_origin=_verify_origin)
|
server = Fido2Server(rp, verify_origin=_verify_origin)
|
||||||
|
|
||||||
def decode(form, key):
|
|
||||||
return base64.b64decode(request.POST[key].encode())
|
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
# idea: use AddCredentialForm
|
form = forms.AddCredentialForm(request.POST)
|
||||||
client_data = ClientData(decode(request.POST, "clientDataJSON"))
|
if not form.is_valid():
|
||||||
att_obj = AttestationObject(decode(request.POST, "attestationObject"))
|
return HttpResponseBadRequest()
|
||||||
print("clientData", client_data)
|
|
||||||
print("AttestationObject:", att_obj)
|
|
||||||
|
|
||||||
auth_data = server.register_complete(
|
auth_data = server.register_complete(
|
||||||
request.session["state"], client_data, att_obj
|
request.session["state"],
|
||||||
|
form.cleaned_data["client_data_json"],
|
||||||
|
form.cleaned_data["attestation_object"],
|
||||||
)
|
)
|
||||||
|
|
||||||
c = Credential(user=request.user)
|
c = Credential(user=request.user)
|
||||||
@ -578,12 +573,9 @@ def add_credential(request):
|
|||||||
c.data = auth_data.credential_data
|
c.data = auth_data.credential_data
|
||||||
c.save()
|
c.save()
|
||||||
|
|
||||||
print("REGISTERED CREDENTIAL:", auth_data.credential_data)
|
return redirect("hc-profile")
|
||||||
return render(request, "accounts/success.html")
|
|
||||||
|
|
||||||
credentials = [c.unpack() for c in request.user.credentials.all()]
|
credentials = [c.unpack() for c in request.user.credentials.all()]
|
||||||
print(credentials)
|
|
||||||
|
|
||||||
options, state = server.register_begin(
|
options, state = server.register_begin(
|
||||||
{
|
{
|
||||||
"id": request.user.username.encode(),
|
"id": request.user.username.encode(),
|
||||||
@ -595,6 +587,5 @@ def add_credential(request):
|
|||||||
|
|
||||||
request.session["state"] = state
|
request.session["state"] = state
|
||||||
|
|
||||||
# FIXME: avoid using cbor and cbor.js?
|
|
||||||
ctx = {"options": base64.b64encode(cbor.encode(options)).decode()}
|
ctx = {"options": base64.b64encode(cbor.encode(options)).decode()}
|
||||||
return render(request, "accounts/add_credential.html", ctx)
|
return render(request, "accounts/add_credential.html", ctx)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
$(function() {
|
$(function() {
|
||||||
var form = document.getElementById("add-credential-form");
|
var form = document.getElementById("add-credential-form");
|
||||||
var optionsBinary = btoa(form.dataset.options);
|
var optionsBytes = Uint8Array.from(atob(form.dataset.options), c => c.charCodeAt(0));
|
||||||
var array = Uint8Array.from(atob(form.dataset.options), c => c.charCodeAt(0));
|
// cbor.js expects ArrayBuffer as input when decoding
|
||||||
var options = CBOR.decode(array.buffer);
|
var options = CBOR.decode(optionsBytes.buffer);
|
||||||
console.log("decoded options:", options);
|
console.log("decoded options:", options);
|
||||||
|
|
||||||
function b64(arraybuffer) {
|
function b64(arraybuffer) {
|
||||||
@ -12,11 +12,14 @@ $(function() {
|
|||||||
navigator.credentials.create(options).then(function(attestation) {
|
navigator.credentials.create(options).then(function(attestation) {
|
||||||
console.log("got attestation: ", attestation);
|
console.log("got attestation: ", attestation);
|
||||||
|
|
||||||
document.getElementById("attestationObject").value = b64(attestation.response.attestationObject);
|
$("#attestation_object").val(b64(attestation.response.attestationObject));
|
||||||
document.getElementById("clientDataJSON").value = b64(attestation.response.clientDataJSON);
|
$("#client_data_json").val(b64(attestation.response.clientDataJSON));
|
||||||
console.log("form updated, all is well");
|
console.log("form updated, all is well");
|
||||||
|
|
||||||
$("#add-credential-submit").prop("disabled", "");
|
$("#add-credential-submit").prop("disabled", "");
|
||||||
|
$("#add-credential-success").removeClass("hide");
|
||||||
}).catch(function(err) {
|
}).catch(function(err) {
|
||||||
console.log("Something went wrong", err);
|
$("#add-credential-error span").text(err);
|
||||||
|
$("#add-credential-error").removeClass("hide");
|
||||||
});
|
});
|
||||||
});
|
});
|
@ -2,18 +2,20 @@
|
|||||||
{% load compress static %}
|
{% load compress static %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Add Credential</h1>
|
|
||||||
|
|
||||||
{{ registration_dict|json_script:"registration" }}
|
{{ registration_dict|json_script:"registration" }}
|
||||||
|
<div class="row">
|
||||||
<form
|
<form
|
||||||
id="add-credential-form"
|
id="add-credential-form"
|
||||||
|
class="col-sm-6 col-sm-offset-3"
|
||||||
data-options="{{ options }}"
|
data-options="{{ options }}"
|
||||||
method="post"
|
method="post"
|
||||||
encrypt="multipart/form-data">
|
encrypt="multipart/form-data">
|
||||||
|
<h1>Add Credential</h1>
|
||||||
|
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input id="attestationObject" type="hidden" name="attestationObject">
|
<input id="attestation_object" type="hidden" name="attestation_object">
|
||||||
<input id="clientDataJSON" type="hidden" name="clientDataJSON">
|
<input id="client_data_json" type="hidden" name="client_data_json">
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="name">Name</label>
|
<label for="name">Name</label>
|
||||||
@ -23,14 +25,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="add-credential-error" class="alert alert-danger hide">
|
||||||
|
<strong>Something went wrong.</strong>
|
||||||
|
<span></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="add-credential-success" class="alert alert-success hide">
|
||||||
|
<strong>Success!</strong>
|
||||||
|
Credential acquired.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<input
|
<input
|
||||||
id="add-credential-submit"
|
id="add-credential-submit"
|
||||||
class="btn btn-default"
|
class="btn btn-default pull-right"
|
||||||
type="submit"
|
type="submit"
|
||||||
name=""
|
name=""
|
||||||
value="Save Credential" disabled>
|
value="Save Credential" disabled>
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user