From 4ff8d2fbbd1d6c3866de72284e5f4af9cf0e10fd Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 23:43:53 +0100 Subject: [PATCH 01/21] translate: Updates for file web/xliff/en.xlf in zh-Hans (#7929) Translate web/xliff/en.xlf in zh-Hans 100% translated source file: 'web/xliff/en.xlf' on 'zh-Hans'. Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- web/xliff/zh-Hans.xlf | 49 ++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/web/xliff/zh-Hans.xlf b/web/xliff/zh-Hans.xlf index 3c3e42d2a..e616d5e7b 100644 --- a/web/xliff/zh-Hans.xlf +++ b/web/xliff/zh-Hans.xlf @@ -1,4 +1,4 @@ - + @@ -613,9 +613,9 @@ - The URL "" was not found. - 未找到 URL " - "。 + The URL "" was not found. + 未找到 URL " + "。 @@ -1057,8 +1057,8 @@ - To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. - 要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。 + To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. + 要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。 @@ -1799,8 +1799,8 @@ - Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". - 输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。 + Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". + 输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。 @@ -2988,8 +2988,8 @@ doesn't pass when either or both of the selected options are equal or above the - Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' - 包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...' + Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' + 包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...' @@ -3781,8 +3781,8 @@ doesn't pass when either or both of the selected options are equal or above the - When using an external logging solution for archiving, this can be set to "minutes=5". - 使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。 + When using an external logging solution for archiving, this can be set to "minutes=5". + 使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。 @@ -3791,8 +3791,8 @@ doesn't pass when either or both of the selected options are equal or above the - Format: "weeks=3;days=2;hours=3,seconds=2". - 格式:"weeks=3;days=2;hours=3,seconds=2"。 + Format: "weeks=3;days=2;hours=3,seconds=2". + 格式:"weeks=3;days=2;hours=3,seconds=2"。 @@ -3988,10 +3988,10 @@ doesn't pass when either or both of the selected options are equal or above the - Are you sure you want to update ""? + Are you sure you want to update ""? 您确定要更新 - " - " 吗? + " + " 吗? @@ -5077,7 +5077,7 @@ doesn't pass when either or both of the selected options are equal or above the - A "roaming" authenticator, like a YubiKey + A "roaming" authenticator, like a YubiKey 像 YubiKey 这样的“漫游”身份验证器 @@ -5412,10 +5412,10 @@ doesn't pass when either or both of the selected options are equal or above the - ("", of type ) + ("", of type ) - (" - ",类型为 + (" + ",类型为 @@ -5464,7 +5464,7 @@ doesn't pass when either or both of the selected options are equal or above the - If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. + If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. 如果设置时长大于 0,用户可以选择“保持登录”选项,这将使用户的会话延长此处设置的时间。 @@ -7970,7 +7970,7 @@ Bindings to groups/users are checked against the user of the event. 成功创建用户并添加到组 - This user will be added to the group "". + This user will be added to the group "". 此用户将会被添加到组 &quot;&quot;。 @@ -8047,7 +8047,8 @@ Bindings to groups/users are checked against the user of the event. Require Outpost (flow can only be executed from an outpost). + 需要前哨(流程只能从前哨执行)。 - + \ No newline at end of file From 2d3b4ad8e2385518d99366462e6da645e66a99a7 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 23:44:12 +0100 Subject: [PATCH 02/21] translate: Updates for file web/xliff/en.xlf in zh_CN (#7928) Translate web/xliff/en.xlf in zh_CN 100% translated source file: 'web/xliff/en.xlf' on 'zh_CN'. Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- web/xliff/zh_CN.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/xliff/zh_CN.xlf b/web/xliff/zh_CN.xlf index 9bf67b95b..15ba558f0 100644 --- a/web/xliff/zh_CN.xlf +++ b/web/xliff/zh_CN.xlf @@ -8044,6 +8044,10 @@ Bindings to groups/users are checked against the user of the event. Event volume 事件容量 + + + Require Outpost (flow can only be executed from an outpost). + 需要前哨(流程只能从前哨执行)。 From 0bf84b77d8040f05da048ebb91ece25327e10ae0 Mon Sep 17 00:00:00 2001 From: Jens L Date: Wed, 20 Dec 2023 00:40:26 +0100 Subject: [PATCH 03/21] providers/scim: set timeout based on page and page count (#7941) providers/scim: set better timeouts Signed-off-by: Jens Langhammer --- authentik/providers/scim/clients/__init__.py | 1 + authentik/providers/scim/tasks.py | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/authentik/providers/scim/clients/__init__.py b/authentik/providers/scim/clients/__init__.py index a57539f67..0e2e573b5 100644 --- a/authentik/providers/scim/clients/__init__.py +++ b/authentik/providers/scim/clients/__init__.py @@ -1,2 +1,3 @@ """SCIM constants""" PAGE_SIZE = 100 +PAGE_TIMEOUT = 60 * 60 * 0.5 # Half an hour diff --git a/authentik/providers/scim/tasks.py b/authentik/providers/scim/tasks.py index f7639c89f..c0c074ea4 100644 --- a/authentik/providers/scim/tasks.py +++ b/authentik/providers/scim/tasks.py @@ -12,7 +12,7 @@ from structlog.stdlib import get_logger from authentik.core.models import Group, User from authentik.events.monitored_tasks import MonitoredTask, TaskResult, TaskResultStatus from authentik.lib.utils.reflection import path_to_class -from authentik.providers.scim.clients import PAGE_SIZE +from authentik.providers.scim.clients import PAGE_SIZE, PAGE_TIMEOUT from authentik.providers.scim.clients.base import SCIMClient from authentik.providers.scim.clients.exceptions import SCIMRequestException, StopSync from authentik.providers.scim.clients.group import SCIMGroupClient @@ -53,6 +53,9 @@ def scim_sync(self: MonitoredTask, provider_pk: int) -> None: LOGGER.debug("Starting SCIM sync") users_paginator = Paginator(provider.get_user_qs(), PAGE_SIZE) groups_paginator = Paginator(provider.get_group_qs(), PAGE_SIZE) + self.soft_time_limit = self.time_limit = ( + users_paginator.count + groups_paginator.count + ) * PAGE_TIMEOUT with allow_join_result(): try: for page in users_paginator.page_range: @@ -69,7 +72,10 @@ def scim_sync(self: MonitoredTask, provider_pk: int) -> None: self.set_status(result) -@CELERY_APP.task() +@CELERY_APP.task( + soft_time_limit=PAGE_TIMEOUT, + task_time_limit=PAGE_TIMEOUT, +) def scim_sync_users(page: int, provider_pk: int): """Sync single or multiple users to SCIM""" messages = [] From 8525b3db01c3e30cf31269d7aa3b2c2b34bceaa7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Dec 2023 11:30:04 +0100 Subject: [PATCH 04/21] core: bump goauthentik.io/api/v3 from 3.2023104.3 to 3.2023104.4 (#7943) Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2023104.3 to 3.2023104.4. - [Release notes](https://github.com/goauthentik/client-go/releases) - [Commits](https://github.com/goauthentik/client-go/compare/v3.2023104.3...v3.2023104.4) --- updated-dependencies: - dependency-name: goauthentik.io/api/v3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 8823d467a..33bc7c364 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 - goauthentik.io/api/v3 v3.2023104.3 + goauthentik.io/api/v3 v3.2023104.4 golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab golang.org/x/oauth2 v0.15.0 golang.org/x/sync v0.5.0 diff --git a/go.sum b/go.sum index a94e23a58..d26320a4a 100644 --- a/go.sum +++ b/go.sum @@ -309,8 +309,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.2023104.3 h1:MzwdB21Q+G+wACEZiX0T1iVV4l7PjopjaVv6muqJE1M= -goauthentik.io/api/v3 v3.2023104.3/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw= +goauthentik.io/api/v3 v3.2023104.4 h1:3jxzoawGCSlUMNsRltV1ETuGox7MM4xDZ+R+8zMNCh4= +goauthentik.io/api/v3 v3.2023104.4/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= From 82956d275a735700584bc331fa76c6360cbfd638 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Dec 2023 11:30:13 +0100 Subject: [PATCH 05/21] web: bump the storybook group in /web with 7 updates (#7945) Bumps the storybook group in /web with 7 updates: | Package | From | To | | --- | --- | --- | | [@storybook/addon-essentials](https://github.com/storybookjs/storybook/tree/HEAD/code/addons/essentials) | `7.6.5` | `7.6.6` | | [@storybook/addon-links](https://github.com/storybookjs/storybook/tree/HEAD/code/addons/links) | `7.6.5` | `7.6.6` | | [@storybook/api](https://github.com/storybookjs/storybook/tree/HEAD/code/deprecated/manager-api-shim) | `7.6.5` | `7.6.6` | | [@storybook/manager-api](https://github.com/storybookjs/storybook/tree/HEAD/code/lib/manager-api) | `7.6.5` | `7.6.6` | | [@storybook/web-components](https://github.com/storybookjs/storybook/tree/HEAD/code/renderers/web-components) | `7.6.5` | `7.6.6` | | [@storybook/web-components-vite](https://github.com/storybookjs/storybook/tree/HEAD/code/frameworks/web-components-vite) | `7.6.5` | `7.6.6` | | [storybook](https://github.com/storybookjs/storybook/tree/HEAD/code/lib/cli) | `7.6.5` | `7.6.6` | Updates `@storybook/addon-essentials` from 7.6.5 to 7.6.6 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v7.6.6/code/addons/essentials) Updates `@storybook/addon-links` from 7.6.5 to 7.6.6 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v7.6.6/code/addons/links) Updates `@storybook/api` from 7.6.5 to 7.6.6 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/v7.6.6/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v7.6.6/code/deprecated/manager-api-shim) Updates `@storybook/manager-api` from 7.6.5 to 7.6.6 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v7.6.6/code/lib/manager-api) Updates `@storybook/web-components` from 7.6.5 to 7.6.6 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v7.6.6/code/renderers/web-components) Updates `@storybook/web-components-vite` from 7.6.5 to 7.6.6 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v7.6.6/code/frameworks/web-components-vite) Updates `storybook` from 7.6.5 to 7.6.6 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v7.6.6/code/lib/cli) --- updated-dependencies: - dependency-name: "@storybook/addon-essentials" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: "@storybook/addon-links" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: "@storybook/api" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: "@storybook/manager-api" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: "@storybook/web-components" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: "@storybook/web-components-vite" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: storybook dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 586 +++++++++++++++++++++--------------------- web/package.json | 14 +- 2 files changed, 300 insertions(+), 300 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 5e7f5a503..da13d73b3 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -61,13 +61,13 @@ "@rollup/plugin-replace": "^5.0.5", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.5", - "@storybook/addon-essentials": "^7.6.5", - "@storybook/addon-links": "^7.6.5", - "@storybook/api": "^7.6.5", + "@storybook/addon-essentials": "^7.6.6", + "@storybook/addon-links": "^7.6.6", + "@storybook/api": "^7.6.6", "@storybook/blocks": "^7.6.4", - "@storybook/manager-api": "^7.6.5", - "@storybook/web-components": "^7.6.5", - "@storybook/web-components-vite": "^7.6.5", + "@storybook/manager-api": "^7.6.6", + "@storybook/web-components": "^7.6.6", + "@storybook/web-components-vite": "^7.6.6", "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@types/chart.js": "^2.9.41", "@types/codemirror": "5.60.15", @@ -95,7 +95,7 @@ "rollup-plugin-cssimport": "^1.0.3", "rollup-plugin-modify": "^3.0.0", "rollup-plugin-postcss-lit": "^2.1.0", - "storybook": "^7.6.5", + "storybook": "^7.6.6", "storybook-addon-mock": "^4.3.0", "ts-lit-plugin": "^2.0.1", "tslib": "^2.6.2", @@ -4856,12 +4856,12 @@ "dev": true }, "node_modules/@storybook/addon-actions": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-7.6.5.tgz", - "integrity": "sha512-lW/m9YcaNfBZk+TZLxyzHdd563mBWpsUIveOKYjcPdl/q0FblWWZrRsFHqwLK1ldZ4AZXs8J/47G8CBr6Ew2uQ==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-7.6.6.tgz", + "integrity": "sha512-mLJip9Evb2Chj7ymKbpaybe5NgDy3Du7oSWeURPy/0qXJ2cBqHWnhZ8CTK2DasrstsUhQSJaZVXHhaENT+fn+g==", "dev": true, "dependencies": { - "@storybook/core-events": "7.6.5", + "@storybook/core-events": "7.6.6", "@storybook/global": "^5.0.0", "@types/uuid": "^9.0.1", "dequal": "^2.0.2", @@ -4874,9 +4874,9 @@ } }, "node_modules/@storybook/addon-backgrounds": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-7.6.5.tgz", - "integrity": "sha512-wZZOL19vg4TTRtOTl71XKqPe5hQx3XUh9Fle0wOi91FiFrBdqusrppnyS89wPS8RQG5lXEOFEUvYcMmdCcdZfw==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-7.6.6.tgz", + "integrity": "sha512-w5dZ/0cOe55M2G/Lx9f+Ptk4txUPb+Ng+KqEvTaTNqHoh0Xw4QxEn/ciJwmh1u1g3aMZsOgOvwPwug7ykmLgsA==", "dev": true, "dependencies": { "@storybook/global": "^5.0.0", @@ -4889,12 +4889,12 @@ } }, "node_modules/@storybook/addon-controls": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-7.6.5.tgz", - "integrity": "sha512-EdSZ2pYf74mOXZGGJ22lrDvdvL0YKc95iWv9FFEhUFOloMy/0OZPB2ybYmd2KVCy3SeIE4Zfeiw8pDXdCUniOQ==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-7.6.6.tgz", + "integrity": "sha512-VAXXfPLi1M3RXhBf3uIBZ2hrD9UPDe7yvXHIlCzgj1HIJELODCFyUc+RtvN0mPc/nnlEfzhGfJtenZou5LYwIw==", "dev": true, "dependencies": { - "@storybook/blocks": "7.6.5", + "@storybook/blocks": "7.6.6", "lodash": "^4.17.21", "ts-dedent": "^2.0.0" }, @@ -4904,26 +4904,26 @@ } }, "node_modules/@storybook/addon-docs": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-7.6.5.tgz", - "integrity": "sha512-D9tZyD41IujCHiPYdfS2bKtZRJPNwO4EydzyqODXppomluhFbY3uTEaf0H1UFnJLQxWNXZ7rr3aS0V3O6yu8pA==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-7.6.6.tgz", + "integrity": "sha512-l4gtoNTn1wHE11x44te1cDkqfm+/w+eNonHe56bwgSqETclS5z18wvM9bQZF32G6C9fpSefaJW3cxVvcuJL1fg==", "dev": true, "dependencies": { "@jest/transform": "^29.3.1", "@mdx-js/react": "^2.1.5", - "@storybook/blocks": "7.6.5", - "@storybook/client-logger": "7.6.5", - "@storybook/components": "7.6.5", - "@storybook/csf-plugin": "7.6.5", - "@storybook/csf-tools": "7.6.5", + "@storybook/blocks": "7.6.6", + "@storybook/client-logger": "7.6.6", + "@storybook/components": "7.6.6", + "@storybook/csf-plugin": "7.6.6", + "@storybook/csf-tools": "7.6.6", "@storybook/global": "^5.0.0", "@storybook/mdx2-csf": "^1.0.0", - "@storybook/node-logger": "7.6.5", - "@storybook/postinstall": "7.6.5", - "@storybook/preview-api": "7.6.5", - "@storybook/react-dom-shim": "7.6.5", - "@storybook/theming": "7.6.5", - "@storybook/types": "7.6.5", + "@storybook/node-logger": "7.6.6", + "@storybook/postinstall": "7.6.6", + "@storybook/preview-api": "7.6.6", + "@storybook/react-dom-shim": "7.6.6", + "@storybook/theming": "7.6.6", + "@storybook/types": "7.6.6", "fs-extra": "^11.1.0", "remark-external-links": "^8.0.0", "remark-slug": "^6.0.0", @@ -4939,17 +4939,17 @@ } }, "node_modules/@storybook/addon-docs/node_modules/@storybook/preview-api": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.5.tgz", - "integrity": "sha512-9XzuDXXgNuA6dDZ3DXsUwEG6ElxeTbzLuYuzcjtS1FusSICZ2iYmxfS0GfSud9MjPPYOJYoSOvMdIHjorjgByA==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.6.tgz", + "integrity": "sha512-Bt6xIAR5yZ/JWc90X4BbLOA97iL65glZ1SOBgFFv2mHrdZ1lcdKhAlQr2aeJAf1mLvBtalPjvKzi9EuVY3FZ4w==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.5", - "@storybook/client-logger": "7.6.5", - "@storybook/core-events": "7.6.5", + "@storybook/channels": "7.6.6", + "@storybook/client-logger": "7.6.6", + "@storybook/core-events": "7.6.6", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/types": "7.6.5", + "@storybook/types": "7.6.6", "@types/qs": "^6.9.5", "dequal": "^2.0.2", "lodash": "^4.17.21", @@ -4979,24 +4979,24 @@ } }, "node_modules/@storybook/addon-essentials": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-7.6.5.tgz", - "integrity": "sha512-VCLj1JAEpGoqF5iFJOo1CZFFck/tg4m/98DLdQuNuXvxT6jqaF0NI9UUQuJLIGteDCR7NKRbTFc1hV3/Ev+Ziw==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-7.6.6.tgz", + "integrity": "sha512-OQ8A6r06mg/HvyIk/j2Gt9DK5Qtqgtwq2Ydm5IgVW6gZsuRnv1FAeUG6okf8oXowAzpYoHdsDmCVwNOAGWGO7w==", "dev": true, "dependencies": { - "@storybook/addon-actions": "7.6.5", - "@storybook/addon-backgrounds": "7.6.5", - "@storybook/addon-controls": "7.6.5", - "@storybook/addon-docs": "7.6.5", - "@storybook/addon-highlight": "7.6.5", - "@storybook/addon-measure": "7.6.5", - "@storybook/addon-outline": "7.6.5", - "@storybook/addon-toolbars": "7.6.5", - "@storybook/addon-viewport": "7.6.5", - "@storybook/core-common": "7.6.5", - "@storybook/manager-api": "7.6.5", - "@storybook/node-logger": "7.6.5", - "@storybook/preview-api": "7.6.5", + "@storybook/addon-actions": "7.6.6", + "@storybook/addon-backgrounds": "7.6.6", + "@storybook/addon-controls": "7.6.6", + "@storybook/addon-docs": "7.6.6", + "@storybook/addon-highlight": "7.6.6", + "@storybook/addon-measure": "7.6.6", + "@storybook/addon-outline": "7.6.6", + "@storybook/addon-toolbars": "7.6.6", + "@storybook/addon-viewport": "7.6.6", + "@storybook/core-common": "7.6.6", + "@storybook/manager-api": "7.6.6", + "@storybook/node-logger": "7.6.6", + "@storybook/preview-api": "7.6.6", "ts-dedent": "^2.0.0" }, "funding": { @@ -5009,17 +5009,17 @@ } }, "node_modules/@storybook/addon-essentials/node_modules/@storybook/preview-api": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.5.tgz", - "integrity": "sha512-9XzuDXXgNuA6dDZ3DXsUwEG6ElxeTbzLuYuzcjtS1FusSICZ2iYmxfS0GfSud9MjPPYOJYoSOvMdIHjorjgByA==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.6.tgz", + "integrity": "sha512-Bt6xIAR5yZ/JWc90X4BbLOA97iL65glZ1SOBgFFv2mHrdZ1lcdKhAlQr2aeJAf1mLvBtalPjvKzi9EuVY3FZ4w==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.5", - "@storybook/client-logger": "7.6.5", - "@storybook/core-events": "7.6.5", + "@storybook/channels": "7.6.6", + "@storybook/client-logger": "7.6.6", + "@storybook/core-events": "7.6.6", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/types": "7.6.5", + "@storybook/types": "7.6.6", "@types/qs": "^6.9.5", "dequal": "^2.0.2", "lodash": "^4.17.21", @@ -5035,9 +5035,9 @@ } }, "node_modules/@storybook/addon-highlight": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-7.6.5.tgz", - "integrity": "sha512-CxzmIb30F9nLPQwT0lCPYhOAwGlGF4IkgkO8hYA7VfGCGUkJZEyyN/YkP/ZCUSdCIRChDBouR3KiFFd4mDFKzg==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-7.6.6.tgz", + "integrity": "sha512-B85UaCts2uMpa0yHBSnupzy2WCdW4vfB+lfaBug9beyOyZQdel07BumblE0KwSJftYgdCNPUZ5MRlqEDzMLTWQ==", "dev": true, "dependencies": { "@storybook/global": "^5.0.0" @@ -5048,9 +5048,9 @@ } }, "node_modules/@storybook/addon-links": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-7.6.5.tgz", - "integrity": "sha512-Lx4Ng+iXt0YpIrKGr+nOZlpN9ypOoEDoP/7bZ6m7GXuVAkDm3JrRCBp7e2ZKSKcTxPdjPuO9HVKkIjtqjINlpw==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-7.6.6.tgz", + "integrity": "sha512-NEcqOz6zZ1dJnCcVmYdaQTAMAGIb8NFAZGnr9DU0q+t4B1fTaWUgqLtBM5V6YqIrXGSC/oKLpjWUkS5UpswlHA==", "dev": true, "dependencies": { "@storybook/csf": "^0.1.2", @@ -5071,9 +5071,9 @@ } }, "node_modules/@storybook/addon-measure": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-7.6.5.tgz", - "integrity": "sha512-tlUudVQSrA+bwI4dhO8J7nYHtYdylcBZ86ybnqMmdTthsnyc7jnaFVQwbb6bbQJpPxvEvoNds5bVGUFocuvymQ==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-7.6.6.tgz", + "integrity": "sha512-b4hyCudlhsbYN1We8pfZHZJ0i0sfC8+GJvrqZQqdSqGicUmA00mggY1GE+gEoHziQ5/4auxFRS3HfUgaQWUNjg==", "dev": true, "dependencies": { "@storybook/global": "^5.0.0", @@ -5085,9 +5085,9 @@ } }, "node_modules/@storybook/addon-outline": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-7.6.5.tgz", - "integrity": "sha512-P7X4+Z9L/l/RZW9UvvM+iuK2SUHD22KPc+dbYOifRXDovUqhfmcKVh1CUqTDMyZrg2ZAbropehMz1eI9BlQfxg==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-7.6.6.tgz", + "integrity": "sha512-BMjpjzNEnN8LC7JK92WCXyWgmJwAaEQjRDinr7eD4cBt4Uas5kbciw1g8PtTnh0GbYUsImKao0nzakSVObAdzg==", "dev": true, "dependencies": { "@storybook/global": "^5.0.0", @@ -5099,9 +5099,9 @@ } }, "node_modules/@storybook/addon-toolbars": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-7.6.5.tgz", - "integrity": "sha512-/zqWbVNE/SHc8I5Prnd2Q8U57RGEIYvHfeXjfkuLcE2Quc4Iss4x/9eU7SKu4jm+IOO2s0wlN6HcqI3XEf2XxA==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-7.6.6.tgz", + "integrity": "sha512-sQm5+FcoSMSGn1ioXHoukO6OhUlcNZil0/fonAY50uvp6Z4DyI0FTU7BKIm/NoMqAExQk3sZRfAC/nZZ9Epb0Q==", "dev": true, "funding": { "type": "opencollective", @@ -5109,9 +5109,9 @@ } }, "node_modules/@storybook/addon-viewport": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-7.6.5.tgz", - "integrity": "sha512-9ghKTaduIUvQ6oShmWLuwMeTjtMR4RgKeKHrTJ7THMqvE/ydDPCYeL7ugF65ocXZSEz/QmxdK7uL686ZMKsqNA==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-7.6.6.tgz", + "integrity": "sha512-/ijbzDf1Iq30LvZW2NE8cO4TeHusw0N+jTDUK1+vhxGNMFo9DUIgRkAi6VpFEfS0aQ5d82523WSWzVso7b/Hmg==", "dev": true, "dependencies": { "memoizerific": "^1.11.3" @@ -5304,13 +5304,13 @@ "dev": true }, "node_modules/@storybook/api": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/api/-/api-7.6.5.tgz", - "integrity": "sha512-o1RH47iIgG4ie4hjJP1HgsCiuTKlGW0egaAy6E6Np3bDmujy5udWEf8vnXbcaBerc5ZSrQs45kfSWugHy2a4FA==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/api/-/api-7.6.6.tgz", + "integrity": "sha512-e3k45k7twP3z5ZJ+rCCaHI+jmYm5yoFo2eLjYmnYFUv2V3vvYPgqD2CiT0crne7uWmhpRxP49aU9DEvQaEZtdA==", "dev": true, "dependencies": { - "@storybook/client-logger": "7.6.5", - "@storybook/manager-api": "7.6.5" + "@storybook/client-logger": "7.6.6", + "@storybook/manager-api": "7.6.6" }, "funding": { "type": "opencollective", @@ -5318,22 +5318,22 @@ } }, "node_modules/@storybook/blocks": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-7.6.5.tgz", - "integrity": "sha512-/NjuYkPks5w9lKn47KLgVC5cBkwfc+ERAp0CY0Xe//BQJkP+bcI8lE8d9Qc9IXFbOTvYEULeQrFgCkesk5BmLg==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-7.6.6.tgz", + "integrity": "sha512-QLqkiSNrtGnh8RK9ipD63jVAUenkRu+72xR31DViZWRV9V8G2hzky5E/RoZWPEx+DfmBIUJ7Tcef6cCRcxEj9A==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.5", - "@storybook/client-logger": "7.6.5", - "@storybook/components": "7.6.5", - "@storybook/core-events": "7.6.5", + "@storybook/channels": "7.6.6", + "@storybook/client-logger": "7.6.6", + "@storybook/components": "7.6.6", + "@storybook/core-events": "7.6.6", "@storybook/csf": "^0.1.2", - "@storybook/docs-tools": "7.6.5", + "@storybook/docs-tools": "7.6.6", "@storybook/global": "^5.0.0", - "@storybook/manager-api": "7.6.5", - "@storybook/preview-api": "7.6.5", - "@storybook/theming": "7.6.5", - "@storybook/types": "7.6.5", + "@storybook/manager-api": "7.6.6", + "@storybook/preview-api": "7.6.6", + "@storybook/theming": "7.6.6", + "@storybook/types": "7.6.6", "@types/lodash": "^4.14.167", "color-convert": "^2.0.1", "dequal": "^2.0.2", @@ -5357,17 +5357,17 @@ } }, "node_modules/@storybook/blocks/node_modules/@storybook/preview-api": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.5.tgz", - "integrity": "sha512-9XzuDXXgNuA6dDZ3DXsUwEG6ElxeTbzLuYuzcjtS1FusSICZ2iYmxfS0GfSud9MjPPYOJYoSOvMdIHjorjgByA==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.6.tgz", + "integrity": "sha512-Bt6xIAR5yZ/JWc90X4BbLOA97iL65glZ1SOBgFFv2mHrdZ1lcdKhAlQr2aeJAf1mLvBtalPjvKzi9EuVY3FZ4w==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.5", - "@storybook/client-logger": "7.6.5", - "@storybook/core-events": "7.6.5", + "@storybook/channels": "7.6.6", + "@storybook/client-logger": "7.6.6", + "@storybook/core-events": "7.6.6", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/types": "7.6.5", + "@storybook/types": "7.6.6", "@types/qs": "^6.9.5", "dequal": "^2.0.2", "lodash": "^4.17.21", @@ -5383,15 +5383,15 @@ } }, "node_modules/@storybook/builder-manager": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/builder-manager/-/builder-manager-7.6.5.tgz", - "integrity": "sha512-FQyI+tfzMam2XKXq7k921YVafIJs9Vqvos5qx8vyRnRffo55UU8tgunwjGn0PswtbMm6sThVqE0C0ZzVr7RG8A==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/builder-manager/-/builder-manager-7.6.6.tgz", + "integrity": "sha512-96vmtUqh016H2n80xhvBZU2w5flTOzY7S0nW9nfxbY4UY4b39WajgwJ5wpg8l0YmCwQTrxCwY9/VE2Pd6CCqPA==", "dev": true, "dependencies": { "@fal-works/esbuild-plugin-global-externals": "^2.1.2", - "@storybook/core-common": "7.6.5", - "@storybook/manager": "7.6.5", - "@storybook/node-logger": "7.6.5", + "@storybook/core-common": "7.6.6", + "@storybook/manager": "7.6.6", + "@storybook/node-logger": "7.6.6", "@types/ejs": "^3.1.1", "@types/find-cache-dir": "^3.2.1", "@yarnpkg/esbuild-plugin-pnp": "^3.0.0-rc.10", @@ -5425,19 +5425,19 @@ } }, "node_modules/@storybook/builder-vite": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-7.6.5.tgz", - "integrity": "sha512-VbAYTGr92lgCWTwO2Z7NgSW3f5/K4Vr0Qxa2IlTgMCymWdDbWdIQiREcmCP0vjAGM2ftq1+vxngohVgx/r7pUw==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-7.6.6.tgz", + "integrity": "sha512-vDBHjsswnVScVgGHeIZ22R/LoRt5T1F62p5czusydBSxKGzma5Va4JHQJp4/IKXwiCZbXcua/Cs7VKtBLO+50A==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.5", - "@storybook/client-logger": "7.6.5", - "@storybook/core-common": "7.6.5", - "@storybook/csf-plugin": "7.6.5", - "@storybook/node-logger": "7.6.5", - "@storybook/preview": "7.6.5", - "@storybook/preview-api": "7.6.5", - "@storybook/types": "7.6.5", + "@storybook/channels": "7.6.6", + "@storybook/client-logger": "7.6.6", + "@storybook/core-common": "7.6.6", + "@storybook/csf-plugin": "7.6.6", + "@storybook/node-logger": "7.6.6", + "@storybook/preview": "7.6.6", + "@storybook/preview-api": "7.6.6", + "@storybook/types": "7.6.6", "@types/find-cache-dir": "^3.2.1", "browser-assert": "^1.2.1", "es-module-lexer": "^0.9.3", @@ -5470,17 +5470,17 @@ } }, "node_modules/@storybook/builder-vite/node_modules/@storybook/preview-api": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.5.tgz", - "integrity": "sha512-9XzuDXXgNuA6dDZ3DXsUwEG6ElxeTbzLuYuzcjtS1FusSICZ2iYmxfS0GfSud9MjPPYOJYoSOvMdIHjorjgByA==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.6.tgz", + "integrity": "sha512-Bt6xIAR5yZ/JWc90X4BbLOA97iL65glZ1SOBgFFv2mHrdZ1lcdKhAlQr2aeJAf1mLvBtalPjvKzi9EuVY3FZ4w==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.5", - "@storybook/client-logger": "7.6.5", - "@storybook/core-events": "7.6.5", + "@storybook/channels": "7.6.6", + "@storybook/client-logger": "7.6.6", + "@storybook/core-events": "7.6.6", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/types": "7.6.5", + "@storybook/types": "7.6.6", "@types/qs": "^6.9.5", "dequal": "^2.0.2", "lodash": "^4.17.21", @@ -5526,13 +5526,13 @@ } }, "node_modules/@storybook/channels": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.6.5.tgz", - "integrity": "sha512-FIlNkyfQy9uHoJfAFL2/wO3ASGJELFvBzURBE2rcEF/TS7GcUiqWnBfiDxAbwSEjSOm2F0eEq3UXhaZEjpJHDw==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.6.6.tgz", + "integrity": "sha512-vvo7fBe2WffPonNNOA7Xx7jcHAto8qJYlq+VMysfheXrsRRbhHl3WQOA18Vm8hV9txtqdqk0hwQiXOWvhYVpeQ==", "dev": true, "dependencies": { - "@storybook/client-logger": "7.6.5", - "@storybook/core-events": "7.6.5", + "@storybook/client-logger": "7.6.6", + "@storybook/core-events": "7.6.6", "@storybook/global": "^5.0.0", "qs": "^6.10.0", "telejson": "^7.2.0", @@ -5544,23 +5544,23 @@ } }, "node_modules/@storybook/cli": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/cli/-/cli-7.6.5.tgz", - "integrity": "sha512-w+Y8dx5oCLQVESOVmpsQuFksr/ewARKrnSKl9kwnVMN4sMgjOgoZ3zmV66J7SKexvwyuwlOjf840pmEglGdPPg==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/cli/-/cli-7.6.6.tgz", + "integrity": "sha512-FLmWrbmGOqe1VYwqyIWxU2lJcYPssORmSbSVVPw6OqQIXx3NrNBrmZDLncMwbVCDQ8eU54J1zb+MyDmSqMbVFg==", "dev": true, "dependencies": { "@babel/core": "^7.23.2", "@babel/preset-env": "^7.23.2", "@babel/types": "^7.23.0", "@ndelangen/get-tarball": "^3.0.7", - "@storybook/codemod": "7.6.5", - "@storybook/core-common": "7.6.5", - "@storybook/core-events": "7.6.5", - "@storybook/core-server": "7.6.5", - "@storybook/csf-tools": "7.6.5", - "@storybook/node-logger": "7.6.5", - "@storybook/telemetry": "7.6.5", - "@storybook/types": "7.6.5", + "@storybook/codemod": "7.6.6", + "@storybook/core-common": "7.6.6", + "@storybook/core-events": "7.6.6", + "@storybook/core-server": "7.6.6", + "@storybook/csf-tools": "7.6.6", + "@storybook/node-logger": "7.6.6", + "@storybook/telemetry": "7.6.6", + "@storybook/types": "7.6.6", "@types/semver": "^7.3.4", "@yarnpkg/fslib": "2.10.3", "@yarnpkg/libzip": "2.3.0", @@ -5724,9 +5724,9 @@ "dev": true }, "node_modules/@storybook/client-logger": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-7.6.5.tgz", - "integrity": "sha512-S5aROWgssqg7tcs9lgW5wmCAz4SxMAtioiyVj5oFecmPCbQtFVIAREYzeoxE4GfJL+plrfRkum4BzziANn8EhQ==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-7.6.6.tgz", + "integrity": "sha512-WEvVyuQR5oNF8jcMmGA13zDjxP/l46kOBBvB6JSc8toUdtLZ/kZWSnU0ioNM8+ECpFqXHjBcF2K6uSJOEb6YEg==", "dev": true, "dependencies": { "@storybook/global": "^5.0.0" @@ -5737,18 +5737,18 @@ } }, "node_modules/@storybook/codemod": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/codemod/-/codemod-7.6.5.tgz", - "integrity": "sha512-K5C9ltBClZ0aSyujGt3RJFtRicrUZy8nzhHrcADUj27rrQD26jH/p+Y05jWKj9JcI8SyMg978GN5X/1aw2Y31A==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/codemod/-/codemod-7.6.6.tgz", + "integrity": "sha512-6QwW6T6ZgwwbTkEoZ7CAoX7lUUob7Sy7bRkMHhSjJe2++wEVFOYLvzHcLUJCupK59+WhmsJU9PpUMlXEKi40TQ==", "dev": true, "dependencies": { "@babel/core": "^7.23.2", "@babel/preset-env": "^7.23.2", "@babel/types": "^7.23.0", "@storybook/csf": "^0.1.2", - "@storybook/csf-tools": "7.6.5", - "@storybook/node-logger": "7.6.5", - "@storybook/types": "7.6.5", + "@storybook/csf-tools": "7.6.6", + "@storybook/node-logger": "7.6.6", + "@storybook/types": "7.6.6", "@types/cross-spawn": "^6.0.2", "cross-spawn": "^7.0.3", "globby": "^11.0.2", @@ -5778,18 +5778,18 @@ } }, "node_modules/@storybook/components": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/components/-/components-7.6.5.tgz", - "integrity": "sha512-w4ZucbBBZ+NKMWlJKVj2I/bMBBq7gzDp9lzc4+8QaQ3vUPXKqc1ilIPYo/7UR5oxwDVMZocmMSgl9L8lvf7+Mw==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-7.6.6.tgz", + "integrity": "sha512-FSfcRxdmV4+LJHjMk0eodGVnZdb2qrKKmbtsn0O/434z586zPA287/wJJsm4JS/Xr1WS9oTvU6mYMDChkcxgeQ==", "dev": true, "dependencies": { "@radix-ui/react-select": "^1.2.2", "@radix-ui/react-toolbar": "^1.0.4", - "@storybook/client-logger": "7.6.5", + "@storybook/client-logger": "7.6.6", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/theming": "7.6.5", - "@storybook/types": "7.6.5", + "@storybook/theming": "7.6.6", + "@storybook/types": "7.6.6", "memoizerific": "^1.11.3", "use-resize-observer": "^9.1.0", "util-deprecate": "^1.0.2" @@ -5804,13 +5804,13 @@ } }, "node_modules/@storybook/core-client": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/core-client/-/core-client-7.6.5.tgz", - "integrity": "sha512-6FtyJcz8MSl+JYwNJZ53FM6rkT27pFHWcJPdtw/9229Ec8as9RpkNeZ/NBZjRTeDkn9Ki0VOiVAefNie9tZ/8Q==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/core-client/-/core-client-7.6.6.tgz", + "integrity": "sha512-P100aNf+WpvzlfULZp1NPd60/nxsppLmft2DdIyAx1j4QPMZvUJyJB+hdBMzTFiPEhIUncIMoIVf2R3UXC5DfA==", "dev": true, "dependencies": { - "@storybook/client-logger": "7.6.5", - "@storybook/preview-api": "7.6.5" + "@storybook/client-logger": "7.6.6", + "@storybook/preview-api": "7.6.6" }, "funding": { "type": "opencollective", @@ -5818,17 +5818,17 @@ } }, "node_modules/@storybook/core-client/node_modules/@storybook/preview-api": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.5.tgz", - "integrity": "sha512-9XzuDXXgNuA6dDZ3DXsUwEG6ElxeTbzLuYuzcjtS1FusSICZ2iYmxfS0GfSud9MjPPYOJYoSOvMdIHjorjgByA==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.6.tgz", + "integrity": "sha512-Bt6xIAR5yZ/JWc90X4BbLOA97iL65glZ1SOBgFFv2mHrdZ1lcdKhAlQr2aeJAf1mLvBtalPjvKzi9EuVY3FZ4w==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.5", - "@storybook/client-logger": "7.6.5", - "@storybook/core-events": "7.6.5", + "@storybook/channels": "7.6.6", + "@storybook/client-logger": "7.6.6", + "@storybook/core-events": "7.6.6", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/types": "7.6.5", + "@storybook/types": "7.6.6", "@types/qs": "^6.9.5", "dequal": "^2.0.2", "lodash": "^4.17.21", @@ -5844,14 +5844,14 @@ } }, "node_modules/@storybook/core-common": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-7.6.5.tgz", - "integrity": "sha512-z4EgzZSIVbID6Ib0jhh3jimKeaDWU8OOhoZYfn3galFmgQWowWOv1oMgipWiXfRLWw9DaLFQiCHIdLANH+VO2g==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-7.6.6.tgz", + "integrity": "sha512-DpbFSYw8LHuwpeU2ec5uWryxrSqslFJnWTfNA7AvpzCviWXkz4kq+YYrDee9XExF6OozNwILmG6m52SnraysBA==", "dev": true, "dependencies": { - "@storybook/core-events": "7.6.5", - "@storybook/node-logger": "7.6.5", - "@storybook/types": "7.6.5", + "@storybook/core-events": "7.6.6", + "@storybook/node-logger": "7.6.6", + "@storybook/types": "7.6.6", "@types/find-cache-dir": "^3.2.1", "@types/node": "^18.0.0", "@types/node-fetch": "^2.6.4", @@ -6000,9 +6000,9 @@ } }, "node_modules/@storybook/core-events": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.6.5.tgz", - "integrity": "sha512-zk2q/qicYXAzHA4oV3GDbIql+Kd4TOHUgDE8e4jPCOPp856z2ScqEKUAbiJizs6eEJOH4nW9Db1kuzgrBVEykQ==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.6.6.tgz", + "integrity": "sha512-7+q9HiZiLxaQcwpaSLQrLdjHNHBoOoUY9ZcZXI9iNFSopOgb/ItDnzzlpv08NC7CbKae1hVKJM/t5aSTl7tCMw==", "dev": true, "dependencies": { "ts-dedent": "^2.0.0" @@ -6013,26 +6013,26 @@ } }, "node_modules/@storybook/core-server": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/core-server/-/core-server-7.6.5.tgz", - "integrity": "sha512-BfKzK/ObTjUcPvE5/r1pogCifM/4nLRhOUYJl7XekwHkOQwn19e6H3/ku1W3jDoYXBu642Dc9X7l/ERjKTqxFg==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/core-server/-/core-server-7.6.6.tgz", + "integrity": "sha512-QFVahaExgGtq9swBXgQAMUiCqpCcyVXOiKTIy1j+1uAhPVqhpCxBkkFoXruih5hbIMZyohE4mLPCAr/ivicoDg==", "dev": true, "dependencies": { "@aw-web-design/x-default-browser": "1.4.126", "@discoveryjs/json-ext": "^0.5.3", - "@storybook/builder-manager": "7.6.5", - "@storybook/channels": "7.6.5", - "@storybook/core-common": "7.6.5", - "@storybook/core-events": "7.6.5", + "@storybook/builder-manager": "7.6.6", + "@storybook/channels": "7.6.6", + "@storybook/core-common": "7.6.6", + "@storybook/core-events": "7.6.6", "@storybook/csf": "^0.1.2", - "@storybook/csf-tools": "7.6.5", + "@storybook/csf-tools": "7.6.6", "@storybook/docs-mdx": "^0.1.0", "@storybook/global": "^5.0.0", - "@storybook/manager": "7.6.5", - "@storybook/node-logger": "7.6.5", - "@storybook/preview-api": "7.6.5", - "@storybook/telemetry": "7.6.5", - "@storybook/types": "7.6.5", + "@storybook/manager": "7.6.6", + "@storybook/node-logger": "7.6.6", + "@storybook/preview-api": "7.6.6", + "@storybook/telemetry": "7.6.6", + "@storybook/types": "7.6.6", "@types/detect-port": "^1.3.0", "@types/node": "^18.0.0", "@types/pretty-hrtime": "^1.0.0", @@ -6066,17 +6066,17 @@ } }, "node_modules/@storybook/core-server/node_modules/@storybook/preview-api": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.5.tgz", - "integrity": "sha512-9XzuDXXgNuA6dDZ3DXsUwEG6ElxeTbzLuYuzcjtS1FusSICZ2iYmxfS0GfSud9MjPPYOJYoSOvMdIHjorjgByA==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.6.tgz", + "integrity": "sha512-Bt6xIAR5yZ/JWc90X4BbLOA97iL65glZ1SOBgFFv2mHrdZ1lcdKhAlQr2aeJAf1mLvBtalPjvKzi9EuVY3FZ4w==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.5", - "@storybook/client-logger": "7.6.5", - "@storybook/core-events": "7.6.5", + "@storybook/channels": "7.6.6", + "@storybook/client-logger": "7.6.6", + "@storybook/core-events": "7.6.6", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/types": "7.6.5", + "@storybook/types": "7.6.6", "@types/qs": "^6.9.5", "dequal": "^2.0.2", "lodash": "^4.17.21", @@ -6209,12 +6209,12 @@ } }, "node_modules/@storybook/csf-plugin": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-7.6.5.tgz", - "integrity": "sha512-iQ8Y/Qq1IUhHRddjDVicWJA2sM7OZA1FR97OvWUT2240WjCuQSCfy32JD8TQlYjqXgEolJeLPv3zW4qH5om4LQ==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-7.6.6.tgz", + "integrity": "sha512-SqdffT14+XNpf+7vA29Elur28VArXtFv4cXMlsCbswbRuY+a0A8vYNwVIfCUy9u4WHTcQX1/tUkDAMh80lrVRQ==", "dev": true, "dependencies": { - "@storybook/csf-tools": "7.6.5", + "@storybook/csf-tools": "7.6.6", "unplugin": "^1.3.1" }, "funding": { @@ -6223,9 +6223,9 @@ } }, "node_modules/@storybook/csf-tools": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-7.6.5.tgz", - "integrity": "sha512-1iaCh7nt+WE7Q5UwRhLLc5flMNoAV/vBr0tvDSCKiHaO+D3dZzlZOe/U+S6wegdyN2QNcvT2xs179CcrX6Qp6w==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-7.6.6.tgz", + "integrity": "sha512-VXOZCzfSVJL832u17pPhFu1x3PPaAN9d8VXNFX+t/2raga7tK3T7Qhe7lWfP7EZcrVvSCEEp0aMRz2EzzDGVtw==", "dev": true, "dependencies": { "@babel/generator": "^7.23.0", @@ -6233,7 +6233,7 @@ "@babel/traverse": "^7.23.2", "@babel/types": "^7.23.0", "@storybook/csf": "^0.1.2", - "@storybook/types": "7.6.5", + "@storybook/types": "7.6.6", "fs-extra": "^11.1.0", "recast": "^0.23.1", "ts-dedent": "^2.0.0" @@ -6264,14 +6264,14 @@ "dev": true }, "node_modules/@storybook/docs-tools": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/docs-tools/-/docs-tools-7.6.5.tgz", - "integrity": "sha512-UyHkHu5Af6jMpYsR4lZ69D32GQGeA0pLAn7jaBbQndgAjBdK1ykZcifiUC7Wz1hG7+YpuYspEGuDEddOh+X8FQ==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/docs-tools/-/docs-tools-7.6.6.tgz", + "integrity": "sha512-nc5ZjN2s8SC2PtsZoFf9Wm6gD8TcSlkYbF/mjtyLCGN+Fi+k5B5iudqoa65H19hwiLlzBdcnpQ8C89AiK33J9Q==", "dev": true, "dependencies": { - "@storybook/core-common": "7.6.5", - "@storybook/preview-api": "7.6.5", - "@storybook/types": "7.6.5", + "@storybook/core-common": "7.6.6", + "@storybook/preview-api": "7.6.6", + "@storybook/types": "7.6.6", "@types/doctrine": "^0.0.3", "assert": "^2.1.0", "doctrine": "^3.0.0", @@ -6283,17 +6283,17 @@ } }, "node_modules/@storybook/docs-tools/node_modules/@storybook/preview-api": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.5.tgz", - "integrity": "sha512-9XzuDXXgNuA6dDZ3DXsUwEG6ElxeTbzLuYuzcjtS1FusSICZ2iYmxfS0GfSud9MjPPYOJYoSOvMdIHjorjgByA==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.6.tgz", + "integrity": "sha512-Bt6xIAR5yZ/JWc90X4BbLOA97iL65glZ1SOBgFFv2mHrdZ1lcdKhAlQr2aeJAf1mLvBtalPjvKzi9EuVY3FZ4w==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.5", - "@storybook/client-logger": "7.6.5", - "@storybook/core-events": "7.6.5", + "@storybook/channels": "7.6.6", + "@storybook/client-logger": "7.6.6", + "@storybook/core-events": "7.6.6", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/types": "7.6.5", + "@storybook/types": "7.6.6", "@types/qs": "^6.9.5", "dequal": "^2.0.2", "lodash": "^4.17.21", @@ -6315,9 +6315,9 @@ "dev": true }, "node_modules/@storybook/manager": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/manager/-/manager-7.6.5.tgz", - "integrity": "sha512-y1KLH0O1PGPyMxGMvOhppzFSO7r4ibjTve5iqsI0JZwxUjNuBKRLYbrhXdAyC2iacvxYNrHgevae1k9XdD+FQw==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/manager/-/manager-7.6.6.tgz", + "integrity": "sha512-Ga3LcSu/xxSyg+cLlO9AS8QjW+D667V+c9qQPmsFyU6qfFc6m6mVqcRLSmFVD5e7P/o0FL7STOf9jAKkDcW8xw==", "dev": true, "funding": { "type": "opencollective", @@ -6325,19 +6325,19 @@ } }, "node_modules/@storybook/manager-api": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-7.6.5.tgz", - "integrity": "sha512-tE3OShOcs6A3XtI3NJd6hYQOZLaP++Fn0dCtowBwYh/vS1EN/AyroVmL97tsxn1DZTyoRt0GidwbB6dvLMBOwA==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-7.6.6.tgz", + "integrity": "sha512-euRAbSZAUzHDt6z1Pq/g45N/RNqta9RaQAym18zt/oLWiYOIrkLmdf7kCuFYsmuA5XQBytiJqwkAD7uF1aLe0g==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.5", - "@storybook/client-logger": "7.6.5", - "@storybook/core-events": "7.6.5", + "@storybook/channels": "7.6.6", + "@storybook/client-logger": "7.6.6", + "@storybook/core-events": "7.6.6", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/router": "7.6.5", - "@storybook/theming": "7.6.5", - "@storybook/types": "7.6.5", + "@storybook/router": "7.6.6", + "@storybook/theming": "7.6.6", + "@storybook/types": "7.6.6", "dequal": "^2.0.2", "lodash": "^4.17.21", "memoizerific": "^1.11.3", @@ -6391,9 +6391,9 @@ "dev": true }, "node_modules/@storybook/node-logger": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-7.6.5.tgz", - "integrity": "sha512-xKw6IH1wLkIssekdBv3bd13xYKUF1t8EwqDR8BYcN8AVjZlqJMTifssqG4bYV+G/B7J3tz4ugJ5nmtWg6RQ0Qw==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-7.6.6.tgz", + "integrity": "sha512-b2OF9GRNI01MlBlnDGS8S6/yOpBNl8eH/0ONafuMPzFEZs5PouHGsFflJvQwwcdVTknMjF5uVS2eSmnLZ8spvA==", "dev": true, "funding": { "type": "opencollective", @@ -6401,9 +6401,9 @@ } }, "node_modules/@storybook/postinstall": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/postinstall/-/postinstall-7.6.5.tgz", - "integrity": "sha512-12WxfpqGKsk7GQ3KWiZSbamsYK8vtRmhOTkavZ9IQkcJ/zuVfmqK80/Mds+njJMudUPzuREuSFGWACczo17EDA==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/postinstall/-/postinstall-7.6.6.tgz", + "integrity": "sha512-jamn7QNTJPZiu22nu25LqfSTJohugFhCu4b48yqP+pdMdkQ3qVd3NdDYhBlgkH/Btar+kppiJP1gRtoiJF761w==", "dev": true, "funding": { "type": "opencollective", @@ -6411,9 +6411,9 @@ } }, "node_modules/@storybook/preview": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/preview/-/preview-7.6.5.tgz", - "integrity": "sha512-zmLa7C7yFGTYhgGZXoecdww9rx0Z5HpNi/GDBRWoNSK+FEdE8Jj2jF5NJ2ncldtYIyegz9ku29JFMKbhMj9K5Q==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/preview/-/preview-7.6.6.tgz", + "integrity": "sha512-Rl+Pom2bNwzc0MdlbFALmvxsbCkbIwlpTZlRZZTh5Ah8JViV9htQgP9e8uwo3NZA2BhjbDLkmnZeloWxQnI5Ig==", "dev": true, "funding": { "type": "opencollective", @@ -6507,9 +6507,9 @@ } }, "node_modules/@storybook/react-dom-shim": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-7.6.5.tgz", - "integrity": "sha512-Qp3N3zENdvx20ikHmz5yI03z+mAWF8bUAwUofqXarVtZUkBNtvfTfUwgAezOAF0eClClH+ktIziIKd976tLSPw==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-7.6.6.tgz", + "integrity": "sha512-WWNlXtCVoBWXX/kLNulUeMgzmlAEHi2aBrdIv2jz0DScPf0YxeWAkWmgK7F0zMot9mdwYncr+pk1AILbTBJSyg==", "dev": true, "funding": { "type": "opencollective", @@ -6521,12 +6521,12 @@ } }, "node_modules/@storybook/router": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/router/-/router-7.6.5.tgz", - "integrity": "sha512-QiTC86gRuoepzzmS6HNJZTwfz/n27NcqtaVEIxJi1Yvsx2/kLa9NkRhylNkfTuZ1gEry9stAlKWanMsB2aKyjQ==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/router/-/router-7.6.6.tgz", + "integrity": "sha512-dkn81MtxrG7JMDbOHEcVZkTDVKsneg72CyqJ8ELZfC81iKQcDMQkV9mdmnMl45aKn6UrscudI4K23OxQmsevkw==", "dev": true, "dependencies": { - "@storybook/client-logger": "7.6.5", + "@storybook/client-logger": "7.6.6", "memoizerific": "^1.11.3", "qs": "^6.10.0" }, @@ -6536,14 +6536,14 @@ } }, "node_modules/@storybook/telemetry": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/telemetry/-/telemetry-7.6.5.tgz", - "integrity": "sha512-FiLRh9k9LoGphqgBqPYySWdGqplihiZyDwqdo+Qs19RcQ/eiKg0W7fdA09nStcdcsHmDl/1cMfRhz9KUiMtwOw==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/telemetry/-/telemetry-7.6.6.tgz", + "integrity": "sha512-2WdDcrMrt1bPVgdMVO0tFmVxT6YIjiPRfKbH/7wwYMOGmV75m4mJ9Ha2gzZc/oXTSK1M4/fiK12IgW+S3ErcMg==", "dev": true, "dependencies": { - "@storybook/client-logger": "7.6.5", - "@storybook/core-common": "7.6.5", - "@storybook/csf-tools": "7.6.5", + "@storybook/client-logger": "7.6.6", + "@storybook/core-common": "7.6.6", + "@storybook/csf-tools": "7.6.6", "chalk": "^4.1.0", "detect-package-manager": "^2.0.1", "fetch-retry": "^5.0.2", @@ -6622,13 +6622,13 @@ } }, "node_modules/@storybook/theming": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-7.6.5.tgz", - "integrity": "sha512-RpcWT0YEgiobO41McVPDfQQHHFnjyr1sJnNTPJIvOUgSfURdgSj17mQVxtD5xcXcPWUdle5UhIOrCixHbL/NNw==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-7.6.6.tgz", + "integrity": "sha512-hNZOOxaF55iAGUEM0dvAIP6LfGMgPKCJQIk/qyotFk+SKkg3PBqzph89XfFl9yCD3KiX5cryqarULgVuNawLJg==", "dev": true, "dependencies": { "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", - "@storybook/client-logger": "7.6.5", + "@storybook/client-logger": "7.6.6", "@storybook/global": "^5.0.0", "memoizerific": "^1.11.3" }, @@ -6642,12 +6642,12 @@ } }, "node_modules/@storybook/types": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/types/-/types-7.6.5.tgz", - "integrity": "sha512-Q757v+fYZZSaEpks/zDL5YgXRozxkgKakXFc+BoQHK5q5sVhJ+0jvpLJiAQAniIIaMIkqY/G24Kd6Uo6UdKBCg==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/types/-/types-7.6.6.tgz", + "integrity": "sha512-77vbQp3GX93OD8UzFkY4a0fAmkZrqLe61XVo6yABrwbVDY0EcAwaCF5gcXRhOHldlH7KYbLfEQkDkkKTBjX7ow==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.5", + "@storybook/channels": "7.6.6", "@types/babel__core": "^7.0.0", "@types/express": "^4.7.0", "file-system-cache": "2.3.0" @@ -6658,18 +6658,18 @@ } }, "node_modules/@storybook/web-components": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/web-components/-/web-components-7.6.5.tgz", - "integrity": "sha512-uBL1d/qSwvbmkV/JGBdLySdmyOnZKBK+hn7+lgfQfTPV7JjOmTzuifnnSrhKlI/wupdBM/LYjlax5kGYt3oBXQ==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/web-components/-/web-components-7.6.6.tgz", + "integrity": "sha512-oBfZBM1Vkzs/rZySk/HXCIRZ10FSYx6wgyMbiT5EmGm7Jz9y5qaqQhG/sPYKsYL0TlPRRKjf1iukHkxD6DWmpA==", "dev": true, "dependencies": { - "@storybook/client-logger": "7.6.5", - "@storybook/core-client": "7.6.5", - "@storybook/docs-tools": "7.6.5", + "@storybook/client-logger": "7.6.6", + "@storybook/core-client": "7.6.6", + "@storybook/docs-tools": "7.6.6", "@storybook/global": "^5.0.0", - "@storybook/manager-api": "7.6.5", - "@storybook/preview-api": "7.6.5", - "@storybook/types": "7.6.5", + "@storybook/manager-api": "7.6.6", + "@storybook/preview-api": "7.6.6", + "@storybook/types": "7.6.6", "tiny-invariant": "^1.3.1", "ts-dedent": "^2.0.0" }, @@ -6685,15 +6685,15 @@ } }, "node_modules/@storybook/web-components-vite": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/web-components-vite/-/web-components-vite-7.6.5.tgz", - "integrity": "sha512-j4lfrgPjlqAeoUdfXWMESUAxrOn+YUJekGh3saxsHxXIiYnzJBdkiJju4Hzqav4j8645bJzlZBw51e6wJJsuFw==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/web-components-vite/-/web-components-vite-7.6.6.tgz", + "integrity": "sha512-AOxvnA7eIRnKqZ21QgUHJ/ENX1MMhJCKPiytvkX8U02gs+0HE+NnZPbhZLPh/Ruax7KfLPUGItv3BcfrIxV5lw==", "dev": true, "dependencies": { - "@storybook/builder-vite": "7.6.5", - "@storybook/core-server": "7.6.5", - "@storybook/node-logger": "7.6.5", - "@storybook/web-components": "7.6.5", + "@storybook/builder-vite": "7.6.6", + "@storybook/core-server": "7.6.6", + "@storybook/node-logger": "7.6.6", + "@storybook/web-components": "7.6.6", "magic-string": "^0.30.0" }, "engines": { @@ -6705,17 +6705,17 @@ } }, "node_modules/@storybook/web-components/node_modules/@storybook/preview-api": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.5.tgz", - "integrity": "sha512-9XzuDXXgNuA6dDZ3DXsUwEG6ElxeTbzLuYuzcjtS1FusSICZ2iYmxfS0GfSud9MjPPYOJYoSOvMdIHjorjgByA==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.6.tgz", + "integrity": "sha512-Bt6xIAR5yZ/JWc90X4BbLOA97iL65glZ1SOBgFFv2mHrdZ1lcdKhAlQr2aeJAf1mLvBtalPjvKzi9EuVY3FZ4w==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.5", - "@storybook/client-logger": "7.6.5", - "@storybook/core-events": "7.6.5", + "@storybook/channels": "7.6.6", + "@storybook/client-logger": "7.6.6", + "@storybook/core-events": "7.6.6", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/types": "7.6.5", + "@storybook/types": "7.6.6", "@types/qs": "^6.9.5", "dequal": "^2.0.2", "lodash": "^4.17.21", @@ -11436,9 +11436,9 @@ "dev": true }, "node_modules/flow-parser": { - "version": "0.224.0", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.224.0.tgz", - "integrity": "sha512-S1P78o0VLB1FZvkoGSIpaRiiTUQ3xDhm9I4Z1qc3lglmkjehfR2sjM0vhwKS7UC1G12VT4Leb/GGV/KlactqjA==", + "version": "0.225.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.225.0.tgz", + "integrity": "sha512-wTr10/1z9wBuaNf+RGdGwD5FOI6TsNcWrMDhE+JBc2vEKe1e4SZuO5zVZCBq9SrFqPyWy0wFO9+hTH4zuPDbMA==", "dev": true, "engines": { "node": ">=0.4.0" @@ -16952,12 +16952,12 @@ "dev": true }, "node_modules/storybook": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/storybook/-/storybook-7.6.5.tgz", - "integrity": "sha512-uHPrL+g/0v6iIVtDA8J0uWd3jDZcdr51lCR/vPXTkrCY1uVaFjswzl8EMy5PR05I7jMpKUzkJWZtFbgbh9e1Bw==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-7.6.6.tgz", + "integrity": "sha512-PmJxpjGdLvDOHaRzqLOvcJ3ALQPaNeW6D5Lv7rPPVbuO24wdDzd/75dPRP7gJKYcGE0NnDZ6cLQq3UlCfbkIBA==", "dev": true, "dependencies": { - "@storybook/cli": "7.6.5" + "@storybook/cli": "7.6.6" }, "bin": { "sb": "index.js", diff --git a/web/package.json b/web/package.json index 786580462..e753c5e3f 100644 --- a/web/package.json +++ b/web/package.json @@ -86,13 +86,13 @@ "@rollup/plugin-replace": "^5.0.5", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.5", - "@storybook/addon-essentials": "^7.6.5", - "@storybook/addon-links": "^7.6.5", - "@storybook/api": "^7.6.5", + "@storybook/addon-essentials": "^7.6.6", + "@storybook/addon-links": "^7.6.6", + "@storybook/api": "^7.6.6", "@storybook/blocks": "^7.6.4", - "@storybook/manager-api": "^7.6.5", - "@storybook/web-components": "^7.6.5", - "@storybook/web-components-vite": "^7.6.5", + "@storybook/manager-api": "^7.6.6", + "@storybook/web-components": "^7.6.6", + "@storybook/web-components-vite": "^7.6.6", "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@types/chart.js": "^2.9.41", "@types/codemirror": "5.60.15", @@ -120,7 +120,7 @@ "rollup-plugin-cssimport": "^1.0.3", "rollup-plugin-modify": "^3.0.0", "rollup-plugin-postcss-lit": "^2.1.0", - "storybook": "^7.6.5", + "storybook": "^7.6.6", "storybook-addon-mock": "^4.3.0", "ts-lit-plugin": "^2.0.1", "tslib": "^2.6.2", From 3afb1a2f2118c06a2e847a0e979ada3425a33864 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Dec 2023 11:30:20 +0100 Subject: [PATCH 06/21] web: bump the sentry group in /web with 2 updates (#7944) Bumps the sentry group in /web with 2 updates: [@sentry/browser](https://github.com/getsentry/sentry-javascript) and [@sentry/tracing](https://github.com/getsentry/sentry-javascript). Updates `@sentry/browser` from 7.88.0 to 7.89.0 - [Release notes](https://github.com/getsentry/sentry-javascript/releases) - [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-javascript/compare/7.88.0...7.89.0) Updates `@sentry/tracing` from 7.88.0 to 7.89.0 - [Release notes](https://github.com/getsentry/sentry-javascript/releases) - [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-javascript/compare/7.88.0...7.89.0) --- updated-dependencies: - dependency-name: "@sentry/browser" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: sentry - dependency-name: "@sentry/tracing" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: sentry ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 92 +++++++++++++++++++++---------------------- web/package.json | 4 +- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index da13d73b3..aa192cfd1 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.88.0", - "@sentry/tracing": "^7.88.0", + "@sentry/browser": "^7.89.0", + "@sentry/tracing": "^7.89.0", "@webcomponents/webcomponentsjs": "^2.8.0", "base64-js": "^1.5.1", "chart.js": "^4.4.1", @@ -4752,98 +4752,98 @@ ] }, "node_modules/@sentry-internal/feedback": { - "version": "7.88.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.88.0.tgz", - "integrity": "sha512-lbK6jgO1I0M96nZQ99mcLSZ55ebwPAP6LhEWhkmc+eAfy97VpiY+qsbmgsmOzCEPqMmEUCEcI0rEZ7fiye2v2Q==", + "version": "7.89.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.89.0.tgz", + "integrity": "sha512-Uz1A/ex3X/cvHjS3C9qH8ENa1Le7Jesxl3Umuv3n1e/rvoPxo2VFNCgDrpsM1mcg2XwiPkmpyMAVxDMgB0A7JQ==", "dependencies": { - "@sentry/core": "7.88.0", - "@sentry/types": "7.88.0", - "@sentry/utils": "7.88.0" + "@sentry/core": "7.89.0", + "@sentry/types": "7.89.0", + "@sentry/utils": "7.89.0" }, "engines": { "node": ">=12" } }, "node_modules/@sentry-internal/tracing": { - "version": "7.88.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.88.0.tgz", - "integrity": "sha512-xXQdcYhsS+ourzJHjXNjZC9zakuc97udmpgaXRjEP7FjPYclIx+YXwgFBdHM2kzAwZLFOsEce5dr46GVXUDfZw==", + "version": "7.89.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.89.0.tgz", + "integrity": "sha512-cSwno2NYteBBqOvcm/ue9cJxGGl2uffG4laEyLR9y4we+bYxigfx/Ki2TFOtwXrv5o59eRAtN1lpzaAf43yfBw==", "dependencies": { - "@sentry/core": "7.88.0", - "@sentry/types": "7.88.0", - "@sentry/utils": "7.88.0" + "@sentry/core": "7.89.0", + "@sentry/types": "7.89.0", + "@sentry/utils": "7.89.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/browser": { - "version": "7.88.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.88.0.tgz", - "integrity": "sha512-il4x3PB99nuU/OJQw2RltgYYbo8vtnYoIgneOeEiw4m0ppK1nKkMkd3vDRipGL6E/0i7IUmQfYYy6U10J5Rx+g==", + "version": "7.89.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.89.0.tgz", + "integrity": "sha512-84hZOymrKyfjQnbD6d/PhlHCsQHjUGCqVU/K6e7g+JiB1DNZOsfZTkLj6Xj8OQzvwKHWzB9egmJN6IA7dUSJXQ==", "dependencies": { - "@sentry-internal/feedback": "7.88.0", - "@sentry-internal/tracing": "7.88.0", - "@sentry/core": "7.88.0", - "@sentry/replay": "7.88.0", - "@sentry/types": "7.88.0", - "@sentry/utils": "7.88.0" + "@sentry-internal/feedback": "7.89.0", + "@sentry-internal/tracing": "7.89.0", + "@sentry/core": "7.89.0", + "@sentry/replay": "7.89.0", + "@sentry/types": "7.89.0", + "@sentry/utils": "7.89.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/core": { - "version": "7.88.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.88.0.tgz", - "integrity": "sha512-Jzbb7dcwiCO7kI0a1w+32UzWxbEn2OcZWzp55QMEeAh6nZ/5CXhXwpuHi0tW7doPj+cJdmxMTMu9LqMVfdGkzQ==", + "version": "7.89.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.89.0.tgz", + "integrity": "sha512-aU3wfZ+tyFi4T06fOH3z5xnTyMzwvzyEohYOmnQnDrqNgvDzjWkyeUzWse9FaFiut8lBN9O+Pd2H0ucPBMPEhQ==", "dependencies": { - "@sentry/types": "7.88.0", - "@sentry/utils": "7.88.0" + "@sentry/types": "7.89.0", + "@sentry/utils": "7.89.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/replay": { - "version": "7.88.0", - "resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.88.0.tgz", - "integrity": "sha512-em5dPKLPG7c/HGDbpIj3aHrWbA4iMwqjevqTzn+++KNO1YslkOosCaGsb1whU3AL1T9c3aIFIhZ4u3rNo+DxcA==", + "version": "7.89.0", + "resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.89.0.tgz", + "integrity": "sha512-iD1E1SbW8Ca34Fn0slM9E0Kh0DjhkZGerPFKqbwjXR7QKCx+ljMRKaCQhb4bBKfVNYZORxpwY4PLJLQ+k6WHJg==", "dependencies": { - "@sentry-internal/tracing": "7.88.0", - "@sentry/core": "7.88.0", - "@sentry/types": "7.88.0", - "@sentry/utils": "7.88.0" + "@sentry-internal/tracing": "7.89.0", + "@sentry/core": "7.89.0", + "@sentry/types": "7.89.0", + "@sentry/utils": "7.89.0" }, "engines": { "node": ">=12" } }, "node_modules/@sentry/tracing": { - "version": "7.88.0", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.88.0.tgz", - "integrity": "sha512-Lj4hhLraalN4w3swXkP2do1hcaQVOuLvO6eJJbcwf10b+P4CcdlwAnqvxOOCNxA5VzG4/K2BqQ8LRU4S0Ulj9A==", + "version": "7.89.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.89.0.tgz", + "integrity": "sha512-POYZ1+YxG0G3JizoPmForqo3kPILYhmHIqypsSz7RT+OKsKVmGt/GuspydJM1xhbPYrFyMxzt6HMMss4JN1Uew==", "dependencies": { - "@sentry-internal/tracing": "7.88.0" + "@sentry-internal/tracing": "7.89.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/types": { - "version": "7.88.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.88.0.tgz", - "integrity": "sha512-FvwvmX1pWAZKicPj4EpKyho8Wm+C4+r5LiepbbBF8oKwSPJdD2QV1fo/LWxsrzNxWOllFIVIXF5Ed3nPYQWpTw==", + "version": "7.89.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.89.0.tgz", + "integrity": "sha512-5Rqt6vIP652p01ypUaEIrELjsHF0vUnzj/JFz+i7nXv6w77GPpNzeIlMYdnauBIgJhLUvYCTQaOPV9GhgZhc4g==", "engines": { "node": ">=8" } }, "node_modules/@sentry/utils": { - "version": "7.88.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.88.0.tgz", - "integrity": "sha512-ukminfRmdBXTzk49orwJf3Lu3hR60ZRHjE2a4IXwYhyDT6JJgJqgsq1hzGXx0AyFfyS4WhfZ6QUBy7fu3BScZQ==", + "version": "7.89.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.89.0.tgz", + "integrity": "sha512-t6qDQajdAjZ6LPraAWO00ZjvDbNH82DoVGV/2o4C5MBPCutJGTGyWIpI2tliYPZPPx+3C2m5L757zh1dCzrgUg==", "dependencies": { - "@sentry/types": "7.88.0" + "@sentry/types": "7.89.0" }, "engines": { "node": ">=8" diff --git a/web/package.json b/web/package.json index e753c5e3f..ffa7d0970 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.88.0", - "@sentry/tracing": "^7.88.0", + "@sentry/browser": "^7.89.0", + "@sentry/tracing": "^7.89.0", "@webcomponents/webcomponentsjs": "^2.8.0", "base64-js": "^1.5.1", "chart.js": "^4.4.1", From 90d88deb814b7d30bd48df4a2659c02877bee94a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Dec 2023 11:30:39 +0100 Subject: [PATCH 07/21] core: bump github.com/redis/go-redis/v9 from 9.3.0 to 9.3.1 (#7942) Bumps [github.com/redis/go-redis/v9](https://github.com/redis/go-redis) from 9.3.0 to 9.3.1. - [Release notes](https://github.com/redis/go-redis/releases) - [Changelog](https://github.com/redis/go-redis/blob/master/CHANGELOG.md) - [Commits](https://github.com/redis/go-redis/compare/v9.3.0...v9.3.1) --- updated-dependencies: - dependency-name: github.com/redis/go-redis/v9 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 33bc7c364..34dad030d 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ 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.17.0 - github.com/redis/go-redis/v9 v9.3.0 + github.com/redis/go-redis/v9 v9.3.1 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 diff --git a/go.sum b/go.sum index d26320a4a..1b4aff0a5 100644 --- a/go.sum +++ b/go.sum @@ -256,8 +256,8 @@ github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdO github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= -github.com/redis/go-redis/v9 v9.3.0 h1:RiVDjmig62jIWp7Kk4XVLs0hzV6pI3PyTnnL0cnn0u0= -github.com/redis/go-redis/v9 v9.3.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +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/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= From 6628088e3b482d615e80d69dfd2613abca8da543 Mon Sep 17 00:00:00 2001 From: Jens L Date: Wed, 20 Dec 2023 12:38:31 +0100 Subject: [PATCH 08/21] website: fix hosted API browser (#7946) Signed-off-by: Jens Langhammer --- website/developer-docs/api/browser.mdx | 39 +++----------------- website/src/components/APIBrowser/index.tsx | 40 +++++++++++++++++++++ website/src/pages/api/index.jsx | 2 +- website/src/pages/api/v3.jsx | 2 +- website/src/pages/index.jsx | 2 +- website/src/pages/terraform-provider.jsx | 2 +- 6 files changed, 49 insertions(+), 38 deletions(-) create mode 100644 website/src/components/APIBrowser/index.tsx diff --git a/website/developer-docs/api/browser.mdx b/website/developer-docs/api/browser.mdx index 7aa35b209..4ea697cfe 100644 --- a/website/developer-docs/api/browser.mdx +++ b/website/developer-docs/api/browser.mdx @@ -1,38 +1,9 @@ +--- +hide_table_of_contents: true +--- + # API Browser -import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; -import useBaseUrl from "@docusaurus/useBaseUrl"; -import BrowserOnly from "@docusaurus/core/lib/client/exports/BrowserOnly"; -import { useColorMode } from "@docusaurus/theme-common"; - -export function APIBrowser() { - const context = useDocusaurusContext(); - const { siteConfig = {} } = context; - const { colorMode, setColorMode } = useColorMode(); - let bg = "#1b1b1d"; - if (colorMode === "light") { - bg = "#fff"; - } - return ( - - {() => { - import("rapidoc"); - return ( - - ); - }} - - ); -} +import APIBrowser from "../../src/components/APIBrowser"; diff --git a/website/src/components/APIBrowser/index.tsx b/website/src/components/APIBrowser/index.tsx new file mode 100644 index 000000000..25c43b743 --- /dev/null +++ b/website/src/components/APIBrowser/index.tsx @@ -0,0 +1,40 @@ +import React from "react"; +import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; +import useBaseUrl from "@docusaurus/useBaseUrl"; +import BrowserOnly from "@docusaurus/BrowserOnly"; +import { useColorMode } from "@docusaurus/theme-common"; + +export function APIBrowser() { + const context = useDocusaurusContext(); + const { siteConfig = {} } = context; + const { colorMode, setColorMode } = useColorMode(); + let bg = "#1b1b1d"; + if (colorMode === "light") { + bg = "#fff"; + } + return ( + + {() => { + require("rapidoc"); + return ( + + ); + }} + + ); +} + +export default APIBrowser; diff --git a/website/src/pages/api/index.jsx b/website/src/pages/api/index.jsx index 8e6647dc0..5ba633bdb 100644 --- a/website/src/pages/api/index.jsx +++ b/website/src/pages/api/index.jsx @@ -1,7 +1,7 @@ import React from "react"; import Layout from "@theme/Layout"; import Head from "@docusaurus/Head"; -import BrowserOnly from "@docusaurus/core/lib/client/exports/BrowserOnly"; +import BrowserOnly from "@docusaurus/BrowserOnly"; function APIPage() { return ( diff --git a/website/src/pages/api/v3.jsx b/website/src/pages/api/v3.jsx index 7cdd45289..8ea704650 100644 --- a/website/src/pages/api/v3.jsx +++ b/website/src/pages/api/v3.jsx @@ -1,7 +1,7 @@ import React from "react"; import Layout from "@theme/Layout"; import Head from "@docusaurus/Head"; -import BrowserOnly from "@docusaurus/core/lib/client/exports/BrowserOnly"; +import BrowserOnly from "@docusaurus/BrowserOnly"; function APIPage() { return ( diff --git a/website/src/pages/index.jsx b/website/src/pages/index.jsx index feea2b292..fcbf951fd 100644 --- a/website/src/pages/index.jsx +++ b/website/src/pages/index.jsx @@ -3,7 +3,7 @@ import clsx from "clsx"; import Layout from "@theme/Layout"; import Link from "@docusaurus/Link"; import Head from "@docusaurus/Head"; -import BrowserOnly from "@docusaurus/core/lib/client/exports/BrowserOnly"; +import BrowserOnly from "@docusaurus/BrowserOnly"; import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; import useBaseUrl from "@docusaurus/useBaseUrl"; import styles from "./styles.module.css"; diff --git a/website/src/pages/terraform-provider.jsx b/website/src/pages/terraform-provider.jsx index 47bfa52f1..e930a8a56 100644 --- a/website/src/pages/terraform-provider.jsx +++ b/website/src/pages/terraform-provider.jsx @@ -1,7 +1,7 @@ import React from "react"; import Layout from "@theme/Layout"; import Head from "@docusaurus/Head"; -import BrowserOnly from "@docusaurus/core/lib/client/exports/BrowserOnly"; +import BrowserOnly from "@docusaurus/BrowserOnly"; function TerraformProviderPage() { return ( From 256187ebc684e97a0c0e7b7c9ff6740126f134ed Mon Sep 17 00:00:00 2001 From: Rukk385 <39340512+Rukk385@users.noreply.github.com> Date: Wed, 20 Dec 2023 15:33:58 +0100 Subject: [PATCH 09/21] website/docs: add expression example for geoip (#7739) * Update expression.mdx Added example for GeoIP Signed-off-by: Rukk385 <39340512+Rukk385@users.noreply.github.com> * Update website/docs/policies/expression.mdx Co-authored-by: Marc 'risson' Schmitt Signed-off-by: Rukk385 <39340512+Rukk385@users.noreply.github.com> --------- Signed-off-by: Rukk385 <39340512+Rukk385@users.noreply.github.com> Co-authored-by: Marc 'risson' Schmitt --- website/docs/policies/expression.mdx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/website/docs/policies/expression.mdx b/website/docs/policies/expression.mdx index 2200cc96f..aaf850608 100644 --- a/website/docs/policies/expression.mdx +++ b/website/docs/policies/expression.mdx @@ -54,6 +54,11 @@ import Objects from "../expressions/_objects.md"; - `request.context`: A dictionary with dynamic data. This depends on the origin of the execution. - `geoip`: GeoIP object, see [GeoIP](https://geoip2.readthedocs.io/en/latest/#geoip2.models.City) + + ```python + return context["geoip"].country.iso_code == "US" + ``` + - `ak_is_sso_flow`: Boolean which is true if request was initiated by authenticating through an external provider. - `ak_client_ip`: Client's IP Address or 255.255.255.255 if no IP Address could be extracted. Can be [compared](#comparing-ip-addresses), for example From 4ff3915d5959aba3b99ad6418ebaa60d825d8028 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Wed, 20 Dec 2023 17:20:56 +0000 Subject: [PATCH 10/21] translate: Updates for file web/xliff/en.xlf in fr (#7951) Translate web/xliff/en.xlf in fr 100% translated source file: 'web/xliff/en.xlf' on 'fr'. Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- web/xliff/fr.xlf | 67 ++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/web/xliff/fr.xlf b/web/xliff/fr.xlf index b6451ddd5..6a1a04d0e 100644 --- a/web/xliff/fr.xlf +++ b/web/xliff/fr.xlf @@ -1,4 +1,4 @@ - + @@ -613,9 +613,9 @@ Il y a jour(s) - The URL "" was not found. - L'URL " - " n'a pas été trouvée. + The URL "" was not found. + L'URL " + " n'a pas été trouvée. @@ -1057,8 +1057,8 @@ Il y a jour(s) - To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. - Pour permettre n'importe quelle URI de redirection, définissez cette valeur sur ".*". Soyez conscient des possibles implications de sécurité que cela peut avoir. + To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. + Pour permettre n'importe quelle URI de redirection, définissez cette valeur sur ".*". Soyez conscient des possibles implications de sécurité que cela peut avoir. @@ -1630,7 +1630,7 @@ Il y a jour(s) Token to authenticate with. Currently only bearer authentication is supported. - Jeton d'authentification à utiliser. Actuellement, seule l'authentification "bearer authentication" est prise en charge. + Jeton d'authentification à utiliser. Actuellement, seule l'authentification "bearer authentication" est prise en charge. @@ -1798,8 +1798,8 @@ Il y a jour(s) - Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". - Entrez une URL complète, un chemin relatif ou utilisez 'fa://fa-test' pour utiliser l'icône Font Awesome "fa-test". + Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". + Entrez une URL complète, un chemin relatif ou utilisez 'fa://fa-test' pour utiliser l'icône Font Awesome "fa-test". @@ -2897,7 +2897,7 @@ doesn't pass when either or both of the selected options are equal or above the To use SSL instead, use 'ldaps://' and disable this option. - Pour utiliser SSL à la base, utilisez "ldaps://" et désactviez cette option. + Pour utiliser SSL à la base, utilisez "ldaps://" et désactviez cette option. @@ -2986,8 +2986,8 @@ doesn't pass when either or both of the selected options are equal or above the - Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' - Champ qui contient les membres d'un groupe. Si vous utilisez le champ "memberUid", la valeur est censée contenir un nom distinctif relatif, par exemple 'memberUid=un-utilisateur' au lieu de 'memberUid=cn=un-utilisateur,ou=groups,...' + Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' + Champ qui contient les membres d'un groupe. Si vous utilisez le champ "memberUid", la valeur est censée contenir un nom distinctif relatif, par exemple 'memberUid=un-utilisateur' au lieu de 'memberUid=cn=un-utilisateur,ou=groups,...' @@ -3282,7 +3282,7 @@ doesn't pass when either or both of the selected options are equal or above the Time offset when temporary users should be deleted. This only applies if your IDP uses the NameID Format 'transient', and the user doesn't log out manually. - Moment où les utilisateurs temporaires doivent être supprimés. Cela ne s'applique que si votre IDP utilise le format NameID "transient" et que l'utilisateur ne se déconnecte pas manuellement. + Moment où les utilisateurs temporaires doivent être supprimés. Cela ne s'applique que si votre IDP utilise le format NameID "transient" et que l'utilisateur ne se déconnecte pas manuellement. @@ -3450,7 +3450,7 @@ doesn't pass when either or both of the selected options are equal or above the Optionally set the 'FriendlyName' value of the Assertion attribute. - Indiquer la valeur "FriendlyName" de l'attribut d'assertion (optionnel) + Indiquer la valeur "FriendlyName" de l'attribut d'assertion (optionnel) @@ -3779,8 +3779,8 @@ doesn't pass when either or both of the selected options are equal or above the - When using an external logging solution for archiving, this can be set to "minutes=5". - En cas d'utilisation d'une solution de journalisation externe pour l'archivage, cette valeur peut être fixée à "minutes=5". + When using an external logging solution for archiving, this can be set to "minutes=5". + En cas d'utilisation d'une solution de journalisation externe pour l'archivage, cette valeur peut être fixée à "minutes=5". @@ -3789,8 +3789,8 @@ doesn't pass when either or both of the selected options are equal or above the - Format: "weeks=3;days=2;hours=3,seconds=2". - Format : "weeks=3;days=2;hours=3,seconds=2". + Format: "weeks=3;days=2;hours=3,seconds=2". + Format : "weeks=3;days=2;hours=3,seconds=2". @@ -3986,10 +3986,10 @@ doesn't pass when either or both of the selected options are equal or above the - Are you sure you want to update ""? + Are you sure you want to update ""? Êtes-vous sûr de vouloir mettre à jour - " - " ? + " + " ? @@ -5075,8 +5075,8 @@ doesn't pass when either or both of the selected options are equal or above the - A "roaming" authenticator, like a YubiKey - Un authentificateur "itinérant", comme une YubiKey + A "roaming" authenticator, like a YubiKey + Un authentificateur "itinérant", comme une YubiKey @@ -5401,7 +5401,7 @@ doesn't pass when either or both of the selected options are equal or above the Show arbitrary input fields to the user, for example during enrollment. Data is saved in the flow context under the 'prompt_data' variable. - Afficher des champs de saisie arbitraires à l'utilisateur, par exemple pendant l'inscription. Les données sont enregistrées dans le contexte du flux sous la variable "prompt_data". + Afficher des champs de saisie arbitraires à l'utilisateur, par exemple pendant l'inscription. Les données sont enregistrées dans le contexte du flux sous la variable "prompt_data". @@ -5410,10 +5410,10 @@ doesn't pass when either or both of the selected options are equal or above the - ("", of type ) + ("", of type ) - (" - ", de type + (" + ", de type ) @@ -5462,8 +5462,8 @@ doesn't pass when either or both of the selected options are equal or above the - If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. - Si défini à une durée supérieure à 0, l'utilisateur aura la possibilité de choisir de "rester connecté", ce qui prolongera sa session jusqu'à la durée spécifiée ici. + If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. + Si défini à une durée supérieure à 0, l'utilisateur aura la possibilité de choisir de "rester connecté", ce qui prolongera sa session jusqu'à la durée spécifiée ici. @@ -6247,7 +6247,7 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti Can be in the format of 'unix://' when connecting to a local docker daemon, using 'ssh://' to connect via SSH, or 'https://:2376' when connecting to a remote system. - Peut être au format "unix://" pour une connexion à un service docker local, "ssh://" pour une connexion via SSH, ou "https://:2376" pour une connexion à un système distant. + Peut être au format "unix://" pour une connexion à un service docker local, "ssh://" pour une connexion via SSH, ou "https://:2376" pour une connexion à un système distant. @@ -7554,7 +7554,7 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you). - Utilisez ce fournisseur avec l'option "auth_request" de Nginx ou "forwardAuth" de Traefik. Chaque application/domaine a besoin de son propre fournisseur. De plus, sur chaque domaine, "/outpost.goauthentik.io" doit être routé vers le poste avancé (lorsque vous utilisez un poste avancé géré, cela est fait pour vous). + Utilisez ce fournisseur avec l'option "auth_request" de Nginx ou "forwardAuth" de Traefik. Chaque application/domaine a besoin de son propre fournisseur. De plus, sur chaque domaine, "/outpost.goauthentik.io" doit être routé vers le poste avancé (lorsque vous utilisez un poste avancé géré, cela est fait pour vous). Default relay state @@ -7968,7 +7968,7 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti Utilisateur créé et ajouté au groupe avec succès - This user will be added to the group "". + This user will be added to the group "". Cet utilisateur sera ajouté au groupe &quot;&quot;. @@ -8045,7 +8045,8 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti Require Outpost (flow can only be executed from an outpost). + Forcer l'utilisation d'un avant-poste (le flux ne pourrait être exécuter que depuis un outpost). - + \ No newline at end of file From 50860d7ffe44a29cabe7407c2bf94facd689b5ca Mon Sep 17 00:00:00 2001 From: Jens L Date: Wed, 20 Dec 2023 22:16:50 +0100 Subject: [PATCH 11/21] events: add ASN Database reader (#7793) * events: add ASN Database reader Signed-off-by: Jens Langhammer * add tests Signed-off-by: Jens Langhammer * fix test config generator Signed-off-by: Jens Langhammer * de-duplicate code Signed-off-by: Jens Langhammer * add enrich_context Signed-off-by: Jens Langhammer * rename to context processors? Signed-off-by: Jens Langhammer * fix cache Signed-off-by: Jens Langhammer * use config deprecation system, update docs Signed-off-by: Jens Langhammer * update more docs and tests Signed-off-by: Jens Langhammer * add test asn db Signed-off-by: Jens Langhammer * re-build schema with latest versions Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer --- Dockerfile | 2 +- authentik/api/v3/config.py | 8 +- authentik/core/api/authenticated_sessions.py | 13 ++- .../events/context_processors/__init__.py | 0 authentik/events/context_processors/asn.py | 79 ++++++++++++++ authentik/events/context_processors/base.py | 43 ++++++++ authentik/events/context_processors/geoip.py | 84 +++++++++++++++ authentik/events/context_processors/mmdb.py | 54 ++++++++++ authentik/events/geo.py | 100 ------------------ authentik/events/models.py | 14 +-- authentik/events/tests/test_enrich_asn.py | 24 +++++ .../{test_geoip.py => test_enrich_geoip.py} | 4 +- authentik/events/utils.py | 9 +- authentik/lib/config.py | 1 + authentik/lib/default.yml | 5 +- authentik/policies/reputation/api.py | 1 + .../migrations/0006_reputation_ip_asn_data.py | 17 +++ authentik/policies/reputation/models.py | 1 + authentik/policies/reputation/tasks.py | 6 +- authentik/policies/types.py | 12 +-- authentik/root/test_runner.py | 3 +- blueprints/schema.json | 5 + schema.yml | 24 ++++- scripts/generate_config.py | 7 +- tests/GeoLite2-ASN-Test.mmdb | Bin 0 -> 12653 bytes website/docs/core/geoip.mdx | 12 ++- website/docs/installation/configuration.mdx | 8 +- 27 files changed, 393 insertions(+), 143 deletions(-) create mode 100644 authentik/events/context_processors/__init__.py create mode 100644 authentik/events/context_processors/asn.py create mode 100644 authentik/events/context_processors/base.py create mode 100644 authentik/events/context_processors/geoip.py create mode 100644 authentik/events/context_processors/mmdb.py delete mode 100644 authentik/events/geo.py create mode 100644 authentik/events/tests/test_enrich_asn.py rename authentik/events/tests/{test_geoip.py => test_enrich_geoip.py} (83%) create mode 100644 authentik/policies/reputation/migrations/0006_reputation_ip_asn_data.py create mode 100644 tests/GeoLite2-ASN-Test.mmdb diff --git a/Dockerfile b/Dockerfile index 629d3258b..114be6253 100644 --- a/Dockerfile +++ b/Dockerfile @@ -71,7 +71,7 @@ RUN --mount=type=cache,sharing=locked,target=/go/pkg/mod \ # Stage 4: MaxMind GeoIP FROM --platform=${BUILDPLATFORM} ghcr.io/maxmind/geoipupdate:v6.0 as geoip -ENV GEOIPUPDATE_EDITION_IDS="GeoLite2-City" +ENV GEOIPUPDATE_EDITION_IDS="GeoLite2-City GeoLite2-ASN" ENV GEOIPUPDATE_VERBOSE="true" ENV GEOIPUPDATE_ACCOUNT_ID_FILE="/run/secrets/GEOIPUPDATE_ACCOUNT_ID" ENV GEOIPUPDATE_LICENSE_KEY_FILE="/run/secrets/GEOIPUPDATE_LICENSE_KEY" diff --git a/authentik/api/v3/config.py b/authentik/api/v3/config.py index 0defd1a5b..93b783629 100644 --- a/authentik/api/v3/config.py +++ b/authentik/api/v3/config.py @@ -19,7 +19,7 @@ from rest_framework.response import Response from rest_framework.views import APIView from authentik.core.api.utils import PassiveSerializer -from authentik.events.geo import GEOIP_READER +from authentik.events.context_processors.base import get_context_processors from authentik.lib.config import CONFIG capabilities = Signal() @@ -30,6 +30,7 @@ class Capabilities(models.TextChoices): CAN_SAVE_MEDIA = "can_save_media" CAN_GEO_IP = "can_geo_ip" + CAN_ASN = "can_asn" CAN_IMPERSONATE = "can_impersonate" CAN_DEBUG = "can_debug" IS_ENTERPRISE = "is_enterprise" @@ -68,8 +69,9 @@ class ConfigView(APIView): deb_test = settings.DEBUG or settings.TEST if Path(settings.MEDIA_ROOT).is_mount() or deb_test: caps.append(Capabilities.CAN_SAVE_MEDIA) - if GEOIP_READER.enabled: - caps.append(Capabilities.CAN_GEO_IP) + for processor in get_context_processors(): + if cap := processor.capability(): + caps.append(cap) if CONFIG.get_bool("impersonation"): caps.append(Capabilities.CAN_IMPERSONATE) if settings.DEBUG: # pragma: no cover diff --git a/authentik/core/api/authenticated_sessions.py b/authentik/core/api/authenticated_sessions.py index 03c1aeaf3..2d77937be 100644 --- a/authentik/core/api/authenticated_sessions.py +++ b/authentik/core/api/authenticated_sessions.py @@ -14,7 +14,8 @@ from ua_parser import user_agent_parser from authentik.api.authorization import OwnerSuperuserPermissions from authentik.core.api.used_by import UsedByMixin from authentik.core.models import AuthenticatedSession -from authentik.events.geo import GEOIP_READER, GeoIPDict +from authentik.events.context_processors.asn import ASN_CONTEXT_PROCESSOR, ASNDict +from authentik.events.context_processors.geoip import GEOIP_CONTEXT_PROCESSOR, GeoIPDict class UserAgentDeviceDict(TypedDict): @@ -59,6 +60,7 @@ class AuthenticatedSessionSerializer(ModelSerializer): current = SerializerMethodField() user_agent = SerializerMethodField() geo_ip = SerializerMethodField() + asn = SerializerMethodField() def get_current(self, instance: AuthenticatedSession) -> bool: """Check if session is currently active session""" @@ -70,8 +72,12 @@ class AuthenticatedSessionSerializer(ModelSerializer): return user_agent_parser.Parse(instance.last_user_agent) def get_geo_ip(self, instance: AuthenticatedSession) -> Optional[GeoIPDict]: # pragma: no cover - """Get parsed user agent""" - return GEOIP_READER.city_dict(instance.last_ip) + """Get GeoIP Data""" + return GEOIP_CONTEXT_PROCESSOR.city_dict(instance.last_ip) + + def get_asn(self, instance: AuthenticatedSession) -> Optional[ASNDict]: # pragma: no cover + """Get ASN Data""" + return ASN_CONTEXT_PROCESSOR.asn_dict(instance.last_ip) class Meta: model = AuthenticatedSession @@ -80,6 +86,7 @@ class AuthenticatedSessionSerializer(ModelSerializer): "current", "user_agent", "geo_ip", + "asn", "user", "last_ip", "last_user_agent", diff --git a/authentik/events/context_processors/__init__.py b/authentik/events/context_processors/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/authentik/events/context_processors/asn.py b/authentik/events/context_processors/asn.py new file mode 100644 index 000000000..afefbcbc6 --- /dev/null +++ b/authentik/events/context_processors/asn.py @@ -0,0 +1,79 @@ +"""ASN Enricher""" +from typing import TYPE_CHECKING, Optional, TypedDict + +from django.http import HttpRequest +from geoip2.errors import GeoIP2Error +from geoip2.models import ASN +from sentry_sdk import Hub + +from authentik.events.context_processors.mmdb import MMDBContextProcessor +from authentik.lib.config import CONFIG +from authentik.root.middleware import ClientIPMiddleware + +if TYPE_CHECKING: + from authentik.api.v3.config import Capabilities + from authentik.events.models import Event + + +class ASNDict(TypedDict): + """ASN Details""" + + asn: int + as_org: str | None + network: str | None + + +class ASNContextProcessor(MMDBContextProcessor): + """ASN Database reader wrapper""" + + def capability(self) -> Optional["Capabilities"]: + from authentik.api.v3.config import Capabilities + + return Capabilities.CAN_ASN + + def path(self) -> str | None: + return CONFIG.get("events.context_processors.asn") + + def enrich_event(self, event: "Event"): + asn = self.asn_dict(event.client_ip) + if not asn: + return + event.context["asn"] = asn + + def enrich_context(self, request: HttpRequest) -> dict: + return { + "asn": self.asn_dict(ClientIPMiddleware.get_client_ip(request)), + } + + def asn(self, ip_address: str) -> Optional[ASN]: + """Wrapper for Reader.asn""" + with Hub.current.start_span( + op="authentik.events.asn.asn", + description=ip_address, + ): + if not self.enabled: + return None + self.check_expired() + try: + return self.reader.asn(ip_address) + except (GeoIP2Error, ValueError): + return None + + def asn_to_dict(self, asn: ASN) -> ASNDict: + """Convert ASN to dict""" + asn_dict: ASNDict = { + "asn": asn.autonomous_system_number, + "as_org": asn.autonomous_system_organization, + "network": str(asn.network) if asn.network else None, + } + return asn_dict + + def asn_dict(self, ip_address: str) -> Optional[ASNDict]: + """Wrapper for self.asn that returns a dict""" + asn = self.asn(ip_address) + if not asn: + return None + return self.asn_to_dict(asn) + + +ASN_CONTEXT_PROCESSOR = ASNContextProcessor() diff --git a/authentik/events/context_processors/base.py b/authentik/events/context_processors/base.py new file mode 100644 index 000000000..96a46a65a --- /dev/null +++ b/authentik/events/context_processors/base.py @@ -0,0 +1,43 @@ +"""Base event enricher""" +from functools import cache +from typing import TYPE_CHECKING, Optional + +from django.http import HttpRequest + +if TYPE_CHECKING: + from authentik.api.v3.config import Capabilities + from authentik.events.models import Event + + +class EventContextProcessor: + """Base event enricher""" + + def capability(self) -> Optional["Capabilities"]: + """Return the capability this context processor provides""" + return None + + def configured(self) -> bool: + """Return true if this context processor is configured""" + return False + + def enrich_event(self, event: "Event"): + """Modify event""" + raise NotImplementedError + + def enrich_context(self, request: HttpRequest) -> dict: + """Modify context""" + raise NotImplementedError + + +@cache +def get_context_processors() -> list[EventContextProcessor]: + """Get a list of all configured context processors""" + from authentik.events.context_processors.asn import ASN_CONTEXT_PROCESSOR + from authentik.events.context_processors.geoip import GEOIP_CONTEXT_PROCESSOR + + processors_types = [ASN_CONTEXT_PROCESSOR, GEOIP_CONTEXT_PROCESSOR] + processors = [] + for _type in processors_types: + if _type.configured(): + processors.append(_type) + return processors diff --git a/authentik/events/context_processors/geoip.py b/authentik/events/context_processors/geoip.py new file mode 100644 index 000000000..ca00a4c54 --- /dev/null +++ b/authentik/events/context_processors/geoip.py @@ -0,0 +1,84 @@ +"""events GeoIP Reader""" +from typing import TYPE_CHECKING, Optional, TypedDict + +from django.http import HttpRequest +from geoip2.errors import GeoIP2Error +from geoip2.models import City +from sentry_sdk.hub import Hub + +from authentik.events.context_processors.mmdb import MMDBContextProcessor +from authentik.lib.config import CONFIG +from authentik.root.middleware import ClientIPMiddleware + +if TYPE_CHECKING: + from authentik.api.v3.config import Capabilities + from authentik.events.models import Event + + +class GeoIPDict(TypedDict): + """GeoIP Details""" + + continent: str + country: str + lat: float + long: float + city: str + + +class GeoIPContextProcessor(MMDBContextProcessor): + """Slim wrapper around GeoIP API""" + + def capability(self) -> Optional["Capabilities"]: + from authentik.api.v3.config import Capabilities + + return Capabilities.CAN_GEO_IP + + def path(self) -> str | None: + return CONFIG.get("events.context_processors.geoip") + + def enrich_event(self, event: "Event"): + city = self.city_dict(event.client_ip) + if not city: + return + event.context["geo"] = city + + def enrich_context(self, request: HttpRequest) -> dict: + # Different key `geoip` vs `geo` for legacy reasons + return {"geoip": self.city(ClientIPMiddleware.get_client_ip(request))} + + def city(self, ip_address: str) -> Optional[City]: + """Wrapper for Reader.city""" + with Hub.current.start_span( + op="authentik.events.geo.city", + description=ip_address, + ): + if not self.enabled: + return None + self.check_expired() + try: + return self.reader.city(ip_address) + except (GeoIP2Error, ValueError): + return None + + def city_to_dict(self, city: City) -> GeoIPDict: + """Convert City to dict""" + city_dict: GeoIPDict = { + "continent": city.continent.code, + "country": city.country.iso_code, + "lat": city.location.latitude, + "long": city.location.longitude, + "city": "", + } + if city.city.name: + city_dict["city"] = city.city.name + return city_dict + + def city_dict(self, ip_address: str) -> Optional[GeoIPDict]: + """Wrapper for self.city that returns a dict""" + city = self.city(ip_address) + if not city: + return None + return self.city_to_dict(city) + + +GEOIP_CONTEXT_PROCESSOR = GeoIPContextProcessor() diff --git a/authentik/events/context_processors/mmdb.py b/authentik/events/context_processors/mmdb.py new file mode 100644 index 000000000..09c17f91f --- /dev/null +++ b/authentik/events/context_processors/mmdb.py @@ -0,0 +1,54 @@ +"""Common logic for reading MMDB files""" +from pathlib import Path +from typing import Optional + +from geoip2.database import Reader +from structlog.stdlib import get_logger + +from authentik.events.context_processors.base import EventContextProcessor + + +class MMDBContextProcessor(EventContextProcessor): + """Common logic for reading MaxMind DB files, including re-loading if the file has changed""" + + def __init__(self): + self.reader: Optional[Reader] = None + self._last_mtime: float = 0.0 + self.logger = get_logger() + self.open() + + def path(self) -> str | None: + """Get the path to the MMDB file to load""" + raise NotImplementedError + + def open(self): + """Get GeoIP Reader, if configured, otherwise none""" + path = self.path() + if path == "" or not path: + return + try: + self.reader = Reader(path) + self._last_mtime = Path(path).stat().st_mtime + self.logger.info("Loaded MMDB database", last_write=self._last_mtime, file=path) + except OSError as exc: + self.logger.warning("Failed to load MMDB database", exc=exc) + + def check_expired(self): + """Check if the modification date of the MMDB database has + changed, and reload it if so""" + path = self.path() + if path == "" or not path: + return + try: + mtime = Path(path).stat().st_mtime + diff = self._last_mtime < mtime + if diff > 0: + self.logger.info("Found new MMDB Database, reopening", diff=diff, path=path) + self.open() + except OSError as exc: + self.logger.warning("Failed to check MMDB age", exc=exc) + + @property + def enabled(self) -> bool: + """Check if MMDB is enabled""" + return bool(self.reader) diff --git a/authentik/events/geo.py b/authentik/events/geo.py deleted file mode 100644 index 95a28539c..000000000 --- a/authentik/events/geo.py +++ /dev/null @@ -1,100 +0,0 @@ -"""events GeoIP Reader""" -from os import stat -from typing import Optional, TypedDict - -from geoip2.database import Reader -from geoip2.errors import GeoIP2Error -from geoip2.models import City -from sentry_sdk.hub import Hub -from structlog.stdlib import get_logger - -from authentik.lib.config import CONFIG - -LOGGER = get_logger() - - -class GeoIPDict(TypedDict): - """GeoIP Details""" - - continent: str - country: str - lat: float - long: float - city: str - - -class GeoIPReader: - """Slim wrapper around GeoIP API""" - - def __init__(self): - self.__reader: Optional[Reader] = None - self.__last_mtime: float = 0.0 - self.__open() - - def __open(self): - """Get GeoIP Reader, if configured, otherwise none""" - path = CONFIG.get("geoip") - if path == "" or not path: - return - try: - self.__reader = Reader(path) - self.__last_mtime = stat(path).st_mtime - LOGGER.info("Loaded GeoIP database", last_write=self.__last_mtime) - except OSError as exc: - LOGGER.warning("Failed to load GeoIP database", exc=exc) - - def __check_expired(self): - """Check if the modification date of the GeoIP database has - changed, and reload it if so""" - path = CONFIG.get("geoip") - try: - mtime = stat(path).st_mtime - diff = self.__last_mtime < mtime - if diff > 0: - LOGGER.info("Found new GeoIP Database, reopening", diff=diff) - self.__open() - except OSError as exc: - LOGGER.warning("Failed to check GeoIP age", exc=exc) - return - - @property - def enabled(self) -> bool: - """Check if GeoIP is enabled""" - return bool(self.__reader) - - def city(self, ip_address: str) -> Optional[City]: - """Wrapper for Reader.city""" - with Hub.current.start_span( - op="authentik.events.geo.city", - description=ip_address, - ): - if not self.enabled: - return None - self.__check_expired() - try: - return self.__reader.city(ip_address) - except (GeoIP2Error, ValueError): - return None - - def city_to_dict(self, city: City) -> GeoIPDict: - """Convert City to dict""" - city_dict: GeoIPDict = { - "continent": city.continent.code, - "country": city.country.iso_code, - "lat": city.location.latitude, - "long": city.location.longitude, - "city": "", - } - if city.city.name: - city_dict["city"] = city.city.name - return city_dict - - def city_dict(self, ip_address: str) -> Optional[GeoIPDict]: - """Wrapper for self.city that returns a dict""" - city = self.city(ip_address) - if not city: - return None - return self.city_to_dict(city) - - -GEOIP_READER = GeoIPReader() diff --git a/authentik/events/models.py b/authentik/events/models.py index 03e9a939c..965e38cc2 100644 --- a/authentik/events/models.py +++ b/authentik/events/models.py @@ -26,7 +26,7 @@ from authentik.core.middleware import ( SESSION_KEY_IMPERSONATE_USER, ) from authentik.core.models import ExpiringModel, Group, PropertyMapping, User -from authentik.events.geo import GEOIP_READER +from authentik.events.context_processors.base import get_context_processors from authentik.events.utils import ( cleanse_dict, get_user, @@ -246,21 +246,15 @@ class Event(SerializerModel, ExpiringModel): self.user["on_behalf_of"] = get_user(request.session[SESSION_KEY_IMPERSONATE_USER]) # User 255.255.255.255 as fallback if IP cannot be determined self.client_ip = ClientIPMiddleware.get_client_ip(request) - # Apply GeoIP Data, when enabled - self.with_geoip() + # Enrich event data + for processor in get_context_processors(): + processor.enrich_event(self) # If there's no app set, we get it from the requests too if not self.app: self.app = Event._get_app_from_request(request) self.save() return self - def with_geoip(self): # pragma: no cover - """Apply GeoIP Data, when enabled""" - city = GEOIP_READER.city_dict(self.client_ip) - if not city: - return - self.context["geo"] = city - def save(self, *args, **kwargs): if self._state.adding: LOGGER.info( diff --git a/authentik/events/tests/test_enrich_asn.py b/authentik/events/tests/test_enrich_asn.py new file mode 100644 index 000000000..2844c4591 --- /dev/null +++ b/authentik/events/tests/test_enrich_asn.py @@ -0,0 +1,24 @@ +"""Test ASN Wrapper""" +from django.test import TestCase + +from authentik.events.context_processors.asn import ASNContextProcessor + + +class TestASN(TestCase): + """Test ASN Wrapper""" + + def setUp(self) -> None: + self.reader = ASNContextProcessor() + + def test_simple(self): + """Test simple asn wrapper""" + # IPs from + # https://github.com/maxmind/MaxMind-DB/blob/main/source-data/GeoLite2-ASN-Test.json + self.assertEqual( + self.reader.asn_dict("1.0.0.1"), + { + "asn": 15169, + "as_org": "Google Inc.", + "network": "1.0.0.0/24", + }, + ) diff --git a/authentik/events/tests/test_geoip.py b/authentik/events/tests/test_enrich_geoip.py similarity index 83% rename from authentik/events/tests/test_geoip.py rename to authentik/events/tests/test_enrich_geoip.py index 3120dacae..5317901a4 100644 --- a/authentik/events/tests/test_geoip.py +++ b/authentik/events/tests/test_enrich_geoip.py @@ -1,14 +1,14 @@ """Test GeoIP Wrapper""" from django.test import TestCase -from authentik.events.geo import GeoIPReader +from authentik.events.context_processors.geoip import GeoIPContextProcessor class TestGeoIP(TestCase): """Test GeoIP Wrapper""" def setUp(self) -> None: - self.reader = GeoIPReader() + self.reader = GeoIPContextProcessor() def test_simple(self): """Test simple city wrapper""" diff --git a/authentik/events/utils.py b/authentik/events/utils.py index a7c3bdf3e..cf1b1b78b 100644 --- a/authentik/events/utils.py +++ b/authentik/events/utils.py @@ -17,12 +17,13 @@ from django.db.models.base import Model from django.http.request import HttpRequest from django.utils import timezone from django.views.debug import SafeExceptionReporterFilter -from geoip2.models import City +from geoip2.models import ASN, City from guardian.utils import get_anonymous_user from authentik.blueprints.v1.common import YAMLTag from authentik.core.models import User -from authentik.events.geo import GEOIP_READER +from authentik.events.context_processors.asn import ASN_CONTEXT_PROCESSOR +from authentik.events.context_processors.geoip import GEOIP_CONTEXT_PROCESSOR from authentik.policies.types import PolicyRequest # Special keys which are *not* cleaned, even when the default filter @@ -123,7 +124,9 @@ def sanitize_item(value: Any) -> Any: if isinstance(value, (HttpRequest, WSGIRequest)): return ... if isinstance(value, City): - return GEOIP_READER.city_to_dict(value) + return GEOIP_CONTEXT_PROCESSOR.city_to_dict(value) + if isinstance(value, ASN): + return ASN_CONTEXT_PROCESSOR.asn_to_dict(value) if isinstance(value, Path): return str(value) if isinstance(value, Exception): diff --git a/authentik/lib/config.py b/authentik/lib/config.py index dd5500f8e..3b977e8a2 100644 --- a/authentik/lib/config.py +++ b/authentik/lib/config.py @@ -35,6 +35,7 @@ REDIS_ENV_KEYS = [ ] DEPRECATIONS = { + "geoip": "events.context_processors.geoip", "redis.broker_url": "broker.url", "redis.broker_transport_options": "broker.transport_options", "redis.cache_timeout": "cache.timeout", diff --git a/authentik/lib/default.yml b/authentik/lib/default.yml index 7573888ae..afb775c44 100644 --- a/authentik/lib/default.yml +++ b/authentik/lib/default.yml @@ -108,7 +108,10 @@ cookie_domain: null disable_update_check: false disable_startup_analytics: false avatars: env://AUTHENTIK_AUTHENTIK__AVATARS?gravatar,initials -geoip: "/geoip/GeoLite2-City.mmdb" +events: + context_processors: + geoip: "/geoip/GeoLite2-City.mmdb" + asn: "/geoip/GeoLite2-ASN.mmdb" footer_links: [] diff --git a/authentik/policies/reputation/api.py b/authentik/policies/reputation/api.py index 9e9d95e13..885f6c162 100644 --- a/authentik/policies/reputation/api.py +++ b/authentik/policies/reputation/api.py @@ -47,6 +47,7 @@ class ReputationSerializer(ModelSerializer): "identifier", "ip", "ip_geo_data", + "ip_asn_data", "score", "updated", ] diff --git a/authentik/policies/reputation/migrations/0006_reputation_ip_asn_data.py b/authentik/policies/reputation/migrations/0006_reputation_ip_asn_data.py new file mode 100644 index 000000000..05557392e --- /dev/null +++ b/authentik/policies/reputation/migrations/0006_reputation_ip_asn_data.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.7 on 2023-12-05 22:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("authentik_policies_reputation", "0005_reputation_expires_reputation_expiring"), + ] + + operations = [ + migrations.AddField( + model_name="reputation", + name="ip_asn_data", + field=models.JSONField(default=dict), + ), + ] diff --git a/authentik/policies/reputation/models.py b/authentik/policies/reputation/models.py index 7fccfa11a..ea8ac2bd6 100644 --- a/authentik/policies/reputation/models.py +++ b/authentik/policies/reputation/models.py @@ -76,6 +76,7 @@ class Reputation(ExpiringModel, SerializerModel): identifier = models.TextField() ip = models.GenericIPAddressField() ip_geo_data = models.JSONField(default=dict) + ip_asn_data = models.JSONField(default=dict) score = models.BigIntegerField(default=0) expires = models.DateTimeField(default=reputation_expiry) diff --git a/authentik/policies/reputation/tasks.py b/authentik/policies/reputation/tasks.py index 7fd7b775f..ac65d1748 100644 --- a/authentik/policies/reputation/tasks.py +++ b/authentik/policies/reputation/tasks.py @@ -2,7 +2,8 @@ from django.core.cache import cache from structlog.stdlib import get_logger -from authentik.events.geo import GEOIP_READER +from authentik.events.context_processors.asn import ASN_CONTEXT_PROCESSOR +from authentik.events.context_processors.geoip import GEOIP_CONTEXT_PROCESSOR from authentik.events.monitored_tasks import ( MonitoredTask, TaskResult, @@ -26,7 +27,8 @@ def save_reputation(self: MonitoredTask): ip=score["ip"], identifier=score["identifier"], ) - rep.ip_geo_data = GEOIP_READER.city_dict(score["ip"]) or {} + rep.ip_geo_data = GEOIP_CONTEXT_PROCESSOR.city_dict(score["ip"]) or {} + rep.ip_asn_data = ASN_CONTEXT_PROCESSOR.asn_dict(score["ip"]) or {} rep.score = score["score"] objects_to_update.append(rep) Reputation.objects.bulk_update(objects_to_update, ["score", "ip_geo_data"]) diff --git a/authentik/policies/types.py b/authentik/policies/types.py index 5e59dbbf0..c9e2e8d86 100644 --- a/authentik/policies/types.py +++ b/authentik/policies/types.py @@ -8,7 +8,7 @@ from django.db.models import Model from django.http import HttpRequest from structlog.stdlib import get_logger -from authentik.events.geo import GEOIP_READER +from authentik.events.context_processors.base import get_context_processors if TYPE_CHECKING: from authentik.core.models import User @@ -37,15 +37,9 @@ class PolicyRequest: def set_http_request(self, request: HttpRequest): # pragma: no cover """Load data from HTTP request, including geoip when enabled""" - from authentik.root.middleware import ClientIPMiddleware - self.http_request = request - if not GEOIP_READER.enabled: - return - client_ip = ClientIPMiddleware.get_client_ip(request) - if not client_ip: - return - self.context["geoip"] = GEOIP_READER.city(client_ip) + for processor in get_context_processors(): + self.context.update(processor.enrich_context(request)) @property def should_cache(self) -> bool: diff --git a/authentik/root/test_runner.py b/authentik/root/test_runner.py index b2bf7a3d7..bc3b3b968 100644 --- a/authentik/root/test_runner.py +++ b/authentik/root/test_runner.py @@ -32,7 +32,8 @@ class PytestTestRunner(DiscoverRunner): # pragma: no cover settings.TEST = True settings.CELERY["task_always_eager"] = True CONFIG.set("avatars", "none") - CONFIG.set("geoip", "tests/GeoLite2-City-Test.mmdb") + CONFIG.set("events.context_processors.geoip", "tests/GeoLite2-City-Test.mmdb") + CONFIG.set("events.context_processors.asn", "tests/GeoLite2-ASN-Test.mmdb") CONFIG.set("blueprints_dir", "./blueprints") CONFIG.set( "outposts.container_image_base", diff --git a/blueprints/schema.json b/blueprints/schema.json index bf66c94ed..eaaed0a8d 100644 --- a/blueprints/schema.json +++ b/blueprints/schema.json @@ -3756,6 +3756,11 @@ "additionalProperties": true, "title": "Ip geo data" }, + "ip_asn_data": { + "type": "object", + "additionalProperties": true, + "title": "Ip asn data" + }, "score": { "type": "integer", "minimum": -9223372036854775808, diff --git a/schema.yml b/schema.yml index da1a90a18..fee6b8d3d 100644 --- a/schema.yml +++ b/schema.yml @@ -28280,7 +28280,7 @@ components: readOnly: true geo_ip: type: object - description: Get parsed user agent + description: Get GeoIP Data properties: continent: type: string @@ -28302,6 +28302,24 @@ components: - long nullable: true readOnly: true + asn: + type: object + description: Get ASN Data + properties: + asn: + type: integer + as_org: + type: string + nullable: true + network: + type: string + nullable: true + required: + - as_org + - asn + - network + nullable: true + readOnly: true user: type: integer last_ip: @@ -28316,6 +28334,7 @@ components: type: string format: date-time required: + - asn - current - geo_ip - last_ip @@ -29283,6 +29302,7 @@ components: enum: - can_save_media - can_geo_ip + - can_asn - can_impersonate - can_debug - is_enterprise @@ -29290,6 +29310,7 @@ components: description: |- * `can_save_media` - Can Save Media * `can_geo_ip` - Can Geo Ip + * `can_asn` - Can Asn * `can_impersonate` - Can Impersonate * `can_debug` - Can Debug * `is_enterprise` - Is Enterprise @@ -39667,6 +39688,7 @@ components: ip: type: string ip_geo_data: {} + ip_asn_data: {} score: type: integer maximum: 9223372036854775807 diff --git a/scripts/generate_config.py b/scripts/generate_config.py index 187eb3ba5..965e3e15e 100644 --- a/scripts/generate_config.py +++ b/scripts/generate_config.py @@ -17,7 +17,12 @@ with open("local.env.yml", "w", encoding="utf-8") as _config: }, "blueprints_dir": "./blueprints", "cert_discovery_dir": "./certs", - "geoip": "tests/GeoLite2-City-Test.mmdb", + "events": { + "processors": { + "geoip": "tests/GeoLite2-City-Test.mmdb", + "asn": "tests/GeoLite2-ASN-Test.mmdb", + } + }, }, _config, default_flow_style=False, diff --git a/tests/GeoLite2-ASN-Test.mmdb b/tests/GeoLite2-ASN-Test.mmdb new file mode 100644 index 0000000000000000000000000000000000000000..3e5033144f505227ef872af685c3664a6d45d03b GIT binary patch literal 12653 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 IzjE~d04QnY!2kdN literal 0 HcmV?d00001 diff --git a/website/docs/core/geoip.mdx b/website/docs/core/geoip.mdx index b3cedbe47..ff73e7a39 100644 --- a/website/docs/core/geoip.mdx +++ b/website/docs/core/geoip.mdx @@ -27,7 +27,8 @@ import TabItem from "@theme/TabItem"; Add the following block to your `.env` file: ```shell -AUTHENTIK_GEOIP=/tmp/non-existent-file +AUTHENTIK_EVENTS__CONTEXT_PROCESSORS__GEOIP=/tmp/non-existent-file +AUTHENTIK_EVENTS__CONTEXT_PROCESSORS__ASN=/tmp/non-existent-file ``` Afterwards, run the upgrade commands from the latest release notes. @@ -38,7 +39,10 @@ Add the following block to your `values.yml` file: ```yaml authentik: - geoip: /tmp/non-existent-file + events: + context_processors: + geoip: "/tmp/non-existent-file" + asn: "/tmp/non-existent-file" ``` Afterwards, run the upgrade commands from the latest release notes. @@ -74,7 +78,7 @@ services: volumes: - "geoip:/usr/share/GeoIP" environment: - GEOIPUPDATE_EDITION_IDS: "GeoLite2-City" + GEOIPUPDATE_EDITION_IDS: "GeoLite2-City GeoLite2-ASN" GEOIPUPDATE_FREQUENCY: "8" GEOIPUPDATE_ACCOUNT_ID: "*your account ID*" GEOIPUPDATE_LICENSE_KEY: "*your license key*" @@ -94,7 +98,7 @@ geoip: enabled: true accountId: "*your account ID*" licenseKey: "*your license key*" - editionIds: "GeoLite2-City" + editionIds: "GeoLite2-City GeoLite2-ASN" image: maxmindinc/geoipupdate:v4.8 updateInterval: 8 ``` diff --git a/website/docs/installation/configuration.mdx b/website/docs/installation/configuration.mdx index 28d8e5f50..6201467f1 100644 --- a/website/docs/installation/configuration.mdx +++ b/website/docs/installation/configuration.mdx @@ -154,9 +154,13 @@ Defaults to `info`. Which domain the session cookie should be set to. By default, the cookie is set to the domain authentik is accessed under. -### `AUTHENTIK_GEOIP` +### `AUTHENTIK_EVENTS__CONTEXT_PROCESSORS__GEOIP` -Path to the GeoIP database. Defaults to `/geoip/GeoLite2-City.mmdb`. If the file is not found, authentik will skip GeoIP support. +Path to the GeoIP City database. Defaults to `/geoip/GeoLite2-City.mmdb`. If the file is not found, authentik will skip GeoIP support. + +### `AUTHENTIK_EVENTS__CONTEXT_PROCESSORS__ASN` + +Path to the GeoIP ASN database. Defaults to `/geoip/GeoLite2-ASN.mmdb`. If the file is not found, authentik will skip GeoIP support. ### `AUTHENTIK_DISABLE_UPDATE_CHECK` From f55bc04d0423ca3e4deea3562b24c2f1dcf2216a Mon Sep 17 00:00:00 2001 From: "authentik-automation[bot]" <135050075+authentik-automation[bot]@users.noreply.github.com> Date: Wed, 20 Dec 2023 22:21:33 +0100 Subject: [PATCH 12/21] web: bump API Client version (#7953) Signed-off-by: GitHub Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com> --- web/package-lock.json | 8 ++++---- web/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index aa192cfd1..81a041ee8 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -17,7 +17,7 @@ "@codemirror/theme-one-dark": "^6.1.2", "@formatjs/intl-listformat": "^7.5.3", "@fortawesome/fontawesome-free": "^6.5.1", - "@goauthentik/api": "^2023.10.4-1702989148", + "@goauthentik/api": "^2023.10.4-1703107046", "@lit-labs/context": "^0.4.0", "@lit-labs/task": "^3.1.0", "@lit/localize": "^0.11.4", @@ -2914,9 +2914,9 @@ } }, "node_modules/@goauthentik/api": { - "version": "2023.10.4-1702989148", - "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2023.10.4-1702989148.tgz", - "integrity": "sha512-BiCZgS/sw9arpQjjXboqjUrAOhn/m5vKH4jg9gioSD5xFQLBBOvfwP0eLpmZTL60ohKZ16/XikowvRPx0K154A==" + "version": "2023.10.4-1703107046", + "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2023.10.4-1703107046.tgz", + "integrity": "sha512-XRu+VB5DRI65yPesv+8FbJHY3bY7rvJYAlSXk/doTelbmSEy66u+omh6QlAW25fwcKHQz1du40W/dUQTI8zF4w==" }, "node_modules/@hcaptcha/types": { "version": "1.0.3", diff --git a/web/package.json b/web/package.json index ffa7d0970..042fc3616 100644 --- a/web/package.json +++ b/web/package.json @@ -42,7 +42,7 @@ "@codemirror/theme-one-dark": "^6.1.2", "@formatjs/intl-listformat": "^7.5.3", "@fortawesome/fontawesome-free": "^6.5.1", - "@goauthentik/api": "^2023.10.4-1702989148", + "@goauthentik/api": "^2023.10.4-1703107046", "@lit-labs/context": "^0.4.0", "@lit-labs/task": "^3.1.0", "@lit/localize": "^0.11.4", From 38997a0fafcc300b67bc191ec2d52d9ac5837409 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Dec 2023 11:19:40 +0100 Subject: [PATCH 13/21] core: bump goauthentik.io/api/v3 from 3.2023104.4 to 3.2023104.5 (#7958) Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2023104.4 to 3.2023104.5. - [Release notes](https://github.com/goauthentik/client-go/releases) - [Commits](https://github.com/goauthentik/client-go/compare/v3.2023104.4...v3.2023104.5) --- updated-dependencies: - dependency-name: goauthentik.io/api/v3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 34dad030d..ceae598ca 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 - goauthentik.io/api/v3 v3.2023104.4 + goauthentik.io/api/v3 v3.2023104.5 golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab golang.org/x/oauth2 v0.15.0 golang.org/x/sync v0.5.0 diff --git a/go.sum b/go.sum index 1b4aff0a5..36d0b8c57 100644 --- a/go.sum +++ b/go.sum @@ -309,8 +309,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.2023104.4 h1:3jxzoawGCSlUMNsRltV1ETuGox7MM4xDZ+R+8zMNCh4= -goauthentik.io/api/v3 v3.2023104.4/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw= +goauthentik.io/api/v3 v3.2023104.5 h1:CWaQq44DxElyqMvZVjqMhWIr1vXzobf4eqFUas0lMgs= +goauthentik.io/api/v3 v3.2023104.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= From d5ed55d0742923a05ee6df6a021e0b3806b3b6e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Dec 2023 11:19:51 +0100 Subject: [PATCH 14/21] web: bump the wdio group in /tests/wdio with 4 updates (#7957) Bumps the wdio group in /tests/wdio with 4 updates: [@wdio/cli](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-cli), [@wdio/local-runner](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-local-runner), [@wdio/mocha-framework](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-mocha-framework) and [@wdio/spec-reporter](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-spec-reporter). Updates `@wdio/cli` from 8.26.3 to 8.27.0 - [Release notes](https://github.com/webdriverio/webdriverio/releases) - [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md) - [Commits](https://github.com/webdriverio/webdriverio/commits/v8.27.0/packages/wdio-cli) Updates `@wdio/local-runner` from 8.26.3 to 8.27.0 - [Release notes](https://github.com/webdriverio/webdriverio/releases) - [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md) - [Commits](https://github.com/webdriverio/webdriverio/commits/v8.27.0/packages/wdio-local-runner) Updates `@wdio/mocha-framework` from 8.26.3 to 8.27.0 - [Release notes](https://github.com/webdriverio/webdriverio/releases) - [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md) - [Commits](https://github.com/webdriverio/webdriverio/commits/v8.27.0/packages/wdio-mocha-framework) Updates `@wdio/spec-reporter` from 8.26.3 to 8.27.0 - [Release notes](https://github.com/webdriverio/webdriverio/releases) - [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md) - [Commits](https://github.com/webdriverio/webdriverio/commits/v8.27.0/packages/wdio-spec-reporter) --- updated-dependencies: - dependency-name: "@wdio/cli" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wdio - dependency-name: "@wdio/local-runner" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wdio - dependency-name: "@wdio/mocha-framework" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wdio - dependency-name: "@wdio/spec-reporter" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wdio ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tests/wdio/package-lock.json | 138 +++++++++++++++++------------------ tests/wdio/package.json | 8 +- 2 files changed, 73 insertions(+), 73 deletions(-) diff --git a/tests/wdio/package-lock.json b/tests/wdio/package-lock.json index 11905de2f..837632bb5 100644 --- a/tests/wdio/package-lock.json +++ b/tests/wdio/package-lock.json @@ -9,10 +9,10 @@ "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@typescript-eslint/eslint-plugin": "^6.15.0", "@typescript-eslint/parser": "^6.15.0", - "@wdio/cli": "^8.26.3", - "@wdio/local-runner": "^8.26.3", - "@wdio/mocha-framework": "^8.26.3", - "@wdio/spec-reporter": "^8.26.3", + "@wdio/cli": "^8.27.0", + "@wdio/local-runner": "^8.27.0", + "@wdio/mocha-framework": "^8.27.0", + "@wdio/spec-reporter": "^8.27.0", "eslint": "^8.56.0", "eslint-config-google": "^0.14.0", "eslint-plugin-sonarjs": "^0.23.0", @@ -1141,18 +1141,18 @@ "dev": true }, "node_modules/@wdio/cli": { - "version": "8.26.3", - "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.26.3.tgz", - "integrity": "sha512-wrq145sNBw4DrsF5GEK8TBxqVWln7GZpNpM5QeDqCcZzVHIqDud4f7nADgZGbR8dJ96NVfC3rby6wbeRQUA+eg==", + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.27.0.tgz", + "integrity": "sha512-wdNYNvu52XxOqNHqDMGAtexBz+MM0RE2Z5U5ljyllbP3ed5vcvvK9vswURtI4cFGoqobVeoC7wif3VeD3aN+aQ==", "dev": true, "dependencies": { "@types/node": "^20.1.1", - "@wdio/config": "8.26.3", - "@wdio/globals": "8.26.3", + "@wdio/config": "8.27.0", + "@wdio/globals": "8.27.0", "@wdio/logger": "8.24.12", "@wdio/protocols": "8.24.12", - "@wdio/types": "8.26.3", - "@wdio/utils": "8.26.3", + "@wdio/types": "8.27.0", + "@wdio/utils": "8.27.0", "async-exit-hook": "^2.0.1", "chalk": "^5.2.0", "chokidar": "^3.5.3", @@ -1167,7 +1167,7 @@ "lodash.union": "^4.6.0", "read-pkg-up": "^10.0.0", "recursive-readdir": "^2.2.3", - "webdriverio": "8.26.3", + "webdriverio": "8.27.0", "yargs": "^17.7.2" }, "bin": { @@ -1190,14 +1190,14 @@ } }, "node_modules/@wdio/config": { - "version": "8.26.3", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.26.3.tgz", - "integrity": "sha512-NWh2JXRSyP4gY+jeC79u0L3hSXW/s3rOWez4M6qAglT91fZTXFbIl1GM8lnZlCq03ye2qFPqYrZ+4tGNQj7YxQ==", + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.27.0.tgz", + "integrity": "sha512-zYM5daeiBVVAbQj0ASymAt0RUsocLVIwKiUHNa8gg/1GsZnztGjetXExSp1gXlxtMVM5xWUSKjh6ceFK79gWDQ==", "dev": true, "dependencies": { "@wdio/logger": "8.24.12", - "@wdio/types": "8.26.3", - "@wdio/utils": "8.26.3", + "@wdio/types": "8.27.0", + "@wdio/utils": "8.27.0", "decamelize": "^6.0.0", "deepmerge-ts": "^5.0.0", "glob": "^10.2.2", @@ -1208,29 +1208,29 @@ } }, "node_modules/@wdio/globals": { - "version": "8.26.3", - "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.26.3.tgz", - "integrity": "sha512-RW3UsvnUb4DjxVOqIngXQMcDJlbH+QL/LeChznUF0FW+Mqg/mZWukBld5/dDwgQHk9F2TOzc8ctk5FM3s1AoWQ==", + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.27.0.tgz", + "integrity": "sha512-HUPOIsrmxfF0LhU68lVsNGQGZkW/bWOvcCd8WxeaggTAH9JyxasxxfwzeCceAuhAvwtlwoMXITOpjAXO2mj38Q==", "dev": true, "engines": { "node": "^16.13 || >=18" }, "optionalDependencies": { "expect-webdriverio": "^4.6.1", - "webdriverio": "8.26.3" + "webdriverio": "8.27.0" } }, "node_modules/@wdio/local-runner": { - "version": "8.26.3", - "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.26.3.tgz", - "integrity": "sha512-YWxTBp6tc8Dlz09rnRhV2GXV4b3w5G0WyYEf81D+kXDI3QxDvYn6QujByr6Q7fQ9yLwJU4ptnT2uL5IbAwVo2A==", + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.27.0.tgz", + "integrity": "sha512-nxS17mhoLkXP20eoPMkz7tbMFMOQejSw0hZfkEvuDCNhJokr8ugp6IjYXL9f7yV9IB9UDGHox8WGY4ArSrOeBA==", "dev": true, "dependencies": { "@types/node": "^20.1.0", "@wdio/logger": "8.24.12", "@wdio/repl": "8.24.12", - "@wdio/runner": "8.26.3", - "@wdio/types": "8.26.3", + "@wdio/runner": "8.27.0", + "@wdio/types": "8.27.0", "async-exit-hook": "^2.0.1", "split2": "^4.1.0", "stream-buffers": "^3.0.2" @@ -1267,16 +1267,16 @@ } }, "node_modules/@wdio/mocha-framework": { - "version": "8.26.3", - "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.26.3.tgz", - "integrity": "sha512-r9uHUcXhh6TKFqTBCacnbtQx0nZjFsnV9Pony8CY9qcNCn2q666ucQbrtMfZdjuevhn5N0E710+El4eAvK3jyw==", + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.27.0.tgz", + "integrity": "sha512-NaFUPv90ks1XlZy0qdUaJ5/ilBtiCCgTIxaPexshJiaVDT5cV+Igjag/O80HIcvqknOZpdKAR0I1ArQzhJrmcA==", "dev": true, "dependencies": { "@types/mocha": "^10.0.0", "@types/node": "^20.1.0", "@wdio/logger": "8.24.12", - "@wdio/types": "8.26.3", - "@wdio/utils": "8.26.3", + "@wdio/types": "8.27.0", + "@wdio/utils": "8.27.0", "mocha": "^10.0.0" }, "engines": { @@ -1302,14 +1302,14 @@ } }, "node_modules/@wdio/reporter": { - "version": "8.26.3", - "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-8.26.3.tgz", - "integrity": "sha512-F/sF1Hwxp1osM2wto4JydONQGxqkbOhwbLM0o4Y8eHPgK7/m+Kn9uygBDqPVpgQnpf0kUfhpICe9gaZzG4Jt+g==", + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-8.27.0.tgz", + "integrity": "sha512-kBwsrHbsblmXfHSWlaOKXjPRPeT29WSKTUoCmzuTcCkhvbjY4TrEB0p04cpaM7uNqdIZTxHng54gZVaG/nZPiw==", "dev": true, "dependencies": { "@types/node": "^20.1.0", "@wdio/logger": "8.24.12", - "@wdio/types": "8.26.3", + "@wdio/types": "8.27.0", "diff": "^5.0.0", "object-inspect": "^1.12.0" }, @@ -1318,35 +1318,35 @@ } }, "node_modules/@wdio/runner": { - "version": "8.26.3", - "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.26.3.tgz", - "integrity": "sha512-mbZGkBbXTRtj1hL5QUbNxpJvhE4rkXvYlUuea1uOVk3e2/+k2dZeGeKPgh1Q7Dt07118dfujCB7pQCYldE/dGg==", + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.27.0.tgz", + "integrity": "sha512-da332r2d1QXdRhMhsDxMObcqLZS0l/u14pHICNTvEHp+72gOttbjUDvdMHPQY6Ae5ul7AVVQ05qpmz9CX7TzOg==", "dev": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.26.3", - "@wdio/globals": "8.26.3", + "@wdio/config": "8.27.0", + "@wdio/globals": "8.27.0", "@wdio/logger": "8.24.12", - "@wdio/types": "8.26.3", - "@wdio/utils": "8.26.3", + "@wdio/types": "8.27.0", + "@wdio/utils": "8.27.0", "deepmerge-ts": "^5.0.0", "expect-webdriverio": "^4.6.1", "gaze": "^1.1.2", - "webdriver": "8.26.3", - "webdriverio": "8.26.3" + "webdriver": "8.27.0", + "webdriverio": "8.27.0" }, "engines": { "node": "^16.13 || >=18" } }, "node_modules/@wdio/spec-reporter": { - "version": "8.26.3", - "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-8.26.3.tgz", - "integrity": "sha512-YfKlBOmxGyJk08BpDnsjPsp85XyhG7Cu2qoAVxtJ8kkJOZaGfUg9TBV9DXDqvdZcxCMnPfDfQIda6LzfkZf58Q==", + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-8.27.0.tgz", + "integrity": "sha512-EOXLBIr4oLzSDp/BQ86IqCulSF0jwEAj2EiMeY6dh9WXzBBtoR8WnoX/27xFoZ8GU2zetWC3EVnLJ0Ex8Up1mA==", "dev": true, "dependencies": { - "@wdio/reporter": "8.26.3", - "@wdio/types": "8.26.3", + "@wdio/reporter": "8.27.0", + "@wdio/types": "8.27.0", "chalk": "^5.1.2", "easy-table": "^1.2.0", "pretty-ms": "^7.0.0" @@ -1368,9 +1368,9 @@ } }, "node_modules/@wdio/types": { - "version": "8.26.3", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.26.3.tgz", - "integrity": "sha512-WOxvSV4sKJ5QCRNTJHeKCzgO2TZmcK1eDlJ+FObt9Pnt+4pCRy/881eVY/Aj2bozn2hhzq0AK/h6oPAUV/gjCg==", + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.27.0.tgz", + "integrity": "sha512-LbP9FKh8r0uW9/dKhTIUCC1Su8PsP9TmzGKXkWt6/IMacgJiB/zW3u1CgyaLw9lG0UiQORHGoeJX9zB2HZAh4w==", "dev": true, "dependencies": { "@types/node": "^20.1.0" @@ -1380,14 +1380,14 @@ } }, "node_modules/@wdio/utils": { - "version": "8.26.3", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.26.3.tgz", - "integrity": "sha512-LA/iCKgJQemAAXoN6vHyKBtngdkFUWEnjB8Yd1Xm3gUQTvY4GVlvcqOxC2RF5Th7/L2LNxc6TWuErYv/mm5H+w==", + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.27.0.tgz", + "integrity": "sha512-4BY+JBQssVn003P5lA289uDMie3LtGinHze5btkcW9timB6VaU+EeZS4eKTPC0pziizLhteVvXYxv3YTpeeRfA==", "dev": true, "dependencies": { "@puppeteer/browsers": "^1.6.0", "@wdio/logger": "8.24.12", - "@wdio/types": "8.26.3", + "@wdio/types": "8.27.0", "decamelize": "^6.0.0", "deepmerge-ts": "^5.1.0", "edgedriver": "^5.3.5", @@ -8495,18 +8495,18 @@ } }, "node_modules/webdriver": { - "version": "8.26.3", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.26.3.tgz", - "integrity": "sha512-vHbMj0BFXPMtKVmJsVIkFVbdOT8eXkjFeJ7LmJL8cMMe1S5Lt44DqRjSBBoGsqYoYgIBmKpqAQcDrHrv9m7smQ==", + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.27.0.tgz", + "integrity": "sha512-n1IA+rR3u84XxU9swiKUM06BkEC0GDimfZkBML57cny+utQOUbdM/mBpqCUnkWX/RBz/p2EfHdKNyOs3/REaog==", "dev": true, "dependencies": { "@types/node": "^20.1.0", "@types/ws": "^8.5.3", - "@wdio/config": "8.26.3", + "@wdio/config": "8.27.0", "@wdio/logger": "8.24.12", "@wdio/protocols": "8.24.12", - "@wdio/types": "8.26.3", - "@wdio/utils": "8.26.3", + "@wdio/types": "8.27.0", + "@wdio/utils": "8.27.0", "deepmerge-ts": "^5.1.0", "got": "^12.6.1", "ky": "^0.33.0", @@ -8517,18 +8517,18 @@ } }, "node_modules/webdriverio": { - "version": "8.26.3", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.26.3.tgz", - "integrity": "sha512-5Ka8MOQoK866EI3whiCvzD1IiKFBq9niWF3lh92uMt6ZjbUZZoe5esWIHhFsHFxT6dOOU8uXR/Gr6qsBJFZReA==", + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.27.0.tgz", + "integrity": "sha512-Qh5VCiBjEmxnmXcL1QEFoDzFqTtaWKrXriuU5G0yHKCModGAt2G7IHTkAok3CpmkVJfZpEvY630aP1MvgDtFhw==", "dev": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.26.3", + "@wdio/config": "8.27.0", "@wdio/logger": "8.24.12", "@wdio/protocols": "8.24.12", "@wdio/repl": "8.24.12", - "@wdio/types": "8.26.3", - "@wdio/utils": "8.26.3", + "@wdio/types": "8.27.0", + "@wdio/utils": "8.27.0", "archiver": "^6.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", @@ -8545,7 +8545,7 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.26.3" + "webdriver": "8.27.0" }, "engines": { "node": "^16.13 || >=18" diff --git a/tests/wdio/package.json b/tests/wdio/package.json index 78b0928fc..badccc3f1 100644 --- a/tests/wdio/package.json +++ b/tests/wdio/package.json @@ -6,10 +6,10 @@ "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@typescript-eslint/eslint-plugin": "^6.15.0", "@typescript-eslint/parser": "^6.15.0", - "@wdio/cli": "^8.26.3", - "@wdio/local-runner": "^8.26.3", - "@wdio/mocha-framework": "^8.26.3", - "@wdio/spec-reporter": "^8.26.3", + "@wdio/cli": "^8.27.0", + "@wdio/local-runner": "^8.27.0", + "@wdio/mocha-framework": "^8.27.0", + "@wdio/spec-reporter": "^8.27.0", "eslint": "^8.56.0", "eslint-config-google": "^0.14.0", "eslint-plugin-sonarjs": "^0.23.0", From 96bdb0ddace0de0778d273964308013a86f6a2d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Dec 2023 11:20:06 +0100 Subject: [PATCH 15/21] web: bump the sentry group in /web with 2 updates (#7955) Bumps the sentry group in /web with 2 updates: [@sentry/browser](https://github.com/getsentry/sentry-javascript) and [@sentry/tracing](https://github.com/getsentry/sentry-javascript). Updates `@sentry/browser` from 7.89.0 to 7.90.0 - [Release notes](https://github.com/getsentry/sentry-javascript/releases) - [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-javascript/compare/7.89.0...7.90.0) Updates `@sentry/tracing` from 7.89.0 to 7.90.0 - [Release notes](https://github.com/getsentry/sentry-javascript/releases) - [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-javascript/compare/7.89.0...7.90.0) --- updated-dependencies: - dependency-name: "@sentry/browser" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: sentry - dependency-name: "@sentry/tracing" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: sentry ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 92 +++++++++++++++++++++---------------------- web/package.json | 4 +- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 81a041ee8..5e48005e4 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.89.0", - "@sentry/tracing": "^7.89.0", + "@sentry/browser": "^7.90.0", + "@sentry/tracing": "^7.90.0", "@webcomponents/webcomponentsjs": "^2.8.0", "base64-js": "^1.5.1", "chart.js": "^4.4.1", @@ -4752,98 +4752,98 @@ ] }, "node_modules/@sentry-internal/feedback": { - "version": "7.89.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.89.0.tgz", - "integrity": "sha512-Uz1A/ex3X/cvHjS3C9qH8ENa1Le7Jesxl3Umuv3n1e/rvoPxo2VFNCgDrpsM1mcg2XwiPkmpyMAVxDMgB0A7JQ==", + "version": "7.90.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.90.0.tgz", + "integrity": "sha512-ZIdpwK9KmiE/UYGUgNE3N9A5MWm92rbC/0u04LxQfZh0tGqN2EchwivQpFCWuu5QsKMlsza7aO6YQXsKvwt1Ww==", "dependencies": { - "@sentry/core": "7.89.0", - "@sentry/types": "7.89.0", - "@sentry/utils": "7.89.0" + "@sentry/core": "7.90.0", + "@sentry/types": "7.90.0", + "@sentry/utils": "7.90.0" }, "engines": { "node": ">=12" } }, "node_modules/@sentry-internal/tracing": { - "version": "7.89.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.89.0.tgz", - "integrity": "sha512-cSwno2NYteBBqOvcm/ue9cJxGGl2uffG4laEyLR9y4we+bYxigfx/Ki2TFOtwXrv5o59eRAtN1lpzaAf43yfBw==", + "version": "7.90.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.90.0.tgz", + "integrity": "sha512-74jEtpdio9aRkiVBcrY1ZJXek0oFMqxDJK6BkJNCA+aUK1z96V9viehANRk3Nbxm01rWjmH1U4e1siuo9FhjuQ==", "dependencies": { - "@sentry/core": "7.89.0", - "@sentry/types": "7.89.0", - "@sentry/utils": "7.89.0" + "@sentry/core": "7.90.0", + "@sentry/types": "7.90.0", + "@sentry/utils": "7.90.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/browser": { - "version": "7.89.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.89.0.tgz", - "integrity": "sha512-84hZOymrKyfjQnbD6d/PhlHCsQHjUGCqVU/K6e7g+JiB1DNZOsfZTkLj6Xj8OQzvwKHWzB9egmJN6IA7dUSJXQ==", + "version": "7.90.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.90.0.tgz", + "integrity": "sha512-ik3Jwo+TYjoEesJlt3PlHDcPE9h//WwyUsVkV9ZsVx0MSXb8c1VC4uDMsyUqjA+gPImmw1l9KlWZtvaOooZEhg==", "dependencies": { - "@sentry-internal/feedback": "7.89.0", - "@sentry-internal/tracing": "7.89.0", - "@sentry/core": "7.89.0", - "@sentry/replay": "7.89.0", - "@sentry/types": "7.89.0", - "@sentry/utils": "7.89.0" + "@sentry-internal/feedback": "7.90.0", + "@sentry-internal/tracing": "7.90.0", + "@sentry/core": "7.90.0", + "@sentry/replay": "7.90.0", + "@sentry/types": "7.90.0", + "@sentry/utils": "7.90.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/core": { - "version": "7.89.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.89.0.tgz", - "integrity": "sha512-aU3wfZ+tyFi4T06fOH3z5xnTyMzwvzyEohYOmnQnDrqNgvDzjWkyeUzWse9FaFiut8lBN9O+Pd2H0ucPBMPEhQ==", + "version": "7.90.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.90.0.tgz", + "integrity": "sha512-HolpdHjULCwehKPWHR6IPQM0NBjmORhlBU7FtCh/e8TtSkZ9ztPsuofNBomMS1+mdbL+yxOIc9KUYEl0zRfeAQ==", "dependencies": { - "@sentry/types": "7.89.0", - "@sentry/utils": "7.89.0" + "@sentry/types": "7.90.0", + "@sentry/utils": "7.90.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/replay": { - "version": "7.89.0", - "resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.89.0.tgz", - "integrity": "sha512-iD1E1SbW8Ca34Fn0slM9E0Kh0DjhkZGerPFKqbwjXR7QKCx+ljMRKaCQhb4bBKfVNYZORxpwY4PLJLQ+k6WHJg==", + "version": "7.90.0", + "resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.90.0.tgz", + "integrity": "sha512-fsABtzQ5JQI7G5CC4fg05lVI5DTbd1uwKi41xVKFRmCB5NVTHvK7bHgP8n6uSbnle+gp9rUxVPLLBIPjKfaTmw==", "dependencies": { - "@sentry-internal/tracing": "7.89.0", - "@sentry/core": "7.89.0", - "@sentry/types": "7.89.0", - "@sentry/utils": "7.89.0" + "@sentry-internal/tracing": "7.90.0", + "@sentry/core": "7.90.0", + "@sentry/types": "7.90.0", + "@sentry/utils": "7.90.0" }, "engines": { "node": ">=12" } }, "node_modules/@sentry/tracing": { - "version": "7.89.0", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.89.0.tgz", - "integrity": "sha512-POYZ1+YxG0G3JizoPmForqo3kPILYhmHIqypsSz7RT+OKsKVmGt/GuspydJM1xhbPYrFyMxzt6HMMss4JN1Uew==", + "version": "7.90.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.90.0.tgz", + "integrity": "sha512-7NeLePk/MaL/VzAJ+uF/ic1dA+3nefeHwKdUtDDxbbz72T3uTfPCfXuiZeSara9ykop3kKWc4Ll5JTSi8LbA0Q==", "dependencies": { - "@sentry-internal/tracing": "7.89.0" + "@sentry-internal/tracing": "7.90.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/types": { - "version": "7.89.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.89.0.tgz", - "integrity": "sha512-5Rqt6vIP652p01ypUaEIrELjsHF0vUnzj/JFz+i7nXv6w77GPpNzeIlMYdnauBIgJhLUvYCTQaOPV9GhgZhc4g==", + "version": "7.90.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.90.0.tgz", + "integrity": "sha512-dA0Mtba5jYlcQ6xBsGILZuFq4NGrWLfr2ys036z2JE4H1+3PxOVERlD3Di7p+WKYM5gjFw10Hn3EgUV979E3dA==", "engines": { "node": ">=8" } }, "node_modules/@sentry/utils": { - "version": "7.89.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.89.0.tgz", - "integrity": "sha512-t6qDQajdAjZ6LPraAWO00ZjvDbNH82DoVGV/2o4C5MBPCutJGTGyWIpI2tliYPZPPx+3C2m5L757zh1dCzrgUg==", + "version": "7.90.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.90.0.tgz", + "integrity": "sha512-6BpqAzONm/HQbdlL4TY2W2vBSmaG/eVvwUaHoz0wB49EkWwpF6j/SO9Kb/XkiA/qp9GoJVXpnGBFQLPx7kv/Yw==", "dependencies": { - "@sentry/types": "7.89.0" + "@sentry/types": "7.90.0" }, "engines": { "node": ">=8" diff --git a/web/package.json b/web/package.json index 042fc3616..37de7a270 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.89.0", - "@sentry/tracing": "^7.89.0", + "@sentry/browser": "^7.90.0", + "@sentry/tracing": "^7.90.0", "@webcomponents/webcomponentsjs": "^2.8.0", "base64-js": "^1.5.1", "chart.js": "^4.4.1", From 218d61648b891b1f1e8be1ffe7e74787d4e57a52 Mon Sep 17 00:00:00 2001 From: Jens L Date: Thu, 21 Dec 2023 14:24:34 +0100 Subject: [PATCH 16/21] website/docs: prepare 2023.10.5 (#7947) Signed-off-by: Jens Langhammer --- website/docs/releases/2023/v2023.10.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/website/docs/releases/2023/v2023.10.md b/website/docs/releases/2023/v2023.10.md index a1f74470c..1034d0115 100644 --- a/website/docs/releases/2023/v2023.10.md +++ b/website/docs/releases/2023/v2023.10.md @@ -165,6 +165,22 @@ helm upgrade authentik authentik/authentik -f values.yaml --version ^2023.10 - stages/email: use uuid for email confirmation token instead of username (cherry-pick #7581) (#7584) - web/admin: fix admins not able to delete MFA devices (#7660) +## Fixed in 2023.10.5 + +- blueprints: improve file change handler (cherry-pick #7813) (#7934) +- events: add better fallback for sanitize_item to ensure everything can be saved as JSON (cherry-pick #7694) (#7937) +- events: fix lint (#7700) +- events: include user agent in events (cherry-pick #7693) (#7938) +- providers/scim: change familyName default (cherry-pick #7904) (#7930) +- root: don't show warning when app has no URLs to import (cherry-pick #7765) (#7935) +- root: Fix cache related image build issues (cherry-pick #7831) (#7932) +- stages/email: improve error handling for incorrect template syntax (cherry-pick #7758) (#7936) +- tests: fix flaky tests (cherry-pick #7676) (#7939) +- web: dark/light theme fixes (#7872) +- web: fix overflow glitch on ak-page-header (cherry-pick #7883) (#7931) +- web/admin: always show oidc well-known URL fields when they're set (#7560) +- web/user: fix search not updating app (cherry-pick #7825) (#7933) + ## API Changes #### What's New From ec8f2d4bf98f35cc8dc03931c85878228df0f992 Mon Sep 17 00:00:00 2001 From: Jens L Date: Thu, 21 Dec 2023 14:32:05 +0100 Subject: [PATCH 17/21] stages/email: prevent authentik emails from being marked as spam (also add text template support) (#7949) * use <> style email address with name Signed-off-by: Jens Langhammer * add support for text templates Signed-off-by: Jens Langhammer * fix icon display in event log Signed-off-by: Jens Langhammer * add text email templates Signed-off-by: Jens Langhammer * update docs, update email screenshot Signed-off-by: Jens Langhammer * prevent prettier from breaking example template Signed-off-by: Jens Langhammer * Optimised images with calibre/image-actions * Apply suggestions from code review Co-authored-by: Marc 'risson' Schmitt Signed-off-by: Jens L. * reword docs Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer Signed-off-by: Jens L. Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com> Co-authored-by: Marc 'risson' Schmitt --- authentik/events/models.py | 2 +- authentik/stages/email/stage.py | 2 +- .../templates/email/account_confirmation.txt | 8 ++++ .../templates/email/event_notification.html | 2 +- .../templates/email/event_notification.txt | 18 +++++++++ .../email/templates/email/password_reset.txt | 12 ++++++ .../stages/email/templates/email/setup.txt | 7 ++++ .../templatetags/authentik_stages_email.py | 6 +++ authentik/stages/email/tests/test_sending.py | 6 ++- authentik/stages/email/tests/test_stage.py | 4 +- authentik/stages/email/utils.py | 11 +++++- web/src/components/ak-event-info.ts | 4 +- .../docs/flow/stages/email/email_recovery.png | Bin 23911 -> 25528 bytes website/docs/flow/stages/email/index.mdx | 37 +++++++++++------- 14 files changed, 95 insertions(+), 24 deletions(-) create mode 100644 authentik/stages/email/templates/email/account_confirmation.txt create mode 100644 authentik/stages/email/templates/email/event_notification.txt create mode 100644 authentik/stages/email/templates/email/password_reset.txt create mode 100644 authentik/stages/email/templates/email/setup.txt diff --git a/authentik/events/models.py b/authentik/events/models.py index 965e38cc2..240ba11de 100644 --- a/authentik/events/models.py +++ b/authentik/events/models.py @@ -461,7 +461,7 @@ class NotificationTransport(SerializerModel): } mail = TemplateEmailMessage( subject=subject_prefix + context["title"], - to=[notification.user.email], + to=[f"{notification.user.name} <{notification.user.email}>"], language=notification.user.locale(), template_name="email/event_notification.html", template_context=context, diff --git a/authentik/stages/email/stage.py b/authentik/stages/email/stage.py index 0fa36bfbe..160a68e92 100644 --- a/authentik/stages/email/stage.py +++ b/authentik/stages/email/stage.py @@ -110,7 +110,7 @@ class EmailStageView(ChallengeStageView): try: message = TemplateEmailMessage( subject=_(current_stage.subject), - to=[email], + to=[f"{pending_user.name} <{email}>"], language=pending_user.locale(self.request), template_name=current_stage.template, template_context={ diff --git a/authentik/stages/email/templates/email/account_confirmation.txt b/authentik/stages/email/templates/email/account_confirmation.txt new file mode 100644 index 000000000..0a1fc70d1 --- /dev/null +++ b/authentik/stages/email/templates/email/account_confirmation.txt @@ -0,0 +1,8 @@ +{% load i18n %}{% translate "Welcome!" %} + +{% translate "We're excited to have you get started. First, you need to confirm your account. Just open the link below." %} + +{{ url }} + +-- +Powered by goauthentik.io. diff --git a/authentik/stages/email/templates/email/event_notification.html b/authentik/stages/email/templates/email/event_notification.html index e34563404..7ca78fc64 100644 --- a/authentik/stages/email/templates/email/event_notification.html +++ b/authentik/stages/email/templates/email/event_notification.html @@ -44,7 +44,7 @@ {% blocktranslate with name=source.from %} - This email was sent from the notification transport {{name}}. + This email was sent from the notification transport {{ name }}. {% endblocktranslate %} diff --git a/authentik/stages/email/templates/email/event_notification.txt b/authentik/stages/email/templates/email/event_notification.txt new file mode 100644 index 000000000..bd7d92896 --- /dev/null +++ b/authentik/stages/email/templates/email/event_notification.txt @@ -0,0 +1,18 @@ +{% load authentik_stages_email %}{% load i18n %}{% translate "Dear authentik user," %} + +{% translate "The following notification was created:" %} + + {{ body|indent }} + +{% if key_value %} +{% translate "Additional attributes:" %} +{% for key, value in key_value.items %} + {{ key }}: {{ value|indent }}{% endfor %} +{% endif %} + +{% if source %}{% blocktranslate with name=source.from %} +This email was sent from the notification transport {{ name }}. +{% endblocktranslate %}{% endif %} + +-- +Powered by goauthentik.io. diff --git a/authentik/stages/email/templates/email/password_reset.txt b/authentik/stages/email/templates/email/password_reset.txt new file mode 100644 index 000000000..0c13ad2f8 --- /dev/null +++ b/authentik/stages/email/templates/email/password_reset.txt @@ -0,0 +1,12 @@ +{% load i18n %}{% load humanize %}{% blocktrans with username=user.username %}Hi {{ username }},{% endblocktrans %} + +{% blocktrans %} +You recently requested to change your password for your authentik account. Use the link below to set a new password. +{% endblocktrans %} +{{ url }} +{% blocktrans with expires=expires|naturaltime %} +If you did not request a password change, please ignore this Email. The link above is valid for {{ expires }}. +{% endblocktrans %} + +-- +Powered by goauthentik.io. diff --git a/authentik/stages/email/templates/email/setup.txt b/authentik/stages/email/templates/email/setup.txt new file mode 100644 index 000000000..6d0eb0ce0 --- /dev/null +++ b/authentik/stages/email/templates/email/setup.txt @@ -0,0 +1,7 @@ +{% load i18n %}authentik Test-Email +{% blocktrans %} +This is a test email to inform you, that you've successfully configured authentik emails. +{% endblocktrans %} + +-- +Powered by goauthentik.io. diff --git a/authentik/stages/email/templatetags/authentik_stages_email.py b/authentik/stages/email/templatetags/authentik_stages_email.py index 7623c6c71..9b3dfb194 100644 --- a/authentik/stages/email/templatetags/authentik_stages_email.py +++ b/authentik/stages/email/templatetags/authentik_stages_email.py @@ -29,3 +29,9 @@ def inline_static_binary(path: str) -> str: b64content = b64encode(_file.read().encode()) return f"data:image/{result.suffix};base64,{b64content.decode('utf-8')}" return path + + +@register.filter(name="indent") +def indent_string(val, num_spaces=4): + """Intent text by a given amount of spaces""" + return val.replace("\n", "\n" + " " * num_spaces) diff --git a/authentik/stages/email/tests/test_sending.py b/authentik/stages/email/tests/test_sending.py index 424d474ce..5c67c8842 100644 --- a/authentik/stages/email/tests/test_sending.py +++ b/authentik/stages/email/tests/test_sending.py @@ -58,9 +58,11 @@ class TestEmailStageSending(FlowTestCase): events = Event.objects.filter(action=EventAction.EMAIL_SENT) self.assertEqual(len(events), 1) event = events.first() - self.assertEqual(event.context["message"], f"Email to {self.user.email} sent") + self.assertEqual( + event.context["message"], f"Email to {self.user.name} <{self.user.email}> sent" + ) self.assertEqual(event.context["subject"], "authentik") - self.assertEqual(event.context["to_email"], [self.user.email]) + self.assertEqual(event.context["to_email"], [f"{self.user.name} <{self.user.email}>"]) self.assertEqual(event.context["from_email"], "system@authentik.local") def test_pending_fake_user(self): diff --git a/authentik/stages/email/tests/test_stage.py b/authentik/stages/email/tests/test_stage.py index 853bc2a77..277549937 100644 --- a/authentik/stages/email/tests/test_stage.py +++ b/authentik/stages/email/tests/test_stage.py @@ -94,7 +94,7 @@ class TestEmailStage(FlowTestCase): self.assertEqual(response.status_code, 200) self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].subject, "authentik") - self.assertEqual(mail.outbox[0].to, [self.user.email]) + self.assertEqual(mail.outbox[0].to, [f"{self.user.name} <{self.user.email}>"]) @patch( "authentik.stages.email.models.EmailStage.backend_class", @@ -114,7 +114,7 @@ class TestEmailStage(FlowTestCase): self.assertEqual(response.status_code, 200) self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].subject, "authentik") - self.assertEqual(mail.outbox[0].to, ["foo@bar.baz"]) + self.assertEqual(mail.outbox[0].to, [f"{self.user.name} "]) @patch( "authentik.stages.email.models.EmailStage.backend_class", diff --git a/authentik/stages/email/utils.py b/authentik/stages/email/utils.py index a6edd4609..8f7f702ce 100644 --- a/authentik/stages/email/utils.py +++ b/authentik/stages/email/utils.py @@ -4,6 +4,7 @@ from functools import lru_cache from pathlib import Path from django.core.mail import EmailMultiAlternatives +from django.template.exceptions import TemplateDoesNotExist from django.template.loader import render_to_string from django.utils import translation @@ -24,9 +25,15 @@ class TemplateEmailMessage(EmailMultiAlternatives): """Wrapper around EmailMultiAlternatives with integrated template rendering""" def __init__(self, template_name=None, template_context=None, language="", **kwargs): + super().__init__(**kwargs) with translation.override(language): html_content = render_to_string(template_name, template_context) - super().__init__(**kwargs) - self.content_subtype = "html" + try: + text_content = render_to_string( + template_name.replace("html", "txt"), template_context + ) + self.body = text_content + except TemplateDoesNotExist: + pass self.mixed_subtype = "related" self.attach_alternative(html_content, "text/html") diff --git a/web/src/components/ak-event-info.ts b/web/src/components/ak-event-info.ts index 6901f31a8..e728958c2 100644 --- a/web/src/components/ak-event-info.ts +++ b/web/src/components/ak-event-info.ts @@ -285,10 +285,12 @@ export class EventInfo extends AKElement { } renderEmailSent() { + let body = this.event.context.body as string; + body = body.replace("cid:logo.png", "/static/dist/assets/icons/icon_left_brand.png"); return html`
${msg("Email info:")}
${this.getEmailInfo(this.event.context)}
- + `; } diff --git a/website/docs/flow/stages/email/email_recovery.png b/website/docs/flow/stages/email/email_recovery.png index 1dc5dbbc4684cf4dc6448808c5c74f67ca82bb12..0bc14bafd1b7718e9f268158b081854fbc69cd0e 100644 GIT binary patch literal 25528 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 c$HsQMsMC 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 diff --git a/website/docs/flow/stages/email/index.mdx b/website/docs/flow/stages/email/index.mdx index 1064d8f13..a7751e295 100644 --- a/website/docs/flow/stages/email/index.mdx +++ b/website/docs/flow/stages/email/index.mdx @@ -25,6 +25,10 @@ return True You can also use custom email templates, to use your own design or layout. +:::info +Starting with authentik 2024.1, it is possible to create `.txt` files with the same name as the `.html` template. If a matching `.txt` file exists, the email sent will be a multipart email with both the text and HTML template. +::: + import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; @@ -81,13 +85,17 @@ Templates are rendered using Django's templating engine. The following variables - `user`: The pending user object. - `expires`: The timestamp when the token expires. + + ```html -{# This is how you can write comments which aren't rendered. #} {# Extend this -template from the base email template, which includes base layout and CSS. #} {% -extends "email/base.html" %} {# Load the internationalization module to -translate strings, and humanize to show date-time #} {% load i18n %} {% load -humanize %} {# The email/base.html template uses a single "content" block #} {% -block content %} +{# This is how you can write comments which aren't rendered. #} +{# Extend this template from the base email template, which includes base layout and CSS. #} +{% extends "email/base.html" %} +{# Load the internationalization module to translate strings, and humanize to show date-time #} +{% load i18n %} +{% load humanize %} +{# The email/base.html template uses a single "content" block #} +{% block content %} {% blocktrans with username=user.username %} Hi {{ username }}, {% @@ -99,9 +107,9 @@ block content %} @@ -130,8 +138,7 @@ block content %} href="{{ url }}" rel="noopener noreferrer" target="_blank" - >{% trans 'Reset - Password' %}{% trans 'Reset Password' %} @@ -145,9 +152,9 @@ block content %}
- {% blocktrans %} You recently requested to change your - password for you authentik account. Use the button below to - set a new password. {% endblocktrans %} + {% blocktrans %} + You recently requested to change your password for you authentik account. Use the button below to set a new password. + {% endblocktrans %}
- {% blocktrans with expires=expires|naturaltime %} If you did - not request a password change, please ignore this Email. The - link above is valid for {{ expires }}. {% endblocktrans %} + {% blocktrans with expires=expires|naturaltime %} + If you did not request a password change, please ignore this Email. The link above is valid for {{ expires }}. + {% endblocktrans %}
@@ -155,3 +162,5 @@ block content %} {% endblock %} ``` + + From 2521073dba2c7aa62b14a0859c1e717f3aee2d30 Mon Sep 17 00:00:00 2001 From: Jens L Date: Thu, 21 Dec 2023 14:43:40 +0100 Subject: [PATCH 18/21] providers/scim: use lock for sync (#7948) * providers/scim: use lock for sync Signed-off-by: Jens Langhammer * fix Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer --- authentik/providers/scim/api/providers.py | 22 ++++++-- authentik/providers/scim/models.py | 12 +++++ authentik/providers/scim/tasks.py | 4 ++ schema.yml | 17 +++++- .../admin-overview/charts/SyncStatusChart.ts | 19 +++---- .../providers/scim/SCIMProviderViewPage.ts | 53 ++++++++++++++----- web/xliff/de.xlf | 3 -- web/xliff/en.xlf | 4 -- web/xliff/es.xlf | 3 -- web/xliff/fr.xlf | 5 -- web/xliff/pl.xlf | 3 -- web/xliff/pseudo-LOCALE.xlf | 5 -- web/xliff/tr.xlf | 3 -- web/xliff/zh-Hans.xlf | 53 +++++++++---------- web/xliff/zh-Hant.xlf | 3 -- web/xliff/zh_TW.xlf | 5 -- 16 files changed, 123 insertions(+), 91 deletions(-) diff --git a/authentik/providers/scim/api/providers.py b/authentik/providers/scim/api/providers.py index 546e62e65..ddca8cfef 100644 --- a/authentik/providers/scim/api/providers.py +++ b/authentik/providers/scim/api/providers.py @@ -2,6 +2,7 @@ from django.utils.text import slugify from drf_spectacular.utils import OpenApiResponse, extend_schema from rest_framework.decorators import action +from rest_framework.fields import BooleanField from rest_framework.request import Request from rest_framework.response import Response from rest_framework.viewsets import ModelViewSet @@ -9,6 +10,7 @@ from rest_framework.viewsets import ModelViewSet from authentik.admin.api.tasks import TaskSerializer from authentik.core.api.providers import ProviderSerializer from authentik.core.api.used_by import UsedByMixin +from authentik.core.api.utils import PassiveSerializer from authentik.events.monitored_tasks import TaskInfo from authentik.providers.scim.models import SCIMProvider @@ -37,6 +39,13 @@ class SCIMProviderSerializer(ProviderSerializer): extra_kwargs = {} +class SCIMSyncStatusSerializer(PassiveSerializer): + """SCIM Provider sync status""" + + is_running = BooleanField(read_only=True) + tasks = TaskSerializer(many=True, read_only=True) + + class SCIMProviderViewSet(UsedByMixin, ModelViewSet): """SCIMProvider Viewset""" @@ -48,15 +57,18 @@ class SCIMProviderViewSet(UsedByMixin, ModelViewSet): @extend_schema( responses={ - 200: TaskSerializer(), + 200: SCIMSyncStatusSerializer(), 404: OpenApiResponse(description="Task not found"), } ) @action(methods=["GET"], detail=True, pagination_class=None, filter_backends=[]) def sync_status(self, request: Request, pk: int) -> Response: """Get provider's sync status""" - provider = self.get_object() + provider: SCIMProvider = self.get_object() task = TaskInfo.by_name(f"scim_sync:{slugify(provider.name)}") - if not task: - return Response(status=404) - return Response(TaskSerializer(task).data) + tasks = [task] if task else [] + status = { + "tasks": tasks, + "is_running": provider.sync_lock.locked(), + } + return Response(SCIMSyncStatusSerializer(status).data) diff --git a/authentik/providers/scim/models.py b/authentik/providers/scim/models.py index ac27288f3..b43a59375 100644 --- a/authentik/providers/scim/models.py +++ b/authentik/providers/scim/models.py @@ -1,11 +1,14 @@ """SCIM Provider models""" +from django.core.cache import cache from django.db import models from django.db.models import QuerySet from django.utils.translation import gettext_lazy as _ from guardian.shortcuts import get_anonymous_user +from redis.lock import Lock from rest_framework.serializers import Serializer from authentik.core.models import BackchannelProvider, Group, PropertyMapping, User, UserTypes +from authentik.providers.scim.clients import PAGE_TIMEOUT class SCIMProvider(BackchannelProvider): @@ -27,6 +30,15 @@ class SCIMProvider(BackchannelProvider): help_text=_("Property mappings used for group creation/updating."), ) + @property + def sync_lock(self) -> Lock: + """Redis lock for syncing SCIM to prevent multiple parallel syncs happening""" + return Lock( + cache.client.get_client(), + name=f"goauthentik.io/providers/scim/sync-{str(self.pk)}", + timeout=(60 * 60 * PAGE_TIMEOUT) * 3, + ) + def get_user_qs(self) -> QuerySet[User]: """Get queryset of all users with consistent ordering according to the provider's settings""" diff --git a/authentik/providers/scim/tasks.py b/authentik/providers/scim/tasks.py index c0c074ea4..7b16b293e 100644 --- a/authentik/providers/scim/tasks.py +++ b/authentik/providers/scim/tasks.py @@ -47,6 +47,10 @@ def scim_sync(self: MonitoredTask, provider_pk: int) -> None: ).first() if not provider: return + lock = provider.sync_lock + if lock.locked(): + LOGGER.debug("SCIM sync locked, skipping task", source=provider.name) + return self.set_uid(slugify(provider.name)) result = TaskResult(TaskResultStatus.SUCCESSFUL, []) result.messages.append(_("Starting full SCIM sync")) diff --git a/schema.yml b/schema.yml index fee6b8d3d..daded5c6d 100644 --- a/schema.yml +++ b/schema.yml @@ -17079,7 +17079,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Task' + $ref: '#/components/schemas/SCIMSyncStatus' description: '' '404': description: Task not found @@ -40645,6 +40645,21 @@ components: - name - token - url + SCIMSyncStatus: + type: object + description: SCIM Provider sync status + properties: + is_running: + type: boolean + readOnly: true + tasks: + type: array + items: + $ref: '#/components/schemas/Task' + readOnly: true + required: + - is_running + - tasks SMSDevice: type: object description: Serializer for sms authenticator devices diff --git a/web/src/admin/admin-overview/charts/SyncStatusChart.ts b/web/src/admin/admin-overview/charts/SyncStatusChart.ts index 28747d682..d9a3cce6c 100644 --- a/web/src/admin/admin-overview/charts/SyncStatusChart.ts +++ b/web/src/admin/admin-overview/charts/SyncStatusChart.ts @@ -93,15 +93,16 @@ export class LDAPSyncStatusChart extends AKChart { const health = await api.providersScimSyncStatusRetrieve({ id: element.pk, }); - - if (health.status !== TaskStatusEnum.Successful) { - sourceKey = "failed"; - } - const now = new Date().getTime(); - const maxDelta = 3600000; // 1 hour - if (!health || now - health.taskFinishTimestamp.getTime() > maxDelta) { - sourceKey = "unsynced"; - } + health.tasks.forEach((task) => { + if (task.status !== TaskStatusEnum.Successful) { + sourceKey = "failed"; + } + const now = new Date().getTime(); + const maxDelta = 3600000; // 1 hour + if (!health || now - task.taskFinishTimestamp.getTime() > maxDelta) { + sourceKey = "unsynced"; + } + }); } catch { sourceKey = "unsynced"; } diff --git a/web/src/admin/providers/scim/SCIMProviderViewPage.ts b/web/src/admin/providers/scim/SCIMProviderViewPage.ts index 3998c7c81..d745ed55e 100644 --- a/web/src/admin/providers/scim/SCIMProviderViewPage.ts +++ b/web/src/admin/providers/scim/SCIMProviderViewPage.ts @@ -10,7 +10,7 @@ import "@goauthentik/elements/Tabs"; import "@goauthentik/elements/buttons/ActionButton"; import "@goauthentik/elements/buttons/ModalButton"; -import { msg } from "@lit/localize"; +import { msg, str } from "@lit/localize"; import { CSSResult, TemplateResult, html } from "lit"; import { customElement, property, state } from "lit/decorators.js"; @@ -31,7 +31,8 @@ import { ProvidersApi, RbacPermissionsAssignedByUsersListModelEnum, SCIMProvider, - Task, + SCIMSyncStatus, + TaskStatusEnum, } from "@goauthentik/api"; @customElement("ak-provider-scim-view") @@ -54,7 +55,7 @@ export class SCIMProviderViewPage extends AKElement { provider?: SCIMProvider; @state() - syncState?: Task; + syncState?: SCIMSyncStatus; static get styles(): CSSResult[] { return [ @@ -128,6 +129,41 @@ export class SCIMProviderViewPage extends AKElement { `; } + renderSyncStatus(): TemplateResult { + if (!this.syncState) { + return html`${msg("No sync status.")}`; + } + if (this.syncState.isRunning) { + return html`${msg("Sync currently running.")}`; + } + if (this.syncState.tasks.length < 1) { + return html`${msg("Not synced yet.")}`; + } + return html` +
    + ${this.syncState.tasks.map((task) => { + let header = ""; + if (task.status === TaskStatusEnum.Warning) { + header = msg("Task finished with warnings"); + } else if (task.status === TaskStatusEnum.Error) { + header = msg("Task finished with errors"); + } else { + header = msg(str`Last sync: ${task.taskFinishTimestamp.toLocaleString()}`); + } + return html`
  • +

    ${task.taskName}

    +
      +
    • ${header}
    • + ${task.messages.map((m) => { + return html`
    • ${m}
    • `; + })} +
    +
  • `; + })} +
+ `; + } + renderTabOverview(): TemplateResult { if (!this.provider) { return html``; @@ -186,16 +222,7 @@ export class SCIMProviderViewPage extends AKElement {

${msg("Sync status")}

-
- ${this.syncState - ? html`
    - ${this.syncState.messages.map((m) => { - return html`
  • ${m}
  • `; - })} -
` - : html` ${msg("Sync not run yet.")} `} -
- +
${this.renderSyncStatus()}