commit 8d57c286753c029a6ce8ecd46e8da3e99a1b7e42 Author: max Date: Thu Oct 3 21:27:06 2024 +0000 new diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/keywind/login/assets/icons/arrow-top-right-on-square.ftl b/keywind/login/assets/icons/arrow-top-right-on-square.ftl new file mode 100644 index 0000000..81c4bf8 --- /dev/null +++ b/keywind/login/assets/icons/arrow-top-right-on-square.ftl @@ -0,0 +1,7 @@ +<#-- https://github.com/tailwindlabs/heroicons/blob/master/src/20/solid/arrow-top-right-on-square.svg --> +<#macro kw> + + + + + diff --git a/keywind/login/assets/icons/chevron-down.ftl b/keywind/login/assets/icons/chevron-down.ftl new file mode 100644 index 0000000..673ef11 --- /dev/null +++ b/keywind/login/assets/icons/chevron-down.ftl @@ -0,0 +1,6 @@ +<#-- https://github.com/tailwindlabs/heroicons/blob/master/src/20/solid/chevron-down.svg --> +<#macro kw> + + + + diff --git a/keywind/login/assets/icons/eye-slash.ftl b/keywind/login/assets/icons/eye-slash.ftl new file mode 100644 index 0000000..74a9f78 --- /dev/null +++ b/keywind/login/assets/icons/eye-slash.ftl @@ -0,0 +1,7 @@ +<#-- https://github.com/tailwindlabs/heroicons/blob/master/src/20/solid/eye.svg --> +<#macro kw> + + + + + diff --git a/keywind/login/assets/icons/eye.ftl b/keywind/login/assets/icons/eye.ftl new file mode 100644 index 0000000..0bd4d06 --- /dev/null +++ b/keywind/login/assets/icons/eye.ftl @@ -0,0 +1,7 @@ +<#-- https://github.com/tailwindlabs/heroicons/blob/master/src/20/solid/eye.svg --> +<#macro kw> + + + + + diff --git a/keywind/login/assets/providers/apple.ftl b/keywind/login/assets/providers/apple.ftl new file mode 100644 index 0000000..2444359 --- /dev/null +++ b/keywind/login/assets/providers/apple.ftl @@ -0,0 +1,7 @@ +<#-- https://apple.com --> +<#macro kw name="Apple"> + + ${name} + + + diff --git a/keywind/login/assets/providers/bitbucket.ftl b/keywind/login/assets/providers/bitbucket.ftl new file mode 100644 index 0000000..068bc73 --- /dev/null +++ b/keywind/login/assets/providers/bitbucket.ftl @@ -0,0 +1,14 @@ +<#-- https://atlassian.design/resources/logo-library --> +<#macro kw name="Bitbucket"> + + ${name} + + + + + + + + + + diff --git a/keywind/login/assets/providers/discord.ftl b/keywind/login/assets/providers/discord.ftl new file mode 100644 index 0000000..8ebecaa --- /dev/null +++ b/keywind/login/assets/providers/discord.ftl @@ -0,0 +1,7 @@ +<#-- https://discord.com/branding --> +<#macro kw name="Discord"> + + ${name} + + + diff --git a/keywind/login/assets/providers/facebook.ftl b/keywind/login/assets/providers/facebook.ftl new file mode 100644 index 0000000..bc692e7 --- /dev/null +++ b/keywind/login/assets/providers/facebook.ftl @@ -0,0 +1,8 @@ +<#-- https://www.facebook.com/brand/resources/facebookapp/logo --> +<#macro kw name="Facebook"> + + ${name} + + + + diff --git a/keywind/login/assets/providers/github.ftl b/keywind/login/assets/providers/github.ftl new file mode 100644 index 0000000..9523103 --- /dev/null +++ b/keywind/login/assets/providers/github.ftl @@ -0,0 +1,7 @@ +<#-- https://github.com/logos --> +<#macro kw name="GitHub"> + + ${name} + + + diff --git a/keywind/login/assets/providers/gitlab.ftl b/keywind/login/assets/providers/gitlab.ftl new file mode 100644 index 0000000..4acfc13 --- /dev/null +++ b/keywind/login/assets/providers/gitlab.ftl @@ -0,0 +1,10 @@ +<#-- https://about.gitlab.com/press/press-kit --> +<#macro kw name="GitLab"> + + ${name} + + + + + + diff --git a/keywind/login/assets/providers/google.ftl b/keywind/login/assets/providers/google.ftl new file mode 100644 index 0000000..b536cdb --- /dev/null +++ b/keywind/login/assets/providers/google.ftl @@ -0,0 +1,10 @@ +<#-- https://developers.google.com/identity/branding-guidelines --> +<#macro kw name="Google"> + + ${name} + + + + + + diff --git a/keywind/login/assets/providers/instagram.ftl b/keywind/login/assets/providers/instagram.ftl new file mode 100644 index 0000000..c4996d8 --- /dev/null +++ b/keywind/login/assets/providers/instagram.ftl @@ -0,0 +1,35 @@ +<#-- https://www.facebook.com/brand/resources/instagram/instagram-brand --> +<#macro kw name="Instagram"> + + ${name} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/keywind/login/assets/providers/linkedin.ftl b/keywind/login/assets/providers/linkedin.ftl new file mode 100644 index 0000000..944d143 --- /dev/null +++ b/keywind/login/assets/providers/linkedin.ftl @@ -0,0 +1,7 @@ +<#-- https://brand.linkedin.com/downloads --> +<#macro kw name="LinkedIn"> + + ${name} + + + diff --git a/keywind/login/assets/providers/microsoft.ftl b/keywind/login/assets/providers/microsoft.ftl new file mode 100644 index 0000000..408635b --- /dev/null +++ b/keywind/login/assets/providers/microsoft.ftl @@ -0,0 +1,10 @@ +<#-- https://learn.microsoft.com/azure/active-directory/develop/howto-add-branding-in-azure-ad-apps --> +<#macro kw name="Microsoft"> + + ${name} + + + + + + diff --git a/keywind/login/assets/providers/oidc.ftl b/keywind/login/assets/providers/oidc.ftl new file mode 100644 index 0000000..f7954ff --- /dev/null +++ b/keywind/login/assets/providers/oidc.ftl @@ -0,0 +1,9 @@ +<#-- https://openid.net/add-openid/logos --> +<#macro kw name="OpenID"> + + ${name} + + + + + diff --git a/keywind/login/assets/providers/openshift.ftl b/keywind/login/assets/providers/openshift.ftl new file mode 100644 index 0000000..e85ddef --- /dev/null +++ b/keywind/login/assets/providers/openshift.ftl @@ -0,0 +1,11 @@ +<#-- https://www.redhat.com/technologies/cloud-computing/openshift --> +<#macro kw name="Red Hat OpenShift"> + + ${name} + + + + + + + diff --git a/keywind/login/assets/providers/paypal.ftl b/keywind/login/assets/providers/paypal.ftl new file mode 100644 index 0000000..7946e03 --- /dev/null +++ b/keywind/login/assets/providers/paypal.ftl @@ -0,0 +1,9 @@ +<#-- https://www.paypal.com --> +<#macro kw name="PayPal"> + + ${name} + + + + + diff --git a/keywind/login/assets/providers/providers.ftl b/keywind/login/assets/providers/providers.ftl new file mode 100644 index 0000000..b2d943a --- /dev/null +++ b/keywind/login/assets/providers/providers.ftl @@ -0,0 +1,84 @@ +<#import "./apple.ftl" as appleIcon> +<#import "./bitbucket.ftl" as bitbucketIcon> +<#import "./discord.ftl" as discordIcon> +<#import "./facebook.ftl" as facebookIcon> +<#import "./github.ftl" as githubIcon> +<#import "./gitlab.ftl" as gitlabIcon> +<#import "./google.ftl" as googleIcon> +<#import "./instagram.ftl" as instagramIcon> +<#import "./linkedin.ftl" as linkedinIcon> +<#import "./microsoft.ftl" as microsoftIcon> +<#import "./oidc.ftl" as oidcIcon> +<#import "./openshift.ftl" as openshiftIcon> +<#import "./paypal.ftl" as paypalIcon> +<#import "./slack.ftl" as slackIcon> +<#import "./stackoverflow.ftl" as stackoverflowIcon> +<#import "./twitter.ftl" as twitterIcon> + +<#macro apple> + <@appleIcon.kw /> + + +<#macro bitbucket> + <@bitbucketIcon.kw /> + + +<#macro discord> + <@discordIcon.kw /> + + +<#macro facebook> + <@facebookIcon.kw /> + + +<#macro github> + <@githubIcon.kw /> + + +<#macro gitlab> + <@gitlabIcon.kw /> + + +<#macro google> + <@googleIcon.kw /> + + +<#macro instagram> + <@instagramIcon.kw /> + + +<#macro "linkedin-openid-connect"> + <@linkedinIcon.kw /> + + +<#macro microsoft> + <@microsoftIcon.kw /> + + +<#macro oidc> + <@oidcIcon.kw /> + + +<#macro "openshift-v3"> + <@openshiftIcon.kw /> + + +<#macro "openshift-v4"> + <@openshiftIcon.kw /> + + +<#macro paypal> + <@paypalIcon.kw /> + + +<#macro slack> + <@slackIcon.kw /> + + +<#macro stackoverflow> + <@stackoverflowIcon.kw /> + + +<#macro twitter> + <@twitterIcon.kw /> + diff --git a/keywind/login/assets/providers/slack.ftl b/keywind/login/assets/providers/slack.ftl new file mode 100644 index 0000000..d4dffe3 --- /dev/null +++ b/keywind/login/assets/providers/slack.ftl @@ -0,0 +1,14 @@ +<#-- https://slack.com/media-kit --> +<#macro kw name="Slack"> + + ${name} + + + + + + + + + + diff --git a/keywind/login/assets/providers/stackoverflow.ftl b/keywind/login/assets/providers/stackoverflow.ftl new file mode 100644 index 0000000..1ffad8d --- /dev/null +++ b/keywind/login/assets/providers/stackoverflow.ftl @@ -0,0 +1,8 @@ +<#-- https://stackoverflow.design/brand/logo --> +<#macro kw name="Stack Overflow"> + + ${name} + + + + diff --git a/keywind/login/assets/providers/twitter.ftl b/keywind/login/assets/providers/twitter.ftl new file mode 100644 index 0000000..2bc7e7e --- /dev/null +++ b/keywind/login/assets/providers/twitter.ftl @@ -0,0 +1,7 @@ +<#-- https://about.twitter.com/en/who-we-are/brand-toolkit --> +<#macro kw name="Twitter"> + + ${name} + + + diff --git a/keywind/login/components/atoms/alert.ftl b/keywind/login/components/atoms/alert.ftl new file mode 100644 index 0000000..58e8309 --- /dev/null +++ b/keywind/login/components/atoms/alert.ftl @@ -0,0 +1,22 @@ +<#macro kw color=""> + <#switch color> + <#case "error"> + <#assign colorClass="bg-red-100 text-red-600"> + <#break> + <#case "info"> + <#assign colorClass="bg-blue-100 text-blue-600"> + <#break> + <#case "success"> + <#assign colorClass="bg-green-100 text-green-600"> + <#break> + <#case "warning"> + <#assign colorClass="bg-orange-100 text-orange-600"> + <#break> + <#default> + <#assign colorClass="bg-blue-100 text-blue-600"> + + + + diff --git a/keywind/login/components/atoms/body.ftl b/keywind/login/components/atoms/body.ftl new file mode 100644 index 0000000..dcc94a0 --- /dev/null +++ b/keywind/login/components/atoms/body.ftl @@ -0,0 +1,5 @@ +<#macro kw> + + <#nested> + + diff --git a/keywind/login/components/atoms/button-group.ftl b/keywind/login/components/atoms/button-group.ftl new file mode 100644 index 0000000..4591209 --- /dev/null +++ b/keywind/login/components/atoms/button-group.ftl @@ -0,0 +1,5 @@ +<#macro kw> +
+ <#nested> +
+ diff --git a/keywind/login/components/atoms/button.ftl b/keywind/login/components/atoms/button.ftl new file mode 100644 index 0000000..eeb0af7 --- /dev/null +++ b/keywind/login/components/atoms/button.ftl @@ -0,0 +1,33 @@ +<#macro kw color="" component="button" size="" rest...> + <#switch color> + <#case "primary"> + <#assign colorClass="bg-primary-600 text-white focus:ring-primary-600 hover:bg-primary-700"> + <#break> + <#case "secondary"> + <#assign colorClass="bg-secondary-100 text-secondary-600 focus:ring-secondary-600 hover:bg-secondary-200 hover:text-secondary-900"> + <#break> + <#default> + <#assign colorClass="bg-primary-600 text-white focus:ring-primary-600 hover:bg-primary-700"> + + + <#switch size> + <#case "medium"> + <#assign sizeClass="px-4 py-2 text-sm"> + <#break> + <#case "small"> + <#assign sizeClass="px-2 py-1 text-xs"> + <#break> + <#default> + <#assign sizeClass="px-4 py-2 text-sm"> + + + <${component} + class="${colorClass} ${sizeClass} flex justify-center relative rounded-lg w-full focus:outline-none focus:ring-2 focus:ring-offset-2" + + <#list rest as attrName, attrValue> + ${attrName}="${attrValue}" + + > + <#nested> + + diff --git a/keywind/login/components/atoms/card.ftl b/keywind/login/components/atoms/card.ftl new file mode 100644 index 0000000..c1e808d --- /dev/null +++ b/keywind/login/components/atoms/card.ftl @@ -0,0 +1,19 @@ +<#macro kw content="" footer="" header=""> +
+ <#if header?has_content> +
+ ${header} +
+ + <#if content?has_content> +
+ ${content} +
+ + <#if footer?has_content> +
+ ${footer} +
+ +
+ diff --git a/keywind/login/components/atoms/checkbox.ftl b/keywind/login/components/atoms/checkbox.ftl new file mode 100644 index 0000000..e47fd61 --- /dev/null +++ b/keywind/login/components/atoms/checkbox.ftl @@ -0,0 +1,19 @@ +<#macro kw checked=false label="" name="" rest...> +
+ checked + + class="border-secondary-200 h-4 rounded text-primary-600 w-4 focus:ring-primary-200 focus:ring-opacity-50" + id="${name}" + name="${name}" + type="checkbox" + + <#list rest as attrName, attrValue> + ${attrName}="${attrValue}" + + > + +
+ diff --git a/keywind/login/components/atoms/container.ftl b/keywind/login/components/atoms/container.ftl new file mode 100644 index 0000000..34ead18 --- /dev/null +++ b/keywind/login/components/atoms/container.ftl @@ -0,0 +1,5 @@ +<#macro kw> +
+ <#nested> +
+ diff --git a/keywind/login/components/atoms/form.ftl b/keywind/login/components/atoms/form.ftl new file mode 100644 index 0000000..014bb4f --- /dev/null +++ b/keywind/login/components/atoms/form.ftl @@ -0,0 +1,11 @@ +<#macro kw rest...> +
+ ${attrName}="${attrValue}" + + > + <#nested> +
+ diff --git a/keywind/login/components/atoms/heading.ftl b/keywind/login/components/atoms/heading.ftl new file mode 100644 index 0000000..7665c01 --- /dev/null +++ b/keywind/login/components/atoms/heading.ftl @@ -0,0 +1,5 @@ +<#macro kw> +

