This commit is contained in:
2025-11-14 02:35:17 +01:00
parent 6f4ff68062
commit a3c5494bf7
53 changed files with 269 additions and 340 deletions
+10
View File
@@ -0,0 +1,10 @@
const objectToString = Object.prototype.toString;
export const isPlainObject = (value: unknown): value is Record<string, unknown> =>
value !== null && !Array.isArray(value) && Object(value) === value;
export const isStringValue = (value: unknown): value is string =>
objectToString.call(value) === '[object String]';
export const isFunctionValue = <T extends (...args: unknown[]) => unknown>(value: unknown): value is T =>
objectToString.call(value) === '[object Function]';
+10 -37
View File
@@ -1,11 +1,5 @@
/* global PublicKeyCredentialCreationOptions, PublicKeyCredentialRequestOptions, BufferSource, PublicKeyCredentialUserEntity, PublicKeyCredentialDescriptor, AuthenticatorSelectionCriteria, AuthenticatorTransport, AuthenticationExtensionsClientOutputs */
type BufferCtor = {
from: (input: string, encoding: string) => {
toString: (encoding: string) => string;
};
};
type CreationChallengeResponse = {
publicKey?: PublicKeyCredentialCreationOptions & {
challenge?: string | BufferSource;
@@ -32,6 +26,8 @@ type AuthenticationCredential = PublicKeyCredential & {
response: AuthenticatorAssertionResponse;
};
import { isStringValue } from './typeGuards';
const base64urlToBase64 = (value: string = ''): string => {
const normalized = value.replace(/-/g, '+').replace(/_/g, '/');
const padding = normalized.length % 4;
@@ -45,32 +41,9 @@ const base64urlToBase64 = (value: string = ''): string => {
const base64ToBase64url = (value: string = ''): string =>
value.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
const getWindowObject = (): (Window & typeof globalThis) | null =>
(typeof window !== 'undefined' ? window : null);
const decodeBase64 = (value: string): string => window.atob(value);
const decodeBase64 = (value: string): string => {
const win = getWindowObject();
if (win?.atob) {
return win.atob(value);
}
const bufferCtor = (globalThis as typeof globalThis & { Buffer?: BufferCtor }).Buffer;
if (bufferCtor) {
return bufferCtor.from(value, 'base64').toString('binary');
}
throw new Error('No base64 decoder available.');
};
const encodeBase64 = (binary: string): string => {
const win = getWindowObject();
if (win?.btoa) {
return win.btoa(binary);
}
const bufferCtor = (globalThis as typeof globalThis & { Buffer?: BufferCtor }).Buffer;
if (bufferCtor) {
return bufferCtor.from(binary, 'binary').toString('base64');
}
throw new Error('No base64 encoder available.');
};
const encodeBase64 = (binary: string): string => window.btoa(binary);
export const base64urlToUint8Array = (value?: string | null): Uint8Array => {
const base64 = base64urlToBase64(value || '');
@@ -119,7 +92,7 @@ export const arrayBufferToBase64url = (
};
export const isWebAuthnAvailable = (): boolean =>
Boolean(typeof navigator !== 'undefined' && navigator?.credentials?.create && navigator.credentials.get);
Boolean(navigator.credentials?.create && navigator.credentials.get);
export const preparePublicKeyCreationOptions = (
challengeResponse: CreationChallengeResponse,
@@ -130,14 +103,14 @@ export const preparePublicKeyCreationOptions = (
const publicKey: PublicKeyCredentialCreationOptions = { ...challengeResponse.publicKey };
if (publicKey.challenge && typeof publicKey.challenge === 'string') {
if (publicKey.challenge && isStringValue(publicKey.challenge)) {
publicKey.challenge = base64urlToBufferSource(publicKey.challenge);
}
if (publicKey.user?.id) {
publicKey.user = {
...publicKey.user,
id: typeof publicKey.user.id === 'string'
id: isStringValue(publicKey.user.id)
? base64urlToBufferSource(publicKey.user.id)
: publicKey.user.id,
};
@@ -146,7 +119,7 @@ export const preparePublicKeyCreationOptions = (
if (Array.isArray(publicKey.excludeCredentials)) {
publicKey.excludeCredentials = publicKey.excludeCredentials.map((descriptor) => ({
...descriptor,
id: typeof descriptor.id === 'string'
id: isStringValue(descriptor.id)
? base64urlToBufferSource(descriptor.id)
: descriptor.id,
}));
@@ -168,14 +141,14 @@ export const preparePublicKeyRequestOptions = (
const publicKey: PublicKeyCredentialRequestOptions = { ...challengeResponse.publicKey };
if (publicKey.challenge && typeof publicKey.challenge === 'string') {
if (publicKey.challenge && isStringValue(publicKey.challenge)) {
publicKey.challenge = base64urlToBufferSource(publicKey.challenge);
}
if (Array.isArray(publicKey.allowCredentials)) {
publicKey.allowCredentials = publicKey.allowCredentials.map((descriptor) => ({
...descriptor,
id: typeof descriptor.id === 'string'
id: isStringValue(descriptor.id)
? base64urlToBufferSource(descriptor.id)
: descriptor.id,
}));