Admin can now hopefully add a passkey to their account
This commit is contained in:
parent
cadd58187a
commit
2fb8339d91
16 changed files with 351 additions and 40 deletions
|
@ -1,35 +1,88 @@
|
|||
class Auth {
|
||||
constructor() {}
|
||||
|
||||
async createCredentials() {
|
||||
async register() {
|
||||
const { challenge, userId, existing } = await this.getRegisterData();
|
||||
|
||||
const publicKeyCredentialCreationOptions = {
|
||||
challenge: Uint8Array.from(
|
||||
'randomStringFromServer',
|
||||
c => c.charCodeAt(0)
|
||||
),
|
||||
challenge: new TextEncoder().encode(challenge),
|
||||
rp: {
|
||||
id: 'jonnybarnes.localhost',
|
||||
name: 'JB',
|
||||
},
|
||||
user: {
|
||||
id: Uint8Array.from(
|
||||
'UZSL85T9AFC',
|
||||
c => c.charCodeAt(0)
|
||||
),
|
||||
id: new TextEncoder().encode(userId),
|
||||
name: 'jonny@jonnybarnes.uk',
|
||||
displayName: 'Jonny',
|
||||
},
|
||||
pubKeyCredParams: [{alg: -7, type: 'public-key'}],
|
||||
// authenticatorSelection: {
|
||||
// authenticatorAttachment: 'cross-platform',
|
||||
// },
|
||||
pubKeyCredParams: [
|
||||
{alg: -8, type: 'public-key'}, // Ed25519
|
||||
{alg: -7, type: 'public-key'}, // ES256
|
||||
{alg: -257, type: 'public-key'}, // RS256
|
||||
],
|
||||
excludeCredentials: existing,
|
||||
authenticatorSelection: {
|
||||
userVerification: 'preferred',
|
||||
residentKey: 'required',
|
||||
},
|
||||
timeout: 60000,
|
||||
attestation: 'direct'
|
||||
};
|
||||
|
||||
return await navigator.credentials.create({
|
||||
const publicKeyCredential = await navigator.credentials.create({
|
||||
publicKey: publicKeyCredentialCreationOptions
|
||||
});
|
||||
if (!publicKeyCredential) {
|
||||
throw new Error('Error generating a passkey');
|
||||
}
|
||||
const {
|
||||
id // the key id a.k.a. kid
|
||||
} = publicKeyCredential;
|
||||
const publicKey = publicKeyCredential.response.getPublicKey();
|
||||
const transports = publicKeyCredential.response.getTransports();
|
||||
const response = publicKeyCredential.response;
|
||||
const clientJSONArrayBuffer = response.clientDataJSON;
|
||||
const clientJSON = JSON.parse(new TextDecoder().decode(clientJSONArrayBuffer));
|
||||
const clientChallenge = clientJSON.challenge;
|
||||
// base64 decode the challenge
|
||||
const clientChallengeDecoded = atob(clientChallenge);
|
||||
|
||||
const saved = await this.savePasskey(id, publicKey, transports, clientChallengeDecoded);
|
||||
|
||||
if (saved) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert('There was an error saving the passkey');
|
||||
}
|
||||
}
|
||||
|
||||
async getRegisterData() {
|
||||
const response = await fetch('/admin/passkeys/init');
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
async savePasskey(id, publicKey, transports, challenge) {
|
||||
const formData = new FormData();
|
||||
formData.append('id', id);
|
||||
formData.append('transports', JSON.stringify(transports));
|
||||
formData.append('challenge', challenge);
|
||||
|
||||
// Convert the ArrayBuffer to a Uint8Array
|
||||
const publicKeyArray = new Uint8Array(publicKey);
|
||||
|
||||
// Create a Blob from the Uint8Array
|
||||
const publicKeyBlob = new Blob([publicKeyArray], { type: 'application/octet-stream' });
|
||||
|
||||
formData.append('public_key', publicKeyBlob);
|
||||
|
||||
const response = await fetch('/admin/passkeys/save', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
|
||||
},
|
||||
});
|
||||
|
||||
return response.ok;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue