Compare commits
36 Commits
providers/
...
providers/
| Author | SHA1 | Date | |
|---|---|---|---|
| faf8bf591f | |||
| 52115f9345 | |||
| b476551f13 | |||
| f9563c25cd | |||
| 0067e6e155 | |||
| ce183929d4 | |||
| 2fdf345271 | |||
| bbcf8418b4 | |||
| dc57be46f4 | |||
| d68b3ba516 | |||
| a9c46cfcbd | |||
| c50353ebf6 | |||
| db6be9e1b6 | |||
| a74892886d | |||
| 74cd4c2236 | |||
| ef3bd7e77b | |||
| 3f5ad2baa4 | |||
| 24805f087b | |||
| 9464b422a3 | |||
| da6d4ede51 | |||
| cecad5bfd3 | |||
| bc4b07d57b | |||
| e85d2d0096 | |||
| be1dd3103b | |||
| 5dfde5e1d3 | |||
| 7cb1e6d81e | |||
| d7c3129b1c | |||
| 2a1d33021b | |||
| f273e49ae6 | |||
| cc31957900 | |||
| b1ccdecc8e | |||
| 34031003a4 | |||
| 055e1d1025 | |||
| 59a804273e | |||
| bce70a1796 | |||
| e86c40a00c |
@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 2025.6.1
|
current_version = 2025.6.2
|
||||||
tag = True
|
tag = True
|
||||||
commit = True
|
commit = True
|
||||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))?
|
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))?
|
||||||
|
|||||||
2
.github/workflows/ci-main.yml
vendored
2
.github/workflows/ci-main.yml
vendored
@ -202,7 +202,7 @@ jobs:
|
|||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: web/dist
|
path: web/dist
|
||||||
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b
|
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b
|
||||||
- name: prepare web ui
|
- name: prepare web ui
|
||||||
if: steps.cache-web.outputs.cache-hit != 'true'
|
if: steps.cache-web.outputs.cache-hit != 'true'
|
||||||
working-directory: web
|
working-directory: web
|
||||||
|
|||||||
@ -77,7 +77,7 @@ RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
|
|||||||
# Stage 4: Download uv
|
# Stage 4: Download uv
|
||||||
FROM ghcr.io/astral-sh/uv:0.7.13 AS uv
|
FROM ghcr.io/astral-sh/uv:0.7.13 AS uv
|
||||||
# Stage 5: Base python image
|
# Stage 5: Base python image
|
||||||
FROM ghcr.io/goauthentik/fips-python:3.13.4-slim-bookworm-fips AS python-base
|
FROM ghcr.io/goauthentik/fips-python:3.13.5-slim-bookworm-fips AS python-base
|
||||||
|
|
||||||
ENV VENV_PATH="/ak-root/.venv" \
|
ENV VENV_PATH="/ak-root/.venv" \
|
||||||
PATH="/lifecycle:/ak-root/.venv/bin:$PATH" \
|
PATH="/lifecycle:/ak-root/.venv/bin:$PATH" \
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from os import environ
|
from os import environ
|
||||||
|
|
||||||
__version__ = "2025.6.1"
|
__version__ = "2025.6.2"
|
||||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,6 @@ class OAuth2Error(SentryIgnoredException):
|
|||||||
|
|
||||||
error: str
|
error: str
|
||||||
description: str
|
description: str
|
||||||
cause: str | None = None
|
|
||||||
|
|
||||||
def create_dict(self):
|
def create_dict(self):
|
||||||
"""Return error as dict for JSON Rendering"""
|
"""Return error as dict for JSON Rendering"""
|
||||||
@ -35,10 +34,6 @@ class OAuth2Error(SentryIgnoredException):
|
|||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
def with_cause(self, cause: str):
|
|
||||||
self.cause = cause
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
|
||||||
class RedirectUriError(OAuth2Error):
|
class RedirectUriError(OAuth2Error):
|
||||||
"""The request fails due to a missing, invalid, or mismatching
|
"""The request fails due to a missing, invalid, or mismatching
|
||||||
|
|||||||
@ -12,7 +12,7 @@ from authentik.core.tests.utils import create_test_admin_user, create_test_flow
|
|||||||
from authentik.events.models import Event, EventAction
|
from authentik.events.models import Event, EventAction
|
||||||
from authentik.lib.generators import generate_id
|
from authentik.lib.generators import generate_id
|
||||||
from authentik.lib.utils.time import timedelta_from_string
|
from authentik.lib.utils.time import timedelta_from_string
|
||||||
from authentik.providers.oauth2.constants import SCOPE_OFFLINE_ACCESS, SCOPE_OPENID, TOKEN_TYPE
|
from authentik.providers.oauth2.constants import TOKEN_TYPE
|
||||||
from authentik.providers.oauth2.errors import AuthorizeError, ClientIdError, RedirectUriError
|
from authentik.providers.oauth2.errors import AuthorizeError, ClientIdError, RedirectUriError
|
||||||
from authentik.providers.oauth2.models import (
|
from authentik.providers.oauth2.models import (
|
||||||
AccessToken,
|
AccessToken,
|
||||||
@ -43,7 +43,7 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
authorization_flow=create_test_flow(),
|
authorization_flow=create_test_flow(),
|
||||||
redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid/Foo")],
|
redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid/Foo")],
|
||||||
)
|
)
|
||||||
with self.assertRaises(AuthorizeError) as cm:
|
with self.assertRaises(AuthorizeError):
|
||||||
request = self.factory.get(
|
request = self.factory.get(
|
||||||
"/",
|
"/",
|
||||||
data={
|
data={
|
||||||
@ -53,7 +53,6 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
OAuthAuthorizationParams.from_request(request)
|
OAuthAuthorizationParams.from_request(request)
|
||||||
self.assertEqual(cm.exception.error, "unsupported_response_type")
|
|
||||||
|
|
||||||
def test_invalid_client_id(self):
|
def test_invalid_client_id(self):
|
||||||
"""Test invalid client ID"""
|
"""Test invalid client ID"""
|
||||||
@ -69,7 +68,7 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
authorization_flow=create_test_flow(),
|
authorization_flow=create_test_flow(),
|
||||||
redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid/Foo")],
|
redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid/Foo")],
|
||||||
)
|
)
|
||||||
with self.assertRaises(AuthorizeError) as cm:
|
with self.assertRaises(AuthorizeError):
|
||||||
request = self.factory.get(
|
request = self.factory.get(
|
||||||
"/",
|
"/",
|
||||||
data={
|
data={
|
||||||
@ -80,30 +79,19 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
OAuthAuthorizationParams.from_request(request)
|
OAuthAuthorizationParams.from_request(request)
|
||||||
self.assertEqual(cm.exception.error, "request_not_supported")
|
|
||||||
|
|
||||||
def test_invalid_redirect_uri_missing(self):
|
|
||||||
"""test missing redirect URI"""
|
|
||||||
OAuth2Provider.objects.create(
|
|
||||||
name=generate_id(),
|
|
||||||
client_id="test",
|
|
||||||
authorization_flow=create_test_flow(),
|
|
||||||
redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
|
|
||||||
)
|
|
||||||
with self.assertRaises(RedirectUriError) as cm:
|
|
||||||
request = self.factory.get("/", data={"response_type": "code", "client_id": "test"})
|
|
||||||
OAuthAuthorizationParams.from_request(request)
|
|
||||||
self.assertEqual(cm.exception.cause, "redirect_uri_missing")
|
|
||||||
|
|
||||||
def test_invalid_redirect_uri(self):
|
def test_invalid_redirect_uri(self):
|
||||||
"""test invalid redirect URI"""
|
"""test missing/invalid redirect URI"""
|
||||||
OAuth2Provider.objects.create(
|
OAuth2Provider.objects.create(
|
||||||
name=generate_id(),
|
name=generate_id(),
|
||||||
client_id="test",
|
client_id="test",
|
||||||
authorization_flow=create_test_flow(),
|
authorization_flow=create_test_flow(),
|
||||||
redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
|
redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
|
||||||
)
|
)
|
||||||
with self.assertRaises(RedirectUriError) as cm:
|
with self.assertRaises(RedirectUriError):
|
||||||
|
request = self.factory.get("/", data={"response_type": "code", "client_id": "test"})
|
||||||
|
OAuthAuthorizationParams.from_request(request)
|
||||||
|
with self.assertRaises(RedirectUriError):
|
||||||
request = self.factory.get(
|
request = self.factory.get(
|
||||||
"/",
|
"/",
|
||||||
data={
|
data={
|
||||||
@ -113,7 +101,6 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
OAuthAuthorizationParams.from_request(request)
|
OAuthAuthorizationParams.from_request(request)
|
||||||
self.assertEqual(cm.exception.cause, "redirect_uri_no_match")
|
|
||||||
|
|
||||||
def test_blocked_redirect_uri(self):
|
def test_blocked_redirect_uri(self):
|
||||||
"""test missing/invalid redirect URI"""
|
"""test missing/invalid redirect URI"""
|
||||||
@ -121,9 +108,9 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
name=generate_id(),
|
name=generate_id(),
|
||||||
client_id="test",
|
client_id="test",
|
||||||
authorization_flow=create_test_flow(),
|
authorization_flow=create_test_flow(),
|
||||||
redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "data:localhost")],
|
redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "data:local.invalid")],
|
||||||
)
|
)
|
||||||
with self.assertRaises(RedirectUriError) as cm:
|
with self.assertRaises(RedirectUriError):
|
||||||
request = self.factory.get(
|
request = self.factory.get(
|
||||||
"/",
|
"/",
|
||||||
data={
|
data={
|
||||||
@ -133,7 +120,6 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
OAuthAuthorizationParams.from_request(request)
|
OAuthAuthorizationParams.from_request(request)
|
||||||
self.assertEqual(cm.exception.cause, "redirect_uri_forbidden_scheme")
|
|
||||||
|
|
||||||
def test_invalid_redirect_uri_empty(self):
|
def test_invalid_redirect_uri_empty(self):
|
||||||
"""test missing/invalid redirect URI"""
|
"""test missing/invalid redirect URI"""
|
||||||
@ -143,6 +129,9 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
authorization_flow=create_test_flow(),
|
authorization_flow=create_test_flow(),
|
||||||
redirect_uris=[],
|
redirect_uris=[],
|
||||||
)
|
)
|
||||||
|
with self.assertRaises(RedirectUriError):
|
||||||
|
request = self.factory.get("/", data={"response_type": "code", "client_id": "test"})
|
||||||
|
OAuthAuthorizationParams.from_request(request)
|
||||||
request = self.factory.get(
|
request = self.factory.get(
|
||||||
"/",
|
"/",
|
||||||
data={
|
data={
|
||||||
@ -161,9 +150,12 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
name=generate_id(),
|
name=generate_id(),
|
||||||
client_id="test",
|
client_id="test",
|
||||||
authorization_flow=create_test_flow(),
|
authorization_flow=create_test_flow(),
|
||||||
redirect_uris=[RedirectURI(RedirectURIMatchingMode.REGEX, "http://local.invalid?")],
|
redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid?")],
|
||||||
)
|
)
|
||||||
with self.assertRaises(RedirectUriError) as cm:
|
with self.assertRaises(RedirectUriError):
|
||||||
|
request = self.factory.get("/", data={"response_type": "code", "client_id": "test"})
|
||||||
|
OAuthAuthorizationParams.from_request(request)
|
||||||
|
with self.assertRaises(RedirectUriError):
|
||||||
request = self.factory.get(
|
request = self.factory.get(
|
||||||
"/",
|
"/",
|
||||||
data={
|
data={
|
||||||
@ -173,7 +165,6 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
OAuthAuthorizationParams.from_request(request)
|
OAuthAuthorizationParams.from_request(request)
|
||||||
self.assertEqual(cm.exception.cause, "redirect_uri_no_match")
|
|
||||||
|
|
||||||
def test_redirect_uri_invalid_regex(self):
|
def test_redirect_uri_invalid_regex(self):
|
||||||
"""test missing/invalid redirect URI (invalid regex)"""
|
"""test missing/invalid redirect URI (invalid regex)"""
|
||||||
@ -181,9 +172,12 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
name=generate_id(),
|
name=generate_id(),
|
||||||
client_id="test",
|
client_id="test",
|
||||||
authorization_flow=create_test_flow(),
|
authorization_flow=create_test_flow(),
|
||||||
redirect_uris=[RedirectURI(RedirectURIMatchingMode.REGEX, "+")],
|
redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "+")],
|
||||||
)
|
)
|
||||||
with self.assertRaises(RedirectUriError) as cm:
|
with self.assertRaises(RedirectUriError):
|
||||||
|
request = self.factory.get("/", data={"response_type": "code", "client_id": "test"})
|
||||||
|
OAuthAuthorizationParams.from_request(request)
|
||||||
|
with self.assertRaises(RedirectUriError):
|
||||||
request = self.factory.get(
|
request = self.factory.get(
|
||||||
"/",
|
"/",
|
||||||
data={
|
data={
|
||||||
@ -193,22 +187,23 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
OAuthAuthorizationParams.from_request(request)
|
OAuthAuthorizationParams.from_request(request)
|
||||||
self.assertEqual(cm.exception.cause, "redirect_uri_no_match")
|
|
||||||
|
|
||||||
def test_redirect_uri_regex(self):
|
def test_empty_redirect_uri(self):
|
||||||
"""test valid redirect URI (regex)"""
|
"""test empty redirect URI (configure in provider)"""
|
||||||
OAuth2Provider.objects.create(
|
OAuth2Provider.objects.create(
|
||||||
name=generate_id(),
|
name=generate_id(),
|
||||||
client_id="test",
|
client_id="test",
|
||||||
authorization_flow=create_test_flow(),
|
authorization_flow=create_test_flow(),
|
||||||
redirect_uris=[RedirectURI(RedirectURIMatchingMode.REGEX, ".+")],
|
|
||||||
)
|
)
|
||||||
|
with self.assertRaises(RedirectUriError):
|
||||||
|
request = self.factory.get("/", data={"response_type": "code", "client_id": "test"})
|
||||||
|
OAuthAuthorizationParams.from_request(request)
|
||||||
request = self.factory.get(
|
request = self.factory.get(
|
||||||
"/",
|
"/",
|
||||||
data={
|
data={
|
||||||
"response_type": "code",
|
"response_type": "code",
|
||||||
"client_id": "test",
|
"client_id": "test",
|
||||||
"redirect_uri": "http://foo.bar.baz",
|
"redirect_uri": "http://localhost",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
OAuthAuthorizationParams.from_request(request)
|
OAuthAuthorizationParams.from_request(request)
|
||||||
@ -263,7 +258,7 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
GrantTypes.IMPLICIT,
|
GrantTypes.IMPLICIT,
|
||||||
)
|
)
|
||||||
# Implicit without openid scope
|
# Implicit without openid scope
|
||||||
with self.assertRaises(AuthorizeError) as cm:
|
with self.assertRaises(AuthorizeError):
|
||||||
request = self.factory.get(
|
request = self.factory.get(
|
||||||
"/",
|
"/",
|
||||||
data={
|
data={
|
||||||
@ -290,7 +285,7 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
OAuthAuthorizationParams.from_request(request).grant_type, GrantTypes.HYBRID
|
OAuthAuthorizationParams.from_request(request).grant_type, GrantTypes.HYBRID
|
||||||
)
|
)
|
||||||
with self.assertRaises(AuthorizeError) as cm:
|
with self.assertRaises(AuthorizeError):
|
||||||
request = self.factory.get(
|
request = self.factory.get(
|
||||||
"/",
|
"/",
|
||||||
data={
|
data={
|
||||||
@ -300,7 +295,6 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
OAuthAuthorizationParams.from_request(request)
|
OAuthAuthorizationParams.from_request(request)
|
||||||
self.assertEqual(cm.exception.error, "unsupported_response_type")
|
|
||||||
|
|
||||||
def test_full_code(self):
|
def test_full_code(self):
|
||||||
"""Test full authorization"""
|
"""Test full authorization"""
|
||||||
@ -393,8 +387,7 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
response.url,
|
response.url,
|
||||||
(
|
(
|
||||||
f"http://localhost#access_token={token.token}"
|
f"http://localhost#id_token={provider.encode(token.id_token.to_dict())}"
|
||||||
f"&id_token={provider.encode(token.id_token.to_dict())}"
|
|
||||||
f"&token_type={TOKEN_TYPE}"
|
f"&token_type={TOKEN_TYPE}"
|
||||||
f"&expires_in={int(expires)}&state={state}"
|
f"&expires_in={int(expires)}&state={state}"
|
||||||
),
|
),
|
||||||
@ -569,7 +562,6 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
"url": "http://localhost",
|
"url": "http://localhost",
|
||||||
"title": f"Redirecting to {app.name}...",
|
"title": f"Redirecting to {app.name}...",
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"access_token": token.token,
|
|
||||||
"id_token": provider.encode(token.id_token.to_dict()),
|
"id_token": provider.encode(token.id_token.to_dict()),
|
||||||
"token_type": TOKEN_TYPE,
|
"token_type": TOKEN_TYPE,
|
||||||
"expires_in": "3600",
|
"expires_in": "3600",
|
||||||
@ -621,54 +613,3 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_openid_missing_invalid(self):
|
|
||||||
"""test request requiring an OpenID scope to be set"""
|
|
||||||
OAuth2Provider.objects.create(
|
|
||||||
name=generate_id(),
|
|
||||||
client_id="test",
|
|
||||||
authorization_flow=create_test_flow(),
|
|
||||||
redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://localhost")],
|
|
||||||
)
|
|
||||||
request = self.factory.get(
|
|
||||||
"/",
|
|
||||||
data={
|
|
||||||
"response_type": "id_token",
|
|
||||||
"client_id": "test",
|
|
||||||
"redirect_uri": "http://localhost",
|
|
||||||
"scope": "",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
with self.assertRaises(AuthorizeError) as cm:
|
|
||||||
OAuthAuthorizationParams.from_request(request)
|
|
||||||
self.assertEqual(cm.exception.cause, "scope_openid_missing")
|
|
||||||
|
|
||||||
@apply_blueprint("system/providers-oauth2.yaml")
|
|
||||||
def test_offline_access_invalid(self):
|
|
||||||
"""test request for offline_access with invalid response type"""
|
|
||||||
provider = OAuth2Provider.objects.create(
|
|
||||||
name=generate_id(),
|
|
||||||
client_id="test",
|
|
||||||
authorization_flow=create_test_flow(),
|
|
||||||
redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://localhost")],
|
|
||||||
)
|
|
||||||
provider.property_mappings.set(
|
|
||||||
ScopeMapping.objects.filter(
|
|
||||||
managed__in=[
|
|
||||||
"goauthentik.io/providers/oauth2/scope-openid",
|
|
||||||
"goauthentik.io/providers/oauth2/scope-offline_access",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
request = self.factory.get(
|
|
||||||
"/",
|
|
||||||
data={
|
|
||||||
"response_type": "id_token",
|
|
||||||
"client_id": "test",
|
|
||||||
"redirect_uri": "http://localhost",
|
|
||||||
"scope": f"{SCOPE_OPENID} {SCOPE_OFFLINE_ACCESS}",
|
|
||||||
"nonce": generate_id(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
parsed = OAuthAuthorizationParams.from_request(request)
|
|
||||||
self.assertNotIn(SCOPE_OFFLINE_ACCESS, parsed.scope)
|
|
||||||
|
|||||||
@ -150,12 +150,12 @@ class OAuthAuthorizationParams:
|
|||||||
self.check_redirect_uri()
|
self.check_redirect_uri()
|
||||||
self.check_grant()
|
self.check_grant()
|
||||||
self.check_scope(github_compat)
|
self.check_scope(github_compat)
|
||||||
self.check_nonce()
|
|
||||||
self.check_code_challenge()
|
|
||||||
if self.request:
|
if self.request:
|
||||||
raise AuthorizeError(
|
raise AuthorizeError(
|
||||||
self.redirect_uri, "request_not_supported", self.grant_type, self.state
|
self.redirect_uri, "request_not_supported", self.grant_type, self.state
|
||||||
)
|
)
|
||||||
|
self.check_nonce()
|
||||||
|
self.check_code_challenge()
|
||||||
|
|
||||||
def check_grant(self):
|
def check_grant(self):
|
||||||
"""Check grant"""
|
"""Check grant"""
|
||||||
@ -190,7 +190,7 @@ class OAuthAuthorizationParams:
|
|||||||
allowed_redirect_urls = self.provider.redirect_uris
|
allowed_redirect_urls = self.provider.redirect_uris
|
||||||
if not self.redirect_uri:
|
if not self.redirect_uri:
|
||||||
LOGGER.warning("Missing redirect uri.")
|
LOGGER.warning("Missing redirect uri.")
|
||||||
raise RedirectUriError("", allowed_redirect_urls).with_cause("redirect_uri_missing")
|
raise RedirectUriError("", allowed_redirect_urls)
|
||||||
|
|
||||||
if len(allowed_redirect_urls) < 1:
|
if len(allowed_redirect_urls) < 1:
|
||||||
LOGGER.info("Setting redirect for blank redirect_uris", redirect=self.redirect_uri)
|
LOGGER.info("Setting redirect for blank redirect_uris", redirect=self.redirect_uri)
|
||||||
@ -219,14 +219,10 @@ class OAuthAuthorizationParams:
|
|||||||
provider=self.provider,
|
provider=self.provider,
|
||||||
)
|
)
|
||||||
if not match_found:
|
if not match_found:
|
||||||
raise RedirectUriError(self.redirect_uri, allowed_redirect_urls).with_cause(
|
raise RedirectUriError(self.redirect_uri, allowed_redirect_urls)
|
||||||
"redirect_uri_no_match"
|
|
||||||
)
|
|
||||||
# Check against forbidden schemes
|
# Check against forbidden schemes
|
||||||
if urlparse(self.redirect_uri).scheme in FORBIDDEN_URI_SCHEMES:
|
if urlparse(self.redirect_uri).scheme in FORBIDDEN_URI_SCHEMES:
|
||||||
raise RedirectUriError(self.redirect_uri, allowed_redirect_urls).with_cause(
|
raise RedirectUriError(self.redirect_uri, allowed_redirect_urls)
|
||||||
"redirect_uri_forbidden_scheme"
|
|
||||||
)
|
|
||||||
|
|
||||||
def check_scope(self, github_compat=False):
|
def check_scope(self, github_compat=False):
|
||||||
"""Ensure openid scope is set in Hybrid flows, or when requesting an id_token"""
|
"""Ensure openid scope is set in Hybrid flows, or when requesting an id_token"""
|
||||||
@ -255,9 +251,7 @@ class OAuthAuthorizationParams:
|
|||||||
or self.response_type in [ResponseTypes.ID_TOKEN, ResponseTypes.ID_TOKEN_TOKEN]
|
or self.response_type in [ResponseTypes.ID_TOKEN, ResponseTypes.ID_TOKEN_TOKEN]
|
||||||
):
|
):
|
||||||
LOGGER.warning("Missing 'openid' scope.")
|
LOGGER.warning("Missing 'openid' scope.")
|
||||||
raise AuthorizeError(
|
raise AuthorizeError(self.redirect_uri, "invalid_scope", self.grant_type, self.state)
|
||||||
self.redirect_uri, "invalid_scope", self.grant_type, self.state
|
|
||||||
).with_cause("scope_openid_missing")
|
|
||||||
if SCOPE_OFFLINE_ACCESS in self.scope:
|
if SCOPE_OFFLINE_ACCESS in self.scope:
|
||||||
# https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess
|
# https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess
|
||||||
# Don't explicitly request consent with offline_access, as the spec allows for
|
# Don't explicitly request consent with offline_access, as the spec allows for
|
||||||
@ -292,9 +286,7 @@ class OAuthAuthorizationParams:
|
|||||||
return
|
return
|
||||||
if not self.nonce:
|
if not self.nonce:
|
||||||
LOGGER.warning("Missing nonce for OpenID Request")
|
LOGGER.warning("Missing nonce for OpenID Request")
|
||||||
raise AuthorizeError(
|
raise AuthorizeError(self.redirect_uri, "invalid_request", self.grant_type, self.state)
|
||||||
self.redirect_uri, "invalid_request", self.grant_type, self.state
|
|
||||||
).with_cause("none_missing")
|
|
||||||
|
|
||||||
def check_code_challenge(self):
|
def check_code_challenge(self):
|
||||||
"""PKCE validation of the transformation method."""
|
"""PKCE validation of the transformation method."""
|
||||||
@ -353,10 +345,10 @@ class AuthorizationFlowInitView(PolicyAccessView):
|
|||||||
self.request, github_compat=self.github_compat
|
self.request, github_compat=self.github_compat
|
||||||
)
|
)
|
||||||
except AuthorizeError as error:
|
except AuthorizeError as error:
|
||||||
LOGGER.warning(error.description, redirect_uri=error.redirect_uri, cause=error.cause)
|
LOGGER.warning(error.description, redirect_uri=error.redirect_uri)
|
||||||
raise RequestValidationError(error.get_response(self.request)) from None
|
raise RequestValidationError(error.get_response(self.request)) from None
|
||||||
except OAuth2Error as error:
|
except OAuth2Error as error:
|
||||||
LOGGER.warning(error.description, cause=error.cause)
|
LOGGER.warning(error.description)
|
||||||
raise RequestValidationError(
|
raise RequestValidationError(
|
||||||
bad_request_message(self.request, error.description, title=error.error)
|
bad_request_message(self.request, error.description, title=error.error)
|
||||||
) from None
|
) from None
|
||||||
@ -638,7 +630,6 @@ class OAuthFulfillmentStage(StageView):
|
|||||||
if self.params.response_type in [
|
if self.params.response_type in [
|
||||||
ResponseTypes.ID_TOKEN_TOKEN,
|
ResponseTypes.ID_TOKEN_TOKEN,
|
||||||
ResponseTypes.CODE_ID_TOKEN_TOKEN,
|
ResponseTypes.CODE_ID_TOKEN_TOKEN,
|
||||||
ResponseTypes.ID_TOKEN,
|
|
||||||
ResponseTypes.CODE_TOKEN,
|
ResponseTypes.CODE_TOKEN,
|
||||||
]:
|
]:
|
||||||
query_fragment["access_token"] = token.token
|
query_fragment["access_token"] = token.token
|
||||||
|
|||||||
@ -190,6 +190,7 @@ class SAMLProviderSerializer(ProviderSerializer):
|
|||||||
"sign_response",
|
"sign_response",
|
||||||
"sp_binding",
|
"sp_binding",
|
||||||
"default_relay_state",
|
"default_relay_state",
|
||||||
|
"default_name_id_policy",
|
||||||
"url_download_metadata",
|
"url_download_metadata",
|
||||||
"url_sso_post",
|
"url_sso_post",
|
||||||
"url_sso_redirect",
|
"url_sso_redirect",
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
# Generated by Django 5.1.11 on 2025-06-18 09:27
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("authentik_providers_saml", "0018_alter_samlprovider_acs_url"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="samlprovider",
|
||||||
|
name="default_name_id_policy",
|
||||||
|
field=models.TextField(
|
||||||
|
choices=[
|
||||||
|
("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", "Email"),
|
||||||
|
("urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", "Persistent"),
|
||||||
|
("urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName", "X509"),
|
||||||
|
(
|
||||||
|
"urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName",
|
||||||
|
"Windows",
|
||||||
|
),
|
||||||
|
("urn:oasis:names:tc:SAML:2.0:nameid-format:transient", "Transient"),
|
||||||
|
("urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", "Unspecified"),
|
||||||
|
],
|
||||||
|
default="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -12,6 +12,7 @@ from authentik.core.models import PropertyMapping, Provider
|
|||||||
from authentik.crypto.models import CertificateKeyPair
|
from authentik.crypto.models import CertificateKeyPair
|
||||||
from authentik.lib.models import DomainlessURLValidator
|
from authentik.lib.models import DomainlessURLValidator
|
||||||
from authentik.lib.utils.time import timedelta_string_validator
|
from authentik.lib.utils.time import timedelta_string_validator
|
||||||
|
from authentik.sources.saml.models import SAMLNameIDPolicy
|
||||||
from authentik.sources.saml.processors.constants import (
|
from authentik.sources.saml.processors.constants import (
|
||||||
DSA_SHA1,
|
DSA_SHA1,
|
||||||
ECDSA_SHA1,
|
ECDSA_SHA1,
|
||||||
@ -179,6 +180,9 @@ class SAMLProvider(Provider):
|
|||||||
default_relay_state = models.TextField(
|
default_relay_state = models.TextField(
|
||||||
default="", blank=True, help_text=_("Default relay_state value for IDP-initiated logins")
|
default="", blank=True, help_text=_("Default relay_state value for IDP-initiated logins")
|
||||||
)
|
)
|
||||||
|
default_name_id_policy = models.TextField(
|
||||||
|
choices=SAMLNameIDPolicy.choices, default=SAMLNameIDPolicy.UNSPECIFIED
|
||||||
|
)
|
||||||
|
|
||||||
sign_assertion = models.BooleanField(default=True)
|
sign_assertion = models.BooleanField(default=True)
|
||||||
sign_response = models.BooleanField(default=False)
|
sign_response = models.BooleanField(default=False)
|
||||||
|
|||||||
@ -205,6 +205,13 @@ class AssertionProcessor:
|
|||||||
def get_name_id(self) -> Element:
|
def get_name_id(self) -> Element:
|
||||||
"""Get NameID Element"""
|
"""Get NameID Element"""
|
||||||
name_id = Element(f"{{{NS_SAML_ASSERTION}}}NameID")
|
name_id = Element(f"{{{NS_SAML_ASSERTION}}}NameID")
|
||||||
|
# For requests that don't specify a NameIDPolicy, check if we
|
||||||
|
# can fall back to the provider default
|
||||||
|
if (
|
||||||
|
self.auth_n_request.name_id_policy == SAML_NAME_ID_FORMAT_UNSPECIFIED
|
||||||
|
and self.provider.default_name_id_policy != SAML_NAME_ID_FORMAT_UNSPECIFIED
|
||||||
|
):
|
||||||
|
self.auth_n_request.name_id_policy = self.provider.default_name_id_policy
|
||||||
name_id.attrib["Format"] = self.auth_n_request.name_id_policy
|
name_id.attrib["Format"] = self.auth_n_request.name_id_policy
|
||||||
# persistent is used as a fallback, so always generate it
|
# persistent is used as a fallback, so always generate it
|
||||||
persistent = self.http_request.user.uid
|
persistent = self.http_request.user.uid
|
||||||
|
|||||||
@ -13,6 +13,7 @@ from authentik.lib.xml import lxml_from_string
|
|||||||
from authentik.providers.saml.exceptions import CannotHandleAssertion
|
from authentik.providers.saml.exceptions import CannotHandleAssertion
|
||||||
from authentik.providers.saml.models import SAMLProvider
|
from authentik.providers.saml.models import SAMLProvider
|
||||||
from authentik.providers.saml.utils.encoding import decode_base64_and_inflate
|
from authentik.providers.saml.utils.encoding import decode_base64_and_inflate
|
||||||
|
from authentik.sources.saml.models import SAMLNameIDPolicy
|
||||||
from authentik.sources.saml.processors.constants import (
|
from authentik.sources.saml.processors.constants import (
|
||||||
DSA_SHA1,
|
DSA_SHA1,
|
||||||
NS_MAP,
|
NS_MAP,
|
||||||
@ -175,7 +176,9 @@ class AuthNRequestParser:
|
|||||||
|
|
||||||
def idp_initiated(self) -> AuthNRequest:
|
def idp_initiated(self) -> AuthNRequest:
|
||||||
"""Create IdP Initiated AuthNRequest"""
|
"""Create IdP Initiated AuthNRequest"""
|
||||||
relay_state = None
|
request = AuthNRequest(relay_state=None)
|
||||||
if self.provider.default_relay_state != "":
|
if self.provider.default_relay_state != "":
|
||||||
relay_state = self.provider.default_relay_state
|
request.relay_state = self.provider.default_relay_state
|
||||||
return AuthNRequest(relay_state=relay_state)
|
if self.provider.default_name_id_policy != SAMLNameIDPolicy.UNSPECIFIED:
|
||||||
|
request.name_id_policy = self.provider.default_name_id_policy
|
||||||
|
return request
|
||||||
|
|||||||
@ -13,6 +13,7 @@ from authentik.crypto.models import CertificateKeyPair
|
|||||||
from authentik.flows.models import Flow
|
from authentik.flows.models import Flow
|
||||||
from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider
|
from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider
|
||||||
from authentik.providers.saml.utils.encoding import PEM_FOOTER, PEM_HEADER
|
from authentik.providers.saml.utils.encoding import PEM_FOOTER, PEM_HEADER
|
||||||
|
from authentik.sources.saml.models import SAMLNameIDPolicy
|
||||||
from authentik.sources.saml.processors.constants import (
|
from authentik.sources.saml.processors.constants import (
|
||||||
NS_MAP,
|
NS_MAP,
|
||||||
NS_SAML_METADATA,
|
NS_SAML_METADATA,
|
||||||
@ -46,6 +47,7 @@ class ServiceProviderMetadata:
|
|||||||
|
|
||||||
auth_n_request_signed: bool
|
auth_n_request_signed: bool
|
||||||
assertion_signed: bool
|
assertion_signed: bool
|
||||||
|
name_id_policy: SAMLNameIDPolicy
|
||||||
|
|
||||||
signing_keypair: CertificateKeyPair | None = None
|
signing_keypair: CertificateKeyPair | None = None
|
||||||
|
|
||||||
@ -60,6 +62,7 @@ class ServiceProviderMetadata:
|
|||||||
provider.issuer = self.entity_id
|
provider.issuer = self.entity_id
|
||||||
provider.sp_binding = self.acs_binding
|
provider.sp_binding = self.acs_binding
|
||||||
provider.acs_url = self.acs_location
|
provider.acs_url = self.acs_location
|
||||||
|
provider.default_name_id_policy = self.name_id_policy
|
||||||
if self.signing_keypair and self.auth_n_request_signed:
|
if self.signing_keypair and self.auth_n_request_signed:
|
||||||
self.signing_keypair.name = f"Provider {name} - SAML Signing Certificate"
|
self.signing_keypair.name = f"Provider {name} - SAML Signing Certificate"
|
||||||
self.signing_keypair.save()
|
self.signing_keypair.save()
|
||||||
@ -148,6 +151,11 @@ class ServiceProviderMetadataParser:
|
|||||||
if signing_keypair:
|
if signing_keypair:
|
||||||
self.check_signature(root, signing_keypair)
|
self.check_signature(root, signing_keypair)
|
||||||
|
|
||||||
|
name_id_format = descriptor.findall(f"{{{NS_SAML_METADATA}}}NameIDFormat")
|
||||||
|
name_id_policy = SAMLNameIDPolicy.UNSPECIFIED
|
||||||
|
if len(name_id_format) > 0:
|
||||||
|
name_id_policy = SAMLNameIDPolicy(name_id_format[0].text)
|
||||||
|
|
||||||
return ServiceProviderMetadata(
|
return ServiceProviderMetadata(
|
||||||
entity_id=entity_id,
|
entity_id=entity_id,
|
||||||
acs_binding=acs_binding,
|
acs_binding=acs_binding,
|
||||||
@ -155,4 +163,5 @@ class ServiceProviderMetadataParser:
|
|||||||
auth_n_request_signed=auth_n_request_signed,
|
auth_n_request_signed=auth_n_request_signed,
|
||||||
assertion_signed=assertion_signed,
|
assertion_signed=assertion_signed,
|
||||||
signing_keypair=signing_keypair,
|
signing_keypair=signing_keypair,
|
||||||
|
name_id_policy=name_id_policy,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
cacheDuration="PT604800S"
|
cacheDuration="PT604800S"
|
||||||
entityID="http://localhost:8080/saml/metadata">
|
entityID="http://localhost:8080/saml/metadata">
|
||||||
<md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
<md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
||||||
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
|
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
|
||||||
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
||||||
Location="http://localhost:8080/saml/acs"
|
Location="http://localhost:8080/saml/acs"
|
||||||
index="1" />
|
index="1" />
|
||||||
|
|||||||
@ -14,6 +14,7 @@ from authentik.lib.xml import lxml_from_string
|
|||||||
from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider
|
from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider
|
||||||
from authentik.providers.saml.processors.metadata import MetadataProcessor
|
from authentik.providers.saml.processors.metadata import MetadataProcessor
|
||||||
from authentik.providers.saml.processors.metadata_parser import ServiceProviderMetadataParser
|
from authentik.providers.saml.processors.metadata_parser import ServiceProviderMetadataParser
|
||||||
|
from authentik.sources.saml.models import SAMLNameIDPolicy
|
||||||
from authentik.sources.saml.processors.constants import ECDSA_SHA256, NS_MAP, NS_SAML_METADATA
|
from authentik.sources.saml.processors.constants import ECDSA_SHA256, NS_MAP, NS_SAML_METADATA
|
||||||
|
|
||||||
|
|
||||||
@ -86,6 +87,7 @@ class TestServiceProviderMetadataParser(TestCase):
|
|||||||
self.assertEqual(provider.acs_url, "http://localhost:8080/saml/acs")
|
self.assertEqual(provider.acs_url, "http://localhost:8080/saml/acs")
|
||||||
self.assertEqual(provider.issuer, "http://localhost:8080/saml/metadata")
|
self.assertEqual(provider.issuer, "http://localhost:8080/saml/metadata")
|
||||||
self.assertEqual(provider.sp_binding, SAMLBindings.POST)
|
self.assertEqual(provider.sp_binding, SAMLBindings.POST)
|
||||||
|
self.assertEqual(provider.default_name_id_policy, SAMLNameIDPolicy.EMAIL)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
len(provider.property_mappings.all()),
|
len(provider.property_mappings.all()),
|
||||||
len(SAMLPropertyMapping.objects.exclude(managed__isnull=True)),
|
len(SAMLPropertyMapping.objects.exclude(managed__isnull=True)),
|
||||||
|
|||||||
@ -166,6 +166,7 @@ SPECTACULAR_SETTINGS = {
|
|||||||
"UserVerificationEnum": "authentik.stages.authenticator_webauthn.models.UserVerification",
|
"UserVerificationEnum": "authentik.stages.authenticator_webauthn.models.UserVerification",
|
||||||
"UserTypeEnum": "authentik.core.models.UserTypes",
|
"UserTypeEnum": "authentik.core.models.UserTypes",
|
||||||
"OutgoingSyncDeleteAction": "authentik.lib.sync.outgoing.models.OutgoingSyncDeleteAction",
|
"OutgoingSyncDeleteAction": "authentik.lib.sync.outgoing.models.OutgoingSyncDeleteAction",
|
||||||
|
"SAMLNameIDPolicyEnum": "authentik.sources.saml.models.SAMLNameIDPolicy",
|
||||||
},
|
},
|
||||||
"ENUM_ADD_EXPLICIT_BLANK_NULL_CHOICE": False,
|
"ENUM_ADD_EXPLICIT_BLANK_NULL_CHOICE": False,
|
||||||
"ENUM_GENERATE_CHOICE_DESCRIPTION": False,
|
"ENUM_GENERATE_CHOICE_DESCRIPTION": False,
|
||||||
|
|||||||
@ -0,0 +1,32 @@
|
|||||||
|
# Generated by Django 5.1.11 on 2025-06-18 09:27
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("authentik_sources_saml", "0019_migrate_usersamlsourceconnection_identifier"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="samlsource",
|
||||||
|
name="name_id_policy",
|
||||||
|
field=models.TextField(
|
||||||
|
choices=[
|
||||||
|
("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", "Email"),
|
||||||
|
("urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", "Persistent"),
|
||||||
|
("urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName", "X509"),
|
||||||
|
(
|
||||||
|
"urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName",
|
||||||
|
"Windows",
|
||||||
|
),
|
||||||
|
("urn:oasis:names:tc:SAML:2.0:nameid-format:transient", "Transient"),
|
||||||
|
("urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", "Unspecified"),
|
||||||
|
],
|
||||||
|
default="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
|
||||||
|
help_text="NameID Policy sent to the IdP. Can be unset, in which case no Policy is sent.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -39,6 +39,7 @@ from authentik.sources.saml.processors.constants import (
|
|||||||
SAML_NAME_ID_FORMAT_EMAIL,
|
SAML_NAME_ID_FORMAT_EMAIL,
|
||||||
SAML_NAME_ID_FORMAT_PERSISTENT,
|
SAML_NAME_ID_FORMAT_PERSISTENT,
|
||||||
SAML_NAME_ID_FORMAT_TRANSIENT,
|
SAML_NAME_ID_FORMAT_TRANSIENT,
|
||||||
|
SAML_NAME_ID_FORMAT_UNSPECIFIED,
|
||||||
SAML_NAME_ID_FORMAT_WINDOWS,
|
SAML_NAME_ID_FORMAT_WINDOWS,
|
||||||
SAML_NAME_ID_FORMAT_X509,
|
SAML_NAME_ID_FORMAT_X509,
|
||||||
SHA1,
|
SHA1,
|
||||||
@ -73,6 +74,7 @@ class SAMLNameIDPolicy(models.TextChoices):
|
|||||||
X509 = SAML_NAME_ID_FORMAT_X509
|
X509 = SAML_NAME_ID_FORMAT_X509
|
||||||
WINDOWS = SAML_NAME_ID_FORMAT_WINDOWS
|
WINDOWS = SAML_NAME_ID_FORMAT_WINDOWS
|
||||||
TRANSIENT = SAML_NAME_ID_FORMAT_TRANSIENT
|
TRANSIENT = SAML_NAME_ID_FORMAT_TRANSIENT
|
||||||
|
UNSPECIFIED = SAML_NAME_ID_FORMAT_UNSPECIFIED
|
||||||
|
|
||||||
|
|
||||||
class SAMLSource(Source):
|
class SAMLSource(Source):
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
"$schema": "http://json-schema.org/draft-07/schema",
|
"$schema": "http://json-schema.org/draft-07/schema",
|
||||||
"$id": "https://goauthentik.io/blueprints/schema.json",
|
"$id": "https://goauthentik.io/blueprints/schema.json",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "authentik 2025.6.1 Blueprint schema",
|
"title": "authentik 2025.6.2 Blueprint schema",
|
||||||
"required": [
|
"required": [
|
||||||
"version",
|
"version",
|
||||||
"entries"
|
"entries"
|
||||||
@ -9233,6 +9233,18 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"title": "Default relay state",
|
"title": "Default relay state",
|
||||||
"description": "Default relay_state value for IDP-initiated logins"
|
"description": "Default relay_state value for IDP-initiated logins"
|
||||||
|
},
|
||||||
|
"default_name_id_policy": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
|
||||||
|
"urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
|
||||||
|
"urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName",
|
||||||
|
"urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName",
|
||||||
|
"urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
|
||||||
|
"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
|
||||||
|
],
|
||||||
|
"title": "Default name id policy"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"required": []
|
||||||
@ -11655,7 +11667,8 @@
|
|||||||
"urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
|
"urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
|
||||||
"urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName",
|
"urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName",
|
||||||
"urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName",
|
"urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName",
|
||||||
"urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
|
"urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
|
||||||
|
"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
|
||||||
],
|
],
|
||||||
"title": "Name id policy",
|
"title": "Name id policy",
|
||||||
"description": "NameID Policy sent to the IdP. Can be unset, in which case no Policy is sent."
|
"description": "NameID Policy sent to the IdP. Can be unset, in which case no Policy is sent."
|
||||||
|
|||||||
@ -31,7 +31,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- redis:/data
|
- redis:/data
|
||||||
server:
|
server:
|
||||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.1}
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.2}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: server
|
command: server
|
||||||
environment:
|
environment:
|
||||||
@ -55,7 +55,7 @@ services:
|
|||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
worker:
|
worker:
|
||||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.1}
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.2}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: worker
|
command: worker
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
4
go.mod
4
go.mod
@ -18,7 +18,7 @@ require (
|
|||||||
github.com/gorilla/sessions v1.4.0
|
github.com/gorilla/sessions v1.4.0
|
||||||
github.com/gorilla/websocket v1.5.3
|
github.com/gorilla/websocket v1.5.3
|
||||||
github.com/grafana/pyroscope-go v1.2.2
|
github.com/grafana/pyroscope-go v1.2.2
|
||||||
github.com/jellydator/ttlcache/v3 v3.3.0
|
github.com/jellydator/ttlcache/v3 v3.4.0
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
|
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
|
||||||
github.com/pires/go-proxyproto v0.8.1
|
github.com/pires/go-proxyproto v0.8.1
|
||||||
@ -29,7 +29,7 @@ require (
|
|||||||
github.com/spf13/cobra v1.9.1
|
github.com/spf13/cobra v1.9.1
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/wwt/guac v1.3.2
|
github.com/wwt/guac v1.3.2
|
||||||
goauthentik.io/api/v3 v3.2025061.2
|
goauthentik.io/api/v3 v3.2025062.1
|
||||||
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
|
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
|
||||||
golang.org/x/oauth2 v0.30.0
|
golang.org/x/oauth2 v0.30.0
|
||||||
golang.org/x/sync v0.15.0
|
golang.org/x/sync v0.15.0
|
||||||
|
|||||||
8
go.sum
8
go.sum
@ -203,8 +203,8 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6
|
|||||||
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
|
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
|
||||||
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
|
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
|
||||||
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||||
github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc=
|
github.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP4mnWdTY=
|
||||||
github.com/jellydator/ttlcache/v3 v3.3.0/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw=
|
github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4=
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
@ -298,8 +298,8 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y
|
|||||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
goauthentik.io/api/v3 v3.2025061.2 h1:bKmrl82Gz6J8lz3f+QIH9g+MEkl3MvkMXF34GktesA0=
|
goauthentik.io/api/v3 v3.2025062.1 h1:spvILDpDDWJNO3pM6QGqmryx6NvSchr1E8H60J/XUCA=
|
||||||
goauthentik.io/api/v3 v3.2025061.2/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
goauthentik.io/api/v3 v3.2025062.1/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-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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
|||||||
@ -33,4 +33,4 @@ func UserAgent() string {
|
|||||||
return fmt.Sprintf("authentik@%s", FullVersion())
|
return fmt.Sprintf("authentik@%s", FullVersion())
|
||||||
}
|
}
|
||||||
|
|
||||||
const VERSION = "2025.6.1"
|
const VERSION = "2025.6.2"
|
||||||
|
|||||||
@ -26,7 +26,7 @@ Parameters:
|
|||||||
Description: authentik Docker image
|
Description: authentik Docker image
|
||||||
AuthentikVersion:
|
AuthentikVersion:
|
||||||
Type: String
|
Type: String
|
||||||
Default: 2025.6.1
|
Default: 2025.6.2
|
||||||
Description: authentik Docker image tag
|
Description: authentik Docker image tag
|
||||||
AuthentikServerCPU:
|
AuthentikServerCPU:
|
||||||
Type: Number
|
Type: Number
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/authentik",
|
"name": "@goauthentik/authentik",
|
||||||
"version": "2025.6.1",
|
"version": "2025.6.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@goauthentik/authentik",
|
"name": "@goauthentik/authentik",
|
||||||
"version": "2025.6.1",
|
"version": "2025.6.2",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/authentik",
|
"name": "@goauthentik/authentik",
|
||||||
"version": "2025.6.1",
|
"version": "2025.6.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
182
packages/eslint-config/package-lock.json
generated
182
packages/eslint-config/package-lock.json
generated
@ -216,9 +216,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/config-array": {
|
"node_modules/@eslint/config-array": {
|
||||||
"version": "0.20.0",
|
"version": "0.20.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.1.tgz",
|
||||||
"integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==",
|
"integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint/object-schema": "^2.1.6",
|
"@eslint/object-schema": "^2.1.6",
|
||||||
@ -274,9 +274,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "9.28.0",
|
"version": "9.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.29.0.tgz",
|
||||||
"integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==",
|
"integrity": "sha512-3PIF4cBw/y+1u2EazflInpV+lYsSG0aByVIQzAgb1m1MhHFSbqTyNqtBKHgWf/9Ykud+DhILS9EGkmekVhbKoQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@ -576,17 +576,17 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.1.tgz",
|
||||||
"integrity": "sha512-QXwAlHlbcAwNlEEMKQS2RCgJsgXrTJdjXT08xEgbPFa2yYQgVjBymxP5DrfrE7X7iodSzd9qBUHUycdyVJTW1w==",
|
"integrity": "sha512-STXcN6ebF6li4PxwNeFnqF8/2BNDvBupf2OPx2yWNzr6mKNGF7q49VM00Pz5FaomJyqvbXpY6PhO+T9w139YEQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.10.0",
|
"@eslint-community/regexpp": "^4.10.0",
|
||||||
"@typescript-eslint/scope-manager": "8.34.0",
|
"@typescript-eslint/scope-manager": "8.34.1",
|
||||||
"@typescript-eslint/type-utils": "8.34.0",
|
"@typescript-eslint/type-utils": "8.34.1",
|
||||||
"@typescript-eslint/utils": "8.34.0",
|
"@typescript-eslint/utils": "8.34.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^7.0.0",
|
"ignore": "^7.0.0",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
@ -600,7 +600,7 @@
|
|||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@typescript-eslint/parser": "^8.34.0",
|
"@typescript-eslint/parser": "^8.34.1",
|
||||||
"eslint": "^8.57.0 || ^9.0.0",
|
"eslint": "^8.57.0 || ^9.0.0",
|
||||||
"typescript": ">=4.8.4 <5.9.0"
|
"typescript": ">=4.8.4 <5.9.0"
|
||||||
}
|
}
|
||||||
@ -616,16 +616,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.1.tgz",
|
||||||
"integrity": "sha512-vxXJV1hVFx3IXz/oy2sICsJukaBrtDEQSBiV48/YIV5KWjX1dO+bcIr/kCPrW6weKXvsaGKFNlwH0v2eYdRRbA==",
|
"integrity": "sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.34.0",
|
"@typescript-eslint/scope-manager": "8.34.1",
|
||||||
"@typescript-eslint/types": "8.34.0",
|
"@typescript-eslint/types": "8.34.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.34.0",
|
"@typescript-eslint/typescript-estree": "8.34.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -641,14 +641,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/project-service": {
|
"node_modules/@typescript-eslint/project-service": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.1.tgz",
|
||||||
"integrity": "sha512-iEgDALRf970/B2YExmtPMPF54NenZUf4xpL3wsCRx/lgjz6ul/l13R81ozP/ZNuXfnLCS+oPmG7JIxfdNYKELw==",
|
"integrity": "sha512-nuHlOmFZfuRwLJKDGQOVc0xnQrAmuq1Mj/ISou5044y1ajGNp2BNliIqp7F2LPQ5sForz8lempMFCovfeS1XoA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/tsconfig-utils": "^8.34.0",
|
"@typescript-eslint/tsconfig-utils": "^8.34.1",
|
||||||
"@typescript-eslint/types": "^8.34.0",
|
"@typescript-eslint/types": "^8.34.1",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -663,14 +663,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.1.tgz",
|
||||||
"integrity": "sha512-9Ac0X8WiLykl0aj1oYQNcLZjHgBojT6cW68yAgZ19letYu+Hxd0rE0veI1XznSSst1X5lwnxhPbVdwjDRIomRw==",
|
"integrity": "sha512-beu6o6QY4hJAgL1E8RaXNC071G4Kso2MGmJskCFQhRhg8VOH/FDbC8soP8NHN7e/Hdphwp8G8cE6OBzC8o41ZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.34.0",
|
"@typescript-eslint/types": "8.34.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.34.0"
|
"@typescript-eslint/visitor-keys": "8.34.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@ -681,9 +681,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.1.tgz",
|
||||||
"integrity": "sha512-+W9VYHKFIzA5cBeooqQxqNriAP0QeQ7xTiDuIOr71hzgffm3EL2hxwWBIIj4GuofIbKxGNarpKqIq6Q6YrShOA==",
|
"integrity": "sha512-K4Sjdo4/xF9NEeA2khOb7Y5nY6NSXBnod87uniVYW9kHP+hNlDV8trUSFeynA2uxWam4gIWgWoygPrv9VMWrYg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -698,14 +698,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.1.tgz",
|
||||||
"integrity": "sha512-n7zSmOcUVhcRYC75W2pnPpbO1iwhJY3NLoHEtbJwJSNlVAZuwqu05zY3f3s2SDWWDSo9FdN5szqc73DCtDObAg==",
|
"integrity": "sha512-Tv7tCCr6e5m8hP4+xFugcrwTOucB8lshffJ6zf1mF1TbU67R+ntCc6DzLNKM+s/uzDyv8gLq7tufaAhIBYeV8g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "8.34.0",
|
"@typescript-eslint/typescript-estree": "8.34.1",
|
||||||
"@typescript-eslint/utils": "8.34.0",
|
"@typescript-eslint/utils": "8.34.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ts-api-utils": "^2.1.0"
|
"ts-api-utils": "^2.1.0"
|
||||||
},
|
},
|
||||||
@ -722,9 +722,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.1.tgz",
|
||||||
"integrity": "sha512-9V24k/paICYPniajHfJ4cuAWETnt7Ssy+R0Rbcqo5sSFr3QEZ/8TSoUi9XeXVBGXCaLtwTOKSLGcInCAvyZeMA==",
|
"integrity": "sha512-rjLVbmE7HR18kDsjNIZQHxmv9RZwlgzavryL5Lnj2ujIRTeXlKtILHgRNmQ3j4daw7zd+mQgy+uyt6Zo6I0IGA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -736,16 +736,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.1.tgz",
|
||||||
"integrity": "sha512-rOi4KZxI7E0+BMqG7emPSK1bB4RICCpF7QD3KCLXn9ZvWoESsOMlHyZPAHyG04ujVplPaHbmEvs34m+wjgtVtg==",
|
"integrity": "sha512-rjCNqqYPuMUF5ODD+hWBNmOitjBWghkGKJg6hiCHzUvXRy6rK22Jd3rwbP2Xi+R7oYVvIKhokHVhH41BxPV5mA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/project-service": "8.34.0",
|
"@typescript-eslint/project-service": "8.34.1",
|
||||||
"@typescript-eslint/tsconfig-utils": "8.34.0",
|
"@typescript-eslint/tsconfig-utils": "8.34.1",
|
||||||
"@typescript-eslint/types": "8.34.0",
|
"@typescript-eslint/types": "8.34.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"fast-glob": "^3.3.2",
|
"fast-glob": "^3.3.2",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
@ -765,9 +765,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -804,16 +804,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.1.tgz",
|
||||||
"integrity": "sha512-8L4tWatGchV9A1cKbjaavS6mwYwp39jql8xUmIIKJdm+qiaeHy5KMKlBrf30akXAWBzn2SqKsNOtSENWUwg7XQ==",
|
"integrity": "sha512-mqOwUdZ3KjtGk7xJJnLbHxTuWVn3GO2WZZuM+Slhkun4+qthLdXx32C8xIXbO1kfCECb3jIs3eoxK3eryk7aoQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.7.0",
|
"@eslint-community/eslint-utils": "^4.7.0",
|
||||||
"@typescript-eslint/scope-manager": "8.34.0",
|
"@typescript-eslint/scope-manager": "8.34.1",
|
||||||
"@typescript-eslint/types": "8.34.0",
|
"@typescript-eslint/types": "8.34.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.34.0"
|
"@typescript-eslint/typescript-estree": "8.34.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@ -828,14 +828,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.1.tgz",
|
||||||
"integrity": "sha512-qHV7pW7E85A0x6qyrFn+O+q1k1p3tQCsqIZ1KZ5ESLXY57aTvUd3/a4rdPTeXisvhXn2VQG0VSKUqs8KHF2zcA==",
|
"integrity": "sha512-xoh5rJ+tgsRKoXnkBPFRLZ7rjKM0AfVbC68UZ/ECXoDbfggb9RbEySN359acY1vS3qZ0jVTVWzbtfapwm5ztxw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.34.0",
|
"@typescript-eslint/types": "8.34.1",
|
||||||
"eslint-visitor-keys": "^4.2.0"
|
"eslint-visitor-keys": "^4.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@ -846,9 +846,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.14.1",
|
"version": "8.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||||
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
@ -1554,18 +1554,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "9.28.0",
|
"version": "9.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.29.0.tgz",
|
||||||
"integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==",
|
"integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
"@eslint/config-array": "^0.20.0",
|
"@eslint/config-array": "^0.20.1",
|
||||||
"@eslint/config-helpers": "^0.2.1",
|
"@eslint/config-helpers": "^0.2.1",
|
||||||
"@eslint/core": "^0.14.0",
|
"@eslint/core": "^0.14.0",
|
||||||
"@eslint/eslintrc": "^3.3.1",
|
"@eslint/eslintrc": "^3.3.1",
|
||||||
"@eslint/js": "9.28.0",
|
"@eslint/js": "9.29.0",
|
||||||
"@eslint/plugin-kit": "^0.3.1",
|
"@eslint/plugin-kit": "^0.3.1",
|
||||||
"@humanfs/node": "^0.16.6",
|
"@humanfs/node": "^0.16.6",
|
||||||
"@humanwhocodes/module-importer": "^1.0.1",
|
"@humanwhocodes/module-importer": "^1.0.1",
|
||||||
@ -1577,9 +1577,9 @@
|
|||||||
"cross-spawn": "^7.0.6",
|
"cross-spawn": "^7.0.6",
|
||||||
"debug": "^4.3.2",
|
"debug": "^4.3.2",
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
"eslint-scope": "^8.3.0",
|
"eslint-scope": "^8.4.0",
|
||||||
"eslint-visitor-keys": "^4.2.0",
|
"eslint-visitor-keys": "^4.2.1",
|
||||||
"espree": "^10.3.0",
|
"espree": "^10.4.0",
|
||||||
"esquery": "^1.5.0",
|
"esquery": "^1.5.0",
|
||||||
"esutils": "^2.0.2",
|
"esutils": "^2.0.2",
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
@ -1792,9 +1792,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-scope": {
|
"node_modules/eslint-scope": {
|
||||||
"version": "8.3.0",
|
"version": "8.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
|
||||||
"integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==",
|
"integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esrecurse": "^4.3.0",
|
"esrecurse": "^4.3.0",
|
||||||
@ -1808,9 +1808,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-visitor-keys": {
|
"node_modules/eslint-visitor-keys": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
|
||||||
"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
|
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@ -1820,14 +1820,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/espree": {
|
"node_modules/espree": {
|
||||||
"version": "10.3.0",
|
"version": "10.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
|
||||||
"integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
|
"integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "^8.14.0",
|
"acorn": "^8.15.0",
|
||||||
"acorn-jsx": "^5.3.2",
|
"acorn-jsx": "^5.3.2",
|
||||||
"eslint-visitor-keys": "^4.2.0"
|
"eslint-visitor-keys": "^4.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@ -4035,15 +4035,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript-eslint": {
|
"node_modules/typescript-eslint": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.1.tgz",
|
||||||
"integrity": "sha512-MRpfN7uYjTrTGigFCt8sRyNqJFhjN0WwZecldaqhWm+wy0gaRt8Edb/3cuUy0zdq2opJWT6iXINKAtewnDOltQ==",
|
"integrity": "sha512-XjS+b6Vg9oT1BaIUfkW3M3LvqZE++rbzAMEHuccCfO/YkP43ha6w3jTEMilQxMF92nVOYCcdjv1ZUhAa1D/0ow==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "8.34.0",
|
"@typescript-eslint/eslint-plugin": "8.34.1",
|
||||||
"@typescript-eslint/parser": "8.34.0",
|
"@typescript-eslint/parser": "8.34.1",
|
||||||
"@typescript-eslint/utils": "8.34.0"
|
"@typescript-eslint/utils": "8.34.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "authentik"
|
name = "authentik"
|
||||||
version = "2025.6.1"
|
version = "2025.6.2"
|
||||||
description = ""
|
description = ""
|
||||||
authors = [{ name = "authentik Team", email = "hello@goauthentik.io" }]
|
authors = [{ name = "authentik Team", email = "hello@goauthentik.io" }]
|
||||||
requires-python = "==3.13.*"
|
requires-python = "==3.13.*"
|
||||||
@ -48,7 +48,7 @@ dependencies = [
|
|||||||
"packaging==25.0",
|
"packaging==25.0",
|
||||||
"paramiko==3.5.1",
|
"paramiko==3.5.1",
|
||||||
"psycopg[c,pool]==3.2.9",
|
"psycopg[c,pool]==3.2.9",
|
||||||
"pydantic==2.11.5",
|
"pydantic==2.11.7",
|
||||||
"pydantic-scim==0.0.8",
|
"pydantic-scim==0.0.8",
|
||||||
"pyjwt==2.10.1",
|
"pyjwt==2.10.1",
|
||||||
"pyrad==2.4",
|
"pyrad==2.4",
|
||||||
@ -68,7 +68,7 @@ dependencies = [
|
|||||||
"urllib3<3",
|
"urllib3<3",
|
||||||
"uvicorn[standard]==0.34.3",
|
"uvicorn[standard]==0.34.3",
|
||||||
"watchdog==6.0.0",
|
"watchdog==6.0.0",
|
||||||
"webauthn==2.5.2",
|
"webauthn==2.6.0",
|
||||||
"wsproto==1.2.0",
|
"wsproto==1.2.0",
|
||||||
"xmlsec==1.3.15",
|
"xmlsec==1.3.15",
|
||||||
"zxcvbn==4.5.0",
|
"zxcvbn==4.5.0",
|
||||||
|
|||||||
43
schema.yml
43
schema.yml
@ -1,7 +1,7 @@
|
|||||||
openapi: 3.0.3
|
openapi: 3.0.3
|
||||||
info:
|
info:
|
||||||
title: authentik
|
title: authentik
|
||||||
version: 2025.6.1
|
version: 2025.6.2
|
||||||
description: Making authentication simple.
|
description: Making authentication simple.
|
||||||
contact:
|
contact:
|
||||||
email: hello@goauthentik.io
|
email: hello@goauthentik.io
|
||||||
@ -22454,6 +22454,17 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
|
- in: query
|
||||||
|
name: default_name_id_policy
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
|
||||||
|
- urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
|
||||||
|
- urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
|
||||||
|
- urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName
|
||||||
|
- urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
|
||||||
|
- urn:oasis:names:tc:SAML:2.0:nameid-format:transient
|
||||||
- in: query
|
- in: query
|
||||||
name: default_relay_state
|
name: default_relay_state
|
||||||
schema:
|
schema:
|
||||||
@ -29670,6 +29681,7 @@ paths:
|
|||||||
enum:
|
enum:
|
||||||
- urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
|
- urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
|
||||||
- urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
|
- urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
|
||||||
|
- urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
|
||||||
- urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName
|
- urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName
|
||||||
- urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
|
- urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
|
||||||
- urn:oasis:names:tc:SAML:2.0:nameid-format:transient
|
- urn:oasis:names:tc:SAML:2.0:nameid-format:transient
|
||||||
@ -48745,14 +48757,6 @@ components:
|
|||||||
- mode
|
- mode
|
||||||
- name
|
- name
|
||||||
- user_attribute
|
- user_attribute
|
||||||
NameIdPolicyEnum:
|
|
||||||
enum:
|
|
||||||
- urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
|
|
||||||
- urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
|
|
||||||
- urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
|
|
||||||
- urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName
|
|
||||||
- urn:oasis:names:tc:SAML:2.0:nameid-format:transient
|
|
||||||
type: string
|
|
||||||
NetworkBindingEnum:
|
NetworkBindingEnum:
|
||||||
enum:
|
enum:
|
||||||
- no_binding
|
- no_binding
|
||||||
@ -54501,6 +54505,8 @@ components:
|
|||||||
default_relay_state:
|
default_relay_state:
|
||||||
type: string
|
type: string
|
||||||
description: Default relay_state value for IDP-initiated logins
|
description: Default relay_state value for IDP-initiated logins
|
||||||
|
default_name_id_policy:
|
||||||
|
$ref: '#/components/schemas/SAMLNameIDPolicyEnum'
|
||||||
PatchedSAMLSourcePropertyMappingRequest:
|
PatchedSAMLSourcePropertyMappingRequest:
|
||||||
type: object
|
type: object
|
||||||
description: SAMLSourcePropertyMapping Serializer
|
description: SAMLSourcePropertyMapping Serializer
|
||||||
@ -54594,7 +54600,7 @@ components:
|
|||||||
be a security risk, as no validation of the request ID is done.
|
be a security risk, as no validation of the request ID is done.
|
||||||
name_id_policy:
|
name_id_policy:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/NameIdPolicyEnum'
|
- $ref: '#/components/schemas/SAMLNameIDPolicyEnum'
|
||||||
description: NameID Policy sent to the IdP. Can be unset, in which case
|
description: NameID Policy sent to the IdP. Can be unset, in which case
|
||||||
no Policy is sent.
|
no Policy is sent.
|
||||||
binding_type:
|
binding_type:
|
||||||
@ -57305,6 +57311,15 @@ components:
|
|||||||
required:
|
required:
|
||||||
- download_url
|
- download_url
|
||||||
- metadata
|
- metadata
|
||||||
|
SAMLNameIDPolicyEnum:
|
||||||
|
enum:
|
||||||
|
- urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
|
||||||
|
- urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
|
||||||
|
- urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
|
||||||
|
- urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName
|
||||||
|
- urn:oasis:names:tc:SAML:2.0:nameid-format:transient
|
||||||
|
- urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
|
||||||
|
type: string
|
||||||
SAMLPropertyMapping:
|
SAMLPropertyMapping:
|
||||||
type: object
|
type: object
|
||||||
description: SAMLPropertyMapping Serializer
|
description: SAMLPropertyMapping Serializer
|
||||||
@ -57522,6 +57537,8 @@ components:
|
|||||||
default_relay_state:
|
default_relay_state:
|
||||||
type: string
|
type: string
|
||||||
description: Default relay_state value for IDP-initiated logins
|
description: Default relay_state value for IDP-initiated logins
|
||||||
|
default_name_id_policy:
|
||||||
|
$ref: '#/components/schemas/SAMLNameIDPolicyEnum'
|
||||||
url_download_metadata:
|
url_download_metadata:
|
||||||
type: string
|
type: string
|
||||||
description: Get metadata download URL
|
description: Get metadata download URL
|
||||||
@ -57694,6 +57711,8 @@ components:
|
|||||||
default_relay_state:
|
default_relay_state:
|
||||||
type: string
|
type: string
|
||||||
description: Default relay_state value for IDP-initiated logins
|
description: Default relay_state value for IDP-initiated logins
|
||||||
|
default_name_id_policy:
|
||||||
|
$ref: '#/components/schemas/SAMLNameIDPolicyEnum'
|
||||||
required:
|
required:
|
||||||
- acs_url
|
- acs_url
|
||||||
- authorization_flow
|
- authorization_flow
|
||||||
@ -57802,7 +57821,7 @@ components:
|
|||||||
be a security risk, as no validation of the request ID is done.
|
be a security risk, as no validation of the request ID is done.
|
||||||
name_id_policy:
|
name_id_policy:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/NameIdPolicyEnum'
|
- $ref: '#/components/schemas/SAMLNameIDPolicyEnum'
|
||||||
description: NameID Policy sent to the IdP. Can be unset, in which case
|
description: NameID Policy sent to the IdP. Can be unset, in which case
|
||||||
no Policy is sent.
|
no Policy is sent.
|
||||||
binding_type:
|
binding_type:
|
||||||
@ -57992,7 +58011,7 @@ components:
|
|||||||
be a security risk, as no validation of the request ID is done.
|
be a security risk, as no validation of the request ID is done.
|
||||||
name_id_policy:
|
name_id_policy:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/NameIdPolicyEnum'
|
- $ref: '#/components/schemas/SAMLNameIDPolicyEnum'
|
||||||
description: NameID Policy sent to the IdP. Can be unset, in which case
|
description: NameID Policy sent to the IdP. Can be unset, in which case
|
||||||
no Policy is sent.
|
no Policy is sent.
|
||||||
binding_type:
|
binding_type:
|
||||||
|
|||||||
@ -7,7 +7,7 @@ services:
|
|||||||
network_mode: host
|
network_mode: host
|
||||||
restart: always
|
restart: always
|
||||||
mailpit:
|
mailpit:
|
||||||
image: docker.io/axllent/mailpit:v1.26.0
|
image: docker.io/axllent/mailpit:v1.26.1
|
||||||
ports:
|
ports:
|
||||||
- 1025:1025
|
- 1025:1025
|
||||||
- 8025:8025
|
- 8025:8025
|
||||||
|
|||||||
18
uv.lock
generated
18
uv.lock
generated
@ -165,7 +165,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "authentik"
|
name = "authentik"
|
||||||
version = "2025.6.1"
|
version = "2025.6.2"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "argon2-cffi" },
|
{ name = "argon2-cffi" },
|
||||||
@ -309,7 +309,7 @@ requires-dist = [
|
|||||||
{ name = "packaging", specifier = "==25.0" },
|
{ name = "packaging", specifier = "==25.0" },
|
||||||
{ name = "paramiko", specifier = "==3.5.1" },
|
{ name = "paramiko", specifier = "==3.5.1" },
|
||||||
{ name = "psycopg", extras = ["c", "pool"], specifier = "==3.2.9" },
|
{ name = "psycopg", extras = ["c", "pool"], specifier = "==3.2.9" },
|
||||||
{ name = "pydantic", specifier = "==2.11.5" },
|
{ name = "pydantic", specifier = "==2.11.7" },
|
||||||
{ name = "pydantic-scim", specifier = "==0.0.8" },
|
{ name = "pydantic-scim", specifier = "==0.0.8" },
|
||||||
{ name = "pyjwt", specifier = "==2.10.1" },
|
{ name = "pyjwt", specifier = "==2.10.1" },
|
||||||
{ name = "pyrad", specifier = "==2.4" },
|
{ name = "pyrad", specifier = "==2.4" },
|
||||||
@ -329,7 +329,7 @@ requires-dist = [
|
|||||||
{ name = "urllib3", specifier = "<3" },
|
{ name = "urllib3", specifier = "<3" },
|
||||||
{ name = "uvicorn", extras = ["standard"], specifier = "==0.34.3" },
|
{ name = "uvicorn", extras = ["standard"], specifier = "==0.34.3" },
|
||||||
{ name = "watchdog", specifier = "==6.0.0" },
|
{ name = "watchdog", specifier = "==6.0.0" },
|
||||||
{ name = "webauthn", specifier = "==2.5.2" },
|
{ name = "webauthn", specifier = "==2.6.0" },
|
||||||
{ name = "wsproto", specifier = "==1.2.0" },
|
{ name = "wsproto", specifier = "==1.2.0" },
|
||||||
{ name = "xmlsec", specifier = "==1.3.15" },
|
{ name = "xmlsec", specifier = "==1.3.15" },
|
||||||
{ name = "zxcvbn", specifier = "==4.5.0" },
|
{ name = "zxcvbn", specifier = "==4.5.0" },
|
||||||
@ -2463,7 +2463,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
version = "2.11.5"
|
version = "2.11.7"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "annotated-types" },
|
{ name = "annotated-types" },
|
||||||
@ -2471,9 +2471,9 @@ dependencies = [
|
|||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
{ name = "typing-inspection" },
|
{ name = "typing-inspection" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/f0/86/8ce9040065e8f924d642c58e4a344e33163a07f6b57f836d0d734e0ad3fb/pydantic-2.11.5.tar.gz", hash = "sha256:7f853db3d0ce78ce8bbb148c401c2cdd6431b3473c0cdff2755c7690952a7b7a", size = 787102, upload-time = "2025-05-22T21:18:08.761Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/b5/69/831ed22b38ff9b4b64b66569f0e5b7b97cf3638346eb95a2147fdb49ad5f/pydantic-2.11.5-py3-none-any.whl", hash = "sha256:f9c26ba06f9747749ca1e5c94d6a85cb84254577553c8785576fd38fa64dc0f7", size = 444229, upload-time = "2025-05-22T21:18:06.329Z" },
|
{ url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.optional-dependencies]
|
[package.optional-dependencies]
|
||||||
@ -3391,7 +3391,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webauthn"
|
name = "webauthn"
|
||||||
version = "2.5.2"
|
version = "2.6.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "asn1crypto" },
|
{ name = "asn1crypto" },
|
||||||
@ -3399,9 +3399,9 @@ dependencies = [
|
|||||||
{ name = "cryptography" },
|
{ name = "cryptography" },
|
||||||
{ name = "pyopenssl" },
|
{ name = "pyopenssl" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/8d/92/8d2a4eec83d8e7feacdaad37c6eb6eb922100cecce5c14a41d8069a59a03/webauthn-2.5.2.tar.gz", hash = "sha256:09c13dfc1c68c810f32fa4d89b1d37acb9f9ae9091c9d7019e313be4525a95ef", size = 124114, upload-time = "2025-03-07T19:44:05.243Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/63/38/5792cb2034673c162a721df0ad65825699516ee0c938a65670ad3cdabf6c/webauthn-2.6.0.tar.gz", hash = "sha256:13cf5b009a64cef569599ffecf24550df1d7c0cd4fbaea870f937148484a80b4", size = 123608, upload-time = "2025-06-16T22:25:26.76Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/7f/fe/f6ae41de9f383439e30b303a67f6f45d2fceabedaedc34c62f74d58c5c73/webauthn-2.5.2-py3-none-any.whl", hash = "sha256:44246e496e617eb5e2f51165046b9f0197fcdf470f69cd6734061a27ba365f8e", size = 71624, upload-time = "2025-03-07T19:44:03.728Z" },
|
{ url = "https://files.pythonhosted.org/packages/56/c5/b1bba7f6a50caca77f37003e098f48f8dc68d990aba8a03ac8376016430b/webauthn-2.6.0-py3-none-any.whl", hash = "sha256:459973eb5780c1f41bec42b682acf587456b185733398a0b99a0714705b79447", size = 71189, upload-time = "2025-06-16T22:25:25.535Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
1703
web/package-lock.json
generated
1703
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -93,7 +93,7 @@
|
|||||||
"@floating-ui/dom": "^1.6.11",
|
"@floating-ui/dom": "^1.6.11",
|
||||||
"@formatjs/intl-listformat": "^7.7.11",
|
"@formatjs/intl-listformat": "^7.7.11",
|
||||||
"@fortawesome/fontawesome-free": "^6.7.2",
|
"@fortawesome/fontawesome-free": "^6.7.2",
|
||||||
"@goauthentik/api": "^2025.6.1-1749515784",
|
"@goauthentik/api": "^2025.6.2-1750112513",
|
||||||
"@lit/context": "^1.1.2",
|
"@lit/context": "^1.1.2",
|
||||||
"@lit/localize": "^0.12.2",
|
"@lit/localize": "^0.12.2",
|
||||||
"@lit/reactive-element": "^2.0.4",
|
"@lit/reactive-element": "^2.0.4",
|
||||||
@ -102,10 +102,9 @@
|
|||||||
"@open-wc/lit-helpers": "^0.7.0",
|
"@open-wc/lit-helpers": "^0.7.0",
|
||||||
"@patternfly/elements": "^4.1.0",
|
"@patternfly/elements": "^4.1.0",
|
||||||
"@patternfly/patternfly": "^4.224.2",
|
"@patternfly/patternfly": "^4.224.2",
|
||||||
"@sentry/browser": "^9.28.1",
|
"@sentry/browser": "^9.30.0",
|
||||||
"@spotlightjs/spotlight": "^3.0.0",
|
"@spotlightjs/spotlight": "^3.0.0",
|
||||||
"@webcomponents/webcomponentsjs": "^2.8.0",
|
"@webcomponents/webcomponentsjs": "^2.8.0",
|
||||||
"base64-js": "^1.5.1",
|
|
||||||
"change-case": "^5.4.4",
|
"change-case": "^5.4.4",
|
||||||
"chart.js": "^4.4.9",
|
"chart.js": "^4.4.9",
|
||||||
"chartjs-adapter-date-fns": "^3.0.0",
|
"chartjs-adapter-date-fns": "^3.0.0",
|
||||||
@ -137,6 +136,7 @@
|
|||||||
"trusted-types": "^2.0.0",
|
"trusted-types": "^2.0.0",
|
||||||
"ts-pattern": "^5.7.1",
|
"ts-pattern": "^5.7.1",
|
||||||
"unist-util-visit": "^5.0.0",
|
"unist-util-visit": "^5.0.0",
|
||||||
|
"webauthn-polyfills": "^0.1.7",
|
||||||
"webcomponent-qr-code": "^1.2.0",
|
"webcomponent-qr-code": "^1.2.0",
|
||||||
"yaml": "^2.8.0"
|
"yaml": "^2.8.0"
|
||||||
},
|
},
|
||||||
@ -170,16 +170,16 @@
|
|||||||
"@types/react-dom": "^19.1.5",
|
"@types/react-dom": "^19.1.5",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.8.0",
|
"@typescript-eslint/eslint-plugin": "^8.8.0",
|
||||||
"@typescript-eslint/parser": "^8.8.0",
|
"@typescript-eslint/parser": "^8.8.0",
|
||||||
"@wdio/browser-runner": "9.4",
|
"@wdio/browser-runner": "9.15",
|
||||||
"@wdio/cli": "9.4",
|
"@wdio/cli": "9.15",
|
||||||
"@wdio/spec-reporter": "^9.1.2",
|
"@wdio/spec-reporter": "^9.15.0",
|
||||||
"@web/test-runner": "^0.20.2",
|
"@web/test-runner": "^0.20.2",
|
||||||
"chromedriver": "^136.0.3",
|
"chromedriver": "^136.0.3",
|
||||||
"esbuild": "^0.25.5",
|
"esbuild": "^0.25.5",
|
||||||
"esbuild-plugin-copy": "^2.1.1",
|
"esbuild-plugin-copy": "^2.1.1",
|
||||||
"esbuild-plugin-polyfill-node": "^0.3.0",
|
"esbuild-plugin-polyfill-node": "^0.3.0",
|
||||||
"esbuild-plugins-node-modules-polyfill": "^1.7.0",
|
"esbuild-plugins-node-modules-polyfill": "^1.7.0",
|
||||||
"eslint": "^9.28.0",
|
"eslint": "^9.29.0",
|
||||||
"eslint-plugin-lit": "^2.1.1",
|
"eslint-plugin-lit": "^2.1.1",
|
||||||
"eslint-plugin-wc": "^3.0.1",
|
"eslint-plugin-wc": "^3.0.1",
|
||||||
"github-slugger": "^2.0.0",
|
"github-slugger": "^2.0.0",
|
||||||
@ -194,7 +194,7 @@
|
|||||||
"storybook-addon-mock": "^5.0.0",
|
"storybook-addon-mock": "^5.0.0",
|
||||||
"turnstile-types": "^1.2.3",
|
"turnstile-types": "^1.2.3",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"typescript-eslint": "^8.34.0",
|
"typescript-eslint": "^8.34.1",
|
||||||
"vite-plugin-lit-css": "^2.0.0",
|
"vite-plugin-lit-css": "^2.0.0",
|
||||||
"vite-tsconfig-paths": "^5.0.1",
|
"vite-tsconfig-paths": "^5.0.1",
|
||||||
"wireit": "^0.14.12"
|
"wireit": "^0.14.12"
|
||||||
|
|||||||
2
web/packages/core/types/node.d.ts
vendored
2
web/packages/core/types/node.d.ts
vendored
@ -14,7 +14,7 @@ declare module "module" {
|
|||||||
* const relativeDirname = dirname(fileURLToPath(import.meta.url));
|
* const relativeDirname = dirname(fileURLToPath(import.meta.url));
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line no-var
|
|
||||||
var __dirname: string;
|
var __dirname: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,11 +11,11 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@goauthentik/api": "^2024.6.0-1719577139",
|
"@goauthentik/api": "^2024.6.0-1719577139",
|
||||||
"base64-js": "^1.5.1",
|
|
||||||
"bootstrap": "^4.6.1",
|
"bootstrap": "^4.6.1",
|
||||||
"formdata-polyfill": "^4.0.10",
|
"formdata-polyfill": "^4.0.10",
|
||||||
"jquery": "^3.7.1",
|
"jquery": "^3.7.1",
|
||||||
"weakmap-polyfill": "^2.0.4"
|
"weakmap-polyfill": "^2.0.4",
|
||||||
|
"webauthn-polyfills": "^0.1.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@goauthentik/core": "^1.0.0",
|
"@goauthentik/core": "^1.0.0",
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { fromByteArray } from "base64-js";
|
|
||||||
import "formdata-polyfill";
|
import "formdata-polyfill";
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
import "weakmap-polyfill";
|
import "weakmap-polyfill";
|
||||||
|
import "webauthn-polyfills";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
type AuthenticatorValidationChallenge,
|
type AuthenticatorValidationChallenge,
|
||||||
@ -257,47 +257,9 @@ class AutosubmitStage extends Stage<AutosubmitChallenge> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Assertion {
|
|
||||||
id: string;
|
|
||||||
rawId: string;
|
|
||||||
type: string;
|
|
||||||
registrationClientExtensions: string;
|
|
||||||
response: {
|
|
||||||
clientDataJSON: string;
|
|
||||||
attestationObject: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AuthAssertion {
|
|
||||||
id: string;
|
|
||||||
rawId: string;
|
|
||||||
type: string;
|
|
||||||
assertionClientExtensions: string;
|
|
||||||
response: {
|
|
||||||
clientDataJSON: string;
|
|
||||||
authenticatorData: string;
|
|
||||||
signature: string;
|
|
||||||
userHandle: string | null;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge> {
|
class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge> {
|
||||||
deviceChallenge?: DeviceChallenge;
|
deviceChallenge?: DeviceChallenge;
|
||||||
|
|
||||||
b64enc(buf: Uint8Array): string {
|
|
||||||
return fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
b64RawEnc(buf: Uint8Array): string {
|
|
||||||
return fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_");
|
|
||||||
}
|
|
||||||
|
|
||||||
u8arr(input: string): Uint8Array {
|
|
||||||
return Uint8Array.from(atob(input.replace(/_/g, "/").replace(/-/g, "+")), (c) =>
|
|
||||||
c.charCodeAt(0),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
checkWebAuthnSupport(): boolean {
|
checkWebAuthnSupport(): boolean {
|
||||||
if ("credentials" in navigator) {
|
if ("credentials" in navigator) {
|
||||||
return true;
|
return true;
|
||||||
@ -310,98 +272,6 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms items in the credentialCreateOptions generated on the server
|
|
||||||
* into byte arrays expected by the navigator.credentials.create() call
|
|
||||||
*/
|
|
||||||
transformCredentialCreateOptions(
|
|
||||||
credentialCreateOptions: PublicKeyCredentialCreationOptions,
|
|
||||||
userId: string,
|
|
||||||
): PublicKeyCredentialCreationOptions {
|
|
||||||
const user = credentialCreateOptions.user;
|
|
||||||
// Because json can't contain raw bytes, the server base64-encodes the User ID
|
|
||||||
// So to get the base64 encoded byte array, we first need to convert it to a regular
|
|
||||||
// string, then a byte array, re-encode it and wrap that in an array.
|
|
||||||
const stringId = decodeURIComponent(window.atob(userId));
|
|
||||||
user.id = this.u8arr(this.b64enc(this.u8arr(stringId)));
|
|
||||||
const challenge = this.u8arr(credentialCreateOptions.challenge.toString());
|
|
||||||
|
|
||||||
return Object.assign({}, credentialCreateOptions, {
|
|
||||||
challenge,
|
|
||||||
user,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms the binary data in the credential into base64 strings
|
|
||||||
* for posting to the server.
|
|
||||||
* @param {PublicKeyCredential} newAssertion
|
|
||||||
*/
|
|
||||||
transformNewAssertionForServer(newAssertion: PublicKeyCredential): Assertion {
|
|
||||||
const attObj = new Uint8Array(
|
|
||||||
(newAssertion.response as AuthenticatorAttestationResponse).attestationObject,
|
|
||||||
);
|
|
||||||
const clientDataJSON = new Uint8Array(newAssertion.response.clientDataJSON);
|
|
||||||
const rawId = new Uint8Array(newAssertion.rawId);
|
|
||||||
|
|
||||||
const registrationClientExtensions = newAssertion.getClientExtensionResults();
|
|
||||||
return {
|
|
||||||
id: newAssertion.id,
|
|
||||||
rawId: this.b64enc(rawId),
|
|
||||||
type: newAssertion.type,
|
|
||||||
registrationClientExtensions: JSON.stringify(registrationClientExtensions),
|
|
||||||
response: {
|
|
||||||
clientDataJSON: this.b64enc(clientDataJSON),
|
|
||||||
attestationObject: this.b64enc(attObj),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
transformCredentialRequestOptions(
|
|
||||||
credentialRequestOptions: PublicKeyCredentialRequestOptions,
|
|
||||||
): PublicKeyCredentialRequestOptions {
|
|
||||||
const challenge = this.u8arr(credentialRequestOptions.challenge.toString());
|
|
||||||
|
|
||||||
const allowCredentials = (credentialRequestOptions.allowCredentials || []).map(
|
|
||||||
(credentialDescriptor) => {
|
|
||||||
const id = this.u8arr(credentialDescriptor.id.toString());
|
|
||||||
return Object.assign({}, credentialDescriptor, { id });
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
return Object.assign({}, credentialRequestOptions, {
|
|
||||||
challenge,
|
|
||||||
allowCredentials,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes the binary data in the assertion into strings for posting to the server.
|
|
||||||
* @param {PublicKeyCredential} newAssertion
|
|
||||||
*/
|
|
||||||
transformAssertionForServer(newAssertion: PublicKeyCredential): AuthAssertion {
|
|
||||||
const response = newAssertion.response as AuthenticatorAssertionResponse;
|
|
||||||
const authData = new Uint8Array(response.authenticatorData);
|
|
||||||
const clientDataJSON = new Uint8Array(response.clientDataJSON);
|
|
||||||
const rawId = new Uint8Array(newAssertion.rawId);
|
|
||||||
const sig = new Uint8Array(response.signature);
|
|
||||||
const assertionClientExtensions = newAssertion.getClientExtensionResults();
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: newAssertion.id,
|
|
||||||
rawId: this.b64enc(rawId),
|
|
||||||
type: newAssertion.type,
|
|
||||||
assertionClientExtensions: JSON.stringify(assertionClientExtensions),
|
|
||||||
|
|
||||||
response: {
|
|
||||||
clientDataJSON: this.b64RawEnc(clientDataJSON),
|
|
||||||
signature: this.b64RawEnc(sig),
|
|
||||||
authenticatorData: this.b64RawEnc(authData),
|
|
||||||
userHandle: null,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.challenge.deviceChallenges.length === 1) {
|
if (this.challenge.deviceChallenges.length === 1) {
|
||||||
this.deviceChallenge = this.challenge.deviceChallenges[0];
|
this.deviceChallenge = this.challenge.deviceChallenges[0];
|
||||||
@ -505,8 +375,8 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
|
|||||||
`);
|
`);
|
||||||
navigator.credentials
|
navigator.credentials
|
||||||
.get({
|
.get({
|
||||||
publicKey: this.transformCredentialRequestOptions(
|
publicKey: PublicKeyCredential.parseRequestOptionsFromJSON(
|
||||||
this.deviceChallenge?.challenge as PublicKeyCredentialRequestOptions,
|
this.deviceChallenge?.challenge as PublicKeyCredentialRequestOptionsJSON,
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
.then((assertion) => {
|
.then((assertion) => {
|
||||||
@ -514,15 +384,9 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
|
|||||||
throw new Error("No assertion");
|
throw new Error("No assertion");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// we now have an authentication assertion! encode the byte arrays contained
|
|
||||||
// in the assertion data as strings for posting to the server
|
|
||||||
const transformedAssertionForServer = this.transformAssertionForServer(
|
|
||||||
assertion as PublicKeyCredential,
|
|
||||||
);
|
|
||||||
|
|
||||||
// post the assertion to the server for verification.
|
// post the assertion to the server for verification.
|
||||||
this.executor.submit({
|
this.executor.submit({
|
||||||
webauthn: transformedAssertionForServer,
|
webauthn: (assertion as PublicKeyCredential).toJSON(),
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new Error(`Error when validating assertion on server: ${err}`);
|
throw new Error(`Error when validating assertion on server: ${err}`);
|
||||||
|
|||||||
@ -88,7 +88,8 @@ export class RecentEventsCard extends Table<Event> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return super.renderEmpty(
|
return super.renderEmpty(
|
||||||
html`<ak-empty-state header=${msg("No Events found.")}>
|
html`<ak-empty-state
|
||||||
|
><span slot="header">${msg("No Events found.")}</span>
|
||||||
<div slot="body">${msg("No matching events could be found.")}</div>
|
<div slot="body">${msg("No matching events could be found.")}</div>
|
||||||
</ak-empty-state>`,
|
</ak-empty-state>`,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { policyEngineModes } from "@goauthentik/admin/policies/PolicyEngineModes
|
|||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import "@goauthentik/components/ak-file-input";
|
import "@goauthentik/components/ak-file-input";
|
||||||
import "@goauthentik/components/ak-radio-input";
|
import "@goauthentik/components/ak-radio-input";
|
||||||
|
import "@goauthentik/components/ak-slug-input";
|
||||||
import "@goauthentik/components/ak-switch-input";
|
import "@goauthentik/components/ak-switch-input";
|
||||||
import "@goauthentik/components/ak-text-input";
|
import "@goauthentik/components/ak-text-input";
|
||||||
import "@goauthentik/components/ak-textarea-input";
|
import "@goauthentik/components/ak-textarea-input";
|
||||||
@ -130,14 +131,14 @@ export class ApplicationForm extends WithCapabilitiesConfig(ModelForm<Applicatio
|
|||||||
required
|
required
|
||||||
help=${msg("Application's display Name.")}
|
help=${msg("Application's display Name.")}
|
||||||
></ak-text-input>
|
></ak-text-input>
|
||||||
<ak-text-input
|
<ak-slug-input
|
||||||
name="slug"
|
name="slug"
|
||||||
value=${ifDefined(this.instance?.slug)}
|
value=${ifDefined(this.instance?.slug)}
|
||||||
label=${msg("Slug")}
|
label=${msg("Slug")}
|
||||||
required
|
required
|
||||||
help=${msg("Internal application name used in URLs.")}
|
help=${msg("Internal application name used in URLs.")}
|
||||||
input-hint="code"
|
input-hint="code"
|
||||||
></ak-text-input>
|
></ak-slug-input>
|
||||||
<ak-text-input
|
<ak-text-input
|
||||||
name="group"
|
name="group"
|
||||||
value=${ifDefined(this.instance?.group)}
|
value=${ifDefined(this.instance?.group)}
|
||||||
|
|||||||
@ -117,13 +117,11 @@ export class ApplicationWizardApplicationStep extends ApplicationWizardStep {
|
|||||||
?invalid=${this.errors.has("name")}
|
?invalid=${this.errors.has("name")}
|
||||||
.errorMessages=${errors.name ?? this.errorMessages("name")}
|
.errorMessages=${errors.name ?? this.errorMessages("name")}
|
||||||
help=${msg("Application's display Name.")}
|
help=${msg("Application's display Name.")}
|
||||||
id="ak-application-wizard-details-name"
|
|
||||||
></ak-text-input>
|
></ak-text-input>
|
||||||
<ak-slug-input
|
<ak-slug-input
|
||||||
name="slug"
|
name="slug"
|
||||||
value=${ifDefined(app.slug)}
|
value=${ifDefined(app.slug)}
|
||||||
label=${msg("Slug")}
|
label=${msg("Slug")}
|
||||||
source="#ak-application-wizard-details-name"
|
|
||||||
required
|
required
|
||||||
?invalid=${errors.slug ?? this.errors.has("slug")}
|
?invalid=${errors.slug ?? this.errors.has("slug")}
|
||||||
.errorMessages=${this.errorMessages("slug")}
|
.errorMessages=${this.errorMessages("slug")}
|
||||||
|
|||||||
@ -115,7 +115,8 @@ export class ApplicationWizardBindingsStep extends ApplicationWizardStep {
|
|||||||
.columns=${COLUMNS}
|
.columns=${COLUMNS}
|
||||||
.content=${[]}
|
.content=${[]}
|
||||||
></ak-select-table>
|
></ak-select-table>
|
||||||
<ak-empty-state header=${msg("No bound policies.")} icon="pf-icon-module">
|
<ak-empty-state icon="pf-icon-module"
|
||||||
|
><span slot="header">${msg("No bound policies.")} </span>
|
||||||
<div slot="body">${msg("No policies are currently bound to this object.")}</div>
|
<div slot="body">${msg("No policies are currently bound to this object.")}</div>
|
||||||
<div slot="primary">
|
<div slot="primary">
|
||||||
<button
|
<button
|
||||||
|
|||||||
@ -135,7 +135,8 @@ export class BoundStagesList extends Table<FlowStageBinding> {
|
|||||||
|
|
||||||
renderEmpty(): TemplateResult {
|
renderEmpty(): TemplateResult {
|
||||||
return super.renderEmpty(
|
return super.renderEmpty(
|
||||||
html`<ak-empty-state header=${msg("No Stages bound")} icon="pf-icon-module">
|
html`<ak-empty-state icon="pf-icon-module">
|
||||||
|
<span slot="header">${msg("No Stages bound")}</span>
|
||||||
<div slot="body">${msg("No stages are currently bound to this flow.")}</div>
|
<div slot="body">${msg("No stages are currently bound to this flow.")}</div>
|
||||||
<div slot="primary">
|
<div slot="primary">
|
||||||
<ak-stage-wizard
|
<ak-stage-wizard
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { DesignationToLabel, LayoutToLabel } from "@goauthentik/admin/flows/util
|
|||||||
import { policyEngineModes } from "@goauthentik/admin/policies/PolicyEngineModes";
|
import { policyEngineModes } from "@goauthentik/admin/policies/PolicyEngineModes";
|
||||||
import { AuthenticationEnum } from "@goauthentik/api/dist/models/AuthenticationEnum";
|
import { AuthenticationEnum } from "@goauthentik/api/dist/models/AuthenticationEnum";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
|
import "@goauthentik/components/ak-slug-input.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||||
@ -91,17 +92,16 @@ export class FlowForm extends WithCapabilitiesConfig(ModelForm<Flow, string>) {
|
|||||||
/>
|
/>
|
||||||
<p class="pf-c-form__helper-text">${msg("Shown as the Title in Flow pages.")}</p>
|
<p class="pf-c-form__helper-text">${msg("Shown as the Title in Flow pages.")}</p>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal label=${msg("Slug")} required name="slug">
|
|
||||||
<input
|
<ak-slug-input
|
||||||
type="text"
|
name="slug"
|
||||||
value="${ifDefined(this.instance?.slug)}"
|
value=${ifDefined(this.instance?.slug)}
|
||||||
class="pf-c-form-control pf-m-monospace"
|
label=${msg("Slug")}
|
||||||
autocomplete="off"
|
required
|
||||||
spellcheck="false"
|
help=${msg("Visible in the URL.")}
|
||||||
required
|
input-hint="code"
|
||||||
/>
|
></ak-slug-input>
|
||||||
<p class="pf-c-form__helper-text">${msg("Visible in the URL.")}</p>
|
|
||||||
</ak-form-element-horizontal>
|
|
||||||
<ak-form-element-horizontal label=${msg("Designation")} required name="designation">
|
<ak-form-element-horizontal label=${msg("Designation")} required name="designation">
|
||||||
<select class="pf-c-form-control">
|
<select class="pf-c-form-control">
|
||||||
<option value="" ?selected=${this.instance?.designation === undefined}>
|
<option value="" ?selected=${this.instance?.designation === undefined}>
|
||||||
|
|||||||
@ -198,7 +198,8 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
|
|||||||
|
|
||||||
renderEmpty(): TemplateResult {
|
renderEmpty(): TemplateResult {
|
||||||
return super.renderEmpty(
|
return super.renderEmpty(
|
||||||
html`<ak-empty-state header=${msg("No Policies bound.")} icon="pf-icon-module">
|
html`<ak-empty-state icon="pf-icon-module"
|
||||||
|
><span slot="header">${msg("No Policies bound.")}</span>
|
||||||
<div slot="body">${msg("No policies are currently bound to this object.")}</div>
|
<div slot="body">${msg("No policies are currently bound to this object.")}</div>
|
||||||
<div slot="primary">
|
<div slot="primary">
|
||||||
<ak-policy-wizard
|
<ak-policy-wizard
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import {
|
|||||||
FlowsInstancesListDesignationEnum,
|
FlowsInstancesListDesignationEnum,
|
||||||
PropertymappingsApi,
|
PropertymappingsApi,
|
||||||
PropertymappingsProviderSamlListRequest,
|
PropertymappingsProviderSamlListRequest,
|
||||||
|
SAMLNameIDPolicyEnum,
|
||||||
SAMLPropertyMapping,
|
SAMLPropertyMapping,
|
||||||
SAMLProvider,
|
SAMLProvider,
|
||||||
SpBindingEnum,
|
SpBindingEnum,
|
||||||
@ -316,6 +317,54 @@ export function renderForm(
|
|||||||
"When using IDP-initiated logins, the relay state will be set to this value.",
|
"When using IDP-initiated logins, the relay state will be set to this value.",
|
||||||
)}
|
)}
|
||||||
></ak-text-input>
|
></ak-text-input>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${msg("Default NameID Policy")}
|
||||||
|
required
|
||||||
|
name="defaultNameIdPolicy"
|
||||||
|
>
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
<option
|
||||||
|
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
|
||||||
|
?selected=${provider?.defaultNameIdPolicy ===
|
||||||
|
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
|
||||||
|
>
|
||||||
|
${msg("Persistent")}
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
|
||||||
|
?selected=${provider?.defaultNameIdPolicy ===
|
||||||
|
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
|
||||||
|
>
|
||||||
|
${msg("Email address")}
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
|
||||||
|
?selected=${provider?.defaultNameIdPolicy ===
|
||||||
|
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
|
||||||
|
>
|
||||||
|
${msg("Windows")}
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
|
||||||
|
?selected=${provider?.defaultNameIdPolicy ===
|
||||||
|
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
|
||||||
|
>
|
||||||
|
${msg("X509 Subject")}
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
|
||||||
|
?selected=${provider?.defaultNameIdPolicy ===
|
||||||
|
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
|
||||||
|
>
|
||||||
|
${msg("Transient")}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<p class="pf-c-form__helper-text">
|
||||||
|
${msg(
|
||||||
|
"Configure the default NameID Policy used by IDP-initiated logins and when an incoming assertion doesn't specify a NameID Policy (also applies when using a custom NameID Mapping).",
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
<ak-radio-input
|
<ak-radio-input
|
||||||
name="digestAlgorithm"
|
name="digestAlgorithm"
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import {
|
|||||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
||||||
import "@goauthentik/components/ak-secret-text-input.js";
|
import "@goauthentik/components/ak-secret-text-input.js";
|
||||||
import "@goauthentik/components/ak-secret-textarea-input.js";
|
import "@goauthentik/components/ak-secret-textarea-input.js";
|
||||||
|
import "@goauthentik/components/ak-slug-input.js";
|
||||||
import "@goauthentik/components/ak-switch-input";
|
import "@goauthentik/components/ak-switch-input";
|
||||||
import "@goauthentik/components/ak-text-input";
|
import "@goauthentik/components/ak-text-input";
|
||||||
import "@goauthentik/components/ak-textarea-input";
|
import "@goauthentik/components/ak-textarea-input";
|
||||||
@ -87,12 +88,13 @@ export class KerberosSourceForm extends WithCapabilitiesConfig(BaseSourceForm<Ke
|
|||||||
value=${ifDefined(this.instance?.name)}
|
value=${ifDefined(this.instance?.name)}
|
||||||
required
|
required
|
||||||
></ak-text-input>
|
></ak-text-input>
|
||||||
<ak-text-input
|
<ak-slug-input
|
||||||
name="slug"
|
name="slug"
|
||||||
label=${msg("Slug")}
|
|
||||||
value=${ifDefined(this.instance?.slug)}
|
value=${ifDefined(this.instance?.slug)}
|
||||||
|
label=${msg("Slug")}
|
||||||
required
|
required
|
||||||
></ak-text-input>
|
input-hint="code"
|
||||||
|
></ak-slug-input>
|
||||||
<ak-switch-input
|
<ak-switch-input
|
||||||
name="enabled"
|
name="enabled"
|
||||||
?checked=${this.instance?.enabled ?? true}
|
?checked=${this.instance?.enabled ?? true}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { placeholderHelperText } from "@goauthentik/admin/helperText";
|
|||||||
import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm";
|
import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import "@goauthentik/components/ak-secret-text-input.js";
|
import "@goauthentik/components/ak-secret-text-input.js";
|
||||||
|
import "@goauthentik/components/ak-slug-input.js";
|
||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
@ -54,14 +55,15 @@ export class LDAPSourceForm extends BaseSourceForm<LDAPSource> {
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal label=${msg("Slug")} required name="slug">
|
|
||||||
<input
|
<ak-slug-input
|
||||||
type="text"
|
name="slug"
|
||||||
value="${ifDefined(this.instance?.slug)}"
|
value=${ifDefined(this.instance?.slug)}
|
||||||
class="pf-c-form-control"
|
label=${msg("Slug")}
|
||||||
required
|
required
|
||||||
/>
|
input-hint="code"
|
||||||
</ak-form-element-horizontal>
|
></ak-slug-input>
|
||||||
|
|
||||||
<ak-form-element-horizontal name="enabled">
|
<ak-form-element-horizontal name="enabled">
|
||||||
<label class="pf-c-switch">
|
<label class="pf-c-switch">
|
||||||
<input
|
<input
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import {
|
|||||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
||||||
import "@goauthentik/components/ak-radio-input";
|
import "@goauthentik/components/ak-radio-input";
|
||||||
import "@goauthentik/components/ak-secret-textarea-input.js";
|
import "@goauthentik/components/ak-secret-textarea-input.js";
|
||||||
|
import "@goauthentik/components/ak-slug-input.js";
|
||||||
import "@goauthentik/elements/CodeMirror";
|
import "@goauthentik/elements/CodeMirror";
|
||||||
import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror";
|
import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror";
|
||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
@ -267,16 +268,13 @@ export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuth
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal label=${msg("Slug")} required name="slug">
|
<ak-slug-input
|
||||||
<input
|
name="slug"
|
||||||
type="text"
|
value=${ifDefined(this.instance?.slug)}
|
||||||
value="${ifDefined(this.instance?.slug)}"
|
label=${msg("Slug")}
|
||||||
class="pf-c-form-control pf-m-monospace"
|
required
|
||||||
autocomplete="off"
|
input-hint="code"
|
||||||
spellcheck="false"
|
></ak-slug-input>
|
||||||
required
|
|
||||||
/>
|
|
||||||
</ak-form-element-horizontal>
|
|
||||||
<ak-form-element-horizontal name="enabled">
|
<ak-form-element-horizontal name="enabled">
|
||||||
<label class="pf-c-switch">
|
<label class="pf-c-switch">
|
||||||
<input
|
<input
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import {
|
|||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import { PlexAPIClient, PlexResource, popupCenterScreen } from "@goauthentik/common/helpers/plex";
|
import { PlexAPIClient, PlexResource, popupCenterScreen } from "@goauthentik/common/helpers/plex";
|
||||||
import { ascii_letters, digits, randomString } from "@goauthentik/common/utils";
|
import { ascii_letters, digits, randomString } from "@goauthentik/common/utils";
|
||||||
|
import "@goauthentik/components/ak-slug-input.js";
|
||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider.js";
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider.js";
|
||||||
@ -183,14 +184,15 @@ export class PlexSourceForm extends WithCapabilitiesConfig(BaseSourceForm<PlexSo
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal label=${msg("Slug")} required name="slug">
|
|
||||||
<input
|
<ak-slug-input
|
||||||
type="text"
|
name="slug"
|
||||||
value="${ifDefined(this.instance?.slug)}"
|
value=${ifDefined(this.instance?.slug)}
|
||||||
class="pf-c-form-control"
|
label=${msg("Slug")}
|
||||||
required
|
required
|
||||||
/>
|
input-hint="code"
|
||||||
</ak-form-element-horizontal>
|
></ak-slug-input>
|
||||||
|
|
||||||
<ak-form-element-horizontal name="enabled">
|
<ak-form-element-horizontal name="enabled">
|
||||||
<label class="pf-c-switch">
|
<label class="pf-c-switch">
|
||||||
<input
|
<input
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import {
|
|||||||
UserMatchingModeToLabel,
|
UserMatchingModeToLabel,
|
||||||
} from "@goauthentik/admin/sources/oauth/utils";
|
} from "@goauthentik/admin/sources/oauth/utils";
|
||||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
||||||
|
import "@goauthentik/components/ak-slug-input.js";
|
||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
@ -25,7 +26,7 @@ import {
|
|||||||
DigestAlgorithmEnum,
|
DigestAlgorithmEnum,
|
||||||
FlowsInstancesListDesignationEnum,
|
FlowsInstancesListDesignationEnum,
|
||||||
GroupMatchingModeEnum,
|
GroupMatchingModeEnum,
|
||||||
NameIdPolicyEnum,
|
SAMLNameIDPolicyEnum,
|
||||||
SAMLSource,
|
SAMLSource,
|
||||||
SignatureAlgorithmEnum,
|
SignatureAlgorithmEnum,
|
||||||
SourcesApi,
|
SourcesApi,
|
||||||
@ -89,14 +90,15 @@ export class SAMLSourceForm extends WithCapabilitiesConfig(BaseSourceForm<SAMLSo
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal label=${msg("Slug")} required name="slug">
|
|
||||||
<input
|
<ak-slug-input
|
||||||
type="text"
|
name="slug"
|
||||||
value="${ifDefined(this.instance?.slug)}"
|
value=${ifDefined(this.instance?.slug)}
|
||||||
class="pf-c-form-control"
|
label=${msg("Slug")}
|
||||||
required
|
required
|
||||||
/>
|
input-hint="code"
|
||||||
</ak-form-element-horizontal>
|
></ak-slug-input>
|
||||||
|
|
||||||
<ak-form-element-horizontal name="enabled">
|
<ak-form-element-horizontal name="enabled">
|
||||||
<label class="pf-c-switch">
|
<label class="pf-c-switch">
|
||||||
<input
|
<input
|
||||||
@ -351,37 +353,37 @@ export class SAMLSourceForm extends WithCapabilitiesConfig(BaseSourceForm<SAMLSo
|
|||||||
>
|
>
|
||||||
<select class="pf-c-form-control">
|
<select class="pf-c-form-control">
|
||||||
<option
|
<option
|
||||||
value=${NameIdPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
|
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
|
||||||
?selected=${this.instance?.nameIdPolicy ===
|
?selected=${this.instance?.nameIdPolicy ===
|
||||||
NameIdPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
|
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
|
||||||
>
|
>
|
||||||
${msg("Persistent")}
|
${msg("Persistent")}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
value=${NameIdPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
|
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
|
||||||
?selected=${this.instance?.nameIdPolicy ===
|
?selected=${this.instance?.nameIdPolicy ===
|
||||||
NameIdPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
|
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
|
||||||
>
|
>
|
||||||
${msg("Email address")}
|
${msg("Email address")}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
value=${NameIdPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
|
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
|
||||||
?selected=${this.instance?.nameIdPolicy ===
|
?selected=${this.instance?.nameIdPolicy ===
|
||||||
NameIdPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
|
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
|
||||||
>
|
>
|
||||||
${msg("Windows")}
|
${msg("Windows")}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
value=${NameIdPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
|
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
|
||||||
?selected=${this.instance?.nameIdPolicy ===
|
?selected=${this.instance?.nameIdPolicy ===
|
||||||
NameIdPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
|
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
|
||||||
>
|
>
|
||||||
${msg("X509 Subject")}
|
${msg("X509 Subject")}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
value=${NameIdPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
|
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
|
||||||
?selected=${this.instance?.nameIdPolicy ===
|
?selected=${this.instance?.nameIdPolicy ===
|
||||||
NameIdPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
|
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
|
||||||
>
|
>
|
||||||
${msg("Transient")}
|
${msg("Transient")}
|
||||||
</option>
|
</option>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { placeholderHelperText } from "@goauthentik/admin/helperText";
|
import { placeholderHelperText } from "@goauthentik/admin/helperText";
|
||||||
import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm";
|
import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
|
import "@goauthentik/components/ak-slug-input.js";
|
||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
@ -48,14 +49,15 @@ export class SCIMSourceForm extends BaseSourceForm<SCIMSource> {
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal label=${msg("Slug")} required name="slug">
|
|
||||||
<input
|
<ak-slug-input
|
||||||
type="text"
|
name="slug"
|
||||||
value="${ifDefined(this.instance?.slug)}"
|
value=${ifDefined(this.instance?.slug)}
|
||||||
class="pf-c-form-control"
|
label=${msg("Slug")}
|
||||||
required
|
required
|
||||||
/>
|
input-hint="code"
|
||||||
</ak-form-element-horizontal>
|
></ak-slug-input>
|
||||||
|
|
||||||
<ak-form-element-horizontal name="enabled">
|
<ak-form-element-horizontal name="enabled">
|
||||||
<div class="pf-c-check">
|
<div class="pf-c-check">
|
||||||
<input
|
<input
|
||||||
|
|||||||
@ -41,14 +41,27 @@ export class InvitationForm extends ModelForm<Invitation, string> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
return html` <ak-form-element-horizontal slugMode label=${msg("Name")} required name="name">
|
const checkSlug = (ev: InputEvent) => {
|
||||||
|
if (ev && ev.target && ev.target instanceof HTMLInputElement) {
|
||||||
|
ev.target.value = (ev.target.value ?? "").replace(/[^a-z0-9-]/g, "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
id="admin-stages-invitation-name"
|
||||||
value="${this.instance?.name || ""}"
|
value="${this.instance?.name || ""}"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
required
|
required
|
||||||
|
@input=${(ev: InputEvent) => checkSlug(ev)}
|
||||||
data-ak-slug="true"
|
data-ak-slug="true"
|
||||||
/>
|
/>
|
||||||
|
<p class="pf-c-form__helper-text">
|
||||||
|
${msg(
|
||||||
|
"The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.",
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal label=${msg("Expires")} required name="expires">
|
<ak-form-element-horizontal label=${msg("Expires")} required name="expires">
|
||||||
<input
|
<input
|
||||||
|
|||||||
@ -1,21 +1,5 @@
|
|||||||
import * as base64js from "base64-js";
|
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
|
|
||||||
export function b64enc(buf: Uint8Array): string {
|
|
||||||
return base64js.fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
export function b64RawEnc(buf: Uint8Array): string {
|
|
||||||
return base64js.fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_");
|
|
||||||
}
|
|
||||||
|
|
||||||
export function u8arr(input: string): Uint8Array {
|
|
||||||
return Uint8Array.from(atob(input.replace(/_/g, "/").replace(/-/g, "+")), (c) =>
|
|
||||||
c.charCodeAt(0),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function checkWebAuthnSupport() {
|
export function checkWebAuthnSupport() {
|
||||||
if ("credentials" in navigator) {
|
if ("credentials" in navigator) {
|
||||||
return;
|
return;
|
||||||
@ -25,121 +9,3 @@ export function checkWebAuthnSupport() {
|
|||||||
}
|
}
|
||||||
throw new Error(msg("WebAuthn not supported by browser."));
|
throw new Error(msg("WebAuthn not supported by browser."));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms items in the credentialCreateOptions generated on the server
|
|
||||||
* into byte arrays expected by the navigator.credentials.create() call
|
|
||||||
*/
|
|
||||||
export function transformCredentialCreateOptions(
|
|
||||||
credentialCreateOptions: PublicKeyCredentialCreationOptions,
|
|
||||||
userId: string,
|
|
||||||
): PublicKeyCredentialCreationOptions {
|
|
||||||
const user = credentialCreateOptions.user;
|
|
||||||
// Because json can't contain raw bytes, the server base64-encodes the User ID
|
|
||||||
// So to get the base64 encoded byte array, we first need to convert it to a regular
|
|
||||||
// string, then a byte array, re-encode it and wrap that in an array.
|
|
||||||
const stringId = decodeURIComponent(window.atob(userId));
|
|
||||||
user.id = u8arr(b64enc(u8arr(stringId)));
|
|
||||||
const challenge = u8arr(credentialCreateOptions.challenge.toString());
|
|
||||||
|
|
||||||
return {
|
|
||||||
...credentialCreateOptions,
|
|
||||||
challenge,
|
|
||||||
user,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Assertion {
|
|
||||||
id: string;
|
|
||||||
rawId: string;
|
|
||||||
type: string;
|
|
||||||
registrationClientExtensions: string;
|
|
||||||
response: {
|
|
||||||
clientDataJSON: string;
|
|
||||||
attestationObject: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms the binary data in the credential into base64 strings
|
|
||||||
* for posting to the server.
|
|
||||||
* @param {PublicKeyCredential} newAssertion
|
|
||||||
*/
|
|
||||||
export function transformNewAssertionForServer(newAssertion: PublicKeyCredential): Assertion {
|
|
||||||
const attObj = new Uint8Array(
|
|
||||||
(newAssertion.response as AuthenticatorAttestationResponse).attestationObject,
|
|
||||||
);
|
|
||||||
const clientDataJSON = new Uint8Array(newAssertion.response.clientDataJSON);
|
|
||||||
const rawId = new Uint8Array(newAssertion.rawId);
|
|
||||||
|
|
||||||
const registrationClientExtensions = newAssertion.getClientExtensionResults();
|
|
||||||
return {
|
|
||||||
id: newAssertion.id,
|
|
||||||
rawId: b64enc(rawId),
|
|
||||||
type: newAssertion.type,
|
|
||||||
registrationClientExtensions: JSON.stringify(registrationClientExtensions),
|
|
||||||
response: {
|
|
||||||
clientDataJSON: b64enc(clientDataJSON),
|
|
||||||
attestationObject: b64enc(attObj),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function transformCredentialRequestOptions(
|
|
||||||
credentialRequestOptions: PublicKeyCredentialRequestOptions,
|
|
||||||
): PublicKeyCredentialRequestOptions {
|
|
||||||
const challenge = u8arr(credentialRequestOptions.challenge.toString());
|
|
||||||
|
|
||||||
const allowCredentials = (credentialRequestOptions.allowCredentials || []).map(
|
|
||||||
(credentialDescriptor) => {
|
|
||||||
const id = u8arr(credentialDescriptor.id.toString());
|
|
||||||
return Object.assign({}, credentialDescriptor, { id });
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
...credentialRequestOptions,
|
|
||||||
challenge,
|
|
||||||
allowCredentials,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AuthAssertion {
|
|
||||||
id: string;
|
|
||||||
rawId: string;
|
|
||||||
type: string;
|
|
||||||
assertionClientExtensions: string;
|
|
||||||
response: {
|
|
||||||
clientDataJSON: string;
|
|
||||||
authenticatorData: string;
|
|
||||||
signature: string;
|
|
||||||
userHandle: string | null;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes the binary data in the assertion into strings for posting to the server.
|
|
||||||
* @param {PublicKeyCredential} newAssertion
|
|
||||||
*/
|
|
||||||
export function transformAssertionForServer(newAssertion: PublicKeyCredential): AuthAssertion {
|
|
||||||
const response = newAssertion.response as AuthenticatorAssertionResponse;
|
|
||||||
const authData = new Uint8Array(response.authenticatorData);
|
|
||||||
const clientDataJSON = new Uint8Array(response.clientDataJSON);
|
|
||||||
const rawId = new Uint8Array(newAssertion.rawId);
|
|
||||||
const sig = new Uint8Array(response.signature);
|
|
||||||
const assertionClientExtensions = newAssertion.getClientExtensionResults();
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: newAssertion.id,
|
|
||||||
rawId: b64enc(rawId),
|
|
||||||
type: newAssertion.type,
|
|
||||||
assertionClientExtensions: JSON.stringify(assertionClientExtensions),
|
|
||||||
|
|
||||||
response: {
|
|
||||||
clientDataJSON: b64RawEnc(clientDataJSON),
|
|
||||||
signature: b64RawEnc(sig),
|
|
||||||
authenticatorData: b64RawEnc(authData),
|
|
||||||
userHandle: null,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { me } from "@goauthentik/common/users.js";
|
import { me } from "@goauthentik/common/users.js";
|
||||||
import { isUserRoute } from "@goauthentik/elements/router/utils.js";
|
import { isUserRoute } from "@goauthentik/elements/router/utils.js";
|
||||||
|
import { deepmerge, deepmergeInto } from "deepmerge-ts";
|
||||||
|
|
||||||
import { UiThemeEnum, UserSelf } from "@goauthentik/api";
|
import { UiThemeEnum, UserSelf } from "@goauthentik/api";
|
||||||
import { CurrentBrand } from "@goauthentik/api";
|
import { CurrentBrand } from "@goauthentik/api";
|
||||||
@ -96,13 +97,12 @@ export class DefaultUIConfig implements UIConfig {
|
|||||||
let globalUiConfig: Promise<UIConfig>;
|
let globalUiConfig: Promise<UIConfig>;
|
||||||
|
|
||||||
export function getConfigForUser(user: UserSelf): UIConfig {
|
export function getConfigForUser(user: UserSelf): UIConfig {
|
||||||
const settings = user.settings;
|
const settings = user.settings as UIConfig;
|
||||||
let config = new DefaultUIConfig();
|
const config = new DefaultUIConfig();
|
||||||
if (!settings) {
|
if (!settings) {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
config = Object.assign(new DefaultUIConfig(), settings);
|
return deepmerge({ ...config }, settings);
|
||||||
return config;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function uiConfig(): Promise<UIConfig> {
|
export function uiConfig(): Promise<UIConfig> {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { formatSlug } from "@goauthentik/elements/router/utils.js";
|
import { bound } from "@goauthentik/elements/decorators/bound.js";
|
||||||
|
import { kebabCase } from "change-case";
|
||||||
|
|
||||||
import { html } from "lit";
|
import { html } from "lit";
|
||||||
import { customElement, property, query } from "lit/decorators.js";
|
import { customElement, property, query } from "lit/decorators.js";
|
||||||
@ -6,59 +7,83 @@ import { ifDefined } from "lit/directives/if-defined.js";
|
|||||||
|
|
||||||
import { HorizontalLightComponent } from "./HorizontalLightComponent";
|
import { HorizontalLightComponent } from "./HorizontalLightComponent";
|
||||||
|
|
||||||
|
const slugify = (s: string) => kebabCase(s, { suffixCharacters: "-" });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @element ak-slug-input
|
||||||
|
* @class AkSlugInput
|
||||||
|
*
|
||||||
|
* A wrapper around `ak-form-element-horizontal` and a text input control that listens for input on
|
||||||
|
* a peer text input control and automatically mirrors that control's value, transforming the value
|
||||||
|
* into a slug and displaying it separately.
|
||||||
|
*
|
||||||
|
* If the user manually changes the slug, mirroring and transformation stop. If, after that, both
|
||||||
|
* fields are cleared manually, mirroring and transformation resume.
|
||||||
|
*
|
||||||
|
* ## Limitations:
|
||||||
|
*
|
||||||
|
* Both the source text field and the slug field must be rendered in the same render pass (i.e.,
|
||||||
|
* part of the same singular call to a `render` function) so that the slug field can find its
|
||||||
|
* source.
|
||||||
|
*
|
||||||
|
* For the same reason, both the source text field and the slug field must share the same immediate
|
||||||
|
* parent DOM object.
|
||||||
|
*
|
||||||
|
* Since we expect the source text field and the slug to be part of the same form and rendered not
|
||||||
|
* just in the same form but in the same form group, these are not considered burdensome
|
||||||
|
* restrictions.
|
||||||
|
*/
|
||||||
@customElement("ak-slug-input")
|
@customElement("ak-slug-input")
|
||||||
export class AkSlugInput extends HorizontalLightComponent<string> {
|
export class AkSlugInput extends HorizontalLightComponent<string> {
|
||||||
@property({ type: String, reflect: true })
|
/**
|
||||||
value = "";
|
* A selector indicating the source text input control. Must be unique within the whole DOM
|
||||||
|
* context of the slug and source controls. The most common use in authentik is the default:
|
||||||
|
* slugifying the "name" of something.
|
||||||
|
*/
|
||||||
@property({ type: String })
|
@property({ type: String })
|
||||||
source = "";
|
public source = "[name='name']";
|
||||||
|
|
||||||
origin?: HTMLInputElement | null;
|
@property({ type: String, reflect: true })
|
||||||
|
public value = "";
|
||||||
|
|
||||||
@query("input")
|
@query("input")
|
||||||
input!: HTMLInputElement;
|
private input!: HTMLInputElement;
|
||||||
|
|
||||||
touched: boolean = false;
|
#origin?: HTMLInputElement | null;
|
||||||
|
|
||||||
constructor() {
|
#touched: boolean = false;
|
||||||
super();
|
|
||||||
this.slugify = this.slugify.bind(this);
|
|
||||||
this.handleTouch = this.handleTouch.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
firstUpdated() {
|
|
||||||
this.input.addEventListener("input", this.handleTouch);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not stop propagation of this event; it must be sent up the tree so that a parent
|
// Do not stop propagation of this event; it must be sent up the tree so that a parent
|
||||||
// component, such as a custom forms manager, may receive it.
|
// component, such as a custom forms manager, may receive it.
|
||||||
handleTouch(ev: Event) {
|
protected handleTouch(ev: Event) {
|
||||||
this.input.value = formatSlug(this.input.value);
|
this.value = this.input.value = slugify(this.input.value);
|
||||||
this.value = this.input.value;
|
|
||||||
|
|
||||||
if (this.origin && this.origin.value === "" && this.input.value === "") {
|
// Reset 'touched' status if the slug & target have been reset
|
||||||
this.touched = false;
|
if (this.#origin && this.#origin.value === "" && this.input.value === "") {
|
||||||
|
this.#touched = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ev && ev.target && ev.target instanceof HTMLInputElement) {
|
if (ev && ev.target && ev.target instanceof HTMLInputElement) {
|
||||||
this.touched = true;
|
this.#touched = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
slugify(ev: Event) {
|
@bound
|
||||||
|
protected slugify(ev: Event) {
|
||||||
if (!(ev && ev.target && ev.target instanceof HTMLInputElement)) {
|
if (!(ev && ev.target && ev.target instanceof HTMLInputElement)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset 'touched' status if the slug & target have been reset
|
// Reset 'touched' status if the slug & target have been reset
|
||||||
if (ev.target.value === "" && this.input.value === "") {
|
if (ev.target.value === "" && this.input.value === "") {
|
||||||
this.touched = false;
|
this.#touched = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't proceed if the user has hand-modified the slug
|
// Don't proceed if the user has hand-modified the slug. (Note the order of statements: if
|
||||||
if (this.touched) {
|
// the user hand modified the slug to be empty as part of resetting the slug/source
|
||||||
|
// relationship, that's a "not-touched" condition and falls through.)
|
||||||
|
if (this.#touched) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +92,7 @@ export class AkSlugInput extends HorizontalLightComponent<string> {
|
|||||||
// "any event which adds or removes a character but leaves the rest of the slug looking like
|
// "any event which adds or removes a character but leaves the rest of the slug looking like
|
||||||
// the previous iteration, set it to the current iteration."
|
// the previous iteration, set it to the current iteration."
|
||||||
|
|
||||||
const newSlug = formatSlug(ev.target.value);
|
const newSlug = slugify(ev.target.value);
|
||||||
const oldSlug = this.input.value;
|
const oldSlug = this.input.value;
|
||||||
const [shorter, longer] =
|
const [shorter, longer] =
|
||||||
newSlug.length < oldSlug.length ? [newSlug, oldSlug] : [oldSlug, newSlug];
|
newSlug.length < oldSlug.length ? [newSlug, oldSlug] : [oldSlug, newSlug];
|
||||||
@ -81,7 +106,6 @@ export class AkSlugInput extends HorizontalLightComponent<string> {
|
|||||||
// to listeners, both the name and value of the host must match those of the target
|
// to listeners, both the name and value of the host must match those of the target
|
||||||
// input. The name is already handled since it's both required and automatically
|
// input. The name is already handled since it's both required and automatically
|
||||||
// forwarded to our templated input, but the value must also be set.
|
// forwarded to our templated input, but the value must also be set.
|
||||||
|
|
||||||
this.value = this.input.value = newSlug;
|
this.value = this.input.value = newSlug;
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new Event("input", {
|
new Event("input", {
|
||||||
@ -91,38 +115,36 @@ export class AkSlugInput extends HorizontalLightComponent<string> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
public override disconnectedCallback() {
|
||||||
super.connectedCallback();
|
if (this.#origin) {
|
||||||
|
this.#origin.removeEventListener("input", this.slugify);
|
||||||
// Set up listener on source element, so we can slugify the content.
|
|
||||||
setTimeout(() => {
|
|
||||||
if (this.source) {
|
|
||||||
const rootNode = this.getRootNode();
|
|
||||||
if (rootNode instanceof ShadowRoot || rootNode instanceof Document) {
|
|
||||||
this.origin = rootNode.querySelector(this.source);
|
|
||||||
}
|
|
||||||
if (this.origin) {
|
|
||||||
this.origin.addEventListener("input", this.slugify);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
disconnectedCallback() {
|
|
||||||
if (this.origin) {
|
|
||||||
this.origin.removeEventListener("input", this.slugify);
|
|
||||||
}
|
}
|
||||||
super.disconnectedCallback();
|
super.disconnectedCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
renderControl() {
|
public override renderControl() {
|
||||||
return html`<input
|
return html`<input
|
||||||
|
@input=${(ev: Event) => this.handleTouch(ev)}
|
||||||
type="text"
|
type="text"
|
||||||
value=${ifDefined(this.value)}
|
value=${ifDefined(this.value)}
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
?required=${this.required}
|
?required=${this.required}
|
||||||
/>`;
|
/>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override firstUpdated() {
|
||||||
|
if (!this.source) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rootNode = this.getRootNode();
|
||||||
|
if (rootNode instanceof ShadowRoot || rootNode instanceof Document) {
|
||||||
|
this.#origin = rootNode.querySelector(this.source);
|
||||||
|
}
|
||||||
|
if (this.#origin) {
|
||||||
|
this.#origin.addEventListener("input", this.slugify);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AkSlugInput;
|
export default AkSlugInput;
|
||||||
|
|||||||
@ -94,7 +94,8 @@ export class ObjectChangelog extends Table<Event> {
|
|||||||
|
|
||||||
renderEmpty(): TemplateResult {
|
renderEmpty(): TemplateResult {
|
||||||
return super.renderEmpty(
|
return super.renderEmpty(
|
||||||
html`<ak-empty-state header=${msg("No Events found.")}>
|
html`<ak-empty-state
|
||||||
|
><span slot="header">${msg("No Events found.")}</span>
|
||||||
<div slot="body">${msg("No matching events could be found.")}</div>
|
<div slot="body">${msg("No matching events could be found.")}</div>
|
||||||
</ak-empty-state>`,
|
</ak-empty-state>`,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -66,7 +66,8 @@ export class UserEvents extends Table<Event> {
|
|||||||
|
|
||||||
renderEmpty(): TemplateResult {
|
renderEmpty(): TemplateResult {
|
||||||
return super.renderEmpty(
|
return super.renderEmpty(
|
||||||
html`<ak-empty-state header=${msg("No Events found.")}>
|
html`<ak-empty-state
|
||||||
|
><span slot="header">${msg("No Events found.")}</span>
|
||||||
<div slot="body">${msg("No matching events could be found.")}</div>
|
<div slot="body">${msg("No matching events could be found.")}</div>
|
||||||
</ak-empty-state>`,
|
</ak-empty-state>`,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { AKElement } from "@goauthentik/elements/Base";
|
|||||||
import "@goauthentik/elements/Spinner";
|
import "@goauthentik/elements/Spinner";
|
||||||
import { type SlottedTemplateResult, type Spread } from "@goauthentik/elements/types";
|
import { type SlottedTemplateResult, type Spread } from "@goauthentik/elements/types";
|
||||||
import { spread } from "@open-wc/lit-helpers";
|
import { spread } from "@open-wc/lit-helpers";
|
||||||
|
import { SlotController } from "@patternfly/pfe-core/controllers/slot-controller.js";
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { css, html, nothing } from "lit";
|
import { css, html, nothing } from "lit";
|
||||||
@ -33,6 +34,8 @@ export class EmptyState extends AKElement implements IEmptyState {
|
|||||||
@property()
|
@property()
|
||||||
header?: string;
|
header?: string;
|
||||||
|
|
||||||
|
slots = new SlotController(this, "header", "body", "primary");
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return [
|
return [
|
||||||
PFBase,
|
PFBase,
|
||||||
@ -48,6 +51,12 @@ export class EmptyState extends AKElement implements IEmptyState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const showHeader = this.loading || this.slots.hasSlotted("header");
|
||||||
|
const header = () =>
|
||||||
|
this.slots.hasSlotted("header")
|
||||||
|
? html`<slot name="header"></slot>`
|
||||||
|
: html`<span>${msg("Loading")}</span>`;
|
||||||
|
|
||||||
return html`<div class="pf-c-empty-state ${this.fullHeight && "pf-m-full-height"}">
|
return html`<div class="pf-c-empty-state ${this.fullHeight && "pf-m-full-height"}">
|
||||||
<div class="pf-c-empty-state__content">
|
<div class="pf-c-empty-state__content">
|
||||||
${this.loading
|
${this.loading
|
||||||
@ -59,15 +68,17 @@ export class EmptyState extends AKElement implements IEmptyState {
|
|||||||
"fa-question-circle"} pf-c-empty-state__icon"
|
"fa-question-circle"} pf-c-empty-state__icon"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>`}
|
></i>`}
|
||||||
<h1 class="pf-c-title pf-m-lg">
|
${showHeader ? html` <h1 class="pf-c-title pf-m-lg">${header()}</h1>` : nothing}
|
||||||
${this.loading && this.header === undefined ? msg("Loading") : this.header}
|
${this.slots.hasSlotted("body")
|
||||||
</h1>
|
? html` <div class="pf-c-empty-state__body">
|
||||||
<div class="pf-c-empty-state__body">
|
<slot name="body"></slot>
|
||||||
<slot name="body"></slot>
|
</div>`
|
||||||
</div>
|
: nothing}
|
||||||
<div class="pf-c-empty-state__primary">
|
${this.slots.hasSlotted("primary")
|
||||||
<slot name="primary"></slot>
|
? html` <div class="pf-c-empty-state__primary">
|
||||||
</div>
|
<slot name="primary"></slot>
|
||||||
|
</div>`
|
||||||
|
: nothing}
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -200,7 +200,8 @@ export abstract class AKChart<T> extends AKElement {
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
${this.error
|
${this.error
|
||||||
? html`
|
? html`
|
||||||
<ak-empty-state header="${msg("Failed to fetch data.")}" icon="fa-times">
|
<ak-empty-state icon="fa-times"
|
||||||
|
><span slot="header">${msg("Failed to fetch data.")}</span>
|
||||||
<p slot="body">${pluckErrorDetail(this.error)}</p>
|
<p slot="body">${pluckErrorDetail(this.error)}</p>
|
||||||
</ak-empty-state>
|
</ak-empty-state>
|
||||||
`
|
`
|
||||||
|
|||||||
@ -40,7 +40,9 @@ export class LogViewer extends Table<LogEvent> {
|
|||||||
|
|
||||||
renderEmpty(): TemplateResult {
|
renderEmpty(): TemplateResult {
|
||||||
return super.renderEmpty(
|
return super.renderEmpty(
|
||||||
html`<ak-empty-state header=${msg("No log messages.")}> </ak-empty-state>`,
|
html`<ak-empty-state
|
||||||
|
><span slot="header">${msg("No log messages.")}</span>
|
||||||
|
</ak-empty-state>`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import { AKElement } from "@goauthentik/elements/Base";
|
|||||||
import { HorizontalFormElement } from "@goauthentik/elements/forms/HorizontalFormElement";
|
import { HorizontalFormElement } from "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import { PreventFormSubmit } from "@goauthentik/elements/forms/helpers";
|
import { PreventFormSubmit } from "@goauthentik/elements/forms/helpers";
|
||||||
import { showMessage } from "@goauthentik/elements/messages/MessageContainer";
|
import { showMessage } from "@goauthentik/elements/messages/MessageContainer";
|
||||||
import { formatSlug } from "@goauthentik/elements/router/utils.js";
|
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||||
@ -197,39 +196,6 @@ export abstract class Form<T> extends AKElement {
|
|||||||
return this.successMessage;
|
return this.successMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* After rendering the form, if there is both a `name` and `slug` element within the form,
|
|
||||||
* events the `name` element so that the slug will always have a slugified version of the
|
|
||||||
* `name.`. This duplicates functionality within ak-form-element-horizontal.
|
|
||||||
*/
|
|
||||||
updated(): void {
|
|
||||||
this.shadowRoot
|
|
||||||
?.querySelectorAll("ak-form-element-horizontal[name=name]")
|
|
||||||
.forEach((nameInput) => {
|
|
||||||
const input = nameInput.firstElementChild as HTMLInputElement;
|
|
||||||
const form = nameInput.closest("form");
|
|
||||||
if (form === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const slugFieldWrapper = form.querySelector(
|
|
||||||
"ak-form-element-horizontal[name=slug]",
|
|
||||||
);
|
|
||||||
if (!slugFieldWrapper) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const slugField = slugFieldWrapper.firstElementChild as HTMLInputElement;
|
|
||||||
// Only attach handler if the slug is already equal to the name
|
|
||||||
// if not, they are probably completely different and shouldn't update
|
|
||||||
// each other
|
|
||||||
if (formatSlug(input.value) !== slugField.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
nameInput.addEventListener("input", () => {
|
|
||||||
slugField.value = formatSlug(input.value);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
resetForm(): void {
|
resetForm(): void {
|
||||||
const form = this.shadowRoot?.querySelector<HTMLFormElement>("form");
|
const form = this.shadowRoot?.querySelector<HTMLFormElement>("form");
|
||||||
form?.reset();
|
form?.reset();
|
||||||
|
|||||||
@ -77,9 +77,6 @@ export class HorizontalFormElement extends AKElement {
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
errorMessages: string[] | string[][] = [];
|
errorMessages: string[] | string[][] = [];
|
||||||
|
|
||||||
@property({ type: Boolean })
|
|
||||||
slugMode = false;
|
|
||||||
|
|
||||||
_invalid = false;
|
_invalid = false;
|
||||||
|
|
||||||
/* If this property changes, we want to make sure the parent control is "opened" so
|
/* If this property changes, we want to make sure the parent control is "opened" so
|
||||||
@ -109,13 +106,6 @@ export class HorizontalFormElement extends AKElement {
|
|||||||
this.querySelectorAll<HTMLInputElement>("input[autofocus]").forEach((input) => {
|
this.querySelectorAll<HTMLInputElement>("input[autofocus]").forEach((input) => {
|
||||||
input.focus();
|
input.focus();
|
||||||
});
|
});
|
||||||
if (this.name === "slug" || this.slugMode) {
|
|
||||||
this.querySelectorAll<HTMLInputElement>("input[type='text']").forEach((input) => {
|
|
||||||
input.addEventListener("keyup", () => {
|
|
||||||
input.value = formatSlug(input.value);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.querySelectorAll("*").forEach((input) => {
|
this.querySelectorAll("*").forEach((input) => {
|
||||||
if (isAkControl(input) && !input.getAttribute("name")) {
|
if (isAkControl(input) && !input.getAttribute("name")) {
|
||||||
input.setAttribute("name", this.name);
|
input.setAttribute("name", this.name);
|
||||||
|
|||||||
@ -163,7 +163,8 @@ export class NotificationDrawer extends AKElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderEmpty() {
|
renderEmpty() {
|
||||||
return html`<ak-empty-state header=${msg("No notifications found.")}>
|
return html`<ak-empty-state
|
||||||
|
><span slot="header">${msg("No notifications found.")}</span>
|
||||||
<div slot="body">${msg("You don't have any notifications currently.")}</div>
|
<div slot="body">${msg("You don't have any notifications currently.")}</div>
|
||||||
</ak-empty-state>`;
|
</ak-empty-state>`;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -288,7 +288,9 @@ export abstract class Table<T> extends AKElement implements TableLike {
|
|||||||
return html`<tr role="row">
|
return html`<tr role="row">
|
||||||
<td role="cell" colspan="25">
|
<td role="cell" colspan="25">
|
||||||
<div class="pf-l-bullseye">
|
<div class="pf-l-bullseye">
|
||||||
<ak-empty-state loading header=${msg("Loading")}></ak-empty-state>
|
<ak-empty-state loading
|
||||||
|
><span slot="header">${msg("Loading")}</span></ak-empty-state
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>`;
|
</tr>`;
|
||||||
@ -300,8 +302,9 @@ export abstract class Table<T> extends AKElement implements TableLike {
|
|||||||
<td role="cell" colspan="8">
|
<td role="cell" colspan="8">
|
||||||
<div class="pf-l-bullseye">
|
<div class="pf-l-bullseye">
|
||||||
${inner ??
|
${inner ??
|
||||||
html`<ak-empty-state header="${msg("No objects found.")}"
|
html`<ak-empty-state
|
||||||
><div slot="primary">${this.renderObjectCreate()}</div>
|
><span slot="header">${msg("No objects found.")}</span> >
|
||||||
|
<div slot="primary">${this.renderObjectCreate()}</div>
|
||||||
</ak-empty-state>`}
|
</ak-empty-state>`}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@ -316,7 +319,8 @@ export abstract class Table<T> extends AKElement implements TableLike {
|
|||||||
renderError(): SlottedTemplateResult {
|
renderError(): SlottedTemplateResult {
|
||||||
if (!this.error) return nothing;
|
if (!this.error) return nothing;
|
||||||
|
|
||||||
return html`<ak-empty-state header="${msg("Failed to fetch objects.")}" icon="fa-ban">
|
return html`<ak-empty-state icon="fa-ban"
|
||||||
|
><span slot="header">${msg("Failed to fetch objects.")}</span>
|
||||||
<div slot="body">${pluckErrorDetail(this.error)}</div>
|
<div slot="body">${pluckErrorDetail(this.error)}</div>
|
||||||
</ak-empty-state>`;
|
</ak-empty-state>`;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,11 @@ describe("ak-empty-state", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should render the default loader", async () => {
|
it("should render the default loader", async () => {
|
||||||
render(html`<ak-empty-state loading header=${msg("Loading")}> </ak-empty-state>`);
|
render(
|
||||||
|
html`<ak-empty-state loading
|
||||||
|
><span slot="header">${msg("Loading")}</span>
|
||||||
|
</ak-empty-state>`,
|
||||||
|
);
|
||||||
|
|
||||||
const empty = await $("ak-empty-state").$(">>>.pf-c-empty-state__icon");
|
const empty = await $("ak-empty-state").$(">>>.pf-c-empty-state__icon");
|
||||||
await expect(empty).toExist();
|
await expect(empty).toExist();
|
||||||
@ -29,7 +33,11 @@ describe("ak-empty-state", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should handle standard boolean", async () => {
|
it("should handle standard boolean", async () => {
|
||||||
render(html`<ak-empty-state loading header=${msg("Loading")}> </ak-empty-state>`);
|
render(
|
||||||
|
html`<ak-empty-state loading
|
||||||
|
><span slot="header">${msg("Loading")}</span>
|
||||||
|
</ak-empty-state>`,
|
||||||
|
);
|
||||||
|
|
||||||
const empty = await $("ak-empty-state").$(">>>.pf-c-empty-state__icon");
|
const empty = await $("ak-empty-state").$(">>>.pf-c-empty-state__icon");
|
||||||
await expect(empty).toExist();
|
await expect(empty).toExist();
|
||||||
@ -39,7 +47,11 @@ describe("ak-empty-state", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should render a static empty state", async () => {
|
it("should render a static empty state", async () => {
|
||||||
render(html`<ak-empty-state header=${msg("No messages found")}> </ak-empty-state>`);
|
render(
|
||||||
|
html`<ak-empty-state
|
||||||
|
><span slot="header">${msg("No messages found")}</span>
|
||||||
|
</ak-empty-state>`,
|
||||||
|
);
|
||||||
|
|
||||||
const empty = await $("ak-empty-state").$(">>>.pf-c-empty-state__icon");
|
const empty = await $("ak-empty-state").$(">>>.pf-c-empty-state__icon");
|
||||||
await expect(empty).toExist();
|
await expect(empty).toExist();
|
||||||
@ -51,7 +63,8 @@ describe("ak-empty-state", () => {
|
|||||||
|
|
||||||
it("should render a slotted message", async () => {
|
it("should render a slotted message", async () => {
|
||||||
render(
|
render(
|
||||||
html`<ak-empty-state header=${msg("No messages found")}>
|
html`<ak-empty-state
|
||||||
|
><span slot="header">${msg("No messages found")}</span>
|
||||||
<p slot="body">Try again with a different filter</p>
|
<p slot="body">Try again with a different filter</p>
|
||||||
</ak-empty-state>`,
|
</ak-empty-state>`,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,8 +1,4 @@
|
|||||||
import {
|
import { checkWebAuthnSupport } from "@goauthentik/common/helpers/webauthn";
|
||||||
checkWebAuthnSupport,
|
|
||||||
transformAssertionForServer,
|
|
||||||
transformCredentialRequestOptions,
|
|
||||||
} from "@goauthentik/common/helpers/webauthn";
|
|
||||||
import "@goauthentik/elements/EmptyState";
|
import "@goauthentik/elements/EmptyState";
|
||||||
import { BaseDeviceStage } from "@goauthentik/flow/stages/authenticator_validate/base";
|
import { BaseDeviceStage } from "@goauthentik/flow/stages/authenticator_validate/base";
|
||||||
|
|
||||||
@ -38,12 +34,12 @@ export class AuthenticatorValidateStageWebAuthn extends BaseDeviceStage<
|
|||||||
async authenticate(): Promise<void> {
|
async authenticate(): Promise<void> {
|
||||||
// request the authenticator to create an assertion signature using the
|
// request the authenticator to create an assertion signature using the
|
||||||
// credential private key
|
// credential private key
|
||||||
let assertion;
|
let assertion: PublicKeyCredential;
|
||||||
checkWebAuthnSupport();
|
checkWebAuthnSupport();
|
||||||
try {
|
try {
|
||||||
assertion = await navigator.credentials.get({
|
assertion = (await navigator.credentials.get({
|
||||||
publicKey: this.transformedCredentialRequestOptions,
|
publicKey: this.transformedCredentialRequestOptions,
|
||||||
});
|
})) as PublicKeyCredential;
|
||||||
if (!assertion) {
|
if (!assertion) {
|
||||||
throw new Error("Assertions is empty");
|
throw new Error("Assertions is empty");
|
||||||
}
|
}
|
||||||
@ -51,17 +47,11 @@ export class AuthenticatorValidateStageWebAuthn extends BaseDeviceStage<
|
|||||||
throw new Error(`Error when creating credential: ${err}`);
|
throw new Error(`Error when creating credential: ${err}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we now have an authentication assertion! encode the byte arrays contained
|
|
||||||
// in the assertion data as strings for posting to the server
|
|
||||||
const transformedAssertionForServer = transformAssertionForServer(
|
|
||||||
assertion as PublicKeyCredential,
|
|
||||||
);
|
|
||||||
|
|
||||||
// post the assertion to the server for verification.
|
// post the assertion to the server for verification.
|
||||||
try {
|
try {
|
||||||
await this.host?.submit(
|
await this.host?.submit(
|
||||||
{
|
{
|
||||||
webauthn: transformedAssertionForServer,
|
webauthn: assertion.toJSON(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
invisible: true,
|
invisible: true,
|
||||||
@ -74,12 +64,10 @@ export class AuthenticatorValidateStageWebAuthn extends BaseDeviceStage<
|
|||||||
|
|
||||||
updated(changedProperties: PropertyValues<this>) {
|
updated(changedProperties: PropertyValues<this>) {
|
||||||
if (changedProperties.has("challenge") && this.challenge !== undefined) {
|
if (changedProperties.has("challenge") && this.challenge !== undefined) {
|
||||||
// convert certain members of the PublicKeyCredentialRequestOptions into
|
|
||||||
// byte arrays as expected by the spec.
|
|
||||||
const credentialRequestOptions = this.deviceChallenge
|
const credentialRequestOptions = this.deviceChallenge
|
||||||
?.challenge as PublicKeyCredentialRequestOptions;
|
?.challenge as unknown as PublicKeyCredentialRequestOptionsJSON;
|
||||||
this.transformedCredentialRequestOptions =
|
this.transformedCredentialRequestOptions =
|
||||||
transformCredentialRequestOptions(credentialRequestOptions);
|
PublicKeyCredential.parseRequestOptionsFromJSON(credentialRequestOptions);
|
||||||
this.authenticateWrapper();
|
this.authenticateWrapper();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,4 @@
|
|||||||
import {
|
import { checkWebAuthnSupport } from "@goauthentik/common/helpers/webauthn";
|
||||||
Assertion,
|
|
||||||
checkWebAuthnSupport,
|
|
||||||
transformCredentialCreateOptions,
|
|
||||||
transformNewAssertionForServer,
|
|
||||||
} from "@goauthentik/common/helpers/webauthn";
|
|
||||||
import "@goauthentik/elements/EmptyState";
|
import "@goauthentik/elements/EmptyState";
|
||||||
import { BaseStage } from "@goauthentik/flow/stages/base";
|
import { BaseStage } from "@goauthentik/flow/stages/base";
|
||||||
|
|
||||||
@ -24,10 +19,6 @@ import {
|
|||||||
AuthenticatorWebAuthnChallengeResponseRequest,
|
AuthenticatorWebAuthnChallengeResponseRequest,
|
||||||
} from "@goauthentik/api";
|
} from "@goauthentik/api";
|
||||||
|
|
||||||
export interface WebAuthnAuthenticatorRegisterChallengeResponse {
|
|
||||||
response: Assertion;
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("ak-stage-authenticator-webauthn")
|
@customElement("ak-stage-authenticator-webauthn")
|
||||||
export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
|
export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
|
||||||
AuthenticatorWebAuthnChallenge,
|
AuthenticatorWebAuthnChallenge,
|
||||||
@ -68,7 +59,7 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
|
|||||||
}
|
}
|
||||||
checkWebAuthnSupport();
|
checkWebAuthnSupport();
|
||||||
// request the authenticator(s) to create a new credential keypair.
|
// request the authenticator(s) to create a new credential keypair.
|
||||||
let credential;
|
let credential: PublicKeyCredential;
|
||||||
try {
|
try {
|
||||||
credential = (await navigator.credentials.create({
|
credential = (await navigator.credentials.create({
|
||||||
publicKey: this.publicKeyCredentialCreateOptions,
|
publicKey: this.publicKeyCredentialCreateOptions,
|
||||||
@ -80,16 +71,12 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
|
|||||||
throw new Error(msg(str`Error creating credential: ${err}`));
|
throw new Error(msg(str`Error creating credential: ${err}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
// we now have a new credential! We now need to encode the byte arrays
|
|
||||||
// in the credential into strings, for posting to our server.
|
|
||||||
const newAssertionForServer = transformNewAssertionForServer(credential);
|
|
||||||
|
|
||||||
// post the transformed credential data to the server for validation
|
// post the transformed credential data to the server for validation
|
||||||
// and storing the public key
|
// and storing the public key
|
||||||
try {
|
try {
|
||||||
await this.host?.submit(
|
await this.host?.submit(
|
||||||
{
|
{
|
||||||
response: newAssertionForServer,
|
response: credential.toJSON(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
invisible: true,
|
invisible: true,
|
||||||
@ -118,12 +105,10 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
|
|||||||
|
|
||||||
updated(changedProperties: PropertyValues<this>) {
|
updated(changedProperties: PropertyValues<this>) {
|
||||||
if (changedProperties.has("challenge") && this.challenge !== undefined) {
|
if (changedProperties.has("challenge") && this.challenge !== undefined) {
|
||||||
// convert certain members of the PublicKeyCredentialCreateOptions into
|
this.publicKeyCredentialCreateOptions =
|
||||||
// byte arrays as expected by the spec.
|
PublicKeyCredential.parseCreationOptionsFromJSON(
|
||||||
this.publicKeyCredentialCreateOptions = transformCredentialCreateOptions(
|
this.challenge?.registration as PublicKeyCredentialCreationOptionsJSON,
|
||||||
this.challenge?.registration as PublicKeyCredentialCreationOptions,
|
);
|
||||||
this.challenge?.registration.user.id,
|
|
||||||
);
|
|
||||||
this.registerWrapper();
|
this.registerWrapper();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import "construct-style-sheets-polyfill";
|
|||||||
import "@webcomponents/webcomponentsjs";
|
import "@webcomponents/webcomponentsjs";
|
||||||
import "lit/polyfill-support.js";
|
import "lit/polyfill-support.js";
|
||||||
import "core-js/actual";
|
import "core-js/actual";
|
||||||
|
import "webauthn-polyfills";
|
||||||
|
|
||||||
import "@formatjs/intl-listformat/polyfill";
|
import "@formatjs/intl-listformat/polyfill";
|
||||||
import "@formatjs/intl-listformat/locale-data/en";
|
import "@formatjs/intl-listformat/locale-data/en";
|
||||||
|
|||||||
2
web/types/node.d.ts
vendored
2
web/types/node.d.ts
vendored
@ -14,7 +14,7 @@ declare module "module" {
|
|||||||
* const relativeDirname = dirname(fileURLToPath(import.meta.url));
|
* const relativeDirname = dirname(fileURLToPath(import.meta.url));
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line no-var
|
|
||||||
var __dirname: string;
|
var __dirname: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9245,6 +9245,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s4f820625804ed29b">
|
<trans-unit id="s4f820625804ed29b">
|
||||||
<source>Re-authenticate with Plex</source>
|
<source>Re-authenticate with Plex</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s0433d667ea6eec1a">
|
||||||
|
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@ -7753,6 +7753,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s4f820625804ed29b">
|
<trans-unit id="s4f820625804ed29b">
|
||||||
<source>Re-authenticate with Plex</source>
|
<source>Re-authenticate with Plex</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s0433d667ea6eec1a">
|
||||||
|
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@ -9305,6 +9305,9 @@ Las vinculaciones a grupos o usuarios se comparan con el usuario del evento.</ta
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s4f820625804ed29b">
|
<trans-unit id="s4f820625804ed29b">
|
||||||
<source>Re-authenticate with Plex</source>
|
<source>Re-authenticate with Plex</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s0433d667ea6eec1a">
|
||||||
|
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@ -9874,6 +9874,9 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s4f820625804ed29b">
|
<trans-unit id="s4f820625804ed29b">
|
||||||
<source>Re-authenticate with Plex</source>
|
<source>Re-authenticate with Plex</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s0433d667ea6eec1a">
|
||||||
|
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@ -9857,6 +9857,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s4f820625804ed29b">
|
<trans-unit id="s4f820625804ed29b">
|
||||||
<source>Re-authenticate with Plex</source>
|
<source>Re-authenticate with Plex</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s0433d667ea6eec1a">
|
||||||
|
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@ -9213,6 +9213,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s4f820625804ed29b">
|
<trans-unit id="s4f820625804ed29b">
|
||||||
<source>Re-authenticate with Plex</source>
|
<source>Re-authenticate with Plex</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s0433d667ea6eec1a">
|
||||||
|
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@ -9117,6 +9117,9 @@ Bindingen naar groepen/gebruikers worden gecontroleerd tegen de gebruiker van de
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s4f820625804ed29b">
|
<trans-unit id="s4f820625804ed29b">
|
||||||
<source>Re-authenticate with Plex</source>
|
<source>Re-authenticate with Plex</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s0433d667ea6eec1a">
|
||||||
|
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@ -9540,6 +9540,9 @@ Powiązania z grupami/użytkownikami są sprawdzane względem użytkownika zdarz
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s4f820625804ed29b">
|
<trans-unit id="s4f820625804ed29b">
|
||||||
<source>Re-authenticate with Plex</source>
|
<source>Re-authenticate with Plex</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s0433d667ea6eec1a">
|
||||||
|
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@ -9549,4 +9549,7 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
<trans-unit id="s4f820625804ed29b">
|
<trans-unit id="s4f820625804ed29b">
|
||||||
<source>Re-authenticate with Plex</source>
|
<source>Re-authenticate with Plex</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="s0433d667ea6eec1a">
|
||||||
|
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||||
|
</trans-unit>
|
||||||
</body></file></xliff>
|
</body></file></xliff>
|
||||||
|
|||||||
@ -9632,6 +9632,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s4f820625804ed29b">
|
<trans-unit id="s4f820625804ed29b">
|
||||||
<source>Re-authenticate with Plex</source>
|
<source>Re-authenticate with Plex</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s0433d667ea6eec1a">
|
||||||
|
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@ -9604,6 +9604,9 @@ Gruplara/kullanıcılara yapılan bağlamalar, etkinliğin kullanıcısına kar
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s4f820625804ed29b">
|
<trans-unit id="s4f820625804ed29b">
|
||||||
<source>Re-authenticate with Plex</source>
|
<source>Re-authenticate with Plex</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s0433d667ea6eec1a">
|
||||||
|
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@ -6368,6 +6368,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
<trans-unit id="s4f820625804ed29b">
|
<trans-unit id="s4f820625804ed29b">
|
||||||
<source>Re-authenticate with Plex</source>
|
<source>Re-authenticate with Plex</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="s0433d667ea6eec1a">
|
||||||
|
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|||||||
@ -9878,12 +9878,18 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sf9686d31d28fcf7d">
|
<trans-unit id="sf9686d31d28fcf7d">
|
||||||
<source>Show field content</source>
|
<source>Show field content</source>
|
||||||
|
<target>显示字段内容</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sb1b05a7573ab618c">
|
<trans-unit id="sb1b05a7573ab618c">
|
||||||
<source>Hide field content</source>
|
<source>Hide field content</source>
|
||||||
|
<target>隐藏字段内容</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s4f820625804ed29b">
|
<trans-unit id="s4f820625804ed29b">
|
||||||
<source>Re-authenticate with Plex</source>
|
<source>Re-authenticate with Plex</source>
|
||||||
|
<target>使用 Plex 重新验证身份</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s0433d667ea6eec1a">
|
||||||
|
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@ -7453,6 +7453,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s4f820625804ed29b">
|
<trans-unit id="s4f820625804ed29b">
|
||||||
<source>Re-authenticate with Plex</source>
|
<source>Re-authenticate with Plex</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s0433d667ea6eec1a">
|
||||||
|
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@ -3011,11 +3011,6 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||||||
<source>Load servers</source>
|
<source>Load servers</source>
|
||||||
<target>加载服务器</target>
|
<target>加载服务器</target>
|
||||||
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="s24f405197ede5ebb">
|
|
||||||
<source>Re-authenticate with plex</source>
|
|
||||||
<target>使用 Plex 重新验证身份</target>
|
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sc297b2e13c28ecf9">
|
<trans-unit id="sc297b2e13c28ecf9">
|
||||||
<source>Allow friends to authenticate via Plex, even if you don't share any servers</source>
|
<source>Allow friends to authenticate via Plex, even if you don't share any servers</source>
|
||||||
@ -9880,6 +9875,18 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
<trans-unit id="sb3d5c0a0501669df">
|
<trans-unit id="sb3d5c0a0501669df">
|
||||||
<source>Generate New Certificate-Key Pair</source>
|
<source>Generate New Certificate-Key Pair</source>
|
||||||
<target>生成新的证书密钥对</target>
|
<target>生成新的证书密钥对</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sf9686d31d28fcf7d">
|
||||||
|
<source>Show field content</source>
|
||||||
|
<target>显示字段内容</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sb1b05a7573ab618c">
|
||||||
|
<source>Hide field content</source>
|
||||||
|
<target>隐藏字段内容</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s4f820625804ed29b">
|
||||||
|
<source>Re-authenticate with Plex</source>
|
||||||
|
<target>使用 Plex 重新验证身份</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@ -9192,6 +9192,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s4f820625804ed29b">
|
<trans-unit id="s4f820625804ed29b">
|
||||||
<source>Re-authenticate with Plex</source>
|
<source>Re-authenticate with Plex</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s0433d667ea6eec1a">
|
||||||
|
<source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@ -70,9 +70,6 @@ To check if your config has been applied correctly, you can run the following co
|
|||||||
- `AUTHENTIK_POSTGRESQL__USER`: Database user
|
- `AUTHENTIK_POSTGRESQL__USER`: Database user
|
||||||
- `AUTHENTIK_POSTGRESQL__PORT`: Database port, defaults to 5432
|
- `AUTHENTIK_POSTGRESQL__PORT`: Database port, defaults to 5432
|
||||||
- `AUTHENTIK_POSTGRESQL__PASSWORD`: Database password, defaults to the environment variable `POSTGRES_PASSWORD`
|
- `AUTHENTIK_POSTGRESQL__PASSWORD`: Database password, defaults to the environment variable `POSTGRES_PASSWORD`
|
||||||
{/* TODO: Temporarily deactivated feature, see https://github.com/goauthentik/authentik/issues/14320 */}
|
|
||||||
{/* - `AUTHENTIK_POSTGRESQL__USE_POOL`: Use a [connection pool](https://docs.djangoproject.com/en/stable/ref/databases/#connection-pool) for PostgreSQL connections. Defaults to `false`. :ak-version[2025.4] */}
|
|
||||||
{/* - `AUTHENTIK_POSTGRESQL__POOL_OPTIONS`: Extra configuration to pass to the [ConnectionPool object](https://www.psycopg.org/psycopg3/docs/api/pool.html#psycopg_pool.ConnectionPool) when it is created. Must be a base64-encoded JSON dictionary. Ignored when `USE_POOL` is set to `false`. :ak-version[2025.4] */}
|
|
||||||
- `AUTHENTIK_POSTGRESQL__USE_PGBOUNCER`: Adjust configuration to support connection to PgBouncer. Deprecated, see below
|
- `AUTHENTIK_POSTGRESQL__USE_PGBOUNCER`: Adjust configuration to support connection to PgBouncer. Deprecated, see below
|
||||||
- `AUTHENTIK_POSTGRESQL__USE_PGPOOL`: Adjust configuration to support connection to Pgpool. Deprecated, see below
|
- `AUTHENTIK_POSTGRESQL__USE_PGPOOL`: Adjust configuration to support connection to Pgpool. Deprecated, see below
|
||||||
- `AUTHENTIK_POSTGRESQL__SSLMODE`: Strictness of ssl verification. Defaults to `"verify-ca"`
|
- `AUTHENTIK_POSTGRESQL__SSLMODE`: Strictness of ssl verification. Defaults to `"verify-ca"`
|
||||||
@ -85,7 +82,7 @@ To check if your config has been applied correctly, you can run the following co
|
|||||||
|
|
||||||
The PostgreSQL settings `HOST`, `PORT`, `USER`, and `PASSWORD` support hot-reloading. Adding and removing read replicas doesn't support hot-reloading.
|
The PostgreSQL settings `HOST`, `PORT`, `USER`, and `PASSWORD` support hot-reloading. Adding and removing read replicas doesn't support hot-reloading.
|
||||||
|
|
||||||
- `AUTHENTIK_POSTGRESQL__DEFAULT_SCHEMA`:ak-version[2024.12]
|
- `AUTHENTIK_POSTGRESQL__DEFAULT_SCHEMA` :ak-version[2024.12]
|
||||||
|
|
||||||
The name of the schema used by default in the database. Defaults to `public`.
|
The name of the schema used by default in the database. Defaults to `public`.
|
||||||
|
|
||||||
|
|||||||
@ -142,6 +142,17 @@ helm upgrade authentik authentik/authentik -f values.yaml --version ^2025.6
|
|||||||
- tenants: fix tenant aware celery scheduler (cherry-pick #14921)
|
- tenants: fix tenant aware celery scheduler (cherry-pick #14921)
|
||||||
- web/user: fix user settings flow not loading (cherry-pick #14911) (#14930)
|
- web/user: fix user settings flow not loading (cherry-pick #14911) (#14930)
|
||||||
|
|
||||||
|
## Fixed in 2025.6.2
|
||||||
|
|
||||||
|
- brands: fix custom_css being escaped (cherry-pick #14994) (#14996)
|
||||||
|
- core: bump django from 5.1.10 to 5.1.11 (cherry-pick #14997) (#15010)
|
||||||
|
- core: bump django from 5.1.9 to 5.1.10 (cherry-pick #14951) (#15008)
|
||||||
|
- internal/outpost: fix incorrect usage of golang SHA API (cherry-pick #14981) (#14982)
|
||||||
|
- providers/rac: fixes prompt data not being merged with connection_settings (cherry-pick #15037) (#15038)
|
||||||
|
- stages/email: Only attach logo to email if used (cherry-pick #14835) (#14969)
|
||||||
|
- web/elements: fix dual select without sortBy (cherry-pick #14977) (#14979)
|
||||||
|
- web/elements: fix typo in localeComparator (cherry-pick #15054) (#15055)
|
||||||
|
|
||||||
## API Changes
|
## API Changes
|
||||||
|
|
||||||
#### What's New
|
#### What's New
|
||||||
|
|||||||
@ -27,3 +27,29 @@ uv run ak create_recovery_key 10 akadmin
|
|||||||
```
|
```
|
||||||
|
|
||||||
This will output a link, that can be used to instantly gain access to authentik as the user specified above. The link is valid for amount of years specified above, in this case, 10 years.
|
This will output a link, that can be used to instantly gain access to authentik as the user specified above. The link is valid for amount of years specified above, in this case, 10 years.
|
||||||
|
|
||||||
|
## Can't access initial setup flow during installation steps
|
||||||
|
|
||||||
|
If you're unable to access the initial setup flow (`/if/flow/initial-setup/`) immediately after installing authentik, first try restarting the containers because this often resolves temporary issues.
|
||||||
|
|
||||||
|
However, if the issue persists after restarting, you can directly set the admin password using the following commands:
|
||||||
|
|
||||||
|
Docker Compose deployments:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose exec server ak changepassword akadmin
|
||||||
|
```
|
||||||
|
|
||||||
|
Kubernetes deployments:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl exec -it deployment/authentik-server -c server -- ak changepassword akadmin
|
||||||
|
```
|
||||||
|
|
||||||
|
After following the prompts to set a new password, you can then login via: `https://authentik.company/if/flow/default-authentication-flow/?next=%2F`
|
||||||
|
|
||||||
|
After logging in, you can set the email address and other settings for the account by navigating to **Directory** > **Users** and editing the user account.
|
||||||
|
|
||||||
|
:::note
|
||||||
|
This method bypasses the initial setup flow and should only be used as a last resort. The initial setup flow is the recommended method to configure the administrator user.
|
||||||
|
:::
|
||||||
|
|||||||
@ -49,7 +49,7 @@ After you are connected, execute these commands to create a database backup:
|
|||||||
cd /bitnami/postgresql/
|
cd /bitnami/postgresql/
|
||||||
|
|
||||||
# Set the PostgreSQL password from environment variable
|
# Set the PostgreSQL password from environment variable
|
||||||
export PGPASSWORD=$POSTGRES_POSTGRES_PASSWORD
|
export PGPASSWORD=$(cat $POSTGRES_PASSWORD_FILE)
|
||||||
|
|
||||||
# Create a full database dump
|
# Create a full database dump
|
||||||
pg_dump -U $POSTGRES_USER $POSTGRES_DB > /bitnami/postgresql/dump.sql
|
pg_dump -U $POSTGRES_USER $POSTGRES_DB > /bitnami/postgresql/dump.sql
|
||||||
@ -117,7 +117,7 @@ cd /bitnami/postgresql/
|
|||||||
ls -lh dump.sql
|
ls -lh dump.sql
|
||||||
|
|
||||||
# Set the PostgreSQL password
|
# Set the PostgreSQL password
|
||||||
export PGPASSWORD=$POSTGRES_POSTGRES_PASSWORD
|
export PGPASSWORD=$(cat $POSTGRES_PASSWORD_FILE)
|
||||||
|
|
||||||
# Import the database dump
|
# Import the database dump
|
||||||
psql -U $POSTGRES_USER $POSTGRES_DB < dump.sql
|
psql -U $POSTGRES_USER $POSTGRES_DB < dump.sql
|
||||||
|
|||||||
@ -81,7 +81,7 @@ If you want to control user storage and designate Nextcloud administrators, you
|
|||||||
- **Create Scope Mapping**:
|
- **Create Scope Mapping**:
|
||||||
|
|
||||||
- **Name**: `Nextcloud Profile`
|
- **Name**: `Nextcloud Profile`
|
||||||
- **Scope name**: `profile`
|
- **Scope name**: `nextcloud`
|
||||||
- **Expression**:
|
- **Expression**:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@ -146,7 +146,7 @@ Depending on your Nextcloud configuration, you may need to use `https://nextclou
|
|||||||
- **Client ID**: Client ID from authentik
|
- **Client ID**: Client ID from authentik
|
||||||
- **Client secret**: Client secret from authentik
|
- **Client secret**: Client secret from authentik
|
||||||
- **Discovery endpoint**: `https://authentik.company/application/o/<application_slug>/.well-known/openid-configuration`
|
- **Discovery endpoint**: `https://authentik.company/application/o/<application_slug>/.well-known/openid-configuration`
|
||||||
- **Scope**: `email profile openid`
|
- **Scope**: `email nextcloud openid`
|
||||||
- Under **Attribute mappings**:
|
- Under **Attribute mappings**:
|
||||||
|
|
||||||
- **User ID mapping**: `sub` (or `user_id` for existing users)
|
- **User ID mapping**: `sub` (or `user_id` for existing users)
|
||||||
@ -161,6 +161,10 @@ Depending on your Nextcloud configuration, you may need to use `https://nextclou
|
|||||||
|
|
||||||
- **Use unique user ID**: If this option is disabled, Nextcloud will use the mapped user ID as the Federated Cloud ID.
|
- **Use unique user ID**: If this option is disabled, Nextcloud will use the mapped user ID as the Federated Cloud ID.
|
||||||
|
|
||||||
|
:::note
|
||||||
|
If authentik and Nextcloud are running on the same host, you will need to add `'allow_local_remote_servers' => true` to your nextcloud `config.php` file. This setting allows remote servers with local addresses.
|
||||||
|
:::
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
To avoid a hashed Federated Cloud ID, deselect **Use unique user ID** and use `user_id` for the User ID mapping.
|
To avoid a hashed Federated Cloud ID, deselect **Use unique user ID** and use `user_id` for the User ID mapping.
|
||||||
:::
|
:::
|
||||||
|
|||||||
@ -40,6 +40,7 @@ To support the integration of Zipline with authentik, you need to create an appl
|
|||||||
- Note the **Client ID** and **Client Secret** values because they will be required later.
|
- Note the **Client ID** and **Client Secret** values because they will be required later.
|
||||||
- Set a `Strict` redirect URI to `https://zipline.company/api/auth/oauth/oidc`.
|
- Set a `Strict` redirect URI to `https://zipline.company/api/auth/oauth/oidc`.
|
||||||
- Select any available signing key.
|
- Select any available signing key.
|
||||||
|
- Under **Advanced Protocol Settings** > **Scopes**, add `authentik default OAuth Mapping: OpenID 'offline_access'` to the **Selected Scopes** list.
|
||||||
- **Configure Bindings** _(optional)_: Create a [binding](/docs/add-secure-apps/flows-stages/bindings/) (policy, group, or user) to manage the listing and access to applications on a user's **My applications** page.
|
- **Configure Bindings** _(optional)_: Create a [binding](/docs/add-secure-apps/flows-stages/bindings/) (policy, group, or user) to manage the listing and access to applications on a user's **My applications** page.
|
||||||
|
|
||||||
3. Click **Submit** to save the new application and provider.
|
3. Click **Submit** to save the new application and provider.
|
||||||
|
|||||||
224
website/package-lock.json
generated
224
website/package-lock.json
generated
@ -19,11 +19,10 @@
|
|||||||
"@goauthentik/docusaurus-config": "^1.1.0",
|
"@goauthentik/docusaurus-config": "^1.1.0",
|
||||||
"@goauthentik/tsconfig": "^1.0.4",
|
"@goauthentik/tsconfig": "^1.0.4",
|
||||||
"@mdx-js/react": "^3.1.0",
|
"@mdx-js/react": "^3.1.0",
|
||||||
"@swc/html-linux-x64-gnu": "1.12.1",
|
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"docusaurus-plugin-openapi-docs": "^4.4.0",
|
"docusaurus-plugin-openapi-docs": "^4.4.0",
|
||||||
"docusaurus-theme-openapi-docs": "^4.4.0",
|
"docusaurus-theme-openapi-docs": "^4.4.0",
|
||||||
"postcss": "^8.5.5",
|
"postcss": "^8.5.6",
|
||||||
"prism-react-renderer": "^2.4.1",
|
"prism-react-renderer": "^2.4.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-before-after-slider-component": "^1.1.8",
|
"react-before-after-slider-component": "^1.1.8",
|
||||||
@ -36,26 +35,26 @@
|
|||||||
"@docusaurus/module-type-aliases": "^3.7.0",
|
"@docusaurus/module-type-aliases": "^3.7.0",
|
||||||
"@docusaurus/tsconfig": "^3.7.0",
|
"@docusaurus/tsconfig": "^3.7.0",
|
||||||
"@docusaurus/types": "^3.7.0",
|
"@docusaurus/types": "^3.7.0",
|
||||||
"@eslint/js": "^9.28.0",
|
"@eslint/js": "^9.29.0",
|
||||||
"@goauthentik/eslint-config": "^1.0.5",
|
"@goauthentik/eslint-config": "^1.0.5",
|
||||||
"@goauthentik/prettier-config": "^1.0.5",
|
"@goauthentik/prettier-config": "^1.0.5",
|
||||||
"@goauthentik/tsconfig": "^1.0.4",
|
"@goauthentik/tsconfig": "^1.0.4",
|
||||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||||
"@types/lodash": "^4.17.17",
|
"@types/lodash": "^4.17.18",
|
||||||
"@types/node": "^24.0.1",
|
"@types/node": "^24.0.3",
|
||||||
"@types/postman-collection": "^3.5.11",
|
"@types/postman-collection": "^3.5.11",
|
||||||
"@types/react": "^18.3.22",
|
"@types/react": "^18.3.22",
|
||||||
"@types/semver": "^7.7.0",
|
"@types/semver": "^7.7.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.34.0",
|
"@typescript-eslint/eslint-plugin": "^8.34.1",
|
||||||
"@typescript-eslint/parser": "^8.34.0",
|
"@typescript-eslint/parser": "^8.34.1",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^9.28.0",
|
"eslint": "^9.29.0",
|
||||||
"fast-glob": "^3.3.3",
|
"fast-glob": "^3.3.3",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"prettier-plugin-packagejson": "^2.5.15",
|
"prettier-plugin-packagejson": "^2.5.15",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"typescript-eslint": "^8.34.0"
|
"typescript-eslint": "^8.34.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22.14.0"
|
"node": ">=22.14.0"
|
||||||
@ -4209,9 +4208,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/config-array": {
|
"node_modules/@eslint/config-array": {
|
||||||
"version": "0.20.0",
|
"version": "0.20.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.1.tgz",
|
||||||
"integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==",
|
"integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -4308,9 +4307,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "9.28.0",
|
"version": "9.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.29.0.tgz",
|
||||||
"integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==",
|
"integrity": "sha512-3PIF4cBw/y+1u2EazflInpV+lYsSG0aByVIQzAgb1m1MhHFSbqTyNqtBKHgWf/9Ykud+DhILS9EGkmekVhbKoQ==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -6581,9 +6580,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/lodash": {
|
"node_modules/@types/lodash": {
|
||||||
"version": "4.17.17",
|
"version": "4.17.18",
|
||||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.17.tgz",
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.18.tgz",
|
||||||
"integrity": "sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==",
|
"integrity": "sha512-KJ65INaxqxmU6EoCiJmRPZC9H9RVWCRd349tXM2M3O5NA7cY6YL7c0bHAHQ93NOfTObEQ004kd2QVHs/r0+m4g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
@ -6615,9 +6614,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "24.0.1",
|
"version": "24.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.3.tgz",
|
||||||
"integrity": "sha512-MX4Zioh39chHlDJbKmEgydJDS3tspMP/lnQC67G3SWsTnb9NeYVWOjkxpOSy4oMfPs4StcWHwBrvUb4ybfnuaw==",
|
"integrity": "sha512-R4I/kzCYAdRLzfiCabn9hxWfbuHS573x+r0dJMkkzThEa7pbrcDWK+9zu3e7aBOouf+rQAciqPFMnxwr0aWgKg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~7.8.0"
|
"undici-types": "~7.8.0"
|
||||||
@ -6831,17 +6830,17 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.1.tgz",
|
||||||
"integrity": "sha512-QXwAlHlbcAwNlEEMKQS2RCgJsgXrTJdjXT08xEgbPFa2yYQgVjBymxP5DrfrE7X7iodSzd9qBUHUycdyVJTW1w==",
|
"integrity": "sha512-STXcN6ebF6li4PxwNeFnqF8/2BNDvBupf2OPx2yWNzr6mKNGF7q49VM00Pz5FaomJyqvbXpY6PhO+T9w139YEQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.10.0",
|
"@eslint-community/regexpp": "^4.10.0",
|
||||||
"@typescript-eslint/scope-manager": "8.34.0",
|
"@typescript-eslint/scope-manager": "8.34.1",
|
||||||
"@typescript-eslint/type-utils": "8.34.0",
|
"@typescript-eslint/type-utils": "8.34.1",
|
||||||
"@typescript-eslint/utils": "8.34.0",
|
"@typescript-eslint/utils": "8.34.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^7.0.0",
|
"ignore": "^7.0.0",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
@ -6855,7 +6854,7 @@
|
|||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@typescript-eslint/parser": "^8.34.0",
|
"@typescript-eslint/parser": "^8.34.1",
|
||||||
"eslint": "^8.57.0 || ^9.0.0",
|
"eslint": "^8.57.0 || ^9.0.0",
|
||||||
"typescript": ">=4.8.4 <5.9.0"
|
"typescript": ">=4.8.4 <5.9.0"
|
||||||
}
|
}
|
||||||
@ -6871,16 +6870,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.1.tgz",
|
||||||
"integrity": "sha512-vxXJV1hVFx3IXz/oy2sICsJukaBrtDEQSBiV48/YIV5KWjX1dO+bcIr/kCPrW6weKXvsaGKFNlwH0v2eYdRRbA==",
|
"integrity": "sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.34.0",
|
"@typescript-eslint/scope-manager": "8.34.1",
|
||||||
"@typescript-eslint/types": "8.34.0",
|
"@typescript-eslint/types": "8.34.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.34.0",
|
"@typescript-eslint/typescript-estree": "8.34.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -6896,14 +6895,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/project-service": {
|
"node_modules/@typescript-eslint/project-service": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.1.tgz",
|
||||||
"integrity": "sha512-iEgDALRf970/B2YExmtPMPF54NenZUf4xpL3wsCRx/lgjz6ul/l13R81ozP/ZNuXfnLCS+oPmG7JIxfdNYKELw==",
|
"integrity": "sha512-nuHlOmFZfuRwLJKDGQOVc0xnQrAmuq1Mj/ISou5044y1ajGNp2BNliIqp7F2LPQ5sForz8lempMFCovfeS1XoA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/tsconfig-utils": "^8.34.0",
|
"@typescript-eslint/tsconfig-utils": "^8.34.1",
|
||||||
"@typescript-eslint/types": "^8.34.0",
|
"@typescript-eslint/types": "^8.34.1",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -6918,14 +6917,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.1.tgz",
|
||||||
"integrity": "sha512-9Ac0X8WiLykl0aj1oYQNcLZjHgBojT6cW68yAgZ19letYu+Hxd0rE0veI1XznSSst1X5lwnxhPbVdwjDRIomRw==",
|
"integrity": "sha512-beu6o6QY4hJAgL1E8RaXNC071G4Kso2MGmJskCFQhRhg8VOH/FDbC8soP8NHN7e/Hdphwp8G8cE6OBzC8o41ZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.34.0",
|
"@typescript-eslint/types": "8.34.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.34.0"
|
"@typescript-eslint/visitor-keys": "8.34.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@ -6936,9 +6935,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.1.tgz",
|
||||||
"integrity": "sha512-+W9VYHKFIzA5cBeooqQxqNriAP0QeQ7xTiDuIOr71hzgffm3EL2hxwWBIIj4GuofIbKxGNarpKqIq6Q6YrShOA==",
|
"integrity": "sha512-K4Sjdo4/xF9NEeA2khOb7Y5nY6NSXBnod87uniVYW9kHP+hNlDV8trUSFeynA2uxWam4gIWgWoygPrv9VMWrYg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -6953,14 +6952,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.1.tgz",
|
||||||
"integrity": "sha512-n7zSmOcUVhcRYC75W2pnPpbO1iwhJY3NLoHEtbJwJSNlVAZuwqu05zY3f3s2SDWWDSo9FdN5szqc73DCtDObAg==",
|
"integrity": "sha512-Tv7tCCr6e5m8hP4+xFugcrwTOucB8lshffJ6zf1mF1TbU67R+ntCc6DzLNKM+s/uzDyv8gLq7tufaAhIBYeV8g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "8.34.0",
|
"@typescript-eslint/typescript-estree": "8.34.1",
|
||||||
"@typescript-eslint/utils": "8.34.0",
|
"@typescript-eslint/utils": "8.34.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ts-api-utils": "^2.1.0"
|
"ts-api-utils": "^2.1.0"
|
||||||
},
|
},
|
||||||
@ -6977,9 +6976,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.1.tgz",
|
||||||
"integrity": "sha512-9V24k/paICYPniajHfJ4cuAWETnt7Ssy+R0Rbcqo5sSFr3QEZ/8TSoUi9XeXVBGXCaLtwTOKSLGcInCAvyZeMA==",
|
"integrity": "sha512-rjLVbmE7HR18kDsjNIZQHxmv9RZwlgzavryL5Lnj2ujIRTeXlKtILHgRNmQ3j4daw7zd+mQgy+uyt6Zo6I0IGA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -6991,16 +6990,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.1.tgz",
|
||||||
"integrity": "sha512-rOi4KZxI7E0+BMqG7emPSK1bB4RICCpF7QD3KCLXn9ZvWoESsOMlHyZPAHyG04ujVplPaHbmEvs34m+wjgtVtg==",
|
"integrity": "sha512-rjCNqqYPuMUF5ODD+hWBNmOitjBWghkGKJg6hiCHzUvXRy6rK22Jd3rwbP2Xi+R7oYVvIKhokHVhH41BxPV5mA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/project-service": "8.34.0",
|
"@typescript-eslint/project-service": "8.34.1",
|
||||||
"@typescript-eslint/tsconfig-utils": "8.34.0",
|
"@typescript-eslint/tsconfig-utils": "8.34.1",
|
||||||
"@typescript-eslint/types": "8.34.0",
|
"@typescript-eslint/types": "8.34.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"fast-glob": "^3.3.2",
|
"fast-glob": "^3.3.2",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
@ -7020,9 +7019,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -7046,16 +7045,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.1.tgz",
|
||||||
"integrity": "sha512-8L4tWatGchV9A1cKbjaavS6mwYwp39jql8xUmIIKJdm+qiaeHy5KMKlBrf30akXAWBzn2SqKsNOtSENWUwg7XQ==",
|
"integrity": "sha512-mqOwUdZ3KjtGk7xJJnLbHxTuWVn3GO2WZZuM+Slhkun4+qthLdXx32C8xIXbO1kfCECb3jIs3eoxK3eryk7aoQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.7.0",
|
"@eslint-community/eslint-utils": "^4.7.0",
|
||||||
"@typescript-eslint/scope-manager": "8.34.0",
|
"@typescript-eslint/scope-manager": "8.34.1",
|
||||||
"@typescript-eslint/types": "8.34.0",
|
"@typescript-eslint/types": "8.34.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.34.0"
|
"@typescript-eslint/typescript-estree": "8.34.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@ -7070,14 +7069,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.1.tgz",
|
||||||
"integrity": "sha512-qHV7pW7E85A0x6qyrFn+O+q1k1p3tQCsqIZ1KZ5ESLXY57aTvUd3/a4rdPTeXisvhXn2VQG0VSKUqs8KHF2zcA==",
|
"integrity": "sha512-xoh5rJ+tgsRKoXnkBPFRLZ7rjKM0AfVbC68UZ/ECXoDbfggb9RbEySN359acY1vS3qZ0jVTVWzbtfapwm5ztxw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.34.0",
|
"@typescript-eslint/types": "8.34.1",
|
||||||
"eslint-visitor-keys": "^4.2.0"
|
"eslint-visitor-keys": "^4.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@ -7291,9 +7290,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.14.0",
|
"version": "8.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||||
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@ -12218,19 +12218,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "9.28.0",
|
"version": "9.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.29.0.tgz",
|
||||||
"integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==",
|
"integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
"@eslint/config-array": "^0.20.0",
|
"@eslint/config-array": "^0.20.1",
|
||||||
"@eslint/config-helpers": "^0.2.1",
|
"@eslint/config-helpers": "^0.2.1",
|
||||||
"@eslint/core": "^0.14.0",
|
"@eslint/core": "^0.14.0",
|
||||||
"@eslint/eslintrc": "^3.3.1",
|
"@eslint/eslintrc": "^3.3.1",
|
||||||
"@eslint/js": "9.28.0",
|
"@eslint/js": "9.29.0",
|
||||||
"@eslint/plugin-kit": "^0.3.1",
|
"@eslint/plugin-kit": "^0.3.1",
|
||||||
"@humanfs/node": "^0.16.6",
|
"@humanfs/node": "^0.16.6",
|
||||||
"@humanwhocodes/module-importer": "^1.0.1",
|
"@humanwhocodes/module-importer": "^1.0.1",
|
||||||
@ -12242,9 +12242,9 @@
|
|||||||
"cross-spawn": "^7.0.6",
|
"cross-spawn": "^7.0.6",
|
||||||
"debug": "^4.3.2",
|
"debug": "^4.3.2",
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
"eslint-scope": "^8.3.0",
|
"eslint-scope": "^8.4.0",
|
||||||
"eslint-visitor-keys": "^4.2.0",
|
"eslint-visitor-keys": "^4.2.1",
|
||||||
"espree": "^10.3.0",
|
"espree": "^10.4.0",
|
||||||
"esquery": "^1.5.0",
|
"esquery": "^1.5.0",
|
||||||
"esutils": "^2.0.2",
|
"esutils": "^2.0.2",
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
@ -12558,9 +12558,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint/node_modules/eslint-scope": {
|
"node_modules/eslint/node_modules/eslint-scope": {
|
||||||
"version": "8.3.0",
|
"version": "8.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
|
||||||
"integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==",
|
"integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -12575,9 +12575,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint/node_modules/eslint-visitor-keys": {
|
"node_modules/eslint/node_modules/eslint-visitor-keys": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
|
||||||
"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
|
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -12706,15 +12706,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/espree": {
|
"node_modules/espree": {
|
||||||
"version": "10.3.0",
|
"version": "10.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
|
||||||
"integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
|
"integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "^8.14.0",
|
"acorn": "^8.15.0",
|
||||||
"acorn-jsx": "^5.3.2",
|
"acorn-jsx": "^5.3.2",
|
||||||
"eslint-visitor-keys": "^4.2.0"
|
"eslint-visitor-keys": "^4.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@ -12724,9 +12724,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/espree/node_modules/eslint-visitor-keys": {
|
"node_modules/espree/node_modules/eslint-visitor-keys": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
|
||||||
"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
|
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -20672,9 +20672,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.5",
|
"version": "8.5.6",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||||
"integrity": "sha512-d/jtm+rdNT8tpXuHY5MMtcbJFBkhXE6593XVR9UoGCH8jSFGci7jGvMGH5RYd5PBJW+00NZQt6gf7CbagJCrhg==",
|
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@ -26387,15 +26387,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript-eslint": {
|
"node_modules/typescript-eslint": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.1.tgz",
|
||||||
"integrity": "sha512-MRpfN7uYjTrTGigFCt8sRyNqJFhjN0WwZecldaqhWm+wy0gaRt8Edb/3cuUy0zdq2opJWT6iXINKAtewnDOltQ==",
|
"integrity": "sha512-XjS+b6Vg9oT1BaIUfkW3M3LvqZE++rbzAMEHuccCfO/YkP43ha6w3jTEMilQxMF92nVOYCcdjv1ZUhAa1D/0ow==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "8.34.0",
|
"@typescript-eslint/eslint-plugin": "8.34.1",
|
||||||
"@typescript-eslint/parser": "8.34.0",
|
"@typescript-eslint/parser": "8.34.1",
|
||||||
"@typescript-eslint/utils": "8.34.0"
|
"@typescript-eslint/utils": "8.34.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"docusaurus-plugin-openapi-docs": "^4.4.0",
|
"docusaurus-plugin-openapi-docs": "^4.4.0",
|
||||||
"docusaurus-theme-openapi-docs": "^4.4.0",
|
"docusaurus-theme-openapi-docs": "^4.4.0",
|
||||||
"postcss": "^8.5.5",
|
"postcss": "^8.5.6",
|
||||||
"prism-react-renderer": "^2.4.1",
|
"prism-react-renderer": "^2.4.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-before-after-slider-component": "^1.1.8",
|
"react-before-after-slider-component": "^1.1.8",
|
||||||
@ -50,26 +50,26 @@
|
|||||||
"@docusaurus/module-type-aliases": "^3.7.0",
|
"@docusaurus/module-type-aliases": "^3.7.0",
|
||||||
"@docusaurus/tsconfig": "^3.7.0",
|
"@docusaurus/tsconfig": "^3.7.0",
|
||||||
"@docusaurus/types": "^3.7.0",
|
"@docusaurus/types": "^3.7.0",
|
||||||
"@eslint/js": "^9.28.0",
|
"@eslint/js": "^9.29.0",
|
||||||
"@goauthentik/eslint-config": "^1.0.5",
|
"@goauthentik/eslint-config": "^1.0.5",
|
||||||
"@goauthentik/prettier-config": "^1.0.5",
|
"@goauthentik/prettier-config": "^1.0.5",
|
||||||
"@goauthentik/tsconfig": "^1.0.4",
|
"@goauthentik/tsconfig": "^1.0.4",
|
||||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||||
"@types/lodash": "^4.17.17",
|
"@types/lodash": "^4.17.18",
|
||||||
"@types/node": "^24.0.1",
|
"@types/node": "^24.0.3",
|
||||||
"@types/postman-collection": "^3.5.11",
|
"@types/postman-collection": "^3.5.11",
|
||||||
"@types/react": "^18.3.22",
|
"@types/react": "^18.3.22",
|
||||||
"@types/semver": "^7.7.0",
|
"@types/semver": "^7.7.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.34.0",
|
"@typescript-eslint/eslint-plugin": "^8.34.1",
|
||||||
"@typescript-eslint/parser": "^8.34.0",
|
"@typescript-eslint/parser": "^8.34.1",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^9.28.0",
|
"eslint": "^9.29.0",
|
||||||
"fast-glob": "^3.3.3",
|
"fast-glob": "^3.3.3",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"prettier-plugin-packagejson": "^2.5.15",
|
"prettier-plugin-packagejson": "^2.5.15",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"typescript-eslint": "^8.34.0"
|
"typescript-eslint": "^8.34.1"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rspack/binding-darwin-arm64": "1.3.15",
|
"@rspack/binding-darwin-arm64": "1.3.15",
|
||||||
|
|||||||
Reference in New Issue
Block a user