Compare commits

..

85 Commits

Author SHA1 Message Date
d18ebb45f8 Update changelog v4.8.2 2022-04-20 20:20:03 +00:00
d8e01f2c5d Bump version (changelog ignore) 2022-04-20 22:14:06 +02:00
4abbaa3841 Tell pepoles they can test with different keycloak version 2022-04-20 22:13:42 +02:00
42a463b348 Update changelog v4.8.1 2022-04-20 19:19:55 +00:00
8e15cf1d45 Bump version (changelog ignore) 2022-04-20 21:17:05 +02:00
2468b4108e Update changelog highlights 2022-04-20 21:15:58 +02:00
528b1bb607 Add missing shebang 2022-04-20 21:13:32 +02:00
b4449bb289 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-04-20 21:09:53 +02:00
737e00b490 Add video demo for npx download-builtin-keycloak-theme 2022-04-20 21:09:36 +02:00
55d4c7f4ab Update changelog v4.8.0 2022-04-20 18:59:10 +00:00
7afb078efd fmt (changelog ignore) 2022-04-20 20:55:53 +02:00
2c04f6c1e9 Bump version (changelog ignore) 2022-04-20 20:44:32 +02:00
2ad5ed7e73 Document email template customization feature #9 2022-04-20 20:44:31 +02:00
f2b7fe46a2 Add mention of download-builtin-keycloak-theme 2022-04-20 20:22:19 +02:00
1a1af62f62 Improve readme (changelog ignore) 2022-04-20 20:11:26 +02:00
98f715e652 Let the choice of kc version be auto in GH Action 2022-04-20 12:23:28 +02:00
fa5f1c230a Only test on node v15 and v14 (bellow is no longer supported (rmSync) 2022-04-20 11:59:19 +02:00
c92ae9cfa9 Fix broken link in readme (changelog ignore) 2022-04-20 11:43:15 +02:00
3dcb3a1a5b cange name of temp dir (changelog ignore) 2022-04-20 01:26:22 +02:00
efde71d07c Feature email customization #9 2022-04-20 00:39:40 +02:00
bff8cf2f32 Update README (changelog ignore) 2022-04-15 12:19:41 +02:00
72730135f1 Mention tested wit CRA 5.0.0 (changelog ignore) 2022-04-14 21:55:42 +02:00
50cf27b686 Mention test on Keycloak 17.0.1 (changelog ignore) 2022-04-14 21:53:27 +02:00
b293abffa4 Update changelog v4.7.6 2022-04-12 16:57:59 +00:00
be84ea299c Bump version (changelog ignore) 2022-04-12 18:51:30 +02:00
d54586426a Fix bugs with language switch #85 2022-04-12 18:51:03 +02:00
6ccf72c707 Update changelog v4.7.5 2022-04-09 20:28:23 +00:00
5817118461 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-04-09 22:25:51 +02:00
ebac1de111 Bump version (changelog ignore) 2022-04-09 22:25:43 +02:00
0d2f841b27 Fix #85 2022-04-09 22:25:20 +02:00
780ca383c9 Update changelog v4.7.4 2022-04-09 18:22:22 +00:00
a652a0f4f3 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-04-09 20:19:13 +02:00
5bdc812c43 Bump version (changelog ignore) 2022-04-09 20:19:07 +02:00
357bc8d19d M1 Mac compat (for real this time) 2022-04-09 20:18:42 +02:00
85b54ac011 Update changelog v4.7.3 2022-04-09 20:17:55 +02:00
17f888019c Update changelog v4.7.2 2022-04-09 20:17:55 +02:00
947fd0564e Update changelog v4.7.3 2022-04-08 13:04:37 +00:00
bd51d02902 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-04-08 15:01:47 +02:00
36d75c8641 Bump version (changelog ignore) 2022-04-08 15:01:39 +02:00
c75f158b48 Mention that there is still problems with M1 Mac 2022-04-08 15:01:21 +02:00
bb37ce9cef Update changelog v4.7.2 2022-04-06 23:41:42 +00:00
77ff33570d Bump version (changelog ignore) 2022-04-07 01:39:03 +02:00
20383d60a9 #43: M1 Mac support 2022-04-07 01:38:58 +02:00
79aa5ac5f2 Update changelog v4.7.1 2022-03-30 14:23:41 +00:00
8be6c0d1d2 Bump version (changelog ignore) 2022-03-30 16:20:34 +02:00
7f5a9e77de Improve browser autofill 2022-03-30 16:20:14 +02:00
ff19ab8b08 factorization 2022-03-30 14:01:10 +02:00
63dcb2ad39 Update changelog v4.7.0 2022-03-17 23:49:31 +00:00
795e8ed0e5 Bump version (changelog ignore) 2022-03-18 00:46:40 +01:00
bccb56ed61 Add support for options validator 2022-03-18 00:46:12 +01:00
02e2ad89ec remove duplicate dependency 2022-03-18 00:41:29 +01:00
a236e2e5de Update changelog v4.6.0 2022-03-07 00:53:27 +00:00
ba294c85f8 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2022-03-07 01:50:38 +01:00
beb3dca495 Bump version (changelog ignore) 2022-03-07 01:50:25 +01:00
04101536c6 Remove powerhooks as dev dependency 2022-03-07 01:43:31 +01:00
2912e7e5dd Update changelog v4.5.5 2022-03-07 00:18:43 +00:00
bf6fadbde8 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2022-03-07 01:16:01 +01:00
001b49d09a Bump version (changelog ignore) 2022-03-07 01:15:52 +01:00
bbd5bdda95 Update tss-react 2022-03-07 01:15:36 +01:00
7e950e8e2b Update changelog v4.5.4 2022-03-06 23:33:45 +00:00
8b0efbc737 Bump version (changelog ignore) 2022-03-07 00:31:08 +01:00
93cfbd6696 Remove tss-react from peerDependencies (it becomes a dependency) 2022-03-07 00:30:44 +01:00
acc1d028ab Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2022-02-18 21:00:56 +01:00
3476b5acc3 (dev script) Use tsconfig.json to tell we are at the root of the project 2022-02-18 21:00:44 +01:00
72ca5da842 Update changelog v4.5.3 2022-01-26 15:33:05 +00:00
e214280fcd Rephrase (changelog ignore) 2022-01-26 10:42:45 +01:00
bf32987a3e Bump version (changelog ignore) 2022-01-26 10:40:36 +01:00
8941fe230b Themes no longer have to break on minor Keycloakify update 2022-01-26 10:40:08 +01:00
b6d4abee21 Update cover image (changelog ignore) 2022-01-25 23:20:26 +01:00
786bdc41c2 Update changelog v4.5.2 2022-01-20 01:57:57 +00:00
ed9f08f678 Update ..prettierignore (changelog ignore) 2022-01-20 02:55:14 +01:00
33fd6768f1 Bump version (changelog ignore) 2022-01-20 02:53:42 +01:00
87b8456531 Test container uses Keycloak 16.1.0 2022-01-20 02:52:31 +01:00
a12bde4656 Merge pull request #78 from InseeFrLab/Ann2827/pull
Ann2827/pull
2022-01-20 01:50:37 +01:00
6f219a4c2a Refactor #78 2022-01-20 01:49:35 +01:00
49d7818b64 Merge branch 'Ann2827/pull' of https://github.com/InseeFrLab/keycloakify into Ann2827/pull 2022-01-20 01:35:36 +01:00
fb0be3272c Compat with Keycloak 16 (and probably 17, 18) #79 2022-01-20 01:34:26 +01:00
994f7d6bea Warning about compat issues with Keycloak 16 2022-01-19 16:11:40 +01:00
6e8dcecaf1 Fix CI (changelog ignore) 2022-01-19 01:29:06 +01:00
40237374a8 Bump beta version (changelog ignore)
Signed-off-by: garronej <joseph.garrone.gj@gmail.com>
2022-01-18 23:59:49 +01:00
3d98860369 fix: changes 2022-01-19 01:35:37 +03:00
804fe33665 fix: Errors on pages login-idp-link-confirm and login-idp-link-email
ref: https://github.com/InseeFrLab/keycloakify/issues/75
2022-01-19 01:26:36 +03:00
703171f96b Merge branch 'InseeFrLab-main' into pull 2022-01-19 01:14:41 +03:00
27bdefeea8 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into InseeFrLab-main 2022-01-19 01:13:36 +03:00
29fbcdc0a6 fix: errors in common.ftl
ref: https://github.com/InseeFrLab/keycloakify/issues/58
2021-12-08 10:30:36 +03:00
36 changed files with 892 additions and 1588 deletions

View File

@ -27,12 +27,12 @@ jobs:
needs: test_formatting
strategy:
matrix:
node: [ '15', '14', '13' ]
node: [ '15', '14' ]
name: Test with Node v${{ matrix.node }}
steps:
- name: Tell if project is using npm or yarn
id: step1
uses: garronej/ts-ci@v1.1.3
uses: garronej/ts-ci@v1.1.6
with:
action_name: tell_if_project_uses_npm_or_yarn
- uses: actions/checkout@v2.3.4
@ -64,7 +64,7 @@ jobs:
is_upgraded_version: ${{ steps.step1.outputs.is_upgraded_version }}
is_release_beta: ${{steps.step1.outputs.is_release_beta }}
steps:
- uses: garronej/ts-ci@v1.1.3
- uses: garronej/ts-ci@v1.1.6
id: step1
with:
action_name: is_package_json_version_upgraded
@ -75,7 +75,7 @@ jobs:
needs: check_if_version_upgraded
if: needs.check_if_version_upgraded.outputs.is_upgraded_version == 'true'
steps:
- uses: garronej/ts-ci@v1.1.3
- uses: garronej/ts-ci@v1.1.6
with:
action_name: update_changelog
branch: ${{ github.head_ref || github.ref }}

2
.gitignore vendored
View File

@ -46,3 +46,5 @@ jspm_packages
/.yarn_home/
.idea
/keycloak_theme_email

View File

@ -3,4 +3,5 @@ node_modules/
/CHANGELOG.md
/.yarn_home/
/src/test/apps/
/src/tools/types/
/src/tools/types/
/sample_react_project

View File

@ -1,3 +1,81 @@
### **4.8.2** (2022-04-20)
- Tell pepoles they can test with different keycloak version
### **4.8.1** (2022-04-20)
- Add missing shebang
- Add video demo for npx download-builtin-keycloak-theme
## **4.8.0** (2022-04-20)
- Document email template customization feature #9
- Add mention of download-builtin-keycloak-theme
- Let the choice of kc version be auto in GH Action
- Only test on node v15 and v14 (bellow is no longer supported (rmSync)
- Feature email customization #9
### **4.7.6** (2022-04-12)
- Fix bugs with language switch #85
### **4.7.5** (2022-04-09)
- Fix #85
### **4.7.4** (2022-04-09)
- M1 Mac compat (for real this time)
### **4.7.3** (2022-04-08)
- Mention that there is still problems with M1 Mac
### **4.7.2** (2022-04-06)
- #43: M1 Mac support
### **4.7.1** (2022-03-30)
- Improve browser autofill
- factorization
## **4.7.0** (2022-03-17)
- Add support for options validator
- remove duplicate dependency
## **4.6.0** (2022-03-07)
- Remove powerhooks as dev dependency
### **4.5.5** (2022-03-07)
- Update tss-react
### **4.5.4** (2022-03-06)
- Remove tss-react from peerDependencies (it becomes a dependency)
- (dev script) Use tsconfig.json to tell we are at the root of the project
### **4.5.3** (2022-01-26)
- Themes no longer have to break on minor Keycloakify update
### **4.5.2** (2022-01-20)
- Test container uses Keycloak 16.1.0
- Merge pull request #78 from InseeFrLab/Ann2827/pull
Ann2827/pull
- Refactor #78
- Compat with Keycloak 16 (and probably 17, 18) #79
- Warning about compat issues with Keycloak 16
- fix: changes
- fix: Errors on pages login-idp-link-confirm and login-idp-link-email
ref: https://github.com/InseeFrLab/keycloakify/issues/75
### **4.5.1** (2022-01-18)
- fix previous version

View File

@ -25,15 +25,13 @@
</a>
</p>
> New with v4.8.0: [Email template customization.](#email-template-customization)
<p align="center">
<i>Ultimately this build tool generates a Keycloak theme</i>
<img src="https://user-images.githubusercontent.com/6702424/110260457-a1c3d380-7fac-11eb-853a-80459b65626b.png">
</p>
> **New in v4.4.0**: Feature [`login-page-expired.ftl`](https://user-images.githubusercontent.com/6702424/147856832-38c042a7-9fc8-473f-9595-e00123095ca6.png).
> Every time a page is added it's a breaking change for non CSS-only theme.
> Change [this](https://github.com/garronej/keycloakify-demo-app/blob/812754109c61157741f4a0b222026deb1538a02d/src/KcApp/KcApp.tsx#L18) and [this](https://github.com/garronej/keycloakify-demo-app/blob/812754109c61157741f4a0b222026deb1538a02d/src/KcApp/KcApp.tsx#L39) to update.
# Motivations
Keycloak provides [theme support](https://www.keycloak.org/docs/latest/server_development/#_themes) for web pages. This allows customizing the look and feel of end-user facing pages so they can be integrated with your applications.
@ -74,6 +72,7 @@ If you already have a Keycloak custom theme, it can be easily ported to Keycloak
- [Advanced pages configuration](#advanced-pages-configuration)
- [Hot reload](#hot-reload)
- [Enable loading in a blink of an eye of login pages ⚡ (--external-assets)](#enable-loading-in-a-blink-of-an-eye-of-login-pages----external-assets)
- [Email template customization.](#email-template-customization)
- [User profile and frontend form validation](#user-profile-and-frontend-form-validation)
- [Support for Terms and conditions](#support-for-terms-and-conditions)
- [Some pages still have the default theme. Why?](#some-pages-still-have-the-default-theme-why)
@ -87,8 +86,16 @@ If you already have a Keycloak custom theme, it can be easily ported to Keycloak
- [Kickstart video](#kickstart-video)
- [FTL errors related to `ftl_object_to_js_code_declaring_an_object` in Keycloak logs.](#ftl-errors-related-to-ftl_object_to_js_code_declaring_an_object-in-keycloak-logs)
- [Adding custom message (to `i18n/useKcMessage.tsx`)](#adding-custom-message-to-i18nusekcmessagetsx)
- [Downloading builtin theme resource files](#downloading-builtin-theme-resource-files)
- [Email domain whitelist](#email-domain-whitelist)
- [Changelog highlights](#changelog-highlights)
- [v4.8.0](#v480)
- [v4.7.4](#v474)
- [v4.7.2](#v472)
- [v4.7.0](#v470)
- [v4.6.0](#v460)
- [v4.5.3](#v453)
- [v4.3.0](#v430)
- [v4](#v4)
- [v3](#v3)
- [v2.5](#v25)
@ -96,13 +103,15 @@ If you already have a Keycloak custom theme, it can be easily ported to Keycloak
# Requirements
On Windows OS you'll have to use [WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10). More info [here](https://github.com/InseeFrLab/keycloakify/issues/54%23issuecomment-984834217)
On Windows OS you'll have to use [WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10). More info [here](https://github.com/InseeFrLab/keycloakify/issues/54#issuecomment-984834217)
Tested with the following Keycloak versions:
- [11.0.3](https://hub.docker.com/layers/jboss/keycloak/11.0.3/images/sha256-4438f1e51c1369371cb807dffa526e1208086b3ebb9cab009830a178de949782?context=explore)
- [12.0.4](https://hub.docker.com/layers/jboss/keycloak/12.0.4/images/sha256-67e0c88e69bd0c7aef972c40bdeb558a974013a28b3668ca790ed63a04d70584?context=explore)
- [15.0.2](https://hub.docker.com/layers/jboss/keycloak/15.0.2/images/sha256-d8ed1ee5df42a178c341f924377da75db49eab08ea9f058ff39a8ed7ee05ec93?context=explore)
- [16.1.0](https://hub.docker.com/layers/jboss/keycloak/16.1.0/images/sha256-6ecb9492224c6cfbb55d43f64a5ab634145d8cc1eba14eae8c37e3afde89546e?context=explore)
- 17.0.1
This tool will be maintained to stay compatible with Keycloak v11 and up, however, the default pages you will get
(before you customize it) will always be the ones of Keycloak v11.
@ -112,27 +121,27 @@ It assumes there is a `build/` directory at the root of your react project direc
and a `build/static/` directory generated by webpack.
For more information see [this issue](https://github.com/InseeFrLab/keycloakify/issues/5#issuecomment-832296432)
**All this is defaults with [`create-react-app`](https://create-react-app.dev)** (tested with 4.0.3)
**All this is defaults with [`create-react-app`](https://create-react-app.dev)** (tested with 5.0.0, 4.0.3)
- `mvn` ([Maven](https://maven.apache.org/)), `rm`, `mkdir`, `curl`, `unzip` are assumed to be available.
- `docker` must be up and running when running `start_keycloak_testing_container.sh` (Instructions provided after running `yarn keycloak`).
## My framework doesnt seem to be supported, what can I do?
Currently Keycloakify is only compatible with `create-react-app` apps.
Currently Keycloakify is only compatible with SPA React apps.
It doesnt mean that you can't use Keycloakify if you are using Next.js, Express or any other
framework that involves SSR but your Keycloak theme will need to be a standalone project.
framework that involves a server but your Keycloak theme will need to be a standalone project.
Find specific instructions about how to get started [**here**](https://github.com/garronej/keycloakify-demo-app#keycloak-theme-only).
To share your styles between your main app and your login pages you will need to externalize your design system by making it a
separate module. Checkout [ts_ci](https://github.com/garronej/ts_ci), it can help with that.
separate module. Checkout [ts_ci](https://github.com/garronej/ts_ci), it can help with that (example with [our design system](https://github.com/InseeFrLab/onyxia-ui)).
# How to use
## Setting up the build tool
```bash
yarn add keycloakify @emotion/react tss-react powerhooks
yarn add keycloakify @emotion/react
```
[`package.json`](https://github.com/garronej/keycloakify-demo-app/blob/main/package.json)
@ -256,8 +265,6 @@ WARNING: If you chose to go this way use:
}
```
in your `package.json` instead of `^X.Y.Z`. A minor update of Keycloakify might break your app.
### Hot reload
Rebuild the theme each time you make a change to see the result is not practical.
@ -304,6 +311,19 @@ performance boost if you jump through those hoops:
Checkout a complete setup [here](https://github.com/garronej/keycloakify-demo-app#about-keycloakify)
# Email template customization.
_Introduced in [v4.8.0](https://github.com/InseeFrLab/keycloakify/releases/tag/v4.8.0)_
It is now possible to customize the emails sent to your users to confirm their email address ect.
Just run `npx create-keycloak-theme-email-directory`, it will create a `keycloak_theme_email` directory
at the root of your project.
This directory should be tracked by Git (`yarn add -A`)
You can start hacking the default template.
When `npx build-keycloak-theme` (`yarn keycloak`) is run. If the directory `keycloak_theme_email` exists
at the root of your project, it will be bundled into your `.jar` file and you will be able to select
it [in the Keycloak administration pages](https://user-images.githubusercontent.com/6702424/164299589-75f8008b-b24e-4836-ad6b-72149bb55621.png).
# User profile and frontend form validation
<p align="center">
@ -359,7 +379,7 @@ the building and publishing of the theme (the .jar file).
## `process.env.PUBLIC_URL` not supported.
You won't be able to [import things from your public directory **in your JavaScript code**](https://create-react-app.dev/docs/using-the-public-folder/#adding-assets-outside-of-the-module-system).
You won't be able to [import things from your public directory **in your JavaScript code** (it's supported in `public/index.html`)](https://create-react-app.dev/docs/using-the-public-folder/#adding-assets-outside-of-the-module-system).
(This isn't recommended anyway).
## `@font-face` importing fonts from the `src/` dir
@ -469,6 +489,13 @@ You can reproduce [this approach](https://github.com/garronej/keycloakify-demo-a
( don't forget to [evaluate the code](https://github.com/garronej/keycloakify-demo-app/blob/0a6d349dba89a5702f98ba48bca6c76ac7265e1f/src/index.tsx#L15) ).
This approach is a bit hacky as it doesn't provide type safety but it works.
# Downloading builtin theme resource files
Running `npx download-builtin-keycloak-theme` will let you download the themes that comes by default with
a Keycloak version of your choosing.
[Video demo](https://user-images.githubusercontent.com/6702424/164304458-934b0e1d-9de7-4bb4-8a1c-e06a70b1636a.mov)
# Email domain whitelist
NOTE: This have been kind of deprecated by [user attribute](#user-profile-and-frontend-form-validation) you could
@ -479,9 +506,41 @@ and `kcRegisterContext["authorizedMailDomains"]` to validate on.
# Changelog highlights
> **New in v4.3.0**: Feature [`login-update-password.ftl`](https://user-images.githubusercontent.com/6702424/147517600-6191cf72-93dd-437b-a35c-47180142063e.png).
> Every time a page is added it's a breaking change for non CSS-only theme.
> Change [this](https://github.com/garronej/keycloakify-demo-app/blob/df664c13c77ce3c53ac7df0622d94d04e76d3f9f/src/KcApp/KcApp.tsx#L17) and [this](https://github.com/garronej/keycloakify-demo-app/blob/df664c13c77ce3c53ac7df0622d94d04e76d3f9f/src/KcApp/KcApp.tsx#L37) to update.
## v4.8.0
[Email template customization.](#email-template-customization)
## v4.7.4
**M1 Mac** support (for testing locally with a dockerized Keycloak).
## v4.7.2
> WARNING: This is broken.
> Testing with local Keycloak container working with M1 Mac. Thanks to [@eduardosanzb](https://github.com/InseeFrLab/keycloakify/issues/43#issuecomment-975699658).
> Be aware: When running M1s you are testing with Keycloak v15 else the local container spun will be a Keycloak v16.1.0.
## v4.7.0
Register with user profile enabled: Out of the box `options` validator support.
[Example](https://user-images.githubusercontent.com/6702424/158911163-81e6bbe8-feb0-4dc8-abff-de199d7a678e.mov)
## v4.6.0
`tss-react` and `powerhooks` are no longer peer dependencies of `keycloakify`.
After updating Keycloakify you can remove `tss-react` and `powerhooks` from your dependencies if you don't use them explicitly.
## v4.5.3
There is a new recommended way to setup highly customized theme. See [here](https://github.com/garronej/keycloakify-demo-app/blob/look_and_feel/src/KcApp/KcApp.tsx).
Unlike with [the previous recommended method](https://github.com/garronej/keycloakify-demo-app/blob/a51660578bea15fb3e506b8a2b78e1056c6d68bb/src/KcApp/KcApp.tsx),
with this new method your theme wont break on minor Keycloakify update.
## v4.3.0
Feature [`login-update-password.ftl`](https://user-images.githubusercontent.com/6702424/147517600-6191cf72-93dd-437b-a35c-47180142063e.png).
Every time a page is added it's a breaking change for non CSS-only theme.
Change [this](https://github.com/garronej/keycloakify-demo-app/blob/df664c13c77ce3c53ac7df0622d94d04e76d3f9f/src/KcApp/KcApp.tsx#L17) and [this](https://github.com/garronej/keycloakify-demo-app/blob/df664c13c77ce3c53ac7df0622d94d04e76d3f9f/src/KcApp/KcApp.tsx#L37) to update.
## v4

View File

@ -1,6 +1,6 @@
{
"name": "keycloakify",
"version": "4.5.1",
"version": "4.8.2",
"description": "Keycloak theme generator for Reacts app",
"repository": {
"type": "git",
@ -22,6 +22,7 @@
},
"bin": {
"build-keycloak-theme": "dist/bin/build-keycloak-theme/index.js",
"create-keycloak-theme-email-directory": "dist/bin/create-keycloak-theme-email-directory.js",
"download-builtin-keycloak-theme": "dist/bin/download-builtin-keycloak-theme.js"
},
"lint-staged": {
@ -56,32 +57,32 @@
"homepage": "https://github.com/garronej/keycloakify",
"peerDependencies": {
"@emotion/react": "^11.4.1",
"powerhooks": "^0.10.0",
"react": "^16.8.0 || ^17.0.0",
"tss-react": "^1.1.0 || ^3.0.0"
"react": "^16.8.0 || ^17.0.0"
},
"devDependencies": {
"@emotion/react": "^11.4.1",
"@types/node": "^10.0.0",
"@types/node": "^17.0.25",
"@types/react": "^17.0.0",
"copyfiles": "^2.4.1",
"husky": "^4.3.8",
"lint-staged": "^11.0.0",
"powerhooks": "^0.11.0",
"prettier": "^2.3.0",
"properties-parser": "^0.3.1",
"react": "^17.0.1",
"rimraf": "^3.0.2",
"tss-react": "^3.0.0",
"typescript": "^4.2.3"
},
"dependencies": {
"@octokit/rest": "^18.12.0",
"cheerio": "^1.0.0-rc.5",
"cli-select": "^1.1.2",
"evt": "2.0.0-beta.39",
"minimal-polyfills": "^2.2.1",
"path-browserify": "^1.0.1",
"powerhooks": "^0.14.0",
"react-markdown": "^5.0.3",
"scripting-tools": "^0.19.13",
"tsafe": "^0.9.0"
"tsafe": "^0.9.0",
"tss-react": "^3.5.2"
}
}

View File

@ -1,3 +0,0 @@
export const keycloakVersions = ["11.0.3", "15.0.2"] as const;
export type KeycloakVersion = typeof keycloakVersions[number];

View File

@ -2,7 +2,7 @@ import { generateKeycloakThemeResources } from "./generateKeycloakThemeResources
import { generateJavaStackFiles } from "./generateJavaStackFiles";
import { join as pathJoin, relative as pathRelative, basename as pathBasename } from "path";
import * as child_process from "child_process";
import { generateDebugFiles, containerLaunchScriptBasename } from "./generateDebugFiles";
import { generateStartKeycloakTestingContainer } from "./generateStartKeycloakTestingContainer";
import { URL } from "url";
import * as fs from "fs";
@ -19,6 +19,7 @@ const doUseExternalAssets = process.argv[2]?.toLowerCase() === "--external-asset
const parsedPackageJson: ParsedPackageJson = require(pathJoin(reactProjectDirPath, "package.json"));
export const keycloakThemeBuildingDirPath = pathJoin(reactProjectDirPath, "build_keycloak");
export const keycloakThemeEmailDirPath = pathJoin(keycloakThemeBuildingDirPath, "..", "keycloak_theme_email");
function sanitizeThemeName(name: string) {
return name
@ -34,8 +35,9 @@ export function main() {
const extraThemeProperties: string[] = (parsedPackageJson as any)["keycloakify"]?.["extraThemeProperties"] ?? [];
const themeName = sanitizeThemeName(parsedPackageJson.name);
generateKeycloakThemeResources({
const { doBundleEmailTemplate } = generateKeycloakThemeResources({
keycloakThemeBuildingDirPath,
keycloakThemeEmailDirPath,
"reactAppBuildDirPath": pathJoin(reactProjectDirPath, "build"),
themeName,
...(() => {
@ -72,26 +74,30 @@ export function main() {
extraPagesId,
extraThemeProperties,
//We have to leave it at that otherwise we break our default theme.
//Problem is that we can't guarantee that the the old resources common
//Problem is that we can't guarantee that the the old resources
//will still be available on the newer keycloak version.
"keycloakVersion": "11.0.3",
});
const { jarFilePath } = generateJavaStackFiles({
version: parsedPackageJson.version,
"version": parsedPackageJson.version,
themeName,
homepage: parsedPackageJson.homepage,
"homepage": parsedPackageJson.homepage,
keycloakThemeBuildingDirPath,
doBundleEmailTemplate,
});
child_process.execSync("mvn package", {
"cwd": keycloakThemeBuildingDirPath,
});
generateDebugFiles({
//We want, however to test in a container running the latest Keycloak version
const containerKeycloakVersion = "18.0.0";
generateStartKeycloakTestingContainer({
keycloakThemeBuildingDirPath,
themeName,
"keycloakVersion": "15.0.2",
"keycloakVersion": containerKeycloakVersion,
});
console.log(
@ -128,12 +134,14 @@ export function main() {
" value: -Dkeycloak.profile=preview",
"",
"",
"To test your theme locally, with hot reloading, you can spin up a Keycloak container image with the theme loaded by running:",
`To test your theme locally you can spin up a Keycloak ${containerKeycloakVersion} container image with the theme pre loaded by running:`,
"",
`👉 $ ./${pathRelative(reactProjectDirPath, pathJoin(keycloakThemeBuildingDirPath, containerLaunchScriptBasename))} 👈`,
`👉 $ ./${pathRelative(reactProjectDirPath, pathJoin(keycloakThemeBuildingDirPath, generateStartKeycloakTestingContainer.basename))} 👈`,
"",
"Test with different Keycloak versions by editing the .sh file. see available versions here: https://quay.io/repository/keycloak/keycloak?tab=tags",
"",
"Once your container is up and running: ",
"- Log into the admin console 👉 http://localhost:8080 username: admin, password: admin 👈",
"- Log into the admin console 👉 http://localhost:8080/admin username: admin, password: admin 👈",
'- Create a realm named "myrealm"',
'- Create a client with id "myclient" and root url: "https://www.keycloak.org/app/"',
`- Select Login Theme: ${themeName} (don't forget to save at the bottom of the page)`,

View File

@ -1,84 +0,0 @@
import * as fs from "fs";
import { join as pathJoin, dirname as pathDirname } from "path";
export const containerLaunchScriptBasename = "start_keycloak_testing_container.sh";
/** Files for being able to run a hot reload keycloak container */
export function generateDebugFiles(params: { keycloakVersion: "11.0.3" | "15.0.2"; themeName: string; keycloakThemeBuildingDirPath: string }) {
const { themeName, keycloakThemeBuildingDirPath, keycloakVersion } = params;
fs.writeFileSync(
pathJoin(keycloakThemeBuildingDirPath, "Dockerfile"),
Buffer.from(
[
`FROM jboss/keycloak:${keycloakVersion}`,
"",
"USER root",
"",
"WORKDIR /",
"",
"ADD configuration /opt/jboss/keycloak/standalone/configuration/",
"",
'ENTRYPOINT [ "/opt/jboss/tools/docker-entrypoint.sh" ]',
].join("\n"),
"utf8",
),
);
const dockerImage = `${themeName}/keycloak-hot-reload`;
const containerName = "keycloak-testing-container";
fs.writeFileSync(
pathJoin(keycloakThemeBuildingDirPath, containerLaunchScriptBasename),
Buffer.from(
[
"#!/bin/bash",
"",
`cd ${keycloakThemeBuildingDirPath}`,
"",
`docker rm ${containerName} || true`,
"",
`docker build . -t ${dockerImage}`,
"",
"docker run \\",
" -p 8080:8080 \\",
` --name ${containerName} \\`,
" -e KEYCLOAK_USER=admin \\",
" -e KEYCLOAK_PASSWORD=admin \\",
" -e JAVA_OPTS=-Dkeycloak.profile=preview \\",
` -v ${pathJoin(
keycloakThemeBuildingDirPath,
"src",
"main",
"resources",
"theme",
themeName,
)}:/opt/jboss/keycloak/themes/${themeName}:rw \\`,
` -it ${dockerImage}:latest`,
"",
].join("\n"),
"utf8",
),
{ "mode": 0o755 },
);
const standaloneHaFilePath = pathJoin(keycloakThemeBuildingDirPath, "configuration", `standalone-ha.xml`);
try {
fs.mkdirSync(pathDirname(standaloneHaFilePath));
} catch {}
fs.writeFileSync(
standaloneHaFilePath,
fs
.readFileSync(pathJoin(__dirname, `standalone-ha_${keycloakVersion}.xml`))
.toString("utf8")
.replace(
new RegExp(
["<staticMaxAge>2592000</staticMaxAge>", "<cacheThemes>true</cacheThemes>", "<cacheTemplates>true</cacheTemplates>"].join("\\s*"),
"g",
),
["<staticMaxAge>-1</staticMaxAge>", "<cacheThemes>false</cacheThemes>", "<cacheTemplates>false</cacheTemplates>"].join("\n"),
),
);
}

View File

@ -1 +0,0 @@
export * from "./generateDebugFiles";

View File

@ -1,666 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<server xmlns="urn:jboss:domain:13.0">
<extensions>
<extension module="org.jboss.as.clustering.infinispan"/>
<extension module="org.jboss.as.clustering.jgroups"/>
<extension module="org.jboss.as.connector"/>
<extension module="org.jboss.as.deployment-scanner"/>
<extension module="org.jboss.as.ee"/>
<extension module="org.jboss.as.ejb3"/>
<extension module="org.jboss.as.jaxrs"/>
<extension module="org.jboss.as.jmx"/>
<extension module="org.jboss.as.jpa"/>
<extension module="org.jboss.as.logging"/>
<extension module="org.jboss.as.mail"/>
<extension module="org.jboss.as.modcluster"/>
<extension module="org.jboss.as.naming"/>
<extension module="org.jboss.as.remoting"/>
<extension module="org.jboss.as.security"/>
<extension module="org.jboss.as.transactions"/>
<extension module="org.jboss.as.weld"/>
<extension module="org.keycloak.keycloak-server-subsystem"/>
<extension module="org.wildfly.extension.bean-validation"/>
<extension module="org.wildfly.extension.core-management"/>
<extension module="org.wildfly.extension.elytron"/>
<extension module="org.wildfly.extension.io"/>
<extension module="org.wildfly.extension.microprofile.config-smallrye"/>
<extension module="org.wildfly.extension.microprofile.health-smallrye"/>
<extension module="org.wildfly.extension.microprofile.metrics-smallrye"/>
<extension module="org.wildfly.extension.request-controller"/>
<extension module="org.wildfly.extension.security.manager"/>
<extension module="org.wildfly.extension.undertow"/>
</extensions>
<management>
<security-realms>
<security-realm name="ManagementRealm">
<authentication>
<local default-user="$local" skip-group-loading="true"/>
<properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/>
</authentication>
<authorization map-groups-to-roles="false">
<properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
</authorization>
</security-realm>
<security-realm name="ApplicationRealm">
<server-identities>
<ssl>
<keystore path="application.keystore" relative-to="jboss.server.config.dir" keystore-password="password" alias="server" key-password="password" generate-self-signed-certificate-host="localhost"/>
</ssl>
</server-identities>
<authentication>
<local default-user="$local" allowed-users="*" skip-group-loading="true"/>
<properties path="application-users.properties" relative-to="jboss.server.config.dir"/>
</authentication>
<authorization>
<properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
</authorization>
</security-realm>
</security-realms>
<audit-log>
<formatters>
<json-formatter name="json-formatter"/>
</formatters>
<handlers>
<file-handler name="file" formatter="json-formatter" path="audit-log.log" relative-to="jboss.server.data.dir"/>
</handlers>
<logger log-boot="true" log-read-only="false" enabled="false">
<handlers>
<handler name="file"/>
</handlers>
</logger>
</audit-log>
<management-interfaces>
<http-interface security-realm="ManagementRealm">
<http-upgrade enabled="true"/>
<socket-binding http="management-http"/>
</http-interface>
</management-interfaces>
<access-control provider="simple">
<role-mapping>
<role name="SuperUser">
<include>
<user name="$local"/>
</include>
</role>
</role-mapping>
</access-control>
</management>
<profile>
<subsystem xmlns="urn:jboss:domain:logging:8.0">
<console-handler name="CONSOLE">
<formatter>
<named-formatter name="COLOR-PATTERN"/>
</formatter>
</console-handler>
<logger category="com.arjuna">
<level name="WARN"/>
</logger>
<logger category="io.jaegertracing.Configuration">
<level name="WARN"/>
</logger>
<logger category="org.jboss.as.config">
<level name="DEBUG"/>
</logger>
<logger category="sun.rmi">
<level name="WARN"/>
</logger>
<logger category="org.keycloak">
<level name="${env.KEYCLOAK_LOGLEVEL:INFO}"/>
</logger>
<root-logger>
<level name="${env.ROOT_LOGLEVEL:INFO}"/>
<handlers>
<handler name="CONSOLE"/>
</handlers>
</root-logger>
<formatter name="PATTERN">
<pattern-formatter pattern="%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n"/>
</formatter>
<formatter name="COLOR-PATTERN">
<pattern-formatter pattern="%K{level}%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n"/>
</formatter>
</subsystem>
<subsystem xmlns="urn:jboss:domain:bean-validation:1.0"/>
<subsystem xmlns="urn:jboss:domain:core-management:1.0"/>
<subsystem xmlns="urn:jboss:domain:datasources:6.0">
<datasources>
<datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true" statistics-enabled="${wildfly.datasources.statistics-enabled:${wildfly.statistics-enabled:false}}">
<connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE</connection-url>
<driver>h2</driver>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
<datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true" statistics-enabled="${wildfly.datasources.statistics-enabled:${wildfly.statistics-enabled:false}}">
<connection-url>jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE</connection-url>
<driver>h2</driver>
<pool>
<max-pool-size>100</max-pool-size>
</pool>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
<drivers>
<driver name="h2" module="com.h2database.h2">
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
</driver>
</drivers>
</datasources>
</subsystem>
<subsystem xmlns="urn:jboss:domain:deployment-scanner:2.0">
<deployment-scanner path="deployments" relative-to="jboss.server.base.dir" scan-interval="5000" runtime-failure-causes-rollback="${jboss.deployment.scanner.rollback.on.failure:false}"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:ee:5.0">
<spec-descriptor-property-replacement>false</spec-descriptor-property-replacement>
<concurrent>
<context-services>
<context-service name="default" jndi-name="java:jboss/ee/concurrency/context/default" use-transaction-setup-provider="true"/>
</context-services>
<managed-thread-factories>
<managed-thread-factory name="default" jndi-name="java:jboss/ee/concurrency/factory/default" context-service="default"/>
</managed-thread-factories>
<managed-executor-services>
<managed-executor-service name="default" jndi-name="java:jboss/ee/concurrency/executor/default" context-service="default" hung-task-threshold="60000" keepalive-time="5000"/>
</managed-executor-services>
<managed-scheduled-executor-services>
<managed-scheduled-executor-service name="default" jndi-name="java:jboss/ee/concurrency/scheduler/default" context-service="default" hung-task-threshold="60000" keepalive-time="3000"/>
</managed-scheduled-executor-services>
</concurrent>
<default-bindings context-service="java:jboss/ee/concurrency/context/default" datasource="java:jboss/datasources/ExampleDS" managed-executor-service="java:jboss/ee/concurrency/executor/default" managed-scheduled-executor-service="java:jboss/ee/concurrency/scheduler/default" managed-thread-factory="java:jboss/ee/concurrency/factory/default"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:ejb3:7.0">
<session-bean>
<stateless>
<bean-instance-pool-ref pool-name="slsb-strict-max-pool"/>
</stateless>
<stateful default-access-timeout="5000" cache-ref="distributable" passivation-disabled-cache-ref="simple"/>
<singleton default-access-timeout="5000"/>
</session-bean>
<pools>
<bean-instance-pools>
<strict-max-pool name="mdb-strict-max-pool" derive-size="from-cpu-count" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
<strict-max-pool name="slsb-strict-max-pool" derive-size="from-worker-pools" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
</bean-instance-pools>
</pools>
<caches>
<cache name="simple"/>
<cache name="distributable" passivation-store-ref="infinispan" aliases="passivating clustered"/>
</caches>
<passivation-stores>
<passivation-store name="infinispan" cache-container="ejb" max-size="10000"/>
</passivation-stores>
<async thread-pool-name="default"/>
<timer-service thread-pool-name="default" default-data-store="default-file-store">
<data-stores>
<file-data-store name="default-file-store" path="timer-service-data" relative-to="jboss.server.data.dir"/>
</data-stores>
</timer-service>
<remote connector-ref="http-remoting-connector" thread-pool-name="default">
<channel-creation-options>
<option name="MAX_OUTBOUND_MESSAGES" value="1234" type="remoting"/>
</channel-creation-options>
</remote>
<thread-pools>
<thread-pool name="default">
<max-threads count="10"/>
<keepalive-time time="60" unit="seconds"/>
</thread-pool>
</thread-pools>
<default-security-domain value="other"/>
<default-missing-method-permissions-deny-access value="true"/>
<statistics enabled="${wildfly.ejb3.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
<log-system-exceptions value="true"/>
</subsystem>
<subsystem xmlns="urn:wildfly:elytron:10.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
<providers>
<aggregate-providers name="combined-providers">
<providers name="elytron"/>
<providers name="openssl"/>
</aggregate-providers>
<provider-loader name="elytron" module="org.wildfly.security.elytron"/>
<provider-loader name="openssl" module="org.wildfly.openssl"/>
</providers>
<audit-logging>
<file-audit-log name="local-audit" path="audit.log" relative-to="jboss.server.log.dir" format="JSON"/>
</audit-logging>
<security-domains>
<security-domain name="ApplicationDomain" default-realm="ApplicationRealm" permission-mapper="default-permission-mapper">
<realm name="ApplicationRealm" role-decoder="groups-to-roles"/>
<realm name="local"/>
</security-domain>
<security-domain name="ManagementDomain" default-realm="ManagementRealm" permission-mapper="default-permission-mapper">
<realm name="ManagementRealm" role-decoder="groups-to-roles"/>
<realm name="local" role-mapper="super-user-mapper"/>
</security-domain>
</security-domains>
<security-realms>
<identity-realm name="local" identity="$local"/>
<properties-realm name="ApplicationRealm">
<users-properties path="application-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="ApplicationRealm"/>
<groups-properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
</properties-realm>
<properties-realm name="ManagementRealm">
<users-properties path="mgmt-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="ManagementRealm"/>
<groups-properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
</properties-realm>
</security-realms>
<mappers>
<simple-permission-mapper name="default-permission-mapper" mapping-mode="first">
<permission-mapping>
<principal name="anonymous"/>
<permission-set name="default-permissions"/>
</permission-mapping>
<permission-mapping match-all="true">
<permission-set name="login-permission"/>
<permission-set name="default-permissions"/>
</permission-mapping>
</simple-permission-mapper>
<constant-realm-mapper name="local" realm-name="local"/>
<simple-role-decoder name="groups-to-roles" attribute="groups"/>
<constant-role-mapper name="super-user-mapper">
<role name="SuperUser"/>
</constant-role-mapper>
</mappers>
<permission-sets>
<permission-set name="login-permission">
<permission class-name="org.wildfly.security.auth.permission.LoginPermission"/>
</permission-set>
<permission-set name="default-permissions">
<permission class-name="org.wildfly.extension.batch.jberet.deployment.BatchPermission" module="org.wildfly.extension.batch.jberet" target-name="*"/>
<permission class-name="org.wildfly.transaction.client.RemoteTransactionPermission" module="org.wildfly.transaction.client"/>
<permission class-name="org.jboss.ejb.client.RemoteEJBPermission" module="org.jboss.ejb-client"/>
</permission-set>
</permission-sets>
<http>
<http-authentication-factory name="management-http-authentication" security-domain="ManagementDomain" http-server-mechanism-factory="global">
<mechanism-configuration>
<mechanism mechanism-name="DIGEST">
<mechanism-realm realm-name="ManagementRealm"/>
</mechanism>
</mechanism-configuration>
</http-authentication-factory>
<provider-http-server-mechanism-factory name="global"/>
</http>
<sasl>
<sasl-authentication-factory name="application-sasl-authentication" sasl-server-factory="configured" security-domain="ApplicationDomain">
<mechanism-configuration>
<mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
<mechanism mechanism-name="DIGEST-MD5">
<mechanism-realm realm-name="ApplicationRealm"/>
</mechanism>
</mechanism-configuration>
</sasl-authentication-factory>
<sasl-authentication-factory name="management-sasl-authentication" sasl-server-factory="configured" security-domain="ManagementDomain">
<mechanism-configuration>
<mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
<mechanism mechanism-name="DIGEST-MD5">
<mechanism-realm realm-name="ManagementRealm"/>
</mechanism>
</mechanism-configuration>
</sasl-authentication-factory>
<configurable-sasl-server-factory name="configured" sasl-server-factory="elytron">
<properties>
<property name="wildfly.sasl.local-user.default-user" value="$local"/>
</properties>
</configurable-sasl-server-factory>
<mechanism-provider-filtering-sasl-server-factory name="elytron" sasl-server-factory="global">
<filters>
<filter provider-name="WildFlyElytron"/>
</filters>
</mechanism-provider-filtering-sasl-server-factory>
<provider-sasl-server-factory name="global"/>
</sasl>
</subsystem>
<subsystem xmlns="urn:jboss:domain:infinispan:10.0">
<cache-container name="keycloak" module="org.keycloak.keycloak-model-infinispan">
<transport lock-timeout="60000"/>
<local-cache name="realms">
<object-memory size="10000"/>
</local-cache>
<local-cache name="users">
<object-memory size="10000"/>
</local-cache>
<local-cache name="authorization">
<object-memory size="10000"/>
</local-cache>
<local-cache name="keys">
<object-memory size="1000"/>
<expiration max-idle="3600000"/>
</local-cache>
<replicated-cache name="work"/>
<distributed-cache name="sessions" owners="1"/>
<distributed-cache name="authenticationSessions" owners="1"/>
<distributed-cache name="offlineSessions" owners="1"/>
<distributed-cache name="clientSessions" owners="1"/>
<distributed-cache name="offlineClientSessions" owners="1"/>
<distributed-cache name="loginFailures" owners="1"/>
<distributed-cache name="actionTokens" owners="2">
<object-memory size="-1"/>
<expiration interval="300000" max-idle="-1"/>
</distributed-cache>
</cache-container>
<cache-container name="server" aliases="singleton cluster" default-cache="default" module="org.wildfly.clustering.server">
<transport lock-timeout="60000"/>
<replicated-cache name="default">
<transaction mode="BATCH"/>
</replicated-cache>
</cache-container>
<cache-container name="web" default-cache="dist" module="org.wildfly.clustering.web.infinispan">
<transport lock-timeout="60000"/>
<replicated-cache name="sso">
<locking isolation="REPEATABLE_READ"/>
<transaction mode="BATCH"/>
</replicated-cache>
<distributed-cache name="dist">
<locking isolation="REPEATABLE_READ"/>
<transaction mode="BATCH"/>
<file-store/>
</distributed-cache>
<distributed-cache name="routing"/>
</cache-container>
<cache-container name="ejb" aliases="sfsb" default-cache="dist" module="org.wildfly.clustering.ejb.infinispan">
<transport lock-timeout="60000"/>
<distributed-cache name="dist">
<locking isolation="REPEATABLE_READ"/>
<transaction mode="BATCH"/>
<file-store/>
</distributed-cache>
</cache-container>
<cache-container name="hibernate" module="org.infinispan.hibernate-cache">
<transport lock-timeout="60000"/>
<local-cache name="local-query">
<object-memory size="10000"/>
<expiration max-idle="100000"/>
</local-cache>
<invalidation-cache name="entity">
<transaction mode="NON_XA"/>
<object-memory size="10000"/>
<expiration max-idle="100000"/>
</invalidation-cache>
<replicated-cache name="timestamps"/>
</cache-container>
</subsystem>
<subsystem xmlns="urn:jboss:domain:io:3.0">
<worker name="default"/>
<buffer-pool name="default"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jaxrs:2.0"/>
<subsystem xmlns="urn:jboss:domain:jca:5.0">
<archive-validation enabled="true" fail-on-error="true" fail-on-warn="false"/>
<bean-validation enabled="true"/>
<default-workmanager>
<short-running-threads>
<core-threads count="50"/>
<queue-length count="50"/>
<max-threads count="50"/>
<keepalive-time time="10" unit="seconds"/>
</short-running-threads>
<long-running-threads>
<core-threads count="50"/>
<queue-length count="50"/>
<max-threads count="50"/>
<keepalive-time time="10" unit="seconds"/>
</long-running-threads>
</default-workmanager>
<cached-connection-manager/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jgroups:8.0">
<channels default="ee">
<channel name="ee" stack="udp" cluster="ejb"/>
</channels>
<stacks>
<stack name="udp">
<transport type="UDP" socket-binding="jgroups-udp"/>
<protocol type="PING"/>
<protocol type="MERGE3"/>
<socket-protocol type="FD_SOCK" socket-binding="jgroups-udp-fd"/>
<protocol type="FD_ALL"/>
<protocol type="VERIFY_SUSPECT"/>
<protocol type="pbcast.NAKACK2"/>
<protocol type="UNICAST3"/>
<protocol type="pbcast.STABLE"/>
<protocol type="pbcast.GMS"/>
<protocol type="UFC"/>
<protocol type="MFC"/>
<protocol type="FRAG3"/>
</stack>
<stack name="tcp">
<transport type="TCP" socket-binding="jgroups-tcp"/>
<socket-protocol type="MPING" socket-binding="jgroups-mping"/>
<protocol type="MERGE3"/>
<socket-protocol type="FD_SOCK" socket-binding="jgroups-tcp-fd"/>
<protocol type="FD_ALL"/>
<protocol type="VERIFY_SUSPECT"/>
<protocol type="pbcast.NAKACK2"/>
<protocol type="UNICAST3"/>
<protocol type="pbcast.STABLE"/>
<protocol type="pbcast.GMS"/>
<protocol type="MFC"/>
<protocol type="FRAG3"/>
</stack>
</stacks>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jmx:1.3">
<expose-resolved-model/>
<expose-expression-model/>
<remoting-connector/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jpa:1.1">
<jpa default-datasource="" default-extended-persistence-inheritance="DEEP"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
<web-context>auth</web-context>
<providers>
<provider>
classpath:${jboss.home.dir}/providers/*
</provider>
</providers>
<master-realm-name>master</master-realm-name>
<scheduled-task-interval>900</scheduled-task-interval>
<theme>
<staticMaxAge>2592000</staticMaxAge>
<cacheThemes>true</cacheThemes>
<cacheTemplates>true</cacheTemplates>
<welcomeTheme>${env.KEYCLOAK_WELCOME_THEME:keycloak}</welcomeTheme>
<default>${env.KEYCLOAK_DEFAULT_THEME:keycloak}</default>
<dir>${jboss.home.dir}/themes</dir>
</theme>
<spi name="eventsStore">
<provider name="jpa" enabled="true">
<properties>
<property name="exclude-events" value="[&quot;REFRESH_TOKEN&quot;]"/>
</properties>
</provider>
</spi>
<spi name="userCache">
<provider name="default" enabled="true"/>
</spi>
<spi name="userSessionPersister">
<default-provider>jpa</default-provider>
</spi>
<spi name="timer">
<default-provider>basic</default-provider>
</spi>
<spi name="connectionsHttpClient">
<provider name="default" enabled="true"/>
</spi>
<spi name="connectionsJpa">
<provider name="default" enabled="true">
<properties>
<property name="dataSource" value="java:jboss/datasources/KeycloakDS"/>
<property name="initializeEmpty" value="true"/>
<property name="migrationStrategy" value="update"/>
<property name="migrationExport" value="${jboss.home.dir}/keycloak-database-update.sql"/>
</properties>
</provider>
</spi>
<spi name="realmCache">
<provider name="default" enabled="true"/>
</spi>
<spi name="connectionsInfinispan">
<default-provider>default</default-provider>
<provider name="default" enabled="true">
<properties>
<property name="cacheContainer" value="java:jboss/infinispan/container/keycloak"/>
</properties>
</provider>
</spi>
<spi name="jta-lookup">
<default-provider>${keycloak.jta.lookup.provider:jboss}</default-provider>
<provider name="jboss" enabled="true"/>
</spi>
<spi name="publicKeyStorage">
<provider name="infinispan" enabled="true">
<properties>
<property name="minTimeBetweenRequests" value="10"/>
</properties>
</provider>
</spi>
<spi name="x509cert-lookup">
<default-provider>${keycloak.x509cert.lookup.provider:default}</default-provider>
<provider name="default" enabled="true"/>
</spi>
<spi name="hostname">
<default-provider>${keycloak.hostname.provider:default}</default-provider>
<provider name="default" enabled="true">
<properties>
<property name="frontendUrl" value="${keycloak.frontendUrl:}"/>
<property name="forceBackendUrlToFrontendUrl" value="false"/>
</properties>
</provider>
<provider name="fixed" enabled="true">
<properties>
<property name="hostname" value="${keycloak.hostname.fixed.hostname:localhost}"/>
<property name="httpPort" value="${keycloak.hostname.fixed.httpPort:-1}"/>
<property name="httpsPort" value="${keycloak.hostname.fixed.httpsPort:-1}"/>
<property name="alwaysHttps" value="${keycloak.hostname.fixed.alwaysHttps:false}"/>
</properties>
</provider>
</spi>
</subsystem>
<subsystem xmlns="urn:jboss:domain:mail:4.0">
<mail-session name="default" jndi-name="java:jboss/mail/Default">
<smtp-server outbound-socket-binding-ref="mail-smtp"/>
</mail-session>
</subsystem>
<subsystem xmlns="urn:wildfly:microprofile-config-smallrye:1.0"/>
<subsystem xmlns="urn:wildfly:microprofile-health-smallrye:2.0" security-enabled="false" empty-liveness-checks-status="${env.MP_HEALTH_EMPTY_LIVENESS_CHECKS_STATUS:UP}" empty-readiness-checks-status="${env.MP_HEALTH_EMPTY_READINESS_CHECKS_STATUS:UP}"/>
<subsystem xmlns="urn:wildfly:microprofile-metrics-smallrye:2.0" security-enabled="false" exposed-subsystems="*" prefix="${wildfly.metrics.prefix:wildfly}"/>
<subsystem xmlns="urn:jboss:domain:modcluster:5.0">
<proxy name="default" advertise-socket="modcluster" listener="ajp">
<dynamic-load-provider>
<load-metric type="cpu"/>
</dynamic-load-provider>
</proxy>
</subsystem>
<subsystem xmlns="urn:jboss:domain:naming:2.0">
<remote-naming/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:remoting:4.0">
<http-connector name="http-remoting-connector" connector-ref="default" security-realm="ApplicationRealm"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:request-controller:1.0"/>
<subsystem xmlns="urn:jboss:domain:security:2.0">
<security-domains>
<security-domain name="other" cache-type="default">
<authentication>
<login-module code="Remoting" flag="optional">
<module-option name="password-stacking" value="useFirstPass"/>
</login-module>
<login-module code="RealmDirect" flag="required">
<module-option name="password-stacking" value="useFirstPass"/>
</login-module>
</authentication>
</security-domain>
<security-domain name="jboss-web-policy" cache-type="default">
<authorization>
<policy-module code="Delegating" flag="required"/>
</authorization>
</security-domain>
<security-domain name="jaspitest" cache-type="default">
<authentication-jaspi>
<login-module-stack name="dummy">
<login-module code="Dummy" flag="optional"/>
</login-module-stack>
<auth-module code="Dummy"/>
</authentication-jaspi>
</security-domain>
<security-domain name="jboss-ejb-policy" cache-type="default">
<authorization>
<policy-module code="Delegating" flag="required"/>
</authorization>
</security-domain>
</security-domains>
</subsystem>
<subsystem xmlns="urn:jboss:domain:security-manager:1.0">
<deployment-permissions>
<maximum-set>
<permission class="java.security.AllPermission"/>
</maximum-set>
</deployment-permissions>
</subsystem>
<subsystem xmlns="urn:jboss:domain:transactions:5.0">
<core-environment node-identifier="${jboss.tx.node.id:1}">
<process-id>
<uuid/>
</process-id>
</core-environment>
<recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/>
<coordinator-environment statistics-enabled="${wildfly.transactions.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
<object-store path="tx-object-store" relative-to="jboss.server.data.dir"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:undertow:11.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other" statistics-enabled="${wildfly.undertow.statistics-enabled:${wildfly.statistics-enabled:false}}">
<buffer-cache name="default"/>
<server name="default-server">
<ajp-listener name="ajp" socket-binding="ajp"/>
<http-listener name="default" read-timeout="30000" socket-binding="http" redirect-socket="https" proxy-address-forwarding="${env.PROXY_ADDRESS_FORWARDING:false}" enable-http2="true"/>
<https-listener name="https" read-timeout="30000" socket-binding="https" proxy-address-forwarding="${env.PROXY_ADDRESS_FORWARDING:false}" security-realm="ApplicationRealm" enable-http2="true"/>
<host name="default-host" alias="localhost">
<location name="/" handler="welcome-content"/>
<http-invoker security-realm="ApplicationRealm"/>
</host>
</server>
<servlet-container name="default">
<jsp-config/>
<websockets/>
</servlet-container>
<handlers>
<file name="welcome-content" path="${jboss.home.dir}/welcome-content"/>
</handlers>
</subsystem>
<subsystem xmlns="urn:jboss:domain:weld:4.0"/>
</profile>
<interfaces>
<interface name="management">
<inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
</interface>
<interface name="private">
<inet-address value="${jboss.bind.address.private:127.0.0.1}"/>
</interface>
<interface name="public">
<inet-address value="${jboss.bind.address:127.0.0.1}"/>
</interface>
</interfaces>
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
<socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
<socket-binding name="http" port="${jboss.http.port:8080}"/>
<socket-binding name="https" port="${jboss.https.port:8443}"/>
<socket-binding name="jgroups-mping" interface="private" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45700"/>
<socket-binding name="jgroups-tcp" interface="private" port="7600"/>
<socket-binding name="jgroups-tcp-fd" interface="private" port="57600"/>
<socket-binding name="jgroups-udp" interface="private" port="55200" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45688"/>
<socket-binding name="jgroups-udp-fd" interface="private" port="54200"/>
<socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
<socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
<socket-binding name="modcluster" multicast-address="${jboss.modcluster.multicast.address:224.0.1.105}" multicast-port="23364"/>
<socket-binding name="txn-recovery-environment" port="4712"/>
<socket-binding name="txn-status-manager" port="4713"/>
<outbound-socket-binding name="mail-smtp">
<remote-destination host="localhost" port="25"/>
</outbound-socket-binding>
</socket-binding-group>
</server>

View File

@ -1,693 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<server xmlns="urn:jboss:domain:16.0">
<extensions>
<extension module="org.jboss.as.clustering.infinispan"/>
<extension module="org.jboss.as.clustering.jgroups"/>
<extension module="org.jboss.as.connector"/>
<extension module="org.jboss.as.deployment-scanner"/>
<extension module="org.jboss.as.ee"/>
<extension module="org.jboss.as.ejb3"/>
<extension module="org.jboss.as.jaxrs"/>
<extension module="org.jboss.as.jmx"/>
<extension module="org.jboss.as.jpa"/>
<extension module="org.jboss.as.logging"/>
<extension module="org.jboss.as.mail"/>
<extension module="org.jboss.as.modcluster"/>
<extension module="org.jboss.as.naming"/>
<extension module="org.jboss.as.remoting"/>
<extension module="org.jboss.as.security"/>
<extension module="org.jboss.as.transactions"/>
<extension module="org.jboss.as.weld"/>
<extension module="org.keycloak.keycloak-server-subsystem"/>
<extension module="org.wildfly.extension.bean-validation"/>
<extension module="org.wildfly.extension.core-management"/>
<extension module="org.wildfly.extension.elytron"/>
<extension module="org.wildfly.extension.health"/>
<extension module="org.wildfly.extension.io"/>
<extension module="org.wildfly.extension.metrics"/>
<extension module="org.wildfly.extension.request-controller"/>
<extension module="org.wildfly.extension.security.manager"/>
<extension module="org.wildfly.extension.undertow"/>
</extensions>
<management>
<security-realms>
<security-realm name="ManagementRealm">
<authentication>
<local default-user="$local" skip-group-loading="true"/>
<properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/>
</authentication>
<authorization map-groups-to-roles="false">
<properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
</authorization>
</security-realm>
<security-realm name="ApplicationRealm">
<server-identities>
<ssl>
<keystore path="application.keystore" relative-to="jboss.server.config.dir" keystore-password="password" alias="server" key-password="password" generate-self-signed-certificate-host="localhost"/>
</ssl>
</server-identities>
<authentication>
<local default-user="$local" allowed-users="*" skip-group-loading="true"/>
<properties path="application-users.properties" relative-to="jboss.server.config.dir"/>
</authentication>
<authorization>
<properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
</authorization>
</security-realm>
</security-realms>
<audit-log>
<formatters>
<json-formatter name="json-formatter"/>
</formatters>
<handlers>
<file-handler name="file" formatter="json-formatter" path="audit-log.log" relative-to="jboss.server.data.dir"/>
</handlers>
<logger log-boot="true" log-read-only="false" enabled="false">
<handlers>
<handler name="file"/>
</handlers>
</logger>
</audit-log>
<management-interfaces>
<http-interface security-realm="ManagementRealm">
<http-upgrade enabled="true"/>
<socket-binding http="management-http"/>
</http-interface>
</management-interfaces>
<access-control provider="simple">
<role-mapping>
<role name="SuperUser">
<include>
<user name="$local"/>
</include>
</role>
</role-mapping>
</access-control>
</management>
<profile>
<subsystem xmlns="urn:jboss:domain:logging:8.0">
<console-handler name="CONSOLE">
<formatter>
<named-formatter name="COLOR-PATTERN"/>
</formatter>
</console-handler>
<logger category="com.arjuna">
<level name="WARN"/>
</logger>
<logger category="io.jaegertracing.Configuration">
<level name="WARN"/>
</logger>
<logger category="org.jboss.as.config">
<level name="DEBUG"/>
</logger>
<logger category="sun.rmi">
<level name="WARN"/>
</logger>
<logger category="org.keycloak">
<level name="${env.KEYCLOAK_LOGLEVEL:INFO}"/>
</logger>
<root-logger>
<level name="${env.ROOT_LOGLEVEL:INFO}"/>
<handlers>
<handler name="CONSOLE"/>
</handlers>
</root-logger>
<formatter name="PATTERN">
<pattern-formatter pattern="%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n"/>
</formatter>
<formatter name="COLOR-PATTERN">
<pattern-formatter pattern="%K{level}%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n"/>
</formatter>
</subsystem>
<subsystem xmlns="urn:jboss:domain:bean-validation:1.0"/>
<subsystem xmlns="urn:jboss:domain:core-management:1.0"/>
<subsystem xmlns="urn:jboss:domain:datasources:6.0">
<datasources>
<datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true" statistics-enabled="${wildfly.datasources.statistics-enabled:${wildfly.statistics-enabled:false}}">
<connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE</connection-url>
<driver>h2</driver>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
<datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true" statistics-enabled="${wildfly.datasources.statistics-enabled:${wildfly.statistics-enabled:false}}">
<connection-url>jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE</connection-url>
<driver>h2</driver>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
<drivers>
<driver name="h2" module="com.h2database.h2">
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
</driver>
</drivers>
</datasources>
</subsystem>
<subsystem xmlns="urn:jboss:domain:deployment-scanner:2.0">
<deployment-scanner path="deployments" relative-to="jboss.server.base.dir" scan-interval="5000" runtime-failure-causes-rollback="${jboss.deployment.scanner.rollback.on.failure:false}"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:ee:6.0">
<spec-descriptor-property-replacement>false</spec-descriptor-property-replacement>
<concurrent>
<context-services>
<context-service name="default" jndi-name="java:jboss/ee/concurrency/context/default" use-transaction-setup-provider="true"/>
</context-services>
<managed-thread-factories>
<managed-thread-factory name="default" jndi-name="java:jboss/ee/concurrency/factory/default" context-service="default"/>
</managed-thread-factories>
<managed-executor-services>
<managed-executor-service name="default" jndi-name="java:jboss/ee/concurrency/executor/default" context-service="default" hung-task-termination-period="0" hung-task-threshold="60000" keepalive-time="5000"/>
</managed-executor-services>
<managed-scheduled-executor-services>
<managed-scheduled-executor-service name="default" jndi-name="java:jboss/ee/concurrency/scheduler/default" context-service="default" hung-task-termination-period="0" hung-task-threshold="60000" keepalive-time="3000"/>
</managed-scheduled-executor-services>
</concurrent>
<default-bindings context-service="java:jboss/ee/concurrency/context/default" datasource="java:jboss/datasources/ExampleDS" managed-executor-service="java:jboss/ee/concurrency/executor/default" managed-scheduled-executor-service="java:jboss/ee/concurrency/scheduler/default" managed-thread-factory="java:jboss/ee/concurrency/factory/default"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:ejb3:9.0">
<session-bean>
<stateless>
<bean-instance-pool-ref pool-name="slsb-strict-max-pool"/>
</stateless>
<stateful default-access-timeout="5000" cache-ref="distributable" passivation-disabled-cache-ref="simple"/>
<singleton default-access-timeout="5000"/>
</session-bean>
<pools>
<bean-instance-pools>
<strict-max-pool name="mdb-strict-max-pool" derive-size="from-cpu-count" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
<strict-max-pool name="slsb-strict-max-pool" derive-size="from-worker-pools" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
</bean-instance-pools>
</pools>
<caches>
<cache name="simple"/>
<cache name="distributable" passivation-store-ref="infinispan" aliases="passivating clustered"/>
</caches>
<passivation-stores>
<passivation-store name="infinispan" cache-container="ejb" max-size="10000"/>
</passivation-stores>
<async thread-pool-name="default"/>
<timer-service thread-pool-name="default" default-data-store="default-file-store">
<data-stores>
<file-data-store name="default-file-store" path="timer-service-data" relative-to="jboss.server.data.dir"/>
</data-stores>
</timer-service>
<remote cluster="ejb" connectors="http-remoting-connector" thread-pool-name="default">
<channel-creation-options>
<option name="MAX_OUTBOUND_MESSAGES" value="1234" type="remoting"/>
</channel-creation-options>
</remote>
<thread-pools>
<thread-pool name="default">
<max-threads count="10"/>
<keepalive-time time="60" unit="seconds"/>
</thread-pool>
</thread-pools>
<default-security-domain value="other"/>
<default-missing-method-permissions-deny-access value="true"/>
<statistics enabled="${wildfly.ejb3.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
<log-system-exceptions value="true"/>
</subsystem>
<subsystem xmlns="urn:wildfly:elytron:13.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
<providers>
<aggregate-providers name="combined-providers">
<providers name="elytron"/>
<providers name="openssl"/>
</aggregate-providers>
<provider-loader name="elytron" module="org.wildfly.security.elytron"/>
<provider-loader name="openssl" module="org.wildfly.openssl"/>
</providers>
<audit-logging>
<file-audit-log name="local-audit" path="audit.log" relative-to="jboss.server.log.dir" format="JSON"/>
</audit-logging>
<security-domains>
<security-domain name="ApplicationDomain" default-realm="ApplicationRealm" permission-mapper="default-permission-mapper">
<realm name="ApplicationRealm" role-decoder="groups-to-roles"/>
<realm name="local"/>
</security-domain>
<security-domain name="ManagementDomain" default-realm="ManagementRealm" permission-mapper="default-permission-mapper">
<realm name="ManagementRealm" role-decoder="groups-to-roles"/>
<realm name="local" role-mapper="super-user-mapper"/>
</security-domain>
</security-domains>
<security-realms>
<identity-realm name="local" identity="$local"/>
<properties-realm name="ApplicationRealm">
<users-properties path="application-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="ApplicationRealm"/>
<groups-properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
</properties-realm>
<properties-realm name="ManagementRealm">
<users-properties path="mgmt-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="ManagementRealm"/>
<groups-properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
</properties-realm>
</security-realms>
<mappers>
<simple-permission-mapper name="default-permission-mapper" mapping-mode="first">
<permission-mapping>
<principal name="anonymous"/>
<permission-set name="default-permissions"/>
</permission-mapping>
<permission-mapping match-all="true">
<permission-set name="login-permission"/>
<permission-set name="default-permissions"/>
</permission-mapping>
</simple-permission-mapper>
<constant-realm-mapper name="local" realm-name="local"/>
<simple-role-decoder name="groups-to-roles" attribute="groups"/>
<constant-role-mapper name="super-user-mapper">
<role name="SuperUser"/>
</constant-role-mapper>
</mappers>
<permission-sets>
<permission-set name="login-permission">
<permission class-name="org.wildfly.security.auth.permission.LoginPermission"/>
</permission-set>
<permission-set name="default-permissions">
<permission class-name="org.wildfly.extension.batch.jberet.deployment.BatchPermission" module="org.wildfly.extension.batch.jberet" target-name="*"/>
<permission class-name="org.wildfly.transaction.client.RemoteTransactionPermission" module="org.wildfly.transaction.client"/>
<permission class-name="org.jboss.ejb.client.RemoteEJBPermission" module="org.jboss.ejb-client"/>
<permission class-name="org.jboss.ejb.client.RemoteEJBPermission" module="org.jboss.ejb-client"/>
</permission-set>
</permission-sets>
<http>
<http-authentication-factory name="management-http-authentication" security-domain="ManagementDomain" http-server-mechanism-factory="global">
<mechanism-configuration>
<mechanism mechanism-name="DIGEST">
<mechanism-realm realm-name="ManagementRealm"/>
</mechanism>
</mechanism-configuration>
</http-authentication-factory>
<provider-http-server-mechanism-factory name="global"/>
</http>
<sasl>
<sasl-authentication-factory name="application-sasl-authentication" sasl-server-factory="configured" security-domain="ApplicationDomain">
<mechanism-configuration>
<mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
<mechanism mechanism-name="DIGEST-MD5">
<mechanism-realm realm-name="ApplicationRealm"/>
</mechanism>
</mechanism-configuration>
</sasl-authentication-factory>
<sasl-authentication-factory name="management-sasl-authentication" sasl-server-factory="configured" security-domain="ManagementDomain">
<mechanism-configuration>
<mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
<mechanism mechanism-name="DIGEST-MD5">
<mechanism-realm realm-name="ManagementRealm"/>
</mechanism>
</mechanism-configuration>
</sasl-authentication-factory>
<configurable-sasl-server-factory name="configured" sasl-server-factory="elytron">
<properties>
<property name="wildfly.sasl.local-user.default-user" value="$local"/>
</properties>
</configurable-sasl-server-factory>
<mechanism-provider-filtering-sasl-server-factory name="elytron" sasl-server-factory="global">
<filters>
<filter provider-name="WildFlyElytron"/>
</filters>
</mechanism-provider-filtering-sasl-server-factory>
<provider-sasl-server-factory name="global"/>
</sasl>
<tls>
<key-stores>
<key-store name="applicationKS">
<credential-reference clear-text="password"/>
<implementation type="JKS"/>
<file path="application.keystore" relative-to="jboss.server.config.dir"/>
</key-store>
</key-stores>
<key-managers>
<key-manager name="applicationKM" key-store="applicationKS" generate-self-signed-certificate-host="localhost">
<credential-reference clear-text="password"/>
</key-manager>
</key-managers>
<server-ssl-contexts>
<server-ssl-context name="applicationSSC" key-manager="applicationKM"/>
</server-ssl-contexts>
</tls>
</subsystem>
<subsystem xmlns="urn:wildfly:health:1.0" security-enabled="false"/>
<subsystem xmlns="urn:jboss:domain:infinispan:12.0">
<cache-container name="ejb" default-cache="dist" aliases="sfsb" modules="org.wildfly.clustering.ejb.infinispan">
<transport lock-timeout="60000"/>
<distributed-cache name="dist">
<locking isolation="REPEATABLE_READ"/>
<transaction mode="BATCH"/>
<file-store/>
</distributed-cache>
</cache-container>
<cache-container name="keycloak" modules="org.keycloak.keycloak-model-infinispan">
<transport lock-timeout="60000"/>
<local-cache name="realms">
<heap-memory size="10000"/>
</local-cache>
<local-cache name="users">
<heap-memory size="10000"/>
</local-cache>
<local-cache name="authorization">
<heap-memory size="10000"/>
</local-cache>
<local-cache name="keys">
<heap-memory size="1000"/>
<expiration max-idle="3600000"/>
</local-cache>
<replicated-cache name="work">
<expiration lifespan="900000000000000000"/>
</replicated-cache>
<distributed-cache name="sessions" owners="1">
<expiration lifespan="900000000000000000"/>
</distributed-cache>
<distributed-cache name="authenticationSessions" owners="1">
<expiration lifespan="900000000000000000"/>
</distributed-cache>
<distributed-cache name="offlineSessions" owners="1">
<expiration lifespan="900000000000000000"/>
</distributed-cache>
<distributed-cache name="clientSessions" owners="1">
<expiration lifespan="900000000000000000"/>
</distributed-cache>
<distributed-cache name="offlineClientSessions" owners="1">
<expiration lifespan="900000000000000000"/>
</distributed-cache>
<distributed-cache name="loginFailures" owners="1">
<expiration lifespan="900000000000000000"/>
</distributed-cache>
<distributed-cache name="actionTokens" owners="2">
<heap-memory size="-1"/>
<expiration interval="300000" lifespan="900000000000000000" max-idle="-1"/>
</distributed-cache>
</cache-container>
<cache-container name="server" default-cache="default" aliases="singleton cluster" modules="org.wildfly.clustering.server">
<transport lock-timeout="60000"/>
<replicated-cache name="default">
<transaction mode="BATCH"/>
</replicated-cache>
</cache-container>
<cache-container name="web" default-cache="dist" modules="org.wildfly.clustering.web.infinispan">
<transport lock-timeout="60000"/>
<replicated-cache name="sso">
<locking isolation="REPEATABLE_READ"/>
<transaction mode="BATCH"/>
</replicated-cache>
<distributed-cache name="dist">
<locking isolation="REPEATABLE_READ"/>
<transaction mode="BATCH"/>
<file-store/>
</distributed-cache>
<distributed-cache name="routing"/>
</cache-container>
<cache-container name="hibernate" modules="org.infinispan.hibernate-cache">
<transport lock-timeout="60000"/>
<local-cache name="local-query">
<heap-memory size="10000"/>
<expiration max-idle="100000"/>
</local-cache>
<invalidation-cache name="entity">
<transaction mode="NON_XA"/>
<heap-memory size="10000"/>
<expiration max-idle="100000"/>
</invalidation-cache>
<replicated-cache name="timestamps"/>
</cache-container>
</subsystem>
<subsystem xmlns="urn:jboss:domain:io:3.0">
<worker name="default"/>
<buffer-pool name="default"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jaxrs:2.0"/>
<subsystem xmlns="urn:jboss:domain:jca:5.0">
<archive-validation enabled="true" fail-on-error="true" fail-on-warn="false"/>
<bean-validation enabled="true"/>
<default-workmanager>
<short-running-threads>
<core-threads count="50"/>
<queue-length count="50"/>
<max-threads count="50"/>
<keepalive-time time="10" unit="seconds"/>
</short-running-threads>
<long-running-threads>
<core-threads count="50"/>
<queue-length count="50"/>
<max-threads count="50"/>
<keepalive-time time="10" unit="seconds"/>
</long-running-threads>
</default-workmanager>
<cached-connection-manager/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jgroups:8.0">
<channels default="ee">
<channel name="ee" stack="udp" cluster="ejb"/>
</channels>
<stacks>
<stack name="udp">
<transport type="UDP" socket-binding="jgroups-udp"/>
<protocol type="PING"/>
<protocol type="MERGE3"/>
<socket-protocol type="FD_SOCK" socket-binding="jgroups-udp-fd"/>
<protocol type="FD_ALL"/>
<protocol type="VERIFY_SUSPECT"/>
<protocol type="pbcast.NAKACK2"/>
<protocol type="UNICAST3"/>
<protocol type="pbcast.STABLE"/>
<protocol type="pbcast.GMS"/>
<protocol type="UFC"/>
<protocol type="MFC"/>
<protocol type="FRAG3"/>
</stack>
<stack name="tcp">
<transport type="TCP" socket-binding="jgroups-tcp"/>
<socket-protocol type="MPING" socket-binding="jgroups-mping"/>
<protocol type="MERGE3"/>
<socket-protocol type="FD_SOCK" socket-binding="jgroups-tcp-fd"/>
<protocol type="FD_ALL"/>
<protocol type="VERIFY_SUSPECT"/>
<protocol type="pbcast.NAKACK2"/>
<protocol type="UNICAST3"/>
<protocol type="pbcast.STABLE"/>
<protocol type="pbcast.GMS"/>
<protocol type="MFC"/>
<protocol type="FRAG3"/>
</stack>
</stacks>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jmx:1.3">
<expose-resolved-model/>
<expose-expression-model/>
<remoting-connector/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jpa:1.1">
<jpa default-extended-persistence-inheritance="DEEP"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
<web-context>auth</web-context>
<providers>
<provider>
classpath:${jboss.home.dir}/providers/*
</provider>
</providers>
<master-realm-name>master</master-realm-name>
<scheduled-task-interval>900</scheduled-task-interval>
<theme>
<staticMaxAge>2592000</staticMaxAge>
<cacheThemes>true</cacheThemes>
<cacheTemplates>true</cacheTemplates>
<welcomeTheme>${env.KEYCLOAK_WELCOME_THEME:keycloak}</welcomeTheme>
<default>${env.KEYCLOAK_DEFAULT_THEME:keycloak}</default>
<dir>${jboss.home.dir}/themes</dir>
</theme>
<spi name="eventsStore">
<provider name="jpa" enabled="true">
<properties>
<property name="exclude-events" value="[&quot;REFRESH_TOKEN&quot;]"/>
</properties>
</provider>
</spi>
<spi name="userCache">
<provider name="default" enabled="true"/>
</spi>
<spi name="userSessionPersister">
<default-provider>jpa</default-provider>
</spi>
<spi name="timer">
<default-provider>basic</default-provider>
</spi>
<spi name="connectionsHttpClient">
<provider name="default" enabled="true"/>
</spi>
<spi name="connectionsJpa">
<provider name="default" enabled="true">
<properties>
<property name="dataSource" value="java:jboss/datasources/KeycloakDS"/>
<property name="initializeEmpty" value="true"/>
<property name="migrationStrategy" value="update"/>
<property name="migrationExport" value="${jboss.home.dir}/keycloak-database-update.sql"/>
</properties>
</provider>
</spi>
<spi name="realmCache">
<provider name="default" enabled="true"/>
</spi>
<spi name="connectionsInfinispan">
<default-provider>default</default-provider>
<provider name="default" enabled="true">
<properties>
<property name="cacheContainer" value="java:jboss/infinispan/container/keycloak"/>
</properties>
</provider>
</spi>
<spi name="jta-lookup">
<default-provider>${keycloak.jta.lookup.provider:jboss}</default-provider>
<provider name="jboss" enabled="true"/>
</spi>
<spi name="publicKeyStorage">
<provider name="infinispan" enabled="true">
<properties>
<property name="minTimeBetweenRequests" value="10"/>
</properties>
</provider>
</spi>
<spi name="x509cert-lookup">
<default-provider>${keycloak.x509cert.lookup.provider:default}</default-provider>
<provider name="default" enabled="true"/>
</spi>
<spi name="hostname">
<default-provider>${keycloak.hostname.provider:default}</default-provider>
<provider name="default" enabled="true">
<properties>
<property name="frontendUrl" value="${keycloak.frontendUrl:}"/>
<property name="forceBackendUrlToFrontendUrl" value="false"/>
</properties>
</provider>
<provider name="fixed" enabled="true">
<properties>
<property name="hostname" value="${keycloak.hostname.fixed.hostname:localhost}"/>
<property name="httpPort" value="${keycloak.hostname.fixed.httpPort:-1}"/>
<property name="httpsPort" value="${keycloak.hostname.fixed.httpsPort:-1}"/>
<property name="alwaysHttps" value="${keycloak.hostname.fixed.alwaysHttps:false}"/>
</properties>
</provider>
</spi>
</subsystem>
<subsystem xmlns="urn:jboss:domain:mail:4.0">
<mail-session name="default" jndi-name="java:jboss/mail/Default">
<smtp-server outbound-socket-binding-ref="mail-smtp"/>
</mail-session>
</subsystem>
<subsystem xmlns="urn:wildfly:metrics:1.0" security-enabled="false" exposed-subsystems="*" prefix="${wildfly.metrics.prefix:wildfly}"/>
<subsystem xmlns="urn:jboss:domain:modcluster:5.0">
<proxy name="default" advertise-socket="modcluster" listener="ajp">
<dynamic-load-provider>
<load-metric type="cpu"/>
</dynamic-load-provider>
</proxy>
</subsystem>
<subsystem xmlns="urn:jboss:domain:naming:2.0">
<remote-naming/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:remoting:4.0">
<http-connector name="http-remoting-connector" connector-ref="default" security-realm="ApplicationRealm"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:request-controller:1.0"/>
<subsystem xmlns="urn:jboss:domain:security:2.0">
<security-domains>
<security-domain name="other" cache-type="default">
<authentication>
<login-module code="Remoting" flag="optional">
<module-option name="password-stacking" value="useFirstPass"/>
</login-module>
<login-module code="RealmDirect" flag="required">
<module-option name="password-stacking" value="useFirstPass"/>
</login-module>
</authentication>
</security-domain>
<security-domain name="jboss-web-policy" cache-type="default">
<authorization>
<policy-module code="Delegating" flag="required"/>
</authorization>
</security-domain>
<security-domain name="jaspitest" cache-type="default">
<authentication-jaspi>
<login-module-stack name="dummy">
<login-module code="Dummy" flag="optional"/>
</login-module-stack>
<auth-module code="Dummy"/>
</authentication-jaspi>
</security-domain>
<security-domain name="jboss-ejb-policy" cache-type="default">
<authorization>
<policy-module code="Delegating" flag="required"/>
</authorization>
</security-domain>
</security-domains>
</subsystem>
<subsystem xmlns="urn:jboss:domain:security-manager:1.0">
<deployment-permissions>
<maximum-set>
<permission class="java.security.AllPermission"/>
</maximum-set>
</deployment-permissions>
</subsystem>
<subsystem xmlns="urn:jboss:domain:transactions:6.0">
<core-environment node-identifier="${jboss.tx.node.id:1}">
<process-id>
<uuid/>
</process-id>
</core-environment>
<recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/>
<coordinator-environment statistics-enabled="${wildfly.transactions.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
<object-store path="tx-object-store" relative-to="jboss.server.data.dir"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:undertow:12.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other" statistics-enabled="${wildfly.undertow.statistics-enabled:${wildfly.statistics-enabled:false}}">
<buffer-cache name="default"/>
<server name="default-server">
<ajp-listener name="ajp" socket-binding="ajp"/>
<http-listener name="default" socket-binding="http" redirect-socket="https" proxy-address-forwarding="${env.PROXY_ADDRESS_FORWARDING:false}" enable-http2="true"/>
<https-listener name="https" socket-binding="https" proxy-address-forwarding="${env.PROXY_ADDRESS_FORWARDING:false}" security-realm="ApplicationRealm" enable-http2="true"/>
<host name="default-host" alias="localhost">
<location name="/" handler="welcome-content"/>
<http-invoker security-realm="ApplicationRealm"/>
</host>
</server>
<servlet-container name="default">
<jsp-config/>
<websockets/>
</servlet-container>
<handlers>
<file name="welcome-content" path="${jboss.home.dir}/welcome-content"/>
</handlers>
</subsystem>
<subsystem xmlns="urn:jboss:domain:weld:4.0"/>
</profile>
<interfaces>
<interface name="management">
<inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
</interface>
<interface name="private">
<inet-address value="${jboss.bind.address.private:127.0.0.1}"/>
</interface>
<interface name="public">
<inet-address value="${jboss.bind.address:127.0.0.1}"/>
</interface>
</interfaces>
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
<socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
<socket-binding name="http" port="${jboss.http.port:8080}"/>
<socket-binding name="https" port="${jboss.https.port:8443}"/>
<socket-binding name="jgroups-mping" interface="private" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45700"/>
<socket-binding name="jgroups-tcp" interface="private" port="7600"/>
<socket-binding name="jgroups-tcp-fd" interface="private" port="57600"/>
<socket-binding name="jgroups-udp" interface="private" port="55200" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45688"/>
<socket-binding name="jgroups-udp-fd" interface="private" port="54200"/>
<socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
<socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
<socket-binding name="modcluster" multicast-address="${jboss.modcluster.multicast.address:224.0.1.105}" multicast-port="23364"/>
<socket-binding name="txn-recovery-environment" port="4712"/>
<socket-binding name="txn-status-manager" port="4713"/>
<outbound-socket-binding name="mail-smtp">
<remote-destination host="${jboss.mail.server.host:localhost}" port="${jboss.mail.server.port:25}"/>
</outbound-socket-binding>
</socket-binding-group>
</server>

View File

@ -126,6 +126,14 @@ ${ftl_object_to_js_code_declaring_an_object(.data_model, [])?no_esc};
key == "loginAction" &&
are_same_path(path, ["url"]) &&
pageId == "saml-post-form.ftl"
) || (
["contextData", "idpConfig", "idp", "authenticationSession"]?seq_contains(key) &&
are_same_path(path, ["brokerContext"]) &&
["login-idp-link-confirm.ftl", "login-idp-link-email.ftl" ]?seq_contains(pageId)
) || (
key == "identityProviderBrokerCtx" &&
are_same_path(path, []) &&
["login-idp-link-confirm.ftl", "login-idp-link-email.ftl" ]?seq_contains(pageId)
)
>
<#local out_seq += ["/*If you need '" + key + "' on " + pageId + ", please submit an issue to the Keycloakify repo*/"]>

View File

@ -2,10 +2,16 @@ import * as url from "url";
import * as fs from "fs";
import { join as pathJoin, dirname as pathDirname } from "path";
export function generateJavaStackFiles(params: { version: string; themeName: string; homepage?: string; keycloakThemeBuildingDirPath: string }): {
export function generateJavaStackFiles(params: {
version: string;
themeName: string;
homepage?: string;
keycloakThemeBuildingDirPath: string;
doBundleEmailTemplate: boolean;
}): {
jarFilePath: string;
} {
const { themeName, version, homepage, keycloakThemeBuildingDirPath } = params;
const { themeName, version, homepage, keycloakThemeBuildingDirPath, doBundleEmailTemplate } = params;
{
const { pomFileCode } = (function generatePomFileCode(): {
@ -63,7 +69,7 @@ export function generateJavaStackFiles(params: { version: string; themeName: str
"themes": [
{
"name": themeName,
"types": ["login"],
"types": ["login", ...(doBundleEmailTemplate ? ["email"] : [])],
},
],
},

View File

@ -1,6 +1,6 @@
import { transformCodebase } from "../tools/transformCodebase";
import * as fs from "fs";
import { join as pathJoin } from "path";
import { join as pathJoin, basename as pathBasename } from "path";
import { replaceImportsInCssCode, replaceImportsFromStaticInJsCode } from "./replaceImportFromStatic";
import { generateFtlFilesCodeFactory, pageIds } from "./generateFtl";
import { downloadBuiltinKeycloakTheme } from "../download-builtin-keycloak-theme";
@ -12,17 +12,19 @@ export function generateKeycloakThemeResources(params: {
themeName: string;
reactAppBuildDirPath: string;
keycloakThemeBuildingDirPath: string;
keycloakThemeEmailDirPath: string;
urlPathname: string;
//If urlOrigin is not undefined then it means --externals-assets
urlOrigin: undefined | string;
extraPagesId: string[];
extraThemeProperties: string[];
keycloakVersion: "11.0.3" | "15.0.2";
}) {
keycloakVersion: string;
}): { doBundleEmailTemplate: boolean } {
const {
themeName,
reactAppBuildDirPath,
keycloakThemeBuildingDirPath,
keycloakThemeEmailDirPath,
urlPathname,
urlOrigin,
extraPagesId,
@ -79,6 +81,28 @@ export function generateKeycloakThemeResources(params: {
},
});
let doBundleEmailTemplate: boolean;
email: {
if (!fs.existsSync(keycloakThemeEmailDirPath)) {
console.log(
[
`Not bundling email template because ${pathBasename(keycloakThemeEmailDirPath)} does not exist`,
`To start customizing the email template, run: 👉 npx create-keycloak-theme-email-directory 👈`,
].join("\n"),
);
doBundleEmailTemplate = false;
break email;
}
doBundleEmailTemplate = true;
transformCodebase({
"srcDirPath": keycloakThemeEmailDirPath,
"destDirPath": pathJoin(themeDirPath, "..", "email"),
});
}
const { generateFtlFilesCode } = generateFtlFilesCodeFactory({
"cssGlobalsToDefine": allCssGlobalsToDefine,
"indexHtmlCode": fs.readFileSync(pathJoin(reactAppBuildDirPath, "index.html")).toString("utf8"),
@ -112,20 +136,22 @@ export function generateKeycloakThemeResources(params: {
const reactAppPublicDirPath = pathJoin(reactAppBuildDirPath, "..", "public");
transformCodebase({
"srcDirPath": themeResourcesDirPath,
"destDirPath": pathJoin(reactAppPublicDirPath, resourcesPath),
"srcDirPath": pathJoin(tmpDirPath, "keycloak", "common", "resources"),
"destDirPath": pathJoin(themeResourcesDirPath, pathBasename(resourcesCommonPath)),
});
transformCodebase({
"srcDirPath": pathJoin(tmpDirPath, "keycloak", "common", "resources"),
"destDirPath": pathJoin(reactAppPublicDirPath, resourcesCommonPath),
"srcDirPath": themeResourcesDirPath,
"destDirPath": pathJoin(reactAppPublicDirPath, resourcesPath),
});
const keycloakResourcesWithinPublicDirPath = pathJoin(reactAppPublicDirPath, subDirOfPublicDirBasename);
fs.writeFileSync(
pathJoin(keycloakResourcesWithinPublicDirPath, "README.txt"),
Buffer.from(["This is just a test folder that helps develop", "the login and register page without having to yarn build"].join(" ")),
Buffer.from(
["This is just a test folder that helps develop", "the login and register page without having to run a Keycloak container"].join(" "),
),
);
fs.writeFileSync(pathJoin(keycloakResourcesWithinPublicDirPath, ".gitignore"), Buffer.from("*", "utf8"));
@ -137,4 +163,6 @@ export function generateKeycloakThemeResources(params: {
pathJoin(themeDirPath, "theme.properties"),
Buffer.from("parent=keycloak".concat("\n\n", extraThemeProperties.join("\n\n")), "utf8"),
);
return { doBundleEmailTemplate };
}

View File

@ -0,0 +1,44 @@
import * as fs from "fs";
import { join as pathJoin } from "path";
generateStartKeycloakTestingContainer.basename = "start_keycloak_testing_container.sh";
const containerName = "keycloak-testing-container";
/** Files for being able to run a hot reload keycloak container */
export function generateStartKeycloakTestingContainer(params: { keycloakVersion: string; themeName: string; keycloakThemeBuildingDirPath: string }) {
const { themeName, keycloakThemeBuildingDirPath, keycloakVersion } = params;
fs.writeFileSync(
pathJoin(keycloakThemeBuildingDirPath, generateStartKeycloakTestingContainer.basename),
Buffer.from(
[
"#!/bin/bash",
"",
`docker rm ${containerName} || true`,
"",
`cd ${keycloakThemeBuildingDirPath}`,
"",
"docker run \\",
" -p 8080:8080 \\",
` --name ${containerName} \\`,
" -e KEYCLOAK_ADMIN=admin \\",
" -e KEYCLOAK_ADMIN_PASSWORD=admin \\",
" -e JAVA_OPTS=-Dkeycloak.profile=preview \\",
` -v ${pathJoin(
keycloakThemeBuildingDirPath,
"src",
"main",
"resources",
"theme",
themeName,
)}:/opt/keycloak/themes/${themeName}:rw \\`,
` -it quay.io/keycloak/keycloak:${keycloakVersion} \\`,
` start-dev`,
"",
].join("\n"),
"utf8",
),
{ "mode": 0o755 },
);
}

View File

@ -0,0 +1,36 @@
#!/usr/bin/env node
import { downloadBuiltinKeycloakTheme } from "./download-builtin-keycloak-theme";
import { keycloakThemeEmailDirPath } from "./build-keycloak-theme";
import { join as pathJoin, basename as pathBasename } from "path";
import { transformCodebase } from "./tools/transformCodebase";
import { promptKeycloakVersion } from "./promptKeycloakVersion";
import * as fs from "fs";
if (require.main === module) {
(async () => {
if (fs.existsSync(keycloakThemeEmailDirPath)) {
console.log(`There is already a ./${pathBasename(keycloakThemeEmailDirPath)} directory in your project. Aborting.`);
process.exit(-1);
}
const { keycloakVersion } = await promptKeycloakVersion();
const builtinKeycloakThemeTmpDirPath = pathJoin(keycloakThemeEmailDirPath, "..", "tmp_xIdP3_builtin_keycloak_theme");
downloadBuiltinKeycloakTheme({
keycloakVersion,
"destDirPath": builtinKeycloakThemeTmpDirPath,
});
transformCodebase({
"srcDirPath": pathJoin(builtinKeycloakThemeTmpDirPath, "base", "email"),
"destDirPath": keycloakThemeEmailDirPath,
});
console.log(`./${pathBasename(keycloakThemeEmailDirPath)} ready to be customized`);
fs.rmSync(builtinKeycloakThemeTmpDirPath, { "recursive": true, "force": true });
})();
}

View File

@ -3,9 +3,9 @@
import { keycloakThemeBuildingDirPath } from "./build-keycloak-theme";
import { join as pathJoin } from "path";
import { downloadAndUnzip } from "./tools/downloadAndUnzip";
import type { KeycloakVersion } from "./KeycloakVersion";
import { promptKeycloakVersion } from "./promptKeycloakVersion";
export function downloadBuiltinKeycloakTheme(params: { keycloakVersion: KeycloakVersion; destDirPath: string }) {
export function downloadBuiltinKeycloakTheme(params: { keycloakVersion: string; destDirPath: string }) {
const { keycloakVersion, destDirPath } = params;
for (const ext of ["", "-community"]) {
@ -18,22 +18,16 @@ export function downloadBuiltinKeycloakTheme(params: { keycloakVersion: Keycloak
}
if (require.main === module) {
const keycloakVersion = (() => {
const keycloakVersion = process.argv[2] as KeycloakVersion | undefined;
(async () => {
const { keycloakVersion } = await promptKeycloakVersion();
if (keycloakVersion === undefined) {
return "15.0.2";
}
const destDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme");
return keycloakVersion;
console.log(`Downloading builtins theme of Keycloak ${keycloakVersion} here ${destDirPath}`);
downloadBuiltinKeycloakTheme({
keycloakVersion,
destDirPath,
});
})();
const destDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme");
console.log(`Downloading builtins theme of Keycloak ${keycloakVersion} here ${destDirPath}`);
downloadBuiltinKeycloakTheme({
keycloakVersion,
destDirPath,
});
}

View File

@ -5,12 +5,11 @@ import { crawl } from "./tools/crawl";
import { downloadBuiltinKeycloakTheme } from "./download-builtin-keycloak-theme";
import { getProjectRoot } from "./tools/getProjectRoot";
import { rm_rf, rm_r } from "./tools/rm";
import { keycloakVersions } from "./KeycloakVersion";
//@ts-ignore
const propertiesParser = require("properties-parser");
for (const keycloakVersion of keycloakVersions) {
for (const keycloakVersion of ["11.0.3", "15.0.2", "16.1.0"]) {
console.log({ keycloakVersion });
const tmpDirPath = pathJoin(getProjectRoot(), "tmp_xImOef9dOd44");

View File

@ -0,0 +1,44 @@
import { getLatestsSemVersionedTagFactory } from "./tools/octokit-addons/getLatestsSemVersionedTag";
import { Octokit } from "@octokit/rest";
import cliSelect from "cli-select";
export async function promptKeycloakVersion() {
const { getLatestsSemVersionedTag } = (() => {
const { octokit } = (() => {
const githubToken = process.env.GITHUB_TOKEN;
const octokit = new Octokit(githubToken === undefined ? undefined : { "auth": githubToken });
return { octokit };
})();
const { getLatestsSemVersionedTag } = getLatestsSemVersionedTagFactory({ octokit });
return { getLatestsSemVersionedTag };
})();
console.log("Initialize the directory with email template from which keycloak version?");
const tags = await getLatestsSemVersionedTag({
"count": 15,
"doIgnoreBeta": true,
"owner": "keycloak",
"repo": "keycloak",
}).then(arr => arr.map(({ tag }) => tag));
if (process.env["GITHUB_ACTIONS"] === "true") {
return { "keycloakVersion": tags[0] };
}
const { value: keycloakVersion } = await cliSelect<string>({
"values": tags,
}).catch(() => {
console.log("Aborting");
process.exit(-1);
});
console.log(keycloakVersion);
return { keycloakVersion };
}

View File

@ -0,0 +1,73 @@
export type NpmModuleVersion = {
major: number;
minor: number;
patch: number;
betaPreRelease?: number;
};
export namespace NpmModuleVersion {
export function parse(versionStr: string): NpmModuleVersion {
const match = versionStr.match(/^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-beta.([0-9]+))?/);
if (!match) {
throw new Error(`${versionStr} is not a valid NPM version`);
}
return {
"major": parseInt(match[1]),
"minor": parseInt(match[2]),
"patch": parseInt(match[3]),
...(() => {
const str = match[4];
return str === undefined ? {} : { "betaPreRelease": parseInt(str) };
})(),
};
}
export function stringify(v: NpmModuleVersion) {
return `${v.major}.${v.minor}.${v.patch}${v.betaPreRelease === undefined ? "" : `-beta.${v.betaPreRelease}`}`;
}
/**
*
* v1 < v2 => -1
* v1 === v2 => 0
* v1 > v2 => 1
*
*/
export function compare(v1: NpmModuleVersion, v2: NpmModuleVersion): -1 | 0 | 1 {
const sign = (diff: number): -1 | 0 | 1 => (diff === 0 ? 0 : diff < 0 ? -1 : 1);
const noUndefined = (n: number | undefined) => n ?? Infinity;
for (const level of ["major", "minor", "patch", "betaPreRelease"] as const) {
if (noUndefined(v1[level]) !== noUndefined(v2[level])) {
return sign(noUndefined(v1[level]) - noUndefined(v2[level]));
}
}
return 0;
}
/*
console.log(compare(parse("3.0.0-beta.3"), parse("3.0.0")) === -1 )
console.log(compare(parse("3.0.0-beta.3"), parse("3.0.0-beta.4")) === -1 )
console.log(compare(parse("3.0.0-beta.3"), parse("4.0.0")) === -1 )
*/
export function bumpType(params: { versionBehindStr: string; versionAheadStr: string }): "major" | "minor" | "patch" | "betaPreRelease" | "same" {
const versionAhead = parse(params.versionAheadStr);
const versionBehind = parse(params.versionBehindStr);
if (compare(versionBehind, versionAhead) === 1) {
throw new Error(`Version regression ${versionBehind} -> ${versionAhead}`);
}
for (const level of ["major", "minor", "patch", "betaPreRelease"] as const) {
if (versionBehind[level] !== versionAhead[level]) {
return level;
}
}
return "same";
}
}

View File

@ -0,0 +1,7 @@
import { Octokit } from "@octokit/rest";
export function createOctokit(params: { github_token: string }) {
const { github_token } = params;
return new Octokit({ ...(github_token !== "" ? { "auth": github_token } : {}) });
}

View File

@ -2,7 +2,7 @@ import * as fs from "fs";
import * as path from "path";
function getProjectRootRec(dirPath: string): string {
if (fs.existsSync(path.join(dirPath, "package.json"))) {
if (fs.existsSync(path.join(dirPath, "tsconfig.json"))) {
return dirPath;
}
return getProjectRootRec(path.join(dirPath, ".."));

View File

@ -0,0 +1,40 @@
import { listTagsFactory } from "./listTags";
import type { Octokit } from "@octokit/rest";
import { NpmModuleVersion } from "../NpmModuleVersion";
export function getLatestsSemVersionedTagFactory(params: { octokit: Octokit }) {
const { octokit } = params;
async function getLatestsSemVersionedTag(params: { owner: string; repo: string; doIgnoreBeta: boolean; count: number }): Promise<
{
tag: string;
version: NpmModuleVersion;
}[]
> {
const { owner, repo, doIgnoreBeta, count } = params;
const semVersionedTags: { tag: string; version: NpmModuleVersion }[] = [];
const { listTags } = listTagsFactory({ octokit });
for await (const tag of listTags({ owner, repo })) {
let version: NpmModuleVersion;
try {
version = NpmModuleVersion.parse(tag.replace(/^[vV]?/, ""));
} catch {
continue;
}
if (doIgnoreBeta && version.betaPreRelease !== undefined) {
continue;
}
semVersionedTags.push({ tag, version });
}
return semVersionedTags.sort(({ version: vX }, { version: vY }) => NpmModuleVersion.compare(vY, vX)).slice(0, count);
}
return { getLatestsSemVersionedTag };
}

View File

@ -0,0 +1,49 @@
import type { Octokit } from "@octokit/rest";
const per_page = 99;
export function listTagsFactory(params: { octokit: Octokit }) {
const { octokit } = params;
const octokit_repo_listTags = async (params: { owner: string; repo: string; per_page: number; page: number }) => {
return octokit.repos.listTags(params);
};
async function* listTags(params: { owner: string; repo: string }): AsyncGenerator<string> {
const { owner, repo } = params;
let page = 1;
while (true) {
const resp = await octokit_repo_listTags({
owner,
repo,
per_page,
"page": page++,
});
for (const branch of resp.data.map(({ name }) => name)) {
yield branch;
}
if (resp.data.length < 99) {
break;
}
}
}
/** Returns the same "latest" tag as deno.land/x, not actually the latest though */
async function getLatestTag(params: { owner: string; repo: string }): Promise<string | undefined> {
const { owner, repo } = params;
const itRes = await listTags({ owner, repo }).next();
if (itRes.done) {
return undefined;
}
return itRes.value;
}
return { listTags, getLatestTag };
}

View File

@ -5,6 +5,7 @@ import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useKcMessage } from "../i18n/useKcMessage";
import { useCssAndCx } from "tss-react";
import { useConstCallback } from "powerhooks/useConstCallback";
import type { FormEventHandler } from "react";
export const Login = memo(({ kcContext, ...props }: { kcContext: KcContextBase.Login } & KcProps) => {
const { social, realm, url, usernameEditDisabled, login, auth, registrationDisabled } = kcContext;
@ -15,7 +16,19 @@ export const Login = memo(({ kcContext, ...props }: { kcContext: KcContextBase.L
const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false);
const onSubmit = useConstCallback(() => (setIsLoginButtonDisabled(true), true));
const onSubmit = useConstCallback<FormEventHandler<HTMLFormElement>>(e => {
e.preventDefault();
setIsLoginButtonDisabled(true);
const formElement = e.target as HTMLFormElement;
//NOTE: Even if we login with email Keycloak expect username and password in
//the POST request.
formElement.querySelector("input[name='email']")?.setAttribute("name", "username");
formElement.submit();
});
return (
<Template
@ -33,27 +46,40 @@ export const Login = memo(({ kcContext, ...props }: { kcContext: KcContextBase.L
{realm.password && (
<form id="kc-form-login" onSubmit={onSubmit} action={url.loginAction} method="post">
<div className={cx(props.kcFormGroupClass)}>
<label htmlFor="username" className={cx(props.kcLabelClass)}>
{!realm.loginWithEmailAllowed
? msg("username")
: !realm.registrationEmailAsUsername
? msg("usernameOrEmail")
: msg("email")}
</label>
<input
tabIndex={1}
id="username"
className={cx(props.kcInputClass)}
name="username"
defaultValue={login.username ?? ""}
type="text"
{...(usernameEditDisabled
? { "disabled": true }
: {
"autoFocus": true,
"autoComplete": "off",
})}
/>
{(() => {
const label = !realm.loginWithEmailAllowed
? "username"
: realm.registrationEmailAsUsername
? "email"
: "usernameOrEmail";
const autoCompleteHelper: typeof label = label === "usernameOrEmail" ? "username" : label;
return (
<>
<label htmlFor={autoCompleteHelper} className={cx(props.kcLabelClass)}>
{msg(label)}
</label>
<input
tabIndex={1}
id={autoCompleteHelper}
className={cx(props.kcInputClass)}
//NOTE: This is used by Google Chrome auto fill so we use it to tell
//the browser how to pre fill the form but before submit we put it back
//to username because it is what keycloak expects.
name={autoCompleteHelper}
defaultValue={login.username ?? ""}
type="text"
{...(usernameEditDisabled
? { "disabled": true }
: {
"autoFocus": true,
"autoComplete": "off",
})}
/>
</>
);
})()}
</div>
<div className={cx(props.kcFormGroupClass)}>
<label htmlFor="password" className={cx(props.kcLabelClass)}>

View File

@ -95,7 +95,7 @@ const UserProfileFormFields = memo(({ kcContext, onIsFormSubmittableValueChange,
{
target: { value },
},
]: [React.ChangeEvent<HTMLInputElement>],
]: [React.ChangeEvent<HTMLInputElement | HTMLSelectElement>],
) =>
formValidationReducer({
"action": "update value",
@ -148,26 +148,50 @@ const UserProfileFormFields = memo(({ kcContext, onIsFormSubmittableValueChange,
{attribute.required && <>*</>}
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type={(() => {
switch (attribute.name) {
case "password-confirm":
case "password":
return "password";
default:
return "text";
}
})()}
id={attribute.name}
name={attribute.name}
value={value}
onChange={onChangeFactory(attribute.name)}
className={cx(props.kcInputClass)}
aria-invalid={displayableErrors.length !== 0}
disabled={attribute.readOnly}
autoComplete={attribute.autocomplete}
onBlur={onBlurFactory(attribute.name)}
/>
{(() => {
const { options } = attribute.validators;
if (options !== undefined) {
return (
<select
id={attribute.name}
name={attribute.name}
onChange={onChangeFactory(attribute.name)}
onBlur={onBlurFactory(attribute.name)}
value={value}
>
{options.options.map(option => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
);
}
return (
<input
type={(() => {
switch (attribute.name) {
case "password-confirm":
case "password":
return "password";
default:
return "text";
}
})()}
id={attribute.name}
name={attribute.name}
value={value}
onChange={onChangeFactory(attribute.name)}
className={cx(props.kcInputClass)}
aria-invalid={displayableErrors.length !== 0}
disabled={attribute.readOnly}
autoComplete={attribute.autocomplete}
onBlur={onBlurFactory(attribute.name)}
/>
);
})()}
{displayableErrors.length !== 0 && (
<span
id={`input-error-${attribute.name}`}

View File

@ -68,11 +68,17 @@ export const Template = memo((props: TemplateProps) => {
assert(locale !== undefined);
if (kcLanguageTag === getBestMatchAmongKcLanguageTag(locale.current)) {
const kcContext_kcLanguageTag = getBestMatchAmongKcLanguageTag(locale.current);
if (["error.ftl", "info.ftl", "login-page-expired.ftl"].indexOf(kcContext.pageId) >= 0) {
setKcLanguageTag(kcContext_kcLanguageTag);
return;
}
window.location.href = locale.supported.find(({ languageTag }) => languageTag === kcLanguageTag)!.url;
if (kcLanguageTag !== kcContext_kcLanguageTag) {
window.location.href = locale.supported.find(({ languageTag }) => languageTag === kcLanguageTag)!.url;
}
}, [kcLanguageTag]);
const [isExtraCssLoaded, setExtraCssLoaded] = useReducer(() => true, false);

View File

@ -315,6 +315,7 @@ export type Validators = Partial<{
name: string;
shouldBe: "equal" | "different";
};
options: Validators.Options;
}>;
export declare namespace Validators {
@ -331,6 +332,9 @@ export declare namespace Validators {
min?: `${number}`;
max?: `${number}`;
};
export type Options = {
options: string[];
};
}
assert<Equals<KcContextBase["pageId"], PageId>>();

View File

@ -7,6 +7,9 @@ import { exclude } from "tsafe/exclude";
import { assert } from "tsafe/assert";
import type { ExtendsKcContextBase } from "./getKcContextFromWindow";
import { getKcContextFromWindow } from "./getKcContextFromWindow";
import { pathJoin } from "../tools/pathJoin";
import { pathBasename } from "../tools/pathBasename";
import { resourcesCommonPath } from "./kcContextMocks/urlResourcesPath";
export function getKcContext<KcContextExtended extends { pageId: string } = never>(params?: {
mockPageId?: ExtendsKcContextBase<KcContextExtended>["pageId"];
@ -93,5 +96,13 @@ export function getKcContext<KcContextExtended extends { pageId: string } = neve
return { kcContext };
}
return { "kcContext": getKcContextFromWindow<KcContextExtended>() };
const kcContext = getKcContextFromWindow<KcContextExtended>();
if (kcContext !== undefined) {
const { url } = kcContext;
url.resourcesCommonPath = pathJoin(url.resourcesPath, pathBasename(resourcesCommonPath));
}
return { kcContext };
}

View File

@ -2,4 +2,4 @@ import { pathJoin } from "../../tools/pathJoin";
export const subDirOfPublicDirBasename = "keycloak_static";
export const resourcesPath = pathJoin(subDirOfPublicDirBasename, "resources");
export const resourcesCommonPath = pathJoin(subDirOfPublicDirBasename, "resources_common");
export const resourcesCommonPath = pathJoin(resourcesPath, "resources_common");

View File

@ -10,6 +10,7 @@ const kcMessages = {
"shouldBeDifferent": "{0} should be different to {1}",
"shouldMatchPattern": "Pattern should match: `/{0}/`",
"mustBeAnInteger": "Must be an integer",
"notAValidOption": "Not a valid option",
},
"fr": {
...kcMessagesBase["fr"],
@ -18,6 +19,7 @@ const kcMessages = {
"shouldBeDifferent": "{0} doit être différent de {1}",
"shouldMatchPattern": "Dois respecter le schéma: `/{0}/`",
"mustBeAnInteger": "Doit être un nombre entiers",
"notAValidOption": "N'est pas une option valide",
/* spell-checker: enable */
},
};

View File

@ -0,0 +1,3 @@
export function pathBasename(path: string) {
return path.split("/").reverse()[0];
}

View File

@ -213,7 +213,7 @@ export function useGetErrors(params: {
break scope;
}
const msgArgs = ["invalidEmailMessage"] as const;
const msgArgs = [id<MessageKey>("invalidEmailMessage")] as const;
errors.push({
validatorName,
@ -276,6 +276,32 @@ export function useGetErrors(params: {
}
}
scope: {
const validatorName = "options";
const validator = validators[validatorName];
if (validator === undefined) {
break scope;
}
if (value === "") {
break scope;
}
if (validator.options.indexOf(value) >= 0) {
break scope;
}
const msgArgs = [id<MessageKey>("notAValidOption")] as const;
errors.push({
validatorName,
"errorMessage": <Fragment key={errors.length}>{advancedMsg(...msgArgs)}</Fragment>,
"errorMessageStr": advancedMsgStr(...msgArgs),
});
}
//TODO: Implement missing validators.
return errors;

View File

@ -8,6 +8,7 @@ generateKeycloakThemeResources({
"themeName": "keycloakify-demo-app",
"reactAppBuildDirPath": pathJoin(sampleReactProjectDirPath, "build"),
"keycloakThemeBuildingDirPath": pathJoin(sampleReactProjectDirPath, "build_keycloak_theme"),
"keycloakThemeEmailDirPath": pathJoin(sampleReactProjectDirPath, "keycloak_theme_email"),
"urlPathname": "/keycloakify-demo-app/",
"urlOrigin": undefined,
"extraPagesId": ["my-custom-page.ftl"],

217
yarn.lock
View File

@ -30,6 +30,17 @@
dependencies:
regenerator-runtime "^0.13.4"
"@emotion/cache@*":
version "11.7.1"
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.7.1.tgz#08d080e396a42e0037848214e8aa7bf879065539"
integrity sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A==
dependencies:
"@emotion/memoize" "^0.7.4"
"@emotion/sheet" "^1.1.0"
"@emotion/utils" "^1.0.0"
"@emotion/weak-memoize" "^0.2.5"
stylis "4.0.13"
"@emotion/cache@^11.4.0":
version "11.4.0"
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.4.0.tgz#293fc9d9a7a38b9aad8e9337e5014366c3b09ac0"
@ -80,6 +91,11 @@
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.0.2.tgz#1d9ffde531714ba28e62dac6a996a8b1089719d0"
integrity sha512-QQPB1B70JEVUHuNtzjHftMGv6eC3Y9wqavyarj4x4lg47RACkeSfNo5pxIOKizwS9AEFLohsqoaxGQj4p0vSIw==
"@emotion/sheet@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.1.0.tgz#56d99c41f0a1cda2726a05aa6a20afd4c63e58d2"
integrity sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==
"@emotion/unitless@^0.7.5":
version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
@ -95,6 +111,107 @@
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
"@octokit/auth-token@^2.4.4":
version "2.5.0"
resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.5.0.tgz#27c37ea26c205f28443402477ffd261311f21e36"
integrity sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==
dependencies:
"@octokit/types" "^6.0.3"
"@octokit/core@^3.5.1":
version "3.6.0"
resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.6.0.tgz#3376cb9f3008d9b3d110370d90e0a1fcd5fe6085"
integrity sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==
dependencies:
"@octokit/auth-token" "^2.4.4"
"@octokit/graphql" "^4.5.8"
"@octokit/request" "^5.6.3"
"@octokit/request-error" "^2.0.5"
"@octokit/types" "^6.0.3"
before-after-hook "^2.2.0"
universal-user-agent "^6.0.0"
"@octokit/endpoint@^6.0.1":
version "6.0.12"
resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658"
integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==
dependencies:
"@octokit/types" "^6.0.3"
is-plain-object "^5.0.0"
universal-user-agent "^6.0.0"
"@octokit/graphql@^4.5.8":
version "4.8.0"
resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.8.0.tgz#664d9b11c0e12112cbf78e10f49a05959aa22cc3"
integrity sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==
dependencies:
"@octokit/request" "^5.6.0"
"@octokit/types" "^6.0.3"
universal-user-agent "^6.0.0"
"@octokit/openapi-types@^11.2.0":
version "11.2.0"
resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-11.2.0.tgz#b38d7fc3736d52a1e96b230c1ccd4a58a2f400a6"
integrity sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==
"@octokit/plugin-paginate-rest@^2.16.8":
version "2.17.0"
resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz#32e9c7cab2a374421d3d0de239102287d791bce7"
integrity sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==
dependencies:
"@octokit/types" "^6.34.0"
"@octokit/plugin-request-log@^1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85"
integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==
"@octokit/plugin-rest-endpoint-methods@^5.12.0":
version "5.13.0"
resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz#8c46109021a3412233f6f50d28786f8e552427ba"
integrity sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==
dependencies:
"@octokit/types" "^6.34.0"
deprecation "^2.3.1"
"@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0":
version "2.1.0"
resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677"
integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==
dependencies:
"@octokit/types" "^6.0.3"
deprecation "^2.0.0"
once "^1.4.0"
"@octokit/request@^5.6.0", "@octokit/request@^5.6.3":
version "5.6.3"
resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.3.tgz#19a022515a5bba965ac06c9d1334514eb50c48b0"
integrity sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==
dependencies:
"@octokit/endpoint" "^6.0.1"
"@octokit/request-error" "^2.1.0"
"@octokit/types" "^6.16.1"
is-plain-object "^5.0.0"
node-fetch "^2.6.7"
universal-user-agent "^6.0.0"
"@octokit/rest@^18.12.0":
version "18.12.0"
resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.12.0.tgz#f06bc4952fc87130308d810ca9d00e79f6988881"
integrity sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==
dependencies:
"@octokit/core" "^3.5.1"
"@octokit/plugin-paginate-rest" "^2.16.8"
"@octokit/plugin-request-log" "^1.0.4"
"@octokit/plugin-rest-endpoint-methods" "^5.12.0"
"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.34.0":
version "6.34.0"
resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.34.0.tgz#c6021333334d1ecfb5d370a8798162ddf1ae8218"
integrity sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==
dependencies:
"@octokit/openapi-types" "^11.2.0"
"@types/mdast@^3.0.0", "@types/mdast@^3.0.3":
version "3.0.10"
resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af"
@ -102,10 +219,10 @@
dependencies:
"@types/unist" "*"
"@types/node@^10.0.0":
version "10.17.60"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b"
integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==
"@types/node@^17.0.25":
version "17.0.25"
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.25.tgz#527051f3c2f77aa52e5dc74e45a3da5fb2301448"
integrity sha512-wANk6fBrUwdpY4isjWrKTufkrXdu1D2YHCot2fD/DfWxF5sMrVSA+KN7ydckvaTCh0HiqX9IVl0L5/ZoXg5M7w==
"@types/parse-json@^4.0.0":
version "4.0.0"
@ -149,6 +266,11 @@ ansi-colors@^4.1.1:
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
ansi-escapes@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
ansi-escapes@^4.3.0:
version "4.3.2"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
@ -190,6 +312,11 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
before-after-hook@^2.2.0:
version "2.2.2"
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e"
integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==
boolbase@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
@ -288,6 +415,13 @@ cli-cursor@^3.1.0:
dependencies:
restore-cursor "^3.1.0"
cli-select@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/cli-select/-/cli-select-1.1.2.tgz#456dced464b3346ca661b16a0e37fc4b28db4818"
integrity sha512-PSvWb8G0PPmBNDcz/uM2LkZN3Nn5JmhUl465tTfynQAXjKzFpmHbxStM6X/+awKp5DJuAaHMzzMPefT0suGm1w==
dependencies:
ansi-escapes "^3.2.0"
cli-truncate@2.1.0, cli-truncate@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7"
@ -423,6 +557,11 @@ debug@^4.0.0, debug@^4.3.2:
dependencies:
ms "2.1.2"
deprecation@^2.0.0, deprecation@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==
dom-serializer@^1.0.1, dom-serializer@^1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91"
@ -536,15 +675,6 @@ event-emitter@^0.3.5:
d "1"
es5-ext "~0.10.14"
evt@2.0.0-beta.38:
version "2.0.0-beta.38"
resolved "https://registry.yarnpkg.com/evt/-/evt-2.0.0-beta.38.tgz#9886a08889cddba1984a236efd6d352f9d6a6539"
integrity sha512-b35iBAVlDHVHOqgWzjSBJZu3C0GRZ/2cIHfNFuMSWwLT/WJO2n/4x7hg6BpaNJlSRywBAtf8KcU1GUyVfEhVIA==
dependencies:
minimal-polyfills "^2.2.1"
run-exclusive "^2.2.14"
tsafe "^0.4.1"
evt@2.0.0-beta.39:
version "2.0.0-beta.39"
resolved "https://registry.yarnpkg.com/evt/-/evt-2.0.0-beta.39.tgz#3c859a83b35940f7eecfb5f148f03b7cbf3fee51"
@ -782,6 +912,11 @@ is-plain-obj@^2.0.0:
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
is-plain-object@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
is-promise@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1"
@ -991,6 +1126,13 @@ next-tick@~1.0.0:
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
node-fetch@^2.6.7:
version "2.6.7"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
dependencies:
whatwg-url "^5.0.0"
noms@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859"
@ -1023,7 +1165,7 @@ object-assign@^4.1.1:
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
once@^1.3.0:
once@^1.3.0, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
@ -1148,12 +1290,12 @@ please-upgrade-node@^3.2.0:
dependencies:
semver-compare "^1.0.0"
powerhooks@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/powerhooks/-/powerhooks-0.11.0.tgz#923749ed405a1189759cd3f16d36bd5efacfd40c"
integrity sha512-I48J5vJqlTRiR3eH6svxiIYLutdedu2YEd3uhCmK+pRg2jcuourVwp1UYORI/EzbKC9vv0X/0Vd/SZ6e07rYtA==
powerhooks@^0.14.0:
version "0.14.0"
resolved "https://registry.yarnpkg.com/powerhooks/-/powerhooks-0.14.0.tgz#44dd201f470761362a139ae2cb51eaa658ed5e3e"
integrity sha512-jWrRHyqev7Lh3MId7h1mNxs+fgegr8liHN17AaHxMgrXI6KxJ14B3Pe1It4FIRWJ4Z1dxsA734FerFGZ3Vgdkg==
dependencies:
evt "2.0.0-beta.38"
evt "2.0.0-beta.39"
memoizee "^0.4.15"
resize-observer-polyfill "^1.5.1"
tsafe "^0.8.1"
@ -1409,6 +1551,11 @@ strip-final-newline@^2.0.0:
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
stylis@4.0.13:
version "4.0.13"
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91"
integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==
stylis@^4.0.3:
version "4.0.10"
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.10.tgz#446512d1097197ab3f02fb3c258358c3f7a14240"
@ -1463,6 +1610,11 @@ to-regex-range@^5.0.1:
dependencies:
is-number "^7.0.0"
tr46@~0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=
trough@^1.0.0:
version "1.0.5"
resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406"
@ -1493,11 +1645,12 @@ tslib@^2.2.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==
tss-react@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-3.0.0.tgz#b084e1d10d1ea23c925b6a2141c1e91a0c5e9a2d"
integrity sha512-aZ/DZEuUvqki/1TKKBM4OmRx6TI5lcaF4BLMo0D8lyT/5S7zRFaAdVfAlsirHcQNgOAdf5IjLUcEbCYWcY6PJw==
tss-react@^3.5.2:
version "3.5.2"
resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-3.5.2.tgz#1b5db1f4a71fe62c939eed5368ea7809ca2ad0a9"
integrity sha512-IgGizaOhbntrWdh2EISJYnhYEEWXXWf3sn5aa8LYf7e59NCM5mg0PxJuEoLx9pLG5WlJF80zTRN/Y1Jnjw9LYA==
dependencies:
"@emotion/cache" "*"
"@emotion/serialize" "*"
"@emotion/utils" "*"
@ -1567,6 +1720,11 @@ unist-util-visit@^2.0.0:
unist-util-is "^4.0.0"
unist-util-visit-parents "^3.0.0"
universal-user-agent@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee"
integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==
untildify@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b"
@ -1595,6 +1753,19 @@ vfile@^4.0.0:
unist-util-stringify-position "^2.0.0"
vfile-message "^2.0.0"
webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=
whatwg-url@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0=
dependencies:
tr46 "~0.0.3"
webidl-conversions "^3.0.0"
which-pm-runs@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb"