More fixes to keycloak theme
This commit is contained in:
parent
cac941a300
commit
b165e70189
|
@ -1,46 +1,46 @@
|
|||
<#import "template.ftl" as layout>
|
||||
<@layout.mainLayout active='sessions' bodyClass='sessions'; section>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
<h2>${msg("sessionsHtmlTitle")}</h2>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
<h2>${msg("sessionsHtmlTitle")}</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="ps-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>${msg("ip")}</td>
|
||||
<td>${msg("started")}</td>
|
||||
<td>${msg("lastAccess")}</td>
|
||||
<td>${msg("expires")}</td>
|
||||
<td>${msg("clients")}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<table class="ps-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>${msg("ip")}</td>
|
||||
<td>${msg("started")}</td>
|
||||
<td>${msg("lastAccess")}</td>
|
||||
<td>${msg("expires")}</td>
|
||||
<td>${msg("clients")}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<#list sessions.sessions as session>
|
||||
<tr>
|
||||
<td>${session.ipAddress}</td>
|
||||
<td>${session.started?datetime}</td>
|
||||
<td>${session.lastAccess?datetime}</td>
|
||||
<td>${session.expires?datetime}</td>
|
||||
<td>
|
||||
<#list session.clients as client>
|
||||
${client}<br/>
|
||||
</#list>
|
||||
</td>
|
||||
</tr>
|
||||
</#list>
|
||||
</tbody>
|
||||
</table>
|
||||
<tbody>
|
||||
<#list sessions.sessions as session>
|
||||
<tr>
|
||||
<td>${session.ipAddress}</td>
|
||||
<td>${session.started?datetime}</td>
|
||||
<td>${session.lastAccess?datetime}</td>
|
||||
<td>${session.expires?datetime}</td>
|
||||
<td>
|
||||
<#list session.clients as client>
|
||||
${client}<br/>
|
||||
</#list>
|
||||
</td>
|
||||
</tr>
|
||||
</#list>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<form action="${url.sessionsUrl}" method="post">
|
||||
<input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
|
||||
<button
|
||||
id="logout-all-sessions"
|
||||
class="ps-button"
|
||||
>${msg("doLogOutAllSessions")}</button>
|
||||
</form>
|
||||
<form action="${url.sessionsUrl}" method="post">
|
||||
<input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
|
||||
<button
|
||||
id="logout-all-sessions"
|
||||
class="ps-button"
|
||||
>${msg("doLogOutAllSessions")}</button>
|
||||
</form>
|
||||
|
||||
</@layout.mainLayout>
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
<link href="${url.resourcesPath}/css/index.css" rel="stylesheet" />
|
||||
|
||||
<script defer src="${url.resourcesPath}/js/background.js" type="text/javascript"></script>
|
||||
<script defer src="${url.resourcesPath}/js/i18n.js" type="text/javascript"></script>
|
||||
|
||||
<#if properties.stylesCommon?has_content>
|
||||
<#list properties.stylesCommon?split(' ') as style>
|
||||
|
@ -59,16 +60,17 @@
|
|||
<a href="https://pub.solar/" class="ps-homelink">pub.solar/</a>
|
||||
|
||||
<#if realm.internationalizationEnabled && locale.supported?size gt 1>
|
||||
<ul class="ps-i18n-links">
|
||||
<#list locale.supported as l>
|
||||
<li class="ps-i18n-links--item">
|
||||
<a
|
||||
class="ps-i18n-links--link <#if locale.current == l.label >ps-i18n-links--link_active</#if>"
|
||||
href="${l.url}"
|
||||
>${l.label}</a>
|
||||
</li>
|
||||
</#list>
|
||||
</ul>
|
||||
<select
|
||||
class="ps-i18n-links"
|
||||
id="language-toggle"
|
||||
>
|
||||
<#list locale.supported as l>
|
||||
<option
|
||||
value="${l.url}"
|
||||
<#if locale.current == l.label>selected</#if>
|
||||
>${l.label}</option>
|
||||
</#list>
|
||||
</select>
|
||||
</#if>
|
||||
|
||||
<nav class="ps-header--nav" role="navigation">
|
||||
|
|
|
@ -127,9 +127,6 @@ html {
|
|||
font-weight: bold; }
|
||||
|
||||
.ps-homelink {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
pointer-events: all;
|
||||
color: var(--foreground);
|
||||
|
@ -152,39 +149,22 @@ html {
|
|||
font-size: 32px;
|
||||
padding: 12px; } }
|
||||
.ps-i18n-links {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
display: flex;
|
||||
margin: 0; }
|
||||
.ps-i18n-links--item {
|
||||
display: flex; }
|
||||
.ps-i18n-links--link {
|
||||
pointer-events: all;
|
||||
color: var(--foreground);
|
||||
background: white;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
font-weight: 900;
|
||||
font-size: 24px;
|
||||
padding: 8px;
|
||||
line-height: 1em;
|
||||
text-shadow: 0.15vw 0px 0px var(--background);
|
||||
transition: text-shadow 0.1s ease;
|
||||
border: 12px solid var(--foreground);
|
||||
border-top: 0;
|
||||
border-right: 0; }
|
||||
.ps-i18n-links--link:hover {
|
||||
text-shadow: 0.3vw 0px 0px var(--accent); }
|
||||
@media screen and (min-width: 1200px) {
|
||||
.ps-i18n-links--link {
|
||||
font-size: 32px;
|
||||
padding: 12px; } }
|
||||
.ps-i18n-links--link_active {
|
||||
background-color: var(--foreground);
|
||||
color: var(--background);
|
||||
text-shadow: 0.15vw 0px 0px var(--foreground); }
|
||||
margin: 0;
|
||||
pointer-events: all;
|
||||
color: var(--foreground);
|
||||
background: white;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
font-weight: 900;
|
||||
font-size: 24px;
|
||||
padding: 8px;
|
||||
line-height: 1em;
|
||||
text-shadow: 0.15vw 0px 0px var(--background);
|
||||
transition: text-shadow 0.1s ease;
|
||||
border: 12px solid var(--foreground);
|
||||
border-top: 0;
|
||||
border-right: 0; }
|
||||
|
||||
.ps-main {
|
||||
display: flex;
|
||||
|
@ -209,9 +189,13 @@ html {
|
|||
z-index: 1; }
|
||||
.ps-main_full {
|
||||
padding: 0; }
|
||||
|
||||
@media screen and (min-width: 1200px) {
|
||||
.ps-main_full .ps-main--page {
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap; } }
|
||||
.ps-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0;
|
||||
margin: 0; }
|
||||
.ps-header--title {
|
||||
|
@ -253,10 +237,12 @@ html {
|
|||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 0;
|
||||
pointer-events: none; }
|
||||
pointer-events: none;
|
||||
padding-top: 4rem; }
|
||||
@media screen and (min-width: 1200px) {
|
||||
.ps-page {
|
||||
padding: 1vw;
|
||||
padding-top: 4rem;
|
||||
flex-direction: row;
|
||||
align-items: flex-start; } }
|
||||
.ps-page_home {
|
||||
|
@ -294,8 +280,12 @@ html {
|
|||
padding: 5vw; }
|
||||
.ps-page--section_full {
|
||||
max-width: unset;
|
||||
width: calc(100% - 8rem);
|
||||
margin: 4rem; }
|
||||
width: calc(100vw - 1.6rem);
|
||||
margin: 0.8rem; }
|
||||
@media screen and (min-width: 1200px) {
|
||||
.ps-page--section_full {
|
||||
width: 96vw;
|
||||
margin: 1vw; } }
|
||||
.ps-page--section a {
|
||||
color: var(--accent);
|
||||
border-bottom: 1px solid transparent;
|
||||
|
@ -347,6 +337,17 @@ html {
|
|||
margin-top: 1.5rem;
|
||||
line-height: 1.5; }
|
||||
|
||||
.ps-login-flow-pre {
|
||||
margin: 2rem;
|
||||
display: flex;
|
||||
border-bottom: 0.25rem solid var(--foreground);
|
||||
padding-bottom: 0.25rem; }
|
||||
.ps-login-flow-pre--selected {
|
||||
font-weight: bold;
|
||||
margin-right: 1rem; }
|
||||
.ps-login-flow-pre--cancel {
|
||||
font-weight: normal; }
|
||||
|
||||
.ps-section-nav {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
|
5
common/resources/js/i18n.js
Normal file
5
common/resources/js/i18n.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
const toggle = document.getElementById('language-toggle');
|
||||
toggle.addEventListener('change', (event) => {
|
||||
window.location = toggle.value;
|
||||
});
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
.ps-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
.ps-homelink {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
|
||||
pointer-events: all;
|
||||
|
|
|
@ -1,44 +1,18 @@
|
|||
.ps-i18n-links {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
display: flex;
|
||||
margin: 0;
|
||||
|
||||
&--item {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&--link {
|
||||
pointer-events: all;
|
||||
color: var(--foreground);
|
||||
background: white;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
font-weight: 900;
|
||||
font-size: 24px;
|
||||
padding: 8px;
|
||||
line-height: 1em;
|
||||
text-shadow: 0.15vw 0px 0px var(--background);
|
||||
transition: text-shadow 0.1s ease;
|
||||
border: 12px solid var(--foreground);
|
||||
border-top: 0;
|
||||
border-right: 0;
|
||||
|
||||
&:hover {
|
||||
text-shadow: 0.3vw 0px 0px var(--accent);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1200px) {
|
||||
font-size: 32px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
&_active {
|
||||
background-color: var(--foreground);
|
||||
color: var(--background);
|
||||
text-shadow: 0.15vw 0px 0px var(--foreground);
|
||||
}
|
||||
}
|
||||
pointer-events: all;
|
||||
color: var(--foreground);
|
||||
background: white;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
font-weight: 900;
|
||||
font-size: 24px;
|
||||
padding: 8px;
|
||||
line-height: 1em;
|
||||
text-shadow: 0.15vw 0px 0px var(--background);
|
||||
transition: text-shadow 0.1s ease;
|
||||
border: 12px solid var(--foreground);
|
||||
border-top: 0;
|
||||
border-right: 0;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ html {
|
|||
@import './main';
|
||||
@import './header';
|
||||
@import './page';
|
||||
@import './login-flow-pre';
|
||||
@import './section-nav';
|
||||
@import './logo';
|
||||
@import './background';
|
||||
|
|
16
common/resources/scss/login-flow-pre.scss
Normal file
16
common/resources/scss/login-flow-pre.scss
Normal file
|
@ -0,0 +1,16 @@
|
|||
.ps-login-flow-pre {
|
||||
margin: 2rem;
|
||||
display: flex;
|
||||
|
||||
border-bottom: 0.25rem solid var(--foreground);
|
||||
padding-bottom: 0.25rem;
|
||||
|
||||
&--selected {
|
||||
font-weight: bold;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
&--cancel {
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
|
@ -27,4 +27,11 @@
|
|||
&_full {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&_full &--page {
|
||||
@media screen and (min-width: 1200px) {
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
justify-content: flex-start;
|
||||
padding: 0;
|
||||
pointer-events: none;
|
||||
padding-top: 4rem;
|
||||
|
||||
@media screen and (min-width: 1200px) {
|
||||
padding: 1vw;
|
||||
padding-top: 4rem;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
@ -58,8 +60,13 @@
|
|||
|
||||
&_full {
|
||||
max-width: unset;
|
||||
width: calc(100% - 8rem);
|
||||
margin: 4rem;
|
||||
width: calc(100vw - 1.6rem);
|
||||
margin: 0.8rem;
|
||||
|
||||
@media screen and (min-width: 1200px) {
|
||||
width: 96vw;
|
||||
margin: 1vw;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
|
|
|
@ -1,58 +1,58 @@
|
|||
<#import "template.ftl" as layout>
|
||||
<@layout.registrationLayout displayMessage=!messagesPerField.existsError('totp'); section>
|
||||
<#if section="header">
|
||||
${msg("doLogIn")}
|
||||
<#elseif section="form">
|
||||
<form id="kc-otp-login-form" class="${properties.kcFormClass!}" action="${url.loginAction}"
|
||||
method="post">
|
||||
<#if otpLogin.userOtpCredentials?size gt 1>
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
<#list otpLogin.userOtpCredentials as otpCredential>
|
||||
<input id="kc-otp-credential-${otpCredential?index}" class="${properties.kcLoginOTPListInputClass!}" type="radio" name="selectedCredentialId" value="${otpCredential.id}" <#if otpCredential.id == otpLogin.selectedCredentialId>checked="checked"</#if>>
|
||||
<label for="kc-otp-credential-${otpCredential?index}" class="${properties.kcLoginOTPListClass!}" tabindex="${otpCredential?index}">
|
||||
<span class="${properties.kcLoginOTPListItemHeaderClass!}">
|
||||
<span class="${properties.kcLoginOTPListItemIconBodyClass!}">
|
||||
<i class="${properties.kcLoginOTPListItemIconClass!}" aria-hidden="true"></i>
|
||||
</span>
|
||||
<span class="${properties.kcLoginOTPListItemTitleClass!}">${otpCredential.userLabel}</span>
|
||||
</span>
|
||||
</label>
|
||||
</#list>
|
||||
</div>
|
||||
</div>
|
||||
</#if>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="otp" class="${properties.kcLabelClass!}">${msg("loginOtpOneTime")}</label>
|
||||
</div>
|
||||
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
<input id="otp" name="otp" autocomplete="off" type="text" class="${properties.kcInputClass!}"
|
||||
autofocus aria-invalid="<#if messagesPerField.existsError('totp')>true</#if>"/>
|
||||
|
||||
<#if messagesPerField.existsError('totp')>
|
||||
<span id="input-error-otp-code" class="${properties.kcInputErrorMessageClass!}"
|
||||
aria-live="polite">
|
||||
${kcSanitize(messagesPerField.get('totp'))?no_esc}
|
||||
</span>
|
||||
</#if>
|
||||
</div>
|
||||
<#if section="header">
|
||||
${msg("doLogIn")}
|
||||
<#elseif section="form">
|
||||
<form
|
||||
id="kc-otp-login-form"
|
||||
class="ps-container"
|
||||
action="${url.loginAction}"
|
||||
method="post"
|
||||
>
|
||||
<#if otpLogin.userOtpCredentials?size gt 1>
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<#list otpLogin.userOtpCredentials as otpCredential>
|
||||
<input id="kc-otp-credential-${otpCredential?index}" class="${properties.kcLoginOTPListInputClass!}" type="radio" name="selectedCredentialId" value="${otpCredential.id}" <#if otpCredential.id == otpLogin.selectedCredentialId>checked="checked"</#if>>
|
||||
<label for="kc-otp-credential-${otpCredential?index}" class="${properties.kcLoginOTPListClass!}" tabindex="${otpCredential?index}">
|
||||
<span class="${properties.kcLoginOTPListItemHeaderClass!}">
|
||||
<span class="${properties.kcLoginOTPListItemIconBodyClass!}">
|
||||
<i class="${properties.kcLoginOTPListItemIconClass!}" aria-hidden="true"></i>
|
||||
</span>
|
||||
<span class="${properties.kcLoginOTPListItemTitleClass!}">${otpCredential.userLabel}</span>
|
||||
</span>
|
||||
</label>
|
||||
</#list>
|
||||
</div>
|
||||
</#if>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
|
||||
<div class="${properties.kcFormOptionsWrapperClass!}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<label for="otp" class="${properties.kcLabelClass!}">${msg("loginOtpOneTime")}</label>
|
||||
|
||||
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
|
||||
<input
|
||||
class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}"
|
||||
name="login" id="kc-login" type="submit" value="${msg("doLogIn")}" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
||||
<input
|
||||
id="otp"
|
||||
name="otp"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
class="${properties.kcInputClass!}"
|
||||
autofocus aria-invalid="<#if messagesPerField.existsError('totp')>true</#if>"
|
||||
/>
|
||||
|
||||
<#if messagesPerField.existsError('totp')>
|
||||
<span id="input-error-otp-code" class="${properties.kcInputErrorMessageClass!}"
|
||||
aria-live="polite">
|
||||
${kcSanitize(messagesPerField.get('totp'))?no_esc}
|
||||
</span>
|
||||
</#if>
|
||||
</div>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<button
|
||||
class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}"
|
||||
name="login"
|
||||
id="kc-login"
|
||||
type="submit"
|
||||
>${msg("doLogIn")}</button>
|
||||
</div>
|
||||
</form>
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
||||
|
|
|
@ -3,163 +3,170 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
|
||||
<title>${msg("loginTitle",(realm.displayName!''))}</title>
|
||||
<title>${msg("loginTitle",(realm.displayName!''))}</title>
|
||||
|
||||
<link rel="icon" href="${url.resourcesPath}/img/pub.solar.svg" />
|
||||
<link rel="icon" href="${url.resourcesPath}/img/pub.solar.svg" />
|
||||
|
||||
<link href="${url.resourcesPath}/css/index.css" rel="stylesheet" />
|
||||
<link href="${url.resourcesPath}/css/index.css" rel="stylesheet" />
|
||||
|
||||
<script defer src="${url.resourcesPath}/js/background.js" type="text/javascript"></script>
|
||||
<script defer src="${url.resourcesPath}/js/background.js" type="text/javascript"></script>
|
||||
<script defer src="${url.resourcesPath}/js/i18n.js" type="text/javascript"></script>
|
||||
|
||||
<#if properties.stylesCommon?has_content>
|
||||
<#list properties.stylesCommon?split(' ') as style>
|
||||
<link href="${url.resourcesCommonPath}/${style}" rel="stylesheet" />
|
||||
</#list>
|
||||
</#if>
|
||||
<#if properties.styles?has_content>
|
||||
<#list properties.styles?split(' ') as style>
|
||||
<link href="${url.resourcesPath}/${style}" rel="stylesheet" />
|
||||
</#list>
|
||||
</#if>
|
||||
<#if properties.scripts?has_content>
|
||||
<#list properties.scripts?split(' ') as script>
|
||||
<script defer src="${url.resourcesPath}/${script}" type="text/javascript"></script>
|
||||
</#list>
|
||||
</#if>
|
||||
<#if properties.scriptsCommon?has_content>
|
||||
<#list properties.scriptsCommon?split(' ') as script>
|
||||
<script defer src="${url.resourcesCommonPath}/${script}" type="text/javascript"></script>
|
||||
</#list>
|
||||
</#if>
|
||||
<#if properties.stylesCommon?has_content>
|
||||
<#list properties.stylesCommon?split(' ') as style>
|
||||
<link href="${url.resourcesCommonPath}/${style}" rel="stylesheet" />
|
||||
</#list>
|
||||
</#if>
|
||||
<#if properties.styles?has_content>
|
||||
<#list properties.styles?split(' ') as style>
|
||||
<link href="${url.resourcesPath}/${style}" rel="stylesheet" />
|
||||
</#list>
|
||||
</#if>
|
||||
<#if properties.scripts?has_content>
|
||||
<#list properties.scripts?split(' ') as script>
|
||||
<script defer src="${url.resourcesPath}/${script}" type="text/javascript"></script>
|
||||
</#list>
|
||||
</#if>
|
||||
<#if properties.scriptsCommon?has_content>
|
||||
<#list properties.scriptsCommon?split(' ') as script>
|
||||
<script defer src="${url.resourcesCommonPath}/${script}" type="text/javascript"></script>
|
||||
</#list>
|
||||
</#if>
|
||||
</head>
|
||||
|
||||
<body class="ps-main ps-main_full">
|
||||
<div
|
||||
id="background"
|
||||
class="ps-background ps-main--background"
|
||||
id="background"
|
||||
class="ps-background ps-main--background"
|
||||
>
|
||||
<div
|
||||
id="x1312"
|
||||
class="ps-background--1312"
|
||||
>0x1312</div>
|
||||
<div
|
||||
id="logo"
|
||||
class="ps-background--logo ps-logo"
|
||||
>
|
||||
<img
|
||||
class="ps-logo--base"
|
||||
src="${url.resourcesPath}/img/pub.solar.svg"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
id="x1312"
|
||||
class="ps-background--1312"
|
||||
>0x1312</div>
|
||||
<div
|
||||
id="logo"
|
||||
class="ps-background--logo ps-logo"
|
||||
>
|
||||
<img
|
||||
class="ps-logo--base"
|
||||
src="${url.resourcesPath}/img/pub.solar.svg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<main class="ps-main--page ps-page">
|
||||
|
||||
<header class="ps-page--header ps-header">
|
||||
<header class="ps-page--header ps-header">
|
||||
|
||||
<a href="https://pub.solar/" class="ps-homelink">pub.solar/</a>
|
||||
<a href="https://pub.solar/" class="ps-homelink">pub.solar/</a>
|
||||
|
||||
<#if realm.internationalizationEnabled && locale.supported?size gt 1>
|
||||
<ul class="ps-i18n-links">
|
||||
<#list locale.supported as l>
|
||||
<li class="ps-i18n-links--item">
|
||||
<a
|
||||
class="ps-i18n-links--link <#if locale.current == l.label >ps-i18n-links--link_active</#if>"
|
||||
href="${l.url}"
|
||||
>${l.label}</a>
|
||||
</li>
|
||||
</#list>
|
||||
</ul>
|
||||
<#if realm.internationalizationEnabled && locale.supported?size gt 1>
|
||||
<select
|
||||
class="ps-i18n-links"
|
||||
id="language-toggle"
|
||||
>
|
||||
<#list locale.supported as l>
|
||||
<option
|
||||
value="${l.url}"
|
||||
<#if locale.current == l.label>selected</#if>
|
||||
>${l.label}</option>
|
||||
</#list>
|
||||
</select>
|
||||
</#if>
|
||||
|
||||
</header>
|
||||
|
||||
<section class="ps-page--section ps-page--section_full">
|
||||
|
||||
<#if !(auth?has_content && auth.showUsername() && !auth.showResetCredentials())>
|
||||
<h1 class="ps-page--title"><#nested "header"></h1>
|
||||
<#if displayRequiredFields>
|
||||
<div class="${properties.kcLabelWrapperClass!} subtitle">
|
||||
<span class="subtitle"><span class="required">*</span> ${msg("requiredFields")}</span>
|
||||
</div>
|
||||
</#if>
|
||||
|
||||
</header>
|
||||
|
||||
<section class="ps-page--section ps-page--section_full">
|
||||
|
||||
<#if !(auth?has_content && auth.showUsername() && !auth.showResetCredentials())>
|
||||
<h1 class="ps-page--title"><#nested "header"></h1>
|
||||
<#if displayRequiredFields>
|
||||
<div class="${properties.kcLabelWrapperClass!} subtitle">
|
||||
<span class="subtitle"><span class="required">*</span> ${msg("requiredFields")}</span>
|
||||
</div>
|
||||
</#if>
|
||||
<#else>
|
||||
<#if displayRequiredFields>
|
||||
<div class="${properties.kcContentWrapperClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!} subtitle">
|
||||
<span class="subtitle"><span class="required">*</span> ${msg("requiredFields")}</span>
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
<#nested "show-username">
|
||||
<div id="kc-username" class="${properties.kcFormGroupClass!}">
|
||||
<label id="kc-attempted-username">${auth.attemptedUsername}</label>
|
||||
<a id="reset-login" href="${url.loginRestartFlowUrl}" aria-label="${msg("restartLoginTooltip")}">
|
||||
<div class="kc-login-tooltip">
|
||||
<i class="${properties.kcResetFlowIcon!}"></i>
|
||||
<span class="kc-tooltip-text">${msg("restartLoginTooltip")}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<#else>
|
||||
<#if displayRequiredFields>
|
||||
<div class="${properties.kcContentWrapperClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!} subtitle">
|
||||
<span class="subtitle"><span class="required">*</span> ${msg("requiredFields")}</span>
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
<#nested "show-username">
|
||||
<div id="kc-username" class="${properties.kcFormGroupClass!}">
|
||||
<label id="kc-attempted-username">${auth.attemptedUsername}</label>
|
||||
<a id="reset-login" href="${url.loginRestartFlowUrl}" aria-label="${msg("restartLoginTooltip")}">
|
||||
<div class="kc-login-tooltip">
|
||||
<i class="${properties.kcResetFlowIcon!}"></i>
|
||||
<span class="kc-tooltip-text">${msg("restartLoginTooltip")}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<#else>
|
||||
<#nested "show-username">
|
||||
<div id="kc-username" class="${properties.kcFormGroupClass!}">
|
||||
<label id="kc-attempted-username">${auth.attemptedUsername}</label>
|
||||
<a id="reset-login" href="${url.loginRestartFlowUrl}" aria-label="${msg("restartLoginTooltip")}">
|
||||
<div class="kc-login-tooltip">
|
||||
<i class="${properties.kcResetFlowIcon!}"></i>
|
||||
<span class="kc-tooltip-text">${msg("restartLoginTooltip")}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</#if>
|
||||
<#nested "show-username">
|
||||
<div class="ps-login-flow-pre">
|
||||
<div class="ps-login-flow-pre--selected">${auth.attemptedUsername}</div>
|
||||
<a
|
||||
id="reset-login"
|
||||
href="${url.loginRestartFlowUrl}"
|
||||
aria-label="${msg("restartLoginTooltip")}"
|
||||
class="ps-login-flow-pre--cancel ps-link"
|
||||
>
|
||||
${msg("restartLoginTooltip")}
|
||||
</a>
|
||||
</div>
|
||||
</#if>
|
||||
</#if>
|
||||
|
||||
<div class="ps-page--section-contents ps-container">
|
||||
<div class="ps-page--section-contents ps-container">
|
||||
|
||||
<#-- App-initiated actions should not see warning messages about the need to complete the action -->
|
||||
<#-- during login. -->
|
||||
<#if displayMessage && message?has_content && (message.type != 'warning' || !isAppInitiatedAction??)>
|
||||
<div class="alert-${message.type} ${properties.kcAlertClass!} pf-m-<#if message.type = 'error'>danger<#else>${message.type}</#if>">
|
||||
<div class="pf-c-alert__icon">
|
||||
<#if message.type = 'success'><span class="${properties.kcFeedbackSuccessIcon!}"></span></#if>
|
||||
<#if message.type = 'warning'><span class="${properties.kcFeedbackWarningIcon!}"></span></#if>
|
||||
<#if message.type = 'error'><span class="${properties.kcFeedbackErrorIcon!}"></span></#if>
|
||||
<#if message.type = 'info'><span class="${properties.kcFeedbackInfoIcon!}"></span></#if>
|
||||
</div>
|
||||
<span class="${properties.kcAlertTitleClass!}">${kcSanitize(message.summary)?no_esc}</span>
|
||||
</div>
|
||||
</#if>
|
||||
|
||||
<#nested "form">
|
||||
|
||||
<#if auth?has_content && auth.showTryAnotherWayLink()>
|
||||
<form id="kc-select-try-another-way-form" action="${url.loginAction}" method="post">
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<input type="hidden" name="tryAnotherWay" value="on"/>
|
||||
<a href="#" id="try-another-way"
|
||||
onclick="document.forms['kc-select-try-another-way-form'].submit();return false;">${msg("doTryAnotherWay")}</a>
|
||||
</div>
|
||||
</form>
|
||||
</#if>
|
||||
|
||||
<#nested "socialProviders">
|
||||
|
||||
<#if displayInfo>
|
||||
<div id="kc-info" class="${properties.kcSignUpClass!}">
|
||||
<div id="kc-info-wrapper" class="${properties.kcInfoAreaWrapperClass!}">
|
||||
<#nested "info">
|
||||
</div>
|
||||
</div>
|
||||
</#if>
|
||||
<#-- App-initiated actions should not see warning messages about the need to complete the action -->
|
||||
<#-- during login. -->
|
||||
<#if displayMessage && message?has_content && (message.type != 'warning' || !isAppInitiatedAction??)>
|
||||
<div class="alert-${message.type} ${properties.kcAlertClass!} pf-m-<#if message.type = 'error'>danger<#else>${message.type}</#if>">
|
||||
<div class="pf-c-alert__icon">
|
||||
<#if message.type = 'success'><span class="${properties.kcFeedbackSuccessIcon!}"></span></#if>
|
||||
<#if message.type = 'warning'><span class="${properties.kcFeedbackWarningIcon!}"></span></#if>
|
||||
<#if message.type = 'error'><span class="${properties.kcFeedbackErrorIcon!}"></span></#if>
|
||||
<#if message.type = 'info'><span class="${properties.kcFeedbackInfoIcon!}"></span></#if>
|
||||
</div>
|
||||
<span class="${properties.kcAlertTitleClass!}">${kcSanitize(message.summary)?no_esc}</span>
|
||||
</div>
|
||||
</section>
|
||||
</#if>
|
||||
|
||||
<#nested "form">
|
||||
|
||||
<#if auth?has_content && auth.showTryAnotherWayLink()>
|
||||
<form id="kc-select-try-another-way-form" action="${url.loginAction}" method="post">
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<input type="hidden" name="tryAnotherWay" value="on"/>
|
||||
<a
|
||||
href="#"
|
||||
id="try-another-way"
|
||||
onclick="document.forms['kc-select-try-another-way-form'].submit();return false;"
|
||||
>${msg("doTryAnotherWay")}</a>
|
||||
</div>
|
||||
</form>
|
||||
</#if>
|
||||
|
||||
<#nested "socialProviders">
|
||||
|
||||
<#if displayInfo>
|
||||
<div id="kc-info" class="${properties.kcSignUpClass!}">
|
||||
<div id="kc-info-wrapper" class="${properties.kcInfoAreaWrapperClass!}">
|
||||
<#nested "info">
|
||||
</div>
|
||||
</div>
|
||||
</#if>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,168 +1,168 @@
|
|||
<#import "template.ftl" as layout>
|
||||
<@layout.registrationLayout; section>
|
||||
<#if section = "title">
|
||||
title
|
||||
<#elseif section = "header">
|
||||
${kcSanitize(msg("webauthn-login-title"))?no_esc}
|
||||
<#elseif section = "form">
|
||||
<div id="kc-form-webauthn" class="${properties.kcFormClass!}">
|
||||
<form id="webauth" action="${url.loginAction}" method="post">
|
||||
<input type="hidden" id="clientDataJSON" name="clientDataJSON"/>
|
||||
<input type="hidden" id="authenticatorData" name="authenticatorData"/>
|
||||
<input type="hidden" id="signature" name="signature"/>
|
||||
<input type="hidden" id="credentialId" name="credentialId"/>
|
||||
<input type="hidden" id="userHandle" name="userHandle"/>
|
||||
<input type="hidden" id="error" name="error"/>
|
||||
</form>
|
||||
<#import "template.ftl" as layout>
|
||||
<@layout.registrationLayout; section>
|
||||
<#if section = "title">
|
||||
title
|
||||
<#elseif section = "header">
|
||||
${kcSanitize(msg("webauthn-login-title"))?no_esc}
|
||||
<#elseif section = "form">
|
||||
<div id="kc-form-webauthn" class="${properties.kcFormClass!}">
|
||||
<form id="webauth" action="${url.loginAction}" method="post">
|
||||
<input type="hidden" id="clientDataJSON" name="clientDataJSON"/>
|
||||
<input type="hidden" id="authenticatorData" name="authenticatorData"/>
|
||||
<input type="hidden" id="signature" name="signature"/>
|
||||
<input type="hidden" id="credentialId" name="credentialId"/>
|
||||
<input type="hidden" id="userHandle" name="userHandle"/>
|
||||
<input type="hidden" id="error" name="error"/>
|
||||
</form>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!} no-bottom-margin">
|
||||
<#if authenticators??>
|
||||
<form id="authn_select" class="${properties.kcFormClass!}">
|
||||
<#list authenticators.authenticators as authenticator>
|
||||
<input type="hidden" name="authn_use_chk" value="${authenticator.credentialId}"/>
|
||||
<div class="${properties.kcFormGroupClass!} no-bottom-margin">
|
||||
<#if authenticators??>
|
||||
<form id="authn_select" class="${properties.kcFormClass!}">
|
||||
<#list authenticators.authenticators as authenticator>
|
||||
<input type="hidden" name="authn_use_chk" value="${authenticator.credentialId}"/>
|
||||
</#list>
|
||||
</form>
|
||||
|
||||
<#if shouldDisplayAuthenticators?? && shouldDisplayAuthenticators>
|
||||
<#if authenticators.authenticators?size gt 1>
|
||||
<p class="${properties.kcSelectAuthListItemTitle!}">${kcSanitize(msg("webauthn-available-authenticators"))?no_esc}</p>
|
||||
</#if>
|
||||
|
||||
<div class="${properties.kcFormClass!}">
|
||||
<#list authenticators.authenticators as authenticator>
|
||||
<div id="kc-webauthn-authenticator" class="${properties.kcSelectAuthListItemClass!}">
|
||||
<div class="${properties.kcSelectAuthListItemIconClass!}">
|
||||
<i class="${(properties['${authenticator.transports.iconClass}'])!'${properties.kcWebAuthnDefaultIcon!}'} ${properties.kcSelectAuthListItemIconPropertyClass!}"></i>
|
||||
</div>
|
||||
<div class="${properties.kcSelectAuthListItemBodyClass!}">
|
||||
<div id="kc-webauthn-authenticator-label"
|
||||
class="${properties.kcSelectAuthListItemHeadingClass!}">
|
||||
${kcSanitize(msg('${authenticator.label}'))?no_esc}
|
||||
</div>
|
||||
|
||||
<#if authenticator.transports?? && authenticator.transports.displayNameProperties?has_content>
|
||||
<div id="kc-webauthn-authenticator-transport"
|
||||
class="${properties.kcSelectAuthListItemDescriptionClass!}">
|
||||
<#list authenticator.transports.displayNameProperties as nameProperty>
|
||||
<span>${kcSanitize(msg('${nameProperty!}'))?no_esc}</span>
|
||||
<#if nameProperty?has_next>
|
||||
<span>, </span>
|
||||
</#if>
|
||||
</#list>
|
||||
</form>
|
||||
|
||||
<#if shouldDisplayAuthenticators?? && shouldDisplayAuthenticators>
|
||||
<#if authenticators.authenticators?size gt 1>
|
||||
<p class="${properties.kcSelectAuthListItemTitle!}">${kcSanitize(msg("webauthn-available-authenticators"))?no_esc}</p>
|
||||
</#if>
|
||||
|
||||
<div class="${properties.kcFormClass!}">
|
||||
<#list authenticators.authenticators as authenticator>
|
||||
<div id="kc-webauthn-authenticator" class="${properties.kcSelectAuthListItemClass!}">
|
||||
<div class="${properties.kcSelectAuthListItemIconClass!}">
|
||||
<i class="${(properties['${authenticator.transports.iconClass}'])!'${properties.kcWebAuthnDefaultIcon!}'} ${properties.kcSelectAuthListItemIconPropertyClass!}"></i>
|
||||
</div>
|
||||
<div class="${properties.kcSelectAuthListItemBodyClass!}">
|
||||
<div id="kc-webauthn-authenticator-label"
|
||||
class="${properties.kcSelectAuthListItemHeadingClass!}">
|
||||
${kcSanitize(msg('${authenticator.label}'))?no_esc}
|
||||
</div>
|
||||
|
||||
<#if authenticator.transports?? && authenticator.transports.displayNameProperties?has_content>
|
||||
<div id="kc-webauthn-authenticator-transport"
|
||||
class="${properties.kcSelectAuthListItemDescriptionClass!}">
|
||||
<#list authenticator.transports.displayNameProperties as nameProperty>
|
||||
<span>${kcSanitize(msg('${nameProperty!}'))?no_esc}</span>
|
||||
<#if nameProperty?has_next>
|
||||
<span>, </span>
|
||||
</#if>
|
||||
</#list>
|
||||
</div>
|
||||
</#if>
|
||||
|
||||
<div class="${properties.kcSelectAuthListItemDescriptionClass!}">
|
||||
<span id="kc-webauthn-authenticator-created-label">
|
||||
${kcSanitize(msg('webauthn-createdAt-label'))?no_esc}
|
||||
</span>
|
||||
<span id="kc-webauthn-authenticator-created">
|
||||
${kcSanitize(authenticator.createdAt)?no_esc}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="${properties.kcSelectAuthListItemFillClass!}"></div>
|
||||
</div>
|
||||
</#list>
|
||||
</div>
|
||||
</div>
|
||||
</#if>
|
||||
</#if>
|
||||
|
||||
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
|
||||
<input id="authenticateWebAuthnButton" type="button" onclick="webAuthnAuthenticate()" autofocus="autofocus"
|
||||
value="${kcSanitize(msg("webauthn-doAuthenticate"))}"
|
||||
class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}"/>
|
||||
<div class="${properties.kcSelectAuthListItemDescriptionClass!}">
|
||||
<span id="kc-webauthn-authenticator-created-label">
|
||||
${kcSanitize(msg('webauthn-createdAt-label'))?no_esc}
|
||||
</span>
|
||||
<span id="kc-webauthn-authenticator-created">
|
||||
${kcSanitize(authenticator.createdAt)?no_esc}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="${properties.kcSelectAuthListItemFillClass!}"></div>
|
||||
</div>
|
||||
</#list>
|
||||
</div>
|
||||
</#if>
|
||||
</#if>
|
||||
|
||||
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
|
||||
<input id="authenticateWebAuthnButton" type="button" onclick="webAuthnAuthenticate()" autofocus="autofocus"
|
||||
value="${kcSanitize(msg("webauthn-doAuthenticate"))}"
|
||||
class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="${url.resourcesCommonPath}/node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="${url.resourcesPath}/js/base64url.js"></script>
|
||||
<script type="text/javascript">
|
||||
function webAuthnAuthenticate() {
|
||||
let isUserIdentified = ${isUserIdentified};
|
||||
if (!isUserIdentified) {
|
||||
doAuthenticate([]);
|
||||
return;
|
||||
}
|
||||
checkAllowCredentials();
|
||||
}
|
||||
|
||||
function checkAllowCredentials() {
|
||||
let allowCredentials = [];
|
||||
let authn_use = document.forms['authn_select'].authn_use_chk;
|
||||
|
||||
if (authn_use !== undefined) {
|
||||
if (authn_use.length === undefined) {
|
||||
allowCredentials.push({
|
||||
id: base64url.decode(authn_use.value, {loose: true}),
|
||||
type: 'public-key',
|
||||
});
|
||||
} else {
|
||||
for (let i = 0; i < authn_use.length; i++) {
|
||||
allowCredentials.push({
|
||||
id: base64url.decode(authn_use[i].value, {loose: true}),
|
||||
type: 'public-key',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
doAuthenticate(allowCredentials);
|
||||
}
|
||||
|
||||
|
||||
function doAuthenticate(allowCredentials) {
|
||||
|
||||
// Check if WebAuthn is supported by this browser
|
||||
if (!window.PublicKeyCredential) {
|
||||
$("#error").val("${msg("webauthn-unsupported-browser-text")?no_esc}");
|
||||
$("#webauth").submit();
|
||||
return;
|
||||
}
|
||||
|
||||
let challenge = "${challenge}";
|
||||
let userVerification = "${userVerification}";
|
||||
let rpId = "${rpId}";
|
||||
let publicKey = {
|
||||
rpId : rpId,
|
||||
challenge: base64url.decode(challenge, { loose: true })
|
||||
};
|
||||
|
||||
let createTimeout = ${createTimeout};
|
||||
if (createTimeout !== 0) publicKey.timeout = createTimeout * 1000;
|
||||
|
||||
if (allowCredentials.length) {
|
||||
publicKey.allowCredentials = allowCredentials;
|
||||
}
|
||||
|
||||
if (userVerification !== 'not specified') publicKey.userVerification = userVerification;
|
||||
|
||||
navigator.credentials.get({publicKey})
|
||||
.then((result) => {
|
||||
window.result = result;
|
||||
|
||||
let clientDataJSON = result.response.clientDataJSON;
|
||||
let authenticatorData = result.response.authenticatorData;
|
||||
let signature = result.response.signature;
|
||||
|
||||
$("#clientDataJSON").val(base64url.encode(new Uint8Array(clientDataJSON), { pad: false }));
|
||||
$("#authenticatorData").val(base64url.encode(new Uint8Array(authenticatorData), { pad: false }));
|
||||
$("#signature").val(base64url.encode(new Uint8Array(signature), { pad: false }));
|
||||
$("#credentialId").val(result.id);
|
||||
if(result.response.userHandle) {
|
||||
$("#userHandle").val(base64url.encode(new Uint8Array(result.response.userHandle), { pad: false }));
|
||||
}
|
||||
$("#webauth").submit();
|
||||
})
|
||||
.catch((err) => {
|
||||
$("#error").val(err);
|
||||
$("#webauth").submit();
|
||||
})
|
||||
;
|
||||
<script type="text/javascript" src="${url.resourcesCommonPath}/node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="${url.resourcesPath}/js/base64url.js"></script>
|
||||
<script type="text/javascript">
|
||||
function webAuthnAuthenticate() {
|
||||
let isUserIdentified = ${isUserIdentified};
|
||||
if (!isUserIdentified) {
|
||||
doAuthenticate([]);
|
||||
return;
|
||||
}
|
||||
checkAllowCredentials();
|
||||
}
|
||||
|
||||
</script>
|
||||
<#elseif section = "info">
|
||||
function checkAllowCredentials() {
|
||||
let allowCredentials = [];
|
||||
let authn_use = document.forms['authn_select'].authn_use_chk;
|
||||
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
||||
if (authn_use !== undefined) {
|
||||
if (authn_use.length === undefined) {
|
||||
allowCredentials.push({
|
||||
id: base64url.decode(authn_use.value, {loose: true}),
|
||||
type: 'public-key',
|
||||
});
|
||||
} else {
|
||||
for (let i = 0; i < authn_use.length; i++) {
|
||||
allowCredentials.push({
|
||||
id: base64url.decode(authn_use[i].value, {loose: true}),
|
||||
type: 'public-key',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
doAuthenticate(allowCredentials);
|
||||
}
|
||||
|
||||
|
||||
function doAuthenticate(allowCredentials) {
|
||||
|
||||
// Check if WebAuthn is supported by this browser
|
||||
if (!window.PublicKeyCredential) {
|
||||
$("#error").val("${msg("webauthn-unsupported-browser-text")?no_esc}");
|
||||
$("#webauth").submit();
|
||||
return;
|
||||
}
|
||||
|
||||
let challenge = "${challenge}";
|
||||
let userVerification = "${userVerification}";
|
||||
let rpId = "${rpId}";
|
||||
let publicKey = {
|
||||
rpId : rpId,
|
||||
challenge: base64url.decode(challenge, { loose: true })
|
||||
};
|
||||
|
||||
let createTimeout = ${createTimeout};
|
||||
if (createTimeout !== 0) publicKey.timeout = createTimeout * 1000;
|
||||
|
||||
if (allowCredentials.length) {
|
||||
publicKey.allowCredentials = allowCredentials;
|
||||
}
|
||||
|
||||
if (userVerification !== 'not specified') publicKey.userVerification = userVerification;
|
||||
|
||||
navigator.credentials.get({publicKey})
|
||||
.then((result) => {
|
||||
window.result = result;
|
||||
|
||||
let clientDataJSON = result.response.clientDataJSON;
|
||||
let authenticatorData = result.response.authenticatorData;
|
||||
let signature = result.response.signature;
|
||||
|
||||
$("#clientDataJSON").val(base64url.encode(new Uint8Array(clientDataJSON), { pad: false }));
|
||||
$("#authenticatorData").val(base64url.encode(new Uint8Array(authenticatorData), { pad: false }));
|
||||
$("#signature").val(base64url.encode(new Uint8Array(signature), { pad: false }));
|
||||
$("#credentialId").val(result.id);
|
||||
if(result.response.userHandle) {
|
||||
$("#userHandle").val(base64url.encode(new Uint8Array(result.response.userHandle), { pad: false }));
|
||||
}
|
||||
$("#webauth").submit();
|
||||
})
|
||||
.catch((err) => {
|
||||
$("#error").val(err);
|
||||
$("#webauth").submit();
|
||||
})
|
||||
;
|
||||
}
|
||||
|
||||
</script>
|
||||
<#elseif section = "info">
|
||||
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
||||
|
|
Loading…
Reference in a new issue