fix(login): improve webauthn error handling (#9474)

This PR improves error handling around webauthn functions in the login.
This commit is contained in:
Max Peintner 2025-03-05 15:47:48 +01:00 committed by GitHub
parent b0fa974419
commit a82f5805b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 68 additions and 50 deletions

View File

@ -15,7 +15,17 @@ function checkWebauthnSupported(button, func) {
function webauthnError(error) {
let err = document.getElementById("wa-error");
err.getElementsByClassName("cause")[0].innerText = error.message;
let causeElement = err.getElementsByClassName("cause")[0];
if (error.message) {
causeElement.innerText = error.message;
} else if (error.value) {
causeElement.innerText = error.value;
} else {
console.error("Unknown error:", error);
causeElement.innerText = "An unknown error occurred.";
}
err.classList.remove("hidden");
}

View File

@ -3,29 +3,36 @@ document.addEventListener(
checkWebauthnSupported("btn-login", login)
);
function login() {
async function login() {
document.getElementById("wa-error").classList.add("hidden");
let makeAssertionOptions = JSON.parse(
atob(document.getElementsByName("credentialAssertionData")[0].value)
);
makeAssertionOptions.publicKey.challenge = bufferDecode(
makeAssertionOptions.publicKey.challenge,
"publicKey.challenge"
);
makeAssertionOptions.publicKey.allowCredentials.forEach(function (listItem) {
listItem.id = bufferDecode(listItem.id, "publicKey.allowCredentials.id");
});
navigator.credentials
.get({
publicKey: makeAssertionOptions.publicKey,
})
.then(function (credential) {
verifyAssertion(credential);
})
.catch(function (err) {
webauthnError(err);
let makeAssertionOptions;
try {
makeAssertionOptions = JSON.parse(atob(document.getElementsByName("credentialAssertionData")[0].value));
} catch (e) {
webauthnError({ message: "Failed to parse credential assertion data." });
return;
}
try {
makeAssertionOptions.publicKey.challenge = bufferDecode(makeAssertionOptions.publicKey.challenge, "publicKey.challenge");
makeAssertionOptions.publicKey.allowCredentials.forEach(function (listItem) {
listItem.id = bufferDecode(listItem.id, "publicKey.allowCredentials.id");
});
} catch (e) {
webauthnError({ message: "Failed to decode buffer data." });
return;
}
try {
const credential = await navigator.credentials.get({
publicKey: makeAssertionOptions.publicKey,
});
verifyAssertion(credential);
} catch (err) {
webauthnError(err);
}
}
function verifyAssertion(assertedCredential) {
@ -49,6 +56,6 @@ function verifyAssertion(assertedCredential) {
},
});
document.getElementsByName("credentialData")[0].value = btoa(data);
document.getElementsByName("credentialData")[0].value = window.btoa(data);
document.getElementsByTagName("form")[0].submit();
}

View File

@ -3,40 +3,41 @@ document.addEventListener(
checkWebauthnSupported("btn-register", registerCredential)
);
function registerCredential() {
async function registerCredential() {
document.getElementById("wa-error").classList.add("hidden");
let opt = JSON.parse(
atob(document.getElementsByName("credentialCreationData")[0].value)
);
opt.publicKey.challenge = bufferDecode(
opt.publicKey.challenge,
"publicKey.challenge"
);
opt.publicKey.user.id = bufferDecode(
opt.publicKey.user.id,
"publicKey.user.id"
);
if (opt.publicKey.excludeCredentials) {
for (let i = 0; i < opt.publicKey.excludeCredentials.length; i++) {
if (opt.publicKey.excludeCredentials[i].id !== null) {
opt.publicKey.excludeCredentials[i].id = bufferDecode(
opt.publicKey.excludeCredentials[i].id,
"publicKey.excludeCredentials"
);
let opt;
try {
opt = JSON.parse(atob(document.getElementsByName("credentialCreationData")[0].value));
} catch (e) {
webauthnError({ message: "Failed to parse credential creation data." });
return;
}
try {
opt.publicKey.challenge = bufferDecode(opt.publicKey.challenge, "publicKey.challenge");
opt.publicKey.user.id = bufferDecode(opt.publicKey.user.id, "publicKey.user.id");
if (opt.publicKey.excludeCredentials) {
for (let i = 0; i < opt.publicKey.excludeCredentials.length; i++) {
if (opt.publicKey.excludeCredentials[i].id !== null) {
opt.publicKey.excludeCredentials[i].id = bufferDecode(opt.publicKey.excludeCredentials[i].id, "publicKey.excludeCredentials");
}
}
}
} catch (e) {
webauthnError({ message: "Failed to decode buffer data." });
return;
}
navigator.credentials
.create({
try {
const credential = await navigator.credentials.create({
publicKey: opt.publicKey,
})
.then(function (credential) {
createCredential(credential);
})
.catch(function (err) {
webauthnError(err);
});
createCredential(credential);
} catch (err) {
webauthnError(err);
}
}
function createCredential(newCredential) {
@ -56,6 +57,6 @@ function createCredential(newCredential) {
},
});
document.getElementsByName("credentialData")[0].value = btoa(data);
document.getElementsByName("credentialData")[0].value = window.btoa(data);
document.getElementsByTagName("form")[0].submit();
}