2022-04-20 19:06:53 +00:00
|
|
|
{% extends "base_settings_page.html" %}
|
|
|
|
{% block content %}
|
|
|
|
<div style="max-width: 700px;">
|
|
|
|
|
2022-04-21 17:24:26 +00:00
|
|
|
<p>In order to continue, please click on the "Start Enrollment" button, insert your security key and approve the
|
|
|
|
registration request.</p>
|
2022-04-20 19:06:53 +00:00
|
|
|
|
2022-04-21 17:24:26 +00:00
|
|
|
<div class="form-group">
|
|
|
|
<label for="inputKeyName" class="form-label mt-4">Key name</label>
|
|
|
|
<input type="text" class="form-control" id="inputKeyName"
|
|
|
|
placeholder="Device / Authenticator app name"
|
2022-11-19 12:38:24 +00:00
|
|
|
value="Security key" minlength="1" maxlength="{{ max_name_len }}" required/>
|
2022-04-21 17:24:26 +00:00
|
|
|
<small class="form-text text-muted">Please give a name to your key to identify it more easily later.</small>
|
|
|
|
<div class="invalid-feedback">Please give a name to this security key</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<input type="button" class="btn btn-primary" value="Start enrollment" onclick="startEnrollment()"
|
2022-04-21 17:31:38 +00:00
|
|
|
style="margin-top: 20px;" id="submitButton" />
|
2022-04-21 17:24:26 +00:00
|
|
|
|
|
|
|
<script src="/assets/js/base64_lib.js"></script>
|
2022-04-20 19:06:53 +00:00
|
|
|
<script>
|
|
|
|
const OPAQUE_STATE = "{{ opaque_state }}";
|
|
|
|
const REGISTRATION_CHALLENGE = JSON.parse(decodeURIComponent("{{ challenge_json }}"));
|
2022-04-21 17:24:26 +00:00
|
|
|
|
|
|
|
// Decode data
|
|
|
|
REGISTRATION_CHALLENGE.publicKey.challenge = base64NoPaddingToUint8Array(
|
|
|
|
REGISTRATION_CHALLENGE.publicKey.challenge
|
|
|
|
);
|
|
|
|
REGISTRATION_CHALLENGE.publicKey.user.id = base64NoPaddingToUint8Array(
|
|
|
|
REGISTRATION_CHALLENGE.publicKey.user.id
|
|
|
|
);
|
|
|
|
|
2022-04-21 17:31:38 +00:00
|
|
|
const submitButton = document.getElementById("submitButton");
|
2022-04-21 17:24:26 +00:00
|
|
|
|
|
|
|
async function startEnrollment() {
|
2022-04-21 17:31:38 +00:00
|
|
|
submitButton.disabled = true;
|
2022-04-21 17:24:26 +00:00
|
|
|
try {
|
|
|
|
const factorNameInput = document.getElementById("inputKeyName");
|
|
|
|
factorNameInput.classList.remove("is-invalid");
|
|
|
|
if (factorNameInput.value.length === 0) {
|
|
|
|
factorNameInput.classList.add("is-invalid");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const cred = await navigator.credentials.create(REGISTRATION_CHALLENGE);
|
|
|
|
|
|
|
|
// Encode data that needs to be encoded
|
|
|
|
const credential_res = {
|
|
|
|
id: cred.id,
|
|
|
|
rawId: ArrayBufferToBase64(cred.rawId),
|
|
|
|
type: cred.type,
|
|
|
|
response: {
|
|
|
|
attestationObject: ArrayBufferToBase64(
|
|
|
|
cred.response.attestationObject
|
|
|
|
),
|
|
|
|
clientDataJSON: ArrayBufferToBase64(
|
|
|
|
cred.response.clientDataJSON
|
|
|
|
),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const res = await fetch("/settings/api/two_factor/save_webauthn_factor", {
|
|
|
|
method: "post",
|
|
|
|
headers: {
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
},
|
|
|
|
body: JSON.stringify({
|
|
|
|
opaque_state: OPAQUE_STATE,
|
|
|
|
factor_name: factorNameInput.value,
|
|
|
|
credential: credential_res,
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
|
|
|
let text = await res.text();
|
|
|
|
alert(text);
|
|
|
|
|
|
|
|
if (res.status == 200)
|
|
|
|
location.href = "/settings/two_factors";
|
|
|
|
} catch(e) {
|
|
|
|
console.error(e);
|
|
|
|
alert("Failed enrollment, please try again!");
|
2022-04-21 17:31:38 +00:00
|
|
|
} finally {
|
|
|
|
submitButton.disabled = false;
|
2022-04-21 17:24:26 +00:00
|
|
|
}
|
|
|
|
}
|
2022-04-20 19:06:53 +00:00
|
|
|
</script>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
{% endblock content %}
|