keycloakify 10.1.0-rc.1 → 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 -338
- 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
@@ -1,6 +1,7 @@
|
|
1
1
|
import { useState } from "react";
|
2
2
|
import type { LazyOrNot } from "keycloakify/tools/LazyOrNot";
|
3
3
|
import { getKcClsx, type KcClsx } from "keycloakify/login/lib/kcClsx";
|
4
|
+
import { clsx } from "keycloakify/tools/clsx";
|
4
5
|
import type { UserProfileFormFieldsProps } from "keycloakify/login/UserProfileFormFieldsProps";
|
5
6
|
import type { PageProps } from "keycloakify/login/pages/PageProps";
|
6
7
|
import type { KcContext } from "../KcContext";
|
@@ -19,9 +20,10 @@ export default function Register(props: RegisterProps) {
|
|
19
20
|
classes
|
20
21
|
});
|
21
22
|
|
22
|
-
const { url, messagesPerField, recaptchaRequired, recaptchaSiteKey, termsAcceptanceRequired } =
|
23
|
+
const { messageHeader, url, messagesPerField, recaptchaRequired, recaptchaVisible, recaptchaSiteKey, recaptchaAction, termsAcceptanceRequired } =
|
24
|
+
kcContext;
|
23
25
|
|
24
|
-
const { msg, msgStr } = i18n;
|
26
|
+
const { msg, msgStr, advancedMsg } = i18n;
|
25
27
|
|
26
28
|
const [isFormSubmittable, setIsFormSubmittable] = useState(false);
|
27
29
|
const [areTermsAccepted, setAreTermsAccepted] = useState(false);
|
@@ -32,7 +34,7 @@ export default function Register(props: RegisterProps) {
|
|
32
34
|
i18n={i18n}
|
33
35
|
doUseDefaultCss={doUseDefaultCss}
|
34
36
|
classes={classes}
|
35
|
-
headerNode={msg("registerTitle")}
|
37
|
+
headerNode={messageHeader !== undefined ? advancedMsg(messageHeader) : msg("registerTitle")}
|
36
38
|
displayMessage={messagesPerField.exists("global")}
|
37
39
|
displayRequiredFields
|
38
40
|
>
|
@@ -53,10 +55,10 @@ export default function Register(props: RegisterProps) {
|
|
53
55
|
onAreTermsAcceptedValueChange={setAreTermsAccepted}
|
54
56
|
/>
|
55
57
|
)}
|
56
|
-
{recaptchaRequired && (
|
58
|
+
{recaptchaRequired && (recaptchaVisible || recaptchaAction === undefined) && (
|
57
59
|
<div className="form-group">
|
58
60
|
<div className={kcClsx("kcInputWrapperClass")}>
|
59
|
-
<div className="g-recaptcha" data-size="compact" data-sitekey={recaptchaSiteKey}></div>
|
61
|
+
<div className="g-recaptcha" data-size="compact" data-sitekey={recaptchaSiteKey} data-action={recaptchaAction}></div>
|
60
62
|
</div>
|
61
63
|
</div>
|
62
64
|
)}
|
@@ -68,14 +70,34 @@ export default function Register(props: RegisterProps) {
|
|
68
70
|
</span>
|
69
71
|
</div>
|
70
72
|
</div>
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
73
|
+
|
74
|
+
{recaptchaRequired && !recaptchaVisible && recaptchaAction !== undefined ? (
|
75
|
+
<div id="kc-form-buttons" className={kcClsx("kcFormButtonsClass")}>
|
76
|
+
<button
|
77
|
+
className={clsx(
|
78
|
+
kcClsx("kcButtonClass", "kcButtonPrimaryClass", "kcButtonBlockClass", "kcButtonLargeClass"),
|
79
|
+
"g-recaptcha"
|
80
|
+
)}
|
81
|
+
data-sitekey={recaptchaSiteKey}
|
82
|
+
data-callback={() => {
|
83
|
+
(document.getElementById("kc-register-form") as HTMLFormElement).submit();
|
84
|
+
}}
|
85
|
+
data-action={recaptchaAction}
|
86
|
+
type="submit"
|
87
|
+
>
|
88
|
+
{msg("doRegister")}
|
89
|
+
</button>
|
90
|
+
</div>
|
91
|
+
) : (
|
92
|
+
<div id="kc-form-buttons" className={kcClsx("kcFormButtonsClass")}>
|
93
|
+
<input
|
94
|
+
disabled={!isFormSubmittable || (termsAcceptanceRequired && !areTermsAccepted)}
|
95
|
+
className={kcClsx("kcButtonClass", "kcButtonPrimaryClass", "kcButtonBlockClass", "kcButtonLargeClass")}
|
96
|
+
type="submit"
|
97
|
+
value={msgStr("doRegister")}
|
98
|
+
/>
|
99
|
+
</div>
|
100
|
+
)}
|
79
101
|
</div>
|
80
102
|
</form>
|
81
103
|
</Template>
|
@@ -1,8 +1,7 @@
|
|
1
|
-
import {
|
2
|
-
import { assert } from "keycloakify/tools/assert";
|
1
|
+
import { Fragment } from "react";
|
3
2
|
import { clsx } from "keycloakify/tools/clsx";
|
4
|
-
import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
5
3
|
import { getKcClsx } from "keycloakify/login/lib/kcClsx";
|
4
|
+
import { useScript } from "keycloakify/login/pages/WebauthnAuthenticate.useScript";
|
6
5
|
import type { PageProps } from "keycloakify/login/pages/PageProps";
|
7
6
|
import type { KcContext } from "../KcContext";
|
8
7
|
import type { I18n } from "../i18n";
|
@@ -12,136 +11,25 @@ export default function WebauthnAuthenticate(props: PageProps<Extract<KcContext,
|
|
12
11
|
|
13
12
|
const { kcClsx } = getKcClsx({ doUseDefaultCss, classes });
|
14
13
|
|
15
|
-
const {
|
16
|
-
url,
|
17
|
-
isUserIdentified,
|
18
|
-
challenge,
|
19
|
-
userVerification,
|
20
|
-
rpId,
|
21
|
-
createTimeout,
|
22
|
-
messagesPerField,
|
23
|
-
realm,
|
24
|
-
registrationDisabled,
|
25
|
-
authenticators,
|
26
|
-
shouldDisplayAuthenticators
|
27
|
-
} = kcContext;
|
14
|
+
const { url, realm, registrationDisabled, authenticators, shouldDisplayAuthenticators } = kcContext;
|
28
15
|
|
29
16
|
const { msg, msgStr, advancedMsg } = i18n;
|
30
17
|
|
31
|
-
const
|
32
|
-
componentOrHookName: "WebauthnAuthenticate",
|
33
|
-
scriptTags: [
|
34
|
-
{
|
35
|
-
type: "text/javascript",
|
36
|
-
src: `${url.resourcesCommonPath}/node_modules/jquery/dist/jquery.min.js`
|
37
|
-
},
|
38
|
-
{
|
39
|
-
type: "text/javascript",
|
40
|
-
src: `${url.resourcesPath}/js/base64url.js`
|
41
|
-
},
|
42
|
-
{
|
43
|
-
type: "text/javascript",
|
44
|
-
textContent: `
|
18
|
+
const authButtonId = "authenticateWebAuthnButton";
|
45
19
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
return;
|
51
|
-
}
|
52
|
-
checkAllowCredentials();
|
53
|
-
}
|
54
|
-
|
55
|
-
function checkAllowCredentials() {
|
56
|
-
let allowCredentials = [];
|
57
|
-
let authn_use = document.forms['authn_select'].authn_use_chk;
|
58
|
-
|
59
|
-
if (authn_use !== undefined) {
|
60
|
-
if (authn_use.length === undefined) {
|
61
|
-
allowCredentials.push({
|
62
|
-
id: base64url.decode(authn_use.value, {loose: true}),
|
63
|
-
type: 'public-key',
|
64
|
-
});
|
65
|
-
} else {
|
66
|
-
for (let i = 0; i < authn_use.length; i++) {
|
67
|
-
allowCredentials.push({
|
68
|
-
id: base64url.decode(authn_use[i].value, {loose: true}),
|
69
|
-
type: 'public-key',
|
70
|
-
});
|
71
|
-
}
|
72
|
-
}
|
73
|
-
}
|
74
|
-
doAuthenticate(allowCredentials);
|
75
|
-
}
|
76
|
-
|
77
|
-
|
78
|
-
function doAuthenticate(allowCredentials) {
|
79
|
-
|
80
|
-
// Check if WebAuthn is supported by this browser
|
81
|
-
if (!window.PublicKeyCredential) {
|
82
|
-
$("#error").val("${msgStr("webauthn-unsupported-browser-text")}");
|
83
|
-
$("#webauth").submit();
|
84
|
-
return;
|
85
|
-
}
|
86
|
-
|
87
|
-
let challenge = "${challenge}";
|
88
|
-
let userVerification = "${userVerification}";
|
89
|
-
let rpId = "${rpId}";
|
90
|
-
let publicKey = {
|
91
|
-
rpId : rpId,
|
92
|
-
challenge: base64url.decode(challenge, { loose: true })
|
93
|
-
};
|
94
|
-
|
95
|
-
let createTimeout = ${createTimeout};
|
96
|
-
if (createTimeout !== 0) publicKey.timeout = createTimeout * 1000;
|
97
|
-
|
98
|
-
if (allowCredentials.length) {
|
99
|
-
publicKey.allowCredentials = allowCredentials;
|
100
|
-
}
|
101
|
-
|
102
|
-
if (userVerification !== 'not specified') publicKey.userVerification = userVerification;
|
103
|
-
|
104
|
-
navigator.credentials.get({publicKey})
|
105
|
-
.then((result) => {
|
106
|
-
window.result = result;
|
107
|
-
|
108
|
-
let clientDataJSON = result.response.clientDataJSON;
|
109
|
-
let authenticatorData = result.response.authenticatorData;
|
110
|
-
let signature = result.response.signature;
|
111
|
-
|
112
|
-
$("#clientDataJSON").val(base64url.encode(new Uint8Array(clientDataJSON), { pad: false }));
|
113
|
-
$("#authenticatorData").val(base64url.encode(new Uint8Array(authenticatorData), { pad: false }));
|
114
|
-
$("#signature").val(base64url.encode(new Uint8Array(signature), { pad: false }));
|
115
|
-
$("#credentialId").val(result.id);
|
116
|
-
if(result.response.userHandle) {
|
117
|
-
$("#userHandle").val(base64url.encode(new Uint8Array(result.response.userHandle), { pad: false }));
|
118
|
-
}
|
119
|
-
$("#webauth").submit();
|
120
|
-
})
|
121
|
-
.catch((err) => {
|
122
|
-
$("#error").val(err);
|
123
|
-
$("#webauth").submit();
|
124
|
-
})
|
125
|
-
;
|
126
|
-
}
|
127
|
-
|
128
|
-
`
|
129
|
-
}
|
130
|
-
]
|
20
|
+
useScript({
|
21
|
+
authButtonId,
|
22
|
+
kcContext,
|
23
|
+
i18n
|
131
24
|
});
|
132
25
|
|
133
|
-
useEffect(() => {
|
134
|
-
insertScriptTags();
|
135
|
-
}, []);
|
136
|
-
|
137
26
|
return (
|
138
27
|
<Template
|
139
28
|
kcContext={kcContext}
|
140
29
|
i18n={i18n}
|
141
30
|
doUseDefaultCss={doUseDefaultCss}
|
142
31
|
classes={classes}
|
143
|
-
|
144
|
-
displayInfo={realm.password && realm.registrationAllowed && !registrationDisabled}
|
32
|
+
displayInfo={realm.registrationAllowed && !registrationDisabled}
|
145
33
|
infoNode={
|
146
34
|
<div id="kc-registration">
|
147
35
|
<span>
|
@@ -179,7 +67,7 @@ export default function WebauthnAuthenticate(props: PageProps<Extract<KcContext,
|
|
179
67
|
)}
|
180
68
|
<div className={kcClsx("kcFormOptionsClass")}>
|
181
69
|
{authenticators.authenticators.map((authenticator, i) => (
|
182
|
-
<div key={i} id=
|
70
|
+
<div key={i} id={`kc-webauthn-authenticator-item-${i}`} className={kcClsx("kcSelectAuthListItemClass")}>
|
183
71
|
<div className={kcClsx("kcSelectAuthListItemIconClass")}>
|
184
72
|
<i
|
185
73
|
className={clsx(
|
@@ -195,12 +83,15 @@ export default function WebauthnAuthenticate(props: PageProps<Extract<KcContext,
|
|
195
83
|
/>
|
196
84
|
</div>
|
197
85
|
<div className={kcClsx("kcSelectAuthListItemArrowIconClass")}>
|
198
|
-
<div
|
86
|
+
<div
|
87
|
+
id={`kc-webauthn-authenticator-label-${i}`}
|
88
|
+
className={kcClsx("kcSelectAuthListItemHeadingClass")}
|
89
|
+
>
|
199
90
|
{advancedMsg(authenticator.label)}
|
200
91
|
</div>
|
201
92
|
{authenticator.transports.displayNameProperties?.length && (
|
202
93
|
<div
|
203
|
-
id=
|
94
|
+
id={`kc-webauthn-authenticator-transport-${i}`}
|
204
95
|
className={kcClsx("kcSelectAuthListItemDescriptionClass")}
|
205
96
|
>
|
206
97
|
{authenticator.transports.displayNameProperties
|
@@ -217,8 +108,10 @@ export default function WebauthnAuthenticate(props: PageProps<Extract<KcContext,
|
|
217
108
|
</div>
|
218
109
|
)}
|
219
110
|
<div className={kcClsx("kcSelectAuthListItemDescriptionClass")}>
|
220
|
-
<span id=
|
221
|
-
|
111
|
+
<span id={`kc-webauthn-authenticator-createdlabel-${i}`}>
|
112
|
+
{msg("webauthn-createdAt-label")}
|
113
|
+
</span>
|
114
|
+
<span id={`kc-webauthn-authenticator-created-${i}`}>{authenticator.createdAt}</span>
|
222
115
|
</div>
|
223
116
|
<div className={kcClsx("kcSelectAuthListItemFillClass")} />
|
224
117
|
</div>
|
@@ -229,16 +122,10 @@ export default function WebauthnAuthenticate(props: PageProps<Extract<KcContext,
|
|
229
122
|
)}
|
230
123
|
</>
|
231
124
|
)}
|
232
|
-
|
233
125
|
<div id="kc-form-buttons" className={kcClsx("kcFormButtonsClass")}>
|
234
126
|
<input
|
235
|
-
id=
|
127
|
+
id={authButtonId}
|
236
128
|
type="button"
|
237
|
-
onClick={() => {
|
238
|
-
assert("webAuthnAuthenticate" in window);
|
239
|
-
assert(typeof window.webAuthnAuthenticate === "function");
|
240
|
-
window.webAuthnAuthenticate();
|
241
|
-
}}
|
242
129
|
autoFocus
|
243
130
|
value={msgStr("webauthn-doAuthenticate")}
|
244
131
|
className={kcClsx("kcButtonClass", "kcButtonPrimaryClass", "kcButtonBlockClass", "kcButtonLargeClass")}
|
@@ -0,0 +1,64 @@
|
|
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: "true" | "false";
|
11
|
+
challenge: string;
|
12
|
+
userVerification: KcContext.WebauthnAuthenticate["userVerification"];
|
13
|
+
rpId: string;
|
14
|
+
createTimeout: number | string;
|
15
|
+
};
|
16
|
+
|
17
|
+
assert<keyof KcContextLike extends keyof KcContext.WebauthnAuthenticate ? true : false>();
|
18
|
+
assert<KcContext.WebauthnAuthenticate extends KcContextLike ? true : false>();
|
19
|
+
|
20
|
+
type I18nLike = {
|
21
|
+
msgStr: (key: "webauthn-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: "WebauthnAuthenticate",
|
34
|
+
scriptTags: [
|
35
|
+
{
|
36
|
+
type: "module",
|
37
|
+
textContent: () => `
|
38
|
+
|
39
|
+
import { authenticateByWebAuthn } from "${url.resourcesPath}/js/webauthnAuthenticate.js";
|
40
|
+
const authButton = document.getElementById('${authButtonId}');
|
41
|
+
authButton.addEventListener("click", function() {
|
42
|
+
const input = {
|
43
|
+
isUserIdentified : ${isUserIdentified},
|
44
|
+
challenge : '${challenge}',
|
45
|
+
userVerification : '${userVerification}',
|
46
|
+
rpId : '${rpId}',
|
47
|
+
createTimeout : ${createTimeout},
|
48
|
+
errmsg : ${JSON.stringify(msgStr("webauthn-unsupported-browser-text"))}
|
49
|
+
};
|
50
|
+
authenticateByWebAuthn(input);
|
51
|
+
});
|
52
|
+
`
|
53
|
+
}
|
54
|
+
]
|
55
|
+
});
|
56
|
+
|
57
|
+
useEffect(() => {
|
58
|
+
if (isFetchingTranslations) {
|
59
|
+
return;
|
60
|
+
}
|
61
|
+
|
62
|
+
insertScriptTags();
|
63
|
+
}, [isFetchingTranslations]);
|
64
|
+
}
|
@@ -1,7 +1,5 @@
|
|
1
|
-
import { useEffect } from "react";
|
2
|
-
import { assert } from "keycloakify/tools/assert";
|
3
1
|
import { getKcClsx, type KcClsx } from "keycloakify/login/lib/kcClsx";
|
4
|
-
import {
|
2
|
+
import { useScript } from "keycloakify/login/pages/WebauthnRegister.useScript";
|
5
3
|
import type { PageProps } from "keycloakify/login/pages/PageProps";
|
6
4
|
import type { KcContext } from "../KcContext";
|
7
5
|
import type { I18n } from "../i18n";
|
@@ -11,198 +9,18 @@ export default function WebauthnRegister(props: PageProps<Extract<KcContext, { p
|
|
11
9
|
|
12
10
|
const { kcClsx } = getKcClsx({ doUseDefaultCss, classes });
|
13
11
|
|
14
|
-
const {
|
15
|
-
url,
|
16
|
-
challenge,
|
17
|
-
userid,
|
18
|
-
username,
|
19
|
-
signatureAlgorithms,
|
20
|
-
rpEntityName,
|
21
|
-
rpId,
|
22
|
-
attestationConveyancePreference,
|
23
|
-
authenticatorAttachment,
|
24
|
-
requireResidentKey,
|
25
|
-
userVerificationRequirement,
|
26
|
-
createTimeout,
|
27
|
-
excludeCredentialIds,
|
28
|
-
isSetRetry,
|
29
|
-
isAppInitiatedAction
|
30
|
-
} = kcContext;
|
12
|
+
const { url, isSetRetry, isAppInitiatedAction } = kcContext;
|
31
13
|
|
32
14
|
const { msg, msgStr } = i18n;
|
33
15
|
|
34
|
-
const
|
35
|
-
componentOrHookName: "WebauthnRegister",
|
36
|
-
scriptTags: [
|
37
|
-
{
|
38
|
-
type: "text/javascript",
|
39
|
-
src: `${url.resourcesCommonPath}/node_modules/jquery/dist/jquery.min.js`
|
40
|
-
},
|
41
|
-
{
|
42
|
-
type: "text/javascript",
|
43
|
-
src: `${url.resourcesPath}/js/base64url.js`
|
44
|
-
},
|
45
|
-
{
|
46
|
-
type: "text/javascript",
|
47
|
-
textContent: `
|
48
|
-
function registerSecurityKey() {
|
16
|
+
const authButtonId = "authenticateWebAuthnButton";
|
49
17
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
return;
|
55
|
-
}
|
56
|
-
|
57
|
-
// mandatory parameters
|
58
|
-
let challenge = "${challenge}";
|
59
|
-
let userid = "${userid}";
|
60
|
-
let username = "${username}";
|
61
|
-
|
62
|
-
let signatureAlgorithms =${JSON.stringify(signatureAlgorithms)};
|
63
|
-
let pubKeyCredParams = getPubKeyCredParams(signatureAlgorithms);
|
64
|
-
|
65
|
-
let rpEntityName = "${rpEntityName}";
|
66
|
-
let rp = {name: rpEntityName};
|
67
|
-
|
68
|
-
let publicKey = {
|
69
|
-
challenge: base64url.decode(challenge, {loose: true}),
|
70
|
-
rp: rp,
|
71
|
-
user: {
|
72
|
-
id: base64url.decode(userid, {loose: true}),
|
73
|
-
name: username,
|
74
|
-
displayName: username
|
75
|
-
},
|
76
|
-
pubKeyCredParams: pubKeyCredParams,
|
77
|
-
};
|
78
|
-
|
79
|
-
// optional parameters
|
80
|
-
let rpId = "${rpId}";
|
81
|
-
publicKey.rp.id = rpId;
|
82
|
-
|
83
|
-
let attestationConveyancePreference = "${attestationConveyancePreference}";
|
84
|
-
if (attestationConveyancePreference !== 'not specified') publicKey.attestation = attestationConveyancePreference;
|
85
|
-
|
86
|
-
let authenticatorSelection = {};
|
87
|
-
let isAuthenticatorSelectionSpecified = false;
|
88
|
-
|
89
|
-
let authenticatorAttachment = "${authenticatorAttachment}";
|
90
|
-
if (authenticatorAttachment !== 'not specified') {
|
91
|
-
authenticatorSelection.authenticatorAttachment = authenticatorAttachment;
|
92
|
-
isAuthenticatorSelectionSpecified = true;
|
93
|
-
}
|
94
|
-
|
95
|
-
let requireResidentKey = "${requireResidentKey}";
|
96
|
-
if (requireResidentKey !== 'not specified') {
|
97
|
-
if (requireResidentKey === 'Yes')
|
98
|
-
authenticatorSelection.requireResidentKey = true;
|
99
|
-
else
|
100
|
-
authenticatorSelection.requireResidentKey = false;
|
101
|
-
isAuthenticatorSelectionSpecified = true;
|
102
|
-
}
|
103
|
-
|
104
|
-
let userVerificationRequirement = "${userVerificationRequirement}";
|
105
|
-
if (userVerificationRequirement !== 'not specified') {
|
106
|
-
authenticatorSelection.userVerification = userVerificationRequirement;
|
107
|
-
isAuthenticatorSelectionSpecified = true;
|
108
|
-
}
|
109
|
-
|
110
|
-
if (isAuthenticatorSelectionSpecified) publicKey.authenticatorSelection = authenticatorSelection;
|
111
|
-
|
112
|
-
let createTimeout = ${createTimeout};
|
113
|
-
if (createTimeout !== 0) publicKey.timeout = createTimeout * 1000;
|
114
|
-
|
115
|
-
let excludeCredentialIds = "${excludeCredentialIds}";
|
116
|
-
let excludeCredentials = getExcludeCredentials(excludeCredentialIds);
|
117
|
-
if (excludeCredentials.length > 0) publicKey.excludeCredentials = excludeCredentials;
|
118
|
-
|
119
|
-
navigator.credentials.create({publicKey})
|
120
|
-
.then(function (result) {
|
121
|
-
window.result = result;
|
122
|
-
let clientDataJSON = result.response.clientDataJSON;
|
123
|
-
let attestationObject = result.response.attestationObject;
|
124
|
-
let publicKeyCredentialId = result.rawId;
|
125
|
-
|
126
|
-
$("#clientDataJSON").val(base64url.encode(new Uint8Array(clientDataJSON), {pad: false}));
|
127
|
-
$("#attestationObject").val(base64url.encode(new Uint8Array(attestationObject), {pad: false}));
|
128
|
-
$("#publicKeyCredentialId").val(base64url.encode(new Uint8Array(publicKeyCredentialId), {pad: false}));
|
129
|
-
|
130
|
-
if (typeof result.response.getTransports === "function") {
|
131
|
-
let transports = result.response.getTransports();
|
132
|
-
if (transports) {
|
133
|
-
$("#transports").val(getTransportsAsString(transports));
|
134
|
-
}
|
135
|
-
} else {
|
136
|
-
console.log("Your browser is not able to recognize supported transport media for the authenticator.");
|
137
|
-
}
|
138
|
-
|
139
|
-
let initLabel = "WebAuthn Authenticator (Default Label)";
|
140
|
-
let labelResult = window.prompt("Please input your registered authenticator's label", initLabel);
|
141
|
-
if (labelResult === null) labelResult = initLabel;
|
142
|
-
$("#authenticatorLabel").val(labelResult);
|
143
|
-
|
144
|
-
$("#register").submit();
|
145
|
-
|
146
|
-
})
|
147
|
-
.catch(function (err) {
|
148
|
-
$("#error").val(err);
|
149
|
-
$("#register").submit();
|
150
|
-
|
151
|
-
});
|
152
|
-
}
|
153
|
-
|
154
|
-
function getPubKeyCredParams(signatureAlgorithmsList) {
|
155
|
-
let pubKeyCredParams = [];
|
156
|
-
if (signatureAlgorithmsList.length === 0) {
|
157
|
-
pubKeyCredParams.push({type: "public-key", alg: -7});
|
158
|
-
return pubKeyCredParams;
|
159
|
-
}
|
160
|
-
|
161
|
-
for (let i = 0; i < signatureAlgorithmsList.length; i++) {
|
162
|
-
pubKeyCredParams.push({
|
163
|
-
type: "public-key",
|
164
|
-
alg: signatureAlgorithmsList[i]
|
165
|
-
});
|
166
|
-
}
|
167
|
-
return pubKeyCredParams;
|
168
|
-
}
|
169
|
-
|
170
|
-
function getExcludeCredentials(excludeCredentialIds) {
|
171
|
-
let excludeCredentials = [];
|
172
|
-
if (excludeCredentialIds === "") return excludeCredentials;
|
173
|
-
|
174
|
-
let excludeCredentialIdsList = excludeCredentialIds.split(',');
|
175
|
-
|
176
|
-
for (let i = 0; i < excludeCredentialIdsList.length; i++) {
|
177
|
-
excludeCredentials.push({
|
178
|
-
type: "public-key",
|
179
|
-
id: base64url.decode(excludeCredentialIdsList[i],
|
180
|
-
{loose: true})
|
181
|
-
});
|
182
|
-
}
|
183
|
-
return excludeCredentials;
|
184
|
-
}
|
185
|
-
|
186
|
-
function getTransportsAsString(transportsList) {
|
187
|
-
if (transportsList === '' || Array.isArray(transportsList)) return "";
|
188
|
-
|
189
|
-
let transportsString = "";
|
190
|
-
|
191
|
-
for (let i = 0; i < transportsList.length; i++) {
|
192
|
-
transportsString += transportsList[i] + ",";
|
193
|
-
}
|
194
|
-
|
195
|
-
return transportsString.slice(0, -1);
|
196
|
-
}
|
197
|
-
`
|
198
|
-
}
|
199
|
-
]
|
18
|
+
useScript({
|
19
|
+
authButtonId,
|
20
|
+
kcContext,
|
21
|
+
i18n
|
200
22
|
});
|
201
23
|
|
202
|
-
useEffect(() => {
|
203
|
-
insertScriptTags();
|
204
|
-
}, []);
|
205
|
-
|
206
24
|
return (
|
207
25
|
<Template
|
208
26
|
kcContext={kcContext}
|
@@ -230,13 +48,8 @@ export default function WebauthnRegister(props: PageProps<Extract<KcContext, { p
|
|
230
48
|
<input
|
231
49
|
type="submit"
|
232
50
|
className={kcClsx("kcButtonClass", "kcButtonPrimaryClass", "kcButtonBlockClass", "kcButtonLargeClass")}
|
233
|
-
id=
|
51
|
+
id={authButtonId}
|
234
52
|
value={msgStr("doRegisterSecurityKey")}
|
235
|
-
onClick={() => {
|
236
|
-
assert("registerSecurityKey" in window);
|
237
|
-
assert(typeof window.registerSecurityKey === "function");
|
238
|
-
window.registerSecurityKey();
|
239
|
-
}}
|
240
53
|
/>
|
241
54
|
|
242
55
|
{!isSetRetry && isAppInitiatedAction && (
|