mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-09 04:43:54 -05:00
the js `fetch` function will follow redirects blindly and return you the final 200 response. when there's an error, we don't want to go anywhere, and we want to use the flask `flash` functionality to pop up an error page (the likely reason for seeing this is using a yubikey that isn't associated with your user). using `flash` and then `window.location.reload()` handles this fine. However, when the user does log in succesfully we need to properly log them in - this includes: * checking their account isn't over the max login count * resetting failed login count to 0 if not * setting a new session id in the database (so other browser windows are logged out) * checking if they need to revalidate their email access (every 90 days) * clearing old user out of the cache This code all happens in the ajax function rather than being in a separate redirect, so that you can't just navigate to the login flow. I wasn't able to unit test that function due how it uses the session and other flask globals, so moved the auth into its own function so it's easy to stub out all that CBOR nonsense. TODO: We still need to pass any `next` URLs through the chain from login page all the way through the javascript AJAX calls and redirects to the log_in_user function
63 lines
2.3 KiB
JavaScript
63 lines
2.3 KiB
JavaScript
(function (window) {
|
|
"use strict";
|
|
|
|
window.GOVUK.Modules.AuthenticateSecurityKey = function () {
|
|
this.start = function (component) {
|
|
$(component)
|
|
.on('click', function (event) {
|
|
event.preventDefault();
|
|
|
|
fetch('/webauthn/authenticate')
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw Error(response.statusText);
|
|
}
|
|
|
|
return response.arrayBuffer();
|
|
})
|
|
.then(data => {
|
|
var options = window.CBOR.decode(data);
|
|
// triggers browser dialogue to login with authenticator
|
|
return window.navigator.credentials.get(options);
|
|
})
|
|
.then(credential => {
|
|
return fetch('/webauthn/authenticate', {
|
|
method: 'POST',
|
|
headers: { 'X-CSRFToken': component.data('csrfToken') },
|
|
body: window.CBOR.encode({
|
|
credentialId: new Uint8Array(credential.rawId),
|
|
authenticatorData: new Uint8Array(credential.response.authenticatorData),
|
|
signature: new Uint8Array(credential.response.signature),
|
|
clientDataJSON: new Uint8Array(credential.response.clientDataJSON),
|
|
})
|
|
});
|
|
})
|
|
.then(response => {
|
|
if (response.status === 403){
|
|
// flask will have `flash`ed an error message up
|
|
window.location.reload();
|
|
return;
|
|
}
|
|
|
|
if (!response.ok) {
|
|
// probably an internal server error
|
|
throw Error(response.statusText);
|
|
}
|
|
|
|
// fetch will already have done the login redirect dance and will at this point be
|
|
// referring to the final 200 - hopefully to the `/accounts` url or similar. Set the location
|
|
// to trigger a browser navigate to that URL.
|
|
window.location.href = response.url;
|
|
})
|
|
.catch(error => {
|
|
console.error(error);
|
|
// some browsers will show an error dialogue for some
|
|
// errors; to be safe we always pop up an alert
|
|
var message = error.message || error;
|
|
alert('Error during authentication.\n\n' + message);
|
|
});
|
|
});
|
|
};
|
|
};
|
|
}) (window);
|