kanidm/server/core/static/modules/cred_update.mjs

144 lines
5.3 KiB
JavaScript
Raw Normal View History

console.debug("credupdate: loaded");
// Makes the password form interactive (e.g. shows when passwords don't match)
function setupInteractivePwdFormListeners() {
const new_pwd = document.getElementById("new-password");
const new_pwd_check = document.getElementById("new-password-check");
const pwd_submit = document.getElementById("password-submit");
function markPwdCheckValid() {
new_pwd_check.classList.remove("is-invalid");
new_pwd_check.classList.add("is-valid");
pwd_submit.disabled = false;
}
function markPwdCheckInvalid() {
new_pwd_check.classList.add("is-invalid");
new_pwd_check.classList.remove("is-valid");
pwd_submit.disabled = true;
}
new_pwd.addEventListener("input", () => {
// Don't mark invalid if user didn't fill in the confirmation box yet
// Also KeepassXC with autocomplete likes to fire off input events when
// both inputs are empty.
if (new_pwd_check.value !== "") {
if (new_pwd.value === new_pwd_check.value) {
markPwdCheckValid();
} else {
markPwdCheckInvalid();
}
}
new_pwd.classList.remove("is-invalid");
});
new_pwd_check.addEventListener("input", () => {
// No point in updating the status if confirmation box is empty
if (new_pwd_check.value === "") return;
if (new_pwd_check.value === new_pwd.value) {
markPwdCheckValid();
} else {
markPwdCheckInvalid();
}
});
}
window.stillSwapFailureResponse = function (event) {
if (event.detail.xhr.status === 422 || event.detail.xhr.status === 500) {
console.debug(`Got HTTP/${event.detail.xhr.status}, still swapping failure response`);
event.detail.shouldSwap = true;
event.detail.isError = false;
}
};
function onPasskeyCreated(assertion) {
try {
console.log(assertion);
let creationData = {};
creationData.id = assertion.id;
creationData.rawId = Base64.fromUint8Array(new Uint8Array(assertion.rawId));
creationData.response = {};
creationData.response.attestationObject = Base64.fromUint8Array(
new Uint8Array(assertion.response.attestationObject),
);
creationData.response.clientDataJSON = Base64.fromUint8Array(new Uint8Array(assertion.response.clientDataJSON));
creationData.type = assertion.type;
creationData.extensions = assertion.getClientExtensionResults();
creationData.extensions.uvm = undefined;
// Put the passkey creation data into the form for submission
document.getElementById("passkey-create-data").value = JSON.stringify(creationData);
// Make the name input visible and hide the "Begin Passkey Enrollment" button
document.getElementById("passkeyNamingSafariPre").classList.add("d-none");
document.getElementById("passkeyNamingForm").classList.remove("d-none");
document.getElementById("passkeyNamingSubmitBtn").classList.remove("d-none");
} catch (e) {
console.log(e);
if (
confirm(
"Failed to encode your new passkey's data for transmission, confirm to reload this page.\nReport this issue if it keeps occurring.",
)
) {
window.location.reload();
}
}
}
function startPasskeyEnrollment() {
try {
const data_elem = document.getElementById("data");
const credentialRequestOptions = JSON.parse(data_elem.textContent);
credentialRequestOptions.publicKey.challenge = Base64.toUint8Array(
credentialRequestOptions.publicKey.challenge,
);
credentialRequestOptions.publicKey.user.id = Base64.toUint8Array(credentialRequestOptions.publicKey.user.id);
console.log(credentialRequestOptions);
navigator.credentials.create({ publicKey: credentialRequestOptions.publicKey }).then(
(assertion) => {
onPasskeyCreated(assertion);
},
(reason) => {
alert(`Passkey creation failed ${reason.toString()}`);
console.log(`Passkey creation failed: ${reason.toString()}`);
},
);
} catch (e) {
console.log(`Failed to initialize passkey creation: ${e}`);
if (
confirm(
"Failed to initialize passkey creation, confirm to reload this page.\nReport this issue if it keeps occurring.",
)
) {
window.location.reload();
}
}
}
function setupPasskeyNamingSafariButton() {
document.getElementById("passkeyNamingSafariBtn").addEventListener("click", startPasskeyEnrollment);
}
function setupSubmitBtnVisibility() {
document.getElementById("passkey-label")?.addEventListener("input", updateSubmitButtonVisibility);
}
function updateSubmitButtonVisibility(event) {
const submitButton = document.getElementById("passkeyNamingSubmitBtn");
submitButton.disabled = event.value === "";
}
(function () {
console.debug("credupdate: init");
document.body.addEventListener("addPasswordSwapped", () => {
setupInteractivePwdFormListeners();
});
document.body.addEventListener("addPasskeySwapped", () => {
setupPasskeyNamingSafariButton();
startPasskeyEnrollment();
setupSubmitBtnVisibility();
});
})();