WebauthnAuthenticate: refactor authentication flow
Lots of weird syntax here, and we were using `useCallback` rather than `useConstCallback`.
This commit is contained in:
@ -1,10 +1,11 @@
|
|||||||
import React, { useCallback, useRef, useState, memo } from "react";
|
import React, { useRef, useState, memo } from "react";
|
||||||
import Template from "./Template";
|
import Template from "./Template";
|
||||||
import type { KcProps } from "./KcProps";
|
import type { KcProps } from "./KcProps";
|
||||||
import type { KcContextBase } from "../getKcContext/KcContextBase";
|
import type { KcContextBase } from "../getKcContext/KcContextBase";
|
||||||
import { useCssAndCx } from "../tools/useCssAndCx";
|
import { useCssAndCx } from "../tools/useCssAndCx";
|
||||||
import type { I18n, MessageKeyBase } from "../i18n";
|
import type { I18n, MessageKeyBase } from "../i18n";
|
||||||
import { base64url } from "rfc4648";
|
import { base64url } from "rfc4648";
|
||||||
|
import { useConstCallback } from "powerhooks/useConstCallback";
|
||||||
|
|
||||||
const WebauthnAuthenticate = memo(
|
const WebauthnAuthenticate = memo(
|
||||||
({
|
({
|
||||||
@ -23,76 +24,67 @@ const WebauthnAuthenticate = memo(
|
|||||||
|
|
||||||
const { cx } = useCssAndCx();
|
const { cx } = useCssAndCx();
|
||||||
|
|
||||||
const webAuthnAuthenticate = useCallback(() => {
|
const webAuthnAuthenticate = useConstCallback(async () => {
|
||||||
if (!isUserIdentified) {
|
if (!isUserIdentified) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checkAllowCredentials();
|
const allowCredentials = authenticators.authenticators.map(
|
||||||
|
authenticator =>
|
||||||
function checkAllowCredentials() {
|
({
|
||||||
const allowCredentials = authenticators.authenticators.map(
|
id: base64url.parse(authenticator.credentialId, { loose: true }),
|
||||||
authenticator =>
|
type: "public-key"
|
||||||
({
|
} as PublicKeyCredentialDescriptor)
|
||||||
id: base64url.parse(authenticator.credentialId, { loose: true }),
|
);
|
||||||
type: "public-key"
|
// Check if WebAuthn is supported by this browser
|
||||||
} as PublicKeyCredentialDescriptor)
|
if (!window.PublicKeyCredential) {
|
||||||
);
|
setError(msgStr("webauthn-unsupported-browser-text"));
|
||||||
doAuthenticate(allowCredentials);
|
submitForm();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
function doAuthenticate(allowCredentials: PublicKeyCredentialDescriptor[]) {
|
|
||||||
// Check if WebAuthn is supported by this browser
|
|
||||||
if (!window.PublicKeyCredential) {
|
|
||||||
setError(msgStr("webauthn-unsupported-browser-text"));
|
|
||||||
submitForm();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const publicKey: PublicKeyCredentialRequestOptions = {
|
const publicKey: PublicKeyCredentialRequestOptions = {
|
||||||
rpId,
|
rpId,
|
||||||
challenge: base64url.parse(challenge, { loose: true })
|
challenge: base64url.parse(challenge, { loose: true })
|
||||||
};
|
};
|
||||||
|
|
||||||
if (createTimeout !== 0) {
|
if (createTimeout !== 0) {
|
||||||
publicKey.timeout = createTimeout * 1000;
|
publicKey.timeout = createTimeout * 1000;
|
||||||
}
|
|
||||||
|
|
||||||
if (allowCredentials.length) {
|
|
||||||
publicKey.allowCredentials = allowCredentials;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userVerification !== "not specified") {
|
|
||||||
publicKey.userVerification = userVerification;
|
|
||||||
}
|
|
||||||
|
|
||||||
navigator.credentials
|
|
||||||
.get({ publicKey })
|
|
||||||
.then(resultRaw => {
|
|
||||||
if (!resultRaw || resultRaw.type != "public-key") return;
|
|
||||||
const result = resultRaw as PublicKeyCredential;
|
|
||||||
if (!("authenticatorData" in result.response)) return;
|
|
||||||
const response = result.response as AuthenticatorAssertionResponse;
|
|
||||||
let clientDataJSON = response.clientDataJSON;
|
|
||||||
let authenticatorData = response.authenticatorData;
|
|
||||||
let signature = response.signature;
|
|
||||||
|
|
||||||
setClientDataJSON(base64url.stringify(new Uint8Array(clientDataJSON), { pad: false }));
|
|
||||||
setAuthenticatorData(base64url.stringify(new Uint8Array(authenticatorData), { pad: false }));
|
|
||||||
setSignature(base64url.stringify(new Uint8Array(signature), { pad: false }));
|
|
||||||
setCredentialId(result.id);
|
|
||||||
setUserHandle(base64url.stringify(new Uint8Array(response.userHandle!), { pad: false }));
|
|
||||||
submitForm();
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
setError(err);
|
|
||||||
submitForm();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, [kcContext]);
|
|
||||||
|
if (allowCredentials.length) {
|
||||||
|
publicKey.allowCredentials = allowCredentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userVerification !== "not specified") {
|
||||||
|
publicKey.userVerification = userVerification;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const resultRaw = await navigator.credentials.get({ publicKey });
|
||||||
|
if (!resultRaw || resultRaw.type != "public-key") return;
|
||||||
|
const result = resultRaw as PublicKeyCredential;
|
||||||
|
if (!("authenticatorData" in result.response)) return;
|
||||||
|
const response = result.response as AuthenticatorAssertionResponse;
|
||||||
|
const clientDataJSON = response.clientDataJSON;
|
||||||
|
const authenticatorData = response.authenticatorData;
|
||||||
|
const signature = response.signature;
|
||||||
|
|
||||||
|
setClientDataJSON(base64url.stringify(new Uint8Array(clientDataJSON), { pad: false }));
|
||||||
|
setAuthenticatorData(base64url.stringify(new Uint8Array(authenticatorData), { pad: false }));
|
||||||
|
setSignature(base64url.stringify(new Uint8Array(signature), { pad: false }));
|
||||||
|
setCredentialId(result.id);
|
||||||
|
setUserHandle(base64url.stringify(new Uint8Array(response.userHandle!), { pad: false }));
|
||||||
|
submitForm();
|
||||||
|
} catch (err) {
|
||||||
|
setError(String(err));
|
||||||
|
submitForm();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const webAuthForm = useRef<HTMLFormElement>(null);
|
const webAuthForm = useRef<HTMLFormElement>(null);
|
||||||
const submitForm = useCallback(() => {
|
const submitForm = useConstCallback(() => {
|
||||||
webAuthForm.current!.submit();
|
webAuthForm.current!.submit();
|
||||||
}, [webAuthForm.current]);
|
});
|
||||||
|
|
||||||
const [clientDataJSON, setClientDataJSON] = useState("");
|
const [clientDataJSON, setClientDataJSON] = useState("");
|
||||||
const [authenticatorData, setAuthenticatorData] = useState("");
|
const [authenticatorData, setAuthenticatorData] = useState("");
|
||||||
|
Reference in New Issue
Block a user