mirror of
https://github.com/lukin/keywind.git
synced 2025-01-10 18:06:23 +00:00
ui(totp): configure and login otp
- added configure and login otp pages
This commit is contained in:
parent
54e9c33abb
commit
4cff8b30c8
11 changed files with 246 additions and 16 deletions
|
@ -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>
|
||||
|
|
10
theme/keywind/login/components/button/secondary.ftl
Normal file
10
theme/keywind/login/components/button/secondary.ftl
Normal 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>
|
5
theme/keywind/login/components/label/totp.ftl
Normal file
5
theme/keywind/login/components/label/totp.ftl
Normal file
|
@ -0,0 +1,5 @@
|
|||
<#macro kw>
|
||||
<#compress>
|
||||
${msg("authenticatorCode")} *
|
||||
</#compress>
|
||||
</#macro>
|
5
theme/keywind/login/components/label/userdevice.ftl
Normal file
5
theme/keywind/login/components/label/userdevice.ftl
Normal file
|
@ -0,0 +1,5 @@
|
|||
<#macro kw>
|
||||
<#compress>
|
||||
${msg("loginTotpDeviceName")} <#if totp.otpCredentials?size gte 1>*</#if>
|
||||
</#compress>
|
||||
</#macro>
|
|
@ -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>
|
||||
|
|
18
theme/keywind/login/components/radio/primary.ftl
Normal file
18
theme/keywind/login/components/radio/primary.ftl
Normal 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>
|
129
theme/keywind/login/login-config-totp.ftl
Normal file
129
theme/keywind/login/login-config-totp.ftl
Normal 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>
|
63
theme/keywind/login/login-otp.ftl
Normal file
63
theme/keywind/login/login-otp.ftl
Normal 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>
|
2
theme/keywind/login/resources/dist/index.css
vendored
2
theme/keywind/login/resources/dist/index.css
vendored
File diff suppressed because one or more lines are too long
7
theme/keywind/login/resources/dist/index.js
vendored
7
theme/keywind/login/resources/dist/index.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue