Compare commits
10 Commits
core/b2c-i
...
web/cleanu
Author | SHA1 | Date | |
---|---|---|---|
27e9e892e7 | |||
70bf745c0c | |||
8b4e0361c4 | |||
22cb5b7379 | |||
2d0117d096 | |||
035bda4eac | |||
50906214e5 | |||
e505f274b6 | |||
fe52f44dca | |||
3146e5a50f |
2
.github/workflows/ci-main.yml
vendored
2
.github/workflows/ci-main.yml
vendored
@ -7,6 +7,8 @@ on:
|
||||
- main
|
||||
- next
|
||||
- version-*
|
||||
paths-ignore:
|
||||
- website/**
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
@ -10,7 +10,7 @@ from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from authentik import __version__, get_build_hash
|
||||
from authentik.admin.tasks import VERSION_CACHE_KEY, VERSION_NULL, update_latest_version
|
||||
from authentik.admin.tasks import VERSION_CACHE_KEY, update_latest_version
|
||||
from authentik.core.api.utils import PassiveSerializer
|
||||
|
||||
|
||||
@ -19,7 +19,6 @@ class VersionSerializer(PassiveSerializer):
|
||||
|
||||
version_current = SerializerMethodField()
|
||||
version_latest = SerializerMethodField()
|
||||
version_latest_valid = SerializerMethodField()
|
||||
build_hash = SerializerMethodField()
|
||||
outdated = SerializerMethodField()
|
||||
|
||||
@ -39,10 +38,6 @@ class VersionSerializer(PassiveSerializer):
|
||||
return __version__
|
||||
return version_in_cache
|
||||
|
||||
def get_version_latest_valid(self, _) -> bool:
|
||||
"""Check if latest version is valid"""
|
||||
return cache.get(VERSION_CACHE_KEY) != VERSION_NULL
|
||||
|
||||
def get_outdated(self, instance) -> bool:
|
||||
"""Check if we're running the latest version"""
|
||||
return parse(self.get_version_current(instance)) < parse(self.get_version_latest(instance))
|
||||
|
@ -18,7 +18,6 @@ from authentik.lib.utils.http import get_http_session
|
||||
from authentik.root.celery import CELERY_APP
|
||||
|
||||
LOGGER = get_logger()
|
||||
VERSION_NULL = "0.0.0"
|
||||
VERSION_CACHE_KEY = "authentik_latest_version"
|
||||
VERSION_CACHE_TIMEOUT = 8 * 60 * 60 # 8 hours
|
||||
# Chop of the first ^ because we want to search the entire string
|
||||
@ -56,7 +55,7 @@ def clear_update_notifications():
|
||||
def update_latest_version(self: SystemTask):
|
||||
"""Update latest version info"""
|
||||
if CONFIG.get_bool("disable_update_check"):
|
||||
cache.set(VERSION_CACHE_KEY, VERSION_NULL, VERSION_CACHE_TIMEOUT)
|
||||
cache.set(VERSION_CACHE_KEY, "0.0.0", VERSION_CACHE_TIMEOUT)
|
||||
self.set_status(TaskStatus.WARNING, "Version check disabled.")
|
||||
return
|
||||
try:
|
||||
@ -83,7 +82,7 @@ def update_latest_version(self: SystemTask):
|
||||
event_dict["message"] = f"Changelog: {match.group()}"
|
||||
Event.new(EventAction.UPDATE_AVAILABLE, **event_dict).save()
|
||||
except (RequestException, IndexError) as exc:
|
||||
cache.set(VERSION_CACHE_KEY, VERSION_NULL, VERSION_CACHE_TIMEOUT)
|
||||
cache.set(VERSION_CACHE_KEY, "0.0.0", VERSION_CACHE_TIMEOUT)
|
||||
self.set_error(exc)
|
||||
|
||||
|
||||
|
@ -46,7 +46,6 @@ class BrandSerializer(ModelSerializer):
|
||||
fields = [
|
||||
"brand_uuid",
|
||||
"domain",
|
||||
"origin",
|
||||
"default",
|
||||
"branding_title",
|
||||
"branding_logo",
|
||||
@ -57,7 +56,6 @@ class BrandSerializer(ModelSerializer):
|
||||
"flow_unenrollment",
|
||||
"flow_user_settings",
|
||||
"flow_device_code",
|
||||
"default_application",
|
||||
"web_certificate",
|
||||
"attributes",
|
||||
]
|
||||
|
@ -1,17 +1,12 @@
|
||||
"""Inject brand into current request"""
|
||||
|
||||
from collections.abc import Callable
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from django.http.request import HttpRequest
|
||||
from django.http.response import HttpResponse
|
||||
from django.utils.translation import activate
|
||||
|
||||
from authentik.brands.utils import get_brand_for_request
|
||||
from authentik.lib.config import CONFIG
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from authentik.brands.models import Brand
|
||||
|
||||
|
||||
class BrandMiddleware:
|
||||
@ -30,41 +25,3 @@ class BrandMiddleware:
|
||||
if locale != "":
|
||||
activate(locale)
|
||||
return self.get_response(request)
|
||||
|
||||
|
||||
class BrandHeaderMiddleware:
|
||||
"""Add headers from currently active brand"""
|
||||
|
||||
get_response: Callable[[HttpRequest], HttpResponse]
|
||||
default_csp_elements: dict[str, list[str]] = {}
|
||||
|
||||
def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]):
|
||||
self.get_response = get_response
|
||||
self.default_csp_elements = {
|
||||
"style-src": ["'self'", "'unsafe-inline'"], # Required due to Lit/ShadowDOM
|
||||
"script-src": ["'self'", "'unsafe-inline'"], # Required for generated scripts
|
||||
"img-src": ["https:", "http:", "data:"],
|
||||
"default-src": ["'self'"],
|
||||
"object-src": ["'none'"],
|
||||
"connect-src": ["'self'"],
|
||||
}
|
||||
if CONFIG.get_bool("error_reporting.enabled"):
|
||||
self.default_csp_elements["connect-src"].append(
|
||||
# Required for sentry (TODO: Dynamic)
|
||||
"https://authentik.error-reporting.a7k.io"
|
||||
)
|
||||
if CONFIG.get_bool("debug"):
|
||||
# Also allow spotlight sidecar connection
|
||||
self.default_csp_elements["connect-src"].append("http://localhost:8969")
|
||||
|
||||
def get_csp(self, request: HttpRequest) -> str:
|
||||
brand: "Brand" = request.brand
|
||||
elements = self.default_csp_elements.copy()
|
||||
if brand.origin != "":
|
||||
elements["frame-ancestors"] = [brand.origin]
|
||||
return ";".join(f"{attr} {" ".join(value)}" for attr, value in elements.items())
|
||||
|
||||
def __call__(self, request: HttpRequest) -> HttpResponse:
|
||||
response = self.get_response(request)
|
||||
response.headers["Content-Security-Policy"] = self.get_csp(request)
|
||||
return response
|
||||
|
@ -1,26 +0,0 @@
|
||||
# Generated by Django 5.0.3 on 2024-03-21 15:42
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_brands", "0005_tenantuuid_to_branduuid"),
|
||||
("authentik_core", "0033_alter_user_options"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="brand",
|
||||
name="default_application",
|
||||
field=models.ForeignKey(
|
||||
default=None,
|
||||
help_text="When set, external users will be redirected to this application after authenticating.",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_DEFAULT,
|
||||
to="authentik_core.application",
|
||||
),
|
||||
),
|
||||
]
|
@ -1,21 +0,0 @@
|
||||
# Generated by Django 5.0.3 on 2024-03-26 14:17
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_brands", "0006_brand_default_application"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="brand",
|
||||
name="origin",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Origin domain that activates this brand. Can be left empty to not allow any origins.",
|
||||
),
|
||||
),
|
||||
]
|
@ -23,12 +23,6 @@ class Brand(SerializerModel):
|
||||
"Domain that activates this brand. Can be a superset, i.e. `a.b` for `aa.b` and `ba.b`"
|
||||
)
|
||||
)
|
||||
origin = models.TextField(
|
||||
help_text=_(
|
||||
"Origin domain that activates this brand. Can be left empty to not allow any origins."
|
||||
),
|
||||
blank=True,
|
||||
)
|
||||
default = models.BooleanField(
|
||||
default=False,
|
||||
)
|
||||
@ -57,16 +51,6 @@ class Brand(SerializerModel):
|
||||
Flow, null=True, on_delete=models.SET_NULL, related_name="brand_device_code"
|
||||
)
|
||||
|
||||
default_application = models.ForeignKey(
|
||||
"authentik_core.Application",
|
||||
null=True,
|
||||
default=None,
|
||||
on_delete=models.SET_DEFAULT,
|
||||
help_text=_(
|
||||
"When set, external users will be redirected to this application after authenticating."
|
||||
),
|
||||
)
|
||||
|
||||
web_certificate = models.ForeignKey(
|
||||
CertificateKeyPair,
|
||||
null=True,
|
||||
|
@ -1,15 +1,11 @@
|
||||
"""Brand utilities"""
|
||||
|
||||
from typing import Any
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from django.db.models import F, Q
|
||||
from django.db.models import Value as V
|
||||
from django.http import HttpResponse
|
||||
from django.http.request import HttpRequest
|
||||
from django.utils.cache import patch_vary_headers
|
||||
from sentry_sdk.hub import Hub
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik import get_full_version
|
||||
from authentik.brands.models import Brand
|
||||
@ -17,17 +13,13 @@ from authentik.tenants.models import Tenant
|
||||
|
||||
_q_default = Q(default=True)
|
||||
DEFAULT_BRAND = Brand(domain="fallback")
|
||||
LOGGER = get_logger()
|
||||
|
||||
|
||||
def get_brand_for_request(request: HttpRequest) -> Brand:
|
||||
"""Get brand object for current request"""
|
||||
query = Q(host_domain__iendswith=F("domain"))
|
||||
if "Origin" in request.headers:
|
||||
query &= Q(Q(origin=request.headers.get("Origin", "")) | Q(origin=""))
|
||||
db_brands = (
|
||||
Brand.objects.annotate(host_domain=V(request.get_host()))
|
||||
.filter(Q(query) | _q_default)
|
||||
.filter(Q(host_domain__iendswith=F("domain")) | _q_default)
|
||||
.order_by("default")
|
||||
)
|
||||
brands = list(db_brands.all())
|
||||
@ -50,46 +42,3 @@ def context_processor(request: HttpRequest) -> dict[str, Any]:
|
||||
"sentry_trace": trace,
|
||||
"version": get_full_version(),
|
||||
}
|
||||
|
||||
|
||||
def cors_allow(request: HttpRequest, response: HttpResponse, *allowed_origins: str):
|
||||
"""Add headers to permit CORS requests from allowed_origins, with or without credentials,
|
||||
with any headers."""
|
||||
origin = request.META.get("HTTP_ORIGIN")
|
||||
if not origin:
|
||||
return response
|
||||
|
||||
# OPTIONS requests don't have an authorization header -> hence
|
||||
# we can't extract the provider this request is for
|
||||
# so for options requests we allow the calling origin without checking
|
||||
allowed = request.method == "OPTIONS"
|
||||
received_origin = urlparse(origin)
|
||||
for allowed_origin in allowed_origins:
|
||||
url = urlparse(allowed_origin)
|
||||
if (
|
||||
received_origin.scheme == url.scheme
|
||||
and received_origin.hostname == url.hostname
|
||||
and received_origin.port == url.port
|
||||
):
|
||||
allowed = True
|
||||
if not allowed:
|
||||
LOGGER.warning(
|
||||
"CORS: Origin is not an allowed origin",
|
||||
requested=received_origin,
|
||||
allowed=allowed_origins,
|
||||
)
|
||||
return response
|
||||
|
||||
# From the CORS spec: The string "*" cannot be used for a resource that supports credentials.
|
||||
response["Access-Control-Allow-Origin"] = origin
|
||||
patch_vary_headers(response, ["Origin"])
|
||||
response["Access-Control-Allow-Credentials"] = "true"
|
||||
|
||||
if request.method == "OPTIONS":
|
||||
if "HTTP_ACCESS_CONTROL_REQUEST_HEADERS" in request.META:
|
||||
response["Access-Control-Allow-Headers"] = request.META[
|
||||
"HTTP_ACCESS_CONTROL_REQUEST_HEADERS"
|
||||
]
|
||||
response["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS"
|
||||
|
||||
return response
|
||||
|
@ -37,7 +37,7 @@ from authentik.lib.utils.file import (
|
||||
)
|
||||
from authentik.policies.api.exec import PolicyTestResultSerializer
|
||||
from authentik.policies.engine import PolicyEngine
|
||||
from authentik.policies.types import CACHE_PREFIX, PolicyResult
|
||||
from authentik.policies.types import PolicyResult
|
||||
from authentik.rbac.decorators import permission_required
|
||||
from authentik.rbac.filters import ObjectFilter
|
||||
|
||||
@ -46,7 +46,7 @@ LOGGER = get_logger()
|
||||
|
||||
def user_app_cache_key(user_pk: str) -> str:
|
||||
"""Cache key where application list for user is saved"""
|
||||
return f"{CACHE_PREFIX}/app_access/{user_pk}"
|
||||
return f"goauthentik.io/core/app_access/{user_pk}"
|
||||
|
||||
|
||||
class ApplicationSerializer(ModelSerializer):
|
||||
@ -214,7 +214,7 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
|
||||
return super().list(request)
|
||||
|
||||
queryset = self._filter_queryset_for_list(self.get_queryset())
|
||||
paginated_apps = self.paginate_queryset(queryset)
|
||||
pagined_apps = self.paginate_queryset(queryset)
|
||||
|
||||
if "for_user" in request.query_params:
|
||||
try:
|
||||
@ -228,18 +228,18 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
|
||||
raise ValidationError({"for_user": "User not found"})
|
||||
except ValueError as exc:
|
||||
raise ValidationError from exc
|
||||
allowed_applications = self._get_allowed_applications(paginated_apps, user=for_user)
|
||||
allowed_applications = self._get_allowed_applications(pagined_apps, user=for_user)
|
||||
serializer = self.get_serializer(allowed_applications, many=True)
|
||||
return self.get_paginated_response(serializer.data)
|
||||
|
||||
allowed_applications = []
|
||||
if not should_cache:
|
||||
allowed_applications = self._get_allowed_applications(paginated_apps)
|
||||
allowed_applications = self._get_allowed_applications(pagined_apps)
|
||||
if should_cache:
|
||||
allowed_applications = cache.get(user_app_cache_key(self.request.user.pk))
|
||||
if not allowed_applications:
|
||||
LOGGER.debug("Caching allowed application list")
|
||||
allowed_applications = self._get_allowed_applications(paginated_apps)
|
||||
allowed_applications = self._get_allowed_applications(pagined_apps)
|
||||
cache.set(
|
||||
user_app_cache_key(self.request.user.pk),
|
||||
allowed_applications,
|
||||
|
@ -617,9 +617,6 @@ class UserSourceConnection(SerializerModel, CreatedUpdatedModel):
|
||||
"""Get serializer for this model"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"User-source connection (user={self.user.username}, source={self.source.slug})"
|
||||
|
||||
class Meta:
|
||||
unique_together = (("user", "source"),)
|
||||
|
||||
|
@ -16,9 +16,8 @@ from authentik.core.models import Source, SourceUserMatchingModes, User, UserSou
|
||||
from authentik.core.sources.stage import PLAN_CONTEXT_SOURCES_CONNECTION, PostUserEnrollmentStage
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.flows.exceptions import FlowNonApplicableException
|
||||
from authentik.flows.models import Flow, FlowToken, Stage, in_memory_stage
|
||||
from authentik.flows.models import Flow, Stage, in_memory_stage
|
||||
from authentik.flows.planner import (
|
||||
PLAN_CONTEXT_IS_RESTORED,
|
||||
PLAN_CONTEXT_PENDING_USER,
|
||||
PLAN_CONTEXT_REDIRECT,
|
||||
PLAN_CONTEXT_SOURCE,
|
||||
@ -36,8 +35,6 @@ from authentik.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
|
||||
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
|
||||
from authentik.stages.user_write.stage import PLAN_CONTEXT_USER_PATH
|
||||
|
||||
SESSION_KEY_OVERRIDE_FLOW_TOKEN = "authentik/flows/source_override_flow_token" # nosec
|
||||
|
||||
|
||||
class Action(Enum):
|
||||
"""Actions that can be decided based on the request
|
||||
@ -225,43 +222,22 @@ class SourceFlowManager:
|
||||
**kwargs,
|
||||
) -> HttpResponse:
|
||||
"""Prepare Authentication Plan, redirect user FlowExecutor"""
|
||||
# Ensure redirect is carried through when user was trying to
|
||||
# authorize application
|
||||
final_redirect = self.request.session.get(SESSION_KEY_GET, {}).get(
|
||||
NEXT_ARG_NAME, "authentik_core:if-user"
|
||||
)
|
||||
kwargs.update(
|
||||
{
|
||||
# Since we authenticate the user by their token, they have no backend set
|
||||
PLAN_CONTEXT_AUTHENTICATION_BACKEND: BACKEND_INBUILT,
|
||||
PLAN_CONTEXT_SSO: True,
|
||||
PLAN_CONTEXT_SOURCE: self.source,
|
||||
PLAN_CONTEXT_REDIRECT: final_redirect,
|
||||
PLAN_CONTEXT_SOURCES_CONNECTION: connection,
|
||||
}
|
||||
)
|
||||
kwargs.update(self.policy_context)
|
||||
if SESSION_KEY_OVERRIDE_FLOW_TOKEN in self.request.session:
|
||||
token: FlowToken = self.request.session.get(SESSION_KEY_OVERRIDE_FLOW_TOKEN)
|
||||
self._logger.info("Replacing source flow with overridden flow", flow=token.flow.slug)
|
||||
plan = token.plan
|
||||
plan.context[PLAN_CONTEXT_IS_RESTORED] = token
|
||||
plan.context.update(kwargs)
|
||||
for stage in self.get_stages_to_append(flow):
|
||||
plan.append_stage(stage)
|
||||
if stages:
|
||||
for stage in stages:
|
||||
plan.append_stage(stage)
|
||||
self.request.session[SESSION_KEY_PLAN] = plan
|
||||
flow_slug = token.flow.slug
|
||||
token.delete()
|
||||
return redirect_with_qs(
|
||||
"authentik_core:if-flow",
|
||||
self.request.GET,
|
||||
flow_slug=flow_slug,
|
||||
)
|
||||
# Ensure redirect is carried through when user was trying to
|
||||
# authorize application
|
||||
final_redirect = self.request.session.get(SESSION_KEY_GET, {}).get(
|
||||
NEXT_ARG_NAME, "authentik_core:if-user"
|
||||
)
|
||||
if PLAN_CONTEXT_REDIRECT not in kwargs:
|
||||
kwargs[PLAN_CONTEXT_REDIRECT] = final_redirect
|
||||
|
||||
if not flow:
|
||||
return bad_request_message(
|
||||
self.request,
|
||||
|
@ -6,6 +6,7 @@ from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.urls import path
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from django.views.generic import RedirectView
|
||||
|
||||
from authentik.core.api.applications import ApplicationViewSet
|
||||
from authentik.core.api.authenticated_sessions import AuthenticatedSessionViewSet
|
||||
@ -19,12 +20,7 @@ from authentik.core.api.transactional_applications import TransactionalApplicati
|
||||
from authentik.core.api.users import UserViewSet
|
||||
from authentik.core.views import apps
|
||||
from authentik.core.views.debug import AccessDeniedView
|
||||
from authentik.core.views.interface import (
|
||||
BrandDefaultRedirectView,
|
||||
FlowInterfaceView,
|
||||
InterfaceView,
|
||||
RootRedirectView,
|
||||
)
|
||||
from authentik.core.views.interface import FlowInterfaceView, InterfaceView
|
||||
from authentik.core.views.session import EndSessionView
|
||||
from authentik.root.asgi_middleware import SessionMiddleware
|
||||
from authentik.root.messages.consumer import MessageConsumer
|
||||
@ -33,11 +29,13 @@ from authentik.root.middleware import ChannelsLoggingMiddleware
|
||||
urlpatterns = [
|
||||
path(
|
||||
"",
|
||||
login_required(RootRedirectView.as_view()),
|
||||
login_required(
|
||||
RedirectView.as_view(pattern_name="authentik_core:if-user", query_string=True)
|
||||
),
|
||||
name="root-redirect",
|
||||
),
|
||||
path(
|
||||
# We have to use this format since everything else uses application/o or application/saml
|
||||
# We have to use this format since everything else uses applications/o or applications/saml
|
||||
"application/launch/<slug:application_slug>/",
|
||||
apps.RedirectToAppLaunch.as_view(),
|
||||
name="application-launch",
|
||||
@ -45,12 +43,12 @@ urlpatterns = [
|
||||
# Interfaces
|
||||
path(
|
||||
"if/admin/",
|
||||
ensure_csrf_cookie(BrandDefaultRedirectView.as_view(template_name="if/admin.html")),
|
||||
ensure_csrf_cookie(InterfaceView.as_view(template_name="if/admin.html")),
|
||||
name="if-admin",
|
||||
),
|
||||
path(
|
||||
"if/user/",
|
||||
ensure_csrf_cookie(BrandDefaultRedirectView.as_view(template_name="if/user.html")),
|
||||
ensure_csrf_cookie(InterfaceView.as_view(template_name="if/user.html")),
|
||||
name="if-user",
|
||||
),
|
||||
path(
|
||||
|
@ -3,43 +3,15 @@
|
||||
from json import dumps
|
||||
from typing import Any
|
||||
|
||||
from django.http import HttpRequest
|
||||
from django.http.response import HttpResponse
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic.base import RedirectView, TemplateView
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.views.generic.base import TemplateView
|
||||
from rest_framework.request import Request
|
||||
|
||||
from authentik import get_build_hash
|
||||
from authentik.admin.tasks import LOCAL_VERSION
|
||||
from authentik.api.v3.config import ConfigView
|
||||
from authentik.brands.api import CurrentBrandSerializer
|
||||
from authentik.brands.models import Brand
|
||||
from authentik.core.models import UserTypes
|
||||
from authentik.flows.models import Flow
|
||||
from authentik.policies.denied import AccessDeniedResponse
|
||||
|
||||
|
||||
class RootRedirectView(RedirectView):
|
||||
"""Root redirect view, redirect to brand's default application if set"""
|
||||
|
||||
pattern_name = "authentik_core:if-user"
|
||||
query_string = True
|
||||
|
||||
def redirect_to_app(self, request: HttpRequest):
|
||||
if request.user.is_authenticated and request.user.type == UserTypes.EXTERNAL:
|
||||
brand: Brand = request.brand
|
||||
if brand.default_application:
|
||||
return redirect(
|
||||
"authentik_core:application-launch",
|
||||
application_slug=brand.default_application.slug,
|
||||
)
|
||||
return None
|
||||
|
||||
def dispatch(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
|
||||
if redirect_response := RootRedirectView().redirect_to_app(request):
|
||||
return redirect_response
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
class InterfaceView(TemplateView):
|
||||
@ -55,22 +27,6 @@ class InterfaceView(TemplateView):
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class BrandDefaultRedirectView(InterfaceView):
|
||||
"""By default redirect to default app"""
|
||||
|
||||
def dispatch(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
|
||||
if request.user.is_authenticated and request.user.type == UserTypes.EXTERNAL:
|
||||
brand: Brand = request.brand
|
||||
if brand.default_application:
|
||||
return redirect(
|
||||
"authentik_core:application-launch",
|
||||
application_slug=brand.default_application.slug,
|
||||
)
|
||||
response = AccessDeniedResponse(self.request)
|
||||
response.error_message = _("Interface can only be accessed by internal users.")
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
class FlowInterfaceView(InterfaceView):
|
||||
"""Flow interface"""
|
||||
|
||||
|
@ -6,13 +6,13 @@ from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
|
||||
from authentik.api.authorization import OwnerFilter, OwnerSuperuserPermissions
|
||||
from authentik.api.authorization import OwnerFilter, OwnerPermissions
|
||||
from authentik.core.api.groups import GroupMemberSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.enterprise.api import EnterpriseRequiredMixin
|
||||
from authentik.enterprise.providers.rac.api.endpoints import EndpointSerializer
|
||||
from authentik.enterprise.providers.rac.api.providers import RACProviderSerializer
|
||||
from authentik.enterprise.providers.rac.models import ConnectionToken
|
||||
from authentik.enterprise.providers.rac.models import ConnectionToken, Endpoint
|
||||
|
||||
|
||||
class ConnectionTokenSerializer(EnterpriseRequiredMixin, ModelSerializer):
|
||||
@ -23,7 +23,7 @@ class ConnectionTokenSerializer(EnterpriseRequiredMixin, ModelSerializer):
|
||||
user = GroupMemberSerializer(source="session.user", read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = ConnectionToken
|
||||
model = Endpoint
|
||||
fields = [
|
||||
"pk",
|
||||
"provider",
|
||||
@ -49,5 +49,5 @@ class ConnectionTokenViewSet(
|
||||
filterset_fields = ["endpoint", "session__user", "provider"]
|
||||
search_fields = ["endpoint__name", "provider__name"]
|
||||
ordering = ["endpoint__name", "provider__name"]
|
||||
permission_classes = [OwnerSuperuserPermissions]
|
||||
permission_classes = [OwnerPermissions]
|
||||
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
|
||||
|
@ -15,7 +15,6 @@ CELERY_BEAT_SCHEDULE = {
|
||||
TENANT_APPS = [
|
||||
"authentik.enterprise.audit",
|
||||
"authentik.enterprise.providers.rac",
|
||||
"authentik.enterprise.stages.source",
|
||||
]
|
||||
|
||||
MIDDLEWARE = ["authentik.enterprise.middleware.EnterpriseMiddleware"]
|
||||
|
@ -1,38 +0,0 @@
|
||||
"""Source Stage API Views"""
|
||||
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.core.models import Source
|
||||
from authentik.enterprise.api import EnterpriseRequiredMixin
|
||||
from authentik.enterprise.stages.source.models import SourceStage
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
|
||||
|
||||
class SourceStageSerializer(EnterpriseRequiredMixin, StageSerializer):
|
||||
"""SourceStage Serializer"""
|
||||
|
||||
def validate_source(self, _source: Source) -> Source:
|
||||
"""Ensure configured source supports web-based login"""
|
||||
source = Source.objects.filter(pk=_source.pk).select_subclasses().first()
|
||||
if not source:
|
||||
raise ValidationError("Invalid source")
|
||||
login_button = source.ui_login_button(self.context["request"])
|
||||
if not login_button:
|
||||
raise ValidationError("Invalid source selected, only web-based sources are supported.")
|
||||
return source
|
||||
|
||||
class Meta:
|
||||
model = SourceStage
|
||||
fields = StageSerializer.Meta.fields + ["source", "resume_timeout"]
|
||||
|
||||
|
||||
class SourceStageViewSet(UsedByMixin, ModelViewSet):
|
||||
"""SourceStage Viewset"""
|
||||
|
||||
queryset = SourceStage.objects.all()
|
||||
serializer_class = SourceStageSerializer
|
||||
filterset_fields = "__all__"
|
||||
ordering = ["name"]
|
||||
search_fields = ["name"]
|
@ -1,12 +0,0 @@
|
||||
"""authentik stage app config"""
|
||||
|
||||
from authentik.enterprise.apps import EnterpriseConfig
|
||||
|
||||
|
||||
class AuthentikEnterpriseStageSourceConfig(EnterpriseConfig):
|
||||
"""authentik source stage config"""
|
||||
|
||||
name = "authentik.enterprise.stages.source"
|
||||
label = "authentik_stages_source"
|
||||
verbose_name = "authentik Enterprise.Stages.Source"
|
||||
default = True
|
@ -1,53 +0,0 @@
|
||||
# Generated by Django 5.0.2 on 2024-02-25 20:44
|
||||
|
||||
import authentik.lib.utils.time
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
("authentik_core", "0033_alter_user_options"),
|
||||
("authentik_flows", "0027_auto_20231028_1424"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="SourceStage",
|
||||
fields=[
|
||||
(
|
||||
"stage_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="authentik_flows.stage",
|
||||
),
|
||||
),
|
||||
(
|
||||
"resume_timeout",
|
||||
models.TextField(
|
||||
default="minutes=10",
|
||||
help_text="Amount of time a user can take to return from the source to continue the flow (Format: hours=-1;minutes=-2;seconds=-3)",
|
||||
validators=[authentik.lib.utils.time.timedelta_string_validator],
|
||||
),
|
||||
),
|
||||
(
|
||||
"source",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to="authentik_core.source"
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Source Stage",
|
||||
"verbose_name_plural": "Source Stages",
|
||||
},
|
||||
bases=("authentik_flows.stage",),
|
||||
),
|
||||
]
|
@ -1,45 +0,0 @@
|
||||
"""Source stage models"""
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views import View
|
||||
from rest_framework.serializers import BaseSerializer
|
||||
|
||||
from authentik.flows.models import Stage
|
||||
from authentik.lib.utils.time import timedelta_string_validator
|
||||
|
||||
|
||||
class SourceStage(Stage):
|
||||
"""Suspend the current flow execution and send the user to a source,
|
||||
after which this flow execution is resumed."""
|
||||
|
||||
source = models.ForeignKey("authentik_core.Source", on_delete=models.CASCADE)
|
||||
|
||||
resume_timeout = models.TextField(
|
||||
default="minutes=10",
|
||||
validators=[timedelta_string_validator],
|
||||
help_text=_(
|
||||
"Amount of time a user can take to return from the source to continue the flow "
|
||||
"(Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
),
|
||||
)
|
||||
|
||||
@property
|
||||
def serializer(self) -> type[BaseSerializer]:
|
||||
from authentik.enterprise.stages.source.api import SourceStageSerializer
|
||||
|
||||
return SourceStageSerializer
|
||||
|
||||
@property
|
||||
def view(self) -> type[View]:
|
||||
from authentik.enterprise.stages.source.stage import SourceStageView
|
||||
|
||||
return SourceStageView
|
||||
|
||||
@property
|
||||
def component(self) -> str:
|
||||
return "ak-stage-source-form"
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Source Stage")
|
||||
verbose_name_plural = _("Source Stages")
|
@ -1,79 +0,0 @@
|
||||
"""Source stage logic"""
|
||||
|
||||
from typing import Any
|
||||
from uuid import uuid4
|
||||
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.utils.text import slugify
|
||||
from django.utils.timezone import now
|
||||
from guardian.shortcuts import get_anonymous_user
|
||||
|
||||
from authentik.core.models import Source, User
|
||||
from authentik.core.sources.flow_manager import SESSION_KEY_OVERRIDE_FLOW_TOKEN
|
||||
from authentik.core.types import UILoginButton
|
||||
from authentik.enterprise.stages.source.models import SourceStage
|
||||
from authentik.flows.challenge import Challenge, ChallengeResponse
|
||||
from authentik.flows.models import FlowToken
|
||||
from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED
|
||||
from authentik.flows.stage import ChallengeStageView
|
||||
from authentik.lib.utils.time import timedelta_from_string
|
||||
|
||||
PLAN_CONTEXT_RESUME_TOKEN = "resume_token" # nosec
|
||||
|
||||
|
||||
class SourceStageView(ChallengeStageView):
|
||||
"""Suspend the current flow execution and send the user to a source,
|
||||
after which this flow execution is resumed."""
|
||||
|
||||
login_button: UILoginButton
|
||||
|
||||
def dispatch(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
|
||||
current_stage: SourceStage = self.executor.current_stage
|
||||
source: Source = (
|
||||
Source.objects.filter(pk=current_stage.source_id).select_subclasses().first()
|
||||
)
|
||||
if not source:
|
||||
self.logger.warning("Source does not exist")
|
||||
return self.executor.stage_invalid("Source does not exist")
|
||||
self.login_button = source.ui_login_button(self.request)
|
||||
if not self.login_button:
|
||||
self.logger.warning("Source does not have a UI login button")
|
||||
return self.executor.stage_invalid("Invalid source")
|
||||
restore_token = self.executor.plan.context.get(PLAN_CONTEXT_IS_RESTORED)
|
||||
override_token = self.request.session.get(SESSION_KEY_OVERRIDE_FLOW_TOKEN)
|
||||
if restore_token and override_token and restore_token.pk == override_token.pk:
|
||||
del self.request.session[SESSION_KEY_OVERRIDE_FLOW_TOKEN]
|
||||
return self.executor.stage_ok()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_challenge(self, *args, **kwargs) -> Challenge:
|
||||
resume_token = self.create_flow_token()
|
||||
self.request.session[SESSION_KEY_OVERRIDE_FLOW_TOKEN] = resume_token
|
||||
return self.login_button.challenge
|
||||
|
||||
def create_flow_token(self) -> FlowToken:
|
||||
"""Save the current flow state in a token that can be used to resume this flow"""
|
||||
pending_user: User = self.get_pending_user()
|
||||
if pending_user.is_anonymous:
|
||||
pending_user = get_anonymous_user()
|
||||
current_stage: SourceStage = self.executor.current_stage
|
||||
identifier = slugify(f"ak-source-stage-{current_stage.name}-{str(uuid4())}")
|
||||
# Don't check for validity here, we only care if the token exists
|
||||
tokens = FlowToken.objects.filter(identifier=identifier)
|
||||
valid_delta = timedelta_from_string(current_stage.resume_timeout)
|
||||
if not tokens.exists():
|
||||
return FlowToken.objects.create(
|
||||
expires=now() + valid_delta,
|
||||
user=pending_user,
|
||||
identifier=identifier,
|
||||
flow=self.executor.flow,
|
||||
_plan=FlowToken.pickle(self.executor.plan),
|
||||
)
|
||||
token = tokens.first()
|
||||
# Check if token is expired and rotate key if so
|
||||
if token.is_expired:
|
||||
token.expire_action()
|
||||
return token
|
||||
|
||||
def challenge_valid(self, response: ChallengeResponse) -> HttpResponse:
|
||||
return self.executor.stage_ok()
|
@ -1,99 +0,0 @@
|
||||
"""Source stage tests"""
|
||||
|
||||
from django.urls import reverse
|
||||
|
||||
from authentik.core.tests.utils import create_test_flow, create_test_user
|
||||
from authentik.enterprise.stages.source.models import SourceStage
|
||||
from authentik.flows.models import FlowDesignation, FlowStageBinding, FlowToken
|
||||
from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED, FlowPlan
|
||||
from authentik.flows.tests import FlowTestCase
|
||||
from authentik.flows.views.executor import SESSION_KEY_PLAN
|
||||
from authentik.lib.generators import generate_id
|
||||
from authentik.sources.saml.models import SAMLSource
|
||||
from authentik.stages.identification.models import IdentificationStage, UserFields
|
||||
from authentik.stages.password import BACKEND_INBUILT
|
||||
from authentik.stages.password.models import PasswordStage
|
||||
from authentik.stages.user_login.models import UserLoginStage
|
||||
|
||||
|
||||
class TestSourceStage(FlowTestCase):
|
||||
"""Source stage tests"""
|
||||
|
||||
def setUp(self):
|
||||
self.source = SAMLSource.objects.create(
|
||||
slug=generate_id(),
|
||||
issuer="authentik",
|
||||
allow_idp_initiated=True,
|
||||
pre_authentication_flow=create_test_flow(),
|
||||
)
|
||||
|
||||
def test_source_success(self):
|
||||
"""Test"""
|
||||
user = create_test_user()
|
||||
flow = create_test_flow(FlowDesignation.AUTHENTICATION)
|
||||
stage = SourceStage.objects.create(name=generate_id(), source=self.source)
|
||||
FlowStageBinding.objects.create(
|
||||
target=flow,
|
||||
stage=IdentificationStage.objects.create(
|
||||
name=generate_id(),
|
||||
user_fields=[UserFields.USERNAME],
|
||||
),
|
||||
order=0,
|
||||
)
|
||||
FlowStageBinding.objects.create(
|
||||
target=flow,
|
||||
stage=PasswordStage.objects.create(name=generate_id(), backends=[BACKEND_INBUILT]),
|
||||
order=5,
|
||||
)
|
||||
FlowStageBinding.objects.create(target=flow, stage=stage, order=10)
|
||||
FlowStageBinding.objects.create(
|
||||
target=flow,
|
||||
stage=UserLoginStage.objects.create(
|
||||
name=generate_id(),
|
||||
),
|
||||
order=15,
|
||||
)
|
||||
|
||||
# Get user identification stage
|
||||
response = self.client.get(
|
||||
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertStageResponse(response, flow, component="ak-stage-identification")
|
||||
# Send username
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
|
||||
data={"uid_field": user.username},
|
||||
follow=True,
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertStageResponse(response, flow, component="ak-stage-password")
|
||||
# Send password
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
|
||||
data={"password": user.username},
|
||||
follow=True,
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertStageRedirects(
|
||||
response,
|
||||
reverse("authentik_sources_saml:login", kwargs={"source_slug": self.source.slug}),
|
||||
)
|
||||
|
||||
# Hijack flow plan so we don't have to emulate the source
|
||||
flow_token = FlowToken.objects.filter(
|
||||
identifier__startswith=f"ak-source-stage-{stage.name.lower()}"
|
||||
).first()
|
||||
self.assertIsNotNone(flow_token)
|
||||
session = self.client.session
|
||||
plan: FlowPlan = session[SESSION_KEY_PLAN]
|
||||
plan.context[PLAN_CONTEXT_IS_RESTORED] = flow_token
|
||||
session[SESSION_KEY_PLAN] = plan
|
||||
session.save()
|
||||
|
||||
# Pretend we've just returned from the source
|
||||
response = self.client.get(
|
||||
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}), follow=True
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
|
@ -1,5 +0,0 @@
|
||||
"""API URLs"""
|
||||
|
||||
from authentik.enterprise.stages.source.api import SourceStageViewSet
|
||||
|
||||
api_urlpatterns = [("stages/source", SourceStageViewSet)]
|
@ -452,13 +452,6 @@ class NotificationTransport(SerializerModel):
|
||||
|
||||
def send_email(self, notification: "Notification") -> list[str]:
|
||||
"""Send notification via global email configuration"""
|
||||
if notification.user.email.strip() == "":
|
||||
LOGGER.info(
|
||||
"Discarding notification as user has no email address",
|
||||
user=notification.user,
|
||||
notification=notification,
|
||||
)
|
||||
return None
|
||||
subject_prefix = "authentik Notification: "
|
||||
context = {
|
||||
"key_value": {
|
||||
|
@ -13,7 +13,6 @@ from structlog.stdlib import get_logger
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.core.api.utils import MetaNameSerializer, TypeCreateSerializer
|
||||
from authentik.core.types import UserSettingSerializer
|
||||
from authentik.enterprise.apps import EnterpriseConfig
|
||||
from authentik.flows.api.flows import FlowSetSerializer
|
||||
from authentik.flows.models import ConfigurableStage, Stage
|
||||
from authentik.lib.utils.reflection import all_subclasses
|
||||
@ -76,7 +75,6 @@ class StageViewSet(
|
||||
"description": subclass.__doc__,
|
||||
"component": subclass().component,
|
||||
"model_name": subclass._meta.model_name,
|
||||
"requires_enterprise": isinstance(subclass._meta.app_config, EnterpriseConfig),
|
||||
}
|
||||
)
|
||||
data = sorted(data, key=lambda x: x["name"])
|
||||
|
@ -53,7 +53,6 @@ class TestFlowInspector(APITestCase):
|
||||
"title": flow.title,
|
||||
"layout": "stacked",
|
||||
},
|
||||
"flow_designation": "authentication",
|
||||
"type": ChallengeTypes.NATIVE.value,
|
||||
"password_fields": False,
|
||||
"primary_action": "Log in",
|
||||
|
@ -24,7 +24,6 @@ from sentry_sdk.hub import Hub
|
||||
from structlog.stdlib import BoundLogger, get_logger
|
||||
|
||||
from authentik.brands.models import Brand
|
||||
from authentik.brands.utils import cors_allow
|
||||
from authentik.core.models import Application
|
||||
from authentik.events.models import Event, EventAction, cleanse_dict
|
||||
from authentik.flows.apps import HIST_FLOW_EXECUTION_STAGE_TIME
|
||||
@ -156,14 +155,6 @@ class FlowExecutorView(APIView):
|
||||
return plan
|
||||
|
||||
def dispatch(self, request: HttpRequest, flow_slug: str) -> HttpResponse:
|
||||
response = self.dispatch_wrapper(request, flow_slug)
|
||||
origins = []
|
||||
if request.brand.origin != "":
|
||||
origins.append(request.brand.origin)
|
||||
cors_allow(request, response, *origins)
|
||||
return response
|
||||
|
||||
def dispatch_wrapper(self, request: HttpRequest, flow_slug: str) -> HttpResponse:
|
||||
with Hub.current.start_span(
|
||||
op="authentik.flow.executor.dispatch", description=self.flow.slug
|
||||
) as span:
|
||||
@ -478,7 +469,7 @@ class FlowExecutorView(APIView):
|
||||
|
||||
|
||||
class CancelView(View):
|
||||
"""View which cancels the currently active plan"""
|
||||
"""View which canels the currently active plan"""
|
||||
|
||||
def get(self, request: HttpRequest) -> HttpResponse:
|
||||
"""View which canels the currently active plan"""
|
||||
|
@ -33,8 +33,6 @@ class ServiceReconciler(KubernetesObjectReconciler[V1Service]):
|
||||
# priority than being updated.
|
||||
if current.spec.selector != reference.spec.selector:
|
||||
raise NeedsUpdate()
|
||||
if current.spec.type != reference.spec.type:
|
||||
raise NeedsUpdate()
|
||||
super().reconcile(current, reference)
|
||||
|
||||
def get_reference_object(self) -> V1Service:
|
||||
|
@ -1,9 +1,9 @@
|
||||
"""authentik oauth provider app config"""
|
||||
|
||||
from authentik.blueprints.apps import ManagedAppConfig
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class AuthentikProviderOAuth2Config(ManagedAppConfig):
|
||||
class AuthentikProviderOAuth2Config(AppConfig):
|
||||
"""authentik oauth provider app config"""
|
||||
|
||||
name = "authentik.providers.oauth2"
|
||||
@ -13,4 +13,3 @@ class AuthentikProviderOAuth2Config(ManagedAppConfig):
|
||||
"authentik.providers.oauth2.urls_root": "",
|
||||
"authentik.providers.oauth2.urls": "application/o/",
|
||||
}
|
||||
default = True
|
||||
|
@ -1,15 +0,0 @@
|
||||
from hashlib import sha256
|
||||
|
||||
from django.contrib.auth.signals import user_logged_out
|
||||
from django.dispatch import receiver
|
||||
from django.http import HttpRequest
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.providers.oauth2.models import AccessToken
|
||||
|
||||
|
||||
@receiver(user_logged_out)
|
||||
def user_logged_out_oauth_access_token(sender, request: HttpRequest, user: User, **_):
|
||||
"""Revoke access tokens upon user logout"""
|
||||
hashed_session_key = sha256(request.session.session_key.encode("ascii")).hexdigest()
|
||||
AccessToken.objects.filter(user=user, session_id=hashed_session_key).delete()
|
@ -4,9 +4,11 @@ import re
|
||||
from base64 import b64decode
|
||||
from binascii import Error
|
||||
from typing import Any
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from django.http import HttpRequest, HttpResponse, JsonResponse
|
||||
from django.http.response import HttpResponseRedirect
|
||||
from django.utils.cache import patch_vary_headers
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.core.middleware import CTX_AUTH_VIA, KEY_USER
|
||||
@ -28,6 +30,49 @@ class TokenResponse(JsonResponse):
|
||||
self["Pragma"] = "no-cache"
|
||||
|
||||
|
||||
def cors_allow(request: HttpRequest, response: HttpResponse, *allowed_origins: str):
|
||||
"""Add headers to permit CORS requests from allowed_origins, with or without credentials,
|
||||
with any headers."""
|
||||
origin = request.META.get("HTTP_ORIGIN")
|
||||
if not origin:
|
||||
return response
|
||||
|
||||
# OPTIONS requests don't have an authorization header -> hence
|
||||
# we can't extract the provider this request is for
|
||||
# so for options requests we allow the calling origin without checking
|
||||
allowed = request.method == "OPTIONS"
|
||||
received_origin = urlparse(origin)
|
||||
for allowed_origin in allowed_origins:
|
||||
url = urlparse(allowed_origin)
|
||||
if (
|
||||
received_origin.scheme == url.scheme
|
||||
and received_origin.hostname == url.hostname
|
||||
and received_origin.port == url.port
|
||||
):
|
||||
allowed = True
|
||||
if not allowed:
|
||||
LOGGER.warning(
|
||||
"CORS: Origin is not an allowed origin",
|
||||
requested=received_origin,
|
||||
allowed=allowed_origins,
|
||||
)
|
||||
return response
|
||||
|
||||
# From the CORS spec: The string "*" cannot be used for a resource that supports credentials.
|
||||
response["Access-Control-Allow-Origin"] = origin
|
||||
patch_vary_headers(response, ["Origin"])
|
||||
response["Access-Control-Allow-Credentials"] = "true"
|
||||
|
||||
if request.method == "OPTIONS":
|
||||
if "HTTP_ACCESS_CONTROL_REQUEST_HEADERS" in request.META:
|
||||
response["Access-Control-Allow-Headers"] = request.META[
|
||||
"HTTP_ACCESS_CONTROL_REQUEST_HEADERS"
|
||||
]
|
||||
response["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS"
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def extract_access_token(request: HttpRequest) -> str | None:
|
||||
"""
|
||||
Get the access token using Authorization Request Header Field method.
|
||||
|
@ -8,7 +8,6 @@ from django.views import View
|
||||
from guardian.shortcuts import get_anonymous_user
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.brands.utils import cors_allow
|
||||
from authentik.core.exceptions import PropertyMappingExpressionException
|
||||
from authentik.core.models import Application
|
||||
from authentik.providers.oauth2.constants import (
|
||||
@ -29,6 +28,7 @@ from authentik.providers.oauth2.models import (
|
||||
ResponseTypes,
|
||||
ScopeMapping,
|
||||
)
|
||||
from authentik.providers.oauth2.utils import cors_allow
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
|
@ -20,7 +20,6 @@ from jwt import PyJWK, PyJWT, PyJWTError, decode
|
||||
from sentry_sdk.hub import Hub
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.brands.utils import cors_allow
|
||||
from authentik.core.middleware import CTX_AUTH_VIA
|
||||
from authentik.core.models import (
|
||||
USER_ATTRIBUTE_EXPIRES,
|
||||
@ -60,7 +59,7 @@ from authentik.providers.oauth2.models import (
|
||||
OAuth2Provider,
|
||||
RefreshToken,
|
||||
)
|
||||
from authentik.providers.oauth2.utils import TokenResponse, extract_client_auth
|
||||
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
|
||||
|
@ -11,7 +11,6 @@ from django.views import View
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.brands.utils import cors_allow
|
||||
from authentik.core.exceptions import PropertyMappingExpressionException
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.flows.challenge import PermissionDict
|
||||
@ -29,7 +28,7 @@ from authentik.providers.oauth2.models import (
|
||||
RefreshToken,
|
||||
ScopeMapping,
|
||||
)
|
||||
from authentik.providers.oauth2.utils import TokenResponse, protected_resource_view
|
||||
from authentik.providers.oauth2.utils import TokenResponse, cors_allow, protected_resource_view
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
|
@ -56,10 +56,7 @@ class IngressReconciler(KubernetesObjectReconciler[V1Ingress]):
|
||||
proxy_provider: ProxyProvider
|
||||
external_host_name = urlparse(proxy_provider.external_host)
|
||||
expected_hosts.append(external_host_name.hostname)
|
||||
if (
|
||||
external_host_name.scheme == "https"
|
||||
and self.controller.outpost.config.kubernetes_ingress_secret_name
|
||||
):
|
||||
if external_host_name.scheme == "https":
|
||||
expected_hosts_tls.append(external_host_name.hostname)
|
||||
expected_hosts.sort()
|
||||
expected_hosts_tls.sort()
|
||||
@ -119,10 +116,7 @@ class IngressReconciler(KubernetesObjectReconciler[V1Ingress]):
|
||||
):
|
||||
proxy_provider: ProxyProvider
|
||||
external_host_name = urlparse(proxy_provider.external_host)
|
||||
if (
|
||||
external_host_name.scheme == "https"
|
||||
and self.controller.outpost.config.kubernetes_ingress_secret_name
|
||||
):
|
||||
if external_host_name.scheme == "https":
|
||||
tls_hosts.append(external_host_name.hostname)
|
||||
if proxy_provider.mode in [
|
||||
ProxyMode.FORWARD_SINGLE,
|
||||
@ -166,15 +160,13 @@ class IngressReconciler(KubernetesObjectReconciler[V1Ingress]):
|
||||
rules.append(rule)
|
||||
tls_config = None
|
||||
if tls_hosts:
|
||||
tls_config = [
|
||||
V1IngressTLS(
|
||||
hosts=tls_hosts,
|
||||
secret_name=self.controller.outpost.config.kubernetes_ingress_secret_name,
|
||||
)
|
||||
]
|
||||
tls_config = V1IngressTLS(
|
||||
hosts=tls_hosts,
|
||||
secret_name=self.controller.outpost.config.kubernetes_ingress_secret_name,
|
||||
)
|
||||
spec = V1IngressSpec(
|
||||
rules=rules,
|
||||
tls=tls_config,
|
||||
tls=[tls_config],
|
||||
)
|
||||
if self.controller.outpost.config.kubernetes_ingress_class_name:
|
||||
spec.ingress_class_name = self.controller.outpost.config.kubernetes_ingress_class_name
|
||||
|
@ -196,10 +196,8 @@ if CONFIG.get_bool("redis.tls", False):
|
||||
_redis_protocol_prefix = "rediss://"
|
||||
_redis_celery_tls_requirements = f"?ssl_cert_reqs={CONFIG.get('redis.tls_reqs')}"
|
||||
_redis_url = (
|
||||
f"{_redis_protocol_prefix}"
|
||||
f"{quote_plus(CONFIG.get('redis.username'))}:"
|
||||
f"{quote_plus(CONFIG.get('redis.password'))}@"
|
||||
f"{quote_plus(CONFIG.get('redis.host'))}:"
|
||||
f"{_redis_protocol_prefix}:"
|
||||
f"{quote_plus(CONFIG.get('redis.password'))}@{quote_plus(CONFIG.get('redis.host'))}:"
|
||||
f"{CONFIG.get_int('redis.port')}"
|
||||
)
|
||||
|
||||
@ -241,7 +239,7 @@ MIDDLEWARE = [
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"authentik.root.middleware.CsrfViewMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"authentik.brands.middleware.BrandHeaderMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
"authentik.core.middleware.ImpersonateMiddleware",
|
||||
"django_prometheus.middleware.PrometheusAfterMiddleware",
|
||||
]
|
||||
|
@ -77,7 +77,6 @@ class LDAPSourceSerializer(SourceSerializer):
|
||||
"group_object_filter",
|
||||
"group_membership_field",
|
||||
"object_uniqueness_field",
|
||||
"password_login_update_internal_password",
|
||||
"sync_users",
|
||||
"sync_users_password",
|
||||
"sync_groups",
|
||||
@ -119,7 +118,6 @@ class LDAPSourceViewSet(UsedByMixin, ModelViewSet):
|
||||
"group_object_filter",
|
||||
"group_membership_field",
|
||||
"object_uniqueness_field",
|
||||
"password_login_update_internal_password",
|
||||
"sync_users",
|
||||
"sync_users_password",
|
||||
"sync_groups",
|
||||
|
@ -41,11 +41,10 @@ class LDAPBackend(InbuiltBackend):
|
||||
# or has a password, but couldn't be authenticated by ModelBackend.
|
||||
# This means we check with a bind to see if the LDAP password has changed
|
||||
if self.auth_user_by_bind(source, user, password):
|
||||
if source.password_login_update_internal_password:
|
||||
# Password given successfully binds to LDAP, so we save it in our Database
|
||||
LOGGER.debug("Updating user's password in DB", user=user)
|
||||
user.set_password(password, signal=False)
|
||||
user.save()
|
||||
# Password given successfully binds to LDAP, so we save it in our Database
|
||||
LOGGER.debug("Updating user's password in DB", user=user)
|
||||
user.set_password(password, signal=False)
|
||||
user.save()
|
||||
return user
|
||||
# Password doesn't match
|
||||
LOGGER.debug("Failed to bind, password invalid")
|
||||
|
@ -1,29 +0,0 @@
|
||||
# Generated by Django 5.0.1 on 2024-01-31 18:41
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_sources_ldap", "0003_ldapsource_client_certificate_ldapsource_sni_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="ldapsource",
|
||||
name="password_login_update_internal_password",
|
||||
field=models.BooleanField(
|
||||
default=True,
|
||||
help_text="Update internal authentik password when login succeeds with LDAP",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ldapsource",
|
||||
name="password_login_update_internal_password",
|
||||
field=models.BooleanField(
|
||||
default=False,
|
||||
help_text="Update internal authentik password when login succeeds with LDAP",
|
||||
),
|
||||
),
|
||||
]
|
@ -98,11 +98,6 @@ class LDAPSource(Source):
|
||||
help_text=_("Property mappings used for group creation/updating."),
|
||||
)
|
||||
|
||||
password_login_update_internal_password = models.BooleanField(
|
||||
default=False,
|
||||
help_text=_("Update internal authentik password when login succeeds with LDAP"),
|
||||
)
|
||||
|
||||
sync_users = models.BooleanField(default=True)
|
||||
sync_users_password = models.BooleanField(
|
||||
default=True,
|
||||
|
@ -47,7 +47,7 @@ class SourceType:
|
||||
def login_challenge(self, source: OAuthSource, request: HttpRequest) -> Challenge:
|
||||
"""Allow types to return custom challenges"""
|
||||
return RedirectChallenge(
|
||||
data={
|
||||
instance={
|
||||
"type": ChallengeTypes.REDIRECT.value,
|
||||
"to": reverse(
|
||||
"authentik_sources_oauth:oauth-client-login",
|
||||
|
@ -54,7 +54,7 @@ class OAuthCallback(OAuthClientMixin, View):
|
||||
raw_profile=exc.doc,
|
||||
).from_http(self.request)
|
||||
return self.handle_login_failure("Could not retrieve profile.")
|
||||
identifier = self.get_user_id(info=raw_info)
|
||||
identifier = self.get_user_id(raw_info)
|
||||
if identifier is None:
|
||||
return self.handle_login_failure("Could not determine id.")
|
||||
# Get or create access record
|
||||
@ -67,7 +67,6 @@ class OAuthCallback(OAuthClientMixin, View):
|
||||
)
|
||||
sfm.policy_context = {"oauth_userinfo": raw_info}
|
||||
return sfm.get_flow(
|
||||
raw_info=raw_info,
|
||||
access_token=self.token.get("access_token"),
|
||||
)
|
||||
|
||||
@ -117,7 +116,6 @@ class OAuthSourceFlowManager(SourceFlowManager):
|
||||
self,
|
||||
connection: UserOAuthSourceConnection,
|
||||
access_token: str | None = None,
|
||||
**_,
|
||||
) -> UserOAuthSourceConnection:
|
||||
"""Set the access_token on the connection"""
|
||||
connection.access_token = access_token
|
||||
|
@ -190,7 +190,7 @@ class SAMLSource(Source):
|
||||
def ui_login_button(self, request: HttpRequest) -> UILoginButton:
|
||||
return UILoginButton(
|
||||
challenge=RedirectChallenge(
|
||||
data={
|
||||
instance={
|
||||
"type": ChallengeTypes.REDIRECT.value,
|
||||
"to": reverse(
|
||||
"authentik_sources_saml:login",
|
||||
|
@ -234,14 +234,12 @@ class ResponseProcessor:
|
||||
if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_TRANSIENT:
|
||||
return self._handle_name_id_transient()
|
||||
|
||||
flow_manager = SAMLSourceFlowManager(
|
||||
return SAMLSourceFlowManager(
|
||||
self._source,
|
||||
self._http_request,
|
||||
name_id.text,
|
||||
delete_none_values(self.get_attributes()),
|
||||
)
|
||||
flow_manager.policy_context["saml_response"] = self._root
|
||||
return flow_manager
|
||||
|
||||
|
||||
class SAMLSourceFlowManager(SourceFlowManager):
|
||||
|
@ -120,9 +120,7 @@ def validate_challenge_code(code: str, stage_view: StageView, user: User) -> Dev
|
||||
stage=stage_view.executor.current_stage,
|
||||
device_class=DeviceClasses.TOTP.value,
|
||||
)
|
||||
raise ValidationError(
|
||||
_("Invalid Token. Please ensure the time on your device is accurate and try again.")
|
||||
)
|
||||
raise ValidationError(_("Invalid Token"))
|
||||
return device
|
||||
|
||||
|
||||
|
@ -12,7 +12,6 @@ class DummyChallenge(Challenge):
|
||||
"""Dummy challenge"""
|
||||
|
||||
component = CharField(default="ak-stage-dummy")
|
||||
name = CharField()
|
||||
|
||||
|
||||
class DummyChallengeResponse(ChallengeResponse):
|
||||
@ -36,6 +35,5 @@ class DummyStageView(ChallengeStageView):
|
||||
data={
|
||||
"type": ChallengeTypes.NATIVE.value,
|
||||
"title": self.executor.current_stage.name,
|
||||
"name": self.executor.current_stage.name,
|
||||
}
|
||||
)
|
||||
|
@ -118,7 +118,6 @@ class EmailStageView(ChallengeStageView):
|
||||
"url": self.get_full_url(**{QS_KEY_TOKEN: token.key}),
|
||||
"user": pending_user,
|
||||
"expires": token.expires,
|
||||
"token": token.key,
|
||||
},
|
||||
)
|
||||
send_mails(current_stage, message)
|
||||
|
@ -10,7 +10,7 @@ from django.db.models import Q
|
||||
from django.http import HttpResponse
|
||||
from django.utils.translation import gettext as _
|
||||
from drf_spectacular.utils import PolymorphicProxySerializer, extend_schema_field
|
||||
from rest_framework.fields import BooleanField, CharField, ChoiceField, DictField, ListField
|
||||
from rest_framework.fields import BooleanField, CharField, DictField, ListField
|
||||
from rest_framework.serializers import ValidationError
|
||||
from sentry_sdk.hub import Hub
|
||||
|
||||
@ -66,7 +66,6 @@ class IdentificationChallenge(Challenge):
|
||||
user_fields = ListField(child=CharField(), allow_empty=True, allow_null=True)
|
||||
password_fields = BooleanField()
|
||||
application_pre = CharField(required=False)
|
||||
flow_designation = ChoiceField(FlowDesignation.choices)
|
||||
|
||||
enroll_url = CharField(required=False)
|
||||
recovery_url = CharField(required=False)
|
||||
@ -195,12 +194,11 @@ class IdentificationStageView(ChallengeStageView):
|
||||
challenge = IdentificationChallenge(
|
||||
data={
|
||||
"type": ChallengeTypes.NATIVE.value,
|
||||
"component": "ak-stage-identification",
|
||||
"primary_action": self.get_primary_action(),
|
||||
"component": "ak-stage-identification",
|
||||
"user_fields": current_stage.user_fields,
|
||||
"password_fields": bool(current_stage.password_stage),
|
||||
"show_source_labels": current_stage.show_source_labels,
|
||||
"flow_designation": self.executor.flow.designation,
|
||||
}
|
||||
)
|
||||
# If the user has been redirected to us whilst trying to access an
|
||||
@ -239,9 +237,7 @@ class IdentificationStageView(ChallengeStageView):
|
||||
ui_login_button = source.ui_login_button(self.request)
|
||||
if ui_login_button:
|
||||
button = asdict(ui_login_button)
|
||||
source_challenge = ui_login_button.challenge
|
||||
source_challenge.is_valid()
|
||||
button["challenge"] = source_challenge.data
|
||||
button["challenge"] = ui_login_button.challenge.data
|
||||
ui_sources.append(button)
|
||||
challenge.initial_data["sources"] = ui_sources
|
||||
return challenge
|
||||
|
@ -12,7 +12,6 @@ from rest_framework.exceptions import ValidationError
|
||||
from authentik.core.middleware import SESSION_KEY_IMPERSONATE_USER
|
||||
from authentik.core.models import USER_ATTRIBUTE_SOURCES, User, UserSourceConnection, UserTypes
|
||||
from authentik.core.sources.stage import PLAN_CONTEXT_SOURCES_CONNECTION
|
||||
from authentik.events.utils import sanitize_item
|
||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
||||
from authentik.flows.stage import StageView
|
||||
from authentik.flows.views.executor import FlowExecutorView
|
||||
@ -48,7 +47,7 @@ class UserWriteStageView(StageView):
|
||||
# this is just a sanity check to ensure that is removed
|
||||
if parts[0] == "attributes":
|
||||
parts = parts[1:]
|
||||
set_path_in_dict(user.attributes, ".".join(parts), sanitize_item(value))
|
||||
set_path_in_dict(user.attributes, ".".join(parts), value)
|
||||
|
||||
def ensure_user(self) -> tuple[User | None, bool]:
|
||||
"""Ensure a user exists"""
|
||||
|
@ -2594,43 +2594,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"model",
|
||||
"identifiers"
|
||||
],
|
||||
"properties": {
|
||||
"model": {
|
||||
"const": "authentik_stages_source.sourcestage"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"state": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"absent",
|
||||
"present",
|
||||
"created",
|
||||
"must_created"
|
||||
],
|
||||
"default": "present"
|
||||
},
|
||||
"conditions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"attrs": {
|
||||
"$ref": "#/$defs/model_authentik_stages_source.sourcestage"
|
||||
},
|
||||
"identifiers": {
|
||||
"$ref": "#/$defs/model_authentik_stages_source.sourcestage"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
@ -3294,7 +3257,6 @@
|
||||
"authentik.enterprise",
|
||||
"authentik.enterprise.audit",
|
||||
"authentik.enterprise.providers.rac",
|
||||
"authentik.enterprise.stages.source",
|
||||
"authentik.events"
|
||||
],
|
||||
"title": "App",
|
||||
@ -3376,7 +3338,6 @@
|
||||
"authentik_providers_rac.racprovider",
|
||||
"authentik_providers_rac.endpoint",
|
||||
"authentik_providers_rac.racpropertymapping",
|
||||
"authentik_stages_source.sourcestage",
|
||||
"authentik_events.event",
|
||||
"authentik_events.notificationtransport",
|
||||
"authentik_events.notification",
|
||||
@ -4347,11 +4308,6 @@
|
||||
"title": "Object uniqueness field",
|
||||
"description": "Field which contains a unique Identifier."
|
||||
},
|
||||
"password_login_update_internal_password": {
|
||||
"type": "boolean",
|
||||
"title": "Password login update internal password",
|
||||
"description": "Update internal authentik password when login succeeds with LDAP"
|
||||
},
|
||||
"sync_users": {
|
||||
"type": "boolean",
|
||||
"title": "Sync users"
|
||||
@ -7609,11 +7565,6 @@
|
||||
"title": "Domain",
|
||||
"description": "Domain that activates this brand. Can be a superset, i.e. `a.b` for `aa.b` and `ba.b`"
|
||||
},
|
||||
"origin": {
|
||||
"type": "string",
|
||||
"title": "Origin",
|
||||
"description": "Origin domain that activates this brand. Can be left empty to not allow any origins."
|
||||
},
|
||||
"default": {
|
||||
"type": "boolean",
|
||||
"title": "Default"
|
||||
@ -7657,11 +7608,6 @@
|
||||
"type": "integer",
|
||||
"title": "Flow device code"
|
||||
},
|
||||
"default_application": {
|
||||
"type": "integer",
|
||||
"title": "Default application",
|
||||
"description": "When set, external users will be redirected to this application after authenticating."
|
||||
},
|
||||
"web_certificate": {
|
||||
"type": "integer",
|
||||
"title": "Web certificate",
|
||||
@ -8072,109 +8018,6 @@
|
||||
},
|
||||
"required": []
|
||||
},
|
||||
"model_authentik_stages_source.sourcestage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"title": "Name"
|
||||
},
|
||||
"flow_set": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"title": "Name"
|
||||
},
|
||||
"slug": {
|
||||
"type": "string",
|
||||
"maxLength": 50,
|
||||
"minLength": 1,
|
||||
"pattern": "^[-a-zA-Z0-9_]+$",
|
||||
"title": "Slug",
|
||||
"description": "Visible in the URL."
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"title": "Title",
|
||||
"description": "Shown as the Title in Flow pages."
|
||||
},
|
||||
"designation": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"authentication",
|
||||
"authorization",
|
||||
"invalidation",
|
||||
"enrollment",
|
||||
"unenrollment",
|
||||
"recovery",
|
||||
"stage_configuration"
|
||||
],
|
||||
"title": "Designation",
|
||||
"description": "Decides what this Flow is used for. For example, the Authentication flow is redirect to when an un-authenticated user visits authentik."
|
||||
},
|
||||
"policy_engine_mode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"all",
|
||||
"any"
|
||||
],
|
||||
"title": "Policy engine mode"
|
||||
},
|
||||
"compatibility_mode": {
|
||||
"type": "boolean",
|
||||
"title": "Compatibility mode",
|
||||
"description": "Enable compatibility mode, increases compatibility with password managers on mobile devices."
|
||||
},
|
||||
"layout": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"stacked",
|
||||
"content_left",
|
||||
"content_right",
|
||||
"sidebar_left",
|
||||
"sidebar_right"
|
||||
],
|
||||
"title": "Layout"
|
||||
},
|
||||
"denied_action": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"message_continue",
|
||||
"message",
|
||||
"continue"
|
||||
],
|
||||
"title": "Denied action",
|
||||
"description": "Configure what should happen when a flow denies access to a user."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"slug",
|
||||
"title",
|
||||
"designation"
|
||||
]
|
||||
},
|
||||
"title": "Flow set"
|
||||
},
|
||||
"source": {
|
||||
"type": "integer",
|
||||
"title": "Source"
|
||||
},
|
||||
"resume_timeout": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"title": "Resume timeout",
|
||||
"description": "Amount of time a user can take to return from the source to continue the flow (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
},
|
||||
"model_authentik_events.event": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
2
go.mod
2
go.mod
@ -30,7 +30,7 @@ require (
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/wwt/guac v1.3.2
|
||||
goauthentik.io/api/v3 v3.2024022.5
|
||||
goauthentik.io/api/v3 v3.2024022.1
|
||||
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
|
||||
golang.org/x/oauth2 v0.18.0
|
||||
golang.org/x/sync v0.6.0
|
||||
|
4
go.sum
4
go.sum
@ -280,8 +280,8 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y
|
||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||
go.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.2024022.5 h1:z1ZaVY/UpwpHAghf/PyYRSOQT7U9g8E2N23YlRB5BJQ=
|
||||
goauthentik.io/api/v3 v3.2024022.5/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
||||
goauthentik.io/api/v3 v3.2024022.1 h1:ydYi3X/OSnu4LumUN+oCe6vvGDXil1Xn186hC9FQb4Q=
|
||||
goauthentik.io/api/v3 v3.2024022.1/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
|
@ -10,17 +10,12 @@ const CodePasswordSeparator = ";"
|
||||
|
||||
var alphaNum = regexp.MustCompile(`^[a-zA-Z0-9]*$`)
|
||||
|
||||
// Sets the secret answers for the flow executor for protocols that only support username/password
|
||||
// according to used options
|
||||
func (fe *FlowExecutor) SetSecrets(password string, mfaCodeBased bool) {
|
||||
if fe.Answers[StageAuthenticatorValidate] != "" || fe.Answers[StagePassword] != "" {
|
||||
return
|
||||
}
|
||||
fe.Answers[StagePassword] = password
|
||||
if !mfaCodeBased {
|
||||
// If code-based MFA is disabled StageAuthenticatorValidate answer is set to password.
|
||||
// This allows flows with a mfa stage only.
|
||||
fe.Answers[StageAuthenticatorValidate] = password
|
||||
// CheckPasswordInlineMFA For protocols that only support username/password, check if the password
|
||||
// contains the TOTP code
|
||||
func (fe *FlowExecutor) CheckPasswordInlineMFA() {
|
||||
password := fe.Answers[StagePassword]
|
||||
// We already have an authenticator answer
|
||||
if fe.Answers[StageAuthenticatorValidate] != "" {
|
||||
return
|
||||
}
|
||||
// password doesn't contain the separator
|
||||
|
@ -23,7 +23,10 @@ func (db *DirectBinder) Bind(username string, req *bind.Request) (ldap.LDAPResul
|
||||
fe.Params.Add("goauthentik.io/outpost/ldap", "true")
|
||||
|
||||
fe.Answers[flow.StageIdentification] = username
|
||||
fe.SetSecrets(req.BindPW, db.si.GetMFASupport())
|
||||
fe.Answers[flow.StagePassword] = req.BindPW
|
||||
if db.si.GetMFASupport() {
|
||||
fe.CheckPasswordInlineMFA()
|
||||
}
|
||||
|
||||
passed, err := fe.Execute()
|
||||
flags := flags.UserFlags{
|
||||
|
@ -56,7 +56,7 @@ func TestProxy_Redirect_Subdirectory(t *testing.T) {
|
||||
loc, _ := rr.Result().Location()
|
||||
assert.Equal(
|
||||
t,
|
||||
"https://ext.t.goauthentik.io/subdir/outpost.goauthentik.io/start?rd=https%3A%2F%2Fext.t.goauthentik.io%2Fsubdir%2Ffoo",
|
||||
"https://ext.t.goauthentik.io/subdir/outpost.goauthentik.io/start?rd=https%3A%2F%2Fext.t.goauthentik.io%2Ffoo",
|
||||
loc.String(),
|
||||
)
|
||||
}
|
||||
|
@ -32,8 +32,8 @@ func (a *Application) getStore(p api.ProxyOutpostConfig, externalHost *url.URL)
|
||||
}
|
||||
if a.isEmbedded {
|
||||
client := redis.NewClient(&redis.Options{
|
||||
Addr: fmt.Sprintf("%s:%d", config.Get().Redis.Host, config.Get().Redis.Port),
|
||||
Username: config.Get().Redis.Username,
|
||||
Addr: fmt.Sprintf("%s:%d", config.Get().Redis.Host, config.Get().Redis.Port),
|
||||
// Username: config.Get().Redis.Password,
|
||||
Password: config.Get().Redis.Password,
|
||||
DB: config.Get().Redis.DB,
|
||||
})
|
||||
|
@ -3,6 +3,7 @@ package application
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@ -10,12 +11,22 @@ import (
|
||||
"goauthentik.io/internal/outpost/proxyv2/constants"
|
||||
)
|
||||
|
||||
func urlJoin(originalUrl string, newPath string) string {
|
||||
u, err := url.JoinPath(originalUrl, newPath)
|
||||
func urlPathSet(originalUrl string, newPath string) string {
|
||||
u, err := url.Parse(originalUrl)
|
||||
if err != nil {
|
||||
return originalUrl
|
||||
}
|
||||
return u
|
||||
u.Path = newPath
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func urlJoin(originalUrl string, newPath string) string {
|
||||
u, err := url.Parse(originalUrl)
|
||||
if err != nil {
|
||||
return originalUrl
|
||||
}
|
||||
u.Path = path.Join(u.Path, newPath)
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func (a *Application) redirectToStart(rw http.ResponseWriter, r *http.Request) {
|
||||
@ -35,7 +46,7 @@ func (a *Application) redirectToStart(rw http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
redirectUrl := urlJoin(a.proxyConfig.ExternalHost, r.URL.Path)
|
||||
redirectUrl := urlPathSet(a.proxyConfig.ExternalHost, r.URL.Path)
|
||||
|
||||
if a.Mode() == api.PROXYMODE_FORWARD_DOMAIN {
|
||||
dom := strings.TrimPrefix(*a.proxyConfig.CookieDomain, ".")
|
||||
|
@ -21,7 +21,10 @@ func (rs *RadiusServer) Handle_AccessRequest(w radius.ResponseWriter, r *RadiusR
|
||||
fe.Params.Add("goauthentik.io/outpost/radius", "true")
|
||||
|
||||
fe.Answers[flow.StageIdentification] = username
|
||||
fe.SetSecrets(rfc2865.UserPassword_GetString(r.Packet), r.pi.MFASupport)
|
||||
fe.Answers[flow.StagePassword] = rfc2865.UserPassword_GetString(r.Packet)
|
||||
if r.pi.MFASupport {
|
||||
fe.CheckPasswordInlineMFA()
|
||||
}
|
||||
|
||||
passed, err := fe.Execute()
|
||||
if err != nil {
|
||||
|
@ -14,27 +14,26 @@ import (
|
||||
)
|
||||
|
||||
func (ws *WebServer) configureStatic() {
|
||||
staticRouter := ws.lh.NewRoute().Subrouter()
|
||||
staticRouter.Use(ws.staticHeaderMiddleware)
|
||||
staticRouter.Use(web.DisableIndex)
|
||||
|
||||
statRouter := ws.lh.NewRoute().Subrouter()
|
||||
statRouter.Use(ws.staticHeaderMiddleware)
|
||||
indexLessRouter := statRouter.NewRoute().Subrouter()
|
||||
indexLessRouter.Use(web.DisableIndex)
|
||||
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)
|
||||
|
||||
// Root file paths, from which they should be accessed
|
||||
staticRouter.PathPrefix("/static/dist/").Handler(http.StripPrefix("/static/dist/", distFs))
|
||||
staticRouter.PathPrefix("/static/authentik/").Handler(authentikHandler)
|
||||
|
||||
// Also serve assets folder in specific interfaces since fonts in patternfly are imported
|
||||
// with a relative path
|
||||
staticRouter.PathPrefix("/if/flow/{flow_slug}/assets").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
// Prevent font-loading issues on safari, which loads fonts relatively to the URL the browser is on
|
||||
indexLessRouter.PathPrefix("/if/flow/{flow_slug}/assets").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
web.DisableIndex(http.StripPrefix(fmt.Sprintf("/if/flow/%s", vars["flow_slug"]), distFs)).ServeHTTP(rw, r)
|
||||
})
|
||||
staticRouter.PathPrefix("/if/admin/assets").Handler(http.StripPrefix("/if/admin", distFs))
|
||||
staticRouter.PathPrefix("/if/user/assets").Handler(http.StripPrefix("/if/user", distFs))
|
||||
staticRouter.PathPrefix("/if/rac/{app_slug}/assets").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
indexLessRouter.PathPrefix("/if/admin/assets").Handler(http.StripPrefix("/if/admin", distFs))
|
||||
indexLessRouter.PathPrefix("/if/user/assets").Handler(http.StripPrefix("/if/user", distFs))
|
||||
indexLessRouter.PathPrefix("/if/rac/{app_slug}/assets").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
web.DisableIndex(http.StripPrefix(fmt.Sprintf("/if/rac/%s", vars["app_slug"]), distFs)).ServeHTTP(rw, r)
|
||||
@ -43,13 +42,12 @@ func (ws *WebServer) configureStatic() {
|
||||
// Media files, if backend is file
|
||||
if config.Get().Storage.Media.Backend == "file" {
|
||||
fsMedia := http.FileServer(http.Dir(config.Get().Storage.Media.File.Path))
|
||||
staticRouter.PathPrefix("/media/").Handler(http.StripPrefix("/media", fsMedia))
|
||||
indexLessRouter.PathPrefix("/media/").Handler(http.StripPrefix("/media", fsMedia))
|
||||
}
|
||||
|
||||
staticRouter.PathPrefix("/if/help/").Handler(http.StripPrefix("/if/help/", http.FileServer(http.Dir("./website/help/"))))
|
||||
staticRouter.PathPrefix("/help").Handler(http.RedirectHandler("/if/help/", http.StatusMovedPermanently))
|
||||
statRouter.PathPrefix("/if/help/").Handler(http.StripPrefix("/if/help/", helpHandler))
|
||||
statRouter.PathPrefix("/help").Handler(http.RedirectHandler("/if/help/", http.StatusMovedPermanently))
|
||||
|
||||
// Static misc files
|
||||
ws.lh.Path("/robots.txt").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
rw.Header()["Content-Type"] = []string{"text/plain"}
|
||||
rw.WriteHeader(200)
|
||||
|
@ -64,7 +64,6 @@ def release_lock(cursor: Cursor):
|
||||
"""Release database lock"""
|
||||
if not LOCKED:
|
||||
return
|
||||
LOGGER.info("releasing database lock")
|
||||
cursor.execute("SELECT pg_advisory_unlock(%s)", (ADV_LOCK_UID,))
|
||||
|
||||
|
||||
|
@ -1,12 +0,0 @@
|
||||
from lifecycle.migrate import BaseMigration
|
||||
|
||||
|
||||
class Migration(BaseMigration):
|
||||
def needs_migration(self) -> bool:
|
||||
self.cur.execute(
|
||||
"SELECT schema_name FROM information_schema.schemata WHERE schema_name = 'template';"
|
||||
)
|
||||
return not bool(self.cur.rowcount)
|
||||
|
||||
def run(self):
|
||||
self.cur.execute("CREATE SCHEMA IF NOT EXISTS template; COMMIT;")
|
@ -116,7 +116,6 @@ class Migration(BaseMigration):
|
||||
host=CONFIG.get("redis.host"),
|
||||
port=6379,
|
||||
db=db,
|
||||
username=CONFIG.get("redis.username"),
|
||||
password=CONFIG.get("redis.password"),
|
||||
)
|
||||
redis.flushall()
|
||||
|
@ -19,7 +19,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-03-05 00:07+0000\n"
|
||||
"POT-Creation-Date: 2024-03-01 00:07+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: Marc Schmitt, 2024\n"
|
||||
"Language-Team: French (https://app.transifex.com/authentik/teams/119923/fr/)\n"
|
||||
@ -802,10 +802,6 @@ msgstr "Jeton du flux"
|
||||
msgid "Flow Tokens"
|
||||
msgstr "Jetons du flux"
|
||||
|
||||
#: authentik/flows/views/executor.py
|
||||
msgid "Invalid next URL"
|
||||
msgstr "URL suivante invalide"
|
||||
|
||||
#: authentik/lib/utils/time.py
|
||||
#, python-format
|
||||
msgid "%(value)s is not in the correct format of 'hours=3;minutes=1'."
|
||||
|
275
poetry.lock
generated
275
poetry.lock
generated
@ -1,4 +1,4 @@
|
||||
# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "aiohttp"
|
||||
@ -392,33 +392,33 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "black"
|
||||
version = "24.3.0"
|
||||
version = "24.2.0"
|
||||
description = "The uncompromising code formatter."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "black-24.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395"},
|
||||
{file = "black-24.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995"},
|
||||
{file = "black-24.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7"},
|
||||
{file = "black-24.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0"},
|
||||
{file = "black-24.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9"},
|
||||
{file = "black-24.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597"},
|
||||
{file = "black-24.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d"},
|
||||
{file = "black-24.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5"},
|
||||
{file = "black-24.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f"},
|
||||
{file = "black-24.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11"},
|
||||
{file = "black-24.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4"},
|
||||
{file = "black-24.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5"},
|
||||
{file = "black-24.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837"},
|
||||
{file = "black-24.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd"},
|
||||
{file = "black-24.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213"},
|
||||
{file = "black-24.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959"},
|
||||
{file = "black-24.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb"},
|
||||
{file = "black-24.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7"},
|
||||
{file = "black-24.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7"},
|
||||
{file = "black-24.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f"},
|
||||
{file = "black-24.3.0-py3-none-any.whl", hash = "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93"},
|
||||
{file = "black-24.3.0.tar.gz", hash = "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f"},
|
||||
{file = "black-24.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6981eae48b3b33399c8757036c7f5d48a535b962a7c2310d19361edeef64ce29"},
|
||||
{file = "black-24.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d533d5e3259720fdbc1b37444491b024003e012c5173f7d06825a77508085430"},
|
||||
{file = "black-24.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61a0391772490ddfb8a693c067df1ef5227257e72b0e4108482b8d41b5aee13f"},
|
||||
{file = "black-24.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:992e451b04667116680cb88f63449267c13e1ad134f30087dec8527242e9862a"},
|
||||
{file = "black-24.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:163baf4ef40e6897a2a9b83890e59141cc8c2a98f2dda5080dc15c00ee1e62cd"},
|
||||
{file = "black-24.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e37c99f89929af50ffaf912454b3e3b47fd64109659026b678c091a4cd450fb2"},
|
||||
{file = "black-24.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9de21bafcba9683853f6c96c2d515e364aee631b178eaa5145fc1c61a3cc92"},
|
||||
{file = "black-24.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:9db528bccb9e8e20c08e716b3b09c6bdd64da0dd129b11e160bf082d4642ac23"},
|
||||
{file = "black-24.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d84f29eb3ee44859052073b7636533ec995bd0f64e2fb43aeceefc70090e752b"},
|
||||
{file = "black-24.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e08fb9a15c914b81dd734ddd7fb10513016e5ce7e6704bdd5e1251ceee51ac9"},
|
||||
{file = "black-24.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:810d445ae6069ce64030c78ff6127cd9cd178a9ac3361435708b907d8a04c693"},
|
||||
{file = "black-24.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ba15742a13de85e9b8f3239c8f807723991fbfae24bad92d34a2b12e81904982"},
|
||||
{file = "black-24.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7e53a8c630f71db01b28cd9602a1ada68c937cbf2c333e6ed041390d6968faf4"},
|
||||
{file = "black-24.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:93601c2deb321b4bad8f95df408e3fb3943d85012dddb6121336b8e24a0d1218"},
|
||||
{file = "black-24.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0057f800de6acc4407fe75bb147b0c2b5cbb7c3ed110d3e5999cd01184d53b0"},
|
||||
{file = "black-24.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:faf2ee02e6612577ba0181f4347bcbcf591eb122f7841ae5ba233d12c39dcb4d"},
|
||||
{file = "black-24.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:057c3dc602eaa6fdc451069bd027a1b2635028b575a6c3acfd63193ced20d9c8"},
|
||||
{file = "black-24.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:08654d0797e65f2423f850fc8e16a0ce50925f9337fb4a4a176a7aa4026e63f8"},
|
||||
{file = "black-24.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca610d29415ee1a30a3f30fab7a8f4144e9d34c89a235d81292a1edb2b55f540"},
|
||||
{file = "black-24.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:4dd76e9468d5536abd40ffbc7a247f83b2324f0c050556d9c371c2b9a9a95e31"},
|
||||
{file = "black-24.2.0-py3-none-any.whl", hash = "sha256:e8a6ae970537e67830776488bca52000eaa37fa63b9988e8c487458d9cd5ace6"},
|
||||
{file = "black-24.2.0.tar.gz", hash = "sha256:bce4f25c27c3435e4dace4815bcb2008b87e167e3bf4ee47ccdc5ce906eb4894"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -455,19 +455,19 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"]
|
||||
|
||||
[[package]]
|
||||
name = "botocore"
|
||||
version = "1.34.63"
|
||||
version = "1.34.15"
|
||||
description = "Low-level, data-driven core of boto 3."
|
||||
optional = false
|
||||
python-versions = ">= 3.8"
|
||||
files = [
|
||||
{file = "botocore-1.34.63-py3-none-any.whl", hash = "sha256:8a6cbc3a5c5988725c00815f8f7f6baf81980b19d9a2ee414b031e726759dba9"},
|
||||
{file = "botocore-1.34.63.tar.gz", hash = "sha256:2237743fc3ed68319bc358b451e7c13a02110242b1522b839806fd64fcee45fb"},
|
||||
{file = "botocore-1.34.15-py3-none-any.whl", hash = "sha256:16bcf871e67ef0177593f06e9e5bae4db51c9a9a2e953cb14feeb42d53441a85"},
|
||||
{file = "botocore-1.34.15.tar.gz", hash = "sha256:c3c3404962a6d9d5e1634bd70ed53b8eff1ff17ee9d7a6240e9e8c94db48ad6f"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
jmespath = ">=0.7.1,<2.0.0"
|
||||
python-dateutil = ">=2.1,<3.0.0"
|
||||
urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""}
|
||||
urllib3 = {version = ">=1.25.4,<2.1", markers = "python_version >= \"3.10\""}
|
||||
|
||||
[package.extras]
|
||||
crt = ["awscrt (==0.19.19)"]
|
||||
@ -919,63 +919,63 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "coverage"
|
||||
version = "7.4.4"
|
||||
version = "7.4.3"
|
||||
description = "Code coverage measurement for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "coverage-7.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0be5efd5127542ef31f165de269f77560d6cdef525fffa446de6f7e9186cfb2"},
|
||||
{file = "coverage-7.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ccd341521be3d1b3daeb41960ae94a5e87abe2f46f17224ba5d6f2b8398016cf"},
|
||||
{file = "coverage-7.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fa497a8ab37784fbb20ab699c246053ac294d13fc7eb40ec007a5043ec91f8"},
|
||||
{file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1a93009cb80730c9bca5d6d4665494b725b6e8e157c1cb7f2db5b4b122ea562"},
|
||||
{file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2"},
|
||||
{file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:09c3255458533cb76ef55da8cc49ffab9e33f083739c8bd4f58e79fecfe288f7"},
|
||||
{file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ce1415194b4a6bd0cdcc3a1dfbf58b63f910dcb7330fe15bdff542c56949f87"},
|
||||
{file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b91cbc4b195444e7e258ba27ac33769c41b94967919f10037e6355e998af255c"},
|
||||
{file = "coverage-7.4.4-cp310-cp310-win32.whl", hash = "sha256:598825b51b81c808cb6f078dcb972f96af96b078faa47af7dfcdf282835baa8d"},
|
||||
{file = "coverage-7.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:09ef9199ed6653989ebbcaacc9b62b514bb63ea2f90256e71fea3ed74bd8ff6f"},
|
||||
{file = "coverage-7.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f9f50e7ef2a71e2fae92774c99170eb8304e3fdf9c8c3c7ae9bab3e7229c5cf"},
|
||||
{file = "coverage-7.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:623512f8ba53c422fcfb2ce68362c97945095b864cda94a92edbaf5994201083"},
|
||||
{file = "coverage-7.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0513b9508b93da4e1716744ef6ebc507aff016ba115ffe8ecff744d1322a7b63"},
|
||||
{file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40209e141059b9370a2657c9b15607815359ab3ef9918f0196b6fccce8d3230f"},
|
||||
{file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a2b2b78c78293782fd3767d53e6474582f62443d0504b1554370bde86cc8227"},
|
||||
{file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:73bfb9c09951125d06ee473bed216e2c3742f530fc5acc1383883125de76d9cd"},
|
||||
{file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f384c3cc76aeedce208643697fb3e8437604b512255de6d18dae3f27655a384"},
|
||||
{file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:54eb8d1bf7cacfbf2a3186019bcf01d11c666bd495ed18717162f7eb1e9dd00b"},
|
||||
{file = "coverage-7.4.4-cp311-cp311-win32.whl", hash = "sha256:cac99918c7bba15302a2d81f0312c08054a3359eaa1929c7e4b26ebe41e9b286"},
|
||||
{file = "coverage-7.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:b14706df8b2de49869ae03a5ccbc211f4041750cd4a66f698df89d44f4bd30ec"},
|
||||
{file = "coverage-7.4.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76"},
|
||||
{file = "coverage-7.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818"},
|
||||
{file = "coverage-7.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978"},
|
||||
{file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70"},
|
||||
{file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51"},
|
||||
{file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c"},
|
||||
{file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48"},
|
||||
{file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9"},
|
||||
{file = "coverage-7.4.4-cp312-cp312-win32.whl", hash = "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0"},
|
||||
{file = "coverage-7.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e"},
|
||||
{file = "coverage-7.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5ae728ff3b5401cc320d792866987e7e7e880e6ebd24433b70a33b643bb0384"},
|
||||
{file = "coverage-7.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc4f1358cb0c78edef3ed237ef2c86056206bb8d9140e73b6b89fbcfcbdd40e1"},
|
||||
{file = "coverage-7.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8130a2aa2acb8788e0b56938786c33c7c98562697bf9f4c7d6e8e5e3a0501e4a"},
|
||||
{file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf271892d13e43bc2b51e6908ec9a6a5094a4df1d8af0bfc360088ee6c684409"},
|
||||
{file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4cdc86d54b5da0df6d3d3a2f0b710949286094c3a6700c21e9015932b81447e"},
|
||||
{file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae71e7ddb7a413dd60052e90528f2f65270aad4b509563af6d03d53e979feafd"},
|
||||
{file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:38dd60d7bf242c4ed5b38e094baf6401faa114fc09e9e6632374388a404f98e7"},
|
||||
{file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa5b1c1bfc28384f1f53b69a023d789f72b2e0ab1b3787aae16992a7ca21056c"},
|
||||
{file = "coverage-7.4.4-cp38-cp38-win32.whl", hash = "sha256:dfa8fe35a0bb90382837b238fff375de15f0dcdb9ae68ff85f7a63649c98527e"},
|
||||
{file = "coverage-7.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:b2991665420a803495e0b90a79233c1433d6ed77ef282e8e152a324bbbc5e0c8"},
|
||||
{file = "coverage-7.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b799445b9f7ee8bf299cfaed6f5b226c0037b74886a4e11515e569b36fe310d"},
|
||||
{file = "coverage-7.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b4d33f418f46362995f1e9d4f3a35a1b6322cb959c31d88ae56b0298e1c22357"},
|
||||
{file = "coverage-7.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aadacf9a2f407a4688d700e4ebab33a7e2e408f2ca04dbf4aef17585389eff3e"},
|
||||
{file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c95949560050d04d46b919301826525597f07b33beba6187d04fa64d47ac82e"},
|
||||
{file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff7687ca3d7028d8a5f0ebae95a6e4827c5616b31a4ee1192bdfde697db110d4"},
|
||||
{file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5fc1de20b2d4a061b3df27ab9b7c7111e9a710f10dc2b84d33a4ab25065994ec"},
|
||||
{file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c74880fc64d4958159fbd537a091d2a585448a8f8508bf248d72112723974cbd"},
|
||||
{file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:742a76a12aa45b44d236815d282b03cfb1de3b4323f3e4ec933acfae08e54ade"},
|
||||
{file = "coverage-7.4.4-cp39-cp39-win32.whl", hash = "sha256:d89d7b2974cae412400e88f35d86af72208e1ede1a541954af5d944a8ba46c57"},
|
||||
{file = "coverage-7.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:9ca28a302acb19b6af89e90f33ee3e1906961f94b54ea37de6737b7ca9d8827c"},
|
||||
{file = "coverage-7.4.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:b2c5edc4ac10a7ef6605a966c58929ec6c1bd0917fb8c15cb3363f65aa40e677"},
|
||||
{file = "coverage-7.4.4.tar.gz", hash = "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49"},
|
||||
{file = "coverage-7.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8580b827d4746d47294c0e0b92854c85a92c2227927433998f0d3320ae8a71b6"},
|
||||
{file = "coverage-7.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:718187eeb9849fc6cc23e0d9b092bc2348821c5e1a901c9f8975df0bc785bfd4"},
|
||||
{file = "coverage-7.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:767b35c3a246bcb55b8044fd3a43b8cd553dd1f9f2c1eeb87a302b1f8daa0524"},
|
||||
{file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae7f19afe0cce50039e2c782bff379c7e347cba335429678450b8fe81c4ef96d"},
|
||||
{file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba3a8aaed13770e970b3df46980cb068d1c24af1a1968b7818b69af8c4347efb"},
|
||||
{file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ee866acc0861caebb4f2ab79f0b94dbfbdbfadc19f82e6e9c93930f74e11d7a0"},
|
||||
{file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:506edb1dd49e13a2d4cac6a5173317b82a23c9d6e8df63efb4f0380de0fbccbc"},
|
||||
{file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd6545d97c98a192c5ac995d21c894b581f1fd14cf389be90724d21808b657e2"},
|
||||
{file = "coverage-7.4.3-cp310-cp310-win32.whl", hash = "sha256:f6a09b360d67e589236a44f0c39218a8efba2593b6abdccc300a8862cffc2f94"},
|
||||
{file = "coverage-7.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:18d90523ce7553dd0b7e23cbb28865db23cddfd683a38fb224115f7826de78d0"},
|
||||
{file = "coverage-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbbe5e739d45a52f3200a771c6d2c7acf89eb2524890a4a3aa1a7fa0695d2a47"},
|
||||
{file = "coverage-7.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:489763b2d037b164846ebac0cbd368b8a4ca56385c4090807ff9fad817de4113"},
|
||||
{file = "coverage-7.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:451f433ad901b3bb00184d83fd83d135fb682d780b38af7944c9faeecb1e0bfe"},
|
||||
{file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcc66e222cf4c719fe7722a403888b1f5e1682d1679bd780e2b26c18bb648cdc"},
|
||||
{file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3ec74cfef2d985e145baae90d9b1b32f85e1741b04cd967aaf9cfa84c1334f3"},
|
||||
{file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:abbbd8093c5229c72d4c2926afaee0e6e3140de69d5dcd918b2921f2f0c8baba"},
|
||||
{file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:35eb581efdacf7b7422af677b92170da4ef34500467381e805944a3201df2079"},
|
||||
{file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8249b1c7334be8f8c3abcaaa996e1e4927b0e5a23b65f5bf6cfe3180d8ca7840"},
|
||||
{file = "coverage-7.4.3-cp311-cp311-win32.whl", hash = "sha256:cf30900aa1ba595312ae41978b95e256e419d8a823af79ce670835409fc02ad3"},
|
||||
{file = "coverage-7.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:18c7320695c949de11a351742ee001849912fd57e62a706d83dfc1581897fa2e"},
|
||||
{file = "coverage-7.4.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b51bfc348925e92a9bd9b2e48dad13431b57011fd1038f08316e6bf1df107d10"},
|
||||
{file = "coverage-7.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d6cdecaedea1ea9e033d8adf6a0ab11107b49571bbb9737175444cea6eb72328"},
|
||||
{file = "coverage-7.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b2eccb883368f9e972e216c7b4c7c06cabda925b5f06dde0650281cb7666a30"},
|
||||
{file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c00cdc8fa4e50e1cc1f941a7f2e3e0f26cb2a1233c9696f26963ff58445bac7"},
|
||||
{file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a4a8dd3dcf4cbd3165737358e4d7dfbd9d59902ad11e3b15eebb6393b0446e"},
|
||||
{file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:062b0a75d9261e2f9c6d071753f7eef0fc9caf3a2c82d36d76667ba7b6470003"},
|
||||
{file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ebe7c9e67a2d15fa97b77ea6571ce5e1e1f6b0db71d1d5e96f8d2bf134303c1d"},
|
||||
{file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c0a120238dd71c68484f02562f6d446d736adcc6ca0993712289b102705a9a3a"},
|
||||
{file = "coverage-7.4.3-cp312-cp312-win32.whl", hash = "sha256:37389611ba54fd6d278fde86eb2c013c8e50232e38f5c68235d09d0a3f8aa352"},
|
||||
{file = "coverage-7.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:d25b937a5d9ffa857d41be042b4238dd61db888533b53bc76dc082cb5a15e914"},
|
||||
{file = "coverage-7.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:28ca2098939eabab044ad68850aac8f8db6bf0b29bc7f2887d05889b17346454"},
|
||||
{file = "coverage-7.4.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:280459f0a03cecbe8800786cdc23067a8fc64c0bd51dc614008d9c36e1659d7e"},
|
||||
{file = "coverage-7.4.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c0cdedd3500e0511eac1517bf560149764b7d8e65cb800d8bf1c63ebf39edd2"},
|
||||
{file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a9babb9466fe1da12417a4aed923e90124a534736de6201794a3aea9d98484e"},
|
||||
{file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dec9de46a33cf2dd87a5254af095a409ea3bf952d85ad339751e7de6d962cde6"},
|
||||
{file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:16bae383a9cc5abab9bb05c10a3e5a52e0a788325dc9ba8499e821885928968c"},
|
||||
{file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2c854ce44e1ee31bda4e318af1dbcfc929026d12c5ed030095ad98197eeeaed0"},
|
||||
{file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ce8c50520f57ec57aa21a63ea4f325c7b657386b3f02ccaedeccf9ebe27686e1"},
|
||||
{file = "coverage-7.4.3-cp38-cp38-win32.whl", hash = "sha256:708a3369dcf055c00ddeeaa2b20f0dd1ce664eeabde6623e516c5228b753654f"},
|
||||
{file = "coverage-7.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:1bf25fbca0c8d121a3e92a2a0555c7e5bc981aee5c3fdaf4bb7809f410f696b9"},
|
||||
{file = "coverage-7.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b253094dbe1b431d3a4ac2f053b6d7ede2664ac559705a704f621742e034f1f"},
|
||||
{file = "coverage-7.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77fbfc5720cceac9c200054b9fab50cb2a7d79660609200ab83f5db96162d20c"},
|
||||
{file = "coverage-7.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6679060424faa9c11808598504c3ab472de4531c571ab2befa32f4971835788e"},
|
||||
{file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4af154d617c875b52651dd8dd17a31270c495082f3d55f6128e7629658d63765"},
|
||||
{file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8640f1fde5e1b8e3439fe482cdc2b0bb6c329f4bb161927c28d2e8879c6029ee"},
|
||||
{file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:69b9f6f66c0af29642e73a520b6fed25ff9fd69a25975ebe6acb297234eda501"},
|
||||
{file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0842571634f39016a6c03e9d4aba502be652a6e4455fadb73cd3a3a49173e38f"},
|
||||
{file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a78ed23b08e8ab524551f52953a8a05d61c3a760781762aac49f8de6eede8c45"},
|
||||
{file = "coverage-7.4.3-cp39-cp39-win32.whl", hash = "sha256:c0524de3ff096e15fcbfe8f056fdb4ea0bf497d584454f344d59fce069d3e6e9"},
|
||||
{file = "coverage-7.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:0209a6369ccce576b43bb227dc8322d8ef9e323d089c6f3f26a597b09cb4d2aa"},
|
||||
{file = "coverage-7.4.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:7cbde573904625509a3f37b6fecea974e363460b556a627c60dc2f47e2fffa51"},
|
||||
{file = "coverage-7.4.3.tar.gz", hash = "sha256:276f6077a5c61447a48d133ed13e759c09e62aff0dc84274a68dc18660104d52"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
@ -1389,13 +1389,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "duo-client"
|
||||
version = "5.3.0"
|
||||
version = "5.2.0"
|
||||
description = "Reference client for Duo Security APIs"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "duo_client-5.3.0-py3-none-any.whl", hash = "sha256:85614bb684cef96285268aef0c1e858df939f6e8a190fb2c707d700bb0215766"},
|
||||
{file = "duo_client-5.3.0.tar.gz", hash = "sha256:afa5ef98a42f06965a2702ca41dba9c85c483abd945e0a440f0ec4871b7593bf"},
|
||||
{file = "duo_client-5.2.0-py3-none-any.whl", hash = "sha256:da3237e34300665c40ba5215f1e6656fec1a0136295917541aa973e7fcbf027e"},
|
||||
{file = "duo_client-5.2.0.tar.gz", hash = "sha256:f82361740792b06303f9721e7ba593916080461769396b4f73c0502c0bfcee44"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -1712,13 +1712,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "importlib-metadata"
|
||||
version = "7.1.0"
|
||||
version = "7.0.2"
|
||||
description = "Read metadata from Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"},
|
||||
{file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"},
|
||||
{file = "importlib_metadata-7.0.2-py3-none-any.whl", hash = "sha256:f4bc4c0c070c490abf4ce96d715f68e95923320370efb66143df00199bb6c100"},
|
||||
{file = "importlib_metadata-7.0.2.tar.gz", hash = "sha256:198f568f3230878cb1b44fbd7975f87906c22336dba2e4a7f05278c281fbd792"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -1727,7 +1727,7 @@ zipp = ">=0.5"
|
||||
[package.extras]
|
||||
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
perf = ["ipython"]
|
||||
testing = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"]
|
||||
testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "incremental"
|
||||
@ -3351,13 +3351,13 @@ test = ["fixtures", "mock", "purl", "pytest", "requests-futures", "sphinx", "tes
|
||||
|
||||
[[package]]
|
||||
name = "requests-oauthlib"
|
||||
version = "2.0.0"
|
||||
version = "1.4.0"
|
||||
description = "OAuthlib authentication support for Requests."
|
||||
optional = false
|
||||
python-versions = ">=3.4"
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
files = [
|
||||
{file = "requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9"},
|
||||
{file = "requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36"},
|
||||
{file = "requests-oauthlib-1.4.0.tar.gz", hash = "sha256:acee623221e4a39abcbb919312c8ff04bd44e7e417087fb4bd5e2a2f53d5e79a"},
|
||||
{file = "requests_oauthlib-1.4.0-py2.py3-none-any.whl", hash = "sha256:7a3130d94a17520169e38db6c8d75f2c974643788465ecc2e4b36d288bf13033"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -3509,28 +3509,28 @@ pyasn1 = ">=0.1.3"
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.3.4"
|
||||
version = "0.3.2"
|
||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "ruff-0.3.4-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:60c870a7d46efcbc8385d27ec07fe534ac32f3b251e4fc44b3cbfd9e09609ef4"},
|
||||
{file = "ruff-0.3.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6fc14fa742e1d8f24910e1fff0bd5e26d395b0e0e04cc1b15c7c5e5fe5b4af91"},
|
||||
{file = "ruff-0.3.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3ee7880f653cc03749a3bfea720cf2a192e4f884925b0cf7eecce82f0ce5854"},
|
||||
{file = "ruff-0.3.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cf133dd744f2470b347f602452a88e70dadfbe0fcfb5fd46e093d55da65f82f7"},
|
||||
{file = "ruff-0.3.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f3860057590e810c7ffea75669bdc6927bfd91e29b4baa9258fd48b540a4365"},
|
||||
{file = "ruff-0.3.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:986f2377f7cf12efac1f515fc1a5b753c000ed1e0a6de96747cdf2da20a1b369"},
|
||||
{file = "ruff-0.3.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fd98e85869603e65f554fdc5cddf0712e352fe6e61d29d5a6fe087ec82b76c"},
|
||||
{file = "ruff-0.3.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64abeed785dad51801b423fa51840b1764b35d6c461ea8caef9cf9e5e5ab34d9"},
|
||||
{file = "ruff-0.3.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df52972138318bc7546d92348a1ee58449bc3f9eaf0db278906eb511889c4b50"},
|
||||
{file = "ruff-0.3.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:98e98300056445ba2cc27d0b325fd044dc17fcc38e4e4d2c7711585bd0a958ed"},
|
||||
{file = "ruff-0.3.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:519cf6a0ebed244dce1dc8aecd3dc99add7a2ee15bb68cf19588bb5bf58e0488"},
|
||||
{file = "ruff-0.3.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:bb0acfb921030d00070539c038cd24bb1df73a2981e9f55942514af8b17be94e"},
|
||||
{file = "ruff-0.3.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:cf187a7e7098233d0d0c71175375c5162f880126c4c716fa28a8ac418dcf3378"},
|
||||
{file = "ruff-0.3.4-py3-none-win32.whl", hash = "sha256:af27ac187c0a331e8ef91d84bf1c3c6a5dea97e912a7560ac0cef25c526a4102"},
|
||||
{file = "ruff-0.3.4-py3-none-win_amd64.whl", hash = "sha256:de0d5069b165e5a32b3c6ffbb81c350b1e3d3483347196ffdf86dc0ef9e37dd6"},
|
||||
{file = "ruff-0.3.4-py3-none-win_arm64.whl", hash = "sha256:6810563cc08ad0096b57c717bd78aeac888a1bfd38654d9113cb3dc4d3f74232"},
|
||||
{file = "ruff-0.3.4.tar.gz", hash = "sha256:f0f4484c6541a99862b693e13a151435a279b271cff20e37101116a21e2a1ad1"},
|
||||
{file = "ruff-0.3.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:77f2612752e25f730da7421ca5e3147b213dca4f9a0f7e0b534e9562c5441f01"},
|
||||
{file = "ruff-0.3.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9966b964b2dd1107797be9ca7195002b874424d1d5472097701ae8f43eadef5d"},
|
||||
{file = "ruff-0.3.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b83d17ff166aa0659d1e1deaf9f2f14cbe387293a906de09bc4860717eb2e2da"},
|
||||
{file = "ruff-0.3.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb875c6cc87b3703aeda85f01c9aebdce3d217aeaca3c2e52e38077383f7268a"},
|
||||
{file = "ruff-0.3.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be75e468a6a86426430373d81c041b7605137a28f7014a72d2fc749e47f572aa"},
|
||||
{file = "ruff-0.3.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:967978ac2d4506255e2f52afe70dda023fc602b283e97685c8447d036863a302"},
|
||||
{file = "ruff-0.3.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1231eacd4510f73222940727ac927bc5d07667a86b0cbe822024dd00343e77e9"},
|
||||
{file = "ruff-0.3.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2c6d613b19e9a8021be2ee1d0e27710208d1603b56f47203d0abbde906929a9b"},
|
||||
{file = "ruff-0.3.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8439338a6303585d27b66b4626cbde89bb3e50fa3cae86ce52c1db7449330a7"},
|
||||
{file = "ruff-0.3.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:de8b480d8379620cbb5ea466a9e53bb467d2fb07c7eca54a4aa8576483c35d36"},
|
||||
{file = "ruff-0.3.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b74c3de9103bd35df2bb05d8b2899bf2dbe4efda6474ea9681280648ec4d237d"},
|
||||
{file = "ruff-0.3.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f380be9fc15a99765c9cf316b40b9da1f6ad2ab9639e551703e581a5e6da6745"},
|
||||
{file = "ruff-0.3.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0ac06a3759c3ab9ef86bbeca665d31ad3aa9a4b1c17684aadb7e61c10baa0df4"},
|
||||
{file = "ruff-0.3.2-py3-none-win32.whl", hash = "sha256:9bd640a8f7dd07a0b6901fcebccedadeb1a705a50350fb86b4003b805c81385a"},
|
||||
{file = "ruff-0.3.2-py3-none-win_amd64.whl", hash = "sha256:0c1bdd9920cab5707c26c8b3bf33a064a4ca7842d91a99ec0634fec68f9f4037"},
|
||||
{file = "ruff-0.3.2-py3-none-win_arm64.whl", hash = "sha256:5f65103b1d76e0d600cabd577b04179ff592064eaa451a70a81085930e907d0b"},
|
||||
{file = "ruff-0.3.2.tar.gz", hash = "sha256:fa78ec9418eb1ca3db392811df3376b46471ae93792a81af2d1cbb0e5dcb5142"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3570,13 +3570,13 @@ urllib3 = {version = ">=1.26,<3", extras = ["socks"]}
|
||||
|
||||
[[package]]
|
||||
name = "sentry-sdk"
|
||||
version = "1.43.0"
|
||||
version = "1.41.0"
|
||||
description = "Python client for Sentry (https://sentry.io)"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "sentry-sdk-1.43.0.tar.gz", hash = "sha256:41df73af89d22921d8733714fb0fc5586c3461907e06688e6537d01a27e0e0f6"},
|
||||
{file = "sentry_sdk-1.43.0-py2.py3-none-any.whl", hash = "sha256:8d768724839ca18d7b4c7463ef7528c40b7aa2bfbf7fe554d5f9a7c044acfd36"},
|
||||
{file = "sentry-sdk-1.41.0.tar.gz", hash = "sha256:4f2d6c43c07925d8cd10dfbd0970ea7cb784f70e79523cca9dbcd72df38e5a46"},
|
||||
{file = "sentry_sdk-1.41.0-py2.py3-none-any.whl", hash = "sha256:be4f8f4b29a80b6a3b71f0f31487beb9e296391da20af8504498a328befed53f"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -3590,7 +3590,6 @@ asyncpg = ["asyncpg (>=0.23)"]
|
||||
beam = ["apache-beam (>=2.12)"]
|
||||
bottle = ["bottle (>=0.12.13)"]
|
||||
celery = ["celery (>=3)"]
|
||||
celery-redbeat = ["celery-redbeat (>=2)"]
|
||||
chalice = ["chalice (>=1.16.0)"]
|
||||
clickhouse-driver = ["clickhouse-driver (>=0.2.0)"]
|
||||
django = ["django (>=1.8)"]
|
||||
@ -3601,7 +3600,6 @@ grpcio = ["grpcio (>=1.21.1)"]
|
||||
httpx = ["httpx (>=0.16.0)"]
|
||||
huey = ["huey (>=2)"]
|
||||
loguru = ["loguru (>=0.5)"]
|
||||
openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"]
|
||||
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"]
|
||||
@ -3820,13 +3818,13 @@ wsproto = ">=0.14"
|
||||
|
||||
[[package]]
|
||||
name = "twilio"
|
||||
version = "9.0.2"
|
||||
version = "9.0.1"
|
||||
description = "Twilio API client and TwiML generator"
|
||||
optional = false
|
||||
python-versions = ">=3.7.0"
|
||||
files = [
|
||||
{file = "twilio-9.0.2-py2.py3-none-any.whl", hash = "sha256:db89a8326f92240cdd8dc1dafb1d3f69169576243be9b9cbf5cf7778ecab0eed"},
|
||||
{file = "twilio-9.0.2.tar.gz", hash = "sha256:9450b7a9987c32146d1760c8680f92baa76b4ba570543758a4937da48ae46d77"},
|
||||
{file = "twilio-9.0.1-py2.py3-none-any.whl", hash = "sha256:7df45f314140b5931199420a2a00f0466d2fd16aff2f8c3e1589a47adc9deecb"},
|
||||
{file = "twilio-9.0.1.tar.gz", hash = "sha256:4ffb63342dff9a5b24dd3f8d33e8fac2ceb55dcd10936d50456cbb44e1834e72"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -3964,33 +3962,48 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "2.2.1"
|
||||
version = "1.26.18"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
||||
files = [
|
||||
{file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"},
|
||||
{file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"},
|
||||
{file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"},
|
||||
{file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pysocks = {version = ">=1.5.6,<1.5.7 || >1.5.7,<2.0", optional = true, markers = "extra == \"socks\""}
|
||||
certifi = {version = "*", optional = true, markers = "extra == \"secure\""}
|
||||
cryptography = {version = ">=1.3.4", optional = true, markers = "extra == \"secure\""}
|
||||
idna = {version = ">=2.0.0", optional = true, markers = "extra == \"secure\""}
|
||||
pyOpenSSL = {version = ">=0.14", optional = true, markers = "extra == \"secure\""}
|
||||
PySocks = {version = ">=1.5.6,<1.5.7 || >1.5.7,<2.0", optional = true, markers = "extra == \"socks\""}
|
||||
urllib3-secure-extra = {version = "*", optional = true, markers = "extra == \"secure\""}
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
|
||||
h2 = ["h2 (>=4,<5)"]
|
||||
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
zstd = ["zstandard (>=0.18.0)"]
|
||||
brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
|
||||
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "urllib3-secure-extra"
|
||||
version = "0.1.0"
|
||||
description = "Marker library to detect whether urllib3 was installed with the deprecated [secure] extra"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "urllib3-secure-extra-0.1.0.tar.gz", hash = "sha256:ee9409cbfeb4b8609047be4c32fb4317870c602767e53fd8a41005ebe6a41dff"},
|
||||
{file = "urllib3_secure_extra-0.1.0-py2.py3-none-any.whl", hash = "sha256:f7adcb108b4d12a4b26b99eb60e265d087f435052a76aefa396b6ee85e9a6ef9"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uvicorn"
|
||||
version = "0.29.0"
|
||||
version = "0.28.0"
|
||||
description = "The lightning-fast ASGI server."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "uvicorn-0.29.0-py3-none-any.whl", hash = "sha256:2c2aac7ff4f4365c206fd773a39bf4ebd1047c238f8b8268ad996829323473de"},
|
||||
{file = "uvicorn-0.29.0.tar.gz", hash = "sha256:6a69214c0b6a087462412670b3ef21224fa48cae0e452b5883e8e8bdfdd11dd0"},
|
||||
{file = "uvicorn-0.28.0-py3-none-any.whl", hash = "sha256:6623abbbe6176204a4226e67607b4d52cc60ff62cda0ff177613645cefa2ece1"},
|
||||
{file = "uvicorn-0.28.0.tar.gz", hash = "sha256:cab4473b5d1eaeb5a0f6375ac4bc85007ffc75c3cc1768816d9e5d589857b067"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -4538,4 +4551,4 @@ files = [
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "~3.12"
|
||||
content-hash = "04ef13e2692c158e5eda1e89876a215746c56a891a161d8434d808dc12c0fc7a"
|
||||
content-hash = "825f1d552ba34206f7bfd55b70bfb42bc5d769605f59410703828ae787cd0baf"
|
||||
|
@ -140,7 +140,7 @@ twilio = "*"
|
||||
twisted = "*"
|
||||
ua-parser = "*"
|
||||
# Pinned because of botocore https://github.com/orgs/python-poetry/discussions/7937
|
||||
urllib3 = { extras = ["secure"], version = "<3" }
|
||||
urllib3 = { extras = ["secure"], version = "<2" }
|
||||
uvicorn = { extras = ["standard"], version = "*" }
|
||||
watchdog = "*"
|
||||
webauthn = "*"
|
||||
|
473
schema.yml
473
schema.yml
@ -18512,7 +18512,6 @@ paths:
|
||||
- authentik_stages_password.passwordstage
|
||||
- authentik_stages_prompt.prompt
|
||||
- authentik_stages_prompt.promptstage
|
||||
- authentik_stages_source.sourcestage
|
||||
- authentik_stages_user_delete.userdeletestage
|
||||
- authentik_stages_user_login.userloginstage
|
||||
- authentik_stages_user_logout.userlogoutstage
|
||||
@ -18588,7 +18587,6 @@ paths:
|
||||
* `authentik_providers_rac.racprovider` - RAC Provider
|
||||
* `authentik_providers_rac.endpoint` - RAC Endpoint
|
||||
* `authentik_providers_rac.racpropertymapping` - RAC Property Mapping
|
||||
* `authentik_stages_source.sourcestage` - Source Stage
|
||||
* `authentik_events.event` - Event
|
||||
* `authentik_events.notificationtransport` - Notification Transport
|
||||
* `authentik_events.notification` - Notification
|
||||
@ -18802,7 +18800,6 @@ paths:
|
||||
- authentik_stages_password.passwordstage
|
||||
- authentik_stages_prompt.prompt
|
||||
- authentik_stages_prompt.promptstage
|
||||
- authentik_stages_source.sourcestage
|
||||
- authentik_stages_user_delete.userdeletestage
|
||||
- authentik_stages_user_login.userloginstage
|
||||
- authentik_stages_user_logout.userlogoutstage
|
||||
@ -18878,7 +18875,6 @@ paths:
|
||||
* `authentik_providers_rac.racprovider` - RAC Provider
|
||||
* `authentik_providers_rac.endpoint` - RAC Endpoint
|
||||
* `authentik_providers_rac.racpropertymapping` - RAC Property Mapping
|
||||
* `authentik_stages_source.sourcestage` - Source Stage
|
||||
* `authentik_events.event` - Event
|
||||
* `authentik_events.notificationtransport` - Notification Transport
|
||||
* `authentik_events.notification` - Notification
|
||||
@ -19926,10 +19922,6 @@ paths:
|
||||
description: Number of results to return per page.
|
||||
schema:
|
||||
type: integer
|
||||
- in: query
|
||||
name: password_login_update_internal_password
|
||||
schema:
|
||||
type: boolean
|
||||
- in: query
|
||||
name: peer_certificate
|
||||
schema:
|
||||
@ -27880,289 +27872,6 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
/stages/source/:
|
||||
get:
|
||||
operationId: stages_source_list
|
||||
description: SourceStage Viewset
|
||||
parameters:
|
||||
- in: query
|
||||
name: name
|
||||
schema:
|
||||
type: string
|
||||
- name: ordering
|
||||
required: false
|
||||
in: query
|
||||
description: Which field to use when ordering the results.
|
||||
schema:
|
||||
type: string
|
||||
- name: page
|
||||
required: false
|
||||
in: query
|
||||
description: A page number within the paginated result set.
|
||||
schema:
|
||||
type: integer
|
||||
- name: page_size
|
||||
required: false
|
||||
in: query
|
||||
description: Number of results to return per page.
|
||||
schema:
|
||||
type: integer
|
||||
- in: query
|
||||
name: resume_timeout
|
||||
schema:
|
||||
type: string
|
||||
- name: search
|
||||
required: false
|
||||
in: query
|
||||
description: A search term.
|
||||
schema:
|
||||
type: string
|
||||
- in: query
|
||||
name: source
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
- in: query
|
||||
name: stage_uuid
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
tags:
|
||||
- stages
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PaginatedSourceStageList'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
post:
|
||||
operationId: stages_source_create
|
||||
description: SourceStage Viewset
|
||||
tags:
|
||||
- stages
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SourceStageRequest'
|
||||
required: true
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'201':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SourceStage'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
/stages/source/{stage_uuid}/:
|
||||
get:
|
||||
operationId: stages_source_retrieve
|
||||
description: SourceStage Viewset
|
||||
parameters:
|
||||
- in: path
|
||||
name: stage_uuid
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this Source Stage.
|
||||
required: true
|
||||
tags:
|
||||
- stages
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SourceStage'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
put:
|
||||
operationId: stages_source_update
|
||||
description: SourceStage Viewset
|
||||
parameters:
|
||||
- in: path
|
||||
name: stage_uuid
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this Source Stage.
|
||||
required: true
|
||||
tags:
|
||||
- stages
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SourceStageRequest'
|
||||
required: true
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SourceStage'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
patch:
|
||||
operationId: stages_source_partial_update
|
||||
description: SourceStage Viewset
|
||||
parameters:
|
||||
- in: path
|
||||
name: stage_uuid
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this Source Stage.
|
||||
required: true
|
||||
tags:
|
||||
- stages
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PatchedSourceStageRequest'
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SourceStage'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
delete:
|
||||
operationId: stages_source_destroy
|
||||
description: SourceStage Viewset
|
||||
parameters:
|
||||
- in: path
|
||||
name: stage_uuid
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this Source Stage.
|
||||
required: true
|
||||
tags:
|
||||
- stages
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'204':
|
||||
description: No response body
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
/stages/source/{stage_uuid}/used_by/:
|
||||
get:
|
||||
operationId: stages_source_used_by_list
|
||||
description: Get a list of all objects that use this object
|
||||
parameters:
|
||||
- in: path
|
||||
name: stage_uuid
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this Source Stage.
|
||||
required: true
|
||||
tags:
|
||||
- stages
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/UsedBy'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
/stages/user_delete/:
|
||||
get:
|
||||
operationId: stages_user_delete_list
|
||||
@ -29933,7 +29642,6 @@ components:
|
||||
- authentik.enterprise
|
||||
- authentik.enterprise.audit
|
||||
- authentik.enterprise.providers.rac
|
||||
- authentik.enterprise.stages.source
|
||||
- authentik.events
|
||||
type: string
|
||||
description: |-
|
||||
@ -29988,7 +29696,6 @@ components:
|
||||
* `authentik.enterprise` - authentik Enterprise
|
||||
* `authentik.enterprise.audit` - authentik Enterprise.Audit
|
||||
* `authentik.enterprise.providers.rac` - authentik Enterprise.Providers.RAC
|
||||
* `authentik.enterprise.stages.source` - authentik Enterprise.Stages.Source
|
||||
* `authentik.events` - authentik Events
|
||||
AppleChallengeResponseRequest:
|
||||
type: object
|
||||
@ -31334,10 +31041,6 @@ components:
|
||||
type: string
|
||||
description: Domain that activates this brand. Can be a superset, i.e. `a.b`
|
||||
for `aa.b` and `ba.b`
|
||||
origin:
|
||||
type: string
|
||||
description: Origin domain that activates this brand. Can be left empty
|
||||
to not allow any origins.
|
||||
default:
|
||||
type: boolean
|
||||
branding_title:
|
||||
@ -31370,12 +31073,6 @@ components:
|
||||
type: string
|
||||
format: uuid
|
||||
nullable: true
|
||||
default_application:
|
||||
type: string
|
||||
format: uuid
|
||||
nullable: true
|
||||
description: When set, external users will be redirected to this application
|
||||
after authenticating.
|
||||
web_certificate:
|
||||
type: string
|
||||
format: uuid
|
||||
@ -31394,10 +31091,6 @@ components:
|
||||
minLength: 1
|
||||
description: Domain that activates this brand. Can be a superset, i.e. `a.b`
|
||||
for `aa.b` and `ba.b`
|
||||
origin:
|
||||
type: string
|
||||
description: Origin domain that activates this brand. Can be left empty
|
||||
to not allow any origins.
|
||||
default:
|
||||
type: boolean
|
||||
branding_title:
|
||||
@ -31433,12 +31126,6 @@ components:
|
||||
type: string
|
||||
format: uuid
|
||||
nullable: true
|
||||
default_application:
|
||||
type: string
|
||||
format: uuid
|
||||
nullable: true
|
||||
description: When set, external users will be redirected to this application
|
||||
after authenticating.
|
||||
web_certificate:
|
||||
type: string
|
||||
format: uuid
|
||||
@ -31806,7 +31493,8 @@ components:
|
||||
pk:
|
||||
type: string
|
||||
format: uuid
|
||||
title: Connection token uuid
|
||||
readOnly: true
|
||||
title: Pbm uuid
|
||||
provider:
|
||||
type: integer
|
||||
provider_obj:
|
||||
@ -31816,6 +31504,7 @@ components:
|
||||
endpoint:
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
endpoint_obj:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/Endpoint'
|
||||
@ -31827,6 +31516,7 @@ components:
|
||||
required:
|
||||
- endpoint
|
||||
- endpoint_obj
|
||||
- pk
|
||||
- provider
|
||||
- provider_obj
|
||||
- user
|
||||
@ -31834,17 +31524,9 @@ components:
|
||||
type: object
|
||||
description: ConnectionToken Serializer
|
||||
properties:
|
||||
pk:
|
||||
type: string
|
||||
format: uuid
|
||||
title: Connection token uuid
|
||||
provider:
|
||||
type: integer
|
||||
endpoint:
|
||||
type: string
|
||||
format: uuid
|
||||
required:
|
||||
- endpoint
|
||||
- provider
|
||||
ConsentChallenge:
|
||||
type: object
|
||||
@ -32375,10 +32057,7 @@ components:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ErrorDetail'
|
||||
name:
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
- type
|
||||
DummyChallengeResponseRequest:
|
||||
type: object
|
||||
@ -33060,7 +32739,6 @@ components:
|
||||
* `authentik.enterprise` - authentik Enterprise
|
||||
* `authentik.enterprise.audit` - authentik Enterprise.Audit
|
||||
* `authentik.enterprise.providers.rac` - authentik Enterprise.Providers.RAC
|
||||
* `authentik.enterprise.stages.source` - authentik Enterprise.Stages.Source
|
||||
* `authentik.events` - authentik Events
|
||||
model:
|
||||
allOf:
|
||||
@ -33138,7 +32816,6 @@ components:
|
||||
* `authentik_providers_rac.racprovider` - RAC Provider
|
||||
* `authentik_providers_rac.endpoint` - RAC Endpoint
|
||||
* `authentik_providers_rac.racpropertymapping` - RAC Property Mapping
|
||||
* `authentik_stages_source.sourcestage` - Source Stage
|
||||
* `authentik_events.event` - Event
|
||||
* `authentik_events.notificationtransport` - Notification Transport
|
||||
* `authentik_events.notification` - Notification
|
||||
@ -33261,7 +32938,6 @@ components:
|
||||
* `authentik.enterprise` - authentik Enterprise
|
||||
* `authentik.enterprise.audit` - authentik Enterprise.Audit
|
||||
* `authentik.enterprise.providers.rac` - authentik Enterprise.Providers.RAC
|
||||
* `authentik.enterprise.stages.source` - authentik Enterprise.Stages.Source
|
||||
* `authentik.events` - authentik Events
|
||||
model:
|
||||
allOf:
|
||||
@ -33339,7 +33015,6 @@ components:
|
||||
* `authentik_providers_rac.racprovider` - RAC Provider
|
||||
* `authentik_providers_rac.endpoint` - RAC Endpoint
|
||||
* `authentik_providers_rac.racpropertymapping` - RAC Property Mapping
|
||||
* `authentik_stages_source.sourcestage` - Source Stage
|
||||
* `authentik_events.event` - Event
|
||||
* `authentik_events.notificationtransport` - Notification Transport
|
||||
* `authentik_events.notification` - Notification
|
||||
@ -34361,8 +34036,6 @@ components:
|
||||
type: boolean
|
||||
application_pre:
|
||||
type: string
|
||||
flow_designation:
|
||||
$ref: '#/components/schemas/FlowDesignationEnum'
|
||||
enroll_url:
|
||||
type: string
|
||||
recovery_url:
|
||||
@ -34378,7 +34051,6 @@ components:
|
||||
show_source_labels:
|
||||
type: boolean
|
||||
required:
|
||||
- flow_designation
|
||||
- password_fields
|
||||
- primary_action
|
||||
- show_source_labels
|
||||
@ -35249,10 +34921,6 @@ components:
|
||||
object_uniqueness_field:
|
||||
type: string
|
||||
description: Field which contains a unique Identifier.
|
||||
password_login_update_internal_password:
|
||||
type: boolean
|
||||
description: Update internal authentik password when login succeeds with
|
||||
LDAP
|
||||
sync_users:
|
||||
type: boolean
|
||||
sync_users_password:
|
||||
@ -35394,10 +35062,6 @@ components:
|
||||
type: string
|
||||
minLength: 1
|
||||
description: Field which contains a unique Identifier.
|
||||
password_login_update_internal_password:
|
||||
type: boolean
|
||||
description: Update internal authentik password when login succeeds with
|
||||
LDAP
|
||||
sync_users:
|
||||
type: boolean
|
||||
sync_users_password:
|
||||
@ -35666,7 +35330,6 @@ components:
|
||||
- authentik_providers_rac.racprovider
|
||||
- authentik_providers_rac.endpoint
|
||||
- authentik_providers_rac.racpropertymapping
|
||||
- authentik_stages_source.sourcestage
|
||||
- authentik_events.event
|
||||
- authentik_events.notificationtransport
|
||||
- authentik_events.notification
|
||||
@ -35743,7 +35406,6 @@ components:
|
||||
* `authentik_providers_rac.racprovider` - RAC Provider
|
||||
* `authentik_providers_rac.endpoint` - RAC Endpoint
|
||||
* `authentik_providers_rac.racpropertymapping` - RAC Property Mapping
|
||||
* `authentik_stages_source.sourcestage` - Source Stage
|
||||
* `authentik_events.event` - Event
|
||||
* `authentik_events.notificationtransport` - Notification Transport
|
||||
* `authentik_events.notification` - Notification
|
||||
@ -37678,18 +37340,6 @@ components:
|
||||
required:
|
||||
- pagination
|
||||
- results
|
||||
PaginatedSourceStageList:
|
||||
type: object
|
||||
properties:
|
||||
pagination:
|
||||
$ref: '#/components/schemas/Pagination'
|
||||
results:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/SourceStage'
|
||||
required:
|
||||
- pagination
|
||||
- results
|
||||
PaginatedStageList:
|
||||
type: object
|
||||
properties:
|
||||
@ -38538,10 +38188,6 @@ components:
|
||||
minLength: 1
|
||||
description: Domain that activates this brand. Can be a superset, i.e. `a.b`
|
||||
for `aa.b` and `ba.b`
|
||||
origin:
|
||||
type: string
|
||||
description: Origin domain that activates this brand. Can be left empty
|
||||
to not allow any origins.
|
||||
default:
|
||||
type: boolean
|
||||
branding_title:
|
||||
@ -38577,12 +38223,6 @@ components:
|
||||
type: string
|
||||
format: uuid
|
||||
nullable: true
|
||||
default_application:
|
||||
type: string
|
||||
format: uuid
|
||||
nullable: true
|
||||
description: When set, external users will be redirected to this application
|
||||
after authenticating.
|
||||
web_certificate:
|
||||
type: string
|
||||
format: uuid
|
||||
@ -38636,15 +38276,8 @@ components:
|
||||
type: object
|
||||
description: ConnectionToken Serializer
|
||||
properties:
|
||||
pk:
|
||||
type: string
|
||||
format: uuid
|
||||
title: Connection token uuid
|
||||
provider:
|
||||
type: integer
|
||||
endpoint:
|
||||
type: string
|
||||
format: uuid
|
||||
PatchedConsentStageRequest:
|
||||
type: object
|
||||
description: ConsentStage Serializer
|
||||
@ -38950,7 +38583,6 @@ components:
|
||||
* `authentik.enterprise` - authentik Enterprise
|
||||
* `authentik.enterprise.audit` - authentik Enterprise.Audit
|
||||
* `authentik.enterprise.providers.rac` - authentik Enterprise.Providers.RAC
|
||||
* `authentik.enterprise.stages.source` - authentik Enterprise.Stages.Source
|
||||
* `authentik.events` - authentik Events
|
||||
model:
|
||||
allOf:
|
||||
@ -39028,7 +38660,6 @@ components:
|
||||
* `authentik_providers_rac.racprovider` - RAC Provider
|
||||
* `authentik_providers_rac.endpoint` - RAC Endpoint
|
||||
* `authentik_providers_rac.racpropertymapping` - RAC Property Mapping
|
||||
* `authentik_stages_source.sourcestage` - Source Stage
|
||||
* `authentik_events.event` - Event
|
||||
* `authentik_events.notificationtransport` - Notification Transport
|
||||
* `authentik_events.notification` - Notification
|
||||
@ -39482,10 +39113,6 @@ components:
|
||||
type: string
|
||||
minLength: 1
|
||||
description: Field which contains a unique Identifier.
|
||||
password_login_update_internal_password:
|
||||
type: boolean
|
||||
description: Update internal authentik password when login succeeds with
|
||||
LDAP
|
||||
sync_users:
|
||||
type: boolean
|
||||
sync_users_password:
|
||||
@ -40615,25 +40242,6 @@ components:
|
||||
impersonation:
|
||||
type: boolean
|
||||
description: Globally enable/disable impersonation.
|
||||
PatchedSourceStageRequest:
|
||||
type: object
|
||||
description: SourceStage Serializer
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
minLength: 1
|
||||
flow_set:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/FlowSetRequest'
|
||||
source:
|
||||
type: string
|
||||
format: uuid
|
||||
resume_timeout:
|
||||
type: string
|
||||
minLength: 1
|
||||
description: 'Amount of time a user can take to return from the source to
|
||||
continue the flow (Format: hours=-1;minutes=-2;seconds=-3)'
|
||||
PatchedStaticDeviceRequest:
|
||||
type: object
|
||||
description: Serializer for static authenticator devices
|
||||
@ -43978,74 +43586,6 @@ components:
|
||||
required:
|
||||
- name
|
||||
- slug
|
||||
SourceStage:
|
||||
type: object
|
||||
description: SourceStage Serializer
|
||||
properties:
|
||||
pk:
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
title: Stage uuid
|
||||
name:
|
||||
type: string
|
||||
component:
|
||||
type: string
|
||||
description: Get object type so that we know how to edit the object
|
||||
readOnly: true
|
||||
verbose_name:
|
||||
type: string
|
||||
description: Return object's verbose_name
|
||||
readOnly: true
|
||||
verbose_name_plural:
|
||||
type: string
|
||||
description: Return object's plural verbose_name
|
||||
readOnly: true
|
||||
meta_model_name:
|
||||
type: string
|
||||
description: Return internal model name
|
||||
readOnly: true
|
||||
flow_set:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/FlowSet'
|
||||
source:
|
||||
type: string
|
||||
format: uuid
|
||||
resume_timeout:
|
||||
type: string
|
||||
description: 'Amount of time a user can take to return from the source to
|
||||
continue the flow (Format: hours=-1;minutes=-2;seconds=-3)'
|
||||
required:
|
||||
- component
|
||||
- meta_model_name
|
||||
- name
|
||||
- pk
|
||||
- source
|
||||
- verbose_name
|
||||
- verbose_name_plural
|
||||
SourceStageRequest:
|
||||
type: object
|
||||
description: SourceStage Serializer
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
minLength: 1
|
||||
flow_set:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/FlowSetRequest'
|
||||
source:
|
||||
type: string
|
||||
format: uuid
|
||||
resume_timeout:
|
||||
type: string
|
||||
minLength: 1
|
||||
description: 'Amount of time a user can take to return from the source to
|
||||
continue the flow (Format: hours=-1;minutes=-2;seconds=-3)'
|
||||
required:
|
||||
- name
|
||||
- source
|
||||
SourceType:
|
||||
type: object
|
||||
description: Serializer for SourceType
|
||||
@ -45644,10 +45184,6 @@ components:
|
||||
type: string
|
||||
description: Get latest version from cache
|
||||
readOnly: true
|
||||
version_latest_valid:
|
||||
type: boolean
|
||||
description: Check if latest version is valid
|
||||
readOnly: true
|
||||
build_hash:
|
||||
type: string
|
||||
description: Get build hash, if version is not latest or released
|
||||
@ -45661,7 +45197,6 @@ components:
|
||||
- outdated
|
||||
- version_current
|
||||
- version_latest
|
||||
- version_latest_valid
|
||||
WebAuthnDevice:
|
||||
type: object
|
||||
description: Serializer for WebAuthn authenticator devices
|
||||
|
@ -128,7 +128,6 @@ class TestSourceLDAPSamba(SeleniumTestCase):
|
||||
base_dn="dc=test,dc=goauthentik,dc=io",
|
||||
additional_user_dn="ou=users",
|
||||
additional_group_dn="ou=groups",
|
||||
password_login_update_internal_password=True,
|
||||
)
|
||||
source.property_mappings.set(
|
||||
LDAPPropertyMapping.objects.filter(
|
||||
|
@ -10,7 +10,6 @@ from kubernetes.client.exceptions import OpenApiException
|
||||
from authentik.core.tests.utils import create_test_flow
|
||||
from authentik.lib.config import CONFIG
|
||||
from authentik.outposts.controllers.k8s.deployment import DeploymentReconciler
|
||||
from authentik.outposts.controllers.k8s.service import ServiceReconciler
|
||||
from authentik.outposts.controllers.k8s.triggers import NeedsUpdate
|
||||
from authentik.outposts.models import KubernetesServiceConnection, Outpost, OutpostType
|
||||
from authentik.outposts.tasks import outpost_connection_discovery
|
||||
@ -92,35 +91,6 @@ class OutpostKubernetesTests(TestCase):
|
||||
|
||||
deployment_reconciler.delete(deployment_reconciler.get_reference_object())
|
||||
|
||||
@pytest.mark.timeout(120)
|
||||
def test_service_reconciler(self):
|
||||
"""test that service requires update"""
|
||||
controller = ProxyKubernetesController(self.outpost, self.service_connection)
|
||||
service_reconciler = ServiceReconciler(controller)
|
||||
|
||||
self.assertIsNotNone(service_reconciler.retrieve())
|
||||
|
||||
config = self.outpost.config
|
||||
config.kubernetes_service_type = "NodePort"
|
||||
config.kubernetes_json_patches = {
|
||||
"service": [
|
||||
{
|
||||
"op": "add",
|
||||
"path": "/spec/ipFamilyPolicy",
|
||||
"value": "PreferDualStack",
|
||||
}
|
||||
]
|
||||
}
|
||||
self.outpost.config = config
|
||||
|
||||
with self.assertRaises(NeedsUpdate):
|
||||
service_reconciler.reconcile(
|
||||
service_reconciler.retrieve(),
|
||||
service_reconciler.get_reference_object(),
|
||||
)
|
||||
|
||||
service_reconciler.delete(service_reconciler.get_reference_object())
|
||||
|
||||
@pytest.mark.timeout(120)
|
||||
def test_controller_rename(self):
|
||||
"""test that objects get deleted and re-created with new names"""
|
||||
|
261
tests/wdio/package-lock.json
generated
261
tests/wdio/package-lock.json
generated
@ -6,15 +6,15 @@
|
||||
"": {
|
||||
"name": "@goauthentik/web-tests",
|
||||
"dependencies": {
|
||||
"chromedriver": "^123.0.0"
|
||||
"chromedriver": "^122.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
||||
"@typescript-eslint/parser": "^7.4.0",
|
||||
"@wdio/cli": "^8.35.1",
|
||||
"@wdio/local-runner": "^8.35.1",
|
||||
"@wdio/mocha-framework": "^8.35.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||
"@typescript-eslint/parser": "^7.2.0",
|
||||
"@wdio/cli": "^8.33.1",
|
||||
"@wdio/local-runner": "^8.33.1",
|
||||
"@wdio/mocha-framework": "^8.33.1",
|
||||
"@wdio/spec-reporter": "^8.32.4",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
@ -22,7 +22,7 @@
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^3.2.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.4.3",
|
||||
"typescript": "^5.4.2",
|
||||
"wdio-wait-for": "^3.0.11"
|
||||
},
|
||||
"engines": {
|
||||
@ -889,13 +889,10 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.11.28",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.28.tgz",
|
||||
"integrity": "sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
"version": "20.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.7.0.tgz",
|
||||
"integrity": "sha512-zI22/pJW2wUZOVyguFaUL1HABdmSVxpXrzIqkjsHmyUjNhPoWM1CKfvVuXfetHhIok4RY573cqS0mZ1SJEnoTg==",
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@types/normalize-package-data": {
|
||||
"version": "2.4.4",
|
||||
@ -955,16 +952,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.4.0.tgz",
|
||||
"integrity": "sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.2.0.tgz",
|
||||
"integrity": "sha512-mdekAHOqS9UjlmyF/LSs6AIEvfceV749GFxoBAjwAv0nkevfKHWQFDMcBZWUiIC5ft6ePWivXoS36aKQ0Cy3sw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.5.1",
|
||||
"@typescript-eslint/scope-manager": "7.4.0",
|
||||
"@typescript-eslint/type-utils": "7.4.0",
|
||||
"@typescript-eslint/utils": "7.4.0",
|
||||
"@typescript-eslint/visitor-keys": "7.4.0",
|
||||
"@typescript-eslint/scope-manager": "7.2.0",
|
||||
"@typescript-eslint/type-utils": "7.2.0",
|
||||
"@typescript-eslint/utils": "7.2.0",
|
||||
"@typescript-eslint/visitor-keys": "7.2.0",
|
||||
"debug": "^4.3.4",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.2.4",
|
||||
@ -973,7 +970,7 @@
|
||||
"ts-api-utils": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@ -990,19 +987,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.4.0.tgz",
|
||||
"integrity": "sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz",
|
||||
"integrity": "sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "7.4.0",
|
||||
"@typescript-eslint/types": "7.4.0",
|
||||
"@typescript-eslint/typescript-estree": "7.4.0",
|
||||
"@typescript-eslint/visitor-keys": "7.4.0",
|
||||
"@typescript-eslint/scope-manager": "7.2.0",
|
||||
"@typescript-eslint/types": "7.2.0",
|
||||
"@typescript-eslint/typescript-estree": "7.2.0",
|
||||
"@typescript-eslint/visitor-keys": "7.2.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@ -1018,16 +1015,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.4.0.tgz",
|
||||
"integrity": "sha512-68VqENG5HK27ypafqLVs8qO+RkNc7TezCduYrx8YJpXq2QGZ30vmNZGJJJC48+MVn4G2dCV8m5ZTVnzRexTVtw==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz",
|
||||
"integrity": "sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.4.0",
|
||||
"@typescript-eslint/visitor-keys": "7.4.0"
|
||||
"@typescript-eslint/types": "7.2.0",
|
||||
"@typescript-eslint/visitor-keys": "7.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@ -1035,18 +1032,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.4.0.tgz",
|
||||
"integrity": "sha512-247ETeHgr9WTRMqHbbQdzwzhuyaJ8dPTuyuUEMANqzMRB1rj/9qFIuIXK7l0FX9i9FXbHeBQl/4uz6mYuCE7Aw==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.2.0.tgz",
|
||||
"integrity": "sha512-xHi51adBHo9O9330J8GQYQwrKBqbIPJGZZVQTHHmy200hvkLZFWJIFtAG/7IYTWUyun6DE6w5InDReePJYJlJA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "7.4.0",
|
||||
"@typescript-eslint/utils": "7.4.0",
|
||||
"@typescript-eslint/typescript-estree": "7.2.0",
|
||||
"@typescript-eslint/utils": "7.2.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@ -1062,12 +1059,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.4.0.tgz",
|
||||
"integrity": "sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.2.0.tgz",
|
||||
"integrity": "sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@ -1075,13 +1072,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.4.0.tgz",
|
||||
"integrity": "sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz",
|
||||
"integrity": "sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.4.0",
|
||||
"@typescript-eslint/visitor-keys": "7.4.0",
|
||||
"@typescript-eslint/types": "7.2.0",
|
||||
"@typescript-eslint/visitor-keys": "7.2.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
@ -1090,7 +1087,7 @@
|
||||
"ts-api-utils": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@ -1127,21 +1124,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.4.0.tgz",
|
||||
"integrity": "sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.2.0.tgz",
|
||||
"integrity": "sha512-YfHpnMAGb1Eekpm3XRK8hcMwGLGsnT6L+7b2XyRv6ouDuJU1tZir1GS2i0+VXRatMwSI1/UfcyPe53ADkU+IuA==",
|
||||
"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": "7.4.0",
|
||||
"@typescript-eslint/types": "7.4.0",
|
||||
"@typescript-eslint/typescript-estree": "7.4.0",
|
||||
"@typescript-eslint/scope-manager": "7.2.0",
|
||||
"@typescript-eslint/types": "7.2.0",
|
||||
"@typescript-eslint/typescript-estree": "7.2.0",
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@ -1152,16 +1149,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.4.0.tgz",
|
||||
"integrity": "sha512-0zkC7YM0iX5Y41homUUeW1CHtZR01K3ybjM1l6QczoMuay0XKtrb93kv95AxUGwdjGr64nNqnOCwmEl616N8CA==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz",
|
||||
"integrity": "sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.4.0",
|
||||
"@typescript-eslint/types": "7.2.0",
|
||||
"eslint-visitor-keys": "^3.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@ -1189,19 +1186,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/cli": {
|
||||
"version": "8.35.1",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.35.1.tgz",
|
||||
"integrity": "sha512-cdFmd6P/eQJdP2lChQ+Fa9b1c2p0bDIPmetVHGCuHiW8ZPkanrvBFtHMUhMu44a1koni9LvN/hu7vIJ/aAC+Rg==",
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.33.1.tgz",
|
||||
"integrity": "sha512-Ngt5R6YAmErkSKnWLWt1JilLIKDPIB0P93bzQhb9bQhmg1arFBcl75uiwe6kf6T355vzcNslMaEJyeuqGChmCg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.1.1",
|
||||
"@vitest/snapshot": "^1.2.1",
|
||||
"@wdio/config": "8.35.0",
|
||||
"@wdio/globals": "8.35.1",
|
||||
"@wdio/config": "8.33.1",
|
||||
"@wdio/globals": "8.33.1",
|
||||
"@wdio/logger": "8.28.0",
|
||||
"@wdio/protocols": "8.32.0",
|
||||
"@wdio/types": "8.32.4",
|
||||
"@wdio/utils": "8.35.0",
|
||||
"@wdio/utils": "8.33.1",
|
||||
"async-exit-hook": "^2.0.1",
|
||||
"chalk": "^5.2.0",
|
||||
"chokidar": "^3.5.3",
|
||||
@ -1216,7 +1213,7 @@
|
||||
"lodash.union": "^4.6.0",
|
||||
"read-pkg-up": "10.0.0",
|
||||
"recursive-readdir": "^2.2.3",
|
||||
"webdriverio": "8.35.1",
|
||||
"webdriverio": "8.33.1",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"bin": {
|
||||
@ -1239,14 +1236,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/config": {
|
||||
"version": "8.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.35.0.tgz",
|
||||
"integrity": "sha512-I36sBPMl/+LCyQ3Pwb8gGQM6KxwmUfhOPp16TxN21Qo/Bc0fZfyGIg6KevmRu4DuqpGUm5MMVSfyPhLUkMk3Cg==",
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.33.1.tgz",
|
||||
"integrity": "sha512-JB7+tRkEsDJ4QAgJIZ3AaZvlp8pfBH6A5cKcGsaOuLVYMnsRPVkEGQc6n2akN9EPlDA2UjyrPOX6KZHbsSty7w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@wdio/logger": "8.28.0",
|
||||
"@wdio/types": "8.32.4",
|
||||
"@wdio/utils": "8.35.0",
|
||||
"@wdio/utils": "8.33.1",
|
||||
"decamelize": "^6.0.0",
|
||||
"deepmerge-ts": "^5.0.0",
|
||||
"glob": "^10.2.2",
|
||||
@ -1257,28 +1254,28 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/globals": {
|
||||
"version": "8.35.1",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.35.1.tgz",
|
||||
"integrity": "sha512-T3IUFcKXRU9WWleAV72DGFWUiXSSr8SBvpc2cUJrvZ5Je9R2gEsrts5eHCY7amXtfeylfMgy5EayGMajgcna6A==",
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.33.1.tgz",
|
||||
"integrity": "sha512-1ud9oq7n9MMNywS/FoMRRWqW6uhcoxgnpXoGeLE2Tr+4f937ABOl+sfZgjycXujyvR7yTL8AROOYajp1Yuv1Xg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^16.13 || >=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"expect-webdriverio": "^4.11.2",
|
||||
"webdriverio": "8.35.1"
|
||||
"webdriverio": "8.33.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/local-runner": {
|
||||
"version": "8.35.1",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.35.1.tgz",
|
||||
"integrity": "sha512-PG+bADoY5VoWPmAfRi030rtxbFj68MVPlcwEN0dN1lDdYKz1ATzzGUK12sqCgGz1ktcC7sQzmJZVBklzbvn3mQ==",
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.33.1.tgz",
|
||||
"integrity": "sha512-eQp12wHIkyh5zl9fun1qjv5Qvf4mCHPgLs5sKbfo3OK4LadzmD4/QNvDG8DYq/9cyuhVvnHgbLQ3XAnkoPde3w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.1.0",
|
||||
"@wdio/logger": "8.28.0",
|
||||
"@wdio/repl": "8.24.12",
|
||||
"@wdio/runner": "8.35.1",
|
||||
"@wdio/runner": "8.33.1",
|
||||
"@wdio/types": "8.32.4",
|
||||
"async-exit-hook": "^2.0.1",
|
||||
"split2": "^4.1.0",
|
||||
@ -1316,16 +1313,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/mocha-framework": {
|
||||
"version": "8.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.35.0.tgz",
|
||||
"integrity": "sha512-riO3aMgvGdFFRMpyMk5m480V+mi5EcKk6cjT1TB9L5XEN7Mo/8qthBw9CLgFCZkr4KlR40hgPKSZFHE0rH2GpQ==",
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.33.1.tgz",
|
||||
"integrity": "sha512-CxYLE22+tgnMnruElvDGJGR+dE0pxvMZ95agIUYYen69DJ705a74XtTR6zX9COWu6RooBezHgEs3fXev0XL79Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/mocha": "^10.0.0",
|
||||
"@types/node": "^20.1.0",
|
||||
"@wdio/logger": "8.28.0",
|
||||
"@wdio/types": "8.32.4",
|
||||
"@wdio/utils": "8.35.0",
|
||||
"@wdio/utils": "8.33.1",
|
||||
"mocha": "^10.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -1367,22 +1364,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/runner": {
|
||||
"version": "8.35.1",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.35.1.tgz",
|
||||
"integrity": "sha512-5F6cbOYeZjF34Vsnycp5JPnDljI52fmyxsV2O/L3h6F2+83YXpbsqBplw/2G24JtIUudV7VOY/38bUicn1OyXg==",
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.33.1.tgz",
|
||||
"integrity": "sha512-i0eRwMCePKkQocWsdkPQpBb1jELyNR5JCwnmOgM3g9fQI6KAf5D4oEUkNDFL/vD4UtgbSRmux7b7j5G01VvuqQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.11.28",
|
||||
"@wdio/config": "8.35.0",
|
||||
"@wdio/globals": "8.35.1",
|
||||
"@types/node": "^20.1.0",
|
||||
"@wdio/config": "8.33.1",
|
||||
"@wdio/globals": "8.33.1",
|
||||
"@wdio/logger": "8.28.0",
|
||||
"@wdio/types": "8.32.4",
|
||||
"@wdio/utils": "8.35.0",
|
||||
"deepmerge-ts": "^5.1.0",
|
||||
"expect-webdriverio": "^4.12.0",
|
||||
"gaze": "^1.1.3",
|
||||
"webdriver": "8.35.0",
|
||||
"webdriverio": "8.35.1"
|
||||
"@wdio/utils": "8.33.1",
|
||||
"deepmerge-ts": "^5.0.0",
|
||||
"expect-webdriverio": "^4.11.2",
|
||||
"gaze": "^1.1.2",
|
||||
"webdriver": "8.33.1",
|
||||
"webdriverio": "8.33.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.13 || >=18"
|
||||
@ -1429,9 +1426,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/utils": {
|
||||
"version": "8.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.35.0.tgz",
|
||||
"integrity": "sha512-9KCyn4aS+9tWfthnUkNFVe52AM6QrLGAeIxgGxNlzTAcQGl7jjwdDM7aSK0RjLkWI3a/88DRH21mN/t2LGDmPQ==",
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.33.1.tgz",
|
||||
"integrity": "sha512-W0ArrZbs4M23POv8+FPsgHDFxg+wwklfZgLSsjVq2kpCmBCfIPxKSAOgTo/XrcH4We/OnshgBzxLcI+BHDgi4w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@puppeteer/browsers": "^1.6.0",
|
||||
@ -2084,9 +2081,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/chromedriver": {
|
||||
"version": "123.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-123.0.0.tgz",
|
||||
"integrity": "sha512-OE9mpxXwbFy5LncAisqXm1aEzuLPtEMORIxyYIn9uT7N8rquJWyoip6w9Rytub3o2gnynW9+PFOTPVTldaYrtw==",
|
||||
"version": "122.0.6",
|
||||
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-122.0.6.tgz",
|
||||
"integrity": "sha512-Q0r+QlUtiJWMQ5HdYaFa0CtBmLFq3n5JWfmq9mOC00UMBvWxku09gUkvBt457QnYfTM/XHqY/HTFOxHvATnTmA==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@testim/chrome-version": "^1.1.4",
|
||||
@ -2691,9 +2688,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/devtools-protocol": {
|
||||
"version": "0.0.1273771",
|
||||
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1273771.tgz",
|
||||
"integrity": "sha512-QDbb27xcTVReQQW/GHJsdQqGKwYBE7re7gxehj467kKP2DKuYBUj6i2k5LRiAC66J1yZG/9gsxooz/s9pcm0Og==",
|
||||
"version": "0.0.1263784",
|
||||
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1263784.tgz",
|
||||
"integrity": "sha512-k0SCZMwj587w4F8QYbP5iIbSonL6sd3q8aVJch036r9Tv2t9b5/Oq7AiJ/FJvRuORm/pJNXZtrdNNWlpRnl56A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/diff": {
|
||||
@ -3413,9 +3410,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/expect-webdriverio": {
|
||||
"version": "4.12.1",
|
||||
"resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-4.12.1.tgz",
|
||||
"integrity": "sha512-jTfyC2bJbPNw4c8MlEwZNX7SjtPbZ73ysJvr/OGKA9mSKC+toyjU2eMNzHlt9WZO5+wl0RDS1dR7VxHXeu7+zA==",
|
||||
"version": "4.11.2",
|
||||
"resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-4.11.2.tgz",
|
||||
"integrity": "sha512-PK8lrQmRhK8NRtE8i/CJsnKS/QGrHULQW5EfmyKxIiLHnXd7t8dX0dWJn/fiYVtrPKBUyXSL6h52QqvZVc9yGQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@vitest/snapshot": "^1.2.2",
|
||||
@ -3699,9 +3696,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.6",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
|
||||
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
|
||||
"version": "1.15.5",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
|
||||
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@ -8620,9 +8617,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.4.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz",
|
||||
"integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==",
|
||||
"version": "5.4.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz",
|
||||
"integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
@ -8657,12 +8654,6 @@
|
||||
"through": "^2.3.8"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "5.26.5",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
@ -8886,18 +8877,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webdriver": {
|
||||
"version": "8.35.0",
|
||||
"resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.35.0.tgz",
|
||||
"integrity": "sha512-D13EroddIXDqdq3jgO8j6sorgTWqTwEiTqwlDoJizpRIgHGBy+UjkNM7XW1yVcvt8gsD2Dei2LQth2tJEnu5Ng==",
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.33.1.tgz",
|
||||
"integrity": "sha512-QREF4c08omN9BPh3QDmz5h+OEvjdzDliuEcrDuXoDnHSMxIj1rsonzsgRaM2PXhFZuPeMIiKZYqc7Qg9BGbh6A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.1.0",
|
||||
"@types/ws": "^8.5.3",
|
||||
"@wdio/config": "8.35.0",
|
||||
"@wdio/config": "8.33.1",
|
||||
"@wdio/logger": "8.28.0",
|
||||
"@wdio/protocols": "8.32.0",
|
||||
"@wdio/types": "8.32.4",
|
||||
"@wdio/utils": "8.35.0",
|
||||
"@wdio/utils": "8.33.1",
|
||||
"deepmerge-ts": "^5.1.0",
|
||||
"got": "^12.6.1",
|
||||
"ky": "^0.33.0",
|
||||
@ -8908,23 +8899,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webdriverio": {
|
||||
"version": "8.35.1",
|
||||
"resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.35.1.tgz",
|
||||
"integrity": "sha512-YAuKR4JERGiMqCJmm5fEVZ160iiFPyupwALqfXfzrYVcEmKltKPFY/oUCArmi6Uzqd+Sa2Kp9WZtz2Eu1R76JA==",
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.33.1.tgz",
|
||||
"integrity": "sha512-1DsF8sx1a46AoVYCUpEwJYU74iBAW/U2H5r6p+60ct7dIiFmxmc4uCbOqtf7NLOTgrIzAOaRnT0EsrRICpg5Qw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.1.0",
|
||||
"@wdio/config": "8.35.0",
|
||||
"@wdio/config": "8.33.1",
|
||||
"@wdio/logger": "8.28.0",
|
||||
"@wdio/protocols": "8.32.0",
|
||||
"@wdio/repl": "8.24.12",
|
||||
"@wdio/types": "8.32.4",
|
||||
"@wdio/utils": "8.35.0",
|
||||
"@wdio/utils": "8.33.1",
|
||||
"archiver": "^7.0.0",
|
||||
"aria-query": "^5.0.0",
|
||||
"css-shorthand-properties": "^1.1.1",
|
||||
"css-value": "^0.0.1",
|
||||
"devtools-protocol": "^0.0.1273771",
|
||||
"devtools-protocol": "^0.0.1263784",
|
||||
"grapheme-splitter": "^1.0.2",
|
||||
"import-meta-resolve": "^4.0.0",
|
||||
"is-plain-obj": "^4.1.0",
|
||||
@ -8936,7 +8927,7 @@
|
||||
"resq": "^1.9.1",
|
||||
"rgb2hex": "0.2.5",
|
||||
"serialize-error": "^11.0.1",
|
||||
"webdriver": "8.35.0"
|
||||
"webdriver": "8.33.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.13 || >=18"
|
||||
|
@ -4,11 +4,11 @@
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
||||
"@typescript-eslint/parser": "^7.4.0",
|
||||
"@wdio/cli": "^8.35.1",
|
||||
"@wdio/local-runner": "^8.35.1",
|
||||
"@wdio/mocha-framework": "^8.35.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||
"@typescript-eslint/parser": "^7.2.0",
|
||||
"@wdio/cli": "^8.33.1",
|
||||
"@wdio/local-runner": "^8.33.1",
|
||||
"@wdio/mocha-framework": "^8.33.1",
|
||||
"@wdio/spec-reporter": "^8.32.4",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
@ -16,7 +16,7 @@
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^3.2.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.4.3",
|
||||
"typescript": "^5.4.2",
|
||||
"wdio-wait-for": "^3.0.11"
|
||||
},
|
||||
"scripts": {
|
||||
@ -32,6 +32,6 @@
|
||||
"node": ">=20"
|
||||
},
|
||||
"dependencies": {
|
||||
"chromedriver": "^123.0.0"
|
||||
"chromedriver": "^122.0.6"
|
||||
}
|
||||
}
|
||||
|
@ -55,15 +55,15 @@ for (const [source, rawdest, strip] of otherFiles) {
|
||||
|
||||
// This starts the definitions used for esbuild: Our targets, our arguments, the function for running a build, and three
|
||||
// options for building: watching, building, and building the proxy.
|
||||
// Ordered by largest to smallest interface to build even faster
|
||||
|
||||
const interfaces = [
|
||||
["admin/AdminInterface/AdminInterface.ts", "admin"],
|
||||
["user/UserInterface.ts", "user"],
|
||||
["flow/FlowInterface.ts", "flow"],
|
||||
["standalone/api-browser/index.ts", "standalone/api-browser"],
|
||||
["enterprise/rac/index.ts", "enterprise/rac"],
|
||||
["standalone/loading/index.ts", "standalone/loading"],
|
||||
["polyfill/poly.ts", "."],
|
||||
["standalone/loading/index.ts", "standalone/loading"],
|
||||
["flow/FlowInterface.ts", "flow"],
|
||||
["user/UserInterface.ts", "user"],
|
||||
["enterprise/rac/index.ts", "enterprise/rac"],
|
||||
["standalone/api-browser/index.ts", "standalone/api-browser"],
|
||||
["admin/AdminInterface/AdminInterface.ts", "admin"],
|
||||
];
|
||||
|
||||
const baseArgs = {
|
||||
@ -80,32 +80,29 @@ const baseArgs = {
|
||||
format: "esm",
|
||||
};
|
||||
|
||||
async function buildOneSource(source, dest) {
|
||||
const DIST = path.join(__dirname, "./dist", dest);
|
||||
console.log(`[${new Date(Date.now()).toISOString()}] Starting build for target ${source}`);
|
||||
|
||||
try {
|
||||
const start = Date.now();
|
||||
await esbuild.build({
|
||||
...baseArgs,
|
||||
entryPoints: [`./src/${source}`],
|
||||
outdir: DIST,
|
||||
});
|
||||
const end = Date.now();
|
||||
console.log(
|
||||
`[${new Date(end).toISOString()}] Finished build for target ${source} in ${
|
||||
Date.now() - start
|
||||
}ms`,
|
||||
);
|
||||
} catch (exc) {
|
||||
console.error(`[${new Date(Date.now()).toISOString()}] Failed to build ${source}: ${exc}`);
|
||||
function buildAuthentik(interfaces) {
|
||||
for (const [source, dest] of interfaces) {
|
||||
const DIST = path.join(__dirname, "./dist", dest);
|
||||
console.log(`[${new Date(Date.now()).toISOString()}] Starting build for target ${source}`);
|
||||
try {
|
||||
const start = Date.now();
|
||||
esbuild.buildSync({
|
||||
...baseArgs,
|
||||
entryPoints: [`./src/${source}`],
|
||||
outdir: DIST,
|
||||
});
|
||||
const end = Date.now();
|
||||
console.log(
|
||||
`[${new Date(end).toISOString()}] Finished build for target ${source} in ${Date.now() - start}ms`,
|
||||
);
|
||||
} catch (exc) {
|
||||
console.error(
|
||||
`[${new Date(Date.now()).toISOString()}] Failed to build ${source}: ${exc}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function buildAuthentik(interfaces) {
|
||||
await Promise.allSettled(interfaces.map(([source, dest]) => buildOneSource(source, dest)));
|
||||
}
|
||||
|
||||
let timeoutId = null;
|
||||
function debouncedBuild() {
|
||||
if (timeoutId !== null) {
|
||||
@ -141,11 +138,9 @@ if (process.argv.length > 2 && (process.argv[2] === "-w" || process.argv[2] ===
|
||||
});
|
||||
} else if (process.argv.length > 2 && (process.argv[2] === "-p" || process.argv[2] === "--proxy")) {
|
||||
// There's no watch-for-proxy, sorry.
|
||||
await buildAuthentik(
|
||||
interfaces.filter(([_, dest]) => ["standalone/loading", "."].includes(dest)),
|
||||
);
|
||||
buildAuthentik(interfaces.slice(0, 2));
|
||||
process.exit(0);
|
||||
} else {
|
||||
// And the fallback: just build it.
|
||||
await buildAuthentik(interfaces);
|
||||
buildAuthentik(interfaces);
|
||||
}
|
||||
|
1228
web/package-lock.json
generated
1228
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -38,23 +38,23 @@
|
||||
"@codemirror/theme-one-dark": "^6.1.2",
|
||||
"@formatjs/intl-listformat": "^7.5.5",
|
||||
"@fortawesome/fontawesome-free": "^6.5.1",
|
||||
"@goauthentik/api": "^2024.2.2-1711369360",
|
||||
"@goauthentik/api": "^2024.2.2-1709583949",
|
||||
"@lit-labs/task": "^3.1.0",
|
||||
"@lit/reactive-element": "^2.0.4",
|
||||
"@lit/context": "^1.1.0",
|
||||
"@lit/localize": "^0.12.1",
|
||||
"@lit/reactive-element": "^2.0.4",
|
||||
"@open-wc/lit-helpers": "^0.7.0",
|
||||
"@patternfly/elements": "^2.4.0",
|
||||
"@patternfly/patternfly": "^4.224.2",
|
||||
"@sentry/browser": "^7.108.0",
|
||||
"@sentry/browser": "^7.106.1",
|
||||
"@webcomponents/webcomponentsjs": "^2.8.0",
|
||||
"base64-js": "^1.5.1",
|
||||
"chart.js": "^4.4.2",
|
||||
"chartjs-adapter-moment": "^1.0.1",
|
||||
"codemirror": "^6.0.1",
|
||||
"construct-style-sheets-polyfill": "^3.1.0",
|
||||
"core-js": "^3.36.1",
|
||||
"country-flag-icons": "^1.5.10",
|
||||
"core-js": "^3.36.0",
|
||||
"country-flag-icons": "^1.5.9",
|
||||
"fuse.js": "^7.0.0",
|
||||
"guacamole-common-js": "^1.5.0",
|
||||
"lit": "^3.1.2",
|
||||
@ -68,19 +68,18 @@
|
||||
"yaml": "^2.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.3",
|
||||
"@babel/core": "^7.24.0",
|
||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||
"@babel/plugin-proposal-decorators": "^7.24.1",
|
||||
"@babel/plugin-transform-private-methods": "^7.24.1",
|
||||
"@babel/plugin-transform-private-property-in-object": "^7.24.1",
|
||||
"@babel/plugin-transform-runtime": "^7.24.3",
|
||||
"@babel/preset-env": "^7.24.3",
|
||||
"@babel/preset-typescript": "^7.24.1",
|
||||
"@babel/plugin-proposal-decorators": "^7.24.0",
|
||||
"@babel/plugin-transform-private-methods": "^7.23.3",
|
||||
"@babel/plugin-transform-private-property-in-object": "^7.23.4",
|
||||
"@babel/plugin-transform-runtime": "^7.24.0",
|
||||
"@babel/preset-env": "^7.24.0",
|
||||
"@babel/preset-typescript": "^7.23.3",
|
||||
"@hcaptcha/types": "^1.0.3",
|
||||
"@jeysal/storybook-addon-css-user-preferences": "^0.2.0",
|
||||
"@lit/localize-tools": "^0.7.2",
|
||||
"@rollup/plugin-replace": "^5.0.5",
|
||||
"@spotlightjs/spotlight": "^1.2.15",
|
||||
"@spotlightjs/spotlight": "^1.2.12",
|
||||
"@storybook/addon-essentials": "^7.6.17",
|
||||
"@storybook/addon-links": "^7.6.17",
|
||||
"@storybook/api": "^7.6.17",
|
||||
@ -91,16 +90,19 @@
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||
"@types/chart.js": "^2.9.41",
|
||||
"@types/codemirror": "5.60.15",
|
||||
"@types/grecaptcha": "^3.0.9",
|
||||
"@types/grecaptcha": "^3.0.8",
|
||||
"@types/guacamole-common-js": "1.5.2",
|
||||
"@types/showdown": "^2.0.6",
|
||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
||||
"@typescript-eslint/parser": "^7.4.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||
"@typescript-eslint/parser": "^7.2.0",
|
||||
"@rollup/plugin-replace": "^5.0.5",
|
||||
"rollup-plugin-modify": "^3.0.0",
|
||||
"rollup-plugin-postcss-lit": "^2.1.0",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
"babel-plugin-tsconfig-paths": "^1.0.3",
|
||||
"chokidar": "^3.6.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"esbuild": "^0.20.2",
|
||||
"esbuild": "^0.20.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-custom-elements": "0.0.8",
|
||||
@ -115,14 +117,12 @@
|
||||
"pseudolocale": "^2.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"rollup-plugin-modify": "^3.0.0",
|
||||
"rollup-plugin-postcss-lit": "^2.1.0",
|
||||
"storybook": "^7.6.17",
|
||||
"storybook-addon-mock": "^4.3.0",
|
||||
"ts-lit-plugin": "^2.0.2",
|
||||
"tslib": "^2.6.2",
|
||||
"turnstile-types": "^1.2.0",
|
||||
"typescript": "^5.4.3",
|
||||
"typescript": "^5.4.2",
|
||||
"vite-tsconfig-paths": "^4.3.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
|
@ -1,155 +1,266 @@
|
||||
import "@goauthentik/admin/admin-overview/AdminOverviewPage";
|
||||
import { ID_REGEX, Route, SLUG_REGEX, UUID_REGEX } from "@goauthentik/elements/router/Route";
|
||||
import { ID_REGEX, SLUG_REGEX, UUID_REGEX } from "@goauthentik/elements/router/Route";
|
||||
import { RawRoute, makeRoute } from "@goauthentik/elements/router/routeUtils";
|
||||
|
||||
import { html } from "lit";
|
||||
|
||||
export const ROUTES: Route[] = [
|
||||
export const _ROUTES: RawRoute[] = [
|
||||
// Prevent infinite Shell loops
|
||||
new Route(new RegExp("^/$")).redirect("/administration/overview"),
|
||||
new Route(new RegExp("^#.*")).redirect("/administration/overview"),
|
||||
new Route(new RegExp("^/library$")).redirect("/if/user/", true),
|
||||
["^/$", "/administration/overview"],
|
||||
["^#.*", "/administration/overview"],
|
||||
["^/library$", ["/if/user/", true]],
|
||||
// statically imported since this is the default route
|
||||
new Route(new RegExp("^/administration/overview$"), async () => {
|
||||
return html`<ak-admin-overview></ak-admin-overview>`;
|
||||
}),
|
||||
new Route(new RegExp("^/administration/dashboard/users$"), async () => {
|
||||
await import("@goauthentik/admin/admin-overview/DashboardUserPage");
|
||||
return html`<ak-admin-dashboard-users></ak-admin-dashboard-users>`;
|
||||
}),
|
||||
new Route(new RegExp("^/administration/system-tasks$"), async () => {
|
||||
await import("@goauthentik/admin/system-tasks/SystemTaskListPage");
|
||||
return html`<ak-system-task-list></ak-system-task-list>`;
|
||||
}),
|
||||
new Route(new RegExp("^/core/providers$"), async () => {
|
||||
await import("@goauthentik/admin/providers/ProviderListPage");
|
||||
return html`<ak-provider-list></ak-provider-list>`;
|
||||
}),
|
||||
new Route(new RegExp(`^/core/providers/(?<id>${ID_REGEX})$`), async (args) => {
|
||||
await import("@goauthentik/admin/providers/ProviderViewPage");
|
||||
return html`<ak-provider-view .providerID=${parseInt(args.id, 10)}></ak-provider-view>`;
|
||||
}),
|
||||
new Route(new RegExp("^/core/applications$"), async () => {
|
||||
await import("@goauthentik/admin/applications/ApplicationListPage");
|
||||
return html`<ak-application-list></ak-application-list>`;
|
||||
}),
|
||||
new Route(new RegExp(`^/core/applications/(?<slug>${SLUG_REGEX})$`), async (args) => {
|
||||
await import("@goauthentik/admin/applications/ApplicationViewPage");
|
||||
return html`<ak-application-view .applicationSlug=${args.slug}></ak-application-view>`;
|
||||
}),
|
||||
new Route(new RegExp("^/core/sources$"), async () => {
|
||||
await import("@goauthentik/admin/sources/SourceListPage");
|
||||
return html`<ak-source-list></ak-source-list>`;
|
||||
}),
|
||||
new Route(new RegExp(`^/core/sources/(?<slug>${SLUG_REGEX})$`), async (args) => {
|
||||
await import("@goauthentik/admin/sources/SourceViewPage");
|
||||
return html`<ak-source-view .sourceSlug=${args.slug}></ak-source-view>`;
|
||||
}),
|
||||
new Route(new RegExp("^/core/property-mappings$"), async () => {
|
||||
await import("@goauthentik/admin/property-mappings/PropertyMappingListPage");
|
||||
return html`<ak-property-mapping-list></ak-property-mapping-list>`;
|
||||
}),
|
||||
new Route(new RegExp("^/core/tokens$"), async () => {
|
||||
await import("@goauthentik/admin/tokens/TokenListPage");
|
||||
return html`<ak-token-list></ak-token-list>`;
|
||||
}),
|
||||
new Route(new RegExp("^/core/brands"), async () => {
|
||||
await import("@goauthentik/admin/brands/BrandListPage");
|
||||
return html`<ak-brand-list></ak-brand-list>`;
|
||||
}),
|
||||
new Route(new RegExp("^/policy/policies$"), async () => {
|
||||
await import("@goauthentik/admin/policies/PolicyListPage");
|
||||
return html`<ak-policy-list></ak-policy-list>`;
|
||||
}),
|
||||
new Route(new RegExp("^/policy/reputation$"), async () => {
|
||||
await import("@goauthentik/admin/policies/reputation/ReputationListPage");
|
||||
return html`<ak-policy-reputation-list></ak-policy-reputation-list>`;
|
||||
}),
|
||||
new Route(new RegExp("^/identity/groups$"), async () => {
|
||||
await import("@goauthentik/admin/groups/GroupListPage");
|
||||
return html`<ak-group-list></ak-group-list>`;
|
||||
}),
|
||||
new Route(new RegExp(`^/identity/groups/(?<uuid>${UUID_REGEX})$`), async (args) => {
|
||||
await import("@goauthentik/admin/groups/GroupViewPage");
|
||||
return html`<ak-group-view .groupId=${args.uuid}></ak-group-view>`;
|
||||
}),
|
||||
new Route(new RegExp("^/identity/users$"), async () => {
|
||||
await import("@goauthentik/admin/users/UserListPage");
|
||||
return html`<ak-user-list></ak-user-list>`;
|
||||
}),
|
||||
new Route(new RegExp(`^/identity/users/(?<id>${ID_REGEX})$`), async (args) => {
|
||||
await import("@goauthentik/admin/users/UserViewPage");
|
||||
return html`<ak-user-view .userId=${parseInt(args.id, 10)}></ak-user-view>`;
|
||||
}),
|
||||
new Route(new RegExp("^/identity/roles$"), async () => {
|
||||
await import("@goauthentik/admin/roles/RoleListPage");
|
||||
return html`<ak-role-list></ak-role-list>`;
|
||||
}),
|
||||
new Route(new RegExp(`^/identity/roles/(?<id>${UUID_REGEX})$`), async (args) => {
|
||||
await import("@goauthentik/admin/roles/RoleViewPage");
|
||||
return html`<ak-role-view roleId=${args.id}></ak-role-view>`;
|
||||
}),
|
||||
new Route(new RegExp("^/flow/stages/invitations$"), async () => {
|
||||
await import("@goauthentik/admin/stages/invitation/InvitationListPage");
|
||||
return html`<ak-stage-invitation-list></ak-stage-invitation-list>`;
|
||||
}),
|
||||
new Route(new RegExp("^/flow/stages/prompts$"), async () => {
|
||||
await import("@goauthentik/admin/stages/prompt/PromptListPage");
|
||||
return html`<ak-stage-prompt-list></ak-stage-prompt-list>`;
|
||||
}),
|
||||
new Route(new RegExp("^/flow/stages$"), async () => {
|
||||
await import("@goauthentik/admin/stages/StageListPage");
|
||||
return html`<ak-stage-list></ak-stage-list>`;
|
||||
}),
|
||||
new Route(new RegExp("^/flow/flows$"), async () => {
|
||||
await import("@goauthentik/admin/flows/FlowListPage");
|
||||
return html`<ak-flow-list></ak-flow-list>`;
|
||||
}),
|
||||
new Route(new RegExp(`^/flow/flows/(?<slug>${SLUG_REGEX})$`), async (args) => {
|
||||
await import("@goauthentik/admin/flows/FlowViewPage");
|
||||
return html`<ak-flow-view .flowSlug=${args.slug}></ak-flow-view>`;
|
||||
}),
|
||||
new Route(new RegExp("^/events/log$"), async () => {
|
||||
await import("@goauthentik/admin/events/EventListPage");
|
||||
return html`<ak-event-list></ak-event-list>`;
|
||||
}),
|
||||
new Route(new RegExp(`^/events/log/(?<id>${UUID_REGEX})$`), async (args) => {
|
||||
await import("@goauthentik/admin/events/EventViewPage");
|
||||
return html`<ak-event-view .eventID=${args.id}></ak-event-view>`;
|
||||
}),
|
||||
new Route(new RegExp("^/events/transports$"), async () => {
|
||||
await import("@goauthentik/admin/events/TransportListPage");
|
||||
return html`<ak-event-transport-list></ak-event-transport-list>`;
|
||||
}),
|
||||
new Route(new RegExp("^/events/rules$"), async () => {
|
||||
await import("@goauthentik/admin/events/RuleListPage");
|
||||
return html`<ak-event-rule-list></ak-event-rule-list>`;
|
||||
}),
|
||||
new Route(new RegExp("^/outpost/outposts$"), async () => {
|
||||
await import("@goauthentik/admin/outposts/OutpostListPage");
|
||||
return html`<ak-outpost-list></ak-outpost-list>`;
|
||||
}),
|
||||
new Route(new RegExp("^/outpost/integrations$"), async () => {
|
||||
await import("@goauthentik/admin/outposts/ServiceConnectionListPage");
|
||||
return html`<ak-outpost-service-connection-list></ak-outpost-service-connection-list>`;
|
||||
}),
|
||||
new Route(new RegExp("^/crypto/certificates$"), async () => {
|
||||
await import("@goauthentik/admin/crypto/CertificateKeyPairListPage");
|
||||
return html`<ak-crypto-certificate-list></ak-crypto-certificate-list>`;
|
||||
}),
|
||||
new Route(new RegExp("^/admin/settings$"), async () => {
|
||||
await import("@goauthentik/admin/admin-settings/AdminSettingsPage");
|
||||
return html`<ak-admin-settings></ak-admin-settings>`;
|
||||
}),
|
||||
new Route(new RegExp("^/blueprints/instances$"), async () => {
|
||||
await import("@goauthentik/admin/blueprints/BlueprintListPage");
|
||||
return html`<ak-blueprint-list></ak-blueprint-list>`;
|
||||
}),
|
||||
new Route(new RegExp("^/debug$"), async () => {
|
||||
await import("@goauthentik/admin/DebugPage");
|
||||
return html`<ak-admin-debug-page></ak-admin-debug-page>`;
|
||||
}),
|
||||
new Route(new RegExp("^/enterprise/licenses$"), async () => {
|
||||
await import("@goauthentik/admin/enterprise/EnterpriseLicenseListPage");
|
||||
return html`<ak-enterprise-license-list></ak-enterprise-license-list>`;
|
||||
}),
|
||||
[
|
||||
"^/administration/overview$",
|
||||
async () => {
|
||||
return html`<ak-admin-overview></ak-admin-overview>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/administration/dashboard/users$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/admin-overview/DashboardUserPage");
|
||||
return html`<ak-admin-dashboard-users></ak-admin-dashboard-users>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/administration/system-tasks$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/system-tasks/SystemTaskListPage");
|
||||
return html`<ak-system-task-list></ak-system-task-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/core/providers$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/providers/ProviderListPage");
|
||||
return html`<ak-provider-list></ak-provider-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
`^/core/providers/(?<id>${ID_REGEX}])$`,
|
||||
async (args) => {
|
||||
await import("@goauthentik/admin/providers/ProviderViewPage");
|
||||
return html`<ak-provider-view .providerID=${parseInt(args.id, 10)}></ak-provider-view>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/core/applications$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/applications/ApplicationListPage");
|
||||
return html`<ak-application-list></ak-application-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
`^/core/applications/(?<slug>${SLUG_REGEX})$`,
|
||||
async (args) => {
|
||||
await import("@goauthentik/admin/applications/ApplicationViewPage");
|
||||
return html`<ak-application-view .applicationSlug=${args.slug}></ak-application-view>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/core/sources$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/sources/SourceListPage");
|
||||
return html`<ak-source-list></ak-source-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
`^/core/sources/(?<slug>${SLUG_REGEX})$`,
|
||||
async (args) => {
|
||||
await import("@goauthentik/admin/sources/SourceViewPage");
|
||||
return html`<ak-source-view .sourceSlug=${args.slug}></ak-source-view>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/core/property-mappings$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/property-mappings/PropertyMappingListPage");
|
||||
return html`<ak-property-mapping-list></ak-property-mapping-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/core/tokens$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/tokens/TokenListPage");
|
||||
return html`<ak-token-list></ak-token-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/core/brands",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/brands/BrandListPage");
|
||||
return html`<ak-brand-list></ak-brand-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/policy/policies$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/policies/PolicyListPage");
|
||||
return html`<ak-policy-list></ak-policy-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/policy/reputation$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/policies/reputation/ReputationListPage");
|
||||
return html`<ak-policy-reputation-list></ak-policy-reputation-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/identity/groups$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/groups/GroupListPage");
|
||||
return html`<ak-group-list></ak-group-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
`^/identity/groups/(?<uuid>${UUID_REGEX})$`,
|
||||
async (args) => {
|
||||
await import("@goauthentik/admin/groups/GroupViewPage");
|
||||
return html`<ak-group-view .groupId=${args.uuid}></ak-group-view>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/identity/users$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/users/UserListPage");
|
||||
return html`<ak-user-list></ak-user-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
`^/identity/users/(?<id>${ID_REGEX})$`,
|
||||
async (args) => {
|
||||
await import("@goauthentik/admin/users/UserViewPage");
|
||||
return html`<ak-user-view .userId=${parseInt(args.id, 10)}></ak-user-view>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/identity/roles$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/roles/RoleListPage");
|
||||
return html`<ak-role-list></ak-role-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
`^/identity/roles/(?<id>${UUID_REGEX})$`,
|
||||
async (args) => {
|
||||
await import("@goauthentik/admin/roles/RoleViewPage");
|
||||
return html`<ak-role-view roleId=${args.id}></ak-role-view>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/flow/stages/invitations$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/stages/invitation/InvitationListPage");
|
||||
return html`<ak-stage-invitation-list></ak-stage-invitation-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/flow/stages/prompts$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/stages/prompt/PromptListPage");
|
||||
return html`<ak-stage-prompt-list></ak-stage-prompt-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/flow/stages$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/stages/StageListPage");
|
||||
return html`<ak-stage-list></ak-stage-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/flow/flows$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/flows/FlowListPage");
|
||||
return html`<ak-flow-list></ak-flow-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
`^/flow/flows/(?<slug>${SLUG_REGEX})$`,
|
||||
async (args) => {
|
||||
await import("@goauthentik/admin/flows/FlowViewPage");
|
||||
return html`<ak-flow-view .flowSlug=${args.slug}></ak-flow-view>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/events/log$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/events/EventListPage");
|
||||
return html`<ak-event-list></ak-event-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
`^/events/log/(?<id>${UUID_REGEX})$`,
|
||||
async (args) => {
|
||||
await import("@goauthentik/admin/events/EventViewPage");
|
||||
return html`<ak-event-view .eventID=${args.id}></ak-event-view>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/events/transports$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/events/TransportListPage");
|
||||
return html`<ak-event-transport-list></ak-event-transport-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/events/rules$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/events/RuleListPage");
|
||||
return html`<ak-event-rule-list></ak-event-rule-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/outpost/outposts$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/outposts/OutpostListPage");
|
||||
return html`<ak-outpost-list></ak-outpost-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/outpost/integrations$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/outposts/ServiceConnectionListPage");
|
||||
return html`<ak-outpost-service-connection-list></ak-outpost-service-connection-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/crypto/certificates$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/crypto/CertificateKeyPairListPage");
|
||||
return html`<ak-crypto-certificate-list></ak-crypto-certificate-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/admin/settings$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/admin-settings/AdminSettingsPage");
|
||||
return html`<ak-admin-settings></ak-admin-settings>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/blueprints/instances$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/blueprints/BlueprintListPage");
|
||||
return html`<ak-blueprint-list></ak-blueprint-list>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/debug$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/DebugPage");
|
||||
return html`<ak-admin-debug-page></ak-admin-debug-page>`;
|
||||
},
|
||||
],
|
||||
[
|
||||
"^/enterprise/licenses$",
|
||||
async () => {
|
||||
await import("@goauthentik/admin/enterprise/EnterpriseLicenseListPage");
|
||||
return html`<ak-enterprise-license-list></ak-enterprise-license-list>`;
|
||||
},
|
||||
],
|
||||
];
|
||||
|
||||
export const ROUTES = _ROUTES.map(makeRoute);
|
||||
|
@ -31,15 +31,9 @@ export class VersionStatusCard extends AdminStatusCard<Version> {
|
||||
message: html`${msg(str`${value.versionLatest} is available!`)}`,
|
||||
});
|
||||
}
|
||||
if (value.versionLatestValid) {
|
||||
return Promise.resolve<AdminStatus>({
|
||||
icon: "fa fa-check-circle pf-m-success",
|
||||
message: html`${msg("Up-to-date!")}`,
|
||||
});
|
||||
}
|
||||
return Promise.resolve<AdminStatus>({
|
||||
icon: "fa fa-question-circle",
|
||||
message: html`${msg("Latest version unknown")}`,
|
||||
icon: "fa fa-check-circle pf-m-success",
|
||||
message: html`${msg("Up-to-date!")}`,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -15,13 +15,7 @@ import { msg } from "@lit/localize";
|
||||
import { TemplateResult, html } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
|
||||
import {
|
||||
Application,
|
||||
Brand,
|
||||
CoreApi,
|
||||
CoreApplicationsListRequest,
|
||||
FlowsInstancesListDesignationEnum,
|
||||
} from "@goauthentik/api";
|
||||
import { Brand, CoreApi, FlowsInstancesListDesignationEnum } from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-brand-form")
|
||||
export class BrandForm extends ModelForm<Brand, string> {
|
||||
@ -143,46 +137,6 @@ export class BrandForm extends ModelForm<Brand, string> {
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
|
||||
<ak-form-group>
|
||||
<span slot="header"> ${msg("External user settings")} </span>
|
||||
<div slot="body" class="pf-c-form">
|
||||
<ak-form-element-horizontal
|
||||
label=${msg("Default application")}
|
||||
name="defaultApplication"
|
||||
>
|
||||
<ak-search-select
|
||||
.fetchObjects=${async (query?: string): Promise<Application[]> => {
|
||||
const args: CoreApplicationsListRequest = {
|
||||
ordering: "name",
|
||||
superuserFullList: true,
|
||||
};
|
||||
if (query !== undefined) {
|
||||
args.search = query;
|
||||
}
|
||||
const users = await new CoreApi(
|
||||
DEFAULT_CONFIG,
|
||||
).coreApplicationsList(args);
|
||||
return users.results;
|
||||
}}
|
||||
.renderElement=${(item: Application): string => {
|
||||
return item.name;
|
||||
}}
|
||||
.renderDescription=${(item: Application): TemplateResult => {
|
||||
return html`${item.slug}`;
|
||||
}}
|
||||
.value=${(item: Application | undefined): string | undefined => {
|
||||
return item?.pk;
|
||||
}}
|
||||
.selected=${(item: Application): boolean => {
|
||||
return item.pk === this.instance?.defaultApplication;
|
||||
}}
|
||||
>
|
||||
</ak-search-select>
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
|
||||
<ak-form-group>
|
||||
<span slot="header"> ${msg("Default flows")} </span>
|
||||
<div slot="body" class="pf-c-form">
|
||||
|
@ -13,14 +13,13 @@ import { TablePage } from "@goauthentik/elements/table/TablePage";
|
||||
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { TemplateResult, html, nothing } from "lit";
|
||||
import { TemplateResult, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
import { Brand, CoreApi, RbacPermissionsAssignedByUsersListModelEnum } from "@goauthentik/api";
|
||||
import { WithBrandConfig } from "@goauthentik/authentik/elements/Interface/brandProvider";
|
||||
|
||||
@customElement("ak-brand-list")
|
||||
export class BrandListPage extends WithBrandConfig(TablePage<Brand>) {
|
||||
export class BrandListPage extends TablePage<Brand> {
|
||||
searchEnabled(): boolean {
|
||||
return true;
|
||||
}
|
||||
@ -85,9 +84,7 @@ export class BrandListPage extends WithBrandConfig(TablePage<Brand>) {
|
||||
|
||||
row(item: Brand): TemplateResult[] {
|
||||
return [
|
||||
html`${item.domain}${this.brand.matchedDomain === item.domain ? html`
|
||||
<ak-status-label ?good=${false} type="info" bad-label=${msg("Active")}></ak-status-label>
|
||||
` : nothing}`,
|
||||
html`${item.domain}`,
|
||||
html`${item.brandingTitle}`,
|
||||
html`<ak-status-label ?good=${item._default}></ak-status-label>`,
|
||||
html`<ak-forms-modal>
|
||||
|
@ -150,6 +150,10 @@ export class EnterpriseLicenseListPage extends TablePage<License> {
|
||||
|
||||
renderSectionBefore(): TemplateResult {
|
||||
return html`
|
||||
<div class="pf-c-banner pf-m-info">
|
||||
${msg("Enterprise is in preview.")}
|
||||
<a href="mailto:hello@goauthentik.io">${msg("Send us feedback!")}</a>
|
||||
</div>
|
||||
<section class="pf-c-page__main-section pf-m-no-padding-bottom">
|
||||
<div
|
||||
class="pf-l-grid pf-m-gutter pf-m-all-6-col-on-sm pf-m-all-4-col-on-md pf-m-all-3-col-on-lg pf-m-all-3-col-on-xl"
|
||||
|
@ -175,7 +175,7 @@ export class OAuth2ProviderViewPage extends AKElement {
|
||||
</div>`}
|
||||
<div class="pf-c-page__main-section pf-m-no-padding-mobile pf-l-grid pf-m-gutter">
|
||||
<div
|
||||
class="pf-c-card pf-l-grid__item pf-l-grid__item pf-m-12-col pf-m-4-col-on-xl pf-m-4-col-on-2xl"
|
||||
class="pf-c-card pf-l-grid__item pf-l-grid__item pf-m-12-col pf-m-3-col-on-xl pf-m-3-col-on-2xl"
|
||||
>
|
||||
<div class="pf-c-card__body">
|
||||
<dl class="pf-c-description-list">
|
||||
@ -255,7 +255,7 @@ export class OAuth2ProviderViewPage extends AKElement {
|
||||
</ak-forms-modal>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-c-card pf-l-grid__item pf-m-8-col">
|
||||
<div class="pf-c-card pf-l-grid__item pf-m-7-col">
|
||||
<div class="pf-c-card__body">
|
||||
<form class="pf-c-form">
|
||||
<div class="pf-c-form__group">
|
||||
|
@ -13,7 +13,7 @@ import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";
|
||||
|
||||
import { ConnectionToken, RACProvider, RacApi } from "@goauthentik/api";
|
||||
import { ConnectionToken, Endpoint, RACProvider, RacApi } from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-rac-connection-token-list")
|
||||
export class ConnectionTokenListPage extends Table<ConnectionToken> {
|
||||
@ -53,20 +53,20 @@ export class ConnectionTokenListPage extends Table<ConnectionToken> {
|
||||
return html`<ak-forms-delete-bulk
|
||||
objectLabel=${msg("Connection Token(s)")}
|
||||
.objects=${this.selectedElements}
|
||||
.metadata=${(item: ConnectionToken) => {
|
||||
.metadata=${(item: Endpoint) => {
|
||||
return [
|
||||
{ key: msg("Endpoint"), value: item.endpointObj.name },
|
||||
{ key: msg("User"), value: item.user.username },
|
||||
{ key: msg("Name"), value: item.name },
|
||||
{ key: msg("Host"), value: item.host },
|
||||
];
|
||||
}}
|
||||
.usedBy=${(item: ConnectionToken) => {
|
||||
.usedBy=${(item: Endpoint) => {
|
||||
return new RacApi(DEFAULT_CONFIG).racConnectionTokensUsedByList({
|
||||
connectionTokenUuid: item.pk || "",
|
||||
connectionTokenUuid: item.pk,
|
||||
});
|
||||
}}
|
||||
.delete=${(item: ConnectionToken) => {
|
||||
.delete=${(item: Endpoint) => {
|
||||
return new RacApi(DEFAULT_CONFIG).racConnectionTokensDestroy({
|
||||
connectionTokenUuid: item.pk || "",
|
||||
connectionTokenUuid: item.pk,
|
||||
});
|
||||
}}
|
||||
>
|
||||
|
@ -88,11 +88,7 @@ export class RACProviderViewPage extends AKElement {
|
||||
<section slot="page-overview" data-tab-title="${msg("Overview")}">
|
||||
${this.renderTabOverview()}
|
||||
</section>
|
||||
<section
|
||||
slot="page-connections"
|
||||
data-tab-title="${msg("Connections")}"
|
||||
class="pf-c-page__main-section pf-m-no-padding-mobile"
|
||||
>
|
||||
<section slot="page-connections" data-tab-title="${msg("Connections")}">
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__body">
|
||||
<ak-rac-connection-token-list
|
||||
|
@ -86,28 +86,6 @@ export class LDAPSourceForm extends BaseSourceForm<LDAPSource> {
|
||||
<span class="pf-c-switch__label">${msg("Enabled")}</span>
|
||||
</label>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="passwordLoginUpdateInternalPassword">
|
||||
<label class="pf-c-switch">
|
||||
<input
|
||||
class="pf-c-switch__input"
|
||||
type="checkbox"
|
||||
?checked=${first(this.instance?.passwordLoginUpdateInternalPassword, false)}
|
||||
/>
|
||||
<span class="pf-c-switch__toggle">
|
||||
<span class="pf-c-switch__toggle-icon">
|
||||
<i class="fas fa-check" aria-hidden="true"></i>
|
||||
</span>
|
||||
</span>
|
||||
<span class="pf-c-switch__label"
|
||||
>${msg("Update internal password on login")}</span
|
||||
>
|
||||
</label>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"When the user logs in to authentik using this source password backend, update their credentials in authentik.",
|
||||
)}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="syncUsers">
|
||||
<label class="pf-c-switch">
|
||||
<input
|
||||
|
@ -15,7 +15,6 @@ import "@goauthentik/admin/stages/identification/IdentificationStageForm";
|
||||
import "@goauthentik/admin/stages/invitation/InvitationStageForm";
|
||||
import "@goauthentik/admin/stages/password/PasswordStageForm";
|
||||
import "@goauthentik/admin/stages/prompt/PromptStageForm";
|
||||
import "@goauthentik/admin/stages/source/SourceStageForm";
|
||||
import "@goauthentik/admin/stages/user_delete/UserDeleteStageForm";
|
||||
import "@goauthentik/admin/stages/user_login/UserLoginStageForm";
|
||||
import "@goauthentik/admin/stages/user_logout/UserLogoutStageForm";
|
||||
|
@ -1,4 +1,3 @@
|
||||
import "@goauthentik/admin/common/ak-license-notice";
|
||||
import { StageBindingForm } from "@goauthentik/admin/flows/StageBindingForm";
|
||||
import "@goauthentik/admin/stages/authenticator_duo/AuthenticatorDuoStageForm";
|
||||
import "@goauthentik/admin/stages/authenticator_sms/AuthenticatorSMSStageForm";
|
||||
@ -15,14 +14,12 @@ import "@goauthentik/admin/stages/identification/IdentificationStageForm";
|
||||
import "@goauthentik/admin/stages/invitation/InvitationStageForm";
|
||||
import "@goauthentik/admin/stages/password/PasswordStageForm";
|
||||
import "@goauthentik/admin/stages/prompt/PromptStageForm";
|
||||
import "@goauthentik/admin/stages/source/SourceStageForm";
|
||||
import "@goauthentik/admin/stages/user_delete/UserDeleteStageForm";
|
||||
import "@goauthentik/admin/stages/user_login/UserLoginStageForm";
|
||||
import "@goauthentik/admin/stages/user_logout/UserLogoutStageForm";
|
||||
import "@goauthentik/admin/stages/user_write/UserWriteStageForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import { WithLicenseSummary } from "@goauthentik/elements/Interface/licenseSummaryProvider";
|
||||
import "@goauthentik/elements/forms/ProxyForm";
|
||||
import "@goauthentik/elements/wizard/FormWizardPage";
|
||||
import { FormWizardPage } from "@goauthentik/elements/wizard/FormWizardPage";
|
||||
@ -31,7 +28,7 @@ import { WizardPage } from "@goauthentik/elements/wizard/WizardPage";
|
||||
|
||||
import { msg, str } from "@lit/localize";
|
||||
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
|
||||
import { CSSResult, TemplateResult, html, nothing } from "lit";
|
||||
import { CSSResult, TemplateResult, html } from "lit";
|
||||
import { property } from "lit/decorators.js";
|
||||
|
||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
||||
@ -42,7 +39,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
import { FlowStageBinding, Stage, StagesApi, TypeCreate } from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-stage-wizard-initial")
|
||||
export class InitialStageWizardPage extends WithLicenseSummary(WizardPage) {
|
||||
export class InitialStageWizardPage extends WizardPage {
|
||||
@property({ attribute: false })
|
||||
stageTypes: TypeCreate[] = [];
|
||||
sidebarLabel = () => msg("Select type");
|
||||
@ -65,7 +62,6 @@ export class InitialStageWizardPage extends WithLicenseSummary(WizardPage) {
|
||||
render(): TemplateResult {
|
||||
return html`<form class="pf-c-form pf-m-horizontal">
|
||||
${this.stageTypes.map((type) => {
|
||||
const requiresEnterprise = type.requiresEnterprise && !this.hasEnterpriseLicense;
|
||||
return html`<div class="pf-c-radio">
|
||||
<input
|
||||
class="pf-c-radio__input"
|
||||
@ -86,15 +82,11 @@ export class InitialStageWizardPage extends WithLicenseSummary(WizardPage) {
|
||||
);
|
||||
this.host.isValid = true;
|
||||
}}
|
||||
?disabled=${requiresEnterprise}
|
||||
/>
|
||||
<label class="pf-c-radio__label" for=${`${type.component}-${type.modelName}`}
|
||||
>${type.name}</label
|
||||
>
|
||||
<span class="pf-c-radio__description">${type.description}${
|
||||
requiresEnterprise ? html`<ak-license-notice></ak-license-notice>` : nothing
|
||||
}</span>
|
||||
</span>
|
||||
<span class="pf-c-radio__description">${type.description}</span>
|
||||
</div>`;
|
||||
})}
|
||||
</form>`;
|
||||
|
@ -29,8 +29,6 @@ class PreviewStageHost implements StageHost {
|
||||
flowSlug = undefined;
|
||||
loading = false;
|
||||
brand = undefined;
|
||||
frameMode = false;
|
||||
|
||||
async submit(payload: unknown): Promise<boolean> {
|
||||
this.promptForm.previewResult = payload;
|
||||
return false;
|
||||
|
@ -1,99 +0,0 @@
|
||||
import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/SearchSelect/index";
|
||||
import "@goauthentik/elements/utils/TimeDeltaHelp";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { TemplateResult, html } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import {
|
||||
Source,
|
||||
SourceStage,
|
||||
SourcesAllListRequest,
|
||||
SourcesApi,
|
||||
StagesApi,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-stage-source-form")
|
||||
export class SourceStageForm extends BaseStageForm<SourceStage> {
|
||||
loadInstance(pk: string): Promise<SourceStage> {
|
||||
return new StagesApi(DEFAULT_CONFIG).stagesSourceRetrieve({
|
||||
stageUuid: pk,
|
||||
});
|
||||
}
|
||||
|
||||
async send(data: SourceStage): Promise<SourceStage> {
|
||||
if (this.instance) {
|
||||
return new StagesApi(DEFAULT_CONFIG).stagesSourceUpdate({
|
||||
stageUuid: this.instance.pk || "",
|
||||
sourceStageRequest: data,
|
||||
});
|
||||
} else {
|
||||
return new StagesApi(DEFAULT_CONFIG).stagesSourceCreate({
|
||||
sourceStageRequest: data,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
renderForm(): TemplateResult {
|
||||
return html`
|
||||
<span> ${msg("TODO.")} </span>
|
||||
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
|
||||
<input
|
||||
type="text"
|
||||
value="${ifDefined(this.instance?.name || "")}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${msg("Source")} ?required=${true} name="source">
|
||||
<ak-search-select
|
||||
.fetchObjects=${async (query?: string): Promise<Source[]> => {
|
||||
const args: SourcesAllListRequest = {
|
||||
ordering: "name",
|
||||
};
|
||||
if (query !== undefined) {
|
||||
args.search = query;
|
||||
}
|
||||
const users = await new SourcesApi(DEFAULT_CONFIG).sourcesAllList(args);
|
||||
return users.results;
|
||||
}}
|
||||
.renderElement=${(source: Source): string => {
|
||||
return source.name;
|
||||
}}
|
||||
.renderDescription=${(source: Source): TemplateResult => {
|
||||
return html`${source.verboseName}`;
|
||||
}}
|
||||
.value=${(source: Source | undefined): string | undefined => {
|
||||
return source?.pk;
|
||||
}}
|
||||
.selected=${(source: Source): boolean => {
|
||||
return source.pk === this.instance?.source;
|
||||
}}
|
||||
>
|
||||
</ak-search-select>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${msg("Resume timeout")}
|
||||
?required=${true}
|
||||
name="resumeTimeout"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
value="${ifDefined(this.instance?.resumeTimeout || "minutes=10")}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
/>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"Amount of time a user can take to return from the source to continue the flow.",
|
||||
)}
|
||||
</p>
|
||||
<ak-utils-time-delta-help></ak-utils-time-delta-help>
|
||||
</ak-form-element-horizontal>
|
||||
`;
|
||||
}
|
||||
}
|
@ -61,18 +61,16 @@ export function brand(): Promise<CurrentBrand> {
|
||||
return globalBrandPromise;
|
||||
}
|
||||
|
||||
export function getMetaContent(key: string): string | undefined {
|
||||
export function getMetaContent(key: string): string {
|
||||
const metaEl = document.querySelector<HTMLMetaElement>(`meta[name=${key}]`);
|
||||
return metaEl?.content;
|
||||
if (!metaEl) return "";
|
||||
return metaEl.content;
|
||||
}
|
||||
|
||||
export const DEFAULT_CONFIG = new Configuration({
|
||||
basePath:
|
||||
(process.env.AK_API_BASE_PATH ||
|
||||
getMetaContent("authentik-api") ||
|
||||
window.location.origin) + "/api/v3",
|
||||
basePath: (process.env.AK_API_BASE_PATH || window.location.origin) + "/api/v3",
|
||||
headers: {
|
||||
"sentry-trace": getMetaContent("sentry-trace") || "",
|
||||
"sentry-trace": getMetaContent("sentry-trace"),
|
||||
},
|
||||
middleware: [
|
||||
new CSRFMiddleware(),
|
||||
|
@ -329,7 +329,3 @@ input[type="date"]::-webkit-calendar-picker-indicator {
|
||||
.pf-c-tree-view__content:focus-within {
|
||||
--pf-c-tree-view__node--hover--BackgroundColor: var(--ak-dark-background-light-ish);
|
||||
}
|
||||
/* stepper */
|
||||
.pf-c-progress-stepper__step-title {
|
||||
--pf-c-progress-stepper__step-title--Color: var(--ak-dark-foreground);
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { PFSize } from "@goauthentik/common/enums.js";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import "@goauthentik/elements/Spinner";
|
||||
|
||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
41
web/src/elements/router/routeUtils.ts
Normal file
41
web/src/elements/router/routeUtils.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { Route, RouteArgs } from "@goauthentik/elements/router/Route";
|
||||
import { P, match } from "ts-pattern";
|
||||
|
||||
import { TemplateResult } from "lit";
|
||||
|
||||
type ListRoute = () => Promise<TemplateResult<1>>;
|
||||
type ViewRoute = (_1: RouteArgs) => Promise<TemplateResult<1>>;
|
||||
type InternalRedirect = string;
|
||||
type ExternalRedirect = [string, boolean];
|
||||
|
||||
type RouteInvoke = ViewRoute | ListRoute;
|
||||
|
||||
type RedirectRoute = [string, InternalRedirect | ExternalRedirect];
|
||||
type PageRoute = [string, RouteInvoke];
|
||||
|
||||
export type RawRoute = PageRoute | RedirectRoute;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const isLoader = (v: any): v is RouteInvoke => typeof v === "function";
|
||||
|
||||
// When discriminating between redirects and loaders, the loader type is irrelevant to routing
|
||||
// correctly. The loader type *is* still well-typed to prevent an incompatible loader being added to
|
||||
// a route, but the two different loader types-- ones that take arguments, and ones that do not-- do
|
||||
// not matter to the route builder.
|
||||
|
||||
// On the other hand, the two different kinds of redirects *do* matter, but only because JavaScript
|
||||
// makes a distinction between methods of one argument that can be `call`'ed and methods of more
|
||||
// than one argument that must be `apply`'d. (Spread arguments are converted to call or apply as
|
||||
// needed).
|
||||
|
||||
// prettier-ignore
|
||||
export function makeRoute(route: RawRoute): Route {
|
||||
return match(route)
|
||||
.with([P.string, P.when(isLoader)],
|
||||
([path, loader]) => new Route(new RegExp(path), loader))
|
||||
.with([P.string, P.string],
|
||||
([path, redirect]) => new Route(new RegExp(path)).redirect(redirect))
|
||||
.with([P.string, [P.string, P.boolean]],
|
||||
([path, redirect]) => new Route(new RegExp(path)).redirect(...redirect))
|
||||
.exhaustive();
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
import { ensureCSSStyleSheet } from "@goauthentik/authentik/elements/utils/ensureCSSStyleSheet";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import {
|
||||
EVENT_FLOW_ADVANCE,
|
||||
@ -33,7 +32,6 @@ import PFTitle from "@patternfly/patternfly/components/Title/title.css";
|
||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
|
||||
import {
|
||||
CapabilitiesEnum,
|
||||
ChallengeChoices,
|
||||
ChallengeTypes,
|
||||
ContextualFlowInfo,
|
||||
@ -77,8 +75,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
@state()
|
||||
flowInfo?: ContextualFlowInfo;
|
||||
|
||||
@state()
|
||||
frameMode = window !== window.top;
|
||||
ws: WebsocketClient;
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [PFBase, PFLogin, PFDrawer, PFButton, PFTitle, PFList, PFBackgroundImage].concat(css`
|
||||
@ -142,25 +139,6 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
:host([theme="dark"]) .pf-c-login.sidebar_right .pf-c-list {
|
||||
color: var(--ak-dark-foreground);
|
||||
}
|
||||
/* frame design */
|
||||
.pf-c-login.frame {
|
||||
padding: 0;
|
||||
min-height: initial !important;
|
||||
}
|
||||
.pf-c-login.frame .pf-c-login__main {
|
||||
margin-bottom: 0;
|
||||
height: 100%;
|
||||
}
|
||||
.pf-c-login.frame .ak-login-container {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
}
|
||||
.pf-c-login.frame .pf-c-login__footer {
|
||||
display: none;
|
||||
}
|
||||
.pf-c-login.frame .pf-c-login__footer .pf-c-list {
|
||||
padding: 0;
|
||||
}
|
||||
.pf-c-brand {
|
||||
padding-top: calc(
|
||||
var(--pf-c-login__main-footer-links--PaddingTop) +
|
||||
@ -182,23 +160,9 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
if (this.frameMode) {
|
||||
// PatternFly sets html and body to 100% height, which we don't
|
||||
// want in this case since the iframe should only take the space it needs
|
||||
document.adoptedStyleSheets = [
|
||||
...document.adoptedStyleSheets,
|
||||
ensureCSSStyleSheet(css`
|
||||
body,
|
||||
html {
|
||||
height: unset !important;
|
||||
}
|
||||
`),
|
||||
];
|
||||
} else {
|
||||
new WebsocketClient();
|
||||
}
|
||||
this.ws = new WebsocketClient();
|
||||
if (window.location.search.includes("inspector")) {
|
||||
this.inspectorOpen = true;
|
||||
this.inspectorOpen = !this.inspectorOpen;
|
||||
}
|
||||
this.addEventListener(EVENT_FLOW_INSPECTOR_TOGGLE, () => {
|
||||
this.inspectorOpen = !this.inspectorOpen;
|
||||
@ -249,9 +213,6 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
|
||||
async firstUpdated(): Promise<void> {
|
||||
configureSentry();
|
||||
if (this.config?.capabilities.includes(CapabilitiesEnum.CanDebug)) {
|
||||
this.inspectorOpen = true;
|
||||
}
|
||||
this.loading = true;
|
||||
try {
|
||||
const challenge = await new FlowsApi(DEFAULT_CONFIG).flowsExecutorGet({
|
||||
@ -472,11 +433,9 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
}
|
||||
|
||||
renderChallengeWrapper(): TemplateResult {
|
||||
const logo = this.frameMode
|
||||
? nothing
|
||||
: html`<div class="pf-c-login__main-header pf-c-brand ak-brand">
|
||||
<img src="${first(this.brand?.brandingLogo, "")}" alt="authentik Logo" />
|
||||
</div>`;
|
||||
const logo = html`<div class="pf-c-login__main-header pf-c-brand ak-brand">
|
||||
<img src="${first(this.brand?.brandingLogo, "")}" alt="authentik Logo" />
|
||||
</div>`;
|
||||
if (!this.challenge) {
|
||||
return html`${logo}<ak-empty-state ?loading=${true} header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
@ -519,26 +478,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
if (this.frameMode) {
|
||||
return html`<ak-locale-context>
|
||||
<div class="pf-c-login frame">
|
||||
<div class="ak-login-container">
|
||||
<div class="pf-c-login__main">${this.renderChallengeWrapper()}</div>
|
||||
<footer class="pf-c-login__footer">
|
||||
<ul class="pf-c-list pf-m-inline">
|
||||
<li>
|
||||
<a
|
||||
href="https://goauthentik.io?utm_source=authentik&utm_medium=flow"
|
||||
>${msg("Powered by authentik")}</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</ak-locale-context>`;
|
||||
}
|
||||
return html`<ak-locale-context>
|
||||
return html` <ak-locale-context>
|
||||
<div class="pf-c-background-image"></div>
|
||||
<div class="pf-c-page__drawer">
|
||||
<div class="pf-c-drawer ${this.inspectorOpen ? "pf-m-expanded" : "pf-m-collapsed"}">
|
||||
|
@ -37,10 +37,6 @@ export class FlowInspector extends AKElement {
|
||||
PFDescriptionList,
|
||||
PFProgressStepper,
|
||||
css`
|
||||
.pf-c-drawer__body {
|
||||
min-height: 100vh;
|
||||
max-height: 100vh;
|
||||
}
|
||||
code.break {
|
||||
word-break: break-all;
|
||||
}
|
||||
@ -49,6 +45,9 @@ export class FlowInspector extends AKElement {
|
||||
overflow-x: hidden;
|
||||
white-space: break-spaces;
|
||||
}
|
||||
.pf-c-notification-drawer__body {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
@ -114,7 +113,6 @@ export class FlowInspector extends AKElement {
|
||||
return this.renderAccessDenied();
|
||||
}
|
||||
if (!this.state) {
|
||||
this.advanceHandler();
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
}
|
||||
|
@ -49,27 +49,8 @@ export class RedirectStage extends BaseStage<RedirectChallenge, FlowChallengeRes
|
||||
"authentik/stages/redirect: redirecting to url from server",
|
||||
this.challenge.to,
|
||||
);
|
||||
window.location.assign(this.challenge.to);
|
||||
this.startedRedirect = true;
|
||||
if (this.host.frameMode && window.top) {
|
||||
try {
|
||||
window.top.location.assign(this.challenge.to);
|
||||
} catch {
|
||||
window.top.postMessage(
|
||||
{
|
||||
source: "goauthentik.io",
|
||||
context: "flow-executor",
|
||||
component: this.challenge.component,
|
||||
to: this.challenge.to,
|
||||
},
|
||||
document.location.ancestorOrigins[0],
|
||||
);
|
||||
}
|
||||
if (this.challenge.to.startsWith("http")) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
window.location.assign(this.challenge.to);
|
||||
}
|
||||
}
|
||||
|
||||
renderLoading(): TemplateResult {
|
||||
|
@ -1,58 +0,0 @@
|
||||
import type { StoryObj } from "@storybook/web-components";
|
||||
|
||||
import { html } from "lit";
|
||||
|
||||
import "@patternfly/patternfly/components/Login/login.css";
|
||||
|
||||
import { AuthenticatorTOTPChallenge, ChallengeChoices, UiThemeEnum } from "@goauthentik/api";
|
||||
|
||||
import "../../../stories/flow-interface";
|
||||
import "./AuthenticatorTOTPStage";
|
||||
|
||||
export default {
|
||||
title: "Flow / Stages / AuthenticatorTOTPStage",
|
||||
};
|
||||
|
||||
export const LoadingNoChallenge = () => {
|
||||
return html`<ak-storybook-interface theme=${UiThemeEnum.Dark}>
|
||||
<div class="pf-c-login">
|
||||
<div class="pf-c-login__container">
|
||||
<div class="pf-c-login__main">
|
||||
<ak-stage-authenticator-totp></ak-stage-authenticator-totp>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ak-storybook-interface>`;
|
||||
};
|
||||
|
||||
export const Challenge: StoryObj = {
|
||||
render: ({ theme, challenge }) => {
|
||||
return html`<ak-storybook-interface theme=${theme}>
|
||||
<div class="pf-c-login">
|
||||
<div class="pf-c-login__container">
|
||||
<div class="pf-c-login__main">
|
||||
<ak-stage-authenticator-totp
|
||||
.challenge=${challenge}
|
||||
></ak-stage-authenticator-totp>
|
||||
</div>
|
||||
</div></div
|
||||
></ak-storybook-interface>`;
|
||||
},
|
||||
args: {
|
||||
theme: "automatic",
|
||||
challenge: {
|
||||
type: ChallengeChoices.Native,
|
||||
pendingUser: "foo",
|
||||
pendingUserAvatar: "https://picsum.photos/64",
|
||||
configUrl: "",
|
||||
} as AuthenticatorTOTPChallenge,
|
||||
},
|
||||
argTypes: {
|
||||
theme: {
|
||||
options: [UiThemeEnum.Automatic, UiThemeEnum.Light, UiThemeEnum.Dark],
|
||||
control: {
|
||||
type: "select",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
@ -106,11 +106,6 @@ export class AuthenticatorTOTPStage extends BaseStage<
|
||||
</button>
|
||||
</div>
|
||||
</ak-form-element>
|
||||
<p>
|
||||
${msg(
|
||||
"Please scan the QR code above using the Microsoft Authenticator, Google Authenticator, or other authenticator apps on your device, and enter the code the device displays below to finish setting up the MFA device.",
|
||||
)}
|
||||
</p>
|
||||
<ak-form-element
|
||||
label="${msg("Code")}"
|
||||
?required="${true}"
|
||||
|
@ -47,10 +47,6 @@ export class AuthenticatorValidateStage
|
||||
return this.host.brand;
|
||||
}
|
||||
|
||||
get frameMode(): boolean {
|
||||
return this.host.frameMode;
|
||||
}
|
||||
|
||||
@state()
|
||||
_selectedDeviceChallenge?: DeviceChallenge;
|
||||
|
||||
|
@ -16,7 +16,6 @@ export interface StageHost {
|
||||
challenge?: unknown;
|
||||
flowSlug?: string;
|
||||
loading: boolean;
|
||||
frameMode: boolean;
|
||||
submit(payload: unknown, options?: SubmitOptions): Promise<boolean>;
|
||||
|
||||
readonly brand?: CurrentBrand;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user