Compare commits
19 Commits
v10.0.0-rc
...
bundle_jar
Author | SHA1 | Date | |
---|---|---|---|
7d8ae040fd | |||
c6cf564842 | |||
380b739017 | |||
c3f3c55303 | |||
2c01018529 | |||
dd2edf3013 | |||
7f3cdf9fac | |||
f75a91fbc1 | |||
f151086bb1 | |||
7c833e6f10 | |||
885e8314e8 | |||
3bdd955ab6 | |||
9499587bad | |||
0879ddba7c | |||
106a1dd4c7 | |||
5580248bcd | |||
c9c10b8fba | |||
ed254922e9 | |||
4b7d1e2cec |
@ -240,6 +240,15 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"code"
|
"code"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "oliviergoulet5",
|
||||||
|
"name": "Olivier Goulet",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/17685861?v=4",
|
||||||
|
"profile": "https://github.com/oliviergoulet5",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contributorsPerLine": 7,
|
"contributorsPerLine": 7,
|
||||||
|
@ -132,6 +132,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/law108000"><img src="https://avatars.githubusercontent.com/u/8112024?v=4?s=100" width="100px;" alt="Rlok"/><br /><sub><b>Rlok</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=law108000" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/law108000"><img src="https://avatars.githubusercontent.com/u/8112024?v=4?s=100" width="100px;" alt="Rlok"/><br /><sub><b>Rlok</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=law108000" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Moulyy"><img src="https://avatars.githubusercontent.com/u/115405804?v=4?s=100" width="100px;" alt="Moulyy"/><br /><sub><b>Moulyy</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=Moulyy" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Moulyy"><img src="https://avatars.githubusercontent.com/u/115405804?v=4?s=100" width="100px;" alt="Moulyy"/><br /><sub><b>Moulyy</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=Moulyy" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/madmadson"><img src="https://avatars.githubusercontent.com/u/798831?v=4?s=100" width="100px;" alt="Tobias Matt"/><br /><sub><b>Tobias Matt</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=madmadson" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/madmadson"><img src="https://avatars.githubusercontent.com/u/798831?v=4?s=100" width="100px;" alt="Tobias Matt"/><br /><sub><b>Tobias Matt</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=madmadson" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/oliviergoulet5"><img src="https://avatars.githubusercontent.com/u/17685861?v=4?s=100" width="100px;" alt="Olivier Goulet"/><br /><sub><b>Olivier Goulet</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=oliviergoulet5" title="Code">💻</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "keycloakify",
|
"name": "keycloakify",
|
||||||
"version": "10.0.0-rc.140",
|
"version": "10.0.0-rc.147",
|
||||||
"description": "Create Keycloak themes using React",
|
"description": "Create Keycloak themes using React",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -17,15 +17,20 @@ import { isInside } from "../../tools/isInside";
|
|||||||
import child_process from "child_process";
|
import child_process from "child_process";
|
||||||
import { rmSync } from "../../tools/fs.rmSync";
|
import { rmSync } from "../../tools/fs.rmSync";
|
||||||
import { writeMetaInfKeycloakThemes } from "../../shared/metaInfKeycloakThemes";
|
import { writeMetaInfKeycloakThemes } from "../../shared/metaInfKeycloakThemes";
|
||||||
|
import {
|
||||||
|
bundleExtensionsIntoJar,
|
||||||
|
type BuildContextLike as BuildContextLike_bundleExtensionsIntoJar
|
||||||
|
} from "./bundleExtensionsIntoJar";
|
||||||
|
|
||||||
export type BuildContextLike = BuildContextLike_generatePom & {
|
export type BuildContextLike = BuildContextLike_generatePom &
|
||||||
keycloakifyBuildDirPath: string;
|
BuildContextLike_bundleExtensionsIntoJar & {
|
||||||
themeNames: string[];
|
keycloakifyBuildDirPath: string;
|
||||||
artifactId: string;
|
themeNames: string[];
|
||||||
themeVersion: string;
|
artifactId: string;
|
||||||
cacheDirPath: string;
|
themeVersion: string;
|
||||||
implementedThemeTypes: BuildContext["implementedThemeTypes"];
|
cacheDirPath: string;
|
||||||
};
|
implementedThemeTypes: BuildContext["implementedThemeTypes"];
|
||||||
|
};
|
||||||
|
|
||||||
assert<BuildContext extends BuildContextLike ? true : false>();
|
assert<BuildContext extends BuildContextLike ? true : false>();
|
||||||
|
|
||||||
@ -234,12 +239,19 @@ export async function buildJar(params: {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const jarFilePath_generatedByMaven = pathJoin(
|
||||||
|
keycloakifyBuildCacheDirPath,
|
||||||
|
"target",
|
||||||
|
`${buildContext.artifactId}-${buildContext.themeVersion}.jar`
|
||||||
|
);
|
||||||
|
|
||||||
|
await bundleExtensionsIntoJar({
|
||||||
|
buildContext,
|
||||||
|
jarFilePath: jarFilePath_generatedByMaven
|
||||||
|
});
|
||||||
|
|
||||||
await fs.rename(
|
await fs.rename(
|
||||||
pathJoin(
|
jarFilePath_generatedByMaven,
|
||||||
keycloakifyBuildCacheDirPath,
|
|
||||||
"target",
|
|
||||||
`${buildContext.artifactId}-${buildContext.themeVersion}.jar`
|
|
||||||
),
|
|
||||||
pathJoin(buildContext.keycloakifyBuildDirPath, jarFileBasename)
|
pathJoin(buildContext.keycloakifyBuildDirPath, jarFileBasename)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
137
src/bin/keycloakify/buildJars/bundleExtensionsIntoJar.ts
Normal file
137
src/bin/keycloakify/buildJars/bundleExtensionsIntoJar.ts
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import { downloadAndExtractArchive } from "../../tools/downloadAndExtractArchive";
|
||||||
|
import { assert } from "tsafe/assert";
|
||||||
|
import type { BuildContext } from "../../shared/buildContext";
|
||||||
|
import { transformCodebase } from "../../tools/transformCodebase";
|
||||||
|
import { join as pathJoin, basename as pathBasename, sep as pathSep } from "path";
|
||||||
|
import { rm } from "../../tools/fs.rm";
|
||||||
|
import { extractArchive } from "../../tools/extractArchive";
|
||||||
|
import * as crypto from "crypto";
|
||||||
|
|
||||||
|
export type BuildContextLike = {
|
||||||
|
cacheDirPath: string;
|
||||||
|
fetchOptions: BuildContext["fetchOptions"];
|
||||||
|
extensionJars: BuildContext["extensionJars"];
|
||||||
|
};
|
||||||
|
|
||||||
|
assert<BuildContext extends BuildContextLike ? true : false>();
|
||||||
|
|
||||||
|
export async function bundleExtensionsIntoJar(params: {
|
||||||
|
jarFilePath: string;
|
||||||
|
buildContext: BuildContextLike;
|
||||||
|
}): Promise<void> {
|
||||||
|
const { jarFilePath, buildContext } = params;
|
||||||
|
|
||||||
|
if (buildContext.extensionJars.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mergeDirPath = pathJoin(
|
||||||
|
buildContext.cacheDirPath,
|
||||||
|
`merge_${pathBasename(jarFilePath).replace(/\.jar$/, "")}_${crypto
|
||||||
|
.createHash("sha256")
|
||||||
|
.update(jarFilePath)
|
||||||
|
.digest("hex")
|
||||||
|
.substring(0, 5)}`
|
||||||
|
);
|
||||||
|
|
||||||
|
await extractArchive({
|
||||||
|
archiveFilePath: jarFilePath,
|
||||||
|
onArchiveFile: async ({ relativeFilePathInArchive, writeFile }) =>
|
||||||
|
writeFile({
|
||||||
|
filePath: pathJoin(mergeDirPath, relativeFilePathInArchive)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const extensionJar of buildContext.extensionJars) {
|
||||||
|
const transformSourceCode = (params: {
|
||||||
|
fileRelativePath: string;
|
||||||
|
sourceCode: Buffer;
|
||||||
|
}): { modifiedSourceCode: Buffer } | undefined => {
|
||||||
|
const { fileRelativePath } = params;
|
||||||
|
|
||||||
|
if (!fileRelativePath.startsWith(`META-INF${pathSep}`)) {
|
||||||
|
for (const ext of [".DSA", ".SF", ".RSA"]) {
|
||||||
|
if (fileRelativePath.endsWith(ext)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (extensionJar.type) {
|
||||||
|
case "path":
|
||||||
|
await extractArchive({
|
||||||
|
archiveFilePath: extensionJar.path,
|
||||||
|
onArchiveFile: async ({
|
||||||
|
relativeFilePathInArchive,
|
||||||
|
writeFile,
|
||||||
|
readFile
|
||||||
|
}) => {
|
||||||
|
const transformResult = transformSourceCode({
|
||||||
|
fileRelativePath: relativeFilePathInArchive,
|
||||||
|
sourceCode: await readFile()
|
||||||
|
});
|
||||||
|
|
||||||
|
if (transformResult === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await writeFile({
|
||||||
|
filePath: pathJoin(mergeDirPath, relativeFilePathInArchive),
|
||||||
|
modifiedData: transformResult.modifiedSourceCode
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "url": {
|
||||||
|
const { extractedDirPath } = await downloadAndExtractArchive({
|
||||||
|
url: extensionJar.url,
|
||||||
|
cacheDirPath: buildContext.cacheDirPath,
|
||||||
|
fetchOptions: buildContext.fetchOptions,
|
||||||
|
uniqueIdOfOnArchiveFile: "noOp",
|
||||||
|
onArchiveFile: async ({ fileRelativePath, writeFile }) =>
|
||||||
|
writeFile({ fileRelativePath })
|
||||||
|
});
|
||||||
|
transformCodebase({
|
||||||
|
srcDirPath: extractedDirPath,
|
||||||
|
destDirPath: mergeDirPath,
|
||||||
|
transformSourceCode
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
transformCodebase({
|
||||||
|
srcDirPath: extractedDirPath,
|
||||||
|
destDirPath: mergeDirPath,
|
||||||
|
transformSourceCode: ({ fileRelativePath, sourceCode }) => {
|
||||||
|
if (fileRelativePath === pathJoin("META-INF", "MANIFEST.MF")) {
|
||||||
|
const sourceCodeStr = sourceCode.toString("utf8");
|
||||||
|
|
||||||
|
const lines = sourceCodeStr.split(/\r?\n/);
|
||||||
|
|
||||||
|
console.log(lines);
|
||||||
|
|
||||||
|
return {
|
||||||
|
modifiedSourceCode: Buffer.concat([
|
||||||
|
sourceCode,
|
||||||
|
Buffer.from(
|
||||||
|
`Class-Path: ${pathBasename(userProvidedJarFilePathOrUrl)}\n`
|
||||||
|
)
|
||||||
|
])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Acctually build new jar
|
||||||
|
|
||||||
|
await rm(mergeDirPath, { recursive: true, force: true });
|
||||||
|
}
|
@ -314,7 +314,7 @@ export async function generateResourcesForMainTheme(params: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { extractedDirPath } = await downloadAndExtractArchive({
|
const { extractedDirPath } = await downloadAndExtractArchive({
|
||||||
urlOrPath: "https://repo1.maven.org/maven2/org/keycloak/keycloak-account-ui/25.0.1/keycloak-account-ui-25.0.1.jar",
|
url: "https://repo1.maven.org/maven2/org/keycloak/keycloak-account-ui/25.0.1/keycloak-account-ui-25.0.1.jar",
|
||||||
cacheDirPath: buildContext.cacheDirPath,
|
cacheDirPath: buildContext.cacheDirPath,
|
||||||
fetchOptions: buildContext.fetchOptions,
|
fetchOptions: buildContext.fetchOptions,
|
||||||
uniqueIdOfOnArchiveFile: "bring_in_account_v3_i18n_messages",
|
uniqueIdOfOnArchiveFile: "bring_in_account_v3_i18n_messages",
|
||||||
|
@ -26,6 +26,8 @@ import { type ThemeType } from "./constants";
|
|||||||
import { id } from "tsafe/id";
|
import { id } from "tsafe/id";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { getProxyFetchOptions, type ProxyFetchOptions } from "../tools/fetchProxyOptions";
|
import { getProxyFetchOptions, type ProxyFetchOptions } from "../tools/fetchProxyOptions";
|
||||||
|
import { removeDuplicates } from "evt/tools/reducers/removeDuplicates";
|
||||||
|
import { same } from "evt/tools/inDepth/same";
|
||||||
|
|
||||||
export type BuildContext = {
|
export type BuildContext = {
|
||||||
themeVersion: string;
|
themeVersion: string;
|
||||||
@ -61,6 +63,7 @@ export type BuildContext = {
|
|||||||
keycloakVersionRange: KeycloakVersionRange;
|
keycloakVersionRange: KeycloakVersionRange;
|
||||||
jarFileBasename: string;
|
jarFileBasename: string;
|
||||||
}[];
|
}[];
|
||||||
|
extensionJars: ({ type: "path"; path: string } | { type: "url"; url: string })[];
|
||||||
startKeycloakOptions: {
|
startKeycloakOptions: {
|
||||||
dockerImage:
|
dockerImage:
|
||||||
| {
|
| {
|
||||||
@ -88,6 +91,7 @@ export type BuildOptions = {
|
|||||||
loginThemeResourcesFromKeycloakVersion?: string;
|
loginThemeResourcesFromKeycloakVersion?: string;
|
||||||
keycloakifyBuildDirPath?: string;
|
keycloakifyBuildDirPath?: string;
|
||||||
kcContextExclusionsFtl?: string;
|
kcContextExclusionsFtl?: string;
|
||||||
|
extensionJars?: string[];
|
||||||
startKeycloakOptions?: {
|
startKeycloakOptions?: {
|
||||||
dockerImage?: string;
|
dockerImage?: string;
|
||||||
dockerExtraArgs?: string[];
|
dockerExtraArgs?: string[];
|
||||||
@ -360,6 +364,7 @@ export function getBuildContext(params: {
|
|||||||
loginThemeResourcesFromKeycloakVersion: z.string().optional(),
|
loginThemeResourcesFromKeycloakVersion: z.string().optional(),
|
||||||
keycloakifyBuildDirPath: z.string().optional(),
|
keycloakifyBuildDirPath: z.string().optional(),
|
||||||
kcContextExclusionsFtl: z.string().optional(),
|
kcContextExclusionsFtl: z.string().optional(),
|
||||||
|
extensionJars: z.array(z.string()).optional(),
|
||||||
startKeycloakOptions: zStartKeycloakOptions.optional()
|
startKeycloakOptions: zStartKeycloakOptions.optional()
|
||||||
}),
|
}),
|
||||||
zAccountThemeImplAndKeycloakVersionTargets
|
zAccountThemeImplAndKeycloakVersionTargets
|
||||||
@ -520,6 +525,36 @@ export function getBuildContext(params: {
|
|||||||
return pathJoin(projectDirPath, resolvedViteConfig.buildDir);
|
return pathJoin(projectDirPath, resolvedViteConfig.buildDir);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
const buildForKeycloakMajorVersionNumber = (() => {
|
||||||
|
const envValue = process.env[BUILD_FOR_KEYCLOAK_MAJOR_VERSION_ENV_NAME];
|
||||||
|
|
||||||
|
if (envValue === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const major = parseInt(envValue);
|
||||||
|
|
||||||
|
assert(!isNaN(major));
|
||||||
|
|
||||||
|
return major;
|
||||||
|
})();
|
||||||
|
|
||||||
|
function urlOrPathToDiscriminatingWrapper(
|
||||||
|
urlOrPath: string
|
||||||
|
): { type: "url"; url: string } | { type: "path"; path: string } {
|
||||||
|
if (/^https?:\/\//.test(urlOrPath)) {
|
||||||
|
return { type: "url", url: urlOrPath };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: "path",
|
||||||
|
path: getAbsoluteAndInOsFormatPath({
|
||||||
|
pathIsh: urlOrPath,
|
||||||
|
cwd: projectDirPath
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
bundler,
|
bundler,
|
||||||
packageJsonFilePath,
|
packageJsonFilePath,
|
||||||
@ -717,21 +752,6 @@ export function getBuildContext(params: {
|
|||||||
`keycloak-theme-for-kc-${range}.jar`;
|
`keycloak-theme-for-kc-${range}.jar`;
|
||||||
|
|
||||||
build_for_specific_keycloak_major_version: {
|
build_for_specific_keycloak_major_version: {
|
||||||
const buildForKeycloakMajorVersionNumber = (() => {
|
|
||||||
const envValue =
|
|
||||||
process.env[BUILD_FOR_KEYCLOAK_MAJOR_VERSION_ENV_NAME];
|
|
||||||
|
|
||||||
if (envValue === undefined) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const major = parseInt(envValue);
|
|
||||||
|
|
||||||
assert(!isNaN(major));
|
|
||||||
|
|
||||||
return major;
|
|
||||||
})();
|
|
||||||
|
|
||||||
if (buildForKeycloakMajorVersionNumber === undefined) {
|
if (buildForKeycloakMajorVersionNumber === undefined) {
|
||||||
break build_for_specific_keycloak_major_version;
|
break build_for_specific_keycloak_major_version;
|
||||||
}
|
}
|
||||||
@ -931,6 +951,10 @@ export function getBuildContext(params: {
|
|||||||
|
|
||||||
return jarTargets;
|
return jarTargets;
|
||||||
})(),
|
})(),
|
||||||
|
extensionJars: (buildForKeycloakMajorVersionNumber !== undefined
|
||||||
|
? []
|
||||||
|
: buildOptions.extensionJars ?? []
|
||||||
|
).map(urlOrPath => urlOrPathToDiscriminatingWrapper(urlOrPath)),
|
||||||
startKeycloakOptions: {
|
startKeycloakOptions: {
|
||||||
dockerImage: (() => {
|
dockerImage: (() => {
|
||||||
if (buildOptions.startKeycloakOptions?.dockerImage === undefined) {
|
if (buildOptions.startKeycloakOptions?.dockerImage === undefined) {
|
||||||
@ -949,21 +973,14 @@ export function getBuildContext(params: {
|
|||||||
})(),
|
})(),
|
||||||
dockerExtraArgs: buildOptions.startKeycloakOptions?.dockerExtraArgs ?? [],
|
dockerExtraArgs: buildOptions.startKeycloakOptions?.dockerExtraArgs ?? [],
|
||||||
keycloakExtraArgs: buildOptions.startKeycloakOptions?.keycloakExtraArgs ?? [],
|
keycloakExtraArgs: buildOptions.startKeycloakOptions?.keycloakExtraArgs ?? [],
|
||||||
extensionJars: (buildOptions.startKeycloakOptions?.extensionJars ?? []).map(
|
extensionJars: [
|
||||||
urlOrPath => {
|
...(buildForKeycloakMajorVersionNumber !== undefined
|
||||||
if (/^https?:\/\//.test(urlOrPath)) {
|
? buildOptions.extensionJars ?? []
|
||||||
return { type: "url", url: urlOrPath };
|
: []),
|
||||||
}
|
...(buildOptions.startKeycloakOptions?.extensionJars ?? [])
|
||||||
|
]
|
||||||
return {
|
.map(urlOrPath => urlOrPathToDiscriminatingWrapper(urlOrPath))
|
||||||
type: "path",
|
.reduce(...removeDuplicates<BuildContext["extensionJars"][number]>(same)),
|
||||||
path: getAbsoluteAndInOsFormatPath({
|
|
||||||
pathIsh: urlOrPath,
|
|
||||||
cwd: projectDirPath
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}
|
|
||||||
),
|
|
||||||
realmJsonFilePath:
|
realmJsonFilePath:
|
||||||
buildOptions.startKeycloakOptions?.realmJsonFilePath === undefined
|
buildOptions.startKeycloakOptions?.realmJsonFilePath === undefined
|
||||||
? undefined
|
? undefined
|
||||||
|
@ -21,7 +21,7 @@ export async function downloadKeycloakDefaultTheme(params: {
|
|||||||
let kcNodeModulesKeepFilePaths_lastAccountV1: Set<string> | undefined = undefined;
|
let kcNodeModulesKeepFilePaths_lastAccountV1: Set<string> | undefined = undefined;
|
||||||
|
|
||||||
const { extractedDirPath } = await downloadAndExtractArchive({
|
const { extractedDirPath } = await downloadAndExtractArchive({
|
||||||
urlOrPath: `https://repo1.maven.org/maven2/org/keycloak/keycloak-themes/${keycloakVersion}/keycloak-themes-${keycloakVersion}.jar`,
|
url: `https://repo1.maven.org/maven2/org/keycloak/keycloak-themes/${keycloakVersion}/keycloak-themes-${keycloakVersion}.jar`,
|
||||||
cacheDirPath: buildContext.cacheDirPath,
|
cacheDirPath: buildContext.cacheDirPath,
|
||||||
fetchOptions: buildContext.fetchOptions,
|
fetchOptions: buildContext.fetchOptions,
|
||||||
uniqueIdOfOnArchiveFile: "downloadKeycloakDefaultTheme",
|
uniqueIdOfOnArchiveFile: "downloadKeycloakDefaultTheme",
|
||||||
|
@ -55,7 +55,7 @@ export async function promptKeycloakVersion(params: {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const lastMajorVersions = Array.from(semVersionedTagByMajor.values()).map(
|
const lastMajorVersions = Array.from(semVersionedTagByMajor.values()).map(
|
||||||
({ tag }) => tag
|
({ version }) => `${version.major}.${version.minor}`
|
||||||
);
|
);
|
||||||
|
|
||||||
const { value } = await cliSelect<string>({
|
const { value } = await cliSelect<string>({
|
||||||
|
@ -200,7 +200,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
|||||||
const { archiveFilePath } = await downloadAndExtractArchive({
|
const { archiveFilePath } = await downloadAndExtractArchive({
|
||||||
cacheDirPath: buildContext.cacheDirPath,
|
cacheDirPath: buildContext.cacheDirPath,
|
||||||
fetchOptions: buildContext.fetchOptions,
|
fetchOptions: buildContext.fetchOptions,
|
||||||
urlOrPath: extensionJar.url,
|
url: extensionJar.url,
|
||||||
uniqueIdOfOnArchiveFile: "no extraction",
|
uniqueIdOfOnArchiveFile: "no extraction",
|
||||||
onArchiveFile: async () => {}
|
onArchiveFile: async () => {}
|
||||||
});
|
});
|
||||||
@ -334,19 +334,30 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
|||||||
});
|
});
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
|
const DEFAULT_PORT = 8080;
|
||||||
|
const port =
|
||||||
|
cliCommandOptions.port ?? buildContext.startKeycloakOptions.port ?? DEFAULT_PORT;
|
||||||
|
|
||||||
const SPACE_PLACEHOLDER = "SPACE_PLACEHOLDER_xKLmdPd";
|
const SPACE_PLACEHOLDER = "SPACE_PLACEHOLDER_xKLmdPd";
|
||||||
|
|
||||||
const dockerRunArgs: string[] = [
|
const dockerRunArgs: string[] = [
|
||||||
`-p${SPACE_PLACEHOLDER}${cliCommandOptions.port ?? buildContext.startKeycloakOptions.port ?? 8080}:8080`,
|
`-p${SPACE_PLACEHOLDER}${port}:8080`,
|
||||||
`--name${SPACE_PLACEHOLDER}${CONTAINER_NAME}`,
|
`--name${SPACE_PLACEHOLDER}${CONTAINER_NAME}`,
|
||||||
`-e${SPACE_PLACEHOLDER}KEYCLOAK_ADMIN=admin`,
|
`-e${SPACE_PLACEHOLDER}KEYCLOAK_ADMIN=admin`,
|
||||||
`-e${SPACE_PLACEHOLDER}KEYCLOAK_ADMIN_PASSWORD=admin`,
|
`-e${SPACE_PLACEHOLDER}KEYCLOAK_ADMIN_PASSWORD=admin`,
|
||||||
|
...(buildContext.startKeycloakOptions.dockerExtraArgs.length === 0
|
||||||
|
? []
|
||||||
|
: [
|
||||||
|
buildContext.startKeycloakOptions.dockerExtraArgs.join(
|
||||||
|
SPACE_PLACEHOLDER
|
||||||
|
)
|
||||||
|
]),
|
||||||
...(realmJsonFilePath === undefined
|
...(realmJsonFilePath === undefined
|
||||||
? []
|
? []
|
||||||
: [
|
: [
|
||||||
`-v${SPACE_PLACEHOLDER}".${pathSep}${pathRelative(process.cwd(), realmJsonFilePath)}":/opt/keycloak/data/import/myrealm-realm.json`
|
`-v${SPACE_PLACEHOLDER}".${pathSep}${pathRelative(process.cwd(), realmJsonFilePath)}":/opt/keycloak/data/import/myrealm-realm.json`
|
||||||
]),
|
]),
|
||||||
`-v${SPACE_PLACEHOLDER}"./${pathRelative(process.cwd(), jarFilePath_cacheDir)}":/opt/keycloak/providers/keycloak-theme.jar`,
|
`-v${SPACE_PLACEHOLDER}".${pathSep}${pathRelative(process.cwd(), jarFilePath_cacheDir)}":/opt/keycloak/providers/keycloak-theme.jar`,
|
||||||
...extensionJarFilePaths.map(
|
...extensionJarFilePaths.map(
|
||||||
jarFilePath =>
|
jarFilePath =>
|
||||||
`-v${SPACE_PLACEHOLDER}".${pathSep}${pathRelative(process.cwd(), jarFilePath)}":/opt/keycloak/providers/${pathBasename(jarFilePath)}`
|
`-v${SPACE_PLACEHOLDER}".${pathSep}${pathRelative(process.cwd(), jarFilePath)}":/opt/keycloak/providers/${pathBasename(jarFilePath)}`
|
||||||
@ -388,14 +399,19 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
|||||||
({ name, envValue }) =>
|
({ name, envValue }) =>
|
||||||
`--env${SPACE_PLACEHOLDER}${name}='${envValue.replace(/'/g, "'\\''")}'`
|
`--env${SPACE_PLACEHOLDER}${name}='${envValue.replace(/'/g, "'\\''")}'`
|
||||||
),
|
),
|
||||||
...buildContext.startKeycloakOptions.dockerExtraArgs.join(SPACE_PLACEHOLDER),
|
|
||||||
`${buildContext.startKeycloakOptions.dockerImage?.reference ?? "quay.io/keycloak/keycloak"}:${dockerImageTag}`,
|
`${buildContext.startKeycloakOptions.dockerImage?.reference ?? "quay.io/keycloak/keycloak"}:${dockerImageTag}`,
|
||||||
"start-dev",
|
"start-dev",
|
||||||
...(21 <= keycloakMajorVersionNumber && keycloakMajorVersionNumber < 24
|
...(21 <= keycloakMajorVersionNumber && keycloakMajorVersionNumber < 24
|
||||||
? ["--features=declarative-user-profile"]
|
? ["--features=declarative-user-profile"]
|
||||||
: []),
|
: []),
|
||||||
...(realmJsonFilePath === undefined ? [] : ["--import-realm"]),
|
...(realmJsonFilePath === undefined ? [] : ["--import-realm"]),
|
||||||
...buildContext.startKeycloakOptions.keycloakExtraArgs.join(SPACE_PLACEHOLDER)
|
...(buildContext.startKeycloakOptions.keycloakExtraArgs.length === 0
|
||||||
|
? []
|
||||||
|
: [
|
||||||
|
buildContext.startKeycloakOptions.keycloakExtraArgs.join(
|
||||||
|
SPACE_PLACEHOLDER
|
||||||
|
)
|
||||||
|
])
|
||||||
];
|
];
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
@ -427,6 +443,18 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
|||||||
const srcDirPath = pathJoin(buildContext.projectDirPath, "src");
|
const srcDirPath = pathJoin(buildContext.projectDirPath, "src");
|
||||||
|
|
||||||
{
|
{
|
||||||
|
const kcHttpRelativePath = (() => {
|
||||||
|
const match = buildContext.startKeycloakOptions.dockerExtraArgs
|
||||||
|
.join(" ")
|
||||||
|
.match(/KC_HTTP_RELATIVE_PATH=([^ ]+)/);
|
||||||
|
|
||||||
|
if (match === null) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return match[1];
|
||||||
|
})();
|
||||||
|
|
||||||
const handler = async (data: Buffer) => {
|
const handler = async (data: Buffer) => {
|
||||||
if (!data.toString("utf8").includes("Listening on: http://0.0.0.0:8080")) {
|
if (!data.toString("utf8").includes("Listening on: http://0.0.0.0:8080")) {
|
||||||
return;
|
return;
|
||||||
@ -444,7 +472,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
|||||||
)} are mounted in the Keycloak container.`,
|
)} are mounted in the Keycloak container.`,
|
||||||
"",
|
"",
|
||||||
`Keycloak Admin console: ${chalk.cyan.bold(
|
`Keycloak Admin console: ${chalk.cyan.bold(
|
||||||
`http://localhost:${cliCommandOptions.port}`
|
`http://localhost:${port}${kcHttpRelativePath ?? ""}`
|
||||||
)}`,
|
)}`,
|
||||||
`- user: ${chalk.cyan.bold("admin")}`,
|
`- user: ${chalk.cyan.bold("admin")}`,
|
||||||
`- password: ${chalk.cyan.bold("admin")}`,
|
`- password: ${chalk.cyan.bold("admin")}`,
|
||||||
@ -452,7 +480,21 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
|||||||
"",
|
"",
|
||||||
`${chalk.green("Your theme is accessible at:")}`,
|
`${chalk.green("Your theme is accessible at:")}`,
|
||||||
`${chalk.green("➜")} ${chalk.cyan.bold(
|
`${chalk.green("➜")} ${chalk.cyan.bold(
|
||||||
`https://my-theme.keycloakify.dev${cliCommandOptions.port === 8080 ? "" : `?port=${cliCommandOptions.port}`}`
|
(() => {
|
||||||
|
const url = new URL("https://my-theme.keycloakify.dev");
|
||||||
|
|
||||||
|
if (port !== DEFAULT_PORT) {
|
||||||
|
url.searchParams.set("port", `${port}`);
|
||||||
|
}
|
||||||
|
if (kcHttpRelativePath !== undefined) {
|
||||||
|
url.searchParams.set(
|
||||||
|
"kcHttpRelativePath",
|
||||||
|
kcHttpRelativePath
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return url.href;
|
||||||
|
})()
|
||||||
)}`,
|
)}`,
|
||||||
"",
|
"",
|
||||||
"You can login with the following credentials:",
|
"You can login with the following credentials:",
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import fetch, { type FetchOptions } from "make-fetch-happen";
|
import fetch, { type FetchOptions } from "make-fetch-happen";
|
||||||
import { mkdir, unlink, writeFile, readdir, readFile } from "fs/promises";
|
import { mkdir, unlink, writeFile, readdir, readFile } from "fs/promises";
|
||||||
import { dirname as pathDirname, join as pathJoin, basename as pathBasename } from "path";
|
import { dirname as pathDirname, join as pathJoin } from "path";
|
||||||
import { assert } from "tsafe/assert";
|
import { assert } from "tsafe/assert";
|
||||||
import { extractArchive } from "./extractArchive";
|
import { extractArchive } from "./extractArchive";
|
||||||
import { existsAsync } from "./fs.existsAsync";
|
import { existsAsync } from "./fs.existsAsync";
|
||||||
import * as crypto from "crypto";
|
import * as crypto from "crypto";
|
||||||
import { rm } from "./fs.rm";
|
import { rm } from "./fs.rm";
|
||||||
import * as fsPr from "fs/promises";
|
|
||||||
|
|
||||||
export async function downloadAndExtractArchive(params: {
|
export async function downloadAndExtractArchive(params: {
|
||||||
urlOrPath: string;
|
url: string;
|
||||||
uniqueIdOfOnArchiveFile: string;
|
uniqueIdOfOnArchiveFile: string;
|
||||||
onArchiveFile: (params: {
|
onArchiveFile: (params: {
|
||||||
fileRelativePath: string;
|
fileRelativePath: string;
|
||||||
@ -21,34 +20,17 @@ export async function downloadAndExtractArchive(params: {
|
|||||||
}) => Promise<void>;
|
}) => Promise<void>;
|
||||||
cacheDirPath: string;
|
cacheDirPath: string;
|
||||||
fetchOptions: FetchOptions | undefined;
|
fetchOptions: FetchOptions | undefined;
|
||||||
}): Promise<{ extractedDirPath: string; archiveFilePath: string; }> {
|
}): Promise<{ extractedDirPath: string; archiveFilePath: string }> {
|
||||||
const {
|
const { url, uniqueIdOfOnArchiveFile, onArchiveFile, cacheDirPath, fetchOptions } =
|
||||||
urlOrPath,
|
params;
|
||||||
uniqueIdOfOnArchiveFile,
|
|
||||||
onArchiveFile,
|
|
||||||
cacheDirPath,
|
|
||||||
fetchOptions
|
|
||||||
} = params;
|
|
||||||
|
|
||||||
const isUrl = /^https?:\/\//.test(urlOrPath);
|
const archiveFileBasename = url.split("?")[0].split("/").reverse()[0];
|
||||||
|
|
||||||
const archiveFileBasename = isUrl
|
|
||||||
? urlOrPath.split("?")[0].split("/").reverse()[0]
|
|
||||||
: pathBasename(urlOrPath);
|
|
||||||
|
|
||||||
const archiveFilePath = pathJoin(cacheDirPath, archiveFileBasename);
|
const archiveFilePath = pathJoin(cacheDirPath, archiveFileBasename);
|
||||||
|
|
||||||
download: {
|
download: {
|
||||||
await mkdir(pathDirname(archiveFilePath), { recursive: true });
|
await mkdir(pathDirname(archiveFilePath), { recursive: true });
|
||||||
|
|
||||||
if (!isUrl) {
|
|
||||||
await fsPr.copyFile(urlOrPath, archiveFilePath);
|
|
||||||
|
|
||||||
break download;
|
|
||||||
}
|
|
||||||
|
|
||||||
const url = urlOrPath;
|
|
||||||
|
|
||||||
if (await existsAsync(archiveFilePath)) {
|
if (await existsAsync(archiveFilePath)) {
|
||||||
const isDownloaded = await SuccessTracker.getIsDownloaded({
|
const isDownloaded = await SuccessTracker.getIsDownloaded({
|
||||||
cacheDirPath,
|
cacheDirPath,
|
||||||
|
@ -153,7 +153,7 @@ export default function WebauthnRegister(props: PageProps<Extract<KcContext, { p
|
|||||||
|
|
||||||
function getPubKeyCredParams(signatureAlgorithmsList) {
|
function getPubKeyCredParams(signatureAlgorithmsList) {
|
||||||
let pubKeyCredParams = [];
|
let pubKeyCredParams = [];
|
||||||
if (signatureAlgorithmsList === []) {
|
if (signatureAlgorithmsList.length === 0) {
|
||||||
pubKeyCredParams.push({type: "public-key", alg: -7});
|
pubKeyCredParams.push({type: "public-key", alg: -7});
|
||||||
return pubKeyCredParams;
|
return pubKeyCredParams;
|
||||||
}
|
}
|
||||||
@ -184,7 +184,7 @@ export default function WebauthnRegister(props: PageProps<Extract<KcContext, { p
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getTransportsAsString(transportsList) {
|
function getTransportsAsString(transportsList) {
|
||||||
if (transportsList === '' || transportsList.constructor !== Array) return "";
|
if (transportsList === '' || Array.isArray(transportsList)) return "";
|
||||||
|
|
||||||
let transportsString = "";
|
let transportsString = "";
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user