+ <#nested> +

+ diff --git a/keywind/login/components/atoms/input.ftl b/keywind/login/components/atoms/input.ftl new file mode 100644 index 0000000..714f832 --- /dev/null +++ b/keywind/login/components/atoms/input.ftl @@ -0,0 +1,78 @@ +<#import "/assets/icons/eye.ftl" as iconEye> +<#import "/assets/icons/eye-slash.ftl" as iconEyeSlash> + +<#macro + kw + autofocus=false + class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" + disabled=false + invalid=false + label="" + message="" + name="" + required=true + type="text" + rest... +> +
+ + <#if type == "password"> +
+ autofocus + <#if disabled>disabled + <#if required>required + + aria-invalid="${invalid?c}" + class="${class}" + id="${name}" + name="${name}" + placeholder="${label}" + :type="show ? 'text' : 'password'" + + <#list rest as attrName, attrValue> + ${attrName}="${attrValue}" + + > + +
+ <#else> + autofocus + <#if disabled>disabled + <#if required>required + + aria-invalid="${invalid?c}" + class="${class}" + id="${name}" + name="${name}" + placeholder="${label}" + type="${type}" + + <#list rest as attrName, attrValue> + ${attrName}="${attrValue}" + + > + + <#if invalid?? && message??> +
+ ${message?no_esc} +
+ +
+ diff --git a/keywind/login/components/atoms/link.ftl b/keywind/login/components/atoms/link.ftl new file mode 100644 index 0000000..bde7666 --- /dev/null +++ b/keywind/login/components/atoms/link.ftl @@ -0,0 +1,30 @@ +<#macro kw color="" component="a" size="" rest...> + <#switch color> + <#case "primary"> + <#assign colorClass="text-primary-600 hover:text-primary-500"> + <#break> + <#case "secondary"> + <#assign colorClass="text-secondary-600 hover:text-secondary-900"> + <#break> + <#default> + <#assign colorClass="text-primary-600 hover:text-primary-500"> + + + <#switch size> + <#case "small"> + <#assign sizeClass="text-sm"> + <#break> + <#default> + <#assign sizeClass=""> + + + <${component} + class="<#compress>${colorClass} ${sizeClass} inline-flex" + + <#list rest as attrName, attrValue> + ${attrName}="${attrValue}" + + > + <#nested> + + diff --git a/keywind/login/components/atoms/logo.ftl b/keywind/login/components/atoms/logo.ftl new file mode 100644 index 0000000..f166403 --- /dev/null +++ b/keywind/login/components/atoms/logo.ftl @@ -0,0 +1,5 @@ +<#macro kw> +
+ <#nested> +
+ diff --git a/keywind/login/components/atoms/nav.ftl b/keywind/login/components/atoms/nav.ftl new file mode 100644 index 0000000..81a4abf --- /dev/null +++ b/keywind/login/components/atoms/nav.ftl @@ -0,0 +1,5 @@ +<#macro kw> +
+ <#nested> +
+ diff --git a/keywind/login/components/atoms/radio.ftl b/keywind/login/components/atoms/radio.ftl new file mode 100644 index 0000000..5596d5c --- /dev/null +++ b/keywind/login/components/atoms/radio.ftl @@ -0,0 +1,18 @@ +<#macro kw checked=false id="" label="" rest...> +
+ checked + + class="border-secondary-200 focus:ring-primary-600" + id="${id}" + type="radio" + + <#list rest as attrName, attrValue> + ${attrName}="${attrValue}" + + > + +
+ diff --git a/keywind/login/components/molecules/identity-provider.ftl b/keywind/login/components/molecules/identity-provider.ftl new file mode 100644 index 0000000..b59962e --- /dev/null +++ b/keywind/login/components/molecules/identity-provider.ftl @@ -0,0 +1,81 @@ +<#import "/assets/providers/providers.ftl" as providerIcons> + +<#macro kw providers=[]> +
+ ${msg("identity-provider-login-label")} +
+
+ <#list providers as provider> + <#switch provider.alias> + <#case "apple"> + <#assign colorClass="hover:bg-provider-apple/10"> + <#break> + <#case "bitbucket"> + <#assign colorClass="hover:bg-provider-bitbucket/10"> + <#break> + <#case "discord"> + <#assign colorClass="hover:bg-provider-discord/10"> + <#break> + <#case "facebook"> + <#assign colorClass="hover:bg-provider-facebook/10"> + <#break> + <#case "github"> + <#assign colorClass="hover:bg-provider-github/10"> + <#break> + <#case "gitlab"> + <#assign colorClass="hover:bg-provider-gitlab/10"> + <#break> + <#case "google"> + <#assign colorClass="hover:bg-provider-google/10"> + <#break> + <#case "instagram"> + <#assign colorClass="hover:bg-provider-instagram/10"> + <#break> + <#case "linkedin-openid-connect"> + <#assign colorClass="hover:bg-provider-linkedin/10"> + <#break> + <#case "microsoft"> + <#assign colorClass="hover:bg-provider-microsoft/10"> + <#break> + <#case "oidc"> + <#assign colorClass="hover:bg-provider-oidc/10"> + <#break> + <#case "openshift-v3"> + <#assign colorClass="hover:bg-provider-openshift/10"> + <#break> + <#case "openshift-v4"> + <#assign colorClass="hover:bg-provider-openshift/10"> + <#break> + <#case "paypal"> + <#assign colorClass="hover:bg-provider-paypal/10"> + <#break> + <#case "slack"> + <#assign colorClass="hover:bg-provider-slack/10"> + <#break> + <#case "stackoverflow"> + <#assign colorClass="hover:bg-provider-stackoverflow/10"> + <#break> + <#case "twitter"> + <#assign colorClass="hover:bg-provider-twitter/10"> + <#break> + <#default> + <#assign colorClass="hover:bg-secondary-100"> + + + + <#if providerIcons[provider.alias]??> +
+ <@providerIcons[provider.alias] /> +
+ <#else> + ${provider.displayName!} + +
+ +
+ diff --git a/keywind/login/components/molecules/locale-provider.ftl b/keywind/login/components/molecules/locale-provider.ftl new file mode 100644 index 0000000..198e5be --- /dev/null +++ b/keywind/login/components/molecules/locale-provider.ftl @@ -0,0 +1,29 @@ +<#import "/assets/icons/chevron-down.ftl" as icon> +<#import "/components/atoms/link.ftl" as link> + +<#macro kw currentLocale="" locales=[]> +
+ <@link.kw @click="open = true" color="secondary" component="button" type="button"> +
+ ${currentLocale} + <@icon.kw /> +
+ +
+ <#list locales as locale> + <#if currentLocale != locale.label> +
+ <@link.kw color="secondary" href=locale.url size="small"> + ${locale.label} + +
+ + +
+
+ diff --git a/keywind/login/components/molecules/username.ftl b/keywind/login/components/molecules/username.ftl new file mode 100644 index 0000000..ba63393 --- /dev/null +++ b/keywind/login/components/molecules/username.ftl @@ -0,0 +1,15 @@ +<#import "/assets/icons/arrow-top-right-on-square.ftl" as icon> +<#import "/components/atoms/link.ftl" as link> + +<#macro kw linkHref="" linkTitle="" name=""> +
+ ${name} + <@link.kw + color="primary" + href=linkHref + title=linkTitle + > + <@icon.kw /> + +
+ diff --git a/keywind/login/document.ftl b/keywind/login/document.ftl new file mode 100644 index 0000000..188e16a --- /dev/null +++ b/keywind/login/document.ftl @@ -0,0 +1,35 @@ +<#macro kw script=""> + ${msg("loginTitle", (realm.displayName!""))} + + + + + + <#if properties.meta?has_content> + <#list properties.meta?split(" ") as meta> + + + + + <#if properties.favicons?has_content> + <#list properties.favicons?split(" ") as favicon> + + + + + <#if properties.styles?has_content> + <#list properties.styles?split(" ") as style> + + + + + <#if script?has_content> + + + + <#if properties.scripts?has_content> + <#list properties.scripts?split(" ") as script> + + + + diff --git a/keywind/login/error.ftl b/keywind/login/error.ftl new file mode 100644 index 0000000..52af9c1 --- /dev/null +++ b/keywind/login/error.ftl @@ -0,0 +1,18 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/alert.ftl" as alert> +<#import "components/atoms/link.ftl" as link> + +<@layout.registrationLayout displayMessage=false; section> + <#if section="header"> + ${kcSanitize(msg("errorTitle"))?no_esc} + <#elseif section="form"> + <@alert.kw color="error">${kcSanitize(message.summary)?no_esc} + <#if !skipLink??> + <#if client?? && client.baseUrl?has_content> + <@link.kw color="secondary" href=client.baseUrl size="small"> + ${kcSanitize(msg("backToApplication"))?no_esc} + + + + + diff --git a/keywind/login/features/labels/totp-device.ftl b/keywind/login/features/labels/totp-device.ftl new file mode 100644 index 0000000..98ae12f --- /dev/null +++ b/keywind/login/features/labels/totp-device.ftl @@ -0,0 +1,5 @@ +<#macro kw> + <#compress> + ${msg("loginTotpDeviceName")} <#if totp.otpCredentials?size gte 1>* + + diff --git a/keywind/login/features/labels/totp.ftl b/keywind/login/features/labels/totp.ftl new file mode 100644 index 0000000..be5158e --- /dev/null +++ b/keywind/login/features/labels/totp.ftl @@ -0,0 +1,5 @@ +<#macro kw> + <#compress> + ${msg("authenticatorCode")} * + + diff --git a/keywind/login/features/labels/username.ftl b/keywind/login/features/labels/username.ftl new file mode 100644 index 0000000..6c01d6b --- /dev/null +++ b/keywind/login/features/labels/username.ftl @@ -0,0 +1,11 @@ +<#macro kw> + <#compress> + <#if !realm.loginWithEmailAllowed> + ${msg("username")} + <#elseif !realm.registrationEmailAsUsername> + ${msg("usernameOrEmail")} + <#else> + ${msg("email")} + + + diff --git a/keywind/login/login-config-totp.ftl b/keywind/login/login-config-totp.ftl new file mode 100644 index 0000000..e0b64c6 --- /dev/null +++ b/keywind/login/login-config-totp.ftl @@ -0,0 +1,110 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> +<#import "components/atoms/link.ftl" as link> +<#import "features/labels/totp.ftl" as totpLabel> +<#import "features/labels/totp-device.ftl" as totpDeviceLabel> + +<#assign totpLabel><@totpLabel.kw /> +<#assign totpDeviceLabel><@totpDeviceLabel.kw /> + +<@layout.registrationLayout + displayMessage=!messagesPerField.existsError("totp", "userLabel") + displayRequiredFields=false + ; + section +> + <#if section="header"> + ${msg("loginTotpTitle")} + <#elseif section="form"> +
    +
  1. +

    ${msg("loginTotpStep1")}

    +
      + <#list totp.supportedApplications as app> +
    • ${msg(app)}
    • + +
    +
  2. + <#if mode?? && mode="manual"> +
  3. +

    ${msg("loginTotpManualStep2")}

    +

    ${totp.totpSecretEncoded}

    +
  4. +
  5. + <@link.kw color="primary" href=totp.qrUrl> + ${msg("loginTotpScanBarcode")} + +
  6. +
  7. +

    ${msg("loginTotpManualStep3")}

    +
      +
    • ${msg("loginTotpType")}: ${msg("loginTotp." + totp.policy.type)}
    • +
    • ${msg("loginTotpAlgorithm")}: ${totp.policy.getAlgorithmKey()}
    • +
    • ${msg("loginTotpDigits")}: ${totp.policy.digits}
    • + <#if totp.policy.type="totp"> +
    • ${msg("loginTotpInterval")}: ${totp.policy.period}
    • + <#elseif totp.policy.type="hotp"> +
    • ${msg("loginTotpCounter")}: ${totp.policy.initialCounter}
    • + +
    +
  8. + <#else> +
  9. +

    ${msg("loginTotpStep2")}

    + Figure: Barcode + <@link.kw color="primary" href=totp.manualUrl> + ${msg("loginTotpUnableToScan")} + +
  10. + +
  11. ${msg("loginTotpStep3")}
  12. +
  13. ${msg("loginTotpStep3DeviceName")}
  14. +
