Compare commits

..

5 Commits

765 changed files with 7423 additions and 20786 deletions

View File

@ -36,7 +36,7 @@ runs:
with:
go-version-file: "go.mod"
- name: Setup docker cache
uses: AndreKurait/docker-cache@0fe76702a40db986d9663c24954fc14c6a6031b7
uses: ScribeMD/docker-cache@0.5.0
with:
key: docker-images-${{ runner.os }}-${{ hashFiles('.github/actions/setup/docker-compose.yml', 'Makefile') }}-${{ inputs.postgresql_version }}
- name: Setup dependencies

View File

@ -62,7 +62,6 @@ jobs:
psql:
- 15-alpine
- 16-alpine
- 17-alpine
run_id: [1, 2, 3, 4, 5]
steps:
- uses: actions/checkout@v4
@ -117,7 +116,6 @@ jobs:
psql:
- 15-alpine
- 16-alpine
- 17-alpine
run_id: [1, 2, 3, 4, 5]
steps:
- uses: actions/checkout@v4

View File

@ -7,7 +7,7 @@ on:
- packages/eslint-config/**
- packages/prettier-config/**
- packages/tsconfig/**
- web/packages/esbuild-plugin-live-reload/**
- packages/web/esbuild-plugin-live-reload/**
workflow_dispatch:
jobs:
publish:
@ -17,28 +17,27 @@ jobs:
fail-fast: false
matrix:
package:
- packages/docusaurus-config
- packages/eslint-config
- packages/prettier-config
- packages/tsconfig
- web/packages/esbuild-plugin-live-reload
- docusaurus-config
- eslint-config
- prettier-config
- tsconfig
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- uses: actions/setup-node@v4
with:
node-version-file: ${{ matrix.package }}/package.json
node-version-file: packages/${{ matrix.package }}/package.json
registry-url: "https://registry.npmjs.org"
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c
with:
files: |
${{ matrix.package }}/package.json
packages/${{ matrix.package }}/package.json
- name: Publish package
if: steps.changed-files.outputs.any_changed == 'true'
working-directory: ${{ matrix.package }}
working-directory: packages/${{ matrix.package}}
run: |
npm ci
npm run build

View File

@ -94,7 +94,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 5: Download uv
FROM ghcr.io/astral-sh/uv:0.7.8 AS uv
FROM ghcr.io/astral-sh/uv:0.7.7 AS uv
# Stage 6: Base python image
FROM ghcr.io/goauthentik/fips-python:3.13.3-slim-bookworm-fips AS python-base

View File

@ -1,6 +1,6 @@
.PHONY: gen dev-reset all clean test web website
SHELL := /usr/bin/env bash
SHELL := /bin/bash
.SHELLFLAGS += ${SHELLFLAGS} -e -o pipefail
PWD = $(shell pwd)
UID = $(shell id -u)

View File

@ -84,7 +84,6 @@ from authentik.flows.views.executor import QS_KEY_TOKEN
from authentik.lib.avatars import get_avatar
from authentik.rbac.decorators import permission_required
from authentik.rbac.models import get_permission_choices
from authentik.stages.email.flow import pickle_flow_token_for_email
from authentik.stages.email.models import EmailStage
from authentik.stages.email.tasks import send_mails
from authentik.stages.email.utils import TemplateEmailMessage
@ -452,7 +451,7 @@ class UserViewSet(UsedByMixin, ModelViewSet):
def list(self, request, *args, **kwargs):
return super().list(request, *args, **kwargs)
def _create_recovery_link(self, for_email=False) -> tuple[str, Token]:
def _create_recovery_link(self) -> 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
@ -474,16 +473,12 @@ class UserViewSet(UsedByMixin, ModelViewSet):
raise ValidationError(
{"non_field_errors": "Recovery flow not applicable to user"}
) from None
_plan = FlowToken.pickle(plan)
if for_email:
_plan = pickle_flow_token_for_email(plan)
token, __ = FlowToken.objects.update_or_create(
identifier=f"{user.uid}-password-reset",
defaults={
"user": user,
"flow": flow,
"_plan": _plan,
"revoke_on_execution": not for_email,
"_plan": FlowToken.pickle(plan),
},
)
querystring = urlencode({QS_KEY_TOKEN: token.key})
@ -653,7 +648,7 @@ class UserViewSet(UsedByMixin, ModelViewSet):
if for_user.email == "":
LOGGER.debug("User doesn't have an email address")
raise ValidationError({"non_field_errors": "User does not have an email address set."})
link, token = self._create_recovery_link(for_email=True)
link, token = self._create_recovery_link()
# Lookup the email stage to assure the current user can access it
stages = get_objects_for_user(
request.user, "authentik_stages_email.view_emailstage"

View File

@ -1,12 +0,0 @@
"""authentik endpoints app config"""
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikEndpointsConfig(ManagedAppConfig):
"""authentik endpoints app config"""
name = "authentik.endpoints"
label = "authentik_endpoints"
verbose_name = "authentik Endpoints"
default = True

View File

@ -1,47 +0,0 @@
from enum import Enum
from pydantic import BaseModel
class UNSUPPORTED(BaseModel):
pass
class OSFamily(Enum):
linux = "linux"
unix = "unix"
bsd = "bsd"
windows = "windows"
macOS = "mac_os"
android = "android"
iOS = "i_os"
other = "other"
class CommonDeviceData(BaseModel):
class Disk(BaseModel):
encryption: bool
class OS(BaseModel):
firewall_enabled: bool
family: OSFamily
name: str
version: str
class Network(BaseModel):
hostname: str
dns_servers: list[str]
class Hardware(BaseModel):
model: str
manufacturer: str
class Software(BaseModel):
name: str
version: str
os: OS | UNSUPPORTED
disks: list[Disk] | UNSUPPORTED
network: Network | UNSUPPORTED
hardware: Hardware | UNSUPPORTED
software: list[Software] | UNSUPPORTED

View File

@ -1,16 +0,0 @@
from authentik.blueprints import models
class EnrollmentMethods(models.TextChoices):
AUTOMATIC_USER = "automatic_user" # Automatically enrolled through user action
AUTOMATIC_API = "automatic_api" # Automatically enrolled through connector integration
MANUAL_USER = "manual_user" # Manually enrolled
class BaseConnector:
def __init__(self) -> None:
pass
def supported_enrollment_methods(self) -> list[EnrollmentMethods]:
return []

View File

@ -1,7 +0,0 @@
from authentik.endpoints.connector import BaseConnector, EnrollmentMethods
class GoogleChromeConnector(BaseConnector):
def supported_enrollment_methods(self) -> list[EnrollmentMethods]:
return [EnrollmentMethods.AUTOMATIC_USER]

View File

@ -1,7 +0,0 @@
from django.db import models
from authentik.endpoints.models import Connector
class GoogleChromeConnector(Connector):
credentials = models.JSONField()

View File

@ -1,125 +0,0 @@
# Generated by Django 5.0.9 on 2024-09-24 19:16
import django.db.models.deletion
import uuid
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name="Connector",
fields=[
(
"id",
models.AutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
("connector_uuid", models.UUIDField(default=uuid.uuid4)),
("name", models.TextField()),
(
"enrollment_method",
models.TextField(
choices=[
("automatic_user", "Automatic User"),
("automatic_api", "Automatic Api"),
("manual_user", "Manual User"),
]
),
),
],
options={
"abstract": False,
},
),
migrations.CreateModel(
name="Device",
fields=[
(
"id",
models.AutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
("device_uuid", models.UUIDField(default=uuid.uuid4)),
("identifier", models.TextField(unique=True)),
],
options={
"abstract": False,
},
),
migrations.CreateModel(
name="DeviceConnection",
fields=[
(
"id",
models.AutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
("device_connection_uuid", models.UUIDField(default=uuid.uuid4)),
("data", models.JSONField(default=dict)),
(
"connection",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="authentik_endpoints.connector",
),
),
(
"device",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="authentik_endpoints.device"
),
),
],
),
migrations.AddField(
model_name="device",
name="connections",
field=models.ManyToManyField(
through="authentik_endpoints.DeviceConnection", to="authentik_endpoints.connector"
),
),
migrations.CreateModel(
name="DeviceUser",
fields=[
(
"id",
models.AutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
("device_user_uuid", models.UUIDField(default=uuid.uuid4)),
("is_primary", models.BooleanField()),
(
"device",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="authentik_endpoints.device"
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
),
),
],
),
migrations.AddField(
model_name="device",
name="users",
field=models.ManyToManyField(
through="authentik_endpoints.DeviceUser", to=settings.AUTH_USER_MODEL
),
),
]

View File

@ -1,40 +0,0 @@
from uuid import uuid4
from django.db import models
from django.utils.functional import cached_property
from authentik.core.models import User
from authentik.endpoints.common_data import CommonDeviceData
from authentik.lib.models import SerializerModel
class Device(SerializerModel):
device_uuid = models.UUIDField(default=uuid4)
identifier = models.TextField(unique=True)
users = models.ManyToManyField(User, through="DeviceUser")
connections = models.ManyToManyField("Connector", through="DeviceConnection")
@cached_property
def data(self) -> CommonDeviceData:
pass
class DeviceUser(models.Model):
device_user_uuid = models.UUIDField(default=uuid4)
device = models.ForeignKey("Device", on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
is_primary = models.BooleanField()
class DeviceConnection(models.Model):
device_connection_uuid = models.UUIDField(default=uuid4)
device = models.ForeignKey("Device", on_delete=models.CASCADE)
connection = models.ForeignKey("Connector", on_delete=models.CASCADE)
data = models.JSONField(default=dict)
class Connector(SerializerModel):
connector_uuid = models.UUIDField(default=uuid4)
name = models.TextField()

View File

@ -1,18 +0,0 @@
# Generated by Django 5.1.9 on 2025-05-27 12:52
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_flows", "0027_auto_20231028_1424"),
]
operations = [
migrations.AddField(
model_name="flowtoken",
name="revoke_on_execution",
field=models.BooleanField(default=True),
),
]

View File

@ -303,10 +303,9 @@ class FlowToken(Token):
flow = models.ForeignKey(Flow, on_delete=models.CASCADE)
_plan = models.TextField()
revoke_on_execution = models.BooleanField(default=True)
@staticmethod
def pickle(plan: "FlowPlan") -> str:
def pickle(plan) -> str:
"""Pickle into string"""
data = dumps(plan)
return b64encode(data).decode()

View File

@ -99,10 +99,9 @@ class ChallengeStageView(StageView):
self.logger.debug("Got StageInvalidException", exc=exc)
return self.executor.stage_invalid()
if not challenge.is_valid():
self.logger.error(
self.logger.warning(
"f(ch): Invalid challenge",
errors=challenge.errors,
challenge=challenge.data,
)
return HttpChallengeResponse(challenge)

View File

@ -146,8 +146,7 @@ class FlowExecutorView(APIView):
except (AttributeError, EOFError, ImportError, IndexError) as exc:
LOGGER.warning("f(exec): Failed to restore token plan", exc=exc)
finally:
if token.revoke_on_execution:
token.delete()
token.delete()
if not isinstance(plan, FlowPlan):
return None
plan.context[PLAN_CONTEXT_IS_RESTORED] = token

View File

@ -1,7 +1,6 @@
from collections.abc import Callable
from dataclasses import asdict
from celery import group
from celery.exceptions import Retry
from celery.result import allow_join_result
from django.core.paginator import Paginator
@ -83,41 +82,21 @@ class SyncTasks:
self.logger.debug("Failed to acquire sync lock, skipping", provider=provider.name)
return
try:
messages.append(_("Syncing users"))
user_results = (
group(
[
sync_objects.signature(
args=(class_to_path(User), page, provider_pk),
time_limit=PAGE_TIMEOUT,
soft_time_limit=PAGE_TIMEOUT,
)
for page in users_paginator.page_range
]
)
.apply_async()
.get()
)
for result in user_results:
for msg in result:
for page in users_paginator.page_range:
messages.append(_("Syncing page {page} of users".format(page=page)))
for msg in sync_objects.apply_async(
args=(class_to_path(User), page, provider_pk),
time_limit=PAGE_TIMEOUT,
soft_time_limit=PAGE_TIMEOUT,
).get():
messages.append(LogEvent(**msg))
messages.append(_("Syncing groups"))
group_results = (
group(
[
sync_objects.signature(
args=(class_to_path(Group), page, provider_pk),
time_limit=PAGE_TIMEOUT,
soft_time_limit=PAGE_TIMEOUT,
)
for page in groups_paginator.page_range
]
)
.apply_async()
.get()
)
for result in group_results:
for msg in result:
for page in groups_paginator.page_range:
messages.append(_("Syncing page {page} of groups".format(page=page)))
for msg in sync_objects.apply_async(
args=(class_to_path(Group), page, provider_pk),
time_limit=PAGE_TIMEOUT,
soft_time_limit=PAGE_TIMEOUT,
).get():
messages.append(LogEvent(**msg))
except TransientSyncException as exc:
self.logger.warning("transient sync exception", exc=exc)
@ -153,15 +132,6 @@ class SyncTasks:
self.logger.debug("starting discover")
client.discover()
self.logger.debug("starting sync for page", page=page)
messages.append(
asdict(
LogEvent(
_("Syncing page {page} of groups".format(page=page)),
log_level="info",
logger=f"{provider._meta.verbose_name}@{object_type}",
)
)
)
for obj in paginator.page(page).object_list:
obj: Model
try:

View File

@ -384,7 +384,7 @@ class SCIMUserTests(TestCase):
self.assertIn(request.method, SAFE_METHODS)
task = SystemTask.objects.filter(uid=slugify(self.provider.name)).first()
self.assertIsNotNone(task)
drop_msg = task.messages[3]
drop_msg = task.messages[2]
self.assertEqual(drop_msg["event"], "Dropping mutating request due to dry run")
self.assertIsNotNone(drop_msg["attributes"]["url"])
self.assertIsNotNone(drop_msg["attributes"]["body"])

View File

@ -73,7 +73,6 @@ TENANT_APPS = [
"authentik.admin",
"authentik.api",
"authentik.crypto",
"authentik.endpoints",
"authentik.flows",
"authentik.outposts",
"authentik.policies.dummy",
@ -425,7 +424,7 @@ else:
"BACKEND": "authentik.root.storages.FileStorage",
"OPTIONS": {
"location": Path(CONFIG.get("storage.media.file.path")),
"base_url": CONFIG.get("web.path", "/") + "media/",
"base_url": "/media/",
},
}
# Compatibility for apps not supporting top-level STORAGES

View File

@ -31,8 +31,6 @@ class PytestTestRunner(DiscoverRunner): # pragma: no cover
if kwargs.get("randomly_seed", None):
self.args.append(f"--randomly-seed={kwargs['randomly_seed']}")
if kwargs.get("no_capture", False):
self.args.append("--capture=no")
settings.TEST = True
settings.CELERY["task_always_eager"] = True
@ -66,11 +64,6 @@ class PytestTestRunner(DiscoverRunner): # pragma: no cover
"Default behaviour: use random.Random().getrandbits(32), so the seed is"
"different on each run.",
)
parser.add_argument(
"--no-capture",
action="store_true",
help="Disable any capturing of stdout/stderr during tests.",
)
def run_tests(self, test_labels, extra_tests=None, **kwargs):
"""Run pytest and return the exitcode.

View File

@ -111,7 +111,6 @@ class LDAPSourceSerializer(SourceSerializer):
"sync_parent_group",
"connectivity",
"lookup_groups_from_user",
"delete_not_found_objects",
]
extra_kwargs = {"bind_password": {"write_only": True}}
@ -148,7 +147,6 @@ class LDAPSourceViewSet(UsedByMixin, ModelViewSet):
"user_property_mappings",
"group_property_mappings",
"lookup_groups_from_user",
"delete_not_found_objects",
]
search_fields = ["name", "slug"]
ordering = ["name"]

View File

@ -1,48 +0,0 @@
# Generated by Django 5.1.9 on 2025-05-28 08:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_core", "0048_delete_oldauthenticatedsession_content_type"),
("authentik_sources_ldap", "0008_groupldapsourceconnection_userldapsourceconnection"),
]
operations = [
migrations.AddField(
model_name="groupldapsourceconnection",
name="validated_by",
field=models.UUIDField(
blank=True,
help_text="Unique ID used while checking if this object still exists in the directory.",
null=True,
),
),
migrations.AddField(
model_name="ldapsource",
name="delete_not_found_objects",
field=models.BooleanField(
default=False,
help_text="Delete authentik users and groups which were previously supplied by this source, but are now missing from it.",
),
),
migrations.AddField(
model_name="userldapsourceconnection",
name="validated_by",
field=models.UUIDField(
blank=True,
help_text="Unique ID used while checking if this object still exists in the directory.",
null=True,
),
),
migrations.AddIndex(
model_name="groupldapsourceconnection",
index=models.Index(fields=["validated_by"], name="authentik_s_validat_b70447_idx"),
),
migrations.AddIndex(
model_name="userldapsourceconnection",
index=models.Index(fields=["validated_by"], name="authentik_s_validat_ff2ebc_idx"),
),
]

View File

@ -137,14 +137,6 @@ class LDAPSource(Source):
),
)
delete_not_found_objects = models.BooleanField(
default=False,
help_text=_(
"Delete authentik users and groups which were previously supplied by this source, "
"but are now missing from it."
),
)
@property
def component(self) -> str:
return "ak-source-ldap-form"
@ -329,12 +321,6 @@ class LDAPSourcePropertyMapping(PropertyMapping):
class UserLDAPSourceConnection(UserSourceConnection):
validated_by = models.UUIDField(
null=True,
blank=True,
help_text=_("Unique ID used while checking if this object still exists in the directory."),
)
@property
def serializer(self) -> type[Serializer]:
from authentik.sources.ldap.api import (
@ -346,18 +332,9 @@ class UserLDAPSourceConnection(UserSourceConnection):
class Meta:
verbose_name = _("User LDAP Source Connection")
verbose_name_plural = _("User LDAP Source Connections")
indexes = [
models.Index(fields=["validated_by"]),
]
class GroupLDAPSourceConnection(GroupSourceConnection):
validated_by = models.UUIDField(
null=True,
blank=True,
help_text=_("Unique ID used while checking if this object still exists in the directory."),
)
@property
def serializer(self) -> type[Serializer]:
from authentik.sources.ldap.api import (
@ -369,6 +346,3 @@ class GroupLDAPSourceConnection(GroupSourceConnection):
class Meta:
verbose_name = _("Group LDAP Source Connection")
verbose_name_plural = _("Group LDAP Source Connections")
indexes = [
models.Index(fields=["validated_by"]),
]

View File

@ -9,7 +9,7 @@ from structlog.stdlib import BoundLogger, get_logger
from authentik.core.sources.mapper import SourceMapper
from authentik.lib.config import CONFIG
from authentik.lib.sync.mapper import PropertyMappingManager
from authentik.sources.ldap.models import LDAPSource, flatten
from authentik.sources.ldap.models import LDAPSource
class BaseLDAPSynchronizer:
@ -77,16 +77,6 @@ class BaseLDAPSynchronizer:
"""Get objects from LDAP, implemented in subclass"""
raise NotImplementedError()
def get_attributes(self, object):
if "attributes" not in object:
return
return object.get("attributes", {})
def get_identifier(self, attributes: dict):
if not attributes.get(self._source.object_uniqueness_field):
return
return flatten(attributes[self._source.object_uniqueness_field])
def search_paginator( # noqa: PLR0913
self,
search_base,

View File

@ -1,61 +0,0 @@
from collections.abc import Generator
from itertools import batched
from uuid import uuid4
from ldap3 import SUBTREE
from authentik.core.models import Group
from authentik.sources.ldap.models import GroupLDAPSourceConnection
from authentik.sources.ldap.sync.base import BaseLDAPSynchronizer
from authentik.sources.ldap.sync.forward_delete_users import DELETE_CHUNK_SIZE, UPDATE_CHUNK_SIZE
class GroupLDAPForwardDeletion(BaseLDAPSynchronizer):
"""Delete LDAP Groups from authentik"""
@staticmethod
def name() -> str:
return "group_deletions"
def get_objects(self, **kwargs) -> Generator:
if not self._source.sync_groups or not self._source.delete_not_found_objects:
self.message("Group syncing is disabled for this Source")
return iter(())
uuid = uuid4()
groups = self._source.connection().extend.standard.paged_search(
search_base=self.base_dn_groups,
search_filter=self._source.group_object_filter,
search_scope=SUBTREE,
attributes=[self._source.object_uniqueness_field],
generator=True,
**kwargs,
)
for batch in batched(groups, UPDATE_CHUNK_SIZE, strict=False):
identifiers = []
for group in batch:
if not (attributes := self.get_attributes(group)):
continue
if identifier := self.get_identifier(attributes):
identifiers.append(identifier)
GroupLDAPSourceConnection.objects.filter(identifier__in=identifiers).update(
validated_by=uuid
)
return batched(
GroupLDAPSourceConnection.objects.filter(source=self._source)
.exclude(validated_by=uuid)
.values_list("group", flat=True)
.iterator(chunk_size=DELETE_CHUNK_SIZE),
DELETE_CHUNK_SIZE,
strict=False,
)
def sync(self, group_pks: tuple) -> int:
"""Delete authentik groups"""
if not self._source.sync_groups or not self._source.delete_not_found_objects:
self.message("Group syncing is disabled for this Source")
return -1
self._logger.debug("Deleting groups", group_pks=group_pks)
_, deleted_per_type = Group.objects.filter(pk__in=group_pks).delete()
return deleted_per_type.get(Group._meta.label, 0)

View File

@ -1,63 +0,0 @@
from collections.abc import Generator
from itertools import batched
from uuid import uuid4
from ldap3 import SUBTREE
from authentik.core.models import User
from authentik.sources.ldap.models import UserLDAPSourceConnection
from authentik.sources.ldap.sync.base import BaseLDAPSynchronizer
UPDATE_CHUNK_SIZE = 10_000
DELETE_CHUNK_SIZE = 50
class UserLDAPForwardDeletion(BaseLDAPSynchronizer):
"""Delete LDAP Users from authentik"""
@staticmethod
def name() -> str:
return "user_deletions"
def get_objects(self, **kwargs) -> Generator:
if not self._source.sync_users or not self._source.delete_not_found_objects:
self.message("User syncing is disabled for this Source")
return iter(())
uuid = uuid4()
users = self._source.connection().extend.standard.paged_search(
search_base=self.base_dn_users,
search_filter=self._source.user_object_filter,
search_scope=SUBTREE,
attributes=[self._source.object_uniqueness_field],
generator=True,
**kwargs,
)
for batch in batched(users, UPDATE_CHUNK_SIZE, strict=False):
identifiers = []
for user in batch:
if not (attributes := self.get_attributes(user)):
continue
if identifier := self.get_identifier(attributes):
identifiers.append(identifier)
UserLDAPSourceConnection.objects.filter(identifier__in=identifiers).update(
validated_by=uuid
)
return batched(
UserLDAPSourceConnection.objects.filter(source=self._source)
.exclude(validated_by=uuid)
.values_list("user", flat=True)
.iterator(chunk_size=DELETE_CHUNK_SIZE),
DELETE_CHUNK_SIZE,
strict=False,
)
def sync(self, user_pks: tuple) -> int:
"""Delete authentik users"""
if not self._source.sync_users or not self._source.delete_not_found_objects:
self.message("User syncing is disabled for this Source")
return -1
self._logger.debug("Deleting users", user_pks=user_pks)
_, deleted_per_type = User.objects.filter(pk__in=user_pks).delete()
return deleted_per_type.get(User._meta.label, 0)

View File

@ -58,16 +58,18 @@ class GroupLDAPSynchronizer(BaseLDAPSynchronizer):
return -1
group_count = 0
for group in page_data:
if (attributes := self.get_attributes(group)) is None:
if "attributes" not in group:
continue
attributes = group.get("attributes", {})
group_dn = flatten(flatten(group.get("entryDN", group.get("dn"))))
if not (uniq := self.get_identifier(attributes)):
if not attributes.get(self._source.object_uniqueness_field):
self.message(
f"Uniqueness field not found/not set in attributes: '{group_dn}'",
attributes=attributes.keys(),
dn=group_dn,
)
continue
uniq = flatten(attributes[self._source.object_uniqueness_field])
try:
defaults = {
k: flatten(v)

View File

@ -63,9 +63,9 @@ class MembershipLDAPSynchronizer(BaseLDAPSynchronizer):
group_member_dn = group_member.get("dn", {})
members.append(group_member_dn)
else:
if (attributes := self.get_attributes(group)) is None:
if "attributes" not in group:
continue
members = attributes.get(self._source.group_membership_field, [])
members = group.get("attributes", {}).get(self._source.group_membership_field, [])
ak_group = self.get_group(group)
if not ak_group:

View File

@ -60,16 +60,18 @@ class UserLDAPSynchronizer(BaseLDAPSynchronizer):
return -1
user_count = 0
for user in page_data:
if (attributes := self.get_attributes(user)) is None:
if "attributes" not in user:
continue
attributes = user.get("attributes", {})
user_dn = flatten(user.get("entryDN", user.get("dn")))
if not (uniq := self.get_identifier(attributes)):
if not attributes.get(self._source.object_uniqueness_field):
self.message(
f"Uniqueness field not found/not set in attributes: '{user_dn}'",
attributes=attributes.keys(),
dn=user_dn,
)
continue
uniq = flatten(attributes[self._source.object_uniqueness_field])
try:
defaults = {
k: flatten(v)

View File

@ -17,8 +17,6 @@ from authentik.lib.utils.reflection import class_to_path, path_to_class
from authentik.root.celery import CELERY_APP
from authentik.sources.ldap.models import LDAPSource
from authentik.sources.ldap.sync.base import BaseLDAPSynchronizer
from authentik.sources.ldap.sync.forward_delete_groups import GroupLDAPForwardDeletion
from authentik.sources.ldap.sync.forward_delete_users import UserLDAPForwardDeletion
from authentik.sources.ldap.sync.groups import GroupLDAPSynchronizer
from authentik.sources.ldap.sync.membership import MembershipLDAPSynchronizer
from authentik.sources.ldap.sync.users import UserLDAPSynchronizer
@ -54,11 +52,11 @@ def ldap_connectivity_check(pk: str | None = None):
@CELERY_APP.task(
# We take the configured hours timeout time by 3.5 as we run user and
# group in parallel and then membership, then deletions, so 3x is to cover the serial tasks,
# We take the configured hours timeout time by 2.5 as we run user and
# group in parallel and then membership, so 2x is to cover the serial tasks,
# and 0.5x on top of that to give some more leeway
soft_time_limit=(60 * 60 * CONFIG.get_int("ldap.task_timeout_hours")) * 3.5,
task_time_limit=(60 * 60 * CONFIG.get_int("ldap.task_timeout_hours")) * 3.5,
soft_time_limit=(60 * 60 * CONFIG.get_int("ldap.task_timeout_hours")) * 2.5,
task_time_limit=(60 * 60 * CONFIG.get_int("ldap.task_timeout_hours")) * 2.5,
)
def ldap_sync_single(source_pk: str):
"""Sync a single source"""
@ -81,25 +79,6 @@ def ldap_sync_single(source_pk: str):
group(
ldap_sync_paginator(source, MembershipLDAPSynchronizer),
),
# Finally, deletions. What we'd really like to do here is something like
# ```
# user_identifiers = <ldap query>
# User.objects.exclude(
# usersourceconnection__identifier__in=user_uniqueness_identifiers,
# ).delete()
# ```
# This runs into performance issues in large installations. So instead we spread the
# work out into three steps:
# 1. Get every object from the LDAP source.
# 2. Mark every object as "safe" in the database. This is quick, but any error could
# mean deleting users which should not be deleted, so we do it immediately, in
# large chunks, and only queue the deletion step afterwards.
# 3. Delete every unmarked item. This is slow, so we spread it over many tasks in
# small chunks.
group(
ldap_sync_paginator(source, UserLDAPForwardDeletion)
+ ldap_sync_paginator(source, GroupLDAPForwardDeletion),
),
)
task()

View File

@ -2,33 +2,6 @@
from ldap3 import MOCK_SYNC, OFFLINE_SLAPD_2_4, Connection, Server
# The mock modifies these in place, so we have to define them per string
user_in_slapd_dn = "cn=user_in_slapd_cn,ou=users,dc=goauthentik,dc=io"
user_in_slapd_cn = "user_in_slapd_cn"
user_in_slapd_uid = "user_in_slapd_uid"
user_in_slapd_object_class = "person"
user_in_slapd = {
"dn": user_in_slapd_dn,
"attributes": {
"cn": user_in_slapd_cn,
"uid": user_in_slapd_uid,
"objectClass": user_in_slapd_object_class,
},
}
group_in_slapd_dn = "cn=user_in_slapd_cn,ou=groups,dc=goauthentik,dc=io"
group_in_slapd_cn = "group_in_slapd_cn"
group_in_slapd_uid = "group_in_slapd_uid"
group_in_slapd_object_class = "groupOfNames"
group_in_slapd = {
"dn": group_in_slapd_dn,
"attributes": {
"cn": group_in_slapd_cn,
"uid": group_in_slapd_uid,
"objectClass": group_in_slapd_object_class,
"member": [user_in_slapd["dn"]],
},
}
def mock_slapd_connection(password: str) -> Connection:
"""Create mock SLAPD connection"""
@ -123,14 +96,5 @@ def mock_slapd_connection(password: str) -> Connection:
"objectClass": "posixAccount",
},
)
# Known user and group
connection.strategy.add_entry(
user_in_slapd["dn"],
user_in_slapd["attributes"],
)
connection.strategy.add_entry(
group_in_slapd["dn"],
group_in_slapd["attributes"],
)
connection.bind()
return connection

View File

@ -13,26 +13,14 @@ from authentik.events.system_tasks import TaskStatus
from authentik.lib.generators import generate_id, generate_key
from authentik.lib.sync.outgoing.exceptions import StopSync
from authentik.lib.utils.reflection import class_to_path
from authentik.sources.ldap.models import (
GroupLDAPSourceConnection,
LDAPSource,
LDAPSourcePropertyMapping,
UserLDAPSourceConnection,
)
from authentik.sources.ldap.sync.forward_delete_users import DELETE_CHUNK_SIZE
from authentik.sources.ldap.models import LDAPSource, LDAPSourcePropertyMapping
from authentik.sources.ldap.sync.groups import GroupLDAPSynchronizer
from authentik.sources.ldap.sync.membership import MembershipLDAPSynchronizer
from authentik.sources.ldap.sync.users import UserLDAPSynchronizer
from authentik.sources.ldap.tasks import ldap_sync, ldap_sync_all
from authentik.sources.ldap.tests.mock_ad import mock_ad_connection
from authentik.sources.ldap.tests.mock_freeipa import mock_freeipa_connection
from authentik.sources.ldap.tests.mock_slapd import (
group_in_slapd_cn,
group_in_slapd_uid,
mock_slapd_connection,
user_in_slapd_cn,
user_in_slapd_uid,
)
from authentik.sources.ldap.tests.mock_slapd import mock_slapd_connection
LDAP_PASSWORD = generate_key()
@ -320,160 +308,3 @@ class LDAPSyncTests(TestCase):
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
ldap_sync_all.delay().get()
def test_user_deletion(self):
"""Test user deletion"""
user = User.objects.create_user(username="not-in-the-source")
UserLDAPSourceConnection.objects.create(
user=user, source=self.source, identifier="not-in-the-source"
)
self.source.object_uniqueness_field = "uid"
self.source.group_object_filter = "(objectClass=groupOfNames)"
self.source.delete_not_found_objects = True
self.source.save()
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
ldap_sync_all.delay().get()
self.assertFalse(User.objects.filter(username="not-in-the-source").exists())
def test_user_deletion_still_in_source(self):
"""Test that user is not deleted if it's still in the source"""
username = user_in_slapd_cn
identifier = user_in_slapd_uid
user = User.objects.create_user(username=username)
UserLDAPSourceConnection.objects.create(
user=user, source=self.source, identifier=identifier
)
self.source.object_uniqueness_field = "uid"
self.source.group_object_filter = "(objectClass=groupOfNames)"
self.source.delete_not_found_objects = True
self.source.save()
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
ldap_sync_all.delay().get()
self.assertTrue(User.objects.filter(username=username).exists())
def test_user_deletion_no_sync(self):
"""Test that user is not deleted if sync_users is False"""
user = User.objects.create_user(username="not-in-the-source")
UserLDAPSourceConnection.objects.create(
user=user, source=self.source, identifier="not-in-the-source"
)
self.source.object_uniqueness_field = "uid"
self.source.group_object_filter = "(objectClass=groupOfNames)"
self.source.delete_not_found_objects = True
self.source.sync_users = False
self.source.save()
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
ldap_sync_all.delay().get()
self.assertTrue(User.objects.filter(username="not-in-the-source").exists())
def test_user_deletion_no_delete(self):
"""Test that user is not deleted if delete_not_found_objects is False"""
user = User.objects.create_user(username="not-in-the-source")
UserLDAPSourceConnection.objects.create(
user=user, source=self.source, identifier="not-in-the-source"
)
self.source.object_uniqueness_field = "uid"
self.source.group_object_filter = "(objectClass=groupOfNames)"
self.source.save()
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
ldap_sync_all.delay().get()
self.assertTrue(User.objects.filter(username="not-in-the-source").exists())
def test_group_deletion(self):
"""Test group deletion"""
group = Group.objects.create(name="not-in-the-source")
GroupLDAPSourceConnection.objects.create(
group=group, source=self.source, identifier="not-in-the-source"
)
self.source.object_uniqueness_field = "uid"
self.source.group_object_filter = "(objectClass=groupOfNames)"
self.source.delete_not_found_objects = True
self.source.save()
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
ldap_sync_all.delay().get()
self.assertFalse(Group.objects.filter(name="not-in-the-source").exists())
def test_group_deletion_still_in_source(self):
"""Test that group is not deleted if it's still in the source"""
groupname = group_in_slapd_cn
identifier = group_in_slapd_uid
group = Group.objects.create(name=groupname)
GroupLDAPSourceConnection.objects.create(
group=group, source=self.source, identifier=identifier
)
self.source.object_uniqueness_field = "uid"
self.source.group_object_filter = "(objectClass=groupOfNames)"
self.source.delete_not_found_objects = True
self.source.save()
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
ldap_sync_all.delay().get()
self.assertTrue(Group.objects.filter(name=groupname).exists())
def test_group_deletion_no_sync(self):
"""Test that group is not deleted if sync_groups is False"""
group = Group.objects.create(name="not-in-the-source")
GroupLDAPSourceConnection.objects.create(
group=group, source=self.source, identifier="not-in-the-source"
)
self.source.object_uniqueness_field = "uid"
self.source.group_object_filter = "(objectClass=groupOfNames)"
self.source.delete_not_found_objects = True
self.source.sync_groups = False
self.source.save()
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
ldap_sync_all.delay().get()
self.assertTrue(Group.objects.filter(name="not-in-the-source").exists())
def test_group_deletion_no_delete(self):
"""Test that group is not deleted if delete_not_found_objects is False"""
group = Group.objects.create(name="not-in-the-source")
GroupLDAPSourceConnection.objects.create(
group=group, source=self.source, identifier="not-in-the-source"
)
self.source.object_uniqueness_field = "uid"
self.source.group_object_filter = "(objectClass=groupOfNames)"
self.source.save()
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
ldap_sync_all.delay().get()
self.assertTrue(Group.objects.filter(name="not-in-the-source").exists())
def test_batch_deletion(self):
"""Test batch deletion"""
BATCH_SIZE = DELETE_CHUNK_SIZE + 1
for i in range(BATCH_SIZE):
user = User.objects.create_user(username=f"not-in-the-source-{i}")
group = Group.objects.create(name=f"not-in-the-source-{i}")
group.users.add(user)
UserLDAPSourceConnection.objects.create(
user=user, source=self.source, identifier=f"not-in-the-source-{i}-user"
)
GroupLDAPSourceConnection.objects.create(
group=group, source=self.source, identifier=f"not-in-the-source-{i}-group"
)
self.source.object_uniqueness_field = "uid"
self.source.group_object_filter = "(objectClass=groupOfNames)"
self.source.delete_not_found_objects = True
self.source.save()
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
ldap_sync_all.delay().get()
self.assertFalse(User.objects.filter(username__startswith="not-in-the-source").exists())
self.assertFalse(Group.objects.filter(name__startswith="not-in-the-source").exists())

View File

@ -9,7 +9,6 @@ from django.http.response import HttpResponseBadRequest
from django.shortcuts import get_object_or_404, redirect
from django.utils.decorators import method_decorator
from django.utils.http import urlencode
from django.utils.translation import gettext as _
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from structlog.stdlib import get_logger
@ -129,9 +128,7 @@ class InitiateView(View):
# otherwise we default to POST_AUTO, with direct redirect
if source.binding_type == SAMLBindingTypes.POST:
injected_stages.append(in_memory_stage(ConsentStageView))
plan_kwargs[PLAN_CONTEXT_CONSENT_HEADER] = _(
"Continue to {source_name}".format(source_name=source.name)
)
plan_kwargs[PLAN_CONTEXT_CONSENT_HEADER] = f"Continue to {source.name}"
injected_stages.append(in_memory_stage(AutosubmitStageView))
return self.handle_login_flow(
source,

View File

@ -4,8 +4,6 @@ from uuid import uuid4
from django.http import HttpRequest, HttpResponse
from django.utils.timezone import now
from django.utils.translation import gettext as _
from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField
from authentik.core.api.utils import PassiveSerializer
@ -49,11 +47,6 @@ class ConsentChallengeResponse(ChallengeResponse):
component = CharField(default="ak-stage-consent")
token = CharField(required=True)
def validate_token(self, token: str):
if token != self.stage.executor.request.session[SESSION_KEY_CONSENT_TOKEN]:
raise ValidationError(_("Invalid consent token, re-showing prompt"))
return token
class ConsentStageView(ChallengeStageView):
"""Simple consent checker."""
@ -127,6 +120,9 @@ class ConsentStageView(ChallengeStageView):
return super().get(request, *args, **kwargs)
def challenge_valid(self, response: ChallengeResponse) -> HttpResponse:
if response.data["token"] != self.request.session[SESSION_KEY_CONSENT_TOKEN]:
self.logger.info("Invalid consent token, re-showing prompt")
return self.get(self.request)
if self.should_always_prompt():
return self.executor.stage_ok()
current_stage: ConsentStage = self.executor.current_stage

View File

@ -17,7 +17,6 @@ from authentik.flows.views.executor import SESSION_KEY_PLAN
from authentik.lib.generators import generate_id
from authentik.stages.consent.models import ConsentMode, ConsentStage, UserConsent
from authentik.stages.consent.stage import (
PLAN_CONTEXT_CONSENT_HEADER,
PLAN_CONTEXT_CONSENT_PERMISSIONS,
SESSION_KEY_CONSENT_TOKEN,
)
@ -34,40 +33,6 @@ class TestConsentStage(FlowTestCase):
slug=generate_id(),
)
def test_mismatched_token(self):
"""Test incorrect token"""
flow = create_test_flow(FlowDesignation.AUTHENTICATION)
stage = ConsentStage.objects.create(name=generate_id(), mode=ConsentMode.ALWAYS_REQUIRE)
binding = FlowStageBinding.objects.create(target=flow, stage=stage, order=2)
plan = FlowPlan(flow_pk=flow.pk.hex, bindings=[binding], markers=[StageMarker()])
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session.save()
response = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
)
self.assertEqual(response.status_code, 200)
session = self.client.session
response = self.client.post(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
{
"token": generate_id(),
},
)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(
response,
flow,
component="ak-stage-consent",
response_errors={
"token": [{"string": "Invalid consent token, re-showing prompt", "code": "invalid"}]
},
)
self.assertFalse(UserConsent.objects.filter(user=self.user).exists())
def test_always_required(self):
"""Test always required consent"""
flow = create_test_flow(FlowDesignation.AUTHENTICATION)
@ -193,7 +158,6 @@ class TestConsentStage(FlowTestCase):
context={
PLAN_CONTEXT_APPLICATION: self.application,
PLAN_CONTEXT_CONSENT_PERMISSIONS: [PermissionDict(id="foo", name="foo-desc")],
PLAN_CONTEXT_CONSENT_HEADER: "test header",
},
)
session = self.client.session

View File

@ -1,38 +0,0 @@
from base64 import b64encode
from copy import deepcopy
from pickle import dumps # nosec
from django.utils.translation import gettext as _
from authentik.flows.models import FlowToken, in_memory_stage
from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED, FlowPlan
from authentik.stages.consent.stage import PLAN_CONTEXT_CONSENT_HEADER, ConsentStageView
def pickle_flow_token_for_email(plan: FlowPlan):
"""Insert a consent stage into the flow plan and pickle it for a FlowToken,
to be sent via Email. This is to prevent automated email scanners, which sometimes
open links in emails in a full browser from breaking the link."""
plan_copy = deepcopy(plan)
plan_copy.insert_stage(in_memory_stage(EmailTokenRevocationConsentStageView), index=0)
plan_copy.context[PLAN_CONTEXT_CONSENT_HEADER] = _("Continue to confirm this email address.")
data = dumps(plan_copy)
return b64encode(data).decode()
class EmailTokenRevocationConsentStageView(ConsentStageView):
def get(self, request, *args, **kwargs):
token: FlowToken = self.executor.plan.context[PLAN_CONTEXT_IS_RESTORED]
try:
token.refresh_from_db()
except FlowToken.DoesNotExist:
return self.executor.stage_invalid(
_("Link was already used, please request a new link.")
)
return super().get(request, *args, **kwargs)
def challenge_valid(self, response):
token: FlowToken = self.executor.plan.context[PLAN_CONTEXT_IS_RESTORED]
token.delete()
return super().challenge_valid(response)

View File

@ -23,7 +23,6 @@ from authentik.flows.stage import ChallengeStageView
from authentik.flows.views.executor import QS_KEY_TOKEN, QS_QUERY
from authentik.lib.utils.errors import exception_to_string
from authentik.lib.utils.time import timedelta_from_string
from authentik.stages.email.flow import pickle_flow_token_for_email
from authentik.stages.email.models import EmailStage
from authentik.stages.email.tasks import send_mails
from authentik.stages.email.utils import TemplateEmailMessage
@ -87,8 +86,7 @@ class EmailStageView(ChallengeStageView):
user=pending_user,
identifier=identifier,
flow=self.executor.flow,
_plan=pickle_flow_token_for_email(self.executor.plan),
revoke_on_execution=False,
_plan=FlowToken.pickle(self.executor.plan),
)
token = tokens.first()
# Check if token is expired and rotate key if so

View File

@ -174,5 +174,5 @@ class TestEmailStageSending(FlowTestCase):
response = self.client.post(url)
response = self.client.post(url)
self.assertEqual(response.status_code, 200)
self.assertGreaterEqual(len(mail.outbox), 1)
self.assertTrue(len(mail.outbox) >= 1)
self.assertEqual(mail.outbox[0].subject, "authentik")

View File

@ -17,7 +17,6 @@ from authentik.flows.tests import FlowTestCase
from authentik.flows.views.executor import QS_KEY_TOKEN, SESSION_KEY_PLAN, FlowExecutorView
from authentik.lib.config import CONFIG
from authentik.lib.generators import generate_id
from authentik.stages.consent.stage import SESSION_KEY_CONSENT_TOKEN
from authentik.stages.email.models import EmailStage
from authentik.stages.email.stage import PLAN_CONTEXT_EMAIL_OVERRIDE, EmailStageView
@ -161,17 +160,6 @@ class TestEmailStage(FlowTestCase):
kwargs={"flow_slug": self.flow.slug},
)
)
self.assertStageResponse(response, self.flow, component="ak-stage-consent")
response = self.client.post(
reverse(
"authentik_api:flow-executor",
kwargs={"flow_slug": self.flow.slug},
),
data={
"token": self.client.session[SESSION_KEY_CONSENT_TOKEN],
},
follow=True,
)
self.assertEqual(response.status_code, 200)
self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
@ -194,7 +182,6 @@ class TestEmailStage(FlowTestCase):
# Set flow token user to a different user
token: FlowToken = FlowToken.objects.get(user=self.user)
token.user = create_test_admin_user()
token.revoke_on_execution = True
token.save()
with patch("authentik.flows.views.executor.FlowExecutorView.cancel", MagicMock()):

View File

@ -8180,11 +8180,6 @@
"type": "boolean",
"title": "Lookup groups from user",
"description": "Lookup group membership based on a user attribute instead of a group attribute. This allows nested group resolution on systems like FreeIPA and Active Directory"
},
"delete_not_found_objects": {
"type": "boolean",
"title": "Delete not found objects",
"description": "Delete authentik users and groups which were previously supplied by this source, but are now missing from it."
}
},
"required": []

View File

@ -28,18 +28,16 @@ func NewSessionBinder(si server.LDAPServerInstance, oldBinder bind.Binder) *Sess
si: si,
log: log.WithField("logger", "authentik.outpost.ldap.binder.session"),
}
if oldBinder != nil {
if oldSb, ok := oldBinder.(*SessionBinder); ok {
sb.DirectBinder = oldSb.DirectBinder
sb.sessions = oldSb.sessions
sb.log.Debug("re-initialised session binder")
return sb
}
if oldSb, ok := oldBinder.(*SessionBinder); ok {
sb.DirectBinder = oldSb.DirectBinder
sb.sessions = oldSb.sessions
sb.log.Debug("re-initialised session binder")
} else {
sb.sessions = ttlcache.New(ttlcache.WithDisableTouchOnHit[Credentials, ldap.LDAPResultCode]())
sb.DirectBinder = *direct.NewDirectBinder(si)
go sb.sessions.Start()
sb.log.Debug("initialised session binder")
}
sb.sessions = ttlcache.New(ttlcache.WithDisableTouchOnHit[Credentials, ldap.LDAPResultCode]())
sb.DirectBinder = *direct.NewDirectBinder(si)
go sb.sessions.Start()
sb.log.Debug("initialised session binder")
return sb
}

View File

@ -16,7 +16,6 @@ import (
memorybind "goauthentik.io/internal/outpost/ldap/bind/memory"
"goauthentik.io/internal/outpost/ldap/constants"
"goauthentik.io/internal/outpost/ldap/flags"
"goauthentik.io/internal/outpost/ldap/search"
directsearch "goauthentik.io/internal/outpost/ldap/search/direct"
memorysearch "goauthentik.io/internal/outpost/ldap/search/memory"
)
@ -86,11 +85,7 @@ func (ls *LDAPServer) Refresh() error {
providers[idx].certUUID = *kp
}
if *provider.SearchMode.Ptr() == api.LDAPAPIACCESSMODE_CACHED {
var oldSearcher search.Searcher
if existing != nil {
oldSearcher = existing.searcher
}
providers[idx].searcher = memorysearch.NewMemorySearcher(providers[idx], oldSearcher)
providers[idx].searcher = memorysearch.NewMemorySearcher(providers[idx])
} else if *provider.SearchMode.Ptr() == api.LDAPAPIACCESSMODE_DIRECT {
providers[idx].searcher = directsearch.NewDirectSearcher(providers[idx])
}

View File

@ -31,26 +31,13 @@ type MemorySearcher struct {
groups []api.Group
}
func NewMemorySearcher(si server.LDAPServerInstance, existing search.Searcher) *MemorySearcher {
func NewMemorySearcher(si server.LDAPServerInstance) *MemorySearcher {
ms := &MemorySearcher{
si: si,
log: log.WithField("logger", "authentik.outpost.ldap.searcher.memory"),
ds: direct.NewDirectSearcher(si),
}
if existing != nil {
if ems, ok := existing.(*MemorySearcher); ok {
ems.si = si
ems.fetch()
ems.log.Debug("re-initialised memory searcher")
return ems
}
}
ms.fetch()
ms.log.Debug("initialised memory searcher")
return ms
}
func (ms *MemorySearcher) fetch() {
// Error is not handled here, we get an empty/truncated list and the error is logged
users, _ := ak.Paginator(ms.si.GetAPIClient().CoreApi.CoreUsersList(context.TODO()).IncludeGroups(true), ak.PaginatorOptions{
PageSize: 100,
@ -62,6 +49,7 @@ func (ms *MemorySearcher) fetch() {
Logger: ms.log,
})
ms.groups = groups
return ms
}
func (ms *MemorySearcher) SearchBase(req *search.Request) (ldap.ServerSearchResult, error) {

View File

@ -67,15 +67,11 @@ func (ws *WebServer) configureStatic() {
// Media files, if backend is file
if config.Get().Storage.Media.Backend == "file" {
fsMedia := http.FileServer(http.Dir(config.Get().Storage.Media.File.Path))
indexLessRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/media/").Handler(pathStripper(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox")
fsMedia.ServeHTTP(w, r)
}),
"media/",
config.Get().Web.Path,
))
fsMedia := http.StripPrefix("/media", http.FileServer(http.Dir(config.Get().Storage.Media.File.Path)))
indexLessRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/media/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox")
fsMedia.ServeHTTP(w, r)
})
}
staticRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/if/help/").Handler(pathStripper(

Binary file not shown.

View File

@ -32,17 +32,15 @@
# datenschmutz, 2025
# 97cce0ae0cad2a2cc552d3165d04643e_de3d740, 2025
# Dominic Wagner <mail@dominic-wagner.de>, 2025
# Till-Frederik Riechard, 2025
# Alexander Mnich, 2025
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-05-28 11:25+0000\n"
"POT-Creation-Date: 2025-04-23 09:00+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Alexander Mnich, 2025\n"
"Last-Translator: Dominic Wagner <mail@dominic-wagner.de>, 2025\n"
"Language-Team: German (https://app.transifex.com/authentik/teams/119923/de/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -134,10 +132,6 @@ msgstr ""
msgid "Web Certificate used by the authentik Core webserver."
msgstr "Vom Authentik-Core-Webserver verwendetes Zertifikat."
#: authentik/brands/models.py
msgid "Certificates used for client authentication."
msgstr ""
#: authentik/brands/models.py
msgid "Brand"
msgstr "Marke"
@ -411,7 +405,7 @@ msgstr "Eigenschaften"
#: authentik/core/models.py
msgid "session data"
msgstr "Sitzungsdaten"
msgstr ""
#: authentik/core/models.py
msgid "Session"
@ -539,7 +533,7 @@ msgstr ""
#: authentik/enterprise/policies/unique_password/models.py
msgid "Number of passwords to check against."
msgstr "Anzahl Passwörter, gegen die geprüft wird."
msgstr ""
#: authentik/enterprise/policies/unique_password/models.py
#: authentik/policies/password/models.py
@ -549,20 +543,18 @@ msgstr "Passwort nicht im Kontext festgelegt"
#: authentik/enterprise/policies/unique_password/models.py
msgid "This password has been used previously. Please choose a different one."
msgstr ""
"Dieses Passwort wurde in Vergangenheit bereits verwendet. Bitte nutzen Sie "
"ein anderes."
#: authentik/enterprise/policies/unique_password/models.py
msgid "Password Uniqueness Policy"
msgstr "Passwort-Einzigartigkeits-Richtlinie"
msgstr ""
#: authentik/enterprise/policies/unique_password/models.py
msgid "Password Uniqueness Policies"
msgstr "Passwort-Einzigartigkeits-Richtlinien"
msgstr ""
#: authentik/enterprise/policies/unique_password/models.py
msgid "User Password History"
msgstr "Nutzer-Passwort-Historie"
msgstr ""
#: authentik/enterprise/policy.py
msgid "Enterprise required to access this feature."
@ -701,33 +693,6 @@ msgstr "Endgeräte"
msgid "Verifying your browser..."
msgstr "Verifiziere deinen Browser..."
#: authentik/enterprise/stages/mtls/models.py
msgid ""
"Configure certificate authorities to validate the certificate against. This "
"option has a higher priority than the `client_certificate` option on "
"`Brand`."
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stage"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stages"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Permissions to pass Certificates for outposts."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "Certificate required but no certificate was given."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "No user found for certificate."
msgstr ""
#: authentik/enterprise/stages/source/models.py
msgid ""
"Amount of time a user can take to return from the source to continue the "
@ -1023,7 +988,7 @@ msgstr ""
#: authentik/flows/models.py
msgid "Evaluate policies when the Stage is presented to the user."
msgstr "Richtlinien auswerten, wenn die Phase dem Benutzer angezeigt wird."
msgstr ""
#: authentik/flows/models.py
msgid ""
@ -1078,12 +1043,9 @@ msgid "Starting full provider sync"
msgstr "Starte komplette Provider Synchronisation."
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr ""
#, python-brace-format
msgid "Syncing page {page} of users"
msgstr "Synchonisiere Benutzer Seite {page}"
#: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format
@ -1631,11 +1593,11 @@ msgstr "ES256 (Asymmetrische Verschlüsselung)"
#: authentik/providers/oauth2/models.py
msgid "ES384 (Asymmetric Encryption)"
msgstr "ES384 (Asymmetrische Verschlüsselung)"
msgstr ""
#: authentik/providers/oauth2/models.py
msgid "ES512 (Asymmetric Encryption)"
msgstr "ES5122 (Asymmetrische Verschlüsselung)"
msgstr ""
#: authentik/providers/oauth2/models.py
msgid "Scope used by the client"
@ -2221,11 +2183,11 @@ msgstr "Standard"
#: authentik/providers/scim/models.py
msgid "AWS"
msgstr "AWS"
msgstr ""
#: authentik/providers/scim/models.py
msgid "Slack"
msgstr "Slack"
msgstr ""
#: authentik/providers/scim/models.py
msgid "Base URL to SCIM requests, usually ends in /v2"
@ -2237,7 +2199,7 @@ msgstr "Authentifizierungstoken"
#: authentik/providers/scim/models.py
msgid "SCIM Compatibility Mode"
msgstr "SCIM Kompatibilitätsmodus"
msgstr ""
#: authentik/providers/scim/models.py
msgid "Alter authentik behavior for vendor-specific SCIM implementations."
@ -2269,7 +2231,7 @@ msgstr "Rollen"
#: authentik/rbac/models.py
msgid "Initial Permissions"
msgstr "Initiale Berechtigungen"
msgstr ""
#: authentik/rbac/models.py
msgid "System permission"
@ -2525,12 +2487,6 @@ msgid ""
"Active Directory"
msgstr ""
#: authentik/sources/ldap/models.py
msgid ""
"Delete authentik users and groups which were previously supplied by this "
"source, but are now missing from it."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "LDAP Source"
msgstr "LDAP Quelle"
@ -2548,25 +2504,20 @@ msgid "LDAP Source Property Mappings"
msgstr "LDAP Quelle Eigenschafts-Zuordnungen"
#: authentik/sources/ldap/models.py
msgid ""
"Unique ID used while checking if this object still exists in the directory."
msgid "User LDAP Source Connection"
msgstr ""
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection"
msgstr "Benutzer LDAP-Quellverbindung"
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connections"
msgstr "Benutzer LDAP-Quellverbindungen"
msgstr ""
#: authentik/sources/ldap/models.py
msgid "Group LDAP Source Connection"
msgstr "LDAP Gruppen Quellverbindung"
msgstr ""
#: authentik/sources/ldap/models.py
msgid "Group LDAP Source Connections"
msgstr "LDAP Gruppen Quellverbindungen"
msgstr ""
#: authentik/sources/ldap/signals.py
msgid "Password does not match Active Directory Complexity."
@ -2579,7 +2530,7 @@ msgstr "Kein Token empfangen."
#: authentik/sources/oauth/models.py
msgid "HTTP Basic Authentication"
msgstr "HTTP Basic Authentifizierung"
msgstr ""
#: authentik/sources/oauth/models.py
msgid "Include the client ID and secret as request parameters"
@ -2945,11 +2896,6 @@ msgstr "SAML Gruppen Quellverbindung"
msgid "Group SAML Source Connections"
msgstr "SAML Gruppen Quellverbindungen"
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py
msgid "SCIM Source"
msgstr "SCIM Quelle"
@ -2984,7 +2930,7 @@ msgstr "Duo Geräte"
#: authentik/stages/authenticator_email/models.py
msgid "Email OTP"
msgstr "E-Mail Einmalpasswort"
msgstr ""
#: authentik/stages/authenticator_email/models.py
#: authentik/stages/email/models.py
@ -3017,11 +2963,11 @@ msgstr "Beim Rendern der E-Mail-Vorlage ist ein Fehler aufgetreten"
#: authentik/stages/authenticator_email/models.py
msgid "Email Device"
msgstr "E-Mail Gerät"
msgstr ""
#: authentik/stages/authenticator_email/models.py
msgid "Email Devices"
msgstr "E-Mail Geräte"
msgstr ""
#: authentik/stages/authenticator_email/stage.py
#: authentik/stages/authenticator_sms/stage.py
@ -3031,7 +2977,7 @@ msgstr "Code stimmt nicht überein"
#: authentik/stages/authenticator_email/stage.py
msgid "Invalid email"
msgstr "Ungültige E-Mail"
msgstr ""
#: authentik/stages/authenticator_email/templates/email/email_otp.html
#: authentik/stages/email/templates/email/password_reset.html
@ -3327,10 +3273,6 @@ msgstr "Zustimmung der Benutzer"
msgid "User Consents"
msgstr "Zustimmungen der Benutzer"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py
msgid "Deny Stage"
msgstr "Verweigerungsstufe"
@ -3347,14 +3289,6 @@ msgstr "Dummy Stufe"
msgid "Dummy Stages"
msgstr "Dummy Stufen"
#: authentik/stages/email/flow.py
msgid "Continue to confirm this email address."
msgstr ""
#: authentik/stages/email/flow.py
msgid "Link was already used, please request a new link."
msgstr ""
#: authentik/stages/email/models.py
msgid "Password Reset"
msgstr "Passwort zurücksetzen"
@ -3956,11 +3890,10 @@ msgstr ""
#: authentik/tenants/models.py
msgid "Reputation cannot decrease lower than this value. Zero or negative."
msgstr ""
"Reputation kann nicht niedriger als dieser Wert sein. Null oder negativ."
#: authentik/tenants/models.py
msgid "Reputation cannot increase higher than this value. Zero or positive."
msgstr "Reputation kann nicht höher als dieser Wert sein. Null oder positiv."
msgstr ""
#: authentik/tenants/models.py
msgid "The option configures the footer links on the flow executor pages."

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-05-28 11:25+0000\n"
"POT-Creation-Date: 2025-05-20 00:10+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -961,11 +961,8 @@ msgid "Starting full provider sync"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
#, python-brace-format
msgid "Syncing page {page} of users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
@ -2255,12 +2252,6 @@ msgid ""
"Active Directory"
msgstr ""
#: authentik/sources/ldap/models.py
msgid ""
"Delete authentik users and groups which were previously supplied by this "
"source, but are now missing from it."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "LDAP Source"
msgstr ""
@ -2277,11 +2268,6 @@ msgstr ""
msgid "LDAP Source Property Mappings"
msgstr ""
#: authentik/sources/ldap/models.py
msgid ""
"Unique ID used while checking if this object still exists in the directory."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection"
msgstr ""
@ -2653,11 +2639,6 @@ msgstr ""
msgid "Group SAML Source Connections"
msgstr ""
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py
msgid "SCIM Source"
msgstr ""
@ -3013,10 +2994,6 @@ msgstr ""
msgid "User Consents"
msgstr ""
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py
msgid "Deny Stage"
msgstr ""
@ -3033,14 +3010,6 @@ msgstr ""
msgid "Dummy Stages"
msgstr ""
#: authentik/stages/email/flow.py
msgid "Continue to confirm this email address."
msgstr ""
#: authentik/stages/email/flow.py
msgid "Link was already used, please request a new link."
msgstr ""
#: authentik/stages/email/models.py
msgid "Password Reset"
msgstr ""

Binary file not shown.

View File

@ -15,7 +15,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-05-28 11:25+0000\n"
"POT-Creation-Date: 2025-04-23 09:00+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Jens L. <jens@goauthentik.io>, 2025\n"
"Language-Team: Spanish (https://app.transifex.com/authentik/teams/119923/es/)\n"
@ -109,10 +109,6 @@ msgstr ""
msgid "Web Certificate used by the authentik Core webserver."
msgstr "Certificado Web usado por el servidor web Core de authentik"
#: authentik/brands/models.py
msgid "Certificates used for client authentication."
msgstr ""
#: authentik/brands/models.py
msgid "Brand"
msgstr "Marca"
@ -675,33 +671,6 @@ msgstr "Dispositivos de Punto de Conexión"
msgid "Verifying your browser..."
msgstr "Verificando tu navegador..."
#: authentik/enterprise/stages/mtls/models.py
msgid ""
"Configure certificate authorities to validate the certificate against. This "
"option has a higher priority than the `client_certificate` option on "
"`Brand`."
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stage"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stages"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Permissions to pass Certificates for outposts."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "Certificate required but no certificate was given."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "No user found for certificate."
msgstr ""
#: authentik/enterprise/stages/source/models.py
msgid ""
"Amount of time a user can take to return from the source to continue the "
@ -1040,12 +1009,9 @@ msgid "Starting full provider sync"
msgstr "Iniciando sincronización completa de proveedor"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr ""
#, python-brace-format
msgid "Syncing page {page} of users"
msgstr "Sincronizando página {page} de usuarios"
#: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format
@ -2486,12 +2452,6 @@ msgid ""
"Active Directory"
msgstr ""
#: authentik/sources/ldap/models.py
msgid ""
"Delete authentik users and groups which were previously supplied by this "
"source, but are now missing from it."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "LDAP Source"
msgstr "Fuente de LDAP"
@ -2508,11 +2468,6 @@ msgstr "Asignación de Propiedades de Fuente de LDAP"
msgid "LDAP Source Property Mappings"
msgstr "Asignaciones de Propiedades de Fuente de LDAP"
#: authentik/sources/ldap/models.py
msgid ""
"Unique ID used while checking if this object still exists in the directory."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection"
msgstr ""
@ -2904,11 +2859,6 @@ msgstr "Conexión de Fuente de SAML de Grupo"
msgid "Group SAML Source Connections"
msgstr "Conexiones de Fuente de SAML de Grupo"
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py
msgid "SCIM Source"
msgstr "Fuente de SCIM"
@ -3295,10 +3245,6 @@ msgstr "Consentimiento del usuario"
msgid "User Consents"
msgstr "Consentimientos del usuario"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py
msgid "Deny Stage"
msgstr "Etapa de denegación"
@ -3315,14 +3261,6 @@ msgstr "Escenario ficticio"
msgid "Dummy Stages"
msgstr "Etapas ficticias"
#: authentik/stages/email/flow.py
msgid "Continue to confirm this email address."
msgstr ""
#: authentik/stages/email/flow.py
msgid "Link was already used, please request a new link."
msgstr ""
#: authentik/stages/email/models.py
msgid "Password Reset"
msgstr "Restablecimiento de contraseña"

Binary file not shown.

View File

@ -15,7 +15,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-05-28 11:25+0000\n"
"POT-Creation-Date: 2025-04-23 09:00+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Ville Ranki, 2025\n"
"Language-Team: Finnish (https://app.transifex.com/authentik/teams/119923/fi/)\n"
@ -106,10 +106,6 @@ msgstr ""
msgid "Web Certificate used by the authentik Core webserver."
msgstr "Web-sertifikaatti, jota authentik Core -verkkopalvelin käyttää."
#: authentik/brands/models.py
msgid "Certificates used for client authentication."
msgstr ""
#: authentik/brands/models.py
msgid "Brand"
msgstr "Brändi"
@ -662,33 +658,6 @@ msgstr "Päätelaitteet"
msgid "Verifying your browser..."
msgstr "Selaintasi varmennetaan..."
#: authentik/enterprise/stages/mtls/models.py
msgid ""
"Configure certificate authorities to validate the certificate against. This "
"option has a higher priority than the `client_certificate` option on "
"`Brand`."
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stage"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stages"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Permissions to pass Certificates for outposts."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "Certificate required but no certificate was given."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "No user found for certificate."
msgstr ""
#: authentik/enterprise/stages/source/models.py
msgid ""
"Amount of time a user can take to return from the source to continue the "
@ -1027,12 +996,9 @@ msgid "Starting full provider sync"
msgstr "Käynnistetään palveluntarjoajan täysi synkronisointi"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr ""
#, python-brace-format
msgid "Syncing page {page} of users"
msgstr "Synkronoidaan käyttäjien sivua {page}"
#: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format
@ -2463,12 +2429,6 @@ msgid ""
"Active Directory"
msgstr ""
#: authentik/sources/ldap/models.py
msgid ""
"Delete authentik users and groups which were previously supplied by this "
"source, but are now missing from it."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "LDAP Source"
msgstr "LDAP-lähde"
@ -2485,11 +2445,6 @@ msgstr "LDAP-lähteen ominaisuuskytkentä"
msgid "LDAP Source Property Mappings"
msgstr "LDAP-lähteen ominaisuuskytkennät"
#: authentik/sources/ldap/models.py
msgid ""
"Unique ID used while checking if this object still exists in the directory."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection"
msgstr ""
@ -2882,11 +2837,6 @@ msgstr "Ryhmän SAML-lähteen yhteys"
msgid "Group SAML Source Connections"
msgstr "Ryhmän SAML-lähteen yhteydet"
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py
msgid "SCIM Source"
msgstr "SCIM-lähde"
@ -3266,10 +3216,6 @@ msgstr "Käyttäjän hyväksyntä"
msgid "User Consents"
msgstr "Käyttäjän hyväksynnät"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py
msgid "Deny Stage"
msgstr "Kieltovaihe"
@ -3286,14 +3232,6 @@ msgstr "Valevaihe"
msgid "Dummy Stages"
msgstr "Valevaiheet"
#: authentik/stages/email/flow.py
msgid "Continue to confirm this email address."
msgstr ""
#: authentik/stages/email/flow.py
msgid "Link was already used, please request a new link."
msgstr ""
#: authentik/stages/email/models.py
msgid "Password Reset"
msgstr "Salasanan nollaus"

View File

@ -19,7 +19,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-05-28 11:25+0000\n"
"POT-Creation-Date: 2025-05-20 00:10+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Marc Schmitt, 2025\n"
"Language-Team: French (https://app.transifex.com/authentik/teams/119923/fr/)\n"
@ -1056,12 +1056,9 @@ msgid "Starting full provider sync"
msgstr "Démarrage d'une synchronisation complète du fournisseur"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users"
msgstr "Synchronisation des utilisateurs"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr "Synchronisation des groupes"
#, python-brace-format
msgid "Syncing page {page} of users"
msgstr "Synchronisation de la page {page} d'utilisateurs"
#: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format
@ -2511,14 +2508,6 @@ msgstr ""
"plutôt que sur un attribut de groupe. Cela permet la résolution des groupes "
"imbriqués sur des systèmes tels que FreeIPA et Active Directory."
#: authentik/sources/ldap/models.py
msgid ""
"Delete authentik users and groups which were previously supplied by this "
"source, but are now missing from it."
msgstr ""
"Supprimer les utilisateurs et les groupes authentik qui étaient auparavant "
"fournis par cette source, mais qui en sont maintenant absents."
#: authentik/sources/ldap/models.py
msgid "LDAP Source"
msgstr "Source LDAP"
@ -2535,13 +2524,6 @@ msgstr "Mappage de propriété source LDAP"
msgid "LDAP Source Property Mappings"
msgstr "Mappages de propriété source LDAP"
#: authentik/sources/ldap/models.py
msgid ""
"Unique ID used while checking if this object still exists in the directory."
msgstr ""
"ID unique utilisé pour vérifier si cet objet existe toujours dans le "
"répertoire."
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection"
msgstr "Connexion de l'utilisateur à la source LDAP"
@ -2936,11 +2918,6 @@ msgstr "Connexion du groupe à la source SAML"
msgid "Group SAML Source Connections"
msgstr "Connexions du groupe à la source SAML"
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr "Continuer vers {source_name}"
#: authentik/sources/scim/models.py
msgid "SCIM Source"
msgstr "Source SCIM"
@ -3331,10 +3308,6 @@ msgstr "Consentement Utilisateur"
msgid "User Consents"
msgstr "Consentements Utilisateur"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr "Jeton de consentement invalide, réaffichage de l'invite"
#: authentik/stages/deny/models.py
msgid "Deny Stage"
msgstr "Étape de Refus"
@ -3351,14 +3324,6 @@ msgstr "Étape factice"
msgid "Dummy Stages"
msgstr "Étapes factices"
#: authentik/stages/email/flow.py
msgid "Continue to confirm this email address."
msgstr "Continuer pour confirmer cette adresse courriel."
#: authentik/stages/email/flow.py
msgid "Link was already used, please request a new link."
msgstr "Ce lien a déjà été utilisé, veuillez en demander un nouveau."
#: authentik/stages/email/models.py
msgid "Password Reset"
msgstr "Réinitialiser le Mot de Passe"

View File

@ -20,7 +20,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-05-28 11:25+0000\n"
"POT-Creation-Date: 2025-04-23 09:00+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Kowalski Dragon (kowalski7cc) <kowalski.7cc@gmail.com>, 2025\n"
"Language-Team: Italian (https://app.transifex.com/authentik/teams/119923/it/)\n"
@ -114,10 +114,6 @@ msgstr ""
msgid "Web Certificate used by the authentik Core webserver."
msgstr "Certificato Web utilizzato dal server Web authentik Core."
#: authentik/brands/models.py
msgid "Certificates used for client authentication."
msgstr ""
#: authentik/brands/models.py
msgid "Brand"
msgstr "Brand"
@ -676,33 +672,6 @@ msgstr "Dispositivi di Accesso"
msgid "Verifying your browser..."
msgstr "Verifica del tuo browser..."
#: authentik/enterprise/stages/mtls/models.py
msgid ""
"Configure certificate authorities to validate the certificate against. This "
"option has a higher priority than the `client_certificate` option on "
"`Brand`."
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stage"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stages"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Permissions to pass Certificates for outposts."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "Certificate required but no certificate was given."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "No user found for certificate."
msgstr ""
#: authentik/enterprise/stages/source/models.py
msgid ""
"Amount of time a user can take to return from the source to continue the "
@ -1049,12 +1018,9 @@ msgid "Starting full provider sync"
msgstr "Avvio della sincronizzazione completa del provider"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr ""
#, python-brace-format
msgid "Syncing page {page} of users"
msgstr "Sincronizzando pagina {page} degli utenti"
#: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format
@ -2497,12 +2463,6 @@ msgstr ""
"attributo di gruppo. Questo consente la risoluzione di gruppi nidificati su "
"sistemi come FreeIPA e Active Directory."
#: authentik/sources/ldap/models.py
msgid ""
"Delete authentik users and groups which were previously supplied by this "
"source, but are now missing from it."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "LDAP Source"
msgstr "Sorgente LDAP"
@ -2519,11 +2479,6 @@ msgstr "Mappatura delle proprietà sorgente LDAP"
msgid "LDAP Source Property Mappings"
msgstr "Mappature delle proprietà della sorgente LDAP"
#: authentik/sources/ldap/models.py
msgid ""
"Unique ID used while checking if this object still exists in the directory."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection"
msgstr "Connessione Sorgente LDAP Utente"
@ -2917,11 +2872,6 @@ msgstr "Connessione sorgente SAML di gruppo"
msgid "Group SAML Source Connections"
msgstr "Connessioni sorgente SAML di gruppo"
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py
msgid "SCIM Source"
msgstr "Sorgente SCIM"
@ -3319,10 +3269,6 @@ msgstr "Consenso utente"
msgid "User Consents"
msgstr "Consensi utente"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py
msgid "Deny Stage"
msgstr "Fase di negazione"
@ -3339,14 +3285,6 @@ msgstr "Fase fittizia"
msgid "Dummy Stages"
msgstr "Fasi fittizie"
#: authentik/stages/email/flow.py
msgid "Continue to confirm this email address."
msgstr ""
#: authentik/stages/email/flow.py
msgid "Link was already used, please request a new link."
msgstr ""
#: authentik/stages/email/models.py
msgid "Password Reset"
msgstr "Ripristino password"

View File

@ -12,7 +12,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-05-28 11:25+0000\n"
"POT-Creation-Date: 2025-04-23 09:00+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: NavyStack, 2023\n"
"Language-Team: Korean (https://app.transifex.com/authentik/teams/119923/ko/)\n"
@ -99,10 +99,6 @@ msgstr ""
msgid "Web Certificate used by the authentik Core webserver."
msgstr "Authentik Core 웹서버에서 사용하는 웹 인증서."
#: authentik/brands/models.py
msgid "Certificates used for client authentication."
msgstr ""
#: authentik/brands/models.py
msgid "Brand"
msgstr ""
@ -629,33 +625,6 @@ msgstr ""
msgid "Verifying your browser..."
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid ""
"Configure certificate authorities to validate the certificate against. This "
"option has a higher priority than the `client_certificate` option on "
"`Brand`."
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stage"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stages"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Permissions to pass Certificates for outposts."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "Certificate required but no certificate was given."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "No user found for certificate."
msgstr ""
#: authentik/enterprise/stages/source/models.py
msgid ""
"Amount of time a user can take to return from the source to continue the "
@ -977,11 +946,8 @@ msgid "Starting full provider sync"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
#, python-brace-format
msgid "Syncing page {page} of users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
@ -2297,12 +2263,6 @@ msgid ""
"Active Directory"
msgstr ""
#: authentik/sources/ldap/models.py
msgid ""
"Delete authentik users and groups which were previously supplied by this "
"source, but are now missing from it."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "LDAP Source"
msgstr "LDAP 소스"
@ -2319,11 +2279,6 @@ msgstr ""
msgid "LDAP Source Property Mappings"
msgstr ""
#: authentik/sources/ldap/models.py
msgid ""
"Unique ID used while checking if this object still exists in the directory."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection"
msgstr ""
@ -2702,11 +2657,6 @@ msgstr ""
msgid "Group SAML Source Connections"
msgstr ""
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py
msgid "SCIM Source"
msgstr ""
@ -3067,10 +3017,6 @@ msgstr "사용자 동의"
msgid "User Consents"
msgstr "사용자 동의"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py
msgid "Deny Stage"
msgstr "거부 스테이지"
@ -3087,14 +3033,6 @@ msgstr "더미 스테이지"
msgid "Dummy Stages"
msgstr "더미 스테이지"
#: authentik/stages/email/flow.py
msgid "Continue to confirm this email address."
msgstr ""
#: authentik/stages/email/flow.py
msgid "Link was already used, please request a new link."
msgstr ""
#: authentik/stages/email/models.py
msgid "Password Reset"
msgstr "비밀번호 초기화"

Binary file not shown.

View File

@ -19,7 +19,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-05-28 11:25+0000\n"
"POT-Creation-Date: 2025-04-11 00:10+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Dany Sluijk, 2025\n"
"Language-Team: Dutch (https://app.transifex.com/authentik/teams/119923/nl/)\n"
@ -113,10 +113,6 @@ msgstr ""
msgid "Web Certificate used by the authentik Core webserver."
msgstr "Webcertificaat gebruikt door de authentik Core-webserver."
#: authentik/brands/models.py
msgid "Certificates used for client authentication."
msgstr ""
#: authentik/brands/models.py
msgid "Brand"
msgstr "Merk"
@ -195,7 +191,6 @@ msgid "User's display name."
msgstr "Weergavenaam van de gebruiker."
#: authentik/core/models.py authentik/providers/oauth2/models.py
#: authentik/rbac/models.py
msgid "User"
msgstr "Gebruiker"
@ -384,18 +379,6 @@ msgstr "Eigenschapskoppeling"
msgid "Property Mappings"
msgstr "Eigenschapskoppelingen"
#: authentik/core/models.py
msgid "session data"
msgstr ""
#: authentik/core/models.py
msgid "Session"
msgstr "Sessie"
#: authentik/core/models.py
msgid "Sessions"
msgstr "Sessies"
#: authentik/core/models.py
msgid "Authenticated Session"
msgstr "Geauthenticeerde Sessie"
@ -503,38 +486,6 @@ msgstr "Licentie Gebruik"
msgid "License Usage Records"
msgstr "Licentie Gebruik Records"
#: authentik/enterprise/policies/unique_password/models.py
#: authentik/policies/password/models.py
msgid "Field key to check, field keys defined in Prompt stages are available."
msgstr ""
"Veldsleutel om te controleren, veldsleutels gedefinieerd in Prompt-stadia "
"zijn beschikbaar."
#: authentik/enterprise/policies/unique_password/models.py
msgid "Number of passwords to check against."
msgstr ""
#: authentik/enterprise/policies/unique_password/models.py
#: authentik/policies/password/models.py
msgid "Password not set in context"
msgstr "Wachtwoord niet ingesteld in context"
#: authentik/enterprise/policies/unique_password/models.py
msgid "This password has been used previously. Please choose a different one."
msgstr ""
#: authentik/enterprise/policies/unique_password/models.py
msgid "Password Uniqueness Policy"
msgstr ""
#: authentik/enterprise/policies/unique_password/models.py
msgid "Password Uniqueness Policies"
msgstr ""
#: authentik/enterprise/policies/unique_password/models.py
msgid "User Password History"
msgstr ""
#: authentik/enterprise/policy.py
msgid "Enterprise required to access this feature."
msgstr "Enterprise benodigd voor toegang tot deze functie."
@ -671,33 +622,6 @@ msgstr ""
msgid "Verifying your browser..."
msgstr "Uw browser wordt geverifieerd..."
#: authentik/enterprise/stages/mtls/models.py
msgid ""
"Configure certificate authorities to validate the certificate against. This "
"option has a higher priority than the `client_certificate` option on "
"`Brand`."
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stage"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stages"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Permissions to pass Certificates for outposts."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "Certificate required but no certificate was given."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "No user found for certificate."
msgstr ""
#: authentik/enterprise/stages/source/models.py
msgid ""
"Amount of time a user can take to return from the source to continue the "
@ -1039,11 +963,8 @@ msgid "Starting full provider sync"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
#, python-brace-format
msgid "Syncing page {page} of users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
@ -1344,6 +1265,12 @@ msgstr ""
msgid "Clear Policy's cache metrics"
msgstr ""
#: authentik/policies/password/models.py
msgid "Field key to check, field keys defined in Prompt stages are available."
msgstr ""
"Veldsleutel om te controleren, veldsleutels gedefinieerd in Prompt-stadia "
"zijn beschikbaar."
#: authentik/policies/password/models.py
msgid "How many times the password hash is allowed to be on haveibeenpwned"
msgstr "Hoe vaak het wachtwoordhash op haveibeenpwned mag voorkomen"
@ -1355,6 +1282,10 @@ msgstr ""
"Als de zxcvbn-score gelijk is aan of lager is dan deze waarde, zal het "
"beleid falen."
#: authentik/policies/password/models.py
msgid "Password not set in context"
msgstr "Wachtwoord niet ingesteld in context"
#: authentik/policies/password/models.py
msgid "Invalid password."
msgstr ""
@ -1396,6 +1327,20 @@ msgstr "Reputatie Score"
msgid "Reputation Scores"
msgstr "Reputatie Scores"
#: authentik/policies/templates/policies/buffer.html
msgid "Waiting for authentication..."
msgstr ""
#: authentik/policies/templates/policies/buffer.html
msgid ""
"You're already authenticating in another tab. This page will refresh once "
"authentication is completed."
msgstr ""
#: authentik/policies/templates/policies/buffer.html
msgid "Authenticate in this tab"
msgstr ""
#: authentik/policies/templates/policies/denied.html
msgid "Permission denied"
msgstr "Toestemming geweigerd"
@ -2215,10 +2160,6 @@ msgstr ""
msgid "Roles"
msgstr ""
#: authentik/rbac/models.py
msgid "Initial Permissions"
msgstr ""
#: authentik/rbac/models.py
msgid "System permission"
msgstr ""
@ -2451,12 +2392,6 @@ msgid ""
"Active Directory"
msgstr ""
#: authentik/sources/ldap/models.py
msgid ""
"Delete authentik users and groups which were previously supplied by this "
"source, but are now missing from it."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "LDAP Source"
msgstr "LDAP-bron"
@ -2473,27 +2408,6 @@ msgstr ""
msgid "LDAP Source Property Mappings"
msgstr ""
#: authentik/sources/ldap/models.py
msgid ""
"Unique ID used while checking if this object still exists in the directory."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection"
msgstr ""
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connections"
msgstr ""
#: authentik/sources/ldap/models.py
msgid "Group LDAP Source Connection"
msgstr ""
#: authentik/sources/ldap/models.py
msgid "Group LDAP Source Connections"
msgstr ""
#: authentik/sources/ldap/signals.py
msgid "Password does not match Active Directory Complexity."
msgstr ""
@ -2503,14 +2417,6 @@ msgstr ""
msgid "No token received."
msgstr "Geen token ontvangen."
#: authentik/sources/oauth/models.py
msgid "HTTP Basic Authentication"
msgstr ""
#: authentik/sources/oauth/models.py
msgid "Include the client ID and secret as request parameters"
msgstr ""
#: authentik/sources/oauth/models.py
msgid "Request Token URL"
msgstr "URL voor aanvragen van token"
@ -2552,12 +2458,6 @@ msgstr ""
msgid "Additional Scopes"
msgstr "Aanvullende scopes"
#: authentik/sources/oauth/models.py
msgid ""
"How to perform authentication during an authorization_code token request "
"flow"
msgstr ""
#: authentik/sources/oauth/models.py
msgid "OAuth Source"
msgstr "OAuth-bron"
@ -2869,11 +2769,6 @@ msgstr ""
msgid "Group SAML Source Connections"
msgstr ""
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py
msgid "SCIM Source"
msgstr ""
@ -3247,10 +3142,6 @@ msgstr "Gebruikerstoestemming"
msgid "User Consents"
msgstr "Gebruikersinstemmingen"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py
msgid "Deny Stage"
msgstr "Weigerfase"
@ -3267,14 +3158,6 @@ msgstr "Dummystadium"
msgid "Dummy Stages"
msgstr "Dummystadia"
#: authentik/stages/email/flow.py
msgid "Continue to confirm this email address."
msgstr ""
#: authentik/stages/email/flow.py
msgid "Link was already used, please request a new link."
msgstr ""
#: authentik/stages/email/models.py
msgid "Password Reset"
msgstr "Wachtwoordherstel"
@ -3474,12 +3357,6 @@ msgstr ""
"Wanneer ingeschakeld, slaagt de stap en gaat verder wanneer ongeldige "
"gebruikersgegevens zijn ingevoerd."
#: authentik/stages/identification/models.py
msgid ""
"Show the user the 'Remember me on this device' toggle, allowing repeat users"
" to skip straight to entering their password."
msgstr ""
#: authentik/stages/identification/models.py
msgid "Optional enrollment flow, which is linked at the bottom of the page."
msgstr "Optionele inschrijvingsflow, die onderaan de pagina is gekoppeld."
@ -3865,14 +3742,6 @@ msgstr ""
"Gebeurtenissen worden verwijderd na deze duur. (Indeling: "
"weken=3;dagen=2;uren=3;seconden=2)."
#: authentik/tenants/models.py
msgid "Reputation cannot decrease lower than this value. Zero or negative."
msgstr ""
#: authentik/tenants/models.py
msgid "Reputation cannot increase higher than this value. Zero or positive."
msgstr ""
#: authentik/tenants/models.py
msgid "The option configures the footer links on the flow executor pages."
msgstr "De optie stelt de voettekst links in op de flow uitvoer pagina's."

View File

@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-05-28 11:25+0000\n"
"POT-Creation-Date: 2025-04-23 09:00+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Hugo Bicho, 2025\n"
"Language-Team: Portuguese (https://app.transifex.com/authentik/teams/119923/pt/)\n"
@ -105,10 +105,6 @@ msgstr ""
msgid "Web Certificate used by the authentik Core webserver."
msgstr "Certificado Web usado pelo servidor web authentik Core."
#: authentik/brands/models.py
msgid "Certificates used for client authentication."
msgstr ""
#: authentik/brands/models.py
msgid "Brand"
msgstr "Marca"
@ -666,33 +662,6 @@ msgstr "Dispositivos do ponto de ligação"
msgid "Verifying your browser..."
msgstr "A verificar o seu browser..."
#: authentik/enterprise/stages/mtls/models.py
msgid ""
"Configure certificate authorities to validate the certificate against. This "
"option has a higher priority than the `client_certificate` option on "
"`Brand`."
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stage"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stages"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Permissions to pass Certificates for outposts."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "Certificate required but no certificate was given."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "No user found for certificate."
msgstr ""
#: authentik/enterprise/stages/source/models.py
msgid ""
"Amount of time a user can take to return from the source to continue the "
@ -1038,12 +1007,9 @@ msgid "Starting full provider sync"
msgstr "Iniciando a sincronização completa com o provedor"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr ""
#, python-brace-format
msgid "Syncing page {page} of users"
msgstr "A sincronizar a página {page} dos utilizadores"
#: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format
@ -2490,12 +2456,6 @@ msgstr ""
" um atributo do grupo. Isto permite a resolução de grupos hierárquicos em "
"sistemas como o FreeIPA e Active Directory."
#: authentik/sources/ldap/models.py
msgid ""
"Delete authentik users and groups which were previously supplied by this "
"source, but are now missing from it."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "LDAP Source"
msgstr "Fonte LDAP"
@ -2512,11 +2472,6 @@ msgstr "Mapeamento de propriedades de fonte LDAP"
msgid "LDAP Source Property Mappings"
msgstr "Mapeamentos de propriedades de fonte LDAP"
#: authentik/sources/ldap/models.py
msgid ""
"Unique ID used while checking if this object still exists in the directory."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection"
msgstr "Ligação à fonte LDAP de Utilizador"
@ -2910,11 +2865,6 @@ msgstr "Ligação à fonte SAML de Grupo"
msgid "Group SAML Source Connections"
msgstr "Ligações à fonte SAML de Grupo"
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py
msgid "SCIM Source"
msgstr "Fonte SCIM"
@ -3305,10 +3255,6 @@ msgstr "Consentimento do Utilizador"
msgid "User Consents"
msgstr "Consentimentos do Utilizador"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py
msgid "Deny Stage"
msgstr "Etapa de negação"
@ -3325,14 +3271,6 @@ msgstr "Etapa fictícia"
msgid "Dummy Stages"
msgstr "Etapas fictícias"
#: authentik/stages/email/flow.py
msgid "Continue to confirm this email address."
msgstr ""
#: authentik/stages/email/flow.py
msgid "Link was already used, please request a new link."
msgstr ""
#: authentik/stages/email/models.py
msgid "Password Reset"
msgstr "Redefinição de Palavra-Passe"

Binary file not shown.

View File

@ -8,19 +8,19 @@
# Josenivaldo Benito Junior, 2023
# Caio Lima, 2023
# Hacklab, 2023
# Wagner Santos, 2024
# Rafael Mundel, 2024
# Anderson Silva Andrade <anderson.asa89@gmail.com>, 2025
# Gil Poiares-Oliveira, 2025
# Wagner Santos, 2025
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-05-28 11:25+0000\n"
"POT-Creation-Date: 2025-04-23 09:00+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Wagner Santos, 2025\n"
"Last-Translator: Gil Poiares-Oliveira, 2025\n"
"Language-Team: Portuguese (Brazil) (https://app.transifex.com/authentik/teams/119923/pt_BR/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -112,10 +112,6 @@ msgstr ""
msgid "Web Certificate used by the authentik Core webserver."
msgstr "Certificado da Web usado pelo servidor da web authentik Core."
#: authentik/brands/models.py
msgid "Certificates used for client authentication."
msgstr ""
#: authentik/brands/models.py
msgid "Brand"
msgstr "Brand"
@ -275,11 +271,11 @@ msgstr "Aplicativos"
#: authentik/core/models.py
msgid "Application Entitlement"
msgstr "Autorização de aplicação"
msgstr ""
#: authentik/core/models.py
msgid "Application Entitlements"
msgstr "Autorizações de aplicação"
msgstr ""
#: authentik/core/models.py
msgid "Use the source-specific identifier"
@ -383,15 +379,15 @@ msgstr "Mapeamentos de propriedades"
#: authentik/core/models.py
msgid "session data"
msgstr "dados de sessão"
msgstr ""
#: authentik/core/models.py
msgid "Session"
msgstr "Sessão"
msgstr ""
#: authentik/core/models.py
msgid "Sessions"
msgstr "Sessões"
msgstr ""
#: authentik/core/models.py
msgid "Authenticated Session"
@ -509,7 +505,7 @@ msgstr ""
#: authentik/enterprise/policies/unique_password/models.py
msgid "Number of passwords to check against."
msgstr "Número de senhas para verificar."
msgstr ""
#: authentik/enterprise/policies/unique_password/models.py
#: authentik/policies/password/models.py
@ -518,19 +514,19 @@ msgstr "Senha não definida no contexto"
#: authentik/enterprise/policies/unique_password/models.py
msgid "This password has been used previously. Please choose a different one."
msgstr "A senha já foi utilizada antes. Por favor, escolha uma diferente."
msgstr ""
#: authentik/enterprise/policies/unique_password/models.py
msgid "Password Uniqueness Policy"
msgstr "Política de exclusividade de senha"
msgstr ""
#: authentik/enterprise/policies/unique_password/models.py
msgid "Password Uniqueness Policies"
msgstr "Políticas de exclusividade de senha"
msgstr ""
#: authentik/enterprise/policies/unique_password/models.py
msgid "User Password History"
msgstr "Histórico de senhas do usuário"
msgstr ""
#: authentik/enterprise/policy.py
msgid "Enterprise required to access this feature."
@ -614,39 +610,39 @@ msgstr "Chave de Assinatura"
#: authentik/enterprise/providers/ssf/models.py
msgid "Key used to sign the SSF Events."
msgstr "Chave utilizada para assinar os eventos SSF."
msgstr ""
#: authentik/enterprise/providers/ssf/models.py
msgid "Shared Signals Framework Provider"
msgstr "Provedor de Shared Signals Framework"
msgstr ""
#: authentik/enterprise/providers/ssf/models.py
msgid "Shared Signals Framework Providers"
msgstr "Provedores de Shared Signals Framework"
msgstr ""
#: authentik/enterprise/providers/ssf/models.py
msgid "Add stream to SSF provider"
msgstr "Adicionar stream ao fornecedor SSF"
msgstr ""
#: authentik/enterprise/providers/ssf/models.py
msgid "SSF Stream"
msgstr "Stream SSF"
msgstr ""
#: authentik/enterprise/providers/ssf/models.py
msgid "SSF Streams"
msgstr "Streams SSF"
msgstr ""
#: authentik/enterprise/providers/ssf/models.py
msgid "SSF Stream Event"
msgstr "Evento de stream SSF"
msgstr ""
#: authentik/enterprise/providers/ssf/models.py
msgid "SSF Stream Events"
msgstr "Eventos de stream SSF"
msgstr ""
#: authentik/enterprise/providers/ssf/tasks.py
msgid "Failed to send request"
msgstr "Falha ao enviar requisição"
msgstr ""
#: authentik/enterprise/stages/authenticator_endpoint_gdtc/models.py
msgid "Endpoint Authenticator Google Device Trust Connector Stage"
@ -668,33 +664,6 @@ msgstr ""
msgid "Verifying your browser..."
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid ""
"Configure certificate authorities to validate the certificate against. This "
"option has a higher priority than the `client_certificate` option on "
"`Brand`."
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stage"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stages"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Permissions to pass Certificates for outposts."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "Certificate required but no certificate was given."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "No user found for certificate."
msgstr ""
#: authentik/enterprise/stages/source/models.py
msgid ""
"Amount of time a user can take to return from the source to continue the "
@ -712,7 +681,7 @@ msgstr ""
#: authentik/events/api/tasks.py
#, python-brace-format
msgid "Successfully started task {name}."
msgstr "Tarefa {name} iniciada com sucesso."
msgstr ""
#: authentik/events/models.py
msgid "Event"
@ -744,16 +713,12 @@ msgid ""
"Customize the body of the request. Mapping should return data that is JSON-"
"serializable."
msgstr ""
"Personalize o corpo do pedido. O mapeamento deve retornar dados que sejam "
"serializáveis em JSON."
#: authentik/events/models.py
msgid ""
"Configure additional headers to be sent. Mapping should return a dictionary "
"of key-value pairs"
msgstr ""
"Configurar cabeçalhos adicionais a serem enviados. O mapeamento deve "
"retornar um dicionário de pares chave-valor"
#: authentik/events/models.py
msgid ""
@ -1033,11 +998,8 @@ msgid "Starting full provider sync"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
#, python-brace-format
msgid "Syncing page {page} of users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
@ -1352,7 +1314,7 @@ msgstr ""
#: authentik/policies/password/models.py
#, python-brace-format
msgid "Password exists on {count} online lists."
msgstr "A senha está presente em {count} listas de senhas vulneráveis."
msgstr ""
#: authentik/policies/password/models.py
msgid "Password is too weak."
@ -2434,12 +2396,6 @@ msgid ""
"Active Directory"
msgstr ""
#: authentik/sources/ldap/models.py
msgid ""
"Delete authentik users and groups which were previously supplied by this "
"source, but are now missing from it."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "LDAP Source"
msgstr "Fonte LDAP"
@ -2456,11 +2412,6 @@ msgstr ""
msgid "LDAP Source Property Mappings"
msgstr ""
#: authentik/sources/ldap/models.py
msgid ""
"Unique ID used while checking if this object still exists in the directory."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection"
msgstr ""
@ -2851,11 +2802,6 @@ msgstr ""
msgid "Group SAML Source Connections"
msgstr ""
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py
msgid "SCIM Source"
msgstr ""
@ -3228,10 +3174,6 @@ msgstr "Consentimento do usuário"
msgid "User Consents"
msgstr "Consentimentos do usuário"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py
msgid "Deny Stage"
msgstr "Negar Estágio"
@ -3248,14 +3190,6 @@ msgstr "Palco fictício"
msgid "Dummy Stages"
msgstr "Fases fictícias"
#: authentik/stages/email/flow.py
msgid "Continue to confirm this email address."
msgstr ""
#: authentik/stages/email/flow.py
msgid "Link was already used, please request a new link."
msgstr ""
#: authentik/stages/email/models.py
msgid "Password Reset"
msgstr "Redefinição de senha"

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-05-28 11:25+0000\n"
"POT-Creation-Date: 2025-04-23 09:00+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Marc Schmitt, 2025\n"
"Language-Team: Russian (https://app.transifex.com/authentik/teams/119923/ru/)\n"
@ -111,10 +111,6 @@ msgstr ""
msgid "Web Certificate used by the authentik Core webserver."
msgstr "Web Certificate используемый для authentik Core webserver."
#: authentik/brands/models.py
msgid "Certificates used for client authentication."
msgstr ""
#: authentik/brands/models.py
msgid "Brand"
msgstr "Бренд"
@ -673,33 +669,6 @@ msgstr "Конечные устройства"
msgid "Verifying your browser..."
msgstr "Проверка вашего браузера..."
#: authentik/enterprise/stages/mtls/models.py
msgid ""
"Configure certificate authorities to validate the certificate against. This "
"option has a higher priority than the `client_certificate` option on "
"`Brand`."
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stage"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stages"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Permissions to pass Certificates for outposts."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "Certificate required but no certificate was given."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "No user found for certificate."
msgstr ""
#: authentik/enterprise/stages/source/models.py
msgid ""
"Amount of time a user can take to return from the source to continue the "
@ -1040,11 +1009,8 @@ msgid "Starting full provider sync"
msgstr "Запуск полной синхронизации провайдера"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
#, python-brace-format
msgid "Syncing page {page} of users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
@ -2464,12 +2430,6 @@ msgid ""
"Active Directory"
msgstr ""
#: authentik/sources/ldap/models.py
msgid ""
"Delete authentik users and groups which were previously supplied by this "
"source, but are now missing from it."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "LDAP Source"
msgstr "Источник LDAP"
@ -2486,11 +2446,6 @@ msgstr "Сопоставление свойства LDAP источника"
msgid "LDAP Source Property Mappings"
msgstr "Сопоставление свойств LDAP источника"
#: authentik/sources/ldap/models.py
msgid ""
"Unique ID used while checking if this object still exists in the directory."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection"
msgstr ""
@ -2887,11 +2842,6 @@ msgstr "Групповое подключение к источнику SAML"
msgid "Group SAML Source Connections"
msgstr "Групповые подключения к источнику SAML"
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py
msgid "SCIM Source"
msgstr "Источник SCIM"
@ -3269,10 +3219,6 @@ msgstr "Согласие пользователя"
msgid "User Consents"
msgstr "Согласия пользователя"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py
msgid "Deny Stage"
msgstr "Этап отказа"
@ -3289,14 +3235,6 @@ msgstr "Фиктивный этап"
msgid "Dummy Stages"
msgstr "Фиктивные этапы"
#: authentik/stages/email/flow.py
msgid "Continue to confirm this email address."
msgstr ""
#: authentik/stages/email/flow.py
msgid "Link was already used, please request a new link."
msgstr ""
#: authentik/stages/email/models.py
msgid "Password Reset"
msgstr "Сброс пароля"

View File

@ -13,7 +13,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-05-28 11:25+0000\n"
"POT-Creation-Date: 2025-04-23 09:00+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Jens L. <jens@goauthentik.io>, 2025\n"
"Language-Team: Turkish (https://app.transifex.com/authentik/teams/119923/tr/)\n"
@ -107,10 +107,6 @@ msgstr ""
msgid "Web Certificate used by the authentik Core webserver."
msgstr "Authentik Core web sunucusu tarafından kullanılan Web Sertifikası."
#: authentik/brands/models.py
msgid "Certificates used for client authentication."
msgstr ""
#: authentik/brands/models.py
msgid "Brand"
msgstr "Marka"
@ -663,33 +659,6 @@ msgstr "Uç Nokta Cihazları"
msgid "Verifying your browser..."
msgstr "Tarayıcınız doğrulanıyor..."
#: authentik/enterprise/stages/mtls/models.py
msgid ""
"Configure certificate authorities to validate the certificate against. This "
"option has a higher priority than the `client_certificate` option on "
"`Brand`."
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stage"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stages"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Permissions to pass Certificates for outposts."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "Certificate required but no certificate was given."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "No user found for certificate."
msgstr ""
#: authentik/enterprise/stages/source/models.py
msgid ""
"Amount of time a user can take to return from the source to continue the "
@ -1031,11 +1000,8 @@ msgid "Starting full provider sync"
msgstr "Tam sağlayıcı senkronizasyonunu başlatma"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
#, python-brace-format
msgid "Syncing page {page} of users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
@ -2464,12 +2430,6 @@ msgid ""
"Active Directory"
msgstr ""
#: authentik/sources/ldap/models.py
msgid ""
"Delete authentik users and groups which were previously supplied by this "
"source, but are now missing from it."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "LDAP Source"
msgstr "LDAP Kaynağı"
@ -2486,11 +2446,6 @@ msgstr "LDAP Kaynak Özellik Eşlemesi"
msgid "LDAP Source Property Mappings"
msgstr "LDAP Kaynak Özellik Eşlemeleri"
#: authentik/sources/ldap/models.py
msgid ""
"Unique ID used while checking if this object still exists in the directory."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection"
msgstr ""
@ -2882,11 +2837,6 @@ msgstr "Grup SAML Kaynak Bağlantısı"
msgid "Group SAML Source Connections"
msgstr "Grup SAML Kaynak Bağlantıları"
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py
msgid "SCIM Source"
msgstr "SCIM Kaynak"
@ -3261,10 +3211,6 @@ msgstr "Kullanıcı Onayı"
msgid "User Consents"
msgstr "Kullanıcı Onayları"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py
msgid "Deny Stage"
msgstr "Aşama Alanını Reddet"
@ -3281,14 +3227,6 @@ msgstr "Kukla Aşaması"
msgid "Dummy Stages"
msgstr "Kukla Aşamaları"
#: authentik/stages/email/flow.py
msgid "Continue to confirm this email address."
msgstr ""
#: authentik/stages/email/flow.py
msgid "Link was already used, please request a new link."
msgstr ""
#: authentik/stages/email/models.py
msgid "Password Reset"
msgstr "Parola Sıfırlama"

Binary file not shown.

View File

@ -15,7 +15,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-05-28 11:25+0000\n"
"POT-Creation-Date: 2025-05-20 00:10+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: deluxghost, 2025\n"
"Language-Team: Chinese Simplified (https://app.transifex.com/authentik/teams/119923/zh-Hans/)\n"
@ -975,12 +975,9 @@ msgid "Starting full provider sync"
msgstr "开始全量提供程序同步"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr ""
#, python-brace-format
msgid "Syncing page {page} of users"
msgstr "正在同步用户页面 {page}"
#: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format
@ -2288,12 +2285,6 @@ msgid ""
"Active Directory"
msgstr "基于用户属性而非组属性查询组成员身份。这允许在 FreeIPA 或 Active Directory 等系统上支持嵌套组决策"
#: authentik/sources/ldap/models.py
msgid ""
"Delete authentik users and groups which were previously supplied by this "
"source, but are now missing from it."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "LDAP Source"
msgstr "LDAP 源"
@ -2310,11 +2301,6 @@ msgstr "LDAP 源属性映射"
msgid "LDAP Source Property Mappings"
msgstr "LDAP 源属性映射"
#: authentik/sources/ldap/models.py
msgid ""
"Unique ID used while checking if this object still exists in the directory."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection"
msgstr "用户 LDAP 源连接"
@ -2692,11 +2678,6 @@ msgstr "组 SAML 源连接"
msgid "Group SAML Source Connections"
msgstr "组 SAML 源连接"
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py
msgid "SCIM Source"
msgstr "SCIM 源"
@ -3063,10 +3044,6 @@ msgstr "用户同意授权"
msgid "User Consents"
msgstr "用户同意授权"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py
msgid "Deny Stage"
msgstr "拒绝阶段"
@ -3083,14 +3060,6 @@ msgstr "虚拟阶段"
msgid "Dummy Stages"
msgstr "虚拟阶段"
#: authentik/stages/email/flow.py
msgid "Continue to confirm this email address."
msgstr ""
#: authentik/stages/email/flow.py
msgid "Link was already used, please request a new link."
msgstr ""
#: authentik/stages/email/models.py
msgid "Password Reset"
msgstr "密码重置"

Binary file not shown.

View File

@ -14,7 +14,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-05-28 11:25+0000\n"
"POT-Creation-Date: 2025-05-20 00:10+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: deluxghost, 2025\n"
"Language-Team: Chinese (China) (https://app.transifex.com/authentik/teams/119923/zh_CN/)\n"
@ -974,12 +974,9 @@ msgid "Starting full provider sync"
msgstr "开始全量提供程序同步"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr ""
#, python-brace-format
msgid "Syncing page {page} of users"
msgstr "正在同步用户页面 {page}"
#: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format
@ -2287,12 +2284,6 @@ msgid ""
"Active Directory"
msgstr "基于用户属性而非组属性查询组成员身份。这允许在 FreeIPA 或 Active Directory 等系统上支持嵌套组决策"
#: authentik/sources/ldap/models.py
msgid ""
"Delete authentik users and groups which were previously supplied by this "
"source, but are now missing from it."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "LDAP Source"
msgstr "LDAP 源"
@ -2309,11 +2300,6 @@ msgstr "LDAP 源属性映射"
msgid "LDAP Source Property Mappings"
msgstr "LDAP 源属性映射"
#: authentik/sources/ldap/models.py
msgid ""
"Unique ID used while checking if this object still exists in the directory."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection"
msgstr "用户 LDAP 源连接"
@ -2691,11 +2677,6 @@ msgstr "组 SAML 源连接"
msgid "Group SAML Source Connections"
msgstr "组 SAML 源连接"
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py
msgid "SCIM Source"
msgstr "SCIM 源"
@ -3062,10 +3043,6 @@ msgstr "用户同意授权"
msgid "User Consents"
msgstr "用户同意授权"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py
msgid "Deny Stage"
msgstr "拒绝阶段"
@ -3082,14 +3059,6 @@ msgstr "虚拟阶段"
msgid "Dummy Stages"
msgstr "虚拟阶段"
#: authentik/stages/email/flow.py
msgid "Continue to confirm this email address."
msgstr ""
#: authentik/stages/email/flow.py
msgid "Link was already used, please request a new link."
msgstr ""
#: authentik/stages/email/models.py
msgid "Password Reset"
msgstr "密码重置"

View File

@ -14,7 +14,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-05-28 11:25+0000\n"
"POT-Creation-Date: 2025-04-23 09:00+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: 刘松, 2025\n"
"Language-Team: Chinese (Taiwan) (https://app.transifex.com/authentik/teams/119923/zh_TW/)\n"
@ -101,10 +101,6 @@ msgstr ""
msgid "Web Certificate used by the authentik Core webserver."
msgstr "用於 authentik Core 網頁伺服器的網頁憑證。"
#: authentik/brands/models.py
msgid "Certificates used for client authentication."
msgstr ""
#: authentik/brands/models.py
msgid "Brand"
msgstr "品牌"
@ -629,33 +625,6 @@ msgstr ""
msgid "Verifying your browser..."
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid ""
"Configure certificate authorities to validate the certificate against. This "
"option has a higher priority than the `client_certificate` option on "
"`Brand`."
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stage"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stages"
msgstr ""
#: authentik/enterprise/stages/mtls/models.py
msgid "Permissions to pass Certificates for outposts."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "Certificate required but no certificate was given."
msgstr ""
#: authentik/enterprise/stages/mtls/stage.py
msgid "No user found for certificate."
msgstr ""
#: authentik/enterprise/stages/source/models.py
msgid ""
"Amount of time a user can take to return from the source to continue the "
@ -974,11 +943,8 @@ msgid "Starting full provider sync"
msgstr "開始同步所有提供程式"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
#, python-brace-format
msgid "Syncing page {page} of users"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
@ -2283,12 +2249,6 @@ msgid ""
"Active Directory"
msgstr ""
#: authentik/sources/ldap/models.py
msgid ""
"Delete authentik users and groups which were previously supplied by this "
"source, but are now missing from it."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "LDAP Source"
msgstr "LDAP 來源"
@ -2305,11 +2265,6 @@ msgstr ""
msgid "LDAP Source Property Mappings"
msgstr ""
#: authentik/sources/ldap/models.py
msgid ""
"Unique ID used while checking if this object still exists in the directory."
msgstr ""
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection"
msgstr ""
@ -2687,11 +2642,6 @@ msgstr ""
msgid "Group SAML Source Connections"
msgstr ""
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py
msgid "SCIM Source"
msgstr "SCIM 來源"
@ -3048,10 +2998,6 @@ msgstr "使用者同意"
msgid "User Consents"
msgstr "使用者同意"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py
msgid "Deny Stage"
msgstr "拒絕階段"
@ -3068,14 +3014,6 @@ msgstr "假階段"
msgid "Dummy Stages"
msgstr "假階段"
#: authentik/stages/email/flow.py
msgid "Continue to confirm this email address."
msgstr ""
#: authentik/stages/email/flow.py
msgid "Link was already used, please request a new link."
msgstr ""
#: authentik/stages/email/models.py
msgid "Password Reset"
msgstr "重設密碼"

View File

@ -3710,9 +3710,9 @@
}
},
"node_modules/@goauthentik/prettier-config": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@goauthentik/prettier-config/-/prettier-config-1.0.5.tgz",
"integrity": "sha512-3W1uJvhzBPerDao53hSXhNzB7Ev8DbGYh+gVkuku1FaUZGBpiwD/6U3ah4sny8NoRiObGQ1geF4dhNLtlRbC/Q==",
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@goauthentik/prettier-config/-/prettier-config-1.0.4.tgz",
"integrity": "sha512-CgUVAThlJHif7ZRXUPMbR/7/YLGzkJw7YbqEcleUjjKkvID0aykrypXx04td6cG76zigspTCgJKoXimKT41E7g==",
"dev": true,
"license": "MIT",
"engines": {
@ -3722,7 +3722,7 @@
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
"prettier": "^3.5.3",
"prettier-plugin-organize-imports": "^4.1.0",
"prettier-plugin-packagejson": "^2.5.14"
"prettier-plugin-packagejson": "^2.5.10"
}
},
"node_modules/@goauthentik/tsconfig": {

View File

@ -308,9 +308,9 @@
}
},
"node_modules/@goauthentik/prettier-config": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@goauthentik/prettier-config/-/prettier-config-1.0.5.tgz",
"integrity": "sha512-3W1uJvhzBPerDao53hSXhNzB7Ev8DbGYh+gVkuku1FaUZGBpiwD/6U3ah4sny8NoRiObGQ1geF4dhNLtlRbC/Q==",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@goauthentik/prettier-config/-/prettier-config-1.0.1.tgz",
"integrity": "sha512-6N0cCG3Uw3Nt+gTxRJ/FYFi/NfuL849CrQkrx307PvEBaG66OjxFFee4bhS/si4XvLdxFdog7oQsPwYmqZeZ+w==",
"dev": true,
"license": "MIT",
"engines": {
@ -320,13 +320,13 @@
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
"prettier": "^3.5.3",
"prettier-plugin-organize-imports": "^4.1.0",
"prettier-plugin-packagejson": "^2.5.14"
"prettier-plugin-packagejson": "^2.5.10"
}
},
"node_modules/@goauthentik/tsconfig": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@goauthentik/tsconfig/-/tsconfig-1.0.4.tgz",
"integrity": "sha512-BTGVpGh8SbCRHTULBf+2WTcw6OHJ8Ws9VtVfAMUUgcq8whbH/A7Q/n8WbkDaEeihzHUFkLk3JBenHKzEKAZWlw==",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@goauthentik/tsconfig/-/tsconfig-1.0.1.tgz",
"integrity": "sha512-kxMDkgUHhAmQ2iIhUZJjrx/CgDb1AwvRoPtU4vrjAZu7x66+qczCjRTK+GzIGCeqB97GEpvCCjU8CThmozVFqA==",
"dev": true,
"license": "MIT",
"engines": {
@ -491,9 +491,9 @@
}
},
"node_modules/@pkgr/core": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.4.tgz",
"integrity": "sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==",
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.2.tgz",
"integrity": "sha512-fdDH1LSGfZdTH2sxdpVMw31BanV28K/Gry0cVFxaNP77neJSkd82mM8ErPNYs9e+0O7SdHBLTDzDgwUuy18RnQ==",
"dev": true,
"license": "MIT",
"peer": true,
@ -501,7 +501,7 @@
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/pkgr"
"url": "https://opencollective.com/unts"
}
},
"node_modules/@rtsao/scc": {
@ -2045,6 +2045,20 @@
"node": ">= 0.4"
}
},
"node_modules/get-stdin": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz",
"integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/get-symbol-description": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
@ -2063,9 +2077,9 @@
}
},
"node_modules/git-hooks-list": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/git-hooks-list/-/git-hooks-list-4.1.1.tgz",
"integrity": "sha512-cmP497iLq54AZnv4YRAEMnEyQ1eIn4tGKbmswqwmFV4GBnAqE8NLtWxxdXa++AalfgL5EBH4IxTPyquEuGY/jA==",
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/git-hooks-list/-/git-hooks-list-3.2.0.tgz",
"integrity": "sha512-ZHG9a1gEhUMX1TvGrLdyWb9kDopCBbTnI8z4JgRMYxsijWipgjSEYoPWqBuIB0DnRnvqlQSEeVmzpeuPm7NdFQ==",
"dev": true,
"license": "MIT",
"peer": true,
@ -3205,15 +3219,15 @@
}
},
"node_modules/prettier-plugin-packagejson": {
"version": "2.5.14",
"resolved": "https://registry.npmjs.org/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.14.tgz",
"integrity": "sha512-h+3tSpr2nVpp+YOK1MDIYtYhHVXr8/0V59UUbJpIJFaqi3w4fvUokJo6eV8W+vELrUXIZzJ+DKm5G7lYzrMcKQ==",
"version": "2.5.10",
"resolved": "https://registry.npmjs.org/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.10.tgz",
"integrity": "sha512-LUxATI5YsImIVSaaLJlJ3aE6wTD+nvots18U3GuQMJpUyClChaZlQrqx3dBnbhF20OnKWZyx8EgyZypQtBDtgQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"sort-package-json": "3.2.1",
"synckit": "0.11.6"
"sort-package-json": "2.15.1",
"synckit": "0.9.2"
},
"peerDependencies": {
"prettier": ">= 1.16.0"
@ -3619,29 +3633,30 @@
"peer": true
},
"node_modules/sort-package-json": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/sort-package-json/-/sort-package-json-3.2.1.tgz",
"integrity": "sha512-rTfRdb20vuoAn7LDlEtCqOkYfl2X+Qze6cLbNOzcDpbmKEhJI30tTN44d5shbKJnXsvz24QQhlCm81Bag7EOKg==",
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/sort-package-json/-/sort-package-json-2.15.1.tgz",
"integrity": "sha512-9x9+o8krTT2saA9liI4BljNjwAbvUnWf11Wq+i/iZt8nl2UGYnf3TH5uBydE7VALmP7AGwlfszuEeL8BDyb0YA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"detect-indent": "^7.0.1",
"detect-newline": "^4.0.1",
"git-hooks-list": "^4.0.0",
"detect-newline": "^4.0.0",
"get-stdin": "^9.0.0",
"git-hooks-list": "^3.0.0",
"is-plain-obj": "^4.1.0",
"semver": "^7.7.1",
"semver": "^7.6.0",
"sort-object-keys": "^1.1.3",
"tinyglobby": "^0.2.12"
"tinyglobby": "^0.2.9"
},
"bin": {
"sort-package-json": "cli.js"
}
},
"node_modules/sort-package-json/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"version": "7.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
"dev": true,
"license": "ISC",
"peer": true,
@ -3791,31 +3806,32 @@
}
},
"node_modules/synckit": {
"version": "0.11.6",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.6.tgz",
"integrity": "sha512-2pR2ubZSV64f/vqm9eLPz/KOvR9Dm+Co/5ChLgeHl0yEDRc6h5hXHoxEQH8Y5Ljycozd3p1k5TTSVdzYGkPvLw==",
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz",
"integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@pkgr/core": "^0.2.4"
"@pkgr/core": "^0.1.0",
"tslib": "^2.6.2"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/synckit"
"url": "https://opencollective.com/unts"
}
},
"node_modules/tinyglobby": {
"version": "0.2.13",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz",
"integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==",
"version": "0.2.12",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz",
"integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"fdir": "^6.4.4",
"fdir": "^6.4.3",
"picomatch": "^4.0.2"
},
"engines": {
@ -3826,9 +3842,9 @@
}
},
"node_modules/tinyglobby/node_modules/fdir": {
"version": "6.4.4",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz",
"integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==",
"version": "6.4.3",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz",
"integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==",
"dev": true,
"license": "MIT",
"peer": true,
@ -3893,6 +3909,14 @@
"strip-bom": "^3.0.0"
}
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"dev": true,
"license": "0BSD",
"peer": true
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",

View File

@ -38,20 +38,17 @@ export const AuthentikPrettierConfig = {
],
importOrder: [
// ---
"^(@goauthentik/|#)common.+",
"^(@goauthentik/|#)elements.+",
"^(@goauthentik/|#)components.+",
"^(@goauthentik/|#)user.+",
"^(@goauthentik/|#)admin.+",
"^(@goauthentik/|#)flow.+",
"^(@goauthentik/|#)flow.+",
"^#.+",
"^@goauthentik.+",
"<THIRD_PARTY_MODULES>",
"^~@goauthentik.+",
"^@goauthentik.+",
"^(@?)lit(.*)$",
"\\.css$",
"^@goauthentik/api$",

View File

@ -1,12 +1,12 @@
{
"name": "@goauthentik/prettier-config",
"version": "2.0.0",
"version": "1.0.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@goauthentik/prettier-config",
"version": "2.0.0",
"version": "1.0.4",
"license": "MIT",
"devDependencies": {
"@goauthentik/tsconfig": "^1.0.1",
@ -143,9 +143,9 @@
}
},
"node_modules/@goauthentik/tsconfig": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@goauthentik/tsconfig/-/tsconfig-1.0.4.tgz",
"integrity": "sha512-BTGVpGh8SbCRHTULBf+2WTcw6OHJ8Ws9VtVfAMUUgcq8whbH/A7Q/n8WbkDaEeihzHUFkLk3JBenHKzEKAZWlw==",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@goauthentik/tsconfig/-/tsconfig-1.0.1.tgz",
"integrity": "sha512-kxMDkgUHhAmQ2iIhUZJjrx/CgDb1AwvRoPtU4vrjAZu7x66+qczCjRTK+GzIGCeqB97GEpvCCjU8CThmozVFqA==",
"dev": true,
"license": "MIT",
"engines": {

View File

@ -1,6 +1,6 @@
{
"name": "@goauthentik/prettier-config",
"version": "2.0.0",
"version": "1.1.0",
"description": "authentik's Prettier config",
"license": "MIT",
"scripts": {

View File

@ -9,7 +9,7 @@ dependencies = [
"celery==5.5.2",
"channels==4.2.2",
"channels-redis==4.2.1",
"cryptography==45.0.3",
"cryptography==44.0.3",
"dacite==1.9.2",
"deepmerge==2.0",
"defusedxml==0.7.1",
@ -23,7 +23,7 @@ dependencies = [
"django-prometheus==2.3.1",
"django-redis==5.4.0",
"django-storages[s3]==1.14.6",
"django-tenants==3.8.0",
"django-tenants==3.7.0",
"djangorestframework==3.16.0",
"djangorestframework-guardian==0.3.0",
"docker==7.1.0",
@ -43,7 +43,7 @@ dependencies = [
"kubernetes==32.0.1",
"ldap3==2.9.1",
"lxml==5.4.0",
"msgraph-sdk==1.31.0",
"msgraph-sdk==1.30.0",
"opencontainers==0.0.14",
"packaging==25.0",
"paramiko==3.5.1",
@ -114,6 +114,7 @@ no-binary-package = [
]
[tool.uv.sources]
django-tenants = { git = "https://github.com/goauthentik/django-tenants.git", branch = "authentik-fixes" }
opencontainers = { git = "https://github.com/vsoch/oci-python", rev = "ceb4fcc090851717a3069d78e85ceb1e86c2740c" }
djangorestframework = { git = "https://github.com/goauthentik/django-rest-framework", rev = "896722bab969fabc74a08b827da59409cf9f1a4e" }

View File

@ -28473,10 +28473,6 @@ paths:
schema:
type: string
format: uuid
- in: query
name: delete_not_found_objects
schema:
type: boolean
- in: query
name: enabled
schema:
@ -47926,10 +47922,6 @@ components:
description: Lookup group membership based on a user attribute instead of
a group attribute. This allows nested group resolution on systems like
FreeIPA and Active Directory
delete_not_found_objects:
type: boolean
description: Delete authentik users and groups which were previously supplied
by this source, but are now missing from it.
required:
- base_dn
- component
@ -48131,10 +48123,6 @@ components:
description: Lookup group membership based on a user attribute instead of
a group attribute. This allows nested group resolution on systems like
FreeIPA and Active Directory
delete_not_found_objects:
type: boolean
description: Delete authentik users and groups which were previously supplied
by this source, but are now missing from it.
required:
- base_dn
- name
@ -53468,10 +53456,6 @@ components:
description: Lookup group membership based on a user attribute instead of
a group attribute. This allows nested group resolution on systems like
FreeIPA and Active Directory
delete_not_found_objects:
type: boolean
description: Delete authentik users and groups which were previously supplied
by this source, but are now missing from it.
PatchedLicenseRequest:
type: object
description: License Serializer

View File

@ -1,7 +0,0 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "dist/esm",
},
}

View File

@ -1,23 +0,0 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"composite": true,
"isolatedModules": true,
"incremental": true,
"baseUrl": ".",
"rootDir": "src",
"strict": true,
"newLine": "lf",
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"outDir": "dist",
"skipDefaultLibCheck": true,
"skipLibCheck": true,
"sourceMap": true,
"declaration": true,
"declarationMap": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
},
"exclude": ["node_modules", "./out/**/*", "./dist/**/*"],
}

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
set -e -x -o pipefail
hash="$(git rev-parse HEAD || openssl rand -base64 36 | sha256sum)"

