From 8d1c19bf1cd8a1d84ebb3ce53127bd4b3c8d1bb9 Mon Sep 17 00:00:00 2001 From: Joseph Garrone Date: Sat, 13 Apr 2024 01:26:41 +0200 Subject: [PATCH] Update prepare template for Keycloak 24 --- src/account/Template.tsx | 14 +++++---- src/lib/usePrepareTemplate.ts | 32 +++++++++++-------- src/login/Template.tsx | 44 ++++++++++++++++++++++----- src/login/kcContext/KcContext.ts | 6 ++++ src/login/kcContext/kcContextMocks.ts | 3 +- src/tools/headInsert.ts | 26 ++++++++++++---- 6 files changed, 92 insertions(+), 33 deletions(-) diff --git a/src/account/Template.tsx b/src/account/Template.tsx index 1c81f6ba..dab8aa99 100644 --- a/src/account/Template.tsx +++ b/src/account/Template.tsx @@ -16,12 +16,14 @@ export default function Template(props: TemplateProps) { const { locale, url, features, realm, message, referrer } = kcContext; const { isReady } = usePrepareTemplate({ - "doFetchDefaultThemeResources": doUseDefaultCss, - "styles": [ - `${url.resourcesCommonPath}/node_modules/patternfly/dist/css/patternfly.min.css`, - `${url.resourcesCommonPath}/node_modules/patternfly/dist/css/patternfly-additions.min.css`, - `${url.resourcesPath}/css/account.css` - ], + "styles": !doUseDefaultCss + ? [] + : [ + `${url.resourcesCommonPath}/node_modules/patternfly/dist/css/patternfly.min.css`, + `${url.resourcesCommonPath}/node_modules/patternfly/dist/css/patternfly-additions.min.css`, + `${url.resourcesPath}/css/account.css` + ], + "scripts": [], "htmlClassName": getClassName("kcHtmlClass"), "bodyClassName": clsx("admin-console", "user", getClassName("kcBodyClass")), "htmlLangProperty": locale?.currentLanguageTag, diff --git a/src/lib/usePrepareTemplate.ts b/src/lib/usePrepareTemplate.ts index 98f0bbd6..bca15c35 100644 --- a/src/lib/usePrepareTemplate.ts +++ b/src/lib/usePrepareTemplate.ts @@ -4,17 +4,27 @@ import { clsx } from "keycloakify/tools/clsx"; import { assert } from "tsafe/assert"; export function usePrepareTemplate(params: { - doFetchDefaultThemeResources: boolean; - styles?: string[]; - scripts?: string[]; + styles: string[]; + scripts: { + isModule: boolean; + source: + | { + type: "url"; + src: string; + } + | { + type: "inline"; + code: string; + }; + }[]; htmlClassName: string | undefined; bodyClassName: string | undefined; - htmlLangProperty?: string | undefined; - documentTitle?: string; + htmlLangProperty: string | undefined; + documentTitle: string | undefined; }) { - const { doFetchDefaultThemeResources, styles = [], scripts = [], htmlClassName, bodyClassName, htmlLangProperty, documentTitle } = params; + const { styles, scripts, htmlClassName, bodyClassName, htmlLangProperty, documentTitle } = params; - const [isReady, setReady] = useReducer(() => true, !doFetchDefaultThemeResources); + const [isReady, setReady] = useReducer(() => true, styles.length === 0 && scripts.length === 0); useEffect(() => { if (htmlLangProperty === undefined) { @@ -35,10 +45,6 @@ export function usePrepareTemplate(params: { }, [documentTitle]); useEffect(() => { - if (!doFetchDefaultThemeResources) { - return; - } - let isUnmounted = false; const removeArray: (() => void)[] = []; @@ -64,10 +70,10 @@ export function usePrepareTemplate(params: { setReady(); })(); - scripts.forEach(src => { + scripts.forEach(script => { const { remove } = headInsert({ "type": "javascript", - src + ...script }); removeArray.push(remove); diff --git a/src/login/Template.tsx b/src/login/Template.tsx index 4d6646bb..c983afb6 100644 --- a/src/login/Template.tsx +++ b/src/login/Template.tsx @@ -27,15 +27,45 @@ export default function Template(props: TemplateProps) { const { msg, changeLocale, labelBySupportedLanguageTag, currentLanguageTag } = i18n; - const { realm, locale, auth, url, message, isAppInitiatedAction } = kcContext; + const { realm, locale, auth, url, message, isAppInitiatedAction, authenticationSession } = kcContext; const { isReady } = usePrepareTemplate({ - "doFetchDefaultThemeResources": doUseDefaultCss, - "styles": [ - `${url.resourcesCommonPath}/node_modules/patternfly/dist/css/patternfly.min.css`, - `${url.resourcesCommonPath}/node_modules/patternfly/dist/css/patternfly-additions.min.css`, - `${url.resourcesCommonPath}/lib/zocial/zocial.css`, - `${url.resourcesPath}/css/login.css` + "styles": !doUseDefaultCss + ? [] + : [ + `${url.resourcesCommonPath}/node_modules/@patternfly/patternfly/patternfly.min.css`, + `${url.resourcesCommonPath}/node_modules/patternfly/dist/css/patternfly.min.css`, + `${url.resourcesCommonPath}/node_modules/patternfly/dist/css/patternfly-additions.min.css`, + `${url.resourcesCommonPath}/lib/pficon/pficon.css`, + `${url.resourcesPath}/css/login.css` + ], + "scripts": [ + { + "isModule": true, + "source": { + "type": "url", + "src": `${url.resourcesPath}/js/menu-button-links.js` + } + }, + ...(authenticationSession === undefined + ? [] + : [ + { + "isModule": true, + "source": { + "type": "inline" as const, + "code": [ + `import { checkCookiesAndSetTimer } from "${url.resourcesPath}/js/authChecker.js";`, + ``, + `checkCookiesAndSetTimer(`, + ` "${authenticationSession.authSessionId}",`, + ` "${authenticationSession.tabId}",`, + ` "${url.ssoLoginInOtherTabsUrl}"`, + `);` + ].join("\n") + } + } + ]) ], "htmlClassName": getClassName("kcHtmlClass"), "bodyClassName": getClassName("kcBodyClass"), diff --git a/src/login/kcContext/KcContext.ts b/src/login/kcContext/KcContext.ts index e1ae9190..65e63c55 100644 --- a/src/login/kcContext/KcContext.ts +++ b/src/login/kcContext/KcContext.ts @@ -50,6 +50,7 @@ export declare namespace KcContext { resourcesCommonPath: string; loginRestartFlowUrl: string; loginUrl: string; + ssoLoginInOtherTabsUrl: string; }; realm: { name: string; @@ -117,6 +118,11 @@ export declare namespace KcContext { exists: (fieldName: string) => boolean; }; properties: Record; + authenticationSession?: { + authSessionId: string; + tabId: string; + ssoLoginInOtherTabsUrl: string; + }; }; export type SamlPostForm = Common & { diff --git a/src/login/kcContext/kcContextMocks.ts b/src/login/kcContext/kcContextMocks.ts index c5262ed7..ca09bb3a 100644 --- a/src/login/kcContext/kcContextMocks.ts +++ b/src/login/kcContext/kcContextMocks.ts @@ -112,7 +112,8 @@ export const kcContextCommonMock: KcContext.Common = { resourcesPath, "resourcesCommonPath": `${resourcesPath}/${resources_common}`, "loginRestartFlowUrl": "/auth/realms/myrealm/login-actions/restart?client_id=account&tab_id=HoAx28ja4xg", - "loginUrl": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg" + "loginUrl": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg", + "ssoLoginInOtherTabsUrl": "/auth/realms/myrealm/login-actions/switch?client_id=account&tab_id=HoAx28ja4xg" }, "realm": { "name": "myrealm", diff --git a/src/tools/headInsert.ts b/src/tools/headInsert.ts index 0a123772..e103904c 100644 --- a/src/tools/headInsert.ts +++ b/src/tools/headInsert.ts @@ -10,7 +10,16 @@ export function headInsert( } | { type: "javascript"; - src: string; + isModule: boolean; + source: + | { + type: "url"; + src: string; + } + | { + type: "inline"; + code: string; + }; } ): { remove: () => void; prLoaded: Promise } { const htmlElement = document.createElement( @@ -35,14 +44,19 @@ export function headInsert( case "css": return { "href": params.href, - "type": "text/css", - "rel": "stylesheet", - "media": "screen,print" + "rel": "stylesheet" }; case "javascript": return { - "src": params.src, - "type": "text/javascript" + ...(() => { + switch (params.source.type) { + case "inline": + return { "textContent": params.source.code }; + case "url": + return { "src": params.source.src }; + } + })(), + "type": params.isModule ? "module" : "text/javascript" }; } })()