ui(totp): configure and login otp

- added configure and login otp pages
This commit is contained in:
Ron Mercado 2022-04-03 00:36:24 +08:00
parent 54e9c33abb
commit 4cff8b30c8
11 changed files with 246 additions and 16 deletions

View file

@ -1,6 +1,6 @@
<#macro kw component="span" rest...>
<${component}
class="absolute left-0 ml-3 text-lg"
class="ml-3 text-lg text-primary-600"
<#list rest as attrName, attrValue>
${attrName}="${attrValue}"
</#list>

View file

@ -0,0 +1,10 @@
<#macro kw component="button" rest...>
<${component}
class="bg-transparent flex justify-center px-4 py-3 relative rounded-lg font-bold text-gray-600 w-full focus:outline-none hover:text-black"
<#list rest as attrName, attrValue>
${attrName}="${attrValue}"
</#list>
>
<#nested>
</${component}>
</#macro>

View file

@ -0,0 +1,5 @@
<#macro kw>
<#compress>
${msg("authenticatorCode")} *
</#compress>
</#macro>

View file

@ -0,0 +1,5 @@
<#macro kw>
<#compress>
${msg("loginTotpDeviceName")} <#if totp.otpCredentials?size gte 1>*</#if>
</#compress>
</#macro>

View file

@ -4,13 +4,14 @@
<#macro kw>
<#nested "show-username">
<div class="mb-4">
<div class="font-bold mb-2 text-center">${auth.attemptedUsername}</div>
<@buttonPrimary.kw component="a" href="${url.loginRestartFlowUrl}">
<@buttonIcon.kw>
<div class="mb-4 flex items-center justify-center">
<div class="font-bold text-center">${auth.attemptedUsername}</div>
<@buttonIcon.kw
component="a"
href="${url.loginRestartFlowUrl}"
title="${msg('restartLoginTooltip')}"
>
<@iconExternalLink.kw />
</@buttonIcon.kw>
${msg("restartLoginTooltip")}
</@buttonPrimary.kw>
</div>
</#macro>

View file

@ -0,0 +1,18 @@
<#macro kw tabIndex id checked=false rest...>
<input
<#if checked>checked</#if>
class="focus:ring-primary-500 h-4 w-4 text-primary-600 border-gray-300"
type="radio"
id="${id}"
<#list rest as attrName, attrValue>
${attrName}="${attrValue}"
</#list>
>
<label
class="ml-1 text-sm font-medium mr-4"
for="${id}"
tabindex="${tabIndex}"
>
<#nested>
</label>
</#macro>

View file