+ <@form.kw action=url.loginAction method="post"> + + <#if mode??> + + + <@input.kw + autocomplete="off" + autofocus=true + invalid=messagesPerField.existsError("totp") + label=totpLabel + message=kcSanitize(messagesPerField.get("totp")) + name="totp" + required=false + type="text" + /> + <@input.kw + autocomplete="off" + invalid=messagesPerField.existsError("userLabel") + label=totpDeviceLabel + message=kcSanitize(messagesPerField.get("userLabel")) + name="userLabel" + required=false + type="text" + /> + <@buttonGroup.kw> + <#if isAppInitiatedAction??> + <@button.kw color="primary" type="submit"> + ${msg("doSubmit")} + + <@button.kw color="secondary" name="cancel-aia" type="submit" value="true"> + ${msg("doCancel")} + + <#else> + <@button.kw color="primary" type="submit"> + ${msg("doSubmit")} + + + + + + diff --git a/keywind/login/login-idp-link-confirm.ftl b/keywind/login/login-idp-link-confirm.ftl new file mode 100644 index 0000000..9a2554d --- /dev/null +++ b/keywind/login/login-idp-link-confirm.ftl @@ -0,0 +1,18 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/form.ftl" as form> + +<@layout.registrationLayout; section> + <#if section="header"> + ${msg("confirmLinkIdpTitle")} + <#elseif section="form"> + <@form.kw action=url.loginAction method="post"> + <@button.kw color="primary" name="submitAction" type="submit" value="updateProfile"> + ${msg("confirmLinkIdpReviewProfile")} + + <@button.kw color="primary" name="submitAction" type="submit" value="linkAccount"> + ${msg("confirmLinkIdpContinue", idpDisplayName)} + + + + diff --git a/keywind/login/login-oauth-grant.ftl b/keywind/login/login-oauth-grant.ftl new file mode 100644 index 0000000..aa4173c --- /dev/null +++ b/keywind/login/login-oauth-grant.ftl @@ -0,0 +1,62 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> + +<@layout.registrationLayout; section> + <#if section="header"> + <#if client.attributes.logoUri??> + + +

