auto submit passkey request

This commit is contained in:
Max Peintner
2023-07-05 14:09:24 +02:00
parent 6e7f0acd94
commit 2dea70c7bc
2 changed files with 71 additions and 67 deletions

View File

@@ -47,7 +47,6 @@ export default async function Page({
{loginName && ( {loginName && (
<LoginPasskey <LoginPasskey
challenge={{} as any}
loginName={loginName} loginName={loginName}
altPassword={altPassword === "true"} altPassword={altPassword === "true"}
/> />

View File

@@ -10,17 +10,11 @@ import { Spinner } from "./Spinner";
type Props = { type Props = {
loginName: string; loginName: string;
challenge: Challenges_Passkey;
altPassword: boolean; altPassword: boolean;
}; };
export default function LoginPasskey({ export default function LoginPasskey({ loginName, altPassword }: Props) {
loginName,
challenge,
altPassword,
}: Props) {
const [error, setError] = useState<string>(""); const [error, setError] = useState<string>("");
const [publicKey, setPublicKey] = useState();
const [loading, setLoading] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false);
const router = useRouter(); const router = useRouter();
@@ -30,19 +24,29 @@ export default function LoginPasskey({
useEffect(() => { useEffect(() => {
if (!initialized.current) { if (!initialized.current) {
initialized.current = true; initialized.current = true;
setLoading(true);
updateSessionForChallenge() updateSessionForChallenge()
.then((response) => { .then((response) => {
const pK = const pK =
response.challenges.passkey.publicKeyCredentialRequestOptions response.challenges.passkey.publicKeyCredentialRequestOptions
.publicKey; .publicKey;
if (pK) { if (pK) {
setPublicKey(pK); submitLoginAndContinue(pK)
.then(() => {
setLoading(false);
})
.catch((error) => {
setError(error);
setLoading(false);
});
} else { } else {
setError("Could not request passkey challenge"); setError("Could not request passkey challenge");
setLoading(false);
} }
}) })
.catch((error) => { .catch((error) => {
setError(error); setError(error);
setLoading(false);
}); });
} }
}, []); }, []);
@@ -91,65 +95,66 @@ export default function LoginPasskey({
return response; return response;
} }
async function submitLoginAndContinue(): Promise<boolean | void> { async function submitLoginAndContinue(
if (publicKey) { publicKey: any
(publicKey as any).challenge = coerceToArrayBuffer( ): Promise<boolean | void> {
(publicKey as any).challenge, publicKey.challenge = coerceToArrayBuffer(
"publicKey.challenge" publicKey.challenge,
"publicKey.challenge"
);
publicKey.allowCredentials.map((listItem: any) => {
listItem.id = coerceToArrayBuffer(
listItem.id,
"publicKey.allowCredentials.id"
); );
(publicKey as any).allowCredentials.map((listItem: any) => { });
listItem.id = coerceToArrayBuffer(
listItem.id, navigator.credentials
"publicKey.allowCredentials.id" .get({
); publicKey,
}); })
navigator.credentials .then((assertedCredential: any) => {
.get({ if (assertedCredential) {
publicKey, let authData = new Uint8Array(
}) assertedCredential.response.authenticatorData
.then((assertedCredential: any) => { );
if (assertedCredential) { let clientDataJSON = new Uint8Array(
let authData = new Uint8Array( assertedCredential.response.clientDataJSON
assertedCredential.response.authenticatorData );
); let rawId = new Uint8Array(assertedCredential.rawId);
let clientDataJSON = new Uint8Array( let sig = new Uint8Array(assertedCredential.response.signature);
assertedCredential.response.clientDataJSON let userHandle = new Uint8Array(
); assertedCredential.response.userHandle
let rawId = new Uint8Array(assertedCredential.rawId); );
let sig = new Uint8Array(assertedCredential.response.signature); let data = JSON.stringify({
let userHandle = new Uint8Array( id: assertedCredential.id,
assertedCredential.response.userHandle rawId: coerceToBase64Url(rawId, "rawId"),
); type: assertedCredential.type,
let data = JSON.stringify({ response: {
id: assertedCredential.id, authenticatorData: coerceToBase64Url(authData, "authData"),
rawId: coerceToBase64Url(rawId, "rawId"), clientDataJSON: coerceToBase64Url(
type: assertedCredential.type, clientDataJSON,
response: { "clientDataJSON"
authenticatorData: coerceToBase64Url(authData, "authData"), ),
clientDataJSON: coerceToBase64Url( signature: coerceToBase64Url(sig, "sig"),
clientDataJSON, userHandle: coerceToBase64Url(userHandle, "userHandle"),
"clientDataJSON" },
), });
signature: coerceToBase64Url(sig, "sig"), return submitLogin(data).then(() => {
userHandle: coerceToBase64Url(userHandle, "userHandle"), return router.push(`/accounts`);
}, });
}); } else {
return submitLogin(data).then(() => {
return router.push(`/accounts`);
});
} else {
setLoading(false);
setError("An error on retrieving passkey");
return null;
}
})
.catch((error) => {
console.error(error);
setLoading(false); setLoading(false);
// setError(error); setError("An error on retrieving passkey");
return null; return null;
}); }
} })
.catch((error) => {
console.error(error);
setLoading(false);
// setError(error);
return null;
});
} }
return ( return (
@@ -187,8 +192,8 @@ export default function LoginPasskey({
type="submit" type="submit"
className="self-end" className="self-end"
variant={ButtonVariants.Primary} variant={ButtonVariants.Primary}
disabled={loading || !publicKey} disabled={loading}
onClick={() => submitLoginAndContinue()} onClick={() => updateSessionForChallenge()}
> >
{loading && <Spinner className="h-5 w-5 mr-2" />} {loading && <Spinner className="h-5 w-5 mr-2" />}
continue continue