Compare commits

..

14 Commits
v10.1.1 ... v10

Author SHA1 Message Date
dee3f6a132 Fix CI 2024-10-05 06:28:04 +02:00
324eec0cdd Fix tag name 2024-10-05 06:26:35 +02:00
3d8bd5e292 Bump version 2024-10-05 06:06:45 +02:00
c473a5e80a Keycloak v26 support for Keycloakify 10 2024-10-05 06:06:30 +02:00
645503119b Bump version 2024-09-30 11:47:15 +02:00
804ef8cec6 Fix allegated vulnerability 2024-09-30 11:46:56 +02:00
85954be93d Prevent publishing on storybook 2024-09-23 04:35:00 +02:00
9a03f37fe3 Make it possible to publish backward compat paches 2024-09-23 04:29:24 +02:00
fb6f450bfe Bump version 2024-09-16 14:30:50 +02:00
9a97d86ff9 #638 #631 Follow up 2024-09-16 14:30:27 +02:00
a5e3ecb38b Bump version 2024-09-16 13:50:08 +02:00
9b22d94600 Remove previous .keycloakify dir 2024-09-16 13:49:54 +02:00
a42ddb959b Bump version 2024-09-16 13:38:05 +02:00
b4e94d3c00 Use keycloakify-dev-resources instead of .keycloakify 2024-09-16 13:37:29 +02:00
17 changed files with 103 additions and 110 deletions

View File

@ -3,6 +3,7 @@ on:
push:
branches:
- main
- v10
pull_request:
branches:
- main
@ -35,21 +36,21 @@ jobs:
- run: npm run build
- run: npm run test
storybook:
runs-on: ubuntu-latest
if: github.event_name == 'push'
needs: test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '18'
- uses: bahmutov/npm-install@v1
- run: npm run build-storybook
- run: git remote set-url origin https://git:${GITHUB_TOKEN}@github.com/${{github.repository}}.git
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: npx -y -p gh-pages@3.1.0 gh-pages -d ./storybook-static -u "github-actions-bot <actions@github.com>"
#storybook:
# runs-on: ubuntu-latest
# if: github.event_name == 'push'
# needs: test
# steps:
# - uses: actions/checkout@v4
# - uses: actions/setup-node@v4
# with:
# node-version: '18'
# - uses: bahmutov/npm-install@v1
# - run: npm run build-storybook
# - run: git remote set-url origin https://git:${GITHUB_TOKEN}@github.com/${{github.repository}}.git
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# - run: npx -y -p gh-pages@3.1.0 gh-pages -d ./storybook-static -u "github-actions-bot <actions@github.com>"
check_if_version_upgraded:
name: Check if version upgrade
@ -95,6 +96,7 @@ jobs:
generate_release_notes: true
draft: false
prerelease: ${{ needs.check_if_version_upgraded.outputs.is_pre_release == 'true' }}
make_latest: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -128,10 +130,7 @@ jobs:
echo "Can't publish on NPM, You must first create a secret called NPM_TOKEN that contains your NPM auth token. https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets"
false
fi
EXTRA_ARGS=""
if [ "$IS_PRE_RELEASE" = "true" ]; then
EXTRA_ARGS="--tag next"
fi
EXTRA_ARGS="--tag keycloakify_v10"
npm publish $EXTRA_ARGS
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}

View File