@ -0,0 +1,129 @@
<#import "template.ftl" as layout>
<#import "components/button/primary.ftl" as buttonPrimary>
<#import "components/button/secondary.ftl" as buttonSecondary>
<#import "components/input/primary.ftl" as inputPrimary>
<#import "components/label/totp.ftl" as labelTotp>
<#import "components/label/userdevice.ftl" as labelUserDevice>
<#import "components/link/primary.ftl" as linkPrimary>
<@layout.registrationLayout
displayRequiredFields=false
displayMessage=!messagesPerField.existsError('totp','userLabel')
;
section
>
<#if section="header">
${msg("loginTotpTitle")}
<#elseif section="form">
<ol class="list-decimal pl-4 space-y-2">
<li>
<p>${msg("loginTotpStep1")}</p>
<ul class="ml-6 list-disc space-y-1">
<#list totp.policy.supportedApplications as app>
<li>${app}</li>
</#list>
</ul>
</li>
<#if mode?? && mode = "manual">
<li class="pt-2">
<p>${msg("loginTotpManualStep2")}</p>
<p class="font-bold text-xl">${totp.totpSecretEncoded}</p>
</li>
<li>
<@linkPrimary.kw href=totp.qrUrl>
${msg("loginTotpScanBarcode")}
</@linkPrimary.kw>
</li>
<li>
<p>${msg("loginTotpManualStep3")}</p>
<ul class="ml-6 list-disc space-y-2">
<li>${msg("loginTotpType")}: ${msg("loginTotp." + totp.policy.type)}</li>
<li>${msg("loginTotpAlgorithm")}: ${totp.policy.getAlgorithmKey()}</li>
<li>${msg("loginTotpDigits")}: ${totp.policy.digits}</li>
<#if totp.policy.type = "totp">
<li>${msg("loginTotpInterval")}: ${totp.policy.period}</li>
<#elseif totp.policy.type = "hotp">
<li>${msg("loginTotpCounter")}: ${totp.policy.initialCounter}</li>
</#if>
</ul>
</li>
<#else>
<li>
<p>${msg("loginTotpStep2")}</p>
<img class="text-center mx-auto" src="data:image/png;base64, ${totp.totpSecretQrCode}" alt="Figure: Barcode"><br/>
<p>
<@linkPrimary.kw href=totp.manualUrl>
${msg("loginTotpUnableToScan")}
</@linkPrimary.kw>
</p>
</li>
</#if>
<li>
<p>${msg("loginTotpStep3")}</p>
</li>
<li>
<p>${msg("loginTotpStep3DeviceName")}</p>
</li>
</ol>
<form action="${url.loginAction}" class="m-0 space-y-4" method="post">
<div>
<@inputPrimary.kw
autocomplete="off"
autofocus=true
invalid=["totp"]
name="totp"
type="text"
id="totp"
>
<@labelTotp.kw />
</@inputPrimary.kw>
<input type="hidden" id="totpSecret" name="totpSecret" value="${totp.totpSecret}" />
<#if mode??><input type="hidden" id="mode" name="mode" value="${mode}"/></#if>
</div>
<div>
<@inputPrimary.kw
autocomplete="off"
autofocus=true
invalid=["userLabel"]
name="userLabel"
type="text"
id="totp"
>
<@labelUserDevice.kw />
</@inputPrimary.kw>
</div>
<#if isAppInitiatedAction??>
<div class="py-2 flex flex-col space-y-1">
<@buttonPrimary.kw
type="submit"
value=msg("doSubmit")
>
${msg("doSubmit")}
</@buttonPrimary.kw>
<@buttonSecondary.kw
type="submit"
value="true"
>
${msg("doCancel")}
</@buttonSecondary.kw>
</div>
<#else>
<div class="py-2">
<@buttonPrimary.kw
type="submit"
value=msg("doSubmit")
>
${msg("doSubmit")}
</@buttonPrimary.kw>
</div>
</#if>
</form>
</#if>
</@layout.registrationLayout>

View file

@ -0,0 +1,63 @@
<#import "template.ftl" as layout>
<#import "components/button/primary.ftl" as buttonPrimary>
<#import "components/input/primary.ftl" as inputPrimary>
<#import "components/radio/primary.ftl" as radioPrimary>
<#import "components/label/totp.ftl" as labelTotp>
<#import "components/link/secondary.ftl" as linkSecondary>
<@layout.registrationLayout
displayMessage=!messagesPerField.existsError('totp')
;
section
>
<#if section="header">
${msg("doLogIn")}
<#elseif section="form">
<form
action="${url.loginAction}"
method="post"
class="m-0 space-y-4"
>
<#if otpLogin.userOtpCredentials?size gt 1>
<div class="${properties.kcFormGroupClass!}">
<div class="flex flex-wrap items-center">
<#list otpLogin.userOtpCredentials as otpCredential>
<@radioPrimary.kw
tabIndex="${otpCredential?index}"
id="kc-otp-credential-${otpCredential?index}"
name="selectedCredentialId"
value="${otpCredential.id}"
checked=(otpCredential.id == otpLogin.selectedCredentialId)
>
${otpCredential.userLabel}
</@radioPrimary.kw>
</#list>
</div>
</div>
</#if>
<div class="py-2">
<@inputPrimary.kw
autocomplete="off"
autofocus=true
invalid=["otp"]
name="otp"
type="text"
id="otp"
>
<@labelTotp.kw />
</@inputPrimary.kw>
</div>
<div class="py-2 flex flex-col items-center justify-center space-y-2">
<@buttonPrimary.kw
name="submitAction"
type="submit"
value=msg("doLogIn")
>
${msg("doLogIn")}
</@buttonPrimary.kw>
</div>
</form>
</#if>
</@layout.registrationLayout>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long