Compare commits

..

5 Commits

765 changed files with 7423 additions and 20786 deletions

View File

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

View File

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

View File

@ -7,7 +7,7 @@ on:
- packages/eslint-config/** - packages/eslint-config/**
- packages/prettier-config/** - packages/prettier-config/**
- packages/tsconfig/** - packages/tsconfig/**
- web/packages/esbuild-plugin-live-reload/** - packages/web/esbuild-plugin-live-reload/**
workflow_dispatch: workflow_dispatch:
jobs: jobs:
publish: publish:
@ -17,28 +17,27 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
package: package:
- packages/docusaurus-config - docusaurus-config
- packages/eslint-config - eslint-config
- packages/prettier-config - prettier-config
- packages/tsconfig - tsconfig
- web/packages/esbuild-plugin-live-reload
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
fetch-depth: 2 fetch-depth: 2
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: ${{ matrix.package }}/package.json node-version-file: packages/${{ matrix.package }}/package.json
registry-url: "https://registry.npmjs.org" registry-url: "https://registry.npmjs.org"
- name: Get changed files - name: Get changed files
id: changed-files id: changed-files
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c
with: with:
files: | files: |
${{ matrix.package }}/package.json packages/${{ matrix.package }}/package.json
- name: Publish package - name: Publish package
if: steps.changed-files.outputs.any_changed == 'true' if: steps.changed-files.outputs.any_changed == 'true'
working-directory: ${{ matrix.package }} working-directory: packages/${{ matrix.package}}
run: | run: |
npm ci npm ci
npm run build 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" /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 # 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 # Stage 6: Base python image
FROM ghcr.io/goauthentik/fips-python:3.13.3-slim-bookworm-fips AS python-base 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 .PHONY: gen dev-reset all clean test web website
SHELL := /usr/bin/env bash SHELL := /bin/bash
.SHELLFLAGS += ${SHELLFLAGS} -e -o pipefail .SHELLFLAGS += ${SHELLFLAGS} -e -o pipefail
PWD = $(shell pwd) PWD = $(shell pwd)
UID = $(shell id -u) 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.lib.avatars import get_avatar
from authentik.rbac.decorators import permission_required from authentik.rbac.decorators import permission_required
from authentik.rbac.models import get_permission_choices 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.models import EmailStage
from authentik.stages.email.tasks import send_mails from authentik.stages.email.tasks import send_mails
from authentik.stages.email.utils import TemplateEmailMessage from authentik.stages.email.utils import TemplateEmailMessage
@ -452,7 +451,7 @@ class UserViewSet(UsedByMixin, ModelViewSet):
def list(self, request, *args, **kwargs): def list(self, request, *args, **kwargs):
return super().list(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), """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""" that can either be shown to an admin or sent to the user directly"""
brand: Brand = self.request._request.brand brand: Brand = self.request._request.brand
@ -474,16 +473,12 @@ class UserViewSet(UsedByMixin, ModelViewSet):
raise ValidationError( raise ValidationError(
{"non_field_errors": "Recovery flow not applicable to user"} {"non_field_errors": "Recovery flow not applicable to user"}
) from None ) from None
_plan = FlowToken.pickle(plan)
if for_email:
_plan = pickle_flow_token_for_email(plan)
token, __ = FlowToken.objects.update_or_create( token, __ = FlowToken.objects.update_or_create(
identifier=f"{user.uid}-password-reset", identifier=f"{user.uid}-password-reset",
defaults={ defaults={
"user": user, "user": user,
"flow": flow, "flow": flow,
"_plan": _plan, "_plan": FlowToken.pickle(plan),
"revoke_on_execution": not for_email,
}, },
) )
querystring = urlencode({QS_KEY_TOKEN: token.key}) querystring = urlencode({QS_KEY_TOKEN: token.key})
@ -653,7 +648,7 @@ class UserViewSet(UsedByMixin, ModelViewSet):
if for_user.email == "": if for_user.email == "":
LOGGER.debug("User doesn't have an email address") LOGGER.debug("User doesn't have an email address")
raise ValidationError({"non_field_errors": "User does not have an email address set."}) 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 # Lookup the email stage to assure the current user can access it
stages = get_objects_for_user( stages = get_objects_for_user(
request.user, "authentik_stages_email.view_emailstage" 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) flow = models.ForeignKey(Flow, on_delete=models.CASCADE)
_plan = models.TextField() _plan = models.TextField()
revoke_on_execution = models.BooleanField(default=True)
@staticmethod @staticmethod
def pickle(plan: "FlowPlan") -> str: def pickle(plan) -> str:
"""Pickle into string""" """Pickle into string"""
data = dumps(plan) data = dumps(plan)
return b64encode(data).decode() return b64encode(data).decode()

View File

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

View File

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

View File

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

View File

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

View File

@ -73,7 +73,6 @@ TENANT_APPS = [
"authentik.admin", "authentik.admin",
"authentik.api", "authentik.api",
"authentik.crypto", "authentik.crypto",
"authentik.endpoints",
"authentik.flows", "authentik.flows",
"authentik.outposts", "authentik.outposts",
"authentik.policies.dummy", "authentik.policies.dummy",
@ -425,7 +424,7 @@ else:
"BACKEND": "authentik.root.storages.FileStorage", "BACKEND": "authentik.root.storages.FileStorage",
"OPTIONS": { "OPTIONS": {
"location": Path(CONFIG.get("storage.media.file.path")), "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 # 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): if kwargs.get("randomly_seed", None):
self.args.append(f"--randomly-seed={kwargs['randomly_seed']}") self.args.append(f"--randomly-seed={kwargs['randomly_seed']}")
if kwargs.get("no_capture", False):
self.args.append("--capture=no")
settings.TEST = True settings.TEST = True
settings.CELERY["task_always_eager"] = 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" "Default behaviour: use random.Random().getrandbits(32), so the seed is"
"different on each run.", "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): def run_tests(self, test_labels, extra_tests=None, **kwargs):
"""Run pytest and return the exitcode. """Run pytest and return the exitcode.

View File

@ -111,7 +111,6 @@ class LDAPSourceSerializer(SourceSerializer):
"sync_parent_group", "sync_parent_group",
"connectivity", "connectivity",
"lookup_groups_from_user", "lookup_groups_from_user",
"delete_not_found_objects",
] ]
extra_kwargs = {"bind_password": {"write_only": True}} extra_kwargs = {"bind_password": {"write_only": True}}
@ -148,7 +147,6 @@ class LDAPSourceViewSet(UsedByMixin, ModelViewSet):
"user_property_mappings", "user_property_mappings",
"group_property_mappings", "group_property_mappings",
"lookup_groups_from_user", "lookup_groups_from_user",
"delete_not_found_objects",
] ]
search_fields = ["name", "slug"] search_fields = ["name", "slug"]
ordering = ["name"] 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 @property
def component(self) -> str: def component(self) -> str:
return "ak-source-ldap-form" return "ak-source-ldap-form"
@ -329,12 +321,6 @@ class LDAPSourcePropertyMapping(PropertyMapping):
class UserLDAPSourceConnection(UserSourceConnection): 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 @property
def serializer(self) -> type[Serializer]: def serializer(self) -> type[Serializer]:
from authentik.sources.ldap.api import ( from authentik.sources.ldap.api import (
@ -346,18 +332,9 @@ class UserLDAPSourceConnection(UserSourceConnection):
class Meta: class Meta:
verbose_name = _("User LDAP Source Connection") verbose_name = _("User LDAP Source Connection")
verbose_name_plural = _("User LDAP Source Connections") verbose_name_plural = _("User LDAP Source Connections")
indexes = [
models.Index(fields=["validated_by"]),
]
class GroupLDAPSourceConnection(GroupSourceConnection): 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 @property
def serializer(self) -> type[Serializer]: def serializer(self) -> type[Serializer]:
from authentik.sources.ldap.api import ( from authentik.sources.ldap.api import (
@ -369,6 +346,3 @@ class GroupLDAPSourceConnection(GroupSourceConnection):
class Meta: class Meta:
verbose_name = _("Group LDAP Source Connection") verbose_name = _("Group LDAP Source Connection")
verbose_name_plural = _("Group LDAP Source Connections") 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.core.sources.mapper import SourceMapper
from authentik.lib.config import CONFIG from authentik.lib.config import CONFIG
from authentik.lib.sync.mapper import PropertyMappingManager from authentik.lib.sync.mapper import PropertyMappingManager
from authentik.sources.ldap.models import LDAPSource, flatten from authentik.sources.ldap.models import LDAPSource
class BaseLDAPSynchronizer: class BaseLDAPSynchronizer:
@ -77,16 +77,6 @@ class BaseLDAPSynchronizer:
"""Get objects from LDAP, implemented in subclass""" """Get objects from LDAP, implemented in subclass"""
raise NotImplementedError() 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 def search_paginator( # noqa: PLR0913
self, self,
search_base, 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 return -1
group_count = 0 group_count = 0
for group in page_data: for group in page_data:
if (attributes := self.get_attributes(group)) is None: if "attributes" not in group:
continue continue
attributes = group.get("attributes", {})
group_dn = flatten(flatten(group.get("entryDN", group.get("dn")))) 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( self.message(
f"Uniqueness field not found/not set in attributes: '{group_dn}'", f"Uniqueness field not found/not set in attributes: '{group_dn}'",
attributes=attributes.keys(), attributes=attributes.keys(),
dn=group_dn, dn=group_dn,
) )
continue continue
uniq = flatten(attributes[self._source.object_uniqueness_field])
try: try:
defaults = { defaults = {
k: flatten(v) k: flatten(v)

View File

@ -63,9 +63,9 @@ class MembershipLDAPSynchronizer(BaseLDAPSynchronizer):
group_member_dn = group_member.get("dn", {}) group_member_dn = group_member.get("dn", {})
members.append(group_member_dn) members.append(group_member_dn)
else: else:
if (attributes := self.get_attributes(group)) is None: if "attributes" not in group:
continue 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) ak_group = self.get_group(group)
if not ak_group: if not ak_group:

View File

@ -60,16 +60,18 @@ class UserLDAPSynchronizer(BaseLDAPSynchronizer):
return -1 return -1
user_count = 0 user_count = 0
for user in page_data: for user in page_data:
if (attributes := self.get_attributes(user)) is None: if "attributes" not in user:
continue continue
attributes = user.get("attributes", {})
user_dn = flatten(user.get("entryDN", user.get("dn"))) 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( self.message(
f"Uniqueness field not found/not set in attributes: '{user_dn}'", f"Uniqueness field not found/not set in attributes: '{user_dn}'",
attributes=attributes.keys(), attributes=attributes.keys(),
dn=user_dn, dn=user_dn,
) )
continue continue
uniq = flatten(attributes[self._source.object_uniqueness_field])
try: try:
defaults = { defaults = {
k: flatten(v) 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.root.celery import CELERY_APP
from authentik.sources.ldap.models import LDAPSource from authentik.sources.ldap.models import LDAPSource
from authentik.sources.ldap.sync.base import BaseLDAPSynchronizer 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.groups import GroupLDAPSynchronizer
from authentik.sources.ldap.sync.membership import MembershipLDAPSynchronizer from authentik.sources.ldap.sync.membership import MembershipLDAPSynchronizer
from authentik.sources.ldap.sync.users import UserLDAPSynchronizer from authentik.sources.ldap.sync.users import UserLDAPSynchronizer
@ -54,11 +52,11 @@ def ldap_connectivity_check(pk: str | None = None):
@CELERY_APP.task( @CELERY_APP.task(
# We take the configured hours timeout time by 3.5 as we run user and # We take the configured hours timeout time by 2.5 as we run user and
# group in parallel and then membership, then deletions, so 3x is to cover the serial tasks, # 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 # 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, 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")) * 3.5, task_time_limit=(60 * 60 * CONFIG.get_int("ldap.task_timeout_hours")) * 2.5,
) )
def ldap_sync_single(source_pk: str): def ldap_sync_single(source_pk: str):
"""Sync a single source""" """Sync a single source"""
@ -81,25 +79,6 @@ def ldap_sync_single(source_pk: str):
group( group(
ldap_sync_paginator(source, MembershipLDAPSynchronizer), 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() task()

View File

@ -2,33 +2,6 @@
from ldap3 import MOCK_SYNC, OFFLINE_SLAPD_2_4, Connection, Server 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: def mock_slapd_connection(password: str) -> Connection:
"""Create mock SLAPD connection""" """Create mock SLAPD connection"""
@ -123,14 +96,5 @@ def mock_slapd_connection(password: str) -> Connection:
"objectClass": "posixAccount", "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() connection.bind()
return connection 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.generators import generate_id, generate_key
from authentik.lib.sync.outgoing.exceptions import StopSync from authentik.lib.sync.outgoing.exceptions import StopSync
from authentik.lib.utils.reflection import class_to_path from authentik.lib.utils.reflection import class_to_path
from authentik.sources.ldap.models import ( from authentik.sources.ldap.models import LDAPSource, LDAPSourcePropertyMapping
GroupLDAPSourceConnection,
LDAPSource,
LDAPSourcePropertyMapping,
UserLDAPSourceConnection,
)
from authentik.sources.ldap.sync.forward_delete_users import DELETE_CHUNK_SIZE
from authentik.sources.ldap.sync.groups import GroupLDAPSynchronizer from authentik.sources.ldap.sync.groups import GroupLDAPSynchronizer
from authentik.sources.ldap.sync.membership import MembershipLDAPSynchronizer from authentik.sources.ldap.sync.membership import MembershipLDAPSynchronizer
from authentik.sources.ldap.sync.users import UserLDAPSynchronizer from authentik.sources.ldap.sync.users import UserLDAPSynchronizer
from authentik.sources.ldap.tasks import ldap_sync, ldap_sync_all 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_ad import mock_ad_connection
from authentik.sources.ldap.tests.mock_freeipa import mock_freeipa_connection from authentik.sources.ldap.tests.mock_freeipa import mock_freeipa_connection
from authentik.sources.ldap.tests.mock_slapd import ( from authentik.sources.ldap.tests.mock_slapd import mock_slapd_connection
group_in_slapd_cn,
group_in_slapd_uid,
mock_slapd_connection,
user_in_slapd_cn,
user_in_slapd_uid,
)
LDAP_PASSWORD = generate_key() LDAP_PASSWORD = generate_key()
@ -320,160 +308,3 @@ class LDAPSyncTests(TestCase):
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD)) connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection): with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
ldap_sync_all.delay().get() 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.shortcuts import get_object_or_404, redirect
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.http import urlencode from django.utils.http import urlencode
from django.utils.translation import gettext as _
from django.views import View from django.views import View
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
@ -129,9 +128,7 @@ class InitiateView(View):
# otherwise we default to POST_AUTO, with direct redirect # otherwise we default to POST_AUTO, with direct redirect
if source.binding_type == SAMLBindingTypes.POST: if source.binding_type == SAMLBindingTypes.POST:
injected_stages.append(in_memory_stage(ConsentStageView)) injected_stages.append(in_memory_stage(ConsentStageView))
plan_kwargs[PLAN_CONTEXT_CONSENT_HEADER] = _( plan_kwargs[PLAN_CONTEXT_CONSENT_HEADER] = f"Continue to {source.name}"
"Continue to {source_name}".format(source_name=source.name)
)
injected_stages.append(in_memory_stage(AutosubmitStageView)) injected_stages.append(in_memory_stage(AutosubmitStageView))
return self.handle_login_flow( return self.handle_login_flow(
source, source,

View File

@ -4,8 +4,6 @@ from uuid import uuid4
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
from django.utils.timezone import now 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 rest_framework.fields import CharField
from authentik.core.api.utils import PassiveSerializer from authentik.core.api.utils import PassiveSerializer
@ -49,11 +47,6 @@ class ConsentChallengeResponse(ChallengeResponse):
component = CharField(default="ak-stage-consent") component = CharField(default="ak-stage-consent")
token = CharField(required=True) 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): class ConsentStageView(ChallengeStageView):
"""Simple consent checker.""" """Simple consent checker."""
@ -127,6 +120,9 @@ class ConsentStageView(ChallengeStageView):
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
def challenge_valid(self, response: ChallengeResponse) -> HttpResponse: 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(): if self.should_always_prompt():
return self.executor.stage_ok() return self.executor.stage_ok()
current_stage: ConsentStage = self.executor.current_stage 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.lib.generators import generate_id
from authentik.stages.consent.models import ConsentMode, ConsentStage, UserConsent from authentik.stages.consent.models import ConsentMode, ConsentStage, UserConsent
from authentik.stages.consent.stage import ( from authentik.stages.consent.stage import (
PLAN_CONTEXT_CONSENT_HEADER,
PLAN_CONTEXT_CONSENT_PERMISSIONS, PLAN_CONTEXT_CONSENT_PERMISSIONS,
SESSION_KEY_CONSENT_TOKEN, SESSION_KEY_CONSENT_TOKEN,
) )
@ -34,40 +33,6 @@ class TestConsentStage(FlowTestCase):
slug=generate_id(), 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): def test_always_required(self):
"""Test always required consent""" """Test always required consent"""
flow = create_test_flow(FlowDesignation.AUTHENTICATION) flow = create_test_flow(FlowDesignation.AUTHENTICATION)
@ -193,7 +158,6 @@ class TestConsentStage(FlowTestCase):
context={ context={
PLAN_CONTEXT_APPLICATION: self.application, PLAN_CONTEXT_APPLICATION: self.application,
PLAN_CONTEXT_CONSENT_PERMISSIONS: [PermissionDict(id="foo", name="foo-desc")], PLAN_CONTEXT_CONSENT_PERMISSIONS: [PermissionDict(id="foo", name="foo-desc")],
PLAN_CONTEXT_CONSENT_HEADER: "test header",
}, },
) )
session = self.client.session 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.flows.views.executor import QS_KEY_TOKEN, QS_QUERY
from authentik.lib.utils.errors import exception_to_string from authentik.lib.utils.errors import exception_to_string
from authentik.lib.utils.time import timedelta_from_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.models import EmailStage
from authentik.stages.email.tasks import send_mails from authentik.stages.email.tasks import send_mails
from authentik.stages.email.utils import TemplateEmailMessage from authentik.stages.email.utils import TemplateEmailMessage
@ -87,8 +86,7 @@ class EmailStageView(ChallengeStageView):
user=pending_user, user=pending_user,
identifier=identifier, identifier=identifier,
flow=self.executor.flow, flow=self.executor.flow,
_plan=pickle_flow_token_for_email(self.executor.plan), _plan=FlowToken.pickle(self.executor.plan),
revoke_on_execution=False,
) )
token = tokens.first() token = tokens.first()
# Check if token is expired and rotate key if so # 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)
response = self.client.post(url) response = self.client.post(url)
self.assertEqual(response.status_code, 200) 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") 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.flows.views.executor import QS_KEY_TOKEN, SESSION_KEY_PLAN, FlowExecutorView
from authentik.lib.config import CONFIG from authentik.lib.config import CONFIG
from authentik.lib.generators import generate_id 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.models import EmailStage
from authentik.stages.email.stage import PLAN_CONTEXT_EMAIL_OVERRIDE, EmailStageView from authentik.stages.email.stage import PLAN_CONTEXT_EMAIL_OVERRIDE, EmailStageView
@ -161,17 +160,6 @@ class TestEmailStage(FlowTestCase):
kwargs={"flow_slug": self.flow.slug}, 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.assertEqual(response.status_code, 200)
self.assertStageRedirects(response, reverse("authentik_core:root-redirect")) self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
@ -194,7 +182,6 @@ class TestEmailStage(FlowTestCase):
# Set flow token user to a different user # Set flow token user to a different user
token: FlowToken = FlowToken.objects.get(user=self.user) token: FlowToken = FlowToken.objects.get(user=self.user)
token.user = create_test_admin_user() token.user = create_test_admin_user()
token.revoke_on_execution = True
token.save() token.save()
with patch("authentik.flows.views.executor.FlowExecutorView.cancel", MagicMock()): with patch("authentik.flows.views.executor.FlowExecutorView.cancel", MagicMock()):

View File

@ -8180,11 +8180,6 @@
"type": "boolean", "type": "boolean",
"title": "Lookup groups from user", "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" "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": [] "required": []

View File

@ -28,18 +28,16 @@ func NewSessionBinder(si server.LDAPServerInstance, oldBinder bind.Binder) *Sess
si: si, si: si,
log: log.WithField("logger", "authentik.outpost.ldap.binder.session"), log: log.WithField("logger", "authentik.outpost.ldap.binder.session"),
} }
if oldBinder != nil { if oldSb, ok := oldBinder.(*SessionBinder); ok {
if oldSb, ok := oldBinder.(*SessionBinder); ok { sb.DirectBinder = oldSb.DirectBinder
sb.DirectBinder = oldSb.DirectBinder sb.sessions = oldSb.sessions
sb.sessions = oldSb.sessions sb.log.Debug("re-initialised session binder")
sb.log.Debug("re-initialised session binder") } else {
return sb 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 return sb
} }

View File

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

View File

@ -31,26 +31,13 @@ type MemorySearcher struct {
groups []api.Group groups []api.Group
} }
func NewMemorySearcher(si server.LDAPServerInstance, existing search.Searcher) *MemorySearcher { func NewMemorySearcher(si server.LDAPServerInstance) *MemorySearcher {
ms := &MemorySearcher{ ms := &MemorySearcher{
si: si, si: si,
log: log.WithField("logger", "authentik.outpost.ldap.searcher.memory"), log: log.WithField("logger", "authentik.outpost.ldap.searcher.memory"),
ds: direct.NewDirectSearcher(si), 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") 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 // 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{ users, _ := ak.Paginator(ms.si.GetAPIClient().CoreApi.CoreUsersList(context.TODO()).IncludeGroups(true), ak.PaginatorOptions{
PageSize: 100, PageSize: 100,
@ -62,6 +49,7 @@ func (ms *MemorySearcher) fetch() {
Logger: ms.log, Logger: ms.log,
}) })
ms.groups = groups ms.groups = groups
return ms
} }
func (ms *MemorySearcher) SearchBase(req *search.Request) (ldap.ServerSearchResult, error) { 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 // Media files, if backend is file
if config.Get().Storage.Media.Backend == "file" { if config.Get().Storage.Media.Backend == "file" {
fsMedia := http.FileServer(http.Dir(config.Get().Storage.Media.File.Path)) fsMedia := http.StripPrefix("/media", http.FileServer(http.Dir(config.Get().Storage.Media.File.Path)))
indexLessRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/media/").Handler(pathStripper( indexLessRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/media/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox")
w.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox") fsMedia.ServeHTTP(w, r)
fsMedia.ServeHTTP(w, r) })
}),
"media/",
config.Get().Web.Path,
))
} }
staticRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/if/help/").Handler(pathStripper( staticRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/if/help/").Handler(pathStripper(

Binary file not shown.

View File

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

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -961,11 +961,8 @@ msgid "Starting full provider sync"
msgstr "" msgstr ""
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users" #, python-brace-format
msgstr "" msgid "Syncing page {page} of users"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr "" msgstr ""
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
@ -2255,12 +2252,6 @@ msgid ""
"Active Directory" "Active Directory"
msgstr "" 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 #: authentik/sources/ldap/models.py
msgid "LDAP Source" msgid "LDAP Source"
msgstr "" msgstr ""
@ -2277,11 +2268,6 @@ msgstr ""
msgid "LDAP Source Property Mappings" msgid "LDAP Source Property Mappings"
msgstr "" 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 #: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection" msgid "User LDAP Source Connection"
msgstr "" msgstr ""
@ -2653,11 +2639,6 @@ msgstr ""
msgid "Group SAML Source Connections" msgid "Group SAML Source Connections"
msgstr "" msgstr ""
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py #: authentik/sources/scim/models.py
msgid "SCIM Source" msgid "SCIM Source"
msgstr "" msgstr ""
@ -3013,10 +2994,6 @@ msgstr ""
msgid "User Consents" msgid "User Consents"
msgstr "" msgstr ""
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py #: authentik/stages/deny/models.py
msgid "Deny Stage" msgid "Deny Stage"
msgstr "" msgstr ""
@ -3033,14 +3010,6 @@ msgstr ""
msgid "Dummy Stages" msgid "Dummy Stages"
msgstr "" 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 #: authentik/stages/email/models.py
msgid "Password Reset" msgid "Password Reset"
msgstr "" msgstr ""

Binary file not shown.

View File

@ -15,7 +15,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Jens L. <jens@goauthentik.io>, 2025\n" "Last-Translator: Jens L. <jens@goauthentik.io>, 2025\n"
"Language-Team: Spanish (https://app.transifex.com/authentik/teams/119923/es/)\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." msgid "Web Certificate used by the authentik Core webserver."
msgstr "Certificado Web usado por el servidor web Core de authentik" 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 #: authentik/brands/models.py
msgid "Brand" msgid "Brand"
msgstr "Marca" msgstr "Marca"
@ -675,33 +671,6 @@ msgstr "Dispositivos de Punto de Conexión"
msgid "Verifying your browser..." msgid "Verifying your browser..."
msgstr "Verificando tu navegador..." 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 #: authentik/enterprise/stages/source/models.py
msgid "" msgid ""
"Amount of time a user can take to return from the source to continue the " "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" msgstr "Iniciando sincronización completa de proveedor"
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users" #, python-brace-format
msgstr "" msgid "Syncing page {page} of users"
msgstr "Sincronizando página {page} de usuarios"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format #, python-brace-format
@ -2486,12 +2452,6 @@ msgid ""
"Active Directory" "Active Directory"
msgstr "" 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 #: authentik/sources/ldap/models.py
msgid "LDAP Source" msgid "LDAP Source"
msgstr "Fuente de LDAP" msgstr "Fuente de LDAP"
@ -2508,11 +2468,6 @@ msgstr "Asignación de Propiedades de Fuente de LDAP"
msgid "LDAP Source Property Mappings" msgid "LDAP Source Property Mappings"
msgstr "Asignaciones de Propiedades de Fuente de LDAP" 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 #: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection" msgid "User LDAP Source Connection"
msgstr "" msgstr ""
@ -2904,11 +2859,6 @@ msgstr "Conexión de Fuente de SAML de Grupo"
msgid "Group SAML Source Connections" msgid "Group SAML Source Connections"
msgstr "Conexiones de Fuente de SAML de Grupo" 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 #: authentik/sources/scim/models.py
msgid "SCIM Source" msgid "SCIM Source"
msgstr "Fuente de SCIM" msgstr "Fuente de SCIM"
@ -3295,10 +3245,6 @@ msgstr "Consentimiento del usuario"
msgid "User Consents" msgid "User Consents"
msgstr "Consentimientos del usuario" msgstr "Consentimientos del usuario"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py #: authentik/stages/deny/models.py
msgid "Deny Stage" msgid "Deny Stage"
msgstr "Etapa de denegación" msgstr "Etapa de denegación"
@ -3315,14 +3261,6 @@ msgstr "Escenario ficticio"
msgid "Dummy Stages" msgid "Dummy Stages"
msgstr "Etapas ficticias" 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 #: authentik/stages/email/models.py
msgid "Password Reset" msgid "Password Reset"
msgstr "Restablecimiento de contraseña" msgstr "Restablecimiento de contraseña"

Binary file not shown.

View File

@ -15,7 +15,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Ville Ranki, 2025\n" "Last-Translator: Ville Ranki, 2025\n"
"Language-Team: Finnish (https://app.transifex.com/authentik/teams/119923/fi/)\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." msgid "Web Certificate used by the authentik Core webserver."
msgstr "Web-sertifikaatti, jota authentik Core -verkkopalvelin käyttää." msgstr "Web-sertifikaatti, jota authentik Core -verkkopalvelin käyttää."
#: authentik/brands/models.py
msgid "Certificates used for client authentication."
msgstr ""
#: authentik/brands/models.py #: authentik/brands/models.py
msgid "Brand" msgid "Brand"
msgstr "Brändi" msgstr "Brändi"
@ -662,33 +658,6 @@ msgstr "Päätelaitteet"
msgid "Verifying your browser..." msgid "Verifying your browser..."
msgstr "Selaintasi varmennetaan..." 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 #: authentik/enterprise/stages/source/models.py
msgid "" msgid ""
"Amount of time a user can take to return from the source to continue the " "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" msgstr "Käynnistetään palveluntarjoajan täysi synkronisointi"
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users" #, python-brace-format
msgstr "" msgid "Syncing page {page} of users"
msgstr "Synkronoidaan käyttäjien sivua {page}"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format #, python-brace-format
@ -2463,12 +2429,6 @@ msgid ""
"Active Directory" "Active Directory"
msgstr "" 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 #: authentik/sources/ldap/models.py
msgid "LDAP Source" msgid "LDAP Source"
msgstr "LDAP-lähde" msgstr "LDAP-lähde"
@ -2485,11 +2445,6 @@ msgstr "LDAP-lähteen ominaisuuskytkentä"
msgid "LDAP Source Property Mappings" msgid "LDAP Source Property Mappings"
msgstr "LDAP-lähteen ominaisuuskytkennät" 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 #: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection" msgid "User LDAP Source Connection"
msgstr "" msgstr ""
@ -2882,11 +2837,6 @@ msgstr "Ryhmän SAML-lähteen yhteys"
msgid "Group SAML Source Connections" msgid "Group SAML Source Connections"
msgstr "Ryhmän SAML-lähteen yhteydet" 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 #: authentik/sources/scim/models.py
msgid "SCIM Source" msgid "SCIM Source"
msgstr "SCIM-lähde" msgstr "SCIM-lähde"
@ -3266,10 +3216,6 @@ msgstr "Käyttäjän hyväksyntä"
msgid "User Consents" msgid "User Consents"
msgstr "Käyttäjän hyväksynnät" 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 #: authentik/stages/deny/models.py
msgid "Deny Stage" msgid "Deny Stage"
msgstr "Kieltovaihe" msgstr "Kieltovaihe"
@ -3286,14 +3232,6 @@ msgstr "Valevaihe"
msgid "Dummy Stages" msgid "Dummy Stages"
msgstr "Valevaiheet" 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 #: authentik/stages/email/models.py
msgid "Password Reset" msgid "Password Reset"
msgstr "Salasanan nollaus" msgstr "Salasanan nollaus"

View File

@ -19,7 +19,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Marc Schmitt, 2025\n" "Last-Translator: Marc Schmitt, 2025\n"
"Language-Team: French (https://app.transifex.com/authentik/teams/119923/fr/)\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" msgstr "Démarrage d'une synchronisation complète du fournisseur"
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users" #, python-brace-format
msgstr "Synchronisation des utilisateurs" msgid "Syncing page {page} of users"
msgstr "Synchronisation de la page {page} d'utilisateurs"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr "Synchronisation des groupes"
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format #, python-brace-format
@ -2511,14 +2508,6 @@ msgstr ""
"plutôt que sur un attribut de groupe. Cela permet la résolution des groupes " "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." "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 #: authentik/sources/ldap/models.py
msgid "LDAP Source" msgid "LDAP Source"
msgstr "Source LDAP" msgstr "Source LDAP"
@ -2535,13 +2524,6 @@ msgstr "Mappage de propriété source LDAP"
msgid "LDAP Source Property Mappings" msgid "LDAP Source Property Mappings"
msgstr "Mappages de propriété source LDAP" 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 #: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection" msgid "User LDAP Source Connection"
msgstr "Connexion de l'utilisateur à la source LDAP" msgstr "Connexion de l'utilisateur à la source LDAP"
@ -2936,11 +2918,6 @@ msgstr "Connexion du groupe à la source SAML"
msgid "Group SAML Source Connections" msgid "Group SAML Source Connections"
msgstr "Connexions du groupe à la source SAML" 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 #: authentik/sources/scim/models.py
msgid "SCIM Source" msgid "SCIM Source"
msgstr "Source SCIM" msgstr "Source SCIM"
@ -3331,10 +3308,6 @@ msgstr "Consentement Utilisateur"
msgid "User Consents" msgid "User Consents"
msgstr "Consentements Utilisateur" 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 #: authentik/stages/deny/models.py
msgid "Deny Stage" msgid "Deny Stage"
msgstr "Étape de Refus" msgstr "Étape de Refus"
@ -3351,14 +3324,6 @@ msgstr "Étape factice"
msgid "Dummy Stages" msgid "Dummy Stages"
msgstr "Étapes factices" 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 #: authentik/stages/email/models.py
msgid "Password Reset" msgid "Password Reset"
msgstr "Réinitialiser le Mot de Passe" msgstr "Réinitialiser le Mot de Passe"

View File

@ -20,7 +20,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Kowalski Dragon (kowalski7cc) <kowalski.7cc@gmail.com>, 2025\n" "Last-Translator: Kowalski Dragon (kowalski7cc) <kowalski.7cc@gmail.com>, 2025\n"
"Language-Team: Italian (https://app.transifex.com/authentik/teams/119923/it/)\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." msgid "Web Certificate used by the authentik Core webserver."
msgstr "Certificato Web utilizzato dal server Web authentik Core." msgstr "Certificato Web utilizzato dal server Web authentik Core."
#: authentik/brands/models.py
msgid "Certificates used for client authentication."
msgstr ""
#: authentik/brands/models.py #: authentik/brands/models.py
msgid "Brand" msgid "Brand"
msgstr "Brand" msgstr "Brand"
@ -676,33 +672,6 @@ msgstr "Dispositivi di Accesso"
msgid "Verifying your browser..." msgid "Verifying your browser..."
msgstr "Verifica del tuo 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 #: authentik/enterprise/stages/source/models.py
msgid "" msgid ""
"Amount of time a user can take to return from the source to continue the " "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" msgstr "Avvio della sincronizzazione completa del provider"
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users" #, python-brace-format
msgstr "" msgid "Syncing page {page} of users"
msgstr "Sincronizzando pagina {page} degli utenti"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format #, python-brace-format
@ -2497,12 +2463,6 @@ msgstr ""
"attributo di gruppo. Questo consente la risoluzione di gruppi nidificati su " "attributo di gruppo. Questo consente la risoluzione di gruppi nidificati su "
"sistemi come FreeIPA e Active Directory." "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 #: authentik/sources/ldap/models.py
msgid "LDAP Source" msgid "LDAP Source"
msgstr "Sorgente LDAP" msgstr "Sorgente LDAP"
@ -2519,11 +2479,6 @@ msgstr "Mappatura delle proprietà sorgente LDAP"
msgid "LDAP Source Property Mappings" msgid "LDAP Source Property Mappings"
msgstr "Mappature delle proprietà della sorgente LDAP" 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 #: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection" msgid "User LDAP Source Connection"
msgstr "Connessione Sorgente LDAP Utente" msgstr "Connessione Sorgente LDAP Utente"
@ -2917,11 +2872,6 @@ msgstr "Connessione sorgente SAML di gruppo"
msgid "Group SAML Source Connections" msgid "Group SAML Source Connections"
msgstr "Connessioni sorgente SAML di gruppo" 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 #: authentik/sources/scim/models.py
msgid "SCIM Source" msgid "SCIM Source"
msgstr "Sorgente SCIM" msgstr "Sorgente SCIM"
@ -3319,10 +3269,6 @@ msgstr "Consenso utente"
msgid "User Consents" msgid "User Consents"
msgstr "Consensi utente" msgstr "Consensi utente"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py #: authentik/stages/deny/models.py
msgid "Deny Stage" msgid "Deny Stage"
msgstr "Fase di negazione" msgstr "Fase di negazione"
@ -3339,14 +3285,6 @@ msgstr "Fase fittizia"
msgid "Dummy Stages" msgid "Dummy Stages"
msgstr "Fasi fittizie" 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 #: authentik/stages/email/models.py
msgid "Password Reset" msgid "Password Reset"
msgstr "Ripristino password" msgstr "Ripristino password"

View File

@ -12,7 +12,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: NavyStack, 2023\n" "Last-Translator: NavyStack, 2023\n"
"Language-Team: Korean (https://app.transifex.com/authentik/teams/119923/ko/)\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." msgid "Web Certificate used by the authentik Core webserver."
msgstr "Authentik Core 웹서버에서 사용하는 웹 인증서." msgstr "Authentik Core 웹서버에서 사용하는 웹 인증서."
#: authentik/brands/models.py
msgid "Certificates used for client authentication."
msgstr ""
#: authentik/brands/models.py #: authentik/brands/models.py
msgid "Brand" msgid "Brand"
msgstr "" msgstr ""
@ -629,33 +625,6 @@ msgstr ""
msgid "Verifying your browser..." msgid "Verifying your browser..."
msgstr "" 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 #: authentik/enterprise/stages/source/models.py
msgid "" msgid ""
"Amount of time a user can take to return from the source to continue the " "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 "" msgstr ""
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users" #, python-brace-format
msgstr "" msgid "Syncing page {page} of users"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr "" msgstr ""
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
@ -2297,12 +2263,6 @@ msgid ""
"Active Directory" "Active Directory"
msgstr "" 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 #: authentik/sources/ldap/models.py
msgid "LDAP Source" msgid "LDAP Source"
msgstr "LDAP 소스" msgstr "LDAP 소스"
@ -2319,11 +2279,6 @@ msgstr ""
msgid "LDAP Source Property Mappings" msgid "LDAP Source Property Mappings"
msgstr "" 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 #: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection" msgid "User LDAP Source Connection"
msgstr "" msgstr ""
@ -2702,11 +2657,6 @@ msgstr ""
msgid "Group SAML Source Connections" msgid "Group SAML Source Connections"
msgstr "" msgstr ""
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py #: authentik/sources/scim/models.py
msgid "SCIM Source" msgid "SCIM Source"
msgstr "" msgstr ""
@ -3067,10 +3017,6 @@ msgstr "사용자 동의"
msgid "User Consents" msgid "User Consents"
msgstr "사용자 동의" msgstr "사용자 동의"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py #: authentik/stages/deny/models.py
msgid "Deny Stage" msgid "Deny Stage"
msgstr "거부 스테이지" msgstr "거부 스테이지"
@ -3087,14 +3033,6 @@ msgstr "더미 스테이지"
msgid "Dummy Stages" msgid "Dummy Stages"
msgstr "더미 스테이지" 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 #: authentik/stages/email/models.py
msgid "Password Reset" msgid "Password Reset"
msgstr "비밀번호 초기화" msgstr "비밀번호 초기화"

Binary file not shown.

View File

@ -19,7 +19,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Dany Sluijk, 2025\n" "Last-Translator: Dany Sluijk, 2025\n"
"Language-Team: Dutch (https://app.transifex.com/authentik/teams/119923/nl/)\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." msgid "Web Certificate used by the authentik Core webserver."
msgstr "Webcertificaat gebruikt door de 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 #: authentik/brands/models.py
msgid "Brand" msgid "Brand"
msgstr "Merk" msgstr "Merk"
@ -195,7 +191,6 @@ msgid "User's display name."
msgstr "Weergavenaam van de gebruiker." msgstr "Weergavenaam van de gebruiker."
#: authentik/core/models.py authentik/providers/oauth2/models.py #: authentik/core/models.py authentik/providers/oauth2/models.py
#: authentik/rbac/models.py
msgid "User" msgid "User"
msgstr "Gebruiker" msgstr "Gebruiker"
@ -384,18 +379,6 @@ msgstr "Eigenschapskoppeling"
msgid "Property Mappings" msgid "Property Mappings"
msgstr "Eigenschapskoppelingen" 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 #: authentik/core/models.py
msgid "Authenticated Session" msgid "Authenticated Session"
msgstr "Geauthenticeerde Sessie" msgstr "Geauthenticeerde Sessie"
@ -503,38 +486,6 @@ msgstr "Licentie Gebruik"
msgid "License Usage Records" msgid "License Usage Records"
msgstr "Licentie Gebruik 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 #: authentik/enterprise/policy.py
msgid "Enterprise required to access this feature." msgid "Enterprise required to access this feature."
msgstr "Enterprise benodigd voor toegang tot deze functie." msgstr "Enterprise benodigd voor toegang tot deze functie."
@ -671,33 +622,6 @@ msgstr ""
msgid "Verifying your browser..." msgid "Verifying your browser..."
msgstr "Uw browser wordt geverifieerd..." 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 #: authentik/enterprise/stages/source/models.py
msgid "" msgid ""
"Amount of time a user can take to return from the source to continue the " "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 "" msgstr ""
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users" #, python-brace-format
msgstr "" msgid "Syncing page {page} of users"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr "" msgstr ""
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
@ -1344,6 +1265,12 @@ msgstr ""
msgid "Clear Policy's cache metrics" msgid "Clear Policy's cache metrics"
msgstr "" 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 #: authentik/policies/password/models.py
msgid "How many times the password hash is allowed to be on haveibeenpwned" msgid "How many times the password hash is allowed to be on haveibeenpwned"
msgstr "Hoe vaak het wachtwoordhash op haveibeenpwned mag voorkomen" 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 " "Als de zxcvbn-score gelijk is aan of lager is dan deze waarde, zal het "
"beleid falen." "beleid falen."
#: authentik/policies/password/models.py
msgid "Password not set in context"
msgstr "Wachtwoord niet ingesteld in context"
#: authentik/policies/password/models.py #: authentik/policies/password/models.py
msgid "Invalid password." msgid "Invalid password."
msgstr "" msgstr ""
@ -1396,6 +1327,20 @@ msgstr "Reputatie Score"
msgid "Reputation Scores" msgid "Reputation Scores"
msgstr "Reputatie 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 #: authentik/policies/templates/policies/denied.html
msgid "Permission denied" msgid "Permission denied"
msgstr "Toestemming geweigerd" msgstr "Toestemming geweigerd"
@ -2215,10 +2160,6 @@ msgstr ""
msgid "Roles" msgid "Roles"
msgstr "" msgstr ""
#: authentik/rbac/models.py
msgid "Initial Permissions"
msgstr ""
#: authentik/rbac/models.py #: authentik/rbac/models.py
msgid "System permission" msgid "System permission"
msgstr "" msgstr ""
@ -2451,12 +2392,6 @@ msgid ""
"Active Directory" "Active Directory"
msgstr "" 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 #: authentik/sources/ldap/models.py
msgid "LDAP Source" msgid "LDAP Source"
msgstr "LDAP-bron" msgstr "LDAP-bron"
@ -2473,27 +2408,6 @@ msgstr ""
msgid "LDAP Source Property Mappings" msgid "LDAP Source Property Mappings"
msgstr "" 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 #: authentik/sources/ldap/signals.py
msgid "Password does not match Active Directory Complexity." msgid "Password does not match Active Directory Complexity."
msgstr "" msgstr ""
@ -2503,14 +2417,6 @@ msgstr ""
msgid "No token received." msgid "No token received."
msgstr "Geen token ontvangen." 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 #: authentik/sources/oauth/models.py
msgid "Request Token URL" msgid "Request Token URL"
msgstr "URL voor aanvragen van token" msgstr "URL voor aanvragen van token"
@ -2552,12 +2458,6 @@ msgstr ""
msgid "Additional Scopes" msgid "Additional Scopes"
msgstr "Aanvullende 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 #: authentik/sources/oauth/models.py
msgid "OAuth Source" msgid "OAuth Source"
msgstr "OAuth-bron" msgstr "OAuth-bron"
@ -2869,11 +2769,6 @@ msgstr ""
msgid "Group SAML Source Connections" msgid "Group SAML Source Connections"
msgstr "" msgstr ""
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py #: authentik/sources/scim/models.py
msgid "SCIM Source" msgid "SCIM Source"
msgstr "" msgstr ""
@ -3247,10 +3142,6 @@ msgstr "Gebruikerstoestemming"
msgid "User Consents" msgid "User Consents"
msgstr "Gebruikersinstemmingen" msgstr "Gebruikersinstemmingen"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py #: authentik/stages/deny/models.py
msgid "Deny Stage" msgid "Deny Stage"
msgstr "Weigerfase" msgstr "Weigerfase"
@ -3267,14 +3158,6 @@ msgstr "Dummystadium"
msgid "Dummy Stages" msgid "Dummy Stages"
msgstr "Dummystadia" 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 #: authentik/stages/email/models.py
msgid "Password Reset" msgid "Password Reset"
msgstr "Wachtwoordherstel" msgstr "Wachtwoordherstel"
@ -3474,12 +3357,6 @@ msgstr ""
"Wanneer ingeschakeld, slaagt de stap en gaat verder wanneer ongeldige " "Wanneer ingeschakeld, slaagt de stap en gaat verder wanneer ongeldige "
"gebruikersgegevens zijn ingevoerd." "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 #: authentik/stages/identification/models.py
msgid "Optional enrollment flow, which is linked at the bottom of the page." msgid "Optional enrollment flow, which is linked at the bottom of the page."
msgstr "Optionele inschrijvingsflow, die onderaan de pagina is gekoppeld." msgstr "Optionele inschrijvingsflow, die onderaan de pagina is gekoppeld."
@ -3865,14 +3742,6 @@ msgstr ""
"Gebeurtenissen worden verwijderd na deze duur. (Indeling: " "Gebeurtenissen worden verwijderd na deze duur. (Indeling: "
"weken=3;dagen=2;uren=3;seconden=2)." "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 #: authentik/tenants/models.py
msgid "The option configures the footer links on the flow executor pages." 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." msgstr "De optie stelt de voettekst links in op de flow uitvoer pagina's."

View File

@ -11,7 +11,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Hugo Bicho, 2025\n" "Last-Translator: Hugo Bicho, 2025\n"
"Language-Team: Portuguese (https://app.transifex.com/authentik/teams/119923/pt/)\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." msgid "Web Certificate used by the authentik Core webserver."
msgstr "Certificado Web usado pelo servidor web authentik Core." msgstr "Certificado Web usado pelo servidor web authentik Core."
#: authentik/brands/models.py
msgid "Certificates used for client authentication."
msgstr ""
#: authentik/brands/models.py #: authentik/brands/models.py
msgid "Brand" msgid "Brand"
msgstr "Marca" msgstr "Marca"
@ -666,33 +662,6 @@ msgstr "Dispositivos do ponto de ligação"
msgid "Verifying your browser..." msgid "Verifying your browser..."
msgstr "A verificar o seu 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 #: authentik/enterprise/stages/source/models.py
msgid "" msgid ""
"Amount of time a user can take to return from the source to continue the " "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" msgstr "Iniciando a sincronização completa com o provedor"
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users" #, python-brace-format
msgstr "" msgid "Syncing page {page} of users"
msgstr "A sincronizar a página {page} dos utilizadores"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format #, python-brace-format
@ -2490,12 +2456,6 @@ msgstr ""
" um atributo do grupo. Isto permite a resolução de grupos hierárquicos em " " um atributo do grupo. Isto permite a resolução de grupos hierárquicos em "
"sistemas como o FreeIPA e Active Directory." "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 #: authentik/sources/ldap/models.py
msgid "LDAP Source" msgid "LDAP Source"
msgstr "Fonte LDAP" msgstr "Fonte LDAP"
@ -2512,11 +2472,6 @@ msgstr "Mapeamento de propriedades de fonte LDAP"
msgid "LDAP Source Property Mappings" msgid "LDAP Source Property Mappings"
msgstr "Mapeamentos de propriedades de fonte LDAP" 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 #: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection" msgid "User LDAP Source Connection"
msgstr "Ligação à fonte LDAP de Utilizador" msgstr "Ligação à fonte LDAP de Utilizador"
@ -2910,11 +2865,6 @@ msgstr "Ligação à fonte SAML de Grupo"
msgid "Group SAML Source Connections" msgid "Group SAML Source Connections"
msgstr "Ligações à fonte SAML de Grupo" 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 #: authentik/sources/scim/models.py
msgid "SCIM Source" msgid "SCIM Source"
msgstr "Fonte SCIM" msgstr "Fonte SCIM"
@ -3305,10 +3255,6 @@ msgstr "Consentimento do Utilizador"
msgid "User Consents" msgid "User Consents"
msgstr "Consentimentos do Utilizador" msgstr "Consentimentos do Utilizador"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py #: authentik/stages/deny/models.py
msgid "Deny Stage" msgid "Deny Stage"
msgstr "Etapa de negação" msgstr "Etapa de negação"
@ -3325,14 +3271,6 @@ msgstr "Etapa fictícia"
msgid "Dummy Stages" msgid "Dummy Stages"
msgstr "Etapas fictícias" 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 #: authentik/stages/email/models.py
msgid "Password Reset" msgid "Password Reset"
msgstr "Redefinição de Palavra-Passe" msgstr "Redefinição de Palavra-Passe"

Binary file not shown.

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Marc Schmitt, 2025\n" "Last-Translator: Marc Schmitt, 2025\n"
"Language-Team: Russian (https://app.transifex.com/authentik/teams/119923/ru/)\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." msgid "Web Certificate used by the authentik Core webserver."
msgstr "Web Certificate используемый для authentik Core webserver." msgstr "Web Certificate используемый для authentik Core webserver."
#: authentik/brands/models.py
msgid "Certificates used for client authentication."
msgstr ""
#: authentik/brands/models.py #: authentik/brands/models.py
msgid "Brand" msgid "Brand"
msgstr "Бренд" msgstr "Бренд"
@ -673,33 +669,6 @@ msgstr "Конечные устройства"
msgid "Verifying your browser..." msgid "Verifying your browser..."
msgstr "Проверка вашего браузера..." 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 #: authentik/enterprise/stages/source/models.py
msgid "" msgid ""
"Amount of time a user can take to return from the source to continue the " "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 "Запуск полной синхронизации провайдера" msgstr "Запуск полной синхронизации провайдера"
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users" #, python-brace-format
msgstr "" msgid "Syncing page {page} of users"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr "" msgstr ""
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
@ -2464,12 +2430,6 @@ msgid ""
"Active Directory" "Active Directory"
msgstr "" 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 #: authentik/sources/ldap/models.py
msgid "LDAP Source" msgid "LDAP Source"
msgstr "Источник LDAP" msgstr "Источник LDAP"
@ -2486,11 +2446,6 @@ msgstr "Сопоставление свойства LDAP источника"
msgid "LDAP Source Property Mappings" msgid "LDAP Source Property Mappings"
msgstr "Сопоставление свойств LDAP источника" 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 #: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection" msgid "User LDAP Source Connection"
msgstr "" msgstr ""
@ -2887,11 +2842,6 @@ msgstr "Групповое подключение к источнику SAML"
msgid "Group SAML Source Connections" msgid "Group SAML Source Connections"
msgstr "Групповые подключения к источнику SAML" msgstr "Групповые подключения к источнику SAML"
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py #: authentik/sources/scim/models.py
msgid "SCIM Source" msgid "SCIM Source"
msgstr "Источник SCIM" msgstr "Источник SCIM"
@ -3269,10 +3219,6 @@ msgstr "Согласие пользователя"
msgid "User Consents" msgid "User Consents"
msgstr "Согласия пользователя" msgstr "Согласия пользователя"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py #: authentik/stages/deny/models.py
msgid "Deny Stage" msgid "Deny Stage"
msgstr "Этап отказа" msgstr "Этап отказа"
@ -3289,14 +3235,6 @@ msgstr "Фиктивный этап"
msgid "Dummy Stages" msgid "Dummy Stages"
msgstr "Фиктивные этапы" 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 #: authentik/stages/email/models.py
msgid "Password Reset" msgid "Password Reset"
msgstr "Сброс пароля" msgstr "Сброс пароля"

View File

@ -13,7 +13,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Jens L. <jens@goauthentik.io>, 2025\n" "Last-Translator: Jens L. <jens@goauthentik.io>, 2025\n"
"Language-Team: Turkish (https://app.transifex.com/authentik/teams/119923/tr/)\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." msgid "Web Certificate used by the authentik Core webserver."
msgstr "Authentik Core web sunucusu tarafından kullanılan Web Sertifikası." 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 #: authentik/brands/models.py
msgid "Brand" msgid "Brand"
msgstr "Marka" msgstr "Marka"
@ -663,33 +659,6 @@ msgstr "Uç Nokta Cihazları"
msgid "Verifying your browser..." msgid "Verifying your browser..."
msgstr "Tarayıcınız doğrulanıyor..." 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 #: authentik/enterprise/stages/source/models.py
msgid "" msgid ""
"Amount of time a user can take to return from the source to continue the " "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" msgstr "Tam sağlayıcı senkronizasyonunu başlatma"
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users" #, python-brace-format
msgstr "" msgid "Syncing page {page} of users"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr "" msgstr ""
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
@ -2464,12 +2430,6 @@ msgid ""
"Active Directory" "Active Directory"
msgstr "" 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 #: authentik/sources/ldap/models.py
msgid "LDAP Source" msgid "LDAP Source"
msgstr "LDAP Kaynağı" msgstr "LDAP Kaynağı"
@ -2486,11 +2446,6 @@ msgstr "LDAP Kaynak Özellik Eşlemesi"
msgid "LDAP Source Property Mappings" msgid "LDAP Source Property Mappings"
msgstr "LDAP Kaynak Özellik Eşlemeleri" 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 #: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection" msgid "User LDAP Source Connection"
msgstr "" msgstr ""
@ -2882,11 +2837,6 @@ msgstr "Grup SAML Kaynak Bağlantısı"
msgid "Group SAML Source Connections" msgid "Group SAML Source Connections"
msgstr "Grup SAML Kaynak Bağlantıları" 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 #: authentik/sources/scim/models.py
msgid "SCIM Source" msgid "SCIM Source"
msgstr "SCIM Kaynak" msgstr "SCIM Kaynak"
@ -3261,10 +3211,6 @@ msgstr "Kullanıcı Onayı"
msgid "User Consents" msgid "User Consents"
msgstr "Kullanıcı Onayları" msgstr "Kullanıcı Onayları"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py #: authentik/stages/deny/models.py
msgid "Deny Stage" msgid "Deny Stage"
msgstr "Aşama Alanını Reddet" msgstr "Aşama Alanını Reddet"
@ -3281,14 +3227,6 @@ msgstr "Kukla Aşaması"
msgid "Dummy Stages" msgid "Dummy Stages"
msgstr "Kukla Aşamaları" 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 #: authentik/stages/email/models.py
msgid "Password Reset" msgid "Password Reset"
msgstr "Parola Sıfırlama" msgstr "Parola Sıfırlama"

Binary file not shown.

View File

@ -15,7 +15,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: deluxghost, 2025\n" "Last-Translator: deluxghost, 2025\n"
"Language-Team: Chinese Simplified (https://app.transifex.com/authentik/teams/119923/zh-Hans/)\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 "开始全量提供程序同步" msgstr "开始全量提供程序同步"
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users" #, python-brace-format
msgstr "" msgid "Syncing page {page} of users"
msgstr "正在同步用户页面 {page}"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format #, python-brace-format
@ -2288,12 +2285,6 @@ msgid ""
"Active Directory" "Active Directory"
msgstr "基于用户属性而非组属性查询组成员身份。这允许在 FreeIPA 或 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 #: authentik/sources/ldap/models.py
msgid "LDAP Source" msgid "LDAP Source"
msgstr "LDAP 源" msgstr "LDAP 源"
@ -2310,11 +2301,6 @@ msgstr "LDAP 源属性映射"
msgid "LDAP Source Property Mappings" msgid "LDAP Source Property Mappings"
msgstr "LDAP 源属性映射" 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 #: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection" msgid "User LDAP Source Connection"
msgstr "用户 LDAP 源连接" msgstr "用户 LDAP 源连接"
@ -2692,11 +2678,6 @@ msgstr "组 SAML 源连接"
msgid "Group SAML Source Connections" msgid "Group SAML Source Connections"
msgstr "组 SAML 源连接" msgstr "组 SAML 源连接"
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py #: authentik/sources/scim/models.py
msgid "SCIM Source" msgid "SCIM Source"
msgstr "SCIM 源" msgstr "SCIM 源"
@ -3063,10 +3044,6 @@ msgstr "用户同意授权"
msgid "User Consents" msgid "User Consents"
msgstr "用户同意授权" msgstr "用户同意授权"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py #: authentik/stages/deny/models.py
msgid "Deny Stage" msgid "Deny Stage"
msgstr "拒绝阶段" msgstr "拒绝阶段"
@ -3083,14 +3060,6 @@ msgstr "虚拟阶段"
msgid "Dummy Stages" msgid "Dummy Stages"
msgstr "虚拟阶段" 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 #: authentik/stages/email/models.py
msgid "Password Reset" msgid "Password Reset"
msgstr "密码重置" msgstr "密码重置"

Binary file not shown.

View File

@ -14,7 +14,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: deluxghost, 2025\n" "Last-Translator: deluxghost, 2025\n"
"Language-Team: Chinese (China) (https://app.transifex.com/authentik/teams/119923/zh_CN/)\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 "开始全量提供程序同步" msgstr "开始全量提供程序同步"
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users" #, python-brace-format
msgstr "" msgid "Syncing page {page} of users"
msgstr "正在同步用户页面 {page}"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format #, python-brace-format
@ -2287,12 +2284,6 @@ msgid ""
"Active Directory" "Active Directory"
msgstr "基于用户属性而非组属性查询组成员身份。这允许在 FreeIPA 或 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 #: authentik/sources/ldap/models.py
msgid "LDAP Source" msgid "LDAP Source"
msgstr "LDAP 源" msgstr "LDAP 源"
@ -2309,11 +2300,6 @@ msgstr "LDAP 源属性映射"
msgid "LDAP Source Property Mappings" msgid "LDAP Source Property Mappings"
msgstr "LDAP 源属性映射" 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 #: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection" msgid "User LDAP Source Connection"
msgstr "用户 LDAP 源连接" msgstr "用户 LDAP 源连接"
@ -2691,11 +2677,6 @@ msgstr "组 SAML 源连接"
msgid "Group SAML Source Connections" msgid "Group SAML Source Connections"
msgstr "组 SAML 源连接" msgstr "组 SAML 源连接"
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py #: authentik/sources/scim/models.py
msgid "SCIM Source" msgid "SCIM Source"
msgstr "SCIM 源" msgstr "SCIM 源"
@ -3062,10 +3043,6 @@ msgstr "用户同意授权"
msgid "User Consents" msgid "User Consents"
msgstr "用户同意授权" msgstr "用户同意授权"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py #: authentik/stages/deny/models.py
msgid "Deny Stage" msgid "Deny Stage"
msgstr "拒绝阶段" msgstr "拒绝阶段"
@ -3082,14 +3059,6 @@ msgstr "虚拟阶段"
msgid "Dummy Stages" msgid "Dummy Stages"
msgstr "虚拟阶段" 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 #: authentik/stages/email/models.py
msgid "Password Reset" msgid "Password Reset"
msgstr "密码重置" msgstr "密码重置"

View File

@ -14,7 +14,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: 刘松, 2025\n" "Last-Translator: 刘松, 2025\n"
"Language-Team: Chinese (Taiwan) (https://app.transifex.com/authentik/teams/119923/zh_TW/)\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." msgid "Web Certificate used by the authentik Core webserver."
msgstr "用於 authentik Core 網頁伺服器的網頁憑證。" msgstr "用於 authentik Core 網頁伺服器的網頁憑證。"
#: authentik/brands/models.py
msgid "Certificates used for client authentication."
msgstr ""
#: authentik/brands/models.py #: authentik/brands/models.py
msgid "Brand" msgid "Brand"
msgstr "品牌" msgstr "品牌"
@ -629,33 +625,6 @@ msgstr ""
msgid "Verifying your browser..." msgid "Verifying your browser..."
msgstr "" 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 #: authentik/enterprise/stages/source/models.py
msgid "" msgid ""
"Amount of time a user can take to return from the source to continue the " "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 "開始同步所有提供程式" msgstr "開始同步所有提供程式"
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing users" #, python-brace-format
msgstr "" msgid "Syncing page {page} of users"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Syncing groups"
msgstr "" msgstr ""
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
@ -2283,12 +2249,6 @@ msgid ""
"Active Directory" "Active Directory"
msgstr "" 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 #: authentik/sources/ldap/models.py
msgid "LDAP Source" msgid "LDAP Source"
msgstr "LDAP 來源" msgstr "LDAP 來源"
@ -2305,11 +2265,6 @@ msgstr ""
msgid "LDAP Source Property Mappings" msgid "LDAP Source Property Mappings"
msgstr "" 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 #: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection" msgid "User LDAP Source Connection"
msgstr "" msgstr ""
@ -2687,11 +2642,6 @@ msgstr ""
msgid "Group SAML Source Connections" msgid "Group SAML Source Connections"
msgstr "" msgstr ""
#: authentik/sources/saml/views.py
#, python-brace-format
msgid "Continue to {source_name}"
msgstr ""
#: authentik/sources/scim/models.py #: authentik/sources/scim/models.py
msgid "SCIM Source" msgid "SCIM Source"
msgstr "SCIM 來源" msgstr "SCIM 來源"
@ -3048,10 +2998,6 @@ msgstr "使用者同意"
msgid "User Consents" msgid "User Consents"
msgstr "使用者同意" msgstr "使用者同意"
#: authentik/stages/consent/stage.py
msgid "Invalid consent token, re-showing prompt"
msgstr ""
#: authentik/stages/deny/models.py #: authentik/stages/deny/models.py
msgid "Deny Stage" msgid "Deny Stage"
msgstr "拒絕階段" msgstr "拒絕階段"
@ -3068,14 +3014,6 @@ msgstr "假階段"
msgid "Dummy Stages" msgid "Dummy Stages"
msgstr "假階段" 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 #: authentik/stages/email/models.py
msgid "Password Reset" msgid "Password Reset"
msgstr "重設密碼" msgstr "重設密碼"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -28473,10 +28473,6 @@ paths:
schema: schema:
type: string type: string
format: uuid format: uuid
- in: query
name: delete_not_found_objects
schema:
type: boolean
- in: query - in: query
name: enabled name: enabled
schema: schema:
@ -47926,10 +47922,6 @@ components:
description: Lookup group membership based on a user attribute instead of description: Lookup group membership based on a user attribute instead of
a group attribute. This allows nested group resolution on systems like a group attribute. This allows nested group resolution on systems like
FreeIPA and Active Directory 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: required:
- base_dn - base_dn
- component - component
@ -48131,10 +48123,6 @@ components:
description: Lookup group membership based on a user attribute instead of description: Lookup group membership based on a user attribute instead of
a group attribute. This allows nested group resolution on systems like a group attribute. This allows nested group resolution on systems like
FreeIPA and Active Directory 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: required:
- base_dn - base_dn
- name - name
@ -53468,10 +53456,6 @@ components:
description: Lookup group membership based on a user attribute instead of description: Lookup group membership based on a user attribute instead of
a group attribute. This allows nested group resolution on systems like a group attribute. This allows nested group resolution on systems like
FreeIPA and Active Directory 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: PatchedLicenseRequest:
type: object type: object
description: License Serializer 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 set -e -x -o pipefail
hash="$(git rev-parse HEAD || openssl rand -base64 36 | sha256sum)" hash="$(git rev-parse HEAD || openssl rand -base64 36 | sha256sum)"

View File

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

View File

@ -10,7 +10,6 @@ from authentik.blueprints.tests import apply_blueprint
from authentik.core.models import User from authentik.core.models import User
from authentik.flows.models import Flow from authentik.flows.models import Flow
from authentik.lib.config import CONFIG from authentik.lib.config import CONFIG
from authentik.lib.generators import generate_id
from authentik.stages.identification.models import IdentificationStage from authentik.stages.identification.models import IdentificationStage
from tests.e2e.utils import SeleniumTestCase, retry from tests.e2e.utils import SeleniumTestCase, retry
@ -18,10 +17,6 @@ from tests.e2e.utils import SeleniumTestCase, retry
class TestFlowsEnroll(SeleniumTestCase): class TestFlowsEnroll(SeleniumTestCase):
"""Test Enroll flow""" """Test Enroll flow"""
def setUp(self):
super().setUp()
self.username = generate_id()
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
@ -44,8 +39,8 @@ class TestFlowsEnroll(SeleniumTestCase):
self.initial_stages() self.initial_stages()
sleep(2) sleep(2)
user = User.objects.get(username=self.username) user = User.objects.get(username="foo")
self.assertEqual(user.username, self.username) self.assertEqual(user.username, "foo")
self.assertEqual(user.name, "some name") self.assertEqual(user.name, "some name")
self.assertEqual(user.email, "foo@bar.baz") self.assertEqual(user.email, "foo@bar.baz")
@ -92,16 +87,7 @@ class TestFlowsEnroll(SeleniumTestCase):
sleep(2) sleep(2)
flow_executor = self.get_shadow_root("ak-flow-executor") self.assert_user(User.objects.get(username="foo"))
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))
def initial_stages(self): def initial_stages(self):
"""Fill out initial stages""" """Fill out initial stages"""
@ -119,7 +105,7 @@ class TestFlowsEnroll(SeleniumTestCase):
wait = WebDriverWait(prompt_stage, self.wait_timeout) wait = WebDriverWait(prompt_stage, self.wait_timeout)
wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "input[name=username]"))) 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( prompt_stage.find_element(By.CSS_SELECTOR, "input[name=password]").send_keys(
self.user.username 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=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, "input[name=email]").send_keys("foo@bar.baz")
prompt_stage.find_element(By.CSS_SELECTOR, ".pf-c-button").click() 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]) self.driver.switch_to.window(self.driver.window_handles[0])
sleep(2) 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 # We can now enter the new password
flow_executor = self.get_shadow_root("ak-flow-executor") flow_executor = self.get_shadow_root("ak-flow-executor")
prompt_stage = self.get_shadow_root("ak-stage-prompt", 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) print("::group::authentik Logs", file=stderr)
apps.get_app_config("authentik_tenants").ready() apps.get_app_config("authentik_tenants").ready()
self.wait_timeout = 60 self.wait_timeout = 60
self.logger = get_logger()
self.driver = self._get_driver() self.driver = self._get_driver()
self.driver.implicitly_wait(30) self.driver.implicitly_wait(30)
self.wait = WebDriverWait(self.driver, self.wait_timeout) self.wait = WebDriverWait(self.driver, self.wait_timeout)
self.logger = get_logger()
self.user = create_test_admin_user() self.user = create_test_admin_user()
super().setUp() super().setUp()
def _get_driver(self) -> WebDriver: def _get_driver(self) -> WebDriver:
count = 0 count = 0
opts = webdriver.ChromeOptions() try:
opts.add_argument("--disable-search-engine-choice-screen") opts = webdriver.ChromeOptions()
# This breaks selenium when running remotely...? opts.add_argument("--disable-search-engine-choice-screen")
# opts.set_capability("goog:loggingPrefs", {"browser": "ALL"}) return webdriver.Chrome(options=opts)
opts.add_experimental_option( except WebDriverException:
"prefs", pass
{
"profile.password_manager_leak_detection": False,
},
)
while count < RETRIES: while count < RETRIES:
try: try:
driver = webdriver.Remote( driver = webdriver.Remote(
command_executor="http://localhost:4444/wd/hub", command_executor="http://localhost:4444/wd/hub",
options=opts, options=webdriver.ChromeOptions(),
) )
driver.maximize_window() driver.maximize_window()
return driver return driver
except WebDriverException as exc: except WebDriverException:
self.logger.warning("Failed to setup webdriver", exc=exc)
count += 1 count += 1
raise ValueError(f"Webdriver failed after {RETRIES}.") 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 = "celery", specifier = "==5.5.2" },
{ name = "channels", specifier = "==4.2.2" }, { name = "channels", specifier = "==4.2.2" },
{ name = "channels-redis", specifier = "==4.2.1" }, { 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 = "dacite", specifier = "==1.9.2" },
{ name = "deepmerge", specifier = "==2.0" }, { name = "deepmerge", specifier = "==2.0" },
{ name = "defusedxml", specifier = "==0.7.1" }, { name = "defusedxml", specifier = "==0.7.1" },
@ -283,7 +283,7 @@ requires-dist = [
{ name = "django-prometheus", specifier = "==2.3.1" }, { name = "django-prometheus", specifier = "==2.3.1" },
{ name = "django-redis", specifier = "==5.4.0" }, { name = "django-redis", specifier = "==5.4.0" },
{ name = "django-storages", extras = ["s3"], specifier = "==1.14.6" }, { 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", git = "https://github.com/goauthentik/django-rest-framework?rev=896722bab969fabc74a08b827da59409cf9f1a4e" },
{ name = "djangorestframework-guardian", specifier = "==0.3.0" }, { name = "djangorestframework-guardian", specifier = "==0.3.0" },
{ name = "docker", specifier = "==7.1.0" }, { name = "docker", specifier = "==7.1.0" },
@ -303,7 +303,7 @@ requires-dist = [
{ name = "kubernetes", specifier = "==32.0.1" }, { name = "kubernetes", specifier = "==32.0.1" },
{ name = "ldap3", specifier = "==2.9.1" }, { name = "ldap3", specifier = "==2.9.1" },
{ name = "lxml", specifier = "==5.4.0" }, { 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 = "opencontainers", git = "https://github.com/vsoch/oci-python?rev=ceb4fcc090851717a3069d78e85ceb1e86c2740c" },
{ name = "packaging", specifier = "==25.0" }, { name = "packaging", specifier = "==25.0" },
{ name = "paramiko", specifier = "==3.5.1" }, { name = "paramiko", specifier = "==3.5.1" },
@ -869,37 +869,37 @@ wheels = [
[[package]] [[package]]
name = "cryptography" name = "cryptography"
version = "45.0.3" version = "44.0.3"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, { 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 = [ 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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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]] [[package]]
@ -1118,12 +1118,11 @@ s3 = [
[[package]] [[package]]
name = "django-tenants" name = "django-tenants"
version = "3.8.0" version = "3.7.0"
source = { registry = "https://pypi.org/simple" } source = { git = "https://github.com/goauthentik/django-tenants.git?branch=authentik-fixes#156e53a6f5902d74b73dd9d0192fffaa2587a740" }
dependencies = [ dependencies = [
{ name = "django" }, { 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]] [[package]]
name = "djangorestframework" name = "djangorestframework"
@ -2066,7 +2065,7 @@ wheels = [
[[package]] [[package]]
name = "msgraph-sdk" name = "msgraph-sdk"
version = "1.31.0" version = "1.30.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "azure-identity" }, { name = "azure-identity" },
@ -2076,9 +2075,9 @@ dependencies = [
{ name = "microsoft-kiota-serialization-text" }, { name = "microsoft-kiota-serialization-text" },
{ name = "msgraph-core" }, { 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 = [ 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]] [[package]]
@ -2577,14 +2576,14 @@ wheels = [
[[package]] [[package]]
name = "pyopenssl" name = "pyopenssl"
version = "25.1.0" version = "25.0.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "cryptography" }, { 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 = [ 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]] [[package]]

View File

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

View File

@ -4,27 +4,30 @@
* @import { * @import {
* OnLoadArgs, * OnLoadArgs,
* OnLoadResult, * OnLoadResult,
* OnResolveArgs,
* OnResolveResult,
* Plugin, * Plugin,
* PluginBuild * PluginBuild
* } from "esbuild" * } from "esbuild"
*/ */
import { MonoRepoRoot } from "@goauthentik/core/paths/node";
import * as fs from "node:fs/promises"; import * as fs from "node:fs/promises";
import * as path from "node:path"; 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`. * @typedef LoadDataFields
* @property {PluginData | null | undefined} [pluginData] Plugin data. * 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 * @typedef MDXPluginOptions
@ -35,35 +38,28 @@ const pluginName = "mdx-plugin";
/** /**
* Bundle MDX into JSON modules. * Bundle MDX into JSON modules.
* *
* @param {MDXPluginOptions} options * @param {MDXPluginOptions} options Options.
* @returns {Plugin} * @returns {Plugin} Plugin.
*/ */
export function mdxPlugin({ root }) { export function mdxPlugin({ root }) {
// TODO: Replace with `resolvePackage` after NPM Workspaces support is added. return { name, setup };
const docsPackageRoot = path.resolve(MonoRepoRoot, "website");
/** /**
* @param {PluginBuild} build * @param {PluginBuild} build
* Build.
* @returns {undefined}
* Nothing.
*/ */
function setup(build) { function setup(build) {
/** build.onLoad({ filter: /\.mdx?$/ }, onload);
* @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,
};
}
/** /**
* @param {LoadData} data * @param {LoadData} data
* Data.
* @returns {Promise<OnLoadResult>} * @returns {Promise<OnLoadResult>}
* Result.
*/ */
async function loadListener(data) { async function onload(data) {
const content = String( const content = String(
data.pluginData && data.pluginData &&
data.pluginData.contents !== null && data.pluginData.contents !== null &&
@ -81,16 +77,7 @@ export function mdxPlugin({ root }) {
return { return {
contents: JSON.stringify({ content, publicPath, publicDirectory }), contents: JSON.stringify({ content, publicPath, publicDirectory }),
loader: "file", 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 tseslint from "typescript-eslint";
import { createESLintPackageConfig } from "@goauthentik/eslint-config";
// @ts-check // @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/legacy-modes": "^6.4.1",
"@codemirror/theme-one-dark": "^6.1.2", "@codemirror/theme-one-dark": "^6.1.2",
"@floating-ui/dom": "^1.6.11", "@floating-ui/dom": "^1.6.11",
"@formatjs/intl-listformat": "^7.7.11", "@formatjs/intl-listformat": "^7.5.7",
"@fortawesome/fontawesome-free": "^6.6.0", "@fortawesome/fontawesome-free": "^6.6.0",
"@goauthentik/api": "^2025.4.1-1748431399", "@goauthentik/api": "^2025.4.1-1747687715",
"@lit/context": "^1.1.2", "@lit/context": "^1.1.2",
"@lit/localize": "^0.12.2", "@lit/localize": "^0.12.2",
"@lit/reactive-element": "^2.0.4", "@lit/reactive-element": "^2.0.4",
@ -111,12 +111,12 @@
"chartjs-adapter-date-fns": "^3.0.0", "chartjs-adapter-date-fns": "^3.0.0",
"codemirror": "^6.0.1", "codemirror": "^6.0.1",
"construct-style-sheets-polyfill": "^3.1.0", "construct-style-sheets-polyfill": "^3.1.0",
"core-js": "^3.42.0", "core-js": "^3.38.1",
"country-flag-icons": "^1.5.19", "country-flag-icons": "^1.5.19",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"deepmerge-ts": "^7.1.5", "deepmerge-ts": "^7.1.5",
"dompurify": "^3.2.6", "dompurify": "^3.2.6",
"fuse.js": "^7.1.0", "fuse.js": "^7.0.0",
"guacamole-common-js": "^1.5.0", "guacamole-common-js": "^1.5.0",
"hastscript": "^9.0.1", "hastscript": "^9.0.1",
"lit": "^3.2.0", "lit": "^3.2.0",
@ -144,15 +144,14 @@
"@eslint/js": "^9.27.0", "@eslint/js": "^9.27.0",
"@goauthentik/core": "^1.0.0", "@goauthentik/core": "^1.0.0",
"@goauthentik/esbuild-plugin-live-reload": "^1.0.4", "@goauthentik/esbuild-plugin-live-reload": "^1.0.4",
"@goauthentik/eslint-config": "^1.0.5", "@goauthentik/eslint-config": "^1.0.4",
"@goauthentik/prettier-config": "^1.0.5", "@goauthentik/prettier-config": "^1.0.4",
"@goauthentik/tsconfig": "^1.0.4", "@goauthentik/tsconfig": "^1.0.4",
"@hcaptcha/types": "^1.0.4", "@hcaptcha/types": "^1.0.4",
"@lit/localize-tools": "^0.8.0", "@lit/localize-tools": "^0.8.0",
"@storybook/addon-essentials": "^8.6.14", "@storybook/addon-essentials": "^8.6.14",
"@storybook/addon-links": "^8.6.14", "@storybook/addon-links": "^8.6.14",
"@storybook/blocks": "^8.6.12", "@storybook/blocks": "^8.6.12",
"@storybook/channels": "^8.6.14",
"@storybook/experimental-addon-test": "^8.6.14", "@storybook/experimental-addon-test": "^8.6.14",
"@storybook/manager-api": "^8.6.14", "@storybook/manager-api": "^8.6.14",
"@storybook/test": "^8.6.14", "@storybook/test": "^8.6.14",
@ -184,7 +183,7 @@
"eslint-plugin-wc": "^3.0.1", "eslint-plugin-wc": "^3.0.1",
"github-slugger": "^2.0.0", "github-slugger": "^2.0.0",
"globals": "^15.10.0", "globals": "^15.10.0",
"knip": "^5.58.0", "knip": "^5.30.6",
"lit-analyzer": "^2.0.3", "lit-analyzer": "^2.0.3",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"prettier": "^3.3.3", "prettier": "^3.3.3",
@ -203,9 +202,9 @@
"@esbuild/darwin-arm64": "^0.25.4", "@esbuild/darwin-arm64": "^0.25.4",
"@esbuild/linux-arm64": "^0.25.4", "@esbuild/linux-arm64": "^0.25.4",
"@esbuild/linux-x64": "^0.25.4", "@esbuild/linux-x64": "^0.25.4",
"@rollup/rollup-darwin-arm64": "^4.41.1", "@rollup/rollup-darwin-arm64": "^4.41.0",
"@rollup/rollup-linux-arm64-gnu": "^4.41.1", "@rollup/rollup-linux-arm64-gnu": "^4.41.0",
"@rollup/rollup-linux-x64-gnu": "^4.41.1" "@rollup/rollup-linux-x64-gnu": "^4.41.0"
}, },
"wireit": { "wireit": {
"build": { "build": {
@ -364,7 +363,6 @@
"workspaces": [ "workspaces": [
"./packages/*" "./packages/*"
], ],
"prettier": "@goauthentik/prettier-config",
"overrides": { "overrides": {
"@storybook/addon-docs": { "@storybook/addon-docs": {
"react": "^19.1.0", "react": "^19.1.0",

View File

@ -45,7 +45,7 @@
} }
}, },
"devDependencies": { "devDependencies": {
"@goauthentik/prettier-config": "^1.0.5", "@goauthentik/prettier-config": "^1.0.4",
"@goauthentik/tsconfig": "^1.0.4", "@goauthentik/tsconfig": "^1.0.4",
"@types/node": "^22.15.21", "@types/node": "^22.15.21",
"prettier": "^3.3.3", "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} * @implements {Disposable}
* @category Plugin
* runtime browser
*/ */
export class ESBuildObserver extends EventSource { export class ESBuildObserver extends EventSource {
/** /**

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