diff --git a/authentik/providers/oauth2/views/token.py b/authentik/providers/oauth2/views/token.py index 78931b6c8..3bf134b09 100644 --- a/authentik/providers/oauth2/views/token.py +++ b/authentik/providers/oauth2/views/token.py @@ -490,11 +490,13 @@ class TokenView(View): auth_time=self.params.authorization_code.auth_time, session_id=self.params.authorization_code.session_id, ) - access_token.id_token = IDToken.new( + access_id_token = IDToken.new( self.provider, access_token, self.request, ) + access_id_token.nonce = self.params.authorization_code.nonce + access_token.id_token = access_id_token access_token.save() response = { diff --git a/authentik/rbac/api/rbac_roles.py b/authentik/rbac/api/rbac_roles.py index 1c48169a2..1ef13c115 100644 --- a/authentik/rbac/api/rbac_roles.py +++ b/authentik/rbac/api/rbac_roles.py @@ -24,7 +24,10 @@ class ExtraRoleObjectPermissionSerializer(RoleObjectPermissionSerializer): def get_app_label_verbose(self, instance: GroupObjectPermission) -> str: """Get app label from permission's model""" - return apps.get_app_config(instance.content_type.app_label).verbose_name + try: + return apps.get_app_config(instance.content_type.app_label).verbose_name + except LookupError: + return instance.content_type.app_label def get_model_verbose(self, instance: GroupObjectPermission) -> str: """Get model label from permission's model""" diff --git a/authentik/rbac/api/rbac_users.py b/authentik/rbac/api/rbac_users.py index 636b327f3..6de2e8bce 100644 --- a/authentik/rbac/api/rbac_users.py +++ b/authentik/rbac/api/rbac_users.py @@ -24,7 +24,10 @@ class ExtraUserObjectPermissionSerializer(UserObjectPermissionSerializer): def get_app_label_verbose(self, instance: UserObjectPermission) -> str: """Get app label from permission's model""" - return apps.get_app_config(instance.content_type.app_label).verbose_name + try: + return apps.get_app_config(instance.content_type.app_label).verbose_name + except LookupError: + return instance.content_type.app_label def get_model_verbose(self, instance: UserObjectPermission) -> str: """Get model label from permission's model""" diff --git a/authentik/stages/user_login/middleware.py b/authentik/stages/user_login/middleware.py index 8fea4c408..73e42e1ac 100644 --- a/authentik/stages/user_login/middleware.py +++ b/authentik/stages/user_login/middleware.py @@ -109,7 +109,10 @@ class BoundSessionMiddleware(SessionMiddleware): self.recheck_session_geo(configured_binding_geo, last_ip, new_ip) # If we got to this point without any error being raised, we need to # update the last saved IP to the current one - request.session[SESSION_KEY_LAST_IP] = new_ip + if SESSION_KEY_BINDING_NET in request.session or SESSION_KEY_BINDING_GEO in request.session: + # Only set the last IP in the session if there's a binding specified + # (== basically requires the user to be logged in) + request.session[SESSION_KEY_LAST_IP] = new_ip AuthenticatedSession.objects.filter(session_key=request.session.session_key).update( last_ip=new_ip, last_user_agent=request.META.get("HTTP_USER_AGENT", "") ) diff --git a/go.mod b/go.mod index ed9759796..aadc18f18 100644 --- a/go.mod +++ b/go.mod @@ -23,15 +23,15 @@ require ( github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 github.com/pires/go-proxyproto v0.7.0 github.com/prometheus/client_golang v1.18.0 - github.com/redis/go-redis/v9 v9.3.1 + github.com/redis/go-redis/v9 v9.4.0 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 github.com/wwt/guac v1.3.2 - goauthentik.io/api/v3 v3.2023105.3 + goauthentik.io/api/v3 v3.2023105.5 golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab golang.org/x/oauth2 v0.15.0 - golang.org/x/sync v0.5.0 + golang.org/x/sync v0.6.0 gopkg.in/yaml.v2 v2.4.0 layeh.com/radius v0.0.0-20210819152912-ad72663a72ab ) diff --git a/go.sum b/go.sum index 3000d744b..fcbdc7618 100644 --- a/go.sum +++ b/go.sum @@ -258,8 +258,8 @@ github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lne github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/redis/go-redis/v9 v9.3.1 h1:KqdY8U+3X6z+iACvumCNxnoluToB+9Me+TvyFa21Mds= -github.com/redis/go-redis/v9 v9.3.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwyKk= +github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= @@ -316,8 +316,8 @@ go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYO go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= -goauthentik.io/api/v3 v3.2023105.3 h1:x0pMJIKkbN198OOssqA94h8bO6ft9gwG8bpZqZL7WVg= -goauthentik.io/api/v3 v3.2023105.3/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw= +goauthentik.io/api/v3 v3.2023105.5 h1:wIL3Q0jry1g4kRWpH/Dv1sQqhzuL4BLC+uP/Tar1P/g= +goauthentik.io/api/v3 v3.2023105.5/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -415,8 +415,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/tests/wdio/package-lock.json b/tests/wdio/package-lock.json index 253a3737e..8db5ea669 100644 --- a/tests/wdio/package-lock.json +++ b/tests/wdio/package-lock.json @@ -10,8 +10,8 @@ }, "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.3.0", - "@typescript-eslint/eslint-plugin": "^6.17.0", - "@typescript-eslint/parser": "^6.17.0", + "@typescript-eslint/eslint-plugin": "^6.18.0", + "@typescript-eslint/parser": "^6.18.0", "@wdio/cli": "^8.27.1", "@wdio/local-runner": "^8.27.0", "@wdio/mocha-framework": "^8.27.0", @@ -953,16 +953,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.17.0.tgz", - "integrity": "sha512-Vih/4xLXmY7V490dGwBQJTpIZxH4ZFH6eCVmQ4RFkB+wmaCTDAx4dtgoWwMNGKLkqRY1L6rPqzEbjorRnDo4rQ==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.0.tgz", + "integrity": "sha512-3lqEvQUdCozi6d1mddWqd+kf8KxmGq2Plzx36BlkjuQe3rSTm/O98cLf0A4uDO+a5N1KD2SeEEl6fW97YHY+6w==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.17.0", - "@typescript-eslint/type-utils": "6.17.0", - "@typescript-eslint/utils": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0", + "@typescript-eslint/scope-manager": "6.18.0", + "@typescript-eslint/type-utils": "6.18.0", + "@typescript-eslint/utils": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -988,15 +988,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.17.0.tgz", - "integrity": "sha512-C4bBaX2orvhK+LlwrY8oWGmSl4WolCfYm513gEccdWZj0CwGadbIADb0FtVEcI+WzUyjyoBj2JRP8g25E6IB8A==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.0.tgz", + "integrity": "sha512-v6uR68SFvqhNQT41frCMCQpsP+5vySy6IdgjlzUWoo7ALCnpaWYcz/Ij2k4L8cEsL0wkvOviCMpjmtRtHNOKzA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.17.0", - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/typescript-estree": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0", + "@typescript-eslint/scope-manager": "6.18.0", + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/typescript-estree": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0", "debug": "^4.3.4" }, "engines": { @@ -1016,13 +1016,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.17.0.tgz", - "integrity": "sha512-RX7a8lwgOi7am0k17NUO0+ZmMOX4PpjLtLRgLmT1d3lBYdWH4ssBUbwdmc5pdRX8rXon8v9x8vaoOSpkHfcXGA==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.0.tgz", + "integrity": "sha512-o/UoDT2NgOJ2VfHpfr+KBY2ErWvCySNUIX/X7O9g8Zzt/tXdpfEU43qbNk8LVuWUT2E0ptzTWXh79i74PP0twA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0" + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1033,13 +1033,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.17.0.tgz", - "integrity": "sha512-hDXcWmnbtn4P2B37ka3nil3yi3VCQO2QEB9gBiHJmQp5wmyQWqnjA85+ZcE8c4FqnaB6lBwMrPkgd4aBYz3iNg==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.0.tgz", + "integrity": "sha512-ZeMtrXnGmTcHciJN1+u2CigWEEXgy1ufoxtWcHORt5kGvpjjIlK9MUhzHm4RM8iVy6dqSaZA/6PVkX6+r+ChjQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.17.0", - "@typescript-eslint/utils": "6.17.0", + "@typescript-eslint/typescript-estree": "6.18.0", + "@typescript-eslint/utils": "6.18.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1060,9 +1060,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.17.0.tgz", - "integrity": "sha512-qRKs9tvc3a4RBcL/9PXtKSehI/q8wuU9xYJxe97WFxnzH8NWWtcW3ffNS+EWg8uPvIerhjsEZ+rHtDqOCiH57A==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.0.tgz", + "integrity": "sha512-/RFVIccwkwSdW/1zeMx3hADShWbgBxBnV/qSrex6607isYjj05t36P6LyONgqdUrNLl5TYU8NIKdHUYpFvExkA==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1073,13 +1073,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.17.0.tgz", - "integrity": "sha512-gVQe+SLdNPfjlJn5VNGhlOhrXz4cajwFd5kAgWtZ9dCZf4XJf8xmgCTLIqec7aha3JwgLI2CK6GY1043FRxZwg==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.0.tgz", + "integrity": "sha512-klNvl+Ql4NsBNGB4W9TZ2Od03lm7aGvTbs0wYaFYsplVPhr+oeXjlPZCDI4U9jgJIDK38W1FKhacCFzCC+nbIg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0", + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1125,17 +1125,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.17.0.tgz", - "integrity": "sha512-LofsSPjN/ITNkzV47hxas2JCsNCEnGhVvocfyOcLzT9c/tSZE7SfhS/iWtzP1lKNOEfLhRTZz6xqI8N2RzweSQ==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.0.tgz", + "integrity": "sha512-wiKKCbUeDPGaYEYQh1S580dGxJ/V9HI7K5sbGAVklyf+o5g3O+adnS4UNJajplF4e7z2q0uVBaTdT/yLb4XAVA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.17.0", - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/typescript-estree": "6.17.0", + "@typescript-eslint/scope-manager": "6.18.0", + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/typescript-estree": "6.18.0", "semver": "^7.5.4" }, "engines": { @@ -1150,12 +1150,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.17.0.tgz", - "integrity": "sha512-H6VwB/k3IuIeQOyYczyyKN8wH6ed8EwliaYHLxOIhyF0dYEIsN8+Bk3GE19qafeMKyZJJHP8+O1HiFhFLUNKSg==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.0.tgz", + "integrity": "sha512-1wetAlSZpewRDb2h9p/Q8kRjdGuqdTAQbkJIOUMLug2LBLG+QOjiWoSj6/3B/hA9/tVTFFdtiKvAYoYnSRW/RA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/types": "6.18.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { diff --git a/tests/wdio/package.json b/tests/wdio/package.json index a41e6c37b..7afde4b67 100644 --- a/tests/wdio/package.json +++ b/tests/wdio/package.json @@ -4,8 +4,8 @@ "type": "module", "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.3.0", - "@typescript-eslint/eslint-plugin": "^6.17.0", - "@typescript-eslint/parser": "^6.17.0", + "@typescript-eslint/eslint-plugin": "^6.18.0", + "@typescript-eslint/parser": "^6.18.0", "@wdio/cli": "^8.27.1", "@wdio/local-runner": "^8.27.0", "@wdio/mocha-framework": "^8.27.0", diff --git a/web/README.md b/web/README.md index 24cc5c622..9a8c1c846 100644 --- a/web/README.md +++ b/web/README.md @@ -3,6 +3,92 @@ This is the default UI for the authentik server. The documentation is going to be a little sparse for awhile, but at least let's get started. +# The Theory of the authentik UI + +In Peter Naur's 1985 essay [Programming as Theory +Building](https://pages.cs.wisc.edu/~remzi/Naur.pdf), programming is described as creating a mental +model of how a program _should_ run, then writing the code to test if the program _can_ run that +way. + +The mental model for the authentik UI is straightforward. There are five "applications" within the +UI, each with its own base URL, router, and responsibilities, and each application needs as many as +three contexts in which to run. + +The three contexts corresponds to objects in the API's `model` section, so let's use those names. + +- The root `Config`. The root configuration object of the server, containing mostly caching and + error reporting information. This is misleading, however; the `Config` object contains some user + information, specifically a list of permissions the current user (or "no user") has. +- The root `CurrentTenant`. This describes the `Brand` information UIs should use, such as themes, + logos, favicon, and specific default flows for logging in, logging out, and recovering a user + password. +- The current `SessionUser`, the person logged in: username, display name, and various states. + (Note: the authentik server permits administrators to "impersonate" any other user in order to + debug their authentikation experience. If impersonation is active, the `user` field reflects that + user, but it also includes a field, `original`, with the administrator's information.) + +(There is a fourth context object, Version, but its use is limited to displaying version information +and checking for upgrades. Just be aware that you will see it, but you will probably never interact +with it.) + +There are five applications. Two (`loading` and `api-browser`) are trivial applications whose +insides are provided by third-party libraries (Patternfly and Rapidoc, respectively). The other +three are actual applications. The descriptions below are wholly from the view of the user's +experience: + +- `Flow`: From a given URL, displays a form that requests information from the user to accomplish a + task. Some tasks require the user to be logged in, but many (such as logging in itself!) + obviously do not. +- `User`: Provides the user with access to the applications they can access, plus a few user + settings. +- `Admin`: Provides someone with super-user permissions access to the administrative functions of + the authentik server. + +**Mental Model** + +- Upon initialization, _every_ authentik UI application fetches `Config` and `CurrentTenant`. `User` + and `Admin` will also attempt to load the `SessionUser`; if there is none, the user is kicked out + to the `Flow` for logging into authentik itself. +- `Config`, `CurrentTenant`, and `SessionUser`, are provided by the `@goauthentik/api` application, + not by the codebase under `./web`. (Where you are now). +- `Flow`, `User`, and `Admin` are all called `Interfaces` and are found in + `./web/src/flow/FlowInterface`, `./web/src/user/UserInterface`, `./web/src/admin/AdminInterface`, + respectively. + +Inside each of these you will find, in a hierarchal order: + +- The context layer described above + - A theme managing layer + - The orchestration layer: + - web socket handler for server-generated events + - The router + - Individual routes for each vertical slice and its relationship to other objects: + +Each slice corresponds to an object table on the server, and each slice _usually_ consists of the +following: + +- A paginated collection display, usually using the `Table` foundation (found in + `./web/src/elements/Table`) +- The ability to view an individual object from the collection, which you may be able to: + - Edit + - Delete +- A form for creating a new object +- Tabs showing that object's relationship to other objects + - Interactive elements for changing or deleting those relationships, or creating new ones. + - The ability to create new objects with which to have that relationship, if they're not part of + the core objects (such as User->MFA authenticator apps, since the latter is not a "core" object + and has no tab of its own). + +We are still a bit "all over the place" with respect to sub-units and common units; there are +folders `common`, `elements`, and `components`, and ideally they would be: + +- `common`: non-UI related libraries all of our applications need +- `elements`: UI elements shared among multiple applications that do not need context +- `components`: UI elements shared among multiple that use one or more context + +... but at the moment there are some context-sensitive elements, and some UI-related stuff in +`common`. + # Comments **NOTE:** The comments in this section are for specific changes to this repository that cannot be diff --git a/web/lit-localize.json b/web/lit-localize.json index 19a901a91..3c9564de8 100644 --- a/web/lit-localize.json +++ b/web/lit-localize.json @@ -3,15 +3,18 @@ "sourceLocale": "en", "targetLocales": [ "en", - "pseudo-LOCALE", - "fr", - "tr", + "de", "es", + "fr", + "ko", + "nl", "pl", - "zh_TW", + "tr", "zh-Hans", "zh-Hant", - "de" + "zh-CN", + "zh_TW", + "pseudo-LOCALE" ], "tsConfig": "./tsconfig.json", "output": { diff --git a/web/package-lock.json b/web/package-lock.json index 0124f6848..8495c62aa 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -24,8 +24,8 @@ "@open-wc/lit-helpers": "^0.6.0", "@patternfly/elements": "^2.4.0", "@patternfly/patternfly": "^4.224.2", - "@sentry/browser": "^7.91.0", - "@sentry/tracing": "^7.91.0", + "@sentry/browser": "^7.92.0", + "@sentry/tracing": "^7.92.0", "@webcomponents/webcomponentsjs": "^2.8.0", "base64-js": "^1.5.1", "chart.js": "^4.4.1", @@ -74,8 +74,8 @@ "@types/codemirror": "5.60.15", "@types/grecaptcha": "^3.0.7", "@types/guacamole-common-js": "1.5.2", - "@typescript-eslint/eslint-plugin": "^6.17.0", - "@typescript-eslint/parser": "^6.17.0", + "@typescript-eslint/eslint-plugin": "^6.18.0", + "@typescript-eslint/parser": "^6.18.0", "babel-plugin-macros": "^3.1.0", "babel-plugin-tsconfig-paths": "^1.0.3", "cross-env": "^7.0.3", @@ -93,7 +93,7 @@ "pyright": "=1.1.338", "react": "^18.2.0", "react-dom": "^18.2.0", - "rollup": "^4.9.2", + "rollup": "^4.9.4", "rollup-plugin-copy": "^3.5.0", "rollup-plugin-cssimport": "^1.0.3", "rollup-plugin-modify": "^3.0.0", @@ -4583,9 +4583,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.2.tgz", - "integrity": "sha512-RKzxFxBHq9ysZ83fn8Iduv3A283K7zPPYuhL/z9CQuyFrjwpErJx0h4aeb/bnJ+q29GRLgJpY66ceQ/Wcsn3wA==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.4.tgz", + "integrity": "sha512-ub/SN3yWqIv5CWiAZPHVS1DloyZsJbtXmX4HxUTIpS0BHm9pW5iYBo2mIZi+hE3AeiTzHz33blwSnhdUo+9NpA==", "cpu": [ "arm" ], @@ -4596,9 +4596,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.2.tgz", - "integrity": "sha512-yZ+MUbnwf3SHNWQKJyWh88ii2HbuHCFQnAYTeeO1Nb8SyEiWASEi5dQUygt3ClHWtA9My9RQAYkjvrsZ0WK8Xg==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.4.tgz", + "integrity": "sha512-ehcBrOR5XTl0W0t2WxfTyHCR/3Cq2jfb+I4W+Ch8Y9b5G+vbAecVv0Fx/J1QKktOrgUYsIKxWAKgIpvw56IFNA==", "cpu": [ "arm64" ], @@ -4609,9 +4609,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.2.tgz", - "integrity": "sha512-vqJ/pAUh95FLc/G/3+xPqlSBgilPnauVf2EXOQCZzhZJCXDXt/5A8mH/OzU6iWhb3CNk5hPJrh8pqJUPldN5zw==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.4.tgz", + "integrity": "sha512-1fzh1lWExwSTWy8vJPnNbNM02WZDS8AW3McEOb7wW+nPChLKf3WG2aG7fhaUmfX5FKw9zhsF5+MBwArGyNM7NA==", "cpu": [ "arm64" ], @@ -4622,9 +4622,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.2.tgz", - "integrity": "sha512-otPHsN5LlvedOprd3SdfrRNhOahhVBwJpepVKUN58L0RnC29vOAej1vMEaVU6DadnpjivVsNTM5eNt0CcwTahw==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.4.tgz", + "integrity": "sha512-Gc6cukkF38RcYQ6uPdiXi70JB0f29CwcQ7+r4QpfNpQFVHXRd0DfWFidoGxjSx1DwOETM97JPz1RXL5ISSB0pA==", "cpu": [ "x64" ], @@ -4635,9 +4635,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.2.tgz", - "integrity": "sha512-ewG5yJSp+zYKBYQLbd1CUA7b1lSfIdo9zJShNTyc2ZP1rcPrqyZcNlsHgs7v1zhgfdS+kW0p5frc0aVqhZCiYQ==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.4.tgz", + "integrity": "sha512-g21RTeFzoTl8GxosHbnQZ0/JkuFIB13C3T7Y0HtKzOXmoHhewLbVTFBQZu+z5m9STH6FZ7L/oPgU4Nm5ErN2fw==", "cpu": [ "arm" ], @@ -4648,9 +4648,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.2.tgz", - "integrity": "sha512-pL6QtV26W52aCWTG1IuFV3FMPL1m4wbsRG+qijIvgFO/VBsiXJjDPE/uiMdHBAO6YcpV4KvpKtd0v3WFbaxBtg==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.4.tgz", + "integrity": "sha512-TVYVWD/SYwWzGGnbfTkrNpdE4HON46orgMNHCivlXmlsSGQOx/OHHYiQcMIOx38/GWgwr/po2LBn7wypkWw/Mg==", "cpu": [ "arm64" ], @@ -4661,9 +4661,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.2.tgz", - "integrity": "sha512-On+cc5EpOaTwPSNetHXBuqylDW+765G/oqB9xGmWU3npEhCh8xu0xqHGUA+4xwZLqBbIZNcBlKSIYfkBm6ko7g==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.4.tgz", + "integrity": "sha512-XcKvuendwizYYhFxpvQ3xVpzje2HHImzg33wL9zvxtj77HvPStbSGI9czrdbfrf8DGMcNNReH9pVZv8qejAQ5A==", "cpu": [ "arm64" ], @@ -4674,9 +4674,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.2.tgz", - "integrity": "sha512-Wnx/IVMSZ31D/cO9HSsU46FjrPWHqtdF8+0eyZ1zIB5a6hXaZXghUKpRrC4D5DcRTZOjml2oBhXoqfGYyXKipw==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.4.tgz", + "integrity": "sha512-LFHS/8Q+I9YA0yVETyjonMJ3UA+DczeBd/MqNEzsGSTdNvSJa1OJZcSH8GiXLvcizgp9AlHs2walqRcqzjOi3A==", "cpu": [ "riscv64" ], @@ -4687,9 +4687,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.2.tgz", - "integrity": "sha512-ym5x1cj4mUAMBummxxRkI4pG5Vht1QMsJexwGP8547TZ0sox9fCLDHw9KCH9c1FO5d9GopvkaJsBIOkTKxksdw==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.4.tgz", + "integrity": "sha512-dIYgo+j1+yfy81i0YVU5KnQrIJZE8ERomx17ReU4GREjGtDW4X+nvkBak2xAUpyqLs4eleDSj3RrV72fQos7zw==", "cpu": [ "x64" ], @@ -4700,9 +4700,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.2.tgz", - "integrity": "sha512-m0hYELHGXdYx64D6IDDg/1vOJEaiV8f1G/iO+tejvRCJNSwK4jJ15e38JQy5Q6dGkn1M/9KcyEOwqmlZ2kqaZg==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.4.tgz", + "integrity": "sha512-RoaYxjdHQ5TPjaPrLsfKqR3pakMr3JGqZ+jZM0zP2IkDtsGa4CqYaWSfQmZVgFUCgLrTnzX+cnHS3nfl+kB6ZQ==", "cpu": [ "x64" ], @@ -4713,9 +4713,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.2.tgz", - "integrity": "sha512-x1CWburlbN5JjG+juenuNa4KdedBdXLjZMp56nHFSHTOsb/MI2DYiGzLtRGHNMyydPGffGId+VgjOMrcltOksA==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.4.tgz", + "integrity": "sha512-T8Q3XHV+Jjf5e49B4EAaLKV74BbX7/qYBRQ8Wop/+TyyU0k+vSjiLVSHNWdVd1goMjZcbhDmYZUYW5RFqkBNHQ==", "cpu": [ "arm64" ], @@ -4726,9 +4726,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.2.tgz", - "integrity": "sha512-VVzCB5yXR1QlfsH1Xw1zdzQ4Pxuzv+CPr5qpElpKhVxlxD3CRdfubAG9mJROl6/dmj5gVYDDWk8sC+j9BI9/kQ==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.4.tgz", + "integrity": "sha512-z+JQ7JirDUHAsMecVydnBPWLwJjbppU+7LZjffGf+Jvrxq+dVjIE7By163Sc9DKc3ADSU50qPVw0KonBS+a+HQ==", "cpu": [ "ia32" ], @@ -4739,9 +4739,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.2.tgz", - "integrity": "sha512-SYRedJi+mweatroB+6TTnJYLts0L0bosg531xnQWtklOI6dezEagx4Q0qDyvRdK+qgdA3YZpjjGuPFtxBmddBA==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.4.tgz", + "integrity": "sha512-LfdGXCV9rdEify1oxlN9eamvDSjv9md9ZVMAbNHA87xqIfFCxImxan9qZ8+Un54iK2nnqPlbnSi4R54ONtbWBw==", "cpu": [ "x64" ], @@ -4752,98 +4752,98 @@ ] }, "node_modules/@sentry-internal/feedback": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.91.0.tgz", - "integrity": "sha512-SJKTSaz68F5YIwF79EttBm915M2LnacgZMYRnRumyTmMKnebGhYQLwWbZdpaDvOa1U18dgRajDX8Qed/8A3tXw==", + "version": "7.92.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.92.0.tgz", + "integrity": "sha512-/jEALRtVqboxB9kcK2tag8QCO6XANTlGBb9RV3oeGXJe0DDNJXRq6wVZbfgztXJRrfgx4XVDcNt1pRVoGGG++g==", "dependencies": { - "@sentry/core": "7.91.0", - "@sentry/types": "7.91.0", - "@sentry/utils": "7.91.0" + "@sentry/core": "7.92.0", + "@sentry/types": "7.92.0", + "@sentry/utils": "7.92.0" }, "engines": { "node": ">=12" } }, "node_modules/@sentry-internal/tracing": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.91.0.tgz", - "integrity": "sha512-JH5y6gs6BS0its7WF2DhySu7nkhPDfZcdpAXldxzIlJpqFkuwQKLU5nkYJpiIyZz1NHYYtW5aum2bV2oCOdDRA==", + "version": "7.92.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.92.0.tgz", + "integrity": "sha512-ur55vPcUUUWFUX4eVLNP71ohswK7ZZpleNZw9Y1GfLqyI+0ILQUwjtzqItJrdClvVsdRZJMRmDV40Hp9Lbb9mA==", "dependencies": { - "@sentry/core": "7.91.0", - "@sentry/types": "7.91.0", - "@sentry/utils": "7.91.0" + "@sentry/core": "7.92.0", + "@sentry/types": "7.92.0", + "@sentry/utils": "7.92.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/browser": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.91.0.tgz", - "integrity": "sha512-lJv3x/xekzC/biiyAsVCioq2XnKNOZhI6jY3ZzLJZClYV8eKRi7D3KCsHRvMiCdGak1d/6sVp8F4NYY+YiWy1Q==", + "version": "7.92.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.92.0.tgz", + "integrity": "sha512-loMr02/zQ38u8aQhYLtIBg0i5n3ps2e3GUXrt3CdsJQdkRYfa62gcrE7SzvoEpMVHTk7VOI4fWGht8cWw/1k3A==", "dependencies": { - "@sentry-internal/feedback": "7.91.0", - "@sentry-internal/tracing": "7.91.0", - "@sentry/core": "7.91.0", - "@sentry/replay": "7.91.0", - "@sentry/types": "7.91.0", - "@sentry/utils": "7.91.0" + "@sentry-internal/feedback": "7.92.0", + "@sentry-internal/tracing": "7.92.0", + "@sentry/core": "7.92.0", + "@sentry/replay": "7.92.0", + "@sentry/types": "7.92.0", + "@sentry/utils": "7.92.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/core": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.91.0.tgz", - "integrity": "sha512-tu+gYq4JrTdrR+YSh5IVHF0fJi/Pi9y0HZ5H9HnYy+UMcXIotxf6hIEaC6ZKGeLWkGXffz2gKpQLe/g6vy/lPA==", + "version": "7.92.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.92.0.tgz", + "integrity": "sha512-1Tly7YB2I1byI5xb0Cwrxs56Rhww+6mQ7m9P7rTmdC3/ijOzbEoohtYIUPwcooCEarpbEJe/tAayRx6BrH2UbQ==", "dependencies": { - "@sentry/types": "7.91.0", - "@sentry/utils": "7.91.0" + "@sentry/types": "7.92.0", + "@sentry/utils": "7.92.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/replay": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.91.0.tgz", - "integrity": "sha512-XwbesnLLNtaVXKtDoyBB96GxJuhGi9zy3a662Ba/McmumCnkXrMQYpQPh08U7MgkTyDRgjDwm7PXDhiKpcb03g==", + "version": "7.92.0", + "resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.92.0.tgz", + "integrity": "sha512-G1t9Uvc9cR8VpNkElwvHIMGzykjIKikb10n0tfVd3e+rBPMCCjCPWOduwG6jZYxcvCjTpqmJh6NSLXxL/Mt4JA==", "dependencies": { - "@sentry-internal/tracing": "7.91.0", - "@sentry/core": "7.91.0", - "@sentry/types": "7.91.0", - "@sentry/utils": "7.91.0" + "@sentry-internal/tracing": "7.92.0", + "@sentry/core": "7.92.0", + "@sentry/types": "7.92.0", + "@sentry/utils": "7.92.0" }, "engines": { "node": ">=12" } }, "node_modules/@sentry/tracing": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.91.0.tgz", - "integrity": "sha512-IlSAMvqfCL/2TwwN4Tmk6bGMgilGruv5oIJ1GMenVZk53bHwjpjzMbd0ms8+S5zJwAgTQXoCbRhaFFrNmptteQ==", + "version": "7.92.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.92.0.tgz", + "integrity": "sha512-1+TFFPVEdax4dNi68gin6MENiyGe9mOuNXfjulrP5eCzUEByus5HAxeDI/LLQ1hArfn048AzwSwKUsS2fO5sbg==", "dependencies": { - "@sentry-internal/tracing": "7.91.0" + "@sentry-internal/tracing": "7.92.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/types": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.91.0.tgz", - "integrity": "sha512-bcQnb7J3P3equbCUc+sPuHog2Y47yGD2sCkzmnZBjvBT0Z1B4f36fI/5WjyZhTjLSiOdg3F2otwvikbMjmBDew==", + "version": "7.92.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.92.0.tgz", + "integrity": "sha512-APmSOuZuoRGpbPpPeYIbMSplPjiWNLZRQa73QiXuTflW4Tu/ItDlU8hOa2+A6JKVkJCuD2EN6yUrxDGSMyNXeg==", "engines": { "node": ">=8" } }, "node_modules/@sentry/utils": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.91.0.tgz", - "integrity": "sha512-fvxjrEbk6T6Otu++Ax9ntlQ0sGRiwSC179w68aC3u26Wr30FAIRKqHTCCdc2jyWk7Gd9uWRT/cq+g8NG/8BfSg==", + "version": "7.92.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.92.0.tgz", + "integrity": "sha512-3nEfrQ1z28b/2zgFGANPh5yMVtgwXmrasZxTvKbrAj+KWJpjrJHrIR84r9W277J44NMeZ5RhRW2uoDmuBslPnA==", "dependencies": { - "@sentry/types": "7.91.0" + "@sentry/types": "7.92.0" }, "engines": { "node": ">=8" @@ -7266,9 +7266,9 @@ "dev": true }, "node_modules/@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, "node_modules/@types/express": { @@ -7577,16 +7577,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.17.0.tgz", - "integrity": "sha512-Vih/4xLXmY7V490dGwBQJTpIZxH4ZFH6eCVmQ4RFkB+wmaCTDAx4dtgoWwMNGKLkqRY1L6rPqzEbjorRnDo4rQ==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.0.tgz", + "integrity": "sha512-3lqEvQUdCozi6d1mddWqd+kf8KxmGq2Plzx36BlkjuQe3rSTm/O98cLf0A4uDO+a5N1KD2SeEEl6fW97YHY+6w==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.17.0", - "@typescript-eslint/type-utils": "6.17.0", - "@typescript-eslint/utils": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0", + "@typescript-eslint/scope-manager": "6.18.0", + "@typescript-eslint/type-utils": "6.18.0", + "@typescript-eslint/utils": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -7645,15 +7645,15 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.17.0.tgz", - "integrity": "sha512-C4bBaX2orvhK+LlwrY8oWGmSl4WolCfYm513gEccdWZj0CwGadbIADb0FtVEcI+WzUyjyoBj2JRP8g25E6IB8A==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.0.tgz", + "integrity": "sha512-v6uR68SFvqhNQT41frCMCQpsP+5vySy6IdgjlzUWoo7ALCnpaWYcz/Ij2k4L8cEsL0wkvOviCMpjmtRtHNOKzA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.17.0", - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/typescript-estree": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0", + "@typescript-eslint/scope-manager": "6.18.0", + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/typescript-estree": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0", "debug": "^4.3.4" }, "engines": { @@ -7673,13 +7673,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.17.0.tgz", - "integrity": "sha512-RX7a8lwgOi7am0k17NUO0+ZmMOX4PpjLtLRgLmT1d3lBYdWH4ssBUbwdmc5pdRX8rXon8v9x8vaoOSpkHfcXGA==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.0.tgz", + "integrity": "sha512-o/UoDT2NgOJ2VfHpfr+KBY2ErWvCySNUIX/X7O9g8Zzt/tXdpfEU43qbNk8LVuWUT2E0ptzTWXh79i74PP0twA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0" + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -7690,13 +7690,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.17.0.tgz", - "integrity": "sha512-hDXcWmnbtn4P2B37ka3nil3yi3VCQO2QEB9gBiHJmQp5wmyQWqnjA85+ZcE8c4FqnaB6lBwMrPkgd4aBYz3iNg==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.0.tgz", + "integrity": "sha512-ZeMtrXnGmTcHciJN1+u2CigWEEXgy1ufoxtWcHORt5kGvpjjIlK9MUhzHm4RM8iVy6dqSaZA/6PVkX6+r+ChjQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.17.0", - "@typescript-eslint/utils": "6.17.0", + "@typescript-eslint/typescript-estree": "6.18.0", + "@typescript-eslint/utils": "6.18.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -7717,9 +7717,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.17.0.tgz", - "integrity": "sha512-qRKs9tvc3a4RBcL/9PXtKSehI/q8wuU9xYJxe97WFxnzH8NWWtcW3ffNS+EWg8uPvIerhjsEZ+rHtDqOCiH57A==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.0.tgz", + "integrity": "sha512-/RFVIccwkwSdW/1zeMx3hADShWbgBxBnV/qSrex6607isYjj05t36P6LyONgqdUrNLl5TYU8NIKdHUYpFvExkA==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -7730,13 +7730,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.17.0.tgz", - "integrity": "sha512-gVQe+SLdNPfjlJn5VNGhlOhrXz4cajwFd5kAgWtZ9dCZf4XJf8xmgCTLIqec7aha3JwgLI2CK6GY1043FRxZwg==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.0.tgz", + "integrity": "sha512-klNvl+Ql4NsBNGB4W9TZ2Od03lm7aGvTbs0wYaFYsplVPhr+oeXjlPZCDI4U9jgJIDK38W1FKhacCFzCC+nbIg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0", + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -7815,17 +7815,17 @@ "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.17.0.tgz", - "integrity": "sha512-LofsSPjN/ITNkzV47hxas2JCsNCEnGhVvocfyOcLzT9c/tSZE7SfhS/iWtzP1lKNOEfLhRTZz6xqI8N2RzweSQ==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.0.tgz", + "integrity": "sha512-wiKKCbUeDPGaYEYQh1S580dGxJ/V9HI7K5sbGAVklyf+o5g3O+adnS4UNJajplF4e7z2q0uVBaTdT/yLb4XAVA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.17.0", - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/typescript-estree": "6.17.0", + "@typescript-eslint/scope-manager": "6.18.0", + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/typescript-estree": "6.18.0", "semver": "^7.5.4" }, "engines": { @@ -7873,12 +7873,12 @@ "dev": true }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.17.0.tgz", - "integrity": "sha512-H6VwB/k3IuIeQOyYczyyKN8wH6ed8EwliaYHLxOIhyF0dYEIsN8+Bk3GE19qafeMKyZJJHP8+O1HiFhFLUNKSg==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.0.tgz", + "integrity": "sha512-1wetAlSZpewRDb2h9p/Q8kRjdGuqdTAQbkJIOUMLug2LBLG+QOjiWoSj6/3B/hA9/tVTFFdtiKvAYoYnSRW/RA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/types": "6.18.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -16426,10 +16426,13 @@ "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" }, "node_modules/rollup": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.2.tgz", - "integrity": "sha512-66RB8OtFKUTozmVEh3qyNfH+b+z2RXBVloqO2KCC/pjFaGaHtxP9fVfOQKPSGXg2mElmjmxjW/fZ7iKrEpMH5Q==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.4.tgz", + "integrity": "sha512-2ztU7pY/lrQyXSCnnoU4ICjT/tCG9cdH3/G25ERqE3Lst6vl2BCM5hL2Nw+sslAvAf+ccKsAq1SkKQALyqhR7g==", "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, "bin": { "rollup": "dist/bin/rollup" }, @@ -16438,19 +16441,19 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.9.2", - "@rollup/rollup-android-arm64": "4.9.2", - "@rollup/rollup-darwin-arm64": "4.9.2", - "@rollup/rollup-darwin-x64": "4.9.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.9.2", - "@rollup/rollup-linux-arm64-gnu": "4.9.2", - "@rollup/rollup-linux-arm64-musl": "4.9.2", - "@rollup/rollup-linux-riscv64-gnu": "4.9.2", - "@rollup/rollup-linux-x64-gnu": "4.9.2", - "@rollup/rollup-linux-x64-musl": "4.9.2", - "@rollup/rollup-win32-arm64-msvc": "4.9.2", - "@rollup/rollup-win32-ia32-msvc": "4.9.2", - "@rollup/rollup-win32-x64-msvc": "4.9.2", + "@rollup/rollup-android-arm-eabi": "4.9.4", + "@rollup/rollup-android-arm64": "4.9.4", + "@rollup/rollup-darwin-arm64": "4.9.4", + "@rollup/rollup-darwin-x64": "4.9.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.9.4", + "@rollup/rollup-linux-arm64-gnu": "4.9.4", + "@rollup/rollup-linux-arm64-musl": "4.9.4", + "@rollup/rollup-linux-riscv64-gnu": "4.9.4", + "@rollup/rollup-linux-x64-gnu": "4.9.4", + "@rollup/rollup-linux-x64-musl": "4.9.4", + "@rollup/rollup-win32-arm64-msvc": "4.9.4", + "@rollup/rollup-win32-ia32-msvc": "4.9.4", + "@rollup/rollup-win32-x64-msvc": "4.9.4", "fsevents": "~2.3.2" } }, diff --git a/web/package.json b/web/package.json index f8e0670dd..1cc0d742c 100644 --- a/web/package.json +++ b/web/package.json @@ -49,8 +49,8 @@ "@open-wc/lit-helpers": "^0.6.0", "@patternfly/elements": "^2.4.0", "@patternfly/patternfly": "^4.224.2", - "@sentry/browser": "^7.91.0", - "@sentry/tracing": "^7.91.0", + "@sentry/browser": "^7.92.0", + "@sentry/tracing": "^7.92.0", "@webcomponents/webcomponentsjs": "^2.8.0", "base64-js": "^1.5.1", "chart.js": "^4.4.1", @@ -99,8 +99,8 @@ "@types/codemirror": "5.60.15", "@types/grecaptcha": "^3.0.7", "@types/guacamole-common-js": "1.5.2", - "@typescript-eslint/eslint-plugin": "^6.17.0", - "@typescript-eslint/parser": "^6.17.0", + "@typescript-eslint/eslint-plugin": "^6.18.0", + "@typescript-eslint/parser": "^6.18.0", "babel-plugin-macros": "^3.1.0", "babel-plugin-tsconfig-paths": "^1.0.3", "cross-env": "^7.0.3", @@ -118,7 +118,7 @@ "pyright": "=1.1.338", "react": "^18.2.0", "react-dom": "^18.2.0", - "rollup": "^4.9.2", + "rollup": "^4.9.4", "rollup-plugin-copy": "^3.5.0", "rollup-plugin-cssimport": "^1.0.3", "rollup-plugin-modify": "^3.0.0", diff --git a/web/src/admin/AdminInterface/AdminInterface.ts b/web/src/admin/AdminInterface/AdminInterface.ts index 834c98f37..0f1a59ccd 100644 --- a/web/src/admin/AdminInterface/AdminInterface.ts +++ b/web/src/admin/AdminInterface/AdminInterface.ts @@ -7,7 +7,7 @@ import { import { configureSentry } from "@goauthentik/common/sentry"; import { me } from "@goauthentik/common/users"; import { WebsocketClient } from "@goauthentik/common/ws"; -import { Interface } from "@goauthentik/elements/Base"; +import { Interface } from "@goauthentik/elements/Interface"; import "@goauthentik/elements/ak-locale-context"; import "@goauthentik/elements/enterprise/EnterpriseStatusBanner"; import "@goauthentik/elements/messages/MessageContainer"; diff --git a/web/src/admin/AdminInterface/AdminSidebar.ts b/web/src/admin/AdminInterface/AdminSidebar.ts index 2f973ca7e..dcced7304 100644 --- a/web/src/admin/AdminInterface/AdminSidebar.ts +++ b/web/src/admin/AdminInterface/AdminSidebar.ts @@ -1,23 +1,25 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { EVENT_SIDEBAR_TOGGLE, VERSION } from "@goauthentik/common/constants"; import { me } from "@goauthentik/common/users"; -import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts"; import { AKElement } from "@goauthentik/elements/Base"; +import { + CapabilitiesEnum, + WithCapabilitiesConfig, +} from "@goauthentik/elements/Interface/capabilitiesProvider"; import { ID_REGEX, SLUG_REGEX, UUID_REGEX } from "@goauthentik/elements/router/Route"; import { getRootStyle } from "@goauthentik/elements/utils/getRootStyle"; import { spread } from "@open-wc/lit-helpers"; -import { consume } from "@lit-labs/context"; import { msg, str } from "@lit/localize"; import { TemplateResult, html, nothing } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import { map } from "lit/directives/map.js"; -import { AdminApi, CapabilitiesEnum, CoreApi, UiThemeEnum, Version } from "@goauthentik/api"; -import type { Config, SessionUser, UserSelf } from "@goauthentik/api"; +import { AdminApi, CoreApi, UiThemeEnum, Version } from "@goauthentik/api"; +import type { SessionUser, UserSelf } from "@goauthentik/api"; @customElement("ak-admin-sidebar") -export class AkAdminSidebar extends AKElement { +export class AkAdminSidebar extends WithCapabilitiesConfig(AKElement) { @property({ type: Boolean, reflect: true }) open = true; @@ -27,9 +29,6 @@ export class AkAdminSidebar extends AKElement { @state() impersonation: UserSelf["username"] | null = null; - @consume({ context: authentikConfigContext }) - public config!: Config; - constructor() { super(); new AdminApi(DEFAULT_CONFIG).adminVersionRetrieve().then((version) => { @@ -200,7 +199,7 @@ export class AkAdminSidebar extends AKElement { } renderEnterpriseMessage() { - return this.config?.capabilities.includes(CapabilitiesEnum.IsEnterprise) + return this.can(CapabilitiesEnum.IsEnterprise) ? html` ${msg("Enterprise")} diff --git a/web/src/admin/admin-overview/AdminOverviewPage.ts b/web/src/admin/admin-overview/AdminOverviewPage.ts index a7e210a7c..9b79f5334 100644 --- a/web/src/admin/admin-overview/AdminOverviewPage.ts +++ b/web/src/admin/admin-overview/AdminOverviewPage.ts @@ -74,10 +74,7 @@ export class AdminOverviewPage extends AKElement { } render(): TemplateResult { - let name = this.user?.user.username; - if (this.user?.user.name) { - name = this.user.user.name; - } + const name = this.user?.user.name ?? this.user?.user.username; return html` ${msg(str`Welcome, ${name}.`)} diff --git a/web/src/admin/applications/ApplicationForm.ts b/web/src/admin/applications/ApplicationForm.ts index 970b3638e..ead17e9b2 100644 --- a/web/src/admin/applications/ApplicationForm.ts +++ b/web/src/admin/applications/ApplicationForm.ts @@ -1,13 +1,16 @@ import "@goauthentik/admin/applications/ProviderSelectModal"; import { iconHelperText } from "@goauthentik/admin/helperText"; -import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config"; +import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { first } from "@goauthentik/common/utils"; import "@goauthentik/components/ak-file-input"; import "@goauthentik/components/ak-radio-input"; import "@goauthentik/components/ak-switch-input"; import "@goauthentik/components/ak-text-input"; import "@goauthentik/components/ak-textarea-input"; -import { rootInterface } from "@goauthentik/elements/Base"; +import { + CapabilitiesEnum, + WithCapabilitiesConfig, +} from "@goauthentik/elements/Interface/capabilitiesProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/ModalForm"; @@ -22,13 +25,7 @@ import { TemplateResult, html } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; -import { - Application, - CapabilitiesEnum, - CoreApi, - PolicyEngineMode, - Provider, -} from "@goauthentik/api"; +import { Application, CoreApi, PolicyEngineMode, Provider } from "@goauthentik/api"; import "./components/ak-backchannel-input"; import "./components/ak-provider-search-input"; @@ -48,7 +45,7 @@ export const policyOptions = [ ]; @customElement("ak-application-form") -export class ApplicationForm extends ModelForm { +export class ApplicationForm extends WithCapabilitiesConfig(ModelForm) { constructor() { super(); this.handleConfirmBackchannelProviders = this.handleConfirmBackchannelProviders.bind(this); @@ -93,8 +90,7 @@ export class ApplicationForm extends ModelForm { applicationRequest: data, }); } - const c = await config(); - if (c.capabilities.includes(CapabilitiesEnum.CanSaveMedia)) { + if (this.can(CapabilitiesEnum.CanSaveMedia)) { const icon = this.getFormFiles()["metaIcon"]; if (icon || this.clearIcon) { await new CoreApi(DEFAULT_CONFIG).coreApplicationsSetIconCreate({ @@ -140,21 +136,21 @@ export class ApplicationForm extends ModelForm { return html`
{ @@ -209,11 +205,11 @@ export class ApplicationForm extends ModelForm { )} > - ${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanSaveMedia) + ${this.can(CapabilitiesEnum.CanSaveMedia) ? html` ${this.instance?.metaIcon diff --git a/web/src/admin/applications/wizard/methods/ldap/ak-application-wizard-authentication-by-ldap.ts b/web/src/admin/applications/wizard/methods/ldap/ak-application-wizard-authentication-by-ldap.ts index a99384171..6e1554196 100644 --- a/web/src/admin/applications/wizard/methods/ldap/ak-application-wizard-authentication-by-ldap.ts +++ b/web/src/admin/applications/wizard/methods/ldap/ak-application-wizard-authentication-by-ldap.ts @@ -7,7 +7,7 @@ import "@goauthentik/components/ak-number-input"; import "@goauthentik/components/ak-radio-input"; import "@goauthentik/components/ak-switch-input"; import "@goauthentik/components/ak-text-input"; -import { rootInterface } from "@goauthentik/elements/Base"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; @@ -32,7 +32,7 @@ import { } from "./LDAPOptionsAndHelp"; @customElement("ak-application-wizard-authentication-by-ldap") -export class ApplicationWizardApplicationDetails extends BaseProviderPanel { +export class ApplicationWizardApplicationDetails extends WithTenantConfig(BaseProviderPanel) { render() { const provider = this.wizard.provider as LDAPProvider | undefined; const errors = this.wizard.errors.provider; @@ -57,7 +57,7 @@ export class ApplicationWizardApplicationDetails extends BaseProviderPanel {

diff --git a/web/src/admin/applications/wizard/methods/radius/ak-application-wizard-authentication-by-radius.ts b/web/src/admin/applications/wizard/methods/radius/ak-application-wizard-authentication-by-radius.ts index cadbd94ad..44f452037 100644 --- a/web/src/admin/applications/wizard/methods/radius/ak-application-wizard-authentication-by-radius.ts +++ b/web/src/admin/applications/wizard/methods/radius/ak-application-wizard-authentication-by-radius.ts @@ -3,7 +3,7 @@ import "@goauthentik/admin/common/ak-crypto-certificate-search"; import "@goauthentik/admin/common/ak-flow-search/ak-tenanted-flow-search"; import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils"; import "@goauthentik/components/ak-text-input"; -import { rootInterface } from "@goauthentik/elements/Base"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; @@ -17,7 +17,7 @@ import { FlowsInstancesListDesignationEnum, RadiusProvider } from "@goauthentik/ import BaseProviderPanel from "../BaseProviderPanel"; @customElement("ak-application-wizard-authentication-by-radius") -export class ApplicationWizardAuthenticationByRadius extends BaseProviderPanel { +export class ApplicationWizardAuthenticationByRadius extends WithTenantConfig(BaseProviderPanel) { render() { const provider = this.wizard.provider as RadiusProvider | undefined; const errors = this.wizard.errors.provider; @@ -42,7 +42,7 @@ export class ApplicationWizardAuthenticationByRadius extends BaseProviderPanel {

diff --git a/web/src/admin/flows/FlowForm.ts b/web/src/admin/flows/FlowForm.ts index 1d279070f..3925f6db9 100644 --- a/web/src/admin/flows/FlowForm.ts +++ b/web/src/admin/flows/FlowForm.ts @@ -1,8 +1,11 @@ import { DesignationToLabel, LayoutToLabel } from "@goauthentik/admin/flows/utils"; import { AuthenticationEnum } from "@goauthentik/api/dist/models/AuthenticationEnum"; -import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config"; +import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { first } from "@goauthentik/common/utils"; -import { rootInterface } from "@goauthentik/elements/Base"; +import { + CapabilitiesEnum, + WithCapabilitiesConfig, +} from "@goauthentik/elements/Interface/capabilitiesProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; @@ -14,7 +17,6 @@ import { customElement, property } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; import { - CapabilitiesEnum, DeniedActionEnum, Flow, FlowDesignationEnum, @@ -24,7 +26,7 @@ import { } from "@goauthentik/api"; @customElement("ak-flow-form") -export class FlowForm extends ModelForm { +export class FlowForm extends WithCapabilitiesConfig(ModelForm) { async loadInstance(pk: string): Promise { const flow = await new FlowsApi(DEFAULT_CONFIG).flowsInstancesRetrieve({ slug: pk, @@ -54,8 +56,8 @@ export class FlowForm extends ModelForm { flowRequest: data, }); } - const c = await config(); - if (c.capabilities.includes(CapabilitiesEnum.CanSaveMedia)) { + + if (this.can(CapabilitiesEnum.CanSaveMedia)) { const icon = this.getFormFiles()["background"]; if (icon || this.clearBackground) { await new FlowsApi(DEFAULT_CONFIG).flowsInstancesSetBackgroundCreate({ @@ -340,7 +342,7 @@ export class FlowForm extends ModelForm { - ${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanSaveMedia) + ${this.can(CapabilitiesEnum.CanSaveMedia) ? html` diff --git a/web/src/admin/groups/RelatedUserList.ts b/web/src/admin/groups/RelatedUserList.ts index 2474ee2fe..5e2c6b952 100644 --- a/web/src/admin/groups/RelatedUserList.ts +++ b/web/src/admin/groups/RelatedUserList.ts @@ -9,7 +9,11 @@ import { MessageLevel } from "@goauthentik/common/messages"; import { uiConfig } from "@goauthentik/common/ui/config"; import { first } from "@goauthentik/common/utils"; import "@goauthentik/components/ak-status-label"; -import { rootInterface } from "@goauthentik/elements/Base"; +import { + CapabilitiesEnum, + WithCapabilitiesConfig, +} from "@goauthentik/elements/Interface/capabilitiesProvider"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import "@goauthentik/elements/buttons/ActionButton"; import "@goauthentik/elements/buttons/Dropdown"; import "@goauthentik/elements/forms/DeleteBulkForm"; @@ -33,7 +37,6 @@ import PFBanner from "@patternfly/patternfly/components/Banner/banner.css"; import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css"; import { - CapabilitiesEnum, CoreApi, CoreUsersListTypeEnum, Group, @@ -107,7 +110,7 @@ export class RelatedUserAdd extends Form<{ users: number[] }> { } @customElement("ak-user-related-list") -export class RelatedUserList extends Table { +export class RelatedUserList extends WithTenantConfig(WithCapabilitiesConfig(Table)) { expandable = true; checkbox = true; @@ -188,8 +191,7 @@ export class RelatedUserList extends Table { row(item: User): TemplateResult[] { const canImpersonate = - rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanImpersonate) && - item.pk !== this.me?.user.pk; + this.can(CapabilitiesEnum.CanImpersonate) && item.pk !== this.me?.user.pk; return [ html`

@@ -293,7 +295,7 @@ export class RelatedUserList extends Table { ${msg("Set password")} - ${rootInterface()?.tenant?.flowRecovery + ${this.tenant?.flowRecovery ? html` { +export class LDAPProviderFormPage extends WithTenantConfig(BaseProviderForm) { async loadInstance(pk: number): Promise { return new ProvidersApi(DEFAULT_CONFIG).providersLdapRetrieve({ id: pk, @@ -68,7 +68,7 @@ export class LDAPProviderFormPage extends BaseProviderForm {

${msg("Flow used for users to authenticate.")}

diff --git a/web/src/admin/providers/radius/RadiusProviderForm.ts b/web/src/admin/providers/radius/RadiusProviderForm.ts index 269a5ee95..f37c865d5 100644 --- a/web/src/admin/providers/radius/RadiusProviderForm.ts +++ b/web/src/admin/providers/radius/RadiusProviderForm.ts @@ -1,7 +1,7 @@ import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils"; -import { rootInterface } from "@goauthentik/elements/Base"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/SearchSelect"; @@ -14,7 +14,7 @@ import { customElement } from "lit/decorators.js"; import { FlowsInstancesListDesignationEnum, ProvidersApi, RadiusProvider } from "@goauthentik/api"; @customElement("ak-provider-radius-form") -export class RadiusProviderFormPage extends BaseProviderForm { +export class RadiusProviderFormPage extends WithTenantConfig(BaseProviderForm) { loadInstance(pk: number): Promise { return new ProvidersApi(DEFAULT_CONFIG).providersRadiusRetrieve({ id: pk, @@ -57,7 +57,7 @@ export class RadiusProviderFormPage extends BaseProviderForm {

${msg("Flow used for users to authenticate.")}

diff --git a/web/src/admin/sources/oauth/OAuthSourceForm.ts b/web/src/admin/sources/oauth/OAuthSourceForm.ts index cf0209fcb..92763bf7b 100644 --- a/web/src/admin/sources/oauth/OAuthSourceForm.ts +++ b/web/src/admin/sources/oauth/OAuthSourceForm.ts @@ -4,9 +4,12 @@ import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm"; import { UserMatchingModeToLabel } from "@goauthentik/admin/sources/oauth/utils"; import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config"; import { first } from "@goauthentik/common/utils"; -import { rootInterface } from "@goauthentik/elements/Base"; import "@goauthentik/elements/CodeMirror"; import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror"; +import { + CapabilitiesEnum, + WithCapabilitiesConfig, +} from "@goauthentik/elements/Interface/capabilitiesProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/SearchSelect"; @@ -17,7 +20,6 @@ import { customElement, property, state } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; import { - CapabilitiesEnum, FlowsInstancesListDesignationEnum, OAuthSource, OAuthSourceRequest, @@ -28,7 +30,7 @@ import { } from "@goauthentik/api"; @customElement("ak-source-oauth-form") -export class OAuthSourceForm extends BaseSourceForm { +export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm) { async loadInstance(pk: string): Promise { const source = await new SourcesApi(DEFAULT_CONFIG).sourcesOauthRetrieve({ slug: pk, @@ -318,7 +320,7 @@ export class OAuthSourceForm extends BaseSourceForm { />

${placeholderHelperText}

- ${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanSaveMedia) + ${this.can(CapabilitiesEnum.CanSaveMedia) ? html` ${this.instance?.icon diff --git a/web/src/admin/sources/plex/PlexSourceForm.ts b/web/src/admin/sources/plex/PlexSourceForm.ts index 8091067ff..8444e1112 100644 --- a/web/src/admin/sources/plex/PlexSourceForm.ts +++ b/web/src/admin/sources/plex/PlexSourceForm.ts @@ -2,10 +2,13 @@ import "@goauthentik/admin/common/ak-flow-search/ak-source-flow-search"; import { iconHelperText, placeholderHelperText } from "@goauthentik/admin/helperText"; import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm"; import { UserMatchingModeToLabel } from "@goauthentik/admin/sources/oauth/utils"; -import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config"; +import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { PlexAPIClient, PlexResource, popupCenterScreen } from "@goauthentik/common/helpers/plex"; import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils"; -import { rootInterface } from "@goauthentik/elements/Base"; +import { + CapabilitiesEnum, + WithCapabilitiesConfig, +} from "@goauthentik/elements/Interface/capabilitiesProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/SearchSelect"; @@ -16,7 +19,6 @@ import { customElement, property, state } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; import { - CapabilitiesEnum, FlowsInstancesListDesignationEnum, PlexSource, SourcesApi, @@ -24,7 +26,7 @@ import { } from "@goauthentik/api"; @customElement("ak-source-plex-form") -export class PlexSourceForm extends BaseSourceForm { +export class PlexSourceForm extends WithCapabilitiesConfig(BaseSourceForm) { async loadInstance(pk: string): Promise { const source = await new SourcesApi(DEFAULT_CONFIG).sourcesPlexRetrieve({ slug: pk, @@ -63,8 +65,7 @@ export class PlexSourceForm extends BaseSourceForm { plexSourceRequest: data, }); } - const c = await config(); - if (c.capabilities.includes(CapabilitiesEnum.CanSaveMedia)) { + if (this.can(CapabilitiesEnum.CanSaveMedia)) { const icon = this.getFormFiles()["icon"]; if (icon || this.clearIcon) { await new SourcesApi(DEFAULT_CONFIG).sourcesAllSetIconCreate({ @@ -255,7 +256,7 @@ export class PlexSourceForm extends BaseSourceForm { />

${placeholderHelperText}

- ${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanSaveMedia) + ${this.can(CapabilitiesEnum.CanSaveMedia) ? html` ${this.instance?.icon diff --git a/web/src/admin/sources/saml/SAMLSourceForm.ts b/web/src/admin/sources/saml/SAMLSourceForm.ts index 76e996322..c969411fb 100644 --- a/web/src/admin/sources/saml/SAMLSourceForm.ts +++ b/web/src/admin/sources/saml/SAMLSourceForm.ts @@ -5,7 +5,10 @@ import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm"; import { UserMatchingModeToLabel } from "@goauthentik/admin/sources/oauth/utils"; import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config"; import { first } from "@goauthentik/common/utils"; -import { rootInterface } from "@goauthentik/elements/Base"; +import { + CapabilitiesEnum, + WithCapabilitiesConfig, +} from "@goauthentik/elements/Interface/capabilitiesProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/Radio"; @@ -18,7 +21,6 @@ import { ifDefined } from "lit/directives/if-defined.js"; import { BindingTypeEnum, - CapabilitiesEnum, DigestAlgorithmEnum, FlowsInstancesListDesignationEnum, NameIdPolicyEnum, @@ -29,7 +31,7 @@ import { } from "@goauthentik/api"; @customElement("ak-source-saml-form") -export class SAMLSourceForm extends BaseSourceForm { +export class SAMLSourceForm extends WithCapabilitiesConfig(BaseSourceForm) { @state() clearIcon = false; @@ -149,7 +151,7 @@ export class SAMLSourceForm extends BaseSourceForm { - ${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanSaveMedia) + ${this.can(CapabilitiesEnum.CanSaveMedia) ? html` ${this.instance?.icon diff --git a/web/src/admin/users/UserListPage.ts b/web/src/admin/users/UserListPage.ts index 1d861b568..afb88f3f6 100644 --- a/web/src/admin/users/UserListPage.ts +++ b/web/src/admin/users/UserListPage.ts @@ -12,6 +12,11 @@ import { DefaultUIConfig, uiConfig } from "@goauthentik/common/ui/config"; import { first } from "@goauthentik/common/utils"; import "@goauthentik/components/ak-status-label"; import { rootInterface } from "@goauthentik/elements/Base"; +import { + CapabilitiesEnum, + WithCapabilitiesConfig, +} from "@goauthentik/elements/Interface/capabilitiesProvider"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import { PFSize } from "@goauthentik/elements/Spinner"; import "@goauthentik/elements/TreeView"; import "@goauthentik/elements/buttons/ActionButton"; @@ -33,14 +38,7 @@ import PFAlert from "@patternfly/patternfly/components/Alert/alert.css"; import PFCard from "@patternfly/patternfly/components/Card/card.css"; import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css"; -import { - CapabilitiesEnum, - CoreApi, - ResponseError, - SessionUser, - User, - UserPath, -} from "@goauthentik/api"; +import { CoreApi, ResponseError, SessionUser, User, UserPath } from "@goauthentik/api"; export const requestRecoveryLink = (user: User) => new CoreApi(DEFAULT_CONFIG) @@ -93,7 +91,7 @@ const recoveryButtonStyles = css` `; @customElement("ak-user-list") -export class UserListPage extends TablePage { +export class UserListPage extends WithTenantConfig(WithCapabilitiesConfig(TablePage)) { expandable = true; checkbox = true; @@ -244,8 +242,7 @@ export class UserListPage extends TablePage { row(item: User): TemplateResult[] { const canImpersonate = - rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanImpersonate) && - item.pk !== this.me?.user.pk; + this.can(CapabilitiesEnum.CanImpersonate) && item.pk !== this.me?.user.pk; return [ html`
${item.username}
@@ -355,7 +352,7 @@ export class UserListPage extends TablePage { ${msg("Set password")} - ${rootInterface()?.tenant?.flowRecovery + ${this.tenant.flowRecovery ? html` { @@ -163,8 +164,7 @@ export class UserViewPage extends AKElement { renderActionButtons(user: User) { const canImpersonate = - rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanImpersonate) && - user.pk !== this.me?.user.pk; + this.can(CapabilitiesEnum.CanImpersonate) && user.pk !== this.me?.user.pk; return html`
diff --git a/web/src/elements/AuthentikContexts.ts b/web/src/elements/AuthentikContexts.ts index 97a89a881..02fa89316 100644 --- a/web/src/elements/AuthentikContexts.ts +++ b/web/src/elements/AuthentikContexts.ts @@ -1,7 +1,11 @@ import { createContext } from "@lit-labs/context"; -import { type Config } from "@goauthentik/api"; +import type { Config, CurrentTenant } from "@goauthentik/api"; export const authentikConfigContext = createContext(Symbol("authentik-config-context")); +export const authentikTenantContext = createContext( + Symbol("authentik-tenant-context"), +); + export default authentikConfigContext; diff --git a/web/src/elements/Base.ts b/web/src/elements/Base.ts index 46c983aad..09a2d2858 100644 --- a/web/src/elements/Base.ts +++ b/web/src/elements/Base.ts @@ -1,20 +1,18 @@ -import { config, tenant } from "@goauthentik/common/api/config"; import { EVENT_THEME_CHANGE } from "@goauthentik/common/constants"; -import { UIConfig, uiConfig } from "@goauthentik/common/ui/config"; +import { UIConfig } from "@goauthentik/common/ui/config"; import { adaptCSS } from "@goauthentik/common/utils"; -import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts"; +import { ensureCSSStyleSheet } from "@goauthentik/elements/utils/ensureCSSStyleSheet"; -import { ContextProvider } from "@lit-labs/context"; import { localized } from "@lit/localize"; -import { CSSResult, LitElement } from "lit"; -import { state } from "lit/decorators.js"; +import { LitElement } from "lit"; import AKGlobal from "@goauthentik/common/styles/authentik.css"; import ThemeDark from "@goauthentik/common/styles/theme-dark.css"; -import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { Config, CurrentTenant, UiThemeEnum } from "@goauthentik/api"; +import { AdoptedStyleSheetsElement } from "./types"; + type AkInterface = HTMLElement & { getTheme: () => Promise; tenant?: CurrentTenant; @@ -25,13 +23,6 @@ type AkInterface = HTMLElement & { export const rootInterface = (): T | undefined => (document.body.querySelector("[data-ak-interface-root]") as T) ?? undefined; -export function ensureCSSStyleSheet(css: CSSStyleSheet | CSSResult): CSSStyleSheet { - if (css instanceof CSSResult) { - return css.styleSheet!; - } - return css; -} - let css: Promise | undefined; function fetchCustomCSS(): Promise { if (!css) { @@ -52,10 +43,6 @@ function fetchCustomCSS(): Promise { return css; } -export interface AdoptedStyleSheetsElement { - adoptedStyleSheets: readonly CSSStyleSheet[]; -} - const QUERY_MEDIA_COLOR_LIGHT = "(prefers-color-scheme: light)"; @localized() @@ -175,49 +162,3 @@ export class AKElement extends LitElement { this.requestUpdate(); } } - -export class Interface extends AKElement implements AkInterface { - @state() - tenant?: CurrentTenant; - - @state() - uiConfig?: UIConfig; - - _configContext = new ContextProvider(this, { - context: authentikConfigContext, - initialValue: undefined, - }); - - _config?: Config; - - @state() - set config(c: Config) { - this._config = c; - this._configContext.setValue(c); - this.requestUpdate(); - } - - get config(): Config | undefined { - return this._config; - } - - constructor() { - super(); - document.adoptedStyleSheets = [...document.adoptedStyleSheets, ensureCSSStyleSheet(PFBase)]; - tenant().then((tenant) => (this.tenant = tenant)); - config().then((config) => (this.config = config)); - this.dataset.akInterfaceRoot = "true"; - } - - _activateTheme(root: AdoptedStyleSheetsElement, theme: UiThemeEnum): void { - super._activateTheme(root, theme); - super._activateTheme(document, theme); - } - - async getTheme(): Promise { - if (!this.uiConfig) { - this.uiConfig = await uiConfig(); - } - return this.uiConfig.theme?.base || UiThemeEnum.Automatic; - } -} diff --git a/web/src/elements/Interface/Interface.ts b/web/src/elements/Interface/Interface.ts new file mode 100644 index 000000000..b2470cfd2 --- /dev/null +++ b/web/src/elements/Interface/Interface.ts @@ -0,0 +1,85 @@ +import { config, tenant } from "@goauthentik/common/api/config"; +import { UIConfig, uiConfig } from "@goauthentik/common/ui/config"; +import { + authentikConfigContext, + authentikTenantContext, +} from "@goauthentik/elements/AuthentikContexts"; +import type { AdoptedStyleSheetsElement } from "@goauthentik/elements/types"; +import { ensureCSSStyleSheet } from "@goauthentik/elements/utils/ensureCSSStyleSheet"; + +import { ContextProvider } from "@lit-labs/context"; +import { state } from "lit/decorators.js"; + +import PFBase from "@patternfly/patternfly/patternfly-base.css"; + +import { Config, CurrentTenant, UiThemeEnum } from "@goauthentik/api"; + +import { AKElement } from "../Base"; + +type AkInterface = HTMLElement & { + getTheme: () => Promise; + tenant?: CurrentTenant; + uiConfig?: UIConfig; + config?: Config; +}; + +export class Interface extends AKElement implements AkInterface { + @state() + uiConfig?: UIConfig; + + _configContext = new ContextProvider(this, { + context: authentikConfigContext, + initialValue: undefined, + }); + + _config?: Config; + + @state() + set config(c: Config) { + this._config = c; + this._configContext.setValue(c); + this.requestUpdate(); + } + + get config(): Config | undefined { + return this._config; + } + + _tenantContext = new ContextProvider(this, { + context: authentikTenantContext, + initialValue: undefined, + }); + + _tenant?: CurrentTenant; + + @state() + set tenant(c: CurrentTenant) { + this._tenant = c; + this._tenantContext.setValue(c); + this.requestUpdate(); + } + + get tenant(): CurrentTenant | undefined { + return this._tenant; + } + + constructor() { + super(); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, ensureCSSStyleSheet(PFBase)]; + tenant().then((tenant) => (this.tenant = tenant)); + config().then((config) => (this.config = config)); + this.dataset.akInterfaceRoot = "true"; + } + + _activateTheme(root: AdoptedStyleSheetsElement, theme: UiThemeEnum): void { + super._activateTheme(root, theme); + super._activateTheme(document, theme); + } + + async getTheme(): Promise { + if (!this.uiConfig) { + this.uiConfig = await uiConfig(); + } + return this.uiConfig.theme?.base || UiThemeEnum.Automatic; + } +} diff --git a/web/src/elements/Interface/authentikConfigProvider.ts b/web/src/elements/Interface/authentikConfigProvider.ts new file mode 100644 index 000000000..5b2027fd0 --- /dev/null +++ b/web/src/elements/Interface/authentikConfigProvider.ts @@ -0,0 +1,20 @@ +import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts"; + +import { consume } from "@lit-labs/context"; +import type { LitElement } from "lit"; + +import type { Config } from "@goauthentik/api"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type Constructor = new (...args: any[]) => T; + +export function WithAuthentikConfig>( + superclass: T, + subscribe = true, +) { + abstract class WithAkConfigProvider extends superclass { + @consume({ context: authentikConfigContext, subscribe }) + public authentikConfig!: Config; + } + return WithAkConfigProvider; +} diff --git a/web/src/elements/Interface/capabilitiesProvider.ts b/web/src/elements/Interface/capabilitiesProvider.ts new file mode 100644 index 000000000..402653880 --- /dev/null +++ b/web/src/elements/Interface/capabilitiesProvider.ts @@ -0,0 +1,69 @@ +import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts"; + +import { consume } from "@lit-labs/context"; +import type { LitElement } from "lit"; + +import { CapabilitiesEnum } from "@goauthentik/api"; +import { Config } from "@goauthentik/api"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type Constructor = abstract new (...args: any[]) => T; + +// Using a unique, lexically scoped, and locally static symbol as the field name for the context +// means that it's inaccessible to any child class looking for it. It's one of the strongest privacy +// guarantees in JavaScript. + +class WCC { + public static readonly capabilitiesConfig: unique symbol = Symbol(); +} + +/** + * withCapabilitiesContext mixes in a single method to any LitElement, `can()`, which takes a + * CapabilitiesEnum and returns true or false. + * + * Usage: + * + * After importing, simply mixin this function: + * + * ``` + * export class AkMyNiftyNewFeature extends withCapabilitiesContext(AKElement) { + * ``` + * + * And then if you need to check on a capability: + * + * ``` + * if (this.can(CapabilitiesEnum.IsEnterprise) { ... } + * ``` + * + * This code re-exports CapabilitiesEnum, so you won't have to import it on a separate line if you + * don't need anything else from the API. + * + * Passing `true` as the second mixin argument will cause the inheriting class to subscribe to the + * configuration context. Should the context be explicitly reset, all active web components that are + * currently active and subscribed to the context will automatically have a `requestUpdate()` + * triggered with the new configuration. + * + */ + +export function WithCapabilitiesConfig>( + superclass: T, + subscribe = true, +) { + abstract class CapabilitiesContext extends superclass { + @consume({ context: authentikConfigContext, subscribe }) + private [WCC.capabilitiesConfig]!: Config; + + can(c: CapabilitiesEnum) { + if (!this[WCC.capabilitiesConfig]) { + throw new Error( + "ConfigContext: Attempted to access site configuration before initialization.", + ); + } + return this[WCC.capabilitiesConfig].capabilities.includes(c); + } + } + + return CapabilitiesContext; +} + +export { CapabilitiesEnum }; diff --git a/web/src/elements/Interface/index.ts b/web/src/elements/Interface/index.ts new file mode 100644 index 000000000..e7d946cf6 --- /dev/null +++ b/web/src/elements/Interface/index.ts @@ -0,0 +1,4 @@ +import { Interface } from "./Interface"; + +export { Interface }; +export default Interface; diff --git a/web/src/elements/Interface/tenantProvider.ts b/web/src/elements/Interface/tenantProvider.ts new file mode 100644 index 000000000..63d389048 --- /dev/null +++ b/web/src/elements/Interface/tenantProvider.ts @@ -0,0 +1,20 @@ +import { authentikTenantContext } from "@goauthentik/elements/AuthentikContexts"; + +import { consume } from "@lit-labs/context"; +import type { LitElement } from "lit"; + +import type { CurrentTenant } from "@goauthentik/api"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type Constructor = abstract new (...args: any[]) => T; + +export function WithTenantConfig>( + superclass: T, + subscribe = true, +) { + abstract class WithTenantProvider extends superclass { + @consume({ context: authentikTenantContext, subscribe }) + public tenant!: CurrentTenant; + } + return WithTenantProvider; +} diff --git a/web/src/elements/PageHeader.ts b/web/src/elements/PageHeader.ts index fcdbbeffc..7be55996d 100644 --- a/web/src/elements/PageHeader.ts +++ b/web/src/elements/PageHeader.ts @@ -8,7 +8,8 @@ import { } from "@goauthentik/common/constants"; import { currentInterface } from "@goauthentik/common/sentry"; import { me } from "@goauthentik/common/users"; -import { AKElement, rootInterface } from "@goauthentik/elements/Base"; +import { AKElement } from "@goauthentik/elements/Base"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import "@patternfly/elements/pf-tooltip/pf-tooltip.js"; import { msg } from "@lit/localize"; @@ -23,7 +24,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { EventsApi } from "@goauthentik/api"; @customElement("ak-page-header") -export class PageHeader extends AKElement { +export class PageHeader extends WithTenantConfig(AKElement) { @property() icon?: string; @@ -35,9 +36,8 @@ export class PageHeader extends AKElement { @property() set header(value: string) { - const tenant = rootInterface()?.tenant; const currentIf = currentInterface(); - let title = tenant?.brandingTitle || TITLE_DEFAULT; + let title = this.tenant?.brandingTitle || TITLE_DEFAULT; if (currentIf === "admin") { title = `${msg("Admin")} - ${title}`; } diff --git a/web/src/elements/ak-locale-context/definitions.ts b/web/src/elements/ak-locale-context/definitions.ts index e920e85b1..018c9e2a1 100644 --- a/web/src/elements/ak-locale-context/definitions.ts +++ b/web/src/elements/ak-locale-context/definitions.ts @@ -46,6 +46,8 @@ const LOCALE_TABLE: LocaleRow[] = [ ["es", /^es([_-]|$)/i, () => msg("Spanish"), async () => await import("@goauthentik/locales/es")], ["de", /^de([_-]|$)/i, () => msg("German"), async () => await import("@goauthentik/locales/de")], ["fr", /^fr([_-]|$)/i, () => msg("French"), async () => await import("@goauthentik/locales/fr")], + ["ko", /^ko([_-]|$)/i, () => msg("Korean"), async () => await import("@goauthentik/locales/ko")], + ["nl", /^nl([_-]|$)/i, () => msg("Dutch"), async () => await import("@goauthentik/locales/nl")], ["pl", /^pl([_-]|$)/i, () => msg("Polish"), async () => await import("@goauthentik/locales/pl")], ["tr", /^tr([_-]|$)/i, () => msg("Turkish"), async () => await import("@goauthentik/locales/tr")], ["zh-Hant", /^zh[_-](HK|Hant)/i, () => msg("Chinese (traditional)"), async () => await import("@goauthentik/locales/zh-Hant")], diff --git a/web/src/elements/sidebar/SidebarBrand.ts b/web/src/elements/sidebar/SidebarBrand.ts index fa442b36c..b57d336f7 100644 --- a/web/src/elements/sidebar/SidebarBrand.ts +++ b/web/src/elements/sidebar/SidebarBrand.ts @@ -1,6 +1,6 @@ import { EVENT_SIDEBAR_TOGGLE } from "@goauthentik/common/constants"; -import { first } from "@goauthentik/common/utils"; -import { AKElement, rootInterface } from "@goauthentik/elements/Base"; +import { AKElement } from "@goauthentik/elements/Base"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import { CSSResult, TemplateResult, css, html } from "lit"; import { customElement } from "lit/decorators.js"; @@ -27,7 +27,7 @@ export const DefaultTenant: CurrentTenant = { }; @customElement("ak-sidebar-brand") -export class SidebarBrand extends AKElement { +export class SidebarBrand extends WithTenantConfig(AKElement) { static get styles(): CSSResult[] { return [ PFBase, @@ -85,10 +85,7 @@ export class SidebarBrand extends AKElement {
authentik Logo diff --git a/web/src/elements/types.ts b/web/src/elements/types.ts new file mode 100644 index 000000000..4273ab6f9 --- /dev/null +++ b/web/src/elements/types.ts @@ -0,0 +1,3 @@ +export interface AdoptedStyleSheetsElement { + adoptedStyleSheets: readonly CSSStyleSheet[]; +} diff --git a/web/src/elements/utils/ensureCSSStyleSheet.ts b/web/src/elements/utils/ensureCSSStyleSheet.ts new file mode 100644 index 000000000..26f2ff898 --- /dev/null +++ b/web/src/elements/utils/ensureCSSStyleSheet.ts @@ -0,0 +1,4 @@ +import { CSSResult } from "lit"; + +export const ensureCSSStyleSheet = (css: CSSStyleSheet | CSSResult): CSSStyleSheet => + css instanceof CSSResult ? css.styleSheet! : css; diff --git a/web/src/enterprise/rac/index.ts b/web/src/enterprise/rac/index.ts index 272ba2211..e5a9e04e7 100644 --- a/web/src/enterprise/rac/index.ts +++ b/web/src/enterprise/rac/index.ts @@ -1,5 +1,5 @@ import { TITLE_DEFAULT } from "@goauthentik/app/common/constants"; -import { Interface } from "@goauthentik/elements/Base"; +import { Interface } from "@goauthentik/elements/Interface"; import "@goauthentik/elements/LoadingOverlay"; import Guacamole from "guacamole-common-js"; diff --git a/web/src/flow/FlowExecutor.ts b/web/src/flow/FlowExecutor.ts index bc1dec3a8..e0d31e421 100644 --- a/web/src/flow/FlowExecutor.ts +++ b/web/src/flow/FlowExecutor.ts @@ -8,7 +8,7 @@ import { globalAK } from "@goauthentik/common/global"; import { configureSentry } from "@goauthentik/common/sentry"; import { first } from "@goauthentik/common/utils"; import { WebsocketClient } from "@goauthentik/common/ws"; -import { Interface } from "@goauthentik/elements/Base"; +import { Interface } from "@goauthentik/elements/Interface"; import "@goauthentik/elements/LoadingOverlay"; import "@goauthentik/elements/ak-locale-context"; import "@goauthentik/flow/sources/apple/AppleLoginInit"; diff --git a/web/src/flow/stages/authenticator_validate/AuthenticatorValidateStage.ts b/web/src/flow/stages/authenticator_validate/AuthenticatorValidateStage.ts index 351b890d6..403a80756 100644 --- a/web/src/flow/stages/authenticator_validate/AuthenticatorValidateStage.ts +++ b/web/src/flow/stages/authenticator_validate/AuthenticatorValidateStage.ts @@ -89,6 +89,9 @@ export class AuthenticatorValidateStage display: flex; align-items: center; } + :host([theme="dark"]) .authenticator-button { + color: var(--ak-dark-foreground) !important; + } i { font-size: 1.5rem; padding: 1rem 0; diff --git a/web/src/flow/stages/prompt/PromptStage.ts b/web/src/flow/stages/prompt/PromptStage.ts index 877d02119..09cc6959e 100644 --- a/web/src/flow/stages/prompt/PromptStage.ts +++ b/web/src/flow/stages/prompt/PromptStage.ts @@ -1,6 +1,9 @@ -import { rootInterface } from "@goauthentik/elements/Base"; import "@goauthentik/elements/Divider"; import "@goauthentik/elements/EmptyState"; +import { + CapabilitiesEnum, + WithCapabilitiesConfig, +} from "@goauthentik/elements/Interface/capabilitiesProvider"; import { LOCALES } from "@goauthentik/elements/ak-locale-context/definitions"; import "@goauthentik/elements/forms/FormElement"; import { BaseStage } from "@goauthentik/flow/stages/base"; @@ -20,7 +23,6 @@ import PFTitle from "@patternfly/patternfly/components/Title/title.css"; import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { - CapabilitiesEnum, PromptChallenge, PromptChallengeResponseRequest, PromptTypeEnum, @@ -28,7 +30,9 @@ import { } from "@goauthentik/api"; @customElement("ak-stage-prompt") -export class PromptStage extends BaseStage { +export class PromptStage extends WithCapabilitiesConfig( + BaseStage, +) { static get styles(): CSSResult[] { return [ PFBase, @@ -193,10 +197,7 @@ ${prompt.initialValue} `; })}`; case PromptTypeEnum.AkLocale: { - const inDebug = rootInterface()?.config?.capabilities.includes( - CapabilitiesEnum.CanDebug, - ); - const locales = inDebug + const locales = this.can(CapabilitiesEnum.CanDebug) ? LOCALES : LOCALES.filter((locale) => locale.code !== "debug"); const options = locales.map( diff --git a/web/src/locale-codes.ts b/web/src/locale-codes.ts index 86337dc8d..8b7a36ac1 100644 --- a/web/src/locale-codes.ts +++ b/web/src/locale-codes.ts @@ -15,10 +15,13 @@ export const targetLocales = [ `en`, `es`, `fr`, + `ko`, + `nl`, `pl`, `pseudo-LOCALE`, `tr`, `zh_TW`, + `zh-CN`, `zh-Hans`, `zh-Hant`, ] as const; @@ -32,10 +35,13 @@ export const allLocales = [ `en`, `es`, `fr`, + `ko`, + `nl`, `pl`, `pseudo-LOCALE`, `tr`, `zh_TW`, + `zh-CN`, `zh-Hans`, `zh-Hant`, ] as const; diff --git a/web/src/standalone/api-browser/index.ts b/web/src/standalone/api-browser/index.ts index b0c5849ed..c6a98159c 100644 --- a/web/src/standalone/api-browser/index.ts +++ b/web/src/standalone/api-browser/index.ts @@ -2,7 +2,7 @@ import { CSRFHeaderName } from "@goauthentik/common/api/middleware"; import { EVENT_THEME_CHANGE } from "@goauthentik/common/constants"; import { globalAK } from "@goauthentik/common/global"; import { first, getCookie } from "@goauthentik/common/utils"; -import { Interface } from "@goauthentik/elements/Base"; +import { Interface } from "@goauthentik/elements/Interface"; import "@goauthentik/elements/ak-locale-context"; import { DefaultTenant } from "@goauthentik/elements/sidebar/SidebarBrand"; import "rapidoc"; diff --git a/web/src/standalone/loading/index.ts b/web/src/standalone/loading/index.ts index 907a05140..24e8c47ef 100644 --- a/web/src/standalone/loading/index.ts +++ b/web/src/standalone/loading/index.ts @@ -1,5 +1,5 @@ import { globalAK } from "@goauthentik/common/global"; -import { Interface } from "@goauthentik/elements/Base"; +import { Interface } from "@goauthentik/elements/Interface"; import { msg } from "@lit/localize"; import { CSSResult, TemplateResult, css, html } from "lit"; diff --git a/web/src/stories/interface.ts b/web/src/stories/interface.ts index c4e2dc03d..1eafc6204 100644 --- a/web/src/stories/interface.ts +++ b/web/src/stories/interface.ts @@ -1,4 +1,4 @@ -import { Interface } from "@goauthentik/app/elements/Base"; +import { Interface } from "@goauthentik/app/elements/Interface"; import { customElement, property } from "lit/decorators.js"; diff --git a/web/src/user/UserInterface.ts b/web/src/user/UserInterface.ts index 09b10d632..aad94e73d 100644 --- a/web/src/user/UserInterface.ts +++ b/web/src/user/UserInterface.ts @@ -9,7 +9,7 @@ import { UserDisplay } from "@goauthentik/common/ui/config"; import { me } from "@goauthentik/common/users"; import { first } from "@goauthentik/common/utils"; import { WebsocketClient } from "@goauthentik/common/ws"; -import { Interface } from "@goauthentik/elements/Base"; +import { Interface } from "@goauthentik/elements/Interface"; import "@goauthentik/elements/ak-locale-context"; import "@goauthentik/elements/buttons/ActionButton"; import "@goauthentik/elements/enterprise/EnterpriseStatusBanner"; diff --git a/web/src/user/user-settings/details/UserSettingsFlowExecutor.ts b/web/src/user/user-settings/details/UserSettingsFlowExecutor.ts index e7aa36343..f4252f58b 100644 --- a/web/src/user/user-settings/details/UserSettingsFlowExecutor.ts +++ b/web/src/user/user-settings/details/UserSettingsFlowExecutor.ts @@ -2,14 +2,15 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { EVENT_REFRESH } from "@goauthentik/common/constants"; import { MessageLevel } from "@goauthentik/common/messages"; import { refreshMe } from "@goauthentik/common/users"; -import { AKElement, rootInterface } from "@goauthentik/elements/Base"; +import { AKElement } from "@goauthentik/elements/Base"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import { showMessage } from "@goauthentik/elements/messages/MessageContainer"; import { StageHost } from "@goauthentik/flow/stages/base"; import "@goauthentik/user/user-settings/details/stages/prompt/PromptStage"; import { msg } from "@lit/localize"; import { CSSResult, TemplateResult, html } from "lit"; -import { customElement, property, state } from "lit/decorators.js"; +import { customElement, property } from "lit/decorators.js"; import { unsafeHTML } from "lit/directives/unsafe-html.js"; import PFButton from "@patternfly/patternfly/components/Button/button.css"; @@ -21,7 +22,6 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { ChallengeChoices, ChallengeTypes, - CurrentTenant, FlowChallengeResponseRequest, FlowErrorChallenge, FlowsApi, @@ -31,13 +31,13 @@ import { } from "@goauthentik/api"; @customElement("ak-user-settings-flow-executor") -export class UserSettingsFlowExecutor extends AKElement implements StageHost { +export class UserSettingsFlowExecutor + extends WithTenantConfig(AKElement, true) + implements StageHost +{ @property() flowSlug?: string; - @state() - tenant?: CurrentTenant; - private _challenge?: ChallengeTypes; @property({ attribute: false }) @@ -87,7 +87,6 @@ export class UserSettingsFlowExecutor extends AKElement implements StageHost { } firstUpdated(): void { - this.tenant = rootInterface()?.tenant; this.flowSlug = this.tenant?.flowUserSettings; if (!this.flowSlug) { return; diff --git a/web/xliff/de.xlf b/web/xliff/de.xlf index d17ecc60c..9769aa739 100644 --- a/web/xliff/de.xlf +++ b/web/xliff/de.xlf @@ -6268,6 +6268,12 @@ Bindings to groups/users are checked against the user of the event. Learn more + + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. diff --git a/web/xliff/en.xlf b/web/xliff/en.xlf index 0717c8a0b..f24c4f341 100644 --- a/web/xliff/en.xlf +++ b/web/xliff/en.xlf @@ -6544,6 +6544,12 @@ Bindings to groups/users are checked against the user of the event. Learn more + + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. diff --git a/web/xliff/es.xlf b/web/xliff/es.xlf index e67d7ad49..cdc933e6d 100644 --- a/web/xliff/es.xlf +++ b/web/xliff/es.xlf @@ -6184,6 +6184,12 @@ Bindings to groups/users are checked against the user of the event. Learn more + + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. diff --git a/web/xliff/fr.xlf b/web/xliff/fr.xlf index d614ea51b..cb5c0de47 100644 --- a/web/xliff/fr.xlf +++ b/web/xliff/fr.xlf @@ -8231,6 +8231,12 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti Learn more + + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. diff --git a/web/xliff/pl.xlf b/web/xliff/pl.xlf index f0fa97650..479397abe 100644 --- a/web/xliff/pl.xlf +++ b/web/xliff/pl.xlf @@ -6392,6 +6392,12 @@ Bindings to groups/users are checked against the user of the event. Learn more + + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. diff --git a/web/xliff/pseudo-LOCALE.xlf b/web/xliff/pseudo-LOCALE.xlf index 0560de48a..67aaf69f0 100644 --- a/web/xliff/pseudo-LOCALE.xlf +++ b/web/xliff/pseudo-LOCALE.xlf @@ -8179,4 +8179,10 @@ Bindings to groups/users are checked against the user of the event. Learn more + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. + diff --git a/web/xliff/tr.xlf b/web/xliff/tr.xlf index 0dd8e30bb..aaadb7b19 100644 --- a/web/xliff/tr.xlf +++ b/web/xliff/tr.xlf @@ -6177,6 +6177,12 @@ Bindings to groups/users are checked against the user of the event. Learn more + + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. diff --git a/web/xliff/zh-Hans.xlf b/web/xliff/zh-Hans.xlf index f618edfab..d3c79633d 100644 --- a/web/xliff/zh-Hans.xlf +++ b/web/xliff/zh-Hans.xlf @@ -8230,9 +8230,17 @@ Bindings to groups/users are checked against the user of the event. item(s) marked to remove. Provider require enterprise. + 提供程序需要企业版。 Learn more + 了解更多 + + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. diff --git a/web/xliff/zh-Hant.xlf b/web/xliff/zh-Hant.xlf index 3414baaeb..139ccdde6 100644 --- a/web/xliff/zh-Hant.xlf +++ b/web/xliff/zh-Hant.xlf @@ -6225,6 +6225,12 @@ Bindings to groups/users are checked against the user of the event. Learn more + + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. diff --git a/web/xliff/zh_CN.xlf b/web/xliff/zh_CN.xlf index ea9939a67..3bbeaddb9 100644 --- a/web/xliff/zh_CN.xlf +++ b/web/xliff/zh_CN.xlf @@ -8203,6 +8203,14 @@ Bindings to groups/users are checked against the user of the event. Determines how long a session lasts before being disconnected and requiring re-authorization. 设置会话在被断开连接并需要重新授权之前持续的时间。 + + + Provider require enterprise. + 提供程序需要企业版。 + + + Learn more + 了解更多 diff --git a/web/xliff/zh_TW.xlf b/web/xliff/zh_TW.xlf index 534d0de34..4c78b96b2 100644 --- a/web/xliff/zh_TW.xlf +++ b/web/xliff/zh_TW.xlf @@ -8113,6 +8113,12 @@ Bindings to groups/users are checked against the user of the event. Learn more + + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. diff --git a/website/package-lock.json b/website/package-lock.json index 743f24714..e03cb069b 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -18,7 +18,7 @@ "@mdx-js/react": "^3.0.0", "clsx": "^2.1.0", "disqus-react": "^1.1.5", - "postcss": "^8.4.32", + "postcss": "^8.4.33", "prism-react-renderer": "^2.3.1", "rapidoc": "^9.3.4", "react": "^18.2.0", @@ -33,7 +33,7 @@ "@docusaurus/module-type-aliases": "3.0.1", "@docusaurus/tsconfig": "3.0.1", "@docusaurus/types": "3.0.1", - "@types/react": "^18.2.46", + "@types/react": "^18.2.47", "prettier": "3.1.1", "typescript": "~5.3.3" }, @@ -4373,9 +4373,9 @@ "integrity": "sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA==" }, "node_modules/@types/react": { - "version": "18.2.46", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.46.tgz", - "integrity": "sha512-nNCvVBcZlvX4NU1nRRNV/mFl1nNRuTuslAJglQsq+8ldXe5Xv0Wd2f7WTE3jOxhLH2BFfiZGC6GCp+kHQbgG+w==", + "version": "18.2.47", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.47.tgz", + "integrity": "sha512-xquNkkOirwyCgoClNk85BjP+aqnIS+ckAJ8i37gAbDs14jfW/J23f2GItAf33oiUPQnqNMALiFeoM9Y5mbjpVQ==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -13137,9 +13137,9 @@ } }, "node_modules/postcss": { - "version": "8.4.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", - "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", + "version": "8.4.33", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", + "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", "funding": [ { "type": "opencollective", diff --git a/website/package.json b/website/package.json index 7773daee1..37ba114a8 100644 --- a/website/package.json +++ b/website/package.json @@ -25,7 +25,7 @@ "@mdx-js/react": "^3.0.0", "clsx": "^2.1.0", "disqus-react": "^1.1.5", - "postcss": "^8.4.32", + "postcss": "^8.4.33", "prism-react-renderer": "^2.3.1", "rapidoc": "^9.3.4", "react-before-after-slider-component": "^1.1.8", @@ -52,7 +52,7 @@ "@docusaurus/module-type-aliases": "3.0.1", "@docusaurus/tsconfig": "3.0.1", "@docusaurus/types": "3.0.1", - "@types/react": "^18.2.46", + "@types/react": "^18.2.47", "prettier": "3.1.1", "typescript": "~5.3.3" },