Cybersecurity-Projects/PROJECTS/advanced/encrypted-p2p-chat/frontend/src/components/Auth/PasskeyButton.tsx

100 lines
2.5 KiB
TypeScript

// ===================
// © AngelaMos | 2025
// PasskeyButton.tsx
// ===================
import type { JSX } from 'solid-js'
import { createSignal, onMount, Show } from 'solid-js'
import {
isPlatformAuthenticatorAvailable,
isWebAuthnSupported,
} from '../../services'
import { Button } from '../UI/Button'
interface PasskeyButtonProps {
mode: 'register' | 'login'
onClick: () => void | Promise<void>
loading?: boolean
disabled?: boolean
class?: string
}
export function PasskeyButton(props: PasskeyButtonProps): JSX.Element {
const [webAuthnSupported, setWebAuthnSupported] = createSignal(true)
const [platformAvailable, setPlatformAvailable] = createSignal(false)
onMount(() => {
const supported = isWebAuthnSupported()
setWebAuthnSupported(supported)
if (supported) {
void isPlatformAuthenticatorAvailable().then((available) => {
setPlatformAvailable(available)
})
}
})
const buttonText = (): string => {
if (!webAuthnSupported()) {
return 'WEBAUTHN NOT SUPPORTED'
}
return props.mode === 'register'
? 'REGISTER WITH PASSKEY'
: 'LOGIN WITH PASSKEY'
}
const isDisabled = (): boolean => {
return !webAuthnSupported() || (props.disabled ?? false)
}
return (
<div class={`flex flex-col gap-2 ${props.class ?? ''}`}>
<Button
variant="primary"
size="lg"
fullWidth
loading={props.loading}
disabled={isDisabled()}
onClick={props.onClick}
leftIcon={<PasskeyIcon />}
>
{buttonText()}
</Button>
<Show when={!webAuthnSupported()}>
<p class="font-pixel text-[8px] text-error text-center">
YOUR BROWSER DOES NOT SUPPORT PASSKEYS
</p>
</Show>
<Show when={webAuthnSupported() && platformAvailable()}>
<p class="font-pixel text-[8px] text-success text-center">
BIOMETRIC AUTH AVAILABLE
</p>
</Show>
</div>
)
}
function PasskeyIcon(): JSX.Element {
return (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="currentColor"
aria-hidden="true"
>
<rect x="2" y="6" width="2" height="6" />
<rect x="4" y="4" width="2" height="2" />
<rect x="6" y="2" width="4" height="2" />
<rect x="10" y="4" width="2" height="2" />
<rect x="12" y="6" width="2" height="2" />
<rect x="6" y="8" width="4" height="2" />
<rect x="4" y="10" width="2" height="2" />
<rect x="10" y="10" width="2" height="2" />
<rect x="6" y="12" width="4" height="2" />
</svg>
)
}