import { useEffect, Fragment } from "react"; import { clsx } from "keycloakify/tools/clsx"; import type { MessageKey } from "keycloakify/login/i18n/i18n"; import type { PageProps } from "keycloakify/login/pages/PageProps"; import { useGetClassName } from "keycloakify/login/lib/useGetClassName"; import { assert } from "tsafe/assert"; import { createUseInsertScriptTags } from "keycloakify/tools/useInsertScriptTags"; import type { KcContext } from "../kcContext"; import type { I18n } from "../i18n"; const { useInsertScriptTags } = createUseInsertScriptTags(); export default function WebauthnAuthenticate(props: PageProps, I18n>) { const { kcContext, i18n, doUseDefaultCss, Template, classes } = props; const { getClassName } = useGetClassName({ doUseDefaultCss, classes }); const { url, isUserIdentified, challenge, userVerification, rpId, createTimeout, messagesPerField, realm, registrationDisabled, authenticators, shouldDisplayAuthenticators } = kcContext; const { msg, msgStr } = i18n; const { insertScriptTags } = useInsertScriptTags({ "scriptTags": [ { "type": "text/javascript", "src": `${url.resourcesCommonPath}/node_modules/jquery/dist/jquery.min.js` }, { "type": "text/javascript", "src": `${url.resourcesPath}/js/base64url.js` }, { "type": "text/javascript", "textContent": ` function webAuthnAuthenticate() { let isUserIdentified = ${isUserIdentified}; if (!isUserIdentified) { doAuthenticate([]); return; } checkAllowCredentials(); } function checkAllowCredentials() { let allowCredentials = []; let authn_use = document.forms['authn_select'].authn_use_chk; if (authn_use !== undefined) { if (authn_use.length === undefined) { allowCredentials.push({ id: base64url.decode(authn_use.value, {loose: true}), type: 'public-key', }); } else { for (let i = 0; i < authn_use.length; i++) { allowCredentials.push({ id: base64url.decode(authn_use[i].value, {loose: true}), type: 'public-key', }); } } } doAuthenticate(allowCredentials); } function doAuthenticate(allowCredentials) { // Check if WebAuthn is supported by this browser if (!window.PublicKeyCredential) { $("#error").val("${msgStr("webauthn-unsupported-browser-text")}"); $("#webauth").submit(); return; } let challenge = "${challenge}"; let userVerification = "${userVerification}"; let rpId = "${rpId}"; let publicKey = { rpId : rpId, challenge: base64url.decode(challenge, { loose: true }) }; let createTimeout = ${createTimeout}; if (createTimeout !== 0) publicKey.timeout = createTimeout * 1000; if (allowCredentials.length) { publicKey.allowCredentials = allowCredentials; } if (userVerification !== 'not specified') publicKey.userVerification = userVerification; navigator.credentials.get({publicKey}) .then((result) => { window.result = result; let clientDataJSON = result.response.clientDataJSON; let authenticatorData = result.response.authenticatorData; let signature = result.response.signature; $("#clientDataJSON").val(base64url.encode(new Uint8Array(clientDataJSON), { pad: false })); $("#authenticatorData").val(base64url.encode(new Uint8Array(authenticatorData), { pad: false })); $("#signature").val(base64url.encode(new Uint8Array(signature), { pad: false })); $("#credentialId").val(result.id); if(result.response.userHandle) { $("#userHandle").val(base64url.encode(new Uint8Array(result.response.userHandle), { pad: false })); } $("#webauth").submit(); }) .catch((err) => { $("#error").val(err); $("#webauth").submit(); }) ; } ` } ] }); useEffect(() => { insertScriptTags(); }, []); return ( ); }