+ <#if client.name?has_content> + ${msg("oauthGrantTitle", advancedMsg(client.name))} + <#else> + ${msg("oauthGrantTitle", client.clientId)} + +

+ <#elseif section="form"> +

${msg("oauthGrantRequest")}

+ + <#if client.attributes.policyUri?? || client.attributes.tosUri??> +

+ <#if client.name?has_content> + ${msg("oauthGrantInformation",advancedMsg(client.name))} + <#else> + ${msg("oauthGrantInformation",client.clientId)} + + <#if client.attributes.tosUri??> + ${msg("oauthGrantReview")} + ${msg("oauthGrantTos")} + + <#if client.attributes.policyUri??> + ${msg("oauthGrantReview")} + ${msg("oauthGrantPolicy")} + +

+ + <@form.kw action=url.oauthAction method="post"> + + <@buttonGroup.kw> + <@button.kw color="primary" name="accept" type="submit"> + ${msg("doYes")} + + <@button.kw color="secondary" name="cancel" type="submit"> + ${msg("doNo")} + + + + + diff --git a/keywind/login/login-otp.ftl b/keywind/login/login-otp.ftl new file mode 100644 index 0000000..b1bb3b9 --- /dev/null +++ b/keywind/login/login-otp.ftl @@ -0,0 +1,50 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> +<#import "components/atoms/radio.ftl" as radio> +<#import "features/labels/totp.ftl" as totpLabel> + +<#assign totpLabel><@totpLabel.kw /> + +<@layout.registrationLayout + displayMessage=!messagesPerField.existsError("totp") + ; + section +> + <#if section="header"> + ${msg("doLogIn")} + <#elseif section="form"> + <@form.kw action=url.loginAction method="post"> + <#if otpLogin.userOtpCredentials?size gt 1> +
+ <#list otpLogin.userOtpCredentials as otpCredential> + <@radio.kw + checked=(otpCredential.id == otpLogin.selectedCredentialId) + id="kw-otp-credential-${otpCredential?index}" + label=otpCredential.userLabel + name="selectedCredentialId" + tabindex=otpCredential?index + value=otpCredential.id + /> + +
+ + <@input.kw + autocomplete="off" + autofocus=true + invalid=messagesPerField.existsError("totp") + label=totpLabel + message=kcSanitize(messagesPerField.get("totp")) + name="otp" + type="text" + /> + <@buttonGroup.kw> + <@button.kw color="primary" name="submitAction" type="submit"> + ${msg("doLogIn")} + + + + + diff --git a/keywind/login/login-page-expired.ftl b/keywind/login/login-page-expired.ftl new file mode 100644 index 0000000..2b6288d --- /dev/null +++ b/keywind/login/login-page-expired.ftl @@ -0,0 +1,18 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> + +<@layout.registrationLayout; section> + <#if section="header"> + ${msg("pageExpiredTitle")} + <#elseif section="form"> + <@buttonGroup.kw> + <@button.kw color="primary" component="a" href=url.loginRestartFlowUrl> + ${msg("doTryAgain")} + + <@button.kw color="secondary" component="a" href=url.loginAction> + ${msg("doContinue")} + + + + diff --git a/keywind/login/login-password.ftl b/keywind/login/login-password.ftl new file mode 100644 index 0000000..54e7d9d --- /dev/null +++ b/keywind/login/login-password.ftl @@ -0,0 +1,39 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> +<#import "components/atoms/link.ftl" as link> + +<@layout.registrationLayout displayMessage=!messagesPerField.existsError("password"); section> + <#if section="header"> + ${msg("doLogIn")} + <#elseif section="form"> + <@form.kw + action=url.loginAction + method="post" + onsubmit="login.disabled = true; return true;" + > + <@input.kw + autofocus=true + invalid=messagesPerField.existsError("password") + label=msg("password") + message=kcSanitize(messagesPerField.get("password"))?no_esc + name="password" + type="password" + /> + <#if realm.resetPasswordAllowed> +
+ <@link.kw color="primary" href=url.loginResetCredentialsUrl size="small"> + ${msg("doForgotPassword")} + +
+ + <@buttonGroup.kw> + <@button.kw color="primary" name="login" type="submit"> + ${msg("doLogIn")} + + + + + diff --git a/keywind/login/login-recovery-authn-code-config.ftl b/keywind/login/login-recovery-authn-code-config.ftl new file mode 100644 index 0000000..186d710 --- /dev/null +++ b/keywind/login/login-recovery-authn-code-config.ftl @@ -0,0 +1,91 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/alert.ftl" as alert> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/checkbox.ftl" as checkbox> +<#import "components/atoms/form.ftl" as form> + +<@layout.registrationLayout script="dist/recoveryCodes.js"; section> + <#if section="header"> + ${msg("recovery-code-config-header")} + <#elseif section="form"> +
+ <@alert.kw color="warning"> +
+

