226 lines
12 KiB
TypeScript
Raw Normal View History

2024-02-16 17:40:12 +02:00
import { clsx } from "keycloakify/tools/clsx";
2024-06-09 08:27:07 +02:00
import { getKcClsx } from "keycloakify/account/lib/kcClsx";
import type { PageProps } from "keycloakify/account/pages/PageProps";
import type { KcContext } from "../KcContext";
import type { I18n } from "../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;
2024-05-16 17:11:45 +03:00
2024-06-09 08:27:07 +02:00
const { kcClsx } = getKcClsx({
2024-02-16 17:40:12 +02:00
doUseDefaultCss,
classes
});
const { totp, mode, url, messagesPerField, stateChecker } = kcContext;
2024-02-16 17:40:12 +02:00
const { msg, msgStr, advancedMsg } = i18n;
2024-02-16 17:40:12 +02:00
return (
<Template {...{ kcContext, i18n, doUseDefaultCss, classes }} active="totp">
2024-02-16 17:40:12 +02:00
<>
2024-02-19 08:58:27 +02:00
<div className="row">
<div className="col-md-10">
<h2>{msg("authenticatorTitle")}</h2>
2024-02-19 08:58:27 +02:00
</div>
{totp.otpCredentials.length === 0 && (
<div className="subtitle col-md-2">
<span className="required">*</span>
{msg("requiredFields")}
</div>
)}
2024-02-19 08:58:27 +02:00
</div>
{totp.enabled && (
<table className="table table-bordered table-striped">
<thead>
{totp.otpCredentials.length > 1 ? (
<tr>
<th colSpan={4}>{msg("configureAuthenticators")}</th>
</tr>
) : (
<tr>
<th colSpan={3}>{msg("configureAuthenticators")}</th>
</tr>
)}
</thead>
<tbody>
{totp.otpCredentials.map((credential, index) => (
<tr key={index}>
<td className="provider">{msg("mobile")}</td>
{totp.otpCredentials.length > 1 && <td className="provider">{credential.id}</td>}
<td className="provider">{credential.userLabel || ""}</td>
<td className="action">
<form action={url.totpUrl} method="post" className="form-inline">
<input type="hidden" id="stateChecker" name="stateChecker" value={stateChecker} />
<input type="hidden" id="submitAction" name="submitAction" value="Delete" />
<input type="hidden" id="credentialId" name="credentialId" value={credential.id} />
<button id={`remove-mobile-${index}`} className="btn btn-default">
<i className="pficon pficon-delete"></i>
</button>
</form>
</td>
</tr>
2024-02-16 17:40:12 +02:00
))}
</tbody>
</table>
)}
{!totp.enabled && (
<div>
<hr />
<ol id="kc-totp-settings">
2024-02-16 17:40:12 +02:00
<li>
<p>{msg("totpStep1")}</p>
2024-05-27 23:44:41 +02:00
<ul id="kc-totp-supported-apps">{totp.supportedApplications?.map(app => <li key={app}>{advancedMsg(app)}</li>)}</ul>
2024-02-16 17:40:12 +02:00
</li>
{mode && mode == "manual" ? (
<>
<li>
<p>{msg("totpManualStep2")}</p>
<p>
<span id="kc-totp-secret-key">{totp.totpSecretEncoded}</span>
</p>
<p>
<a href={totp.qrUrl} id="mode-barcode">
{msg("totpScanBarcode")}
</a>
</p>
</li>
<li>
<p>{msg("totpManualStep3")}</p>
2024-05-16 17:11:45 +03:00
<ul>
<li id="kc-totp-type">
{msg("totpType")}: {msg(`totp.${totp.policy.type}`)}
</li>
<li id="kc-totp-algorithm">
2024-06-15 17:33:27 +02:00
{msg("totpAlgorithm")}: {totp.policy.getAlgorithmKey()}
2024-05-16 17:11:45 +03:00
</li>
<li id="kc-totp-digits">
{msg("totpDigits")}: {totp.policy.digits}
</li>
{totp.policy.type === "totp" ? (
<li id="kc-totp-period">
{msg("totpInterval")}: {totp.policy.period}
</li>
2024-05-16 17:11:45 +03:00
) : (
<li id="kc-totp-counter">
{msg("totpCounter")}: {totp.policy.initialCounter}
</li>
2024-05-16 17:11:45 +03:00
)}
</ul>
</li>
</>
) : (
<li>
<p>{msg("totpStep2")}</p>
<p>
<img
id="kc-totp-secret-qr-code"
src={`data:image/png;base64, ${totp.totpSecretQrCode}`}
alt="Figure: Barcode"
/>
</p>
<p>
<a href={totp.manualUrl} id="mode-manual">
{msg("totpUnableToScan")}
</a>
</p>
</li>
)}
2024-02-16 17:40:12 +02:00
<li>
<p>{msg("totpStep3")}</p>
<p>{msg("totpStep3DeviceName")}</p>
2024-02-16 17:40:12 +02:00
</li>
</ol>
<hr />
2024-06-09 08:27:07 +02:00
<form action={url.totpUrl} className={kcClsx("kcFormClass")} id="kc-totp-settings-form" method="post">
<input type="hidden" id="stateChecker" name="stateChecker" value={stateChecker} />
2024-06-09 08:27:07 +02:00
<div className={kcClsx("kcFormGroupClass")}>
<div className="col-sm-2 col-md-2">
<label htmlFor="totp" className="control-label">
{msg("authenticatorCode")}
</label>
<span className="required">*</span>
</div>
<div className="col-sm-10 col-md-10">
<input
type="text"
id="totp"
name="totp"
autoComplete="off"
2024-06-09 08:27:07 +02:00
className={kcClsx("kcInputClass")}
aria-invalid={messagesPerField.existsError("totp")}
/>
2024-02-16 17:40:12 +02:00
{messagesPerField.existsError("totp") && (
2024-07-04 19:53:57 +02:00
<span
id="input-error-otp-code"
className={kcClsx("kcInputErrorMessageClass")}
aria-live="polite"
dangerouslySetInnerHTML={{
__html: messagesPerField.get("totp")
}}
/>
)}
</div>
<input type="hidden" id="totpSecret" name="totpSecret" value={totp.totpSecret} />
{mode && <input type="hidden" id="mode" value={mode} />}
</div>
2024-02-16 17:40:12 +02:00
2024-06-09 08:27:07 +02:00
<div className={kcClsx("kcFormGroupClass")}>
<div className="col-sm-2 col-md-2">
2024-06-09 08:27:07 +02:00
<label htmlFor="userLabel" className={kcClsx("kcLabelClass")}>
{msg("totpDeviceName")}
</label>
{totp.otpCredentials.length >= 1 && <span className="required">*</span>}
</div>
<div className="col-sm-10 col-md-10">
<input
type="text"
id="userLabel"
name="userLabel"
autoComplete="off"
2024-06-09 08:27:07 +02:00
className={kcClsx("kcInputClass")}
aria-invalid={messagesPerField.existsError("userLabel")}
/>
{messagesPerField.existsError("userLabel") && (
2024-07-04 19:53:57 +02:00
<span
id="input-error-otp-label"
className={kcClsx("kcInputErrorMessageClass")}
aria-live="polite"
dangerouslySetInnerHTML={{
__html: messagesPerField.get("userLabel")
}}
/>
)}
</div>
</div>
2024-02-16 17:40:12 +02:00
2024-06-09 08:27:07 +02:00
<div id="kc-form-buttons" className={clsx(kcClsx("kcFormGroupClass"), "text-right")}>
<div className={kcClsx("kcInputWrapperClass")}>
<input
type="submit"
2024-06-09 08:27:07 +02:00
className={kcClsx("kcButtonClass", "kcButtonPrimaryClass", "kcButtonLargeClass")}
id="saveTOTPBtn"
value={msgStr("doSave")}
/>
<button
type="submit"
2024-06-09 08:27:07 +02:00
className={kcClsx("kcButtonClass", "kcButtonDefaultClass", "kcButtonLargeClass", "kcButtonLargeClass")}
id="cancelTOTPBtn"
name="submitAction"
value="Cancel"
>
{msg("doCancel")}
</button>
</div>
</div>
</form>
2024-02-19 08:58:27 +02:00
</div>
)}
2024-02-16 17:40:12 +02:00
</>
</Template>
);
}