@ -1,6 +1,6 @@
{
"name": "keycloakify",
"version": "10.1.1",
"version": "10.1.6",
"description": "Create Keycloak themes using React",
"repository": {
"type": "git",

View File

@ -1,59 +1,8 @@
import * as child_process from "child_process";
import { transformCodebase } from "../src/bin/tools/transformCodebase";
import { join as pathJoin, sep as pathSep } from "path";
import { assert } from "tsafe/assert";
run("yarn build");
run("npx build-storybook");
const storybookStaticDirPath = "storybook-static";
{
let hasPatched = false;
transformCodebase({
srcDirPath: storybookStaticDirPath,
destDirPath: storybookStaticDirPath,
transformSourceCode: ({ fileRelativePath, sourceCode }) => {
replace_dot_keycloakify: {
if (fileRelativePath.includes(pathSep)) {
break replace_dot_keycloakify;
}
if (!fileRelativePath.endsWith(".js")) {
break replace_dot_keycloakify;
}
const search = `DOT_KEYCLOAKIFY:".keycloakify"`;
if (!sourceCode.includes(search)) {
break replace_dot_keycloakify;
}
hasPatched = true;
return {
modifiedSourceCode: Buffer.from(
sourceCode
.toString("utf8")
.replace(search, `DOT_KEYCLOAKIFY:"dot_keycloakify"`),
"utf8"
)
};
}
return { modifiedSourceCode: sourceCode };
}
});
assert(hasPatched);
}
transformCodebase({
srcDirPath: pathJoin(storybookStaticDirPath, ".keycloakify"),
destDirPath: pathJoin(storybookStaticDirPath, "dot_keycloakify")
});
function run(command: string, options?: { env?: NodeJS.ProcessEnv }) {
console.log(`$ ${command}`);

View File

@ -7,7 +7,7 @@ import { WELL_KNOWN_DIRECTORY_BASE_NAME } from "../../src/bin/shared/constants";
import { assert, type Equals } from "tsafe/assert";
import * as fsPr from "fs/promises";
export async function createPublicDotKeycloakifyDir() {
export async function createPublicKeycloakifyDevResourcesDir() {
await Promise.all(
(["login", "account"] as const).map(async themeType => {
const { extractedDirPath } = await downloadKeycloakDefaultTheme({
@ -27,7 +27,7 @@ export async function createPublicDotKeycloakifyDir() {
"dist",
"res",
"public",
WELL_KNOWN_DIRECTORY_BASE_NAME.DOT_KEYCLOAKIFY,
WELL_KNOWN_DIRECTORY_BASE_NAME.KEYCLOAKIFY_DEV_RESOURCES,
themeType
);

View File

@ -3,7 +3,7 @@ import * as fs from "fs";
import { join } from "path";
import { assert } from "tsafe/assert";
import { transformCodebase } from "../../src/bin/tools/transformCodebase";
import { createPublicDotKeycloakifyDir } from "./createPublicDotKeycloakifyDir";
import { createPublicKeycloakifyDevResourcesDir } from "./createPublicKeycloakifyDevResourcesDir";
import { createAccountV1Dir } from "./createAccountV1Dir";
import chalk from "chalk";
@ -144,7 +144,7 @@ import chalk from "chalk";
fs.cpSync(dirBasename, destDirPath, { recursive: true });
}
await createPublicDotKeycloakifyDir();
await createPublicKeycloakifyDevResourcesDir();
await createAccountV1Dir();
transformCodebase({

View File

@ -4,7 +4,7 @@ import { id } from "tsafe/id";
import type { KcContext } from "./KcContext";
import { BASE_URL } from "keycloakify/lib/BASE_URL";
const resourcesPath = `${BASE_URL}${WELL_KNOWN_DIRECTORY_BASE_NAME.DOT_KEYCLOAKIFY}/account`;
const resourcesPath = `${BASE_URL}${WELL_KNOWN_DIRECTORY_BASE_NAME.KEYCLOAKIFY_DEV_RESOURCES}/account`;
export const kcContextCommonMock: KcContext.Common = {
themeVersion: "0.0.0",

View File

@ -52,9 +52,9 @@ export function getKeycloakVersionRangeForJar(params: {
case "0.6":
switch (keycloakThemeAdditionalInfoExtensionVersion) {
case null:
return undefined;
return "26-and-above" as const;
case "1.1.5":
return "25-and-above" as const;
return "25" as const;
}
}
assert<Equals<typeof keycloakAccountV1Version, never>>(false);
@ -75,9 +75,9 @@ export function getKeycloakVersionRangeForJar(params: {
}
switch (keycloakThemeAdditionalInfoExtensionVersion) {
case null:
return "21-and-below";
return "all-other-versions";
case "1.1.5":
return "22-and-above";
return "22-to-25";
}
assert<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(
false

View File

@ -85,6 +85,19 @@ attributes_to_attributesByName: {
});
}
window.kcContext = kcContext;
<#if xKeycloakify.themeType == "login" >
const script = document.createElement("script");
script.type = "importmap";
script.textContent = JSON.stringify({
imports: {
"rfc4648": kcContext.url.resourcesCommonPath + "/node_modules/rfc4648/lib/rfc4648.js"
}
}, null, 2);
document.head.appendChild(script);
</#if>
function decodeHtmlEntities(htmlStr){
var element = decodeHtmlEntities.element;
if (!element) {
@ -153,6 +166,9 @@ function decodeHtmlEntities(htmlStr){
) || (
["masterAdminClient", "delegateForUpdate", "defaultRole"]?seq_contains(key) &&
areSamePath(path, ["realm"])
) || (
"smtpConfig" == key &&
are_same_path(path, ["realm"])
) || (
xKeycloakify.pageId == "error.ftl" &&
areSamePath(path, ["realm"]) &&
@ -220,6 +236,9 @@ function decodeHtmlEntities(htmlStr){
"identityFederationEnabled",
"userManagedAccessAllowed"
]?seq_contains(key)
) || (
["flowContext", "session", "realm"]?seq_contains(key) &&
areSamePath(path, ["social"])
)
>
<#-- <#local outSeq += ["/*" + path?join(".") + "." + key + " excluded*/"]> -->

View File

@ -99,7 +99,7 @@ export async function generateResourcesForMainTheme(params: {
{
const dirPath = pathJoin(
buildContext.projectBuildDirPath,
WELL_KNOWN_DIRECTORY_BASE_NAME.DOT_KEYCLOAKIFY
WELL_KNOWN_DIRECTORY_BASE_NAME.KEYCLOAKIFY_DEV_RESOURCES
);
if (fs.existsSync(dirPath)) {
@ -107,7 +107,7 @@ export async function generateResourcesForMainTheme(params: {
throw new Error(
[
`Keycloakify build error: The ${WELL_KNOWN_DIRECTORY_BASE_NAME.DOT_KEYCLOAKIFY} directory shouldn't exist in your build directory.`,
`Keycloakify build error: The ${WELL_KNOWN_DIRECTORY_BASE_NAME.KEYCLOAKIFY_DEV_RESOURCES} directory shouldn't exist in your build directory.`,
`(${pathRelative(process.cwd(), dirPath)}).\n`,
`Theses assets are only required for local development with Storybook.",
"Please remove this directory as an additional step of your command.\n`,
@ -256,7 +256,7 @@ export async function generateResourcesForMainTheme(params: {
getThisCodebaseRootDirPath(),
"res",
"public",
WELL_KNOWN_DIRECTORY_BASE_NAME.DOT_KEYCLOAKIFY,
WELL_KNOWN_DIRECTORY_BASE_NAME.KEYCLOAKIFY_DEV_RESOURCES,
themeType
),
destDirPath: pathJoin(themeTypeDirPath, "resources")

View File

@ -3,7 +3,7 @@ export type KeycloakVersionRange =
| KeycloakVersionRange.WithoutAccountV1Theme;
export namespace KeycloakVersionRange {
export type WithoutAccountV1Theme = "21-and-below" | "22-and-above";
export type WithoutAccountV1Theme = "22-to-25" | "all-other-versions";
export type WithAccountV1Theme = "21-and-below" | "23" | "24" | "25-and-above";
export type WithAccountV1Theme = "21-and-below" | "23" | "24" | "25" | "26-and-above";
}

View File

@ -25,6 +25,7 @@ import { type ThemeType } from "./constants";
import { id } from "tsafe/id";
import chalk from "chalk";
import { getProxyFetchOptions, type ProxyFetchOptions } from "../tools/fetchProxyOptions";
import { is } from "tsafe/is";
export type BuildContext = {
themeVersion: string;
@ -277,7 +278,8 @@ export function getBuildContext(params: {
"21-and-below": z.union([z.boolean(), z.string()]),
"23": z.union([z.boolean(), z.string()]),
"24": z.union([z.boolean(), z.string()]),
"25-and-above": z.union([z.boolean(), z.string()])
"25": z.union([z.boolean(), z.string()]),
"26-and-above": z.union([z.boolean(), z.string()])
})
.optional()
});
@ -298,8 +300,8 @@ export function getBuildContext(params: {
]),
keycloakVersionTargets: z
.object({
"21-and-below": z.union([z.boolean(), z.string()]),
"22-and-above": z.union([z.boolean(), z.string()])
"22-to-25": z.union([z.boolean(), z.string()]),
"all-other-versions": z.union([z.boolean(), z.string()])
})
.optional()
});
@ -749,7 +751,11 @@ export function getBuildContext(params: {
return "24" as const;
}
return "25-and-above" as const;
if (buildForKeycloakMajorVersionNumber === 25) {
return "25" as const;
}
return "26-and-above" as const;
})();
assert<
@ -762,11 +768,14 @@ export function getBuildContext(params: {
return keycloakVersionRange;
} else {
const keycloakVersionRange = (() => {
if (buildForKeycloakMajorVersionNumber <= 21) {
return "21-and-below" as const;
if (
buildForKeycloakMajorVersionNumber <= 21 ||
buildForKeycloakMajorVersionNumber >= 26
) {
return "all-other-versions" as const;
}
return "22-and-above" as const;
return "22-to-25" as const;
})();
assert<
@ -784,6 +793,12 @@ export function getBuildContext(params: {
use_custom_jar_basename: {
const { keycloakVersionTargets } = buildOptions;
assert(
is<Record<KeycloakVersionRange, string | boolean>>(
keycloakVersionTargets
)
);
if (keycloakVersionTargets === undefined) {
break use_custom_jar_basename;
}
@ -828,7 +843,8 @@ export function getBuildContext(params: {
"21-and-below",
"23",
"24",
"25-and-above"
"25",
"26-and-above"
] as const) {
assert<
Equals<
@ -844,8 +860,8 @@ export function getBuildContext(params: {
}
} else {
for (const keycloakVersionRange of [
"21-and-below",
"22-and-above"
"22-to-25",
"all-other-versions"
] as const) {
assert<
Equals<
@ -871,7 +887,17 @@ export function getBuildContext(params: {
const jarTargets: BuildContext["jarTargets"] = [];
for (const [keycloakVersionRange, jarNameOrBoolean] of objectEntries(
buildOptions.keycloakVersionTargets
(() => {
const { keycloakVersionTargets } = buildOptions;
assert(
is<Record<KeycloakVersionRange, string | boolean>>(
keycloakVersionTargets
)
);
return keycloakVersionTargets;
})()
)) {
if (jarNameOrBoolean === false) {
continue;

View File

@ -1,5 +1,5 @@
export const WELL_KNOWN_DIRECTORY_BASE_NAME = {
DOT_KEYCLOAKIFY: ".keycloakify",
KEYCLOAKIFY_DEV_RESOURCES: "keycloakify-dev-resources",
RESOURCES_COMMON: "resources-common",
DIST: "dist"
} as const;

View File

@ -21,7 +21,7 @@ export function copyKeycloakResourcesToPublic(params: {
const destDirPath = pathJoin(
buildContext.publicDirPath,
WELL_KNOWN_DIRECTORY_BASE_NAME.DOT_KEYCLOAKIFY
WELL_KNOWN_DIRECTORY_BASE_NAME.KEYCLOAKIFY_DEV_RESOURCES
);
const keycloakifyBuildinfoFilePath = pathJoin(destDirPath, "keycloakify.buildinfo");
@ -57,6 +57,10 @@ export function copyKeycloakResourcesToPublic(params: {
force: true,
recursive: true
});
rmSync(pathJoin(pathDirname(destDirPath), ".keycloakify"), {
force: true,
recursive: true
});
fs.mkdirSync(destDirPath, { recursive: true });
@ -67,7 +71,7 @@ export function copyKeycloakResourcesToPublic(params: {
getThisCodebaseRootDirPath(),
"res",
"public",
WELL_KNOWN_DIRECTORY_BASE_NAME.DOT_KEYCLOAKIFY
WELL_KNOWN_DIRECTORY_BASE_NAME.KEYCLOAKIFY_DEV_RESOURCES
),
destDirPath
});

View File

@ -75,7 +75,7 @@ const attributesByName = Object.fromEntries(
]).map(attribute => [attribute.name, attribute])
);
const resourcesPath = `${BASE_URL}${WELL_KNOWN_DIRECTORY_BASE_NAME.DOT_KEYCLOAKIFY}/login`;
const resourcesPath = `${BASE_URL}${WELL_KNOWN_DIRECTORY_BASE_NAME.KEYCLOAKIFY_DEV_RESOURCES}/login`;
export const kcContextCommonMock: KcContext.Common = {
themeVersion: "0.0.0",

View File

@ -55,14 +55,7 @@ export function useStylesAndScripts(params: {
const { insertScriptTags } = useInsertScriptTags({
componentOrHookName: "Template",
scriptTags: [
{
type: "importmap",
textContent: JSON.stringify({
imports: {
rfc4648: `${url.resourcesCommonPath}/node_modules/rfc4648/lib/rfc4648.js`
}
})
},
// NOTE: The importmap is added in by the FTL script because it's too late to add it here.
{
type: "module",
src: `${url.resourcesPath}/js/menu-button-links.js`

View File

@ -6,7 +6,7 @@ export type ScriptTag = ScriptTag.TextContent | ScriptTag.Src;
export namespace ScriptTag {
type Common = {
type: "text/javascript" | "module" | "importmap";
type: "text/javascript" | "module";
};
export type TextContent = Common & {

View File

@ -201,7 +201,10 @@ export function keycloakify(params: keycloakify.Params) {
assert(buildDirPath !== undefined);
await rm(
pathJoin(buildDirPath, WELL_KNOWN_DIRECTORY_BASE_NAME.DOT_KEYCLOAKIFY),
pathJoin(
buildDirPath,
WELL_KNOWN_DIRECTORY_BASE_NAME.KEYCLOAKIFY_DEV_RESOURCES
),
{
recursive: true,
force: true