${msg("recovery-code-config-warning-title")}

+

${msg("recovery-code-config-warning-message")}

+
+ + +
+ <@button.kw @click="print" color="secondary" size="small" type="button"> + ${msg("recovery-codes-print")} + + <@button.kw @click="download" color="secondary" size="small" type="button"> + ${msg("recovery-codes-download")} + + <@button.kw @click="copy" color="secondary" size="small" type="button"> + ${msg("recovery-codes-copy")} + +
+ <@form.kw action=url.loginAction method="post"> + + + + <@checkbox.kw + label=msg("recovery-codes-confirmation-message") + name="kcRecoveryCodesConfirmationCheck" + required="required" + x\-ref="confirmationCheck" + /> + <@buttonGroup.kw> + <#if isAppInitiatedAction??> + <@button.kw color="primary" type="submit"> + ${msg("recovery-codes-action-complete")} + + <@button.kw + @click="$refs.confirmationCheck.required = false" + color="secondary" + name="cancel-aia" + type="submit" + value="true" + > + ${msg("recovery-codes-action-cancel")} + + <#else> + <@button.kw color="primary" type="submit"> + ${msg("recovery-codes-action-complete")} + + + + +
+ + + + diff --git a/keywind/login/login-recovery-authn-code-input.ftl b/keywind/login/login-recovery-authn-code-input.ftl new file mode 100644 index 0000000..a46bcfa --- /dev/null +++ b/keywind/login/login-recovery-authn-code-input.ftl @@ -0,0 +1,26 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> + +<@layout.registrationLayout; section> + <#if section="header"> + ${msg("auth-recovery-code-header")} + <#elseif section="form"> + <@form.kw action=url.loginAction method="post"> + <@input.kw + autocomplete="off" + autofocus=true + label=msg("auth-recovery-code-prompt", recoveryAuthnCodesInputBean.codeNumber?c) + name="recoveryCodeInput" + type="text" + /> + <@buttonGroup.kw> + <@button.kw color="primary" name="login" type="submit"> + ${msg("doLogIn")} + + + + + diff --git a/keywind/login/login-reset-password.ftl b/keywind/login/login-reset-password.ftl new file mode 100644 index 0000000..b0516aa --- /dev/null +++ b/keywind/login/login-reset-password.ftl @@ -0,0 +1,44 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> +<#import "components/atoms/link.ftl" as link> +<#import "features/labels/username.ftl" as usernameLabel> + +<#assign usernameLabel><@usernameLabel.kw /> + +<@layout.registrationLayout + displayInfo=true + displayMessage=!messagesPerField.existsError("username") + ; + section +> + <#if section="header"> + ${msg("emailForgotTitle")} + <#elseif section="form"> + <@form.kw action=url.loginAction method="post"> + <@input.kw + autocomplete=realm.loginWithEmailAllowed?string("email", "username") + autofocus=true + invalid=messagesPerField.existsError("username") + label=usernameLabel + message=kcSanitize(messagesPerField.get("username")) + name="username" + type="text" + value=(auth?has_content && auth.showUsername())?then(auth.attemptedUsername, '') + /> + <@buttonGroup.kw> + <@button.kw color="primary" type="submit"> + ${msg("doSubmit")} + + + + <#elseif section="info"> + ${msg("emailInstruction")} + <#elseif section="nav"> + <@link.kw color="secondary" href=url.loginUrl size="small"> + ${kcSanitize(msg("backToLogin"))?no_esc} + + + diff --git a/keywind/login/login-update-password.ftl b/keywind/login/login-update-password.ftl new file mode 100644 index 0000000..ed82380 --- /dev/null +++ b/keywind/login/login-update-password.ftl @@ -0,0 +1,64 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/checkbox.ftl" as checkbox> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> + +<@layout.registrationLayout + displayMessage=!messagesPerField.existsError("password", "password-confirm") + ; + section +> + <#if section="header"> + ${msg("updatePasswordTitle")} + <#elseif section="form"> + <@form.kw action=url.loginAction method="post"> + + + <@input.kw + autocomplete="new-password" + autofocus=true + invalid=messagesPerField.existsError("password", "password-confirm") + label=msg("passwordNew") + name="password-new" + type="password" + /> + <@input.kw + autocomplete="new-password" + invalid=messagesPerField.existsError("password-confirm") + label=msg("passwordConfirm") + message=kcSanitize(messagesPerField.get("password-confirm")) + name="password-confirm" + type="password" + /> + <#if isAppInitiatedAction??> + <@checkbox.kw + checked=true + label=msg("logoutOtherSessions") + name="logout-sessions" + value="on" + /> + + <@buttonGroup.kw> + <#if isAppInitiatedAction??> + <@button.kw color="primary" type="submit"> + ${msg("doSubmit")} + + <@button.kw color="secondary" name="cancel-aia" type="submit" value="true"> + ${msg("doCancel")} + + <#else> + <@button.kw color="primary" type="submit"> + ${msg("doSubmit")} + + + + + + diff --git a/keywind/login/login-update-profile.ftl b/keywind/login/login-update-profile.ftl new file mode 100644 index 0000000..306bad9 --- /dev/null +++ b/keywind/login/login-update-profile.ftl @@ -0,0 +1,71 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> + +<@layout.registrationLayout + displayMessage=!messagesPerField.existsError("email", "firstName", "lastName", "username") + ; + section +> + <#if section="header"> + ${msg("loginProfileTitle")} + <#elseif section="form"> + <@form.kw action=url.loginAction method="post"> + <#if user.editUsernameAllowed> + <@input.kw + autocomplete="username" + autofocus=true + invalid=messagesPerField.existsError("username") + label=msg("username") + message=kcSanitize(messagesPerField.get("username")) + name="username" + type="text" + value=(user.username)!'' + /> + + <@input.kw + autocomplete="email" + invalid=messagesPerField.existsError("email") + label=msg("email") + message=kcSanitize(messagesPerField.get("email")) + name="email" + type="email" + value=(user.email)!'' + /> + <@input.kw + autocomplete="given-name" + invalid=messagesPerField.existsError("firstName") + label=msg("firstName") + message=kcSanitize(messagesPerField.get("firstName")) + name="firstName" + type="text" + value=(user.firstName)!'' + /> + <@input.kw + autocomplete="family-name" + invalid=messagesPerField.existsError("lastName") + label=msg("lastName") + message=kcSanitize(messagesPerField.get("lastName")) + name="lastName" + type="text" + value=(user.lastName)!'' + /> + <@buttonGroup.kw> + <#if isAppInitiatedAction??> + <@button.kw color="primary" type="submit"> + ${msg("doSubmit")} + + <@button.kw color="secondary" name="cancel-aia" type="submit" value="true"> + ${msg("doCancel")} + + <#else> + <@button.kw color="primary" type="submit"> + ${msg("doSubmit")} + + + + + + diff --git a/keywind/login/login-username.ftl b/keywind/login/login-username.ftl new file mode 100644 index 0000000..b8064b2 --- /dev/null +++ b/keywind/login/login-username.ftl @@ -0,0 +1,71 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/checkbox.ftl" as checkbox> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> +<#import "components/atoms/link.ftl" as link> +<#import "components/molecules/identity-provider.ftl" as identityProvider> +<#import "features/labels/username.ftl" as usernameLabel> + +<#assign usernameLabel><@usernameLabel.kw /> + +<@layout.registrationLayout + displayInfo=realm.password && realm.registrationAllowed && !registrationDisabled?? + displayMessage=!messagesPerField.existsError("username") + ; + section +> + <#if section="header"> + ${msg("loginAccountTitle")} + <#elseif section="form"> + <#if realm.password> + <@form.kw + action=url.loginAction + method="post" + onsubmit="login.disabled = true; return true;" + > + <#if !usernameHidden??> + <@input.kw + autocomplete=realm.loginWithEmailAllowed?string("email", "username") + autofocus=true + disabled=usernameEditDisabled?? + invalid=messagesPerField.existsError("username") + label=usernameLabel + message=kcSanitize(messagesPerField.get("username"))?no_esc + name="username" + type="text" + value=(login.username)!'' + /> + + <#if realm.rememberMe && !usernameHidden??> +
+ <@checkbox.kw + checked=login.rememberMe?? + label=msg("rememberMe") + name="rememberMe" + /> +
+ + <@buttonGroup.kw> + <@button.kw color="primary" name="login" type="submit"> + ${msg("doLogIn")} + + + + + <#elseif section="info"> + <#if realm.password && realm.registrationAllowed && !registrationDisabled??> +
+ ${msg("noAccount")} + <@link.kw color="primary" href=url.registrationUrl> + ${msg("doRegister")} + +
+ + <#elseif section="socialProviders"> + <#if realm.password && social.providers??> + <@identityProvider.kw providers=social.providers /> + + + diff --git a/keywind/login/login-x509-info.ftl b/keywind/login/login-x509-info.ftl new file mode 100644 index 0000000..70d8432 --- /dev/null +++ b/keywind/login/login-x509-info.ftl @@ -0,0 +1,40 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/link.ftl" as link> + +<@layout.registrationLayout; section> + <#if section = "header"> + ${msg("doLogIn")} + <#elseif section = "form"> +
+
${msg("clientCertificate")}
+
+ <#if x509.formData.subjectDN??> + ${(x509.formData.subjectDN!"")} + <#else> + ${msg("noCertificate")} + +
+
+ <#if x509.formData.isUserEnabled??> +
+ ${msg("doX509Login")} + ${(x509.formData.username!'')} +
+ + <@form.kw action=url.loginAction method="post"> + <@buttonGroup.kw> + <@button.kw color="primary" name="login" type="submit"> + ${msg("doContinue")} + + <#if x509.formData.isUserEnabled??> + <@button.kw color="secondary" name="cancel" type="submit"> + ${msg("doIgnore")} + + + + + + diff --git a/keywind/login/login.ftl b/keywind/login/login.ftl new file mode 100644 index 0000000..331da06 --- /dev/null +++ b/keywind/login/login.ftl @@ -0,0 +1,87 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/checkbox.ftl" as checkbox> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> +<#import "components/atoms/link.ftl" as link> +<#import "components/molecules/identity-provider.ftl" as identityProvider> +<#import "features/labels/username.ftl" as usernameLabel> + +<#assign usernameLabel><@usernameLabel.kw /> + +<@layout.registrationLayout + displayInfo=realm.password && realm.registrationAllowed && !registrationDisabled?? + displayMessage=!messagesPerField.existsError("username", "password") + ; + section +> + <#if section="header"> + ${msg("loginAccountTitle")} + <#elseif section="form"> + <#if realm.password> + <@form.kw + action=url.loginAction + method="post" + onsubmit="login.disabled = true; return true;" + > + + <@input.kw + autocomplete=realm.loginWithEmailAllowed?string("email", "username") + autofocus=true + disabled=usernameEditDisabled?? + invalid=messagesPerField.existsError("username", "password") + label=usernameLabel + message=kcSanitize(messagesPerField.getFirstError("username", "password")) + name="username" + type="text" + value=(login.username)!'' + /> + <@input.kw + invalid=messagesPerField.existsError("username", "password") + label=msg("password") + name="password" + type="password" + /> + <#if realm.rememberMe && !usernameEditDisabled?? || realm.resetPasswordAllowed> +
+ <#if realm.rememberMe && !usernameEditDisabled??> + <@checkbox.kw + checked=login.rememberMe?? + label=msg("rememberMe") + name="rememberMe" + /> + + <#if realm.resetPasswordAllowed> + <@link.kw color="primary" href=url.loginResetCredentialsUrl size="small"> + ${msg("doForgotPassword")} + + +
+ + <@buttonGroup.kw> + <@button.kw color="primary" name="login" type="submit"> + ${msg("doLogIn")} + + + + + <#elseif section="info"> + <#if realm.password && realm.registrationAllowed && !registrationDisabled??> +
+ ${msg("noAccount")} + <@link.kw color="primary" href=url.registrationUrl> + ${msg("doRegister")} + +
+ + <#elseif section="socialProviders"> + <#if realm.password && social.providers??> + <@identityProvider.kw providers=social.providers /> + + + diff --git a/keywind/login/logout-confirm.ftl b/keywind/login/logout-confirm.ftl new file mode 100644 index 0000000..e7ec486 --- /dev/null +++ b/keywind/login/logout-confirm.ftl @@ -0,0 +1,25 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/link.ftl" as link> + +<@layout.registrationLayout; section> + <#if section="header"> + ${msg("logoutConfirmTitle")} + <#elseif section="form"> +

