Compare commits
30 Commits
root/remov
...
web/config
Author | SHA1 | Date | |
---|---|---|---|
79da411f10 | |||
ce761c4337 | |||
0d3025794c | |||
79601f6d66 | |||
1ec0623ab6 | |||
4bf151cfc2 | |||
6752d19375 | |||
284c2327c6 | |||
600c3caa62 | |||
366d48eddb | |||
e67a290b73 | |||
4456f085d3 | |||
53e982594e | |||
def988c3b1 | |||
e164661321 | |||
849fea6e91 | |||
24278d0781 | |||
8c6f83b88e | |||
fc80596432 | |||
03fde51313 | |||
f669222529 | |||
297c29b231 | |||
21b50838db | |||
d2a9b2a343 | |||
c52fa631b4 | |||
6cf2de8a7c | |||
d4b80c17e8 | |||
828b8a83ea | |||
115e2f3dcb | |||
6228931305 |
@ -1,5 +1,5 @@
|
||||
[bumpversion]
|
||||
current_version = 2023.10.6
|
||||
current_version = 2023.10.5
|
||||
tag = True
|
||||
commit = True
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)
|
||||
|
4
.github/actions/setup/action.yml
vendored
4
.github/actions/setup/action.yml
vendored
@ -4,7 +4,7 @@ description: "Setup authentik testing environment"
|
||||
inputs:
|
||||
postgresql_version:
|
||||
description: "Optional postgresql image tag"
|
||||
default: "16"
|
||||
default: "12"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
@ -18,7 +18,7 @@ runs:
|
||||
- name: Setup python and restore poetry
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version-file: "pyproject.toml"
|
||||
python-version-file: 'pyproject.toml'
|
||||
cache: "poetry"
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
|
2
.github/actions/setup/docker-compose.yml
vendored
2
.github/actions/setup/docker-compose.yml
vendored
@ -2,7 +2,7 @@ version: "3.7"
|
||||
|
||||
services:
|
||||
postgresql:
|
||||
image: docker.io/library/postgres:${PSQL_TAG:-16}
|
||||
image: docker.io/library/postgres:${PSQL_TAG:-12}
|
||||
volumes:
|
||||
- db-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
|
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
@ -35,7 +35,6 @@ updates:
|
||||
sentry:
|
||||
patterns:
|
||||
- "@sentry/*"
|
||||
- "@spotlightjs/*"
|
||||
babel:
|
||||
patterns:
|
||||
- "@babel/*"
|
||||
@ -67,7 +66,6 @@ updates:
|
||||
sentry:
|
||||
patterns:
|
||||
- "@sentry/*"
|
||||
- "@spotlightjs/*"
|
||||
babel:
|
||||
patterns:
|
||||
- "@babel/*"
|
||||
|
2
.github/workflows/ci-main.yml
vendored
2
.github/workflows/ci-main.yml
vendored
@ -172,7 +172,7 @@ jobs:
|
||||
run: |
|
||||
docker-compose -f tests/e2e/docker-compose.yml up -d
|
||||
- id: cache-web
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: web/dist
|
||||
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/src/**') }}
|
||||
|
33
Dockerfile
33
Dockerfile
@ -1,6 +1,24 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
# Stage 1: Build webui
|
||||
# Stage 1: Build website
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/node:21 as website-builder
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
||||
WORKDIR /work/website
|
||||
|
||||
RUN --mount=type=bind,target=/work/website/package.json,src=./website/package.json \
|
||||
--mount=type=bind,target=/work/website/package-lock.json,src=./website/package-lock.json \
|
||||
--mount=type=cache,id=npm-website,sharing=shared,target=/root/.npm \
|
||||
npm ci --include=dev
|
||||
|
||||
COPY ./website /work/website/
|
||||
COPY ./blueprints /work/blueprints/
|
||||
COPY ./SECURITY.md /work/
|
||||
|
||||
RUN npm run build-docs-only
|
||||
|
||||
# Stage 2: Build webui
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/node:21 as web-builder
|
||||
|
||||
ENV NODE_ENV=production
|
||||
@ -18,8 +36,8 @@ COPY ./gen-ts-api /work/web/node_modules/@goauthentik/api
|
||||
|
||||
RUN npm run build
|
||||
|
||||
# Stage 2: Build go proxy
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/golang:1.21.6-bookworm AS go-builder
|
||||
# Stage 3: Build go proxy
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/golang:1.21.5-bookworm AS go-builder
|
||||
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
@ -50,8 +68,8 @@ RUN --mount=type=cache,sharing=locked,target=/go/pkg/mod \
|
||||
--mount=type=cache,id=go-build-$TARGETARCH$TARGETVARIANT,sharing=locked,target=/root/.cache/go-build \
|
||||
GOARM="${TARGETVARIANT#v}" go build -o /go/authentik ./cmd/server
|
||||
|
||||
# Stage 3: MaxMind GeoIP
|
||||
FROM --platform=${BUILDPLATFORM} ghcr.io/maxmind/geoipupdate:v6.1 as geoip
|
||||
# Stage 4: MaxMind GeoIP
|
||||
FROM --platform=${BUILDPLATFORM} ghcr.io/maxmind/geoipupdate:v6.0 as geoip
|
||||
|
||||
ENV GEOIPUPDATE_EDITION_IDS="GeoLite2-City GeoLite2-ASN"
|
||||
ENV GEOIPUPDATE_VERBOSE="true"
|
||||
@ -64,7 +82,7 @@ RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
|
||||
mkdir -p /usr/share/GeoIP && \
|
||||
/bin/sh -c "/usr/bin/entry.sh || echo 'Failed to get GeoIP database, disabling'; exit 0"
|
||||
|
||||
# Stage 4: Python dependencies
|
||||
# Stage 5: Python dependencies
|
||||
FROM docker.io/python:3.12.1-slim-bookworm AS python-deps
|
||||
|
||||
WORKDIR /ak-root/poetry
|
||||
@ -89,7 +107,7 @@ RUN --mount=type=bind,target=./pyproject.toml,src=./pyproject.toml \
|
||||
pip3 install poetry && \
|
||||
poetry install --only=main --no-ansi --no-interaction
|
||||
|
||||
# Stage 5: Run
|
||||
# Stage 6: Run
|
||||
FROM docker.io/python:3.12.1-slim-bookworm AS final-image
|
||||
|
||||
ARG GIT_BUILD_HASH
|
||||
@ -131,6 +149,7 @@ COPY --from=go-builder /go/authentik /bin/authentik
|
||||
COPY --from=python-deps /ak-root/venv /ak-root/venv
|
||||
COPY --from=web-builder /work/web/dist/ /web/dist/
|
||||
COPY --from=web-builder /work/web/authentik/ /web/authentik/
|
||||
COPY --from=website-builder /work/website/help/ /website/help/
|
||||
COPY --from=geoip /usr/share/GeoIP /geoip
|
||||
|
||||
USER 1000
|
||||
|
@ -2,7 +2,7 @@
|
||||
from os import environ
|
||||
from typing import Optional
|
||||
|
||||
__version__ = "2023.10.6"
|
||||
__version__ = "2023.10.5"
|
||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||
|
||||
|
||||
|
@ -35,7 +35,7 @@ from authentik.core.models import (
|
||||
Source,
|
||||
UserSourceConnection,
|
||||
)
|
||||
from authentik.enterprise.models import LicenseKey, LicenseUsage
|
||||
from authentik.enterprise.models import LicenseUsage
|
||||
from authentik.events.utils import cleanse_dict
|
||||
from authentik.flows.models import FlowToken, Stage
|
||||
from authentik.lib.models import SerializerModel
|
||||
@ -108,16 +108,12 @@ class Importer:
|
||||
self.__pk_map: dict[Any, Model] = {}
|
||||
self._import = blueprint
|
||||
self.logger = get_logger()
|
||||
ctx = self.default_context()
|
||||
ctx = {}
|
||||
always_merger.merge(ctx, self._import.context)
|
||||
if context:
|
||||
always_merger.merge(ctx, context)
|
||||
self._import.context = ctx
|
||||
|
||||
def default_context(self):
|
||||
"""Default context"""
|
||||
return {"goauthentik.io/enterprise/licensed": LicenseKey.get_total().is_valid()}
|
||||
|
||||
@staticmethod
|
||||
def from_string(yaml_input: str, context: dict | None = None) -> "Importer":
|
||||
"""Parse YAML string and create blueprint importer from it"""
|
||||
|
@ -1,18 +1,15 @@
|
||||
"""RAC Provider API Views"""
|
||||
from django_filters.filters import AllValuesMultipleFilter
|
||||
from django_filters.filterset import FilterSet
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import extend_schema_field
|
||||
from rest_framework.fields import CharField
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.core.api.propertymappings import PropertyMappingSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.core.api.utils import JSONDictField
|
||||
from authentik.enterprise.api import EnterpriseRequiredMixin
|
||||
from authentik.enterprise.providers.rac.models import RACPropertyMapping
|
||||
|
||||
|
||||
class RACPropertyMappingSerializer(PropertyMappingSerializer):
|
||||
class RACPropertyMappingSerializer(EnterpriseRequiredMixin, PropertyMappingSerializer):
|
||||
"""RACPropertyMapping Serializer"""
|
||||
|
||||
static_settings = JSONDictField()
|
||||
@ -29,16 +26,6 @@ class RACPropertyMappingSerializer(PropertyMappingSerializer):
|
||||
fields = PropertyMappingSerializer.Meta.fields + ["static_settings"]
|
||||
|
||||
|
||||
class RACPropertyMappingFilter(FilterSet):
|
||||
"""Filter for RACPropertyMapping"""
|
||||
|
||||
managed = extend_schema_field(OpenApiTypes.STR)(AllValuesMultipleFilter(field_name="managed"))
|
||||
|
||||
class Meta:
|
||||
model = RACPropertyMapping
|
||||
fields = ["name", "managed"]
|
||||
|
||||
|
||||
class RACPropertyMappingViewSet(UsedByMixin, ModelViewSet):
|
||||
"""RACPropertyMapping Viewset"""
|
||||
|
||||
@ -46,4 +33,4 @@ class RACPropertyMappingViewSet(UsedByMixin, ModelViewSet):
|
||||
serializer_class = RACPropertyMappingSerializer
|
||||
search_fields = ["name"]
|
||||
ordering = ["name"]
|
||||
filterset_class = RACPropertyMappingFilter
|
||||
filterset_fields = ["name", "managed"]
|
||||
|
@ -15,7 +15,7 @@ from authentik.events.models import Event, EventAction
|
||||
from authentik.flows.challenge import RedirectChallenge
|
||||
from authentik.flows.exceptions import FlowNonApplicableException
|
||||
from authentik.flows.models import in_memory_stage
|
||||
from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, FlowPlanner
|
||||
from authentik.flows.planner import FlowPlanner
|
||||
from authentik.flows.stage import RedirectStage
|
||||
from authentik.flows.views.executor import SESSION_KEY_PLAN
|
||||
from authentik.lib.utils.time import timedelta_from_string
|
||||
@ -39,12 +39,7 @@ class RACStartView(EnterprisePolicyAccessView):
|
||||
planner = FlowPlanner(self.provider.authorization_flow)
|
||||
planner.allow_empty_flows = True
|
||||
try:
|
||||
plan = planner.plan(
|
||||
self.request,
|
||||
{
|
||||
PLAN_CONTEXT_APPLICATION: self.application,
|
||||
},
|
||||
)
|
||||
plan = planner.plan(self.request)
|
||||
except FlowNonApplicableException:
|
||||
raise Http404
|
||||
plan.insert_stage(
|
||||
|
@ -61,6 +61,9 @@ IGNORED_MODELS = (
|
||||
|
||||
def should_log_model(model: Model) -> bool:
|
||||
"""Return true if operation on `model` should be logged"""
|
||||
# Check for silk by string so this comparison doesn't fail when silk isn't installed
|
||||
if model.__module__.startswith("silk"):
|
||||
return False
|
||||
return model.__class__ not in IGNORED_MODELS
|
||||
|
||||
|
||||
|
@ -94,6 +94,7 @@ def get_logger_config():
|
||||
"kubernetes": "INFO",
|
||||
"asyncio": "WARNING",
|
||||
"redis": "WARNING",
|
||||
"silk": "INFO",
|
||||
"fsevents": "WARNING",
|
||||
"uvicorn": "WARNING",
|
||||
"gunicorn": "INFO",
|
||||
|
@ -60,8 +60,6 @@ def sentry_init(**sentry_init_kwargs):
|
||||
},
|
||||
}
|
||||
kwargs.update(**sentry_init_kwargs)
|
||||
if settings.DEBUG:
|
||||
kwargs["spotlight"] = True
|
||||
# pylint: disable=abstract-class-instantiated
|
||||
sentry_sdk_init(
|
||||
dsn=CONFIG.get("error_reporting.sentry_dsn"),
|
||||
|
@ -87,25 +87,6 @@ class TestAuthorize(OAuthTestCase):
|
||||
)
|
||||
OAuthAuthorizationParams.from_request(request)
|
||||
|
||||
def test_blocked_redirect_uri(self):
|
||||
"""test missing/invalid redirect URI"""
|
||||
OAuth2Provider.objects.create(
|
||||
name=generate_id(),
|
||||
client_id="test",
|
||||
authorization_flow=create_test_flow(),
|
||||
redirect_uris="data:local.invalid",
|
||||
)
|
||||
with self.assertRaises(RedirectUriError):
|
||||
request = self.factory.get(
|
||||
"/",
|
||||
data={
|
||||
"response_type": "code",
|
||||
"client_id": "test",
|
||||
"redirect_uri": "data:localhost",
|
||||
},
|
||||
)
|
||||
OAuthAuthorizationParams.from_request(request)
|
||||
|
||||
def test_invalid_redirect_uri_empty(self):
|
||||
"""test missing/invalid redirect URI"""
|
||||
provider = OAuth2Provider.objects.create(
|
||||
|
@ -76,7 +76,6 @@ PLAN_CONTEXT_PARAMS = "goauthentik.io/providers/oauth2/params"
|
||||
SESSION_KEY_LAST_LOGIN_UID = "authentik/providers/oauth2/last_login_uid"
|
||||
|
||||
ALLOWED_PROMPT_PARAMS = {PROMPT_NONE, PROMPT_CONSENT, PROMPT_LOGIN}
|
||||
FORBIDDEN_URI_SCHEMES = {"javascript", "data", "vbscript"}
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
@ -180,10 +179,6 @@ class OAuthAuthorizationParams:
|
||||
self.check_scope(github_compat)
|
||||
self.check_nonce()
|
||||
self.check_code_challenge()
|
||||
if self.request:
|
||||
raise AuthorizeError(
|
||||
self.redirect_uri, "request_not_supported", self.grant_type, self.state
|
||||
)
|
||||
|
||||
def check_redirect_uri(self):
|
||||
"""Redirect URI validation."""
|
||||
@ -221,9 +216,10 @@ class OAuthAuthorizationParams:
|
||||
redirect_uri_expected=allowed_redirect_urls,
|
||||
)
|
||||
raise RedirectUriError(self.redirect_uri, allowed_redirect_urls)
|
||||
# Check against forbidden schemes
|
||||
if urlparse(self.redirect_uri).scheme in FORBIDDEN_URI_SCHEMES:
|
||||
raise RedirectUriError(self.redirect_uri, allowed_redirect_urls)
|
||||
if self.request:
|
||||
raise AuthorizeError(
|
||||
self.redirect_uri, "request_not_supported", self.grant_type, self.state
|
||||
)
|
||||
|
||||
def check_scope(self, github_compat=False):
|
||||
"""Ensure openid scope is set in Hybrid flows, or when requesting an id_token"""
|
||||
|
@ -6,7 +6,6 @@ from hashlib import sha256
|
||||
from re import error as RegexError
|
||||
from re import fullmatch
|
||||
from typing import Any, Optional
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.utils import timezone
|
||||
@ -56,7 +55,6 @@ from authentik.providers.oauth2.models import (
|
||||
RefreshToken,
|
||||
)
|
||||
from authentik.providers.oauth2.utils import TokenResponse, cors_allow, extract_client_auth
|
||||
from authentik.providers.oauth2.views.authorize import FORBIDDEN_URI_SCHEMES
|
||||
from authentik.sources.oauth.models import OAuthSource
|
||||
from authentik.stages.password.stage import PLAN_CONTEXT_METHOD, PLAN_CONTEXT_METHOD_ARGS
|
||||
|
||||
@ -208,10 +206,6 @@ class TokenParams:
|
||||
).from_http(request)
|
||||
raise TokenError("invalid_client")
|
||||
|
||||
# Check against forbidden schemes
|
||||
if urlparse(self.redirect_uri).scheme in FORBIDDEN_URI_SCHEMES:
|
||||
raise TokenError("invalid_request")
|
||||
|
||||
self.authorization_code = AuthorizationCode.objects.filter(code=raw_code).first()
|
||||
if not self.authorization_code:
|
||||
LOGGER.warning("Code does not exist", code=raw_code)
|
||||
|
@ -415,6 +415,8 @@ _update_settings("data.user_settings")
|
||||
if DEBUG:
|
||||
CELERY["task_always_eager"] = True
|
||||
os.environ[ENV_GIT_HASH_KEY] = "dev"
|
||||
INSTALLED_APPS.append("silk")
|
||||
MIDDLEWARE = ["silk.middleware.SilkyMiddleware"] + MIDDLEWARE
|
||||
REST_FRAMEWORK["DEFAULT_RENDERER_CLASSES"].append(
|
||||
"rest_framework.renderers.BrowsableAPIRenderer"
|
||||
)
|
||||
|
@ -1,4 +1,5 @@
|
||||
"""authentik URL Configuration"""
|
||||
from django.conf import settings
|
||||
from django.urls import include, path
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
@ -47,3 +48,8 @@ urlpatterns += [
|
||||
path("-/health/live/", LiveView.as_view(), name="health-live"),
|
||||
path("-/health/ready/", ReadyView.as_view(), name="health-ready"),
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
urlpatterns += [
|
||||
path("debug/silk/", include("silk.urls", namespace="silk")),
|
||||
]
|
||||
|
@ -24,7 +24,7 @@ class SourceTypeSerializer(PassiveSerializer):
|
||||
"""Serializer for SourceType"""
|
||||
|
||||
name = CharField(required=True)
|
||||
verbose_name = CharField(required=True)
|
||||
slug = CharField(required=True)
|
||||
urls_customizable = BooleanField()
|
||||
request_token_url = CharField(read_only=True, allow_null=True)
|
||||
authorization_url = CharField(read_only=True, allow_null=True)
|
||||
@ -56,7 +56,6 @@ class OAuthSourceSerializer(SourceSerializer):
|
||||
"""Get source's type configuration"""
|
||||
return SourceTypeSerializer(instance.source_type).data
|
||||
|
||||
# pylint: disable=too-many-locals
|
||||
def validate(self, attrs: dict) -> dict:
|
||||
session = get_http_session()
|
||||
source_type = registry.find_type(attrs["provider_type"])
|
||||
@ -74,17 +73,9 @@ class OAuthSourceSerializer(SourceSerializer):
|
||||
config = well_known_config.json()
|
||||
if "issuer" not in config:
|
||||
raise ValidationError({"oidc_well_known_url": "Invalid well-known configuration"})
|
||||
field_map = {
|
||||
# authentik field to oidc field
|
||||
"authorization_url": "authorization_endpoint",
|
||||
"access_token_url": "token_endpoint",
|
||||
"profile_url": "userinfo_endpoint",
|
||||
}
|
||||
for ak_key, oidc_key in field_map.items():
|
||||
# Don't overwrite user-set values
|
||||
if ak_key in attrs and attrs[ak_key]:
|
||||
continue
|
||||
attrs[ak_key] = config.get(oidc_key, "")
|
||||
attrs["authorization_url"] = config.get("authorization_endpoint", "")
|
||||
attrs["access_token_url"] = config.get("token_endpoint", "")
|
||||
attrs["profile_url"] = config.get("userinfo_endpoint", "")
|
||||
inferred_oidc_jwks_url = config.get("jwks_uri", "")
|
||||
|
||||
# Prefer user-entered URL to inferred URL to default URL
|
||||
|
@ -44,7 +44,3 @@ class TestTypeAzureAD(TestCase):
|
||||
self.assertEqual(ak_context["username"], AAD_USER["userPrincipalName"])
|
||||
self.assertEqual(ak_context["email"], AAD_USER["mail"])
|
||||
self.assertEqual(ak_context["name"], AAD_USER["displayName"])
|
||||
|
||||
def test_user_id(self):
|
||||
"""Test azure AD user ID"""
|
||||
self.assertEqual(AzureADOAuthCallback().get_user_id(AAD_USER), AAD_USER["id"])
|
||||
|
@ -1,14 +1,13 @@
|
||||
"""OAuth Source tests"""
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
from requests_mock import Mocker
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.tests.utils import create_test_admin_user
|
||||
from authentik.sources.oauth.api.source import OAuthSourceSerializer
|
||||
from authentik.sources.oauth.models import OAuthSource
|
||||
|
||||
|
||||
class TestOAuthSource(APITestCase):
|
||||
class TestOAuthSource(TestCase):
|
||||
"""OAuth Source tests"""
|
||||
|
||||
def setUp(self):
|
||||
@ -21,19 +20,6 @@ class TestOAuthSource(APITestCase):
|
||||
consumer_key="",
|
||||
)
|
||||
|
||||
def test_api_read(self):
|
||||
"""Test reading a source"""
|
||||
self.client.force_login(create_test_admin_user())
|
||||
response = self.client.get(
|
||||
reverse(
|
||||
"authentik_api:oauthsource-detail",
|
||||
kwargs={
|
||||
"slug": self.source.slug,
|
||||
},
|
||||
)
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_api_validate(self):
|
||||
"""Test API validation"""
|
||||
self.assertTrue(
|
||||
@ -83,6 +69,9 @@ class TestOAuthSource(APITestCase):
|
||||
"provider_type": "openidconnect",
|
||||
"consumer_key": "foo",
|
||||
"consumer_secret": "foo",
|
||||
"authorization_url": "http://foo",
|
||||
"access_token_url": "http://foo",
|
||||
"profile_url": "http://foo",
|
||||
"oidc_well_known_url": url,
|
||||
"oidc_jwks_url": "",
|
||||
},
|
||||
|
@ -25,11 +25,6 @@ class AzureADOAuthCallback(OpenIDConnectOAuth2Callback):
|
||||
|
||||
client_class = UserprofileHeaderAuthClient
|
||||
|
||||
def get_user_id(self, info: dict[str, str]) -> str:
|
||||
# Default try to get `id` for the Graph API endpoint
|
||||
# fallback to OpenID logic in case the profile URL was changed
|
||||
return info.get("id", super().get_user_id(info))
|
||||
|
||||
def get_user_enroll_context(
|
||||
self,
|
||||
info: dict[str, Any],
|
||||
@ -55,7 +50,7 @@ class AzureADType(SourceType):
|
||||
|
||||
authorization_url = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"
|
||||
access_token_url = "https://login.microsoftonline.com/common/oauth2/v2.0/token" # nosec
|
||||
profile_url = "https://graph.microsoft.com/v1.0/me"
|
||||
profile_url = "https://login.microsoftonline.com/common/openid/userinfo"
|
||||
oidc_well_known_url = (
|
||||
"https://login.microsoftonline.com/common/.well-known/openid-configuration"
|
||||
)
|
||||
|
@ -1,5 +1,4 @@
|
||||
"""Validation stage challenge checking"""
|
||||
from json import loads
|
||||
from typing import Optional
|
||||
from urllib.parse import urlencode
|
||||
|
||||
@ -11,12 +10,11 @@ from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework.fields import CharField
|
||||
from rest_framework.serializers import ValidationError
|
||||
from structlog.stdlib import get_logger
|
||||
from webauthn import options_to_json
|
||||
from webauthn.authentication.generate_authentication_options import generate_authentication_options
|
||||
from webauthn.authentication.verify_authentication_response import verify_authentication_response
|
||||
from webauthn.helpers.base64url_to_bytes import base64url_to_bytes
|
||||
from webauthn.helpers.exceptions import InvalidAuthenticationResponse
|
||||
from webauthn.helpers.structs import UserVerificationRequirement
|
||||
from webauthn.helpers.structs import AuthenticationCredential
|
||||
|
||||
from authentik.core.api.utils import JSONDictField, PassiveSerializer
|
||||
from authentik.core.models import Application, User
|
||||
@ -68,7 +66,12 @@ def get_webauthn_challenge_without_user(
|
||||
)
|
||||
request.session[SESSION_KEY_WEBAUTHN_CHALLENGE] = authentication_options.challenge
|
||||
|
||||
return loads(options_to_json(authentication_options))
|
||||
return authentication_options.model_dump(
|
||||
mode="json",
|
||||
by_alias=True,
|
||||
exclude_unset=False,
|
||||
exclude_none=True,
|
||||
)
|
||||
|
||||
|
||||
def get_webauthn_challenge(
|
||||
@ -88,12 +91,17 @@ def get_webauthn_challenge(
|
||||
authentication_options = generate_authentication_options(
|
||||
rp_id=get_rp_id(request),
|
||||
allow_credentials=allowed_credentials,
|
||||
user_verification=UserVerificationRequirement(stage.webauthn_user_verification),
|
||||
user_verification=stage.webauthn_user_verification,
|
||||
)
|
||||
|
||||
request.session[SESSION_KEY_WEBAUTHN_CHALLENGE] = authentication_options.challenge
|
||||
|
||||
return loads(options_to_json(authentication_options))
|
||||
return authentication_options.model_dump(
|
||||
mode="json",
|
||||
by_alias=True,
|
||||
exclude_unset=False,
|
||||
exclude_none=True,
|
||||
)
|
||||
|
||||
|
||||
def select_challenge(request: HttpRequest, device: Device):
|
||||
@ -144,7 +152,7 @@ def validate_challenge_webauthn(data: dict, stage_view: StageView, user: User) -
|
||||
|
||||
try:
|
||||
authentication_verification = verify_authentication_response(
|
||||
credential=data,
|
||||
credential=AuthenticationCredential.model_validate(data),
|
||||
expected_challenge=challenge,
|
||||
expected_rp_id=get_rp_id(request),
|
||||
expected_origin=get_origin(request),
|
||||
|
@ -1,18 +1,14 @@
|
||||
"""WebAuthn stage"""
|
||||
from json import loads
|
||||
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.http.request import QueryDict
|
||||
from rest_framework.fields import CharField
|
||||
from rest_framework.serializers import ValidationError
|
||||
from webauthn import options_to_json
|
||||
from webauthn.helpers.bytes_to_base64url import bytes_to_base64url
|
||||
from webauthn.helpers.exceptions import InvalidRegistrationResponse
|
||||
from webauthn.helpers.structs import (
|
||||
AuthenticatorSelectionCriteria,
|
||||
PublicKeyCredentialCreationOptions,
|
||||
ResidentKeyRequirement,
|
||||
UserVerificationRequirement,
|
||||
RegistrationCredential,
|
||||
)
|
||||
from webauthn.registration.generate_registration_options import generate_registration_options
|
||||
from webauthn.registration.verify_registration_response import (
|
||||
@ -57,7 +53,7 @@ class AuthenticatorWebAuthnChallengeResponse(ChallengeResponse):
|
||||
|
||||
try:
|
||||
registration: VerifiedRegistration = verify_registration_response(
|
||||
credential=response,
|
||||
credential=RegistrationCredential.model_validate(response),
|
||||
expected_challenge=challenge,
|
||||
expected_rp_id=get_rp_id(self.request),
|
||||
expected_origin=get_origin(self.request),
|
||||
@ -95,12 +91,12 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
|
||||
registration_options: PublicKeyCredentialCreationOptions = generate_registration_options(
|
||||
rp_id=get_rp_id(self.request),
|
||||
rp_name=self.request.tenant.branding_title,
|
||||
user_id=user.uid.encode("utf-8"),
|
||||
user_id=user.uid,
|
||||
user_name=user.username,
|
||||
user_display_name=user.name,
|
||||
authenticator_selection=AuthenticatorSelectionCriteria(
|
||||
resident_key=ResidentKeyRequirement(str(stage.resident_key_requirement)),
|
||||
user_verification=UserVerificationRequirement(str(stage.user_verification)),
|
||||
resident_key=str(stage.resident_key_requirement),
|
||||
user_verification=str(stage.user_verification),
|
||||
authenticator_attachment=authenticator_attachment,
|
||||
),
|
||||
)
|
||||
@ -110,7 +106,12 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
|
||||
return AuthenticatorWebAuthnChallenge(
|
||||
data={
|
||||
"type": ChallengeTypes.NATIVE.value,
|
||||
"registration": loads(options_to_json(registration_options)),
|
||||
"registration": registration_options.model_dump(
|
||||
mode="json",
|
||||
by_alias=True,
|
||||
exclude_unset=False,
|
||||
exclude_none=True,
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -32,7 +32,7 @@ services:
|
||||
volumes:
|
||||
- redis:/data
|
||||
server:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.10.6}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.10.5}
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment:
|
||||
@ -53,7 +53,7 @@ services:
|
||||
- postgresql
|
||||
- redis
|
||||
worker:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.10.6}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.10.5}
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
environment:
|
||||
|
14
go.mod
14
go.mod
@ -4,8 +4,9 @@ go 1.21
|
||||
|
||||
require (
|
||||
beryju.io/ldap v0.1.0
|
||||
github.com/Netflix/go-env v0.0.0-20210215222557-e437a7e7f9fb
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||
github.com/getsentry/sentry-go v0.26.0
|
||||
github.com/getsentry/sentry-go v0.25.0
|
||||
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
|
||||
github.com/go-ldap/ldap/v3 v3.4.6
|
||||
github.com/go-openapi/runtime v0.26.2
|
||||
@ -23,14 +24,13 @@ require (
|
||||
github.com/pires/go-proxyproto v0.7.0
|
||||
github.com/prometheus/client_golang v1.18.0
|
||||
github.com/redis/go-redis/v9 v9.4.0
|
||||
github.com/sethvargo/go-envconfig v1.0.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/wwt/guac v1.3.2
|
||||
goauthentik.io/api/v3 v3.2023106.3
|
||||
goauthentik.io/api/v3 v3.2023105.5
|
||||
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
|
||||
golang.org/x/oauth2 v0.16.0
|
||||
golang.org/x/oauth2 v0.15.0
|
||||
golang.org/x/sync v0.6.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
layeh.com/radius v0.0.0-20210819152912-ad72663a72ab
|
||||
@ -74,9 +74,9 @@ require (
|
||||
go.opentelemetry.io/otel v1.17.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.17.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.17.0 // indirect
|
||||
golang.org/x/crypto v0.18.0 // indirect
|
||||
golang.org/x/net v0.20.0 // indirect
|
||||
golang.org/x/sys v0.16.0 // indirect
|
||||
golang.org/x/crypto v0.17.0 // indirect
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
|
32
go.sum
32
go.sum
@ -37,6 +37,8 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Netflix/go-env v0.0.0-20210215222557-e437a7e7f9fb h1:w9IDEB7P1VzNcBpOG7kMpFkZp2DkyJIUt0gDx5MBhRU=
|
||||
github.com/Netflix/go-env v0.0.0-20210215222557-e437a7e7f9fb/go.mod h1:9XMFaCeRyW7fC9XJOWQ+NdAv8VLG7ys7l3x4ozEGLUQ=
|
||||
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA=
|
||||
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
@ -71,8 +73,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
||||
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/getsentry/sentry-go v0.26.0 h1:IX3++sF6/4B5JcevhdZfdKIHfyvMmAq/UnqcyT2H6mA=
|
||||
github.com/getsentry/sentry-go v0.26.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
|
||||
github.com/getsentry/sentry-go v0.25.0 h1:q6Eo+hS+yoJlTO3uu/azhQadsD8V+jQn2D8VvX1eOyI=
|
||||
github.com/getsentry/sentry-go v0.25.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||
@ -165,8 +167,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
@ -262,8 +264,6 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sethvargo/go-envconfig v1.0.0 h1:1C66wzy4QrROf5ew4KdVw942CQDa55qmlYmw9FZxZdU=
|
||||
github.com/sethvargo/go-envconfig v1.0.0/go.mod h1:Lzc75ghUn5ucmcRGIdGQ33DKJrcjk4kihFYgSTBmjIc=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
@ -316,8 +316,8 @@ go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYO
|
||||
go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY=
|
||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
||||
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
|
||||
goauthentik.io/api/v3 v3.2023106.3 h1:/ROBnDg6HBNOEyINKdI8pnwiu+ETQfB3MMdjgAoxJ/I=
|
||||
goauthentik.io/api/v3 v3.2023106.3/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
||||
goauthentik.io/api/v3 v3.2023105.5 h1:wIL3Q0jry1g4kRWpH/Dv1sQqhzuL4BLC+uP/Tar1P/g=
|
||||
goauthentik.io/api/v3 v3.2023105.5/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@ -327,8 +327,8 @@ golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@ -394,16 +394,16 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
|
||||
golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
|
||||
golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
|
||||
golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -452,8 +452,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
|
@ -1,7 +1,6 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -11,11 +10,10 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
env "github.com/sethvargo/go-envconfig"
|
||||
env "github.com/Netflix/go-env"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"goauthentik.io/authentik/lib"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var cfg *Config
|
||||
@ -115,8 +113,7 @@ func (c *Config) LoadConfigFromFile(path string) error {
|
||||
}
|
||||
|
||||
func (c *Config) fromEnv() error {
|
||||
ctx := context.Background()
|
||||
err := env.Process(ctx, c)
|
||||
_, err := env.UnmarshalFromEnviron(c)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load environment variables: %w", err)
|
||||
}
|
||||
|
@ -3,17 +3,17 @@ package config
|
||||
type Config struct {
|
||||
// Core specific config
|
||||
Paths PathsConfig `yaml:"paths"`
|
||||
LogLevel string `yaml:"log_level" env:"AUTHENTIK_LOG_LEVEL, overwrite"`
|
||||
ErrorReporting ErrorReportingConfig `yaml:"error_reporting" env:", prefix=AUTHENTIK_ERROR_REPORTING__"`
|
||||
Redis RedisConfig `yaml:"redis" env:", prefix=AUTHENTIK_REDIS__"`
|
||||
Outposts OutpostConfig `yaml:"outposts" env:", prefix=AUTHENTIK_OUTPOSTS__"`
|
||||
LogLevel string `yaml:"log_level" env:"AUTHENTIK_LOG_LEVEL"`
|
||||
ErrorReporting ErrorReportingConfig `yaml:"error_reporting"`
|
||||
Redis RedisConfig `yaml:"redis"`
|
||||
Outposts OutpostConfig `yaml:"outposts"`
|
||||
|
||||
// Config for core and embedded outpost
|
||||
SecretKey string `yaml:"secret_key" env:"AUTHENTIK_SECRET_KEY, overwrite"`
|
||||
SecretKey string `yaml:"secret_key" env:"AUTHENTIK_SECRET_KEY"`
|
||||
|
||||
// Config for both core and outposts
|
||||
Debug bool `yaml:"debug" env:"AUTHENTIK_DEBUG, overwrite"`
|
||||
Listen ListenConfig `yaml:"listen" env:", prefix=AUTHENTIK_LISTEN__"`
|
||||
Debug bool `yaml:"debug" env:"AUTHENTIK_DEBUG"`
|
||||
Listen ListenConfig `yaml:"listen"`
|
||||
|
||||
// Outpost specific config
|
||||
// These are only relevant for proxy/ldap outposts, and cannot be set via YAML
|
||||
@ -25,24 +25,24 @@ type Config struct {
|
||||
}
|
||||
|
||||
type RedisConfig struct {
|
||||
Host string `yaml:"host" env:"HOST, overwrite"`
|
||||
Port int `yaml:"port" env:"PORT, overwrite"`
|
||||
DB int `yaml:"db" env:"DB, overwrite"`
|
||||
Username string `yaml:"username" env:"USERNAME, overwrite"`
|
||||
Password string `yaml:"password" env:"PASSWORD, overwrite"`
|
||||
TLS bool `yaml:"tls" env:"TLS, overwrite"`
|
||||
TLSReqs string `yaml:"tls_reqs" env:"TLS_REQS, overwrite"`
|
||||
Host string `yaml:"host" env:"AUTHENTIK_REDIS__HOST"`
|
||||
Port int `yaml:"port" env:"AUTHENTIK_REDIS__PORT"`
|
||||
DB int `yaml:"db" env:"AUTHENTIK_REDIS__DB"`
|
||||
Username string `yaml:"username" env:"AUTHENTIK_REDIS__USERNAME"`
|
||||
Password string `yaml:"password" env:"AUTHENTIK_REDIS__PASSWORD"`
|
||||
TLS bool `yaml:"tls" env:"AUTHENTIK_REDIS__TLS"`
|
||||
TLSReqs string `yaml:"tls_reqs" env:"AUTHENTIK_REDIS__TLS_REQS"`
|
||||
}
|
||||
|
||||
type ListenConfig struct {
|
||||
HTTP string `yaml:"listen_http" env:"HTTP, overwrite"`
|
||||
HTTPS string `yaml:"listen_https" env:"HTTPS, overwrite"`
|
||||
LDAP string `yaml:"listen_ldap" env:"LDAP, overwrite"`
|
||||
LDAPS string `yaml:"listen_ldaps" env:"LDAPS, overwrite"`
|
||||
Radius string `yaml:"listen_radius" env:"RADIUS, overwrite"`
|
||||
Metrics string `yaml:"listen_metrics" env:"METRICS, overwrite"`
|
||||
Debug string `yaml:"listen_debug" env:"DEBUG, overwrite"`
|
||||
TrustedProxyCIDRs []string `yaml:"trusted_proxy_cidrs" env:"TRUSTED_PROXY_CIDRS, overwrite"`
|
||||
HTTP string `yaml:"listen_http" env:"AUTHENTIK_LISTEN__HTTP"`
|
||||
HTTPS string `yaml:"listen_https" env:"AUTHENTIK_LISTEN__HTTPS"`
|
||||
LDAP string `yaml:"listen_ldap" env:"AUTHENTIK_LISTEN__LDAP"`
|
||||
LDAPS string `yaml:"listen_ldaps" env:"AUTHENTIK_LISTEN__LDAPS"`
|
||||
Radius string `yaml:"listen_radius" env:"AUTHENTIK_LISTEN__RADIUS"`
|
||||
Metrics string `yaml:"listen_metrics" env:"AUTHENTIK_LISTEN__METRICS"`
|
||||
Debug string `yaml:"listen_debug" env:"AUTHENTIK_LISTEN__DEBUG"`
|
||||
TrustedProxyCIDRs []string `yaml:"trusted_proxy_cidrs" env:"AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS"`
|
||||
}
|
||||
|
||||
type PathsConfig struct {
|
||||
@ -50,15 +50,15 @@ type PathsConfig struct {
|
||||
}
|
||||
|
||||
type ErrorReportingConfig struct {
|
||||
Enabled bool `yaml:"enabled" env:"ENABLED, overwrite"`
|
||||
SentryDSN string `yaml:"sentry_dsn" env:"SENTRY_DSN, overwrite"`
|
||||
Environment string `yaml:"environment" env:"ENVIRONMENT, overwrite"`
|
||||
SendPII bool `yaml:"send_pii" env:"SEND_PII, overwrite"`
|
||||
SampleRate float64 `yaml:"sample_rate" env:"SAMPLE_RATE, overwrite"`
|
||||
Enabled bool `yaml:"enabled" env:"AUTHENTIK_ERROR_REPORTING__ENABLED"`
|
||||
SentryDSN string `yaml:"sentry_dsn" env:"AUTHENTIK_ERROR_REPORTING__SENTRY_DSN"`
|
||||
Environment string `yaml:"environment" env:"AUTHENTIK_ERROR_REPORTING__ENVIRONMENT"`
|
||||
SendPII bool `yaml:"send_pii" env:"AUTHENTIK_ERROR_REPORTING__SEND_PII"`
|
||||
SampleRate float64 `yaml:"sample_rate" env:"AUTHENTIK_ERROR_REPORTING__SAMPLE_RATE"`
|
||||
}
|
||||
|
||||
type OutpostConfig struct {
|
||||
ContainerImageBase string `yaml:"container_image_base" env:"CONTAINER_IMAGE_BASE, overwrite"`
|
||||
Discover bool `yaml:"discover" env:"DISCOVER, overwrite"`
|
||||
DisableEmbeddedOutpost bool `yaml:"disable_embedded_outpost" env:"DISABLE_EMBEDDED_OUTPOST, overwrite"`
|
||||
ContainerImageBase string `yaml:"container_image_base" env:"AUTHENTIK_OUTPOSTS__CONTAINER_IMAGE_BASE"`
|
||||
Discover bool `yaml:"discover" env:"AUTHENTIK_OUTPOSTS__DISCOVER"`
|
||||
DisableEmbeddedOutpost bool `yaml:"disable_embedded_outpost" env:"AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST"`
|
||||
}
|
||||
|
@ -29,4 +29,4 @@ func UserAgent() string {
|
||||
return fmt.Sprintf("authentik@%s", FullVersion())
|
||||
}
|
||||
|
||||
const VERSION = "2023.10.6"
|
||||
const VERSION = "2023.10.5"
|
||||
|
@ -22,6 +22,7 @@ func (ws *WebServer) configureStatic() {
|
||||
distFs := http.FileServer(http.Dir("./web/dist"))
|
||||
distHandler := http.StripPrefix("/static/dist/", distFs)
|
||||
authentikHandler := http.StripPrefix("/static/authentik/", http.FileServer(http.Dir("./web/authentik")))
|
||||
helpHandler := http.FileServer(http.Dir("./website/help/"))
|
||||
indexLessRouter.PathPrefix("/static/dist/").Handler(distHandler)
|
||||
indexLessRouter.PathPrefix("/static/authentik/").Handler(authentikHandler)
|
||||
|
||||
@ -41,6 +42,9 @@ func (ws *WebServer) configureStatic() {
|
||||
|
||||
indexLessRouter.PathPrefix("/media/").Handler(http.StripPrefix("/media", fs))
|
||||
|
||||
statRouter.PathPrefix("/if/help/").Handler(http.StripPrefix("/if/help/", helpHandler))
|
||||
statRouter.PathPrefix("/help").Handler(http.RedirectHandler("/if/help/", http.StatusMovedPermanently))
|
||||
|
||||
ws.lh.Path("/robots.txt").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
rw.Header()["Content-Type"] = []string{"text/plain"}
|
||||
rw.WriteHeader(200)
|
||||
|
@ -1,7 +1,7 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
# Stage 1: Build
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/golang:1.21.6-bookworm AS builder
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/golang:1.21.5-bookworm AS builder
|
||||
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
|
262
poetry.lock
generated
262
poetry.lock
generated
@ -326,6 +326,20 @@ six = "*"
|
||||
[package.extras]
|
||||
visualize = ["Twisted (>=16.1.1)", "graphviz (>0.5.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "autopep8"
|
||||
version = "2.0.4"
|
||||
description = "A tool that automatically formats Python code to conform to the PEP 8 style guide"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "autopep8-2.0.4-py2.py3-none-any.whl", hash = "sha256:067959ca4a07b24dbd5345efa8325f5f58da4298dab0dde0443d5ed765de80cb"},
|
||||
{file = "autopep8-2.0.4.tar.gz", hash = "sha256:2913064abd97b3419d1cc83ea71f042cb821f87e45b9c88cad5ad3c4ea87fe0c"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pycodestyle = ">=2.10.0"
|
||||
|
||||
[[package]]
|
||||
name = "bandit"
|
||||
version = "1.7.6"
|
||||
@ -669,20 +683,20 @@ tests = ["async-timeout", "coverage (>=4.5,<5.0)", "pytest", "pytest-asyncio", "
|
||||
|
||||
[[package]]
|
||||
name = "channels-redis"
|
||||
version = "4.2.0"
|
||||
version = "4.1.0"
|
||||
description = "Redis-backed ASGI channel layer implementation"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "channels_redis-4.2.0-py3-none-any.whl", hash = "sha256:2c5b944a39bd984b72aa8005a3ae11637bf29b5092adeb91c9aad4ab819a8ac4"},
|
||||
{file = "channels_redis-4.2.0.tar.gz", hash = "sha256:01c26c4d5d3a203f104bba9e5585c0305a70df390d21792386586068162027fd"},
|
||||
{file = "channels_redis-4.1.0-py3-none-any.whl", hash = "sha256:3696f5b9fe367ea495d402ba83d7c3c99e8ca0e1354ff8d913535976ed0abf73"},
|
||||
{file = "channels_redis-4.1.0.tar.gz", hash = "sha256:6bd4f75f4ab4a7db17cee495593ace886d7e914c66f8214a1f247ff6659c073a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
asgiref = ">=3.2.10,<4"
|
||||
channels = "*"
|
||||
msgpack = ">=1.0,<2.0"
|
||||
redis = ">=4.6"
|
||||
redis = ">=4.5.3"
|
||||
|
||||
[package.extras]
|
||||
cryptography = ["cryptography (>=1.3.0)"]
|
||||
@ -1095,17 +1109,17 @@ graph = ["objgraph (>=1.7.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "django"
|
||||
version = "5.0.1"
|
||||
version = "5.0"
|
||||
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
files = [
|
||||
{file = "Django-5.0.1-py3-none-any.whl", hash = "sha256:f47a37a90b9bbe2c8ec360235192c7fddfdc832206fcf618bb849b39256affc1"},
|
||||
{file = "Django-5.0.1.tar.gz", hash = "sha256:8c8659665bc6e3a44fefe1ab0a291e5a3fb3979f9a8230be29de975e57e8f854"},
|
||||
{file = "Django-5.0-py3-none-any.whl", hash = "sha256:3a9fd52b8dbeae335ddf4a9dfa6c6a0853a1122f1fb071a8d5eca979f73a05c8"},
|
||||
{file = "Django-5.0.tar.gz", hash = "sha256:7d29e14dfbc19cb6a95a4bd669edbde11f5d4c6a71fdaa42c2d40b6846e807f7"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
asgiref = ">=3.7.0,<4"
|
||||
asgiref = ">=3.7.0"
|
||||
sqlparse = ">=0.3.1"
|
||||
tzdata = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
|
||||
@ -1187,6 +1201,23 @@ redis = ">=3,<4.0.0 || >4.0.0,<4.0.1 || >4.0.1"
|
||||
[package.extras]
|
||||
hiredis = ["redis[hiredis] (>=3,!=4.0.0,!=4.0.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "django-silk"
|
||||
version = "5.0.4"
|
||||
description = "Silky smooth profiling for the Django Framework"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "django-silk-5.0.4.tar.gz", hash = "sha256:8cbfbc647d182527726d8d52d3fcfa193f4d250f21406c3fb1062efa6fb95c63"},
|
||||
{file = "django_silk-5.0.4-py3-none-any.whl", hash = "sha256:b345d3973d1d382e09735eb525eaf3eebd3edee9a69d1003eb9b01badb2438db"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
autopep8 = "*"
|
||||
Django = ">=3.2"
|
||||
gprof2dot = ">=2017.09.19"
|
||||
sqlparse = "*"
|
||||
|
||||
[[package]]
|
||||
name = "djangorestframework"
|
||||
version = "3.14.0"
|
||||
@ -1516,20 +1547,20 @@ smmap = ">=3.0.1,<6"
|
||||
|
||||
[[package]]
|
||||
name = "gitpython"
|
||||
version = "3.1.41"
|
||||
version = "3.1.40"
|
||||
description = "GitPython is a Python library used to interact with Git repositories"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "GitPython-3.1.41-py3-none-any.whl", hash = "sha256:c36b6634d069b3f719610175020a9aed919421c87552185b085e04fbbdb10b7c"},
|
||||
{file = "GitPython-3.1.41.tar.gz", hash = "sha256:ed66e624884f76df22c8e16066d567aaa5a37d5b5fa19db2c6df6f7156db9048"},
|
||||
{file = "GitPython-3.1.40-py3-none-any.whl", hash = "sha256:cf14627d5a8049ffbf49915732e5eddbe8134c3bdb9d476e6182b676fc573f8a"},
|
||||
{file = "GitPython-3.1.40.tar.gz", hash = "sha256:22b126e9ffb671fdd0c129796343a02bf67bf2994b35449ffc9321aa755e18a4"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
gitdb = ">=4.0.1,<5"
|
||||
|
||||
[package.extras]
|
||||
test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "sumtypes"]
|
||||
test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest", "pytest-cov", "pytest-instafail", "pytest-subtests", "pytest-sugar"]
|
||||
|
||||
[[package]]
|
||||
name = "google-auth"
|
||||
@ -1554,6 +1585,17 @@ pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"]
|
||||
reauth = ["pyu2f (>=0.1.5)"]
|
||||
requests = ["requests (>=2.20.0,<3.0.0.dev0)"]
|
||||
|
||||
[[package]]
|
||||
name = "gprof2dot"
|
||||
version = "2022.7.29"
|
||||
description = "Generate a dot graph from the output of several profilers."
|
||||
optional = false
|
||||
python-versions = ">=2.7"
|
||||
files = [
|
||||
{file = "gprof2dot-2022.7.29-py2.py3-none-any.whl", hash = "sha256:f165b3851d3c52ee4915eb1bd6cca571e5759823c2cd0f71a79bda93c2dc85d6"},
|
||||
{file = "gprof2dot-2022.7.29.tar.gz", hash = "sha256:45b4d298bd36608fccf9511c3fd88a773f7a1abc04d6cd39445b11ba43133ec5"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gunicorn"
|
||||
version = "21.2.0"
|
||||
@ -1744,13 +1786,13 @@ colors = ["colorama (>=0.4.6)"]
|
||||
|
||||
[[package]]
|
||||
name = "jinja2"
|
||||
version = "3.1.3"
|
||||
version = "3.1.2"
|
||||
description = "A very fast and expressive template engine."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"},
|
||||
{file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"},
|
||||
{file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"},
|
||||
{file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -1853,13 +1895,13 @@ zookeeper = ["kazoo (>=2.8.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "kubernetes"
|
||||
version = "29.0.0"
|
||||
version = "27.2.0"
|
||||
description = "Kubernetes python client"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "kubernetes-29.0.0-py2.py3-none-any.whl", hash = "sha256:ab8cb0e0576ccdfb71886366efb102c6a20f268d817be065ce7f9909c631e43e"},
|
||||
{file = "kubernetes-29.0.0.tar.gz", hash = "sha256:c4812e227ae74d07d53c88293e564e54b850452715a59a927e7e1bc6b9a60459"},
|
||||
{file = "kubernetes-27.2.0-py2.py3-none-any.whl", hash = "sha256:0f9376329c85cf07615ed6886bf9bf21eb1cbfc05e14ec7b0f74ed8153cd2815"},
|
||||
{file = "kubernetes-27.2.0.tar.gz", hash = "sha256:d479931c6f37561dbfdf28fc5f46384b1cb8b28f9db344ed4a232ce91990825a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -2543,13 +2585,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "pdoc"
|
||||
version = "14.4.0"
|
||||
version = "14.3.0"
|
||||
description = "API Documentation for Python Projects"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pdoc-14.4.0-py3-none-any.whl", hash = "sha256:6ea4fe07620b1f7601e2708a307a257636ec206e20b5611640b30f2e3cab47d6"},
|
||||
{file = "pdoc-14.4.0.tar.gz", hash = "sha256:c92edc425429ccbe287ace2a027953c24f13de53eab484c1a6d31ca72dd2fda9"},
|
||||
{file = "pdoc-14.3.0-py3-none-any.whl", hash = "sha256:9a8f9a48bda5a99c249367c2b99779dbdd9f4a56f905068c9c2d6868dbae6882"},
|
||||
{file = "pdoc-14.3.0.tar.gz", hash = "sha256:40bf8f092fcd91560d5e6cebb7c21b65df699f90a468c8ea316235c3368d5449"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -2620,23 +2662,23 @@ wcwidth = "*"
|
||||
|
||||
[[package]]
|
||||
name = "psycopg"
|
||||
version = "3.1.17"
|
||||
version = "3.1.16"
|
||||
description = "PostgreSQL database adapter for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "psycopg-3.1.17-py3-none-any.whl", hash = "sha256:96b7b13af6d5a514118b759a66b2799a8a4aa78675fa6bb0d3f7d52d67eff002"},
|
||||
{file = "psycopg-3.1.17.tar.gz", hash = "sha256:437e7d7925459f21de570383e2e10542aceb3b9cb972ce957fdd3826ca47edc6"},
|
||||
{file = "psycopg-3.1.16-py3-none-any.whl", hash = "sha256:0bfe9741f4fb1c8115cadd8fe832fa91ac277e81e0652ff7fa1400f0ef0f59ba"},
|
||||
{file = "psycopg-3.1.16.tar.gz", hash = "sha256:a34d922fd7df3134595e71c3428ba6f1bd5f4968db74857fe95de12db2d6b763"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
psycopg-c = {version = "3.1.17", optional = true, markers = "implementation_name != \"pypy\" and extra == \"c\""}
|
||||
psycopg-c = {version = "3.1.16", optional = true, markers = "implementation_name != \"pypy\" and extra == \"c\""}
|
||||
typing-extensions = ">=4.1"
|
||||
tzdata = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
|
||||
[package.extras]
|
||||
binary = ["psycopg-binary (==3.1.17)"]
|
||||
c = ["psycopg-c (==3.1.17)"]
|
||||
binary = ["psycopg-binary (==3.1.16)"]
|
||||
c = ["psycopg-c (==3.1.16)"]
|
||||
dev = ["black (>=23.1.0)", "codespell (>=2.2)", "dnspython (>=2.1)", "flake8 (>=4.0)", "mypy (>=1.4.1)", "types-setuptools (>=57.4)", "wheel (>=0.37)"]
|
||||
docs = ["Sphinx (>=5.0)", "furo (==2022.6.21)", "sphinx-autobuild (>=2021.3.14)", "sphinx-autodoc-typehints (>=1.12)"]
|
||||
pool = ["psycopg-pool"]
|
||||
@ -2644,12 +2686,12 @@ test = ["anyio (>=3.6.2,<4.0)", "mypy (>=1.4.1)", "pproxy (>=2.7)", "pytest (>=6
|
||||
|
||||
[[package]]
|
||||
name = "psycopg-c"
|
||||
version = "3.1.17"
|
||||
version = "3.1.16"
|
||||
description = "PostgreSQL database adapter for Python -- C optimisation distribution"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "psycopg-c-3.1.17.tar.gz", hash = "sha256:5cc4d544d552b8ab92a9e3a9dbe3b4f46ce0a86338654d26387fc076e0c97977"},
|
||||
{file = "psycopg-c-3.1.16.tar.gz", hash = "sha256:24f9805e0c20742c72c7be1412e3a600de0980104ff1a264a49333996e6adba3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2677,6 +2719,17 @@ files = [
|
||||
[package.dependencies]
|
||||
pyasn1 = ">=0.4.6,<0.6.0"
|
||||
|
||||
[[package]]
|
||||
name = "pycodestyle"
|
||||
version = "2.11.1"
|
||||
description = "Python style guide checker"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"},
|
||||
{file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pycparser"
|
||||
version = "2.21"
|
||||
@ -2690,43 +2743,43 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "pycryptodome"
|
||||
version = "3.20.0"
|
||||
version = "3.19.1"
|
||||
description = "Cryptographic library for Python"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
files = [
|
||||
{file = "pycryptodome-3.20.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:f0e6d631bae3f231d3634f91ae4da7a960f7ff87f2865b2d2b831af1dfb04e9a"},
|
||||
{file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:baee115a9ba6c5d2709a1e88ffe62b73ecc044852a925dcb67713a288c4ec70f"},
|
||||
{file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:417a276aaa9cb3be91f9014e9d18d10e840a7a9b9a9be64a42f553c5b50b4d1d"},
|
||||
{file = "pycryptodome-3.20.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a1250b7ea809f752b68e3e6f3fd946b5939a52eaeea18c73bdab53e9ba3c2dd"},
|
||||
{file = "pycryptodome-3.20.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:d5954acfe9e00bc83ed9f5cb082ed22c592fbbef86dc48b907238be64ead5c33"},
|
||||
{file = "pycryptodome-3.20.0-cp27-cp27m-win32.whl", hash = "sha256:06d6de87c19f967f03b4cf9b34e538ef46e99a337e9a61a77dbe44b2cbcf0690"},
|
||||
{file = "pycryptodome-3.20.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ec0bb1188c1d13426039af8ffcb4dbe3aad1d7680c35a62d8eaf2a529b5d3d4f"},
|
||||
{file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5601c934c498cd267640b57569e73793cb9a83506f7c73a8ec57a516f5b0b091"},
|
||||
{file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d29daa681517f4bc318cd8a23af87e1f2a7bad2fe361e8aa29c77d652a065de4"},
|
||||
{file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3427d9e5310af6680678f4cce149f54e0bb4af60101c7f2c16fdf878b39ccccc"},
|
||||
{file = "pycryptodome-3.20.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:3cd3ef3aee1079ae44afaeee13393cf68b1058f70576b11439483e34f93cf818"},
|
||||
{file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac1c7c0624a862f2e53438a15c9259d1655325fc2ec4392e66dc46cdae24d044"},
|
||||
{file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76658f0d942051d12a9bd08ca1b6b34fd762a8ee4240984f7c06ddfb55eaf15a"},
|
||||
{file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f35d6cee81fa145333137009d9c8ba90951d7d77b67c79cbe5f03c7eb74d8fe2"},
|
||||
{file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cb39afede7055127e35a444c1c041d2e8d2f1f9c121ecef573757ba4cd2c3c"},
|
||||
{file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a4c4dc60b78ec41d2afa392491d788c2e06edf48580fbfb0dd0f828af49d25"},
|
||||
{file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fb3b87461fa35afa19c971b0a2b7456a7b1db7b4eba9a8424666104925b78128"},
|
||||
{file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:acc2614e2e5346a4a4eab6e199203034924313626f9620b7b4b38e9ad74b7e0c"},
|
||||
{file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:210ba1b647837bfc42dd5a813cdecb5b86193ae11a3f5d972b9a0ae2c7e9e4b4"},
|
||||
{file = "pycryptodome-3.20.0-cp35-abi3-win32.whl", hash = "sha256:8d6b98d0d83d21fb757a182d52940d028564efe8147baa9ce0f38d057104ae72"},
|
||||
{file = "pycryptodome-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:9b3ae153c89a480a0ec402e23db8d8d84a3833b65fa4b15b81b83be9d637aab9"},
|
||||
{file = "pycryptodome-3.20.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:4401564ebf37dfde45d096974c7a159b52eeabd9969135f0426907db367a652a"},
|
||||
{file = "pycryptodome-3.20.0-pp27-pypy_73-win32.whl", hash = "sha256:ec1f93feb3bb93380ab0ebf8b859e8e5678c0f010d2d78367cf6bc30bfeb148e"},
|
||||
{file = "pycryptodome-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:acae12b9ede49f38eb0ef76fdec2df2e94aad85ae46ec85be3648a57f0a7db04"},
|
||||
{file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f47888542a0633baff535a04726948e876bf1ed880fddb7c10a736fa99146ab3"},
|
||||
{file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e0e4a987d38cfc2e71b4a1b591bae4891eeabe5fa0f56154f576e26287bfdea"},
|
||||
{file = "pycryptodome-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c18b381553638414b38705f07d1ef0a7cf301bc78a5f9bc17a957eb19446834b"},
|
||||
{file = "pycryptodome-3.20.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a60fedd2b37b4cb11ccb5d0399efe26db9e0dd149016c1cc6c8161974ceac2d6"},
|
||||
{file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:405002eafad114a2f9a930f5db65feef7b53c4784495dd8758069b89baf68eab"},
|
||||
{file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ab6ab0cb755154ad14e507d1df72de9897e99fd2d4922851a276ccc14f4f1a5"},
|
||||
{file = "pycryptodome-3.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acf6e43fa75aca2d33e93409f2dafe386fe051818ee79ee8a3e21de9caa2ac9e"},
|
||||
{file = "pycryptodome-3.20.0.tar.gz", hash = "sha256:09609209ed7de61c2b560cc5c8c4fbf892f8b15b1faf7e4cbffac97db1fffda7"},
|
||||
{file = "pycryptodome-3.19.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:694020d2ff985cd714381b9da949a21028c24b86f562526186f6af7c7547e986"},
|
||||
{file = "pycryptodome-3.19.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:4464b0e8fd5508bff9baf18e6fd4c6548b1ac2ce9862d6965ff6a84ec9cb302a"},
|
||||
{file = "pycryptodome-3.19.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:420972f9c62978e852c74055d81c354079ce3c3a2213a92c9d7e37bbc63a26e2"},
|
||||
{file = "pycryptodome-3.19.1-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1bc0c49d986a1491d66d2a56570f12e960b12508b7e71f2423f532e28857f36"},
|
||||
{file = "pycryptodome-3.19.1-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:e038ab77fec0956d7aa989a3c647652937fc142ef41c9382c2ebd13c127d5b4a"},
|
||||
{file = "pycryptodome-3.19.1-cp27-cp27m-win32.whl", hash = "sha256:a991f8ffe8dfe708f86690948ae46442eebdd0fff07dc1b605987939a34ec979"},
|
||||
{file = "pycryptodome-3.19.1-cp27-cp27m-win_amd64.whl", hash = "sha256:2c16426ef49d9cba018be2340ea986837e1dfa25c2ea181787971654dd49aadd"},
|
||||
{file = "pycryptodome-3.19.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6d0d2b97758ebf2f36c39060520447c26455acb3bcff309c28b1c816173a6ff5"},
|
||||
{file = "pycryptodome-3.19.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:b8b80ff92049fd042177282917d994d344365ab7e8ec2bc03e853d93d2401786"},
|
||||
{file = "pycryptodome-3.19.1-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd4e7e8bf0fc1ada854688b9b309ee607e2aa85a8b44180f91021a4dd330a928"},
|
||||
{file = "pycryptodome-3.19.1-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:8cf5d3d6cf921fa81acd1f632f6cedcc03f5f68fc50c364cd39490ba01d17c49"},
|
||||
{file = "pycryptodome-3.19.1-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:67939a3adbe637281c611596e44500ff309d547e932c449337649921b17b6297"},
|
||||
{file = "pycryptodome-3.19.1-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:11ddf6c9b52116b62223b6a9f4741bc4f62bb265392a4463282f7f34bb287180"},
|
||||
{file = "pycryptodome-3.19.1-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3e6f89480616781d2a7f981472d0cdb09b9da9e8196f43c1234eff45c915766"},
|
||||
{file = "pycryptodome-3.19.1-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27e1efcb68993b7ce5d1d047a46a601d41281bba9f1971e6be4aa27c69ab8065"},
|
||||
{file = "pycryptodome-3.19.1-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c6273ca5a03b672e504995529b8bae56da0ebb691d8ef141c4aa68f60765700"},
|
||||
{file = "pycryptodome-3.19.1-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:b0bfe61506795877ff974f994397f0c862d037f6f1c0bfc3572195fc00833b96"},
|
||||
{file = "pycryptodome-3.19.1-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:f34976c5c8eb79e14c7d970fb097482835be8d410a4220f86260695ede4c3e17"},
|
||||
{file = "pycryptodome-3.19.1-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:7c9e222d0976f68d0cf6409cfea896676ddc1d98485d601e9508f90f60e2b0a2"},
|
||||
{file = "pycryptodome-3.19.1-cp35-abi3-win32.whl", hash = "sha256:4805e053571140cb37cf153b5c72cd324bb1e3e837cbe590a19f69b6cf85fd03"},
|
||||
{file = "pycryptodome-3.19.1-cp35-abi3-win_amd64.whl", hash = "sha256:a470237ee71a1efd63f9becebc0ad84b88ec28e6784a2047684b693f458f41b7"},
|
||||
{file = "pycryptodome-3.19.1-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:ed932eb6c2b1c4391e166e1a562c9d2f020bfff44a0e1b108f67af38b390ea89"},
|
||||
{file = "pycryptodome-3.19.1-pp27-pypy_73-win32.whl", hash = "sha256:81e9d23c0316fc1b45d984a44881b220062336bbdc340aa9218e8d0656587934"},
|
||||
{file = "pycryptodome-3.19.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:37e531bf896b70fe302f003d3be5a0a8697737a8d177967da7e23eff60d6483c"},
|
||||
{file = "pycryptodome-3.19.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd4e95b0eb4b28251c825fe7aa941fe077f993e5ca9b855665935b86fbb1cc08"},
|
||||
{file = "pycryptodome-3.19.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c22c80246c3c880c6950d2a8addf156cee74ec0dc5757d01e8e7067a3c7da015"},
|
||||
{file = "pycryptodome-3.19.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e70f5c839c7798743a948efa2a65d1fe96bb397fe6d7f2bde93d869fe4f0ad69"},
|
||||
{file = "pycryptodome-3.19.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6c3df3613592ea6afaec900fd7189d23c8c28b75b550254f4bd33fe94acb84b9"},
|
||||
{file = "pycryptodome-3.19.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08b445799d571041765e7d5c9ca09c5d3866c2f22eeb0dd4394a4169285184f4"},
|
||||
{file = "pycryptodome-3.19.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:954d156cd50130afd53f8d77f830fe6d5801bd23e97a69d358fed068f433fbfe"},
|
||||
{file = "pycryptodome-3.19.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b7efd46b0b4ac869046e814d83244aeab14ef787f4850644119b1c8b0ec2d637"},
|
||||
{file = "pycryptodome-3.19.1.tar.gz", hash = "sha256:8ae0dd1bcfada451c35f9e29a3e5db385caabc190f98e4a80ad02a61098fb776"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3473,28 +3526,28 @@ pyasn1 = ">=0.1.3"
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.1.13"
|
||||
version = "0.1.9"
|
||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "ruff-0.1.13-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e3fd36e0d48aeac672aa850045e784673449ce619afc12823ea7868fcc41d8ba"},
|
||||
{file = "ruff-0.1.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9fb6b3b86450d4ec6a6732f9f60c4406061b6851c4b29f944f8c9d91c3611c7a"},
|
||||
{file = "ruff-0.1.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b13ba5d7156daaf3fd08b6b993360a96060500aca7e307d95ecbc5bb47a69296"},
|
||||
{file = "ruff-0.1.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9ebb40442f7b531e136d334ef0851412410061e65d61ca8ce90d894a094feb22"},
|
||||
{file = "ruff-0.1.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:226b517f42d59a543d6383cfe03cccf0091e3e0ed1b856c6824be03d2a75d3b6"},
|
||||
{file = "ruff-0.1.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5f0312ba1061e9b8c724e9a702d3c8621e3c6e6c2c9bd862550ab2951ac75c16"},
|
||||
{file = "ruff-0.1.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2f59bcf5217c661254bd6bc42d65a6fd1a8b80c48763cb5c2293295babd945dd"},
|
||||
{file = "ruff-0.1.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6894b00495e00c27b6ba61af1fc666f17de6140345e5ef27dd6e08fb987259d"},
|
||||
{file = "ruff-0.1.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a1600942485c6e66119da294c6294856b5c86fd6df591ce293e4a4cc8e72989"},
|
||||
{file = "ruff-0.1.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ee3febce7863e231a467f90e681d3d89210b900d49ce88723ce052c8761be8c7"},
|
||||
{file = "ruff-0.1.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dcaab50e278ff497ee4d1fe69b29ca0a9a47cd954bb17963628fa417933c6eb1"},
|
||||
{file = "ruff-0.1.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f57de973de4edef3ad3044d6a50c02ad9fc2dff0d88587f25f1a48e3f72edf5e"},
|
||||
{file = "ruff-0.1.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7a36fa90eb12208272a858475ec43ac811ac37e91ef868759770b71bdabe27b6"},
|
||||
{file = "ruff-0.1.13-py3-none-win32.whl", hash = "sha256:a623349a505ff768dad6bd57087e2461be8db58305ebd5577bd0e98631f9ae69"},
|
||||
{file = "ruff-0.1.13-py3-none-win_amd64.whl", hash = "sha256:f988746e3c3982bea7f824c8fa318ce7f538c4dfefec99cd09c8770bd33e6539"},
|
||||
{file = "ruff-0.1.13-py3-none-win_arm64.whl", hash = "sha256:6bbbc3042075871ec17f28864808540a26f0f79a4478c357d3e3d2284e832998"},
|
||||
{file = "ruff-0.1.13.tar.gz", hash = "sha256:e261f1baed6291f434ffb1d5c6bd8051d1c2a26958072d38dfbec39b3dda7352"},
|
||||
{file = "ruff-0.1.9-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e6a212f436122ac73df851f0cf006e0c6612fe6f9c864ed17ebefce0eff6a5fd"},
|
||||
{file = "ruff-0.1.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:28d920e319783d5303333630dae46ecc80b7ba294aeffedf946a02ac0b7cc3db"},
|
||||
{file = "ruff-0.1.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:104aa9b5e12cb755d9dce698ab1b97726b83012487af415a4512fedd38b1459e"},
|
||||
{file = "ruff-0.1.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1e63bf5a4a91971082a4768a0aba9383c12392d0d6f1e2be2248c1f9054a20da"},
|
||||
{file = "ruff-0.1.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4d0738917c203246f3e275b37006faa3aa96c828b284ebfe3e99a8cb413c8c4b"},
|
||||
{file = "ruff-0.1.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:69dac82d63a50df2ab0906d97a01549f814b16bc806deeac4f064ff95c47ddf5"},
|
||||
{file = "ruff-0.1.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2aec598fb65084e41a9c5d4b95726173768a62055aafb07b4eff976bac72a592"},
|
||||
{file = "ruff-0.1.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:744dfe4b35470fa3820d5fe45758aace6269c578f7ddc43d447868cfe5078bcb"},
|
||||
{file = "ruff-0.1.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:479ca4250cab30f9218b2e563adc362bd6ae6343df7c7b5a7865300a5156d5a6"},
|
||||
{file = "ruff-0.1.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:aa8344310f1ae79af9ccd6e4b32749e93cddc078f9b5ccd0e45bd76a6d2e8bb6"},
|
||||
{file = "ruff-0.1.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:837c739729394df98f342319f5136f33c65286b28b6b70a87c28f59354ec939b"},
|
||||
{file = "ruff-0.1.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e6837202c2859b9f22e43cb01992373c2dbfeae5c0c91ad691a4a2e725392464"},
|
||||
{file = "ruff-0.1.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:331aae2cd4a0554667ac683243b151c74bd60e78fb08c3c2a4ac05ee1e606a39"},
|
||||
{file = "ruff-0.1.9-py3-none-win32.whl", hash = "sha256:8151425a60878e66f23ad47da39265fc2fad42aed06fb0a01130e967a7a064f4"},
|
||||
{file = "ruff-0.1.9-py3-none-win_amd64.whl", hash = "sha256:c497d769164df522fdaf54c6eba93f397342fe4ca2123a2e014a5b8fc7df81c7"},
|
||||
{file = "ruff-0.1.9-py3-none-win_arm64.whl", hash = "sha256:0e17f53bcbb4fff8292dfd84cf72d767b5e146f009cccd40c2fad27641f8a7a9"},
|
||||
{file = "ruff-0.1.9.tar.gz", hash = "sha256:b041dee2734719ddbb4518f762c982f2e912e7f28b8ee4fe1dee0b15d1b6e800"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3516,13 +3569,13 @@ urllib3 = {version = ">=1.26,<3", extras = ["socks"]}
|
||||
|
||||
[[package]]
|
||||
name = "sentry-sdk"
|
||||
version = "1.39.2"
|
||||
version = "1.39.1"
|
||||
description = "Python client for Sentry (https://sentry.io)"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "sentry-sdk-1.39.2.tar.gz", hash = "sha256:24c83b0b41c887d33328a9166f5950dc37ad58f01c9f2fbff6b87a6f1094170c"},
|
||||
{file = "sentry_sdk-1.39.2-py2.py3-none-any.whl", hash = "sha256:acaf597b30258fc7663063b291aa99e58f3096e91fe1e6634f4b79f9c1943e8e"},
|
||||
{file = "sentry-sdk-1.39.1.tar.gz", hash = "sha256:320a55cdf9da9097a0bead239c35b7e61f53660ef9878861824fd6d9b2eaf3b5"},
|
||||
{file = "sentry_sdk-1.39.1-py2.py3-none-any.whl", hash = "sha256:81b5b9ffdd1a374e9eb0c053b5d2012155db9cbe76393a8585677b753bd5fdc1"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -3548,7 +3601,7 @@ huey = ["huey (>=2)"]
|
||||
loguru = ["loguru (>=0.5)"]
|
||||
opentelemetry = ["opentelemetry-distro (>=0.35b0)"]
|
||||
opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"]
|
||||
pure-eval = ["asttokens", "executing", "pure_eval"]
|
||||
pure-eval = ["asttokens", "executing", "pure-eval"]
|
||||
pymongo = ["pymongo (>=3.1)"]
|
||||
pyspark = ["pyspark (>=2.4.4)"]
|
||||
quart = ["blinker (>=1.1)", "quart (>=0.16.1)"]
|
||||
@ -3561,13 +3614,13 @@ tornado = ["tornado (>=5)"]
|
||||
|
||||
[[package]]
|
||||
name = "service-identity"
|
||||
version = "24.1.0"
|
||||
version = "23.1.0"
|
||||
description = "Service identity verification for pyOpenSSL & cryptography."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "service_identity-24.1.0-py3-none-any.whl", hash = "sha256:a28caf8130c8a5c1c7a6f5293faaf239bbfb7751e4862436920ee6f2616f568a"},
|
||||
{file = "service_identity-24.1.0.tar.gz", hash = "sha256:6829c9d62fb832c2e1c435629b0a8c476e1929881f28bee4d20bc24161009221"},
|
||||
{file = "service_identity-23.1.0-py3-none-any.whl", hash = "sha256:87415a691d52fcad954a500cb81f424d0273f8e7e3ee7d766128f4575080f383"},
|
||||
{file = "service_identity-23.1.0.tar.gz", hash = "sha256:ecb33cd96307755041e978ab14f8b14e13b40f1fbd525a4dc78f46d2b986431d"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -3577,7 +3630,7 @@ pyasn1 = "*"
|
||||
pyasn1-modules = "*"
|
||||
|
||||
[package.extras]
|
||||
dev = ["pyopenssl", "service-identity[idna,mypy,tests]"]
|
||||
dev = ["pyopenssl", "service-identity[docs,idna,mypy,tests]"]
|
||||
docs = ["furo", "myst-parser", "pyopenssl", "sphinx", "sphinx-notfound-page"]
|
||||
idna = ["idna"]
|
||||
mypy = ["idna", "mypy", "types-pyopenssl"]
|
||||
@ -3675,13 +3728,13 @@ pbr = ">=2.0.0,<2.1.0 || >2.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "structlog"
|
||||
version = "24.1.0"
|
||||
version = "23.3.0"
|
||||
description = "Structured Logging for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "structlog-24.1.0-py3-none-any.whl", hash = "sha256:3f6efe7d25fab6e86f277713c218044669906537bb717c1807a09d46bca0714d"},
|
||||
{file = "structlog-24.1.0.tar.gz", hash = "sha256:41a09886e4d55df25bdcb9b5c9674bccfab723ff43e0a86a1b7b236be8e57b16"},
|
||||
{file = "structlog-23.3.0-py3-none-any.whl", hash = "sha256:d6922a88ceabef5b13b9eda9c4043624924f60edbb00397f4d193bd754cde60a"},
|
||||
{file = "structlog-23.3.0.tar.gz", hash = "sha256:24b42b914ac6bc4a4e6f716e82ac70d7fb1e8c3b1035a765591953bfc37101a5"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
@ -3773,13 +3826,13 @@ wsproto = ">=0.14"
|
||||
|
||||
[[package]]
|
||||
name = "twilio"
|
||||
version = "8.11.1"
|
||||
version = "8.11.0"
|
||||
description = "Twilio API client and TwiML generator"
|
||||
optional = false
|
||||
python-versions = ">=3.7.0"
|
||||
files = [
|
||||
{file = "twilio-8.11.1-py2.py3-none-any.whl", hash = "sha256:0c079601b972cca25dbe0e259d5c4a01c94795842f6b9f1d02c82269019d7cbb"},
|
||||
{file = "twilio-8.11.1.tar.gz", hash = "sha256:6dfafb60e7a89ad19d2fc4055ce2b86215d30fc68d88452fa588897de8608c71"},
|
||||
{file = "twilio-8.11.0-py2.py3-none-any.whl", hash = "sha256:90fd47f220e597163020d3755a81aed76fd217e116ab36fd241d9bf48d1a0a18"},
|
||||
{file = "twilio-8.11.0.tar.gz", hash = "sha256:792509da936c4f47d9fa7071d5f1f3bdc9314aaf96225bac4f0ef28f8688a95b"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -3936,13 +3989,13 @@ zstd = ["zstandard (>=0.18.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "uvicorn"
|
||||
version = "0.26.0"
|
||||
version = "0.25.0"
|
||||
description = "The lightning-fast ASGI server."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "uvicorn-0.26.0-py3-none-any.whl", hash = "sha256:cdb58ef6b8188c6c174994b2b1ba2150a9a8ae7ea5fb2f1b856b94a815d6071d"},
|
||||
{file = "uvicorn-0.26.0.tar.gz", hash = "sha256:48bfd350fce3c5c57af5fb4995fded8fb50da3b4feb543eb18ad7e0d54589602"},
|
||||
{file = "uvicorn-0.25.0-py3-none-any.whl", hash = "sha256:ce107f5d9bd02b4636001a77a4e74aab5e1e2b146868ebbad565237145af444c"},
|
||||
{file = "uvicorn-0.25.0.tar.gz", hash = "sha256:6dddbad1d7ee0f5140aba5ec138ddc9612c5109399903828b4874c9937f009c2"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -4153,20 +4206,21 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "webauthn"
|
||||
version = "2.0.0"
|
||||
version = "1.11.1"
|
||||
description = "Pythonic WebAuthn"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "webauthn-2.0.0-py3-none-any.whl", hash = "sha256:644dc68af5caaade06be6a2a2278775e85116e92dd755ad7a49d992d51c82033"},
|
||||
{file = "webauthn-2.0.0.tar.gz", hash = "sha256:12cc1759da98668b8242badc37c4129df300f89d89f5c183fac80e7b33c41dfd"},
|
||||
{file = "webauthn-1.11.1-py3-none-any.whl", hash = "sha256:13592ee71489b571cb6e4a5d8b3c34f7b040cd3539a9d94b6b7d23fa88df5dfb"},
|
||||
{file = "webauthn-1.11.1.tar.gz", hash = "sha256:24eda57903897369797f52a377f8c470e7057e79da5525779d0720a9fcc11926"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
asn1crypto = ">=1.4.0"
|
||||
cbor2 = ">=5.4.6"
|
||||
cryptography = ">=41.0.7"
|
||||
pyOpenSSL = ">=23.3.0"
|
||||
cryptography = ">=41.0.4"
|
||||
pydantic = ">=1.10.11"
|
||||
pyOpenSSL = ">=23.2.0"
|
||||
|
||||
[[package]]
|
||||
name = "websocket-client"
|
||||
@ -4488,4 +4542,4 @@ files = [
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "~3.12"
|
||||
content-hash = "6dcbc2c6d02643a72285e075528ec0841b9c8fda244632386ec19efb7350d4cd"
|
||||
content-hash = "9d28b9e79139895839ffcba88e2eaad0f842a15888f3f6f8c0ac8879616ac850"
|
||||
|
@ -17,7 +17,7 @@ COPY web .
|
||||
RUN npm run build-proxy
|
||||
|
||||
# Stage 2: Build
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/golang:1.21.6-bookworm AS builder
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/golang:1.21.5-bookworm AS builder
|
||||
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
|
@ -113,7 +113,7 @@ filterwarnings = [
|
||||
|
||||
[tool.poetry]
|
||||
name = "authentik"
|
||||
version = "2023.10.6"
|
||||
version = "2023.10.5"
|
||||
description = ""
|
||||
authors = ["authentik Team <hello@goauthentik.io>"]
|
||||
|
||||
@ -185,6 +185,7 @@ bump2version = "*"
|
||||
colorama = "*"
|
||||
coverage = { extras = ["toml"], version = "*" }
|
||||
debugpy = "*"
|
||||
django-silk = "*"
|
||||
drf-jsonschema-serializer = "*"
|
||||
freezegun = "*"
|
||||
importlib-metadata = "*"
|
||||
|
@ -1,7 +1,7 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
# Stage 1: Build
|
||||
FROM docker.io/golang:1.21.6-bookworm AS builder
|
||||
FROM docker.io/golang:1.21.5-bookworm AS builder
|
||||
|
||||
WORKDIR /go/src/goauthentik.io
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
# Stage 1: Build
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/golang:1.21.6-bookworm AS builder
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/golang:1.21.5-bookworm AS builder
|
||||
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
|
12
schema.yml
12
schema.yml
@ -1,7 +1,7 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: authentik
|
||||
version: 2023.10.6
|
||||
version: 2023.10.5
|
||||
description: Making authentication simple.
|
||||
contact:
|
||||
email: hello@goauthentik.io
|
||||
@ -13961,11 +13961,7 @@ paths:
|
||||
- in: query
|
||||
name: managed
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
explode: true
|
||||
style: form
|
||||
type: string
|
||||
- in: query
|
||||
name: name
|
||||
schema:
|
||||
@ -42372,7 +42368,7 @@ components:
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
verbose_name:
|
||||
slug:
|
||||
type: string
|
||||
urls_customizable:
|
||||
type: boolean
|
||||
@ -42408,8 +42404,8 @@ components:
|
||||
- oidc_well_known_url
|
||||
- profile_url
|
||||
- request_token_url
|
||||
- slug
|
||||
- urls_customizable
|
||||
- verbose_name
|
||||
SpBindingEnum:
|
||||
enum:
|
||||
- redirect
|
||||
|
@ -3,7 +3,7 @@ version: "3.7"
|
||||
services:
|
||||
postgresql:
|
||||
container_name: postgres
|
||||
image: docker.io/library/postgres:16
|
||||
image: docker.io/library/postgres:12
|
||||
volumes:
|
||||
- db-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
@ -18,11 +18,6 @@ services:
|
||||
ports:
|
||||
- 127.0.0.1:6379:6379
|
||||
restart: always
|
||||
spotlight:
|
||||
image: ghcr.io/getsentry/spotlight
|
||||
ports:
|
||||
- 127.0.0.1:8969:8969
|
||||
restart: always
|
||||
|
||||
volumes:
|
||||
db-data:
|
||||
|
@ -2,6 +2,3 @@
|
||||
node_modules
|
||||
# don't lint nyc coverage output
|
||||
coverage
|
||||
# Prettier breaks the tsconfig file
|
||||
tsconfig.json
|
||||
.eslintrc.json
|
||||
|
282
tests/wdio/package-lock.json
generated
282
tests/wdio/package-lock.json
generated
@ -7,17 +7,17 @@
|
||||
"name": "@goauthentik/web-tests",
|
||||
"devDependencies": {
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
||||
"@typescript-eslint/parser": "^6.19.0",
|
||||
"@wdio/cli": "^8.28.6",
|
||||
"@wdio/local-runner": "^8.28.7",
|
||||
"@wdio/mocha-framework": "^8.28.6",
|
||||
"@wdio/spec-reporter": "^8.28.6",
|
||||
"@typescript-eslint/eslint-plugin": "^6.18.0",
|
||||
"@typescript-eslint/parser": "^6.18.0",
|
||||
"@wdio/cli": "^8.27.1",
|
||||
"@wdio/local-runner": "^8.27.0",
|
||||
"@wdio/mocha-framework": "^8.27.0",
|
||||
"@wdio/spec-reporter": "^8.27.0",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-sonarjs": "^0.23.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^3.2.4",
|
||||
"prettier": "^3.1.1",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.3.3",
|
||||
"wdio-wait-for": "^3.0.10"
|
||||
@ -946,16 +946,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "6.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.19.0.tgz",
|
||||
"integrity": "sha512-DUCUkQNklCQYnrBSSikjVChdc84/vMPDQSgJTHBZ64G9bA9w0Crc0rd2diujKbTdp6w2J47qkeHQLoi0rpLCdg==",
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.0.tgz",
|
||||
"integrity": "sha512-3lqEvQUdCozi6d1mddWqd+kf8KxmGq2Plzx36BlkjuQe3rSTm/O98cLf0A4uDO+a5N1KD2SeEEl6fW97YHY+6w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.5.1",
|
||||
"@typescript-eslint/scope-manager": "6.19.0",
|
||||
"@typescript-eslint/type-utils": "6.19.0",
|
||||
"@typescript-eslint/utils": "6.19.0",
|
||||
"@typescript-eslint/visitor-keys": "6.19.0",
|
||||
"@typescript-eslint/scope-manager": "6.18.0",
|
||||
"@typescript-eslint/type-utils": "6.18.0",
|
||||
"@typescript-eslint/utils": "6.18.0",
|
||||
"@typescript-eslint/visitor-keys": "6.18.0",
|
||||
"debug": "^4.3.4",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.2.4",
|
||||
@ -981,15 +981,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "6.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.19.0.tgz",
|
||||
"integrity": "sha512-1DyBLG5SH7PYCd00QlroiW60YJ4rWMuUGa/JBV0iZuqi4l4IK3twKPq5ZkEebmGqRjXWVgsUzfd3+nZveewgow==",
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.0.tgz",
|
||||
"integrity": "sha512-v6uR68SFvqhNQT41frCMCQpsP+5vySy6IdgjlzUWoo7ALCnpaWYcz/Ij2k4L8cEsL0wkvOviCMpjmtRtHNOKzA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "6.19.0",
|
||||
"@typescript-eslint/types": "6.19.0",
|
||||
"@typescript-eslint/typescript-estree": "6.19.0",
|
||||
"@typescript-eslint/visitor-keys": "6.19.0",
|
||||
"@typescript-eslint/scope-manager": "6.18.0",
|
||||
"@typescript-eslint/types": "6.18.0",
|
||||
"@typescript-eslint/typescript-estree": "6.18.0",
|
||||
"@typescript-eslint/visitor-keys": "6.18.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@ -1009,13 +1009,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "6.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.0.tgz",
|
||||
"integrity": "sha512-dO1XMhV2ehBI6QN8Ufi7I10wmUovmLU0Oru3n5LVlM2JuzB4M+dVphCPLkVpKvGij2j/pHBWuJ9piuXx+BhzxQ==",
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.0.tgz",
|
||||
"integrity": "sha512-o/UoDT2NgOJ2VfHpfr+KBY2ErWvCySNUIX/X7O9g8Zzt/tXdpfEU43qbNk8LVuWUT2E0ptzTWXh79i74PP0twA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.19.0",
|
||||
"@typescript-eslint/visitor-keys": "6.19.0"
|
||||
"@typescript-eslint/types": "6.18.0",
|
||||
"@typescript-eslint/visitor-keys": "6.18.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
@ -1026,13 +1026,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "6.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.19.0.tgz",
|
||||
"integrity": "sha512-mcvS6WSWbjiSxKCwBcXtOM5pRkPQ6kcDds/juxcy/727IQr3xMEcwr/YLHW2A2+Fp5ql6khjbKBzOyjuPqGi/w==",
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.0.tgz",
|
||||
"integrity": "sha512-ZeMtrXnGmTcHciJN1+u2CigWEEXgy1ufoxtWcHORt5kGvpjjIlK9MUhzHm4RM8iVy6dqSaZA/6PVkX6+r+ChjQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "6.19.0",
|
||||
"@typescript-eslint/utils": "6.19.0",
|
||||
"@typescript-eslint/typescript-estree": "6.18.0",
|
||||
"@typescript-eslint/utils": "6.18.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.0.1"
|
||||
},
|
||||
@ -1053,9 +1053,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "6.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.0.tgz",
|
||||
"integrity": "sha512-lFviGV/vYhOy3m8BJ/nAKoAyNhInTdXpftonhWle66XHAtT1ouBlkjL496b5H5hb8dWXHwtypTqgtb/DEa+j5A==",
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.0.tgz",
|
||||
"integrity": "sha512-/RFVIccwkwSdW/1zeMx3hADShWbgBxBnV/qSrex6607isYjj05t36P6LyONgqdUrNLl5TYU8NIKdHUYpFvExkA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
@ -1066,13 +1066,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "6.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.0.tgz",
|
||||
"integrity": "sha512-o/zefXIbbLBZ8YJ51NlkSAt2BamrK6XOmuxSR3hynMIzzyMY33KuJ9vuMdFSXW+H0tVvdF9qBPTHA91HDb4BIQ==",
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.0.tgz",
|
||||
"integrity": "sha512-klNvl+Ql4NsBNGB4W9TZ2Od03lm7aGvTbs0wYaFYsplVPhr+oeXjlPZCDI4U9jgJIDK38W1FKhacCFzCC+nbIg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.19.0",
|
||||
"@typescript-eslint/visitor-keys": "6.19.0",
|
||||
"@typescript-eslint/types": "6.18.0",
|
||||
"@typescript-eslint/visitor-keys": "6.18.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
@ -1118,17 +1118,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "6.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.19.0.tgz",
|
||||
"integrity": "sha512-QR41YXySiuN++/dC9UArYOg4X86OAYP83OWTewpVx5ct1IZhjjgTLocj7QNxGhWoTqknsgpl7L+hGygCO+sdYw==",
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.0.tgz",
|
||||
"integrity": "sha512-wiKKCbUeDPGaYEYQh1S580dGxJ/V9HI7K5sbGAVklyf+o5g3O+adnS4UNJajplF4e7z2q0uVBaTdT/yLb4XAVA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@types/json-schema": "^7.0.12",
|
||||
"@types/semver": "^7.5.0",
|
||||
"@typescript-eslint/scope-manager": "6.19.0",
|
||||
"@typescript-eslint/types": "6.19.0",
|
||||
"@typescript-eslint/typescript-estree": "6.19.0",
|
||||
"@typescript-eslint/scope-manager": "6.18.0",
|
||||
"@typescript-eslint/types": "6.18.0",
|
||||
"@typescript-eslint/typescript-estree": "6.18.0",
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"engines": {
|
||||
@ -1143,12 +1143,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "6.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.0.tgz",
|
||||
"integrity": "sha512-hZaUCORLgubBvtGpp1JEFEazcuEdfxta9j4iUwdSAr7mEsYYAp3EAUyCZk3VEEqGj6W+AV4uWyrDGtrlawAsgQ==",
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.0.tgz",
|
||||
"integrity": "sha512-1wetAlSZpewRDb2h9p/Q8kRjdGuqdTAQbkJIOUMLug2LBLG+QOjiWoSj6/3B/hA9/tVTFFdtiKvAYoYnSRW/RA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.19.0",
|
||||
"@typescript-eslint/types": "6.18.0",
|
||||
"eslint-visitor-keys": "^3.4.1"
|
||||
},
|
||||
"engines": {
|
||||
@ -1166,18 +1166,18 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@wdio/cli": {
|
||||
"version": "8.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.28.6.tgz",
|
||||
"integrity": "sha512-cBgm/RA12tlKGqIywsqAJaACST2tbcBtbkNl16io88iiBKAWOMlK5tX75+5dNEeyKs7JlQqBJ+3toXcypf68tA==",
|
||||
"version": "8.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.27.1.tgz",
|
||||
"integrity": "sha512-RY9o4h0iN6UGpU31X5c9mu/TK2FlHtKtDaRJYunm5ycZvGahQcN+naYpea1ftDr4IpI2gGGlHxvEeHkJF7urDQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.1.1",
|
||||
"@wdio/config": "8.28.6",
|
||||
"@wdio/globals": "8.28.6",
|
||||
"@wdio/logger": "8.28.0",
|
||||
"@wdio/config": "8.27.0",
|
||||
"@wdio/globals": "8.27.0",
|
||||
"@wdio/logger": "8.24.12",
|
||||
"@wdio/protocols": "8.24.12",
|
||||
"@wdio/types": "8.28.6",
|
||||
"@wdio/utils": "8.28.6",
|
||||
"@wdio/types": "8.27.0",
|
||||
"@wdio/utils": "8.27.0",
|
||||
"async-exit-hook": "^2.0.1",
|
||||
"chalk": "^5.2.0",
|
||||
"chokidar": "^3.5.3",
|
||||
@ -1192,7 +1192,7 @@
|
||||
"lodash.union": "^4.6.0",
|
||||
"read-pkg-up": "^10.0.0",
|
||||
"recursive-readdir": "^2.2.3",
|
||||
"webdriverio": "8.28.6",
|
||||
"webdriverio": "8.27.0",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"bin": {
|
||||
@ -1215,14 +1215,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/config": {
|
||||
"version": "8.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.28.6.tgz",
|
||||
"integrity": "sha512-rJ7GFnzg55MvG/CmN3rX79fFFBMcpoFZpILPTNaWJg43lBxidHue5pm7kXJT06D41sSJJPbtgoh6w4VPThIJrg==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.27.0.tgz",
|
||||
"integrity": "sha512-zYM5daeiBVVAbQj0ASymAt0RUsocLVIwKiUHNa8gg/1GsZnztGjetXExSp1gXlxtMVM5xWUSKjh6ceFK79gWDQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@wdio/logger": "8.28.0",
|
||||
"@wdio/types": "8.28.6",
|
||||
"@wdio/utils": "8.28.6",
|
||||
"@wdio/logger": "8.24.12",
|
||||
"@wdio/types": "8.27.0",
|
||||
"@wdio/utils": "8.27.0",
|
||||
"decamelize": "^6.0.0",
|
||||
"deepmerge-ts": "^5.0.0",
|
||||
"glob": "^10.2.2",
|
||||
@ -1233,29 +1233,29 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/globals": {
|
||||
"version": "8.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.28.6.tgz",
|
||||
"integrity": "sha512-6Wjk7iWnpK1ft/caTAhDXxlmwU+pARouzCssqUtdO/vlvP1VhUo3xArCA2dzzJgE+uD16KLR63DRpgkTdwWPkQ==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.27.0.tgz",
|
||||
"integrity": "sha512-HUPOIsrmxfF0LhU68lVsNGQGZkW/bWOvcCd8WxeaggTAH9JyxasxxfwzeCceAuhAvwtlwoMXITOpjAXO2mj38Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^16.13 || >=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"expect-webdriverio": "^4.8.0",
|
||||
"webdriverio": "8.28.6"
|
||||
"expect-webdriverio": "^4.6.1",
|
||||
"webdriverio": "8.27.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/local-runner": {
|
||||
"version": "8.28.7",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.28.7.tgz",
|
||||
"integrity": "sha512-QOeJluWEV3My+41f4kHe7Bo08UcSd3TvH4TbPMflOkl0VvGqxJuKfXlllkQhJ8w5e53fBRsf368vzHscbX86/A==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.27.0.tgz",
|
||||
"integrity": "sha512-nxS17mhoLkXP20eoPMkz7tbMFMOQejSw0hZfkEvuDCNhJokr8ugp6IjYXL9f7yV9IB9UDGHox8WGY4ArSrOeBA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.1.0",
|
||||
"@wdio/logger": "8.28.0",
|
||||
"@wdio/logger": "8.24.12",
|
||||
"@wdio/repl": "8.24.12",
|
||||
"@wdio/runner": "8.28.7",
|
||||
"@wdio/types": "8.28.6",
|
||||
"@wdio/runner": "8.27.0",
|
||||
"@wdio/types": "8.27.0",
|
||||
"async-exit-hook": "^2.0.1",
|
||||
"split2": "^4.1.0",
|
||||
"stream-buffers": "^3.0.2"
|
||||
@ -1265,9 +1265,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/logger": {
|
||||
"version": "8.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.28.0.tgz",
|
||||
"integrity": "sha512-/s6zNCqwy1hoc+K4SJypis0Ud0dlJ+urOelJFO1x0G0rwDRWyFiUP6ijTaCcFxAm29jYEcEPWijl2xkVIHwOyA==",
|
||||
"version": "8.24.12",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.24.12.tgz",
|
||||
"integrity": "sha512-QisOiVIWKTUCf1H7S+DOtC+gruhlpimQrUXfWMTeeh672PvAJYnTpOJDWA+BtXfsikkUYFAzAaq8SeMJk8rqKg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chalk": "^5.1.2",
|
||||
@ -1292,16 +1292,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/mocha-framework": {
|
||||
"version": "8.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.28.6.tgz",
|
||||
"integrity": "sha512-3jTI1GilFGZROJi+UCywEt/ac0b8ETQkG9YlkTAVcxMqG+wUKY2Ks7ow/UDGAaYMHkrEPdopvUFGZmJmpNMKUg==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.27.0.tgz",
|
||||
"integrity": "sha512-NaFUPv90ks1XlZy0qdUaJ5/ilBtiCCgTIxaPexshJiaVDT5cV+Igjag/O80HIcvqknOZpdKAR0I1ArQzhJrmcA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/mocha": "^10.0.0",
|
||||
"@types/node": "^20.1.0",
|
||||
"@wdio/logger": "8.28.0",
|
||||
"@wdio/types": "8.28.6",
|
||||
"@wdio/utils": "8.28.6",
|
||||
"@wdio/logger": "8.24.12",
|
||||
"@wdio/types": "8.27.0",
|
||||
"@wdio/utils": "8.27.0",
|
||||
"mocha": "^10.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -1327,14 +1327,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/reporter": {
|
||||
"version": "8.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-8.28.6.tgz",
|
||||
"integrity": "sha512-2KUSytk75fjT4XGEL43u1XLzZSvu1SUg3a7h8fRm2fU2q1dCC16TJk5eod4eSxHzjm2fL1vwFQIAZkwO3WyQZQ==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-8.27.0.tgz",
|
||||
"integrity": "sha512-kBwsrHbsblmXfHSWlaOKXjPRPeT29WSKTUoCmzuTcCkhvbjY4TrEB0p04cpaM7uNqdIZTxHng54gZVaG/nZPiw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.1.0",
|
||||
"@wdio/logger": "8.28.0",
|
||||
"@wdio/types": "8.28.6",
|
||||
"@wdio/logger": "8.24.12",
|
||||
"@wdio/types": "8.27.0",
|
||||
"diff": "^5.0.0",
|
||||
"object-inspect": "^1.12.0"
|
||||
},
|
||||
@ -1343,35 +1343,35 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/runner": {
|
||||
"version": "8.28.7",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.28.7.tgz",
|
||||
"integrity": "sha512-qk/3cMccCLXrIMN4a/vqmL0UeKaGXDclL/8buWC61IeZZ3SpDUgOoCJH47ULrkIeuoXXrnttZvo12fGjb8zmOg==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.27.0.tgz",
|
||||
"integrity": "sha512-da332r2d1QXdRhMhsDxMObcqLZS0l/u14pHICNTvEHp+72gOttbjUDvdMHPQY6Ae5ul7AVVQ05qpmz9CX7TzOg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.1.0",
|
||||
"@wdio/config": "8.28.6",
|
||||
"@wdio/globals": "8.28.6",
|
||||
"@wdio/logger": "8.28.0",
|
||||
"@wdio/types": "8.28.6",
|
||||
"@wdio/utils": "8.28.6",
|
||||
"@wdio/config": "8.27.0",
|
||||
"@wdio/globals": "8.27.0",
|
||||
"@wdio/logger": "8.24.12",
|
||||
"@wdio/types": "8.27.0",
|
||||
"@wdio/utils": "8.27.0",
|
||||
"deepmerge-ts": "^5.0.0",
|
||||
"expect-webdriverio": "^4.8.0",
|
||||
"expect-webdriverio": "^4.6.1",
|
||||
"gaze": "^1.1.2",
|
||||
"webdriver": "8.28.6",
|
||||
"webdriverio": "8.28.6"
|
||||
"webdriver": "8.27.0",
|
||||
"webdriverio": "8.27.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.13 || >=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/spec-reporter": {
|
||||
"version": "8.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-8.28.6.tgz",
|
||||
"integrity": "sha512-ZMwbM7hxcV0DumGaK0Y9jzPgTjwYHN539FFcEgbYZV1eNKUyIi9cdEP2xIWZiYQHmq2eKBMlUEPA87mwVZ1V6w==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-8.27.0.tgz",
|
||||
"integrity": "sha512-EOXLBIr4oLzSDp/BQ86IqCulSF0jwEAj2EiMeY6dh9WXzBBtoR8WnoX/27xFoZ8GU2zetWC3EVnLJ0Ex8Up1mA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@wdio/reporter": "8.28.6",
|
||||
"@wdio/types": "8.28.6",
|
||||
"@wdio/reporter": "8.27.0",
|
||||
"@wdio/types": "8.27.0",
|
||||
"chalk": "^5.1.2",
|
||||
"easy-table": "^1.2.0",
|
||||
"pretty-ms": "^7.0.0"
|
||||
@ -1393,9 +1393,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/types": {
|
||||
"version": "8.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.28.6.tgz",
|
||||
"integrity": "sha512-FU3mMRqULpc2XYh6DrSo/KgNoaS6EO9GFJQX5q7+EiOAqVeo1TCLggvAWIPayKyjfD1/ctd9q+uW9vmNicaOjw==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.27.0.tgz",
|
||||
"integrity": "sha512-LbP9FKh8r0uW9/dKhTIUCC1Su8PsP9TmzGKXkWt6/IMacgJiB/zW3u1CgyaLw9lG0UiQORHGoeJX9zB2HZAh4w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.1.0"
|
||||
@ -1405,14 +1405,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/utils": {
|
||||
"version": "8.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.28.6.tgz",
|
||||
"integrity": "sha512-EYQmGvejMiTMB18lW3CDc6cR+jXXjxDebP6ci53oK20QPx9VBuMQZdCbuoftKrKVLA+e9Fk0XfXq8xWYbjAvBQ==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.27.0.tgz",
|
||||
"integrity": "sha512-4BY+JBQssVn003P5lA289uDMie3LtGinHze5btkcW9timB6VaU+EeZS4eKTPC0pziizLhteVvXYxv3YTpeeRfA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@puppeteer/browsers": "^1.6.0",
|
||||
"@wdio/logger": "8.28.0",
|
||||
"@wdio/types": "8.28.6",
|
||||
"@wdio/logger": "8.24.12",
|
||||
"@wdio/types": "8.27.0",
|
||||
"decamelize": "^6.0.0",
|
||||
"deepmerge-ts": "^5.1.0",
|
||||
"edgedriver": "^5.3.5",
|
||||
@ -2481,9 +2481,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/devtools-protocol": {
|
||||
"version": "0.0.1245094",
|
||||
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1245094.tgz",
|
||||
"integrity": "sha512-c7Tk8wCk2bw+wuQbl8vDh/7rDboWY8TEtcuHj5Q8S9E4F0AJMGJBnp+OqBCTI+xuVeGitQHt04/Rp3tzUStJxg==",
|
||||
"version": "0.0.1237913",
|
||||
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1237913.tgz",
|
||||
"integrity": "sha512-Pxtmz2ZIqBkpU82HaIdsvCQBG94yTC4xajrEsWx9p38QKEfBCJktSazsHkrjf9j3dVVNPhg5LR21F6KWeXpjiQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/diff": {
|
||||
@ -3182,9 +3182,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/expect-webdriverio": {
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-4.8.1.tgz",
|
||||
"integrity": "sha512-JD5aboj/tCiMXdEPCpt3BA0xL3DBhNu1MoiOdBGT9LT+9COIXoDG6Ks6h5S4c4PNwLs6xSeU8s7XxFAmBPu45Q==",
|
||||
"version": "4.6.1",
|
||||
"resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-4.6.1.tgz",
|
||||
"integrity": "sha512-w6ee91kN3BoxNGVKQheAqFpRGMehdDg7kDiErEk/oM7tbd/WUT4R4v9KYOUtjiaUFHWWCRW2FtcOOjcd0+1pvQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"expect": "^29.7.0",
|
||||
@ -3195,9 +3195,9 @@
|
||||
"node": ">=16 || >=18 || >=20"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@wdio/globals": "^8.27.0",
|
||||
"@wdio/logger": "^8.24.12",
|
||||
"webdriverio": "^8.27.0"
|
||||
"@wdio/globals": "^8.23.1",
|
||||
"@wdio/logger": "^8.16.17",
|
||||
"webdriverio": "^8.23.1"
|
||||
}
|
||||
},
|
||||
"node_modules/external-editor": {
|
||||
@ -6508,9 +6508,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.4.tgz",
|
||||
"integrity": "sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ==",
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz",
|
||||
"integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
@ -8520,18 +8520,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webdriver": {
|
||||
"version": "8.28.6",
|
||||
"resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.28.6.tgz",
|
||||
"integrity": "sha512-qKZuG2uqGhq2xjk14vSAvE3C6TTTYQyOqDHQOSWNzPNhdBI99g2h4EUbmO3bc/5YaWRsVWWp+RB7jfQZUcE/MA==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.27.0.tgz",
|
||||
"integrity": "sha512-n1IA+rR3u84XxU9swiKUM06BkEC0GDimfZkBML57cny+utQOUbdM/mBpqCUnkWX/RBz/p2EfHdKNyOs3/REaog==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.1.0",
|
||||
"@types/ws": "^8.5.3",
|
||||
"@wdio/config": "8.28.6",
|
||||
"@wdio/logger": "8.28.0",
|
||||
"@wdio/config": "8.27.0",
|
||||
"@wdio/logger": "8.24.12",
|
||||
"@wdio/protocols": "8.24.12",
|
||||
"@wdio/types": "8.28.6",
|
||||
"@wdio/utils": "8.28.6",
|
||||
"@wdio/types": "8.27.0",
|
||||
"@wdio/utils": "8.27.0",
|
||||
"deepmerge-ts": "^5.1.0",
|
||||
"got": "^12.6.1",
|
||||
"ky": "^0.33.0",
|
||||
@ -8542,23 +8542,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webdriverio": {
|
||||
"version": "8.28.6",
|
||||
"resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.28.6.tgz",
|
||||
"integrity": "sha512-vWo3Qx0bWubzUBBLaLYgeQkSN63KTfW5P3IbayhJ8Qx+NVVnclG0mu4mQj00gvj8+3a8opef6T54gdzitVSHSw==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.27.0.tgz",
|
||||
"integrity": "sha512-Qh5VCiBjEmxnmXcL1QEFoDzFqTtaWKrXriuU5G0yHKCModGAt2G7IHTkAok3CpmkVJfZpEvY630aP1MvgDtFhw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.1.0",
|
||||
"@wdio/config": "8.28.6",
|
||||
"@wdio/logger": "8.28.0",
|
||||
"@wdio/config": "8.27.0",
|
||||
"@wdio/logger": "8.24.12",
|
||||
"@wdio/protocols": "8.24.12",
|
||||
"@wdio/repl": "8.24.12",
|
||||
"@wdio/types": "8.28.6",
|
||||
"@wdio/utils": "8.28.6",
|
||||
"@wdio/types": "8.27.0",
|
||||
"@wdio/utils": "8.27.0",
|
||||
"archiver": "^6.0.0",
|
||||
"aria-query": "^5.0.0",
|
||||
"css-shorthand-properties": "^1.1.1",
|
||||
"css-value": "^0.0.1",
|
||||
"devtools-protocol": "^0.0.1245094",
|
||||
"devtools-protocol": "^0.0.1237913",
|
||||
"grapheme-splitter": "^1.0.2",
|
||||
"import-meta-resolve": "^4.0.0",
|
||||
"is-plain-obj": "^4.1.0",
|
||||
@ -8570,7 +8570,7 @@
|
||||
"resq": "^1.9.1",
|
||||
"rgb2hex": "0.2.5",
|
||||
"serialize-error": "^11.0.1",
|
||||
"webdriver": "8.28.6"
|
||||
"webdriver": "8.27.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.13 || >=18"
|
||||
|
@ -4,17 +4,17 @@
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
||||
"@typescript-eslint/parser": "^6.19.0",
|
||||
"@wdio/cli": "^8.28.6",
|
||||
"@wdio/local-runner": "^8.28.7",
|
||||
"@wdio/mocha-framework": "^8.28.6",
|
||||
"@wdio/spec-reporter": "^8.28.6",
|
||||
"@typescript-eslint/eslint-plugin": "^6.18.0",
|
||||
"@typescript-eslint/parser": "^6.18.0",
|
||||
"@wdio/cli": "^8.27.1",
|
||||
"@wdio/local-runner": "^8.27.0",
|
||||
"@wdio/mocha-framework": "^8.27.0",
|
||||
"@wdio/spec-reporter": "^8.27.0",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-sonarjs": "^0.23.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^3.2.4",
|
||||
"prettier": "^3.1.1",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.3.3",
|
||||
"wdio-wait-for": "^3.0.10"
|
||||
|
@ -9,5 +9,3 @@ poly.ts
|
||||
src/locale-codes.ts
|
||||
src/locales/
|
||||
storybook-static/
|
||||
# Prettier breaks the tsconfig file
|
||||
tsconfig.json
|
||||
|
1118
web/package-lock.json
generated
1118
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -40,17 +40,17 @@
|
||||
"@codemirror/lang-xml": "^6.0.2",
|
||||
"@codemirror/legacy-modes": "^6.3.3",
|
||||
"@codemirror/theme-one-dark": "^6.1.2",
|
||||
"@formatjs/intl-listformat": "^7.5.5",
|
||||
"@formatjs/intl-listformat": "^7.5.3",
|
||||
"@fortawesome/fontawesome-free": "^6.5.1",
|
||||
"@goauthentik/api": "^2023.10.6-1705263684",
|
||||
"@goauthentik/api": "^2023.10.5-1704382057",
|
||||
"@lit-labs/context": "^0.4.0",
|
||||
"@lit-labs/task": "^3.1.0",
|
||||
"@lit/localize": "^0.11.4",
|
||||
"@open-wc/lit-helpers": "^0.6.0",
|
||||
"@patternfly/elements": "^2.4.0",
|
||||
"@patternfly/patternfly": "^4.224.2",
|
||||
"@sentry/browser": "^7.93.0",
|
||||
"@sentry/tracing": "^7.93.0",
|
||||
"@sentry/browser": "^7.92.0",
|
||||
"@sentry/tracing": "^7.92.0",
|
||||
"@webcomponents/webcomponentsjs": "^2.8.0",
|
||||
"base64-js": "^1.5.1",
|
||||
"chart.js": "^4.4.1",
|
||||
@ -62,7 +62,7 @@
|
||||
"fuse.js": "^7.0.0",
|
||||
"guacamole-common-js": "^1.5.0",
|
||||
"lit": "^2.8.0",
|
||||
"mermaid": "^10.7.0",
|
||||
"mermaid": "^10.6.1",
|
||||
"rapidoc": "^9.3.4",
|
||||
"style-mod": "^4.1.0",
|
||||
"webcomponent-qr-code": "^1.2.0",
|
||||
@ -75,7 +75,7 @@
|
||||
"@babel/plugin-transform-private-methods": "^7.23.3",
|
||||
"@babel/plugin-transform-private-property-in-object": "^7.23.4",
|
||||
"@babel/plugin-transform-runtime": "^7.23.7",
|
||||
"@babel/preset-env": "^7.23.8",
|
||||
"@babel/preset-env": "^7.23.7",
|
||||
"@babel/preset-typescript": "^7.23.3",
|
||||
"@hcaptcha/types": "^1.0.3",
|
||||
"@jackfranklin/rollup-plugin-markdown": "^0.4.0",
|
||||
@ -86,22 +86,21 @@
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@rollup/plugin-replace": "^5.0.5",
|
||||
"@rollup/plugin-terser": "^0.4.4",
|
||||
"@rollup/plugin-typescript": "^11.1.6",
|
||||
"@spotlightjs/spotlight": "^1.2.7",
|
||||
"@storybook/addon-essentials": "^7.6.9",
|
||||
"@storybook/addon-links": "^7.6.9",
|
||||
"@storybook/api": "^7.6.9",
|
||||
"@rollup/plugin-typescript": "^11.1.5",
|
||||
"@storybook/addon-essentials": "^7.6.7",
|
||||
"@storybook/addon-links": "^7.6.7",
|
||||
"@storybook/api": "^7.6.7",
|
||||
"@storybook/blocks": "^7.6.4",
|
||||
"@storybook/manager-api": "^7.6.9",
|
||||
"@storybook/web-components": "^7.6.9",
|
||||
"@storybook/web-components-vite": "^7.6.9",
|
||||
"@storybook/manager-api": "^7.6.7",
|
||||
"@storybook/web-components": "^7.6.7",
|
||||
"@storybook/web-components-vite": "^7.6.7",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||
"@types/chart.js": "^2.9.41",
|
||||
"@types/codemirror": "5.60.15",
|
||||
"@types/grecaptcha": "^3.0.7",
|
||||
"@types/guacamole-common-js": "1.5.2",
|
||||
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
||||
"@typescript-eslint/parser": "^6.19.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.18.0",
|
||||
"@typescript-eslint/parser": "^6.18.0",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
"babel-plugin-tsconfig-paths": "^1.0.3",
|
||||
"cross-env": "^7.0.3",
|
||||
@ -111,25 +110,25 @@
|
||||
"eslint-plugin-lit": "^1.11.0",
|
||||
"eslint-plugin-sonarjs": "^0.23.0",
|
||||
"eslint-plugin-storybook": "^0.6.15",
|
||||
"lit-analyzer": "^2.0.3",
|
||||
"lit-analyzer": "^2.0.2",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^3.2.4",
|
||||
"prettier": "^3.1.1",
|
||||
"pseudolocale": "^2.0.0",
|
||||
"pyright": "=1.1.338",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"rollup": "^4.9.5",
|
||||
"rollup": "^4.9.4",
|
||||
"rollup-plugin-copy": "^3.5.0",
|
||||
"rollup-plugin-cssimport": "^1.0.3",
|
||||
"rollup-plugin-modify": "^3.0.0",
|
||||
"rollup-plugin-postcss-lit": "^2.1.0",
|
||||
"storybook": "^7.6.9",
|
||||
"storybook": "^7.6.7",
|
||||
"storybook-addon-mock": "^4.3.0",
|
||||
"ts-lit-plugin": "^2.0.2",
|
||||
"ts-lit-plugin": "^2.0.1",
|
||||
"tslib": "^2.6.2",
|
||||
"turnstile-types": "^1.2.0",
|
||||
"typescript": "^5.3.3",
|
||||
"vite-tsconfig-paths": "^4.3.1"
|
||||
"vite-tsconfig-paths": "^4.2.3"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/darwin-arm64": "^0.19.11",
|
||||
|
@ -7,7 +7,7 @@ import "@goauthentik/components/ak-number-input";
|
||||
import "@goauthentik/components/ak-radio-input";
|
||||
import "@goauthentik/components/ak-switch-input";
|
||||
import "@goauthentik/components/ak-text-input";
|
||||
import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider";
|
||||
import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
|
||||
@ -32,7 +32,7 @@ import {
|
||||
} from "./LDAPOptionsAndHelp";
|
||||
|
||||
@customElement("ak-application-wizard-authentication-by-ldap")
|
||||
export class ApplicationWizardApplicationDetails extends WithTenantConfig(BaseProviderPanel) {
|
||||
export class ApplicationWizardApplicationDetails extends WithBrandConfig(BaseProviderPanel) {
|
||||
render() {
|
||||
const provider = this.wizard.provider as LDAPProvider | undefined;
|
||||
const errors = this.wizard.errors.provider;
|
||||
@ -57,7 +57,7 @@ export class ApplicationWizardApplicationDetails extends WithTenantConfig(BasePr
|
||||
<ak-tenanted-flow-search
|
||||
flowType=${FlowsInstancesListDesignationEnum.Authentication}
|
||||
.currentFlow=${provider?.authorizationFlow}
|
||||
.tenantFlow=${this.tenant.flowAuthentication}
|
||||
.tenantFlow=${this.brand.flowAuthentication}
|
||||
required
|
||||
></ak-tenanted-flow-search>
|
||||
<p class="pf-c-form__helper-text">
|
||||
|
@ -3,7 +3,7 @@ import "@goauthentik/admin/common/ak-crypto-certificate-search";
|
||||
import "@goauthentik/admin/common/ak-flow-search/ak-tenanted-flow-search";
|
||||
import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/components/ak-text-input";
|
||||
import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider";
|
||||
import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
|
||||
@ -17,7 +17,7 @@ import { FlowsInstancesListDesignationEnum, RadiusProvider } from "@goauthentik/
|
||||
import BaseProviderPanel from "../BaseProviderPanel";
|
||||
|
||||
@customElement("ak-application-wizard-authentication-by-radius")
|
||||
export class ApplicationWizardAuthenticationByRadius extends WithTenantConfig(BaseProviderPanel) {
|
||||
export class ApplicationWizardAuthenticationByRadius extends WithBrandConfig(BaseProviderPanel) {
|
||||
render() {
|
||||
const provider = this.wizard.provider as RadiusProvider | undefined;
|
||||
const errors = this.wizard.errors.provider;
|
||||
@ -42,7 +42,7 @@ export class ApplicationWizardAuthenticationByRadius extends WithTenantConfig(Ba
|
||||
<ak-tenanted-flow-search
|
||||
flowType=${FlowsInstancesListDesignationEnum.Authentication}
|
||||
.currentFlow=${provider?.authorizationFlow}
|
||||
.tenantFlow=${this.tenant.flowAuthentication}
|
||||
.tenantFlow=${this.brand.flowAuthentication}
|
||||
required
|
||||
></ak-tenanted-flow-search>
|
||||
<p class="pf-c-form__helper-text">
|
||||
|
@ -9,11 +9,11 @@ import { MessageLevel } from "@goauthentik/common/messages";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider";
|
||||
import {
|
||||
CapabilitiesEnum,
|
||||
WithCapabilitiesConfig,
|
||||
} from "@goauthentik/elements/Interface/capabilitiesProvider";
|
||||
import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider";
|
||||
import "@goauthentik/elements/buttons/ActionButton";
|
||||
import "@goauthentik/elements/buttons/Dropdown";
|
||||
import "@goauthentik/elements/forms/DeleteBulkForm";
|
||||
@ -110,7 +110,7 @@ export class RelatedUserAdd extends Form<{ users: number[] }> {
|
||||
}
|
||||
|
||||
@customElement("ak-user-related-list")
|
||||
export class RelatedUserList extends WithTenantConfig(WithCapabilitiesConfig(Table<User>)) {
|
||||
export class RelatedUserList extends WithBrandConfig(WithCapabilitiesConfig(Table<User>)) {
|
||||
expandable = true;
|
||||
checkbox = true;
|
||||
|
||||
@ -295,7 +295,7 @@ export class RelatedUserList extends WithTenantConfig(WithCapabilitiesConfig(Tab
|
||||
${msg("Set password")}
|
||||
</button>
|
||||
</ak-forms-modal>
|
||||
${this.tenant?.flowRecovery
|
||||
${this.brand?.flowRecovery
|
||||
? html`
|
||||
<ak-action-button
|
||||
class="pf-m-secondary"
|
||||
|
@ -5,7 +5,6 @@ import "@goauthentik/admin/property-mappings/PropertyMappingSAMLForm";
|
||||
import "@goauthentik/admin/property-mappings/PropertyMappingScopeForm";
|
||||
import "@goauthentik/admin/property-mappings/PropertyMappingTestForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/elements/Alert";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import "@goauthentik/elements/forms/ProxyForm";
|
||||
import "@goauthentik/elements/wizard/FormWizardPage";
|
||||
@ -64,7 +63,7 @@ export class InitialPropertyMappingWizardPage extends WizardPage {
|
||||
];
|
||||
this.host.isValid = true;
|
||||
}}
|
||||
?disabled=${type.requiresEnterprise ? this.enterprise?.hasLicense : false}
|
||||
?disabled=${type.requiresEnterprise ? !this.enterprise?.hasLicense : false}
|
||||
/>
|
||||
<label class="pf-c-radio__label" for=${`${type.component}-${type.modelName}`}
|
||||
>${type.name}</label
|
||||
@ -115,7 +114,6 @@ export class PropertyMappingWizard extends AKElement {
|
||||
<ak-property-mapping-wizard-initial
|
||||
slot="initial"
|
||||
.mappingTypes=${this.mappingTypes}
|
||||
.enterprise=${this.enterprise}
|
||||
>
|
||||
</ak-property-mapping-wizard-initial>
|
||||
${this.mappingTypes.map((type) => {
|
||||
|
@ -3,7 +3,7 @@ import "@goauthentik/admin/common/ak-flow-search/ak-tenanted-flow-search";
|
||||
import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider";
|
||||
import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
@ -25,7 +25,7 @@ import {
|
||||
} from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-provider-ldap-form")
|
||||
export class LDAPProviderFormPage extends WithTenantConfig(BaseProviderForm<LDAPProvider>) {
|
||||
export class LDAPProviderFormPage extends WithBrandConfig(BaseProviderForm<LDAPProvider>) {
|
||||
async loadInstance(pk: number): Promise<LDAPProvider> {
|
||||
return new ProvidersApi(DEFAULT_CONFIG).providersLdapRetrieve({
|
||||
id: pk,
|
||||
@ -68,7 +68,7 @@ export class LDAPProviderFormPage extends WithTenantConfig(BaseProviderForm<LDAP
|
||||
<ak-tenanted-flow-search
|
||||
flowType=${FlowsInstancesListDesignationEnum.Authentication}
|
||||
.currentFlow=${this.instance?.authorizationFlow}
|
||||
.tenantFlow=${this.tenant?.flowAuthentication}
|
||||
.tenantFlow=${this.brand?.flowAuthentication}
|
||||
required
|
||||
></ak-tenanted-flow-search>
|
||||
<p class="pf-c-form__helper-text">${msg("Flow used for users to authenticate.")}</p>
|
||||
|
@ -203,9 +203,8 @@ export class LDAPProviderViewPage extends AKElement {
|
||||
class="pf-c-form-control"
|
||||
readonly
|
||||
type="text"
|
||||
value=${`cn=${
|
||||
this.me?.user.username
|
||||
},ou=users,${this.provider?.baseDn?.toLowerCase()}`}
|
||||
value=${`cn=${this.me?.user
|
||||
.username},ou=users,${this.provider?.baseDn?.toLowerCase()}`}
|
||||
/>
|
||||
</div>
|
||||
<div class="pf-c-form__group">
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils";
|
||||
import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider";
|
||||
import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
@ -14,7 +14,7 @@ import { customElement } from "lit/decorators.js";
|
||||
import { FlowsInstancesListDesignationEnum, ProvidersApi, RadiusProvider } from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-provider-radius-form")
|
||||
export class RadiusProviderFormPage extends WithTenantConfig(BaseProviderForm<RadiusProvider>) {
|
||||
export class RadiusProviderFormPage extends WithBrandConfig(BaseProviderForm<RadiusProvider>) {
|
||||
loadInstance(pk: number): Promise<RadiusProvider> {
|
||||
return new ProvidersApi(DEFAULT_CONFIG).providersRadiusRetrieve({
|
||||
id: pk,
|
||||
@ -57,7 +57,7 @@ export class RadiusProviderFormPage extends WithTenantConfig(BaseProviderForm<Ra
|
||||
<ak-tenanted-flow-search
|
||||
flowType=${FlowsInstancesListDesignationEnum.Authentication}
|
||||
.currentFlow=${this.instance?.authorizationFlow}
|
||||
.tenantFlow=${this.tenant?.flowAuthentication}
|
||||
.tenantFlow=${this.brand?.flowAuthentication}
|
||||
required
|
||||
></ak-tenanted-flow-search>
|
||||
<p class="pf-c-form__helper-text">${msg("Flow used for users to authenticate.")}</p>
|
||||
|
@ -64,7 +64,7 @@ export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuth
|
||||
clearIcon = false;
|
||||
|
||||
async send(data: OAuthSource): Promise<OAuthSource> {
|
||||
data.providerType = (this.providerType?.name || "") as ProviderTypeEnum;
|
||||
data.providerType = (this.providerType?.slug || "") as ProviderTypeEnum;
|
||||
let source: OAuthSource;
|
||||
if (this.instance) {
|
||||
source = await new SourcesApi(DEFAULT_CONFIG).sourcesOauthPartialUpdate({
|
||||
@ -178,7 +178,7 @@ export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuth
|
||||
</p>
|
||||
</ak-form-element-horizontal> `
|
||||
: html``}
|
||||
${this.providerType.name === ProviderTypeEnum.Openidconnect ||
|
||||
${this.providerType.slug === ProviderTypeEnum.Openidconnect ||
|
||||
this.providerType.oidcWellKnownUrl !== ""
|
||||
? html`<ak-form-element-horizontal
|
||||
label=${msg("OIDC Well-known URL")}
|
||||
@ -200,7 +200,7 @@ export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuth
|
||||
</p>
|
||||
</ak-form-element-horizontal>`
|
||||
: html``}
|
||||
${this.providerType.name === ProviderTypeEnum.Openidconnect ||
|
||||
${this.providerType.slug === ProviderTypeEnum.Openidconnect ||
|
||||
this.providerType.oidcJwksUrl !== ""
|
||||
? html`<ak-form-element-horizontal
|
||||
label=${msg("OIDC JWKS URL")}
|
||||
|
@ -8,7 +8,7 @@ import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
import { DefaultTenant } from "@goauthentik/elements/sidebar/SidebarBrand";
|
||||
import { DefaultBrand } from "@goauthentik/elements/sidebar/SidebarBrand";
|
||||
import YAML from "yaml";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
@ -93,7 +93,7 @@ export class TenantForm extends ModelForm<Tenant, string> {
|
||||
type="text"
|
||||
value="${first(
|
||||
this.instance?.brandingTitle,
|
||||
DefaultTenant.brandingTitle,
|
||||
DefaultBrand.brandingTitle,
|
||||
)}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
@ -109,10 +109,7 @@ export class TenantForm extends ModelForm<Tenant, string> {
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
value="${first(
|
||||
this.instance?.brandingLogo,
|
||||
DefaultTenant.brandingLogo,
|
||||
)}"
|
||||
value="${first(this.instance?.brandingLogo, DefaultBrand.brandingLogo)}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
/>
|
||||
@ -129,7 +126,7 @@ export class TenantForm extends ModelForm<Tenant, string> {
|
||||
type="text"
|
||||
value="${first(
|
||||
this.instance?.brandingFavicon,
|
||||
DefaultTenant.brandingFavicon,
|
||||
DefaultBrand.brandingFavicon,
|
||||
)}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
|
@ -12,11 +12,11 @@ import { DefaultUIConfig, uiConfig } from "@goauthentik/common/ui/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/components/ak-status-label";
|
||||
import { rootInterface } from "@goauthentik/elements/Base";
|
||||
import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider";
|
||||
import {
|
||||
CapabilitiesEnum,
|
||||
WithCapabilitiesConfig,
|
||||
} from "@goauthentik/elements/Interface/capabilitiesProvider";
|
||||
import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider";
|
||||
import { PFSize } from "@goauthentik/elements/Spinner";
|
||||
import "@goauthentik/elements/TreeView";
|
||||
import "@goauthentik/elements/buttons/ActionButton";
|
||||
@ -91,7 +91,7 @@ const recoveryButtonStyles = css`
|
||||
`;
|
||||
|
||||
@customElement("ak-user-list")
|
||||
export class UserListPage extends WithTenantConfig(WithCapabilitiesConfig(TablePage<User>)) {
|
||||
export class UserListPage extends WithBrandConfig(WithCapabilitiesConfig(TablePage<User>)) {
|
||||
expandable = true;
|
||||
checkbox = true;
|
||||
|
||||
@ -352,7 +352,7 @@ export class UserListPage extends WithTenantConfig(WithCapabilitiesConfig(TableP
|
||||
${msg("Set password")}
|
||||
</button>
|
||||
</ak-forms-modal>
|
||||
${this.tenant.flowRecovery
|
||||
${this.brand.flowRecovery
|
||||
? html`
|
||||
<ak-action-button
|
||||
class="pf-m-secondary"
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 699 KiB After Width: | Height: | Size: 717 KiB |
@ -6,7 +6,13 @@ import {
|
||||
import { EVENT_LOCALE_REQUEST, EVENT_REFRESH, VERSION } from "@goauthentik/common/constants";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
|
||||
import { Config, Configuration, CoreApi, CurrentTenant, RootApi } from "@goauthentik/api";
|
||||
import {
|
||||
Config,
|
||||
Configuration,
|
||||
CoreApi,
|
||||
CurrentTenant as CurrentBrand,
|
||||
RootApi,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
let globalConfigPromise: Promise<Config> | undefined = Promise.resolve(globalAK().config);
|
||||
export function config(): Promise<Config> {
|
||||
@ -16,7 +22,7 @@ export function config(): Promise<Config> {
|
||||
return globalConfigPromise;
|
||||
}
|
||||
|
||||
export function tenantSetFavicon(tenant: CurrentTenant) {
|
||||
export function brandSetFavicon(brand: CurrentBrand) {
|
||||
/**
|
||||
* <link rel="icon" href="/static/dist/assets/icons/icon.png">
|
||||
* <link rel="shortcut icon" href="/static/dist/assets/icons/icon.png">
|
||||
@ -29,36 +35,36 @@ export function tenantSetFavicon(tenant: CurrentTenant) {
|
||||
relIcon.rel = rel;
|
||||
document.getElementsByTagName("head")[0].appendChild(relIcon);
|
||||
}
|
||||
relIcon.href = tenant.brandingFavicon;
|
||||
relIcon.href = brand.brandingFavicon;
|
||||
});
|
||||
}
|
||||
|
||||
export function tenantSetLocale(tenant: CurrentTenant) {
|
||||
if (tenant.defaultLocale === "") {
|
||||
export function brandSetLocale(brand: CurrentBrand) {
|
||||
if (brand.defaultLocale === "") {
|
||||
return;
|
||||
}
|
||||
console.debug("authentik/locale: setting locale from tenant default");
|
||||
console.debug("authentik/locale: setting locale from brand default");
|
||||
window.dispatchEvent(
|
||||
new CustomEvent(EVENT_LOCALE_REQUEST, {
|
||||
composed: true,
|
||||
bubbles: true,
|
||||
detail: { locale: tenant.defaultLocale },
|
||||
detail: { locale: brand.defaultLocale },
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
let globalTenantPromise: Promise<CurrentTenant> | undefined = Promise.resolve(globalAK().tenant);
|
||||
export function tenant(): Promise<CurrentTenant> {
|
||||
if (!globalTenantPromise) {
|
||||
globalTenantPromise = new CoreApi(DEFAULT_CONFIG)
|
||||
let globalBrandPromise: Promise<CurrentBrand> | undefined = Promise.resolve(globalAK().tenant);
|
||||
export function brand(): Promise<CurrentBrand> {
|
||||
if (!globalBrandPromise) {
|
||||
globalBrandPromise = new CoreApi(DEFAULT_CONFIG)
|
||||
.coreTenantsCurrentRetrieve()
|
||||
.then((tenant) => {
|
||||
tenantSetFavicon(tenant);
|
||||
tenantSetLocale(tenant);
|
||||
return tenant;
|
||||
.then((brand) => {
|
||||
brandSetFavicon(brand);
|
||||
brandSetLocale(brand);
|
||||
return brand;
|
||||
});
|
||||
}
|
||||
return globalTenantPromise;
|
||||
return globalBrandPromise;
|
||||
}
|
||||
|
||||
export function getMetaContent(key: string): string {
|
||||
@ -90,9 +96,9 @@ window.addEventListener(EVENT_REFRESH, () => {
|
||||
// Upon global refresh, disregard whatever was pre-hydrated and
|
||||
// actually load info from API
|
||||
globalConfigPromise = undefined;
|
||||
globalTenantPromise = undefined;
|
||||
globalBrandPromise = undefined;
|
||||
config();
|
||||
tenant();
|
||||
brand();
|
||||
});
|
||||
|
||||
console.debug(`authentik(early): version ${VERSION}, apiBase ${DEFAULT_CONFIG.basePath}`);
|
||||
|
@ -2,7 +2,7 @@ import { EVENT_REQUEST_POST } from "@goauthentik/common/constants";
|
||||
import { getCookie } from "@goauthentik/common/utils";
|
||||
|
||||
import {
|
||||
CurrentTenant,
|
||||
CurrentTenant as CurrentBrand,
|
||||
FetchParams,
|
||||
Middleware,
|
||||
RequestContext,
|
||||
@ -18,13 +18,13 @@ export interface RequestInfo {
|
||||
}
|
||||
|
||||
export class LoggingMiddleware implements Middleware {
|
||||
tenant: CurrentTenant;
|
||||
constructor(tenant: CurrentTenant) {
|
||||
this.tenant = tenant;
|
||||
brand: CurrentBrand;
|
||||
constructor(brand: CurrentBrand) {
|
||||
this.brand = brand;
|
||||
}
|
||||
|
||||
post(context: ResponseContext): Promise<Response | void> {
|
||||
let msg = `authentik/api[${this.tenant.matchedDomain}]: `;
|
||||
let msg = `authentik/api[${this.brand.matchedDomain}]: `;
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/console#styling_console_output
|
||||
msg += `%c${context.response.status}%c ${context.init.method} ${context.url}`;
|
||||
let style = "";
|
||||
|
@ -3,7 +3,7 @@ export const SUCCESS_CLASS = "pf-m-success";
|
||||
export const ERROR_CLASS = "pf-m-danger";
|
||||
export const PROGRESS_CLASS = "pf-m-in-progress";
|
||||
export const CURRENT_CLASS = "pf-m-current";
|
||||
export const VERSION = "2023.10.6";
|
||||
export const VERSION = "2023.10.5";
|
||||
export const TITLE_DEFAULT = "authentik";
|
||||
export const ROUTE_SEPARATOR = ";";
|
||||
|
||||
|
@ -5,7 +5,7 @@ import { me } from "@goauthentik/common/users";
|
||||
import * as Sentry from "@sentry/browser";
|
||||
import { Integrations } from "@sentry/tracing";
|
||||
|
||||
import { CapabilitiesEnum, Config, ResponseError } from "@goauthentik/api";
|
||||
import { Config, ResponseError } from "@goauthentik/api";
|
||||
|
||||
export const TAG_SENTRY_COMPONENT = "authentik.component";
|
||||
export const TAG_SENTRY_CAPABILITIES = "authentik.capabilities";
|
||||
@ -60,11 +60,6 @@ export async function configureSentry(canDoPpi = false): Promise<Config> {
|
||||
scope.setTransactionName(`authentik.web.if.${currentInterface()}`),
|
||||
);
|
||||
}
|
||||
if (cfg.capabilities.includes(CapabilitiesEnum.CanDebug)) {
|
||||
const Spotlight = await import("@spotlightjs/spotlight");
|
||||
|
||||
Spotlight.init({ injectImmediately: true });
|
||||
}
|
||||
if (cfg.errorReporting.sendPii && canDoPpi) {
|
||||
me().then((user) => {
|
||||
Sentry.setUser({ email: user.user.email });
|
||||
|
@ -134,11 +134,9 @@ html > form > input {
|
||||
);
|
||||
max-height: 9rem;
|
||||
}
|
||||
|
||||
.ak-brand {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
.ak-brand img {
|
||||
padding: 0 2rem;
|
||||
|
@ -257,8 +257,7 @@ select[multiple] option:checked {
|
||||
.pf-c-login__main-header-desc {
|
||||
color: var(--ak-dark-foreground);
|
||||
}
|
||||
.pf-c-login__main-footer-links-item img,
|
||||
.pf-c-login__main-footer-links-item .fas {
|
||||
.pf-c-login__main-footer-links-item img {
|
||||
filter: invert(1);
|
||||
}
|
||||
.pf-c-login__main-footer-band {
|
||||
|
@ -1,11 +1,9 @@
|
||||
import { createContext } from "@lit-labs/context";
|
||||
|
||||
import type { Config, CurrentTenant } from "@goauthentik/api";
|
||||
import type { Config, CurrentTenant as CurrentBrand } from "@goauthentik/api";
|
||||
|
||||
export const authentikConfigContext = createContext<Config>(Symbol("authentik-config-context"));
|
||||
|
||||
export const authentikTenantContext = createContext<CurrentTenant>(
|
||||
Symbol("authentik-tenant-context"),
|
||||
);
|
||||
export const authentikBrandContext = createContext<CurrentBrand>(Symbol("authentik-brand-context"));
|
||||
|
||||
export default authentikConfigContext;
|
||||
|
@ -9,13 +9,13 @@ import { LitElement } from "lit";
|
||||
import AKGlobal from "@goauthentik/common/styles/authentik.css";
|
||||
import ThemeDark from "@goauthentik/common/styles/theme-dark.css";
|
||||
|
||||
import { Config, CurrentTenant, UiThemeEnum } from "@goauthentik/api";
|
||||
import { Config, CurrentTenant as CurrentBrand, UiThemeEnum } from "@goauthentik/api";
|
||||
|
||||
import { AdoptedStyleSheetsElement } from "./types";
|
||||
|
||||
type AkInterface = HTMLElement & {
|
||||
getTheme: () => Promise<UiThemeEnum>;
|
||||
tenant?: CurrentTenant;
|
||||
brand?: CurrentBrand;
|
||||
uiConfig?: UIConfig;
|
||||
config?: Config;
|
||||
};
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { config, tenant } from "@goauthentik/common/api/config";
|
||||
import { brand, config } from "@goauthentik/common/api/config";
|
||||
import { UIConfig, uiConfig } from "@goauthentik/common/ui/config";
|
||||
import {
|
||||
authentikBrandContext,
|
||||
authentikConfigContext,
|
||||
authentikTenantContext,
|
||||
} from "@goauthentik/elements/AuthentikContexts";
|
||||
import type { AdoptedStyleSheetsElement } from "@goauthentik/elements/types";
|
||||
import { ensureCSSStyleSheet } from "@goauthentik/elements/utils/ensureCSSStyleSheet";
|
||||
@ -12,13 +12,13 @@ import { state } from "lit/decorators.js";
|
||||
|
||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
|
||||
import { Config, CurrentTenant, UiThemeEnum } from "@goauthentik/api";
|
||||
import { Config, CurrentTenant as CurrentBrand, UiThemeEnum } from "@goauthentik/api";
|
||||
|
||||
import { AKElement } from "../Base";
|
||||
|
||||
type AkInterface = HTMLElement & {
|
||||
getTheme: () => Promise<UiThemeEnum>;
|
||||
tenant?: CurrentTenant;
|
||||
brand?: CurrentBrand;
|
||||
uiConfig?: UIConfig;
|
||||
config?: Config;
|
||||
};
|
||||
@ -45,28 +45,28 @@ export class Interface extends AKElement implements AkInterface {
|
||||
return this._config;
|
||||
}
|
||||
|
||||
_tenantContext = new ContextProvider(this, {
|
||||
context: authentikTenantContext,
|
||||
_brandContext = new ContextProvider(this, {
|
||||
context: authentikBrandContext,
|
||||
initialValue: undefined,
|
||||
});
|
||||
|
||||
_tenant?: CurrentTenant;
|
||||
_brand?: CurrentBrand;
|
||||
|
||||
@state()
|
||||
set tenant(c: CurrentTenant) {
|
||||
this._tenant = c;
|
||||
this._tenantContext.setValue(c);
|
||||
set brand(c: CurrentBrand) {
|
||||
this._brand = c;
|
||||
this._brandContext.setValue(c);
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
get tenant(): CurrentTenant | undefined {
|
||||
return this._tenant;
|
||||
get brand(): CurrentBrand | undefined {
|
||||
return this._brand;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
document.adoptedStyleSheets = [...document.adoptedStyleSheets, ensureCSSStyleSheet(PFBase)];
|
||||
tenant().then((tenant) => (this.tenant = tenant));
|
||||
brand().then((brand) => (this.brand = brand));
|
||||
config().then((config) => (this.config = config));
|
||||
this.dataset.akInterfaceRoot = "true";
|
||||
}
|
||||
|
20
web/src/elements/Interface/brandProvider.ts
Normal file
20
web/src/elements/Interface/brandProvider.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { authentikBrandContext } from "@goauthentik/elements/AuthentikContexts";
|
||||
|
||||
import { consume } from "@lit-labs/context";
|
||||
import type { LitElement } from "lit";
|
||||
|
||||
import type { CurrentTenant as CurrentBrand } from "@goauthentik/api";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type Constructor<T = object> = abstract new (...args: any[]) => T;
|
||||
|
||||
export function WithBrandConfig<T extends Constructor<LitElement>>(
|
||||
superclass: T,
|
||||
subscribe = true,
|
||||
) {
|
||||
abstract class WithBrandProvider extends superclass {
|
||||
@consume({ context: authentikBrandContext, subscribe })
|
||||
public brand!: CurrentBrand;
|
||||
}
|
||||
return WithBrandProvider;
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
import { authentikTenantContext } from "@goauthentik/elements/AuthentikContexts";
|
||||
|
||||
import { consume } from "@lit-labs/context";
|
||||
import type { LitElement } from "lit";
|
||||
|
||||
import type { CurrentTenant } from "@goauthentik/api";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type Constructor<T = object> = abstract new (...args: any[]) => T;
|
||||
|
||||
export function WithTenantConfig<T extends Constructor<LitElement>>(
|
||||
superclass: T,
|
||||
subscribe = true,
|
||||
) {
|
||||
abstract class WithTenantProvider extends superclass {
|
||||
@consume({ context: authentikTenantContext, subscribe })
|
||||
public tenant!: CurrentTenant;
|
||||
}
|
||||
return WithTenantProvider;
|
||||
}
|
@ -9,7 +9,7 @@ import {
|
||||
import { currentInterface } from "@goauthentik/common/sentry";
|
||||
import { me } from "@goauthentik/common/users";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider";
|
||||
import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider";
|
||||
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
@ -24,7 +24,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
import { EventsApi } from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-page-header")
|
||||
export class PageHeader extends WithTenantConfig(AKElement) {
|
||||
export class PageHeader extends WithBrandConfig(AKElement) {
|
||||
@property()
|
||||
icon?: string;
|
||||
|
||||
@ -37,7 +37,7 @@ export class PageHeader extends WithTenantConfig(AKElement) {
|
||||
@property()
|
||||
set header(value: string) {
|
||||
const currentIf = currentInterface();
|
||||
let title = this.tenant?.brandingTitle || TITLE_DEFAULT;
|
||||
let title = this.brand?.brandingTitle || TITLE_DEFAULT;
|
||||
if (currentIf === "admin") {
|
||||
title = `${msg("Admin")} - ${title}`;
|
||||
}
|
||||
|
324
web/src/elements/forms/SearchSelect.ts
Normal file
324
web/src/elements/forms/SearchSelect.ts
Normal file
@ -0,0 +1,324 @@
|
||||
import { PreventFormSubmit } from "@goauthentik/app/elements/forms/helpers";
|
||||
import { EVENT_REFRESH } from "@goauthentik/common/constants";
|
||||
import { ascii_letters, digits, groupBy, randomString } from "@goauthentik/common/utils";
|
||||
import { adaptCSS } from "@goauthentik/common/utils";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { CSSResult, TemplateResult, html, render } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
import PFDropdown from "@patternfly/patternfly/components/Dropdown/dropdown.css";
|
||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||
import PFSelect from "@patternfly/patternfly/components/Select/select.css";
|
||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
|
||||
@customElement("ak-search-select")
|
||||
export class SearchSelect<T> extends CustomEmitterElement(AKElement) {
|
||||
@property()
|
||||
query?: string;
|
||||
|
||||
@property({ attribute: false })
|
||||
objects?: T[];
|
||||
|
||||
@property({ attribute: false })
|
||||
selectedObject?: T;
|
||||
|
||||
@property()
|
||||
name?: string;
|
||||
|
||||
@property({ type: Boolean })
|
||||
open = false;
|
||||
|
||||
@property({ type: Boolean })
|
||||
blankable = false;
|
||||
|
||||
@property()
|
||||
placeholder: string = msg("Select an object.");
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [PFBase, PFForm, PFFormControl, PFSelect];
|
||||
}
|
||||
|
||||
@property({ attribute: false })
|
||||
fetchObjects!: (query?: string) => Promise<T[]>;
|
||||
|
||||
@property({ attribute: false })
|
||||
renderElement!: (element: T) => string;
|
||||
|
||||
@property({ attribute: false })
|
||||
renderDescription?: (element: T) => TemplateResult;
|
||||
|
||||
@property({ attribute: false })
|
||||
value!: (element: T | undefined) => unknown;
|
||||
|
||||
@property({ attribute: false })
|
||||
selected?: (element: T, elements: T[]) => boolean;
|
||||
|
||||
@property()
|
||||
emptyOption = "---------";
|
||||
|
||||
@property({ attribute: false })
|
||||
groupBy: (items: T[]) => [string, T[]][] = (items: T[]): [string, T[]][] => {
|
||||
return groupBy(items, () => {
|
||||
return "";
|
||||
});
|
||||
};
|
||||
|
||||
scrollHandler?: () => void;
|
||||
observer: IntersectionObserver;
|
||||
dropdownUID: string;
|
||||
dropdownContainer: HTMLDivElement;
|
||||
isFetchingData = false;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
if (!document.adoptedStyleSheets.includes(PFDropdown)) {
|
||||
document.adoptedStyleSheets = adaptCSS([...document.adoptedStyleSheets, PFDropdown]);
|
||||
}
|
||||
this.dropdownContainer = document.createElement("div");
|
||||
this.observer = new IntersectionObserver(() => {
|
||||
this.open = false;
|
||||
this.shadowRoot
|
||||
?.querySelectorAll<HTMLInputElement>(
|
||||
".pf-c-form-control.pf-c-select__toggle-typeahead",
|
||||
)
|
||||
.forEach((input) => {
|
||||
input.blur();
|
||||
});
|
||||
});
|
||||
this.observer.observe(this);
|
||||
this.dropdownUID = `dropdown-${randomString(10, ascii_letters + digits)}`;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
shouldUpdate(changedProperties: Map<string, any>) {
|
||||
if (changedProperties.has("selectedObject")) {
|
||||
this.dispatchCustomEvent("ak-change", {
|
||||
value: this.selectedObject,
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
toForm(): unknown {
|
||||
if (!this.objects) {
|
||||
throw new PreventFormSubmit(msg("Loading options..."));
|
||||
}
|
||||
return this.value(this.selectedObject) || "";
|
||||
}
|
||||
|
||||
firstUpdated(): void {
|
||||
this.updateData();
|
||||
}
|
||||
|
||||
updateData(): void {
|
||||
if (this.isFetchingData) {
|
||||
return;
|
||||
}
|
||||
this.isFetchingData = true;
|
||||
this.fetchObjects(this.query).then((objects) => {
|
||||
objects.forEach((obj) => {
|
||||
if (this.selected && this.selected(obj, objects || [])) {
|
||||
this.selectedObject = obj;
|
||||
}
|
||||
});
|
||||
this.objects = objects;
|
||||
this.isFetchingData = false;
|
||||
});
|
||||
}
|
||||
|
||||
connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this.dropdownContainer = document.createElement("div");
|
||||
this.dropdownContainer.dataset["managedBy"] = "ak-search-select";
|
||||
if (this.name) {
|
||||
this.dropdownContainer.dataset["managedFor"] = this.name;
|
||||
}
|
||||
document.body.append(this.dropdownContainer);
|
||||
this.updateData();
|
||||
this.addEventListener(EVENT_REFRESH, this.updateData);
|
||||
this.scrollHandler = () => {
|
||||
this.requestUpdate();
|
||||
};
|
||||
window.addEventListener("scroll", this.scrollHandler);
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
this.removeEventListener(EVENT_REFRESH, this.updateData);
|
||||
if (this.scrollHandler) {
|
||||
window.removeEventListener("scroll", this.scrollHandler);
|
||||
}
|
||||
this.dropdownContainer.remove();
|
||||
this.observer.disconnect();
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a little bit hacky. Because we mainly want to use this field in modal-based forms,
|
||||
* rendering this menu inline makes the menu not overlay over top of the modal, and cause
|
||||
* the modal to scroll.
|
||||
* Hence, we render the menu into the document root, hide it when this menu isn't open
|
||||
* and remove it on disconnect
|
||||
* Also to move it to the correct position we're getting this elements's position and use that
|
||||
* to position the menu
|
||||
* The other downside this has is that, since we're rendering outside of a shadow root,
|
||||
* the pf-c-dropdown CSS needs to be loaded on the body.
|
||||
*/
|
||||
renderMenu(): void {
|
||||
if (!this.objects) {
|
||||
return;
|
||||
}
|
||||
const pos = this.getBoundingClientRect();
|
||||
let groupedItems = this.groupBy(this.objects);
|
||||
let shouldRenderGroups = true;
|
||||
if (groupedItems.length === 1) {
|
||||
if (groupedItems[0].length < 1 || groupedItems[0][0] === "") {
|
||||
shouldRenderGroups = false;
|
||||
}
|
||||
}
|
||||
if (groupedItems.length === 0) {
|
||||
shouldRenderGroups = false;
|
||||
groupedItems = [["", []]];
|
||||
}
|
||||
const renderGroup = (items: T[], tabIndexStart: number): TemplateResult => {
|
||||
return html`${items.map((obj, index) => {
|
||||
let desc = undefined;
|
||||
if (this.renderDescription) {
|
||||
desc = this.renderDescription(obj);
|
||||
}
|
||||
return html`
|
||||
<li>
|
||||
<button
|
||||
class="pf-c-dropdown__menu-item ${desc === undefined
|
||||
? ""
|
||||
: "pf-m-description"}"
|
||||
role="option"
|
||||
@click=${() => {
|
||||
this.selectedObject = obj;
|
||||
this.open = false;
|
||||
}}
|
||||
tabindex=${index + tabIndexStart}
|
||||
>
|
||||
${desc === undefined
|
||||
? this.renderElement(obj)
|
||||
: html`
|
||||
<div class="pf-c-dropdown__menu-item-main">
|
||||
${this.renderElement(obj)}
|
||||
</div>
|
||||
<div class="pf-c-dropdown__menu-item-description">
|
||||
${desc}
|
||||
</div>
|
||||
`}
|
||||
</button>
|
||||
</li>
|
||||
`;
|
||||
})}`;
|
||||
};
|
||||
render(
|
||||
html`<div
|
||||
class="pf-c-dropdown pf-m-expanded"
|
||||
style="position: fixed; inset: 0px auto auto 0px; z-index: 9999; transform: translate(${pos.x}px, ${pos.y +
|
||||
this.offsetHeight}px); width: ${pos.width}px; ${this.open
|
||||
? ""
|
||||
: "visibility: hidden;"}"
|
||||
>
|
||||
<ul
|
||||
class="pf-c-dropdown__menu pf-m-static"
|
||||
role="listbox"
|
||||
style="max-height:50vh;overflow-y:auto;"
|
||||
id=${this.dropdownUID}
|
||||
tabindex="0"
|
||||
>
|
||||
${this.blankable
|
||||
? html`
|
||||
<li>
|
||||
<button
|
||||
class="pf-c-dropdown__menu-item"
|
||||
role="option"
|
||||
@click=${() => {
|
||||
this.selectedObject = undefined;
|
||||
this.open = false;
|
||||
}}
|
||||
tabindex="0"
|
||||
>
|
||||
${this.emptyOption}
|
||||
</button>
|
||||
</li>
|
||||
`
|
||||
: html``}
|
||||
${shouldRenderGroups
|
||||
? html`${groupedItems.map(([group, items], idx) => {
|
||||
return html`
|
||||
<section class="pf-c-dropdown__group">
|
||||
<h1 class="pf-c-dropdown__group-title">${group}</h1>
|
||||
<ul>
|
||||
${renderGroup(items, idx)}
|
||||
</ul>
|
||||
</section>
|
||||
`;
|
||||
})}`
|
||||
: html`${renderGroup(groupedItems[0][1], 0)}`}
|
||||
</ul>
|
||||
</div>`,
|
||||
this.dropdownContainer,
|
||||
{ host: this },
|
||||
);
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
this.renderMenu();
|
||||
let value = "";
|
||||
if (!this.objects) {
|
||||
value = msg("Loading...");
|
||||
} else if (this.selectedObject) {
|
||||
value = this.renderElement(this.selectedObject);
|
||||
} else if (this.blankable) {
|
||||
value = this.emptyOption;
|
||||
}
|
||||
return html`<div class="pf-c-select">
|
||||
<div class="pf-c-select__toggle pf-m-typeahead">
|
||||
<div class="pf-c-select__toggle-wrapper">
|
||||
<input
|
||||
class="pf-c-form-control pf-c-select__toggle-typeahead"
|
||||
type="text"
|
||||
placeholder=${this.placeholder}
|
||||
spellcheck="false"
|
||||
@input=${(ev: InputEvent) => {
|
||||
this.query = (ev.target as HTMLInputElement).value;
|
||||
this.updateData();
|
||||
}}
|
||||
@focus=${() => {
|
||||
this.open = true;
|
||||
this.renderMenu();
|
||||
}}
|
||||
@blur=${(ev: FocusEvent) => {
|
||||
// For Safari, we get the <ul> element itself here when clicking on one of
|
||||
// it's buttons, as the container has tabindex set
|
||||
if (
|
||||
ev.relatedTarget &&
|
||||
(ev.relatedTarget as HTMLElement).id === this.dropdownUID
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// Check if we're losing focus to one of our dropdown items, and if such don't blur
|
||||
if (ev.relatedTarget instanceof HTMLButtonElement) {
|
||||
const parentMenu = ev.relatedTarget.closest(
|
||||
"ul.pf-c-dropdown__menu.pf-m-static",
|
||||
);
|
||||
if (parentMenu && parentMenu.id === this.dropdownUID) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.open = false;
|
||||
this.renderMenu();
|
||||
}}
|
||||
.value=${value}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
}
|
@ -1,370 +0,0 @@
|
||||
import { PreventFormSubmit } from "@goauthentik/app/elements/forms/helpers";
|
||||
import { EVENT_REFRESH } from "@goauthentik/common/constants";
|
||||
import { ascii_letters, digits, groupBy, randomString } from "@goauthentik/common/utils";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { TemplateResult, html, render } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { styleMap } from "lit/directives/style-map.js";
|
||||
|
||||
import PFDropdown from "@patternfly/patternfly/components/Dropdown/dropdown.css";
|
||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||
import PFSelect from "@patternfly/patternfly/components/Select/select.css";
|
||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
|
||||
type Group<T> = [string, T[]];
|
||||
|
||||
@customElement("ak-search-select")
|
||||
export class SearchSelect<T> extends CustomEmitterElement(AKElement) {
|
||||
// A function which takes the query state object (accepting that it may be empty) and returns a
|
||||
// new collection of objects.
|
||||
@property({ attribute: false })
|
||||
fetchObjects!: (query?: string) => Promise<T[]>;
|
||||
|
||||
// A function passed to this object that extracts a string representation of items of the
|
||||
// collection under search.
|
||||
@property({ attribute: false })
|
||||
renderElement!: (element: T) => string;
|
||||
|
||||
// A function passed to this object that extracts an HTML representation of additional
|
||||
// information for items of the collection under search.
|
||||
@property({ attribute: false })
|
||||
renderDescription?: (element: T) => TemplateResult;
|
||||
|
||||
// A function which returns the currently selected object's primary key, used for serialization
|
||||
// into forms.
|
||||
@property({ attribute: false })
|
||||
value!: (element: T | undefined) => unknown;
|
||||
|
||||
// A function passed to this object that determines an object in the collection under search
|
||||
// should be automatically selected. Only used when the search itself is responsible for
|
||||
// fetching the data; sets an initial default value.
|
||||
@property({ attribute: false })
|
||||
selected?: (element: T, elements: T[]) => boolean;
|
||||
|
||||
// A function passed to this object (or using the default below) that groups objects in the
|
||||
// collection under search into categories.
|
||||
@property({ attribute: false })
|
||||
groupBy: (items: T[]) => [string, T[]][] = (items: T[]): [string, T[]][] => {
|
||||
return groupBy(items, () => {
|
||||
return "";
|
||||
});
|
||||
};
|
||||
|
||||
// Whether or not the dropdown component can be left blank
|
||||
@property({ type: Boolean })
|
||||
blankable = false;
|
||||
|
||||
// An initial string to filter the search contents, and the value of the input which further
|
||||
// serves to restrict the search
|
||||
@property()
|
||||
query?: string;
|
||||
|
||||
// The objects currently available under search
|
||||
@property({ attribute: false })
|
||||
objects?: T[];
|
||||
|
||||
// The currently selected object
|
||||
@property({ attribute: false })
|
||||
selectedObject?: T;
|
||||
|
||||
// Not used in this object. No known purpose.
|
||||
@property()
|
||||
name?: string;
|
||||
|
||||
// Whether or not the dropdown component is visible.
|
||||
@property({ type: Boolean })
|
||||
open = false;
|
||||
|
||||
// The textual placeholder for the search's <input> object, if currently empty. Used as the
|
||||
// native <input> object's `placeholder` field.
|
||||
@property()
|
||||
placeholder: string = msg("Select an object.");
|
||||
|
||||
// A textual string representing "The user has affirmed they want to leave the selection blank."
|
||||
// Only used if `blankable` above is true.
|
||||
@property()
|
||||
emptyOption = "---------";
|
||||
|
||||
// Handle the behavior of the drop-down when the :host scrolls off the page.
|
||||
scrollHandler?: () => void;
|
||||
observer: IntersectionObserver;
|
||||
|
||||
// Handle communication between the :host and the portal
|
||||
dropdownUID: string;
|
||||
dropdownContainer: HTMLDivElement;
|
||||
|
||||
isFetchingData = false;
|
||||
|
||||
static styles = [PFBase, PFForm, PFFormControl, PFSelect];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
if (!document.adoptedStyleSheets.includes(PFDropdown)) {
|
||||
document.adoptedStyleSheets = [...document.adoptedStyleSheets, PFDropdown];
|
||||
}
|
||||
this.dropdownContainer = document.createElement("div");
|
||||
this.observer = new IntersectionObserver(() => {
|
||||
this.open = false;
|
||||
this.shadowRoot
|
||||
?.querySelectorAll<HTMLInputElement>(
|
||||
".pf-c-form-control.pf-c-select__toggle-typeahead",
|
||||
)
|
||||
.forEach((input) => {
|
||||
input.blur();
|
||||
});
|
||||
});
|
||||
this.observer.observe(this);
|
||||
this.dropdownUID = `dropdown-${randomString(10, ascii_letters + digits)}`;
|
||||
this.onMenuItemClick = this.onMenuItemClick.bind(this);
|
||||
this.renderWithMenuGroupTitle = this.renderWithMenuGroupTitle.bind(this);
|
||||
}
|
||||
|
||||
toForm(): unknown {
|
||||
if (!this.objects) {
|
||||
throw new PreventFormSubmit(msg("Loading options..."));
|
||||
}
|
||||
return this.value(this.selectedObject) || "";
|
||||
}
|
||||
|
||||
firstUpdated(): void {
|
||||
this.updateData();
|
||||
}
|
||||
|
||||
updateData(): void {
|
||||
if (this.isFetchingData) {
|
||||
return;
|
||||
}
|
||||
this.isFetchingData = true;
|
||||
this.fetchObjects(this.query).then((objects) => {
|
||||
objects.forEach((obj) => {
|
||||
if (this.selected && this.selected(obj, objects || [])) {
|
||||
this.selectedObject = obj;
|
||||
}
|
||||
});
|
||||
this.objects = objects;
|
||||
this.isFetchingData = false;
|
||||
});
|
||||
}
|
||||
|
||||
connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this.dropdownContainer = document.createElement("div");
|
||||
this.dropdownContainer.dataset["managedBy"] = "ak-search-select";
|
||||
document.body.append(this.dropdownContainer);
|
||||
this.updateData();
|
||||
this.addEventListener(EVENT_REFRESH, this.updateData);
|
||||
this.scrollHandler = () => {
|
||||
this.requestUpdate();
|
||||
};
|
||||
window.addEventListener("scroll", this.scrollHandler);
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
this.removeEventListener(EVENT_REFRESH, this.updateData);
|
||||
if (this.scrollHandler) {
|
||||
window.removeEventListener("scroll", this.scrollHandler);
|
||||
}
|
||||
this.dropdownContainer.remove();
|
||||
this.observer.disconnect();
|
||||
}
|
||||
|
||||
renderMenuItemWithDescription(obj: T, desc: TemplateResult, index: number) {
|
||||
return html`
|
||||
<li>
|
||||
<button
|
||||
class="pf-c-dropdown__menu-item pf-m-description"
|
||||
role="option"
|
||||
@click=${this.onMenuItemClick(obj)}
|
||||
tabindex=${index}
|
||||
>
|
||||
<div class="pf-c-dropdown__menu-item-main">${this.renderElement(obj)}</div>
|
||||
<div class="pf-c-dropdown__menu-item-description">${desc}</div>
|
||||
</button>
|
||||
</li>
|
||||
`;
|
||||
}
|
||||
|
||||
renderMenuItemWithoutDescription(obj: T, index: number) {
|
||||
return html`
|
||||
<li>
|
||||
<button
|
||||
class="pf-c-dropdown__menu-item"
|
||||
role="option"
|
||||
@click=${this.onMenuItemClick(obj)}
|
||||
tabindex=${index}
|
||||
>
|
||||
${this.renderElement(obj)}
|
||||
</button>
|
||||
</li>
|
||||
`;
|
||||
}
|
||||
|
||||
renderEmptyMenuItem() {
|
||||
return html`<li>
|
||||
<button
|
||||
class="pf-c-dropdown__menu-item"
|
||||
role="option"
|
||||
@click=${this.onMenuItemClick(undefined)}
|
||||
tabindex="0"
|
||||
>
|
||||
${this.emptyOption}
|
||||
</button>
|
||||
</li>`;
|
||||
}
|
||||
|
||||
onMenuItemClick(obj: T | undefined) {
|
||||
return () => {
|
||||
this.selectedObject = obj;
|
||||
this.open = false;
|
||||
};
|
||||
}
|
||||
|
||||
renderMenuGroup(items: T[], tabIndexStart: number) {
|
||||
const renderedItems = items.map((obj, index) => {
|
||||
const desc = this.renderDescription ? this.renderDescription(obj) : null;
|
||||
const tabIndex = index + tabIndexStart;
|
||||
return desc
|
||||
? this.renderMenuItemWithDescription(obj, desc, tabIndex)
|
||||
: this.renderMenuItemWithoutDescription(obj, tabIndex);
|
||||
});
|
||||
return html`${renderedItems}`;
|
||||
}
|
||||
|
||||
renderWithMenuGroupTitle([group, items]: Group<T>, idx: number) {
|
||||
return html`
|
||||
<section class="pf-c-dropdown__group">
|
||||
<h1 class="pf-c-dropdown__group-title">${group}</h1>
|
||||
<ul>
|
||||
${this.renderMenuGroup(items, idx)}
|
||||
</ul>
|
||||
</section>
|
||||
`;
|
||||
}
|
||||
|
||||
get groupedItems(): [boolean, Group<T>[]] {
|
||||
const items = this.groupBy(this.objects || []);
|
||||
if (items.length === 0) {
|
||||
return [false, [["", []]]];
|
||||
}
|
||||
if (items.length === 1 && (items[0].length < 1 || items[0][0] === "")) {
|
||||
return [false, items];
|
||||
}
|
||||
return [true, items];
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a little bit hacky. Because we mainly want to use this field in modal-based forms,
|
||||
* rendering this menu inline makes the menu not overlay over top of the modal, and cause
|
||||
* the modal to scroll.
|
||||
* Hence, we render the menu into the document root, hide it when this menu isn't open
|
||||
* and remove it on disconnect
|
||||
* Also to move it to the correct position we're getting this elements's position and use that
|
||||
* to position the menu
|
||||
* The other downside this has is that, since we're rendering outside of a shadow root,
|
||||
* the pf-c-dropdown CSS needs to be loaded on the body.
|
||||
*/
|
||||
|
||||
renderMenu(): void {
|
||||
if (!this.objects) {
|
||||
return;
|
||||
}
|
||||
const [shouldRenderGroups, groupedItems] = this.groupedItems;
|
||||
|
||||
const pos = this.getBoundingClientRect();
|
||||
const position = {
|
||||
"position": "fixed",
|
||||
"inset": "0px auto auto 0px",
|
||||
"z-index": "9999",
|
||||
"transform": `translate(${pos.x}px, ${pos.y + this.offsetHeight}px)`,
|
||||
"width": `${pos.width}px`,
|
||||
...(this.open ? {} : { visibility: "hidden" }),
|
||||
};
|
||||
|
||||
render(
|
||||
html`<div style=${styleMap(position)} class="pf-c-dropdown pf-m-expanded">
|
||||
<ul
|
||||
class="pf-c-dropdown__menu pf-m-static"
|
||||
role="listbox"
|
||||
style="max-height:50vh;overflow-y:auto;"
|
||||
id=${this.dropdownUID}
|
||||
tabindex="0"
|
||||
>
|
||||
${this.blankable ? this.renderEmptyMenuItem() : html``}
|
||||
${shouldRenderGroups
|
||||
? html`${groupedItems.map(this.renderWithMenuGroupTitle)}`
|
||||
: html`${this.renderMenuGroup(groupedItems[0][1], 0)}`}
|
||||
</ul>
|
||||
</div>`,
|
||||
this.dropdownContainer,
|
||||
{ host: this },
|
||||
);
|
||||
}
|
||||
|
||||
get renderedValue() {
|
||||
// prettier-ignore
|
||||
return (!this.objects) ? msg("Loading...")
|
||||
: (this.selectedObject) ? this.renderElement(this.selectedObject)
|
||||
: (this.blankable) ? this.emptyOption
|
||||
: "";
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
this.renderMenu();
|
||||
|
||||
const onFocus = (ev: FocusEvent) => {
|
||||
this.open = true;
|
||||
this.renderMenu();
|
||||
if (this.blankable && this.renderedValue === this.emptyOption) {
|
||||
if (ev.target && ev.target instanceof HTMLInputElement) {
|
||||
ev.target.value = "";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onInput = (ev: InputEvent) => {
|
||||
this.query = (ev.target as HTMLInputElement).value;
|
||||
this.updateData();
|
||||
};
|
||||
|
||||
const onBlur = (ev: FocusEvent) => {
|
||||
// For Safari, we get the <ul> element itself here when clicking on one of
|
||||
// it's buttons, as the container has tabindex set
|
||||
if (ev.relatedTarget && (ev.relatedTarget as HTMLElement).id === this.dropdownUID) {
|
||||
return;
|
||||
}
|
||||
// Check if we're losing focus to one of our dropdown items, and if such don't blur
|
||||
if (ev.relatedTarget instanceof HTMLButtonElement) {
|
||||
const parentMenu = ev.relatedTarget.closest("ul.pf-c-dropdown__menu.pf-m-static");
|
||||
if (parentMenu && parentMenu.id === this.dropdownUID) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.open = false;
|
||||
this.renderMenu();
|
||||
};
|
||||
|
||||
return html`<div class="pf-c-select">
|
||||
<div class="pf-c-select__toggle pf-m-typeahead">
|
||||
<div class="pf-c-select__toggle-wrapper">
|
||||
<input
|
||||
class="pf-c-form-control pf-c-select__toggle-typeahead"
|
||||
type="text"
|
||||
placeholder=${this.placeholder}
|
||||
spellcheck="false"
|
||||
@input=${onInput}
|
||||
@focus=${onFocus}
|
||||
@blur=${onBlur}
|
||||
.value=${this.renderedValue}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
export default SearchSelect;
|
@ -1,4 +0,0 @@
|
||||
import { SearchSelect } from "./ak-search-select";
|
||||
|
||||
export { SearchSelect };
|
||||
export default SearchSelect;
|
@ -1,6 +1,6 @@
|
||||
import { EVENT_SIDEBAR_TOGGLE } from "@goauthentik/common/constants";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider";
|
||||
import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider";
|
||||
|
||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
@ -10,13 +10,13 @@ import PFPage from "@patternfly/patternfly/components/Page/page.css";
|
||||
import PFGlobal from "@patternfly/patternfly/patternfly-base.css";
|
||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
|
||||
import { CurrentTenant, UiThemeEnum } from "@goauthentik/api";
|
||||
import { CurrentTenant as CurrentBrand, UiThemeEnum } from "@goauthentik/api";
|
||||
|
||||
// If the viewport is wider than MIN_WIDTH, the sidebar
|
||||
// is shown besides the content, and not overlaid.
|
||||
export const MIN_WIDTH = 1200;
|
||||
|
||||
export const DefaultTenant: CurrentTenant = {
|
||||
export const DefaultBrand: CurrentBrand = {
|
||||
brandingLogo: "/static/dist/assets/icons/icon_left_brand.svg",
|
||||
brandingFavicon: "/static/dist/assets/icons/icon.png",
|
||||
brandingTitle: "authentik",
|
||||
@ -27,7 +27,7 @@ export const DefaultTenant: CurrentTenant = {
|
||||
};
|
||||
|
||||
@customElement("ak-sidebar-brand")
|
||||
export class SidebarBrand extends WithTenantConfig(AKElement) {
|
||||
export class SidebarBrand extends WithBrandConfig(AKElement) {
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
PFBase,
|
||||
@ -43,6 +43,7 @@ export class SidebarBrand extends WithTenantConfig(AKElement) {
|
||||
min-height: 114px;
|
||||
}
|
||||
.pf-c-brand img {
|
||||
width: 100%;
|
||||
padding: 0 0.5rem;
|
||||
height: 42px;
|
||||
}
|
||||
@ -64,6 +65,7 @@ export class SidebarBrand extends WithTenantConfig(AKElement) {
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
console.log(this.brand);
|
||||
return html` ${window.innerWidth <= MIN_WIDTH
|
||||
? html`
|
||||
<button
|
||||
@ -84,7 +86,7 @@ export class SidebarBrand extends WithTenantConfig(AKElement) {
|
||||
<a href="#/" class="pf-c-page__header-brand-link">
|
||||
<div class="pf-c-brand ak-brand">
|
||||
<img
|
||||
src=${this.tenant?.brandingLogo ?? DefaultTenant.brandingLogo}
|
||||
src=${this.brand?.brandingLogo ?? DefaultBrand.brandingLogo}
|
||||
alt="authentik Logo"
|
||||
loading="lazy"
|
||||
/>
|
||||
|
@ -83,12 +83,8 @@ export class RacInterface extends Interface {
|
||||
// Keep track of current connection attempt
|
||||
connectionAttempt = 0;
|
||||
|
||||
static domSize(): { width: number; height: number } {
|
||||
const size = document.body.getBoundingClientRect();
|
||||
return {
|
||||
width: size.width * window.devicePixelRatio,
|
||||
height: size.height * window.devicePixelRatio,
|
||||
};
|
||||
static domSize(): DOMRect {
|
||||
return document.body.getBoundingClientRect();
|
||||
}
|
||||
|
||||
constructor() {
|
||||
@ -209,7 +205,7 @@ export class RacInterface extends Interface {
|
||||
}
|
||||
|
||||
updateTitle(): void {
|
||||
let title = this.tenant?.brandingTitle || TITLE_DEFAULT;
|
||||
let title = this.brand?.brandingTitle || TITLE_DEFAULT;
|
||||
if (this.endpointName) {
|
||||
title = `${this.endpointName} - ${title}`;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import { configureSentry } from "@goauthentik/common/sentry";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import { WebsocketClient } from "@goauthentik/common/ws";
|
||||
import { Interface } from "@goauthentik/elements/Interface";
|
||||
import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider";
|
||||
import "@goauthentik/elements/LoadingOverlay";
|
||||
import "@goauthentik/elements/ak-locale-context";
|
||||
import "@goauthentik/flow/sources/apple/AppleLoginInit";
|
||||
@ -45,7 +46,7 @@ import {
|
||||
} from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-flow-executor")
|
||||
export class FlowExecutor extends Interface implements StageHost {
|
||||
export class FlowExecutor extends WithBrandConfig(Interface) implements StageHost {
|
||||
@property()
|
||||
flowSlug: string = window.location.pathname.split("/")[3];
|
||||
|
||||
@ -55,9 +56,9 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
set challenge(value: ChallengeTypes | undefined) {
|
||||
this._challenge = value;
|
||||
if (value?.flowInfo?.title) {
|
||||
document.title = `${value.flowInfo?.title} - ${this.tenant?.brandingTitle}`;
|
||||
document.title = `${value.flowInfo?.title} - ${this.brand?.brandingTitle}`;
|
||||
} else {
|
||||
document.title = this.tenant?.brandingTitle || TITLE_DEFAULT;
|
||||
document.title = this.brand?.brandingTitle || TITLE_DEFAULT;
|
||||
}
|
||||
this.requestUpdate();
|
||||
}
|
||||
@ -213,10 +214,8 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
if (this.challenge.flowInfo) {
|
||||
this.flowInfo = this.challenge.flowInfo;
|
||||
}
|
||||
if (this.challenge.responseErrors) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
return this.challenge.responseErrors ? false : true;
|
||||
} catch (exc: unknown) {
|
||||
this.errorMessage(exc as Error | ResponseError);
|
||||
return false;
|
||||
@ -430,7 +429,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
|
||||
renderChallengeWrapper(): TemplateResult {
|
||||
const logo = html`<div class="pf-c-login__main-header pf-c-brand ak-brand">
|
||||
<img src="${first(this.tenant?.brandingLogo, "")}" alt="authentik Logo" />
|
||||
<img src="${first(this.brand?.brandingLogo, "")}" alt="authentik Logo" />
|
||||
</div>`;
|
||||
if (!this.challenge) {
|
||||
return html`${logo}<ak-empty-state ?loading=${true} header=${msg("Loading")}>
|
||||
@ -483,12 +482,20 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
<div class="pf-c-drawer__body">
|
||||
<div class="pf-c-login ${this.getLayout()}">
|
||||
<div class="${this.getLayoutClass()}">
|
||||
<header class="pf-c-login__header">
|
||||
<div class="pf-c-brand ak-brand">
|
||||
<img
|
||||
src="${first(this.brand?.brandingLogo, "")}"
|
||||
alt="authentik Logo"
|
||||
/>
|
||||
</div>
|
||||
</header>
|
||||
<div class="pf-c-login__main">
|
||||
${this.renderChallengeWrapper()}
|
||||
</div>
|
||||
<footer class="pf-c-login__footer">
|
||||
<ul class="pf-c-list pf-m-inline">
|
||||
${this.tenant?.uiFooterLinks?.map((link) => {
|
||||
${this.brand?.uiFooterLinks?.map((link) => {
|
||||
return html`<li>
|
||||
<a href="${link.href || ""}"
|
||||
>${link.name}</a
|
||||
@ -505,7 +512,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
? html`
|
||||
<li>
|
||||
<a
|
||||
href="https://unsplash.com/@theforestbirds"
|
||||
href="https://unsplash.com/@federize"
|
||||
>${msg("Background image")}</a
|
||||
>
|
||||
</li>
|
||||
|
@ -4,7 +4,7 @@ import { globalAK } from "@goauthentik/common/global";
|
||||
import { first, getCookie } from "@goauthentik/common/utils";
|
||||
import { Interface } from "@goauthentik/elements/Interface";
|
||||
import "@goauthentik/elements/ak-locale-context";
|
||||
import { DefaultTenant } from "@goauthentik/elements/sidebar/SidebarBrand";
|
||||
import { DefaultBrand } from "@goauthentik/elements/sidebar/SidebarBrand";
|
||||
import "rapidoc";
|
||||
|
||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||
@ -103,7 +103,7 @@ export class APIBrowser extends Interface {
|
||||
<img
|
||||
alt="authentik Logo"
|
||||
class="logo"
|
||||
src="${first(this.tenant?.brandingLogo, DefaultTenant.brandingLogo)}"
|
||||
src="${first(this.brand?.brandingLogo, DefaultBrand.brandingLogo)}"
|
||||
/>
|
||||
</div>
|
||||
</rapi-doc>
|
||||
|
@ -19,7 +19,7 @@ import "@goauthentik/elements/notifications/NotificationDrawer";
|
||||
import { getURLParam, updateURLParams } from "@goauthentik/elements/router/RouteMatch";
|
||||
import "@goauthentik/elements/router/RouterOutlet";
|
||||
import "@goauthentik/elements/sidebar/Sidebar";
|
||||
import { DefaultTenant } from "@goauthentik/elements/sidebar/SidebarBrand";
|
||||
import { DefaultBrand } from "@goauthentik/elements/sidebar/SidebarBrand";
|
||||
import "@goauthentik/elements/sidebar/SidebarItem";
|
||||
import { ROUTES } from "@goauthentik/user/Routes";
|
||||
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
|
||||
@ -192,11 +192,8 @@ export class UserInterface extends Interface {
|
||||
<a href="#/" class="pf-c-page__header-brand-link">
|
||||
<img
|
||||
class="pf-c-brand"
|
||||
src="${first(
|
||||
this.tenant?.brandingLogo,
|
||||
DefaultTenant.brandingLogo,
|
||||
)}"
|
||||
alt="${(this.tenant?.brandingTitle, DefaultTenant.brandingTitle)}"
|
||||
src="${first(this.brand?.brandingLogo, DefaultBrand.brandingLogo)}"
|
||||
alt="${(this.brand?.brandingTitle, DefaultBrand.brandingTitle)}"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -3,7 +3,7 @@ import { EVENT_REFRESH } from "@goauthentik/common/constants";
|
||||
import { MessageLevel } from "@goauthentik/common/messages";
|
||||
import { refreshMe } from "@goauthentik/common/users";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider";
|
||||
import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider";
|
||||
import { showMessage } from "@goauthentik/elements/messages/MessageContainer";
|
||||
import { StageHost } from "@goauthentik/flow/stages/base";
|
||||
import "@goauthentik/user/user-settings/details/stages/prompt/PromptStage";
|
||||
@ -31,10 +31,7 @@ import {
|
||||
} from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-user-settings-flow-executor")
|
||||
export class UserSettingsFlowExecutor
|
||||
extends WithTenantConfig(AKElement, true)
|
||||
implements StageHost
|
||||
{
|
||||
export class UserSettingsFlowExecutor extends WithBrandConfig(AKElement) implements StageHost {
|
||||
@property()
|
||||
flowSlug?: string;
|
||||
|
||||
@ -87,7 +84,7 @@ export class UserSettingsFlowExecutor
|
||||
}
|
||||
|
||||
firstUpdated(): void {
|
||||
this.flowSlug = this.tenant?.flowUserSettings;
|
||||
this.flowSlug = this.brand?.flowUserSettings;
|
||||
if (!this.flowSlug) {
|
||||
return;
|
||||
}
|
||||
|
@ -6249,12 +6249,6 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s62418cbcd2a25498">
|
||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s94d61907ee22a8c1">
|
||||
<source>Korean</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s95d56e58f816d211">
|
||||
<source>Dutch</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -6525,12 +6525,6 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s62418cbcd2a25498">
|
||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s94d61907ee22a8c1">
|
||||
<source>Korean</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s95d56e58f816d211">
|
||||
<source>Dutch</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -6165,12 +6165,6 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s62418cbcd2a25498">
|
||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s94d61907ee22a8c1">
|
||||
<source>Korean</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s95d56e58f816d211">
|
||||
<source>Dutch</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" ?><xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<?xml version="1.0"?><xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file target-language="fr" source-language="en" original="lit-localize-inputs" datatype="plaintext">
|
||||
<body>
|
||||
<trans-unit id="s4caed5b7a7e5d89b">
|
||||
@ -613,9 +613,9 @@ Il y a <x id="0" equiv-text="${ago}"/> jour(s)</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="saa0e2675da69651b">
|
||||
<source>The URL "<x id="0" equiv-text="${this.url}"/>" was not found.</source>
|
||||
<target>L'URL "
|
||||
<x id="0" equiv-text="${this.url}"/>" n'a pas été trouvée.</target>
|
||||
<source>The URL "<x id="0" equiv-text="${this.url}"/>" was not found.</source>
|
||||
<target>L'URL "
|
||||
<x id="0" equiv-text="${this.url}"/>" n'a pas été trouvée.</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s58cd9c2fe836d9c6">
|
||||
@ -1057,8 +1057,8 @@ Il y a <x id="0" equiv-text="${ago}"/> jour(s)</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sa8384c9c26731f83">
|
||||
<source>To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have.</source>
|
||||
<target>Pour permettre n'importe quelle URI de redirection, définissez cette valeur sur ".*". Soyez conscient des possibles implications de sécurité que cela peut avoir.</target>
|
||||
<source>To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have.</source>
|
||||
<target>Pour permettre n'importe quelle URI de redirection, définissez cette valeur sur ".*". Soyez conscient des possibles implications de sécurité que cela peut avoir.</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s55787f4dfcdce52b">
|
||||
@ -1630,7 +1630,7 @@ Il y a <x id="0" equiv-text="${ago}"/> jour(s)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s33ed903c210a6209">
|
||||
<source>Token to authenticate with. Currently only bearer authentication is supported.</source>
|
||||
<target>Jeton d'authentification à utiliser. Actuellement, seule l'authentification "bearer authentication" est prise en charge.</target>
|
||||
<target>Jeton d'authentification à utiliser. Actuellement, seule l'authentification "bearer authentication" est prise en charge.</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sfc8bb104e2c05af8">
|
||||
@ -1798,8 +1798,8 @@ Il y a <x id="0" equiv-text="${ago}"/> jour(s)</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sa90b7809586c35ce">
|
||||
<source>Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".</source>
|
||||
<target>Entrez une URL complète, un chemin relatif ou utilisez 'fa://fa-test' pour utiliser l'icône Font Awesome "fa-test".</target>
|
||||
<source>Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".</source>
|
||||
<target>Entrez une URL complète, un chemin relatif ou utilisez 'fa://fa-test' pour utiliser l'icône Font Awesome "fa-test".</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s0410779cb47de312">
|
||||
@ -2892,7 +2892,7 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
</trans-unit>
|
||||
<trans-unit id="s33683c3b1dbaf264">
|
||||
<source>To use SSL instead, use 'ldaps://' and disable this option.</source>
|
||||
<target>Pour utiliser SSL à la base, utilisez "ldaps://" et désactviez cette option.</target>
|
||||
<target>Pour utiliser SSL à la base, utilisez "ldaps://" et désactviez cette option.</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s2221fef80f4753a2">
|
||||
@ -2981,8 +2981,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s76768bebabb7d543">
|
||||
<source>Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'</source>
|
||||
<target>Champ qui contient les membres d'un groupe. Si vous utilisez le champ "memberUid", la valeur est censée contenir un nom distinctif relatif, par exemple 'memberUid=un-utilisateur' au lieu de 'memberUid=cn=un-utilisateur,ou=groups,...'</target>
|
||||
<source>Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'</source>
|
||||
<target>Champ qui contient les membres d'un groupe. Si vous utilisez le champ "memberUid", la valeur est censée contenir un nom distinctif relatif, par exemple 'memberUid=un-utilisateur' au lieu de 'memberUid=cn=un-utilisateur,ou=groups,...'</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s026555347e589f0e">
|
||||
@ -3277,7 +3277,7 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
</trans-unit>
|
||||
<trans-unit id="s3198c384c2f68b08">
|
||||
<source>Time offset when temporary users should be deleted. This only applies if your IDP uses the NameID Format 'transient', and the user doesn't log out manually.</source>
|
||||
<target>Moment où les utilisateurs temporaires doivent être supprimés. Cela ne s'applique que si votre IDP utilise le format NameID "transient" et que l'utilisateur ne se déconnecte pas manuellement.</target>
|
||||
<target>Moment où les utilisateurs temporaires doivent être supprimés. Cela ne s'applique que si votre IDP utilise le format NameID "transient" et que l'utilisateur ne se déconnecte pas manuellement.</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sb32e9c1faa0b8673">
|
||||
@ -3445,7 +3445,7 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
</trans-unit>
|
||||
<trans-unit id="s9f8aac89fe318acc">
|
||||
<source>Optionally set the 'FriendlyName' value of the Assertion attribute.</source>
|
||||
<target>Indiquer la valeur "FriendlyName" de l'attribut d'assertion (optionnel)</target>
|
||||
<target>Indiquer la valeur "FriendlyName" de l'attribut d'assertion (optionnel)</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s851c108679653d2a">
|
||||
@ -3774,8 +3774,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s7b1fba26d245cb1c">
|
||||
<source>When using an external logging solution for archiving, this can be set to "minutes=5".</source>
|
||||
<target>En cas d'utilisation d'une solution de journalisation externe pour l'archivage, cette valeur peut être fixée à "minutes=5".</target>
|
||||
<source>When using an external logging solution for archiving, this can be set to "minutes=5".</source>
|
||||
<target>En cas d'utilisation d'une solution de journalisation externe pour l'archivage, cette valeur peut être fixée à "minutes=5".</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s44536d20bb5c8257">
|
||||
@ -3784,8 +3784,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s3bb51cabb02b997e">
|
||||
<source>Format: "weeks=3;days=2;hours=3,seconds=2".</source>
|
||||
<target>Format : "weeks=3;days=2;hours=3,seconds=2".</target>
|
||||
<source>Format: "weeks=3;days=2;hours=3,seconds=2".</source>
|
||||
<target>Format : "weeks=3;days=2;hours=3,seconds=2".</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s04bfd02201db5ab8">
|
||||
@ -3981,10 +3981,10 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sa95a538bfbb86111">
|
||||
<source>Are you sure you want to update <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>"?</source>
|
||||
<source>Are you sure you want to update <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>"?</source>
|
||||
<target>Êtes-vous sûr de vouloir mettre à jour
|
||||
<x id="0" equiv-text="${this.objectLabel}"/>"
|
||||
<x id="1" equiv-text="${this.obj?.name}"/>" ?</target>
|
||||
<x id="0" equiv-text="${this.objectLabel}"/>"
|
||||
<x id="1" equiv-text="${this.obj?.name}"/>" ?</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sc92d7cfb6ee1fec6">
|
||||
@ -5070,8 +5070,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sdf1d8edef27236f0">
|
||||
<source>A "roaming" authenticator, like a YubiKey</source>
|
||||
<target>Un authentificateur "itinérant", comme une YubiKey</target>
|
||||
<source>A "roaming" authenticator, like a YubiKey</source>
|
||||
<target>Un authentificateur "itinérant", comme une YubiKey</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sfffba7b23d8fb40c">
|
||||
@ -5396,7 +5396,7 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
</trans-unit>
|
||||
<trans-unit id="s5170f9ef331949c0">
|
||||
<source>Show arbitrary input fields to the user, for example during enrollment. Data is saved in the flow context under the 'prompt_data' variable.</source>
|
||||
<target>Afficher des champs de saisie arbitraires à l'utilisateur, par exemple pendant l'inscription. Les données sont enregistrées dans le contexte du flux sous la variable "prompt_data".</target>
|
||||
<target>Afficher des champs de saisie arbitraires à l'utilisateur, par exemple pendant l'inscription. Les données sont enregistrées dans le contexte du flux sous la variable "prompt_data".</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s36cb242ac90353bc">
|
||||
@ -5405,10 +5405,10 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s2d5f69929bb7221d">
|
||||
<source><x id="0" equiv-text="${prompt.name}"/> ("<x id="1" equiv-text="${prompt.fieldKey}"/>", of type <x id="2" equiv-text="${prompt.type}"/>)</source>
|
||||
<source><x id="0" equiv-text="${prompt.name}"/> ("<x id="1" equiv-text="${prompt.fieldKey}"/>", of type <x id="2" equiv-text="${prompt.type}"/>)</source>
|
||||
<target>
|
||||
<x id="0" equiv-text="${prompt.name}"/>("
|
||||
<x id="1" equiv-text="${prompt.fieldKey}"/>", de type
|
||||
<x id="0" equiv-text="${prompt.name}"/>("
|
||||
<x id="1" equiv-text="${prompt.fieldKey}"/>", de type
|
||||
<x id="2" equiv-text="${prompt.type}"/>)</target>
|
||||
|
||||
</trans-unit>
|
||||
@ -5457,8 +5457,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s1608b2f94fa0dbd4">
|
||||
<source>If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here.</source>
|
||||
<target>Si défini à une durée supérieure à 0, l'utilisateur aura la possibilité de choisir de "rester connecté", ce qui prolongera sa session jusqu'à la durée spécifiée ici.</target>
|
||||
<source>If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here.</source>
|
||||
<target>Si défini à une durée supérieure à 0, l'utilisateur aura la possibilité de choisir de "rester connecté", ce qui prolongera sa session jusqu'à la durée spécifiée ici.</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s542a71bb8f41e057">
|
||||
@ -6093,7 +6093,7 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
|
||||
</trans-unit>
|
||||
<trans-unit id="s8afc8c5aafb392d3">
|
||||
<source>Radius</source>
|
||||
<target>Radius</target>
|
||||
<target>Rayon</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s03970aa76a09982d">
|
||||
@ -6242,7 +6242,7 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
|
||||
</trans-unit>
|
||||
<trans-unit id="sa7fcf026bd25f231">
|
||||
<source>Can be in the format of 'unix://' when connecting to a local docker daemon, using 'ssh://' to connect via SSH, or 'https://:2376' when connecting to a remote system.</source>
|
||||
<target>Peut être au format "unix://" pour une connexion à un service docker local, "ssh://" pour une connexion via SSH, ou "https://:2376" pour une connexion à un système distant.</target>
|
||||
<target>Peut être au format "unix://" pour une connexion à un service docker local, "ssh://" pour une connexion via SSH, ou "https://:2376" pour une connexion à un système distant.</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="saf1d289e3137c2ea">
|
||||
@ -7549,7 +7549,7 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
|
||||
</trans-unit>
|
||||
<trans-unit id="sff0ac1ace2d90709">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you).</source>
|
||||
<target>Utilisez ce fournisseur avec l'option "auth_request" de Nginx ou "forwardAuth" de Traefik. Chaque application/domaine a besoin de son propre fournisseur. De plus, sur chaque domaine, "/outpost.goauthentik.io" doit être routé vers le poste avancé (lorsque vous utilisez un poste avancé géré, cela est fait pour vous).</target>
|
||||
<target>Utilisez ce fournisseur avec l'option "auth_request" de Nginx ou "forwardAuth" de Traefik. Chaque application/domaine a besoin de son propre fournisseur. De plus, sur chaque domaine, "/outpost.goauthentik.io" doit être routé vers le poste avancé (lorsque vous utilisez un poste avancé géré, cela est fait pour vous).</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="scb58b8a60cad8762">
|
||||
<source>Default relay state</source>
|
||||
@ -7963,7 +7963,7 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
|
||||
<target>Utilisateur créé et ajouté au groupe <x id="0" equiv-text="${this.group.name}"/> avec succès</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s824e0943a7104668">
|
||||
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
|
||||
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
|
||||
<target>Cet utilisateur sera ajouté au groupe &quot;<x id="0" equiv-text="${this.targetGroup.name}"/>&quot;.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s62e7f6ed7d9cb3ca">
|
||||
@ -8204,28 +8204,16 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
|
||||
</trans-unit>
|
||||
<trans-unit id="scc7f34824150bfb8">
|
||||
<source>Provider require enterprise.</source>
|
||||
<target>Ce fournisseur requiert la version entreprise.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s31f1afc1bfe1cb3a">
|
||||
<source>Learn more</source>
|
||||
<target>En apprendre plus</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sc39f6abf0daedb0f">
|
||||
<source>Maximum concurrent connections</source>
|
||||
<target>Connections concurrentes maximum</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s62418cbcd2a25498">
|
||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||
<target>Nombre maximum de connections concurrentes à ce point de terminaison. Peut être défini à -1 pour désactiver la limite.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s94d61907ee22a8c1">
|
||||
<source>Korean</source>
|
||||
<target>Coréen</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s95d56e58f816d211">
|
||||
<source>Dutch</source>
|
||||
<target>Néerlandais</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
</xliff>
|
||||
|
182
web/xliff/ko.xlf
182
web/xliff/ko.xlf
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0"?><xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<?xml version="1.0" ?><xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file target-language="ko" source-language="en" original="lit-localize-inputs" datatype="plaintext">
|
||||
<body>
|
||||
<trans-unit id="s4caed5b7a7e5d89b">
|
||||
@ -612,8 +612,8 @@
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="saa0e2675da69651b">
|
||||
<source>The URL "<x id="0" equiv-text="${this.url}"/>" was not found.</source>
|
||||
<target>URL "<x id="0" equiv-text="${this.url}"/>" 을 찾을 수 없습니다.</target>
|
||||
<source>The URL "<x id="0" equiv-text="${this.url}"/>" was not found.</source>
|
||||
<target>URL "<x id="0" equiv-text="${this.url}"/>" 을 찾을 수 없습니다.</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s58cd9c2fe836d9c6">
|
||||
@ -1054,8 +1054,8 @@
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sa8384c9c26731f83">
|
||||
<source>To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have.</source>
|
||||
<target>리디렉션 URI를 허용하려면 이 값을 ".*"로 설정합니다. 이로 인해 발생할 수 있는 보안상의 영향에 유의하세요.</target>
|
||||
<source>To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have.</source>
|
||||
<target>리디렉션 URI를 허용하려면 이 값을 ".*"로 설정합니다. 이로 인해 발생할 수 있는 보안상의 영향에 유의하세요.</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s55787f4dfcdce52b">
|
||||
@ -1792,8 +1792,8 @@
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sa90b7809586c35ce">
|
||||
<source>Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".</source>
|
||||
<target>전체 URL, 상대 경로를 입력하거나, 또는 'fa://fa-test'를 사용하여 Font Awesome 아이콘 "fa-test"를 사용합니다.</target>
|
||||
<source>Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".</source>
|
||||
<target>전체 URL, 상대 경로를 입력하거나, 또는 'fa://fa-test'를 사용하여 Font Awesome 아이콘 "fa-test"를 사용합니다.</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s0410779cb47de312">
|
||||
@ -2972,7 +2972,7 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s76768bebabb7d543">
|
||||
<source>Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'</source>
|
||||
<source>Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'</source>
|
||||
<target>그룹 구성원이 포함된 필드입니다. 'memberUid' 필드를 사용하는 경우 값에 상대적인 고유 이름이 포함된 것으로 가정합니다 (예:'memberUid=some-user' 대신 'memberUid=cn=some-user,ou=groups,...').</target>
|
||||
|
||||
</trans-unit>
|
||||
@ -3764,8 +3764,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s7b1fba26d245cb1c">
|
||||
<source>When using an external logging solution for archiving, this can be set to "minutes=5".</source>
|
||||
<target>아카이브에 외부 로깅 솔루션을 사용하는 경우, 이 값을 "minutes=5"로 설정할 수 있습니다.</target>
|
||||
<source>When using an external logging solution for archiving, this can be set to "minutes=5".</source>
|
||||
<target>아카이브에 외부 로깅 솔루션을 사용하는 경우, 이 값을 "minutes=5"로 설정할 수 있습니다.</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s44536d20bb5c8257">
|
||||
@ -3774,8 +3774,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s3bb51cabb02b997e">
|
||||
<source>Format: "weeks=3;days=2;hours=3,seconds=2".</source>
|
||||
<target>서식: "weeks=3;days=2;hours=3,seconds=2".</target>
|
||||
<source>Format: "weeks=3;days=2;hours=3,seconds=2".</source>
|
||||
<target>서식: "weeks=3;days=2;hours=3,seconds=2".</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s04bfd02201db5ab8">
|
||||
@ -3967,8 +3967,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sa95a538bfbb86111">
|
||||
<source>Are you sure you want to update <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>"?</source>
|
||||
<target>정말 <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>" 을(를) 업데이트 하시겠습니까?</target>
|
||||
<source>Are you sure you want to update <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>"?</source>
|
||||
<target>정말 <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>" 을(를) 업데이트 하시겠습니까?</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sc92d7cfb6ee1fec6">
|
||||
@ -5052,8 +5052,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sdf1d8edef27236f0">
|
||||
<source>A "roaming" authenticator, like a YubiKey</source>
|
||||
<target>YubiKey 같은 "로밍" 인증기</target>
|
||||
<source>A "roaming" authenticator, like a YubiKey</source>
|
||||
<target>YubiKey 같은 "로밍" 인증기</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sfffba7b23d8fb40c">
|
||||
@ -5387,8 +5387,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s2d5f69929bb7221d">
|
||||
<source><x id="0" equiv-text="${prompt.name}"/> ("<x id="1" equiv-text="${prompt.fieldKey}"/>", of type <x id="2" equiv-text="${prompt.type}"/>)</source>
|
||||
<target><x id="0" equiv-text="${prompt.name}"/> ("<x id="1" equiv-text="${prompt.fieldKey}"/>", of type <x id="2" equiv-text="${prompt.type}"/>)</target>
|
||||
<source><x id="0" equiv-text="${prompt.name}"/> ("<x id="1" equiv-text="${prompt.fieldKey}"/>", of type <x id="2" equiv-text="${prompt.type}"/>)</source>
|
||||
<target><x id="0" equiv-text="${prompt.name}"/> ("<x id="1" equiv-text="${prompt.fieldKey}"/>", of type <x id="2" equiv-text="${prompt.type}"/>)</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s3b7b519444181264">
|
||||
@ -5436,7 +5436,7 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s1608b2f94fa0dbd4">
|
||||
<source>If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here.</source>
|
||||
<source>If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here.</source>
|
||||
<target>기간을 0 이상으로 설정하면, 사용자에게 '로그인 상태 유지'를 선택할 수 있는 옵션이 제공되며, 이 경우 세션이 여기에 지정된 시간만큼 연장됩니다.</target>
|
||||
|
||||
</trans-unit>
|
||||
@ -7926,8 +7926,8 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
<target>사용자 생성과 <x id="0" equiv-text="${this.group.name}"/> 그룹 추가에 성공했습니다.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s824e0943a7104668">
|
||||
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
|
||||
<target>이 사용자는 "<x id="0" equiv-text="${this.targetGroup.name}"/>" 그룹에 추가됩니다.</target>
|
||||
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
|
||||
<target>이 사용자는 "<x id="0" equiv-text="${this.targetGroup.name}"/>" 그룹에 추가됩니다.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s62e7f6ed7d9cb3ca">
|
||||
<source>Pretend user exists</source>
|
||||
@ -8004,145 +8004,7 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
<trans-unit id="s047a5f0211fedc72">
|
||||
<source>Require Outpost (flow can only be executed from an outpost).</source>
|
||||
<target>Outpost필요 (플로우는 Outpost에서만 실행할 수 있음).</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="scc7f34824150bfb8">
|
||||
<source>Provider require enterprise.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s31f1afc1bfe1cb3a">
|
||||
<source>Learn more</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sa2ea0fcd3ffa80e0">
|
||||
<source>Connection expiry</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s6dd297c217729828">
|
||||
<source>Determines how long a session lasts before being disconnected and requiring re-authorization.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s3271da6c18c25b18">
|
||||
<source>Connection settings.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2f4ca2148183d692">
|
||||
<source>Successfully updated endpoint.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s5adee855dbe191d9">
|
||||
<source>Successfully created endpoint.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s61e136c0658e27d5">
|
||||
<source>Protocol</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sa062b019ff0c8809">
|
||||
<source>RDP</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s97f9bf19fa5b57d1">
|
||||
<source>SSH</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7c100119e9ffcc32">
|
||||
<source>VNC</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s6b05f9d8801fc14f">
|
||||
<source>Host</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sb474f652a2c2fc76">
|
||||
<source>Hostname/IP to connect to.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sc39f6abf0daedb0f">
|
||||
<source>Maximum concurrent connections</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s62418cbcd2a25498">
|
||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s8276649077e8715c">
|
||||
<source>Endpoint(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sf1dabfe0fe8a75ad">
|
||||
<source>Update Endpoint</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s008496c7716b9812">
|
||||
<source>These bindings control which users will have access to this endpoint. Users must also have access to the application.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s38e7cd1a24e70faa">
|
||||
<source>Create Endpoint</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s4770c10e5b1c028c">
|
||||
<source>RAC is in preview.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s168565f5ac74a89f">
|
||||
<source>Update RAC Provider</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s8465a2caa2d9ea5d">
|
||||
<source>Endpoints</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s9857d883d8eb98fc">
|
||||
<source>General settings</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sd2066881798a1b96">
|
||||
<source>RDP settings</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sb864dc36a463a155">
|
||||
<source>Ignore server certificate</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s20366a8d1eaaca54">
|
||||
<source>Enable wallpaper</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s1e44c5350ef7598c">
|
||||
<source>Enable font-smoothing</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s04ff5d6ae711e6d6">
|
||||
<source>Enable full window dragging</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s94d61907ee22a8c1">
|
||||
<source>Korean</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s95d56e58f816d211">
|
||||
<source>Dutch</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s663ccbfdf27e8dd0">
|
||||
<source>Network binding</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sb108a06693c67753">
|
||||
<source>No binding</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s5aab90c74f1233b8">
|
||||
<source>Bind ASN</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s488303b048afe83b">
|
||||
<source>Bind ASN and Network</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s3268dcfe0c8234dc">
|
||||
<source>Bind ASN, Network and IP</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s226381aca231644f">
|
||||
<source>Configure if sessions created by this stage should be bound to the Networks they were created in.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2555a1f20f3fd93e">
|
||||
<source>GeoIP binding</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s3d63c78f93c9a92e">
|
||||
<source>Bind Continent</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s395d5863b3a259b5">
|
||||
<source>Bind Continent and Country</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s625ea0c32b4b136c">
|
||||
<source>Bind Continent, Country and City</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s4bc7a1a88961be90">
|
||||
<source>Configure if sessions created by this stage should be bound to their GeoIP-based location</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sa06cd519ff151b6d">
|
||||
<source>RAC</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s28b99b59541f54ca">
|
||||
<source>Connection failed after <x id="0" equiv-text="${this.connectionAttempt}"/> attempts.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7c7d956418e1c8c8">
|
||||
<source>Re-connecting in <x id="0" equiv-text="${Math.max(1, delay / 1000)}"/> second(s).</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sfc003381f593d943">
|
||||
<source>Connecting...</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s31aa94a0b3c7edb2">
|
||||
<source>Select endpoint to connect to</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
</xliff>
|
899
web/xliff/nl.xlf
899
web/xliff/nl.xlf
File diff suppressed because it is too large
Load Diff
@ -6373,12 +6373,6 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s62418cbcd2a25498">
|
||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s94d61907ee22a8c1">
|
||||
<source>Korean</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s95d56e58f816d211">
|
||||
<source>Dutch</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -8111,10 +8111,4 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
<trans-unit id="s62418cbcd2a25498">
|
||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s94d61907ee22a8c1">
|
||||
<source>Korean</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s95d56e58f816d211">
|
||||
<source>Dutch</source>
|
||||
</trans-unit>
|
||||
</body></file></xliff>
|
||||
|
@ -6158,12 +6158,6 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s62418cbcd2a25498">
|
||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s94d61907ee22a8c1">
|
||||
<source>Korean</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s95d56e58f816d211">
|
||||
<source>Dutch</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
5068
web/xliff/zh-CN.xlf
5068
web/xliff/zh-CN.xlf
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" ?><xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<?xml version="1.0"?><xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file target-language="zh-Hans" source-language="en" original="lit-localize-inputs" datatype="plaintext">
|
||||
<body>
|
||||
<trans-unit id="s4caed5b7a7e5d89b">
|
||||
@ -613,9 +613,9 @@
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="saa0e2675da69651b">
|
||||
<source>The URL "<x id="0" equiv-text="${this.url}"/>" was not found.</source>
|
||||
<target>未找到 URL "
|
||||
<x id="0" equiv-text="${this.url}"/>"。</target>
|
||||
<source>The URL "<x id="0" equiv-text="${this.url}"/>" was not found.</source>
|
||||
<target>未找到 URL "
|
||||
<x id="0" equiv-text="${this.url}"/>"。</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s58cd9c2fe836d9c6">
|
||||
@ -1057,8 +1057,8 @@
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sa8384c9c26731f83">
|
||||
<source>To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have.</source>
|
||||
<target>要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。</target>
|
||||
<source>To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have.</source>
|
||||
<target>要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s55787f4dfcdce52b">
|
||||
@ -1799,8 +1799,8 @@
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sa90b7809586c35ce">
|
||||
<source>Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".</source>
|
||||
<target>输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。</target>
|
||||
<source>Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".</source>
|
||||
<target>输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s0410779cb47de312">
|
||||
@ -2983,8 +2983,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s76768bebabb7d543">
|
||||
<source>Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'</source>
|
||||
<target>包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...'</target>
|
||||
<source>Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'</source>
|
||||
<target>包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...'</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s026555347e589f0e">
|
||||
@ -3776,8 +3776,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s7b1fba26d245cb1c">
|
||||
<source>When using an external logging solution for archiving, this can be set to "minutes=5".</source>
|
||||
<target>使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。</target>
|
||||
<source>When using an external logging solution for archiving, this can be set to "minutes=5".</source>
|
||||
<target>使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s44536d20bb5c8257">
|
||||
@ -3786,8 +3786,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s3bb51cabb02b997e">
|
||||
<source>Format: "weeks=3;days=2;hours=3,seconds=2".</source>
|
||||
<target>格式:"weeks=3;days=2;hours=3,seconds=2"。</target>
|
||||
<source>Format: "weeks=3;days=2;hours=3,seconds=2".</source>
|
||||
<target>格式:"weeks=3;days=2;hours=3,seconds=2"。</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s04bfd02201db5ab8">
|
||||
@ -3983,10 +3983,10 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sa95a538bfbb86111">
|
||||
<source>Are you sure you want to update <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>"?</source>
|
||||
<source>Are you sure you want to update <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>"?</source>
|
||||
<target>您确定要更新
|
||||
<x id="0" equiv-text="${this.objectLabel}"/>"
|
||||
<x id="1" equiv-text="${this.obj?.name}"/>" 吗?</target>
|
||||
<x id="0" equiv-text="${this.objectLabel}"/>"
|
||||
<x id="1" equiv-text="${this.obj?.name}"/>" 吗?</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sc92d7cfb6ee1fec6">
|
||||
@ -5072,7 +5072,7 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sdf1d8edef27236f0">
|
||||
<source>A "roaming" authenticator, like a YubiKey</source>
|
||||
<source>A "roaming" authenticator, like a YubiKey</source>
|
||||
<target>像 YubiKey 这样的“漫游”身份验证器</target>
|
||||
|
||||
</trans-unit>
|
||||
@ -5407,10 +5407,10 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s2d5f69929bb7221d">
|
||||
<source><x id="0" equiv-text="${prompt.name}"/> ("<x id="1" equiv-text="${prompt.fieldKey}"/>", of type <x id="2" equiv-text="${prompt.type}"/>)</source>
|
||||
<source><x id="0" equiv-text="${prompt.name}"/> ("<x id="1" equiv-text="${prompt.fieldKey}"/>", of type <x id="2" equiv-text="${prompt.type}"/>)</source>
|
||||
<target>
|
||||
<x id="0" equiv-text="${prompt.name}"/>("
|
||||
<x id="1" equiv-text="${prompt.fieldKey}"/>",类型为
|
||||
<x id="0" equiv-text="${prompt.name}"/>("
|
||||
<x id="1" equiv-text="${prompt.fieldKey}"/>",类型为
|
||||
<x id="2" equiv-text="${prompt.type}"/>)</target>
|
||||
|
||||
</trans-unit>
|
||||
@ -5459,7 +5459,7 @@ doesn't pass when either or both of the selected options are equal or above the
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s1608b2f94fa0dbd4">
|
||||
<source>If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here.</source>
|
||||
<source>If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here.</source>
|
||||
<target>如果设置时长大于 0,用户可以选择“保持登录”选项,这将使用户的会话延长此处设置的时间。</target>
|
||||
|
||||
</trans-unit>
|
||||
@ -7965,7 +7965,7 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
<target>成功创建用户并添加到组 <x id="0" equiv-text="${this.group.name}"/></target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s824e0943a7104668">
|
||||
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
|
||||
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
|
||||
<target>此用户将会被添加到组 &quot;<x id="0" equiv-text="${this.targetGroup.name}"/>&quot;。</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s62e7f6ed7d9cb3ca">
|
||||
@ -8214,20 +8214,10 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sc39f6abf0daedb0f">
|
||||
<source>Maximum concurrent connections</source>
|
||||
<target>最大并发连接数</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s62418cbcd2a25498">
|
||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||
<target>允许到此端点的最大并发连接数。可以设置为 -1 以禁用限制。</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s94d61907ee22a8c1">
|
||||
<source>Korean</source>
|
||||
<target>韩语</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s95d56e58f816d211">
|
||||
<source>Dutch</source>
|
||||
<target>荷兰语</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
</xliff>
|
||||
|
@ -6206,12 +6206,6 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s62418cbcd2a25498">
|
||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s94d61907ee22a8c1">
|
||||
<source>Korean</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s95d56e58f816d211">
|
||||
<source>Dutch</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -8211,22 +8211,6 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
<trans-unit id="s31f1afc1bfe1cb3a">
|
||||
<source>Learn more</source>
|
||||
<target>了解更多</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sc39f6abf0daedb0f">
|
||||
<source>Maximum concurrent connections</source>
|
||||
<target>最大并发连接数</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s62418cbcd2a25498">
|
||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||
<target>允许到此端点的最大并发连接数。可以设置为 -1 以禁用限制。</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s94d61907ee22a8c1">
|
||||
<source>Korean</source>
|
||||
<target>韩语</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s95d56e58f816d211">
|
||||
<source>Dutch</source>
|
||||
<target>荷兰语</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -8095,12 +8095,6 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s62418cbcd2a25498">
|
||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s94d61907ee22a8c1">
|
||||
<source>Korean</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s95d56e58f816d211">
|
||||
<source>Dutch</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -1,99 +0,0 @@
|
||||
---
|
||||
title: "Happy New Year from Authentik Security"
|
||||
slug: 2024-1-12-happy-new-year-from-authentik-security
|
||||
authors:
|
||||
- name: Jens Langhammer
|
||||
title: CTO at Authentik Security Inc
|
||||
url: https://github.com/BeryJu
|
||||
image_url: https://github.com/BeryJu.png
|
||||
tags:
|
||||
- authentik
|
||||
- happy new year
|
||||
- new features
|
||||
- year in review
|
||||
- SSO
|
||||
- SaaS
|
||||
- SCIM
|
||||
- RADIUS
|
||||
- remote access
|
||||
- RBAC
|
||||
- identity provider
|
||||
- authentication
|
||||
- Authentik Security
|
||||
hide_table_of_contents: false
|
||||
---
|
||||
|
||||
> **_authentik is an open source Identity Provider that unifies your identity needs into a single platform, replacing Okta, Active Directory, and auth0. Authentik Security is a [public benefit company](https://github.com/OpenCoreVentures/ocv-public-benefit-company/blob/main/ocv-public-benefit-company-charter.md) building on top of the open source project._**
|
||||
|
||||
---
|
||||
|
||||
A hearty Happy New Year to you all, from all of of us at Authentik Security, with sincere wishes that your 2024 may be filled with a maximum of joys (new features and elegant code) and a minimum of pains (bugs and the dreadful reality of not-enough-time).
|
||||
|
||||
> The start of a new year makes me want to first say **thank you** for the past year.
|
||||
|
||||
## Thank you!
|
||||
|
||||
**Thank you to our community**, from the newly joined members to our long-time friends and moderators and holders-of-knowledge. Without you all, well… we literally wouldn’t be here. No matter how deep your knowledge of authentik is, it’s really your willingness to explore and test and give feedback on new and old features, all while supporting each other and staying in touch with good humor and vibes, that make us such a vibrant community.
|
||||
|
||||
**Thank you to our users**, from those who run authentik in their homelabs to those who run authentik in production, and everyone in between. We appreciate your trust and guidance, and your input into how we can provide the most-needed features and grow our product in the ways that solve your business needs and challenges.
|
||||
|
||||
**And of course thanks to our small team** here at Authentik Security, who joined me on this adventure and brought your skills and talents, your experience and passions, and your dedication to our product and users. We built a lot together last year, and this year has a rock-star list of features and functionality coming up!
|
||||
|
||||
## Accomplishments in 2023
|
||||
|
||||
Looking back to the work we did in 2023, the new features are just a part of the overall achievements and celebrations (and challenges) of building a new [company](https://goauthentik.io/blog/2022-11-02-the-next-step-for-authentik), growing the team, celebrating our [1st year](https://goauthentik.io/blog/2023-11-1-happy-birthday-to-us), and [defining our tools and processes](https://goauthentik.io/blog/2023-12-21-five-lessons-from-choosing-infrastructure-tooling). But we released quite a few new features that I’m proud to share.
|
||||
|
||||
### RBAC
|
||||
|
||||
[RBAC](https://goauthentik.io/docs/user-group-role/access-control/) (role-based access control) is the gold standard of access control. RBAC provides the ability to finely configure permissions within authentik. These permissions can be used to delegate different tasks, such as user management, application creation and more to users without granting them full superuser permissions. authentik has had internal RBAC for a long time (and of course the policy engine for restricting access to applications), however access to different objects within authentik (like Users, Groups, etc) was not possible previously.
|
||||
|
||||
### Enterprise Support
|
||||
|
||||
Providing dedicated support with a proper ticketing system was a big accomplishment for 2023. Support was the flagship feature of our [Enterprise release](https://goauthentik.io/blog/2023-08-31-announcing-the-authentik-enterprise-release) in the fall of 2023.
|
||||
|
||||
### SCIM support
|
||||
|
||||
Our [2023.3 release](https://goauthentik.io/docs/releases/2023.3) added support for SCIM (System for Cross-domain Identity Management) protocol, allowing for the provision of users into other IT systems, where the provider synchronizes Users, Groups and the user membership.
|
||||
|
||||
### RADIUS Support
|
||||
|
||||
The [RADIUS protocol](https://goauthentik.io/docs/providers/radius/) for authentication allows for the integration of a wider variety of systems such as VPN software, network switches/routers, and others. The RADIUS provider also uses a flow to authenticate users, and supports the same stages as the [LDAP Provider](https://goauthentik.io/docs/providers/ldap/).
|
||||
|
||||
## What’s coming up in 2024?
|
||||
|
||||
Looking forward to new functionality for the new year, let me share some of the ones I am most excited about. As with any small development team, we tackle what we can, with an eye on which features will be most beneficial for you all, which have dependencies upon later features, maintainability as we further develop the feature, and how to best get them all out the door fully tested and documented.
|
||||
|
||||
### Wizardry
|
||||
|
||||
The task of adding the applications that you want authentik to authenticate is about to get a lot easier; we have a new wizard that combines the process of defining a new provider and a new application into one single task. This new wizard saves many steps and streamlines the process. Look for it in preview mode in our current 2023.10 release (navigate to the Applications page in the Admin UI), and let us know your thoughts. We will continue tweaking it, specifically the multi-select functionality, but feedback is always welcome!
|
||||
|
||||

|
||||
|
||||
### Remote Access Control (RAC)
|
||||
|
||||
With [RAC](https://goauthentik.io/docs/providers/rac/), in preview now with a full release in early 2024, authentik Admins are able to access remote Windows/macOS/Linux machines via [RDP](https://en.wikipedia.org/wiki/Remote_Desktop_Protocol)/[SSH](https://en.wikipedia.org/wiki/Secure_Shell)/[VNC](https://en.wikipedia.org/wiki/Virtual_Network_Computing). The preview version already has capabilities for using a bi-directoinal clipboard between the authentik client and the remote machine, audio redirection (meaning you can hear audio from the remote machine on your local instance), and resizing of the window you view of the remote machine.
|
||||
|
||||
### Mobile authenticator app for authentik
|
||||
|
||||
Soon you will be able to download our new authentik authentication app from Apple Store, and a bit further into 2024, from Google Play Store. This app can be used for 2FA/MFA verification when authentik users log in to authentik or access any application managed by an authentik instance. The first release of this app will use number-matching as the default verification process; users will view their authentik authenticator app on their phone, be prompted with a set of three numbers, and then need to select the same number that is displayed on their authentik instance login panel.
|
||||
|
||||
### Building out our SaaS offering
|
||||
|
||||
One of our most exciting, and definitely our biggest, projects for 2024 will be developing our SaaS offering, the hosted, fully-managed Enterprise Cloud. The Enterprise Cloud plan will provide the convenience of our enterprise-level product as a SaaS offering, hosted and managed by Authentik Security. For many organizations, the benefits of decreased operational costs and universal data access (no VPN, servers, and network configuration required) make SaaS the best choice. With the cloud offering, the same enterprise-level support plan is included, and migrating to self-hosted is always an option.
|
||||
|
||||
### DX and UX and quality-of-life improvements
|
||||
|
||||
As we mentioned in our blog about our one-year anniversary, we also plan to spend some time focused on user experience.
|
||||
|
||||
- Increase our focus on UX and ease-of-use, templatizing as much as possible of the frontend components, and developing a UI Style Guide
|
||||
- A redesigned website, with more information about our solutions, use cases, and offerings
|
||||
- New structure for our technical documentation; leveraging information architecture and user research to make it easier to find what you are looking for in our docs
|
||||
- Defining even more robust tests and checks for our CI/CD pipeline and build process
|
||||
- Stronger integration and migration testing, both automated and manual
|
||||
- Spending more time on outreach and user research to learn what you all want
|
||||
|
||||
### Yes, a big year ahead
|
||||
|
||||
As most of us in the software and technology space know, the hard work of building new features and growing a company is, well, actually kind of fun. Challenging, yes, but always rewarding.
|
||||
|
||||
We’d love to hear from you all about our upcoming plans; reach out to us with an email to [hello@goauthentik.io](mailto:hello@goauthentik.io) or on [Discord](https://discord.com/channels/809154715984199690/809154716507963434).
|
Binary file not shown.
Before Width: | Height: | Size: 78 KiB |
@ -116,7 +116,7 @@ To check if your config has been applied correctly, you can run the following co
|
||||
`AUTHENTIK_REDIS__CACHE_TIMEOUT_REPUTATION` only applies to the cache expiry, see [`AUTHENTIK_REPUTATION__EXPIRY`](#authentik_reputation__expiry) to control how long reputation is persisted for.
|
||||
:::
|
||||
|
||||
## Listen Settings
|
||||
## Listen Setting
|
||||
|
||||
- `AUTHENTIK_LISTEN__HTTP`: Listening address:port (e.g. `0.0.0.0:9000`) for HTTP (Applies to Server and Proxy outpost)
|
||||
- `AUTHENTIK_LISTEN__HTTPS`: Listening address:port (e.g. `0.0.0.0:9443`) for HTTPS (Applies to Server and Proxy outpost)
|
||||
@ -124,7 +124,7 @@ To check if your config has been applied correctly, you can run the following co
|
||||
- `AUTHENTIK_LISTEN__LDAPS`: Listening address:port (e.g. `0.0.0.0:6636`) for LDAPS (Applies to LDAP outpost)
|
||||
- `AUTHENTIK_LISTEN__METRICS`: Listening address:port (e.g. `0.0.0.0:9300`) for Prometheus metrics (Applies to All)
|
||||
- `AUTHENTIK_LISTEN__DEBUG`: Listening address:port (e.g. `0.0.0.0:9900`) for Go Debugging metrics (Applies to All)
|
||||
- `AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS`: List of comma-separated CIDRs that proxy headers should be accepted from (Applies to Server)
|
||||
- `AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS`: List of CIDRs that proxy headers should be accepted from (Applies to Server)
|
||||
|
||||
Defaults to `127.0.0.0/8`, `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `fe80::/10`, `::1/128`.
|
||||
|
||||
|
@ -4,16 +4,16 @@ title: Docker Compose installation
|
||||
|
||||
This installation method is for test-setups and small-scale production setups.
|
||||
|
||||
:::info
|
||||
You can also [view a video walk-through](https://www.youtube.com/watch?v=O1qUbrk4Yc8) of the installation process on Docker (with bonus details about email configuration and other important options).
|
||||
:::
|
||||
|
||||
## Requirements
|
||||
|
||||
- A host with at least 2 CPU cores and 2 GB of RAM
|
||||
- Docker
|
||||
- Docker Compose
|
||||
|
||||
## Video
|
||||
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/O1qUbrk4Yc8?si=HiSBjmJYhE_oJhB1&start=22" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||
|
||||
## Preparation
|
||||
|
||||
To download the latest `docker-compose.yml` open your terminal and navigate to the directory of your choice.
|
||||
|
@ -4,6 +4,6 @@ title: Installation
|
||||
|
||||
Everything you need to get authentik up and running! For information about upgrading to a new version, refer to the <b>Upgrade</b> section in the relevant [Release Notes](../releases).
|
||||
|
||||
import DocCardList from "@theme/DocCardList";
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
|
||||
<DocCardList />
|
@ -13,10 +13,6 @@ You can also [view a video walk-through](https://www.youtube.com/watch?v=O1qUbrk
|
||||
- Kubernetes
|
||||
- Helm
|
||||
|
||||
## Video
|
||||
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/O1qUbrk4Yc8?si=hs-ZhbVk4Y-TW_Vw&start=562" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||
|
||||
### Generate Passwords
|
||||
|
||||
Start by generating passwords for the database and cache. You can use either of the following commands:
|
||||
|
@ -181,18 +181,6 @@ helm upgrade authentik authentik/authentik -f values.yaml --version ^2023.10
|
||||
- web/admin: always show oidc well-known URL fields when they're set (#7560)
|
||||
- web/user: fix search not updating app (cherry-pick #7825) (#7933)
|
||||
|
||||
## Fixed in 2023.10.6
|
||||
|
||||
- core: fix PropertyMapping context not being available in request context
|
||||
- outposts: disable deployment and secret reconciler for embedded outpost in code instead of in config (cherry-pick #8021) (#8024)
|
||||
- outposts: fix Outpost reconcile not re-assigning managed attribute (cherry-pick #8014) (#8020)
|
||||
- providers/oauth2: fix [CVE-2024-21637](../../security/CVE-2024-21637.md), Reported by [@lauritzh](https://github.com/lauritzh) (#8104)
|
||||
- providers/oauth2: remember session_id from initial token (cherry-pick #7976) (#7977)
|
||||
- providers/proxy: use access token (cherry-pick #8022) (#8023)
|
||||
- rbac: fix error when looking up permissions for now uninstalled apps (cherry-pick #8068) (#8070)
|
||||
- sources/oauth: fix missing get_user_id for OIDC-like sources (Azure AD) (#7970)
|
||||
- web/flows: fix device picker incorrect foreground color (cherry-pick #8067) (#8069)
|
||||
|
||||
## API Changes
|
||||
|
||||
#### What's New
|
||||
|
@ -163,10 +163,6 @@ image:
|
||||
|
||||
- security: fix [CVE-2023-48228](../../security/CVE-2023-48228.md), Reported by [@Sapd](https://github.com/Sapd) (#7666)
|
||||
|
||||
## Fixed in 2023.8.6
|
||||
|
||||
- providers/oauth2: fix [CVE-2024-21637](../../security/CVE-2024-21637.md), Reported by [@lauritzh](https://github.com/lauritzh) (#8104)
|
||||
|
||||
## API Changes
|
||||
|
||||
#### What's New
|
||||
|
@ -1,39 +0,0 @@
|
||||
# CVE-2024-21637
|
||||
|
||||
_Reported by [@lauritzh](https://github.com/lauritzh)_
|
||||
|
||||
## XSS in Authentik via JavaScript-URI as Redirect URI and form_post Response Mode
|
||||
|
||||
### Summary
|
||||
|
||||
Given an OAuth2 provider configured with allowed redirect URIs set to `*` or `.*`, an attacker can send an OAuth Authorization request using `response_mode=form_post` and setting `redirect_uri` to a malicious URI, to capture authentik's session token.
|
||||
|
||||
### Patches
|
||||
|
||||
authentik 2023.8.6 and 2023.10.6 fix this issue.
|
||||
|
||||
### Impact
|
||||
|
||||
The impact depends on the attack scenario. In the following I will describe the two scenario that were identified for Authentik.
|
||||
|
||||
#### Redirect URI Misconfiguration
|
||||
|
||||
While advising that this may cause security issues, Authentik generally allows wildcards as Redirect URI. Therefore, using a wildcard-only effectively allowing arbitrary URLS is possible misconfiguration that may be present in real-world instances.
|
||||
|
||||
In such cases, unauthenticated and unprivileged attackers can perform the above described actions.
|
||||
|
||||
### User with (only) App Administration Permissions
|
||||
|
||||
A more likely scenario is an administrative user (e.g. a normal developer) having only permissions to manage applications.
|
||||
|
||||
This relatively user could use the described attacks to perform a privilege escalation.
|
||||
|
||||
### Workaround
|
||||
|
||||
It is recommended to upgrade to the patched version of authentik. If not possible, ensure that OAuth2 providers do not use a wildcard (`*` or `.*`) value as allowed redirect URI setting. (This is _not_ exploitable if part of the redirect URI has a wildcard, for example `https://foo-.*\.bar\.com`)
|
||||
|
||||
### For more information
|
||||
|
||||
If you have any questions or comments about this advisory:
|
||||
|
||||
- Email us at [security@goauthentik.io](mailto:security@goauthentik.io)
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user