View File

@ -1,13 +1,12 @@
services:
chrome:
platform: linux/x86_64
image: docker.io/selenium/standalone-chrome:136.0
volumes:
- /dev/shm:/dev/shm
network_mode: host
restart: always
mailpit:
image: docker.io/axllent/mailpit:v1.25.1
image: docker.io/axllent/mailpit:v1.25.0
ports:
- 1025:1025
- 8025:8025

View File

@ -10,7 +10,6 @@ from authentik.blueprints.tests import apply_blueprint
from authentik.core.models import User
from authentik.flows.models import Flow
from authentik.lib.config import CONFIG
from authentik.lib.generators import generate_id
from authentik.stages.identification.models import IdentificationStage
from tests.e2e.utils import SeleniumTestCase, retry
@ -18,10 +17,6 @@ from tests.e2e.utils import SeleniumTestCase, retry
class TestFlowsEnroll(SeleniumTestCase):
"""Test Enroll flow"""
def setUp(self):
super().setUp()
self.username = generate_id()
@retry()
@apply_blueprint(
"default/flow-default-authentication-flow.yaml",
@ -44,8 +39,8 @@ class TestFlowsEnroll(SeleniumTestCase):
self.initial_stages()
sleep(2)
user = User.objects.get(username=self.username)
self.assertEqual(user.username, self.username)
user = User.objects.get(username="foo")
self.assertEqual(user.username, "foo")
self.assertEqual(user.name, "some name")
self.assertEqual(user.email, "foo@bar.baz")
@ -92,16 +87,7 @@ class TestFlowsEnroll(SeleniumTestCase):
sleep(2)
flow_executor = self.get_shadow_root("ak-flow-executor")
consent_stage = self.get_shadow_root("ak-stage-consent", flow_executor)
consent_stage.find_element(
By.CSS_SELECTOR,
"[type=submit]",
).click()
self.wait_for_url(self.if_user_url())
self.assert_user(User.objects.get(username=self.username))
self.assert_user(User.objects.get(username="foo"))
def initial_stages(self):
"""Fill out initial stages"""
@ -119,7 +105,7 @@ class TestFlowsEnroll(SeleniumTestCase):
wait = WebDriverWait(prompt_stage, self.wait_timeout)
wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "input[name=username]")))
prompt_stage.find_element(By.CSS_SELECTOR, "input[name=username]").send_keys(self.username)
prompt_stage.find_element(By.CSS_SELECTOR, "input[name=username]").send_keys("foo")
prompt_stage.find_element(By.CSS_SELECTOR, "input[name=password]").send_keys(
self.user.username
)
@ -138,82 +124,3 @@ class TestFlowsEnroll(SeleniumTestCase):
prompt_stage.find_element(By.CSS_SELECTOR, "input[name=name]").send_keys("some name")
prompt_stage.find_element(By.CSS_SELECTOR, "input[name=email]").send_keys("foo@bar.baz")
prompt_stage.find_element(By.CSS_SELECTOR, ".pf-c-button").click()
@retry()
@apply_blueprint(
"default/flow-default-authentication-flow.yaml",
"default/flow-default-invalidation-flow.yaml",
)
@apply_blueprint(
"example/flows-enrollment-email-verification.yaml",
)
@CONFIG.patch("email.port", 1025)
def test_enroll_email_pretend_email_scanner(self):
"""Test enroll with Email verification. Open the email link twice to pretend we have an
email scanner that clicks on links"""
# Attach enrollment flow to identification stage
ident_stage: IdentificationStage = IdentificationStage.objects.get(
name="default-authentication-identification"
)
ident_stage.enrollment_flow = Flow.objects.get(slug="default-enrollment-flow")
ident_stage.save()
self.driver.get(self.live_server_url)
self.initial_stages()
# Email stage
flow_executor = self.get_shadow_root("ak-flow-executor")
email_stage = self.get_shadow_root("ak-stage-email", flow_executor)
wait = WebDriverWait(email_stage, self.wait_timeout)
# Wait for the success message so we know the email is sent
wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, ".pf-c-form p")))
# Open Mailpit
self.driver.get("http://localhost:8025")
# Click on first message
self.wait.until(ec.presence_of_element_located((By.CLASS_NAME, "message")))
self.driver.find_element(By.CLASS_NAME, "message").click()
self.driver.switch_to.frame(self.driver.find_element(By.ID, "preview-html"))
confirmation_link = self.driver.find_element(By.ID, "confirm").get_attribute("href")
main_tab = self.driver.current_window_handle
self.driver.switch_to.new_window("tab")
confirm_tab = self.driver.current_window_handle
# On the new tab, check that we have the confirmation screen
self.driver.get(confirmation_link)
self.wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "ak-flow-executor")))
flow_executor = self.get_shadow_root("ak-flow-executor")
consent_stage = self.get_shadow_root("ak-stage-consent", flow_executor)
self.assertEqual(
"Continue to confirm this email address.",
consent_stage.find_element(By.CSS_SELECTOR, "#header-text").text,
)
# Back on the main tab, confirm
self.driver.switch_to.window(main_tab)
self.driver.get(confirmation_link)
flow_executor = self.get_shadow_root("ak-flow-executor")
consent_stage = self.get_shadow_root("ak-stage-consent", flow_executor)
consent_stage.find_element(
By.CSS_SELECTOR,
"[type=submit]",
).click()
self.wait_for_url(self.if_user_url())
sleep(2)
self.assert_user(User.objects.get(username=self.username))
self.driver.switch_to.window(confirm_tab)
self.driver.refresh()
flow_executor = self.get_shadow_root("ak-flow-executor")
wait = WebDriverWait(flow_executor, self.wait_timeout)
wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "ak-stage-access-denied")))

