import { useInsertScriptTags } from '@keycloakify/svelte/tools/useInsertScriptTags'; import { assert } from 'keycloakify/tools/assert'; import { waitForElementMountedOnDom } from 'keycloakify/tools/waitForElementMountedOnDom'; import { onMount } from 'svelte'; import type { Readable } from 'svelte/store'; import type { KcContext } from '../KcContext'; type KcContextLike = { url: { resourcesPath: string; }; challenge: string; userid: string; username: string; signatureAlgorithms: string[]; rpEntityName: string; rpId: string; attestationConveyancePreference: string; authenticatorAttachment: string; requireResidentKey: string; userVerificationRequirement: string; createTimeout: number | string; excludeCredentialIds: string; }; assert(); assert(); type I18nLike = { msgStr: ( key: | 'webauthn-registration-init-label' | 'webauthn-registration-init-label-prompt' | 'webauthn-unsupported-browser-text', ) => string; isFetchingTranslations: boolean; }; export function useScript(params: { authButtonId: string; kcContext: KcContextLike; i18n: Readable }) { const { authButtonId, kcContext, i18n } = params; const { url, challenge, userid, username, signatureAlgorithms, rpEntityName, rpId, attestationConveyancePreference, authenticatorAttachment, requireResidentKey, userVerificationRequirement, createTimeout, excludeCredentialIds, } = kcContext; onMount(() => { let hasInserted = false; const unsubscribe = i18n.subscribe(($i18n) => { if (hasInserted) { return; } const { msgStr, isFetchingTranslations } = $i18n; if (isFetchingTranslations) { return; } const { insertScriptTags } = useInsertScriptTags({ componentOrHookName: 'LoginRecoveryAuthnCodeConfig', scriptTags: [ { type: 'module', textContent: () => ` import { registerByWebAuthn } from "${url.resourcesPath}/js/webauthnRegister.js"; const registerButton = document.getElementById('${authButtonId}'); registerButton.addEventListener("click", function() { const input = { challenge : ${JSON.stringify(challenge)}, userid : ${JSON.stringify(userid)}, username : ${JSON.stringify(username)}, signatureAlgorithms : ${JSON.stringify(signatureAlgorithms)}, rpEntityName : ${JSON.stringify(rpEntityName)}, rpId : ${JSON.stringify(rpId)}, attestationConveyancePreference : ${JSON.stringify(attestationConveyancePreference)}, authenticatorAttachment : ${JSON.stringify(authenticatorAttachment)}, requireResidentKey : ${JSON.stringify(requireResidentKey)}, userVerificationRequirement : ${JSON.stringify(userVerificationRequirement)}, createTimeout : ${JSON.stringify(createTimeout)}, excludeCredentialIds : ${JSON.stringify(excludeCredentialIds)}, initLabel : ${JSON.stringify(msgStr('webauthn-registration-init-label'))}, initLabelPrompt : ${JSON.stringify(msgStr('webauthn-registration-init-label-prompt'))}, errmsg : ${JSON.stringify(msgStr('webauthn-unsupported-browser-text'))} }; registerByWebAuthn(input); }, { once: true }); `, }, ], }); hasInserted = true; (async () => { await waitForElementMountedOnDom({ elementId: authButtonId, }); insertScriptTags(); })(); }); return () => unsubscribe(); }); }