Update to work with Keycloak 26
This commit is contained in:
parent
410a09aec6
commit
e63d2dc74d
|
@ -72,4 +72,4 @@ To add new languages, the corresponding file must be added under `static/login/r
|
||||||
|
|
||||||
Special thanks to the following projects, without which the development of keycloak-modern-login would not be possible:
|
Special thanks to the following projects, without which the development of keycloak-modern-login would not be possible:
|
||||||
|
|
||||||
- [Keycloakify](https://github.com/keycloakify/keycloakify), from which the [`ftl_object_to_js_code_declaring_an_object`](src/static/login/baselayout.ftl) function and [Keycloak context type definitions](src/types/context.ts) are derived.
|
- [Keycloakify](https://github.com/keycloakify/keycloakify), from which the [FTL object to JSON](src/static/login/baselayout.ftl) function and [Keycloak context type definitions](src/types/context.ts) are derived.
|
|
@ -21,216 +21,411 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
-->
|
-->
|
||||||
<#function are_same_path path searchedPath>
|
|
||||||
<#if path?size != searchedPath?size>
|
|
||||||
<#return false>
|
|
||||||
</#if>
|
|
||||||
<#local i=0>
|
|
||||||
<#list path as property>
|
|
||||||
<#local searchedProperty=searchedPath[i]>
|
|
||||||
<#if searchedProperty?is_string && searchedProperty == "*">
|
|
||||||
<#continue>
|
|
||||||
</#if>
|
|
||||||
<#if searchedProperty?is_string && !property?is_string>
|
|
||||||
<#return false>
|
|
||||||
</#if>
|
|
||||||
<#if searchedProperty?is_number && !property?is_number>
|
|
||||||
<#return false>
|
|
||||||
</#if>
|
|
||||||
<#if searchedProperty?string != property?string>
|
|
||||||
<#return false>
|
|
||||||
</#if>
|
|
||||||
<#local i+= 1>
|
|
||||||
</#list>
|
|
||||||
<#return true>
|
|
||||||
</#function>
|
|
||||||
<#function ftl_object_to_js_code_declaring_an_object pageId object path>
|
|
||||||
<#local isHash = "">
|
|
||||||
<#attempt>
|
|
||||||
<#local isHash = object?is_hash || object?is_hash_ex>
|
|
||||||
<#recover>
|
|
||||||
<#return "ABORT: Can't evaluate if " + path?join(".") + " is hash">
|
|
||||||
</#attempt>
|
|
||||||
|
|
||||||
<#if isHash>
|
<#--
|
||||||
|
Code derived from Keycloakify (https://github.com/keycloakify/keycloakify/blob/main/src/bin/keycloakify/generateFtl/kcContextDeclarationTemplate.ftl)
|
||||||
<#if path?size gt 10>
|
-->
|
||||||
<#return "ABORT: Too many recursive calls">
|
|
||||||
</#if>
|
|
||||||
|
|
||||||
<#local keys = "">
|
|
||||||
|
|
||||||
|
<#function toJsDeclarationString object path>
|
||||||
|
<#local isHash = -1>
|
||||||
<#attempt>
|
<#attempt>
|
||||||
<#local keys = object?keys>
|
<#local isHash = object?is_hash || object?is_hash_ex>
|
||||||
<#recover>
|
<#recover>
|
||||||
<#return "ABORT: We can't list keys on this object">
|
<#return "ABORT: Can't evaluate if " + path?join(".") + " is a hash">
|
||||||
</#attempt>
|
</#attempt>
|
||||||
|
|
||||||
<#local out_seq = []>
|
<#if isHash>
|
||||||
<#list keys as key>
|
<#if path?size gt 10>
|
||||||
<#if ["class","declaredConstructors","superclass","declaringClass" ]?seq_contains(key) >
|
<#return "ABORT: Too many recursive calls, path: " + path?join(".")>
|
||||||
<#continue>
|
</#if>
|
||||||
</#if>
|
<#local keys = -1>
|
||||||
|
|
||||||
<#if
|
|
||||||
(
|
|
||||||
["loginUpdatePasswordUrl", "loginUpdateProfileUrl", "loginUsernameReminderUrl", "loginUpdateTotpUrl"]?seq_contains(key) &&
|
|
||||||
are_same_path(path, ["url"])
|
|
||||||
) || (
|
|
||||||
key == "updateProfileCtx" &&
|
|
||||||
are_same_path(path, [])
|
|
||||||
) || (
|
|
||||||
key == "loginAction" &&
|
|
||||||
are_same_path(path, ["url"]) &&
|
|
||||||
["saml-post-form.ftl", "error.ftl", "info.ftl"]?seq_contains(pageId) &&
|
|
||||||
!(auth?has_content && auth.showTryAnotherWayLink())
|
|
||||||
) || (
|
|
||||||
["contextData", "idpConfig", "idp", "authenticationSession"]?seq_contains(key) &&
|
|
||||||
are_same_path(path, ["brokerContext"]) &&
|
|
||||||
["login-idp-link-confirm.ftl", "login-idp-link-email.ftl" ]?seq_contains(pageId)
|
|
||||||
) || (
|
|
||||||
key == "identityProviderBrokerCtx" &&
|
|
||||||
are_same_path(path, []) &&
|
|
||||||
["login-idp-link-confirm.ftl", "login-idp-link-email.ftl" ]?seq_contains(pageId)
|
|
||||||
) || (
|
|
||||||
["masterAdminClient", "delegateForUpdate", "defaultRole"]?seq_contains(key) &&
|
|
||||||
are_same_path(path, ["realm"])
|
|
||||||
) || (
|
|
||||||
["password"]?seq_contains(key) &&
|
|
||||||
are_same_path(path, ["login"])
|
|
||||||
)
|
|
||||||
>
|
|
||||||
<#continue>
|
|
||||||
</#if>
|
|
||||||
|
|
||||||
<#if key == "attemptedUsername" && are_same_path(path, ["auth"])>
|
|
||||||
<#attempt>
|
<#attempt>
|
||||||
<#if !(auth?has_content && auth.showUsername() && !auth.showResetCredentials())>
|
<#local keys = object?keys>
|
||||||
<#continue>
|
|
||||||
</#if>
|
|
||||||
<#recover>
|
<#recover>
|
||||||
|
<#return "ABORT: We can't list keys on object">
|
||||||
</#attempt>
|
</#attempt>
|
||||||
</#if>
|
|
||||||
|
|
||||||
<#attempt>
|
<#local outSeq = []>
|
||||||
<#if !object[key]??>
|
|
||||||
<#continue>
|
<#list keys as key>
|
||||||
|
<#if ["class","declaredConstructors","superclass","declaringClass" ]?seq_contains(key) >
|
||||||
|
<#continue>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if (
|
||||||
|
areSamePath(path, ["url"]) &&
|
||||||
|
["loginUpdatePasswordUrl", "loginUpdateProfileUrl", "loginUsernameReminderUrl", "loginUpdateTotpUrl"]?seq_contains(key)
|
||||||
|
) || (
|
||||||
|
key == "updateProfileCtx" &&
|
||||||
|
areSamePath(path, [])
|
||||||
|
) || (
|
||||||
|
<#-- https://github.com/keycloakify/keycloakify/pull/65#issuecomment-991896344 (reports with saml-post-form.ftl) -->
|
||||||
|
<#-- https://github.com/keycloakify/keycloakify/issues/91#issue-1212319466 (reports with error.ftl and Kc18) -->
|
||||||
|
<#-- https://github.com/keycloakify/keycloakify/issues/109#issuecomment-1134610163 -->
|
||||||
|
<#-- https://github.com/keycloakify/keycloakify/issues/357 -->
|
||||||
|
<#-- https://github.com/keycloakify/keycloakify/discussions/406#discussioncomment-7514787 -->
|
||||||
|
key == "loginAction" &&
|
||||||
|
areSamePath(path, ["url"]) &&
|
||||||
|
["saml-post-form.ftl", "error.ftl", "info.ftl", "login-oauth-grant.ftl", "logout-confirm.ftl", "login-oauth2-device-verify-user-code.ftl"]?seq_contains(pageId) &&
|
||||||
|
!(auth?has_content && auth.showTryAnotherWayLink())
|
||||||
|
) || (
|
||||||
|
<#-- https://github.com/keycloakify/keycloakify/issues/362 -->
|
||||||
|
["secretData", "value"]?seq_contains(key) &&
|
||||||
|
areSamePath(path, [ "totp", "otpCredentials", "*" ])
|
||||||
|
) || (
|
||||||
|
["contextData", "idpConfig", "idp", "authenticationSession"]?seq_contains(key) &&
|
||||||
|
areSamePath(path, ["brokerContext"]) &&
|
||||||
|
["login-idp-link-confirm.ftl", "login-idp-link-email.ftl" ]?seq_contains(pageId)
|
||||||
|
) || (
|
||||||
|
key == "identityProviderBrokerCtx" &&
|
||||||
|
areSamePath(path, []) &&
|
||||||
|
["login-idp-link-confirm.ftl", "login-idp-link-email.ftl" ]?seq_contains(pageId)
|
||||||
|
) || (
|
||||||
|
["masterAdminClient", "delegateForUpdate", "defaultRole", "smtpConfig"]?seq_contains(key) &&
|
||||||
|
areSamePath(path, ["realm"])
|
||||||
|
) || (
|
||||||
|
areSamePath(path, ["realm"]) &&
|
||||||
|
!["name", "displayName", "displayNameHtml", "internationalizationEnabled", "registrationEmailAsUsername" ]?seq_contains(key)
|
||||||
|
) || (
|
||||||
|
(
|
||||||
|
key == "realm" ||
|
||||||
|
key == "container"
|
||||||
|
) &&
|
||||||
|
isSubpath(path, ["applications", "applications"])
|
||||||
|
) || (
|
||||||
|
key == "delegateForUpdate" &&
|
||||||
|
areSamePath(path, ["user"])
|
||||||
|
) || (
|
||||||
|
<#-- Security audit forwarded by Garth (Gmail) -->
|
||||||
|
key == "saml.signing.private.key" &&
|
||||||
|
areSamePath(path, ["client", "attributes"])
|
||||||
|
) || (
|
||||||
|
<#-- See: https://github.com/keycloakify/keycloakify/issues/534 -->
|
||||||
|
key == "password" &&
|
||||||
|
areSamePath(path, ["login"])
|
||||||
|
) || (
|
||||||
|
<#-- Remove realmAttributes added by https://github.com/jcputney/keycloak-theme-additional-info-extension for peace of mind. -->
|
||||||
|
key == "realmAttributes" &&
|
||||||
|
areSamePath(path, [])
|
||||||
|
) || (
|
||||||
|
<#-- attributesByName adds a lot of noise to the output and is not needed, we already have profile.attributes -->
|
||||||
|
key == "attributesByName" &&
|
||||||
|
areSamePath(path, ["profile"])
|
||||||
|
) || (
|
||||||
|
<#-- We already have the attributes in profile speedup the rendering by filtering it out from the register object -->
|
||||||
|
(key == "attributes" || key == "attributesByName") &&
|
||||||
|
areSamePath(path, ["register"])
|
||||||
|
) || (
|
||||||
|
areSamePath(path, ["properties"]) &&
|
||||||
|
(
|
||||||
|
key?starts_with("kc") ||
|
||||||
|
key == "locales" ||
|
||||||
|
key == "import" ||
|
||||||
|
key == "parent" ||
|
||||||
|
key == "meta" ||
|
||||||
|
key == "stylesCommon" ||
|
||||||
|
key == "styles" ||
|
||||||
|
key == "accountResourceProvider"
|
||||||
|
)
|
||||||
|
) || (
|
||||||
|
key == "execution" &&
|
||||||
|
areSamePath(path, [])
|
||||||
|
) || (
|
||||||
|
key == "entity" &&
|
||||||
|
areSamePath(path, ["user"])
|
||||||
|
) || (
|
||||||
|
key == "attributes" &&
|
||||||
|
areSamePath(path, ["realm"])
|
||||||
|
) || (
|
||||||
|
areSamePath(path, ["realm"]) &&
|
||||||
|
![
|
||||||
|
"name",
|
||||||
|
"registrationEmailAsUsername",
|
||||||
|
"editUsernameAllowed",
|
||||||
|
"isInternationalizationEnabled",
|
||||||
|
"identityFederationEnabled",
|
||||||
|
"userManagedAccessAllowed"
|
||||||
|
]?seq_contains(key)
|
||||||
|
) || (
|
||||||
|
["flowContext", "session", "realm"]?seq_contains(key) &&
|
||||||
|
areSamePath(path, ["social"])
|
||||||
|
)
|
||||||
|
>
|
||||||
|
<#-- <#local outSeq += ["/*" + path?join(".") + "." + key + " excluded*/"]> -->
|
||||||
|
<#continue>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#-- https://github.com/keycloakify/keycloakify/discussions/406 -->
|
||||||
|
<#if (
|
||||||
|
key == "attemptedUsername" &&
|
||||||
|
areSamePath(path, ["auth"]) &&
|
||||||
|
[
|
||||||
|
"register.ftl", "terms.ftl", "info.ftl", "login.ftl",
|
||||||
|
"login-update-password.ftl", "login-oauth2-device-verify-user-code.ftl"
|
||||||
|
]?seq_contains(pageId)
|
||||||
|
)>
|
||||||
|
<#attempt>
|
||||||
|
<#-- https://github.com/keycloak/keycloak/blob/3a2bf0c04bcde185e497aaa32d0bb7ab7520cf4a/themes/src/main/resources/theme/base/login/template.ftl#L63 -->
|
||||||
|
<#if !(auth?has_content && auth.showUsername() && !auth.showResetCredentials())>
|
||||||
|
<#local outSeq += ["/*" + path?join(".") + "." + key + " excluded*/"]>
|
||||||
|
<#continue>
|
||||||
|
</#if>
|
||||||
|
<#recover>
|
||||||
|
<#local outSeq += ["/*Accessing attemptedUsername throwed an exception */"]>
|
||||||
|
</#attempt>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
{{userDefinedExclusions}}
|
||||||
|
|
||||||
|
<#attempt>
|
||||||
|
<#if !object[key]??>
|
||||||
|
<#continue>
|
||||||
|
</#if>
|
||||||
|
<#recover>
|
||||||
|
<#local outSeq += ["/*Couldn't test if '" + key + "' is available on this object*/"]>
|
||||||
|
<#continue>
|
||||||
|
</#attempt>
|
||||||
|
|
||||||
|
<#local propertyValue = -1>
|
||||||
|
|
||||||
|
<#attempt>
|
||||||
|
<#local propertyValue = object[key]>
|
||||||
|
<#recover>
|
||||||
|
<#local outSeq += ["/*Couldn't dereference '" + key + "' on this object*/"]>
|
||||||
|
<#continue>
|
||||||
|
</#attempt>
|
||||||
|
|
||||||
|
<#local recOut = toJsDeclarationString(propertyValue, path + [ key ])>
|
||||||
|
|
||||||
|
<#if recOut?starts_with("ABORT:")>
|
||||||
|
|
||||||
|
<#local errorMessage = recOut?remove_beginning("ABORT:")>
|
||||||
|
|
||||||
|
<#if errorMessage != " It's a method" >
|
||||||
|
<#local outSeq += ["/*" + key + ": " + errorMessage + "*/"]>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#continue>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#local outSeq += ['"' + key + '": ' + recOut + ","]>
|
||||||
|
|
||||||
|
</#list>
|
||||||
|
|
||||||
|
<#return (["{"] + outSeq?map(str -> ""?right_pad(4 * (path?size + 1)) + str) + [ ""?right_pad(4 * path?size) + "}"])?join("\n")>
|
||||||
|
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#local isMethod = -1>
|
||||||
|
<#attempt>
|
||||||
|
<#local isMethod = object?is_method>
|
||||||
|
<#recover>
|
||||||
|
<#return "ABORT: Can't test if it'sa method.">
|
||||||
|
</#attempt>
|
||||||
|
|
||||||
|
<#if isMethod>
|
||||||
|
|
||||||
|
<#if areSamePath(path, ["auth", "showUsername"])>
|
||||||
|
<#attempt>
|
||||||
|
<#return auth.showUsername()?c>
|
||||||
|
<#recover>
|
||||||
|
<#return "ABORT: Couldn't evaluate auth.showUsername()">
|
||||||
|
</#attempt>
|
||||||
</#if>
|
</#if>
|
||||||
<#recover>
|
|
||||||
<#local out_seq += ["/*Couldn't test if '" + key + "' is available on this object*/"]>
|
|
||||||
<#continue>
|
|
||||||
</#attempt>
|
|
||||||
|
|
||||||
<#local propertyValue = "">
|
<#if areSamePath(path, ["auth", "showResetCredentials"])>
|
||||||
<#attempt>
|
<#attempt>
|
||||||
<#local propertyValue = object[key]>
|
<#return auth.showResetCredentials()?c>
|
||||||
<#recover>
|
<#recover>
|
||||||
<#local out_seq += ["/*Couldn't dereference '" + key + "' on this object*/"]>
|
<#return "ABORT: Couldn't evaluate auth.showResetCredentials()">
|
||||||
<#continue>
|
</#attempt>
|
||||||
</#attempt>
|
</#if>
|
||||||
|
|
||||||
<#local rec_out = ftl_object_to_js_code_declaring_an_object(pageId, propertyValue, path + [ key ])>
|
<#if areSamePath(path, ["auth", "showTryAnotherWayLink"])>
|
||||||
<#if rec_out?starts_with("ABORT:")>
|
<#attempt>
|
||||||
<#local errorMessage = rec_out?remove_beginning("ABORT:")>
|
<#return auth.showTryAnotherWayLink()?c>
|
||||||
<#if errorMessage != " It's a method" >
|
<#recover>
|
||||||
<#local out_seq += ["/*" + key + ": " + errorMessage + "*/"]>
|
<#return "ABORT: Couldn't evaluate auth.showTryAnotherWayLink()">
|
||||||
|
</#attempt>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if areSamePath(path, ["url", "getLogoutUrl"])>
|
||||||
|
<#local returnValue = -1>
|
||||||
|
<#attempt>
|
||||||
|
<#local returnValue = url.getLogoutUrl()>
|
||||||
|
<#recover>
|
||||||
|
<#return "ABORT: Couldn't evaluate url.getLogoutUrl()">
|
||||||
|
</#attempt>
|
||||||
|
<#return 'function(){ return "' + returnValue + '"; }'>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if areSamePath(path, ["totp", "policy", "getAlgorithmKey"])>
|
||||||
|
<#local returnValue = "error">
|
||||||
|
<#if mode?? && mode = "manual">
|
||||||
|
<#attempt>
|
||||||
|
<#local returnValue = totp.policy.getAlgorithmKey()>
|
||||||
|
<#recover>
|
||||||
|
<#return "ABORT: Couldn't evaluate totp.policy.getAlgorithmKey()">
|
||||||
|
</#attempt>
|
||||||
|
</#if>
|
||||||
|
<#return 'function(){ return "' + returnValue + '"; }'>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if profile?? && profile.attributes??>
|
||||||
|
<#list profile.attributes as attribute>
|
||||||
|
<#if fieldNames?seq_contains(attribute.name)>
|
||||||
|
<#continue>
|
||||||
|
</#if>
|
||||||
|
<#assign fieldNames += [attribute.name]>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#return "ABORT: It's a method">
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#local isBoolean = -1>
|
||||||
|
<#attempt>
|
||||||
|
<#local isBoolean = object?is_boolean>
|
||||||
|
<#recover>
|
||||||
|
<#return "ABORT: Can't test if it's a boolean">
|
||||||
|
</#attempt>
|
||||||
|
|
||||||
|
<#if isBoolean>
|
||||||
|
<#return object?c>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#local isEnumerable = -1>
|
||||||
|
<#attempt>
|
||||||
|
<#local isEnumerable = object?is_enumerable>
|
||||||
|
<#recover>
|
||||||
|
<#return "ABORT: Can't test if it's an enumerable">
|
||||||
|
</#attempt>
|
||||||
|
|
||||||
|
|
||||||
|
<#if isEnumerable>
|
||||||
|
|
||||||
|
<#local outSeq = []>
|
||||||
|
|
||||||
|
<#local i = 0>
|
||||||
|
|
||||||
|
<#list object as array_item>
|
||||||
|
|
||||||
|
<#if !array_item??>
|
||||||
|
<#local outSeq += ["null,"]>
|
||||||
|
<#continue>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#local recOut = toJsDeclarationString(array_item, path + [ i ])>
|
||||||
|
|
||||||
|
<#local i = i + 1>
|
||||||
|
|
||||||
|
<#if recOut?starts_with("ABORT:")>
|
||||||
|
|
||||||
|
<#local errorMessage = recOut?remove_beginning("ABORT:")>
|
||||||
|
|
||||||
|
<#if errorMessage != " It's a method" >
|
||||||
|
<#local outSeq += ["/*" + i?string + ": " + errorMessage + "*/"]>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#continue>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#local outSeq += [recOut + ","]>
|
||||||
|
|
||||||
|
</#list>
|
||||||
|
|
||||||
|
<#return (["["] + outSeq?map(str -> ""?right_pad(4 * (path?size + 1)) + str) + [ ""?right_pad(4 * path?size) + "]"])?join("\n")>
|
||||||
|
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#local isDate = -1>
|
||||||
|
<#attempt>
|
||||||
|
<#local isDate = object?is_date_like>
|
||||||
|
<#recover>
|
||||||
|
<#return "ABORT: Can't test if it's a date">
|
||||||
|
</#attempt>
|
||||||
|
|
||||||
|
<#if isDate>
|
||||||
|
<#return '"' + object?datetime?iso_utc + '"'>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#local isNumber = -1>
|
||||||
|
<#attempt>
|
||||||
|
<#local isNumber = object?is_number>
|
||||||
|
<#recover>
|
||||||
|
<#return "ABORT: Can't test if it's a number">
|
||||||
|
</#attempt>
|
||||||
|
|
||||||
|
<#if isNumber>
|
||||||
|
<#return object?c>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#local isString = -1>
|
||||||
|
<#attempt>
|
||||||
|
<#local isString = object?is_string>
|
||||||
|
<#recover>
|
||||||
|
<#return "ABORT: Can't test if it's a string">
|
||||||
|
</#attempt>
|
||||||
|
|
||||||
|
<#attempt>
|
||||||
|
<#return '"' + object?js_string + '"'>;
|
||||||
|
<#recover>
|
||||||
|
</#attempt>
|
||||||
|
|
||||||
|
<#return "ABORT: Couldn't convert into string non hash, non method, non boolean, non number, non enumerable object">
|
||||||
|
|
||||||
|
</#function>
|
||||||
|
<#function isSubpath path searchedPath>
|
||||||
|
|
||||||
|
<#if path?size < searchedPath?size>
|
||||||
|
<#return false>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#local i=0>
|
||||||
|
|
||||||
|
<#list path as property>
|
||||||
|
|
||||||
|
<#if i == searchedPath?size >
|
||||||
|
<#continue>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#local searchedProperty=searchedPath[i]>
|
||||||
|
|
||||||
|
<#local i+= 1>
|
||||||
|
|
||||||
|
<#if searchedProperty?is_string && searchedProperty == "*">
|
||||||
|
<#continue>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if searchedProperty?is_string && !property?is_string>
|
||||||
|
<#return false>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if searchedProperty?is_number && !property?is_number>
|
||||||
|
<#return false>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if searchedProperty?string != property?string>
|
||||||
|
<#return false>
|
||||||
</#if>
|
</#if>
|
||||||
<#continue>
|
|
||||||
</#if>
|
|
||||||
|
|
||||||
<#local out_seq += ['"' + key + '": ' + rec_out + ","]>
|
|
||||||
</#list>
|
</#list>
|
||||||
|
|
||||||
<#return (["{"] + out_seq?map(str -> ""?right_pad(4 * (path?size + 1)) + str) + [ ""?right_pad(4 * path?size) + "}"])?join("\n")>
|
<#return true>
|
||||||
|
|
||||||
</#if>
|
</#function>
|
||||||
|
|
||||||
<#local isMethod = "">
|
<#function areSamePath path searchedPath>
|
||||||
<#attempt>
|
<#return path?size == searchedPath?size && isSubpath(path, searchedPath)>
|
||||||
<#local isMethod = object?is_method>
|
</#function>
|
||||||
<#recover>
|
|
||||||
<#return "ABORT: Can't test if it'sa method.">
|
|
||||||
</#attempt>
|
|
||||||
|
|
||||||
<#if isMethod>
|
<#function removeBrackets str>
|
||||||
<#if are_same_path(path, ["auth", "showUsername"])>
|
<#if str?starts_with("${") && str?ends_with("}")>
|
||||||
<#attempt>
|
<#return str[2..(str?length-2)]>
|
||||||
<#return auth.showUsername()?c>
|
<#else>
|
||||||
<#recover>
|
<#return str>
|
||||||
<#return "ABORT: Couldn't evaluate auth.showUsername()">
|
|
||||||
</#attempt>
|
|
||||||
</#if>
|
</#if>
|
||||||
|
|
||||||
<#if are_same_path(path, ["auth", "showResetCredentials"])>
|
|
||||||
<#attempt>
|
|
||||||
<#return auth.showResetCredentials()?c>
|
|
||||||
<#recover>
|
|
||||||
<#return "ABORT: Couldn't evaluate auth.showResetCredentials()">
|
|
||||||
</#attempt>
|
|
||||||
</#if>
|
|
||||||
|
|
||||||
<#if are_same_path(path, ["auth", "showTryAnotherWayLink"])>
|
|
||||||
<#attempt>
|
|
||||||
<#return auth.showTryAnotherWayLink()?c>
|
|
||||||
<#recover>
|
|
||||||
<#return "ABORT: Couldn't evaluate auth.showTryAnotherWayLink()">
|
|
||||||
</#attempt>
|
|
||||||
</#if>
|
|
||||||
|
|
||||||
<#return "ABORT: It's a method">
|
|
||||||
</#if>
|
|
||||||
|
|
||||||
<#local isBoolean = "">
|
|
||||||
<#attempt>
|
|
||||||
<#local isBoolean = object?is_boolean>
|
|
||||||
<#recover>
|
|
||||||
<#return "ABORT: Can't test if it's a boolean">
|
|
||||||
</#attempt>
|
|
||||||
|
|
||||||
<#if isBoolean>
|
|
||||||
<#return object?c>
|
|
||||||
</#if>
|
|
||||||
|
|
||||||
<#local isEnumerable = "">
|
|
||||||
<#attempt>
|
|
||||||
<#local isEnumerable = object?is_enumerable>
|
|
||||||
<#recover>
|
|
||||||
<#return "ABORT: Can't test if it's an enumerable">
|
|
||||||
</#attempt>
|
|
||||||
|
|
||||||
<#if isEnumerable>
|
|
||||||
<#local out_seq = []>
|
|
||||||
<#local i = 0>
|
|
||||||
|
|
||||||
<#list object as array_item>
|
|
||||||
<#if !array_item??>
|
|
||||||
<#local out_seq += ["null,"]>
|
|
||||||
<#continue>
|
|
||||||
</#if>
|
|
||||||
|
|
||||||
<#local rec_out = ftl_object_to_js_code_declaring_an_object(pageId, array_item, path + [ i ])>
|
|
||||||
<#local i = i + 1>
|
|
||||||
|
|
||||||
<#if rec_out?starts_with("ABORT:")>
|
|
||||||
<#local errorMessage = rec_out?remove_beginning("ABORT:")>
|
|
||||||
<#if errorMessage != " It's a method" >
|
|
||||||
<#local out_seq += ["/*" + i?string + ": " + errorMessage + "*/"]>
|
|
||||||
</#if>
|
|
||||||
|
|
||||||
<#continue>
|
|
||||||
</#if>
|
|
||||||
<#local out_seq += [rec_out + ","]>
|
|
||||||
</#list>
|
|
||||||
|
|
||||||
<#return (["["] + out_seq?map(str -> ""?right_pad(4 * (path?size + 1)) + str) + [ ""?right_pad(4 * path?size) + "]"])?join("\n")>
|
|
||||||
</#if>
|
|
||||||
|
|
||||||
<#attempt>
|
|
||||||
<#return '"' + object?js_string + '"'>;
|
|
||||||
<#recover>
|
|
||||||
</#attempt>
|
|
||||||
|
|
||||||
<#return "ABORT: Couldn't convert into string non hash, non method, non boolean, non enumerable object">
|
|
||||||
</#function>
|
</#function>
|
||||||
|
|
||||||
<#macro baseLayout pageId="template.ftl">
|
<#macro baseLayout pageId="template.ftl">
|
||||||
|
@ -252,7 +447,7 @@ SOFTWARE.
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
window.kcContext = ${ftl_object_to_js_code_declaring_an_object(pageId, .data_model, [])?no_esc}
|
window.kcContext = ${toJsDeclarationString(.data_model, [])?no_esc};
|
||||||
</script>
|
</script>
|
||||||
<#nested "head">
|
<#nested "head">
|
||||||
</head>
|
</head>
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
locales=en
|
locales=en
|
||||||
parent=keycloak
|
parent=keycloak.v2
|
|
@ -3304,11 +3304,6 @@ minimist@^1.2.0, minimist@^1.2.6:
|
||||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
|
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
|
||||||
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
|
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
|
||||||
|
|
||||||
moment@^2.29.4:
|
|
||||||
version "2.29.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
|
|
||||||
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
|
|
||||||
|
|
||||||
ms@2.1.2:
|
ms@2.1.2:
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||||
|
|
Loading…
Reference in a new issue