keycloakify 10.0.0-rc.21 → 10.0.0-rc.23
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/account/i18n/i18n.d.ts +19 -4
- package/account/i18n/i18n.js +26 -17
- package/account/i18n/i18n.js.map +1 -1
- package/account/pages/Totp.js +2 -2
- package/account/pages/Totp.js.map +1 -1
- package/bin/main.js +33 -11
- package/login/i18n/i18n.d.ts +20 -5
- package/login/i18n/i18n.js +22 -15
- package/login/i18n/i18n.js.map +1 -1
- package/login/kcContext/KcContext.d.ts +1 -2
- package/login/kcContext/KcContext.js.map +1 -1
- package/login/kcContext/createGetKcContext.js +2 -5
- package/login/kcContext/createGetKcContext.js.map +1 -1
- package/login/kcContext/kcContextMocks.js +4 -11
- package/login/kcContext/kcContextMocks.js.map +1 -1
- package/login/pages/LoginConfigTotp.js +2 -2
- package/login/pages/LoginConfigTotp.js.map +1 -1
- package/login/pages/WebauthnAuthenticate.js +2 -2
- package/login/pages/WebauthnAuthenticate.js.map +1 -1
- package/package.json +1 -1
- package/src/account/i18n/i18n.tsx +55 -26
- package/src/account/pages/Totp.tsx +2 -5
- package/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +21 -11
- package/src/bin/start-keycloak/start-keycloak.ts +18 -5
- package/src/login/i18n/i18n.tsx +49 -18
- package/src/login/kcContext/KcContext.ts +3 -5
- package/src/login/kcContext/createGetKcContext.ts +2 -9
- package/src/login/kcContext/kcContextMocks.ts +4 -16
- package/src/login/pages/LoginConfigTotp.tsx +2 -3
- package/src/login/pages/WebauthnAuthenticate.tsx +2 -3
@@ -8,8 +8,8 @@ export default function LoginConfigTotp(props) {
|
|
8
8
|
classes
|
9
9
|
});
|
10
10
|
const { url, isAppInitiatedAction, totp, mode, messagesPerField } = kcContext;
|
11
|
-
const { msg, msgStr } = i18n;
|
12
|
-
return (_jsx(Template, { kcContext, i18n, doUseDefaultCss, classes, headerNode: msg("loginTotpTitle"), children: _jsxs(_Fragment, { children: [_jsxs("ol", { id: "kc-totp-settings", children: [_jsxs("li", { children: [_jsx("p", { children: msg("loginTotpStep1") }), _jsx("ul", { id: "kc-totp-supported-apps", children: totp.supportedApplications.map(app => (_jsx("li", { children:
|
11
|
+
const { msg, msgStr, advancedMsg } = i18n;
|
12
|
+
return (_jsx(Template, { kcContext, i18n, doUseDefaultCss, classes, headerNode: msg("loginTotpTitle"), children: _jsxs(_Fragment, { children: [_jsxs("ol", { id: "kc-totp-settings", children: [_jsxs("li", { children: [_jsx("p", { children: msg("loginTotpStep1") }), _jsx("ul", { id: "kc-totp-supported-apps", children: totp.supportedApplications.map(app => (_jsx("li", { children: advancedMsg(app) }))) })] }), mode == "manual" ? (_jsxs(_Fragment, { children: [_jsxs("li", { children: [_jsx("p", { children: msg("loginTotpManualStep2") }), _jsx("p", { children: _jsx("span", { id: "kc-totp-secret-key", children: totp.totpSecretEncoded }) }), _jsx("p", { children: _jsx("a", { href: totp.qrUrl, id: "mode-barcode", children: msg("loginTotpScanBarcode") }) })] }), _jsxs("li", { children: [_jsx("p", { children: msg("loginTotpManualStep3") }), _jsx("p", { children: _jsxs("ul", { children: [_jsxs("li", { id: "kc-totp-type", children: [msg("loginTotpType"), ": ", msg(`loginTotp.${totp.policy.type}`)] }), _jsxs("li", { id: "kc-totp-algorithm", children: [msg("loginTotpAlgorithm"), ": ", totp.policy.getAlgorithmKey()] }), _jsxs("li", { id: "kc-totp-digits", children: [msg("loginTotpDigits"), ": ", totp.policy.digits] }), totp.policy.type === "totp" ? (_jsxs("li", { id: "kc-totp-period", children: [msg("loginTotpInterval"), ": ", totp.policy.period] })) : (_jsxs("li", { id: "kc-totp-counter", children: [msg("loginTotpCounter"), ": ", totp.policy.initialCounter] }))] }) })] })] })) : (_jsxs("li", { children: [_jsx("p", { children: msg("loginTotpStep2") }), _jsx("img", { id: "kc-totp-secret-qr-code", src: `data:image/png;base64, ${totp.totpSecretQrCode}`, alt: "Figure: Barcode" }), _jsx("br", {}), _jsx("p", { children: _jsx("a", { href: totp.manualUrl, id: "mode-manual", children: msg("loginTotpUnableToScan") }) })] })), _jsxs("li", { children: [_jsx("p", { children: msg("loginTotpStep3") }), _jsx("p", { children: msg("loginTotpStep3DeviceName") })] })] }), _jsxs("form", { action: url.loginAction, className: getClassName("kcFormClass"), id: "kc-totp-settings-form", method: "post", children: [_jsxs("div", { className: getClassName("kcFormGroupClass"), children: [_jsxs("div", { className: getClassName("kcInputWrapperClass"), children: [_jsx("label", { htmlFor: "totp", className: getClassName("kcLabelClass"), children: msg("authenticatorCode") }), " ", _jsx("span", { className: "required", children: "*" })] }), _jsxs("div", { className: getClassName("kcInputWrapperClass"), children: [_jsx("input", { type: "text", id: "totp", name: "totp", autoComplete: "off", className: getClassName("kcInputClass"), "aria-invalid": messagesPerField.existsError("totp") }), messagesPerField.existsError("totp") && (_jsx("span", { id: "input-error-otp-code", className: getClassName("kcInputErrorMessageClass"), "aria-live": "polite", children: messagesPerField.get("totp") }))] }), _jsx("input", { type: "hidden", id: "totpSecret", name: "totpSecret", value: totp.totpSecret }), mode && _jsx("input", { type: "hidden", id: "mode", value: mode })] }), _jsxs("div", { className: getClassName("kcFormGroupClass"), children: [_jsxs("div", { className: getClassName("kcInputWrapperClass"), children: [_jsx("label", { htmlFor: "userLabel", className: getClassName("kcLabelClass"), children: msg("loginTotpDeviceName") }), " ", totp.otpCredentials.length >= 1 && _jsx("span", { className: "required", children: "*" })] }), _jsxs("div", { className: getClassName("kcInputWrapperClass"), children: [_jsx("input", { type: "text", id: "userLabel", name: "userLabel", autoComplete: "off", className: getClassName("kcInputClass"), "aria-invalid": messagesPerField.existsError("userLabel") }), messagesPerField.existsError("userLabel") && (_jsx("span", { id: "input-error-otp-label", className: getClassName("kcInputErrorMessageClass"), "aria-live": "polite", children: messagesPerField.get("userLabel") }))] })] }), _jsx("div", { className: getClassName("kcFormGroupClass"), children: _jsx(LogoutOtherSessions, { getClassName, i18n }) }), isAppInitiatedAction ? (_jsxs(_Fragment, { children: [_jsx("input", { type: "submit", className: clsx(getClassName("kcButtonClass"), getClassName("kcButtonPrimaryClass"), getClassName("kcButtonLargeClass")), id: "saveTOTPBtn", value: msgStr("doSubmit") }), _jsx("button", { type: "submit", className: clsx(getClassName("kcButtonClass"), getClassName("kcButtonDefaultClass"), getClassName("kcButtonLargeClass"), getClassName("kcButtonLargeClass")), id: "cancelTOTPBtn", name: "cancel-aia", value: "true", children: msg("doCancel") })] })) : (_jsx("input", { type: "submit", className: clsx(getClassName("kcButtonClass"), getClassName("kcButtonPrimaryClass"), getClassName("kcButtonLargeClass")), id: "saveTOTPBtn", value: msgStr("doSubmit") }))] })] }) }));
|
13
13
|
}
|
14
14
|
function LogoutOtherSessions(props) {
|
15
15
|
const { getClassName, i18n } = props;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"LoginConfigTotp.js","sourceRoot":"","sources":["../../src/login/pages/LoginConfigTotp.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAE9C,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;
|
1
|
+
{"version":3,"file":"LoginConfigTotp.js","sourceRoot":"","sources":["../../src/login/pages/LoginConfigTotp.tsx"],"names":[],"mappings":"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"}
|
@@ -9,7 +9,7 @@ export default function WebauthnAuthenticate(props) {
|
|
9
9
|
const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
|
10
10
|
const { getClassName } = useGetClassName({ doUseDefaultCss, classes });
|
11
11
|
const { url, isUserIdentified, challenge, userVerification, rpId, createTimeout, messagesPerField, realm, registrationDisabled, authenticators, shouldDisplayAuthenticators } = kcContext;
|
12
|
-
const { msg, msgStr } = i18n;
|
12
|
+
const { msg, msgStr, advancedMsg } = i18n;
|
13
13
|
const { insertScriptTags } = useInsertScriptTags({
|
14
14
|
scriptTags: [
|
15
15
|
{
|
@@ -121,7 +121,7 @@ export default function WebauthnAuthenticate(props) {
|
|
121
121
|
return getClassName("kcWebAuthnDefaultIcon");
|
122
122
|
}
|
123
123
|
return className;
|
124
|
-
})(), getClassName("kcSelectAuthListItemIconPropertyClass")) }) }), _jsxs("div", { className: getClassName("kcSelectAuthListItemArrowIconClass"), children: [_jsx("div", { id: "kc-webauthn-authenticator-label", className: getClassName("kcSelectAuthListItemHeadingClass"), children:
|
124
|
+
})(), getClassName("kcSelectAuthListItemIconPropertyClass")) }) }), _jsxs("div", { className: getClassName("kcSelectAuthListItemArrowIconClass"), children: [_jsx("div", { id: "kc-webauthn-authenticator-label", className: getClassName("kcSelectAuthListItemHeadingClass"), children: advancedMsg(authenticator.label) }), ((_a = authenticator.transports.displayNameProperties) === null || _a === void 0 ? void 0 : _a.length) && (_jsx("div", { id: "kc-webauthn-authenticator-transport", className: getClassName("kcSelectAuthListItemDescriptionClass"), children: authenticator.transports.displayNameProperties
|
125
125
|
.map((nameProperty, i, arr) => ({
|
126
126
|
nameProperty,
|
127
127
|
hasNext: i !== arr.length - 1
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"WebauthnAuthenticate.js","sourceRoot":"","sources":["../../src/login/pages/WebauthnAuthenticate.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;
|
1
|
+
{"version":3,"file":"WebauthnAuthenticate.js","sourceRoot":"","sources":["../../src/login/pages/WebauthnAuthenticate.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
import "minimal-polyfills/Object.fromEntries";
|
2
|
-
//NOTE for later: https://github.com/remarkjs/react-markdown/blob/236182ecf30bd89c1e5a7652acaf8d0bf81e6170/src/renderers.js#L7-L35
|
3
2
|
import { useEffect, useState, useRef } from "react";
|
4
3
|
import fallbackMessages from "./baseMessages/en";
|
5
4
|
import { getMessages } from "./baseMessages";
|
6
5
|
import { assert } from "tsafe/assert";
|
7
6
|
import type { KcContext } from "../kcContext/KcContext";
|
8
|
-
import { Markdown } from "keycloakify/tools/Markdown";
|
9
7
|
|
10
8
|
export const fallbackLanguageTag = "en";
|
11
9
|
|
@@ -53,16 +51,31 @@ export type GenericI18n<MessageKey extends string> = {
|
|
53
51
|
*/
|
54
52
|
msgStr: (key: MessageKey, ...args: (string | undefined)[]) => string;
|
55
53
|
/**
|
54
|
+
* This is meant to be used when the key argument is variable, something that might have been configured by the user
|
55
|
+
* in the Keycloak admin for example.
|
56
|
+
*
|
56
57
|
* Examples assuming currentLanguageTag === "en"
|
57
|
-
*
|
58
|
+
* {
|
59
|
+
* en: {
|
60
|
+
* "access-denied": "Access denied",
|
61
|
+
* "foo": "Foo {0} {1}",
|
62
|
+
* "bar": "Bar {0}"
|
63
|
+
* }
|
64
|
+
* }
|
65
|
+
*
|
66
|
+
* advancedMsg("${access-denied} foo bar") === <span>{msgStr("access-denied")} foo bar<span> === <span>Access denied foo bar</span>
|
58
67
|
* advancedMsg("${access-denied}") === advancedMsg("access-denied") === msg("access-denied") === <span>Access denied</span>
|
59
68
|
* advancedMsg("${not-a-message-key}") === advancedMsg(not-a-message-key") === <span>not-a-message-key</span>
|
69
|
+
* advancedMsg("${bar}", "<strong>c</strong>")
|
70
|
+
* === <span>{msgStr("bar", "<strong>XXX</strong>")}<span>
|
71
|
+
* === <span>Bar <strong>XXX</strong></span> (The html in the arg is partially escaped for security reasons, it might be untrusted)
|
72
|
+
* advancedMsg("${foo} xx ${bar}", "a", "b", "c")
|
73
|
+
* === <span>{msgStr("foo", "a", "b")} xx {msgStr("bar")}<span>
|
74
|
+
* === <span>Foo a b xx Bar {0}</span> (The substitution are only applied in the first message)
|
60
75
|
*/
|
61
76
|
advancedMsg: (key: string, ...args: (string | undefined)[]) => JSX.Element;
|
62
77
|
/**
|
63
|
-
*
|
64
|
-
* advancedMsg("${access-denied} foo bar") === msg("access-denied") + " foo bar" === "Access denied foo bar"
|
65
|
-
* advancedMsg("${not-a-message-key}") === advancedMsg(not-a-message-key") === "not-a-message-key"
|
78
|
+
* See advancedMsg() but instead of returning a JSX.Element it returns a string.
|
66
79
|
*/
|
67
80
|
advancedMsgStr: (key: string, ...args: (string | undefined)[]) => string;
|
68
81
|
};
|
@@ -133,8 +146,8 @@ function createI18nTranslationFunctions<MessageKey extends string>(params: {
|
|
133
146
|
}): Pick<GenericI18n<MessageKey>, "msg" | "msgStr" | "advancedMsg" | "advancedMsgStr"> {
|
134
147
|
const { fallbackMessages, messages } = params;
|
135
148
|
|
136
|
-
function resolveMsg(props: { key: string; args: (string | undefined)[];
|
137
|
-
const { key, args,
|
149
|
+
function resolveMsg(props: { key: string; args: (string | undefined)[]; doRenderAsHtml: boolean }): string | JSX.Element | undefined {
|
150
|
+
const { key, args, doRenderAsHtml } = props;
|
138
151
|
|
139
152
|
const messageOrUndefined: string | undefined = (messages as any)[key] ?? (fallbackMessages as any)[key];
|
140
153
|
|
@@ -163,51 +176,67 @@ function createI18nTranslationFunctions<MessageKey extends string>(params: {
|
|
163
176
|
return;
|
164
177
|
}
|
165
178
|
|
166
|
-
messageWithArgsInjected = messageWithArgsInjected.replace(
|
179
|
+
messageWithArgsInjected = messageWithArgsInjected.replace(
|
180
|
+
new RegExp(`\\{${i + startIndex}\\}`, "g"),
|
181
|
+
arg.replace(/</g, "<").replace(/>/g, ">")
|
182
|
+
);
|
167
183
|
});
|
168
184
|
|
169
185
|
return messageWithArgsInjected;
|
170
186
|
})();
|
171
187
|
|
172
|
-
return
|
173
|
-
<
|
174
|
-
|
175
|
-
|
188
|
+
return doRenderAsHtml ? (
|
189
|
+
<span
|
190
|
+
// NOTE: The message is trusted. The arguments are not but are escaped.
|
191
|
+
dangerouslySetInnerHTML={{
|
192
|
+
__html: messageWithArgsInjectedIfAny
|
193
|
+
}}
|
194
|
+
/>
|
176
195
|
) : (
|
177
196
|
messageWithArgsInjectedIfAny
|
178
197
|
);
|
179
198
|
}
|
180
199
|
|
181
|
-
function resolveMsgAdvanced(props: { key: string; args: (string | undefined)[];
|
182
|
-
const { key, args,
|
200
|
+
function resolveMsgAdvanced(props: { key: string; args: (string | undefined)[]; doRenderAsHtml: boolean }): JSX.Element | string {
|
201
|
+
const { key, args, doRenderAsHtml } = props;
|
202
|
+
|
203
|
+
if (!/\$\{[^}]+\}/.test(key)) {
|
204
|
+
const resolvedMessage = resolveMsg({ key, args, doRenderAsHtml });
|
205
|
+
|
206
|
+
if (resolvedMessage === undefined) {
|
207
|
+
return doRenderAsHtml ? <span dangerouslySetInnerHTML={{ __html: key }} /> : key;
|
208
|
+
}
|
209
|
+
|
210
|
+
return resolvedMessage;
|
211
|
+
}
|
212
|
+
|
213
|
+
let isFirstMatch = true;
|
183
214
|
|
184
|
-
const
|
215
|
+
const resolvedComplexMessage = key.replace(/\$\{([^}]+)\}/g, (...[, key_i]) => {
|
216
|
+
const replaceBy = resolveMsg({ key: key_i, args: isFirstMatch ? args : [], doRenderAsHtml: false }) ?? key_i;
|
185
217
|
|
186
|
-
|
218
|
+
isFirstMatch = false;
|
187
219
|
|
188
|
-
|
189
|
-
key: keyUnwrappedFromCurlyBraces,
|
190
|
-
args,
|
191
|
-
doRenderMarkdown
|
220
|
+
return replaceBy;
|
192
221
|
});
|
193
222
|
|
194
|
-
return
|
223
|
+
return doRenderAsHtml ? <span dangerouslySetInnerHTML={{ __html: resolvedComplexMessage }} /> : resolvedComplexMessage;
|
195
224
|
}
|
196
225
|
|
197
226
|
return {
|
198
|
-
msgStr: (key, ...args) => resolveMsg({ key, args,
|
199
|
-
msg: (key, ...args) => resolveMsg({ key, args,
|
227
|
+
msgStr: (key, ...args) => resolveMsg({ key, args, doRenderAsHtml: false }) as string,
|
228
|
+
msg: (key, ...args) => resolveMsg({ key, args, doRenderAsHtml: true }) as JSX.Element,
|
200
229
|
advancedMsg: (key, ...args) =>
|
201
230
|
resolveMsgAdvanced({
|
202
231
|
key,
|
203
232
|
args,
|
204
|
-
|
233
|
+
doRenderAsHtml: true
|
205
234
|
}) as JSX.Element,
|
206
235
|
advancedMsgStr: (key, ...args) =>
|
207
236
|
resolveMsgAdvanced({
|
208
237
|
key,
|
209
238
|
args,
|
210
|
-
|
239
|
+
doRenderAsHtml: false
|
211
240
|
}) as string
|
212
241
|
};
|
213
242
|
}
|
@@ -3,7 +3,6 @@ import type { PageProps } from "keycloakify/account/pages/PageProps";
|
|
3
3
|
import { useGetClassName } from "keycloakify/account/lib/useGetClassName";
|
4
4
|
import type { KcContext } from "../kcContext";
|
5
5
|
import type { I18n } from "../i18n";
|
6
|
-
import { MessageKey } from "keycloakify/account/i18n/i18n";
|
7
6
|
|
8
7
|
export default function Totp(props: PageProps<Extract<KcContext, { pageId: "totp.ftl" }>, I18n>) {
|
9
8
|
const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
|
@@ -15,7 +14,7 @@ export default function Totp(props: PageProps<Extract<KcContext, { pageId: "totp
|
|
15
14
|
|
16
15
|
const { totp, mode, url, messagesPerField, stateChecker } = kcContext;
|
17
16
|
|
18
|
-
const { msg, msgStr } = i18n;
|
17
|
+
const { msg, msgStr, advancedMsg } = i18n;
|
19
18
|
|
20
19
|
const algToKeyUriAlg: Record<(typeof kcContext)["totp"]["policy"]["algorithm"], string> = {
|
21
20
|
HmacSHA1: "SHA1",
|
@@ -78,9 +77,7 @@ export default function Totp(props: PageProps<Extract<KcContext, { pageId: "totp
|
|
78
77
|
<li>
|
79
78
|
<p>{msg("totpStep1")}</p>
|
80
79
|
|
81
|
-
<ul id="kc-totp-supported-apps">
|
82
|
-
{totp.supportedApplications?.map(app => <li key={app}>{msg(app as MessageKey)}</li>)}
|
83
|
-
</ul>
|
80
|
+
<ul id="kc-totp-supported-apps">{totp.supportedApplications?.map(app => <li key={app}>{advancedMsg(app)}</li>)}</ul>
|
84
81
|
</li>
|
85
82
|
|
86
83
|
{mode && mode == "manual" ? (
|
@@ -193,7 +193,7 @@ function decodeHtmlEntities(htmlStr){
|
|
193
193
|
decodeHtmlEntities.element = element;
|
194
194
|
}
|
195
195
|
element.innerHTML = htmlStr;
|
196
|
-
return
|
196
|
+
return element.value;
|
197
197
|
}
|
198
198
|
|
199
199
|
})();
|
@@ -266,26 +266,36 @@ function decodeHtmlEntities(htmlStr){
|
|
266
266
|
!["name", "displayName", "displayNameHtml", "internationalizationEnabled", "registrationEmailAsUsername" ]?seq_contains(key)
|
267
267
|
) || (
|
268
268
|
"applications.ftl" == pageId &&
|
269
|
-
is_subpath(path, ["applications", "applications"]) &&
|
270
269
|
(
|
271
270
|
key == "realm" ||
|
272
271
|
key == "container"
|
273
|
-
)
|
272
|
+
) &&
|
273
|
+
is_subpath(path, ["applications", "applications"])
|
274
274
|
) || (
|
275
|
-
|
276
|
-
|
275
|
+
key == "delegateForUpdate" &&
|
276
|
+
are_same_path(path, ["user"])
|
277
277
|
) || (
|
278
278
|
<#-- Security audit forwarded by Garth (Gmail) -->
|
279
|
-
|
280
|
-
|
279
|
+
key == "saml.signing.private.key" &&
|
280
|
+
are_same_path(path, ["client", "attributes"])
|
281
281
|
) || (
|
282
282
|
<#-- See: https://github.com/keycloakify/keycloakify/issues/534 -->
|
283
|
-
|
284
|
-
|
283
|
+
key == "password" &&
|
284
|
+
are_same_path(path, ["login"])
|
285
285
|
) || (
|
286
286
|
<#-- Remove realmAttributes added by https://github.com/jcputney/keycloak-theme-additional-info-extension for peace of mind. -->
|
287
|
-
|
288
|
-
|
287
|
+
key == "realmAttributes" &&
|
288
|
+
are_same_path(path, [])
|
289
|
+
) || (
|
290
|
+
<#-- attributesByName adds a lot of noise to the output and is not needed -->
|
291
|
+
key == "attributesByName" &&
|
292
|
+
(
|
293
|
+
are_same_path(path, ["profile"]) ||
|
294
|
+
are_same_path(path, ["register"])
|
295
|
+
)
|
296
|
+
) || (
|
297
|
+
key == "attributes" &&
|
298
|
+
are_same_path(path, ["register"])
|
289
299
|
)
|
290
300
|
>
|
291
301
|
<#local out_seq += ["/*" + path?join(".") + "." + key + " excluded*/"]>
|
@@ -417,7 +417,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
|
417
417
|
`- password: ${chalk.cyan.bold("password123")}`,
|
418
418
|
"",
|
419
419
|
`Watching for changes in ${chalk.bold(
|
420
|
-
`.${pathSep}${pathRelative(process.cwd(),
|
420
|
+
`.${pathSep}${pathRelative(process.cwd(), buildOptions.reactAppRootDirPath)}`
|
421
421
|
)}`
|
422
422
|
].join("\n")
|
423
423
|
);
|
@@ -455,10 +455,23 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
|
455
455
|
const { waitForDebounce } = waitForDebounceFactory({ delay: 400 });
|
456
456
|
|
457
457
|
chokidar
|
458
|
-
.watch(
|
459
|
-
|
460
|
-
|
461
|
-
|
458
|
+
.watch(
|
459
|
+
[
|
460
|
+
srcDirPath,
|
461
|
+
buildOptions.publicDirPath,
|
462
|
+
pathJoin(buildOptions.reactAppRootDirPath, "package.json"),
|
463
|
+
pathJoin(buildOptions.reactAppRootDirPath, "vite.config.ts"),
|
464
|
+
pathJoin(buildOptions.reactAppRootDirPath, "vite.config.js"),
|
465
|
+
pathJoin(buildOptions.reactAppRootDirPath, "index.html"),
|
466
|
+
pathJoin(getThisCodebaseRootDirPath(), "src")
|
467
|
+
],
|
468
|
+
{
|
469
|
+
ignoreInitial: true
|
470
|
+
}
|
471
|
+
)
|
472
|
+
.on("all", async (...[, filePath]) => {
|
473
|
+
console.log(`Detected changes in ${filePath}`);
|
474
|
+
|
462
475
|
await waitForDebounce();
|
463
476
|
|
464
477
|
runFullBuild();
|
package/src/login/i18n/i18n.tsx
CHANGED
@@ -12,7 +12,7 @@ export type KcContextLike = {
|
|
12
12
|
currentLanguageTag: string;
|
13
13
|
supported: { languageTag: string; url: string; label: string }[];
|
14
14
|
};
|
15
|
-
__localizationRealmOverridesUserProfile
|
15
|
+
__localizationRealmOverridesUserProfile?: Record<string, string>;
|
16
16
|
};
|
17
17
|
|
18
18
|
assert<KcContext extends KcContextLike ? true : false>();
|
@@ -52,16 +52,31 @@ export type GenericI18n<MessageKey extends string> = {
|
|
52
52
|
*/
|
53
53
|
msgStr: (key: MessageKey, ...args: (string | undefined)[]) => string;
|
54
54
|
/**
|
55
|
+
* This is meant to be used when the key argument is variable, something that might have been configured by the user
|
56
|
+
* in the Keycloak admin for example.
|
57
|
+
*
|
55
58
|
* Examples assuming currentLanguageTag === "en"
|
56
|
-
*
|
59
|
+
* {
|
60
|
+
* en: {
|
61
|
+
* "access-denied": "Access denied",
|
62
|
+
* "foo": "Foo {0} {1}",
|
63
|
+
* "bar": "Bar {0}"
|
64
|
+
* }
|
65
|
+
* }
|
66
|
+
*
|
67
|
+
* advancedMsg("${access-denied} foo bar") === <span>{msgStr("access-denied")} foo bar<span> === <span>Access denied foo bar</span>
|
57
68
|
* advancedMsg("${access-denied}") === advancedMsg("access-denied") === msg("access-denied") === <span>Access denied</span>
|
58
69
|
* advancedMsg("${not-a-message-key}") === advancedMsg(not-a-message-key") === <span>not-a-message-key</span>
|
70
|
+
* advancedMsg("${bar}", "<strong>c</strong>")
|
71
|
+
* === <span>{msgStr("bar", "<strong>XXX</strong>")}<span>
|
72
|
+
* === <span>Bar <strong>XXX</strong></span> (The html in the arg is partially escaped for security reasons, it might be untrusted)
|
73
|
+
* advancedMsg("${foo} xx ${bar}", "a", "b", "c")
|
74
|
+
* === <span>{msgStr("foo", "a", "b")} xx {msgStr("bar")}<span>
|
75
|
+
* === <span>Foo a b xx Bar {0}</span> (The substitution are only applied in the first message)
|
59
76
|
*/
|
60
77
|
advancedMsg: (key: string, ...args: (string | undefined)[]) => JSX.Element;
|
61
78
|
/**
|
62
|
-
*
|
63
|
-
* advancedMsg("${access-denied} foo bar") === msg("access-denied") + " foo bar" === "Access denied foo bar"
|
64
|
-
* advancedMsg("${not-a-message-key}") === advancedMsg("not-a-message-key") === "not-a-message-key"
|
79
|
+
* See advancedMsg() but instead of returning a JSX.Element it returns a string.
|
65
80
|
*/
|
66
81
|
advancedMsgStr: (key: string, ...args: (string | undefined)[]) => string;
|
67
82
|
};
|
@@ -130,9 +145,9 @@ export function createUseI18n<ExtraMessageKey extends string = never>(extraMessa
|
|
130
145
|
function createI18nTranslationFunctions<MessageKey extends string>(params: {
|
131
146
|
fallbackMessages: Record<MessageKey, string>;
|
132
147
|
messages: Record<MessageKey, string>;
|
133
|
-
__localizationRealmOverridesUserProfile: Record<string, string
|
148
|
+
__localizationRealmOverridesUserProfile: Record<string, string> | undefined;
|
134
149
|
}): Pick<GenericI18n<MessageKey>, "msg" | "msgStr" | "advancedMsg" | "advancedMsgStr"> {
|
135
|
-
const { fallbackMessages, messages
|
150
|
+
const { fallbackMessages, messages, __localizationRealmOverridesUserProfile } = params;
|
136
151
|
|
137
152
|
function resolveMsg(props: { key: string; args: (string | undefined)[]; doRenderAsHtml: boolean }): string | JSX.Element | undefined {
|
138
153
|
const { key, args, doRenderAsHtml } = props;
|
@@ -188,26 +203,42 @@ function createI18nTranslationFunctions<MessageKey extends string>(params: {
|
|
188
203
|
function resolveMsgAdvanced(props: { key: string; args: (string | undefined)[]; doRenderAsHtml: boolean }): JSX.Element | string {
|
189
204
|
const { key, args, doRenderAsHtml } = props;
|
190
205
|
|
191
|
-
|
192
|
-
|
193
|
-
|
206
|
+
if (__localizationRealmOverridesUserProfile !== undefined && key in __localizationRealmOverridesUserProfile) {
|
207
|
+
const resolvedMessage = __localizationRealmOverridesUserProfile[key];
|
208
|
+
|
209
|
+
return doRenderAsHtml ? (
|
210
|
+
<span
|
211
|
+
// NOTE: The message is trusted. The arguments are not but are escaped.
|
212
|
+
dangerouslySetInnerHTML={{
|
213
|
+
__html: resolvedMessage
|
214
|
+
}}
|
215
|
+
/>
|
216
|
+
) : (
|
217
|
+
resolvedMessage
|
218
|
+
);
|
219
|
+
}
|
194
220
|
|
221
|
+
if (!/\$\{[^}]+\}/.test(key)) {
|
222
|
+
const resolvedMessage = resolveMsg({ key, args, doRenderAsHtml });
|
195
223
|
|
224
|
+
if (resolvedMessage === undefined) {
|
225
|
+
return doRenderAsHtml ? <span dangerouslySetInnerHTML={{ __html: key }} /> : key;
|
226
|
+
}
|
196
227
|
|
228
|
+
return resolvedMessage;
|
197
229
|
}
|
198
|
-
*/
|
199
230
|
|
200
|
-
|
231
|
+
let isFirstMatch = true;
|
232
|
+
|
233
|
+
const resolvedComplexMessage = key.replace(/\$\{([^}]+)\}/g, (...[, key_i]) => {
|
234
|
+
const replaceBy = resolveMsg({ key: key_i, args: isFirstMatch ? args : [], doRenderAsHtml: false }) ?? key_i;
|
201
235
|
|
202
|
-
|
236
|
+
isFirstMatch = false;
|
203
237
|
|
204
|
-
|
205
|
-
key: keyUnwrappedFromCurlyBraces,
|
206
|
-
args,
|
207
|
-
doRenderAsHtml
|
238
|
+
return replaceBy;
|
208
239
|
});
|
209
240
|
|
210
|
-
return
|
241
|
+
return doRenderAsHtml ? <span dangerouslySetInnerHTML={{ __html: resolvedComplexMessage }} /> : resolvedComplexMessage;
|
211
242
|
}
|
212
243
|
|
213
244
|
return {
|
@@ -144,7 +144,7 @@ export declare namespace KcContext {
|
|
144
144
|
tabId: string;
|
145
145
|
ssoLoginInOtherTabsUrl: string;
|
146
146
|
};
|
147
|
-
__localizationRealmOverridesUserProfile
|
147
|
+
__localizationRealmOverridesUserProfile?: Record<string, string>;
|
148
148
|
};
|
149
149
|
|
150
150
|
export type SamlPostForm = Common & {
|
@@ -586,7 +586,6 @@ export declare namespace KcContext {
|
|
586
586
|
|
587
587
|
export type UserProfile = {
|
588
588
|
attributes: Attribute[];
|
589
|
-
attributesByName: Record<string, Attribute>;
|
590
589
|
html5DataAnnotations?: Record<string, string>;
|
591
590
|
};
|
592
591
|
|
@@ -757,9 +756,8 @@ export type PasswordPolicies = {
|
|
757
756
|
};
|
758
757
|
|
759
758
|
assert<
|
760
|
-
KcContext.Common extends
|
761
|
-
typeof nameOfTheLocalizationRealmOverridesUserProfileProperty,
|
762
|
-
unknown
|
759
|
+
KcContext.Common extends Partial<
|
760
|
+
Record<typeof nameOfTheLocalizationRealmOverridesUserProfileProperty, unknown>
|
763
761
|
>
|
764
762
|
? true
|
765
763
|
: false
|
@@ -39,9 +39,9 @@ export function createGetKcContext<
|
|
39
39
|
if (mockPageId !== undefined && realKcContext === undefined) {
|
40
40
|
//TODO maybe trow if no mock fo custom page
|
41
41
|
|
42
|
-
|
42
|
+
warn_that_mock_is_enabled: {
|
43
43
|
if (isStorybook) {
|
44
|
-
break
|
44
|
+
break warn_that_mock_is_enabled;
|
45
45
|
}
|
46
46
|
|
47
47
|
console.log(
|
@@ -118,7 +118,6 @@ export function createGetKcContext<
|
|
118
118
|
const { attributes } = kcContextDefaultMock.profile;
|
119
119
|
|
120
120
|
id<KcContext.Register>(kcContext).profile.attributes = [];
|
121
|
-
id<KcContext.Register>(kcContext).profile.attributesByName = {};
|
122
121
|
|
123
122
|
const partialAttributes = [
|
124
123
|
...((
|
@@ -153,9 +152,6 @@ export function createGetKcContext<
|
|
153
152
|
id<KcContext.Register>(kcContext).profile.attributes.push(
|
154
153
|
augmentedAttribute
|
155
154
|
);
|
156
|
-
id<KcContext.Register>(kcContext).profile.attributesByName[
|
157
|
-
augmentedAttribute.name
|
158
|
-
] = augmentedAttribute;
|
159
155
|
});
|
160
156
|
|
161
157
|
partialAttributes
|
@@ -174,9 +170,6 @@ export function createGetKcContext<
|
|
174
170
|
id<KcContext.Register>(kcContext).profile.attributes.push(
|
175
171
|
partialAttribute as any
|
176
172
|
);
|
177
|
-
id<KcContext.Register>(kcContext).profile.attributesByName[
|
178
|
-
name
|
179
|
-
] = partialAttribute as any;
|
180
173
|
});
|
181
174
|
}
|
182
175
|
}
|
@@ -75,10 +75,6 @@ const attributes: Attribute[] = [
|
|
75
75
|
}
|
76
76
|
];
|
77
77
|
|
78
|
-
const attributesByName = Object.fromEntries(
|
79
|
-
attributes.map(attribute => [attribute.name, attribute])
|
80
|
-
) as any;
|
81
|
-
|
82
78
|
const resourcesPath = `${BASE_URL}${keycloak_resources}/login/resources`;
|
83
79
|
|
84
80
|
export const kcContextCommonMock: KcContext.Common = {
|
@@ -269,8 +265,7 @@ export const kcContextMocks = [
|
|
269
265
|
recaptchaRequired: false,
|
270
266
|
pageId: "register.ftl",
|
271
267
|
profile: {
|
272
|
-
attributes
|
273
|
-
attributesByName
|
268
|
+
attributes
|
274
269
|
},
|
275
270
|
scripts: [
|
276
271
|
//"https://www.google.com/recaptcha/api.js"
|
@@ -421,8 +416,7 @@ export const kcContextMocks = [
|
|
421
416
|
...kcContextCommonMock,
|
422
417
|
pageId: "login-update-profile.ftl",
|
423
418
|
profile: {
|
424
|
-
attributes
|
425
|
-
attributesByName
|
419
|
+
attributes
|
426
420
|
}
|
427
421
|
}),
|
428
422
|
id<KcContext.LoginIdpLinkConfirm>({
|
@@ -478,20 +472,14 @@ export const kcContextMocks = [
|
|
478
472
|
...kcContextCommonMock,
|
479
473
|
pageId: "idp-review-user-profile.ftl",
|
480
474
|
profile: {
|
481
|
-
attributes
|
482
|
-
attributesByName
|
475
|
+
attributes
|
483
476
|
}
|
484
477
|
}),
|
485
478
|
id<KcContext.UpdateEmail>({
|
486
479
|
...kcContextCommonMock,
|
487
480
|
pageId: "update-email.ftl",
|
488
481
|
profile: {
|
489
|
-
attributes: attributes.filter(attribute => attribute.name === "email")
|
490
|
-
attributesByName: Object.fromEntries(
|
491
|
-
attributes
|
492
|
-
.filter(attribute => attribute.name === "email")
|
493
|
-
.map(attribute => [attribute.name, attribute])
|
494
|
-
)
|
482
|
+
attributes: attributes.filter(attribute => attribute.name === "email")
|
495
483
|
}
|
496
484
|
}),
|
497
485
|
id<KcContext.SelectAuthenticator>({
|