keycloakify 9.0.0-rc.0 → 9.0.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.
Files changed (134) hide show
  1. package/README.md +8 -18
  2. package/account/Template.js +1 -1
  3. package/account/Template.js.map +1 -1
  4. package/account/TemplateProps.d.ts +1 -1
  5. package/account/kcContext/KcContext.d.ts +1 -0
  6. package/account/kcContext/KcContext.js.map +1 -1
  7. package/account/kcContext/kcContextMocks.js +1 -0
  8. package/account/kcContext/kcContextMocks.js.map +1 -1
  9. package/account/lib/useGetClassName.js +1 -0
  10. package/account/lib/useGetClassName.js.map +1 -1
  11. package/account/pages/Account.js +1 -1
  12. package/account/pages/Account.js.map +1 -1
  13. package/bin/getSrcDirPath.js +30 -17
  14. package/bin/getSrcDirPath.js.map +1 -1
  15. package/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +6 -0
  16. package/bin/keycloakify/generateFtl/generateFtl.js +22 -0
  17. package/bin/keycloakify/generateFtl/generateFtl.js.map +1 -1
  18. package/bin/keycloakify/generateFtl/pageId.d.ts +1 -1
  19. package/bin/keycloakify/generateFtl/pageId.js +2 -0
  20. package/bin/keycloakify/generateFtl/pageId.js.map +1 -1
  21. package/bin/keycloakify/generateJavaStackFiles/bringInAccountV1.js +1 -5
  22. package/bin/keycloakify/generateJavaStackFiles/bringInAccountV1.js.map +1 -1
  23. package/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.js +32 -103
  24. package/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.js.map +1 -1
  25. package/bin/keycloakify/generateStartKeycloakTestingContainer.d.ts +1 -0
  26. package/bin/keycloakify/generateStartKeycloakTestingContainer.js +4 -3
  27. package/bin/keycloakify/generateStartKeycloakTestingContainer.js.map +1 -1
  28. package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.d.ts +0 -1
  29. package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.js +22 -13
  30. package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.js.map +1 -1
  31. package/bin/keycloakify/generateTheme/readStaticResourcesUsage.d.ts +0 -2
  32. package/bin/keycloakify/generateTheme/readStaticResourcesUsage.js +37 -51
  33. package/bin/keycloakify/generateTheme/readStaticResourcesUsage.js.map +1 -1
  34. package/bin/keycloakify/keycloakify.js +3 -2
  35. package/bin/keycloakify/keycloakify.js.map +1 -1
  36. package/bin/keycloakify/replacers/replaceImportsFromStaticInJsCode.js +7 -3
  37. package/bin/keycloakify/replacers/replaceImportsFromStaticInJsCode.js.map +1 -1
  38. package/lib/usePrepareTemplate.js +7 -8
  39. package/lib/usePrepareTemplate.js.map +1 -1
  40. package/login/Fallback.js +6 -0
  41. package/login/Fallback.js.map +1 -1
  42. package/login/Template.js +1 -1
  43. package/login/Template.js.map +1 -1
  44. package/login/TemplateProps.d.ts +1 -1
  45. package/login/kcContext/KcContext.d.ts +21 -1
  46. package/login/kcContext/KcContext.js.map +1 -1
  47. package/login/kcContext/kcContextMocks.d.ts +1 -1
  48. package/login/kcContext/kcContextMocks.js +12 -1
  49. package/login/kcContext/kcContextMocks.js.map +1 -1
  50. package/login/lib/useGetClassName.js +2 -0
  51. package/login/lib/useGetClassName.js.map +1 -1
  52. package/login/pages/Info.js +1 -1
  53. package/login/pages/Info.js.map +1 -1
  54. package/login/pages/LoginConfigTotp.js +1 -1
  55. package/login/pages/LoginConfigTotp.js.map +1 -1
  56. package/login/pages/LoginDeviceVerifyUserCode.d.ts +7 -0
  57. package/login/pages/LoginDeviceVerifyUserCode.js +15 -0
  58. package/login/pages/LoginDeviceVerifyUserCode.js.map +1 -0
  59. package/login/pages/LoginOauthGrant.d.ts +7 -0
  60. package/login/pages/LoginOauthGrant.js +15 -0
  61. package/login/pages/LoginOauthGrant.js.map +1 -0
  62. package/package.json +11 -67
  63. package/src/account/Template.tsx +1 -1
  64. package/src/account/TemplateProps.ts +1 -1
  65. package/src/account/kcContext/KcContext.ts +1 -0
  66. package/src/account/kcContext/kcContextMocks.ts +1 -0
  67. package/src/account/lib/useGetClassName.ts +1 -0
  68. package/src/account/pages/Account.tsx +4 -4
  69. package/src/bin/getSrcDirPath.ts +8 -8
  70. package/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +6 -0
  71. package/src/bin/keycloakify/generateFtl/generateFtl.ts +21 -0
  72. package/src/bin/keycloakify/generateFtl/pageId.ts +2 -0
  73. package/src/bin/keycloakify/generateJavaStackFiles/bringInAccountV1.ts +1 -6
  74. package/src/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.ts +32 -103
  75. package/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts +11 -4
  76. package/src/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.ts +29 -15
  77. package/src/bin/keycloakify/generateTheme/readStaticResourcesUsage.ts +21 -28
  78. package/src/bin/keycloakify/keycloakify.ts +3 -3
  79. package/src/bin/keycloakify/replacers/replaceImportsFromStaticInJsCode.ts +14 -7
  80. package/src/lib/usePrepareTemplate.ts +7 -10
  81. package/src/login/Fallback.tsx +6 -0
  82. package/src/login/Template.tsx +1 -1
  83. package/src/login/TemplateProps.ts +3 -1
  84. package/src/login/kcContext/KcContext.ts +24 -0
  85. package/src/login/kcContext/kcContextMocks.ts +23 -1
  86. package/src/login/lib/useGetClassName.ts +2 -0
  87. package/src/login/pages/Info.tsx +4 -1
  88. package/src/login/pages/LoginConfigTotp.tsx +1 -1
  89. package/src/login/pages/LoginDeviceVerifyUserCode.tsx +68 -0
  90. package/src/login/pages/LoginOauthGrant.tsx +73 -0
  91. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountPages.java +0 -33
  92. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProvider.java +0 -76
  93. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProviderFactory.java +0 -25
  94. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountSpi.java +0 -50
  95. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProvider.java +0 -424
  96. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProviderFactory.java +0 -51
  97. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/Templates.java +0 -51
  98. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountBean.java +0 -91
  99. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountFederatedIdentityBean.java +0 -157
  100. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ApplicationsBean.java +0 -258
  101. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AuthorizationBean.java +0 -515
  102. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/FeaturesBean.java +0 -56
  103. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/LogBean.java +0 -95
  104. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/PasswordBean.java +0 -34
  105. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/RealmBean.java +0 -75
  106. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ReferrerBean.java +0 -38
  107. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/SessionsBean.java +0 -93
  108. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/TotpBean.java +0 -125
  109. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/UrlBean.java +0 -121
  110. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/AccountUrls.java +0 -115
  111. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormService.java +0 -1320
  112. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormServiceFactory.java +0 -64
  113. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountPages.java +0 -33
  114. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProvider.java +0 -76
  115. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProviderFactory.java +0 -25
  116. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountSpi.java +0 -50
  117. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProvider.java +0 -424
  118. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProviderFactory.java +0 -51
  119. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/Templates.java +0 -51
  120. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountBean.java +0 -91
  121. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountFederatedIdentityBean.java +0 -157
  122. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ApplicationsBean.java +0 -258
  123. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AuthorizationBean.java +0 -515
  124. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/FeaturesBean.java +0 -56
  125. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/LogBean.java +0 -95
  126. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/PasswordBean.java +0 -34
  127. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/RealmBean.java +0 -75
  128. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ReferrerBean.java +0 -38
  129. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/SessionsBean.java +0 -93
  130. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/TotpBean.java +0 -125
  131. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/UrlBean.java +0 -121
  132. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/AccountUrls.java +0 -115
  133. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormService.java +0 -1320
  134. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormServiceFactory.java +0 -64