View File

@ -84,14 +84,6 @@ class TestFlowsRecovery(SeleniumTestCase):
self.driver.switch_to.window(self.driver.window_handles[0])
sleep(2)
flow_executor = self.get_shadow_root("ak-flow-executor")
consent_stage = self.get_shadow_root("ak-stage-consent", flow_executor)
consent_stage.find_element(
By.CSS_SELECTOR,
"[type=submit]",
).click()
# We can now enter the new password
flow_executor = self.get_shadow_root("ak-flow-executor")
prompt_stage = self.get_shadow_root("ak-stage-prompt", flow_executor)

View File

@ -166,35 +166,30 @@ class SeleniumTestCase(DockerTestCase, StaticLiveServerTestCase):
print("::group::authentik Logs", file=stderr)
apps.get_app_config("authentik_tenants").ready()
self.wait_timeout = 60
self.logger = get_logger()
self.driver = self._get_driver()
self.driver.implicitly_wait(30)
self.wait = WebDriverWait(self.driver, self.wait_timeout)
self.logger = get_logger()
self.user = create_test_admin_user()
super().setUp()
def _get_driver(self) -> WebDriver:
count = 0
opts = webdriver.ChromeOptions()
opts.add_argument("--disable-search-engine-choice-screen")
# This breaks selenium when running remotely...?
# opts.set_capability("goog:loggingPrefs", {"browser": "ALL"})
opts.add_experimental_option(
"prefs",
{
"profile.password_manager_leak_detection": False,
},
)
try:
opts = webdriver.ChromeOptions()
opts.add_argument("--disable-search-engine-choice-screen")
return webdriver.Chrome(options=opts)
except WebDriverException:
pass
while count < RETRIES:
try:
driver = webdriver.Remote(
command_executor="http://localhost:4444/wd/hub",
options=opts,
options=webdriver.ChromeOptions(),
)
driver.maximize_window()
return driver
except WebDriverException as exc:
self.logger.warning("Failed to setup webdriver", exc=exc)
except WebDriverException:
count += 1
raise ValueError(f"Webdriver failed after {RETRIES}.")

