keycloakify 10.1.0-rc.0 → 10.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PUBLIC_URL.js +2 -2
- package/PUBLIC_URL.js.map +1 -1
- package/account/KcContext/kcContextMocks.js +3 -3
- package/account/KcContext/kcContextMocks.js.map +1 -1
- package/bin/193.index.js +198 -62
- package/bin/{365.index.js → 20.index.js} +302 -263
- package/bin/31.index.js +15 -23
- package/bin/{430.index.js → 33.index.js} +579 -4
- package/bin/{678.index.js → 36.index.js} +2 -577
- package/bin/{440.index.js → 499.index.js} +259 -181
- package/bin/526.index.js +3 -784
- package/bin/599.index.js +4 -1
- package/bin/780.index.js +1 -1
- package/bin/{525.index.js → 903.index.js} +4840 -97
- package/bin/932.index.js +115 -886
- package/bin/main.js +4 -4
- package/bin/shared/buildContext.d.ts +0 -2
- package/bin/shared/buildContext.js.map +1 -1
- package/bin/shared/constants.d.ts +5 -6
- package/bin/shared/constants.js +5 -6
- package/bin/shared/constants.js.map +1 -1
- package/bin/shared/copyKeycloakResourcesToPublic.d.ts +2 -4
- package/bin/shared/copyKeycloakResourcesToPublic.js.map +1 -1
- package/login/KcContext/KcContext.d.ts +9 -18
- package/login/KcContext/KcContext.js.map +1 -1
- package/login/KcContext/kcContextMocks.js +6 -10
- package/login/KcContext/kcContextMocks.js.map +1 -1
- package/login/Template.js +4 -59
- package/login/Template.js.map +1 -1
- package/login/Template.useStylesAndScripts.d.ts +17 -0
- package/login/Template.useStylesAndScripts.js +69 -0
- package/login/Template.useStylesAndScripts.js.map +1 -0
- package/login/pages/Login.js +1 -1
- package/login/pages/Login.js.map +1 -1
- package/login/pages/LoginIdpLinkConfirmOverride.js +0 -1
- package/login/pages/LoginIdpLinkConfirmOverride.js.map +1 -1
- package/login/pages/LoginPasskeysConditionalAuthenticate.js +6 -49
- package/login/pages/LoginPasskeysConditionalAuthenticate.js.map +1 -1
- package/login/pages/LoginPasskeysConditionalAuthenticate.useScript.d.ts +20 -0
- package/login/pages/LoginPasskeysConditionalAuthenticate.useScript.js +49 -0
- package/login/pages/LoginPasskeysConditionalAuthenticate.useScript.js.map +1 -0
- package/login/pages/LoginRecoveryAuthnCodeConfig.js +4 -126
- package/login/pages/LoginRecoveryAuthnCodeConfig.js.map +1 -1
- package/login/pages/LoginRecoveryAuthnCodeConfig.useScript.d.ts +9 -0
- package/login/pages/LoginRecoveryAuthnCodeConfig.useScript.js +133 -0
- package/login/pages/LoginRecoveryAuthnCodeConfig.useScript.js.map +1 -0
- package/login/pages/LoginUsername.js +1 -1
- package/login/pages/LoginUsername.js.map +1 -1
- package/login/pages/Register.js +6 -3
- package/login/pages/Register.js.map +1 -1
- package/login/pages/WebauthnAuthenticate.js +13 -116
- package/login/pages/WebauthnAuthenticate.js.map +1 -1
- package/login/pages/WebauthnAuthenticate.useScript.d.ts +21 -0
- package/login/pages/WebauthnAuthenticate.useScript.js +41 -0
- package/login/pages/WebauthnAuthenticate.useScript.js.map +1 -0
- package/login/pages/WebauthnRegister.js +8 -178
- package/login/pages/WebauthnRegister.js.map +1 -1
- package/login/pages/WebauthnRegister.useScript.d.ts +27 -0
- package/login/pages/WebauthnRegister.useScript.js +49 -0
- package/login/pages/WebauthnRegister.useScript.js.map +1 -0
- package/package.json +125 -15
- package/res/account-v1/account.ftl +70 -0
- package/res/account-v1/applications.ftl +76 -0
- package/res/account-v1/federatedIdentity.ftl +42 -0
- package/res/account-v1/log.ftl +35 -0
- package/res/account-v1/messages/messages_ar.properties +406 -0
- package/res/account-v1/messages/messages_ca.properties +147 -0
- package/res/account-v1/messages/messages_cs.properties +171 -0
- package/res/account-v1/messages/messages_da.properties +339 -0
- package/res/account-v1/messages/messages_de.properties +353 -0
- package/res/account-v1/messages/messages_en.properties +404 -0
- package/res/account-v1/messages/messages_es.properties +147 -0
- package/res/account-v1/messages/messages_fi.properties +400 -0
- package/res/account-v1/messages/messages_fr.properties +180 -0
- package/res/account-v1/messages/messages_hu.properties +334 -0
- package/res/account-v1/messages/messages_it.properties +336 -0
- package/res/account-v1/messages/messages_ja.properties +335 -0
- package/res/account-v1/messages/messages_lt.properties +154 -0
- package/res/account-v1/messages/messages_lv.properties +197 -0
- package/res/account-v1/messages/messages_nl.properties +371 -0
- package/res/account-v1/messages/messages_no.properties +152 -0
- package/res/account-v1/messages/messages_pl.properties +248 -0
- package/res/account-v1/messages/messages_pt_BR.properties +349 -0
- package/res/account-v1/messages/messages_ru.properties +235 -0
- package/res/account-v1/messages/messages_sk.properties +196 -0
- package/res/account-v1/messages/messages_sv.properties +150 -0
- package/res/account-v1/messages/messages_tr.properties +315 -0
- package/res/account-v1/messages/messages_zh_CN.properties +153 -0
- package/res/account-v1/password.ftl +59 -0
- package/res/account-v1/resource-detail.ftl +277 -0
- package/res/account-v1/resources/css/account.css +277 -0
- package/res/account-v1/resources/img/icon-sidebar-active.png +0 -0
- package/res/account-v1/resources/img/keycloak-logo.png +0 -0
- package/res/account-v1/resources/img/logo.png +0 -0
- package/res/account-v1/resources/resources-common/img/favicon.ico +0 -0
- package/res/account-v1/resources/resources-common/node_modules/patternfly/dist/css/patternfly-additions.min.css +5 -0
- package/res/account-v1/resources/resources-common/node_modules/patternfly/dist/css/patternfly.min.css +8 -0
- package/res/account-v1/resources/resources-common/node_modules/patternfly/dist/fonts/OpenSans-Bold-webfont.woff2 +0 -0
- package/res/account-v1/resources/resources-common/node_modules/patternfly/dist/fonts/OpenSans-Light-webfont.woff2 +0 -0
- package/res/account-v1/resources/resources-common/node_modules/patternfly/dist/fonts/OpenSans-Regular-webfont.woff2 +0 -0
- package/res/account-v1/resources/resources-common/node_modules/patternfly/dist/fonts/OpenSans-Semibold-webfont.woff2 +0 -0
- package/res/account-v1/resources/resources-common/node_modules/patternfly/dist/fonts/PatternFlyIcons-webfont.ttf +0 -0
- package/res/account-v1/resources/resources-common/node_modules/patternfly/dist/fonts/PatternFlyIcons-webfont.woff +0 -0
- package/res/account-v1/resources.ftl +403 -0
- package/res/account-v1/sessions.ftl +44 -0
- package/res/account-v1/template.ftl +88 -0
- package/res/account-v1/theme.properties +14 -0
- package/res/account-v1/totp.ftl +141 -0
- package/res/public/.keycloakify/account/css/account.css +277 -0
- package/res/public/.keycloakify/account/img/icon-sidebar-active.png +0 -0
- package/res/public/.keycloakify/account/img/keycloak-logo.png +0 -0
- package/res/public/.keycloakify/account/img/logo.png +0 -0
- package/res/public/.keycloakify/account/resources-common/img/favicon.ico +0 -0
- package/res/public/.keycloakify/account/resources-common/node_modules/patternfly/dist/css/patternfly-additions.min.css +5 -0
- package/res/public/.keycloakify/account/resources-common/node_modules/patternfly/dist/css/patternfly.min.css +8 -0
- package/res/public/.keycloakify/account/resources-common/node_modules/patternfly/dist/fonts/OpenSans-Bold-webfont.woff2 +0 -0
- package/res/public/.keycloakify/account/resources-common/node_modules/patternfly/dist/fonts/OpenSans-Light-webfont.woff2 +0 -0
- package/res/public/.keycloakify/account/resources-common/node_modules/patternfly/dist/fonts/OpenSans-Regular-webfont.woff2 +0 -0
- package/res/public/.keycloakify/account/resources-common/node_modules/patternfly/dist/fonts/OpenSans-Semibold-webfont.woff2 +0 -0
- package/res/public/.keycloakify/account/resources-common/node_modules/patternfly/dist/fonts/PatternFlyIcons-webfont.ttf +0 -0
- package/res/public/.keycloakify/account/resources-common/node_modules/patternfly/dist/fonts/PatternFlyIcons-webfont.woff +0 -0
- package/res/public/.keycloakify/login/css/login.css +629 -0
- package/res/public/.keycloakify/login/img/feedback-error-arrow-down.png +0 -0
- package/res/public/.keycloakify/login/img/feedback-error-sign.png +0 -0
- package/res/public/.keycloakify/login/img/feedback-success-arrow-down.png +0 -0
- package/res/public/.keycloakify/login/img/feedback-success-sign.png +0 -0
- package/res/public/.keycloakify/login/img/feedback-warning-arrow-down.png +0 -0
- package/res/public/.keycloakify/login/img/feedback-warning-sign.png +0 -0
- package/res/public/.keycloakify/login/img/keycloak-bg.png +0 -0
- package/res/public/.keycloakify/login/img/keycloak-logo-text.png +0 -0
- package/res/public/.keycloakify/login/img/keycloak-logo.png +0 -0
- package/res/public/.keycloakify/login/js/authChecker.js +49 -0
- package/res/public/.keycloakify/login/js/common.js +48 -0
- package/res/public/.keycloakify/login/js/kcMultivalued.js +106 -0
- package/res/public/.keycloakify/login/js/kcNumberFormat.js +21 -0
- package/res/public/.keycloakify/login/js/kcNumberUnFormat.js +19 -0
- package/res/public/.keycloakify/login/js/menu-button-links.js +315 -0
- package/{src/bin/shared/downloadKeycloakDefaultTheme/extra-assets → res/public/.keycloakify/login/js}/passkeysConditionalAuth.js +1 -1
- package/res/public/.keycloakify/login/js/passwordVisibility.js +15 -0
- package/res/public/.keycloakify/login/js/userProfile.js +71 -0
- package/res/public/.keycloakify/login/js/webauthnRegister.js +140 -0
- package/res/public/.keycloakify/login/resources-common/img/favicon.ico +0 -0
- package/res/public/.keycloakify/login/resources-common/lib/pficon/pficon.css +22 -0
- package/res/public/.keycloakify/login/resources-common/lib/pficon/pficon.woff2 +0 -0
- package/res/public/.keycloakify/login/resources-common/node_modules/@patternfly/patternfly/patternfly.min.css +2 -0
- package/res/public/.keycloakify/login/resources-common/node_modules/jquery/dist/jquery.min.js +2 -0
- package/res/public/.keycloakify/login/resources-common/node_modules/patternfly/dist/css/patternfly-additions.min.css +5 -0
- package/res/public/.keycloakify/login/resources-common/node_modules/patternfly/dist/css/patternfly.min.css +8 -0
- package/res/public/.keycloakify/login/resources-common/node_modules/patternfly/dist/fonts/OpenSans-Bold-webfont.ttf +0 -0
- package/res/public/.keycloakify/login/resources-common/node_modules/patternfly/dist/fonts/OpenSans-Bold-webfont.woff +0 -0
- package/res/public/.keycloakify/login/resources-common/node_modules/patternfly/dist/fonts/OpenSans-Bold-webfont.woff2 +0 -0
- package/res/public/.keycloakify/login/resources-common/node_modules/patternfly/dist/fonts/OpenSans-Light-webfont.woff2 +0 -0
- package/res/public/.keycloakify/login/resources-common/node_modules/patternfly/dist/fonts/OpenSans-Regular-webfont.woff2 +0 -0
- package/res/public/.keycloakify/login/resources-common/node_modules/patternfly/dist/fonts/OpenSans-Semibold-webfont.woff2 +0 -0
- package/res/public/.keycloakify/login/resources-common/node_modules/patternfly/dist/fonts/PatternFlyIcons-webfont.ttf +0 -0
- package/res/public/.keycloakify/login/resources-common/node_modules/patternfly/dist/fonts/PatternFlyIcons-webfont.woff +0 -0
- package/res/public/.keycloakify/login/resources-common/node_modules/patternfly/dist/fonts/fontawesome-webfont.woff2 +0 -0
- package/res/public/.keycloakify/login/resources-common/node_modules/patternfly/dist/img/bg-login.jpg +0 -0
- package/res/public/.keycloakify/login/resources-common/node_modules/rfc4648/lib/rfc4648.js +178 -0
- package/src/PUBLIC_URL.ts +5 -3
- package/src/account/KcContext/kcContextMocks.ts +3 -3
- package/src/bin/copy-keycloak-resources-to-public.ts +1 -1
- package/src/bin/initialize-account-theme/initializeAccountTheme_singlePage.ts +4 -1
- package/src/bin/initialize-email-theme.ts +28 -8
- package/src/bin/keycloakify/buildJars/buildJar.ts +3 -7
- package/src/bin/keycloakify/generateFtl/generateFtl.ts +3 -7
- package/src/bin/keycloakify/generateResources/generateResourcesForMainTheme.ts +65 -90
- package/src/bin/keycloakify/keycloakify.ts +38 -21
- package/src/bin/keycloakify/replacers/replaceImportsInCssCode.ts +2 -2
- package/src/bin/keycloakify/replacers/replaceImportsInJsCode/vite.ts +3 -3
- package/src/bin/keycloakify/replacers/replaceImportsInJsCode/webpack.ts +3 -3
- package/src/bin/shared/buildContext.ts +1 -8
- package/src/bin/shared/constants.ts +5 -7
- package/src/bin/shared/copyKeycloakResourcesToPublic.ts +30 -40
- package/src/bin/start-keycloak/start-keycloak.ts +3 -7
- package/src/login/KcContext/KcContext.ts +9 -18
- package/src/login/KcContext/kcContextMocks.ts +5 -13
- package/src/login/Template.tsx +4 -67
- package/src/login/Template.useStylesAndScripts.ts +94 -0
- package/src/login/pages/Login.tsx +1 -1
- package/src/login/pages/LoginIdpLinkConfirmOverride.tsx +0 -1
- package/src/login/pages/LoginPasskeysConditionalAuthenticate.tsx +6 -81
- package/src/login/pages/LoginPasskeysConditionalAuthenticate.useScript.tsx +72 -0
- package/src/login/pages/LoginRecoveryAuthnCodeConfig.tsx +4 -126
- package/src/login/pages/LoginRecoveryAuthnCodeConfig.useScript.tsx +142 -0
- package/src/login/pages/LoginUsername.tsx +1 -1
- package/src/login/pages/Register.tsx +35 -13
- package/src/login/pages/WebauthnAuthenticate.tsx +20 -133
- package/src/login/pages/WebauthnAuthenticate.useScript.tsx +64 -0
- package/src/login/pages/WebauthnRegister.tsx +8 -195
- package/src/login/pages/WebauthnRegister.useScript.tsx +93 -0
- package/src/tools/useInsertScriptTags.ts +14 -4
- package/src/vite-plugin/vite-plugin.ts +11 -15
- package/tools/useInsertScriptTags.d.ts +2 -2
- package/tools/useInsertScriptTags.js +8 -2
- package/tools/useInsertScriptTags.js.map +1 -1
- package/vite-plugin/index.js +3357 -47132
- package/bin/697.index.js +0 -4749
- package/bin/shared/downloadKeycloakStaticResources.d.ts +0 -9
- package/bin/shared/downloadKeycloakStaticResources.js.map +0 -1
- package/src/bin/keycloakify/generateResources/bringInAccountV1.ts +0 -89
- package/src/bin/shared/downloadKeycloakDefaultTheme/downloadKeycloakDefaultTheme.ts +0 -337
- package/src/bin/shared/downloadKeycloakDefaultTheme/index.ts +0 -1
- package/src/bin/shared/downloadKeycloakStaticResources.ts +0 -53
- /package/{src/bin/shared/downloadKeycloakDefaultTheme/extra-assets → res/public/.keycloakify/login/js}/webauthnAuthenticate.js +0 -0
@@ -0,0 +1,94 @@
|
|
1
|
+
import { useEffect } from "react";
|
2
|
+
import { assert } from "keycloakify/tools/assert";
|
3
|
+
import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
4
|
+
import { useInsertLinkTags } from "keycloakify/tools/useInsertLinkTags";
|
5
|
+
import { KcContext } from "keycloakify/login/KcContext/KcContext";
|
6
|
+
|
7
|
+
export type KcContextLike = {
|
8
|
+
url: {
|
9
|
+
resourcesCommonPath: string;
|
10
|
+
resourcesPath: string;
|
11
|
+
ssoLoginInOtherTabsUrl: string;
|
12
|
+
};
|
13
|
+
locale?: {
|
14
|
+
currentLanguageTag: string;
|
15
|
+
};
|
16
|
+
scripts: string[];
|
17
|
+
};
|
18
|
+
|
19
|
+
assert<keyof KcContextLike extends keyof KcContext ? true : false>();
|
20
|
+
assert<KcContext extends KcContextLike ? true : false>();
|
21
|
+
|
22
|
+
export function useStylesAndScripts(params: {
|
23
|
+
kcContext: KcContextLike;
|
24
|
+
doUseDefaultCss: boolean;
|
25
|
+
}) {
|
26
|
+
const { kcContext, doUseDefaultCss } = params;
|
27
|
+
|
28
|
+
const { url, locale, scripts } = kcContext;
|
29
|
+
|
30
|
+
useEffect(() => {
|
31
|
+
const { currentLanguageTag } = locale ?? {};
|
32
|
+
|
33
|
+
if (currentLanguageTag === undefined) {
|
34
|
+
return;
|
35
|
+
}
|
36
|
+
|
37
|
+
const html = document.querySelector("html");
|
38
|
+
assert(html !== null);
|
39
|
+
html.lang = currentLanguageTag;
|
40
|
+
}, []);
|
41
|
+
|
42
|
+
const { areAllStyleSheetsLoaded } = useInsertLinkTags({
|
43
|
+
componentOrHookName: "Template",
|
44
|
+
hrefs: !doUseDefaultCss
|
45
|
+
? []
|
46
|
+
: [
|
47
|
+
`${url.resourcesCommonPath}/node_modules/@patternfly/patternfly/patternfly.min.css`,
|
48
|
+
`${url.resourcesCommonPath}/node_modules/patternfly/dist/css/patternfly.min.css`,
|
49
|
+
`${url.resourcesCommonPath}/node_modules/patternfly/dist/css/patternfly-additions.min.css`,
|
50
|
+
`${url.resourcesCommonPath}/lib/pficon/pficon.css`,
|
51
|
+
`${url.resourcesPath}/css/login.css`
|
52
|
+
]
|
53
|
+
});
|
54
|
+
|
55
|
+
const { insertScriptTags } = useInsertScriptTags({
|
56
|
+
componentOrHookName: "Template",
|
57
|
+
scriptTags: [
|
58
|
+
{
|
59
|
+
type: "importmap",
|
60
|
+
textContent: JSON.stringify({
|
61
|
+
imports: {
|
62
|
+
rfc4648: `${url.resourcesCommonPath}/node_modules/rfc4648/lib/rfc4648.js`
|
63
|
+
}
|
64
|
+
})
|
65
|
+
},
|
66
|
+
{
|
67
|
+
type: "module",
|
68
|
+
src: `${url.resourcesPath}/js/menu-button-links.js`
|
69
|
+
},
|
70
|
+
...scripts.map(src => ({
|
71
|
+
type: "text/javascript" as const,
|
72
|
+
src
|
73
|
+
})),
|
74
|
+
{
|
75
|
+
type: "module",
|
76
|
+
textContent: `
|
77
|
+
import { checkCookiesAndSetTimer } from "${url.resourcesPath}/js/authChecker.js";
|
78
|
+
|
79
|
+
checkCookiesAndSetTimer(
|
80
|
+
"${url.ssoLoginInOtherTabsUrl}"
|
81
|
+
);
|
82
|
+
`
|
83
|
+
}
|
84
|
+
]
|
85
|
+
});
|
86
|
+
|
87
|
+
useEffect(() => {
|
88
|
+
if (areAllStyleSheetsLoaded) {
|
89
|
+
insertScriptTags();
|
90
|
+
}
|
91
|
+
}, [areAllStyleSheetsLoaded]);
|
92
|
+
|
93
|
+
return { isReadyToRender: areAllStyleSheetsLoaded };
|
94
|
+
}
|
@@ -43,7 +43,7 @@ export default function Login(props: PageProps<Extract<KcContext, { pageId: "log
|
|
43
43
|
}
|
44
44
|
socialProvidersNode={
|
45
45
|
<>
|
46
|
-
{realm.password && social
|
46
|
+
{realm.password && social?.providers !== undefined && social.providers.length !== 0 && (
|
47
47
|
<div id="kc-social-providers" className={kcClsx("kcFormSocialAccountSectionClass")}>
|
48
48
|
<hr />
|
49
49
|
<h2>{msg("identity-provider-login-label")}</h2>
|
@@ -3,7 +3,6 @@ import type { PageProps } from "keycloakify/login/pages/PageProps";
|
|
3
3
|
import type { KcContext } from "../KcContext";
|
4
4
|
import type { I18n } from "../i18n";
|
5
5
|
|
6
|
-
// NOTE: Added with Keycloak 25
|
7
6
|
export default function LoginIdpLinkConfirmOverride(props: PageProps<Extract<KcContext, { pageId: "login-idp-link-confirm-override.ftl" }>, I18n>) {
|
8
7
|
const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
|
9
8
|
|
@@ -1,33 +1,17 @@
|
|
1
|
-
import {
|
1
|
+
import { Fragment } from "react";
|
2
2
|
import { clsx } from "keycloakify/tools/clsx";
|
3
3
|
import type { PageProps } from "keycloakify/login/pages/PageProps";
|
4
|
-
import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
5
4
|
import { getKcClsx } from "keycloakify/login/lib/kcClsx";
|
6
|
-
import {
|
5
|
+
import { useScript } from "keycloakify/login/pages/LoginPasskeysConditionalAuthenticate.useScript";
|
7
6
|
import type { KcContext } from "../KcContext";
|
8
7
|
import type { I18n } from "../i18n";
|
9
8
|
|
10
|
-
// NOTE: From Keycloak 25.0.4
|
11
9
|
export default function LoginPasskeysConditionalAuthenticate(
|
12
10
|
props: PageProps<Extract<KcContext, { pageId: "login-passkeys-conditional-authenticate.ftl" }>, I18n>
|
13
11
|
) {
|
14
12
|
const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
|
15
13
|
|
16
|
-
const {
|
17
|
-
messagesPerField,
|
18
|
-
login,
|
19
|
-
url,
|
20
|
-
usernameHidden,
|
21
|
-
shouldDisplayAuthenticators,
|
22
|
-
authenticators,
|
23
|
-
registrationDisabled,
|
24
|
-
realm,
|
25
|
-
isUserIdentified,
|
26
|
-
challenge,
|
27
|
-
userVerification,
|
28
|
-
rpId,
|
29
|
-
createTimeout
|
30
|
-
} = kcContext;
|
14
|
+
const { messagesPerField, login, url, usernameHidden, shouldDisplayAuthenticators, authenticators, registrationDisabled, realm } = kcContext;
|
31
15
|
|
32
16
|
const { msg, msgStr, advancedMsg } = i18n;
|
33
17
|
|
@@ -36,46 +20,9 @@ export default function LoginPasskeysConditionalAuthenticate(
|
|
36
20
|
classes
|
37
21
|
});
|
38
22
|
|
39
|
-
const
|
40
|
-
componentOrHookName: "LoginRecoveryAuthnCodeConfig",
|
41
|
-
scriptTags: [
|
42
|
-
{
|
43
|
-
type: "module",
|
44
|
-
textContent: `
|
45
|
-
import { authenticateByWebAuthn } from "${url.resourcesPath}/js/webauthnAuthenticate.js";
|
46
|
-
import { initAuthenticate } from "${url.resourcesPath}/js/passkeysConditionalAuth.js";
|
23
|
+
const authButtonId = "authenticateWebAuthnButton";
|
47
24
|
|
48
|
-
|
49
|
-
const input = {
|
50
|
-
isUserIdentified : ${isUserIdentified},
|
51
|
-
challenge : '${challenge}',
|
52
|
-
userVerification : '${userVerification}',
|
53
|
-
rpId : '${rpId}',
|
54
|
-
createTimeout : ${createTimeout},
|
55
|
-
errmsg : "${msgStr("webauthn-unsupported-browser-text")}"
|
56
|
-
};
|
57
|
-
authButton.addEventListener("click", () => {
|
58
|
-
authenticateByWebAuthn(input);
|
59
|
-
});
|
60
|
-
|
61
|
-
const args = {
|
62
|
-
isUserIdentified : ${isUserIdentified},
|
63
|
-
challenge : '${challenge}',
|
64
|
-
userVerification : '${userVerification}',
|
65
|
-
rpId : '${rpId}',
|
66
|
-
createTimeout : ${createTimeout},
|
67
|
-
errmsg : "${msgStr("passkey-unsupported-browser-text")}"
|
68
|
-
};
|
69
|
-
|
70
|
-
document.addEventListener("DOMContentLoaded", (event) => initAuthenticate(args));
|
71
|
-
`
|
72
|
-
}
|
73
|
-
]
|
74
|
-
});
|
75
|
-
|
76
|
-
useEffect(() => {
|
77
|
-
insertScriptTags();
|
78
|
-
}, []);
|
25
|
+
useScript({ authButtonId, kcContext, i18n });
|
79
26
|
|
80
27
|
return (
|
81
28
|
<Template
|
@@ -213,29 +160,7 @@ export default function LoginPasskeysConditionalAuthenticate(
|
|
213
160
|
)}
|
214
161
|
<div id="kc-form-passkey-button" className={kcClsx("kcFormButtonsClass")} style={{ display: "none" }}>
|
215
162
|
<input
|
216
|
-
id=
|
217
|
-
type="button"
|
218
|
-
onClick={() => {
|
219
|
-
assert("doAuthenticate" in window);
|
220
|
-
assert(typeof window.doAuthenticate === "function");
|
221
|
-
window.doAuthenticate(
|
222
|
-
[],
|
223
|
-
rpId,
|
224
|
-
challenge,
|
225
|
-
typeof isUserIdentified === "boolean" ? isUserIdentified : isUserIdentified === "true",
|
226
|
-
createTimeout,
|
227
|
-
userVerification,
|
228
|
-
msgStr("passkey-unsupported-browser-text")
|
229
|
-
);
|
230
|
-
}}
|
231
|
-
autoFocus
|
232
|
-
value={msgStr("passkey-doAuthenticate")}
|
233
|
-
className={kcClsx("kcButtonClass", "kcButtonPrimaryClass", "kcButtonBlockClass", "kcButtonLargeClass")}
|
234
|
-
/>
|
235
|
-
</div>
|
236
|
-
<div id="kc-form-passkey-button" className={kcClsx("kcFormButtonsClass")} style={{ display: "none" }}>
|
237
|
-
<input
|
238
|
-
id="authenticateWebAuthnButton"
|
163
|
+
id={authButtonId}
|
239
164
|
type="button"
|
240
165
|
autoFocus
|
241
166
|
value={msgStr("passkey-doAuthenticate")}
|
@@ -0,0 +1,72 @@
|
|
1
|
+
import { useEffect } from "react";
|
2
|
+
import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
3
|
+
import { assert } from "keycloakify/tools/assert";
|
4
|
+
import { KcContext } from "keycloakify/login/KcContext/KcContext";
|
5
|
+
|
6
|
+
type KcContextLike = {
|
7
|
+
url: {
|
8
|
+
resourcesPath: string;
|
9
|
+
};
|
10
|
+
isUserIdentified: boolean | "true" | "false";
|
11
|
+
challenge: string;
|
12
|
+
userVerification: string;
|
13
|
+
rpId: string;
|
14
|
+
createTimeout: number | string;
|
15
|
+
};
|
16
|
+
|
17
|
+
assert<keyof KcContextLike extends keyof KcContext.LoginPasskeysConditionalAuthenticate ? true : false>();
|
18
|
+
assert<KcContext.LoginPasskeysConditionalAuthenticate extends KcContextLike ? true : false>();
|
19
|
+
|
20
|
+
type I18nLike = {
|
21
|
+
msgStr: (key: "webauthn-unsupported-browser-text" | "passkey-unsupported-browser-text") => string;
|
22
|
+
isFetchingTranslations: boolean;
|
23
|
+
};
|
24
|
+
|
25
|
+
export function useScript(params: { authButtonId: string; kcContext: KcContextLike; i18n: I18nLike }) {
|
26
|
+
const { authButtonId, kcContext, i18n } = params;
|
27
|
+
|
28
|
+
const { url, isUserIdentified, challenge, userVerification, rpId, createTimeout } = kcContext;
|
29
|
+
|
30
|
+
const { msgStr, isFetchingTranslations } = i18n;
|
31
|
+
|
32
|
+
const { insertScriptTags } = useInsertScriptTags({
|
33
|
+
componentOrHookName: "LoginRecoveryAuthnCodeConfig",
|
34
|
+
scriptTags: [
|
35
|
+
{
|
36
|
+
type: "module",
|
37
|
+
textContent: () => `
|
38
|
+
import { authenticateByWebAuthn } from "${url.resourcesPath}/js/webauthnAuthenticate.js";
|
39
|
+
import { initAuthenticate } from "${url.resourcesPath}/js/passkeysConditionalAuth.js";
|
40
|
+
|
41
|
+
const authButton = document.getElementById("${authButtonId}");
|
42
|
+
const input = {
|
43
|
+
isUserIdentified : ${isUserIdentified},
|
44
|
+
challenge : ${JSON.stringify(challenge)},
|
45
|
+
userVerification : ${JSON.stringify(userVerification)},
|
46
|
+
rpId : ${JSON.stringify(rpId)},
|
47
|
+
createTimeout : ${createTimeout}
|
48
|
+
};
|
49
|
+
authButton.addEventListener("click", () => {
|
50
|
+
authenticateByWebAuthn({
|
51
|
+
...input,
|
52
|
+
errmsg : ${JSON.stringify(msgStr("webauthn-unsupported-browser-text"))}
|
53
|
+
});
|
54
|
+
});
|
55
|
+
|
56
|
+
initAuthenticate({
|
57
|
+
...input,
|
58
|
+
errmsg : ${JSON.stringify(msgStr("passkey-unsupported-browser-text"))}
|
59
|
+
});
|
60
|
+
`
|
61
|
+
}
|
62
|
+
]
|
63
|
+
});
|
64
|
+
|
65
|
+
useEffect(() => {
|
66
|
+
if (isFetchingTranslations) {
|
67
|
+
return;
|
68
|
+
}
|
69
|
+
|
70
|
+
insertScriptTags();
|
71
|
+
}, [isFetchingTranslations]);
|
72
|
+
}
|
@@ -1,7 +1,6 @@
|
|
1
|
-
import { useEffect } from "react";
|
2
1
|
import { clsx } from "keycloakify/tools/clsx";
|
3
2
|
import { getKcClsx, type KcClsx } from "keycloakify/login/lib/kcClsx";
|
4
|
-
import {
|
3
|
+
import { useScript } from "keycloakify/login/pages/LoginRecoveryAuthnCodeConfig.useScript";
|
5
4
|
import type { PageProps } from "keycloakify/login/pages/PageProps";
|
6
5
|
import type { KcContext } from "../KcContext";
|
7
6
|
import type { I18n } from "../i18n";
|
@@ -18,130 +17,9 @@ export default function LoginRecoveryAuthnCodeConfig(props: PageProps<Extract<Kc
|
|
18
17
|
|
19
18
|
const { msg, msgStr } = i18n;
|
20
19
|
|
21
|
-
const
|
22
|
-
componentOrHookName: "LoginRecoveryAuthnCodeConfig",
|
23
|
-
scriptTags: [
|
24
|
-
{
|
25
|
-
type: "text/javascript",
|
26
|
-
textContent: `
|
20
|
+
const olRecoveryCodesListId = "kc-recovery-codes-list";
|
27
21
|
|
28
|
-
|
29
|
-
function copyRecoveryCodes() {
|
30
|
-
var tmpTextarea = document.createElement("textarea");
|
31
|
-
var codes = document.getElementById("kc-recovery-codes-list").getElementsByTagName("li");
|
32
|
-
for (i = 0; i < codes.length; i++) {
|
33
|
-
tmpTextarea.value = tmpTextarea.value + codes[i].innerText + "\\n";
|
34
|
-
}
|
35
|
-
document.body.appendChild(tmpTextarea);
|
36
|
-
tmpTextarea.select();
|
37
|
-
document.execCommand("copy");
|
38
|
-
document.body.removeChild(tmpTextarea);
|
39
|
-
}
|
40
|
-
|
41
|
-
var copyButton = document.getElementById("copyRecoveryCodes");
|
42
|
-
copyButton && copyButton.addEventListener("click", function () {
|
43
|
-
copyRecoveryCodes();
|
44
|
-
});
|
45
|
-
|
46
|
-
/* download recovery codes */
|
47
|
-
function formatCurrentDateTime() {
|
48
|
-
var dt = new Date();
|
49
|
-
var options = {
|
50
|
-
month: 'long',
|
51
|
-
day: 'numeric',
|
52
|
-
year: 'numeric',
|
53
|
-
hour: 'numeric',
|
54
|
-
minute: 'numeric',
|
55
|
-
timeZoneName: 'short'
|
56
|
-
};
|
57
|
-
|
58
|
-
return dt.toLocaleString('en-US', options);
|
59
|
-
}
|
60
|
-
|
61
|
-
function parseRecoveryCodeList() {
|
62
|
-
var recoveryCodes = document.querySelectorAll(".kc-recovery-codes-list li");
|
63
|
-
var recoveryCodeList = "";
|
64
|
-
|
65
|
-
for (var i = 0; i < recoveryCodes.length; i++) {
|
66
|
-
var recoveryCodeLiElement = recoveryCodes[i].innerText;
|
67
|
-
recoveryCodeList += recoveryCodeLiElement + "\\r\\n";
|
68
|
-
}
|
69
|
-
|
70
|
-
return recoveryCodeList;
|
71
|
-
}
|
72
|
-
|
73
|
-
function buildDownloadContent() {
|
74
|
-
var recoveryCodeList = parseRecoveryCodeList();
|
75
|
-
var dt = new Date();
|
76
|
-
var options = {
|
77
|
-
month: 'long',
|
78
|
-
day: 'numeric',
|
79
|
-
year: 'numeric',
|
80
|
-
hour: 'numeric',
|
81
|
-
minute: 'numeric',
|
82
|
-
timeZoneName: 'short'
|
83
|
-
};
|
84
|
-
|
85
|
-
return fileBodyContent =
|
86
|
-
"${msgStr("recovery-codes-download-file-header")}\\n\\n" +
|
87
|
-
recoveryCodeList + "\\n" +
|
88
|
-
"${msgStr("recovery-codes-download-file-description")}\\n\\n" +
|
89
|
-
"${msgStr("recovery-codes-download-file-date")} " + formatCurrentDateTime();
|
90
|
-
}
|
91
|
-
|
92
|
-
function setUpDownloadLinkAndDownload(filename, text) {
|
93
|
-
var el = document.createElement('a');
|
94
|
-
el.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
95
|
-
el.setAttribute('download', filename);
|
96
|
-
el.style.display = 'none';
|
97
|
-
document.body.appendChild(el);
|
98
|
-
el.click();
|
99
|
-
document.body.removeChild(el);
|
100
|
-
}
|
101
|
-
|
102
|
-
function downloadRecoveryCodes() {
|
103
|
-
setUpDownloadLinkAndDownload('kc-download-recovery-codes.txt', buildDownloadContent());
|
104
|
-
}
|
105
|
-
|
106
|
-
var downloadButton = document.getElementById("downloadRecoveryCodes");
|
107
|
-
downloadButton && downloadButton.addEventListener("click", downloadRecoveryCodes);
|
108
|
-
|
109
|
-
/* print recovery codes */
|
110
|
-
function buildPrintContent() {
|
111
|
-
var recoveryCodeListHTML = document.getElementById('kc-recovery-codes-list').innerHTML;
|
112
|
-
var styles =
|
113
|
-
\`@page { size: auto; margin-top: 0; }
|
114
|
-
body { width: 480px; }
|
115
|
-
div { list-style-type: none; font-family: monospace }
|
116
|
-
p:first-of-type { margin-top: 48px }\`;
|
117
|
-
|
118
|
-
return printFileContent =
|
119
|
-
"<html><style>" + styles + "</style><body>" +
|
120
|
-
"<title>kc-download-recovery-codes</title>" +
|
121
|
-
"<p>${msgStr("recovery-codes-download-file-header")}</p>" +
|
122
|
-
"<div>" + recoveryCodeListHTML + "</div>" +
|
123
|
-
"<p>${msgStr("recovery-codes-download-file-description")}</p>" +
|
124
|
-
"<p>${msgStr("recovery-codes-download-file-date")} " + formatCurrentDateTime() + "</p>" +
|
125
|
-
"</body></html>";
|
126
|
-
}
|
127
|
-
|
128
|
-
function printRecoveryCodes() {
|
129
|
-
var w = window.open();
|
130
|
-
w.document.write(buildPrintContent());
|
131
|
-
w.print();
|
132
|
-
w.close();
|
133
|
-
}
|
134
|
-
|
135
|
-
var printButton = document.getElementById("printRecoveryCodes");
|
136
|
-
printButton && printButton.addEventListener("click", printRecoveryCodes);
|
137
|
-
`
|
138
|
-
}
|
139
|
-
]
|
140
|
-
});
|
141
|
-
|
142
|
-
useEffect(() => {
|
143
|
-
insertScriptTags();
|
144
|
-
}, []);
|
22
|
+
useScript({ olRecoveryCodesListId, i18n });
|
145
23
|
|
146
24
|
return (
|
147
25
|
<Template
|
@@ -164,7 +42,7 @@ export default function LoginRecoveryAuthnCodeConfig(props: PageProps<Extract<Kc
|
|
164
42
|
</div>
|
165
43
|
</div>
|
166
44
|
|
167
|
-
<ol id=
|
45
|
+
<ol id={olRecoveryCodesListId} className={kcClsx("kcRecoveryCodesList")}>
|
168
46
|
{recoveryAuthnCodesConfigBean.generatedRecoveryAuthnCodesList.map((code, index) => (
|
169
47
|
<li key={index}>
|
170
48
|
<span>{index + 1}:</span> {code.slice(0, 4)}-{code.slice(4, 8)}-{code.slice(8)}
|
@@ -0,0 +1,142 @@
|
|
1
|
+
import { useEffect } from "react";
|
2
|
+
import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
3
|
+
|
4
|
+
type I18nLike = {
|
5
|
+
msgStr: (key: "recovery-codes-download-file-header" | "recovery-codes-download-file-description" | "recovery-codes-download-file-date") => string;
|
6
|
+
isFetchingTranslations: boolean;
|
7
|
+
};
|
8
|
+
|
9
|
+
export function useScript(params: { olRecoveryCodesListId: string; i18n: I18nLike }) {
|
10
|
+
const { olRecoveryCodesListId, i18n } = params;
|
11
|
+
|
12
|
+
const { msgStr, isFetchingTranslations } = i18n;
|
13
|
+
|
14
|
+
const { insertScriptTags } = useInsertScriptTags({
|
15
|
+
componentOrHookName: "LoginRecoveryAuthnCodeConfig",
|
16
|
+
scriptTags: [
|
17
|
+
{
|
18
|
+
type: "text/javascript",
|
19
|
+
textContent: () => `
|
20
|
+
|
21
|
+
/* copy recovery codes */
|
22
|
+
function copyRecoveryCodes() {
|
23
|
+
var tmpTextarea = document.createElement("textarea");
|
24
|
+
var codes = document.querySelectorAll("#${olRecoveryCodesListId} li");
|
25
|
+
for (i = 0; i < codes.length; i++) {
|
26
|
+
tmpTextarea.value = tmpTextarea.value + codes[i].innerText + "\\n";
|
27
|
+
}
|
28
|
+
document.body.appendChild(tmpTextarea);
|
29
|
+
tmpTextarea.select();
|
30
|
+
document.execCommand("copy");
|
31
|
+
document.body.removeChild(tmpTextarea);
|
32
|
+
}
|
33
|
+
|
34
|
+
var copyButton = document.getElementById("copyRecoveryCodes");
|
35
|
+
copyButton && copyButton.addEventListener("click", function () {
|
36
|
+
copyRecoveryCodes();
|
37
|
+
});
|
38
|
+
|
39
|
+
/* download recovery codes */
|
40
|
+
function formatCurrentDateTime() {
|
41
|
+
var dt = new Date();
|
42
|
+
var options = {
|
43
|
+
month: 'long',
|
44
|
+
day: 'numeric',
|
45
|
+
year: 'numeric',
|
46
|
+
hour: 'numeric',
|
47
|
+
minute: 'numeric',
|
48
|
+
timeZoneName: 'short'
|
49
|
+
};
|
50
|
+
|
51
|
+
return dt.toLocaleString('en-US', options);
|
52
|
+
}
|
53
|
+
|
54
|
+
function parseRecoveryCodeList() {
|
55
|
+
var recoveryCodes = document.querySelectorAll("#${olRecoveryCodesListId} li");
|
56
|
+
var recoveryCodeList = "";
|
57
|
+
|
58
|
+
for (var i = 0; i < recoveryCodes.length; i++) {
|
59
|
+
var recoveryCodeLiElement = recoveryCodes[i].innerText;
|
60
|
+
recoveryCodeList += recoveryCodeLiElement + "\\r\\n";
|
61
|
+
}
|
62
|
+
|
63
|
+
return recoveryCodeList;
|
64
|
+
}
|
65
|
+
|
66
|
+
function buildDownloadContent() {
|
67
|
+
var recoveryCodeList = parseRecoveryCodeList();
|
68
|
+
var dt = new Date();
|
69
|
+
var options = {
|
70
|
+
month: 'long',
|
71
|
+
day: 'numeric',
|
72
|
+
year: 'numeric',
|
73
|
+
hour: 'numeric',
|
74
|
+
minute: 'numeric',
|
75
|
+
timeZoneName: 'short'
|
76
|
+
};
|
77
|
+
|
78
|
+
return fileBodyContent =
|
79
|
+
${JSON.stringify(msgStr("recovery-codes-download-file-header"))} + "\\n\\n" +
|
80
|
+
recoveryCodeList + "\\n" +
|
81
|
+
${JSON.stringify(msgStr("recovery-codes-download-file-description"))} + "\\n\\n" +
|
82
|
+
${JSON.stringify(msgStr("recovery-codes-download-file-date"))} + " " + formatCurrentDateTime();
|
83
|
+
}
|
84
|
+
|
85
|
+
function setUpDownloadLinkAndDownload(filename, text) {
|
86
|
+
var el = document.createElement('a');
|
87
|
+
el.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
88
|
+
el.setAttribute('download', filename);
|
89
|
+
el.style.display = 'none';
|
90
|
+
document.body.appendChild(el);
|
91
|
+
el.click();
|
92
|
+
document.body.removeChild(el);
|
93
|
+
}
|
94
|
+
|
95
|
+
function downloadRecoveryCodes() {
|
96
|
+
setUpDownloadLinkAndDownload('kc-download-recovery-codes.txt', buildDownloadContent());
|
97
|
+
}
|
98
|
+
|
99
|
+
var downloadButton = document.getElementById("downloadRecoveryCodes");
|
100
|
+
downloadButton && downloadButton.addEventListener("click", downloadRecoveryCodes);
|
101
|
+
|
102
|
+
/* print recovery codes */
|
103
|
+
function buildPrintContent() {
|
104
|
+
var recoveryCodeListHTML = document.getElementById('${olRecoveryCodesListId}').innerHTML;
|
105
|
+
var styles =
|
106
|
+
\`@page { size: auto; margin-top: 0; }
|
107
|
+
body { width: 480px; }
|
108
|
+
div { list-style-type: none; font-family: monospace }
|
109
|
+
p:first-of-type { margin-top: 48px }\`;
|
110
|
+
|
111
|
+
return printFileContent =
|
112
|
+
"<html><style>" + styles + "</style><body>" +
|
113
|
+
"<title>kc-download-recovery-codes</title>" +
|
114
|
+
"<p>" + ${JSON.stringify(msgStr("recovery-codes-download-file-header"))} + "</p>" +
|
115
|
+
"<div>" + recoveryCodeListHTML + "</div>" +
|
116
|
+
"<p>" + ${JSON.stringify(msgStr("recovery-codes-download-file-description"))} + "</p>" +
|
117
|
+
"<p>" + ${JSON.stringify(msgStr("recovery-codes-download-file-date"))} + " " + formatCurrentDateTime() + "</p>" +
|
118
|
+
"</body></html>";
|
119
|
+
}
|
120
|
+
|
121
|
+
function printRecoveryCodes() {
|
122
|
+
var w = window.open();
|
123
|
+
w.document.write(buildPrintContent());
|
124
|
+
w.print();
|
125
|
+
w.close();
|
126
|
+
}
|
127
|
+
|
128
|
+
var printButton = document.getElementById("printRecoveryCodes");
|
129
|
+
printButton && printButton.addEventListener("click", printRecoveryCodes);
|
130
|
+
`
|
131
|
+
}
|
132
|
+
]
|
133
|
+
});
|
134
|
+
|
135
|
+
useEffect(() => {
|
136
|
+
if (isFetchingTranslations) {
|
137
|
+
return;
|
138
|
+
}
|
139
|
+
|
140
|
+
insertScriptTags();
|
141
|
+
}, [isFetchingTranslations]);
|
142
|
+
}
|
@@ -40,7 +40,7 @@ export default function LoginUsername(props: PageProps<Extract<KcContext, { page
|
|
40
40
|
headerNode={msg("doLogIn")}
|
41
41
|
socialProvidersNode={
|
42
42
|
<>
|
43
|
-
{realm.password && social
|
43
|
+
{realm.password && social?.providers !== undefined && social.providers.length !== 0 && (
|
44
44
|
<div id="kc-social-providers" className={kcClsx("kcFormSocialAccountSectionClass")}>
|
45
45
|
<hr />
|
46
46
|
<h2>{msg("identity-provider-login-label")}</h2>
|