Fix LoginRecoveryAuthnCodeConfig
This commit is contained in:
parent
7e5abe8589
commit
28990a12da
@ -19,6 +19,7 @@ assert<KcContext.LoginPasskeysConditionalAuthenticate extends KcContextLike ? tr
|
||||
|
||||
type I18nLike = {
|
||||
msgStr: (key: "webauthn-unsupported-browser-text" | "passkey-unsupported-browser-text") => string;
|
||||
isFetchingTranslations: boolean;
|
||||
};
|
||||
|
||||
export function useScript(params: { authButtonId: string; kcContext: KcContextLike; i18n: I18nLike }) {
|
||||
@ -26,18 +27,18 @@ export function useScript(params: { authButtonId: string; kcContext: KcContextLi
|
||||
|
||||
const { url, isUserIdentified, challenge, userVerification, rpId, createTimeout } = kcContext;
|
||||
|
||||
const { msgStr } = i18n;
|
||||
const { msgStr, isFetchingTranslations } = i18n;
|
||||
|
||||
const { insertScriptTags } = useInsertScriptTags({
|
||||
componentOrHookName: "LoginRecoveryAuthnCodeConfig",
|
||||
scriptTags: [
|
||||
{
|
||||
type: "module",
|
||||
textContent: `
|
||||
textContent: () => `
|
||||
import { authenticateByWebAuthn } from "${url.resourcesPath}/js/webauthnAuthenticate.js";
|
||||
import { initAuthenticate } from "${url.resourcesPath}/js/passkeysConditionalAuth.js";
|
||||
|
||||
const authButton = document.getElementById(${JSON.stringify(authButtonId)});
|
||||
const authButton = document.getElementById("${authButtonId}");
|
||||
const input = {
|
||||
isUserIdentified : ${isUserIdentified},
|
||||
challenge : '${challenge}',
|
||||
@ -62,6 +63,10 @@ export function useScript(params: { authButtonId: string; kcContext: KcContextLi
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (isFetchingTranslations) {
|
||||
return;
|
||||
}
|
||||
|
||||
insertScriptTags();
|
||||
}, []);
|
||||
}, [isFetchingTranslations]);
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { useEffect } from "react";
|
||||
import { clsx } from "keycloakify/tools/clsx";
|
||||
import { getKcClsx, type KcClsx } from "keycloakify/login/lib/kcClsx";
|
||||
import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
||||
import { useScript } from "keycloakify/login/pages/LoginRecoveryAuthnCodeConfig.useScript";
|
||||
import type { PageProps } from "keycloakify/login/pages/PageProps";
|
||||
import type { KcContext } from "../KcContext";
|
||||
import type { I18n } from "../i18n";
|
||||
@ -18,130 +17,9 @@ export default function LoginRecoveryAuthnCodeConfig(props: PageProps<Extract<Kc
|
||||
|
||||
const { msg, msgStr } = i18n;
|
||||
|
||||
const { insertScriptTags } = useInsertScriptTags({
|
||||
componentOrHookName: "LoginRecoveryAuthnCodeConfig",
|
||||
scriptTags: [
|
||||
{
|
||||
type: "text/javascript",
|
||||
textContent: `
|
||||
const olRecoveryCodesListId = "kc-recovery-codes-list";
|
||||
|
||||
/* copy recovery codes */
|
||||
function copyRecoveryCodes() {
|
||||
var tmpTextarea = document.createElement("textarea");
|
||||
var codes = document.getElementById("kc-recovery-codes-list").getElementsByTagName("li");
|
||||
for (i = 0; i < codes.length; i++) {
|
||||
tmpTextarea.value = tmpTextarea.value + codes[i].innerText + "\\n";
|
||||
}
|
||||
document.body.appendChild(tmpTextarea);
|
||||
tmpTextarea.select();
|
||||
document.execCommand("copy");
|
||||
document.body.removeChild(tmpTextarea);
|
||||
}
|
||||
|
||||
var copyButton = document.getElementById("copyRecoveryCodes");
|
||||
copyButton && copyButton.addEventListener("click", function () {
|
||||
copyRecoveryCodes();
|
||||
});
|
||||
|
||||
/* download recovery codes */
|
||||
function formatCurrentDateTime() {
|
||||
var dt = new Date();
|
||||
var options = {
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
timeZoneName: 'short'
|
||||
};
|
||||
|
||||
return dt.toLocaleString('en-US', options);
|
||||
}
|
||||
|
||||
function parseRecoveryCodeList() {
|
||||
var recoveryCodes = document.querySelectorAll(".kc-recovery-codes-list li");
|
||||
var recoveryCodeList = "";
|
||||
|
||||
for (var i = 0; i < recoveryCodes.length; i++) {
|
||||
var recoveryCodeLiElement = recoveryCodes[i].innerText;
|
||||
recoveryCodeList += recoveryCodeLiElement + "\\r\\n";
|
||||
}
|
||||
|
||||
return recoveryCodeList;
|
||||
}
|
||||
|
||||
function buildDownloadContent() {
|
||||
var recoveryCodeList = parseRecoveryCodeList();
|
||||
var dt = new Date();
|
||||
var options = {
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
timeZoneName: 'short'
|
||||
};
|
||||
|
||||
return fileBodyContent =
|
||||
"${msgStr("recovery-codes-download-file-header")}\\n\\n" +
|
||||
recoveryCodeList + "\\n" +
|
||||
"${msgStr("recovery-codes-download-file-description")}\\n\\n" +
|
||||
"${msgStr("recovery-codes-download-file-date")} " + formatCurrentDateTime();
|
||||
}
|
||||
|
||||
function setUpDownloadLinkAndDownload(filename, text) {
|
||||
var el = document.createElement('a');
|
||||
el.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
||||
el.setAttribute('download', filename);
|
||||
el.style.display = 'none';
|
||||
document.body.appendChild(el);
|
||||
el.click();
|
||||
document.body.removeChild(el);
|
||||
}
|
||||
|
||||
function downloadRecoveryCodes() {
|
||||
setUpDownloadLinkAndDownload('kc-download-recovery-codes.txt', buildDownloadContent());
|
||||
}
|
||||
|
||||
var downloadButton = document.getElementById("downloadRecoveryCodes");
|
||||
downloadButton && downloadButton.addEventListener("click", downloadRecoveryCodes);
|
||||
|
||||
/* print recovery codes */
|
||||
function buildPrintContent() {
|
||||
var recoveryCodeListHTML = document.getElementById('kc-recovery-codes-list').innerHTML;
|
||||
var styles =
|
||||
\`@page { size: auto; margin-top: 0; }
|
||||
body { width: 480px; }
|
||||
div { list-style-type: none; font-family: monospace }
|
||||
p:first-of-type { margin-top: 48px }\`;
|
||||
|
||||
return printFileContent =
|
||||
"<html><style>" + styles + "</style><body>" +
|
||||
"<title>kc-download-recovery-codes</title>" +
|
||||
"<p>${msgStr("recovery-codes-download-file-header")}</p>" +
|
||||
"<div>" + recoveryCodeListHTML + "</div>" +
|
||||
"<p>${msgStr("recovery-codes-download-file-description")}</p>" +
|
||||
"<p>${msgStr("recovery-codes-download-file-date")} " + formatCurrentDateTime() + "</p>" +
|
||||
"</body></html>";
|
||||
}
|
||||
|
||||
function printRecoveryCodes() {
|
||||
var w = window.open();
|
||||
w.document.write(buildPrintContent());
|
||||
w.print();
|
||||
w.close();
|
||||
}
|
||||
|
||||
var printButton = document.getElementById("printRecoveryCodes");
|
||||
printButton && printButton.addEventListener("click", printRecoveryCodes);
|
||||
`
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
insertScriptTags();
|
||||
}, []);
|
||||
useScript({ olRecoveryCodesListId, i18n });
|
||||
|
||||
return (
|
||||
<Template
|
||||
@ -164,7 +42,7 @@ export default function LoginRecoveryAuthnCodeConfig(props: PageProps<Extract<Kc
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ol id="kc-recovery-codes-list" className={kcClsx("kcRecoveryCodesList")}>
|
||||
<ol id={olRecoveryCodesListId} className={kcClsx("kcRecoveryCodesList")}>
|
||||
{recoveryAuthnCodesConfigBean.generatedRecoveryAuthnCodesList.map((code, index) => (
|
||||
<li key={index}>
|
||||
<span>{index + 1}:</span> {code.slice(0, 4)}-{code.slice(4, 8)}-{code.slice(8)}
|
||||
|
142
src/login/pages/LoginRecoveryAuthnCodeConfig.useScript.tsx
Normal file
142
src/login/pages/LoginRecoveryAuthnCodeConfig.useScript.tsx
Normal file
@ -0,0 +1,142 @@
|
||||
import { useEffect } from "react";
|
||||
import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
||||
|
||||
type I18nLike = {
|
||||
msgStr: (key: "recovery-codes-download-file-header" | "recovery-codes-download-file-description" | "recovery-codes-download-file-date") => string;
|
||||
isFetchingTranslations: boolean;
|
||||
};
|
||||
|
||||
export function useScript(params: { olRecoveryCodesListId: string; i18n: I18nLike }) {
|
||||
const { olRecoveryCodesListId, i18n } = params;
|
||||
|
||||
const { msgStr, isFetchingTranslations } = i18n;
|
||||
|
||||
const { insertScriptTags } = useInsertScriptTags({
|
||||
componentOrHookName: "LoginRecoveryAuthnCodeConfig",
|
||||
scriptTags: [
|
||||
{
|
||||
type: "text/javascript",
|
||||
textContent: () => `
|
||||
|
||||
/* copy recovery codes */
|
||||
function copyRecoveryCodes() {
|
||||
var tmpTextarea = document.createElement("textarea");
|
||||
var codes = document.querySelectorAll("#${olRecoveryCodesListId} li");
|
||||
for (i = 0; i < codes.length; i++) {
|
||||
tmpTextarea.value = tmpTextarea.value + codes[i].innerText + "\\n";
|
||||
}
|
||||
document.body.appendChild(tmpTextarea);
|
||||
tmpTextarea.select();
|
||||
document.execCommand("copy");
|
||||
document.body.removeChild(tmpTextarea);
|
||||
}
|
||||
|
||||
var copyButton = document.getElementById("copyRecoveryCodes");
|
||||
copyButton && copyButton.addEventListener("click", function () {
|
||||
copyRecoveryCodes();
|
||||
});
|
||||
|
||||
/* download recovery codes */
|
||||
function formatCurrentDateTime() {
|
||||
var dt = new Date();
|
||||
var options = {
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
timeZoneName: 'short'
|
||||
};
|
||||
|
||||
return dt.toLocaleString('en-US', options);
|
||||
}
|
||||
|
||||
function parseRecoveryCodeList() {
|
||||
var recoveryCodes = document.querySelectorAll("#${olRecoveryCodesListId} li");
|
||||
var recoveryCodeList = "";
|
||||
|
||||
for (var i = 0; i < recoveryCodes.length; i++) {
|
||||
var recoveryCodeLiElement = recoveryCodes[i].innerText;
|
||||
recoveryCodeList += recoveryCodeLiElement + "\\r\\n";
|
||||
}
|
||||
|
||||
return recoveryCodeList;
|
||||
}
|
||||
|
||||
function buildDownloadContent() {
|
||||
var recoveryCodeList = parseRecoveryCodeList();
|
||||
var dt = new Date();
|
||||
var options = {
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
timeZoneName: 'short'
|
||||
};
|
||||
|
||||
return fileBodyContent =
|
||||
${JSON.stringify(msgStr("recovery-codes-download-file-header"))} + "\\n\\n" +
|
||||
recoveryCodeList + "\\n" +
|
||||
${JSON.stringify(msgStr("recovery-codes-download-file-description"))} + "\\n\\n" +
|
||||
${JSON.stringify(msgStr("recovery-codes-download-file-date"))} + " " + formatCurrentDateTime();
|
||||
}
|
||||
|
||||
function setUpDownloadLinkAndDownload(filename, text) {
|
||||
var el = document.createElement('a');
|
||||
el.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
||||
el.setAttribute('download', filename);
|
||||
el.style.display = 'none';
|
||||
document.body.appendChild(el);
|
||||
el.click();
|
||||
document.body.removeChild(el);
|
||||
}
|
||||
|
||||
function downloadRecoveryCodes() {
|
||||
setUpDownloadLinkAndDownload('kc-download-recovery-codes.txt', buildDownloadContent());
|
||||
}
|
||||
|
||||
var downloadButton = document.getElementById("downloadRecoveryCodes");
|
||||
downloadButton && downloadButton.addEventListener("click", downloadRecoveryCodes);
|
||||
|
||||
/* print recovery codes */
|
||||
function buildPrintContent() {
|
||||
var recoveryCodeListHTML = document.getElementById('${olRecoveryCodesListId}').innerHTML;
|
||||
var styles =
|
||||
\`@page { size: auto; margin-top: 0; }
|
||||
body { width: 480px; }
|
||||
div { list-style-type: none; font-family: monospace }
|
||||
p:first-of-type { margin-top: 48px }\`;
|
||||
|
||||
return printFileContent =
|
||||
"<html><style>" + styles + "</style><body>" +
|
||||
"<title>kc-download-recovery-codes</title>" +
|
||||
"<p>" + ${JSON.stringify(msgStr("recovery-codes-download-file-header"))} + "</p>" +
|
||||
"<div>" + recoveryCodeListHTML + "</div>" +
|
||||
"<p>" + ${JSON.stringify(msgStr("recovery-codes-download-file-description"))} + "</p>" +
|
||||
"<p>" + ${JSON.stringify(msgStr("recovery-codes-download-file-date"))} + " " + formatCurrentDateTime() + "</p>" +
|
||||
"</body></html>";
|
||||
}
|
||||
|
||||
function printRecoveryCodes() {
|
||||
var w = window.open();
|
||||
w.document.write(buildPrintContent());
|
||||
w.print();
|
||||
w.close();
|
||||
}
|
||||
|
||||
var printButton = document.getElementById("printRecoveryCodes");
|
||||
printButton && printButton.addEventListener("click", printRecoveryCodes);
|
||||
`
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (isFetchingTranslations) {
|
||||
return;
|
||||
}
|
||||
|
||||
insertScriptTags();
|
||||
}, [isFetchingTranslations]);
|
||||
}
|
@ -10,7 +10,7 @@ export namespace ScriptTag {
|
||||
};
|
||||
|
||||
export type TextContent = Common & {
|
||||
textContent: string;
|
||||
textContent: string | (() => string);
|
||||
};
|
||||
export type Src = Common & {
|
||||
src: string;
|
||||
@ -69,7 +69,12 @@ export function useInsertScriptTags(params: {
|
||||
for (let i = 0; i < scripts.length; i++) {
|
||||
const script = scripts[i];
|
||||
if ("textContent" in scriptTag) {
|
||||
if (script.textContent === scriptTag.textContent) {
|
||||
const textContent =
|
||||
typeof scriptTag.textContent === "function"
|
||||
? scriptTag.textContent()
|
||||
: scriptTag.textContent;
|
||||
|
||||
if (script.textContent === textContent) {
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
@ -90,7 +95,12 @@ export function useInsertScriptTags(params: {
|
||||
|
||||
(() => {
|
||||
if ("textContent" in scriptTag) {
|
||||
htmlElement.textContent = scriptTag.textContent;
|
||||
const textContent =
|
||||
typeof scriptTag.textContent === "function"
|
||||
? scriptTag.textContent()
|
||||
: scriptTag.textContent;
|
||||
|
||||
htmlElement.textContent = textContent;
|
||||
return;
|
||||
}
|
||||
if ("src" in scriptTag) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user