Browse Source

Improve the "add security key" UX, require sudo mode

pull/456/head
Pēteris Caune 4 years ago
parent
commit
2c3286c280
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
5 changed files with 81 additions and 26 deletions
  1. +2
    -0
      hc/accounts/views.py
  2. +8
    -0
      static/css/add_credential.css
  3. +23
    -12
      static/js/add_credential.js
  4. +47
    -14
      templates/accounts/add_credential.html
  5. +1
    -0
      templates/base.html

+ 2
- 0
hc/accounts/views.py View File

@ -22,6 +22,7 @@ from fido2.server import Fido2Server
from fido2.webauthn import PublicKeyCredentialRpEntity
from fido2 import cbor
from hc.accounts import forms
from hc.accounts.decorators import require_sudo_mode
from hc.accounts.models import Credential, Profile, Project, Member
from hc.api.models import Channel, Check, TokenBucket
from hc.lib.date import choose_next_report_date
@ -552,6 +553,7 @@ def _verify_origin(aaa):
@login_required
@require_sudo_mode
def add_credential(request):
rp = PublicKeyCredentialRpEntity("localhost", "Healthchecks")
# FIXME use HTTPS, remove the verify_origin hack


+ 8
- 0
static/css/add_credential.css View File

@ -0,0 +1,8 @@
#add-credential-waiting .spinner {
margin: 0;
}
#add-credential-error-text {
font-family: "Lucida Console", Monaco, monospace;
margin: 16px 0;
}

+ 23
- 12
static/js/add_credential.js View File

@ -3,23 +3,34 @@ $(function() {
var optionsBytes = Uint8Array.from(atob(form.dataset.options), c => c.charCodeAt(0));
// cbor.js expects ArrayBuffer as input when decoding
var options = CBOR.decode(optionsBytes.buffer);
console.log("decoded options:", options);
function b64(arraybuffer) {
return btoa(String.fromCharCode.apply(null, new Uint8Array(arraybuffer)));
}
navigator.credentials.create(options).then(function(attestation) {
console.log("got attestation: ", attestation);
function requestCredentials() {
// Hide error & success messages, show the "waiting" message
$("#name-next").addClass("hide");
$("#add-credential-waiting").removeClass("hide");
$("#add-credential-error").addClass("hide");
$("#add-credential-success").addClass("hide");
$("#attestation_object").val(b64(attestation.response.attestationObject));
$("#client_data_json").val(b64(attestation.response.clientDataJSON));
console.log("form updated, all is well");
navigator.credentials.create(options).then(function(attestation) {
$("#attestation_object").val(b64(attestation.response.attestationObject));
$("#client_data_json").val(b64(attestation.response.clientDataJSON));
// Show the success message and save button
$("#add-credential-waiting").addClass("hide");
$("#add-credential-success").removeClass("hide");
}).catch(function(err) {
// Show the error message
$("#add-credential-waiting").addClass("hide");
$("#add-credential-error-text").text(err);
$("#add-credential-error").removeClass("hide");
});
}
$("#name-next").click(requestCredentials);
$("#retry").click(requestCredentials);
$("#add-credential-submit").prop("disabled", "");
$("#add-credential-success").removeClass("hide");
}).catch(function(err) {
$("#add-credential-error span").text(err);
$("#add-credential-error").removeClass("hide");
});
});

+ 47
- 14
templates/accounts/add_credential.html View File

@ -1,5 +1,5 @@
{% extends "base.html" %}
{% load compress static %}
{% load compress static hc_extras %}
{% block content %}
@ -11,7 +11,7 @@
data-options="{{ options }}"
method="post"
encrypt="multipart/form-data">
<h1>Add Credential</h1>
<h1>Add Security Key</h1>
{% csrf_token %}
<input id="attestation_object" type="hidden" name="attestation_object">
@ -25,23 +25,56 @@
</div>
</div>
<div id="add-credential-error" class="alert alert-danger hide">
<strong>Something went wrong.</strong>
<span></span>
<div class="form-group text-right">
<button
id="name-next"
class="btn btn-default" type="button">
Confirm Name and Continue
</button>
</div>
<div id="add-credential-success" class="alert alert-success hide">
<strong>Success!</strong>
Credential acquired.
<div id="add-credential-waiting" class="hide">
<h2>Waiting for security key</h2>
<p>
Follow your browser's steps to register your security key
with {% site_name %}.
</p>
<div class="spinner started">
<div class="d1"></div>
<div class="d2"></div>
<div class="d3"></div>
</div>
</div>
<div id="add-credential-error" class="alert alert-danger hide">
<p>
<strong>Something went wrong.</strong>
</p>
<p id="add-credential-error-text"></p>
<input
id="add-credential-submit"
class="btn btn-default pull-right"
type="submit"
name=""
value="Save Credential" disabled>
<div class="text-right">
<button id="retry" type="button" class="btn btn-danger">
Try Again
</button>
</div>
</div>
<div id="add-credential-success" class="hide">
<div class="alert alert-success">
<strong>Success!</strong>
Credential acquired.
</div>
<div class="form-group text-right">
<input
id="add-credential-submit"
class="btn btn-primary"
type="submit"
name=""
value="Save Security Key">
</div>
</div>
</form>
</div>
{% endblock %}


+ 1
- 0
templates/base.html View File

@ -20,6 +20,7 @@
<link rel="stylesheet" href="{% static 'css/bootstrap-select.min.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/selectize.hc.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/add_credential.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/add_project_modal.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/add_pushover.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/webhook_form.css' %}" type="text/css">


Loading…
Cancel
Save