mirror of
https://github.com/goauthentik/authentik
synced 2026-05-07 07:32:23 +02:00
Compare commits
2 Commits
patch-2
...
mokeytype_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7325bfde36 | ||
|
|
6383d0bfc0 |
@@ -75,7 +75,7 @@ RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
|
||||
/bin/sh -c "GEOIPUPDATE_LICENSE_KEY_FILE=/run/secrets/GEOIPUPDATE_LICENSE_KEY /usr/bin/entry.sh || echo 'Failed to get GeoIP database, disabling'; exit 0"
|
||||
|
||||
# Stage 4: Download uv
|
||||
FROM ghcr.io/astral-sh/uv:0.8.0 AS uv
|
||||
FROM ghcr.io/astral-sh/uv:0.7.21 AS uv
|
||||
# Stage 5: Base python image
|
||||
FROM ghcr.io/goauthentik/fips-python:3.13.5-slim-bookworm-fips AS python-base
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ class GroupSerializer(ModelSerializer):
|
||||
return None
|
||||
return GroupMemberSerializer(instance.users, many=True).data
|
||||
|
||||
def validate_parent(self, parent: Group | None):
|
||||
def validate_parent(self, parent: Group | None) -> None:
|
||||
"""Validate group parent (if set), ensuring the parent isn't itself"""
|
||||
if not self.instance or not parent:
|
||||
return parent
|
||||
@@ -85,7 +85,7 @@ class GroupSerializer(ModelSerializer):
|
||||
raise ValidationError(_("Cannot set group as parent of itself."))
|
||||
return parent
|
||||
|
||||
def validate_is_superuser(self, superuser: bool):
|
||||
def validate_is_superuser(self, superuser: bool) -> bool:
|
||||
"""Ensure that the user creating this group has permissions to set the superuser flag"""
|
||||
request: Request = self.context.get("request", None)
|
||||
if not request:
|
||||
@@ -210,7 +210,7 @@ class GroupViewSet(UsedByMixin, ModelViewSet):
|
||||
OpenApiParameter("include_users", bool, default=True),
|
||||
]
|
||||
)
|
||||
def list(self, request, *args, **kwargs):
|
||||
def list(self, request: Request, *args, **kwargs) -> Response:
|
||||
return super().list(request, *args, **kwargs)
|
||||
|
||||
@extend_schema(
|
||||
@@ -218,7 +218,7 @@ class GroupViewSet(UsedByMixin, ModelViewSet):
|
||||
OpenApiParameter("include_users", bool, default=True),
|
||||
]
|
||||
)
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
def retrieve(self, request: Request, *args, **kwargs) -> Response:
|
||||
return super().retrieve(request, *args, **kwargs)
|
||||
|
||||
@permission_required("authentik_core.add_user_to_group")
|
||||
|
||||
@@ -5,6 +5,7 @@ from django.db.models.query import Q
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_filters.filters import BooleanFilter
|
||||
from django_filters.filterset import FilterSet
|
||||
from model_utils.managers import InheritanceQuerySet
|
||||
from rest_framework import mixins
|
||||
from rest_framework.fields import ReadOnlyField, SerializerMethodField
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
@@ -99,5 +100,5 @@ class ProviderViewSet(
|
||||
"application__name",
|
||||
]
|
||||
|
||||
def get_queryset(self): # pragma: no cover
|
||||
def get_queryset(self) -> InheritanceQuerySet: # pragma: no cover
|
||||
return Provider.objects.select_subclasses()
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
from collections.abc import Iterable
|
||||
|
||||
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
||||
from model_utils.managers import InheritanceQuerySet
|
||||
from rest_framework import mixins
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.exceptions import ValidationError
|
||||
@@ -88,7 +89,7 @@ class SourceViewSet(
|
||||
search_fields = ["slug", "name"]
|
||||
filterset_fields = ["slug", "name", "managed", "pbm_uuid"]
|
||||
|
||||
def get_queryset(self): # pragma: no cover
|
||||
def get_queryset(self) -> InheritanceQuerySet: # pragma: no cover
|
||||
return Source.objects.select_subclasses()
|
||||
|
||||
@permission_required("authentik_core.change_source")
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
from typing import Any
|
||||
|
||||
from django.db.models.query import QuerySet
|
||||
from django.utils.timezone import now
|
||||
from drf_spectacular.utils import OpenApiResponse, extend_schema, inline_serializer
|
||||
from guardian.shortcuts import assign_perm, get_anonymous_user
|
||||
@@ -41,7 +42,7 @@ class TokenSerializer(ManagedSerializer, ModelSerializer):
|
||||
if SERIALIZER_CONTEXT_BLUEPRINT in self.context:
|
||||
self.fields["key"] = CharField(required=False)
|
||||
|
||||
def validate_user(self, user: User):
|
||||
def validate_user(self, user: User) -> User:
|
||||
"""Ensure user of token cannot be changed"""
|
||||
if self.instance and self.instance.user_id:
|
||||
if user.pk != self.instance.user_id:
|
||||
@@ -138,13 +139,13 @@ class TokenViewSet(UsedByMixin, ModelViewSet):
|
||||
owner_field = "user"
|
||||
rbac_allow_create_without_perm = True
|
||||
|
||||
def get_queryset(self):
|
||||
def get_queryset(self) -> QuerySet:
|
||||
user = self.request.user if self.request else get_anonymous_user()
|
||||
if user.is_superuser:
|
||||
return super().get_queryset()
|
||||
return super().get_queryset().filter(user=user.pk)
|
||||
|
||||
def perform_create(self, serializer: TokenSerializer):
|
||||
def perform_create(self, serializer: TokenSerializer) -> Token:
|
||||
if not self.request.user.is_superuser:
|
||||
instance = serializer.save(
|
||||
user=self.request.user,
|
||||
|
||||
@@ -21,6 +21,7 @@ from django_filters.filters import (
|
||||
UUIDFilter,
|
||||
)
|
||||
from django_filters.filterset import FilterSet
|
||||
from djangoql.schema import BoolField, StrField
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import (
|
||||
OpenApiParameter,
|
||||
@@ -72,8 +73,10 @@ from authentik.core.models import (
|
||||
Token,
|
||||
TokenIntents,
|
||||
User,
|
||||
UserQuerySet,
|
||||
UserTypes,
|
||||
)
|
||||
from authentik.enterprise.search.fields import ChoiceSearchField, JSONSearchField
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.flows.exceptions import FlowNonApplicableException
|
||||
from authentik.flows.models import FlowToken
|
||||
@@ -349,7 +352,7 @@ class UsersFilter(FilterSet):
|
||||
queryset=Group.objects.all().order_by("name"),
|
||||
)
|
||||
|
||||
def filter_is_superuser(self, queryset, name, value):
|
||||
def filter_is_superuser(self, queryset: UserQuerySet, name: str, value: bool) -> UserQuerySet:
|
||||
if value:
|
||||
return queryset.filter(ak_groups__is_superuser=True).distinct()
|
||||
return queryset.exclude(ak_groups__is_superuser=True).distinct()
|
||||
@@ -395,7 +398,7 @@ class UserViewSet(UsedByMixin, ModelViewSet):
|
||||
filterset_class = UsersFilter
|
||||
search_fields = ["username", "name", "is_active", "email", "uuid", "attributes"]
|
||||
|
||||
def get_ql_fields(self):
|
||||
def get_ql_fields(self) -> list[StrField | BoolField | ChoiceSearchField | JSONSearchField]:
|
||||
from djangoql.schema import BoolField, StrField
|
||||
|
||||
from authentik.enterprise.search.fields import ChoiceSearchField, JSONSearchField
|
||||
@@ -410,7 +413,7 @@ class UserViewSet(UsedByMixin, ModelViewSet):
|
||||
JSONSearchField(User, "attributes", suggest_nested=False),
|
||||
]
|
||||
|
||||
def get_queryset(self):
|
||||
def get_queryset(self) -> UserQuerySet:
|
||||
base_qs = User.objects.all().exclude_anonymous()
|
||||
if self.serializer_class(context={"request": self.request})._should_include_groups:
|
||||
base_qs = base_qs.prefetch_related("ak_groups")
|
||||
@@ -421,10 +424,10 @@ class UserViewSet(UsedByMixin, ModelViewSet):
|
||||
OpenApiParameter("include_groups", bool, default=True),
|
||||
]
|
||||
)
|
||||
def list(self, request, *args, **kwargs):
|
||||
def list(self, request: Request, *args, **kwargs) -> Response:
|
||||
return super().list(request, *args, **kwargs)
|
||||
|
||||
def _create_recovery_link(self, for_email=False) -> tuple[str, Token]:
|
||||
def _create_recovery_link(self, for_email: bool = False) -> tuple[str, Token]:
|
||||
"""Create a recovery link (when the current brand has a recovery flow set),
|
||||
that can either be shown to an admin or sent to the user directly"""
|
||||
brand: Brand = self.request._request.brand
|
||||
|
||||
@@ -42,7 +42,7 @@ class JSONExtension(OpenApiSerializerFieldExtension):
|
||||
|
||||
target_class = "authentik.core.api.utils.JSONDictField"
|
||||
|
||||
def map_serializer_field(self, auto_schema, direction):
|
||||
def map_serializer_field(self, auto_schema, direction: str) -> dict[str, str]:
|
||||
return build_basic_type(OpenApiTypes.OBJECT)
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ class ModelSerializer(BaseModelSerializer):
|
||||
serializer_field_mapping = BaseModelSerializer.serializer_field_mapping.copy()
|
||||
serializer_field_mapping[models.JSONField] = JSONDictField
|
||||
|
||||
def create(self, validated_data):
|
||||
def create(self, validated_data: dict[str, Any]):
|
||||
instance = super().create(validated_data)
|
||||
|
||||
request = self.context.get("request")
|
||||
@@ -61,7 +61,7 @@ class ModelSerializer(BaseModelSerializer):
|
||||
|
||||
return instance
|
||||
|
||||
def update(self, instance: Model, validated_data):
|
||||
def update(self, instance: Model, validated_data: dict[str, Any]):
|
||||
raise_errors_on_nested_writes("update", self, validated_data)
|
||||
info = model_meta.get_field_info(instance)
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ from uuid import uuid4
|
||||
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.core.handlers.wsgi import WSGIRequest
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.utils.deprecation import MiddlewareMixin
|
||||
from django.utils.functional import SimpleLazyObject
|
||||
@@ -14,6 +15,8 @@ from django.utils.translation import override
|
||||
from sentry_sdk.api import set_tag
|
||||
from structlog.contextvars import STRUCTLOG_KEY_PREFIX
|
||||
|
||||
from authentik.core.models import User
|
||||
|
||||
SESSION_KEY_IMPERSONATE_USER = "authentik/impersonate/user"
|
||||
SESSION_KEY_IMPERSONATE_ORIGINAL_USER = "authentik/impersonate/original_user"
|
||||
RESPONSE_HEADER_ID = "X-authentik-id"
|
||||
@@ -25,7 +28,7 @@ CTX_HOST = ContextVar[str | None](STRUCTLOG_KEY_PREFIX + "host", default=None)
|
||||
CTX_AUTH_VIA = ContextVar[str | None](STRUCTLOG_KEY_PREFIX + KEY_AUTH_VIA, default=None)
|
||||
|
||||
|
||||
def get_user(request):
|
||||
def get_user(request: WSGIRequest) -> AnonymousUser | User:
|
||||
if not hasattr(request, "_cached_user"):
|
||||
user = None
|
||||
if (authenticated_session := request.session.get("authenticatedsession", None)) is not None:
|
||||
@@ -46,7 +49,7 @@ async def aget_user(request):
|
||||
|
||||
|
||||
class AuthenticationMiddleware(MiddlewareMixin):
|
||||
def process_request(self, request):
|
||||
def process_request(self, request: WSGIRequest):
|
||||
if not hasattr(request, "session"):
|
||||
raise ImproperlyConfigured(
|
||||
"The Django authentication middleware requires session "
|
||||
|
||||
@@ -11,6 +11,7 @@ from django.contrib.auth.hashers import check_password
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.contrib.auth.models import UserManager as DjangoUserManager
|
||||
from django.contrib.sessions.base_session import AbstractBaseSession
|
||||
from django.core.handlers.wsgi import WSGIRequest
|
||||
from django.db import models
|
||||
from django.db.models import Q, QuerySet, options
|
||||
from django.db.models.constants import LOOKUP_SEP
|
||||
@@ -22,6 +23,7 @@ from django_cte import CTE, with_cte
|
||||
from guardian.conf import settings
|
||||
from guardian.mixins import GuardianUserMixin
|
||||
from model_utils.managers import InheritanceManager
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.serializers import Serializer
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
@@ -137,7 +139,7 @@ class AttributesMixin(models.Model):
|
||||
|
||||
|
||||
class GroupQuerySet(QuerySet):
|
||||
def with_children_recursive(self):
|
||||
def with_children_recursive(self) -> "GroupQuerySet":
|
||||
"""Recursively get all groups that have the current queryset as parents
|
||||
or are indirectly related."""
|
||||
|
||||
@@ -210,7 +212,7 @@ class Group(SerializerModel, AttributesMixin):
|
||||
("disable_group_superuser", _("Disable superuser status")),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return f"Group {self.name}"
|
||||
|
||||
@property
|
||||
@@ -241,7 +243,7 @@ class Group(SerializerModel, AttributesMixin):
|
||||
class UserQuerySet(models.QuerySet):
|
||||
"""User queryset"""
|
||||
|
||||
def exclude_anonymous(self):
|
||||
def exclude_anonymous(self) -> "UserQuerySet":
|
||||
"""Exclude anonymous user"""
|
||||
return self.exclude(**{User.USERNAME_FIELD: settings.ANONYMOUS_USER_NAME})
|
||||
|
||||
@@ -249,7 +251,7 @@ class UserQuerySet(models.QuerySet):
|
||||
class UserManager(DjangoUserManager):
|
||||
"""User manager that doesn't assign is_superuser and is_staff"""
|
||||
|
||||
def get_queryset(self):
|
||||
def get_queryset(self) -> UserQuerySet:
|
||||
"""Create special user queryset"""
|
||||
return UserQuerySet(self.model, using=self._db)
|
||||
|
||||
@@ -295,7 +297,7 @@ class User(SerializerModel, GuardianUserMixin, AttributesMixin, AbstractUser):
|
||||
models.Index(fields=["type"]),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return self.username
|
||||
|
||||
@staticmethod
|
||||
@@ -360,7 +362,13 @@ class User(SerializerModel, GuardianUserMixin, AttributesMixin, AbstractUser):
|
||||
"""superuser == staff user"""
|
||||
return self.is_superuser # type: ignore
|
||||
|
||||
def set_password(self, raw_password, signal=True, sender=None, request=None):
|
||||
def set_password(
|
||||
self,
|
||||
raw_password: str,
|
||||
signal: bool = True,
|
||||
sender: None = None,
|
||||
request: WSGIRequest | Request | None = None,
|
||||
) -> None:
|
||||
if self.pk and signal:
|
||||
from authentik.core.signals import password_changed
|
||||
|
||||
@@ -479,7 +487,7 @@ class Provider(SerializerModel):
|
||||
"""Get serializer for this model"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return str(self.name)
|
||||
|
||||
|
||||
@@ -611,7 +619,7 @@ class Application(SerializerModel, PolicyBindingModel):
|
||||
)
|
||||
return getattr(providers.first(), provider_type._meta.model_name)
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return str(self.name)
|
||||
|
||||
class Meta:
|
||||
@@ -631,7 +639,7 @@ class ApplicationEntitlement(AttributesMixin, SerializerModel, PolicyBindingMode
|
||||
verbose_name_plural = _("Application Entitlements")
|
||||
unique_together = (("app", "name"),)
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return f"Application Entitlement {self.name} for app {self.app_id}"
|
||||
|
||||
@property
|
||||
@@ -640,7 +648,7 @@ class ApplicationEntitlement(AttributesMixin, SerializerModel, PolicyBindingMode
|
||||
|
||||
return ApplicationEntitlementSerializer
|
||||
|
||||
def supported_policy_binding_targets(self):
|
||||
def supported_policy_binding_targets(self) -> list[str]:
|
||||
return ["group", "user"]
|
||||
|
||||
|
||||
@@ -812,7 +820,7 @@ class Source(ManagedModel, SerializerModel, PolicyBindingModel):
|
||||
return {}
|
||||
raise NotImplementedError
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return str(self.name)
|
||||
|
||||
class Meta:
|
||||
@@ -895,7 +903,7 @@ class ExpiringModel(models.Model):
|
||||
models.Index(fields=["expiring", "expires"]),
|
||||
]
|
||||
|
||||
def expire_action(self, *args, **kwargs):
|
||||
def expire_action(self, *args, **kwargs) -> tuple[int, dict[str, int]]:
|
||||
"""Handler which is called when this object is expired. By
|
||||
default the object is deleted. This is less efficient compared
|
||||
to bulk deleting objects, but classes like Token() need to change
|
||||
@@ -958,7 +966,7 @@ class Token(SerializerModel, ManagedModel, ExpiringModel):
|
||||
("set_token_key", _("Set a token's key")),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
description = f"{self.identifier}"
|
||||
if self.expiring:
|
||||
description += f" (expires={self.expires})"
|
||||
@@ -1023,7 +1031,7 @@ class PropertyMapping(SerializerModel, ManagedModel):
|
||||
except Exception as exc:
|
||||
raise PropertyMappingExpressionException(exc, self) from exc
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return f"Property Mapping {self.name}"
|
||||
|
||||
class Meta:
|
||||
@@ -1051,7 +1059,7 @@ class Session(ExpiringModel, AbstractBaseSession):
|
||||
]
|
||||
default_permissions = []
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return self.session_key
|
||||
|
||||
class Keys(StrEnum):
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""authentik sessions engine"""
|
||||
|
||||
import pickle # nosec
|
||||
from typing import Any
|
||||
|
||||
from django.contrib.auth import BACKEND_SESSION_KEY, HASH_SESSION_KEY, SESSION_KEY
|
||||
from django.contrib.sessions.backends.db import SessionStore as SessionBase
|
||||
@@ -9,13 +10,19 @@ from django.utils import timezone
|
||||
from django.utils.functional import cached_property
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.core.models import Session
|
||||
from authentik.root.middleware import ClientIPMiddleware
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
|
||||
class SessionStore(SessionBase):
|
||||
def __init__(self, session_key=None, last_ip=None, last_user_agent=""):
|
||||
def __init__(
|
||||
self,
|
||||
session_key: str | None = None,
|
||||
last_ip: str | None = None,
|
||||
last_user_agent: str = "",
|
||||
):
|
||||
super().__init__(session_key)
|
||||
self._create_kwargs = {
|
||||
"last_ip": last_ip or ClientIPMiddleware.default_ip,
|
||||
@@ -23,16 +30,16 @@ class SessionStore(SessionBase):
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_model_class(cls):
|
||||
def get_model_class(cls) -> type[Session]:
|
||||
from authentik.core.models import Session
|
||||
|
||||
return Session
|
||||
|
||||
@cached_property
|
||||
def model_fields(self):
|
||||
def model_fields(self) -> list[str]:
|
||||
return [k.value for k in self.model.Keys]
|
||||
|
||||
def _get_session_from_db(self):
|
||||
def _get_session_from_db(self) -> Session:
|
||||
try:
|
||||
return (
|
||||
self.model.objects.select_related(
|
||||
@@ -74,10 +81,10 @@ class SessionStore(SessionBase):
|
||||
LOGGER.warning(str(exc))
|
||||
self._session_key = None
|
||||
|
||||
def encode(self, session_dict):
|
||||
def encode(self, session_dict: dict[str, Any]) -> bytes:
|
||||
return pickle.dumps(session_dict, protocol=pickle.HIGHEST_PROTOCOL)
|
||||
|
||||
def decode(self, session_data):
|
||||
def decode(self, session_data: bytes) -> dict[str, Any]:
|
||||
try:
|
||||
return pickle.loads(session_data) # nosec
|
||||
except pickle.PickleError:
|
||||
@@ -86,7 +93,7 @@ class SessionStore(SessionBase):
|
||||
pass
|
||||
return {}
|
||||
|
||||
def load(self):
|
||||
def load(self) -> dict[str, Any]:
|
||||
s = self._get_session_from_db()
|
||||
if s:
|
||||
return {
|
||||
@@ -108,7 +115,7 @@ class SessionStore(SessionBase):
|
||||
else:
|
||||
return {}
|
||||
|
||||
def create_model_instance(self, data):
|
||||
def create_model_instance(self, data: dict[str, Any]) -> Session:
|
||||
args = {
|
||||
"session_key": self._get_or_create_session_key(),
|
||||
"expires": self.get_expiry_date(),
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
from django.http.response import (
|
||||
HttpResponseBadRequest,
|
||||
HttpResponseForbidden,
|
||||
HttpResponseNotAllowed,
|
||||
HttpResponseNotFound,
|
||||
HttpResponseServerError,
|
||||
)
|
||||
@@ -61,6 +62,6 @@ class ServerErrorView(TemplateView):
|
||||
response_class = ServerErrorTemplateResponse
|
||||
template_name = "if/error.html"
|
||||
|
||||
def dispatch(self, *args, **kwargs): # pragma: no cover
|
||||
def dispatch(self, *args, **kwargs) -> HttpResponseNotAllowed: # pragma: no cover
|
||||
"""Little wrapper so django accepts this function"""
|
||||
return super().dispatch(*args, **kwargs)
|
||||
|
||||
4
go.mod
4
go.mod
@@ -17,7 +17,7 @@ require (
|
||||
github.com/gorilla/securecookie v1.1.2
|
||||
github.com/gorilla/sessions v1.4.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/grafana/pyroscope-go v1.2.4
|
||||
github.com/grafana/pyroscope-go v1.2.3
|
||||
github.com/jellydator/ttlcache/v3 v3.4.0
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
|
||||
@@ -29,7 +29,7 @@ require (
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/wwt/guac v1.3.2
|
||||
goauthentik.io/api/v3 v3.2025063.6
|
||||
goauthentik.io/api/v3 v3.2025063.5
|
||||
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
golang.org/x/sync v0.16.0
|
||||
|
||||
8
go.sum
8
go.sum
@@ -180,8 +180,8 @@ github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2e
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grafana/pyroscope-go v1.2.4 h1:B22GMXz+O0nWLatxLuaP7o7L9dvP0clLvIpmeEQQM0Q=
|
||||
github.com/grafana/pyroscope-go v1.2.4/go.mod h1:zzT9QXQAp2Iz2ZdS216UiV8y9uXJYQiGE1q8v1FyhqU=
|
||||
github.com/grafana/pyroscope-go v1.2.3 h1:Rp8mjqqGqmRDvV6XYmuedUAv7wVnQJK/M1pBt6uNwxU=
|
||||
github.com/grafana/pyroscope-go v1.2.3/go.mod h1:zzT9QXQAp2Iz2ZdS216UiV8y9uXJYQiGE1q8v1FyhqU=
|
||||
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 h1:iwOtYXeeVSAeYefJNaxDytgjKtUuKQbJqgAIjlnicKg=
|
||||
github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU=
|
||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||
@@ -298,8 +298,8 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y
|
||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
goauthentik.io/api/v3 v3.2025063.6 h1:TFMnE0bXiWZ5oVYrnxDLpS+pnGNv+KIjLmZHT5qzpcM=
|
||||
goauthentik.io/api/v3 v3.2025063.6/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
||||
goauthentik.io/api/v3 v3.2025063.5 h1:j5el9/qI/72Q5x5QAiMzgQTswMj2TK3h74OaBcFEtkI=
|
||||
goauthentik.io/api/v3 v3.2025063.5/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
|
||||
@@ -2,7 +2,6 @@ package radius
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -12,7 +11,9 @@ import (
|
||||
"layeh.com/radius/rfc2865"
|
||||
)
|
||||
|
||||
func (rs *RadiusServer) Handle_AccessRequest_PAP_Auth(r *RadiusRequest, username, password string) (*radius.Packet, error) {
|
||||
func (rs *RadiusServer) Handle_AccessRequest(w radius.ResponseWriter, r *RadiusRequest) {
|
||||
username := rfc2865.UserName_GetString(r.Packet)
|
||||
|
||||
fe := flow.NewFlowExecutor(r.Context(), r.pi.flowSlug, r.pi.s.ac.Client.GetConfig(), log.Fields{
|
||||
"username": username,
|
||||
"client": r.RemoteAddr(),
|
||||
@@ -22,64 +23,67 @@ func (rs *RadiusServer) Handle_AccessRequest_PAP_Auth(r *RadiusRequest, username
|
||||
fe.Params.Add("goauthentik.io/outpost/radius", "true")
|
||||
|
||||
fe.Answers[flow.StageIdentification] = username
|
||||
fe.SetSecrets(password, r.pi.MFASupport)
|
||||
fe.SetSecrets(rfc2865.UserPassword_GetString(r.Packet), r.pi.MFASupport)
|
||||
|
||||
passed, err := fe.Execute()
|
||||
if err != nil {
|
||||
r.Log().WithField("username", username).WithError(err).Warning("failed to execute flow")
|
||||
return nil, errors.New("flow_error")
|
||||
metrics.RequestsRejected.With(prometheus.Labels{
|
||||
"outpost_name": rs.ac.Outpost.Name,
|
||||
"reason": "flow_error",
|
||||
"app": r.pi.appSlug,
|
||||
}).Inc()
|
||||
_ = w.Write(r.Response(radius.CodeAccessReject))
|
||||
return
|
||||
}
|
||||
if !passed {
|
||||
return nil, errors.New("invalid_credentials")
|
||||
metrics.RequestsRejected.With(prometheus.Labels{
|
||||
"outpost_name": rs.ac.Outpost.Name,
|
||||
"reason": "invalid_credentials",
|
||||
"app": r.pi.appSlug,
|
||||
}).Inc()
|
||||
_ = w.Write(r.Response(radius.CodeAccessReject))
|
||||
return
|
||||
}
|
||||
access, _, err := fe.ApiClient().OutpostsApi.OutpostsRadiusAccessCheck(
|
||||
r.Context(), r.pi.providerId,
|
||||
).AppSlug(r.pi.appSlug).Execute()
|
||||
if err != nil {
|
||||
r.Log().WithField("username", username).WithError(err).Warning("failed to check access")
|
||||
return nil, errors.New("access_check_fail")
|
||||
_ = w.Write(r.Response(radius.CodeAccessReject))
|
||||
metrics.RequestsRejected.With(prometheus.Labels{
|
||||
"outpost_name": rs.ac.Outpost.Name,
|
||||
"reason": "access_check_fail",
|
||||
"app": r.pi.appSlug,
|
||||
}).Inc()
|
||||
return
|
||||
}
|
||||
if !access.Access.Passing {
|
||||
r.Log().WithField("username", username).Info("Access denied for user")
|
||||
return nil, errors.New("access_denied")
|
||||
_ = w.Write(r.Response(radius.CodeAccessReject))
|
||||
metrics.RequestsRejected.With(prometheus.Labels{
|
||||
"outpost_name": rs.ac.Outpost.Name,
|
||||
"reason": "access_denied",
|
||||
"app": r.pi.appSlug,
|
||||
}).Inc()
|
||||
return
|
||||
}
|
||||
res := r.Response(radius.CodeAccessAccept)
|
||||
defer func() { _ = w.Write(res) }()
|
||||
if !access.HasAttributes() {
|
||||
r.Log().Debug("No attributes")
|
||||
return res, nil
|
||||
return
|
||||
}
|
||||
rawData, err := base64.StdEncoding.DecodeString(access.GetAttributes())
|
||||
if err != nil {
|
||||
r.Log().WithError(err).Warning("failed to decode attributes from core")
|
||||
return nil, errors.New("attribute_decode_failed")
|
||||
return
|
||||
}
|
||||
p, err := radius.Parse(rawData, r.pi.SharedSecret)
|
||||
if err != nil {
|
||||
r.Log().WithError(err).Warning("failed to parse attributes from core")
|
||||
return nil, errors.New("attribute_parse_failed")
|
||||
}
|
||||
for _, attr := range p.Attributes {
|
||||
res.Add(attr.Type, attr.Attribute)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (rs *RadiusServer) Handle_AccessRequest(w radius.ResponseWriter, r *RadiusRequest) {
|
||||
username := rfc2865.UserName_GetString(r.Packet)
|
||||
password := rfc2865.UserPassword_GetString(r.Packet)
|
||||
res, err := rs.Handle_AccessRequest_PAP_Auth(r, username, password)
|
||||
if err != nil {
|
||||
metrics.RequestsRejected.With(prometheus.Labels{
|
||||
"outpost_name": rs.ac.Outpost.Name,
|
||||
"reason": err.Error(),
|
||||
"app": r.pi.appSlug,
|
||||
}).Inc()
|
||||
_ = w.Write(r.Reject())
|
||||
return
|
||||
}
|
||||
err = r.setMessageAuthenticator(res)
|
||||
if err != nil {
|
||||
rs.log.WithError(err).Warning("failed to set message authenticator")
|
||||
}
|
||||
_ = w.Write(res)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
package radius
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/getsentry/sentry-go"
|
||||
@@ -17,11 +13,6 @@ import (
|
||||
"goauthentik.io/internal/outpost/radius/metrics"
|
||||
"goauthentik.io/internal/utils"
|
||||
"layeh.com/radius"
|
||||
"layeh.com/radius/rfc2869"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidMessageAuthenticator = errors.New("invalid message authenticator")
|
||||
)
|
||||
|
||||
type RadiusRequest struct {
|
||||
@@ -44,41 +35,6 @@ func (r *RadiusRequest) ID() string {
|
||||
return r.id
|
||||
}
|
||||
|
||||
func (r *RadiusRequest) validateMessageAuthenticator() error {
|
||||
mauth := rfc2869.MessageAuthenticator_Get(r.Packet)
|
||||
hash := hmac.New(md5.New, r.Secret)
|
||||
encode, err := r.MarshalBinary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hash.Write(encode)
|
||||
if bytes.Equal(mauth, hash.Sum(nil)) {
|
||||
return ErrInvalidMessageAuthenticator
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *RadiusRequest) setMessageAuthenticator(rp *radius.Packet) error {
|
||||
_ = rfc2869.MessageAuthenticator_Set(rp, make([]byte, 16))
|
||||
hash := hmac.New(md5.New, rp.Secret)
|
||||
encode, err := rp.MarshalBinary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hash.Write(encode)
|
||||
_ = rfc2869.MessageAuthenticator_Set(rp, hash.Sum(nil))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *RadiusRequest) Reject() *radius.Packet {
|
||||
res := r.Response(radius.CodeAccessReject)
|
||||
err := r.setMessageAuthenticator(res)
|
||||
if err != nil {
|
||||
r.log.WithError(err).Warning("failed to set message authenticator")
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (rs *RadiusServer) ServeRADIUS(w radius.ResponseWriter, r *radius.Request) {
|
||||
span := sentry.StartSpan(r.Context(), "authentik.providers.radius.connect",
|
||||
sentry.WithTransactionName("authentik.providers.radius.connect"))
|
||||
@@ -103,11 +59,6 @@ func (rs *RadiusServer) ServeRADIUS(w radius.ResponseWriter, r *radius.Request)
|
||||
|
||||
rl.Info("Radius Request")
|
||||
|
||||
if err := nr.validateMessageAuthenticator(); err != nil {
|
||||
rl.WithError(err).Warning("Invalid message authenticator")
|
||||
return
|
||||
}
|
||||
|
||||
// Lookup provider by shared secret
|
||||
var pi *ProviderInstance
|
||||
for _, p := range rs.providers {
|
||||
@@ -121,7 +72,7 @@ func (rs *RadiusServer) ServeRADIUS(w radius.ResponseWriter, r *radius.Request)
|
||||
hs := sha512.Sum512([]byte(r.Secret))
|
||||
bs := hex.EncodeToString(hs[:])
|
||||
nr.Log().WithField("hashed_secret", bs).Warning("No provider found")
|
||||
_ = w.Write(nr.Reject())
|
||||
_ = w.Write(r.Response(radius.CodeAccessReject))
|
||||
return
|
||||
}
|
||||
nr.pi = pi
|
||||
|
||||
20
monkeytype_config.py
Normal file
20
monkeytype_config.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# Standard Library
|
||||
import os
|
||||
from collections.abc import Iterator
|
||||
from contextlib import contextmanager
|
||||
|
||||
# 3rd-party
|
||||
from monkeytype.config import DefaultConfig
|
||||
|
||||
|
||||
class MonkeyConfig(DefaultConfig):
|
||||
@contextmanager
|
||||
def cli_context(self, command: str) -> Iterator[None]:
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings")
|
||||
import django
|
||||
|
||||
django.setup()
|
||||
yield
|
||||
|
||||
|
||||
CONFIG = MonkeyConfig()
|
||||
14
packages/docusaurus-config/package-lock.json
generated
14
packages/docusaurus-config/package-lock.json
generated
@@ -5954,9 +5954,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/compression": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz",
|
||||
"integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==",
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz",
|
||||
"integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -5964,7 +5964,7 @@
|
||||
"compressible": "~2.0.18",
|
||||
"debug": "2.6.9",
|
||||
"negotiator": "~0.6.4",
|
||||
"on-headers": "~1.1.0",
|
||||
"on-headers": "~1.0.2",
|
||||
"safe-buffer": "5.2.1",
|
||||
"vary": "~1.1.2"
|
||||
},
|
||||
@@ -12708,9 +12708,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/on-headers": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
|
||||
"integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
|
||||
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
||||
248
packages/esbuild-plugin-live-reload/package-lock.json
generated
248
packages/esbuild-plugin-live-reload/package-lock.json
generated
@@ -132,9 +132,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz",
|
||||
"integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.6.tgz",
|
||||
"integrity": "sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -149,9 +149,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.8.tgz",
|
||||
"integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.6.tgz",
|
||||
"integrity": "sha512-S8ToEOVfg++AU/bHwdksHNnyLyVM+eMVAOf6yRKFitnwnbwwPNqKr3srzFRe7nzV69RQKb5DgchIX5pt3L53xg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -166,9 +166,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz",
|
||||
"integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.6.tgz",
|
||||
"integrity": "sha512-hd5zdUarsK6strW+3Wxi5qWws+rJhCCbMiC9QZyzoxfk5uHRIE8T287giQxzVpEvCwuJ9Qjg6bEjcRJcgfLqoA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -183,9 +183,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.8.tgz",
|
||||
"integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.6.tgz",
|
||||
"integrity": "sha512-0Z7KpHSr3VBIO9A/1wcT3NTy7EB4oNC4upJ5ye3R7taCc2GUdeynSLArnon5G8scPwaU866d3H4BCrE5xLW25A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -200,9 +200,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz",
|
||||
"integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.6.tgz",
|
||||
"integrity": "sha512-FFCssz3XBavjxcFxKsGy2DYK5VSvJqa6y5HXljKzhRZ87LvEi13brPrf/wdyl/BbpbMKJNOr1Sd0jtW4Ge1pAA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -217,9 +217,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz",
|
||||
"integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.6.tgz",
|
||||
"integrity": "sha512-GfXs5kry/TkGM2vKqK2oyiLFygJRqKVhawu3+DOCk7OxLy/6jYkWXhlHwOoTb0WqGnWGAS7sooxbZowy+pK9Yg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -234,9 +234,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz",
|
||||
"integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.6.tgz",
|
||||
"integrity": "sha512-aoLF2c3OvDn2XDTRvn8hN6DRzVVpDlj2B/F66clWd/FHLiHaG3aVZjxQX2DYphA5y/evbdGvC6Us13tvyt4pWg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -251,9 +251,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz",
|
||||
"integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.6.tgz",
|
||||
"integrity": "sha512-2SkqTjTSo2dYi/jzFbU9Plt1vk0+nNg8YC8rOXXea+iA3hfNJWebKYPs3xnOUf9+ZWhKAaxnQNUf2X9LOpeiMQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -268,9 +268,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz",
|
||||
"integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.6.tgz",
|
||||
"integrity": "sha512-SZHQlzvqv4Du5PrKE2faN0qlbsaW/3QQfUUc6yO2EjFcA83xnwm91UbEEVx4ApZ9Z5oG8Bxz4qPE+HFwtVcfyw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -285,9 +285,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz",
|
||||
"integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.6.tgz",
|
||||
"integrity": "sha512-b967hU0gqKd9Drsh/UuAm21Khpoh6mPBSgz8mKRq4P5mVK8bpA+hQzmm/ZwGVULSNBzKdZPQBRT3+WuVavcWsQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -302,9 +302,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz",
|
||||
"integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.6.tgz",
|
||||
"integrity": "sha512-aHWdQ2AAltRkLPOsKdi3xv0mZ8fUGPdlKEjIEhxCPm5yKEThcUjHpWB1idN74lfXGnZ5SULQSgtr5Qos5B0bPw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -319,9 +319,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz",
|
||||
"integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.6.tgz",
|
||||
"integrity": "sha512-VgKCsHdXRSQ7E1+QXGdRPlQ/e08bN6WMQb27/TMfV+vPjjTImuT9PmLXupRlC90S1JeNNW5lzkAEO/McKeJ2yg==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -336,9 +336,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz",
|
||||
"integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.6.tgz",
|
||||
"integrity": "sha512-WViNlpivRKT9/py3kCmkHnn44GkGXVdXfdc4drNmRl15zVQ2+D2uFwdlGh6IuK5AAnGTo2qPB1Djppj+t78rzw==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
@@ -353,9 +353,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz",
|
||||
"integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.6.tgz",
|
||||
"integrity": "sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -370,9 +370,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz",
|
||||
"integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.6.tgz",
|
||||
"integrity": "sha512-KZh7bAGGcrinEj4qzilJ4hqTY3Dg2U82c8bv+e1xqNqZCrCyc+TL9AUEn5WGKDzm3CfC5RODE/qc96OcbIe33w==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -387,9 +387,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz",
|
||||
"integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.6.tgz",
|
||||
"integrity": "sha512-9N1LsTwAuE9oj6lHMyyAM+ucxGiVnEqUdp4v7IaMmrwb06ZTEVCIs3oPPplVsnjPfyjmxwHxHMF8b6vzUVAUGw==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -404,9 +404,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz",
|
||||
"integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.6.tgz",
|
||||
"integrity": "sha512-A6bJB41b4lKFWRKNrWoP2LHsjVzNiaurf7wyj/XtFNTsnPuxwEBWHLty+ZE0dWBKuSK1fvKgrKaNjBS7qbFKig==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -421,9 +421,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-arm64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz",
|
||||
"integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.6.tgz",
|
||||
"integrity": "sha512-IjA+DcwoVpjEvyxZddDqBY+uJ2Snc6duLpjmkXm/v4xuS3H+3FkLZlDm9ZsAbF9rsfP3zeA0/ArNDORZgrxR/Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -438,9 +438,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz",
|
||||
"integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.6.tgz",
|
||||
"integrity": "sha512-dUXuZr5WenIDlMHdMkvDc1FAu4xdWixTCRgP7RQLBOkkGgwuuzaGSYcOpW4jFxzpzL1ejb8yF620UxAqnBrR9g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -455,9 +455,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-arm64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz",
|
||||
"integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.6.tgz",
|
||||
"integrity": "sha512-l8ZCvXP0tbTJ3iaqdNf3pjaOSd5ex/e6/omLIQCVBLmHTlfXW3zAxQ4fnDmPLOB1x9xrcSi/xtCWFwCZRIaEwg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -472,9 +472,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz",
|
||||
"integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.6.tgz",
|
||||
"integrity": "sha512-hKrmDa0aOFOr71KQ/19JC7az1P0GWtCN1t2ahYAf4O007DHZt/dW8ym5+CUdJhQ/qkZmI1HAF8KkJbEFtCL7gw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -489,9 +489,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openharmony-arm64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz",
|
||||
"integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.6.tgz",
|
||||
"integrity": "sha512-+SqBcAWoB1fYKmpWoQP4pGtx+pUUC//RNYhFdbcSA16617cchuryuhOCRpPsjCblKukAckWsV+aQ3UKT/RMPcA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -506,9 +506,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz",
|
||||
"integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.6.tgz",
|
||||
"integrity": "sha512-dyCGxv1/Br7MiSC42qinGL8KkG4kX0pEsdb0+TKhmJZgCUDBGmyo1/ArCjNGiOLiIAgdbWgmWgib4HoCi5t7kA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -523,9 +523,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz",
|
||||
"integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.6.tgz",
|
||||
"integrity": "sha512-42QOgcZeZOvXfsCBJF5Afw73t4veOId//XD3i+/9gSkhSV6Gk3VPlWncctI+JcOyERv85FUo7RxuxGy+z8A43Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -540,9 +540,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz",
|
||||
"integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.6.tgz",
|
||||
"integrity": "sha512-4AWhgXmDuYN7rJI6ORB+uU9DHLq/erBbuMoAuB4VWJTu5KtCgcKYPynF0YI1VkBNuEfjNlLrFr9KZPJzrtLkrQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -557,9 +557,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz",
|
||||
"integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.6.tgz",
|
||||
"integrity": "sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -832,9 +832,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@pkgr/core": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz",
|
||||
"integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==",
|
||||
"version": "0.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.7.tgz",
|
||||
"integrity": "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -904,9 +904,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "24.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.15.tgz",
|
||||
"integrity": "sha512-oaeTSbCef7U/z7rDeJA138xpG3NuKc64/rZ2qmUFkFJmnMsAPaluIifqyWd8hSSMxyP9oie3dLAqYPblag9KgA==",
|
||||
"version": "24.0.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.14.tgz",
|
||||
"integrity": "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1269,9 +1269,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.25.8",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz",
|
||||
"integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==",
|
||||
"version": "0.25.6",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.6.tgz",
|
||||
"integrity": "sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
@@ -1282,32 +1282,32 @@
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.25.8",
|
||||
"@esbuild/android-arm": "0.25.8",
|
||||
"@esbuild/android-arm64": "0.25.8",
|
||||
"@esbuild/android-x64": "0.25.8",
|
||||
"@esbuild/darwin-arm64": "0.25.8",
|
||||
"@esbuild/darwin-x64": "0.25.8",
|
||||
"@esbuild/freebsd-arm64": "0.25.8",
|
||||
"@esbuild/freebsd-x64": "0.25.8",
|
||||
"@esbuild/linux-arm": "0.25.8",
|
||||
"@esbuild/linux-arm64": "0.25.8",
|
||||
"@esbuild/linux-ia32": "0.25.8",
|
||||
"@esbuild/linux-loong64": "0.25.8",
|
||||
"@esbuild/linux-mips64el": "0.25.8",
|
||||
"@esbuild/linux-ppc64": "0.25.8",
|
||||
"@esbuild/linux-riscv64": "0.25.8",
|
||||
"@esbuild/linux-s390x": "0.25.8",
|
||||
"@esbuild/linux-x64": "0.25.8",
|
||||
"@esbuild/netbsd-arm64": "0.25.8",
|
||||
"@esbuild/netbsd-x64": "0.25.8",
|
||||
"@esbuild/openbsd-arm64": "0.25.8",
|
||||
"@esbuild/openbsd-x64": "0.25.8",
|
||||
"@esbuild/openharmony-arm64": "0.25.8",
|
||||
"@esbuild/sunos-x64": "0.25.8",
|
||||
"@esbuild/win32-arm64": "0.25.8",
|
||||
"@esbuild/win32-ia32": "0.25.8",
|
||||
"@esbuild/win32-x64": "0.25.8"
|
||||
"@esbuild/aix-ppc64": "0.25.6",
|
||||
"@esbuild/android-arm": "0.25.6",
|
||||
"@esbuild/android-arm64": "0.25.6",
|
||||
"@esbuild/android-x64": "0.25.6",
|
||||
"@esbuild/darwin-arm64": "0.25.6",
|
||||
"@esbuild/darwin-x64": "0.25.6",
|
||||
"@esbuild/freebsd-arm64": "0.25.6",
|
||||
"@esbuild/freebsd-x64": "0.25.6",
|
||||
"@esbuild/linux-arm": "0.25.6",
|
||||
"@esbuild/linux-arm64": "0.25.6",
|
||||
"@esbuild/linux-ia32": "0.25.6",
|
||||
"@esbuild/linux-loong64": "0.25.6",
|
||||
"@esbuild/linux-mips64el": "0.25.6",
|
||||
"@esbuild/linux-ppc64": "0.25.6",
|
||||
"@esbuild/linux-riscv64": "0.25.6",
|
||||
"@esbuild/linux-s390x": "0.25.6",
|
||||
"@esbuild/linux-x64": "0.25.6",
|
||||
"@esbuild/netbsd-arm64": "0.25.6",
|
||||
"@esbuild/netbsd-x64": "0.25.6",
|
||||
"@esbuild/openbsd-arm64": "0.25.6",
|
||||
"@esbuild/openbsd-x64": "0.25.6",
|
||||
"@esbuild/openharmony-arm64": "0.25.6",
|
||||
"@esbuild/sunos-x64": "0.25.6",
|
||||
"@esbuild/win32-arm64": "0.25.6",
|
||||
"@esbuild/win32-ia32": "0.25.6",
|
||||
"@esbuild/win32-x64": "0.25.6"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-string-regexp": {
|
||||
@@ -2328,14 +2328,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier-plugin-packagejson": {
|
||||
"version": "2.5.19",
|
||||
"resolved": "https://registry.npmjs.org/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.19.tgz",
|
||||
"integrity": "sha512-Qsqp4+jsZbKMpEGZB1UP1pxeAT8sCzne2IwnKkr+QhUe665EXUo3BAvTf1kAPCqyMv9kg3ZmO0+7eOni/C6Uag==",
|
||||
"version": "2.5.18",
|
||||
"resolved": "https://registry.npmjs.org/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.18.tgz",
|
||||
"integrity": "sha512-NKznPGcGrcj4NPGxnh+w78JXPyfB6I4RQSCM0v+CAXwpDG7OEpJQ5zMyfC5NBgKH1k7Skwcj5ak5by2mrHvC5g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"sort-package-json": "3.4.0",
|
||||
"synckit": "0.11.11"
|
||||
"synckit": "0.11.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"prettier": ">= 1.16.0"
|
||||
@@ -2628,13 +2628,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/synckit": {
|
||||
"version": "0.11.11",
|
||||
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz",
|
||||
"integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==",
|
||||
"version": "0.11.8",
|
||||
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.8.tgz",
|
||||
"integrity": "sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@pkgr/core": "^0.2.9"
|
||||
"@pkgr/core": "^0.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18.0 || >=16.0.0"
|
||||
@@ -2728,9 +2728,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typedoc-plugin-markdown": {
|
||||
"version": "4.7.1",
|
||||
"resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-4.7.1.tgz",
|
||||
"integrity": "sha512-HN/fHLm2S6MD4HX8txfB4eWvVBzX/mEYy5U5s1KTAdh3E5uX5/lilswqTzZlPTT6fNZInAboAdFGpbAuBKnE4A==",
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-4.7.0.tgz",
|
||||
"integrity": "sha512-PitbnAps2vpcqK2gargKoiFXLWFttvwUbyns/E6zGIFG5Gz8ZQJGttHnYR9csOlcSjB/uyjd8tnoayrtsXG17w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
||||
26
packages/eslint-config/package-lock.json
generated
26
packages/eslint-config/package-lock.json
generated
@@ -237,9 +237,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/core": {
|
||||
"version": "0.15.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz",
|
||||
"integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==",
|
||||
"version": "0.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz",
|
||||
"integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.15"
|
||||
@@ -292,12 +292,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/plugin-kit": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.3.tgz",
|
||||
"integrity": "sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==",
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz",
|
||||
"integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@eslint/core": "^0.15.1",
|
||||
"@eslint/core": "^0.14.0",
|
||||
"levn": "^0.4.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1822,6 +1822,18 @@
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/@eslint/core": {
|
||||
"version": "0.15.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz",
|
||||
"integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.15"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/espree": {
|
||||
"version": "10.4.0",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
|
||||
|
||||
28
packages/prettier-config/package-lock.json
generated
28
packages/prettier-config/package-lock.json
generated
@@ -360,9 +360,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@pkgr/core": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz",
|
||||
"integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==",
|
||||
"version": "0.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.7.tgz",
|
||||
"integrity": "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -385,9 +385,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "24.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.15.tgz",
|
||||
"integrity": "sha512-oaeTSbCef7U/z7rDeJA138xpG3NuKc64/rZ2qmUFkFJmnMsAPaluIifqyWd8hSSMxyP9oie3dLAqYPblag9KgA==",
|
||||
"version": "24.0.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.14.tgz",
|
||||
"integrity": "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1466,14 +1466,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier-plugin-packagejson": {
|
||||
"version": "2.5.19",
|
||||
"resolved": "https://registry.npmjs.org/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.19.tgz",
|
||||
"integrity": "sha512-Qsqp4+jsZbKMpEGZB1UP1pxeAT8sCzne2IwnKkr+QhUe665EXUo3BAvTf1kAPCqyMv9kg3ZmO0+7eOni/C6Uag==",
|
||||
"version": "2.5.18",
|
||||
"resolved": "https://registry.npmjs.org/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.18.tgz",
|
||||
"integrity": "sha512-NKznPGcGrcj4NPGxnh+w78JXPyfB6I4RQSCM0v+CAXwpDG7OEpJQ5zMyfC5NBgKH1k7Skwcj5ak5by2mrHvC5g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"sort-package-json": "3.4.0",
|
||||
"synckit": "0.11.11"
|
||||
"synckit": "0.11.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"prettier": ">= 1.16.0"
|
||||
@@ -1657,13 +1657,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/synckit": {
|
||||
"version": "0.11.11",
|
||||
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz",
|
||||
"integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==",
|
||||
"version": "0.11.8",
|
||||
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.8.tgz",
|
||||
"integrity": "sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@pkgr/core": "^0.2.9"
|
||||
"@pkgr/core": "^0.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18.0 || >=16.0.0"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from dataclasses import asdict
|
||||
from time import sleep
|
||||
|
||||
from pyrad.client import Client, Timeout
|
||||
from pyrad.client import Client
|
||||
from pyrad.dictionary import Dictionary
|
||||
from pyrad.packet import AccessAccept, AccessReject, AccessRequest
|
||||
|
||||
@@ -27,7 +27,7 @@ class TestProviderRadius(SeleniumTestCase):
|
||||
"""Start radius container based on outpost created"""
|
||||
self.run_container(
|
||||
image=self.get_container_image("ghcr.io/goauthentik/dev-radius"),
|
||||
ports={"1812/udp": 1812},
|
||||
ports={"1812/udp": "1812/udp"},
|
||||
environment={
|
||||
"AUTHENTIK_TOKEN": outpost.token.key,
|
||||
},
|
||||
@@ -63,7 +63,7 @@ class TestProviderRadius(SeleniumTestCase):
|
||||
sleep(5)
|
||||
return outpost
|
||||
|
||||
@retry(exceptions=[Timeout])
|
||||
@retry()
|
||||
@apply_blueprint(
|
||||
"default/flow-default-authentication-flow.yaml",
|
||||
"default/flow-default-invalidation-flow.yaml",
|
||||
@@ -85,7 +85,7 @@ class TestProviderRadius(SeleniumTestCase):
|
||||
reply = srv.SendPacket(req)
|
||||
self.assertEqual(reply.code, AccessAccept)
|
||||
|
||||
@retry(exceptions=[Timeout])
|
||||
@retry()
|
||||
@apply_blueprint(
|
||||
"default/flow-default-authentication-flow.yaml",
|
||||
"default/flow-default-invalidation-flow.yaml",
|
||||
|
||||
777
web/package-lock.json
generated
777
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -97,7 +97,7 @@
|
||||
"@lit/context": "^1.1.2",
|
||||
"@lit/localize": "^0.12.2",
|
||||
"@lit/reactive-element": "^2.0.4",
|
||||
"@lit/task": "^1.0.3",
|
||||
"@lit/task": "^1.0.2",
|
||||
"@mdx-js/mdx": "^3.1.0",
|
||||
"@mrmarble/djangoql-completion": "^0.8.3",
|
||||
"@open-wc/lit-helpers": "^0.7.0",
|
||||
@@ -105,16 +105,16 @@
|
||||
"@openlayers-elements/maps": "^0.4.0",
|
||||
"@patternfly/elements": "^4.1.0",
|
||||
"@patternfly/patternfly": "^4.224.2",
|
||||
"@sentry/browser": "^9.40.0",
|
||||
"@sentry/browser": "^9.39.0",
|
||||
"@spotlightjs/spotlight": "^3.0.1",
|
||||
"@webcomponents/webcomponentsjs": "^2.8.0",
|
||||
"base64-js": "^1.5.1",
|
||||
"change-case": "^5.4.4",
|
||||
"chart.js": "^4.5.0",
|
||||
"chart.js": "^4.4.9",
|
||||
"chartjs-adapter-date-fns": "^3.0.0",
|
||||
"codemirror": "^6.0.2",
|
||||
"codemirror": "^6.0.1",
|
||||
"construct-style-sheets-polyfill": "^3.1.0",
|
||||
"core-js": "^3.44.0",
|
||||
"core-js": "^3.42.0",
|
||||
"country-flag-icons": "^1.5.19",
|
||||
"date-fns": "^4.1.0",
|
||||
"deepmerge-ts": "^7.1.5",
|
||||
@@ -156,13 +156,13 @@
|
||||
"@storybook/addon-links": "^9.0.17",
|
||||
"@storybook/web-components": "^9.0.17",
|
||||
"@storybook/web-components-vite": "^9.0.17",
|
||||
"@types/chart.js": "^4.0.1",
|
||||
"@types/chart.js": "^2.9.41",
|
||||
"@types/codemirror": "^5.60.15",
|
||||
"@types/dompurify": "^3.2.0",
|
||||
"@types/grecaptcha": "^3.0.9",
|
||||
"@types/guacamole-common-js": "^1.5.3",
|
||||
"@types/mocha": "^10.0.10",
|
||||
"@types/node": "^24.0.15",
|
||||
"@types/node": "^24.0.14",
|
||||
"@types/react": "^19.1.8",
|
||||
"@types/react-dom": "^19.1.6",
|
||||
"@typescript-eslint/eslint-plugin": "^8.8.0",
|
||||
@@ -172,7 +172,7 @@
|
||||
"@wdio/spec-reporter": "^9.15.0",
|
||||
"@web/test-runner": "^0.20.2",
|
||||
"chromedriver": "^136.0.3",
|
||||
"esbuild": "^0.25.8",
|
||||
"esbuild": "^0.25.6",
|
||||
"esbuild-plugin-copy": "^2.1.1",
|
||||
"esbuild-plugin-polyfill-node": "^0.3.0",
|
||||
"esbuild-plugins-node-modules-polyfill": "^1.7.1",
|
||||
@@ -181,7 +181,7 @@
|
||||
"eslint-plugin-wc": "^3.0.1",
|
||||
"github-slugger": "^2.0.0",
|
||||
"globals": "^15.10.0",
|
||||
"knip": "^5.61.3",
|
||||
"knip": "^5.58.0",
|
||||
"lit-analyzer": "^2.0.3",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^3.3.3",
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
"devDependencies": {
|
||||
"@goauthentik/prettier-config": "^1.0.5",
|
||||
"@goauthentik/tsconfig": "^1.0.4",
|
||||
"@types/node": "^24.0.15",
|
||||
"@types/node": "^24.0.14",
|
||||
"prettier": "^3.3.3",
|
||||
"typescript": "^5.6.3"
|
||||
},
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"dependencies": {
|
||||
"@goauthentik/api": "^2024.6.0-1719577139",
|
||||
"base64-js": "^1.5.1",
|
||||
"bootstrap": "^5.3.7",
|
||||
"bootstrap": "^4.6.1",
|
||||
"formdata-polyfill": "^4.0.10",
|
||||
"jquery": "^3.7.1",
|
||||
"weakmap-polyfill": "^2.0.4"
|
||||
@@ -23,7 +23,7 @@
|
||||
"@rollup/plugin-node-resolve": "^16.0.1",
|
||||
"@rollup/plugin-swc": "^0.4.0",
|
||||
"@swc/cli": "^0.7.8",
|
||||
"@swc/core": "^1.13.1",
|
||||
"@swc/core": "^1.12.14",
|
||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||
"prettier": "^3.5.3",
|
||||
"rollup": "^4.45.1",
|
||||
|
||||
@@ -59,7 +59,7 @@ export class AboutModal extends WithLicenseSummary(WithBrandConfig(ModalButton))
|
||||
renderModal() {
|
||||
let product = this.brandingTitle;
|
||||
|
||||
if (this.licenseSummary?.status !== LicenseSummaryStatusEnum.Unlicensed) {
|
||||
if (this.licenseSummary.status !== LicenseSummaryStatusEnum.Unlicensed) {
|
||||
product += ` ${msg("Enterprise")}`;
|
||||
}
|
||||
return html`<div
|
||||
|
||||
@@ -20,7 +20,7 @@ export class EnterpriseStatusBanner extends WithLicenseSummary(AKElement) {
|
||||
|
||||
renderStatusBanner() {
|
||||
// Check if we're in the correct interface to render a banner
|
||||
switch (this.licenseSummary?.status) {
|
||||
switch (this.licenseSummary.status) {
|
||||
// user warning is both on admin interface and user interface
|
||||
case LicenseSummaryStatusEnum.LimitExceededUser:
|
||||
if (
|
||||
@@ -45,7 +45,7 @@ export class EnterpriseStatusBanner extends WithLicenseSummary(AKElement) {
|
||||
break;
|
||||
}
|
||||
let message = "";
|
||||
switch (this.licenseSummary?.status) {
|
||||
switch (this.licenseSummary.status) {
|
||||
case LicenseSummaryStatusEnum.LimitExceededAdmin:
|
||||
case LicenseSummaryStatusEnum.LimitExceededUser:
|
||||
message = msg(
|
||||
@@ -83,12 +83,12 @@ export class EnterpriseStatusBanner extends WithLicenseSummary(AKElement) {
|
||||
|
||||
renderFlagBanner() {
|
||||
return html`
|
||||
${this.licenseSummary?.licenseFlags.includes(LicenseFlagsEnum.Trial)
|
||||
${this.licenseSummary.licenseFlags.includes(LicenseFlagsEnum.Trial)
|
||||
? html`<div class="pf-c-banner pf-m-sticky pf-m-gold">
|
||||
${msg("This authentik instance uses a Trial license.")}
|
||||
</div>`
|
||||
: nothing}
|
||||
${this.licenseSummary?.licenseFlags.includes(LicenseFlagsEnum.NonProduction)
|
||||
${this.licenseSummary.licenseFlags.includes(LicenseFlagsEnum.NonProduction)
|
||||
? html`<div class="pf-c-banner pf-m-sticky pf-m-gold">
|
||||
${msg("This authentik instance uses a Non-production license.")}
|
||||
</div>`
|
||||
|
||||
@@ -17,7 +17,7 @@ export interface LicenseMixin {
|
||||
/**
|
||||
* Summary of the current license.
|
||||
*/
|
||||
readonly licenseSummary: LicenseSummary | null;
|
||||
readonly licenseSummary: LicenseSummary;
|
||||
|
||||
/**
|
||||
* Whether or not the current license is an enterprise license.
|
||||
@@ -39,12 +39,12 @@ export const WithLicenseSummary = createMixin<LicenseMixin>(
|
||||
context: LicenseContext,
|
||||
subscribe,
|
||||
})
|
||||
public readonly licenseSummary: LicenseSummary | null = null;
|
||||
public readonly licenseSummary!: LicenseSummary;
|
||||
|
||||
get hasEnterpriseLicense() {
|
||||
return (
|
||||
this.licenseSummary?.status === LicenseSummaryStatusEnum.Valid ||
|
||||
this.licenseSummary?.status === LicenseSummaryStatusEnum.ExpirySoon
|
||||
this.licenseSummary.status === LicenseSummaryStatusEnum.Valid ||
|
||||
this.licenseSummary.status === LicenseSummaryStatusEnum.ExpirySoon
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,12 +48,12 @@
|
||||
"@rspack/binding-darwin-arm64": "1.4.8",
|
||||
"@rspack/binding-linux-arm64-gnu": "1.4.8",
|
||||
"@rspack/binding-linux-x64-gnu": "1.4.8",
|
||||
"@swc/core-darwin-arm64": "1.13.0",
|
||||
"@swc/core-linux-arm64-gnu": "1.13.0",
|
||||
"@swc/core-linux-x64-gnu": "1.13.0",
|
||||
"@swc/html-darwin-arm64": "1.13.0",
|
||||
"@swc/html-linux-arm64-gnu": "1.13.0",
|
||||
"@swc/html-linux-x64-gnu": "1.13.0",
|
||||
"@swc/core-darwin-arm64": "1.12.14",
|
||||
"@swc/core-linux-arm64-gnu": "1.12.14",
|
||||
"@swc/core-linux-x64-gnu": "1.12.14",
|
||||
"@swc/html-darwin-arm64": "1.12.14",
|
||||
"@swc/html-linux-arm64-gnu": "1.12.14",
|
||||
"@swc/html-linux-x64-gnu": "1.12.14",
|
||||
"lightningcss-darwin-arm64": "1.30.1",
|
||||
"lightningcss-linux-arm64-gnu": "1.30.1",
|
||||
"lightningcss-linux-x64-gnu": "1.30.1"
|
||||
|
||||
@@ -4,81 +4,60 @@ title: Writing documentation
|
||||
|
||||
Writing documentation for authentik is a great way for both new and experienced users to improve and contribute to the project. We appreciate contributions to our documentation; everything from fixing a typo to adding additional content to writing a completely new topic.
|
||||
|
||||
The technical documentation (https://docs.goauthentik.io/docs/) and our integration guides (https://integrations.goauthentik.io/) are built, formatted, and tested using npm. The commands to build the content locally are defined in the `Makefile` in the root of the repository. Each command is prefixed with `docs-` or `integrations-` and corresponds to an NPM script within the `website` directory.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Node.js 24 (or later)
|
||||
|
||||
## Guidelines
|
||||
|
||||
Adhering to the following guidelines will help us get your PRs merged much easier and faster, with fewer edits needed.
|
||||
|
||||
- Ideally, when you are making contributions to the documentation, you should fork and clone our repo, then [build it locally](#set-up-your-local-build-tools), so that you can test the docs and run the required linting and spell checkers before pushing your PR. While you can do much of the writing and editing within the GitHub UI, you cannot run the required linters from the GitHub UI.
|
||||
|
||||
- After submitting a PR, you can view the Netlify Deploy Preview for the PR on GitHub, to check that your content rendered correctly, links work, etc. This is especially useful when using Docusaurus-specific features in your content.
|
||||
- Ideally, when you are making contributions to the documentation, you should fork and clone our repo, then [build it locally](#set-up-your-local-build), so that you can test the docs and run the required linting and spell checkers before pushing your PR. While you can do much of the writing and editing within the GitHub UI, you cannot run the required linters from the GitHub UI.
|
||||
|
||||
- Please refer to our [Style Guide](./style-guide.mdx) for authentik documentation. Here you will learn important guidelines about not capitalizing authentik, how we format our titles and headers, and much more.
|
||||
|
||||
- Remember to use our templates when possible; they are already set up to follow our style guidelines, they make it a lot easier for you (no blank page frights!), and they keep the documentation structure and headings consistent.
|
||||
- [docs templates](./templates/index.md)
|
||||
- [integration guide template](https://integrations.goauthentik.io/applications#add-a-new-application)
|
||||
- Remember to use our [docs templates](./templates/index.md) when possible; they are already set up to follow our style guidelines, they make it a lot easier for you (no blank page frights!), and keeps the documentation structure and headings consistent.
|
||||
|
||||
:::tip
|
||||
If you encounter build check fails, or issues you with your local build, you might need to run `make docs-install` in order to get the latest build tools and dependencies; we do occasionally update our build tools.
|
||||
:::
|
||||
- To test how the documentation renders you can build locally and then use the Netlify Deploy Preview, especially when using Docusaurus-specific features. You can also run the `make docs-watch` command on your local build, to see the rendered pages as you make changes.
|
||||
|
||||
## Clone and fork the authentik repository
|
||||
- Be sure to run the `make docs` command on your local branch, before pushing the PR to the authentik repo. This command does important linting, and the build check in our repo will fail if the linting has not been done.
|
||||
|
||||
The documentation, integration guides, API docs, and the code are in the same [GitHub repo](https://github.com/goauthentik/authentik), so if you have cloned and forked the repo, you already have the docs and integration guides.
|
||||
- For new entries, make sure to add any new pages to the appropriate `sidebar.js` file. Otherwise, the new page will not appear in the table of contents to the left.
|
||||
|
||||
## Set up your local build tools
|
||||
## Set up your local build
|
||||
|
||||
Run the following command to install the build tools for both the technical docs and integration guides.
|
||||
Requirements:
|
||||
|
||||
- **Install (or update) the build tools**: `make docs-install`
|
||||
- Node.js 20 (or greater, we use Node.js 24)
|
||||
|
||||
Installs the build dependencies such as Docusaurus, Prettier, and ESLint. You should run this command when you are first setting up your writing environment, and also if you encounter build check fails either when you build locally or when you push your PR to the authentik repository. Running this command will grab any new dependencies that we might have added to our build tool package.
|
||||
The docs and the code are in the same Github repo, at https://github.com/goauthentik/authentik, so if you have cloned the repo, you already have the docs.
|
||||
|
||||
## Writing or modifying technical docs
|
||||
You can do local builds of the documentation to test your changes or review your new content, and to run the required `make docs` command (which runs `prettier` and other linters) before pushing your PR.
|
||||
|
||||
In addition to following the [Style Guide](./style-guide.mdx) please review the following guidelines about our technical documentation (https://docs.goauthentik.io/docs/):
|
||||
The documentation site is situated in the `/website` folder of the repo.
|
||||
|
||||
- For new entries, make sure to add any new pages to the `/docs/sidebar.mjs` file.
|
||||
Otherwise, the new page will not appear in the table of contents to the left.
|
||||
The site is built using npm, below are some useful make commands:
|
||||
|
||||
- Always be sure to run the `make docs` command on your local branch _before_ pushing the PR to the authentik repo. This command does important linting, and the build check in our repo will fail if the linting has not been done. In general, check on the health of your build before pushing to the authentik repo, and also check on the build status of your PR after you create it.
|
||||
- **Installation**: `make docs-install`
|
||||
|
||||
For our technical documentation (https://docs.goauthentik.io/docs/), the following commands are used:
|
||||
This command is required before running any of the following commands, and after upgrading any dependencies.
|
||||
|
||||
- **Build locally**: `make docs`
|
||||
- **Formatting**: `make docs`, `make docs-lint-fix`, or `npm run prettier`
|
||||
|
||||
This command is a combination of `make docs-lint-fix` and `make docs-build`. It is important to run this command before committing changes because linter errors will prevent the build checks from passing.
|
||||
Run the appropriate formatting command for your set up before committing, to ensure consistent syntax, clean formatting, and verify links. Note that if the formatting command is not run, the build will fail with an error about linting.
|
||||
|
||||
- **Live editing**: `make docs-watch`
|
||||
|
||||
Starts a development server for the documentation site. This command will automatically rebuild your local documentation site whenever you make changes to the Markdown files in the `website/docs` directory.
|
||||
For real-time viewing of changes, as you make them.
|
||||
|
||||
## Writing or modifying integration guides
|
||||
:::info
|
||||
Be sure to run a formatting command before committing changes.
|
||||
:::
|
||||
|
||||
In addition to following the [Style Guide](./style-guide.mdx) please review the following guidelines about our integration guides (https://integrations.goauthentik.io/).
|
||||
## Documentation for integrations
|
||||
|
||||
- For new integration documentation, please use the Integrations template in our [Github repo](https://github.com/goauthentik/authentik) at `/website/integrations/template/service.md`.
|
||||
In addition to following the [Style Guide](./style-guide.mdx) please review the following guidelines.
|
||||
|
||||
For new integration documentation, please use the Integrations template in our [Github repo](https://github.com/goauthentik/authentik) at `/website/integrations/template/service.md`.
|
||||
|
||||
- For placeholder domains, use `authentik.company` and `app-name.company`, where `app-name` is the name of the application that you are writing documentation for.
|
||||
|
||||
- Make sure to create a directory for your service in a fitting category within [`/website/integrations/`](https://github.com/goauthentik/authentik/tree/main/website/integrations).
|
||||
Make sure to create a directory for your service in a fitting category within `/website/integrations/`.
|
||||
|
||||
:::tip Sidebars and categories
|
||||
You no longer need to modify the integrations sidebar file manually. This is now automatically generated from the categories in [`/website/integrations/categories.mjs`](https://github.com/goauthentik/authentik/blob/main/website/integrations/categories.mjs).
|
||||
:::tip
|
||||
You no longer need to modify the integrations sidebar file manually. This is now automatically generated from the categories in `/website/integrations/categories.mjs`.
|
||||
:::
|
||||
|
||||
When authoring integration guides, the following commands are used:
|
||||
|
||||
- **Build locally**: `make integrations`
|
||||
|
||||
This command is a combination of `make docs-lint-fix` and `make integrations-build`. This command should always be run on your local branch before committing your changes to a pull request to the authentik repo. It is important to run this command before committing changes because linter errors will prevent the build checks from passing.
|
||||
|
||||
- **Live editing**: `make integrations-watch`
|
||||
|
||||
Starts a development server for the integrations guides. This command will automatically rebuild your local integrations site whenever you make changes to the Markdown files in the [`/website/integrations/`](https://github.com/goauthentik/authentik/tree/main/website/integrations) directory.
|
||||
|
||||
@@ -26,8 +26,8 @@ import Tabs from "@theme/Tabs";
|
||||
|
||||
## Services Setup
|
||||
|
||||
For PostgreSQL and Redis, you can use the `docker-compose.yml` file in `/scripts`. To use these pre-configured database instances, navigate to the `/scripts` directory in your local copy of the authentik git repo, and start the services by running `docker compose up -d`.
|
||||
Alternatively, you can also use a native install, if you prefer.
|
||||
For PostgreSQL and Redis, you can use the `docker-compose.yml` file in `/scripts`.To use these pre-configured database instances, navigate to the `/scripts` directory in your local copy of the authentik git repo, and run `docker compose up -d`.
|
||||
You can also use a native install, if you prefer.
|
||||
|
||||
:::info
|
||||
If you use locally installed databases, the PostgreSQL credentials given to authentik should have permissions for `CREATE DATABASE` and `DROP DATABASE`, because authentik creates a temporary database for tests.
|
||||
@@ -147,18 +147,6 @@ To define a password for the default admin (called **akadmin**), you can manuall
|
||||
In case of issues in this process, feel free to use `make dev-reset` which drops and restores the authentik PostgreSQL instance to a "fresh install" state.
|
||||
:::
|
||||
|
||||
## End-to-End (E2E) Setup
|
||||
|
||||
To run E2E tests, navigate to the `/tests/e2e` directory in your local copy of the authentik git repo, and start the services by running `docker compose up -d`.
|
||||
|
||||
You can then view the Selenium Chrome browser via http://localhost:7900/ using the password: `secret`.
|
||||
|
||||
Alternatively, you can connect directly via VNC on port `5900` using the password: `secret`.
|
||||
|
||||
:::note
|
||||
When using Docker Desktop, host networking needs to be enabled via **Docker Settings** > **Resources** > **Network** > **Enable host networking**.
|
||||
:::
|
||||
|
||||
## Submitting Pull Requests
|
||||
|
||||
Before submitting a pull request, run the following commands in the same directory as your local authentik git repository:
|
||||
|
||||
@@ -450,7 +450,6 @@ const items = [
|
||||
"users-sources/user/user_basic_operations",
|
||||
"users-sources/user/user_ref",
|
||||
"users-sources/user/invitations",
|
||||
"users-sources/user/password_reset_on_login",
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
---
|
||||
title: Notification Rule Expression Policies
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
Notification rules with bound expression policies are very powerful. The following are examples of what can be achieved.
|
||||
|
||||
### Change user attributes upon account deactivation
|
||||
|
||||
This example code is triggered when a user account with the `sshPublicKey` attribute set is deactivated. It saves the `sshPublicKey` attribute to a new `inactivesshPublicKey` attribute, and subsequently nullifies the `sshPublicKey` attribute.
|
||||
|
||||
```python
|
||||
from authentik.core.models import User
|
||||
|
||||
# Check if an event has occurred
|
||||
event = request.context.get("event", None)
|
||||
if not event:
|
||||
ak_logger.info("no event")
|
||||
return False
|
||||
|
||||
# Check if the event action includes updating a model
|
||||
if event.action != "model_updated":
|
||||
ak_logger.info("event action does not match")
|
||||
return False
|
||||
|
||||
model_app = event.context["model"]["app"]
|
||||
model_name = event.context["model"]["model_name"]
|
||||
|
||||
# Check if the model that was updated is the user model
|
||||
if model_app != "authentik_core" or model_name != "user":
|
||||
ak_logger.info("model does not match")
|
||||
|
||||
user_pk = event.context["model"]["pk"]
|
||||
user = User.objects.filter(pk=user_pk).first()
|
||||
|
||||
# Check if an user object was found
|
||||
if not user:
|
||||
ak_logger.info("user not found")
|
||||
return False
|
||||
|
||||
# Check if user is active
|
||||
if user.is_active:
|
||||
ak_logger.info("user is active, not changing")
|
||||
return False
|
||||
|
||||
# Check if user has the `sshPublicKey` attribute set
|
||||
if not user.attributes.get("sshPublicKey"):
|
||||
ak_logger.info("no public keys to remove")
|
||||
return False
|
||||
|
||||
# Save the `sshPublicKey` attribute to a new `inactiveSSHPublicKey` attribute
|
||||
user.attributes["inactiveSSHPublicKey"] = user.attributes["sshPublicKey"]
|
||||
|
||||
# Nullify the `sshPublicKey` attribute
|
||||
user.attributes["sshPublicKey"] = []
|
||||
|
||||
# Save the changes made to the user
|
||||
user.save()
|
||||
|
||||
return False
|
||||
```
|
||||
|
||||
### Alert when application is created without binding
|
||||
|
||||
This code is triggered when a new application is created without any user, group, or policy bound to it. The notification rule can then be configured to alert an administrator. This feature is useful for ensuring limited access to applications, as by default, an application without any users, groups, or policies bound to it can be accessed by all users.
|
||||
|
||||
```python
|
||||
from authentik.core.models import Application
|
||||
from authentik.policies.models import PolicyBinding
|
||||
|
||||
# Check if an event has occurred
|
||||
event = request.context.get("event", None)
|
||||
if not event:
|
||||
ak_logger.info("no event")
|
||||
return False
|
||||
|
||||
# Check if the event action includes creating a model
|
||||
if event.action != "model_created":
|
||||
ak_logger.info("event action does not match")
|
||||
return False
|
||||
|
||||
model_app = event.context["model"]["app"]
|
||||
model_name = event.context["model"]["model_name"]
|
||||
|
||||
# Check if the model that was created is the application model
|
||||
if model_app != "authentik_core" or model_name != "application":
|
||||
ak_logger.info("model does not match")
|
||||
|
||||
application_pk = event.context["model"]["pk"]
|
||||
application = Application.objects.filter(pk=application_pk).first()
|
||||
|
||||
# Check if an application object was found
|
||||
if not application:
|
||||
ak_logger.info("application not found")
|
||||
return False
|
||||
|
||||
# Check if application has binding
|
||||
if PolicyBinding.objects.filter(target=application).exists():
|
||||
output = PolicyBinding.objects.filter(target=application)
|
||||
ak_logger.info("application has bindings, returning true")
|
||||
return True
|
||||
|
||||
return False
|
||||
```
|
||||
|
||||
### Append user addition history to group attributes
|
||||
|
||||
This code is triggered when a user is added to a group. It then creates and updates a `UserAddedHistory` attribute to the group with a date/time stamp and the username of the added user. This functionality is already available within the changelog of a group, but this code can be used as a template to trigger alerts or other events.
|
||||
|
||||
:::note
|
||||
This policy interacts with the `diff` event output. This field is only available with an enterprise license.
|
||||
:::
|
||||
|
||||
```python
|
||||
from authentik.core.models import User
|
||||
from authentik.core.models import Group
|
||||
from datetime import datetime
|
||||
|
||||
# Check if an event has occurred
|
||||
event = request.context.get("event", None)
|
||||
if not event:
|
||||
ak_logger.info("no event")
|
||||
return False
|
||||
|
||||
# Check if the event action includes updating a model
|
||||
if event.action != "model_updated":
|
||||
ak_logger.info("event action does not match")
|
||||
return False
|
||||
|
||||
model_app = event.context["model"]["app"]
|
||||
model_name = event.context["model"]["model_name"]
|
||||
|
||||
# Check if the model that was updated is the group model
|
||||
if model_app != "authentik_core" or model_name != "group":
|
||||
ak_logger.info("model does not match")
|
||||
|
||||
group_pk = event.context["model"]["pk"]
|
||||
group = Group.objects.filter(pk=group_pk).first()
|
||||
|
||||
# If user was added to group, get user object, else return false
|
||||
if "add" in event.context["diff"]["users"]:
|
||||
ak_logger.info("user added to group")
|
||||
|
||||
user_pk = event.context["diff"]["users"]["add"][0]
|
||||
user = User.objects.filter(pk=user_pk).first()
|
||||
else:
|
||||
ak_logger.info("user not added to group")
|
||||
return False
|
||||
|
||||
# Check if a group object was found
|
||||
if not group:
|
||||
ak_logger.info("group not found")
|
||||
return False
|
||||
|
||||
# Check if an user object was found
|
||||
if not user:
|
||||
ak_logger.info("user not found")
|
||||
return False
|
||||
|
||||
if not group.attributes.get("UserAddedHistory"):
|
||||
group.attributes["UserAddedHistory"] = []
|
||||
|
||||
current_date_time = datetime.now().isoformat(timespec='seconds')
|
||||
|
||||
group.attributes["UserAddedHistory"].append(current_date_time + " - Added user: " + user.username)
|
||||
|
||||
# Save the changes made to the group
|
||||
group.save()
|
||||
|
||||
return False
|
||||
```
|
||||
@@ -27,13 +27,13 @@ You will need to create a policy (either the **Event Matcher** policy or a custo
|
||||
|
||||
### Event Matcher policy
|
||||
|
||||
For simple event matching you can [create and configure](../../customize/policies/working_with_policies.md) an **Event Matcher policy** to define which events (known as _Actions_ in the policy) will trigger a notification. For example, whenever a user deletes a model object, or whenever any user fails to successfully log in.
|
||||
For simple event matching you can [create and configure](../../customize/policies/working_with_policies.md) a **Event Matcher** policy to define which events (known as _Actions_ in the policy) will trigger a notification. For example, whenever a user deletes a model object, or whenever any user fails to successfully log in.
|
||||
|
||||
Be aware that an event has to match all configured fields in the policy, otherwise the notification rule will not trigger.
|
||||
|
||||
### Expression policy for events
|
||||
|
||||
To match events with an **Expression Policy**, you can write code like so:
|
||||
To match events with an "Expression Policy", you can write code like so:
|
||||
|
||||
```python
|
||||
if "event" not in request.context:
|
||||
@@ -42,8 +42,6 @@ if "event" not in request.context:
|
||||
return ip_address(request.context["event"].client_ip) in ip_network('192.0.2.0/24')
|
||||
```
|
||||
|
||||
For more code examples, see [notification rule expression policies](./notification_rule_expression_policies.mdx).
|
||||
|
||||
## 3. Create a notification rule and bind it to the policy
|
||||
|
||||
After you've created the policies to match the events you want, create a notification rule.
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
---
|
||||
title: Force password reset on next login
|
||||
sidebar_label: Password reset on login
|
||||
---
|
||||
|
||||
You can require users to reset their password on their next login, using expression policies, custom stages, and a custom user attribute. This guide explains how to configure this with the `default-authentication-flow`; however, the same steps apply to any authentication flow.
|
||||
|
||||
Configuring forced password reset on next login involves the following steps:
|
||||
|
||||
1. Creating two expression policicies.
|
||||
2. Creating and binding two stages to the active authentication flow.
|
||||
3. Binding the expression policies to the stages.
|
||||
4. Setting a custom user attribute which triggers the password prompt.
|
||||
|
||||
## Create expression policies
|
||||
|
||||
You'll need to create two expression policies; one that checks the value of a custom user attribute on the user account attempting to log in, and another that resets the value of the custom user attribute.
|
||||
|
||||
1. Log in to authentik as an administrator and open the authentik Admin interface.
|
||||
2. Navigate to **Customization** > **Policies** and click **Create** to set up the first policy.
|
||||
3. Select **Expression Policy** as the policy type, click **Next**, and configure the following settings:
|
||||
- **Name**: Provide a descriptive name for the policy (e.g. `reset_password_check`).
|
||||
- **Expression**:
|
||||
|
||||
```python
|
||||
# Check if the "reset_password" attribute set to true for the pending user
|
||||
if request.context["pending_user"].attributes.get("reset_password") == True:
|
||||
return True
|
||||
|
||||
return False
|
||||
```
|
||||
|
||||
4. Click **Finish** to save the first policy, then repeat the steps to create the second policy using the following settings:
|
||||
- **Name**: Provide a descriptive name for the policy (e.g. `reset_password_update`).
|
||||
- **Expression**:
|
||||
|
||||
```python
|
||||
# Check if the "reset_password" attribute is set to true for the pending user
|
||||
if request.context["pending_user"].attributes.get("reset_password") == True:
|
||||
# Reset the "reset_password" attribute to false to prevent forcing a password reset on next login
|
||||
request.context["pending_user"].attributes["reset_password"] = False
|
||||
return True
|
||||
|
||||
return False
|
||||
```
|
||||
|
||||
5. Click **Finish**.
|
||||
|
||||
## Create stages
|
||||
|
||||
You'll need to create two stages; a _Prompt stage_ to prompt the user to enter a new password, and a _User Write stage_ to update the user's account with the new password. Both stages will need to be bound to the active authentication flow, typically the `default-authentication-flow`.
|
||||
|
||||
1. Log in to authentik as an administrator and open the authentik Admin interface.
|
||||
2. Navigate to **Flows and Stages** > **Flows** and click on the name of the active authentication flow, typically the `default-authentication-flow`.
|
||||
3. Select the **Stage Bindings** tab and click **Create and bind stage**.
|
||||
4. Select **Prompt Stage** as the stage type, click **Next**, and configure the following settings for the stage:
|
||||
- **Name**: Provide a descriptive name for the stage (e.g. `Force Password Reset Prompt Stage`).
|
||||
- Under **Fields**:
|
||||
- Click the `x` icon between **Available Fields** and **Selected Fields** to clear the selections.
|
||||
- Select `default-password-change-field-password` and `default-password-change-field-password-repeat`.
|
||||
- Under **Validation Policies**:
|
||||
- Click the `x` icon between **Available Policies** and **Selected Policies** to clear the selections.
|
||||
- _(Optional but recommended)_ Select `default-password-change-policy`.
|
||||
|
||||
:::tip
|
||||
Optionally, you can create and add a text field to the prompt stage to inform users that they are required to reset their password. For more details on configuring this, refer to the [Prompt Stage documentation](../../add-secure-apps/flows-stages/stages/prompt/index.md).
|
||||
:::
|
||||
|
||||
5. Click **Next** to create the stage and then configure the following settings for the binding:
|
||||
- **Order**: `25` or any number higher than the `default-authentication-password` stage order and lower than the `default-authentication-mfa-validation` stage order.
|
||||
- Leave the other settings as their default values.
|
||||
|
||||
6. Click **Finish** to create the binding and repeat the process for the second stage using the following settings:
|
||||
- **Stage type**: Select **User Write Stage** as the type.
|
||||
- **Name**: Provide a descriptive name for the stage (e.g. `Force Password Reset User Write Stage`).
|
||||
- Leave the other settings as their default values.
|
||||
|
||||
7. Click **Next** to create the stage and then configure the following settings for the binding:
|
||||
- **Order**: `26` or any number higher than the `Force Password Reset Prompt Stage` stage order and lower than the `default-authentication-mfa-validation` stage order.
|
||||
- Leave the other settings as their default values.
|
||||
|
||||
8. Click **Finish** to create the binding.
|
||||
|
||||
## Bind policies to stages
|
||||
|
||||
You will need to bind the previously created policies to the newly created stages. Specifically:
|
||||
|
||||
- The `reset_password_check` policy needs to be bound to the `Force Password Reset Prompt Stage`.
|
||||
- The `reset_password_update` policy needs to be bound to the `Force Password Reset User Write Stage`.
|
||||
|
||||
1. Log in to authentik as an administrator and open the authentik Admin interface.
|
||||
2. Navigate to **Flows and Stages** > **Flows** and click on the name of the active authentication flow, typically `default-authentication-flow`.
|
||||
3. Select the **Stage Bindings** tab and click the arrow next to the newly created `Force Password Reset Prompt Stage` to expand it.
|
||||
4. Click **Bind existing Policy / Group / User**.
|
||||
5. Set **Policy** to `reset_password_check` and click **Create**.
|
||||
6. Click the arrow next to the newly created `Force Password Reset User Write Stage` to expand it.
|
||||
7. Click **Bind existing Policy / Group / User**.
|
||||
8. Set **Policy** to `reset_password_update` and click **Create**.
|
||||
|
||||
## Set custom user attribute
|
||||
|
||||
To require a user to reset their password on next login, you will need to set a custom user attribute on their account.
|
||||
|
||||
1. Log in to authentik as an administrator and open the authentik Admin interface.
|
||||
2. Navigate to **Directory** > **Users** and click the **Edit** icon of the user in question.
|
||||
3. Add the following values to the user's attribute field:
|
||||
```python
|
||||
reset_password: True
|
||||
```
|
||||
4. Click **Update**.
|
||||
|
||||
The next time the user logs in, they will be required to reset their password, and the `reset_password` attribute on their account will be set to `False`.
|
||||
@@ -16,7 +16,7 @@ The User object has the following properties:
|
||||
- `password_change_date`: Date password was last changed. Read-only.
|
||||
- `path`: User's path, see [Path](#path)
|
||||
- `attributes`: Dynamic attributes, see [Attributes](#attributes)
|
||||
- `group_attributes()`: Merged attributes of all groups the user is a member of and the user's own attributes. Read-only.
|
||||
- `group_attributes()`: Merged attributes of all groups the user is member of and the user's own attributes. Ready-only.
|
||||
- `ak_groups`: This is a queryset of all the user's groups.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -13,7 +13,7 @@ support_level: community
|
||||
> -- https://nodered.org/
|
||||
|
||||
:::caution
|
||||
This requires modification of the Node-RED `settings.js` file and installing additional Passport-js packages; see [Securing Node-RED](https://nodered.org/docs/user-guide/runtime/securing-node-red#oauthopenid-based-authentication) documentation for further details.
|
||||
This requires modification of the Node-RED settings.js and installing additional Passport-js packages, see [Securing Node-RED](https://nodered.org/docs/user-guide/runtime/securing-node-red#oauthopenid-based-authentication) documentation for further details.
|
||||
:::
|
||||
|
||||
## Preparation
|
||||
@@ -66,29 +66,29 @@ Edit the node-red settings.js file `/data/settings.js` to use the external authe
|
||||
|
||||
```js
|
||||
adminAuth: {
|
||||
type:"strategy",
|
||||
strategy: {
|
||||
name: "openidconnect",
|
||||
label: 'Sign in with authentik',
|
||||
icon:"fa-cloud",
|
||||
strategy: require("passport-openidconnect").Strategy,
|
||||
options: {
|
||||
issuer: 'https://authentik.company/application/o/<application_slug>/',
|
||||
authorizationURL: 'https://authentik.company/application/o/authorize/',
|
||||
tokenURL: 'https://authentik.company/application/o/token/',
|
||||
userInfoURL: 'https://authentik.company/application/o/userinfo/',
|
||||
clientID: '<Client ID (Key): Step 2>',
|
||||
clientSecret: '<Client Secret: Step 2>',
|
||||
callbackURL: 'https://nodered.company/auth/strategy/callback/',
|
||||
scope: ['email', 'profile', 'openid'],
|
||||
proxy: true,
|
||||
verify: function(context, issuer, profile, done) {
|
||||
return done(null, profile);
|
||||
},
|
||||
}
|
||||
},
|
||||
users: function(user) {
|
||||
return Promise.resolve({ username: user, permissions: "*" });
|
||||
type:"strategy",
|
||||
strategy: {
|
||||
name: "openidconnect",
|
||||
label: 'Sign in with authentik',
|
||||
icon:"fa-cloud",
|
||||
strategy: require("passport-openidconnect").Strategy,
|
||||
options: {
|
||||
issuer: 'https://authentik.company/application/o/<application_slug>/',
|
||||
authorizationURL: 'https://authentik.company/application/o/authorize/',
|
||||
tokenURL: 'https://authentik.company/application/o/token/',
|
||||
userInfoURL: 'https://authentik.company/application/o/userinfo/',
|
||||
clientID: '<Client ID (Key): Step 2>',
|
||||
clientSecret: '<Client Secret: Step 2>',
|
||||
callbackURL: 'https://nodered.company/auth/strategy/callback/',
|
||||
scope: ['email', 'profile', 'openid'],
|
||||
proxy: true,
|
||||
verify: function(issuer, profile, done) {
|
||||
done(null, profile)
|
||||
}
|
||||
}
|
||||
},
|
||||
users: function(user) {
|
||||
return Promise.resolve({ username: user, permissions: "*" });
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
@@ -140,6 +140,54 @@ This section depends on the operating system hosting Apache Guacamole.
|
||||
More information on the keytool command can be found in the [Oracle documentation.](https://docs.oracle.com/en/java/javase/21/docs/specs/man/keytool.html)
|
||||
:::
|
||||
|
||||
### Self Signed Certificates
|
||||
|
||||
When using a self-signed certificate, it is necessary to incorporate the certificate of the corresponding Certificate Authority into both the `/etc/ssl/certs/ca-certificates.crt` file and the `/opt/java/openjkd/jre/lib/security/cacerts` keystore on your Apache Guacamole host. This ensures that the self-signed certificate is trusted by both the system and the Java runtime environment used by Guacamole.
|
||||
|
||||
#### Adding Certificate Authority certificate as trusted in `/etc/ssl/certs/ca-certificates.crt`
|
||||
|
||||
:::note
|
||||
This section depends on the operating system hosting Apache Guacamole.
|
||||
:::
|
||||
|
||||
##### For _Debian_ based operating systems:
|
||||
|
||||
1. Copy the certificate of the Certificate Authority (e.g. `<CA_certificate>.crt`) to the `/usr/local/share/ca-certificates/` directory on the Apache Guacamole host. Ensure that the file extension is `.crt`.
|
||||
|
||||
2. To add the certificate as trusted in `/etc/ssl/certs/ca-certificates.crt`, use the following command:
|
||||
|
||||
```shell
|
||||
update-ca-certificates
|
||||
```
|
||||
|
||||
##### For _Synology_ systems:
|
||||
|
||||
1. Copy the certificate of the Certificate Authority (e.g. `<CA_certificate>.crt`) to the `/usr/syno/etc/security-profile/ca-bundle-profile/ca-certificates/` directory on the Synology host. Ensure that the filetype is `.crt`.
|
||||
|
||||
2. To add the certificate as trusted in `/etc/ssl/certs/ca-certificates.crt`, use the following command:
|
||||
|
||||
```shell
|
||||
update-ca-certificates.sh
|
||||
```
|
||||
|
||||
#### Adding Certificate Authority certificate to `/opt/java/openjkd/jre/lib/security/cacerts`
|
||||
|
||||
1. To export the certificate of the Certificate Authority, use the following command on the Certificate Authority host:
|
||||
|
||||
```shell
|
||||
openssl pkcs12 -export -in <CA_certificate>.crt -inkey <CA_certificate>.key -out <CA_certificate>.p12 -passout pass:<password>
|
||||
```
|
||||
|
||||
2. To import the certificate to the `/opt/java/openjdk/jre/lib/security/cacerts` keystore on the Apache Guacamole host, use the following command:
|
||||
|
||||
```shell
|
||||
keytool -importkeystore -srckeystore <CA_certificate>.p12 -srcstoretype PKCS12 -keystore /opt/java/openjdk/jre/lib/security/cacerts -deststorepass <destination_store_password> -nopromt -srcstorepass <password>
|
||||
```
|
||||
|
||||
:::note
|
||||
More information on the keytool command can be found in the [Oracle documentation.](https://docs.oracle.com/en/java/javase/21/docs/specs/man/keytool.html)
|
||||
:::
|
||||
|
||||
## Configuration verification
|
||||
|
||||
To verify that authentik is correctly configured with Apache Guacamole, log out and log back in through authentik. You should notice a new button appearing at the bottom left of the login page.
|
||||
|
||||
188
website/package-lock.json
generated
188
website/package-lock.json
generated
@@ -19,13 +19,13 @@
|
||||
"@goauthentik/eslint-config": "^1.0.5",
|
||||
"@goauthentik/prettier-config": "^3.1.0",
|
||||
"@goauthentik/tsconfig": "^1.0.4",
|
||||
"@types/node": "^24.0.15",
|
||||
"@types/node": "^24.0.14",
|
||||
"@typescript-eslint/eslint-plugin": "^8.37.0",
|
||||
"@typescript-eslint/parser": "^8.37.0",
|
||||
"eslint": "^9.30.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-plugin-packagejson": "^2.5.19",
|
||||
"prettier-plugin-packagejson": "^2.5.18",
|
||||
"typescript-eslint": "^8.37.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -35,12 +35,12 @@
|
||||
"@rspack/binding-darwin-arm64": "1.4.8",
|
||||
"@rspack/binding-linux-arm64-gnu": "1.4.8",
|
||||
"@rspack/binding-linux-x64-gnu": "1.4.8",
|
||||
"@swc/core-darwin-arm64": "1.13.0",
|
||||
"@swc/core-linux-arm64-gnu": "1.13.0",
|
||||
"@swc/core-linux-x64-gnu": "1.13.0",
|
||||
"@swc/html-darwin-arm64": "1.13.0",
|
||||
"@swc/html-linux-arm64-gnu": "1.13.0",
|
||||
"@swc/html-linux-x64-gnu": "1.13.0",
|
||||
"@swc/core-darwin-arm64": "1.12.14",
|
||||
"@swc/core-linux-arm64-gnu": "1.12.14",
|
||||
"@swc/core-linux-x64-gnu": "1.12.14",
|
||||
"@swc/html-darwin-arm64": "1.12.14",
|
||||
"@swc/html-linux-arm64-gnu": "1.12.14",
|
||||
"@swc/html-linux-x64-gnu": "1.12.14",
|
||||
"lightningcss-darwin-arm64": "1.30.1",
|
||||
"lightningcss-linux-arm64-gnu": "1.30.1",
|
||||
"lightningcss-linux-x64-gnu": "1.30.1"
|
||||
@@ -79,12 +79,12 @@
|
||||
"@rspack/binding-darwin-arm64": "1.4.8",
|
||||
"@rspack/binding-linux-arm64-gnu": "1.4.8",
|
||||
"@rspack/binding-linux-x64-gnu": "1.4.8",
|
||||
"@swc/core-darwin-arm64": "1.13.0",
|
||||
"@swc/core-linux-arm64-gnu": "1.13.0",
|
||||
"@swc/core-linux-x64-gnu": "1.13.0",
|
||||
"@swc/html-darwin-arm64": "1.13.0",
|
||||
"@swc/html-linux-arm64-gnu": "1.13.0",
|
||||
"@swc/html-linux-x64-gnu": "1.13.0",
|
||||
"@swc/core-darwin-arm64": "1.12.14",
|
||||
"@swc/core-linux-arm64-gnu": "1.12.14",
|
||||
"@swc/core-linux-x64-gnu": "1.12.14",
|
||||
"@swc/html-darwin-arm64": "1.12.14",
|
||||
"@swc/html-linux-arm64-gnu": "1.12.14",
|
||||
"@swc/html-linux-x64-gnu": "1.12.14",
|
||||
"lightningcss-darwin-arm64": "1.30.1",
|
||||
"lightningcss-linux-arm64-gnu": "1.30.1",
|
||||
"lightningcss-linux-x64-gnu": "1.30.1"
|
||||
@@ -6584,9 +6584,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@pkgr/core": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz",
|
||||
"integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==",
|
||||
"version": "0.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.7.tgz",
|
||||
"integrity": "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
|
||||
@@ -7269,9 +7269,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-darwin-arm64": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.13.0.tgz",
|
||||
"integrity": "sha512-SkmR9u7MHDu2X8hf7SjZTmsAfQTmel0mi+TJ7AGtufLwGySv6pwQfJ/CIJpcPxYENVqDJAFnDrHaKV8mgA6kxQ==",
|
||||
"version": "1.12.14",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.12.14.tgz",
|
||||
"integrity": "sha512-HNukQoOKgMsHSETj8vgGGKK3SEcH7Cz6k4bpntCxBKNkO3sH7RcBTDulWGGHJfZaDNix7Rw2ExUVWtLZlzkzXg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -7317,9 +7317,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm64-gnu": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.13.0.tgz",
|
||||
"integrity": "sha512-qyZmBZF7asF6954/x7yn6R7Bzd45KRG05rK2atIF9J3MTa8az7vubP1Q3BWmmss1j8699DELpbuoJucGuhsNXw==",
|
||||
"version": "1.12.14",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.12.14.tgz",
|
||||
"integrity": "sha512-akUAe1YrBqZf1EDdUxahQ8QZnJi8Ts6Ya0jf6GBIMvnXL4Y6QIuvKTRwfNxy7rJ+x9zpzP1Vlh14ZZkSKZ1EGA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -7349,9 +7349,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-x64-gnu": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.13.0.tgz",
|
||||
"integrity": "sha512-51n4P4nv6rblXyH3zCEktvmR9uSAZ7+zbfeby0sxbj8LS/IKuVd7iCwD5dwMj4CxG9Fs+HgjN73dLQF/OerHhg==",
|
||||
"version": "1.12.14",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.12.14.tgz",
|
||||
"integrity": "sha512-71EPPccwJiJUxd2aMwNlTfom2mqWEWYGdbeTju01tzSHsEuD7E6ePlgC3P3ngBqB3urj41qKs87z7zPOswT5Iw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -7428,54 +7428,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core/node_modules/@swc/core-darwin-arm64": {
|
||||
"version": "1.12.14",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.12.14.tgz",
|
||||
"integrity": "sha512-HNukQoOKgMsHSETj8vgGGKK3SEcH7Cz6k4bpntCxBKNkO3sH7RcBTDulWGGHJfZaDNix7Rw2ExUVWtLZlzkzXg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core/node_modules/@swc/core-linux-arm64-gnu": {
|
||||
"version": "1.12.14",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.12.14.tgz",
|
||||
"integrity": "sha512-akUAe1YrBqZf1EDdUxahQ8QZnJi8Ts6Ya0jf6GBIMvnXL4Y6QIuvKTRwfNxy7rJ+x9zpzP1Vlh14ZZkSKZ1EGA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core/node_modules/@swc/core-linux-x64-gnu": {
|
||||
"version": "1.12.14",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.12.14.tgz",
|
||||
"integrity": "sha512-71EPPccwJiJUxd2aMwNlTfom2mqWEWYGdbeTju01tzSHsEuD7E6ePlgC3P3ngBqB3urj41qKs87z7zPOswT5Iw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/counter": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
|
||||
@@ -7507,9 +7459,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/html-darwin-arm64": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@swc/html-darwin-arm64/-/html-darwin-arm64-1.13.0.tgz",
|
||||
"integrity": "sha512-tRAScqaFehYDugB3F+eWiEvsWpL+2broMrt7amY6lN6Eemu2VSL91KykvaiaBXhmhJFL9Z2kFHgV3jD4lCTUcA==",
|
||||
"version": "1.12.14",
|
||||
"resolved": "https://registry.npmjs.org/@swc/html-darwin-arm64/-/html-darwin-arm64-1.12.14.tgz",
|
||||
"integrity": "sha512-qbZBSd2oalqBxGfVwpgT9I7gaCleL05XjuatMZIca94QhvLp0+FhCNqujrdq6Ggcrlk8IVoxtsVS5GTeDH5jAw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -7555,9 +7507,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/html-linux-arm64-gnu": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@swc/html-linux-arm64-gnu/-/html-linux-arm64-gnu-1.13.0.tgz",
|
||||
"integrity": "sha512-ppau7AB47WasAsTKjUlLdK40hpAPKkFMoaY2IgDhM5Qdi4H84sPf5z7AcXupMnTEm4QmFM2qZBXGNnxIp1W0sg==",
|
||||
"version": "1.12.14",
|
||||
"resolved": "https://registry.npmjs.org/@swc/html-linux-arm64-gnu/-/html-linux-arm64-gnu-1.12.14.tgz",
|
||||
"integrity": "sha512-wjUyMqxYSp/NGEXwdyEVfE/P/1DNt090KGEM/UbH55i1oyIYqq4T+FJacn7ITtypJp4lYQ7s7Bb5bB/BX+TZ1w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -7587,9 +7539,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/html-linux-x64-gnu": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@swc/html-linux-x64-gnu/-/html-linux-x64-gnu-1.13.0.tgz",
|
||||
"integrity": "sha512-9UNYdUt4n/LG2VxLNtCXkEjZNPj2yQuo6Z/F93+12qlueG2GUVSDuN1d/M/WogZq1uthRbwjF2QQbsrTVhXOHA==",
|
||||
"version": "1.12.14",
|
||||
"resolved": "https://registry.npmjs.org/@swc/html-linux-x64-gnu/-/html-linux-x64-gnu-1.12.14.tgz",
|
||||
"integrity": "sha512-oLqGIB9u7X+SI0Zu2kxAOgAzEOr53n030esUcXzwGRn0BzCxAF2NaQav9HwKrCboQfK3SDtVGx/7Hy7metgacA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -7666,54 +7618,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/html/node_modules/@swc/html-darwin-arm64": {
|
||||
"version": "1.12.14",
|
||||
"resolved": "https://registry.npmjs.org/@swc/html-darwin-arm64/-/html-darwin-arm64-1.12.14.tgz",
|
||||
"integrity": "sha512-qbZBSd2oalqBxGfVwpgT9I7gaCleL05XjuatMZIca94QhvLp0+FhCNqujrdq6Ggcrlk8IVoxtsVS5GTeDH5jAw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/html/node_modules/@swc/html-linux-arm64-gnu": {
|
||||
"version": "1.12.14",
|
||||
"resolved": "https://registry.npmjs.org/@swc/html-linux-arm64-gnu/-/html-linux-arm64-gnu-1.12.14.tgz",
|
||||
"integrity": "sha512-wjUyMqxYSp/NGEXwdyEVfE/P/1DNt090KGEM/UbH55i1oyIYqq4T+FJacn7ITtypJp4lYQ7s7Bb5bB/BX+TZ1w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/html/node_modules/@swc/html-linux-x64-gnu": {
|
||||
"version": "1.12.14",
|
||||
"resolved": "https://registry.npmjs.org/@swc/html-linux-x64-gnu/-/html-linux-x64-gnu-1.12.14.tgz",
|
||||
"integrity": "sha512-oLqGIB9u7X+SI0Zu2kxAOgAzEOr53n030esUcXzwGRn0BzCxAF2NaQav9HwKrCboQfK3SDtVGx/7Hy7metgacA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/types": {
|
||||
"version": "0.1.23",
|
||||
"resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.23.tgz",
|
||||
@@ -8254,9 +8158,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "24.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.15.tgz",
|
||||
"integrity": "sha512-oaeTSbCef7U/z7rDeJA138xpG3NuKc64/rZ2qmUFkFJmnMsAPaluIifqyWd8hSSMxyP9oie3dLAqYPblag9KgA==",
|
||||
"version": "24.0.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.14.tgz",
|
||||
"integrity": "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~7.8.0"
|
||||
@@ -23859,13 +23763,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier-plugin-packagejson": {
|
||||
"version": "2.5.19",
|
||||
"resolved": "https://registry.npmjs.org/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.19.tgz",
|
||||
"integrity": "sha512-Qsqp4+jsZbKMpEGZB1UP1pxeAT8sCzne2IwnKkr+QhUe665EXUo3BAvTf1kAPCqyMv9kg3ZmO0+7eOni/C6Uag==",
|
||||
"version": "2.5.18",
|
||||
"resolved": "https://registry.npmjs.org/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.18.tgz",
|
||||
"integrity": "sha512-NKznPGcGrcj4NPGxnh+w78JXPyfB6I4RQSCM0v+CAXwpDG7OEpJQ5zMyfC5NBgKH1k7Skwcj5ak5by2mrHvC5g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"sort-package-json": "3.4.0",
|
||||
"synckit": "0.11.11"
|
||||
"synckit": "0.11.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"prettier": ">= 1.16.0"
|
||||
@@ -27565,12 +27469,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/synckit": {
|
||||
"version": "0.11.11",
|
||||
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz",
|
||||
"integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==",
|
||||
"version": "0.11.8",
|
||||
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.8.tgz",
|
||||
"integrity": "sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@pkgr/core": "^0.2.9"
|
||||
"@pkgr/core": "^0.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18.0 || >=16.0.0"
|
||||
|
||||
@@ -24,25 +24,25 @@
|
||||
"@goauthentik/eslint-config": "^1.0.5",
|
||||
"@goauthentik/prettier-config": "^3.1.0",
|
||||
"@goauthentik/tsconfig": "^1.0.4",
|
||||
"@types/node": "^24.0.15",
|
||||
"@types/node": "^24.0.14",
|
||||
"@typescript-eslint/eslint-plugin": "^8.37.0",
|
||||
"@typescript-eslint/parser": "^8.37.0",
|
||||
"eslint": "^9.30.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-plugin-packagejson": "^2.5.19",
|
||||
"prettier-plugin-packagejson": "^2.5.18",
|
||||
"typescript-eslint": "^8.37.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rspack/binding-darwin-arm64": "1.4.8",
|
||||
"@rspack/binding-linux-arm64-gnu": "1.4.8",
|
||||
"@rspack/binding-linux-x64-gnu": "1.4.8",
|
||||
"@swc/core-darwin-arm64": "1.13.0",
|
||||
"@swc/core-linux-arm64-gnu": "1.13.0",
|
||||
"@swc/core-linux-x64-gnu": "1.13.0",
|
||||
"@swc/html-darwin-arm64": "1.13.0",
|
||||
"@swc/html-linux-arm64-gnu": "1.13.0",
|
||||
"@swc/html-linux-x64-gnu": "1.13.0",
|
||||
"@swc/core-darwin-arm64": "1.12.14",
|
||||
"@swc/core-linux-arm64-gnu": "1.12.14",
|
||||
"@swc/core-linux-x64-gnu": "1.12.14",
|
||||
"@swc/html-darwin-arm64": "1.12.14",
|
||||
"@swc/html-linux-arm64-gnu": "1.12.14",
|
||||
"@swc/html-linux-x64-gnu": "1.12.14",
|
||||
"lightningcss-darwin-arm64": "1.30.1",
|
||||
"lightningcss-linux-arm64-gnu": "1.30.1",
|
||||
"lightningcss-linux-x64-gnu": "1.30.1"
|
||||
|
||||
Reference in New Issue
Block a user