Merge branch 'main' into dev

* main: (25 commits)
  root: fix readme (#9178)
  enterprise: fix audit middleware import (#9177)
  web: bump @spotlightjs/spotlight from 1.2.16 to 1.2.17 in /web in the sentry group (#9162)
  web: bump API Client version (#9174)
  stages/authenticator_webauthn: add MDS support (#9114)
  website/integrations: Update Nextcloud OIDC secret size limitation (#9139)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#9170)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#9171)
  web: bump the rollup group in /web with 3 updates (#9164)
  web: bump @codemirror/legacy-modes from 6.3.3 to 6.4.0 in /web (#9166)
  web: bump ts-pattern from 5.1.0 to 5.1.1 in /web (#9167)
  core: bump github.com/go-ldap/ldap/v3 from 3.4.6 to 3.4.7 (#9168)
  core, web: update translations (#9156)
  root: fix redis username in lifecycle (#9158)
  web: ak-checkbox-group for short, static, multi-select events (#9138)
  root: fix startup (#9151)
  core: Bump golang.org/x/oauth2 from 0.18.0 to 0.19.0 (#9146)
  core: Bump twilio from 9.0.3 to 9.0.4 (#9143)
  web: Bump country-flag-icons from 1.5.10 to 1.5.11 in /web (#9144)
  web: Bump typescript from 5.4.3 to 5.4.4 in /web (#9145)
  ...
This commit is contained in:
Ken Sternberg
2024-04-08 09:22:54 -07:00
71 changed files with 2339 additions and 730 deletions

2
.github/FUNDING.yml vendored
View File

@ -1 +1 @@
github: [BeryJu]
custom: https://goauthentik.io/pricing/

View File

@ -0,0 +1,37 @@
name: authentik-gen-update-webauthn-mds
on:
workflow_dispatch:
schedule:
- cron: '30 1 1,15 * *'
jobs:
build:
runs-on: ubuntu-latest
steps:
- id: generate_token
uses: tibdex/github-app-token@v2
with:
app_id: ${{ secrets.GH_APP_ID }}
private_key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/checkout@v4
with:
token: ${{ steps.generate_token.outputs.token }}
- name: Setup authentik env
uses: ./.github/actions/setup
- run: poetry run ak update_webauthn_mds
- uses: peter-evans/create-pull-request@v6
id: cpr
with:
token: ${{ steps.generate_token.outputs.token }}
branch: update-fido-mds-client
commit-message: "stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs"
title: "stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs"
body: "stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs"
delete-branch: true
signoff: true
# ID from https://api.github.com/users/authentik-automation[bot]
author: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
- uses: peter-evans/enable-pull-request-automerge@v3
with:
token: ${{ steps.generate_token.outputs.token }}
pull-request-number: ${{ steps.cpr.outputs.pull-request-number }}
merge-method: squash

View File

@ -65,7 +65,7 @@ lint-fix: ## Lint and automatically fix errors in the python source code. Repor
codespell -w $(CODESPELL_ARGS)
lint: ## Lint the python and golang sources
bandit -r $(PY_SOURCES) -x node_modules
bandit -r $(PY_SOURCES) -x web/node_modules -x tests/wdio/node_modules -x website/node_modules
golangci-lint run -v
core-install:

View File

@ -25,10 +25,10 @@ For bigger setups, there is a Helm Chart [here](https://github.com/goauthentik/h
## Screenshots
| Light | Dark |
| ------------------------------------------------------ | ----------------------------------------------------- |
| ![](https://goauthentik.io/img/screen_apps_light.jpg) | ![](https://goauthentik.io/img/screen_apps_dark.jpg) |
| ![](https://goauthentik.io/img/screen_admin_light.jpg) | ![](https://goauthentik.io/img/screen_admin_dark.jpg) |
| Light | Dark |
| ----------------------------------------------------------- | ---------------------------------------------------------- |
| ![](https://docs.goauthentik.io/img/screen_apps_light.jpg) | ![](https://docs.goauthentik.io/img/screen_apps_dark.jpg) |
| ![](https://docs.goauthentik.io/img/screen_admin_light.jpg) | ![](https://docs.goauthentik.io/img/screen_admin_dark.jpg) |
## Development

View File

@ -4,12 +4,14 @@ from json import dumps
from typing import Any
from django.core.management.base import BaseCommand, no_translations
from django.db.models import Model
from drf_jsonschema_serializer.convert import field_to_converter
from django.db.models import Model, fields
from drf_jsonschema_serializer.convert import converter, field_to_converter
from rest_framework.fields import Field, JSONField, UUIDField
from rest_framework.relations import PrimaryKeyRelatedField
from rest_framework.serializers import Serializer
from structlog.stdlib import get_logger
from authentik import __version__
from authentik.blueprints.v1.common import BlueprintEntryDesiredState
from authentik.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT, is_model_allowed
from authentik.blueprints.v1.meta.registry import BaseMetaModel, registry
@ -18,6 +20,23 @@ from authentik.lib.models import SerializerModel
LOGGER = get_logger()
@converter
class PrimaryKeyRelatedFieldConverter:
"""Custom primary key field converter which is aware of non-integer based PKs
This is not an exhaustive fix for other non-int PKs, however in authentik we either
use UUIDs or ints"""
field_class = PrimaryKeyRelatedField
def convert(self, field: PrimaryKeyRelatedField):
model: Model = field.queryset.model
pk_field = model._meta.pk
if isinstance(pk_field, fields.UUIDField):
return {"type": "string", "format": "uuid"}
return {"type": "integer"}
class Command(BaseCommand):
"""Generate JSON Schema for blueprints"""
@ -29,7 +48,7 @@ class Command(BaseCommand):
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://goauthentik.io/blueprints/schema.json",
"type": "object",
"title": "authentik Blueprint schema",
"title": f"authentik {__version__} Blueprint schema",
"required": ["version", "entries"],
"properties": {
"version": {

View File

@ -556,7 +556,11 @@ class BlueprintDumper(SafeDumper):
def factory(items):
final_dict = dict(items)
# Remove internal state variables
final_dict.pop("_state", None)
# Future-proof to only remove the ID if we don't set a value
if "id" in final_dict and final_dict.get("id") is None:
final_dict.pop("id")
return final_dict
data = asdict(data, dict_factory=factory)

View File

@ -51,6 +51,7 @@ from authentik.policies.models import Policy, PolicyBindingModel
from authentik.policies.reputation.models import Reputation
from authentik.providers.oauth2.models import AccessToken, AuthorizationCode, RefreshToken
from authentik.providers.scim.models import SCIMGroup, SCIMUser
from authentik.stages.authenticator_webauthn.models import WebAuthnDeviceType
from authentik.tenants.models import Tenant
# Context set when the serializer is created in a blueprint context
@ -95,6 +96,7 @@ def excluded_models() -> list[type[Model]]:
AccessToken,
RefreshToken,
Reputation,
WebAuthnDeviceType,
)

View File

@ -13,9 +13,9 @@ class AuthentikEnterpriseAuditConfig(EnterpriseConfig):
verbose_name = "authentik Enterprise.Audit"
default = True
@EnterpriseConfig.reconcile_global
def install_middleware(self):
def ready(self):
"""Install enterprise audit middleware"""
orig_import = "authentik.events.middleware.AuditMiddleware"
new_import = "authentik.enterprise.audit.middleware.EnterpriseAuditMiddleware"
settings.MIDDLEWARE = [new_import if x == orig_import else x for x in settings.MIDDLEWARE]
return super().ready()

View File

@ -0,0 +1,18 @@
from django.apps import apps
from django.conf import settings
from django.test import TestCase
class TestEnterpriseAudit(TestCase):
def test_import(self):
"""Ensure middleware is imported when app.ready is called"""
# Revert import swap
orig_import = "authentik.events.middleware.AuditMiddleware"
new_import = "authentik.enterprise.audit.middleware.EnterpriseAuditMiddleware"
settings.MIDDLEWARE = [orig_import if x == new_import else x for x in settings.MIDDLEWARE]
# Re-call ready()
apps.get_app_config("authentik_enterprise_audit").ready()
self.assertIn(
"authentik.enterprise.audit.middleware.EnterpriseAuditMiddleware", settings.MIDDLEWARE
)

View File

@ -2,11 +2,11 @@
from uuid import uuid4
from django.conf import settings
from requests.sessions import PreparedRequest, Session
from structlog.stdlib import get_logger
from authentik import get_full_version
from authentik.lib.config import CONFIG
LOGGER = get_logger()
@ -35,6 +35,6 @@ class DebugSession(Session):
def get_http_session() -> Session:
"""Get a requests session with common headers"""
session = DebugSession() if settings.DEBUG else Session()
session = DebugSession() if CONFIG.get_bool("debug") else Session()
session.headers["User-Agent"] = authentik_user_agent()
return session

View File

@ -4,7 +4,7 @@ from django.urls import reverse
from guardian.shortcuts import assign_perm
from rest_framework.test import APITestCase
from authentik.core.models import Group, UserTypes
from authentik.core.models import Group, User, UserTypes
from authentik.core.tests.utils import create_test_admin_user, create_test_user
from authentik.lib.generators import generate_id
from authentik.rbac.api.rbac_assigned_by_users import UserAssignedObjectPermissionSerializer
@ -26,6 +26,7 @@ class TestRBACUserAPI(APITestCase):
def test_filter_assigned(self):
"""Test UserAssignedPermissionViewSet's filters"""
User.objects.filter(username="akadmin").delete()
inv = Invitation.objects.create(
name=generate_id(),
created_by=self.superuser,

View File

@ -163,6 +163,7 @@ def validate_challenge_webauthn(data: dict, stage_view: StageView, user: User) -
stage=stage_view.executor.current_stage,
device=device,
device_class=DeviceClasses.WEBAUTHN.value,
device_type=device.device_type,
)
raise ValidationError("Assertion failed") from exc

View File

@ -398,5 +398,6 @@ class AuthenticatorValidateStageView(ChallengeStageView):
self.executor.plan.context[PLAN_CONTEXT_METHOD] = "auth_webauthn_pwl"
self.executor.plan.context[PLAN_CONTEXT_METHOD_ARGS] = {
"device": webauthn_device,
"device_type": webauthn_device.device_type,
}
return self.set_valid_mfa_cookie(response.device)

View File

@ -0,0 +1,27 @@
"""WebAuthnDeviceType API Views"""
from rest_framework.viewsets import ReadOnlyModelViewSet
from authentik.flows.api.stages import StageSerializer
from authentik.stages.authenticator_webauthn.models import WebAuthnDeviceType
class WebAuthnDeviceTypeSerializer(StageSerializer):
"""WebAuthnDeviceType Serializer"""
class Meta:
model = WebAuthnDeviceType
fields = [
"aaguid",
"description",
]
class WebAuthnDeviceTypeViewSet(ReadOnlyModelViewSet):
"""WebAuthnDeviceType Viewset"""
queryset = WebAuthnDeviceType.objects.all()
serializer_class = WebAuthnDeviceTypeSerializer
filterset_fields = "__all__"
ordering = ["description"]
search_fields = ["description", "aaguid"]

View File

@ -1,4 +1,4 @@
"""AuthenticateWebAuthnStage API Views"""
"""AuthenticatorWebAuthnStage API Views"""
from django_filters.rest_framework.backends import DjangoFilterBackend
from rest_framework import mixins
@ -9,41 +9,18 @@ from rest_framework.viewsets import GenericViewSet, ModelViewSet
from authentik.api.authorization import OwnerFilter, OwnerPermissions
from authentik.core.api.used_by import UsedByMixin
from authentik.flows.api.stages import StageSerializer
from authentik.stages.authenticator_webauthn.models import AuthenticateWebAuthnStage, WebAuthnDevice
class AuthenticateWebAuthnStageSerializer(StageSerializer):
"""AuthenticateWebAuthnStage Serializer"""
class Meta:
model = AuthenticateWebAuthnStage
fields = StageSerializer.Meta.fields + [
"configure_flow",
"friendly_name",
"user_verification",
"authenticator_attachment",
"resident_key_requirement",
]
class AuthenticateWebAuthnStageViewSet(UsedByMixin, ModelViewSet):
"""AuthenticateWebAuthnStage Viewset"""
queryset = AuthenticateWebAuthnStage.objects.all()
serializer_class = AuthenticateWebAuthnStageSerializer
filterset_fields = "__all__"
ordering = ["name"]
search_fields = ["name"]
from authentik.stages.authenticator_webauthn.api.device_types import WebAuthnDeviceTypeSerializer
from authentik.stages.authenticator_webauthn.models import WebAuthnDevice
class WebAuthnDeviceSerializer(ModelSerializer):
"""Serializer for WebAuthn authenticator devices"""
device_type = WebAuthnDeviceTypeSerializer(read_only=True, allow_null=True)
class Meta:
model = WebAuthnDevice
fields = ["pk", "name", "created_on"]
depth = 2
fields = ["pk", "name", "created_on", "device_type"]
class WebAuthnDeviceViewSet(

View File

@ -0,0 +1,38 @@
"""AuthenticatorWebAuthnStage API Views"""
from rest_framework.viewsets import ModelViewSet
from authentik.core.api.used_by import UsedByMixin
from authentik.flows.api.stages import StageSerializer
from authentik.stages.authenticator_webauthn.api.device_types import WebAuthnDeviceTypeSerializer
from authentik.stages.authenticator_webauthn.models import AuthenticatorWebAuthnStage
class AuthenticatorWebAuthnStageSerializer(StageSerializer):
"""AuthenticatorWebAuthnStage Serializer"""
device_type_restrictions_obj = WebAuthnDeviceTypeSerializer(
source="device_type_restrictions", many=True, read_only=True
)
class Meta:
model = AuthenticatorWebAuthnStage
fields = StageSerializer.Meta.fields + [
"configure_flow",
"friendly_name",
"user_verification",
"authenticator_attachment",
"resident_key_requirement",
"device_type_restrictions",
"device_type_restrictions_obj",
]
class AuthenticatorWebAuthnStageViewSet(UsedByMixin, ModelViewSet):
"""AuthenticatorWebAuthnStage Viewset"""
queryset = AuthenticatorWebAuthnStage.objects.all()
serializer_class = AuthenticatorWebAuthnStageSerializer
filterset_fields = "__all__"
ordering = ["name"]
search_fields = ["name"]

View File

@ -1,11 +1,22 @@
"""authentik webauthn app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikStageAuthenticatorWebAuthnConfig(AppConfig):
class AuthentikStageAuthenticatorWebAuthnConfig(ManagedAppConfig):
"""authentik webauthn config"""
name = "authentik.stages.authenticator_webauthn"
label = "authentik_stages_authenticator_webauthn"
verbose_name = "authentik Stages.Authenticator.WebAuthn"
default = True
@ManagedAppConfig.reconcile_tenant
def webauthn_device_types(self):
from authentik.stages.authenticator_webauthn.tasks import (
webauthn_aaguid_import,
webauthn_mds_import,
)
webauthn_mds_import.delay()
webauthn_aaguid_import.delay()

View File

@ -0,0 +1,34 @@
from django.core.management.base import BaseCommand
from fido2.mds3 import parse_blob
from structlog.stdlib import get_logger
from authentik.lib.utils.http import get_http_session
from authentik.stages.authenticator_webauthn.tasks import AAGUID_BLOB_PATH, MDS_BLOB_PATH, mds_ca
MDS3_URL = "https://mds3.fidoalliance.org/"
AAGUID_URL = "https://passkeydeveloper.github.io/passkey-authenticator-aaguids/aaguid.json"
class Command(BaseCommand):
"""Update FIDO Alliances' MDS3 blob and validate it."""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.logger = get_logger()
def update_fido_mds(self):
with open(MDS_BLOB_PATH, "w", encoding="utf-8") as _raw_file:
_raw_file.write(get_http_session().get(MDS3_URL).text)
self.logger.info("Updated MDS blob")
with open(MDS_BLOB_PATH, mode="rb") as _raw_blob:
parse_blob(_raw_blob.read(), mds_ca())
self.logger.info("Successfully validated MDS blob")
def update_passkey_aaguids(self):
with open(AAGUID_BLOB_PATH, "w", encoding="utf-8") as _raw_file:
_raw_file.write(get_http_session().get(AAGUID_URL).text)
self.logger.info("Updated AAGUID blob")
def handle(self, *args, **options):
self.update_fido_mds()
self.update_passkey_aaguids()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,45 @@
# Generated by Django 5.0.3 on 2024-04-02 23:38
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_flows", "0027_auto_20231028_1424"),
("authentik_stages_authenticator_webauthn", "0009_authenticatewebauthnstage_friendly_name"),
]
operations = [
migrations.CreateModel(
name="WebAuthnDeviceType",
fields=[
("aaguid", models.UUIDField(primary_key=True, serialize=False, unique=True)),
("description", models.TextField()),
("icon", models.TextField(null=True)),
],
options={
"verbose_name": "WebAuthn Device type",
"verbose_name_plural": "WebAuthn Device types",
},
),
migrations.RenameModel("AuthenticateWebAuthnStage", "AuthenticatorWebAuthnStage"),
migrations.AddField(
model_name="webauthndevice",
name="device_type",
field=models.ForeignKey(
default=None,
null=True,
on_delete=django.db.models.deletion.SET_DEFAULT,
to="authentik_stages_authenticator_webauthn.webauthndevicetype",
),
),
migrations.AddField(
model_name="authenticatorwebauthnstage",
name="device_type_restrictions",
field=models.ManyToManyField(
blank=True, to="authentik_stages_authenticator_webauthn.webauthndevicetype"
),
),
]

View File

@ -14,6 +14,8 @@ from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage
from authentik.lib.models import SerializerModel
from authentik.stages.authenticator.models import Device
UNKNOWN_DEVICE_TYPE_AAGUID = "00000000-0000-0000-0000-000000000000"
class UserVerification(models.TextChoices):
"""The degree to which the Relying Party wishes to verify a user's identity.
@ -65,7 +67,7 @@ class AuthenticatorAttachment(models.TextChoices):
CROSS_PLATFORM = "cross-platform"
class AuthenticateWebAuthnStage(ConfigurableStage, FriendlyNamedStage, Stage):
class AuthenticatorWebAuthnStage(ConfigurableStage, FriendlyNamedStage, Stage):
"""WebAuthn stage"""
user_verification = models.TextField(
@ -80,11 +82,15 @@ class AuthenticateWebAuthnStage(ConfigurableStage, FriendlyNamedStage, Stage):
choices=AuthenticatorAttachment.choices, default=None, null=True
)
device_type_restrictions = models.ManyToManyField("WebAuthnDeviceType", blank=True)
@property
def serializer(self) -> type[BaseSerializer]:
from authentik.stages.authenticator_webauthn.api import AuthenticateWebAuthnStageSerializer
from authentik.stages.authenticator_webauthn.api.stages import (
AuthenticatorWebAuthnStageSerializer,
)
return AuthenticateWebAuthnStageSerializer
return AuthenticatorWebAuthnStageSerializer
@property
def view(self) -> type[View]:
@ -126,6 +132,10 @@ class WebAuthnDevice(SerializerModel, Device):
created_on = models.DateTimeField(auto_now_add=True)
last_t = models.DateTimeField(default=now)
device_type = models.ForeignKey(
"WebAuthnDeviceType", on_delete=models.SET_DEFAULT, null=True, default=None
)
@property
def descriptor(self) -> PublicKeyCredentialDescriptor:
"""Get a publickeydescriptor for this device"""
@ -139,7 +149,7 @@ class WebAuthnDevice(SerializerModel, Device):
@property
def serializer(self) -> Serializer:
from authentik.stages.authenticator_webauthn.api import WebAuthnDeviceSerializer
from authentik.stages.authenticator_webauthn.api.devices import WebAuthnDeviceSerializer
return WebAuthnDeviceSerializer
@ -149,3 +159,27 @@ class WebAuthnDevice(SerializerModel, Device):
class Meta:
verbose_name = _("WebAuthn Device")
verbose_name_plural = _("WebAuthn Devices")
class WebAuthnDeviceType(SerializerModel):
"""WebAuthn device type, used to restrict which device types are allowed"""
aaguid = models.UUIDField(primary_key=True, unique=True)
description = models.TextField()
icon = models.TextField(null=True)
@property
def serializer(self) -> Serializer:
from authentik.stages.authenticator_webauthn.api.device_types import (
WebAuthnDeviceTypeSerializer,
)
return WebAuthnDeviceTypeSerializer
class Meta:
verbose_name = _("WebAuthn Device type")
verbose_name_plural = _("WebAuthn Device types")
def __str__(self) -> str:
return f"WebAuthn device type {self.description} ({self.aaguid})"

View File

@ -1,15 +1,18 @@
"""WebAuthn stage"""
from json import loads
from uuid import UUID
from django.http import HttpRequest, HttpResponse
from django.http.request import QueryDict
from django.utils.translation import gettext_lazy as _
from rest_framework.fields import CharField
from rest_framework.serializers import ValidationError
from webauthn import options_to_json
from webauthn.helpers.bytes_to_base64url import bytes_to_base64url
from webauthn.helpers.exceptions import InvalidRegistrationResponse
from webauthn.helpers.structs import (
AttestationConveyancePreference,
AuthenticatorAttachment,
AuthenticatorSelectionCriteria,
PublicKeyCredentialCreationOptions,
@ -31,7 +34,12 @@ from authentik.flows.challenge import (
WithUserInfoChallenge,
)
from authentik.flows.stage import ChallengeStageView
from authentik.stages.authenticator_webauthn.models import AuthenticateWebAuthnStage, WebAuthnDevice
from authentik.stages.authenticator_webauthn.models import (
UNKNOWN_DEVICE_TYPE_AAGUID,
AuthenticatorWebAuthnStage,
WebAuthnDevice,
WebAuthnDeviceType,
)
from authentik.stages.authenticator_webauthn.utils import get_origin, get_rp_id
SESSION_KEY_WEBAUTHN_CHALLENGE = "authentik/stages/authenticator_webauthn/challenge"
@ -74,6 +82,30 @@ class AuthenticatorWebAuthnChallengeResponse(ChallengeResponse):
if credential_id_exists:
raise ValidationError("Credential ID already exists.")
stage: AuthenticatorWebAuthnStage = self.stage.executor.current_stage
aaguid = registration.aaguid
allowed_aaguids = stage.device_type_restrictions.values_list("aaguid", flat=True)
if allowed_aaguids.exists():
invalid_error = ValidationError(
_(
"Invalid device type. Contact your {brand} administrator for help.".format(
brand=self.stage.request.brand.branding_title
)
)
)
# If there are any restrictions set and we didn't get an aaguid, invalid
if not aaguid:
raise invalid_error
# If one of the restrictions is the "special" unknown device type UUID
# but we do have a device type for the given aaguid, invalid
if (
UUID(UNKNOWN_DEVICE_TYPE_AAGUID) in allowed_aaguids
and not WebAuthnDeviceType.objects.filter(aaguid=aaguid).exists()
):
return registration
# Otherwise just check if the given aaguid is in the allowed aaguids
if UUID(aaguid) not in allowed_aaguids:
raise invalid_error
return registration
@ -85,7 +117,7 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
def get_challenge(self, *args, **kwargs) -> Challenge:
# clear session variables prior to starting a new registration
self.request.session.pop(SESSION_KEY_WEBAUTHN_CHALLENGE, None)
stage: AuthenticateWebAuthnStage = self.executor.current_stage
stage: AuthenticatorWebAuthnStage = self.executor.current_stage
user = self.get_pending_user()
# library accepts none so we store null in the database, but if there is a value
@ -105,6 +137,7 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
user_verification=UserVerificationRequirement(str(stage.user_verification)),
authenticator_attachment=authenticator_attachment,
),
attestation=AttestationConveyancePreference.DIRECT,
)
self.request.session[SESSION_KEY_WEBAUTHN_CHALLENGE] = registration_options.challenge
@ -129,13 +162,20 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
credential_id=bytes_to_base64url(webauthn_credential.credential_id)
).first()
if not existing_device:
name = "WebAuthn Device"
device_type = WebAuthnDeviceType.objects.filter(
aaguid=webauthn_credential.aaguid
).first()
if device_type and device_type.description:
name = device_type.description
WebAuthnDevice.objects.create(
name=name,
user=self.get_pending_user(),
public_key=bytes_to_base64url(webauthn_credential.credential_public_key),
credential_id=bytes_to_base64url(webauthn_credential.credential_id),
sign_count=webauthn_credential.sign_count,
rp_id=get_rp_id(self.request),
name="WebAuthn Device",
device_type=device_type,
)
else:
return self.executor.stage_invalid("Device with Credential ID already exists.")

View File

@ -0,0 +1,69 @@
"""MDS Helpers"""
from functools import lru_cache
from json import loads
from pathlib import Path
from django.core.cache import cache
from django.db.transaction import atomic
from fido2.mds3 import filter_revoked, parse_blob
from authentik.root.celery import CELERY_APP
from authentik.stages.authenticator_webauthn.models import (
UNKNOWN_DEVICE_TYPE_AAGUID,
WebAuthnDeviceType,
)
CACHE_KEY_MDS_NO = "goauthentik.io/stages/authenticator_webauthn/mds_no"
AAGUID_BLOB_PATH = Path(__file__).parent / "mds" / "aaguid.json"
MDS_BLOB_PATH = Path(__file__).parent / "mds" / "blob.jwt"
MDS_CA_PATH = Path(__file__).parent / "mds" / "root-r3.crt"
@lru_cache
def mds_ca() -> bytes:
"""Cache MDS Signature CA, GlobalSign Root CA - R3"""
with open(MDS_CA_PATH, mode="rb") as _raw_root:
return _raw_root.read()
@CELERY_APP.task()
def webauthn_mds_import(force=False):
"""Background task to import FIDO Alliance MDS blob into database"""
with open(MDS_BLOB_PATH, mode="rb") as _raw_blob:
blob = parse_blob(_raw_blob.read(), mds_ca())
with atomic():
WebAuthnDeviceType.objects.update_or_create(
aaguid=UNKNOWN_DEVICE_TYPE_AAGUID,
defaults={
"description": "authentik: Unknown devices",
},
)
if cache.get(CACHE_KEY_MDS_NO) == blob.no and not force:
return
for entry in blob.entries:
aaguid = entry.aaguid
if not aaguid:
continue
if not filter_revoked(entry):
WebAuthnDeviceType.objects.filter(aaguid=str(aaguid)).delete()
continue
metadata = entry.metadata_statement
WebAuthnDeviceType.objects.update_or_create(
aaguid=str(aaguid),
defaults={"description": metadata.description, "icon": metadata.icon},
)
cache.set(CACHE_KEY_MDS_NO, blob.no)
@CELERY_APP.task()
def webauthn_aaguid_import(force=False):
"""Background task to import AAGUIDs into database"""
with open(AAGUID_BLOB_PATH, mode="rb") as _raw_blob:
entries = loads(_raw_blob.read())
with atomic():
for aaguid, details in entries.items():
WebAuthnDeviceType.objects.update_or_create(
aaguid=str(aaguid),
defaults={"description": details.get("name"), "icon": details.get("icon_light")},
)

View File

@ -12,15 +12,24 @@ from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, 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.stages.authenticator_webauthn.models import AuthenticateWebAuthnStage, WebAuthnDevice
from authentik.stages.authenticator_webauthn.models import (
UNKNOWN_DEVICE_TYPE_AAGUID,
AuthenticatorWebAuthnStage,
WebAuthnDevice,
WebAuthnDeviceType,
)
from authentik.stages.authenticator_webauthn.stage import SESSION_KEY_WEBAUTHN_CHALLENGE
from authentik.stages.authenticator_webauthn.tasks import (
webauthn_aaguid_import,
webauthn_mds_import,
)
class TestAuthenticatorWebAuthnStage(FlowTestCase):
"""Test WebAuthn API"""
def setUp(self) -> None:
self.stage = AuthenticateWebAuthnStage.objects.create(
self.stage = AuthenticatorWebAuthnStage.objects.create(
name=generate_id(),
)
self.flow = create_test_flow()
@ -46,10 +55,6 @@ class TestAuthenticatorWebAuthnStage(FlowTestCase):
plan.context[PLAN_CONTEXT_PENDING_USER] = self.user
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session[SESSION_KEY_WEBAUTHN_CHALLENGE] = b64decode(
b"o90Yh1osqW3mjGift+6WclWOya5lcdff/G0mqueN3hChacMUz"
b"V4mxiDafuQ0x0e1d/fcPai0fx/jMBZ8/nG2qQ=="
)
session.save()
response = self.client.get(
@ -87,6 +92,218 @@ class TestAuthenticatorWebAuthnStage(FlowTestCase):
"requireResidentKey": False,
"userVerification": "preferred",
},
"attestation": "none",
"attestation": "direct",
},
)
def test_register(self):
"""Test registration"""
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
plan.context[PLAN_CONTEXT_PENDING_USER] = self.user
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session[SESSION_KEY_WEBAUTHN_CHALLENGE] = b64decode(
b"03Xodi54gKsfnP5I9VFfhaGXVVE2NUyZpBBXns/JI+x6V9RY2Tw2QmxRJkhh7174EkRazUntIwjMVY9bFG60Lw=="
)
session.save()
response = self.client.post(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
data={
"component": "ak-stage-authenticator-webauthn",
"response": {
"id": "kqnmrVLnDG-OwsSNHkihYZaNz5s",
"rawId": "kqnmrVLnDG-OwsSNHkihYZaNz5s",
"type": "public-key",
"registrationClientExtensions": "{}",
"response": {
"clientDataJSON": (
"eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmd"
"lIjoiMDNYb2RpNTRnS3NmblA1STlWRmZoYUdYVlZFMk5VeV"
"pwQkJYbnNfSkkteDZWOVJZMlR3MlFteFJKa2hoNzE3NEVrU"
"mF6VW50SXdqTVZZOWJGRzYwTHciLCJvcmlnaW4iOiJodHRw"
"Oi8vbG9jYWxob3N0OjkwMDAiLCJjcm9zc09yaWdpbiI6ZmFsc2V9"
),
"attestationObject": (
"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViYSZYN5Yg"
"OjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NdAAAAAPv8MA"
"cVTk7MjAtuAgVX170AFJKp5q1S5wxvjsLEjR5IoWGWjc-bp"
"QECAyYgASFYIKtcZHPumH37XHs0IM1v3pUBRIqHVV_SE-Lq"
"2zpJAOVXIlgg74Fg_WdB0kuLYqCKbxogkEPaVtR_iR3IyQFIJAXBzds"
),
},
},
},
SERVER_NAME="localhost",
SERVER_PORT="9000",
)
self.assertEqual(response.status_code, 200)
self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
self.assertTrue(WebAuthnDevice.objects.filter(user=self.user).exists())
def test_register_restricted_device_type_deny(self):
"""Test registration with restricted devices (fail)"""
webauthn_mds_import(force=True)
webauthn_aaguid_import()
self.stage.device_type_restrictions.set(
WebAuthnDeviceType.objects.filter(
description="Android Authenticator with SafetyNet Attestation"
)
)
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
plan.context[PLAN_CONTEXT_PENDING_USER] = self.user
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session[SESSION_KEY_WEBAUTHN_CHALLENGE] = b64decode(
b"03Xodi54gKsfnP5I9VFfhaGXVVE2NUyZpBBXns/JI+x6V9RY2Tw2QmxRJkhh7174EkRazUntIwjMVY9bFG60Lw=="
)
session.save()
response = self.client.post(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
data={
"component": "ak-stage-authenticator-webauthn",
"response": {
"id": "kqnmrVLnDG-OwsSNHkihYZaNz5s",
"rawId": "kqnmrVLnDG-OwsSNHkihYZaNz5s",
"type": "public-key",
"registrationClientExtensions": "{}",
"response": {
"clientDataJSON": (
"eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmd"
"lIjoiMDNYb2RpNTRnS3NmblA1STlWRmZoYUdYVlZFMk5VeV"
"pwQkJYbnNfSkkteDZWOVJZMlR3MlFteFJKa2hoNzE3NEVrU"
"mF6VW50SXdqTVZZOWJGRzYwTHciLCJvcmlnaW4iOiJodHRw"
"Oi8vbG9jYWxob3N0OjkwMDAiLCJjcm9zc09yaWdpbiI6ZmFsc2V9"
),
"attestationObject": (
"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViYSZYN5Yg"
"OjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NdAAAAAPv8MA"
"cVTk7MjAtuAgVX170AFJKp5q1S5wxvjsLEjR5IoWGWjc-bp"
"QECAyYgASFYIKtcZHPumH37XHs0IM1v3pUBRIqHVV_SE-Lq"
"2zpJAOVXIlgg74Fg_WdB0kuLYqCKbxogkEPaVtR_iR3IyQFIJAXBzds"
),
},
},
},
SERVER_NAME="localhost",
SERVER_PORT="9000",
)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(
response,
flow=self.flow,
component="ak-stage-authenticator-webauthn",
response_errors={
"response": [
{
"string": (
"Invalid device type. Contact your authentik administrator for help."
),
"code": "invalid",
}
]
},
)
self.assertFalse(WebAuthnDevice.objects.filter(user=self.user).exists())
def test_register_restricted_device_type_allow(self):
"""Test registration with restricted devices (allow)"""
webauthn_mds_import(force=True)
webauthn_aaguid_import()
self.stage.device_type_restrictions.set(
WebAuthnDeviceType.objects.filter(description="iCloud Keychain")
)
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
plan.context[PLAN_CONTEXT_PENDING_USER] = self.user
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session[SESSION_KEY_WEBAUTHN_CHALLENGE] = b64decode(
b"03Xodi54gKsfnP5I9VFfhaGXVVE2NUyZpBBXns/JI+x6V9RY2Tw2QmxRJkhh7174EkRazUntIwjMVY9bFG60Lw=="
)
session.save()
response = self.client.post(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
data={
"component": "ak-stage-authenticator-webauthn",
"response": {
"id": "kqnmrVLnDG-OwsSNHkihYZaNz5s",
"rawId": "kqnmrVLnDG-OwsSNHkihYZaNz5s",
"type": "public-key",
"registrationClientExtensions": "{}",
"response": {
"clientDataJSON": (
"eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmd"
"lIjoiMDNYb2RpNTRnS3NmblA1STlWRmZoYUdYVlZFMk5VeV"
"pwQkJYbnNfSkkteDZWOVJZMlR3MlFteFJKa2hoNzE3NEVrU"
"mF6VW50SXdqTVZZOWJGRzYwTHciLCJvcmlnaW4iOiJodHRw"
"Oi8vbG9jYWxob3N0OjkwMDAiLCJjcm9zc09yaWdpbiI6ZmFsc2V9"
),
"attestationObject": (
"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViYSZYN5Yg"
"OjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NdAAAAAPv8MA"
"cVTk7MjAtuAgVX170AFJKp5q1S5wxvjsLEjR5IoWGWjc-bp"
"QECAyYgASFYIKtcZHPumH37XHs0IM1v3pUBRIqHVV_SE-Lq"
"2zpJAOVXIlgg74Fg_WdB0kuLYqCKbxogkEPaVtR_iR3IyQFIJAXBzds"
),
},
},
},
SERVER_NAME="localhost",
SERVER_PORT="9000",
)
self.assertEqual(response.status_code, 200)
self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
self.assertTrue(WebAuthnDevice.objects.filter(user=self.user).exists())
def test_register_restricted_device_type_allow_unknown(self):
"""Test registration with restricted devices (allow, unknown device type)"""
webauthn_mds_import(force=True)
webauthn_aaguid_import()
WebAuthnDeviceType.objects.filter(description="iCloud Keychain").delete()
self.stage.device_type_restrictions.set(
WebAuthnDeviceType.objects.filter(aaguid=UNKNOWN_DEVICE_TYPE_AAGUID)
)
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
plan.context[PLAN_CONTEXT_PENDING_USER] = self.user
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session[SESSION_KEY_WEBAUTHN_CHALLENGE] = b64decode(
b"03Xodi54gKsfnP5I9VFfhaGXVVE2NUyZpBBXns/JI+x6V9RY2Tw2QmxRJkhh7174EkRazUntIwjMVY9bFG60Lw=="
)
session.save()
response = self.client.post(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
data={
"component": "ak-stage-authenticator-webauthn",
"response": {
"id": "kqnmrVLnDG-OwsSNHkihYZaNz5s",
"rawId": "kqnmrVLnDG-OwsSNHkihYZaNz5s",
"type": "public-key",
"registrationClientExtensions": "{}",
"response": {
"clientDataJSON": (
"eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmd"
"lIjoiMDNYb2RpNTRnS3NmblA1STlWRmZoYUdYVlZFMk5VeV"
"pwQkJYbnNfSkkteDZWOVJZMlR3MlFteFJKa2hoNzE3NEVrU"
"mF6VW50SXdqTVZZOWJGRzYwTHciLCJvcmlnaW4iOiJodHRw"
"Oi8vbG9jYWxob3N0OjkwMDAiLCJjcm9zc09yaWdpbiI6ZmFsc2V9"
),
"attestationObject": (
"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViYSZYN5Yg"
"OjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NdAAAAAPv8MA"
"cVTk7MjAtuAgVX170AFJKp5q1S5wxvjsLEjR5IoWGWjc-bp"
"QECAyYgASFYIKtcZHPumH37XHs0IM1v3pUBRIqHVV_SE-Lq"
"2zpJAOVXIlgg74Fg_WdB0kuLYqCKbxogkEPaVtR_iR3IyQFIJAXBzds"
),
},
},
},
SERVER_NAME="localhost",
SERVER_PORT="9000",
)
self.assertEqual(response.status_code, 200)
print(response.content)
self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
self.assertTrue(WebAuthnDevice.objects.filter(user=self.user).exists())

View File

@ -1,13 +1,15 @@
"""API URLs"""
from authentik.stages.authenticator_webauthn.api import (
AuthenticateWebAuthnStageViewSet,
from authentik.stages.authenticator_webauthn.api.device_types import WebAuthnDeviceTypeViewSet
from authentik.stages.authenticator_webauthn.api.devices import (
WebAuthnAdminDeviceViewSet,
WebAuthnDeviceViewSet,
)
from authentik.stages.authenticator_webauthn.api.stages import AuthenticatorWebAuthnStageViewSet
api_urlpatterns = [
("stages/authenticator/webauthn", AuthenticateWebAuthnStageViewSet),
("stages/authenticator/webauthn", AuthenticatorWebAuthnStageViewSet),
("stages/authenticator/webauthn_device_types", WebAuthnDeviceTypeViewSet),
(
"authenticators/admin/webauthn",
WebAuthnAdminDeviceViewSet,

View File

@ -17,7 +17,7 @@ entries:
identifiers:
name: default-authenticator-webauthn-setup
id: default-authenticator-webauthn-setup
model: authentik_stages_authenticator_webauthn.authenticatewebauthnstage
model: authentik_stages_authenticator_webauthn.authenticatorwebauthnstage
- identifiers:
order: 0
stage: !KeyOf default-authenticator-webauthn-setup

View File

@ -2,7 +2,7 @@
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://goauthentik.io/blueprints/schema.json",
"type": "object",
"title": "authentik Blueprint schema",
"title": "authentik 2024.2.2 Blueprint schema",
"required": [
"version",
"entries"
@ -1566,7 +1566,7 @@
],
"properties": {
"model": {
"const": "authentik_stages_authenticator_webauthn.authenticatewebauthnstage"
"const": "authentik_stages_authenticator_webauthn.authenticatorwebauthnstage"
},
"id": {
"type": "string"
@ -1588,10 +1588,10 @@
}
},
"attrs": {
"$ref": "#/$defs/model_authentik_stages_authenticator_webauthn.authenticatewebauthnstage"
"$ref": "#/$defs/model_authentik_stages_authenticator_webauthn.authenticatorwebauthnstage"
},
"identifiers": {
"$ref": "#/$defs/model_authentik_stages_authenticator_webauthn.authenticatewebauthnstage"
"$ref": "#/$defs/model_authentik_stages_authenticator_webauthn.authenticatorwebauthnstage"
}
}
},
@ -2872,7 +2872,8 @@
"title": "Is primary"
},
"tenant": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Tenant"
}
},
@ -2994,11 +2995,13 @@
"type": "object",
"properties": {
"target": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Target"
},
"stage": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Stage"
},
"evaluate_on_plan": {
@ -3058,12 +3061,14 @@
"description": "Can be in the format of 'unix://<path>' when connecting to a local docker daemon, or 'https://<hostname>:2376' when connecting to a remote system."
},
"tls_verification": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Tls verification",
"description": "CA which the endpoint's Certificate is verified against. Can be left empty for no validation."
},
"tls_authentication": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Tls authentication",
"description": "Certificate/Key used for authentication. Can be left empty for no authentication."
}
@ -3123,7 +3128,8 @@
"title": "Providers"
},
"service_connection": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Service connection",
"description": "Select Service-Connection authentik should use to manage this outpost. Leave empty if authentik should not handle the deployment."
},
@ -3348,7 +3354,7 @@
"authentik_stages_authenticator_totp.authenticatortotpstage",
"authentik_stages_authenticator_totp.totpdevice",
"authentik_stages_authenticator_validate.authenticatorvalidatestage",
"authentik_stages_authenticator_webauthn.authenticatewebauthnstage",
"authentik_stages_authenticator_webauthn.authenticatorwebauthnstage",
"authentik_stages_authenticator_webauthn.webauthndevice",
"authentik_stages_captcha.captchastage",
"authentik_stages_consent.consentstage",
@ -3557,11 +3563,13 @@
"type": "object",
"properties": {
"policy": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Policy"
},
"group": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Group"
},
"user": {
@ -3569,7 +3577,8 @@
"title": "User"
},
"target": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Target"
},
"negate": {
@ -3611,19 +3620,22 @@
"title": "Name"
},
"authentication_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Authentication flow",
"description": "Flow used for authentication when the associated application is accessed by an un-authenticated user."
},
"authorization_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Authorization flow",
"description": "Flow used when authorizing this provider."
},
"property_mappings": {
"type": "array",
"items": {
"type": "integer"
"type": "string",
"format": "uuid"
},
"title": "Property mappings"
},
@ -3634,12 +3646,14 @@
"description": "DN under which objects are accessible."
},
"search_group": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Search group",
"description": "Users in this group can do search queries. If not set, every user can execute search queries."
},
"certificate": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Certificate"
},
"tls_server_name": {
@ -3729,19 +3743,22 @@
"title": "Name"
},
"authentication_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Authentication flow",
"description": "Flow used for authentication when the associated application is accessed by an un-authenticated user."
},
"authorization_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Authorization flow",
"description": "Flow used when authorizing this provider."
},
"property_mappings": {
"type": "array",
"items": {
"type": "integer"
"type": "string",
"format": "uuid"
},
"title": "Property mappings"
},
@ -3789,7 +3806,8 @@
"description": "Include User claims from scopes in the id_token, for applications that don't access the userinfo endpoint."
},
"signing_key": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Signing Key",
"description": "Key used to sign the tokens. Only required when JWT Algorithm is set to RS256."
},
@ -3840,19 +3858,22 @@
"title": "Name"
},
"authentication_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Authentication flow",
"description": "Flow used for authentication when the associated application is accessed by an un-authenticated user."
},
"authorization_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Authorization flow",
"description": "Flow used when authorizing this provider."
},
"property_mappings": {
"type": "array",
"items": {
"type": "integer"
"type": "string",
"format": "uuid"
},
"title": "Property mappings"
},
@ -3871,7 +3892,8 @@
"description": "Validate SSL Certificates of upstream servers"
},
"certificate": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Certificate"
},
"skip_path_regex": {
@ -3945,19 +3967,22 @@
"title": "Name"
},
"authentication_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Authentication flow",
"description": "Flow used for authentication when the associated application is accessed by an un-authenticated user."
},
"authorization_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Authorization flow",
"description": "Flow used when authorizing this provider."
},
"property_mappings": {
"type": "array",
"items": {
"type": "integer"
"type": "string",
"format": "uuid"
},
"title": "Property mappings"
},
@ -3990,19 +4015,22 @@
"title": "Name"
},
"authentication_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Authentication flow",
"description": "Flow used for authentication when the associated application is accessed by an un-authenticated user."
},
"authorization_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Authorization flow",
"description": "Flow used when authorizing this provider."
},
"property_mappings": {
"type": "array",
"items": {
"type": "integer"
"type": "string",
"format": "uuid"
},
"title": "Property mappings"
},
@ -4069,12 +4097,14 @@
"title": "Signature algorithm"
},
"signing_kp": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Signing Keypair",
"description": "Keypair used to sign outgoing Responses going to the Service Provider."
},
"verification_kp": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Verification Certificate",
"description": "When selected, incoming assertion's Signatures will be validated against this certificate. To allow unsigned Requests, leave on default."
},
@ -4143,14 +4173,16 @@
"property_mappings": {
"type": "array",
"items": {
"type": "integer"
"type": "string",
"format": "uuid"
},
"title": "Property mappings"
},
"property_mappings_group": {
"type": "array",
"items": {
"type": "integer",
"type": "string",
"format": "uuid",
"description": "Property mappings used for group creation/updating."
},
"title": "Property mappings group",
@ -4173,7 +4205,8 @@
"title": "Exclude users service account"
},
"filter_group": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Filter group"
}
},
@ -4238,12 +4271,14 @@
"title": "Enabled"
},
"authentication_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Authentication flow",
"description": "Flow to use when authenticating existing users."
},
"enrollment_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Enrollment flow",
"description": "Flow to use when enrolling new users."
},
@ -4283,12 +4318,14 @@
"title": "Server URI"
},
"peer_certificate": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Peer certificate",
"description": "Optionally verify the LDAP Server's Certificate against the CA Chain in this keypair."
},
"client_certificate": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Client certificate",
"description": "Client certificate to authenticate against the LDAP Server's Certificate."
},
@ -4366,20 +4403,23 @@
"title": "Sync groups"
},
"sync_parent_group": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Sync parent group"
},
"property_mappings": {
"type": "array",
"items": {
"type": "integer"
"type": "string",
"format": "uuid"
},
"title": "Property mappings"
},
"property_mappings_group": {
"type": "array",
"items": {
"type": "integer",
"type": "string",
"format": "uuid",
"description": "Property mappings used for group creation/updating."
},
"title": "Property mappings group",
@ -4440,12 +4480,14 @@
"title": "Enabled"
},
"authentication_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Authentication flow",
"description": "Flow to use when authenticating existing users."
},
"enrollment_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Enrollment flow",
"description": "Flow to use when enrolling new users."
},
@ -4619,12 +4661,14 @@
"title": "Enabled"
},
"authentication_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Authentication flow",
"description": "Flow to use when authenticating existing users."
},
"enrollment_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Enrollment flow",
"description": "Flow to use when enrolling new users."
},
@ -4731,12 +4775,14 @@
"title": "Enabled"
},
"authentication_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Authentication flow",
"description": "Flow to use when authenticating existing users."
},
"enrollment_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Enrollment flow",
"description": "Flow to use when enrolling new users."
},
@ -4771,7 +4817,8 @@
"title": "Icon"
},
"pre_authentication_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Pre authentication flow",
"description": "Flow used before authentication."
},
@ -4825,12 +4872,14 @@
"title": "Binding type"
},
"verification_kp": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Verification Certificate",
"description": "When selected, incoming assertion's Signatures will be validated against this certificate. To allow unsigned Requests, leave on default."
},
"signing_kp": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Signing Keypair",
"description": "Keypair used to sign outgoing Responses going to the Identity Provider."
},
@ -4975,7 +5024,8 @@
"title": "Flow set"
},
"configure_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Configure flow",
"description": "Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage."
},
@ -5117,7 +5167,8 @@
"title": "Flow set"
},
"configure_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Configure flow",
"description": "Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage."
},
@ -5281,7 +5332,8 @@
"title": "Flow set"
},
"configure_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Configure flow",
"description": "Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage."
},
@ -5412,7 +5464,8 @@
"title": "Flow set"
},
"configure_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Configure flow",
"description": "Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage."
},
@ -5566,7 +5619,8 @@
"configuration_stages": {
"type": "array",
"items": {
"type": "integer",
"type": "string",
"format": "uuid",
"description": "Stages used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again."
},
"title": "Configuration stages",
@ -5591,7 +5645,7 @@
},
"required": []
},
"model_authentik_stages_authenticator_webauthn.authenticatewebauthnstage": {
"model_authentik_stages_authenticator_webauthn.authenticatorwebauthnstage": {
"type": "object",
"properties": {
"name": {
@ -5682,7 +5736,8 @@
"title": "Flow set"
},
"configure_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Configure flow",
"description": "Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage."
},
@ -5723,6 +5778,13 @@
"required"
],
"title": "Resident key requirement"
},
"device_type_restrictions": {
"type": "array",
"items": {
"type": "integer"
},
"title": "Device type restrictions"
}
},
"required": []
@ -6004,7 +6066,8 @@
"groups": {
"type": "array",
"items": {
"type": "integer"
"type": "string",
"format": "uuid"
},
"title": "Groups"
},
@ -6587,17 +6650,20 @@
"description": "When a valid username/email has been entered, and this option is enabled, the user's username and avatar will be shown. Otherwise, the text that the user entered will be shown"
},
"enrollment_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Enrollment flow",
"description": "Optional enrollment flow, which is linked at the bottom of the page."
},
"recovery_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Recovery flow",
"description": "Optional recovery flow, which is linked at the bottom of the page."
},
"passwordless_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Passwordless flow",
"description": "Optional passwordless flow, which is linked at the bottom of the page."
},
@ -6746,7 +6812,8 @@
"description": "When enabled, the invitation will be deleted after usage."
},
"flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Flow",
"description": "When set, only the configured flow can use this invitation."
}
@ -6858,7 +6925,8 @@
"description": "Selection of backends to test the password against."
},
"configure_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Configure flow",
"description": "Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage."
},
@ -7142,14 +7210,16 @@
"fields": {
"type": "array",
"items": {
"type": "integer"
"type": "string",
"format": "uuid"
},
"title": "Fields"
},
"validation_policies": {
"type": "array",
"items": {
"type": "integer"
"type": "string",
"format": "uuid"
},
"title": "Validation policies"
}
@ -7579,7 +7649,8 @@
"description": "When set, newly created users are inactive and cannot login."
},
"create_users_group": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Create users group",
"description": "Optionally add newly created users to this group."
},
@ -7629,31 +7700,38 @@
"title": "Branding favicon"
},
"flow_authentication": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Flow authentication"
},
"flow_invalidation": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Flow invalidation"
},
"flow_recovery": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Flow recovery"
},
"flow_unenrollment": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Flow unenrollment"
},
"flow_user_settings": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Flow user settings"
},
"flow_device_code": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Flow device code"
},
"web_certificate": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Web certificate",
"description": "Web Certificate used by the authentik Core webserver."
},
@ -7708,7 +7786,8 @@
"description": "Users added to this group will be superusers."
},
"parent": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Parent"
},
"users": {
@ -7726,7 +7805,8 @@
"roles": {
"type": "array",
"items": {
"type": "integer"
"type": "string",
"format": "uuid"
},
"title": "Roles"
}
@ -7763,7 +7843,8 @@
"groups": {
"type": "array",
"items": {
"type": "integer"
"type": "string",
"format": "uuid"
},
"title": "Groups"
},
@ -7943,19 +8024,22 @@
"title": "Name"
},
"authentication_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Authentication flow",
"description": "Flow used for authentication when the associated application is accessed by an un-authenticated user."
},
"authorization_flow": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Authorization flow",
"description": "Flow used when authorizing this provider."
},
"property_mappings": {
"type": "array",
"items": {
"type": "integer"
"type": "string",
"format": "uuid"
},
"title": "Property mappings"
},
@ -8012,7 +8096,8 @@
"property_mappings": {
"type": "array",
"items": {
"type": "integer"
"type": "string",
"format": "uuid"
},
"title": "Property mappings"
},
@ -8368,7 +8453,8 @@
"transports": {
"type": "array",
"items": {
"type": "integer",
"type": "string",
"format": "uuid",
"description": "Select which transports should be used to notify the user. If none are selected, the notification will only be shown in the authentik UI."
},
"title": "Transports",
@ -8385,7 +8471,8 @@
"description": "Controls which severity level the created notifications will have."
},
"group": {
"type": "integer",
"type": "string",
"format": "uuid",
"title": "Group",
"description": "Define which group of users this notification should be sent and shown to. If left empty, Notification won't ben sent."
}

8
go.mod
View File

@ -9,7 +9,7 @@ require (
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/getsentry/sentry-go v0.27.0
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
github.com/go-ldap/ldap/v3 v3.4.6
github.com/go-ldap/ldap/v3 v3.4.7
github.com/go-openapi/runtime v0.28.0
github.com/go-openapi/strfmt v0.23.0
github.com/golang-jwt/jwt v3.2.2+incompatible
@ -32,8 +32,8 @@ require (
github.com/wwt/guac v1.3.2
goauthentik.io/api/v3 v3.2024022.7
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
golang.org/x/oauth2 v0.18.0
golang.org/x/sync v0.6.0
golang.org/x/oauth2 v0.19.0
golang.org/x/sync v0.7.0
gopkg.in/yaml.v2 v2.4.0
layeh.com/radius v0.0.0-20210819152912-ad72663a72ab
)
@ -59,7 +59,6 @@ require (
github.com/go-openapi/spec v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-openapi/validate v0.24.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
@ -79,7 +78,6 @@ require (
golang.org/x/net v0.22.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

55
go.sum
View File

@ -37,8 +37,8 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA=
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@ -84,8 +84,8 @@ github.com/go-http-utils/fresh v0.0.0-20161124030543-7231e26a4b27 h1:O6yi4xa9b2D
github.com/go-http-utils/fresh v0.0.0-20161124030543-7231e26a4b27/go.mod h1:AYvN8omj7nKLmbcXS2dyABYU6JB1Lz1bHmkkq1kf4I4=
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a h1:v6zMvHuY9yue4+QkG/HQ/W67wvtQmWJ4SDo9aK/GIno=
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a/go.mod h1:I79BieaU4fxrw4LMXby6q5OS9XnoR9UIKLOzDFjUmuw=
github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A=
github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc=
github.com/go-ldap/ldap/v3 v3.4.7 h1:3Hbd7mIB1qjd3Ra59fI3JYea/t5kykFu2CVHBca9koE=
github.com/go-ldap/ldap/v3 v3.4.7/go.mod h1:qS3Sjlu76eHfHGpUdWkAXQTw4beih+cHsco2jXlIXrk=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@ -137,9 +137,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@ -149,7 +146,6 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
@ -165,7 +161,6 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
@ -174,18 +169,35 @@ github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyE
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg=
github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo=
github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8=
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
github.com/jellydator/ttlcache/v3 v3.2.0 h1:6lqVJ8X3ZaUwvzENqPAobDsXNExfUJd61u++uW8a3LE=
github.com/jellydator/ttlcache/v3 v3.2.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@ -248,6 +260,7 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -255,6 +268,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/wwt/guac v1.3.2 h1:sH6OFGa/1tBs7ieWBVlZe7t6F5JAOWBry/tqQL/Vup4=
@ -289,7 +303,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -355,7 +370,9 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -364,8 +381,8 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -376,8 +393,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -411,14 +428,15 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -427,7 +445,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -501,8 +518,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@ -554,8 +569,6 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -39,8 +39,10 @@ def check_redis():
if CONFIG.get_bool("redis.tls", False):
REDIS_PROTOCOL_PREFIX = "rediss://"
REDIS_URL = (
f"{REDIS_PROTOCOL_PREFIX}:"
f"{quote_plus(CONFIG.get('redis.password'))}@{quote_plus(CONFIG.get('redis.host'))}:"
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"{CONFIG.get_int('redis.port')}/{CONFIG.get('redis.db')}"
)
while True:

25
poetry.lock generated
View File

@ -1431,6 +1431,23 @@ files = [
[package.dependencies]
requests = "*"
[[package]]
name = "fido2"
version = "1.1.3"
description = "FIDO2/WebAuthn library for implementing clients and servers."
optional = false
python-versions = ">=3.8,<4.0"
files = [
{file = "fido2-1.1.3-py3-none-any.whl", hash = "sha256:6be34c0b9fe85e4911fd2d103cce7ae8ce2f064384a7a2a3bd970b3ef7702931"},
{file = "fido2-1.1.3.tar.gz", hash = "sha256:26100f226d12ced621ca6198528ce17edf67b78df4287aee1285fee3cd5aa9fc"},
]
[package.dependencies]
cryptography = ">=2.6,<35 || >35,<45"
[package.extras]
pcsc = ["pyscard (>=1.9,<3)"]
[[package]]
name = "flower"
version = "2.0.1"
@ -3918,13 +3935,13 @@ wsproto = ">=0.14"
[[package]]
name = "twilio"
version = "9.0.3"
version = "9.0.4"
description = "Twilio API client and TwiML generator"
optional = false
python-versions = ">=3.7.0"
files = [
{file = "twilio-9.0.3-py2.py3-none-any.whl", hash = "sha256:c21fd70d8518823831143999a38cc86c40dad45fab5a6b5ecfee85672e9e5cb2"},
{file = "twilio-9.0.3.tar.gz", hash = "sha256:c13973415966e93b70651a58733fa76317df64621c74e0e4896613f10a368438"},
{file = "twilio-9.0.4-py2.py3-none-any.whl", hash = "sha256:086abae1a575a0ee89a72c0792d814ee349fe55c8df76b563ecfc49463c3c533"},
{file = "twilio-9.0.4.tar.gz", hash = "sha256:d493d5bde6361bb713dffec00b9465ff84978b71334dd75002152e79604688ba"},
]
[package.dependencies]
@ -4636,4 +4653,4 @@ files = [
[metadata]
lock-version = "2.0"
python-versions = "~3.12"
content-hash = "c5a36b528980277b07f80200da251a2bea31cc2b7d5438250706f23a825f3628"
content-hash = "4544b2a0b0065aa9e13d9a3b5a951fb5212921fe72f0fe259069e2e9205e9830"

View File

@ -108,6 +108,7 @@ drf-spectacular = "*"
dumb-init = "*"
duo-client = "*"
facebook-sdk = "*"
fido2 = "*"
flower = "*"
geoip2 = "*"
gunicorn = "*"

View File

@ -18405,7 +18405,7 @@ paths:
- authentik_stages_authenticator_totp.authenticatortotpstage
- authentik_stages_authenticator_totp.totpdevice
- authentik_stages_authenticator_validate.authenticatorvalidatestage
- authentik_stages_authenticator_webauthn.authenticatewebauthnstage
- authentik_stages_authenticator_webauthn.authenticatorwebauthnstage
- authentik_stages_authenticator_webauthn.webauthndevice
- authentik_stages_captcha.captchastage
- authentik_stages_consent.consentstage
@ -18619,7 +18619,7 @@ paths:
- authentik_stages_authenticator_totp.authenticatortotpstage
- authentik_stages_authenticator_totp.totpdevice
- authentik_stages_authenticator_validate.authenticatorvalidatestage
- authentik_stages_authenticator_webauthn.authenticatewebauthnstage
- authentik_stages_authenticator_webauthn.authenticatorwebauthnstage
- authentik_stages_authenticator_webauthn.webauthndevice
- authentik_stages_captcha.captchastage
- authentik_stages_consent.consentstage
@ -24007,7 +24007,7 @@ paths:
/stages/authenticator/webauthn/:
get:
operationId: stages_authenticator_webauthn_list
description: AuthenticateWebAuthnStage Viewset
description: AuthenticatorWebAuthnStage Viewset
parameters:
- in: query
name: authenticator_attachment
@ -24022,6 +24022,15 @@ paths:
schema:
type: string
format: uuid
- in: query
name: device_type_restrictions
schema:
type: array
items:
type: string
format: uuid
explode: true
style: form
- in: query
name: friendly_name
schema:
@ -24084,7 +24093,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/PaginatedAuthenticateWebAuthnStageList'
$ref: '#/components/schemas/PaginatedAuthenticatorWebAuthnStageList'
description: ''
'400':
content:
@ -24100,14 +24109,14 @@ paths:
description: ''
post:
operationId: stages_authenticator_webauthn_create
description: AuthenticateWebAuthnStage Viewset
description: AuthenticatorWebAuthnStage Viewset
tags:
- stages
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/AuthenticateWebAuthnStageRequest'
$ref: '#/components/schemas/AuthenticatorWebAuthnStageRequest'
required: true
security:
- authentik: []
@ -24116,7 +24125,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/AuthenticateWebAuthnStage'
$ref: '#/components/schemas/AuthenticatorWebAuthnStage'
description: ''
'400':
content:
@ -24133,7 +24142,7 @@ paths:
/stages/authenticator/webauthn/{stage_uuid}/:
get:
operationId: stages_authenticator_webauthn_retrieve
description: AuthenticateWebAuthnStage Viewset
description: AuthenticatorWebAuthnStage Viewset
parameters:
- in: path
name: stage_uuid
@ -24151,7 +24160,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/AuthenticateWebAuthnStage'
$ref: '#/components/schemas/AuthenticatorWebAuthnStage'
description: ''
'400':
content:
@ -24167,7 +24176,7 @@ paths:
description: ''
put:
operationId: stages_authenticator_webauthn_update
description: AuthenticateWebAuthnStage Viewset
description: AuthenticatorWebAuthnStage Viewset
parameters:
- in: path
name: stage_uuid
@ -24182,7 +24191,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/AuthenticateWebAuthnStageRequest'
$ref: '#/components/schemas/AuthenticatorWebAuthnStageRequest'
required: true
security:
- authentik: []
@ -24191,7 +24200,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/AuthenticateWebAuthnStage'
$ref: '#/components/schemas/AuthenticatorWebAuthnStage'
description: ''
'400':
content:
@ -24207,7 +24216,7 @@ paths:
description: ''
patch:
operationId: stages_authenticator_webauthn_partial_update
description: AuthenticateWebAuthnStage Viewset
description: AuthenticatorWebAuthnStage Viewset
parameters:
- in: path
name: stage_uuid
@ -24222,7 +24231,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/PatchedAuthenticateWebAuthnStageRequest'
$ref: '#/components/schemas/PatchedAuthenticatorWebAuthnStageRequest'
security:
- authentik: []
responses:
@ -24230,7 +24239,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/AuthenticateWebAuthnStage'
$ref: '#/components/schemas/AuthenticatorWebAuthnStage'
description: ''
'400':
content:
@ -24246,7 +24255,7 @@ paths:
description: ''
delete:
operationId: stages_authenticator_webauthn_destroy
description: AuthenticateWebAuthnStage Viewset
description: AuthenticatorWebAuthnStage Viewset
parameters:
- in: path
name: stage_uuid
@ -24311,6 +24320,106 @@ paths:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/stages/authenticator/webauthn_device_types/:
get:
operationId: stages_authenticator_webauthn_device_types_list
description: WebAuthnDeviceType Viewset
parameters:
- in: query
name: aaguid
schema:
type: string
format: uuid
- in: query
name: description
schema:
type: string
- in: query
name: icon
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
- name: search
required: false
in: query
description: A search term.
schema:
type: string
tags:
- stages
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PaginatedWebAuthnDeviceTypeList'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/stages/authenticator/webauthn_device_types/{aaguid}/:
get:
operationId: stages_authenticator_webauthn_device_types_retrieve
description: WebAuthnDeviceType Viewset
parameters:
- in: path
name: aaguid
schema:
type: string
format: uuid
description: A UUID string identifying this WebAuthn Device type.
required: true
tags:
- stages
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/WebAuthnDeviceType'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/stages/captcha/:
get:
operationId: stages_captcha_list
@ -29738,92 +29847,6 @@ components:
- basic
- bearer
type: string
AuthenticateWebAuthnStage:
type: object
description: AuthenticateWebAuthnStage 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'
configure_flow:
type: string
format: uuid
nullable: true
description: Flow used by an authenticated user to configure this Stage.
If empty, user will not be able to configure this stage.
friendly_name:
type: string
nullable: true
user_verification:
$ref: '#/components/schemas/UserVerificationEnum'
authenticator_attachment:
allOf:
- $ref: '#/components/schemas/AuthenticatorAttachmentEnum'
nullable: true
resident_key_requirement:
$ref: '#/components/schemas/ResidentKeyRequirementEnum'
required:
- component
- meta_model_name
- name
- pk
- verbose_name
- verbose_name_plural
AuthenticateWebAuthnStageRequest:
type: object
description: AuthenticateWebAuthnStage Serializer
properties:
name:
type: string
minLength: 1
flow_set:
type: array
items:
$ref: '#/components/schemas/FlowSetRequest'
configure_flow:
type: string
format: uuid
nullable: true
description: Flow used by an authenticated user to configure this Stage.
If empty, user will not be able to configure this stage.
friendly_name:
type: string
nullable: true
minLength: 1
user_verification:
$ref: '#/components/schemas/UserVerificationEnum'
authenticator_attachment:
allOf:
- $ref: '#/components/schemas/AuthenticatorAttachmentEnum'
nullable: true
resident_key_requirement:
$ref: '#/components/schemas/ResidentKeyRequirementEnum'
required:
- name
AuthenticatedSession:
type: object
description: AuthenticatedSession Serializer
@ -30738,6 +30761,108 @@ components:
additionalProperties: {}
required:
- response
AuthenticatorWebAuthnStage:
type: object
description: AuthenticatorWebAuthnStage 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'
configure_flow:
type: string
format: uuid
nullable: true
description: Flow used by an authenticated user to configure this Stage.
If empty, user will not be able to configure this stage.
friendly_name:
type: string
nullable: true
user_verification:
$ref: '#/components/schemas/UserVerificationEnum'
authenticator_attachment:
allOf:
- $ref: '#/components/schemas/AuthenticatorAttachmentEnum'
nullable: true
resident_key_requirement:
$ref: '#/components/schemas/ResidentKeyRequirementEnum'
device_type_restrictions:
type: array
items:
type: string
format: uuid
device_type_restrictions_obj:
type: array
items:
$ref: '#/components/schemas/WebAuthnDeviceType'
readOnly: true
required:
- component
- device_type_restrictions_obj
- meta_model_name
- name
- pk
- verbose_name
- verbose_name_plural
AuthenticatorWebAuthnStageRequest:
type: object
description: AuthenticatorWebAuthnStage Serializer
properties:
name:
type: string
minLength: 1
flow_set:
type: array
items:
$ref: '#/components/schemas/FlowSetRequest'
configure_flow:
type: string
format: uuid
nullable: true
description: Flow used by an authenticated user to configure this Stage.
If empty, user will not be able to configure this stage.
friendly_name:
type: string
nullable: true
minLength: 1
user_verification:
$ref: '#/components/schemas/UserVerificationEnum'
authenticator_attachment:
allOf:
- $ref: '#/components/schemas/AuthenticatorAttachmentEnum'
nullable: true
resident_key_requirement:
$ref: '#/components/schemas/ResidentKeyRequirementEnum'
device_type_restrictions:
type: array
items:
type: string
format: uuid
required:
- name
AutoSubmitChallengeResponseRequest:
type: object
description: Pseudo class for autosubmit response
@ -34706,7 +34831,7 @@ components:
- authentik_stages_authenticator_totp.authenticatortotpstage
- authentik_stages_authenticator_totp.totpdevice
- authentik_stages_authenticator_validate.authenticatorvalidatestage
- authentik_stages_authenticator_webauthn.authenticatewebauthnstage
- authentik_stages_authenticator_webauthn.authenticatorwebauthnstage
- authentik_stages_authenticator_webauthn.webauthndevice
- authentik_stages_captcha.captchastage
- authentik_stages_consent.consentstage
@ -35673,18 +35798,6 @@ components:
required:
- pagination
- results
PaginatedAuthenticateWebAuthnStageList:
type: object
properties:
pagination:
$ref: '#/components/schemas/Pagination'
results:
type: array
items:
$ref: '#/components/schemas/AuthenticateWebAuthnStage'
required:
- pagination
- results
PaginatedAuthenticatedSessionList:
type: object
properties:
@ -35757,6 +35870,18 @@ components:
required:
- pagination
- results
PaginatedAuthenticatorWebAuthnStageList:
type: object
properties:
pagination:
$ref: '#/components/schemas/Pagination'
results:
type: array
items:
$ref: '#/components/schemas/AuthenticatorWebAuthnStage'
required:
- pagination
- results
PaginatedBlueprintInstanceList:
type: object
properties:
@ -36825,6 +36950,18 @@ components:
required:
- pagination
- results
PaginatedWebAuthnDeviceTypeList:
type: object
properties:
pagination:
$ref: '#/components/schemas/Pagination'
results:
type: array
items:
$ref: '#/components/schemas/WebAuthnDeviceType'
required:
- pagination
- results
Pagination:
type: object
properties:
@ -37230,35 +37367,6 @@ components:
$ref: '#/components/schemas/PolicyEngineMode'
group:
type: string
PatchedAuthenticateWebAuthnStageRequest:
type: object
description: AuthenticateWebAuthnStage Serializer
properties:
name:
type: string
minLength: 1
flow_set:
type: array
items:
$ref: '#/components/schemas/FlowSetRequest'
configure_flow:
type: string
format: uuid
nullable: true
description: Flow used by an authenticated user to configure this Stage.
If empty, user will not be able to configure this stage.
friendly_name:
type: string
nullable: true
minLength: 1
user_verification:
$ref: '#/components/schemas/UserVerificationEnum'
authenticator_attachment:
allOf:
- $ref: '#/components/schemas/AuthenticatorAttachmentEnum'
nullable: true
resident_key_requirement:
$ref: '#/components/schemas/ResidentKeyRequirementEnum'
PatchedAuthenticatorDuoStageRequest:
type: object
description: AuthenticatorDuoStage Serializer
@ -37428,6 +37536,40 @@ components:
allOf:
- $ref: '#/components/schemas/UserVerificationEnum'
description: Enforce user verification for WebAuthn devices.
PatchedAuthenticatorWebAuthnStageRequest:
type: object
description: AuthenticatorWebAuthnStage Serializer
properties:
name:
type: string
minLength: 1
flow_set:
type: array
items:
$ref: '#/components/schemas/FlowSetRequest'
configure_flow:
type: string
format: uuid
nullable: true
description: Flow used by an authenticated user to configure this Stage.
If empty, user will not be able to configure this stage.
friendly_name:
type: string
nullable: true
minLength: 1
user_verification:
$ref: '#/components/schemas/UserVerificationEnum'
authenticator_attachment:
allOf:
- $ref: '#/components/schemas/AuthenticatorAttachmentEnum'
nullable: true
resident_key_requirement:
$ref: '#/components/schemas/ResidentKeyRequirementEnum'
device_type_restrictions:
type: array
items:
type: string
format: uuid
PatchedBlueprintInstanceRequest:
type: object
description: Info about a single blueprint instance file
@ -44133,8 +44275,14 @@ components:
type: string
format: date-time
readOnly: true
device_type:
allOf:
- $ref: '#/components/schemas/WebAuthnDeviceType'
readOnly: true
nullable: true
required:
- created_on
- device_type
- name
- pk
WebAuthnDeviceRequest:
@ -44147,6 +44295,31 @@ components:
maxLength: 200
required:
- name
WebAuthnDeviceType:
type: object
description: WebAuthnDeviceType Serializer
properties:
aaguid:
type: string
format: uuid
description:
type: string
required:
- aaguid
- description
WebAuthnDeviceTypeRequest:
type: object
description: WebAuthnDeviceType Serializer
properties:
aaguid:
type: string
format: uuid
description:
type: string
minLength: 1
required:
- aaguid
- description
Workers:
type: object
properties:

View File

@ -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.4",
"wdio-wait-for": "^3.0.11"
},
"engines": {
@ -8620,9 +8620,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.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz",
"integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",

View File

@ -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.4",
"wdio-wait-for": "^3.0.11"
},
"scripts": {

79
web/package-lock.json generated
View File

@ -13,11 +13,11 @@
"@codemirror/lang-javascript": "^6.2.2",
"@codemirror/lang-python": "^6.1.5",
"@codemirror/lang-xml": "^6.1.0",
"@codemirror/legacy-modes": "^6.3.3",
"@codemirror/legacy-modes": "^6.4.0",
"@codemirror/theme-one-dark": "^6.1.2",
"@formatjs/intl-listformat": "^7.5.5",
"@fortawesome/fontawesome-free": "^6.5.2",
"@goauthentik/api": "^2024.2.2-1712238004",
"@goauthentik/api": "^2024.2.2-1712571709",
"@lit-labs/task": "^3.1.0",
"@lit/context": "^1.1.0",
"@lit/localize": "^0.12.1",
@ -33,7 +33,7 @@
"codemirror": "^6.0.1",
"construct-style-sheets-polyfill": "^3.1.0",
"core-js": "^3.36.1",
"country-flag-icons": "^1.5.10",
"country-flag-icons": "^1.5.11",
"fuse.js": "^7.0.0",
"guacamole-common-js": "^1.5.0",
"lit": "^3.1.2",
@ -42,7 +42,7 @@
"rapidoc": "^9.3.4",
"showdown": "^2.1.0",
"style-mod": "^4.1.2",
"ts-pattern": "^5.1.0",
"ts-pattern": "^5.1.1",
"webcomponent-qr-code": "^1.2.0",
"yaml": "^2.4.1"
},
@ -59,7 +59,7 @@
"@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.16",
"@spotlightjs/spotlight": "^1.2.17",
"@storybook/addon-essentials": "^7.6.17",
"@storybook/addon-links": "^7.6.17",
"@storybook/api": "^7.6.17",
@ -101,7 +101,7 @@
"ts-lit-plugin": "^2.0.2",
"tslib": "^2.6.2",
"turnstile-types": "^1.2.0",
"typescript": "^5.4.3",
"typescript": "^5.4.4",
"vite-tsconfig-paths": "^4.3.2"
},
"engines": {
@ -111,9 +111,9 @@
"@esbuild/darwin-arm64": "^0.20.1",
"@esbuild/linux-amd64": "^0.18.11",
"@esbuild/linux-arm64": "^0.20.1",
"@rollup/rollup-darwin-arm64": "4.14.0",
"@rollup/rollup-linux-arm64-gnu": "4.14.0",
"@rollup/rollup-linux-x64-gnu": "4.14.0"
"@rollup/rollup-darwin-arm64": "4.14.1",
"@rollup/rollup-linux-arm64-gnu": "4.14.1",
"@rollup/rollup-linux-x64-gnu": "4.14.1"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@ -2218,8 +2218,9 @@
}
},
"node_modules/@codemirror/legacy-modes": {
"version": "6.3.3",
"license": "MIT",
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/@codemirror/legacy-modes/-/legacy-modes-6.4.0.tgz",
"integrity": "sha512-5m/K+1A6gYR0e+h/dEde7LoGimMjRtWXZFg4Lo70cc8HzjSdHe3fLwjWMR0VRl5KFT1SxalSap7uMgPKF28wBA==",
"dependencies": {
"@codemirror/language": "^6.0.0"
}
@ -2839,9 +2840,9 @@
}
},
"node_modules/@goauthentik/api": {
"version": "2024.2.2-1712238004",
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2024.2.2-1712238004.tgz",
"integrity": "sha512-Y1wNhIYN3/CwpcCKGm8JT0Vkkqjfh3Og91IvzLRVJ61qBQ3/hc016YBjdAEnXzzDOmylRalI0Umfl2nl2NXdHQ=="
"version": "2024.2.2-1712571709",
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2024.2.2-1712571709.tgz",
"integrity": "sha512-+uS+d13aCDC7W3bZk8j3RnqvDq8iivXnP98GHFEoB9pUuMJ1LK7sgJwr2JHmJe5KiFMl0oxycY8VutsBnYmjog=="
},
"node_modules/@hcaptcha/types": {
"version": "1.0.3",
@ -4247,9 +4248,9 @@
"peer": true
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.0.tgz",
"integrity": "sha512-BcnSPRM76/cD2gQC+rQNGBN6GStBs2pl/FpweW8JYuz5J/IEa0Fr4AtrPv766DB/6b2MZ/AfSIOSGw3nEIP8SA==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.1.tgz",
"integrity": "sha512-+kecg3FY84WadgcuSVm6llrABOdQAEbNdnpi5X3UwWiFVhZIZvKgGrF7kmLguvxHNQy+UuRV66cLVl3S+Rkt+Q==",
"cpu": [
"arm64"
],
@ -4287,9 +4288,9 @@
"peer": true
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.0.tgz",
"integrity": "sha512-x+uJ6MAYRlHGe9wi4HQjxpaKHPM3d3JjqqCkeC5gpnnI6OWovLdXTpfa8trjxPLnWKyBsSi5kne+146GAxFt4A==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.1.tgz",
"integrity": "sha512-p9rGKYkHdFMzhckOTFubfxgyIO1vw//7IIjBBRVzyZebWlzRLeNhqxuSaZ7kCEKVkm/kuC9fVRW9HkC/zNRG2w==",
"cpu": [
"arm64"
],
@ -4355,9 +4356,9 @@
"peer": true
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.0.tgz",
"integrity": "sha512-C6y6z2eCNCfhZxT9u+jAM2Fup89ZjiG5pIzZIDycs1IwESviLxwkQcFRGLjnDrP+PT+v5i4YFvlcfAs+LnreXg==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.1.tgz",
"integrity": "sha512-9Q7DGjZN+hTdJomaQ3Iub4m6VPu1r94bmK2z3UeWP3dGUecRC54tmVu9vKHTm1bOt3ASoYtEz6JSRLFzrysKlA==",
"cpu": [
"x64"
],
@ -4530,9 +4531,9 @@
"license": "MIT"
},
"node_modules/@spotlightjs/overlay": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/@spotlightjs/overlay/-/overlay-1.8.2.tgz",
"integrity": "sha512-g3pzaJFKK67pBIl72qSNoFJIfP/dmdFoSPWZZQW6MKAdU7IOY5yf3BB52xEc6iSfeLGG/KpYNThefpobX3hb7Q==",
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/@spotlightjs/overlay/-/overlay-1.8.3.tgz",
"integrity": "sha512-6b5tBspOOEd6Gj0l4xgdUwR4Ydn2dNX9lqJ/WSzIu1lqkI96w2lqf69IGzEo6jb9aPtfTtu8nx5K2SD6JXH2SA==",
"dev": true
},
"node_modules/@spotlightjs/sidecar": {
@ -4544,12 +4545,12 @@
}
},
"node_modules/@spotlightjs/spotlight": {
"version": "1.2.16",
"resolved": "https://registry.npmjs.org/@spotlightjs/spotlight/-/spotlight-1.2.16.tgz",
"integrity": "sha512-grqK7Qwzz0zJKaM4+u/0DS81gEGKkUsKwXGY1kA07rXsbp6ilT62JWI1tQDgYHb1i3MbR2ch0EuMT476CAtA+A==",
"version": "1.2.17",
"resolved": "https://registry.npmjs.org/@spotlightjs/spotlight/-/spotlight-1.2.17.tgz",
"integrity": "sha512-91qtnLspMl2e1olBTeWoZcupwwTzQs8clQgTF8wv2Ib18zce7YYLvWpnDhNIVNQlbKIjGhYum6UY/KCfUCXQYg==",
"dev": true,
"dependencies": {
"@spotlightjs/overlay": "1.8.2",
"@spotlightjs/overlay": "1.8.3",
"@spotlightjs/sidecar": "1.4.0"
},
"bin": {
@ -8620,9 +8621,9 @@
}
},
"node_modules/country-flag-icons": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/country-flag-icons/-/country-flag-icons-1.5.10.tgz",
"integrity": "sha512-x3elaK+ZY23W1YtFsNQknRdURzkV7g3Z93AoA7SHZJUEXbVjRsNh4h9Uf09+OjWF/4u8tXeAt37gezGRdwR/2g=="
"version": "1.5.11",
"resolved": "https://registry.npmjs.org/country-flag-icons/-/country-flag-icons-1.5.11.tgz",
"integrity": "sha512-B+mvFywunkRJs270k7kCBjhogvIA0uNn6GAXv6m2cPn3rrwqZzZVr2gBWcz+Cz7OGVWlcbERlYRIX0S6OGr8Bw=="
},
"node_modules/crelt": {
"version": "1.0.6",
@ -16940,9 +16941,9 @@
"license": "MIT"
},
"node_modules/ts-pattern": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-5.1.0.tgz",
"integrity": "sha512-sULbgZDTXrcr6WMeuR8gPb+dvNN/fNpxE8GHfosFHPJRPuxHVNtGcEiiNuQa6nxu40/dY6xYdTJmc7MG3w8B5g=="
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-5.1.1.tgz",
"integrity": "sha512-i+owkHr5RYdQxj8olUgRrqpiWH9x27PuWVfXwDmJ/n/CoF/SAa7WW1i2oUpPDMQpJ4U+bGRUcZkVq7i1m3zFCg=="
},
"node_modules/ts-simple-type": {
"version": "2.0.0-next.0",
@ -17128,9 +17129,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.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz",
"integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",

View File

@ -14,8 +14,8 @@
"build": "run-s build-locales esbuild:build",
"build-proxy": "run-s build-locales esbuild:build-proxy",
"watch": "run-s build-locales esbuild:watch",
"lint": "cross-env NODE_OPTIONS='--max_old_space_size=8192' eslint . --max-warnings 0 --fix",
"lint:precommit": "cross-env NODE_OPTIONS='--max_old_space_size=8192' node scripts/eslint-precommit.mjs",
"lint": "cross-env NODE_OPTIONS='--max_old_space_size=16384' eslint . --max-warnings 0 --fix",
"lint:precommit": "cross-env NODE_OPTIONS='--max_old_space_size=16384' node scripts/eslint-precommit.mjs",
"lint:spelling": "node scripts/check-spelling.mjs",
"lit-analyse": "lit-analyzer src",
"precommit": "npm-run-all --parallel tsc lit-analyse lint:spelling --sequential lint:precommit prettier",
@ -34,11 +34,11 @@
"@codemirror/lang-javascript": "^6.2.2",
"@codemirror/lang-python": "^6.1.5",
"@codemirror/lang-xml": "^6.1.0",
"@codemirror/legacy-modes": "^6.3.3",
"@codemirror/legacy-modes": "^6.4.0",
"@codemirror/theme-one-dark": "^6.1.2",
"@formatjs/intl-listformat": "^7.5.5",
"@fortawesome/fontawesome-free": "^6.5.2",
"@goauthentik/api": "^2024.2.2-1712238004",
"@goauthentik/api": "^2024.2.2-1712571709",
"@lit-labs/task": "^3.1.0",
"@lit/context": "^1.1.0",
"@lit/localize": "^0.12.1",
@ -54,7 +54,7 @@
"codemirror": "^6.0.1",
"construct-style-sheets-polyfill": "^3.1.0",
"core-js": "^3.36.1",
"country-flag-icons": "^1.5.10",
"country-flag-icons": "^1.5.11",
"fuse.js": "^7.0.0",
"guacamole-common-js": "^1.5.0",
"lit": "^3.1.2",
@ -63,7 +63,7 @@
"rapidoc": "^9.3.4",
"showdown": "^2.1.0",
"style-mod": "^4.1.2",
"ts-pattern": "^5.1.0",
"ts-pattern": "^5.1.1",
"webcomponent-qr-code": "^1.2.0",
"yaml": "^2.4.1"
},
@ -80,7 +80,7 @@
"@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.16",
"@spotlightjs/spotlight": "^1.2.17",
"@storybook/addon-essentials": "^7.6.17",
"@storybook/addon-links": "^7.6.17",
"@storybook/api": "^7.6.17",
@ -122,16 +122,16 @@
"ts-lit-plugin": "^2.0.2",
"tslib": "^2.6.2",
"turnstile-types": "^1.2.0",
"typescript": "^5.4.3",
"typescript": "^5.4.4",
"vite-tsconfig-paths": "^4.3.2"
},
"optionalDependencies": {
"@esbuild/darwin-arm64": "^0.20.1",
"@esbuild/linux-amd64": "^0.18.11",
"@esbuild/linux-arm64": "^0.20.1",
"@rollup/rollup-darwin-arm64": "4.14.0",
"@rollup/rollup-linux-arm64-gnu": "4.14.0",
"@rollup/rollup-linux-x64-gnu": "4.14.0"
"@rollup/rollup-darwin-arm64": "4.14.1",
"@rollup/rollup-linux-arm64-gnu": "4.14.1",
"@rollup/rollup-linux-x64-gnu": "4.14.1"
},
"engines": {
"node": ">=20"

View File

@ -75,6 +75,9 @@ export class EnterpriseLicenseListPage extends TablePage<License> {
.pf-m-no-padding-bottom {
padding-bottom: 0;
}
.install-id {
word-break: break-all;
}
`,
);
}
@ -255,7 +258,7 @@ export class EnterpriseLicenseListPage extends TablePage<License> {
>
</div>
<div class="pf-c-card__title">${msg("Your Install ID")}</div>
<div class="pf-c-card__body">${installID}</div>
<div class="pf-c-card__body install-id">${installID}</div>
`;
return html`<div class="pf-l-grid__item pf-c-card">

View File

@ -18,7 +18,7 @@ import PFPage from "@patternfly/patternfly/components/Page/page.css";
import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { EventsApi } from "@goauthentik/api";
import { EventToJSON, EventsApi } from "@goauthentik/api";
@customElement("ak-event-view")
export class EventViewPage extends AKElement {
@ -143,7 +143,7 @@ export class EventViewPage extends AKElement {
<div class="pf-c-card pf-l-grid__item pf-m-12-col">
<div class="pf-c-card__title">${msg("Raw event info")}</div>
<div class="pf-c-card__body">
<pre>${JSON.stringify(this.event, null, 4)}</pre>
<pre>${JSON.stringify(EventToJSON(this.event), null, 4)}</pre>
</div>
</div>
</div>

View File

@ -5,7 +5,7 @@ import "@goauthentik/admin/stages/authenticator_sms/AuthenticatorSMSStageForm";
import "@goauthentik/admin/stages/authenticator_static/AuthenticatorStaticStageForm";
import "@goauthentik/admin/stages/authenticator_totp/AuthenticatorTOTPStageForm";
import "@goauthentik/admin/stages/authenticator_validate/AuthenticatorValidateStageForm";
import "@goauthentik/admin/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm";
import "@goauthentik/admin/stages/authenticator_webauthn/AuthenticatorWebAuthnStageForm";
import "@goauthentik/admin/stages/captcha/CaptchaStageForm";
import "@goauthentik/admin/stages/consent/ConsentStageForm";
import "@goauthentik/admin/stages/deny/DenyStageForm";

View File

@ -5,7 +5,7 @@ import "@goauthentik/admin/stages/authenticator_sms/AuthenticatorSMSStageForm";
import "@goauthentik/admin/stages/authenticator_static/AuthenticatorStaticStageForm";
import "@goauthentik/admin/stages/authenticator_totp/AuthenticatorTOTPStageForm";
import "@goauthentik/admin/stages/authenticator_validate/AuthenticatorValidateStageForm";
import "@goauthentik/admin/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm";
import "@goauthentik/admin/stages/authenticator_webauthn/AuthenticatorWebAuthnStageForm";
import "@goauthentik/admin/stages/captcha/CaptchaStageForm";
import "@goauthentik/admin/stages/consent/ConsentStageForm";
import "@goauthentik/admin/stages/deny/DenyStageForm";

View File

@ -63,6 +63,14 @@ export class AuthenticatorValidateStageForm extends BaseStageForm<AuthenticatorV
}
renderForm(): TemplateResult {
const authenticators = [
[DeviceClassesEnum.Static, msg("Static Tokens")],
[DeviceClassesEnum.Totp, msg("TOTP Authenticators")],
[DeviceClassesEnum.Webauthn, msg("WebAuthn Authenticators")],
[DeviceClassesEnum.Duo, msg("Duo Authenticators")],
[DeviceClassesEnum.Sms, msg("SMS-based Authenticators")],
];
return html` <span>
${msg(
"Stage used to validate any authenticator. This stage should be used during authentication or authorization flows.",
@ -84,44 +92,19 @@ export class AuthenticatorValidateStageForm extends BaseStageForm<AuthenticatorV
?required=${true}
name="deviceClasses"
>
<select name="users" class="pf-c-form-control" multiple>
<option
value=${DeviceClassesEnum.Static}
?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Static)}
>
${msg("Static Tokens")}
</option>
<option
value=${DeviceClassesEnum.Totp}
?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Totp)}
>
${msg("TOTP Authenticators")}
</option>
<option
value=${DeviceClassesEnum.Webauthn}
?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Webauthn)}
>
${msg("WebAuthn Authenticators")}
</option>
<option
value=${DeviceClassesEnum.Duo}
?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Duo)}
>
${msg("Duo Authenticators")}
</option>
<option
value=${DeviceClassesEnum.Sms}
?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Sms)}
>
${msg("SMS-based Authenticators")}
</option>
</select>
<ak-checkbox-group
name="users"
class="user-field-select"
.options=${authenticators}
.value=${authenticators
.map((authenticator) => authenticator[0])
.filter((name) =>
this.isDeviceClassSelected(name as DeviceClassesEnum),
)}
></ak-checkbox-group>
<p class="pf-c-form__helper-text">
${msg("Device classes which can be used to authenticate.")}
</p>
<p class="pf-c-form__helper-text">
${msg("Hold control/command to select multiple items.")}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("Last validation threshold")}

View File

@ -1,7 +1,12 @@
import { RenderFlowOption } from "@goauthentik/admin/flows/utils";
import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
import {
DataProvision,
DualSelectPair,
} from "@goauthentik/authentik/elements/ak-dual-select/types";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider";
import "@goauthentik/elements/forms/HorizontalFormElement";
import "@goauthentik/elements/forms/Radio";
import "@goauthentik/elements/forms/SearchSelect";
@ -11,8 +16,8 @@ import { TemplateResult, html } from "lit";
import { customElement } from "lit/decorators.js";
import {
AuthenticateWebAuthnStage,
AuthenticatorAttachmentEnum,
AuthenticatorWebAuthnStage,
Flow,
FlowsApi,
FlowsInstancesListDesignationEnum,
@ -20,28 +25,39 @@ import {
ResidentKeyRequirementEnum,
StagesApi,
UserVerificationEnum,
WebAuthnDeviceType,
} from "@goauthentik/api";
@customElement("ak-stage-authenticator-webauthn-form")
export class AuthenticateWebAuthnStageForm extends BaseStageForm<AuthenticateWebAuthnStage> {
loadInstance(pk: string): Promise<AuthenticateWebAuthnStage> {
export class AuthenticatorWebAuthnStageForm extends BaseStageForm<AuthenticatorWebAuthnStage> {
deviceTypeRestrictionPair(item: WebAuthnDeviceType): DualSelectPair {
const label = item.description ? item.description : item.aaguid;
return [
item.aaguid,
html`<div class="selection-main">${label}</div>
<div class="selection-desc">${item.aaguid}</div>`,
label,
];
}
loadInstance(pk: string): Promise<AuthenticatorWebAuthnStage> {
return new StagesApi(DEFAULT_CONFIG).stagesAuthenticatorWebauthnRetrieve({
stageUuid: pk,
});
}
async send(data: AuthenticateWebAuthnStage): Promise<AuthenticateWebAuthnStage> {
async send(data: AuthenticatorWebAuthnStage): Promise<AuthenticatorWebAuthnStage> {
if (data.authenticatorAttachment?.toString() === "") {
data.authenticatorAttachment = null;
}
if (this.instance) {
return new StagesApi(DEFAULT_CONFIG).stagesAuthenticatorWebauthnUpdate({
stageUuid: this.instance.pk || "",
authenticateWebAuthnStageRequest: data,
authenticatorWebAuthnStageRequest: data,
});
} else {
return new StagesApi(DEFAULT_CONFIG).stagesAuthenticatorWebauthnCreate({
authenticateWebAuthnStageRequest: data,
authenticatorWebAuthnStageRequest: data,
});
}
}
@ -164,6 +180,38 @@ export class AuthenticateWebAuthnStageForm extends BaseStageForm<AuthenticateWeb
>
</ak-radio>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("Device type restrictions")}
name="deviceTypeRestrictions"
>
<ak-dual-select-provider
.provider=${(page: number, search?: string): Promise<DataProvision> => {
return new StagesApi(DEFAULT_CONFIG)
.stagesAuthenticatorWebauthnDeviceTypesList({
page: page,
search: search,
})
.then((results) => {
return {
pagination: results.pagination,
options: results.results.map(
this.deviceTypeRestrictionPair,
),
};
});
}}
.selected=${(this.instance?.deviceTypeRestrictionsObj ?? []).map(
this.deviceTypeRestrictionPair,
)}
available-label="${msg("Available Device types")}"
selected-label="${msg("Selected Device types")}"
></ak-dual-select-provider>
<p class="pf-c-form__helper-text">
${msg(
"Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed.",
)}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("Configuration flow")}
name="configureFlow"

View File

@ -2,12 +2,13 @@ import "@goauthentik/admin/common/ak-flow-search/ak-flow-search";
import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first, groupBy } from "@goauthentik/common/utils";
import "@goauthentik/elements/ak-checkbox-group/ak-checkbox-group.js";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import "@goauthentik/elements/forms/SearchSelect";
import { msg } from "@lit/localize";
import { TemplateResult, html } from "lit";
import { TemplateResult, css, html } from "lit";
import { customElement } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
@ -24,6 +25,17 @@ import {
@customElement("ak-stage-identification-form")
export class IdentificationStageForm extends BaseStageForm<IdentificationStage> {
static get styles() {
return [
...super.styles,
css`
ak-checkbox-group::part(checkbox-group) {
padding-top: var(--pf-c-form--m-horizontal__group-label--md--PaddingTop);
}
`,
];
}
loadInstance(pk: string): Promise<IdentificationStage> {
return new StagesApi(DEFAULT_CONFIG).stagesIdentificationRetrieve({
stageUuid: pk,
@ -60,6 +72,12 @@ export class IdentificationStageForm extends BaseStageForm<IdentificationStage>
}
renderForm(): TemplateResult {
const userSelectFields = [
{ name: UserFieldsEnum.Username, label: msg("Username") },
{ name: UserFieldsEnum.Email, label: msg("Email") },
{ name: UserFieldsEnum.Upn, label: msg("UPN") },
];
return html`<span>
${msg("Let the user identify themselves with their username or Email address.")}
</span>
@ -75,34 +93,18 @@ export class IdentificationStageForm extends BaseStageForm<IdentificationStage>
<span slot="header"> ${msg("Stage-specific settings")} </span>
<div slot="body" class="pf-c-form">
<ak-form-element-horizontal label=${msg("User fields")} name="userFields">
<select class="pf-c-form-control" multiple>
<option
value=${UserFieldsEnum.Username}
?selected=${this.isUserFieldSelected(UserFieldsEnum.Username)}
>
${msg("Username")}
</option>
<option
value=${UserFieldsEnum.Email}
?selected=${this.isUserFieldSelected(UserFieldsEnum.Email)}
>
${msg("Email")}
</option>
<option
value=${UserFieldsEnum.Upn}
?selected=${this.isUserFieldSelected(UserFieldsEnum.Upn)}
>
${msg("UPN")}
</option>
</select>
<ak-checkbox-group
class="user-field-select"
.options=${userSelectFields}
.value=${userSelectFields
.map(({ name }) => name)
.filter((name) => this.isUserFieldSelected(name))}
></ak-checkbox-group>
<p class="pf-c-form__helper-text">
${msg(
"Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources.",
)}
</p>
<p class="pf-c-form__helper-text">
${msg("Hold control/command to select multiple items.")}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${msg("Password stage")} name="passwordStage">
<ak-search-select

View File

@ -54,6 +54,21 @@ export class PasswordStageForm extends BaseStageForm<PasswordStage> {
}
renderForm(): TemplateResult {
const backends = [
{
name: BackendsEnum.CoreAuthInbuiltBackend,
label: msg("User database + standard password"),
},
{
name: BackendsEnum.CoreAuthTokenBackend,
label: msg("User database + app passwords"),
},
{
name: BackendsEnum.SourcesLdapAuthLdapBackend,
label: msg("User database + LDAP password"),
},
];
return html` <span>
${msg("Validate the user's password against the selected backend(s).")}
</span>
@ -73,32 +88,13 @@ export class PasswordStageForm extends BaseStageForm<PasswordStage> {
?required=${true}
name="backends"
>
<select name="users" class="pf-c-form-control" multiple>
<option
value=${BackendsEnum.CoreAuthInbuiltBackend}
?selected=${this.isBackendSelected(
BackendsEnum.CoreAuthInbuiltBackend,
)}
>
${msg("User database + standard password")}
</option>
<option
value=${BackendsEnum.CoreAuthTokenBackend}
?selected=${this.isBackendSelected(
BackendsEnum.CoreAuthTokenBackend,
)}
>
${msg("User database + app passwords")}
</option>
<option
value=${BackendsEnum.SourcesLdapAuthLdapBackend}
?selected=${this.isBackendSelected(
BackendsEnum.SourcesLdapAuthLdapBackend,
)}
>
${msg("User database + LDAP password")}
</option>
</select>
<ak-checkbox-group
class="user-field-select"
.options=${backends}
.value=${backends
.map(({ name }) => name)
.filter((name) => this.isBackendSelected(name))}
></ak-checkbox-group>
<p class="pf-c-form__helper-text">
${msg("Selection of backends to test the password against.")}
</p>

View File

@ -0,0 +1,112 @@
import "@goauthentik/elements/messages/MessageContainer";
import { Meta } from "@storybook/web-components";
import { TemplateResult, html } from "lit";
import "./ak-checkbox-group";
import { CheckboxGroup as AkCheckboxGroup } from "./ak-checkbox-group";
const metadata: Meta<AkCheckboxGroup> = {
title: "Elements / Checkbox Group",
component: "ak-checkbox-group",
parameters: {
docs: {
description: {
component: "A stylized value control for check buttons",
},
},
},
};
export default metadata;
const container = (testItem: TemplateResult) =>
html` <div style="background: #fff; padding: 2em">
<style>
li {
display: block;
}
p {
margin-top: 1em;
}
</style>
${testItem}
<ul id="check-message-pad" style="margin-top: 1em"></ul>
</div>`;
const testOptions = [
{ label: "Option One: funky", name: "funky" },
{ label: "Option Two: invalid", name: "invalid" },
{ label: "Option Three: weird", name: "weird" },
];
export const CheckboxGroup = () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const displayChange = (ev: any) => {
document.getElementById("check-message-pad")!.innerHTML = `
<p>Values selected on target: ${ev.target.value.join(", ")}</p>
<p>Values sent in event: ${ev.detail.join(", ")}</p>
<p>Values present as data-ak-control: <kbd>${JSON.stringify(ev.target.json, null)}</kbd></p>`;
};
return container(
html` <p style="max-width: 50ch; padding-bottom: 1rem;">
Evented example. Intercept the <kbd>input</kbd> event and display the value seen in
the event target.
</p>
<ak-checkbox-group
@change=${displayChange}
name="ak-test-check-input"
.options=${testOptions}
></ak-checkbox-group>`,
);
};
type FDType = [string, string | FormDataEntryValue];
export const FormCheckboxGroup = () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const displayChange = (ev: any) => {
ev.preventDefault();
const formData = new FormData(ev.target);
const valList = Array.from(formData)
.map(([_key, val]: FDType) => val)
.join(", ");
const fdList = Array.from(formData)
.map(
([key, val]: FDType) =>
`${encodeURIComponent(key)}=${encodeURIComponent(val as string)}`,
)
.join("&");
document.getElementById("check-message-pad")!.innerHTML = `
<p>Values as seen in \`form.formData\`: ${valList}</p>
<p>Values as seen in x-form-encoded format: <kbd>${fdList}</kbd></p>`;
};
return container(
html`<p style="max-width: 50ch; padding-bottom: 1rem;">
FormData example. This variant emits the same events and exhibits the same behavior
as the above, but instead of monitoring for 'change' events on the checkbox group,
we monitor for the user pressing the 'submit' button. What is displayed is the
values as understood by the &lt;form&gt; object, via its internal \`formData\`
field, to demonstrate that this component works with forms as if it were a native
form element.
</p>
<form @submit=${displayChange}>
<ak-checkbox-group
name="ak-test-checkgroup-input"
.options=${testOptions}
></ak-checkbox-group>
<button type="submit" style="margin-top: 2em">
<em><strong>Submit</strong></em>
</button>
</form>`,
);
};

View File

@ -0,0 +1,212 @@
import { AKElement } from "@goauthentik/elements/Base";
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
import { msg } from "@lit/localize";
import { TemplateResult, css, html } from "lit";
import { customElement, property, queryAll } from "lit/decorators.js";
import { map } from "lit/directives/map.js";
import PFCheck from "@patternfly/patternfly/components/Check/check.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
type CheckboxKv = { name: string; label: string | TemplateResult };
type CheckboxPr = [string, string | TemplateResult];
export type CheckboxPair = CheckboxKv | CheckboxPr;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const isCheckboxPr = (t: any): t is CheckboxPr => Array.isArray(t);
function* kvToPairs(items: CheckboxPair[]): Iterable<CheckboxPr> {
for (const item of items) {
yield isCheckboxPr(item) ? item : [item.name, item.label];
}
}
const AkElementWithCustomEvents = CustomEmitterElement(AKElement);
/**
* @element ak-checkbox-group
*
* @class CheckboxGroup
*
* @description
* CheckboxGroup renders a collection of checkboxes in a linear list. Multiple
* checkboxes may be picked.
*
* @attr {options} - An array of either `[string, string | TemplateResult]` or
* `{ name: string, label: string | TemplateResult }`. The first value or
* `name` field must be a valid HTML identifier compatible with the HTML
* `name` attribute.
*
* @attr {value} - An array of `name` values corresponding to the options that
* are selected when the element is rendered.
*
* @attr {name} - The name of this element as it will appear in any <form>
* transaction
*
* @attr {required} - If true, and if name is set, and no values are chosen,
* will automatically fail a form `submit` event, providing a warning
* message for any labeling. Note: if `name` is not set, this has no effect,
* and a warn() will appear on the console.
*
* @event {input} - Fired when the component's value has changed. Current value
* as an array of `name` will be in the `Event.detail` field.
*
* @event {change} - Fired when the component's value has changed. Current value
* as an array of `name` will be in the `Event.detail` field.
*
* @csspart checkbox - The div containing the checkbox item and the label
* @csspart label - the label
* @csspart input - the input item
* @csspart checkbox-group - the wrapper div with flexbox control
*
* ## Bigger hit area
*
* Providing properly formatted names for selections allows the element to
* associate the label with the event, so the entire horizontal area from
* checkbox to end-of-label will be the hit area.
*
* ## FormAssociated compliance
*
* If a <form> component is a parent, this component will correctly send its
* values to the form for `x-form-encoded` data; multiples will appear in the
* form of `name=value1&name=value2` format, and must be unpacked into an array
* correctly on the server side according to the CGI (common gateway interface)
* protocol.
*
*/
@customElement("ak-checkbox-group")
export class CheckboxGroup extends AkElementWithCustomEvents {
static get styles() {
return [
PFBase,
PFForm,
PFCheck,
css`
.pf-c-form__group-control {
padding-top: calc(
var(--pf-c-form--m-horizontal__group-label--md--PaddingTop) * 1.3
);
}
`,
];
}
static get formAssociated() {
return true;
}
@property({ type: Array })
options: CheckboxPair[] = [];
@property({ type: Array })
value: string[] = [];
@property({ type: String })
name?: string;
@property({ type: Boolean })
required = false;
@queryAll('input[type="checkbox"]')
checkboxes!: NodeListOf<HTMLInputElement>;
internals?: ElementInternals;
get json() {
return this.value;
}
private get formValue() {
if (this.name === undefined) {
throw new Error("This cannot be called without having the name set.");
}
const name = this.name;
const entries = new FormData();
this.value.forEach((v) => entries.append(name, v));
return entries;
}
constructor() {
super();
this.onClick = this.onClick.bind(this);
this.dataset.akControl = "true";
}
onClick(ev: Event) {
ev.stopPropagation();
this.value = Array.from(this.checkboxes)
.filter((checkbox) => checkbox.checked)
.map((checkbox) => checkbox.name);
this.dispatchCustomEvent("change", this.value);
this.dispatchCustomEvent("input", this.value);
if (this.internals) {
this.internals.setValidity({});
if (this.required && this.value.length === 0) {
this.internals.setValidity(
{
valueMissing: true,
},
msg("A selection is required"),
this,
);
}
this.internals.setFormValue(this.formValue);
}
}
connectedCallback() {
super.connectedCallback();
if (this.name && !this.internals) {
this.internals = this.attachInternals();
}
if (this.internals && this.name) {
this.internals.ariaRequired = this.required ? "true" : "false";
}
if (this.required && !this.internals) {
console.warn(
"Setting `required` on ak-checkbox-group has no effect when the `name` attribute is unset",
);
}
// These are necessary to prevent the input components' own events from
// leaking out. This helps maintain the illusion that this component
// behaves similarly to the multiple selection behavior of, well,
// <select multiple>.
this.addEventListener("input", (ev) => {
ev.stopPropagation();
});
this.addEventListener("change", (ev) => {
ev.stopPropagation();
});
}
render() {
const renderOne = ([name, label]: CheckboxPr) => {
const selected = this.value.includes(name);
const blockFwd = (e: Event) => {
e.stopImmediatePropagation();
};
return html` <div part="checkbox" class="pf-c-check" @click=${this.onClick}>
<input
part="input"
@change=${blockFwd}
@input=${blockFwd}
name="${name}"
class="pf-c-check__input"
type="checkbox"
?checked=${selected}
id="ak-check-${name}"
/>
<label part="label" class="pf-c-check__label" for="ak-check-${name}"
>${label}</label
>
</div>`;
};
return html`<div part="checkbox-group" class="pf-c-form__group-control pf-m-stack">
${map(kvToPairs(this.options), renderOne)}
</div>`;
}
}

View File

@ -10,6 +10,7 @@ import { BaseStage } from "@goauthentik/flow/stages/base";
import { msg, str } from "@lit/localize";
import { CSSResult, TemplateResult, css, html, nothing } from "lit";
import { customElement, property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css";
@ -130,6 +131,17 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
</header>
<div class="pf-c-login__main-body">
<form class="pf-c-form">
<ak-form-static
class="pf-c-form__group"
userAvatar="${this.challenge.pendingUserAvatar}"
user=${this.challenge.pendingUser}
>
<div slot="link">
<a href="${ifDefined(this.challenge.flowInfo?.cancelUrl)}"
>${msg("Not you?")}</a
>
</div>
</ak-form-static>
<ak-empty-state
?loading="${this.registerRunning}"
header=${this.registerRunning

View File

@ -6472,6 +6472,9 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s02160dc6adba3456">
<source>Inject an OAuth or SAML Source into the flow execution. This allows for additional user verification, or to dynamically access different sources for different user identifiers (username, email address, etc).</source>
</trans-unit>
<trans-unit id="sc7d071fb5cc1f6bf">
<source>A selection is required</source>
</trans-unit>
</body>
</file>

View File

@ -6741,6 +6741,9 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s02160dc6adba3456">
<source>Inject an OAuth or SAML Source into the flow execution. This allows for additional user verification, or to dynamically access different sources for different user identifiers (username, email address, etc).</source>
</trans-unit>
<trans-unit id="sc7d071fb5cc1f6bf">
<source>A selection is required</source>
</trans-unit>
</body>
</file>

View File

@ -6388,6 +6388,9 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s02160dc6adba3456">
<source>Inject an OAuth or SAML Source into the flow execution. This allows for additional user verification, or to dynamically access different sources for different user identifiers (username, email address, etc).</source>
</trans-unit>
<trans-unit id="sc7d071fb5cc1f6bf">
<source>A selection is required</source>
</trans-unit>
</body>
</file>

View File

@ -8501,6 +8501,9 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
</trans-unit>
<trans-unit id="s02160dc6adba3456">
<source>Inject an OAuth or SAML Source into the flow execution. This allows for additional user verification, or to dynamically access different sources for different user identifiers (username, email address, etc).</source>
</trans-unit>
<trans-unit id="sc7d071fb5cc1f6bf">
<source>A selection is required</source>
</trans-unit>
</body>
</file>

View File

@ -8329,6 +8329,9 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s02160dc6adba3456">
<source>Inject an OAuth or SAML Source into the flow execution. This allows for additional user verification, or to dynamically access different sources for different user identifiers (username, email address, etc).</source>
</trans-unit>
<trans-unit id="sc7d071fb5cc1f6bf">
<source>A selection is required</source>
</trans-unit>
</body>
</file>

View File

@ -8172,6 +8172,9 @@ Bindingen naar groepen/gebruikers worden gecontroleerd tegen de gebruiker van de
</trans-unit>
<trans-unit id="s02160dc6adba3456">
<source>Inject an OAuth or SAML Source into the flow execution. This allows for additional user verification, or to dynamically access different sources for different user identifiers (username, email address, etc).</source>
</trans-unit>
<trans-unit id="sc7d071fb5cc1f6bf">
<source>A selection is required</source>
</trans-unit>
</body>
</file>

View File

@ -6593,6 +6593,9 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s02160dc6adba3456">
<source>Inject an OAuth or SAML Source into the flow execution. This allows for additional user verification, or to dynamically access different sources for different user identifiers (username, email address, etc).</source>
</trans-unit>
<trans-unit id="sc7d071fb5cc1f6bf">
<source>A selection is required</source>
</trans-unit>
</body>
</file>

View File

@ -8445,4 +8445,7 @@ Bindings to groups/users are checked against the user of the event.</source>
<trans-unit id="s02160dc6adba3456">
<source>Inject an OAuth or SAML Source into the flow execution. This allows for additional user verification, or to dynamically access different sources for different user identifiers (username, email address, etc).</source>
</trans-unit>
<trans-unit id="sc7d071fb5cc1f6bf">
<source>A selection is required</source>
</trans-unit>
</body></file></xliff>

View File

@ -6381,6 +6381,9 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s02160dc6adba3456">
<source>Inject an OAuth or SAML Source into the flow execution. This allows for additional user verification, or to dynamically access different sources for different user identifiers (username, email address, etc).</source>
</trans-unit>
<trans-unit id="sc7d071fb5cc1f6bf">
<source>A selection is required</source>
</trans-unit>
</body>
</file>

View File

@ -5299,6 +5299,9 @@ Bindings to groups/users are checked against the user of the event.</source>
<trans-unit id="s02160dc6adba3456">
<source>Inject an OAuth or SAML Source into the flow execution. This allows for additional user verification, or to dynamically access different sources for different user identifiers (username, email address, etc).</source>
</trans-unit>
<trans-unit id="sc7d071fb5cc1f6bf">
<source>A selection is required</source>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -1,4 +1,4 @@
<?xml version="1.0"?><xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
<?xml version="1.0" ?><xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
<file target-language="zh-Hans" source-language="en" original="lit-localize-inputs" datatype="plaintext">
<body>
<trans-unit id="s4caed5b7a7e5d89b">
@ -596,9 +596,9 @@
</trans-unit>
<trans-unit id="saa0e2675da69651b">
<source>The URL "<x id="0" equiv-text="${this.url}"/>" was not found.</source>
<target>未找到 URL "
<x id="0" equiv-text="${this.url}"/>"。</target>
<source>The URL &quot;<x id="0" equiv-text="${this.url}"/>&quot; was not found.</source>
<target>未找到 URL &quot;
<x id="0" equiv-text="${this.url}"/>&quot;。</target>
</trans-unit>
<trans-unit id="s58cd9c2fe836d9c6">
@ -1040,8 +1040,8 @@
</trans-unit>
<trans-unit id="sa8384c9c26731f83">
<source>To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have.</source>
<target>要允许任何重定向 URI请将此值设置为 ".*"。请注意这可能带来的安全影响。</target>
<source>To allow any redirect URI, set this value to &quot;.*&quot;. Be aware of the possible security implications this can have.</source>
<target>要允许任何重定向 URI请将此值设置为 &quot;.*&quot;。请注意这可能带来的安全影响。</target>
</trans-unit>
<trans-unit id="s55787f4dfcdce52b">
@ -1782,8 +1782,8 @@
</trans-unit>
<trans-unit id="sa90b7809586c35ce">
<source>Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".</source>
<target>输入完整 URL、相对路径或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。</target>
<source>Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon &quot;fa-test&quot;.</source>
<target>输入完整 URL、相对路径或者使用 'fa://fa-test' 来使用 Font Awesome 图标 &quot;fa-test&quot;。</target>
</trans-unit>
<trans-unit id="s0410779cb47de312">
@ -2961,8 +2961,8 @@ doesn't pass when either or both of the selected options are equal or above the
</trans-unit>
<trans-unit id="s76768bebabb7d543">
<source>Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'</source>
<target>包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...'</target>
<source>Field which contains members of a group. Note that if using the &quot;memberUid&quot; field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'</source>
<target>包含组成员的字段。请注意,如果使用 &quot;memberUid&quot; 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...'</target>
</trans-unit>
<trans-unit id="s026555347e589f0e">
@ -3739,8 +3739,8 @@ doesn't pass when either or both of the selected options are equal or above the
</trans-unit>
<trans-unit id="s7b1fba26d245cb1c">
<source>When using an external logging solution for archiving, this can be set to "minutes=5".</source>
<target>使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。</target>
<source>When using an external logging solution for archiving, this can be set to &quot;minutes=5&quot;.</source>
<target>使用外部日志记录解决方案进行存档时,可以将其设置为 &quot;minutes=5&quot;。</target>
</trans-unit>
<trans-unit id="s44536d20bb5c8257">
@ -3916,10 +3916,10 @@ doesn't pass when either or both of the selected options are equal or above the
</trans-unit>
<trans-unit id="sa95a538bfbb86111">
<source>Are you sure you want to update <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>"?</source>
<source>Are you sure you want to update <x id="0" equiv-text="${this.objectLabel}"/> &quot;<x id="1" equiv-text="${this.obj?.name}"/>&quot;?</source>
<target>您确定要更新
<x id="0" equiv-text="${this.objectLabel}"/>"
<x id="1" equiv-text="${this.obj?.name}"/>" 吗?</target>
<x id="0" equiv-text="${this.objectLabel}"/>&quot;
<x id="1" equiv-text="${this.obj?.name}"/>&quot; 吗?</target>
</trans-unit>
<trans-unit id="sc92d7cfb6ee1fec6">
@ -5000,7 +5000,7 @@ doesn't pass when either or both of the selected options are equal or above the
</trans-unit>
<trans-unit id="sdf1d8edef27236f0">
<source>A "roaming" authenticator, like a YubiKey</source>
<source>A &quot;roaming&quot; authenticator, like a YubiKey</source>
<target>像 YubiKey 这样的“漫游”身份验证器</target>
</trans-unit>
@ -5335,10 +5335,10 @@ doesn't pass when either or both of the selected options are equal or above the
</trans-unit>
<trans-unit id="s2d5f69929bb7221d">
<source><x id="0" equiv-text="${prompt.name}"/> ("<x id="1" equiv-text="${prompt.fieldKey}"/>", of type <x id="2" equiv-text="${prompt.type}"/>)</source>
<source><x id="0" equiv-text="${prompt.name}"/> (&quot;<x id="1" equiv-text="${prompt.fieldKey}"/>&quot;, of type <x id="2" equiv-text="${prompt.type}"/>)</source>
<target>
<x id="0" equiv-text="${prompt.name}"/>"
<x id="1" equiv-text="${prompt.fieldKey}"/>",类型为
<x id="0" equiv-text="${prompt.name}"/>&quot;
<x id="1" equiv-text="${prompt.fieldKey}"/>&quot;,类型为
<x id="2" equiv-text="${prompt.type}"/></target>
</trans-unit>
@ -5387,7 +5387,7 @@ doesn't pass when either or both of the selected options are equal or above the
</trans-unit>
<trans-unit id="s1608b2f94fa0dbd4">
<source>If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here.</source>
<source>If set to a duration above 0, the user will have the option to choose to &quot;stay signed in&quot;, which will extend their session by the time specified here.</source>
<target>如果设置时长大于 0用户可以选择“保持登录”选项这将使用户的会话延长此处设置的时间。</target>
</trans-unit>
@ -7839,7 +7839,7 @@ Bindings to groups/users are checked against the user of the event.</source>
<target>成功创建用户并添加到组 <x id="0" equiv-text="${this.group.name}"/></target>
</trans-unit>
<trans-unit id="s824e0943a7104668">
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
<source>This user will be added to the group &quot;<x id="0" equiv-text="${this.targetGroup.name}"/>&quot;.</source>
<target>此用户将会被添加到组 &amp;quot;<x id="0" equiv-text="${this.targetGroup.name}"/>&amp;quot;。</target>
</trans-unit>
<trans-unit id="s62e7f6ed7d9cb3ca">
@ -8519,7 +8519,11 @@ Bindings to groups/users are checked against the user of the event.</source>
<trans-unit id="s02160dc6adba3456">
<source>Inject an OAuth or SAML Source into the flow execution. This allows for additional user verification, or to dynamically access different sources for different user identifiers (username, email address, etc).</source>
<target>将 OAuth 或 SAML 源注入到流程执行过程中。这允许额外的用户验证,或者基于不同的用户标识符(用户名、电子邮件地址等)动态访问不同的源。</target>
</trans-unit>
<trans-unit id="sc7d071fb5cc1f6bf">
<source>A selection is required</source>
<target>需要进行选择</target>
</trans-unit>
</body>
</file>
</xliff>
</xliff>

View File

@ -6429,6 +6429,9 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s02160dc6adba3456">
<source>Inject an OAuth or SAML Source into the flow execution. This allows for additional user verification, or to dynamically access different sources for different user identifiers (username, email address, etc).</source>
</trans-unit>
<trans-unit id="sc7d071fb5cc1f6bf">
<source>A selection is required</source>
</trans-unit>
</body>
</file>

View File

@ -8519,6 +8519,10 @@ Bindings to groups/users are checked against the user of the event.</source>
<trans-unit id="s02160dc6adba3456">
<source>Inject an OAuth or SAML Source into the flow execution. This allows for additional user verification, or to dynamically access different sources for different user identifiers (username, email address, etc).</source>
<target>将 OAuth 或 SAML 源注入到流程执行过程中。这允许额外的用户验证,或者基于不同的用户标识符(用户名、电子邮件地址等)动态访问不同的源。</target>
</trans-unit>
<trans-unit id="sc7d071fb5cc1f6bf">
<source>A selection is required</source>
<target>需要进行选择</target>
</trans-unit>
</body>
</file>

View File

@ -8290,6 +8290,9 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s02160dc6adba3456">
<source>Inject an OAuth or SAML Source into the flow execution. This allows for additional user verification, or to dynamically access different sources for different user identifiers (username, email address, etc).</source>
</trans-unit>
<trans-unit id="sc7d071fb5cc1f6bf">
<source>A selection is required</source>
</trans-unit>
</body>
</file>

View File

@ -4,4 +4,26 @@ title: WebAuthn authenticator setup stage
This stage configures a WebAuthn-based Authenticator. This can either be a browser, biometrics or a Security stick like a YubiKey.
There are no stage-specific settings.
### `User verification`
Configure if authentik should require, prefer or discourage user verification for the authenticator. For example when using a virtual authenticator like Windows Hello, this setting controls if a PIN is required.
### `Resident key requirement`
Configure if the created authenticator is stored in the encrypted memory on the device or in persistent memory. When configuring [passwordless login](../identification/index.md#passwordless-flow), this should be set to either _Preferred_ or _Required_, otherwise the authenticator cannot be used for passwordless authentication.
### `Authenticator Attachment`
Configure if authentik will require either a removable device (like a YubiKey, Google Titan, etc) or a non-removable device (like Windows Hello, TouchID or password managers), or not send a requirement.
### `Device type restrictions`
:::info
Requires authentik 2024.4
:::
Optionally restrict the types of devices allowed to be enrolled. This option can be used to ensure users are only able to enroll FIPS-compliant devices for example.
When no restrictions are selected, all device types are allowed.
As authentik does not know of all possible device types, it is possible to select the special option `authentik: Unknown devices` to allow unknown devices.

View File

@ -104,8 +104,8 @@ Create a provider for Nextcloud. In the Admin Interface, go to _Applications_ ->
Before continuing, make sure to take note of your `client ID` and `secret ID`. Don't worry you can go back to see/change them at any time.
:::warning
Currently there is a bug in the Nextcloud OIDC app, that is [limiting the size of the secret ID](https://github.com/nextcloud/user_oidc/issues/405) token to 64 characters. Since authentik uses 128 characters for a secret ID by default, you will need to trim it down to 64 characters in order to be able to set it in Nextcloud. Don't worry, 64 characters is still sufficiently long and should not compromise security.
:::note
There were an issue in the Nextcloud OIDC app that was [limiting the size of the secret ID](https://github.com/nextcloud/user_oidc/issues/405) token to 64 characters. This issue was fixed in December 2023, so make sure you update to the latest version of the [OpenID Connect user backend](https://apps.nextcloud.com/apps/user_oidc) application.
:::
:::note

View File

@ -9,12 +9,12 @@
"version": "0.0.0",
"license": "MIT",
"dependencies": {
"@docusaurus/core": "^3.2.0",
"@docusaurus/plugin-client-redirects": "^3.2.0",
"@docusaurus/plugin-content-docs": "^3.2.0",
"@docusaurus/preset-classic": "^3.2.0",
"@docusaurus/theme-common": "^3.2.0",
"@docusaurus/theme-mermaid": "^3.2.0",
"@docusaurus/core": "^3.2.1",
"@docusaurus/plugin-client-redirects": "^3.2.1",
"@docusaurus/plugin-content-docs": "^3.2.1",
"@docusaurus/preset-classic": "^3.2.1",
"@docusaurus/theme-common": "^3.2.1",
"@docusaurus/theme-mermaid": "^3.2.1",
"@mdx-js/react": "^3.0.1",
"clsx": "^2.1.0",
"disqus-react": "^1.1.5",
@ -30,12 +30,12 @@
"remark-github": "^12.0.0"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "3.2.0",
"@docusaurus/tsconfig": "3.2.0",
"@docusaurus/types": "3.2.0",
"@docusaurus/module-type-aliases": "3.2.1",
"@docusaurus/tsconfig": "3.2.1",
"@docusaurus/types": "3.2.1",
"@types/react": "^18.2.74",
"prettier": "3.2.5",
"typescript": "~5.4.3"
"typescript": "~5.4.4"
},
"engines": {
"node": ">=20"
@ -2187,9 +2187,9 @@
}
},
"node_modules/@docusaurus/core": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.2.0.tgz",
"integrity": "sha512-WTO6vW4404nhTmK9NL+95nd13I1JveFwZ8iOBYxb4xt+N2S3KzY+mm+1YtWw2vV37FbYfH+w+KrlrRaWuy5Hzw==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.2.1.tgz",
"integrity": "sha512-ZeMAqNvy0eBv2dThEeMuNzzuu+4thqMQakhxsgT5s02A8LqRcdkg+rbcnuNqUIpekQ4GRx3+M5nj0ODJhBXo9w==",
"dependencies": {
"@babel/core": "^7.23.3",
"@babel/generator": "^7.23.3",
@ -2201,13 +2201,13 @@
"@babel/runtime": "^7.22.6",
"@babel/runtime-corejs3": "^7.22.6",
"@babel/traverse": "^7.22.8",
"@docusaurus/cssnano-preset": "3.2.0",
"@docusaurus/logger": "3.2.0",
"@docusaurus/mdx-loader": "3.2.0",
"@docusaurus/cssnano-preset": "3.2.1",
"@docusaurus/logger": "3.2.1",
"@docusaurus/mdx-loader": "3.2.1",
"@docusaurus/react-loadable": "5.5.2",
"@docusaurus/utils": "3.2.0",
"@docusaurus/utils-common": "3.2.0",
"@docusaurus/utils-validation": "3.2.0",
"@docusaurus/utils": "3.2.1",
"@docusaurus/utils-common": "3.2.1",
"@docusaurus/utils-validation": "3.2.1",
"@svgr/webpack": "^6.5.1",
"autoprefixer": "^10.4.14",
"babel-loader": "^9.1.3",
@ -2273,40 +2273,14 @@
"react-dom": "^18.0.0"
}
},
"node_modules/@docusaurus/cssnano-preset": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.2.0.tgz",
"integrity": "sha512-H88RXGUia7r/VF3XfyoA4kbwgpUZcKsObF6VvwBOP91EdArTf6lnHbJ/x8Ca79KS/zf98qaWyBGzW+5ez58Iyw==",
"node_modules/@docusaurus/core/node_modules/@docusaurus/mdx-loader": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.2.1.tgz",
"integrity": "sha512-Fs8tXhXKZjNkdGaOy1xSLXSwfjCMT73J3Zfrju2U16uGedRFRjgK0ojpK5tiC7TnunsL3tOFgp1BSMBRflX9gw==",
"dependencies": {
"cssnano-preset-advanced": "^5.3.10",
"postcss": "^8.4.26",
"postcss-sort-media-queries": "^4.4.1",
"tslib": "^2.6.0"
},
"engines": {
"node": ">=18.0"
}
},
"node_modules/@docusaurus/logger": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.2.0.tgz",
"integrity": "sha512-Z1R1NcOGXZ8CkIJSvjvyxnuDDSlx/+1xlh20iVTw1DZRjonFmI3T3tTgk40YpXyWUYQpIgAoqqPMpuseMMdgRQ==",
"dependencies": {
"chalk": "^4.1.2",
"tslib": "^2.6.0"
},
"engines": {
"node": ">=18.0"
}
},
"node_modules/@docusaurus/mdx-loader": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.2.0.tgz",
"integrity": "sha512-JtkI5o6R/rJSr1Y23cHKz085aBJCvJw3AYHihJ7r+mBX+O8EuQIynG0e6/XpbSCpr7Ino0U50UtxaXcEbFwg9Q==",
"dependencies": {
"@docusaurus/logger": "3.2.0",
"@docusaurus/utils": "3.2.0",
"@docusaurus/utils-validation": "3.2.0",
"@docusaurus/logger": "3.2.1",
"@docusaurus/utils": "3.2.1",
"@docusaurus/utils-validation": "3.2.1",
"@mdx-js/mdx": "^3.0.0",
"@slorber/remark-comment": "^1.0.0",
"escape-html": "^1.0.3",
@ -2337,13 +2311,39 @@
"react-dom": "^18.0.0"
}
},
"node_modules/@docusaurus/cssnano-preset": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.2.1.tgz",
"integrity": "sha512-wTL9KuSSbMJjKrfu385HZEzAoamUsbKqwscAQByZw4k6Ja/RWpqgVvt/CbAC+aYEH6inLzOt+MjuRwMOrD3VBA==",
"dependencies": {
"cssnano-preset-advanced": "^5.3.10",
"postcss": "^8.4.26",
"postcss-sort-media-queries": "^4.4.1",
"tslib": "^2.6.0"
},
"engines": {
"node": ">=18.0"
}
},
"node_modules/@docusaurus/logger": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.2.1.tgz",
"integrity": "sha512-0voOKJCn9RaM3np6soqEfo7SsVvf2C+CDTWhW+H/1AyBhybASpExtDEz+7ECck9TwPzFQ5tt+I3zVugUJbJWDg==",
"dependencies": {
"chalk": "^4.1.2",
"tslib": "^2.6.0"
},
"engines": {
"node": ">=18.0"
}
},
"node_modules/@docusaurus/module-type-aliases": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.2.0.tgz",
"integrity": "sha512-jRSp9YkvBwwNz6Xgy0RJPsnie+Ebb//gy7GdbkJ2pW2gvvlYKGib2+jSF0pfIzvyZLulfCynS1KQdvDKdSl8zQ==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.2.1.tgz",
"integrity": "sha512-FyViV5TqhL1vsM7eh29nJ5NtbRE6Ra6LP1PDcPvhwPSlA7eiWGRKAn3jWwMUcmjkos5SYY+sr0/feCdbM3eQHQ==",
"dependencies": {
"@docusaurus/react-loadable": "5.5.2",
"@docusaurus/types": "3.2.0",
"@docusaurus/types": "3.2.1",
"@types/history": "^4.7.11",
"@types/react": "*",
"@types/react-router-config": "*",
@ -2357,15 +2357,15 @@
}
},
"node_modules/@docusaurus/plugin-client-redirects": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-3.2.0.tgz",
"integrity": "sha512-re5bgvYOgBHmevlI8HO3fZHL7mvX2lAULr4E89n/bQ5kgekLLhsaerWrAah22ZluMZyJC2439EGjR63E9Ba6KA==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-3.2.1.tgz",
"integrity": "sha512-GgzuqwbqNQSP5s/ouUrOQFuHI8m4Rn8a5CHuWkwpqj+5lbQMsABcvsoiWjrH9M00CzN48q+slSbJy7rtHjn7zg==",
"dependencies": {
"@docusaurus/core": "3.2.0",
"@docusaurus/logger": "3.2.0",
"@docusaurus/utils": "3.2.0",
"@docusaurus/utils-common": "3.2.0",
"@docusaurus/utils-validation": "3.2.0",
"@docusaurus/core": "3.2.1",
"@docusaurus/logger": "3.2.1",
"@docusaurus/utils": "3.2.1",
"@docusaurus/utils-common": "3.2.1",
"@docusaurus/utils-validation": "3.2.1",
"eta": "^2.2.0",
"fs-extra": "^11.1.1",
"lodash": "^4.17.21",
@ -2380,17 +2380,17 @@
}
},
"node_modules/@docusaurus/plugin-content-blog": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.2.0.tgz",
"integrity": "sha512-MABqwjSicyHmYEfQueMthPCz18JkVxhK3EGhXTSRWwReAZ0UTuw9pG6+Wo+uXAugDaIcJH28rVZSwTDINPm2bw==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.2.1.tgz",
"integrity": "sha512-lOx0JfhlGZoZu6pEJfeEpSISZR5dQbJGGvb42IP13G5YThNHhG9R9uoWuo4IOimPqBC7sHThdLA3VLevk61Fsw==",
"dependencies": {
"@docusaurus/core": "3.2.0",
"@docusaurus/logger": "3.2.0",
"@docusaurus/mdx-loader": "3.2.0",
"@docusaurus/types": "3.2.0",
"@docusaurus/utils": "3.2.0",
"@docusaurus/utils-common": "3.2.0",
"@docusaurus/utils-validation": "3.2.0",
"@docusaurus/core": "3.2.1",
"@docusaurus/logger": "3.2.1",
"@docusaurus/mdx-loader": "3.2.1",
"@docusaurus/types": "3.2.1",
"@docusaurus/utils": "3.2.1",
"@docusaurus/utils-common": "3.2.1",
"@docusaurus/utils-validation": "3.2.1",
"cheerio": "^1.0.0-rc.12",
"feed": "^4.2.2",
"fs-extra": "^11.1.1",
@ -2410,19 +2410,57 @@
"react-dom": "^18.0.0"
}
},
"node_modules/@docusaurus/plugin-content-docs": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.2.0.tgz",
"integrity": "sha512-uuqhahmsBnirxOz+SXksnWt7+wc+iN4ntxNRH48BUgo7QRNLATWjHCgI8t6zrMJxK4o+QL9DhLaPDlFHs91B3Q==",
"node_modules/@docusaurus/plugin-content-blog/node_modules/@docusaurus/mdx-loader": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.2.1.tgz",
"integrity": "sha512-Fs8tXhXKZjNkdGaOy1xSLXSwfjCMT73J3Zfrju2U16uGedRFRjgK0ojpK5tiC7TnunsL3tOFgp1BSMBRflX9gw==",
"dependencies": {
"@docusaurus/core": "3.2.0",
"@docusaurus/logger": "3.2.0",
"@docusaurus/mdx-loader": "3.2.0",
"@docusaurus/module-type-aliases": "3.2.0",
"@docusaurus/types": "3.2.0",
"@docusaurus/utils": "3.2.0",
"@docusaurus/utils-common": "3.2.0",
"@docusaurus/utils-validation": "3.2.0",
"@docusaurus/logger": "3.2.1",
"@docusaurus/utils": "3.2.1",
"@docusaurus/utils-validation": "3.2.1",
"@mdx-js/mdx": "^3.0.0",
"@slorber/remark-comment": "^1.0.0",
"escape-html": "^1.0.3",
"estree-util-value-to-estree": "^3.0.1",
"file-loader": "^6.2.0",
"fs-extra": "^11.1.1",
"image-size": "^1.0.2",
"mdast-util-mdx": "^3.0.0",
"mdast-util-to-string": "^4.0.0",
"rehype-raw": "^7.0.0",
"remark-directive": "^3.0.0",
"remark-emoji": "^4.0.0",
"remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.0",
"stringify-object": "^3.3.0",
"tslib": "^2.6.0",
"unified": "^11.0.3",
"unist-util-visit": "^5.0.0",
"url-loader": "^4.1.1",
"vfile": "^6.0.1",
"webpack": "^5.88.1"
},
"engines": {
"node": ">=18.0"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
},
"node_modules/@docusaurus/plugin-content-docs": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.2.1.tgz",
"integrity": "sha512-GHe5b/lCskAR8QVbfWAfPAApvRZgqk7FN3sOHgjCtjzQACZxkHmq6QqyqZ8Jp45V7lVck4wt2Xw2IzBJ7Cz3bA==",
"dependencies": {
"@docusaurus/core": "3.2.1",
"@docusaurus/logger": "3.2.1",
"@docusaurus/mdx-loader": "3.2.1",
"@docusaurus/module-type-aliases": "3.2.1",
"@docusaurus/types": "3.2.1",
"@docusaurus/utils": "3.2.1",
"@docusaurus/utils-common": "3.2.1",
"@docusaurus/utils-validation": "3.2.1",
"@types/react-router-config": "^5.0.7",
"combine-promises": "^1.1.0",
"fs-extra": "^11.1.1",
@ -2440,16 +2478,54 @@
"react-dom": "^18.0.0"
}
},
"node_modules/@docusaurus/plugin-content-pages": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.2.0.tgz",
"integrity": "sha512-4ofAN7JDsdb4tODO9OIrizWY5DmEJXr0eu+UDIkLqGP+gXXTahJZv8h2mlxO+lPXGXRCVBOfA14OG1hOYJVPwA==",
"node_modules/@docusaurus/plugin-content-docs/node_modules/@docusaurus/mdx-loader": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.2.1.tgz",
"integrity": "sha512-Fs8tXhXKZjNkdGaOy1xSLXSwfjCMT73J3Zfrju2U16uGedRFRjgK0ojpK5tiC7TnunsL3tOFgp1BSMBRflX9gw==",
"dependencies": {
"@docusaurus/core": "3.2.0",
"@docusaurus/mdx-loader": "3.2.0",
"@docusaurus/types": "3.2.0",
"@docusaurus/utils": "3.2.0",
"@docusaurus/utils-validation": "3.2.0",
"@docusaurus/logger": "3.2.1",
"@docusaurus/utils": "3.2.1",
"@docusaurus/utils-validation": "3.2.1",
"@mdx-js/mdx": "^3.0.0",
"@slorber/remark-comment": "^1.0.0",
"escape-html": "^1.0.3",
"estree-util-value-to-estree": "^3.0.1",
"file-loader": "^6.2.0",
"fs-extra": "^11.1.1",
"image-size": "^1.0.2",
"mdast-util-mdx": "^3.0.0",
"mdast-util-to-string": "^4.0.0",
"rehype-raw": "^7.0.0",
"remark-directive": "^3.0.0",
"remark-emoji": "^4.0.0",
"remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.0",
"stringify-object": "^3.3.0",
"tslib": "^2.6.0",
"unified": "^11.0.3",
"unist-util-visit": "^5.0.0",
"url-loader": "^4.1.1",
"vfile": "^6.0.1",
"webpack": "^5.88.1"
},
"engines": {
"node": ">=18.0"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
},
"node_modules/@docusaurus/plugin-content-pages": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.2.1.tgz",
"integrity": "sha512-TOqVfMVTAHqWNEGM94Drz+PUpHDbwFy6ucHFgyTx9zJY7wPNSG5EN+rd/mU7OvAi26qpOn2o9xTdUmb28QLjEQ==",
"dependencies": {
"@docusaurus/core": "3.2.1",
"@docusaurus/mdx-loader": "3.2.1",
"@docusaurus/types": "3.2.1",
"@docusaurus/utils": "3.2.1",
"@docusaurus/utils-validation": "3.2.1",
"fs-extra": "^11.1.1",
"tslib": "^2.6.0",
"webpack": "^5.88.1"
@ -2462,14 +2538,52 @@
"react-dom": "^18.0.0"
}
},
"node_modules/@docusaurus/plugin-debug": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.2.0.tgz",
"integrity": "sha512-p6WxtO5XZGz66y6QNQtCJwBefq4S6/w75XaXVvH1/2P9uaijvF7R+Cm2EWQZ5WsvA5wl//DFWblyDHRyVC207Q==",
"node_modules/@docusaurus/plugin-content-pages/node_modules/@docusaurus/mdx-loader": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.2.1.tgz",
"integrity": "sha512-Fs8tXhXKZjNkdGaOy1xSLXSwfjCMT73J3Zfrju2U16uGedRFRjgK0ojpK5tiC7TnunsL3tOFgp1BSMBRflX9gw==",
"dependencies": {
"@docusaurus/core": "3.2.0",
"@docusaurus/types": "3.2.0",
"@docusaurus/utils": "3.2.0",
"@docusaurus/logger": "3.2.1",
"@docusaurus/utils": "3.2.1",
"@docusaurus/utils-validation": "3.2.1",
"@mdx-js/mdx": "^3.0.0",
"@slorber/remark-comment": "^1.0.0",
"escape-html": "^1.0.3",
"estree-util-value-to-estree": "^3.0.1",
"file-loader": "^6.2.0",
"fs-extra": "^11.1.1",
"image-size": "^1.0.2",
"mdast-util-mdx": "^3.0.0",
"mdast-util-to-string": "^4.0.0",
"rehype-raw": "^7.0.0",
"remark-directive": "^3.0.0",
"remark-emoji": "^4.0.0",
"remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.0",
"stringify-object": "^3.3.0",
"tslib": "^2.6.0",
"unified": "^11.0.3",
"unist-util-visit": "^5.0.0",
"url-loader": "^4.1.1",
"vfile": "^6.0.1",
"webpack": "^5.88.1"
},
"engines": {
"node": ">=18.0"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
},
"node_modules/@docusaurus/plugin-debug": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.2.1.tgz",
"integrity": "sha512-AMKq8NuUKf2sRpN1m/sIbqbRbnmk+rSA+8mNU1LNxEl9BW9F/Gng8m9HKlzeyMPrf5XidzS1jqkuTLDJ6KIrFw==",
"dependencies": {
"@docusaurus/core": "3.2.1",
"@docusaurus/types": "3.2.1",
"@docusaurus/utils": "3.2.1",
"fs-extra": "^11.1.1",
"react-json-view-lite": "^1.2.0",
"tslib": "^2.6.0"
@ -2483,13 +2597,13 @@
}
},
"node_modules/@docusaurus/plugin-google-analytics": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.2.0.tgz",
"integrity": "sha512-//TepJTEyAZSvBwHKEbXHu9xT/VkK3wUil2ZakKvQZYfUC01uWn6A1E3toa8R7WhCy1xPUeIukqmJy1Clg8njQ==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.2.1.tgz",
"integrity": "sha512-/rJ+9u+Px0eTCiF4TNcNtj3kHf8cp6K1HCwOTdbsSlz6Xn21syZYcy+f1VM9wF6HrvUkXUcbM5TDCvg2IRL6bQ==",
"dependencies": {
"@docusaurus/core": "3.2.0",
"@docusaurus/types": "3.2.0",
"@docusaurus/utils-validation": "3.2.0",
"@docusaurus/core": "3.2.1",
"@docusaurus/types": "3.2.1",
"@docusaurus/utils-validation": "3.2.1",
"tslib": "^2.6.0"
},
"engines": {
@ -2501,13 +2615,13 @@
}
},
"node_modules/@docusaurus/plugin-google-gtag": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.2.0.tgz",
"integrity": "sha512-3s6zxlaMMb87MW2Rxy6EnSRDs0WDEQPuHilZZH402C8kOrUnIwlhlfjWZ4ZyLDziGl/Eec/DvD0PVqj0qHRomA==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.2.1.tgz",
"integrity": "sha512-XtuJnlMvYfppeVdUyKiDIJAa/gTJKCQU92z8CLZZ9ibJdgVjFOLS10s0hIC0eL5z0U2u2loJz2rZ63HOkNHbBA==",
"dependencies": {
"@docusaurus/core": "3.2.0",
"@docusaurus/types": "3.2.0",
"@docusaurus/utils-validation": "3.2.0",
"@docusaurus/core": "3.2.1",
"@docusaurus/types": "3.2.1",
"@docusaurus/utils-validation": "3.2.1",
"@types/gtag.js": "^0.0.12",
"tslib": "^2.6.0"
},
@ -2520,13 +2634,13 @@
}
},
"node_modules/@docusaurus/plugin-google-tag-manager": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.2.0.tgz",
"integrity": "sha512-rAKtsJ11vPHA7dTAqWCgyIy7AyFRF/lpI77Zd/4HKgqcIvIayVBvL3QtelhUazfYTLTH6ls6kQ9wjMcIFxRiGg==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.2.1.tgz",
"integrity": "sha512-wiS/kE0Ny5pnjTxVCs8ljRnkL1RVMj59t6jmSsgEX7piDOoaXSMIUaoIt9ogS/v132uO0xEsxHstkRUZHQyPcQ==",
"dependencies": {
"@docusaurus/core": "3.2.0",
"@docusaurus/types": "3.2.0",
"@docusaurus/utils-validation": "3.2.0",
"@docusaurus/core": "3.2.1",
"@docusaurus/types": "3.2.1",
"@docusaurus/utils-validation": "3.2.1",
"tslib": "^2.6.0"
},
"engines": {
@ -2538,16 +2652,16 @@
}
},
"node_modules/@docusaurus/plugin-sitemap": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.2.0.tgz",
"integrity": "sha512-gnWDFt6MStjLkdtt63Lzc+14EPSd8B6mzJGJp9GQMvWDUoMAUijUqpVIHYQq+DPMcI4PJZ5I2nsl5XFf1vOldA==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.2.1.tgz",
"integrity": "sha512-uWZ7AxzdeaQSTCwD2yZtOiEm9zyKU+wqCmi/Sf25kQQqqFSBZUStXfaQ8OHP9cecnw893ZpZ811rPhB/wfujJw==",
"dependencies": {
"@docusaurus/core": "3.2.0",
"@docusaurus/logger": "3.2.0",
"@docusaurus/types": "3.2.0",
"@docusaurus/utils": "3.2.0",
"@docusaurus/utils-common": "3.2.0",
"@docusaurus/utils-validation": "3.2.0",
"@docusaurus/core": "3.2.1",
"@docusaurus/logger": "3.2.1",
"@docusaurus/types": "3.2.1",
"@docusaurus/utils": "3.2.1",
"@docusaurus/utils-common": "3.2.1",
"@docusaurus/utils-validation": "3.2.1",
"fs-extra": "^11.1.1",
"sitemap": "^7.1.1",
"tslib": "^2.6.0"
@ -2561,23 +2675,23 @@
}
},
"node_modules/@docusaurus/preset-classic": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.2.0.tgz",
"integrity": "sha512-t7tXyk8kUgT7hUqEOgSJnPs+Foem9ucuan/a9QVYaVFCDjp92Sb2FpCY8bVasAokYCjodYe2LfpAoSCj5YDYWg==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.2.1.tgz",
"integrity": "sha512-E3OHSmttpEBcSMhfPBq3EJMBxZBM01W1rnaCUTXy9EHvkmB5AwgTfW1PwGAybPAX579ntE03R+2zmXdizWfKnQ==",
"dependencies": {
"@docusaurus/core": "3.2.0",
"@docusaurus/plugin-content-blog": "3.2.0",
"@docusaurus/plugin-content-docs": "3.2.0",
"@docusaurus/plugin-content-pages": "3.2.0",
"@docusaurus/plugin-debug": "3.2.0",
"@docusaurus/plugin-google-analytics": "3.2.0",
"@docusaurus/plugin-google-gtag": "3.2.0",
"@docusaurus/plugin-google-tag-manager": "3.2.0",
"@docusaurus/plugin-sitemap": "3.2.0",
"@docusaurus/theme-classic": "3.2.0",
"@docusaurus/theme-common": "3.2.0",
"@docusaurus/theme-search-algolia": "3.2.0",
"@docusaurus/types": "3.2.0"
"@docusaurus/core": "3.2.1",
"@docusaurus/plugin-content-blog": "3.2.1",
"@docusaurus/plugin-content-docs": "3.2.1",
"@docusaurus/plugin-content-pages": "3.2.1",
"@docusaurus/plugin-debug": "3.2.1",
"@docusaurus/plugin-google-analytics": "3.2.1",
"@docusaurus/plugin-google-gtag": "3.2.1",
"@docusaurus/plugin-google-tag-manager": "3.2.1",
"@docusaurus/plugin-sitemap": "3.2.1",
"@docusaurus/theme-classic": "3.2.1",
"@docusaurus/theme-common": "3.2.1",
"@docusaurus/theme-search-algolia": "3.2.1",
"@docusaurus/types": "3.2.1"
},
"engines": {
"node": ">=18.0"
@ -2600,22 +2714,22 @@
}
},
"node_modules/@docusaurus/theme-classic": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.2.0.tgz",
"integrity": "sha512-4oSO5BQOJ5ja7WYdL6jK1n4J96tp+VJHamdwao6Ea252sA3W3vvR0otTflG4p4XVjNZH6hlPQoi5lKW0HeRgfQ==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.2.1.tgz",
"integrity": "sha512-+vSbnQyoWjc6vRZi4vJO2dBU02wqzynsai15KK+FANZudrYaBHtkbLZAQhgmxzBGVpxzi87gRohlMm+5D8f4tA==",
"dependencies": {
"@docusaurus/core": "3.2.0",
"@docusaurus/mdx-loader": "3.2.0",
"@docusaurus/module-type-aliases": "3.2.0",
"@docusaurus/plugin-content-blog": "3.2.0",
"@docusaurus/plugin-content-docs": "3.2.0",
"@docusaurus/plugin-content-pages": "3.2.0",
"@docusaurus/theme-common": "3.2.0",
"@docusaurus/theme-translations": "3.2.0",
"@docusaurus/types": "3.2.0",
"@docusaurus/utils": "3.2.0",
"@docusaurus/utils-common": "3.2.0",
"@docusaurus/utils-validation": "3.2.0",
"@docusaurus/core": "3.2.1",
"@docusaurus/mdx-loader": "3.2.1",
"@docusaurus/module-type-aliases": "3.2.1",
"@docusaurus/plugin-content-blog": "3.2.1",
"@docusaurus/plugin-content-docs": "3.2.1",
"@docusaurus/plugin-content-pages": "3.2.1",
"@docusaurus/theme-common": "3.2.1",
"@docusaurus/theme-translations": "3.2.1",
"@docusaurus/types": "3.2.1",
"@docusaurus/utils": "3.2.1",
"@docusaurus/utils-common": "3.2.1",
"@docusaurus/utils-validation": "3.2.1",
"@mdx-js/react": "^3.0.0",
"clsx": "^2.0.0",
"copy-text-to-clipboard": "^3.2.0",
@ -2638,18 +2752,56 @@
"react-dom": "^18.0.0"
}
},
"node_modules/@docusaurus/theme-common": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.2.0.tgz",
"integrity": "sha512-sFbw9XviNJJ+760kAcZCQMQ3jkNIznGqa6MQ70E5BnbP+ja36kGgPOfjcsvAcNey1H1Rkhh3p2Mhf4HVLdKVVw==",
"node_modules/@docusaurus/theme-classic/node_modules/@docusaurus/mdx-loader": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.2.1.tgz",
"integrity": "sha512-Fs8tXhXKZjNkdGaOy1xSLXSwfjCMT73J3Zfrju2U16uGedRFRjgK0ojpK5tiC7TnunsL3tOFgp1BSMBRflX9gw==",
"dependencies": {
"@docusaurus/mdx-loader": "3.2.0",
"@docusaurus/module-type-aliases": "3.2.0",
"@docusaurus/plugin-content-blog": "3.2.0",
"@docusaurus/plugin-content-docs": "3.2.0",
"@docusaurus/plugin-content-pages": "3.2.0",
"@docusaurus/utils": "3.2.0",
"@docusaurus/utils-common": "3.2.0",
"@docusaurus/logger": "3.2.1",
"@docusaurus/utils": "3.2.1",
"@docusaurus/utils-validation": "3.2.1",
"@mdx-js/mdx": "^3.0.0",
"@slorber/remark-comment": "^1.0.0",
"escape-html": "^1.0.3",
"estree-util-value-to-estree": "^3.0.1",
"file-loader": "^6.2.0",
"fs-extra": "^11.1.1",
"image-size": "^1.0.2",
"mdast-util-mdx": "^3.0.0",
"mdast-util-to-string": "^4.0.0",
"rehype-raw": "^7.0.0",
"remark-directive": "^3.0.0",
"remark-emoji": "^4.0.0",
"remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.0",
"stringify-object": "^3.3.0",
"tslib": "^2.6.0",
"unified": "^11.0.3",
"unist-util-visit": "^5.0.0",
"url-loader": "^4.1.1",
"vfile": "^6.0.1",
"webpack": "^5.88.1"
},
"engines": {
"node": ">=18.0"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
},
"node_modules/@docusaurus/theme-common": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.2.1.tgz",
"integrity": "sha512-d+adiD7L9xv6EvfaAwUqdKf4orsM3jqgeqAM+HAjgL/Ux0GkVVnfKr+tsoe+4ow4rHe6NUt+nkkW8/K8dKdilA==",
"dependencies": {
"@docusaurus/mdx-loader": "3.2.1",
"@docusaurus/module-type-aliases": "3.2.1",
"@docusaurus/plugin-content-blog": "3.2.1",
"@docusaurus/plugin-content-docs": "3.2.1",
"@docusaurus/plugin-content-pages": "3.2.1",
"@docusaurus/utils": "3.2.1",
"@docusaurus/utils-common": "3.2.1",
"@types/history": "^4.7.11",
"@types/react": "*",
"@types/react-router-config": "*",
@ -2667,16 +2819,54 @@
"react-dom": "^18.0.0"
}
},
"node_modules/@docusaurus/theme-mermaid": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-mermaid/-/theme-mermaid-3.2.0.tgz",
"integrity": "sha512-PvN6K6m3JaM9cr9oSPyba6OlwAiSfBzqQtNqdgPFDjakKuT4kj6JODfExi+HKtWuxayOVRQlRl7zTnWxM4sTVw==",
"node_modules/@docusaurus/theme-common/node_modules/@docusaurus/mdx-loader": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.2.1.tgz",
"integrity": "sha512-Fs8tXhXKZjNkdGaOy1xSLXSwfjCMT73J3Zfrju2U16uGedRFRjgK0ojpK5tiC7TnunsL3tOFgp1BSMBRflX9gw==",
"dependencies": {
"@docusaurus/core": "3.2.0",
"@docusaurus/module-type-aliases": "3.2.0",
"@docusaurus/theme-common": "3.2.0",
"@docusaurus/types": "3.2.0",
"@docusaurus/utils-validation": "3.2.0",
"@docusaurus/logger": "3.2.1",
"@docusaurus/utils": "3.2.1",
"@docusaurus/utils-validation": "3.2.1",
"@mdx-js/mdx": "^3.0.0",
"@slorber/remark-comment": "^1.0.0",
"escape-html": "^1.0.3",
"estree-util-value-to-estree": "^3.0.1",
"file-loader": "^6.2.0",
"fs-extra": "^11.1.1",
"image-size": "^1.0.2",
"mdast-util-mdx": "^3.0.0",
"mdast-util-to-string": "^4.0.0",
"rehype-raw": "^7.0.0",
"remark-directive": "^3.0.0",
"remark-emoji": "^4.0.0",
"remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.0",
"stringify-object": "^3.3.0",
"tslib": "^2.6.0",
"unified": "^11.0.3",
"unist-util-visit": "^5.0.0",
"url-loader": "^4.1.1",
"vfile": "^6.0.1",
"webpack": "^5.88.1"
},
"engines": {
"node": ">=18.0"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
},
"node_modules/@docusaurus/theme-mermaid": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-mermaid/-/theme-mermaid-3.2.1.tgz",
"integrity": "sha512-l1FzUPgDUor/25XeJDeO22dttmzB0QnmAbF2qKjDz3ENa9vlD5rd5r0NrItZIe8y7qoa+OOxkl5lLBKBxBVbLg==",
"dependencies": {
"@docusaurus/core": "3.2.1",
"@docusaurus/module-type-aliases": "3.2.1",
"@docusaurus/theme-common": "3.2.1",
"@docusaurus/types": "3.2.1",
"@docusaurus/utils-validation": "3.2.1",
"mermaid": "^10.4.0",
"tslib": "^2.6.0"
},
@ -2689,18 +2879,18 @@
}
},
"node_modules/@docusaurus/theme-search-algolia": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.2.0.tgz",
"integrity": "sha512-PgvF4qHoqJp8+GfqClUbTF/zYNOsz4De251IuzXon7+7FAXwvb2qmYtA2nEwyMbB7faKOz33Pxzv+y+153KS/g==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.2.1.tgz",
"integrity": "sha512-bzhCrpyXBXzeydNUH83II2akvFEGfhsNTPPWsk5N7e+odgQCQwoHhcF+2qILbQXjaoZ6B3c48hrvkyCpeyqGHw==",
"dependencies": {
"@docsearch/react": "^3.5.2",
"@docusaurus/core": "3.2.0",
"@docusaurus/logger": "3.2.0",
"@docusaurus/plugin-content-docs": "3.2.0",
"@docusaurus/theme-common": "3.2.0",
"@docusaurus/theme-translations": "3.2.0",
"@docusaurus/utils": "3.2.0",
"@docusaurus/utils-validation": "3.2.0",
"@docusaurus/core": "3.2.1",
"@docusaurus/logger": "3.2.1",
"@docusaurus/plugin-content-docs": "3.2.1",
"@docusaurus/theme-common": "3.2.1",
"@docusaurus/theme-translations": "3.2.1",
"@docusaurus/utils": "3.2.1",
"@docusaurus/utils-validation": "3.2.1",
"algoliasearch": "^4.18.0",
"algoliasearch-helper": "^3.13.3",
"clsx": "^2.0.0",
@ -2719,9 +2909,9 @@
}
},
"node_modules/@docusaurus/theme-translations": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.2.0.tgz",
"integrity": "sha512-VXzZJBuyVEmwUYyud+7IgJQEBRM6R2u/s10Rp3DOP19CBQxeKgHYTKkKhFtDeKMHDassb665kjgOi0YlJfUT6w==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.2.1.tgz",
"integrity": "sha512-jAUMkIkFfY+OAhJhv6mV8zlwY6J4AQxJPTgLdR2l+Otof9+QdJjHNh/ifVEu9q0lp3oSPlJj9l05AaP7Ref+cg==",
"dependencies": {
"fs-extra": "^11.1.1",
"tslib": "^2.6.0"
@ -2731,15 +2921,15 @@
}
},
"node_modules/@docusaurus/tsconfig": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/tsconfig/-/tsconfig-3.2.0.tgz",
"integrity": "sha512-gWGa/72TYRxSRRxGFU2G6Au0yif6zmbkAgzW3+SeXAxoq1a7OLytMLGEwaHjMoIRXl7WbThnpx4gZVwo0xRRAg==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/tsconfig/-/tsconfig-3.2.1.tgz",
"integrity": "sha512-+biUwtsYW3oChLxYezzA+NIgS3Q9KDRl7add/YT54RXs9Q4rKInebxdHdG6JFs5BaTg45gyjDu0rvNVcGeHODg==",
"dev": true
},
"node_modules/@docusaurus/types": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.2.0.tgz",
"integrity": "sha512-uG3FfTkkkbZIPPNYx6xRfZHKeGyRd/inIT1cqvYt1FobFLd+7WhRXrSBqwJ9JajJjEAjNioRMVFgGofGf/Wdww==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.2.1.tgz",
"integrity": "sha512-n/toxBzL2oxTtRTOFiGKsHypzn/Pm+sXyw+VSk1UbqbXQiHOwHwts55bpKwbcUgA530Is6kix3ELiFOv9GAMfw==",
"dependencies": {
"@mdx-js/mdx": "^3.0.0",
"@types/history": "^4.7.11",
@ -2757,12 +2947,12 @@
}
},
"node_modules/@docusaurus/utils": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.2.0.tgz",
"integrity": "sha512-3rgrE7iL60yV2JQivlcoxUNNTK2APmn+OHLUmTvX2pueIM8DEOCEFHpJO4MiWjFO7V/Wq3iA/W1M03JnjdugVw==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.2.1.tgz",
"integrity": "sha512-DPkIS/EPc+pGAV798PUXgNzJFM3HJouoQXgr0KDZuJVz1EkWbDLOcQwLIz8Qx7liI9ddfkN/TXTRQdsTPZNakw==",
"dependencies": {
"@docusaurus/logger": "3.2.0",
"@docusaurus/utils-common": "3.2.0",
"@docusaurus/logger": "3.2.1",
"@docusaurus/utils-common": "3.2.1",
"@svgr/webpack": "^6.5.1",
"escape-string-regexp": "^4.0.0",
"file-loader": "^6.2.0",
@ -2794,9 +2984,9 @@
}
},
"node_modules/@docusaurus/utils-common": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.2.0.tgz",
"integrity": "sha512-WEQT5L2lT/tBQgDRgeZQAIi9YJBrwEILb1BuObQn1St3T/4K1gx5fWwOT8qdLOov296XLd1FQg9Ywu27aE9svw==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.2.1.tgz",
"integrity": "sha512-N5vadULnRLiqX2QfTjVEU3u5vo6RG2EZTdyXvJdzDOdrLCGIZAfnf/VkssinFZ922sVfaFfQ4FnStdhn5TWdVg==",
"dependencies": {
"tslib": "^2.6.0"
},
@ -2813,13 +3003,13 @@
}
},
"node_modules/@docusaurus/utils-validation": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.2.0.tgz",
"integrity": "sha512-rCzMTqwNrBrEOyU8EaD1fYWdig4TDhfj+YLqB8DY68VUAqSIgbY+yshpqFKB0bznFYNBJbn0bGpvVuImQOa/vA==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.2.1.tgz",
"integrity": "sha512-+x7IR9hNMXi62L1YAglwd0s95fR7+EtirjTxSN4kahYRWGqOi3jlQl1EV0az/yTEvKbxVvOPcdYicGu9dk4LJw==",
"dependencies": {
"@docusaurus/logger": "3.2.0",
"@docusaurus/utils": "3.2.0",
"@docusaurus/utils-common": "3.2.0",
"@docusaurus/logger": "3.2.1",
"@docusaurus/utils": "3.2.1",
"@docusaurus/utils-common": "3.2.1",
"joi": "^17.9.2",
"js-yaml": "^4.1.0",
"tslib": "^2.6.0"
@ -4125,9 +4315,9 @@
}
},
"node_modules/algoliasearch-helper": {
"version": "3.16.3",
"resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.16.3.tgz",
"integrity": "sha512-1OuJT6sONAa9PxcOmWo5WCAT3jQSpCR9/m5Azujja7nhUQwAUDvaaAYrcmUySsrvHh74usZHbE3jFfGnWtZj8w==",
"version": "3.17.0",
"resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.17.0.tgz",
"integrity": "sha512-R5422OiQjvjlK3VdpNQ/Qk7KsTIGeM5ACm8civGifOVWdRRV/3SgXuKmeNxe94Dz6fwj/IgpVmXbHutU4mHubg==",
"dependencies": {
"@algolia/events": "^4.0.1"
},
@ -15616,9 +15806,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.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz",
"integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"

View File

@ -16,12 +16,12 @@
"test": "node --test"
},
"dependencies": {
"@docusaurus/core": "^3.2.0",
"@docusaurus/plugin-client-redirects": "^3.2.0",
"@docusaurus/plugin-content-docs": "^3.2.0",
"@docusaurus/preset-classic": "^3.2.0",
"@docusaurus/theme-common": "^3.2.0",
"@docusaurus/theme-mermaid": "^3.2.0",
"@docusaurus/core": "^3.2.1",
"@docusaurus/plugin-client-redirects": "^3.2.1",
"@docusaurus/plugin-content-docs": "^3.2.1",
"@docusaurus/preset-classic": "^3.2.1",
"@docusaurus/theme-common": "^3.2.1",
"@docusaurus/theme-mermaid": "^3.2.1",
"@mdx-js/react": "^3.0.1",
"clsx": "^2.1.0",
"disqus-react": "^1.1.5",
@ -49,12 +49,12 @@
]
},
"devDependencies": {
"@docusaurus/module-type-aliases": "3.2.0",
"@docusaurus/tsconfig": "3.2.0",
"@docusaurus/types": "3.2.0",
"@docusaurus/module-type-aliases": "3.2.1",
"@docusaurus/tsconfig": "3.2.1",
"@docusaurus/types": "3.2.1",
"@types/react": "^18.2.74",
"prettier": "3.2.5",
"typescript": "~5.4.3"
"typescript": "~5.4.4"
},
"engines": {
"node": ">=20"