${msg("logoutConfirmHeader")}

+ <@form.kw action=url.logoutConfirmAction method="post"> + + <@button.kw color="primary" name="confirmLogout" type="submit" value=msg('doLogout')> + ${msg("doLogout")} + + + <#if !logoutConfirm.skipLink> + <#if (client.baseUrl)?has_content> + <@link.kw color="secondary" href=client.baseUrl size="small"> + ${kcSanitize(msg("backToApplication"))?no_esc} + + + + + diff --git a/keywind/login/register.ftl b/keywind/login/register.ftl new file mode 100644 index 0000000..c1a2f06 --- /dev/null +++ b/keywind/login/register.ftl @@ -0,0 +1,88 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> +<#import "components/atoms/link.ftl" as link> + +<@layout.registrationLayout + displayMessage=!messagesPerField.existsError("firstName", "lastName", "email", "username", "password", "password-confirm") + ; + section +> + <#if section="header"> + ${msg("registerTitle")} + <#elseif section="form"> + <@form.kw action=url.registrationAction method="post"> + <@input.kw + autocomplete="given-name" + autofocus=true + invalid=messagesPerField.existsError("firstName") + label=msg("firstName") + message=kcSanitize(messagesPerField.get("firstName")) + name="firstName" + type="text" + value=(register.formData.firstName)!'' + /> + <@input.kw + autocomplete="family-name" + invalid=messagesPerField.existsError("lastName") + label=msg("lastName") + message=kcSanitize(messagesPerField.get("lastName")) + name="lastName" + type="text" + value=(register.formData.lastName)!'' + /> + <@input.kw + autocomplete="email" + invalid=messagesPerField.existsError("email") + label=msg("email") + message=kcSanitize(messagesPerField.get("email")) + name="email" + type="email" + value=(register.formData.email)!'' + /> + <#if !realm.registrationEmailAsUsername> + <@input.kw + autocomplete="username" + invalid=messagesPerField.existsError("username") + label=msg("username") + message=kcSanitize(messagesPerField.get("username")) + name="username" + type="text" + value=(register.formData.username)!'' + /> + + <#if passwordRequired??> + <@input.kw + autocomplete="new-password" + invalid=messagesPerField.existsError("password", "password-confirm") + label=msg("password") + message=kcSanitize(messagesPerField.getFirstError("password", "password-confirm")) + name="password" + type="password" + /> + <@input.kw + autocomplete="new-password" + invalid=messagesPerField.existsError("password-confirm") + label=msg("passwordConfirm") + message=kcSanitize(messagesPerField.get("password-confirm")) + name="password-confirm" + type="password" + /> + + <#if recaptchaRequired??> +
+ + <@buttonGroup.kw> + <@button.kw color="primary" type="submit"> + ${msg("doRegister")} + + + + <#elseif section="nav"> + <@link.kw color="secondary" href=url.loginUrl size="small"> + ${kcSanitize(msg("backToLogin"))?no_esc} + + + diff --git a/keywind/login/resources/dist/assets/index-a7b84447.js b/keywind/login/resources/dist/assets/index-a7b84447.js new file mode 100644 index 0000000..c1b2f3c --- /dev/null +++ b/keywind/login/resources/dist/assets/index-a7b84447.js @@ -0,0 +1 @@ +var s={};Object.defineProperty(s,"__esModule",{value:!0});function v(e,r,a){var l;if(a===void 0&&(a={}),!r.codes){r.codes={};for(var n=0;n=8&&(t-=8,c[u++]=255&i>>t)}if(t>=r.bits||255&i<<8-t)throw new SyntaxError("Unexpected end of data");return c}function o(e,r,a){a===void 0&&(a={});for(var l=a,n=l.pad,b=n===void 0?!0:n,c=(1<r.bits;)i-=r.bits,t+=r.chars[c&u>>i];if(i&&(t+=r.chars[c&u<Ce&&N.splice(t,1)}function Bn(){!Oe&&!Ae&&(Ae=!0,queueMicrotask(Kn))}function Kn(){Ae=!1,Oe=!0;for(let e=0;ee.effect(t,{scheduler:n=>{Me?Ln(n):n()}}),At=e.raw}function ft(e){H=e}function zn(e){let t=()=>{};return[r=>{let i=H(r);return e._x_effects||(e._x_effects=new Set,e._x_runEffects=()=>{e._x_effects.forEach(o=>o())}),e._x_effects.add(i),t=()=>{i!==void 0&&(e._x_effects.delete(i),Z(i))},i},()=>{t()}]}function Y(e,t,n={}){e.dispatchEvent(new CustomEvent(t,{detail:n,bubbles:!0,composed:!0,cancelable:!0}))}function T(e,t){if(typeof ShadowRoot=="function"&&e instanceof ShadowRoot){Array.from(e.children).forEach(i=>T(i,t));return}let n=!1;if(t(e,()=>n=!0),n)return;let r=e.firstElementChild;for(;r;)T(r,t),r=r.nextElementSibling}function I(e,...t){console.warn(`Alpine Warning: ${e}`,...t)}var dt=!1;function Hn(){dt&&I("Alpine has already been initialized on this page. Calling Alpine.start() more than once can cause problems."),dt=!0,document.body||I("Unable to initialize. Trying to load Alpine before `` is available. Did you forget to add `defer` in Alpine's ` diff --git a/keywind/login/webauthn-error.ftl b/keywind/login/webauthn-error.ftl new file mode 100644 index 0000000..852d1e3 --- /dev/null +++ b/keywind/login/webauthn-error.ftl @@ -0,0 +1,34 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> + +<@layout.registrationLayout displayMessage=true; section> + <#if section="header"> + ${kcSanitize(msg("webauthn-error-title"))?no_esc} + <#elseif section="form"> +
+
+ + +
+ <@buttonGroup.kw> + <@button.kw + @click="$refs.executionValueInput.value = '${execution}'; $refs.isSetRetryInput.value = 'retry'; $refs.errorCredentialForm.submit()" + color="primary" + name="try-again" + tabindex="4" + type="button" + > + ${kcSanitize(msg("doTryAgain"))?no_esc} + + <#if isAppInitiatedAction??> +
+ <@button.kw color="secondary" name="cancel-aia" type="submit" value="true"> + ${msg("doCancel")} + +
+ + +
+ + diff --git a/keywind/login/webauthn-register.ftl b/keywind/login/webauthn-register.ftl new file mode 100644 index 0000000..57f4dad --- /dev/null +++ b/keywind/login/webauthn-register.ftl @@ -0,0 +1,54 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> + +<@layout.registrationLayout script="dist/webAuthnRegister.js"; section> + <#if section="title"> + title + <#elseif section="header"> + ${kcSanitize(msg("webauthn-registration-title"))?no_esc} + <#elseif section="form"> +
+
+ + + + + + +
+ <@buttonGroup.kw> + <@button.kw @click="registerSecurityKey" color="primary" type="submit"> + ${msg("doRegister")} + + <#if !isSetRetry?has_content && isAppInitiatedAction?has_content> +
+ <@button.kw color="secondary" name="cancel-aia" type="submit" value="true"> + ${msg("doCancel")} + +
+ + +
+ + + +