184 lines
8.8 KiB
TypeScript
Raw Normal View History

2024-02-16 17:40:12 +02:00
import { clsx } from "keycloakify/tools/clsx";
import type { PageProps } from "keycloakify/account/pages/PageProps";
import { useGetClassName } from "keycloakify/account/lib/useGetClassName";
import type { KcContext } from "../kcContext";
import type { I18n } from "../i18n";
2024-02-19 08:58:27 +02:00
import { MessageKey } from "keycloakify/account/i18n/i18n";
2024-02-16 17:40:12 +02:00
export default function Totp(props: PageProps<Extract<KcContext, { pageId: "totp.ftl" }>, I18n>) {
const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { getClassName } = useGetClassName({
doUseDefaultCss,
classes
});
2024-02-19 08:58:27 +02:00
const { totp, mode, messagesPerField } = kcContext;
2024-02-16 17:40:12 +02:00
const { msg, msgStr } = i18n;
const algToKeyUriAlg: Record<(typeof kcContext)["totp"]["policy"]["algorithm"], string> = {
"HmacSHA1": "SHA1",
"HmacSHA256": "SHA256",
"HmacSHA512": "SHA512"
};
return (
<Template {...{ kcContext, i18n, doUseDefaultCss, classes }} active="totp">
<>
2024-02-19 08:58:27 +02:00
<div className="row">
<div className="col-md-10">
<h2>{msg("changePasswordHtmlTitle")}</h2>
</div>
<div className="col-md-2 subtitle">
<span className="subtitle">{msg("allFieldsRequired")}</span>
</div>
</div>
2024-02-16 17:40:12 +02:00
<ol id="kc-totp-settings">
<li>
2024-02-19 08:58:27 +02:00
<p>{msg("totpStep1")}</p>
2024-02-16 17:40:12 +02:00
<ul id="kc-totp-supported-apps">
{totp.supportedApplications.map(app => (
2024-02-19 08:58:27 +02:00
<li key={app}>{msg(app as MessageKey)}</li>
2024-02-16 17:40:12 +02:00
))}
</ul>
</li>
{mode && mode == "manual" ? (
<>
<li>
2024-02-19 08:58:27 +02:00
<p>{msg("totpManualStep2")}</p>
2024-02-16 17:40:12 +02:00
<p>
<span id="kc-totp-secret-key">{totp.totpSecretEncoded}</span>
</p>
<p>
<a href={totp.qrUrl} id="mode-barcode">
2024-02-19 08:58:27 +02:00
{msg("totpScanBarcode")}
2024-02-16 17:40:12 +02:00
</a>
</p>
</li>
<li>
2024-02-19 08:58:27 +02:00
<p>{msg("totpManualStep3")}</p>
2024-02-16 17:40:12 +02:00
<p>
<ul>
<li id="kc-totp-type">
2024-02-19 08:58:27 +02:00
{msg("totpType")}: {msg(`totp.${totp.policy.type}`)}
2024-02-16 17:40:12 +02:00
</li>
<li id="kc-totp-algorithm">
2024-02-19 08:58:27 +02:00
{msg("totpAlgorithm")}: {algToKeyUriAlg?.[totp.policy.algorithm] ?? totp.policy.algorithm}
2024-02-16 17:40:12 +02:00
</li>
<li id="kc-totp-digits">
2024-02-19 08:58:27 +02:00
{msg("totpDigits")}: {totp.policy.digits}
2024-02-16 17:40:12 +02:00
</li>
{totp.policy.type === "totp" ? (
<li id="kc-totp-period">
2024-02-19 08:58:27 +02:00
{msg("totpInterval")}: {totp.policy.period}
2024-02-16 17:40:12 +02:00
</li>
) : (
<li id="kc-totp-counter">
2024-02-19 08:58:27 +02:00
{msg("totpCounter")}: {totp.policy.initialCounter}
2024-02-16 17:40:12 +02:00
</li>
)}
</ul>
</p>
</li>
</>
) : (
<li>
2024-02-19 08:58:27 +02:00
<p>{msg("totpStep2")}</p>
2024-02-16 17:40:12 +02:00
<img id="kc-totp-secret-qr-code" src={`data:image/png;base64, ${totp.totpSecretQrCode}`} alt="Figure: Barcode" />
<br />
<p>
<a href={totp.manualUrl} id="mode-manual">
2024-02-19 08:58:27 +02:00
{msg("totpUnableToScan")}
2024-02-16 17:40:12 +02:00
</a>
</p>
</li>
)}
<li>
2024-02-19 08:58:27 +02:00
<p>{msg("totpStep3")}</p>
<p>{msg("totpStep3DeviceName")}</p>
2024-02-16 17:40:12 +02:00
</li>
</ol>
2024-02-19 08:58:27 +02:00
{/* <form action={url.loginAction} className={getClassName("kcFormClass")} id="kc-totp-settings-form" method="post"> */}
2024-02-16 17:40:12 +02:00
2024-02-19 08:58:27 +02:00
<form className={getClassName("kcFormClass")} id="kc-totp-settings-form" method="post">
2024-02-16 17:40:12 +02:00
<div className={getClassName("kcFormGroupClass")}>
2024-02-19 08:58:27 +02:00
<div className="col-sm-2 col-md-2">
<label htmlFor="totp" className="control-label">
2024-02-16 17:40:12 +02:00
{msg("authenticatorCode")}
</label>{" "}
<span className="required">*</span>
</div>
2024-02-19 08:58:27 +02:00
<div className="col-sm-10 col-md-10">
2024-02-16 17:40:12 +02:00
<input
type="text"
id="totp"
name="totp"
autoComplete="off"
className={getClassName("kcInputClass")}
aria-invalid={messagesPerField.existsError("totp")}
/>
{messagesPerField.existsError("totp") && (
<span id="input-error-otp-code" className={getClassName("kcInputErrorMessageClass")} aria-live="polite">
{messagesPerField.get("totp")}
</span>
)}
</div>
<input type="hidden" id="totpSecret" name="totpSecret" value={totp.totpSecret} />
{mode && <input type="hidden" id="mode" value={mode} />}
</div>
<div className={getClassName("kcFormGroupClass")}>
2024-02-19 08:58:27 +02:00
<div className="col-sm-2 col-md-2">
2024-02-16 17:40:12 +02:00
<label htmlFor="userLabel" className={getClassName("kcLabelClass")}>
2024-02-19 08:58:27 +02:00
{msg("totpDeviceName")}
2024-02-16 17:40:12 +02:00
</label>{" "}
{totp.otpCredentials.length >= 1 && <span className="required">*</span>}
</div>
2024-02-19 08:58:27 +02:00
<div className="col-sm-10 col-md-10">
2024-02-16 17:40:12 +02:00
<input
type="text"
id="userLabel"
name="userLabel"
autoComplete="off"
className={getClassName("kcInputClass")}
aria-invalid={messagesPerField.existsError("userLabel")}
/>
{messagesPerField.existsError("userLabel") && (
<span id="input-error-otp-label" className={getClassName("kcInputErrorMessageClass")} aria-live="polite">
{messagesPerField.get("userLabel")}
</span>
)}
</div>
</div>
2024-02-19 08:58:27 +02:00
<div className="text-right kcFormGroupClass">
2024-02-16 17:40:12 +02:00
<input
type="submit"
className={clsx(getClassName("kcButtonClass"), getClassName("kcButtonPrimaryClass"), getClassName("kcButtonLargeClass"))}
id="saveTOTPBtn"
2024-02-19 08:58:27 +02:00
value={msgStr("doSave")}
2024-02-16 17:40:12 +02:00
/>
2024-02-19 08:58:27 +02:00
<button
type="submit"
className={clsx(
getClassName("kcButtonClass"),
getClassName("kcButtonDefaultClass"),
getClassName("kcButtonLargeClass"),
getClassName("kcButtonLargeClass")
)}
id="cancelTOTPBtn"
name="cancel-aia"
value="true"
>
{msg("doCancel")}
</button>
</div>
2024-02-16 17:40:12 +02:00
</form>
</>
</Template>
);
}