75
uv.lock generated
View File

@ -269,7 +269,7 @@ requires-dist = [
{ name = "celery", specifier = "==5.5.2" },
{ name = "channels", specifier = "==4.2.2" },
{ name = "channels-redis", specifier = "==4.2.1" },
{ name = "cryptography", specifier = "==45.0.3" },
{ name = "cryptography", specifier = "==44.0.3" },
{ name = "dacite", specifier = "==1.9.2" },
{ name = "deepmerge", specifier = "==2.0" },
{ name = "defusedxml", specifier = "==0.7.1" },
@ -283,7 +283,7 @@ requires-dist = [
{ name = "django-prometheus", specifier = "==2.3.1" },
{ name = "django-redis", specifier = "==5.4.0" },
{ name = "django-storages", extras = ["s3"], specifier = "==1.14.6" },
{ name = "django-tenants", specifier = "==3.8.0" },
{ name = "django-tenants", git = "https://github.com/goauthentik/django-tenants.git?branch=authentik-fixes" },
{ name = "djangorestframework", git = "https://github.com/goauthentik/django-rest-framework?rev=896722bab969fabc74a08b827da59409cf9f1a4e" },
{ name = "djangorestframework-guardian", specifier = "==0.3.0" },
{ name = "docker", specifier = "==7.1.0" },
@ -303,7 +303,7 @@ requires-dist = [
{ name = "kubernetes", specifier = "==32.0.1" },
{ name = "ldap3", specifier = "==2.9.1" },
{ name = "lxml", specifier = "==5.4.0" },
{ name = "msgraph-sdk", specifier = "==1.31.0" },
{ name = "msgraph-sdk", specifier = "==1.30.0" },
{ name = "opencontainers", git = "https://github.com/vsoch/oci-python?rev=ceb4fcc090851717a3069d78e85ceb1e86c2740c" },
{ name = "packaging", specifier = "==25.0" },
{ name = "paramiko", specifier = "==3.5.1" },
@ -869,37 +869,37 @@ wheels = [
[[package]]
name = "cryptography"
version = "45.0.3"
version = "44.0.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/13/1f/9fa001e74a1993a9cadd2333bb889e50c66327b8594ac538ab8a04f915b7/cryptography-45.0.3.tar.gz", hash = "sha256:ec21313dd335c51d7877baf2972569f40a4291b76a0ce51391523ae358d05899", size = 744738, upload-time = "2025-05-25T14:17:24.777Z" }
sdist = { url = "https://files.pythonhosted.org/packages/53/d6/1411ab4d6108ab167d06254c5be517681f1e331f90edf1379895bcb87020/cryptography-44.0.3.tar.gz", hash = "sha256:fe19d8bc5536a91a24a8133328880a41831b6c5df54599a8417b62fe015d3053", size = 711096, upload-time = "2025-05-02T19:36:04.667Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/82/b2/2345dc595998caa6f68adf84e8f8b50d18e9fc4638d32b22ea8daedd4b7a/cryptography-45.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:7573d9eebaeceeb55285205dbbb8753ac1e962af3d9640791d12b36864065e71", size = 7056239, upload-time = "2025-05-25T14:16:12.22Z" },
{ url = "https://files.pythonhosted.org/packages/71/3d/ac361649a0bfffc105e2298b720d8b862330a767dab27c06adc2ddbef96a/cryptography-45.0.3-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d377dde61c5d67eb4311eace661c3efda46c62113ff56bf05e2d679e02aebb5b", size = 4205541, upload-time = "2025-05-25T14:16:14.333Z" },
{ url = "https://files.pythonhosted.org/packages/70/3e/c02a043750494d5c445f769e9c9f67e550d65060e0bfce52d91c1362693d/cryptography-45.0.3-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fae1e637f527750811588e4582988932c222f8251f7b7ea93739acb624e1487f", size = 4433275, upload-time = "2025-05-25T14:16:16.421Z" },
{ url = "https://files.pythonhosted.org/packages/40/7a/9af0bfd48784e80eef3eb6fd6fde96fe706b4fc156751ce1b2b965dada70/cryptography-45.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ca932e11218bcc9ef812aa497cdf669484870ecbcf2d99b765d6c27a86000942", size = 4209173, upload-time = "2025-05-25T14:16:18.163Z" },
{ url = "https://files.pythonhosted.org/packages/31/5f/d6f8753c8708912df52e67969e80ef70b8e8897306cd9eb8b98201f8c184/cryptography-45.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af3f92b1dc25621f5fad065288a44ac790c5798e986a34d393ab27d2b27fcff9", size = 3898150, upload-time = "2025-05-25T14:16:20.34Z" },
{ url = "https://files.pythonhosted.org/packages/8b/50/f256ab79c671fb066e47336706dc398c3b1e125f952e07d54ce82cf4011a/cryptography-45.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2f8f8f0b73b885ddd7f3d8c2b2234a7d3ba49002b0223f58cfde1bedd9563c56", size = 4466473, upload-time = "2025-05-25T14:16:22.605Z" },
{ url = "https://files.pythonhosted.org/packages/62/e7/312428336bb2df0848d0768ab5a062e11a32d18139447a76dfc19ada8eed/cryptography-45.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9cc80ce69032ffa528b5e16d217fa4d8d4bb7d6ba8659c1b4d74a1b0f4235fca", size = 4211890, upload-time = "2025-05-25T14:16:24.738Z" },
{ url = "https://files.pythonhosted.org/packages/e7/53/8a130e22c1e432b3c14896ec5eb7ac01fb53c6737e1d705df7e0efb647c6/cryptography-45.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c824c9281cb628015bfc3c59335163d4ca0540d49de4582d6c2637312907e4b1", size = 4466300, upload-time = "2025-05-25T14:16:26.768Z" },
{ url = "https://files.pythonhosted.org/packages/ba/75/6bb6579688ef805fd16a053005fce93944cdade465fc92ef32bbc5c40681/cryptography-45.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5833bb4355cb377ebd880457663a972cd044e7f49585aee39245c0d592904578", size = 4332483, upload-time = "2025-05-25T14:16:28.316Z" },
{ url = "https://files.pythonhosted.org/packages/2f/11/2538f4e1ce05c6c4f81f43c1ef2bd6de7ae5e24ee284460ff6c77e42ca77/cryptography-45.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9bb5bf55dcb69f7067d80354d0a348368da907345a2c448b0babc4215ccd3497", size = 4573714, upload-time = "2025-05-25T14:16:30.474Z" },
{ url = "https://files.pythonhosted.org/packages/f5/bb/e86e9cf07f73a98d84a4084e8fd420b0e82330a901d9cac8149f994c3417/cryptography-45.0.3-cp311-abi3-win32.whl", hash = "sha256:3ad69eeb92a9de9421e1f6685e85a10fbcfb75c833b42cc9bc2ba9fb00da4710", size = 2934752, upload-time = "2025-05-25T14:16:32.204Z" },
{ url = "https://files.pythonhosted.org/packages/c7/75/063bc9ddc3d1c73e959054f1fc091b79572e716ef74d6caaa56e945b4af9/cryptography-45.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:97787952246a77d77934d41b62fb1b6f3581d83f71b44796a4158d93b8f5c490", size = 3412465, upload-time = "2025-05-25T14:16:33.888Z" },
{ url = "https://files.pythonhosted.org/packages/71/9b/04ead6015229a9396890d7654ee35ef630860fb42dc9ff9ec27f72157952/cryptography-45.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:c92519d242703b675ccefd0f0562eb45e74d438e001f8ab52d628e885751fb06", size = 7031892, upload-time = "2025-05-25T14:16:36.214Z" },
{ url = "https://files.pythonhosted.org/packages/46/c7/c7d05d0e133a09fc677b8a87953815c522697bdf025e5cac13ba419e7240/cryptography-45.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5edcb90da1843df85292ef3a313513766a78fbbb83f584a5a58fb001a5a9d57", size = 4196181, upload-time = "2025-05-25T14:16:37.934Z" },
{ url = "https://files.pythonhosted.org/packages/08/7a/6ad3aa796b18a683657cef930a986fac0045417e2dc428fd336cfc45ba52/cryptography-45.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38deed72285c7ed699864f964a3f4cf11ab3fb38e8d39cfcd96710cd2b5bb716", size = 4423370, upload-time = "2025-05-25T14:16:39.502Z" },
{ url = "https://files.pythonhosted.org/packages/4f/58/ec1461bfcb393525f597ac6a10a63938d18775b7803324072974b41a926b/cryptography-45.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5555365a50efe1f486eed6ac7062c33b97ccef409f5970a0b6f205a7cfab59c8", size = 4197839, upload-time = "2025-05-25T14:16:41.322Z" },
{ url = "https://files.pythonhosted.org/packages/d4/3d/5185b117c32ad4f40846f579369a80e710d6146c2baa8ce09d01612750db/cryptography-45.0.3-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9e4253ed8f5948a3589b3caee7ad9a5bf218ffd16869c516535325fece163dcc", size = 3886324, upload-time = "2025-05-25T14:16:43.041Z" },
{ url = "https://files.pythonhosted.org/packages/67/85/caba91a57d291a2ad46e74016d1f83ac294f08128b26e2a81e9b4f2d2555/cryptography-45.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cfd84777b4b6684955ce86156cfb5e08d75e80dc2585e10d69e47f014f0a5342", size = 4450447, upload-time = "2025-05-25T14:16:44.759Z" },
{ url = "https://files.pythonhosted.org/packages/ae/d1/164e3c9d559133a38279215c712b8ba38e77735d3412f37711b9f8f6f7e0/cryptography-45.0.3-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:a2b56de3417fd5f48773ad8e91abaa700b678dc7fe1e0c757e1ae340779acf7b", size = 4200576, upload-time = "2025-05-25T14:16:46.438Z" },
{ url = "https://files.pythonhosted.org/packages/71/7a/e002d5ce624ed46dfc32abe1deff32190f3ac47ede911789ee936f5a4255/cryptography-45.0.3-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:57a6500d459e8035e813bd8b51b671977fb149a8c95ed814989da682314d0782", size = 4450308, upload-time = "2025-05-25T14:16:48.228Z" },
{ url = "https://files.pythonhosted.org/packages/87/ad/3fbff9c28cf09b0a71e98af57d74f3662dea4a174b12acc493de00ea3f28/cryptography-45.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f22af3c78abfbc7cbcdf2c55d23c3e022e1a462ee2481011d518c7fb9c9f3d65", size = 4325125, upload-time = "2025-05-25T14:16:49.844Z" },
{ url = "https://files.pythonhosted.org/packages/f5/b4/51417d0cc01802304c1984d76e9592f15e4801abd44ef7ba657060520bf0/cryptography-45.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:232954730c362638544758a8160c4ee1b832dc011d2c41a306ad8f7cccc5bb0b", size = 4560038, upload-time = "2025-05-25T14:16:51.398Z" },
{ url = "https://files.pythonhosted.org/packages/80/38/d572f6482d45789a7202fb87d052deb7a7b136bf17473ebff33536727a2c/cryptography-45.0.3-cp37-abi3-win32.whl", hash = "sha256:cb6ab89421bc90e0422aca911c69044c2912fc3debb19bb3c1bfe28ee3dff6ab", size = 2924070, upload-time = "2025-05-25T14:16:53.472Z" },
{ url = "https://files.pythonhosted.org/packages/91/5a/61f39c0ff4443651cc64e626fa97ad3099249152039952be8f344d6b0c86/cryptography-45.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:d54ae41e6bd70ea23707843021c778f151ca258081586f0cfa31d936ae43d1b2", size = 3395005, upload-time = "2025-05-25T14:16:55.134Z" },
{ url = "https://files.pythonhosted.org/packages/08/53/c776d80e9d26441bb3868457909b4e74dd9ccabd182e10b2b0ae7a07e265/cryptography-44.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:962bc30480a08d133e631e8dfd4783ab71cc9e33d5d7c1e192f0b7c06397bb88", size = 6670281, upload-time = "2025-05-02T19:34:50.665Z" },
{ url = "https://files.pythonhosted.org/packages/6a/06/af2cf8d56ef87c77319e9086601bef621bedf40f6f59069e1b6d1ec498c5/cryptography-44.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffc61e8f3bf5b60346d89cd3d37231019c17a081208dfbbd6e1605ba03fa137", size = 3959305, upload-time = "2025-05-02T19:34:53.042Z" },
{ url = "https://files.pythonhosted.org/packages/ae/01/80de3bec64627207d030f47bf3536889efee8913cd363e78ca9a09b13c8e/cryptography-44.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58968d331425a6f9eedcee087f77fd3c927c88f55368f43ff7e0a19891f2642c", size = 4171040, upload-time = "2025-05-02T19:34:54.675Z" },
{ url = "https://files.pythonhosted.org/packages/bd/48/bb16b7541d207a19d9ae8b541c70037a05e473ddc72ccb1386524d4f023c/cryptography-44.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e28d62e59a4dbd1d22e747f57d4f00c459af22181f0b2f787ea83f5a876d7c76", size = 3963411, upload-time = "2025-05-02T19:34:56.61Z" },
{ url = "https://files.pythonhosted.org/packages/42/b2/7d31f2af5591d217d71d37d044ef5412945a8a8e98d5a2a8ae4fd9cd4489/cryptography-44.0.3-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af653022a0c25ef2e3ffb2c673a50e5a0d02fecc41608f4954176f1933b12359", size = 3689263, upload-time = "2025-05-02T19:34:58.591Z" },
{ url = "https://files.pythonhosted.org/packages/25/50/c0dfb9d87ae88ccc01aad8eb93e23cfbcea6a6a106a9b63a7b14c1f93c75/cryptography-44.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:157f1f3b8d941c2bd8f3ffee0af9b049c9665c39d3da9db2dc338feca5e98a43", size = 4196198, upload-time = "2025-05-02T19:35:00.988Z" },
{ url = "https://files.pythonhosted.org/packages/66/c9/55c6b8794a74da652690c898cb43906310a3e4e4f6ee0b5f8b3b3e70c441/cryptography-44.0.3-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:c6cd67722619e4d55fdb42ead64ed8843d64638e9c07f4011163e46bc512cf01", size = 3966502, upload-time = "2025-05-02T19:35:03.091Z" },
{ url = "https://files.pythonhosted.org/packages/b6/f7/7cb5488c682ca59a02a32ec5f975074084db4c983f849d47b7b67cc8697a/cryptography-44.0.3-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b424563394c369a804ecbee9b06dfb34997f19d00b3518e39f83a5642618397d", size = 4196173, upload-time = "2025-05-02T19:35:05.018Z" },
{ url = "https://files.pythonhosted.org/packages/d2/0b/2f789a8403ae089b0b121f8f54f4a3e5228df756e2146efdf4a09a3d5083/cryptography-44.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c91fc8e8fd78af553f98bc7f2a1d8db977334e4eea302a4bfd75b9461c2d8904", size = 4087713, upload-time = "2025-05-02T19:35:07.187Z" },
{ url = "https://files.pythonhosted.org/packages/1d/aa/330c13655f1af398fc154089295cf259252f0ba5df93b4bc9d9c7d7f843e/cryptography-44.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:25cd194c39fa5a0aa4169125ee27d1172097857b27109a45fadc59653ec06f44", size = 4299064, upload-time = "2025-05-02T19:35:08.879Z" },
{ url = "https://files.pythonhosted.org/packages/10/a8/8c540a421b44fd267a7d58a1fd5f072a552d72204a3f08194f98889de76d/cryptography-44.0.3-cp37-abi3-win32.whl", hash = "sha256:3be3f649d91cb182c3a6bd336de8b61a0a71965bd13d1a04a0e15b39c3d5809d", size = 2773887, upload-time = "2025-05-02T19:35:10.41Z" },
{ url = "https://files.pythonhosted.org/packages/b9/0d/c4b1657c39ead18d76bbd122da86bd95bdc4095413460d09544000a17d56/cryptography-44.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:3883076d5c4cc56dbef0b898a74eb6992fdac29a7b9013870b34efe4ddb39a0d", size = 3209737, upload-time = "2025-05-02T19:35:12.12Z" },
{ url = "https://files.pythonhosted.org/packages/34/a3/ad08e0bcc34ad436013458d7528e83ac29910943cea42ad7dd4141a27bbb/cryptography-44.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:5639c2b16764c6f76eedf722dbad9a0914960d3489c0cc38694ddf9464f1bb2f", size = 6673501, upload-time = "2025-05-02T19:35:13.775Z" },
{ url = "https://files.pythonhosted.org/packages/b1/f0/7491d44bba8d28b464a5bc8cc709f25a51e3eac54c0a4444cf2473a57c37/cryptography-44.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3ffef566ac88f75967d7abd852ed5f182da252d23fac11b4766da3957766759", size = 3960307, upload-time = "2025-05-02T19:35:15.917Z" },
{ url = "https://files.pythonhosted.org/packages/f7/c8/e5c5d0e1364d3346a5747cdcd7ecbb23ca87e6dea4f942a44e88be349f06/cryptography-44.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:192ed30fac1728f7587c6f4613c29c584abdc565d7417c13904708db10206645", size = 4170876, upload-time = "2025-05-02T19:35:18.138Z" },
{ url = "https://files.pythonhosted.org/packages/73/96/025cb26fc351d8c7d3a1c44e20cf9a01e9f7cf740353c9c7a17072e4b264/cryptography-44.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7d5fe7195c27c32a64955740b949070f21cba664604291c298518d2e255931d2", size = 3964127, upload-time = "2025-05-02T19:35:19.864Z" },
{ url = "https://files.pythonhosted.org/packages/01/44/eb6522db7d9f84e8833ba3bf63313f8e257729cf3a8917379473fcfd6601/cryptography-44.0.3-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3f07943aa4d7dad689e3bb1638ddc4944cc5e0921e3c227486daae0e31a05e54", size = 3689164, upload-time = "2025-05-02T19:35:21.449Z" },
{ url = "https://files.pythonhosted.org/packages/68/fb/d61a4defd0d6cee20b1b8a1ea8f5e25007e26aeb413ca53835f0cae2bcd1/cryptography-44.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb90f60e03d563ca2445099edf605c16ed1d5b15182d21831f58460c48bffb93", size = 4198081, upload-time = "2025-05-02T19:35:23.187Z" },
{ url = "https://files.pythonhosted.org/packages/1b/50/457f6911d36432a8811c3ab8bd5a6090e8d18ce655c22820994913dd06ea/cryptography-44.0.3-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:ab0b005721cc0039e885ac3503825661bd9810b15d4f374e473f8c89b7d5460c", size = 3967716, upload-time = "2025-05-02T19:35:25.426Z" },
{ url = "https://files.pythonhosted.org/packages/35/6e/dca39d553075980ccb631955c47b93d87d27f3596da8d48b1ae81463d915/cryptography-44.0.3-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:3bb0847e6363c037df8f6ede57d88eaf3410ca2267fb12275370a76f85786a6f", size = 4197398, upload-time = "2025-05-02T19:35:27.678Z" },
{ url = "https://files.pythonhosted.org/packages/9b/9d/d1f2fe681eabc682067c66a74addd46c887ebacf39038ba01f8860338d3d/cryptography-44.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b0cc66c74c797e1db750aaa842ad5b8b78e14805a9b5d1348dc603612d3e3ff5", size = 4087900, upload-time = "2025-05-02T19:35:29.312Z" },
{ url = "https://files.pythonhosted.org/packages/c4/f5/3599e48c5464580b73b236aafb20973b953cd2e7b44c7c2533de1d888446/cryptography-44.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6866df152b581f9429020320e5eb9794c8780e90f7ccb021940d7f50ee00ae0b", size = 4301067, upload-time = "2025-05-02T19:35:31.547Z" },
{ url = "https://files.pythonhosted.org/packages/a7/6c/d2c48c8137eb39d0c193274db5c04a75dab20d2f7c3f81a7dcc3a8897701/cryptography-44.0.3-cp39-abi3-win32.whl", hash = "sha256:c138abae3a12a94c75c10499f1cbae81294a6f983b3af066390adee73f433028", size = 2775467, upload-time = "2025-05-02T19:35:33.805Z" },
{ url = "https://files.pythonhosted.org/packages/c9/ad/51f212198681ea7b0deaaf8846ee10af99fba4e894f67b353524eab2bbe5/cryptography-44.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:5d186f32e52e66994dce4f766884bcb9c68b8da62d61d9d215bfe5fb56d21334", size = 3210375, upload-time = "2025-05-02T19:35:35.369Z" },
]
[[package]]
@ -1118,12 +1118,11 @@ s3 = [
[[package]]
name = "django-tenants"
version = "3.8.0"
source = { registry = "https://pypi.org/simple" }
version = "3.7.0"
source = { git = "https://github.com/goauthentik/django-tenants.git?branch=authentik-fixes#156e53a6f5902d74b73dd9d0192fffaa2587a740" }
dependencies = [
{ name = "django" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a8/7b/22e3bb79d48e5a4fdcacdcdc27bbc5c2523a2b7892b440bfe229f313d823/django_tenants-3.8.0.tar.gz", hash = "sha256:07d009d5d01be2d65c3f5ddbf323d58d1228838fc1a64fded15c8e5c6f41cf8f", size = 154307, upload-time = "2025-05-23T16:07:24.307Z" }
[[package]]
name = "djangorestframework"
@ -2066,7 +2065,7 @@ wheels = [
[[package]]
name = "msgraph-sdk"
version = "1.31.0"
version = "1.30.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "azure-identity" },
@ -2076,9 +2075,9 @@ dependencies = [
{ name = "microsoft-kiota-serialization-text" },
{ name = "msgraph-core" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d3/1c/5afdf21f92840c7029f0fdb6c2ead7373b1fcdc3c4279fe556a2fc3702a2/msgraph_sdk-1.31.0.tar.gz", hash = "sha256:7ae5f29152251f61c1fc19cca6389dd03b0120b179ddf39d8ab8cdfed7952dba", size = 6626610, upload-time = "2025-05-20T13:15:08.062Z" }
sdist = { url = "https://files.pythonhosted.org/packages/e9/4a/4ff19671f6ea06f98fb2405f73a90350e4719ccc692e85e9e0c2fa066826/msgraph_sdk-1.30.0.tar.gz", hash = "sha256:59e30af6d7244c9009146d620c331e169701b651317746b16f561e2e2452e73f", size = 6608744, upload-time = "2025-05-13T13:09:12.594Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d9/b9/099b28478575126ec26bd61ff0931fb291263ac813afb8baf4b4cc30c6fc/msgraph_sdk-1.31.0-py3-none-any.whl", hash = "sha256:bb2edfe17c377f37bbf2e155fc915171763d49e1cf93b665bafd721a85220dc5", size = 27185846, upload-time = "2025-05-20T13:15:05.307Z" },
{ url = "https://files.pythonhosted.org/packages/70/95/451ec4db8a924274a1f7260809ea03fe9c2b446d84dc5238e92e49a1b522/msgraph_sdk-1.30.0-py3-none-any.whl", hash = "sha256:6748f5cdb5ddbcff9e4f3fb073dd0a604cb00e1cf285dd0fea6969c93ba8282f", size = 27140767, upload-time = "2025-05-13T13:09:07.718Z" },
]
[[package]]
@ -2577,14 +2576,14 @@ wheels = [
[[package]]
name = "pyopenssl"
version = "25.1.0"
version = "25.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cryptography" },
]
sdist = { url = "https://files.pythonhosted.org/packages/04/8c/cd89ad05804f8e3c17dea8f178c3f40eeab5694c30e0c9f5bcd49f576fc3/pyopenssl-25.1.0.tar.gz", hash = "sha256:8d031884482e0c67ee92bf9a4d8cceb08d92aba7136432ffb0703c5280fc205b", size = 179937, upload-time = "2025-05-17T16:28:31.31Z" }
sdist = { url = "https://files.pythonhosted.org/packages/9f/26/e25b4a374b4639e0c235527bbe31c0524f26eda701d79456a7e1877f4cc5/pyopenssl-25.0.0.tar.gz", hash = "sha256:cd2cef799efa3936bb08e8ccb9433a575722b9dd986023f1cabc4ae64e9dac16", size = 179573, upload-time = "2025-01-12T17:22:48.897Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/80/28/2659c02301b9500751f8d42f9a6632e1508aa5120de5e43042b8b30f8d5d/pyopenssl-25.1.0-py3-none-any.whl", hash = "sha256:2b11f239acc47ac2e5aca04fd7fa829800aeee22a2eb30d744572a157bd8a1ab", size = 56771, upload-time = "2025-05-17T16:28:29.197Z" },
{ url = "https://files.pythonhosted.org/packages/ca/d7/eb76863d2060dcbe7c7e6cccfd95ac02ea0b9acc37745a0d99ff6457aefb/pyOpenSSL-25.0.0-py3-none-any.whl", hash = "sha256:424c247065e46e76a37411b9ab1782541c23bb658bf003772c3405fbaa128e90", size = 56453, upload-time = "2025-01-12T17:22:43.44Z" },
]
[[package]]

View File

@ -3,10 +3,11 @@
*
* @import { ThemeVarsPartial } from "storybook/internal/theming";
*/
import { createUIThemeEffect, resolveUITheme } from "@goauthentik/web/common/theme.ts";
import { addons } from "@storybook/manager-api";
import { create } from "@storybook/theming/create";
import { createUIThemeEffect, resolveUITheme } from "@goauthentik/web/common/theme.ts";
/**
* @satisfies {Partial<ThemeVarsPartial>}
*/

View File

@ -4,27 +4,30 @@
* @import {
* OnLoadArgs,
* OnLoadResult,
* OnResolveArgs,
* OnResolveResult,
* Plugin,
* PluginBuild
* } from "esbuild"
*/
import { MonoRepoRoot } from "@goauthentik/core/paths/node";
import * as fs from "node:fs/promises";
import * as path from "node:path";
/**
* @typedef {Omit<OnLoadArgs, 'pluginData'> & LoadDataFields} LoadData Data passed to `onload`.
* @typedef {Omit<OnLoadArgs, 'pluginData'> & LoadDataFields} LoadData
* Data passed to `onload`.
*
* @typedef LoadDataFields Extra fields given in `data` to `onload`.
* @property {PluginData | null | undefined} [pluginData] Plugin data.
* @typedef LoadDataFields
* Extra fields given in `data` to `onload`.
* @property {PluginData | null | undefined} [pluginData]
* Plugin data.
*
* @typedef PluginData Extra data passed.
* @property {Buffer | string | null | undefined} [contents] File contents.
*
* @typedef PluginData
* Extra data passed.
* @property {Buffer | string | null | undefined} [contents]
* File contents.
*/
const pluginName = "mdx-plugin";
const name = "mdx-plugin";
/**
* @typedef MDXPluginOptions
@ -35,35 +38,28 @@ const pluginName = "mdx-plugin";
/**
* Bundle MDX into JSON modules.
*
* @param {MDXPluginOptions} options
* @returns {Plugin}
* @param {MDXPluginOptions} options Options.
* @returns {Plugin} Plugin.
*/
export function mdxPlugin({ root }) {
// TODO: Replace with `resolvePackage` after NPM Workspaces support is added.
const docsPackageRoot = path.resolve(MonoRepoRoot, "website");
return { name, setup };
/**
* @param {PluginBuild} build
* Build.
* @returns {undefined}
* Nothing.
*/
function setup(build) {
/**
* @param {OnResolveArgs} args
* @returns {Promise<OnResolveResult>}
*/
async function resolveListener(args) {
if (!args.path.startsWith("~")) return args;
return {
path: path.resolve(docsPackageRoot, args.path.slice(1)),
pluginName,
};
}
build.onLoad({ filter: /\.mdx?$/ }, onload);
/**
* @param {LoadData} data
* Data.
* @returns {Promise<OnLoadResult>}
* Result.
*/
async function loadListener(data) {
async function onload(data) {
const content = String(
data.pluginData &&
data.pluginData.contents !== null &&
@ -81,16 +77,7 @@ export function mdxPlugin({ root }) {
return {
contents: JSON.stringify({ content, publicPath, publicDirectory }),
loader: "file",
pluginName,
};
}
build.onResolve({ filter: /\.mdx?$/ }, resolveListener);
build.onLoad({ filter: /\.mdx?$/ }, loadListener);
}
return {
name: pluginName,
setup,
};
}

View File

@ -1,6 +1,7 @@
import { createESLintPackageConfig } from "@goauthentik/eslint-config";
import tseslint from "typescript-eslint";
import { createESLintPackageConfig } from "@goauthentik/eslint-config";
// @ts-check
/**

2518
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -91,9 +91,9 @@
"@codemirror/legacy-modes": "^6.4.1",
"@codemirror/theme-one-dark": "^6.1.2",
"@floating-ui/dom": "^1.6.11",
"@formatjs/intl-listformat": "^7.7.11",
"@formatjs/intl-listformat": "^7.5.7",
"@fortawesome/fontawesome-free": "^6.6.0",
"@goauthentik/api": "^2025.4.1-1748431399",
"@goauthentik/api": "^2025.4.1-1747687715",
"@lit/context": "^1.1.2",
"@lit/localize": "^0.12.2",
"@lit/reactive-element": "^2.0.4",
@ -111,12 +111,12 @@
"chartjs-adapter-date-fns": "^3.0.0",
"codemirror": "^6.0.1",
"construct-style-sheets-polyfill": "^3.1.0",
"core-js": "^3.42.0",
"core-js": "^3.38.1",
"country-flag-icons": "^1.5.19",
"date-fns": "^4.1.0",
"deepmerge-ts": "^7.1.5",
"dompurify": "^3.2.6",
"fuse.js": "^7.1.0",
"fuse.js": "^7.0.0",
"guacamole-common-js": "^1.5.0",
"hastscript": "^9.0.1",
"lit": "^3.2.0",
@ -144,15 +144,14 @@
"@eslint/js": "^9.27.0",
"@goauthentik/core": "^1.0.0",
"@goauthentik/esbuild-plugin-live-reload": "^1.0.4",
"@goauthentik/eslint-config": "^1.0.5",
"@goauthentik/prettier-config": "^1.0.5",
"@goauthentik/eslint-config": "^1.0.4",
"@goauthentik/prettier-config": "^1.0.4",
"@goauthentik/tsconfig": "^1.0.4",
"@hcaptcha/types": "^1.0.4",
"@lit/localize-tools": "^0.8.0",
"@storybook/addon-essentials": "^8.6.14",
"@storybook/addon-links": "^8.6.14",
"@storybook/blocks": "^8.6.12",
"@storybook/channels": "^8.6.14",
"@storybook/experimental-addon-test": "^8.6.14",
"@storybook/manager-api": "^8.6.14",
"@storybook/test": "^8.6.14",
@ -184,7 +183,7 @@
"eslint-plugin-wc": "^3.0.1",
"github-slugger": "^2.0.0",
"globals": "^15.10.0",
"knip": "^5.58.0",
"knip": "^5.30.6",
"lit-analyzer": "^2.0.3",
"npm-run-all": "^4.1.5",
"prettier": "^3.3.3",
@ -203,9 +202,9 @@
"@esbuild/darwin-arm64": "^0.25.4",
"@esbuild/linux-arm64": "^0.25.4",
"@esbuild/linux-x64": "^0.25.4",
"@rollup/rollup-darwin-arm64": "^4.41.1",
"@rollup/rollup-linux-arm64-gnu": "^4.41.1",
"@rollup/rollup-linux-x64-gnu": "^4.41.1"
"@rollup/rollup-darwin-arm64": "^4.41.0",
"@rollup/rollup-linux-arm64-gnu": "^4.41.0",
"@rollup/rollup-linux-x64-gnu": "^4.41.0"
},
"wireit": {
"build": {
@ -364,7 +363,6 @@
"workspaces": [
"./packages/*"
],
"prettier": "@goauthentik/prettier-config",
"overrides": {
"@storybook/addon-docs": {
"react": "^19.1.0",

View File

@ -45,7 +45,7 @@
}
},
"devDependencies": {
"@goauthentik/prettier-config": "^1.0.5",
"@goauthentik/prettier-config": "^1.0.4",
"@goauthentik/tsconfig": "^1.0.4",
"@types/node": "^22.15.21",
"prettier": "^3.3.3",

View File

@ -1,59 +0,0 @@
_An ESBuild development plugin that watches for file changes and triggers automatic browser refreshes._
## Quick start
```sh
npm install -D @goauthentik/esbuild-plugin-live-reload
# Or with Yarn:
yarn add -D @goauthentik/esbuild-plugin-live-reload
```
### 1. Configure ESBuild
```js
import { liveReloadPlugin } from "@goauthentik/esbuild-plugin-live-reload";
import esbuild from "esbuild";
const NodeEnvironment = process.env.NODE_ENV || "development";
/**
* @type {esbuild.BuildOptions}
*/
const buildOptions = {
// ... Your build options.
define: {
"process.env.NODE_ENV": JSON.stringify(NodeEnvironment),
},
plugins: [
/** @see {@link LiveReloadPluginOptions} */
liveReloadPlugin(),
],
};
const buildContext = await esbuild.context(buildOptions);
await buildContext.rebuild();
await buildContext.watch();
```
### 2. Connect your browser
Add the following import near the beginning of your application's entry point.
```js
if (process.env.NODE_ENV === "development") {
await import("@goauthentik/esbuild-plugin-live-reload/client");
}
```
That's it! Your browser will now automatically refresh whenever ESBuild finishes rebuilding your code.
## About authentik
[authentik](https://goauthentik.io) is an open source Identity Provider that unifies your identity needs into a single platform, replacing Okta, Active Directory, and Auth0.
We built this plugin to streamline our development workflow, and we're sharing it with the community. If you have any questions, feature requests, or bug reports, please [open an issue](https://github.com/goauthentik/authentik/issues/new/choose).
## License
This code is licensed under the [MIT License](https://www.tldrlegal.com/license/mit-license)

View File

@ -1,3 +0,0 @@
README.md
node_modules
_media

View File

@ -1,3 +0,0 @@
node_modules
./README.md
out

View File

@ -1,18 +0,0 @@
The MIT License (MIT)
Copyright (c) 2025 Authentik Security, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,40 @@
# `@goauthentik/esbuild-plugin-live-reload`
_A plugin that enables live reloading of ESBuild during development._
## Usage
### Node.js setup
```js
import { liveReloadPlugin } from "@goauthentik/esbuild-plugin-live-reload";
import esbuild from "esbuild";
const NodeEnvironment = process.env.NODE_ENV || "development";
/**
* @type {esbuild.BuildOptions}
*/
const buildOptions = {
// ... Your build options.
define: {
"process.env.NODE_ENV": JSON.stringify(NodeEnvironment),
},
plugins: [liveReloadPlugin(/** @see {@link LiveReloadPluginOptions} */)],
};
const buildContext = await esbuild.context(buildOptions);
await buildContext.rebuild();
await buildContext.watch();
```
### Browser setup
```js
// Place this at the beginning of your application's entry point.
if (process.env.NODE_ENV === "development") {
await import("@goauthentik/esbuild-plugin-live-reload/client");
}
```

View File

@ -28,8 +28,6 @@ const log = console.debug.bind(console, logPrefix);
* ```
*
* @implements {Disposable}
* @category Plugin
* runtime browser
*/
export class ESBuildObserver extends EventSource {
/**

Some files were not shown because too many files have changed in this diff Show More