This commit is contained in:
2026-02-16 19:34:35 +00:00
commit 9ab0940ca4
784 changed files with 41710 additions and 0 deletions
+61
View File
@@ -0,0 +1,61 @@
// Frontend
type PasskeyUser = {
id: string;
email: string;
firstName: string;
lastName: string;
};
export function arrayBufferToBase64(buffer: ArrayBuffer) {
const bytes = new Uint8Array(buffer);
const binary = Array.from(bytes, (byte) => String.fromCharCode(byte)).join('');
return window.btoa(binary);
}
export function getCredentialPayload(challenge: number[], user: PasskeyUser) {
return {
challenge: new Uint8Array(challenge),
rp: {
name: 'Pertento AI',
},
user: {
id: Uint8Array.from(atob(btoa(user.id)), (c) => c.charCodeAt(0)),
name: user.email,
displayName: `${user.firstName} ${user.lastName}`,
},
pubKeyCredParams: [
{ type: 'public-key' as const, alg: -7 },
{ type: 'public-key' as const, alg: -257 },
],
};
}
export function getSigninPayload(challenge: number[], credentialIds: string[]) {
return {
challenge: new Uint8Array(challenge),
allowCredentials: credentialIds.map((id) => {
const urlSafeId = id.replace(/-/g, '+').replace(/_/g, '/');
const decodedId = atob(urlSafeId);
return {
type: 'public-key' as const,
id: Uint8Array.from(decodedId, (c) => c.charCodeAt(0)),
};
}),
userVerification: 'preferred' as const,
};
}
// Backend
export function createChallenge() {
const challenge = crypto.randomUUID();
const hex = challenge.replace(/-/g, '');
const array: number[] = new Array(hex.length / 2);
for (let i = 0; i < hex.length; i += 2) {
array[i / 2] = parseInt(hex.substr(i, 2), 16);
}
return array;
}
export const hexToString = (array: number[]) => array.map((byte) => byte.toString(16).padStart(2, '0')).join('');