89 lines
No EOL
3.1 KiB
TypeScript
89 lines
No EOL
3.1 KiB
TypeScript
document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
// If the browser doesn't support WebAuthn, remove the register elements.
|
|
if (!window.PublicKeyCredential) {
|
|
const registerEls = document.querySelectorAll('[data-webauthn-register]');
|
|
for (const regEl of registerEls) regEl.remove();
|
|
}
|
|
|
|
document.getElementById('webAuthnRegister')?.addEventListener('submit', async (ev) => {
|
|
ev.preventDefault();
|
|
|
|
if (!window.PublicKeyCredential) {
|
|
alert('Your browser does not support WebAuthn.');
|
|
return;
|
|
}
|
|
|
|
const bgnRegisterRes = await fetch('/auth/webauthn/register');
|
|
const registerData = await bgnRegisterRes.json();
|
|
|
|
registerData.publicKey.challenge = base64ToArrayBuffer(registerData.publicKey.challenge);
|
|
registerData.publicKey.user.id = base64ToArrayBuffer(registerData.publicKey.user.id);
|
|
if (registerData.publicKey.excludeCredentials) {
|
|
for (let i = 0; i < registerData.publicKey.excludeCredentials.length; i++) {
|
|
registerData.publicKey.excludeCredentials[i].id = base64ToArrayBuffer(registerData.publicKey.excludeCredentials[i].id);
|
|
}
|
|
}
|
|
|
|
const cred = await navigator.credentials.create({
|
|
publicKey: registerData.publicKey,
|
|
})
|
|
|
|
if (!cred) {
|
|
return;
|
|
}
|
|
|
|
const form = new FormData(ev.target! as HTMLFormElement);
|
|
let name = form.get('name');
|
|
if (!name || name.length === 0) {
|
|
name = 'WebAuthn Key';
|
|
}
|
|
|
|
const credentialCreationRes = (cred as PublicKeyCredential).response as AuthenticatorAttestationResponse;
|
|
const attestationObj = credentialCreationRes.attestationObject;
|
|
const clientDataJSON = credentialCreationRes.clientDataJSON;
|
|
const rawID = (cred as PublicKeyCredential).rawId;
|
|
|
|
const fnRegisterRes = await fetch('/user/webauthn/register', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
id: cred.id,
|
|
name: name,
|
|
rawID: arrayBufferToBase64(rawID),
|
|
type: cred.type,
|
|
response: {
|
|
attestationObject: arrayBufferToBase64(attestationObj),
|
|
clientDataJSON: arrayBufferToBase64(clientDataJSON),
|
|
},
|
|
}),
|
|
});
|
|
|
|
if (fnRegisterRes.status != 200) {
|
|
alert('Failed to register WebAuthn key.');
|
|
return;
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
function arrayBufferToBase64(arrayBuffer: ArrayBufferLike) {
|
|
const base64String = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));
|
|
return base64String.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
}
|
|
|
|
function base64ToArrayBuffer(base64: string) {
|
|
const binaryString = atob(base64.replace(/-/g, '+').replace(/_/g, '/'));
|
|
|
|
const length = binaryString.length;
|
|
const bytes = new Uint8Array(length);
|
|
|
|
for (let i = 0; i < length; i++) {
|
|
bytes[i] = binaryString.charCodeAt(i);
|
|
}
|
|
|
|
return bytes.buffer;
|
|
} |