@@ -36,113 +36,42 @@ export async function generateJavaStackFiles(params: {
36
36
  const pomFileCode = [
37
37
  `<?xml version="1.0"?>`,
38
38
  `<project xmlns="http://maven.apache.org/POM/4.0.0"`,
39
- ` xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"`,
40
- ` xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">`,
41
- ` <modelVersion>4.0.0</modelVersion>`,
39
+ ` xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"`,
40
+ ` xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">`,
41
+ ` <modelVersion>4.0.0</modelVersion>`,
42
42
  ` <groupId>${buildOptions.groupId}</groupId>`,
43
43
  ` <artifactId>${buildOptions.artifactId}</artifactId>`,
44
44
  ` <version>${buildOptions.themeVersion}</version>`,
45
45
  ` <name>${buildOptions.artifactId}</name>`,
46
- ` <description />`,
47
- ` <packaging>jar</packaging>`,
48
- ` <properties>`,
49
- ` <java.version>17</java.version>`,
50
- ` <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>`,
51
- ` <keycloak.version>999.0.0-SNAPSHOT</keycloak.version>`,
52
- ` <guava.version>32.0.0-jre</guava.version>`,
53
- ` <lombok.version>1.18.28</lombok.version>`,
54
- ` <auto-service.version>1.1.1</auto-service.version>`,
55
- ` </properties>`,
56
- ` <build>`,
57
- ` <plugins>`,
58
- ` <plugin>`,
59
- ` <artifactId>maven-compiler-plugin</artifactId>`,
60
- ` <version>3.11.0</version>`,
61
- ` <configuration>`,
62
- ` <source>\${java.version}</source>`,
63
- ` <target>\${java.version}</target>`,
64
- ` <compilerArgument>-Xlint:unchecked</compilerArgument>`,
65
- ` <compilerArgument>-Xlint:deprecation</compilerArgument>`,
66
- ` <useIncrementalCompilation>false</useIncrementalCompilation>`,
67
- ` <annotationProcessorPaths>`,
68
- ` <path>`,
69
- ` <groupId>com.google.auto.service</groupId>`,
70
- ` <artifactId>auto-service</artifactId>`,
71
- ` <version>\${auto-service.version}</version>`,
72
- ` </path>`,
73
- ` <path>`,
74
- ` <groupId>org.projectlombok</groupId>`,
75
- ` <artifactId>lombok</artifactId>`,
76
- ` <version>\${lombok.version}</version>`,
77
- ` </path>`,
78
- ` </annotationProcessorPaths>`,
79
- ` </configuration>`,
80
- ` </plugin>`,
81
- ` <plugin>`,
82
- ` <groupId>org.apache.maven.plugins</groupId>`,
83
- ` <artifactId>maven-jar-plugin</artifactId>`,
84
- ` <version>3.2.0</version>`,
85
- ` <configuration>`,
86
- ` <archive>`,
87
- ` <manifestEntries>`,
88
- ` <Dependencies>`,
89
- ` <![CDATA[org.keycloak.keycloak-common,org.keycloak.keycloak-core,org.keycloak.keycloak-server-spi,org.keycloak.keycloak-server-spi-private,org.keycloak.keycloak-services,com.google.guava]]>`,
90
- ` </Dependencies>`,
91
- ` </manifestEntries>`,
92
- ` </archive>`,
93
- ` </configuration>`,
94
- ` </plugin>`,
95
- ` <plugin>`,
96
- ` <groupId>com.spotify.fmt</groupId>`,
97
- ` <artifactId>fmt-maven-plugin</artifactId>`,
98
- ` <version>2.20</version>`,
99
- ` </plugin>`,
100
- ` </plugins>`,
101
- ` </build>`,
102
- ` <dependencies>`,
103
- ` <dependency>`,
104
- ` <groupId>org.projectlombok</groupId>`,
105
- ` <artifactId>lombok</artifactId>`,
106
- ` <version>\${lombok.version}</version>`,
107
- ` <scope>provided</scope>`,
108
- ` </dependency>`,
109
- ` <dependency>`,
110
- ` <groupId>com.google.auto.service</groupId>`,
111
- ` <artifactId>auto-service</artifactId>`,
112
- ` <version>\${auto-service.version}</version>`,
113
- ` <scope>provided</scope>`,
114
- ` </dependency>`,
115
- ` <dependency>`,
116
- ` <groupId>org.keycloak</groupId>`,
117
- ` <artifactId>keycloak-server-spi</artifactId>`,
118
- ` <version>\${keycloak.version}</version>`,
119
- ` <scope>provided</scope>`,
120
- ` </dependency>`,
121
- ` <dependency>`,
122
- ` <groupId>org.keycloak</groupId>`,
123
- ` <artifactId>keycloak-server-spi-private</artifactId>`,
124
- ` <version>\${keycloak.version}</version>`,
125
- ` <scope>provided</scope>`,
126
- ` </dependency>`,
127
- ` <dependency>`,
128
- ` <groupId>org.keycloak</groupId>`,
129
- ` <artifactId>keycloak-services</artifactId>`,
130
- ` <version>\${keycloak.version}</version>`,
131
- ` <scope>provided</scope>`,
132
- ` </dependency>`,
133
- ` <dependency>`,
134
- ` <groupId>jakarta.ws.rs</groupId>`,
135
- ` <artifactId>jakarta.ws.rs-api</artifactId>`,
136
- ` <version>3.1.0</version>`,
137
- ` <scope>provided</scope>`,
138
- ` </dependency>`,
139
- ` <dependency>`,
140
- ` <groupId>com.google.guava</groupId>`,
141
- ` <artifactId>guava</artifactId>`,
142
- ` <version>\${guava.version}</version>`,
143
- ` <scope>provided</scope>`,
144
- ` </dependency>`,
145
- ` </dependencies>`,
46
+ ` <description />`,
47
+ ` <packaging>jar</packaging>`,
48
+ ` <properties>`,
49
+ ` <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>`,
50
+ ` </properties>`,
51
+ ` <build>`,
52
+ ` <plugins>`,
53
+ ` <plugin>`,
54
+ ` <groupId>org.apache.maven.plugins</groupId>`,
55
+ ` <artifactId>maven-shade-plugin</artifactId>`,
56
+ ` <version>3.5.1</version>`,
57
+ ` <executions>`,
58
+ ` <execution>`,
59
+ ` <phase>package</phase>`,
60
+ ` <goals>`,
61
+ ` <goal>shade</goal>`,
62
+ ` </goals>`,
63
+ ` </execution>`,
64
+ ` </executions>`,
65
+ ` </plugin>`,
66
+ ` </plugins>`,
67
+ ` </build>`,
68
+ ` <dependencies>`,
69
+ ` <dependency>`,
70
+ ` <groupId>io.phasetwo.keycloak</groupId>`,
71
+ ` <artifactId>keycloak-account-v1</artifactId>`,
72
+ ` <version>0.1</version>`,
73
+ ` </dependency>`,
74
+ ` </dependencies>`,
146
75
  `</project>`
147
76
  ].join("\n");
148
77
 
@@ -1,5 +1,5 @@
1
1
  import * as fs from "fs";
2
- import { join as pathJoin } from "path";
2
+ import { join as pathJoin, relative as pathRelative, basename as pathBasename } from "path";
3
3
  import { assert } from "tsafe/assert";
4
4
  import { Reflect } from "tsafe/Reflect";
5
5
  import type { BuildOptions } from "./BuildOptions";
@@ -19,8 +19,8 @@ generateStartKeycloakTestingContainer.basename = "start_keycloak_testing_contain
19
19
  const containerName = "keycloak-testing-container";
20
20
 
21
21
  /** Files for being able to run a hot reload keycloak container */
22
- export function generateStartKeycloakTestingContainer(params: { keycloakVersion: string; buildOptions: BuildOptionsLike }) {
23
- const { keycloakVersion, buildOptions } = params;
22
+ export function generateStartKeycloakTestingContainer(params: { jarFilePath: string; keycloakVersion: string; buildOptions: BuildOptionsLike }) {
23
+ const { jarFilePath, keycloakVersion, buildOptions } = params;
24
24
 
25
25
  const themeRelativeDirPath = pathJoin("src", "main", "resources", "theme");
26
26
  const themeDirPath = pathJoin(buildOptions.keycloakifyBuildDirPath, themeRelativeDirPath);
@@ -40,12 +40,19 @@ export function generateStartKeycloakTestingContainer(params: { keycloakVersion:
40
40
  ` --name ${containerName} \\`,
41
41
  " -e KEYCLOAK_ADMIN=admin \\",
42
42
  " -e KEYCLOAK_ADMIN_PASSWORD=admin \\",
43
+ ` -v "${pathJoin(
44
+ "$(pwd)",
45
+ pathRelative(buildOptions.keycloakifyBuildDirPath, jarFilePath)
46
+ )}":"/opt/keycloak/providers/${pathBasename(jarFilePath)}" \\`,
43
47
  ...fs
44
48
  .readdirSync(themeDirPath)
45
49
  .filter(name => fs.lstatSync(pathJoin(themeDirPath, name)).isDirectory())
46
50
  .map(
47
51
  themeName =>
48
- ` -v "${pathJoin(".", themeRelativeDirPath, themeName).replace(/\\/g, "/")}":"/opt/keycloak/themes/${themeName}":rw \\`
52
+ ` -v "${pathJoin("$(pwd)", themeRelativeDirPath, themeName).replace(
53
+ /\\/g,
54
+ "/"
55
+ )}":"/opt/keycloak/themes/${themeName}":rw \\`
49
56
  ),
50
57
  ` -it quay.io/keycloak/keycloak:${keycloakVersion} \\`,
51
58
  ` start-dev --features=declarative-user-profile`,
@@ -1,6 +1,6 @@
1
1
  import { transformCodebase } from "../../tools/transformCodebase";
2
2
  import * as fs from "fs";
3
- import { join as pathJoin } from "path";
3
+ import { join as pathJoin, dirname as pathDirname } from "path";
4
4
  import { downloadBuiltinKeycloakTheme } from "../../download-builtin-keycloak-theme";
5
5
  import { resources_common, type ThemeType } from "../../constants";
6
6
  import { BuildOptions } from "../BuildOptions";
@@ -21,12 +21,36 @@ export async function downloadKeycloakStaticResources(
21
21
  keycloakVersion: string;
22
22
  usedResources: {
23
23
  resourcesCommonFilePaths: string[];
24
- resourcesFilePaths: string[];
25
24
  } | undefined;
26
25
  buildOptions: BuildOptionsLike;
27
26
  }
28
27
  ) {
29
- const { themeType, themeDirPath, keycloakVersion, usedResources, buildOptions } = params;
28
+ const { themeType, themeDirPath, keycloakVersion, buildOptions } = params;
29
+
30
+ // NOTE: Hack for 427
31
+ const usedResources = (() => {
32
+ const { usedResources } = params;
33
+
34
+ if (usedResources === undefined) {
35
+ return undefined;
36
+ }
37
+
38
+ assert(usedResources !== undefined);
39
+
40
+ return {
41
+ "resourcesCommonDirPaths": usedResources.resourcesCommonFilePaths.map(filePath => {
42
+ {
43
+ const splitArg = "/dist/";
44
+
45
+ if (filePath.includes(splitArg)) {
46
+ return filePath.split(splitArg)[0] + splitArg;
47
+ }
48
+ }
49
+
50
+ return pathDirname(filePath);
51
+ })
52
+ };
53
+ })();
30
54
 
31
55
  const tmpDirPath = pathJoin(
32
56
  themeDirPath,
@@ -43,17 +67,7 @@ export async function downloadKeycloakStaticResources(
43
67
 
44
68
  transformCodebase({
45
69
  "srcDirPath": pathJoin(tmpDirPath, "keycloak", themeType, "resources"),
46
- "destDirPath": resourcesPath,
47
- "transformSourceCode":
48
- usedResources === undefined
49
- ? undefined
50
- : ({ fileRelativePath, sourceCode }) => {
51
- if (!usedResources.resourcesFilePaths.includes(fileRelativePath)) {
52
- return undefined;
53
- }
54
-
55
- return { "modifiedSourceCode": sourceCode };
56
- }
70
+ "destDirPath": resourcesPath
57
71
  });
58
72
 
59
73
  transformCodebase({
@@ -63,7 +77,7 @@ export async function downloadKeycloakStaticResources(
63
77
  usedResources === undefined
64
78
  ? undefined
65
79
  : ({ fileRelativePath, sourceCode }) => {
66
- if (!usedResources.resourcesCommonFilePaths.includes(fileRelativePath)) {
80
+ if (usedResources.resourcesCommonDirPaths.find(dirPath => fileRelativePath.startsWith(dirPath)) === undefined) {
67
81
  return undefined;
68
82
  }
69
83
 
@@ -1,17 +1,15 @@
1
1
  import { crawl } from "../../tools/crawl";
2
- import { join as pathJoin } from "path";
2
+ import { join as pathJoin, sep as pathSep } from "path";
3
3
  import * as fs from "fs";
4
4
  import type { ThemeType } from "../../constants";
5
5
 
6
6
  /** Assumes the theme type exists */
7
7
  export function readStaticResourcesUsage(params: { keycloakifySrcDirPath: string; themeSrcDirPath: string; themeType: ThemeType }): {
8
8
  resourcesCommonFilePaths: string[];
9
- resourcesFilePaths: string[];
10
9
  } {
11
10
  const { keycloakifySrcDirPath, themeSrcDirPath, themeType } = params;
12
11
 
13
12
  const resourcesCommonFilePaths = new Set<string>();
14
- const resourcesFilePaths = new Set<string>();
15
13
 
16
14
  for (const srcDirPath of [pathJoin(keycloakifySrcDirPath, themeType), pathJoin(themeSrcDirPath, themeType)]) {
17
15
  const filePaths = crawl({ "dirPath": srcDirPath, "returnedPathsType": "absolute" }).filter(filePath => /\.(ts|tsx|js|jsx)$/.test(filePath));
@@ -26,58 +24,53 @@ export function readStaticResourcesUsage(params: { keycloakifySrcDirPath: string
26
24
  const wrap = readPaths({ rawSourceFile });
27
25
 
28
26
  wrap.resourcesCommonFilePaths.forEach(filePath => resourcesCommonFilePaths.add(filePath));
29
- wrap.resourcesFilePaths.forEach(filePath => resourcesFilePaths.add(filePath));
30
27
  }
31
28
  }
32
29
 
33
30
  return {
34
- "resourcesCommonFilePaths": Array.from(resourcesCommonFilePaths),
35
- "resourcesFilePaths": Array.from(resourcesFilePaths)
31
+ "resourcesCommonFilePaths": Array.from(resourcesCommonFilePaths)
36
32
  };
37
33
  }
38
34
 
39
35
  /** Exported for testing purpose */
40
36
  export function readPaths(params: { rawSourceFile: string }): {
41
37
  resourcesCommonFilePaths: string[];
42
- resourcesFilePaths: string[];
43
38
  } {
44
39
  const { rawSourceFile } = params;
45
40
 
46
41
  const resourcesCommonFilePaths = new Set<string>();
47
- const resourcesFilePaths = new Set<string>();
48
42
 
49
- for (const isCommon of [true, false]) {
50
- const set = isCommon ? resourcesCommonFilePaths : resourcesFilePaths;
43
+ {
44
+ const regexp = new RegExp(`resourcesCommonPath\\s*}([^\`]+)\``, "g");
51
45
 
52
- {
53
- const regexp = new RegExp(`resources${isCommon ? "Common" : ""}Path\\s*}([^\`]+)\``, "g");
46
+ const matches = [...rawSourceFile.matchAll(regexp)];
54
47
 
55
- const matches = [...rawSourceFile.matchAll(regexp)];
48
+ for (const match of matches) {
49
+ const filePath = match[1];
56
50
 
57
- for (const match of matches) {
58
- const filePath = match[1];
59
-
60
- set.add(filePath);
61
- }
51
+ resourcesCommonFilePaths.add(filePath);
62
52
  }
53
+ }
63
54
 
64
- {
65
- const regexp = new RegExp(`resources${isCommon ? "Common" : ""}Path\\s*[+,]\\s*["']([^"'\`]+)["'\`]`, "g");
55
+ {
56
+ const regexp = new RegExp(`resourcesCommonPath\\s*[+,]\\s*["']([^"'\`]+)["'\`]`, "g");
66
57
 
67
- const matches = [...rawSourceFile.matchAll(regexp)];
58
+ const matches = [...rawSourceFile.matchAll(regexp)];
68
59
 
69
- for (const match of matches) {
70
- const filePath = match[1];
60
+ for (const match of matches) {
61
+ const filePath = match[1];
71
62
 
72
- set.add(filePath);
73
- }
63
+ resourcesCommonFilePaths.add(filePath);
74
64
  }
75
65
  }
76
66
 
77
- const removePrefixSlash = (filePath: string) => (filePath.startsWith("/") ? filePath.slice(1) : filePath);
67
+ const normalizePath = (filePath: string) => {
68
+ filePath = filePath.startsWith("/") ? filePath.slice(1) : filePath;
69
+ filePath = filePath.replace(/\//g, pathSep);
70
+ return filePath;
71
+ };
78
72
 
79
73
  return {
80
- "resourcesCommonFilePaths": Array.from(resourcesCommonFilePaths).map(removePrefixSlash),
81
- "resourcesFilePaths": Array.from(resourcesFilePaths).map(removePrefixSlash)
74
+ "resourcesCommonFilePaths": Array.from(resourcesCommonFilePaths).map(normalizePath)
82
75
  };
83
76
  }
@@ -63,14 +63,14 @@ export async function main() {
63
63
  });
64
64
 
65
65
  if (buildOptions.doCreateJar) {
66
- child_process.execSync("mvn package", { "cwd": buildOptions.keycloakifyBuildDirPath });
66
+ child_process.execSync("mvn clean install", { "cwd": buildOptions.keycloakifyBuildDirPath });
67
67
  }
68
68
 
69
- // We want, however, to test in a container running the latest Keycloak version
70
- const containerKeycloakVersion = "21.1.2";
69
+ const containerKeycloakVersion = "23.0.0";
71
70
 
72
71
  generateStartKeycloakTestingContainer({
73
72
  "keycloakVersion": containerKeycloakVersion,
73
+ jarFilePath,
74
74
  buildOptions
75
75
  });
76
76
 
@@ -16,18 +16,25 @@ export function replaceImportsFromStaticInJsCode(params: { jsCode: string }): {
16
16
  const { jsCode } = params;
17
17
 
18
18
  const getReplaceArgs = (language: "js" | "css"): Parameters<typeof String.prototype.replace> => [
19
- new RegExp(`([a-zA-Z_]+)\\.([a-zA-Z]+)=function\\(([a-zA-Z]+)\\){return"static\\/${language}\\/"`, "g"),
20
- (...[, n, u, e]) => `
21
- ${n}[(function(){
22
- var pd= Object.getOwnPropertyDescriptor(${n}, "p");
19
+ new RegExp(`([a-zA-Z_]+)\\.([a-zA-Z]+)=(function\\(([a-z]+)\\){return|([a-z]+)=>)"static\\/${language}\\/"`, "g"),
20
+ (...[, n, u, matchedFunction, eForFunction]) => {
21
+ const isArrowFunction = matchedFunction.includes("=>");
22
+ const e = isArrowFunction ? matchedFunction.replace("=>", "").trim() : eForFunction;
23
+
24
+ return `
25
+ ${n}[(function(){
26
+ var pd = Object.getOwnPropertyDescriptor(${n}, "p");
23
27
  if( pd === undefined || pd.configurable ){
24
28
  Object.defineProperty(${n}, "p", {
25
29
  get: function() { return window.${ftlValuesGlobalName}.url.resourcesPath; },
26
- set: function (){}
30
+ set: function() {}
27
31
  });
28
32
  }
29
- return "${u}";
30
- })()] = function(${e}) { return "${true ? "/build/" : ""}static/${language}/"`
33
+ return "${u}";
34
+ })()] = ${isArrowFunction ? `${e} =>` : `function(${e}) { return `} "/build/static/${language}/"`
35
+ .replace(/\s+/g, " ")
36
+ .trim();
37
+ }
31
38
  ];
32
39
 
33
40
  const fixedJsCode = jsCode
@@ -23,24 +23,21 @@ export function usePrepareTemplate(params: {
23
23
  const removeArray: (() => void)[] = [];
24
24
 
25
25
  (async () => {
26
- const prLoadedArray: Promise<void>[] = [];
27
-
28
- styles.reverse().forEach(href => {
26
+ for (const style of [...styles].reverse()) {
29
27
  const { prLoaded, remove } = headInsert({
30
28
  "type": "css",
31
29
  "position": "prepend",
32
- href
30
+ "href": style
33
31
  });
34
32
 
35
33
  removeArray.push(remove);
36
34
 
37
- prLoadedArray.push(prLoaded);
38
- });
39
-
40
- await Promise.all(prLoadedArray);
35
+ // TODO: Find a way to do that in parallel (without breaking the order)
36
+ await prLoaded;
41
37
 
42
- if (isUnmounted) {
43
- return;
38
+ if (isUnmounted) {
39
+ return;
40
+ }
44
41
  }
45
42
 
46
43
  setReady();
@@ -12,6 +12,8 @@ const Error = lazy(() => import("keycloakify/login/pages/Error"));
12
12
  const LoginResetPassword = lazy(() => import("keycloakify/login/pages/LoginResetPassword"));
13
13
  const LoginVerifyEmail = lazy(() => import("keycloakify/login/pages/LoginVerifyEmail"));
14
14
  const Terms = lazy(() => import("keycloakify/login/pages/Terms"));
15
+ const LoginDeviceVerifyUserCode = lazy(() => import("keycloakify/login/pages/LoginDeviceVerifyUserCode"));
16
+ const LoginOauthGrant = lazy(() => import("keycloakify/login/pages/LoginOauthGrant"));
15
17
  const LoginOtp = lazy(() => import("keycloakify/login/pages/LoginOtp"));
16
18
  const LoginPassword = lazy(() => import("keycloakify/login/pages/LoginPassword"));
17
19
  const LoginUsername = lazy(() => import("keycloakify/login/pages/LoginUsername"));
@@ -52,6 +54,10 @@ export default function Fallback(props: PageProps<KcContext, I18n>) {
52
54
  return <LoginVerifyEmail kcContext={kcContext} {...rest} />;
53
55
  case "terms.ftl":
54
56
  return <Terms kcContext={kcContext} {...rest} />;
57
+ case "login-oauth2-device-verify-user-code.ftl":
58
+ return <LoginDeviceVerifyUserCode kcContext={kcContext} {...rest} />;
59
+ case "login-oauth-grant.ftl":
60
+ return <LoginOauthGrant kcContext={kcContext} {...rest} />;
55
61
  case "login-otp.ftl":
56
62
  return <LoginOtp kcContext={kcContext} {...rest} />;
57
63
  case "login-username.ftl":
@@ -38,7 +38,7 @@ export default function Template(props: TemplateProps<KcContext, I18n>) {
38
38
  `${url.resourcesPath}/css/login.css`
39
39
  ],
40
40
  "htmlClassName": getClassName("kcHtmlClass"),
41
- "bodyClassName": undefined
41
+ "bodyClassName": getClassName("kcBodyClass")
42
42
  });
43
43
 
44
44
  if (!isReady) {
@@ -21,6 +21,7 @@ export type TemplateProps<KcContext extends KcContext.Common, I18nExtended exten
21
21
  };
22
22
 
23
23
  export type ClassKey =
24
+ | "kcBodyClass"
24
25
  | "kcHtmlClass"
25
26
  | "kcLoginClass"
26
27
  | "kcHeaderClass"
@@ -93,4 +94,5 @@ export type ClassKey =
93
94
  | "kcSelectOTPListItemClass"
94
95
  | "kcAuthenticatorOtpCircleClass"
95
96
  | "kcSelectOTPItemHeadingClass"
96
- | "kcFormOptionsWrapperClass";
97
+ | "kcFormOptionsWrapperClass"
98
+ | "kcFormButtonsWrapperClass";
@@ -19,6 +19,8 @@ export type KcContext =
19
19
  | KcContext.LoginResetPassword
20
20
  | KcContext.LoginVerifyEmail
21
21
  | KcContext.Terms
22
+ | KcContext.LoginDeviceVerifyUserCode
23
+ | KcContext.LoginOauthGrant
22
24
  | KcContext.LoginOtp
23
25
  | KcContext.LoginUsername
24
26
  | KcContext.WebauthnAuthenticate
@@ -38,6 +40,7 @@ export type KcContext =
38
40
 
39
41
  export declare namespace KcContext {
40
42
  export type Common = {
43
+ themeVersion: string;
41
44
  keycloakifyVersion: string;
42
45
  themeType: "login";
43
46
  themeName: string;
@@ -242,6 +245,27 @@ export declare namespace KcContext {
242
245
  pageId: "terms.ftl";
243
246
  };
244
247
 
248
+ export type LoginDeviceVerifyUserCode = Common & {
249
+ pageId: "login-oauth2-device-verify-user-code.ftl";
250
+ url: {
251
+ oauth2DeviceVerificationAction: string;
252
+ };
253
+ };
254
+
255
+ export type LoginOauthGrant = Common & {
256
+ pageId: "login-oauth-grant.ftl";
257
+ oauth: {
258
+ code: string;
259
+ client: string;
260
+ clientScopesRequested: {
261
+ consentScreenText: string;
262
+ }[];
263
+ };
264
+ url: {
265
+ oauthAction: string;
266
+ };
267
+ };
268
+
245
269
  export type LoginOtp = Common & {
246
270
  pageId: "login-otp.ftl";
247
271
  otpLogin: {
@@ -105,6 +105,7 @@ const PUBLIC_URL = (typeof process !== "object" ? undefined : process.env?.["PUB
105
105
  const resourcesPath = pathJoin(PUBLIC_URL, keycloak_resources, "login", "resources");
106
106
 
107
107
  export const kcContextCommonMock: KcContext.Common = {
108
+ "themeVersion": "0.0.0",
108
109
  "keycloakifyVersion": "0.0.0",
109
110
  "themeType": "login",
110
111
  "themeName": "my-theme-name",
@@ -242,7 +243,9 @@ export const kcContextCommonMock: KcContext.Common = {
242
243
  const loginUrl = {
243
244
  ...kcContextCommonMock.url,
244
245
  "loginResetCredentialsUrl": "/auth/realms/myrealm/login-actions/reset-credentials?client_id=account&tab_id=HoAx28ja4xg",
245
- "registrationUrl": "/auth/realms/myrealm/login-actions/registration?client_id=account&tab_id=HoAx28ja4xg"
246
+ "registrationUrl": "/auth/realms/myrealm/login-actions/registration?client_id=account&tab_id=HoAx28ja4xg",
247
+ "oauth2DeviceVerificationAction": "/auth/realms/myrealm/device",
248
+ "oauthAction": "/auth/realms/myrealm/login-actions/consent?client_id=account&tab_id=HoAx28ja4xg"
246
249
  };
247
250
 
248
251
  export const kcContextMocks = [
@@ -346,6 +349,25 @@ export const kcContextMocks = [
346
349
  ...kcContextCommonMock,
347
350
  "pageId": "terms.ftl"
348
351
  }),
352
+ id<KcContext.LoginDeviceVerifyUserCode>({
353
+ ...kcContextCommonMock,
354
+ "pageId": "login-oauth2-device-verify-user-code.ftl",
355
+ url: loginUrl
356
+ }),
357
+ id<KcContext.LoginOauthGrant>({
358
+ ...kcContextCommonMock,
359
+ "pageId": "login-oauth-grant.ftl",
360
+ oauth: {
361
+ code: "5-1N4CIzfi1aprIQjmylI-9e3spLCWW9i5d-GDcs-Sw",
362
+ clientScopesRequested: [
363
+ { consentScreenText: "${profileScopeConsentText}" },
364
+ { consentScreenText: "${rolesScopeConsentText}" },
365
+ { consentScreenText: "${emailScopeConsentText}" }
366
+ ],
367
+ client: "account"
368
+ },
369
+ url: loginUrl
370
+ }),
349
371
  id<KcContext.LoginOtp>({
350
372
  ...kcContextCommonMock,
351
373
  "pageId": "login-otp.ftl",
@@ -3,6 +3,7 @@ import type { ClassKey } from "keycloakify/login/TemplateProps";
3
3
 
4
4
  export const { useGetClassName } = createUseClassName<ClassKey>({
5
5
  "defaultClasses": {
6
+ "kcBodyClass": undefined,
6
7
  "kcHtmlClass": "login-pf",
7
8
  "kcLoginClass": "login-pf-page",
8
9
  "kcContentWrapperClass": "row",
@@ -44,6 +45,7 @@ export const { useGetClassName } = createUseClassName<ClassKey>({
44
45
  "kcInputClass": "form-control",
45
46
  "kcInputErrorMessageClass": "pf-c-form__helper-text pf-m-error required kc-feedback-text",
46
47
  "kcInputWrapperClass": "col-xs-12 col-sm-12 col-md-12 col-lg-12",
48
+ "kcFormButtonsWrapperClass": undefined,
47
49
  "kcFormOptionsClass": "col-xs-12 col-sm-12 col-md-12 col-lg-12",
48
50
  "kcFormButtonsClass": "col-xs-12 col-sm-12 col-md-12 col-lg-12",
49
51
  "kcFormSettingClass": "login-pf-settings",
@@ -8,7 +8,10 @@ export default function Info(props: PageProps<Extract<KcContext, { pageId: "info
8
8
 
9
9
  const { msgStr, msg } = i18n;
10
10
 
11
- assert(kcContext.message !== undefined);
11
+ assert(
12
+ kcContext.message !== undefined,
13
+ "No message in kcContext.message, there will always be a message in production context, add it in your mock"
14
+ );
12
15
 
13
16
  const { messageHeader, message, requiredActions, skipLink, pageRedirectUri, actionUri, client } = kcContext;
14
17
 
@@ -32,7 +32,7 @@ export default function LoginConfigTotp(props: PageProps<Extract<KcContext, { pa
32
32
 
33
33
  <ul id="kc-totp-supported-apps">
34
34
  {totp.supportedApplications.map(app => (
35
- <li>{msgStr(app as MessageKey, app)}</li>
35
+ <li>{msg(app as MessageKey)}</li>
36
36
  ))}
37
37
  </ul>
38
38
  </li>