Compare commits
110 Commits
website/do
...
events/imp
Author | SHA1 | Date | |
---|---|---|---|
1fcef476c3 | |||
e8b6b3366b | |||
f76becfd86 | |||
080e2311fe | |||
eacc0eb546 | |||
c77a54dc2a | |||
84781df51b | |||
a640866534 | |||
e070241407 | |||
85985c3673 | |||
3abe6cd02c | |||
90c5b5c475 | |||
adfbd1e0f2 | |||
caa5617ce6 | |||
d043dacece | |||
6a367d4ddf | |||
e802c536a5 | |||
39db9d9e6a | |||
f9ea4fc8e7 | |||
2320efc256 | |||
7b81cbbb43 | |||
2d480bffb4 | |||
e6e0e49535 | |||
31b90d5e1d | |||
e39f186e26 | |||
cdb1351cfb | |||
7b2c08073f | |||
9ad4dfb522 | |||
6b05195add | |||
2ae095bfeb | |||
cc68d8dd92 | |||
89a158f66c | |||
c56ee219a9 | |||
d596c08954 | |||
070cdba521 | |||
148d83c519 | |||
77146d2bac | |||
03d5cde5fa | |||
4af922165e | |||
c3e57a7566 | |||
423354fb09 | |||
f3fb064908 | |||
492ef54d55 | |||
8eaed2b2f4 | |||
092b6f7faf | |||
d145f91be7 | |||
36c9929e1f | |||
3fa6ce2e34 | |||
073c02cbb9 | |||
bc8971f19d | |||
104c116678 | |||
f025d0d1d5 | |||
52115f9345 | |||
b476551f13 | |||
f9563c25cd | |||
0067e6e155 | |||
ce183929d4 | |||
2fdf345271 | |||
bbcf8418b4 | |||
dc57be46f4 | |||
d68b3ba516 | |||
a9c46cfcbd | |||
c50353ebf6 | |||
db6be9e1b6 | |||
a74892886d | |||
74cd4c2236 | |||
ef3bd7e77b | |||
3f5ad2baa4 | |||
24805f087b | |||
9464b422a3 | |||
da6d4ede51 | |||
cecad5bfd3 | |||
bc4b07d57b | |||
e85d2d0096 | |||
be1dd3103b | |||
5dfde5e1d3 | |||
7cb1e6d81e | |||
d7c3129b1c | |||
2a1d33021b | |||
f273e49ae6 | |||
cc31957900 | |||
b1ccdecc8e | |||
34031003a4 | |||
055e1d1025 | |||
59a804273e | |||
bce70a1796 | |||
e86c40a00c | |||
20e07486ee | |||
0cb7cf2c96 | |||
07736a90b2 | |||
ec28a86259 | |||
260800c60b | |||
ee4780394d | |||
23b746941f | |||
3c2ce40afd | |||
2aceed285e | |||
81e5fef667 | |||
7aa6593760 | |||
c40a17beb9 | |||
335c9fbc10 | |||
51b53caf61 | |||
989100a900 | |||
8e1531d051 | |||
f6f37d6d92 | |||
5b6ca70f22 | |||
a74674c3d6 | |||
f46984dec4 | |||
c7963e4af7 | |||
6e30b11974 | |||
13bd4069e4 |
@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 2025.6.1
|
current_version = 2025.6.2
|
||||||
tag = True
|
tag = True
|
||||||
commit = True
|
commit = True
|
||||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))?
|
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))?
|
||||||
@ -21,6 +21,8 @@ optional_value = final
|
|||||||
|
|
||||||
[bumpversion:file:package.json]
|
[bumpversion:file:package.json]
|
||||||
|
|
||||||
|
[bumpversion:file:package-lock.json]
|
||||||
|
|
||||||
[bumpversion:file:docker-compose.yml]
|
[bumpversion:file:docker-compose.yml]
|
||||||
|
|
||||||
[bumpversion:file:schema.yml]
|
[bumpversion:file:schema.yml]
|
||||||
@ -31,6 +33,4 @@ optional_value = final
|
|||||||
|
|
||||||
[bumpversion:file:internal/constants/constants.go]
|
[bumpversion:file:internal/constants/constants.go]
|
||||||
|
|
||||||
[bumpversion:file:web/src/common/constants.ts]
|
|
||||||
|
|
||||||
[bumpversion:file:lifecycle/aws/template.yaml]
|
[bumpversion:file:lifecycle/aws/template.yaml]
|
||||||
|
@ -7,6 +7,9 @@ charset = utf-8
|
|||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.toml]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
[*.html]
|
[*.html]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
|
2
.github/workflows/ci-main.yml
vendored
2
.github/workflows/ci-main.yml
vendored
@ -202,7 +202,7 @@ jobs:
|
|||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: web/dist
|
path: web/dist
|
||||||
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b
|
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b
|
||||||
- name: prepare web ui
|
- name: prepare web ui
|
||||||
if: steps.cache-web.outputs.cache-hit != 'true'
|
if: steps.cache-web.outputs.cache-hit != 'true'
|
||||||
working-directory: web
|
working-directory: web
|
||||||
|
22
.github/workflows/ci-website.yml
vendored
22
.github/workflows/ci-website.yml
vendored
@ -41,6 +41,27 @@ jobs:
|
|||||||
- name: test
|
- name: test
|
||||||
working-directory: website/
|
working-directory: website/
|
||||||
run: npm test
|
run: npm test
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: ${{ matrix.job }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
job:
|
||||||
|
- build
|
||||||
|
- build:integrations
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version-file: website/package.json
|
||||||
|
cache: "npm"
|
||||||
|
cache-dependency-path: website/package-lock.json
|
||||||
|
- working-directory: website/
|
||||||
|
run: npm ci
|
||||||
|
- name: build
|
||||||
|
working-directory: website/
|
||||||
|
run: npm run ${{ matrix.job }}
|
||||||
build-container:
|
build-container:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
@ -94,6 +115,7 @@ jobs:
|
|||||||
needs:
|
needs:
|
||||||
- lint
|
- lint
|
||||||
- test
|
- test
|
||||||
|
- build
|
||||||
- build-container
|
- build-container
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
@ -75,9 +75,9 @@ 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 4: Download uv
|
# Stage 4: Download uv
|
||||||
FROM ghcr.io/astral-sh/uv:0.7.12 AS uv
|
FROM ghcr.io/astral-sh/uv:0.7.13 AS uv
|
||||||
# Stage 5: Base python image
|
# Stage 5: Base python image
|
||||||
FROM ghcr.io/goauthentik/fips-python:3.13.4-slim-bookworm-fips AS python-base
|
FROM ghcr.io/goauthentik/fips-python:3.13.5-slim-bookworm-fips AS python-base
|
||||||
|
|
||||||
ENV VENV_PATH="/ak-root/.venv" \
|
ENV VENV_PATH="/ak-root/.venv" \
|
||||||
PATH="/lifecycle:/ak-root/.venv/bin:$PATH" \
|
PATH="/lifecycle:/ak-root/.venv/bin:$PATH" \
|
||||||
|
6
Makefile
6
Makefile
@ -86,6 +86,10 @@ dev-create-db:
|
|||||||
|
|
||||||
dev-reset: dev-drop-db dev-create-db migrate ## Drop and restore the Authentik PostgreSQL instance to a "fresh install" state.
|
dev-reset: dev-drop-db dev-create-db migrate ## Drop and restore the Authentik PostgreSQL instance to a "fresh install" state.
|
||||||
|
|
||||||
|
update-test-mmdb: ## Update test GeoIP and ASN Databases
|
||||||
|
curl -L https://raw.githubusercontent.com/maxmind/MaxMind-DB/refs/heads/main/test-data/GeoLite2-ASN-Test.mmdb -o ${PWD}/tests/GeoLite2-ASN-Test.mmdb
|
||||||
|
curl -L https://raw.githubusercontent.com/maxmind/MaxMind-DB/refs/heads/main/test-data/GeoLite2-City-Test.mmdb -o ${PWD}/tests/GeoLite2-City-Test.mmdb
|
||||||
|
|
||||||
#########################
|
#########################
|
||||||
## API Schema
|
## API Schema
|
||||||
#########################
|
#########################
|
||||||
@ -94,7 +98,7 @@ gen-build: ## Extract the schema from the database
|
|||||||
AUTHENTIK_DEBUG=true \
|
AUTHENTIK_DEBUG=true \
|
||||||
AUTHENTIK_TENANTS__ENABLED=true \
|
AUTHENTIK_TENANTS__ENABLED=true \
|
||||||
AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST=true \
|
AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST=true \
|
||||||
uv run ak make_blueprint_schema > blueprints/schema.json
|
uv run ak make_blueprint_schema --file blueprints/schema.json
|
||||||
AUTHENTIK_DEBUG=true \
|
AUTHENTIK_DEBUG=true \
|
||||||
AUTHENTIK_TENANTS__ENABLED=true \
|
AUTHENTIK_TENANTS__ENABLED=true \
|
||||||
AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST=true \
|
AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST=true \
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from os import environ
|
from os import environ
|
||||||
|
|
||||||
__version__ = "2025.6.1"
|
__version__ = "2025.6.2"
|
||||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,20 +72,33 @@ class Command(BaseCommand):
|
|||||||
"additionalProperties": True,
|
"additionalProperties": True,
|
||||||
},
|
},
|
||||||
"entries": {
|
"entries": {
|
||||||
"type": "array",
|
"anyOf": [
|
||||||
"items": {
|
{
|
||||||
"oneOf": [],
|
"type": "array",
|
||||||
},
|
"items": {"$ref": "#/$defs/blueprint_entry"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/$defs/blueprint_entry"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"$defs": {},
|
"$defs": {"blueprint_entry": {"oneOf": []}},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument("--file", type=str)
|
||||||
|
|
||||||
@no_translations
|
@no_translations
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, file: str, **options):
|
||||||
"""Generate JSON Schema for blueprints"""
|
"""Generate JSON Schema for blueprints"""
|
||||||
self.build()
|
self.build()
|
||||||
self.stdout.write(dumps(self.schema, indent=4, default=Command.json_default))
|
with open(file, "w") as _schema:
|
||||||
|
_schema.write(dumps(self.schema, indent=4, default=Command.json_default))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def json_default(value: Any) -> Any:
|
def json_default(value: Any) -> Any:
|
||||||
@ -112,7 +125,7 @@ class Command(BaseCommand):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
model_path = f"{model._meta.app_label}.{model._meta.model_name}"
|
model_path = f"{model._meta.app_label}.{model._meta.model_name}"
|
||||||
self.schema["properties"]["entries"]["items"]["oneOf"].append(
|
self.schema["$defs"]["blueprint_entry"]["oneOf"].append(
|
||||||
self.template_entry(model_path, model, serializer)
|
self.template_entry(model_path, model, serializer)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -134,7 +147,7 @@ class Command(BaseCommand):
|
|||||||
"id": {"type": "string"},
|
"id": {"type": "string"},
|
||||||
"state": {
|
"state": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [s.value for s in BlueprintEntryDesiredState],
|
"enum": sorted([s.value for s in BlueprintEntryDesiredState]),
|
||||||
"default": "present",
|
"default": "present",
|
||||||
},
|
},
|
||||||
"conditions": {"type": "array", "items": {"type": "boolean"}},
|
"conditions": {"type": "array", "items": {"type": "boolean"}},
|
||||||
@ -205,7 +218,7 @@ class Command(BaseCommand):
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["permission"],
|
"required": ["permission"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"permission": {"type": "string", "enum": perms},
|
"permission": {"type": "string", "enum": sorted(perms)},
|
||||||
"user": {"type": "integer"},
|
"user": {"type": "integer"},
|
||||||
"role": {"type": "string"},
|
"role": {"type": "string"},
|
||||||
},
|
},
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
version: 1
|
version: 1
|
||||||
entries:
|
entries:
|
||||||
- identifiers:
|
foo:
|
||||||
name: "%(id)s"
|
- identifiers:
|
||||||
slug: "%(id)s"
|
name: "%(id)s"
|
||||||
model: authentik_flows.flow
|
slug: "%(id)s"
|
||||||
state: present
|
model: authentik_flows.flow
|
||||||
attrs:
|
state: present
|
||||||
designation: stage_configuration
|
attrs:
|
||||||
title: foo
|
designation: stage_configuration
|
||||||
|
title: foo
|
||||||
|
@ -191,11 +191,18 @@ class Blueprint:
|
|||||||
"""Dataclass used for a full export"""
|
"""Dataclass used for a full export"""
|
||||||
|
|
||||||
version: int = field(default=1)
|
version: int = field(default=1)
|
||||||
entries: list[BlueprintEntry] = field(default_factory=list)
|
entries: list[BlueprintEntry] | dict[str, list[BlueprintEntry]] = field(default_factory=list)
|
||||||
context: dict = field(default_factory=dict)
|
context: dict = field(default_factory=dict)
|
||||||
|
|
||||||
metadata: BlueprintMetadata | None = field(default=None)
|
metadata: BlueprintMetadata | None = field(default=None)
|
||||||
|
|
||||||
|
def iter_entries(self) -> Iterable[BlueprintEntry]:
|
||||||
|
if isinstance(self.entries, dict):
|
||||||
|
for _section, entries in self.entries.items():
|
||||||
|
yield from entries
|
||||||
|
else:
|
||||||
|
yield from self.entries
|
||||||
|
|
||||||
|
|
||||||
class YAMLTag:
|
class YAMLTag:
|
||||||
"""Base class for all YAML Tags"""
|
"""Base class for all YAML Tags"""
|
||||||
@ -226,7 +233,7 @@ class KeyOf(YAMLTag):
|
|||||||
self.id_from = node.value
|
self.id_from = node.value
|
||||||
|
|
||||||
def resolve(self, entry: BlueprintEntry, blueprint: Blueprint) -> Any:
|
def resolve(self, entry: BlueprintEntry, blueprint: Blueprint) -> Any:
|
||||||
for _entry in blueprint.entries:
|
for _entry in blueprint.iter_entries():
|
||||||
if _entry.id == self.id_from and _entry._state.instance:
|
if _entry.id == self.id_from and _entry._state.instance:
|
||||||
# Special handling for PolicyBindingModels, as they'll have a different PK
|
# Special handling for PolicyBindingModels, as they'll have a different PK
|
||||||
# which is used when creating policy bindings
|
# which is used when creating policy bindings
|
||||||
|
@ -384,7 +384,7 @@ class Importer:
|
|||||||
def _apply_models(self, raise_errors=False) -> bool:
|
def _apply_models(self, raise_errors=False) -> bool:
|
||||||
"""Apply (create/update) models yaml"""
|
"""Apply (create/update) models yaml"""
|
||||||
self.__pk_map = {}
|
self.__pk_map = {}
|
||||||
for entry in self._import.entries:
|
for entry in self._import.iter_entries():
|
||||||
model_app_label, model_name = entry.get_model(self._import).split(".")
|
model_app_label, model_name = entry.get_model(self._import).split(".")
|
||||||
try:
|
try:
|
||||||
model: type[SerializerModel] = registry.get_model(model_app_label, model_name)
|
model: type[SerializerModel] = registry.get_model(model_app_label, model_name)
|
||||||
|
@ -47,7 +47,7 @@ class MetaModelRegistry:
|
|||||||
models = apps.get_models()
|
models = apps.get_models()
|
||||||
for _, value in self.models.items():
|
for _, value in self.models.items():
|
||||||
models.append(value)
|
models.append(value)
|
||||||
return models
|
return sorted(models, key=str)
|
||||||
|
|
||||||
def get_model(self, app_label: str, model_id: str) -> type[Model]:
|
def get_model(self, app_label: str, model_id: str) -> type[Model]:
|
||||||
"""Get model checks if any virtual models are registered, and falls back
|
"""Get model checks if any virtual models are registered, and falls back
|
||||||
|
@ -386,8 +386,23 @@ class UserViewSet(UsedByMixin, ModelViewSet):
|
|||||||
queryset = User.objects.none()
|
queryset = User.objects.none()
|
||||||
ordering = ["username"]
|
ordering = ["username"]
|
||||||
serializer_class = UserSerializer
|
serializer_class = UserSerializer
|
||||||
search_fields = ["username", "name", "is_active", "email", "uuid", "attributes"]
|
|
||||||
filterset_class = UsersFilter
|
filterset_class = UsersFilter
|
||||||
|
search_fields = ["username", "name", "is_active", "email", "uuid", "attributes"]
|
||||||
|
|
||||||
|
def get_ql_fields(self):
|
||||||
|
from djangoql.schema import BoolField, StrField
|
||||||
|
|
||||||
|
from authentik.enterprise.search.fields import ChoiceSearchField, JSONSearchField
|
||||||
|
|
||||||
|
return [
|
||||||
|
StrField(User, "username"),
|
||||||
|
StrField(User, "name"),
|
||||||
|
StrField(User, "email"),
|
||||||
|
StrField(User, "path"),
|
||||||
|
BoolField(User, "is_active", nullable=True),
|
||||||
|
ChoiceSearchField(User, "type"),
|
||||||
|
JSONSearchField(User, "attributes"),
|
||||||
|
]
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
base_qs = User.objects.all().exclude_anonymous()
|
base_qs = User.objects.all().exclude_anonymous()
|
||||||
|
@ -11,7 +11,6 @@ from authentik.core.expression.exceptions import SkipObjectException
|
|||||||
from authentik.core.models import User
|
from authentik.core.models import User
|
||||||
from authentik.events.models import Event, EventAction
|
from authentik.events.models import Event, EventAction
|
||||||
from authentik.lib.expression.evaluator import BaseEvaluator
|
from authentik.lib.expression.evaluator import BaseEvaluator
|
||||||
from authentik.lib.utils.errors import exception_to_string
|
|
||||||
from authentik.policies.types import PolicyRequest
|
from authentik.policies.types import PolicyRequest
|
||||||
|
|
||||||
PROPERTY_MAPPING_TIME = Histogram(
|
PROPERTY_MAPPING_TIME = Histogram(
|
||||||
@ -69,12 +68,11 @@ class PropertyMappingEvaluator(BaseEvaluator):
|
|||||||
# For dry-run requests we don't save exceptions
|
# For dry-run requests we don't save exceptions
|
||||||
if self.dry_run:
|
if self.dry_run:
|
||||||
return
|
return
|
||||||
error_string = exception_to_string(exc)
|
|
||||||
event = Event.new(
|
event = Event.new(
|
||||||
EventAction.PROPERTY_MAPPING_EXCEPTION,
|
EventAction.PROPERTY_MAPPING_EXCEPTION,
|
||||||
expression=expression_source,
|
expression=expression_source,
|
||||||
message=error_string,
|
message="Failed to execute property mapping",
|
||||||
)
|
).with_exception(exc)
|
||||||
if "request" in self._context:
|
if "request" in self._context:
|
||||||
req: PolicyRequest = self._context["request"]
|
req: PolicyRequest = self._context["request"]
|
||||||
if req.http_request:
|
if req.http_request:
|
||||||
|
@ -18,7 +18,7 @@ from django.http import HttpRequest
|
|||||||
from django.utils.functional import SimpleLazyObject, cached_property
|
from django.utils.functional import SimpleLazyObject, cached_property
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django_cte import CTEQuerySet, With
|
from django_cte import CTE, with_cte
|
||||||
from guardian.conf import settings
|
from guardian.conf import settings
|
||||||
from guardian.mixins import GuardianUserMixin
|
from guardian.mixins import GuardianUserMixin
|
||||||
from model_utils.managers import InheritanceManager
|
from model_utils.managers import InheritanceManager
|
||||||
@ -136,7 +136,7 @@ class AttributesMixin(models.Model):
|
|||||||
return instance, False
|
return instance, False
|
||||||
|
|
||||||
|
|
||||||
class GroupQuerySet(CTEQuerySet):
|
class GroupQuerySet(QuerySet):
|
||||||
def with_children_recursive(self):
|
def with_children_recursive(self):
|
||||||
"""Recursively get all groups that have the current queryset as parents
|
"""Recursively get all groups that have the current queryset as parents
|
||||||
or are indirectly related."""
|
or are indirectly related."""
|
||||||
@ -165,9 +165,9 @@ class GroupQuerySet(CTEQuerySet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Build the recursive query, see above
|
# Build the recursive query, see above
|
||||||
cte = With.recursive(make_cte)
|
cte = CTE.recursive(make_cte)
|
||||||
# Return the result, as a usable queryset for Group.
|
# Return the result, as a usable queryset for Group.
|
||||||
return cte.join(Group, group_uuid=cte.col.group_uuid).with_cte(cte)
|
return with_cte(cte, select=cte.join(Group, group_uuid=cte.col.group_uuid))
|
||||||
|
|
||||||
|
|
||||||
class Group(SerializerModel, AttributesMixin):
|
class Group(SerializerModel, AttributesMixin):
|
||||||
|
@ -114,6 +114,7 @@ class TestApplicationsAPI(APITestCase):
|
|||||||
self.assertJSONEqual(
|
self.assertJSONEqual(
|
||||||
response.content.decode(),
|
response.content.decode(),
|
||||||
{
|
{
|
||||||
|
"autocomplete": {},
|
||||||
"pagination": {
|
"pagination": {
|
||||||
"next": 0,
|
"next": 0,
|
||||||
"previous": 0,
|
"previous": 0,
|
||||||
@ -167,6 +168,7 @@ class TestApplicationsAPI(APITestCase):
|
|||||||
self.assertJSONEqual(
|
self.assertJSONEqual(
|
||||||
response.content.decode(),
|
response.content.decode(),
|
||||||
{
|
{
|
||||||
|
"autocomplete": {},
|
||||||
"pagination": {
|
"pagination": {
|
||||||
"next": 0,
|
"next": 0,
|
||||||
"previous": 0,
|
"previous": 0,
|
||||||
|
@ -119,17 +119,17 @@ class TestTrimPasswordHistory(TestCase):
|
|||||||
[
|
[
|
||||||
UserPasswordHistory(
|
UserPasswordHistory(
|
||||||
user=self.user,
|
user=self.user,
|
||||||
old_password="hunter1", # nosec B106
|
old_password="hunter1", # nosec
|
||||||
created_at=_now - timedelta(days=3),
|
created_at=_now - timedelta(days=3),
|
||||||
),
|
),
|
||||||
UserPasswordHistory(
|
UserPasswordHistory(
|
||||||
user=self.user,
|
user=self.user,
|
||||||
old_password="hunter2", # nosec B106
|
old_password="hunter2", # nosec
|
||||||
created_at=_now - timedelta(days=2),
|
created_at=_now - timedelta(days=2),
|
||||||
),
|
),
|
||||||
UserPasswordHistory(
|
UserPasswordHistory(
|
||||||
user=self.user,
|
user=self.user,
|
||||||
old_password="hunter3", # nosec B106
|
old_password="hunter3", # nosec
|
||||||
created_at=_now,
|
created_at=_now,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
0
authentik/enterprise/search/__init__.py
Normal file
0
authentik/enterprise/search/__init__.py
Normal file
12
authentik/enterprise/search/apps.py
Normal file
12
authentik/enterprise/search/apps.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
"""Enterprise app config"""
|
||||||
|
|
||||||
|
from authentik.enterprise.apps import EnterpriseConfig
|
||||||
|
|
||||||
|
|
||||||
|
class AuthentikEnterpriseSearchConfig(EnterpriseConfig):
|
||||||
|
"""Enterprise app config"""
|
||||||
|
|
||||||
|
name = "authentik.enterprise.search"
|
||||||
|
label = "authentik_search"
|
||||||
|
verbose_name = "authentik Enterprise.Search"
|
||||||
|
default = True
|
128
authentik/enterprise/search/fields.py
Normal file
128
authentik/enterprise/search/fields.py
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
"""DjangoQL search"""
|
||||||
|
|
||||||
|
from collections import OrderedDict, defaultdict
|
||||||
|
from collections.abc import Generator
|
||||||
|
|
||||||
|
from django.db import connection
|
||||||
|
from django.db.models import Model, Q
|
||||||
|
from djangoql.compat import text_type
|
||||||
|
from djangoql.schema import StrField
|
||||||
|
|
||||||
|
|
||||||
|
class JSONSearchField(StrField):
|
||||||
|
"""JSON field for DjangoQL"""
|
||||||
|
|
||||||
|
model: Model
|
||||||
|
|
||||||
|
def __init__(self, model=None, name=None, nullable=None, suggest_nested=True):
|
||||||
|
# Set this in the constructor to not clobber the type variable
|
||||||
|
self.type = "relation"
|
||||||
|
self.suggest_nested = suggest_nested
|
||||||
|
super().__init__(model, name, nullable)
|
||||||
|
|
||||||
|
def get_lookup(self, path, operator, value):
|
||||||
|
search = "__".join(path)
|
||||||
|
op, invert = self.get_operator(operator)
|
||||||
|
q = Q(**{f"{search}{op}": self.get_lookup_value(value)})
|
||||||
|
return ~q if invert else q
|
||||||
|
|
||||||
|
def json_field_keys(self) -> Generator[tuple[str]]:
|
||||||
|
with connection.cursor() as cursor:
|
||||||
|
cursor.execute(
|
||||||
|
f"""
|
||||||
|
WITH RECURSIVE "{self.name}_keys" AS (
|
||||||
|
SELECT
|
||||||
|
ARRAY[jsonb_object_keys("{self.name}")] AS key_path_array,
|
||||||
|
"{self.name}" -> jsonb_object_keys("{self.name}") AS value
|
||||||
|
FROM {self.model._meta.db_table}
|
||||||
|
WHERE "{self.name}" IS NOT NULL
|
||||||
|
AND jsonb_typeof("{self.name}") = 'object'
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
ck.key_path_array || jsonb_object_keys(ck.value),
|
||||||
|
ck.value -> jsonb_object_keys(ck.value) AS value
|
||||||
|
FROM "{self.name}_keys" ck
|
||||||
|
WHERE jsonb_typeof(ck.value) = 'object'
|
||||||
|
),
|
||||||
|
|
||||||
|
unique_paths AS (
|
||||||
|
SELECT DISTINCT key_path_array
|
||||||
|
FROM "{self.name}_keys"
|
||||||
|
)
|
||||||
|
|
||||||
|
SELECT key_path_array FROM unique_paths;
|
||||||
|
""" # nosec
|
||||||
|
)
|
||||||
|
return (x[0] for x in cursor.fetchall())
|
||||||
|
|
||||||
|
def get_nested_options(self) -> OrderedDict:
|
||||||
|
"""Get keys of all nested objects to show autocomplete"""
|
||||||
|
if not self.suggest_nested:
|
||||||
|
return OrderedDict()
|
||||||
|
base_model_name = f"{self.model._meta.app_label}.{self.model._meta.model_name}_{self.name}"
|
||||||
|
|
||||||
|
def recursive_function(parts: list[str], parent_parts: list[str] | None = None):
|
||||||
|
if not parent_parts:
|
||||||
|
parent_parts = []
|
||||||
|
path = parts.pop(0)
|
||||||
|
parent_parts.append(path)
|
||||||
|
relation_key = "_".join(parent_parts)
|
||||||
|
if len(parts) > 1:
|
||||||
|
out_dict = {
|
||||||
|
relation_key: {
|
||||||
|
parts[0]: {
|
||||||
|
"type": "relation",
|
||||||
|
"relation": f"{relation_key}_{parts[0]}",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
child_paths = recursive_function(parts.copy(), parent_parts.copy())
|
||||||
|
child_paths.update(out_dict)
|
||||||
|
return child_paths
|
||||||
|
else:
|
||||||
|
return {relation_key: {parts[0]: {}}}
|
||||||
|
|
||||||
|
relation_structure = defaultdict(dict)
|
||||||
|
|
||||||
|
for relations in self.json_field_keys():
|
||||||
|
result = recursive_function([base_model_name] + relations)
|
||||||
|
for relation_key, value in result.items():
|
||||||
|
for sub_relation_key, sub_value in value.items():
|
||||||
|
if not relation_structure[relation_key].get(sub_relation_key, None):
|
||||||
|
relation_structure[relation_key][sub_relation_key] = sub_value
|
||||||
|
else:
|
||||||
|
relation_structure[relation_key][sub_relation_key].update(sub_value)
|
||||||
|
|
||||||
|
final_dict = defaultdict(dict)
|
||||||
|
|
||||||
|
for key, value in relation_structure.items():
|
||||||
|
for sub_key, sub_value in value.items():
|
||||||
|
if not sub_value:
|
||||||
|
final_dict[key][sub_key] = {
|
||||||
|
"type": "str",
|
||||||
|
"nullable": True,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
final_dict[key][sub_key] = sub_value
|
||||||
|
return OrderedDict(final_dict)
|
||||||
|
|
||||||
|
def relation(self) -> str:
|
||||||
|
return f"{self.model._meta.app_label}.{self.model._meta.model_name}_{self.name}"
|
||||||
|
|
||||||
|
|
||||||
|
class ChoiceSearchField(StrField):
|
||||||
|
def __init__(self, model=None, name=None, nullable=None):
|
||||||
|
super().__init__(model, name, nullable, suggest_options=True)
|
||||||
|
|
||||||
|
def get_options(self, search):
|
||||||
|
result = []
|
||||||
|
choices = self._field_choices()
|
||||||
|
if choices:
|
||||||
|
search = search.lower()
|
||||||
|
for c in choices:
|
||||||
|
choice = text_type(c[0])
|
||||||
|
if search in choice.lower():
|
||||||
|
result.append(choice)
|
||||||
|
return result
|
53
authentik/enterprise/search/pagination.py
Normal file
53
authentik/enterprise/search/pagination.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
from rest_framework.response import Response
|
||||||
|
|
||||||
|
from authentik.api.pagination import Pagination
|
||||||
|
from authentik.enterprise.search.ql import AUTOCOMPLETE_COMPONENT_NAME, QLSearch
|
||||||
|
|
||||||
|
|
||||||
|
class AutocompletePagination(Pagination):
|
||||||
|
|
||||||
|
def paginate_queryset(self, queryset, request, view=None):
|
||||||
|
self.view = view
|
||||||
|
return super().paginate_queryset(queryset, request, view)
|
||||||
|
|
||||||
|
def get_autocomplete(self):
|
||||||
|
schema = QLSearch().get_schema(self.request, self.view)
|
||||||
|
introspections = {}
|
||||||
|
if hasattr(self.view, "get_ql_fields"):
|
||||||
|
from authentik.enterprise.search.schema import AKQLSchemaSerializer
|
||||||
|
|
||||||
|
introspections = AKQLSchemaSerializer().serialize(
|
||||||
|
schema(self.page.paginator.object_list.model)
|
||||||
|
)
|
||||||
|
return introspections
|
||||||
|
|
||||||
|
def get_paginated_response(self, data):
|
||||||
|
previous_page_number = 0
|
||||||
|
if self.page.has_previous():
|
||||||
|
previous_page_number = self.page.previous_page_number()
|
||||||
|
next_page_number = 0
|
||||||
|
if self.page.has_next():
|
||||||
|
next_page_number = self.page.next_page_number()
|
||||||
|
return Response(
|
||||||
|
{
|
||||||
|
"pagination": {
|
||||||
|
"next": next_page_number,
|
||||||
|
"previous": previous_page_number,
|
||||||
|
"count": self.page.paginator.count,
|
||||||
|
"current": self.page.number,
|
||||||
|
"total_pages": self.page.paginator.num_pages,
|
||||||
|
"start_index": self.page.start_index(),
|
||||||
|
"end_index": self.page.end_index(),
|
||||||
|
},
|
||||||
|
"results": data,
|
||||||
|
"autocomplete": self.get_autocomplete(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_paginated_response_schema(self, schema):
|
||||||
|
final_schema = super().get_paginated_response_schema(schema)
|
||||||
|
final_schema["properties"]["autocomplete"] = {
|
||||||
|
"$ref": f"#/components/schemas/{AUTOCOMPLETE_COMPONENT_NAME}"
|
||||||
|
}
|
||||||
|
final_schema["required"].append("autocomplete")
|
||||||
|
return final_schema
|
78
authentik/enterprise/search/ql.py
Normal file
78
authentik/enterprise/search/ql.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
"""DjangoQL search"""
|
||||||
|
|
||||||
|
from django.apps import apps
|
||||||
|
from django.db.models import QuerySet
|
||||||
|
from djangoql.ast import Name
|
||||||
|
from djangoql.exceptions import DjangoQLError
|
||||||
|
from djangoql.queryset import apply_search
|
||||||
|
from djangoql.schema import DjangoQLSchema
|
||||||
|
from rest_framework.filters import SearchFilter
|
||||||
|
from rest_framework.request import Request
|
||||||
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
|
from authentik.enterprise.search.fields import JSONSearchField
|
||||||
|
|
||||||
|
LOGGER = get_logger()
|
||||||
|
AUTOCOMPLETE_COMPONENT_NAME = "Autocomplete"
|
||||||
|
AUTOCOMPLETE_SCHEMA = {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class BaseSchema(DjangoQLSchema):
|
||||||
|
"""Base Schema which deals with JSON Fields"""
|
||||||
|
|
||||||
|
def resolve_name(self, name: Name):
|
||||||
|
model = self.model_label(self.current_model)
|
||||||
|
root_field = name.parts[0]
|
||||||
|
field = self.models[model].get(root_field)
|
||||||
|
# If the query goes into a JSON field, return the root
|
||||||
|
# field as the JSON field will do the rest
|
||||||
|
if isinstance(field, JSONSearchField):
|
||||||
|
# This is a workaround; build_filter will remove the right-most
|
||||||
|
# entry in the path as that is intended to be the same as the field
|
||||||
|
# however for JSON that is not the case
|
||||||
|
if name.parts[-1] != root_field:
|
||||||
|
name.parts.append(root_field)
|
||||||
|
return field
|
||||||
|
return super().resolve_name(name)
|
||||||
|
|
||||||
|
|
||||||
|
class QLSearch(SearchFilter):
|
||||||
|
"""rest_framework search filter which uses DjangoQL"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enabled(self):
|
||||||
|
return apps.get_app_config("authentik_enterprise").enabled()
|
||||||
|
|
||||||
|
def get_search_terms(self, request) -> str:
|
||||||
|
"""
|
||||||
|
Search terms are set by a ?search=... query parameter,
|
||||||
|
and may be comma and/or whitespace delimited.
|
||||||
|
"""
|
||||||
|
params = request.query_params.get(self.search_param, "")
|
||||||
|
params = params.replace("\x00", "") # strip null characters
|
||||||
|
return params
|
||||||
|
|
||||||
|
def get_schema(self, request: Request, view) -> BaseSchema:
|
||||||
|
ql_fields = []
|
||||||
|
if hasattr(view, "get_ql_fields"):
|
||||||
|
ql_fields = view.get_ql_fields()
|
||||||
|
|
||||||
|
class InlineSchema(BaseSchema):
|
||||||
|
def get_fields(self, model):
|
||||||
|
return ql_fields or []
|
||||||
|
|
||||||
|
return InlineSchema
|
||||||
|
|
||||||
|
def filter_queryset(self, request: Request, queryset: QuerySet, view) -> QuerySet:
|
||||||
|
search_query = self.get_search_terms(request)
|
||||||
|
schema = self.get_schema(request, view)
|
||||||
|
if len(search_query) == 0 or not self.enabled:
|
||||||
|
return super().filter_queryset(request, queryset, view)
|
||||||
|
try:
|
||||||
|
return apply_search(queryset, search_query, schema=schema)
|
||||||
|
except DjangoQLError as exc:
|
||||||
|
LOGGER.debug("Failed to parse search expression", exc=exc)
|
||||||
|
return super().filter_queryset(request, queryset, view)
|
29
authentik/enterprise/search/schema.py
Normal file
29
authentik/enterprise/search/schema.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
from djangoql.serializers import DjangoQLSchemaSerializer
|
||||||
|
from drf_spectacular.generators import SchemaGenerator
|
||||||
|
|
||||||
|
from authentik.api.schema import create_component
|
||||||
|
from authentik.enterprise.search.fields import JSONSearchField
|
||||||
|
from authentik.enterprise.search.ql import AUTOCOMPLETE_COMPONENT_NAME, AUTOCOMPLETE_SCHEMA
|
||||||
|
|
||||||
|
|
||||||
|
class AKQLSchemaSerializer(DjangoQLSchemaSerializer):
|
||||||
|
def serialize(self, schema):
|
||||||
|
serialization = super().serialize(schema)
|
||||||
|
for _, fields in schema.models.items():
|
||||||
|
for _, field in fields.items():
|
||||||
|
if not isinstance(field, JSONSearchField):
|
||||||
|
continue
|
||||||
|
serialization["models"].update(field.get_nested_options())
|
||||||
|
return serialization
|
||||||
|
|
||||||
|
def serialize_field(self, field):
|
||||||
|
result = super().serialize_field(field)
|
||||||
|
if isinstance(field, JSONSearchField):
|
||||||
|
result["relation"] = field.relation()
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def postprocess_schema_search_autocomplete(result, generator: SchemaGenerator, **kwargs):
|
||||||
|
create_component(generator, AUTOCOMPLETE_COMPONENT_NAME, AUTOCOMPLETE_SCHEMA)
|
||||||
|
|
||||||
|
return result
|
17
authentik/enterprise/search/settings.py
Normal file
17
authentik/enterprise/search/settings.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
SPECTACULAR_SETTINGS = {
|
||||||
|
"POSTPROCESSING_HOOKS": [
|
||||||
|
"authentik.api.schema.postprocess_schema_responses",
|
||||||
|
"authentik.enterprise.search.schema.postprocess_schema_search_autocomplete",
|
||||||
|
"drf_spectacular.hooks.postprocess_schema_enums",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
REST_FRAMEWORK = {
|
||||||
|
"DEFAULT_PAGINATION_CLASS": "authentik.enterprise.search.pagination.AutocompletePagination",
|
||||||
|
"DEFAULT_FILTER_BACKENDS": [
|
||||||
|
"authentik.enterprise.search.ql.QLSearch",
|
||||||
|
"authentik.rbac.filters.ObjectFilter",
|
||||||
|
"django_filters.rest_framework.DjangoFilterBackend",
|
||||||
|
"rest_framework.filters.OrderingFilter",
|
||||||
|
],
|
||||||
|
}
|
78
authentik/enterprise/search/tests.py
Normal file
78
authentik/enterprise/search/tests.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
from json import loads
|
||||||
|
from unittest.mock import PropertyMock, patch
|
||||||
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
|
from django.urls import reverse
|
||||||
|
from rest_framework.test import APITestCase
|
||||||
|
|
||||||
|
from authentik.core.tests.utils import create_test_admin_user
|
||||||
|
|
||||||
|
|
||||||
|
@patch(
|
||||||
|
"authentik.enterprise.audit.middleware.EnterpriseAuditMiddleware.enabled",
|
||||||
|
PropertyMock(return_value=True),
|
||||||
|
)
|
||||||
|
class QLTest(APITestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.user = create_test_admin_user()
|
||||||
|
# ensure we have more than 1 user
|
||||||
|
create_test_admin_user()
|
||||||
|
|
||||||
|
def test_search(self):
|
||||||
|
"""Test simple search query"""
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
query = f'username = "{self.user.username}"'
|
||||||
|
res = self.client.get(
|
||||||
|
reverse(
|
||||||
|
"authentik_api:user-list",
|
||||||
|
)
|
||||||
|
+ f"?{urlencode({"search": query})}"
|
||||||
|
)
|
||||||
|
self.assertEqual(res.status_code, 200)
|
||||||
|
content = loads(res.content)
|
||||||
|
self.assertEqual(content["pagination"]["count"], 1)
|
||||||
|
self.assertEqual(content["results"][0]["username"], self.user.username)
|
||||||
|
|
||||||
|
def test_no_search(self):
|
||||||
|
"""Ensure works with no search query"""
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
res = self.client.get(
|
||||||
|
reverse(
|
||||||
|
"authentik_api:user-list",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertEqual(res.status_code, 200)
|
||||||
|
content = loads(res.content)
|
||||||
|
self.assertNotEqual(content["pagination"]["count"], 1)
|
||||||
|
|
||||||
|
def test_search_no_ql(self):
|
||||||
|
"""Test simple search query (no QL)"""
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
res = self.client.get(
|
||||||
|
reverse(
|
||||||
|
"authentik_api:user-list",
|
||||||
|
)
|
||||||
|
+ f"?{urlencode({"search": self.user.username})}"
|
||||||
|
)
|
||||||
|
self.assertEqual(res.status_code, 200)
|
||||||
|
content = loads(res.content)
|
||||||
|
self.assertGreaterEqual(content["pagination"]["count"], 1)
|
||||||
|
self.assertEqual(content["results"][0]["username"], self.user.username)
|
||||||
|
|
||||||
|
def test_search_json(self):
|
||||||
|
"""Test search query with a JSON attribute"""
|
||||||
|
self.user.attributes = {"foo": {"bar": "baz"}}
|
||||||
|
self.user.save()
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
query = 'attributes.foo.bar = "baz"'
|
||||||
|
res = self.client.get(
|
||||||
|
reverse(
|
||||||
|
"authentik_api:user-list",
|
||||||
|
)
|
||||||
|
+ f"?{urlencode({"search": query})}"
|
||||||
|
)
|
||||||
|
self.assertEqual(res.status_code, 200)
|
||||||
|
content = loads(res.content)
|
||||||
|
self.assertEqual(content["pagination"]["count"], 1)
|
||||||
|
self.assertEqual(content["results"][0]["username"], self.user.username)
|
@ -18,6 +18,7 @@ TENANT_APPS = [
|
|||||||
"authentik.enterprise.providers.google_workspace",
|
"authentik.enterprise.providers.google_workspace",
|
||||||
"authentik.enterprise.providers.microsoft_entra",
|
"authentik.enterprise.providers.microsoft_entra",
|
||||||
"authentik.enterprise.providers.ssf",
|
"authentik.enterprise.providers.ssf",
|
||||||
|
"authentik.enterprise.search",
|
||||||
"authentik.enterprise.stages.authenticator_endpoint_gdtc",
|
"authentik.enterprise.stages.authenticator_endpoint_gdtc",
|
||||||
"authentik.enterprise.stages.mtls",
|
"authentik.enterprise.stages.mtls",
|
||||||
"authentik.enterprise.stages.source",
|
"authentik.enterprise.stages.source",
|
||||||
|
@ -132,6 +132,22 @@ class EventViewSet(ModelViewSet):
|
|||||||
]
|
]
|
||||||
filterset_class = EventsFilter
|
filterset_class = EventsFilter
|
||||||
|
|
||||||
|
def get_ql_fields(self):
|
||||||
|
from djangoql.schema import DateTimeField, StrField
|
||||||
|
|
||||||
|
from authentik.enterprise.search.fields import ChoiceSearchField, JSONSearchField
|
||||||
|
|
||||||
|
return [
|
||||||
|
ChoiceSearchField(Event, "action"),
|
||||||
|
StrField(Event, "event_uuid"),
|
||||||
|
StrField(Event, "app", suggest_options=True),
|
||||||
|
StrField(Event, "client_ip"),
|
||||||
|
JSONSearchField(Event, "user", suggest_nested=False),
|
||||||
|
JSONSearchField(Event, "brand", suggest_nested=False),
|
||||||
|
JSONSearchField(Event, "context", suggest_nested=False),
|
||||||
|
DateTimeField(Event, "created", suggest_options=True),
|
||||||
|
]
|
||||||
|
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
methods=["GET"],
|
methods=["GET"],
|
||||||
responses={200: EventTopPerUserSerializer(many=True)},
|
responses={200: EventTopPerUserSerializer(many=True)},
|
||||||
|
@ -11,7 +11,7 @@ from authentik.events.models import NotificationRule
|
|||||||
class NotificationRuleSerializer(ModelSerializer):
|
class NotificationRuleSerializer(ModelSerializer):
|
||||||
"""NotificationRule Serializer"""
|
"""NotificationRule Serializer"""
|
||||||
|
|
||||||
group_obj = GroupSerializer(read_only=True, source="group")
|
destination_group_obj = GroupSerializer(read_only=True, source="destination_group")
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = NotificationRule
|
model = NotificationRule
|
||||||
@ -20,8 +20,9 @@ class NotificationRuleSerializer(ModelSerializer):
|
|||||||
"name",
|
"name",
|
||||||
"transports",
|
"transports",
|
||||||
"severity",
|
"severity",
|
||||||
"group",
|
"destination_group",
|
||||||
"group_obj",
|
"destination_group_obj",
|
||||||
|
"destination_event_user",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -30,6 +31,6 @@ class NotificationRuleViewSet(UsedByMixin, ModelViewSet):
|
|||||||
|
|
||||||
queryset = NotificationRule.objects.all()
|
queryset = NotificationRule.objects.all()
|
||||||
serializer_class = NotificationRuleSerializer
|
serializer_class = NotificationRuleSerializer
|
||||||
filterset_fields = ["name", "severity", "group__name"]
|
filterset_fields = ["name", "severity", "destination_group__name"]
|
||||||
ordering = ["name"]
|
ordering = ["name"]
|
||||||
search_fields = ["name", "group__name"]
|
search_fields = ["name", "destination_group__name"]
|
||||||
|
@ -15,13 +15,13 @@ class MMDBContextProcessor(EventContextProcessor):
|
|||||||
self.reader: Reader | None = None
|
self.reader: Reader | None = None
|
||||||
self._last_mtime: float = 0.0
|
self._last_mtime: float = 0.0
|
||||||
self.logger = get_logger()
|
self.logger = get_logger()
|
||||||
self.open()
|
self.load()
|
||||||
|
|
||||||
def path(self) -> str | None:
|
def path(self) -> str | None:
|
||||||
"""Get the path to the MMDB file to load"""
|
"""Get the path to the MMDB file to load"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def open(self):
|
def load(self):
|
||||||
"""Get GeoIP Reader, if configured, otherwise none"""
|
"""Get GeoIP Reader, if configured, otherwise none"""
|
||||||
path = self.path()
|
path = self.path()
|
||||||
if path == "" or not path:
|
if path == "" or not path:
|
||||||
@ -44,7 +44,7 @@ class MMDBContextProcessor(EventContextProcessor):
|
|||||||
diff = self._last_mtime < mtime
|
diff = self._last_mtime < mtime
|
||||||
if diff > 0:
|
if diff > 0:
|
||||||
self.logger.info("Found new MMDB Database, reopening", diff=diff, path=path)
|
self.logger.info("Found new MMDB Database, reopening", diff=diff, path=path)
|
||||||
self.open()
|
self.load()
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
self.logger.warning("Failed to check MMDB age", exc=exc)
|
self.logger.warning("Failed to check MMDB age", exc=exc)
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ from authentik.core.models import Group, User
|
|||||||
from authentik.events.models import Event, EventAction, Notification
|
from authentik.events.models import Event, EventAction, Notification
|
||||||
from authentik.events.utils import model_to_dict
|
from authentik.events.utils import model_to_dict
|
||||||
from authentik.lib.sentry import before_send
|
from authentik.lib.sentry import before_send
|
||||||
from authentik.lib.utils.errors import exception_to_string
|
from authentik.lib.utils.errors import exception_to_dict
|
||||||
from authentik.stages.authenticator_static.models import StaticToken
|
from authentik.stages.authenticator_static.models import StaticToken
|
||||||
|
|
||||||
IGNORED_MODELS = tuple(
|
IGNORED_MODELS = tuple(
|
||||||
@ -170,14 +170,16 @@ class AuditMiddleware:
|
|||||||
thread = EventNewThread(
|
thread = EventNewThread(
|
||||||
EventAction.SUSPICIOUS_REQUEST,
|
EventAction.SUSPICIOUS_REQUEST,
|
||||||
request,
|
request,
|
||||||
message=exception_to_string(exception),
|
message=str(exception),
|
||||||
|
exception=exception_to_dict(exception),
|
||||||
)
|
)
|
||||||
thread.run()
|
thread.run()
|
||||||
elif before_send({}, {"exc_info": (None, exception, None)}) is not None:
|
elif before_send({}, {"exc_info": (None, exception, None)}) is not None:
|
||||||
thread = EventNewThread(
|
thread = EventNewThread(
|
||||||
EventAction.SYSTEM_EXCEPTION,
|
EventAction.SYSTEM_EXCEPTION,
|
||||||
request,
|
request,
|
||||||
message=exception_to_string(exception),
|
message=str(exception),
|
||||||
|
exception=exception_to_dict(exception),
|
||||||
)
|
)
|
||||||
thread.run()
|
thread.run()
|
||||||
|
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
# Generated by Django 5.1.11 on 2025-06-16 23:21
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("authentik_events", "0009_remove_notificationtransport_webhook_mapping_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name="notificationrule",
|
||||||
|
old_name="group",
|
||||||
|
new_name="destination_group",
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="notificationrule",
|
||||||
|
name="destination_event_user",
|
||||||
|
field=models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
help_text="When enabled, notification will be sent to user the user that triggered the event.When destination_group is configured, notification is sent to both.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
@ -1,10 +1,12 @@
|
|||||||
"""authentik events models"""
|
"""authentik events models"""
|
||||||
|
|
||||||
|
from collections.abc import Generator
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from difflib import get_close_matches
|
from difflib import get_close_matches
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from inspect import currentframe
|
from inspect import currentframe
|
||||||
from smtplib import SMTPException
|
from smtplib import SMTPException
|
||||||
|
from typing import Any
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
@ -36,6 +38,7 @@ from authentik.events.utils import (
|
|||||||
)
|
)
|
||||||
from authentik.lib.models import DomainlessURLValidator, SerializerModel
|
from authentik.lib.models import DomainlessURLValidator, SerializerModel
|
||||||
from authentik.lib.sentry import SentryIgnoredException
|
from authentik.lib.sentry import SentryIgnoredException
|
||||||
|
from authentik.lib.utils.errors import exception_to_dict
|
||||||
from authentik.lib.utils.http import get_http_session
|
from authentik.lib.utils.http import get_http_session
|
||||||
from authentik.lib.utils.time import timedelta_from_string
|
from authentik.lib.utils.time import timedelta_from_string
|
||||||
from authentik.policies.models import PolicyBindingModel
|
from authentik.policies.models import PolicyBindingModel
|
||||||
@ -161,6 +164,12 @@ class Event(SerializerModel, ExpiringModel):
|
|||||||
event = Event(action=action, app=app, context=cleaned_kwargs)
|
event = Event(action=action, app=app, context=cleaned_kwargs)
|
||||||
return event
|
return event
|
||||||
|
|
||||||
|
def with_exception(self, exc: Exception) -> "Event":
|
||||||
|
"""Add data from 'exc' to the event in a database-saveable format"""
|
||||||
|
self.context.setdefault("message", str(exc))
|
||||||
|
self.context["exception"] = exception_to_dict(exc)
|
||||||
|
return self
|
||||||
|
|
||||||
def set_user(self, user: User) -> "Event":
|
def set_user(self, user: User) -> "Event":
|
||||||
"""Set `.user` based on user, ensuring the correct attributes are copied.
|
"""Set `.user` based on user, ensuring the correct attributes are copied.
|
||||||
This should only be used when self.from_http is *not* used."""
|
This should only be used when self.from_http is *not* used."""
|
||||||
@ -547,7 +556,7 @@ class NotificationRule(SerializerModel, PolicyBindingModel):
|
|||||||
default=NotificationSeverity.NOTICE,
|
default=NotificationSeverity.NOTICE,
|
||||||
help_text=_("Controls which severity level the created notifications will have."),
|
help_text=_("Controls which severity level the created notifications will have."),
|
||||||
)
|
)
|
||||||
group = models.ForeignKey(
|
destination_group = models.ForeignKey(
|
||||||
Group,
|
Group,
|
||||||
help_text=_(
|
help_text=_(
|
||||||
"Define which group of users this notification should be sent and shown to. "
|
"Define which group of users this notification should be sent and shown to. "
|
||||||
@ -557,6 +566,19 @@ class NotificationRule(SerializerModel, PolicyBindingModel):
|
|||||||
blank=True,
|
blank=True,
|
||||||
on_delete=models.SET_NULL,
|
on_delete=models.SET_NULL,
|
||||||
)
|
)
|
||||||
|
destination_event_user = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
help_text=_(
|
||||||
|
"When enabled, notification will be sent to user the user that triggered the event."
|
||||||
|
"When destination_group is configured, notification is sent to both."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
def destination_users(self, event: Event) -> Generator[User, Any]:
|
||||||
|
if self.destination_event_user and event.user.get("pk"):
|
||||||
|
yield User(pk=event.user.get("pk"))
|
||||||
|
if self.destination_group:
|
||||||
|
yield from self.destination_group.users.all()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def serializer(self) -> type[Serializer]:
|
def serializer(self) -> type[Serializer]:
|
||||||
|
@ -127,8 +127,8 @@ class SystemTask(TenantTask):
|
|||||||
)
|
)
|
||||||
Event.new(
|
Event.new(
|
||||||
EventAction.SYSTEM_TASK_EXCEPTION,
|
EventAction.SYSTEM_TASK_EXCEPTION,
|
||||||
message=f"Task {self.__name__} encountered an error: {exception_to_string(exc)}",
|
message=f"Task {self.__name__} encountered an error",
|
||||||
).save()
|
).with_exception(exc).save()
|
||||||
|
|
||||||
def run(self, *args, **kwargs):
|
def run(self, *args, **kwargs):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
@ -68,14 +68,10 @@ def event_trigger_handler(event_uuid: str, trigger_name: str):
|
|||||||
if not result.passing:
|
if not result.passing:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not trigger.group:
|
|
||||||
LOGGER.debug("e(trigger): trigger has no group", trigger=trigger)
|
|
||||||
return
|
|
||||||
|
|
||||||
LOGGER.debug("e(trigger): event trigger matched", trigger=trigger)
|
LOGGER.debug("e(trigger): event trigger matched", trigger=trigger)
|
||||||
# Create the notification objects
|
# Create the notification objects
|
||||||
for transport in trigger.transports.all():
|
for transport in trigger.transports.all():
|
||||||
for user in trigger.group.users.all():
|
for user in trigger.destination_users(event):
|
||||||
LOGGER.debug("created notification")
|
LOGGER.debug("created notification")
|
||||||
notification_transport.apply_async(
|
notification_transport.apply_async(
|
||||||
args=[
|
args=[
|
||||||
|
@ -6,6 +6,7 @@ from django.urls import reverse
|
|||||||
from rest_framework.test import APITestCase
|
from rest_framework.test import APITestCase
|
||||||
|
|
||||||
from authentik.core.models import Group, User
|
from authentik.core.models import Group, User
|
||||||
|
from authentik.core.tests.utils import create_test_user
|
||||||
from authentik.events.models import (
|
from authentik.events.models import (
|
||||||
Event,
|
Event,
|
||||||
EventAction,
|
EventAction,
|
||||||
@ -34,7 +35,7 @@ class TestEventsNotifications(APITestCase):
|
|||||||
def test_trigger_empty(self):
|
def test_trigger_empty(self):
|
||||||
"""Test trigger without any policies attached"""
|
"""Test trigger without any policies attached"""
|
||||||
transport = NotificationTransport.objects.create(name=generate_id())
|
transport = NotificationTransport.objects.create(name=generate_id())
|
||||||
trigger = NotificationRule.objects.create(name=generate_id(), group=self.group)
|
trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
|
||||||
trigger.transports.add(transport)
|
trigger.transports.add(transport)
|
||||||
trigger.save()
|
trigger.save()
|
||||||
|
|
||||||
@ -46,7 +47,7 @@ class TestEventsNotifications(APITestCase):
|
|||||||
def test_trigger_single(self):
|
def test_trigger_single(self):
|
||||||
"""Test simple transport triggering"""
|
"""Test simple transport triggering"""
|
||||||
transport = NotificationTransport.objects.create(name=generate_id())
|
transport = NotificationTransport.objects.create(name=generate_id())
|
||||||
trigger = NotificationRule.objects.create(name=generate_id(), group=self.group)
|
trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
|
||||||
trigger.transports.add(transport)
|
trigger.transports.add(transport)
|
||||||
trigger.save()
|
trigger.save()
|
||||||
matcher = EventMatcherPolicy.objects.create(
|
matcher = EventMatcherPolicy.objects.create(
|
||||||
@ -59,6 +60,25 @@ class TestEventsNotifications(APITestCase):
|
|||||||
Event.new(EventAction.CUSTOM_PREFIX).save()
|
Event.new(EventAction.CUSTOM_PREFIX).save()
|
||||||
self.assertEqual(execute_mock.call_count, 1)
|
self.assertEqual(execute_mock.call_count, 1)
|
||||||
|
|
||||||
|
def test_trigger_event_user(self):
|
||||||
|
"""Test trigger with event user"""
|
||||||
|
user = create_test_user()
|
||||||
|
transport = NotificationTransport.objects.create(name=generate_id())
|
||||||
|
trigger = NotificationRule.objects.create(name=generate_id(), destination_event_user=True)
|
||||||
|
trigger.transports.add(transport)
|
||||||
|
trigger.save()
|
||||||
|
matcher = EventMatcherPolicy.objects.create(
|
||||||
|
name="matcher", action=EventAction.CUSTOM_PREFIX
|
||||||
|
)
|
||||||
|
PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
|
||||||
|
|
||||||
|
execute_mock = MagicMock()
|
||||||
|
with patch("authentik.events.models.NotificationTransport.send", execute_mock):
|
||||||
|
Event.new(EventAction.CUSTOM_PREFIX).set_user(user).save()
|
||||||
|
self.assertEqual(execute_mock.call_count, 1)
|
||||||
|
notification: Notification = execute_mock.call_args[0][0]
|
||||||
|
self.assertEqual(notification.user, user)
|
||||||
|
|
||||||
def test_trigger_no_group(self):
|
def test_trigger_no_group(self):
|
||||||
"""Test trigger without group"""
|
"""Test trigger without group"""
|
||||||
trigger = NotificationRule.objects.create(name=generate_id())
|
trigger = NotificationRule.objects.create(name=generate_id())
|
||||||
@ -76,7 +96,7 @@ class TestEventsNotifications(APITestCase):
|
|||||||
"""Test Policy error which would cause recursion"""
|
"""Test Policy error which would cause recursion"""
|
||||||
transport = NotificationTransport.objects.create(name=generate_id())
|
transport = NotificationTransport.objects.create(name=generate_id())
|
||||||
NotificationRule.objects.filter(name__startswith="default").delete()
|
NotificationRule.objects.filter(name__startswith="default").delete()
|
||||||
trigger = NotificationRule.objects.create(name=generate_id(), group=self.group)
|
trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
|
||||||
trigger.transports.add(transport)
|
trigger.transports.add(transport)
|
||||||
trigger.save()
|
trigger.save()
|
||||||
matcher = EventMatcherPolicy.objects.create(
|
matcher = EventMatcherPolicy.objects.create(
|
||||||
@ -99,7 +119,7 @@ class TestEventsNotifications(APITestCase):
|
|||||||
|
|
||||||
transport = NotificationTransport.objects.create(name=generate_id(), send_once=True)
|
transport = NotificationTransport.objects.create(name=generate_id(), send_once=True)
|
||||||
NotificationRule.objects.filter(name__startswith="default").delete()
|
NotificationRule.objects.filter(name__startswith="default").delete()
|
||||||
trigger = NotificationRule.objects.create(name=generate_id(), group=self.group)
|
trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
|
||||||
trigger.transports.add(transport)
|
trigger.transports.add(transport)
|
||||||
trigger.save()
|
trigger.save()
|
||||||
matcher = EventMatcherPolicy.objects.create(
|
matcher = EventMatcherPolicy.objects.create(
|
||||||
@ -123,7 +143,7 @@ class TestEventsNotifications(APITestCase):
|
|||||||
name=generate_id(), webhook_mapping_body=mapping, mode=TransportMode.LOCAL
|
name=generate_id(), webhook_mapping_body=mapping, mode=TransportMode.LOCAL
|
||||||
)
|
)
|
||||||
NotificationRule.objects.filter(name__startswith="default").delete()
|
NotificationRule.objects.filter(name__startswith="default").delete()
|
||||||
trigger = NotificationRule.objects.create(name=generate_id(), group=self.group)
|
trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
|
||||||
trigger.transports.add(transport)
|
trigger.transports.add(transport)
|
||||||
matcher = EventMatcherPolicy.objects.create(
|
matcher = EventMatcherPolicy.objects.create(
|
||||||
name="matcher", action=EventAction.CUSTOM_PREFIX
|
name="matcher", action=EventAction.CUSTOM_PREFIX
|
||||||
|
@ -56,7 +56,6 @@ from authentik.flows.planner import (
|
|||||||
)
|
)
|
||||||
from authentik.flows.stage import AccessDeniedStage, StageView
|
from authentik.flows.stage import AccessDeniedStage, StageView
|
||||||
from authentik.lib.sentry import SentryIgnoredException
|
from authentik.lib.sentry import SentryIgnoredException
|
||||||
from authentik.lib.utils.errors import exception_to_string
|
|
||||||
from authentik.lib.utils.reflection import all_subclasses, class_to_path
|
from authentik.lib.utils.reflection import all_subclasses, class_to_path
|
||||||
from authentik.lib.utils.urls import is_url_absolute, redirect_with_qs
|
from authentik.lib.utils.urls import is_url_absolute, redirect_with_qs
|
||||||
from authentik.policies.engine import PolicyEngine
|
from authentik.policies.engine import PolicyEngine
|
||||||
@ -238,8 +237,8 @@ class FlowExecutorView(APIView):
|
|||||||
self._logger.warning(exc)
|
self._logger.warning(exc)
|
||||||
Event.new(
|
Event.new(
|
||||||
action=EventAction.SYSTEM_EXCEPTION,
|
action=EventAction.SYSTEM_EXCEPTION,
|
||||||
message=exception_to_string(exc),
|
message="System exception during flow execution.",
|
||||||
).from_http(self.request)
|
).with_exception(exc).from_http(self.request)
|
||||||
challenge = FlowErrorChallenge(self.request, exc)
|
challenge = FlowErrorChallenge(self.request, exc)
|
||||||
challenge.is_valid(raise_exception=True)
|
challenge.is_valid(raise_exception=True)
|
||||||
return to_stage_response(self.request, HttpChallengeResponse(challenge))
|
return to_stage_response(self.request, HttpChallengeResponse(challenge))
|
||||||
|
@ -14,7 +14,6 @@ from authentik.events.models import Event, EventAction
|
|||||||
from authentik.lib.expression.exceptions import ControlFlowException
|
from authentik.lib.expression.exceptions import ControlFlowException
|
||||||
from authentik.lib.sync.mapper import PropertyMappingManager
|
from authentik.lib.sync.mapper import PropertyMappingManager
|
||||||
from authentik.lib.sync.outgoing.exceptions import NotFoundSyncException, StopSync
|
from authentik.lib.sync.outgoing.exceptions import NotFoundSyncException, StopSync
|
||||||
from authentik.lib.utils.errors import exception_to_string
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from django.db.models import Model
|
from django.db.models import Model
|
||||||
@ -106,9 +105,9 @@ class BaseOutgoingSyncClient[
|
|||||||
# Value error can be raised when assigning invalid data to an attribute
|
# Value error can be raised when assigning invalid data to an attribute
|
||||||
Event.new(
|
Event.new(
|
||||||
EventAction.CONFIGURATION_ERROR,
|
EventAction.CONFIGURATION_ERROR,
|
||||||
message=f"Failed to evaluate property-mapping {exception_to_string(exc)}",
|
message="Failed to evaluate property-mapping",
|
||||||
mapping=exc.mapping,
|
mapping=exc.mapping,
|
||||||
).save()
|
).with_exception(exc).save()
|
||||||
raise StopSync(exc, obj, exc.mapping) from exc
|
raise StopSync(exc, obj, exc.mapping) from exc
|
||||||
if not raw_final_object:
|
if not raw_final_object:
|
||||||
raise StopSync(ValueError("No mappings configured"), obj)
|
raise StopSync(ValueError("No mappings configured"), obj)
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
from traceback import extract_tb
|
from traceback import extract_tb
|
||||||
|
|
||||||
|
from structlog.tracebacks import ExceptionDictTransformer
|
||||||
|
|
||||||
from authentik.lib.utils.reflection import class_to_path
|
from authentik.lib.utils.reflection import class_to_path
|
||||||
|
|
||||||
TRACEBACK_HEADER = "Traceback (most recent call last):"
|
TRACEBACK_HEADER = "Traceback (most recent call last):"
|
||||||
@ -17,3 +19,8 @@ def exception_to_string(exc: Exception) -> str:
|
|||||||
f"{class_to_path(exc.__class__)}: {str(exc)}",
|
f"{class_to_path(exc.__class__)}: {str(exc)}",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def exception_to_dict(exc: Exception) -> dict:
|
||||||
|
"""Format exception as a dictionary"""
|
||||||
|
return ExceptionDictTransformer()((type(exc), exc, exc.__traceback__))
|
||||||
|
@ -35,7 +35,6 @@ from authentik.events.models import Event, EventAction
|
|||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
from authentik.lib.models import InheritanceForeignKey, SerializerModel
|
from authentik.lib.models import InheritanceForeignKey, SerializerModel
|
||||||
from authentik.lib.sentry import SentryIgnoredException
|
from authentik.lib.sentry import SentryIgnoredException
|
||||||
from authentik.lib.utils.errors import exception_to_string
|
|
||||||
from authentik.outposts.controllers.k8s.utils import get_namespace
|
from authentik.outposts.controllers.k8s.utils import get_namespace
|
||||||
|
|
||||||
OUR_VERSION = parse(__version__)
|
OUR_VERSION = parse(__version__)
|
||||||
@ -326,9 +325,8 @@ class Outpost(SerializerModel, ManagedModel):
|
|||||||
"While setting the permissions for the service-account, a "
|
"While setting the permissions for the service-account, a "
|
||||||
"permission was not found: Check "
|
"permission was not found: Check "
|
||||||
"https://goauthentik.io/docs/troubleshooting/missing_permission"
|
"https://goauthentik.io/docs/troubleshooting/missing_permission"
|
||||||
)
|
),
|
||||||
+ exception_to_string(exc),
|
).with_exception(exc).set_user(user).save()
|
||||||
).set_user(user).save()
|
|
||||||
else:
|
else:
|
||||||
app_label, perm = model_or_perm.split(".")
|
app_label, perm = model_or_perm.split(".")
|
||||||
permission = Permission.objects.filter(
|
permission = Permission.objects.filter(
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
"""Websocket tests"""
|
"""Websocket tests"""
|
||||||
|
|
||||||
from dataclasses import asdict
|
from dataclasses import asdict
|
||||||
from unittest.mock import patch
|
|
||||||
|
|
||||||
from channels.routing import URLRouter
|
from channels.routing import URLRouter
|
||||||
from channels.testing import WebsocketCommunicator
|
from channels.testing import WebsocketCommunicator
|
||||||
from django.contrib.contenttypes.models import ContentType
|
|
||||||
from django.test import TransactionTestCase
|
from django.test import TransactionTestCase
|
||||||
|
|
||||||
from authentik import __version__
|
from authentik import __version__
|
||||||
@ -16,12 +14,6 @@ from authentik.providers.proxy.models import ProxyProvider
|
|||||||
from authentik.root import websocket
|
from authentik.root import websocket
|
||||||
|
|
||||||
|
|
||||||
def patched__get_ct_cached(app_label, codename):
|
|
||||||
"""Caches `ContentType` instances like its `QuerySet` does."""
|
|
||||||
return ContentType.objects.get(app_label=app_label, permission__codename=codename)
|
|
||||||
|
|
||||||
|
|
||||||
@patch("guardian.shortcuts._get_ct_cached", patched__get_ct_cached)
|
|
||||||
class TestOutpostWS(TransactionTestCase):
|
class TestOutpostWS(TransactionTestCase):
|
||||||
"""Websocket tests"""
|
"""Websocket tests"""
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ from structlog.stdlib import get_logger
|
|||||||
|
|
||||||
from authentik.events.models import Event, EventAction
|
from authentik.events.models import Event, EventAction
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
from authentik.lib.utils.errors import exception_to_string
|
from authentik.lib.utils.errors import exception_to_dict
|
||||||
from authentik.lib.utils.reflection import class_to_path
|
from authentik.lib.utils.reflection import class_to_path
|
||||||
from authentik.policies.apps import HIST_POLICIES_EXECUTION_TIME
|
from authentik.policies.apps import HIST_POLICIES_EXECUTION_TIME
|
||||||
from authentik.policies.exceptions import PolicyException
|
from authentik.policies.exceptions import PolicyException
|
||||||
@ -95,10 +95,13 @@ class PolicyProcess(PROCESS_CLASS):
|
|||||||
except PolicyException as exc:
|
except PolicyException as exc:
|
||||||
# Either use passed original exception or whatever we have
|
# Either use passed original exception or whatever we have
|
||||||
src_exc = exc.src_exc if exc.src_exc else exc
|
src_exc = exc.src_exc if exc.src_exc else exc
|
||||||
error_string = exception_to_string(src_exc)
|
|
||||||
# Create policy exception event, only when we're not debugging
|
# Create policy exception event, only when we're not debugging
|
||||||
if not self.request.debug:
|
if not self.request.debug:
|
||||||
self.create_event(EventAction.POLICY_EXCEPTION, message=error_string)
|
self.create_event(
|
||||||
|
EventAction.POLICY_EXCEPTION,
|
||||||
|
message="Policy failed to execute",
|
||||||
|
exception=exception_to_dict(src_exc),
|
||||||
|
)
|
||||||
LOGGER.debug("P_ENG(proc): error, using failure result", exc=src_exc)
|
LOGGER.debug("P_ENG(proc): error, using failure result", exc=src_exc)
|
||||||
policy_result = PolicyResult(self.binding.failure_result, str(src_exc))
|
policy_result = PolicyResult(self.binding.failure_result, str(src_exc))
|
||||||
policy_result.source_binding = self.binding
|
policy_result.source_binding = self.binding
|
||||||
@ -143,5 +146,5 @@ class PolicyProcess(PROCESS_CLASS):
|
|||||||
try:
|
try:
|
||||||
self.connection.send(self.profiling_wrapper())
|
self.connection.send(self.profiling_wrapper())
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
LOGGER.warning("Policy failed to run", exc=exception_to_string(exc))
|
LOGGER.warning("Policy failed to run", exc=exc)
|
||||||
self.connection.send(PolicyResult(False, str(exc)))
|
self.connection.send(PolicyResult(False, str(exc)))
|
||||||
|
@ -237,4 +237,4 @@ class TestPolicyProcess(TestCase):
|
|||||||
self.assertEqual(len(events), 1)
|
self.assertEqual(len(events), 1)
|
||||||
event = events.first()
|
event = events.first()
|
||||||
self.assertEqual(event.user["username"], self.user.username)
|
self.assertEqual(event.user["username"], self.user.username)
|
||||||
self.assertIn("division by zero", event.context["message"])
|
self.assertIn("Policy failed to execute", event.context["message"])
|
||||||
|
@ -387,8 +387,7 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
response.url,
|
response.url,
|
||||||
(
|
(
|
||||||
f"http://localhost#access_token={token.token}"
|
f"http://localhost#id_token={provider.encode(token.id_token.to_dict())}"
|
||||||
f"&id_token={provider.encode(token.id_token.to_dict())}"
|
|
||||||
f"&token_type={TOKEN_TYPE}"
|
f"&token_type={TOKEN_TYPE}"
|
||||||
f"&expires_in={int(expires)}&state={state}"
|
f"&expires_in={int(expires)}&state={state}"
|
||||||
),
|
),
|
||||||
@ -563,7 +562,6 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
"url": "http://localhost",
|
"url": "http://localhost",
|
||||||
"title": f"Redirecting to {app.name}...",
|
"title": f"Redirecting to {app.name}...",
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"access_token": token.token,
|
|
||||||
"id_token": provider.encode(token.id_token.to_dict()),
|
"id_token": provider.encode(token.id_token.to_dict()),
|
||||||
"token_type": TOKEN_TYPE,
|
"token_type": TOKEN_TYPE,
|
||||||
"expires_in": "3600",
|
"expires_in": "3600",
|
||||||
|
@ -150,12 +150,12 @@ class OAuthAuthorizationParams:
|
|||||||
self.check_redirect_uri()
|
self.check_redirect_uri()
|
||||||
self.check_grant()
|
self.check_grant()
|
||||||
self.check_scope(github_compat)
|
self.check_scope(github_compat)
|
||||||
self.check_nonce()
|
|
||||||
self.check_code_challenge()
|
|
||||||
if self.request:
|
if self.request:
|
||||||
raise AuthorizeError(
|
raise AuthorizeError(
|
||||||
self.redirect_uri, "request_not_supported", self.grant_type, self.state
|
self.redirect_uri, "request_not_supported", self.grant_type, self.state
|
||||||
)
|
)
|
||||||
|
self.check_nonce()
|
||||||
|
self.check_code_challenge()
|
||||||
|
|
||||||
def check_grant(self):
|
def check_grant(self):
|
||||||
"""Check grant"""
|
"""Check grant"""
|
||||||
@ -630,7 +630,6 @@ class OAuthFulfillmentStage(StageView):
|
|||||||
if self.params.response_type in [
|
if self.params.response_type in [
|
||||||
ResponseTypes.ID_TOKEN_TOKEN,
|
ResponseTypes.ID_TOKEN_TOKEN,
|
||||||
ResponseTypes.CODE_ID_TOKEN_TOKEN,
|
ResponseTypes.CODE_ID_TOKEN_TOKEN,
|
||||||
ResponseTypes.ID_TOKEN,
|
|
||||||
ResponseTypes.CODE_TOKEN,
|
ResponseTypes.CODE_TOKEN,
|
||||||
]:
|
]:
|
||||||
query_fragment["access_token"] = token.token
|
query_fragment["access_token"] = token.token
|
||||||
|
@ -49,6 +49,7 @@ class TestEndpointsAPI(APITestCase):
|
|||||||
self.assertJSONEqual(
|
self.assertJSONEqual(
|
||||||
response.content.decode(),
|
response.content.decode(),
|
||||||
{
|
{
|
||||||
|
"autocomplete": {},
|
||||||
"pagination": {
|
"pagination": {
|
||||||
"next": 0,
|
"next": 0,
|
||||||
"previous": 0,
|
"previous": 0,
|
||||||
@ -101,6 +102,7 @@ class TestEndpointsAPI(APITestCase):
|
|||||||
self.assertJSONEqual(
|
self.assertJSONEqual(
|
||||||
response.content.decode(),
|
response.content.decode(),
|
||||||
{
|
{
|
||||||
|
"autocomplete": {},
|
||||||
"pagination": {
|
"pagination": {
|
||||||
"next": 0,
|
"next": 0,
|
||||||
"previous": 0,
|
"previous": 0,
|
||||||
|
@ -20,6 +20,9 @@ from authentik.lib.utils.time import timedelta_from_string
|
|||||||
from authentik.policies.engine import PolicyEngine
|
from authentik.policies.engine import PolicyEngine
|
||||||
from authentik.policies.views import PolicyAccessView
|
from authentik.policies.views import PolicyAccessView
|
||||||
from authentik.providers.rac.models import ConnectionToken, Endpoint, RACProvider
|
from authentik.providers.rac.models import ConnectionToken, Endpoint, RACProvider
|
||||||
|
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
|
||||||
|
|
||||||
|
PLAN_CONNECTION_SETTINGS = "connection_settings"
|
||||||
|
|
||||||
|
|
||||||
class RACStartView(PolicyAccessView):
|
class RACStartView(PolicyAccessView):
|
||||||
@ -109,10 +112,15 @@ class RACFinalStage(RedirectStage):
|
|||||||
return super().dispatch(request, *args, **kwargs)
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_challenge(self, *args, **kwargs) -> RedirectChallenge:
|
def get_challenge(self, *args, **kwargs) -> RedirectChallenge:
|
||||||
|
settings = self.executor.plan.context.get(PLAN_CONNECTION_SETTINGS)
|
||||||
|
if not settings:
|
||||||
|
settings = self.executor.plan.context.get(PLAN_CONTEXT_PROMPT, {}).get(
|
||||||
|
PLAN_CONNECTION_SETTINGS
|
||||||
|
)
|
||||||
token = ConnectionToken.objects.create(
|
token = ConnectionToken.objects.create(
|
||||||
provider=self.provider,
|
provider=self.provider,
|
||||||
endpoint=self.endpoint,
|
endpoint=self.endpoint,
|
||||||
settings=self.executor.plan.context.get("connection_settings", {}),
|
settings=settings or {},
|
||||||
session=self.request.session["authenticatedsession"],
|
session=self.request.session["authenticatedsession"],
|
||||||
expires=now() + timedelta_from_string(self.provider.connection_expiry),
|
expires=now() + timedelta_from_string(self.provider.connection_expiry),
|
||||||
expiring=True,
|
expiring=True,
|
||||||
|
@ -23,7 +23,6 @@ from authentik.core.models import Application
|
|||||||
from authentik.events.models import Event, EventAction
|
from authentik.events.models import Event, EventAction
|
||||||
from authentik.lib.expression.exceptions import ControlFlowException
|
from authentik.lib.expression.exceptions import ControlFlowException
|
||||||
from authentik.lib.sync.mapper import PropertyMappingManager
|
from authentik.lib.sync.mapper import PropertyMappingManager
|
||||||
from authentik.lib.utils.errors import exception_to_string
|
|
||||||
from authentik.policies.api.exec import PolicyTestResultSerializer
|
from authentik.policies.api.exec import PolicyTestResultSerializer
|
||||||
from authentik.policies.engine import PolicyEngine
|
from authentik.policies.engine import PolicyEngine
|
||||||
from authentik.policies.types import PolicyResult
|
from authentik.policies.types import PolicyResult
|
||||||
@ -142,9 +141,9 @@ class RadiusOutpostConfigViewSet(ListModelMixin, GenericViewSet):
|
|||||||
# Value error can be raised when assigning invalid data to an attribute
|
# Value error can be raised when assigning invalid data to an attribute
|
||||||
Event.new(
|
Event.new(
|
||||||
EventAction.CONFIGURATION_ERROR,
|
EventAction.CONFIGURATION_ERROR,
|
||||||
message=f"Failed to evaluate property-mapping {exception_to_string(exc)}",
|
message="Failed to evaluate property-mapping",
|
||||||
mapping=exc.mapping,
|
mapping=exc.mapping,
|
||||||
).save()
|
).with_exception(exc).save()
|
||||||
return None
|
return None
|
||||||
return b64encode(packet.RequestPacket()).decode()
|
return b64encode(packet.RequestPacket()).decode()
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ class TestRBACRoleAPI(APITestCase):
|
|||||||
self.assertJSONEqual(
|
self.assertJSONEqual(
|
||||||
res.content.decode(),
|
res.content.decode(),
|
||||||
{
|
{
|
||||||
|
"autocomplete": {},
|
||||||
"pagination": {
|
"pagination": {
|
||||||
"next": 0,
|
"next": 0,
|
||||||
"previous": 0,
|
"previous": 0,
|
||||||
|
@ -46,6 +46,7 @@ class TestRBACUserAPI(APITestCase):
|
|||||||
self.assertJSONEqual(
|
self.assertJSONEqual(
|
||||||
res.content.decode(),
|
res.content.decode(),
|
||||||
{
|
{
|
||||||
|
"autocomplete": {},
|
||||||
"pagination": {
|
"pagination": {
|
||||||
"next": 0,
|
"next": 0,
|
||||||
"previous": 0,
|
"previous": 0,
|
||||||
|
@ -38,6 +38,7 @@ class TestAPIPerms(APITestCase):
|
|||||||
self.assertJSONEqual(
|
self.assertJSONEqual(
|
||||||
res.content.decode(),
|
res.content.decode(),
|
||||||
{
|
{
|
||||||
|
"autocomplete": {},
|
||||||
"pagination": {
|
"pagination": {
|
||||||
"next": 0,
|
"next": 0,
|
||||||
"previous": 0,
|
"previous": 0,
|
||||||
@ -73,6 +74,7 @@ class TestAPIPerms(APITestCase):
|
|||||||
self.assertJSONEqual(
|
self.assertJSONEqual(
|
||||||
res.content.decode(),
|
res.content.decode(),
|
||||||
{
|
{
|
||||||
|
"autocomplete": {},
|
||||||
"pagination": {
|
"pagination": {
|
||||||
"next": 0,
|
"next": 0,
|
||||||
"previous": 0,
|
"previous": 0,
|
||||||
|
@ -9,13 +9,14 @@ https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/
|
|||||||
|
|
||||||
import django
|
import django
|
||||||
from channels.routing import ProtocolTypeRouter, URLRouter
|
from channels.routing import ProtocolTypeRouter, URLRouter
|
||||||
from defusedxml import defuse_stdlib
|
|
||||||
from django.core.asgi import get_asgi_application
|
from django.core.asgi import get_asgi_application
|
||||||
from sentry_sdk.integrations.asgi import SentryAsgiMiddleware
|
from sentry_sdk.integrations.asgi import SentryAsgiMiddleware
|
||||||
|
|
||||||
|
from authentik.root.setup import setup
|
||||||
|
|
||||||
# DJANGO_SETTINGS_MODULE is set in gunicorn.conf.py
|
# DJANGO_SETTINGS_MODULE is set in gunicorn.conf.py
|
||||||
|
|
||||||
defuse_stdlib()
|
setup()
|
||||||
django.setup()
|
django.setup()
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,7 +28,6 @@ from tenant_schemas_celery.app import CeleryApp as TenantAwareCeleryApp
|
|||||||
|
|
||||||
from authentik import get_full_version
|
from authentik import get_full_version
|
||||||
from authentik.lib.sentry import before_send
|
from authentik.lib.sentry import before_send
|
||||||
from authentik.lib.utils.errors import exception_to_string
|
|
||||||
|
|
||||||
# set the default Django settings module for the 'celery' program.
|
# set the default Django settings module for the 'celery' program.
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings")
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings")
|
||||||
@ -83,8 +82,8 @@ def task_error_hook(task_id: str, exception: Exception, traceback, *args, **kwar
|
|||||||
CTX_TASK_ID.set(...)
|
CTX_TASK_ID.set(...)
|
||||||
if before_send({}, {"exc_info": (None, exception, None)}) is not None:
|
if before_send({}, {"exc_info": (None, exception, None)}) is not None:
|
||||||
Event.new(
|
Event.new(
|
||||||
EventAction.SYSTEM_EXCEPTION, message=exception_to_string(exception), task_id=task_id
|
EventAction.SYSTEM_EXCEPTION, message="Failed to execute task", task_id=task_id
|
||||||
).save()
|
).with_exception(exception).save()
|
||||||
|
|
||||||
|
|
||||||
def _get_startup_tasks_default_tenant() -> list[Callable]:
|
def _get_startup_tasks_default_tenant() -> list[Callable]:
|
||||||
|
@ -446,6 +446,8 @@ _DISALLOWED_ITEMS = [
|
|||||||
"MIDDLEWARE",
|
"MIDDLEWARE",
|
||||||
"AUTHENTICATION_BACKENDS",
|
"AUTHENTICATION_BACKENDS",
|
||||||
"CELERY",
|
"CELERY",
|
||||||
|
"SPECTACULAR_SETTINGS",
|
||||||
|
"REST_FRAMEWORK",
|
||||||
]
|
]
|
||||||
|
|
||||||
SILENCED_SYSTEM_CHECKS = [
|
SILENCED_SYSTEM_CHECKS = [
|
||||||
@ -468,6 +470,8 @@ def _update_settings(app_path: str):
|
|||||||
TENANT_APPS.extend(getattr(settings_module, "TENANT_APPS", []))
|
TENANT_APPS.extend(getattr(settings_module, "TENANT_APPS", []))
|
||||||
MIDDLEWARE.extend(getattr(settings_module, "MIDDLEWARE", []))
|
MIDDLEWARE.extend(getattr(settings_module, "MIDDLEWARE", []))
|
||||||
AUTHENTICATION_BACKENDS.extend(getattr(settings_module, "AUTHENTICATION_BACKENDS", []))
|
AUTHENTICATION_BACKENDS.extend(getattr(settings_module, "AUTHENTICATION_BACKENDS", []))
|
||||||
|
SPECTACULAR_SETTINGS.update(getattr(settings_module, "SPECTACULAR_SETTINGS", {}))
|
||||||
|
REST_FRAMEWORK.update(getattr(settings_module, "REST_FRAMEWORK", {}))
|
||||||
CELERY["beat_schedule"].update(getattr(settings_module, "CELERY_BEAT_SCHEDULE", {}))
|
CELERY["beat_schedule"].update(getattr(settings_module, "CELERY_BEAT_SCHEDULE", {}))
|
||||||
for _attr in dir(settings_module):
|
for _attr in dir(settings_module):
|
||||||
if not _attr.startswith("__") and _attr not in _DISALLOWED_ITEMS:
|
if not _attr.startswith("__") and _attr not in _DISALLOWED_ITEMS:
|
||||||
|
26
authentik/root/setup.py
Normal file
26
authentik/root/setup.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import os
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
from cryptography.hazmat.backends.openssl.backend import backend
|
||||||
|
from defusedxml import defuse_stdlib
|
||||||
|
|
||||||
|
from authentik.lib.config import CONFIG
|
||||||
|
|
||||||
|
|
||||||
|
def setup():
|
||||||
|
warnings.filterwarnings("ignore", "SelectableGroups dict interface")
|
||||||
|
warnings.filterwarnings(
|
||||||
|
"ignore",
|
||||||
|
"defusedxml.lxml is no longer supported and will be removed in a future release.",
|
||||||
|
)
|
||||||
|
warnings.filterwarnings(
|
||||||
|
"ignore",
|
||||||
|
"defusedxml.cElementTree is deprecated, import from defusedxml.ElementTree instead.",
|
||||||
|
)
|
||||||
|
|
||||||
|
defuse_stdlib()
|
||||||
|
|
||||||
|
if CONFIG.get_bool("compliance.fips.enabled", False):
|
||||||
|
backend._enable_fips()
|
||||||
|
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings")
|
@ -3,21 +3,40 @@
|
|||||||
import os
|
import os
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.test.runner import DiscoverRunner
|
from django.test.runner import DiscoverRunner
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
|
from authentik.events.context_processors.asn import ASN_CONTEXT_PROCESSOR
|
||||||
|
from authentik.events.context_processors.geoip import GEOIP_CONTEXT_PROCESSOR
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
from authentik.lib.sentry import sentry_init
|
from authentik.lib.sentry import sentry_init
|
||||||
from authentik.root.signals import post_startup, pre_startup, startup
|
from authentik.root.signals import post_startup, pre_startup, startup
|
||||||
from tests.e2e.utils import get_docker_tag
|
|
||||||
|
|
||||||
# globally set maxDiff to none to show full assert error
|
# globally set maxDiff to none to show full assert error
|
||||||
TestCase.maxDiff = None
|
TestCase.maxDiff = None
|
||||||
|
|
||||||
|
|
||||||
|
def get_docker_tag() -> str:
|
||||||
|
"""Get docker-tag based off of CI variables"""
|
||||||
|
env_pr_branch = "GITHUB_HEAD_REF"
|
||||||
|
default_branch = "GITHUB_REF"
|
||||||
|
branch_name = os.environ.get(default_branch, "main")
|
||||||
|
if os.environ.get(env_pr_branch, "") != "":
|
||||||
|
branch_name = os.environ[env_pr_branch]
|
||||||
|
branch_name = branch_name.replace("refs/heads/", "").replace("/", "-")
|
||||||
|
return f"gh-{branch_name}"
|
||||||
|
|
||||||
|
|
||||||
|
def patched__get_ct_cached(app_label, codename):
|
||||||
|
"""Caches `ContentType` instances like its `QuerySet` does."""
|
||||||
|
return ContentType.objects.get(app_label=app_label, permission__codename=codename)
|
||||||
|
|
||||||
|
|
||||||
class PytestTestRunner(DiscoverRunner): # pragma: no cover
|
class PytestTestRunner(DiscoverRunner): # pragma: no cover
|
||||||
"""Runs pytest to discover and run tests."""
|
"""Runs pytest to discover and run tests."""
|
||||||
|
|
||||||
@ -59,6 +78,9 @@ class PytestTestRunner(DiscoverRunner): # pragma: no cover
|
|||||||
for key, value in test_config.items():
|
for key, value in test_config.items():
|
||||||
CONFIG.set(key, value)
|
CONFIG.set(key, value)
|
||||||
|
|
||||||
|
ASN_CONTEXT_PROCESSOR.load()
|
||||||
|
GEOIP_CONTEXT_PROCESSOR.load()
|
||||||
|
|
||||||
sentry_init()
|
sentry_init()
|
||||||
self.logger.debug("Test environment configured")
|
self.logger.debug("Test environment configured")
|
||||||
|
|
||||||
@ -149,8 +171,9 @@ class PytestTestRunner(DiscoverRunner): # pragma: no cover
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
self.logger.info("Running tests", test_files=self.args)
|
self.logger.info("Running tests", test_files=self.args)
|
||||||
try:
|
with patch("guardian.shortcuts._get_ct_cached", patched__get_ct_cached):
|
||||||
return pytest.main(self.args)
|
try:
|
||||||
except Exception as e:
|
return pytest.main(self.args)
|
||||||
self.logger.error("Error running tests", error=str(e), test_files=self.args)
|
except Exception as e:
|
||||||
return 1
|
self.logger.error("Error running tests", error=str(e), test_files=self.args)
|
||||||
|
return 1
|
||||||
|
@ -8,7 +8,6 @@ from authentik.events.models import TaskStatus
|
|||||||
from authentik.events.system_tasks import SystemTask
|
from authentik.events.system_tasks import SystemTask
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
from authentik.lib.sync.outgoing.exceptions import StopSync
|
from authentik.lib.sync.outgoing.exceptions import StopSync
|
||||||
from authentik.lib.utils.errors import exception_to_string
|
|
||||||
from authentik.root.celery import CELERY_APP
|
from authentik.root.celery import CELERY_APP
|
||||||
from authentik.sources.kerberos.models import KerberosSource
|
from authentik.sources.kerberos.models import KerberosSource
|
||||||
from authentik.sources.kerberos.sync import KerberosSync
|
from authentik.sources.kerberos.sync import KerberosSync
|
||||||
@ -64,5 +63,5 @@ def kerberos_sync_single(self, source_pk: str):
|
|||||||
syncer.sync()
|
syncer.sync()
|
||||||
self.set_status(TaskStatus.SUCCESSFUL, *syncer.messages)
|
self.set_status(TaskStatus.SUCCESSFUL, *syncer.messages)
|
||||||
except StopSync as exc:
|
except StopSync as exc:
|
||||||
LOGGER.warning(exception_to_string(exc))
|
LOGGER.warning("Error syncing kerberos", exc=exc, source=source)
|
||||||
self.set_error(exc)
|
self.set_error(exc)
|
||||||
|
@ -12,7 +12,6 @@ from authentik.events.models import TaskStatus
|
|||||||
from authentik.events.system_tasks import SystemTask
|
from authentik.events.system_tasks import SystemTask
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
from authentik.lib.sync.outgoing.exceptions import StopSync
|
from authentik.lib.sync.outgoing.exceptions import StopSync
|
||||||
from authentik.lib.utils.errors import exception_to_string
|
|
||||||
from authentik.lib.utils.reflection import class_to_path, path_to_class
|
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
|
||||||
@ -71,37 +70,31 @@ def ldap_sync_single(source_pk: str):
|
|||||||
return
|
return
|
||||||
# Delete all sync tasks from the cache
|
# Delete all sync tasks from the cache
|
||||||
DBSystemTask.objects.filter(name="ldap_sync", uid__startswith=source.slug).delete()
|
DBSystemTask.objects.filter(name="ldap_sync", uid__startswith=source.slug).delete()
|
||||||
task = chain(
|
|
||||||
# User and group sync can happen at once, they have no dependencies on each other
|
# The order of these operations needs to be preserved as each depends on the previous one(s)
|
||||||
group(
|
# 1. User and group sync can happen simultaneously
|
||||||
ldap_sync_paginator(source, UserLDAPSynchronizer)
|
# 2. Membership sync needs to run afterwards
|
||||||
+ ldap_sync_paginator(source, GroupLDAPSynchronizer),
|
# 3. Finally, user and group deletions can happen simultaneously
|
||||||
),
|
user_group_sync = ldap_sync_paginator(source, UserLDAPSynchronizer) + ldap_sync_paginator(
|
||||||
# Membership sync needs to run afterwards
|
source, GroupLDAPSynchronizer
|
||||||
group(
|
|
||||||
ldap_sync_paginator(source, MembershipLDAPSynchronizer),
|
|
||||||
),
|
|
||||||
# Finally, deletions. What we'd really like to do here is something like
|
|
||||||
# ```
|
|
||||||
# user_identifiers = <ldap query>
|
|
||||||
# User.objects.exclude(
|
|
||||||
# usersourceconnection__identifier__in=user_uniqueness_identifiers,
|
|
||||||
# ).delete()
|
|
||||||
# ```
|
|
||||||
# This runs into performance issues in large installations. So instead we spread the
|
|
||||||
# work out into three steps:
|
|
||||||
# 1. Get every object from the LDAP source.
|
|
||||||
# 2. Mark every object as "safe" in the database. This is quick, but any error could
|
|
||||||
# mean deleting users which should not be deleted, so we do it immediately, in
|
|
||||||
# large chunks, and only queue the deletion step afterwards.
|
|
||||||
# 3. Delete every unmarked item. This is slow, so we spread it over many tasks in
|
|
||||||
# small chunks.
|
|
||||||
group(
|
|
||||||
ldap_sync_paginator(source, UserLDAPForwardDeletion)
|
|
||||||
+ ldap_sync_paginator(source, GroupLDAPForwardDeletion),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
task()
|
membership_sync = ldap_sync_paginator(source, MembershipLDAPSynchronizer)
|
||||||
|
user_group_deletion = ldap_sync_paginator(
|
||||||
|
source, UserLDAPForwardDeletion
|
||||||
|
) + ldap_sync_paginator(source, GroupLDAPForwardDeletion)
|
||||||
|
|
||||||
|
# Celery is buggy with empty groups, so we are careful only to add non-empty groups.
|
||||||
|
# See https://github.com/celery/celery/issues/9772
|
||||||
|
task_groups = []
|
||||||
|
if user_group_sync:
|
||||||
|
task_groups.append(group(user_group_sync))
|
||||||
|
if membership_sync:
|
||||||
|
task_groups.append(group(membership_sync))
|
||||||
|
if user_group_deletion:
|
||||||
|
task_groups.append(group(user_group_deletion))
|
||||||
|
|
||||||
|
all_tasks = chain(task_groups)
|
||||||
|
all_tasks()
|
||||||
|
|
||||||
|
|
||||||
def ldap_sync_paginator(source: LDAPSource, sync: type[BaseLDAPSynchronizer]) -> list:
|
def ldap_sync_paginator(source: LDAPSource, sync: type[BaseLDAPSynchronizer]) -> list:
|
||||||
@ -155,5 +148,5 @@ def ldap_sync(self: SystemTask, source_pk: str, sync_class: str, page_cache_key:
|
|||||||
cache.delete(page_cache_key)
|
cache.delete(page_cache_key)
|
||||||
except (LDAPException, StopSync) as exc:
|
except (LDAPException, StopSync) as exc:
|
||||||
# No explicit event is created here as .set_status with an error will do that
|
# No explicit event is created here as .set_status with an error will do that
|
||||||
LOGGER.warning(exception_to_string(exc))
|
LOGGER.warning("Failed to sync LDAP", exc=exc, source=source)
|
||||||
self.set_error(exc)
|
self.set_error(exc)
|
||||||
|
@ -13,7 +13,6 @@ from authentik.flows.exceptions import StageInvalidException
|
|||||||
from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage
|
from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
from authentik.lib.models import SerializerModel
|
from authentik.lib.models import SerializerModel
|
||||||
from authentik.lib.utils.errors import exception_to_string
|
|
||||||
from authentik.lib.utils.time import timedelta_string_validator
|
from authentik.lib.utils.time import timedelta_string_validator
|
||||||
from authentik.stages.authenticator.models import SideChannelDevice
|
from authentik.stages.authenticator.models import SideChannelDevice
|
||||||
from authentik.stages.email.utils import TemplateEmailMessage
|
from authentik.stages.email.utils import TemplateEmailMessage
|
||||||
@ -160,9 +159,8 @@ class EmailDevice(SerializerModel, SideChannelDevice):
|
|||||||
Event.new(
|
Event.new(
|
||||||
EventAction.CONFIGURATION_ERROR,
|
EventAction.CONFIGURATION_ERROR,
|
||||||
message=_("Exception occurred while rendering E-mail template"),
|
message=_("Exception occurred while rendering E-mail template"),
|
||||||
error=exception_to_string(exc),
|
|
||||||
template=stage.template,
|
template=stage.template,
|
||||||
).from_http(self.request)
|
).with_exception(exc).from_http(self.request)
|
||||||
raise StageInvalidException from exc
|
raise StageInvalidException from exc
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
@ -17,7 +17,6 @@ from authentik.flows.challenge import (
|
|||||||
from authentik.flows.exceptions import StageInvalidException
|
from authentik.flows.exceptions import StageInvalidException
|
||||||
from authentik.flows.stage import ChallengeStageView
|
from authentik.flows.stage import ChallengeStageView
|
||||||
from authentik.lib.utils.email import mask_email
|
from authentik.lib.utils.email import mask_email
|
||||||
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.authenticator_email.models import (
|
from authentik.stages.authenticator_email.models import (
|
||||||
AuthenticatorEmailStage,
|
AuthenticatorEmailStage,
|
||||||
@ -100,9 +99,8 @@ class AuthenticatorEmailStageView(ChallengeStageView):
|
|||||||
Event.new(
|
Event.new(
|
||||||
EventAction.CONFIGURATION_ERROR,
|
EventAction.CONFIGURATION_ERROR,
|
||||||
message=_("Exception occurred while rendering E-mail template"),
|
message=_("Exception occurred while rendering E-mail template"),
|
||||||
error=exception_to_string(exc),
|
|
||||||
template=stage.template,
|
template=stage.template,
|
||||||
).from_http(self.request)
|
).with_exception(exc).from_http(self.request)
|
||||||
raise StageInvalidException from exc
|
raise StageInvalidException from exc
|
||||||
|
|
||||||
def _has_email(self) -> str | None:
|
def _has_email(self) -> str | None:
|
||||||
|
@ -19,7 +19,6 @@ from authentik.events.models import Event, EventAction, NotificationWebhookMappi
|
|||||||
from authentik.events.utils import sanitize_item
|
from authentik.events.utils import sanitize_item
|
||||||
from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage
|
from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage
|
||||||
from authentik.lib.models import SerializerModel
|
from authentik.lib.models import SerializerModel
|
||||||
from authentik.lib.utils.errors import exception_to_string
|
|
||||||
from authentik.lib.utils.http import get_http_session
|
from authentik.lib.utils.http import get_http_session
|
||||||
from authentik.stages.authenticator.models import SideChannelDevice
|
from authentik.stages.authenticator.models import SideChannelDevice
|
||||||
|
|
||||||
@ -142,10 +141,9 @@ class AuthenticatorSMSStage(ConfigurableStage, FriendlyNamedStage, Stage):
|
|||||||
Event.new(
|
Event.new(
|
||||||
EventAction.CONFIGURATION_ERROR,
|
EventAction.CONFIGURATION_ERROR,
|
||||||
message="Error sending SMS",
|
message="Error sending SMS",
|
||||||
exc=exception_to_string(exc),
|
|
||||||
status_code=response.status_code,
|
status_code=response.status_code,
|
||||||
body=response.text,
|
body=response.text,
|
||||||
).set_user(device.user).save()
|
).with_exception(exc).set_user(device.user).save()
|
||||||
if response.status_code >= HttpResponseBadRequest.status_code:
|
if response.status_code >= HttpResponseBadRequest.status_code:
|
||||||
raise ValidationError(response.text) from None
|
raise ValidationError(response.text) from None
|
||||||
raise
|
raise
|
||||||
|
File diff suppressed because one or more lines are too long
@ -21,7 +21,6 @@ from authentik.flows.models import FlowDesignation, FlowToken
|
|||||||
from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED, PLAN_CONTEXT_PENDING_USER
|
from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED, PLAN_CONTEXT_PENDING_USER
|
||||||
from authentik.flows.stage import ChallengeStageView
|
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.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.flow import pickle_flow_token_for_email
|
||||||
from authentik.stages.email.models import EmailStage
|
from authentik.stages.email.models import EmailStage
|
||||||
@ -129,9 +128,8 @@ class EmailStageView(ChallengeStageView):
|
|||||||
Event.new(
|
Event.new(
|
||||||
EventAction.CONFIGURATION_ERROR,
|
EventAction.CONFIGURATION_ERROR,
|
||||||
message=_("Exception occurred while rendering E-mail template"),
|
message=_("Exception occurred while rendering E-mail template"),
|
||||||
error=exception_to_string(exc),
|
|
||||||
template=current_stage.template,
|
template=current_stage.template,
|
||||||
).from_http(self.request)
|
).with_exception(exc).from_http(self.request)
|
||||||
raise StageInvalidException from exc
|
raise StageInvalidException from exc
|
||||||
|
|
||||||
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||||
|
@ -101,9 +101,9 @@ class BoundSessionMiddleware(SessionMiddleware):
|
|||||||
SESSION_KEY_BINDING_GEO, GeoIPBinding.NO_BINDING
|
SESSION_KEY_BINDING_GEO, GeoIPBinding.NO_BINDING
|
||||||
)
|
)
|
||||||
if configured_binding_net != NetworkBinding.NO_BINDING:
|
if configured_binding_net != NetworkBinding.NO_BINDING:
|
||||||
self.recheck_session_net(configured_binding_net, last_ip, new_ip)
|
BoundSessionMiddleware.recheck_session_net(configured_binding_net, last_ip, new_ip)
|
||||||
if configured_binding_geo != GeoIPBinding.NO_BINDING:
|
if configured_binding_geo != GeoIPBinding.NO_BINDING:
|
||||||
self.recheck_session_geo(configured_binding_geo, last_ip, new_ip)
|
BoundSessionMiddleware.recheck_session_geo(configured_binding_geo, last_ip, new_ip)
|
||||||
# If we got to this point without any error being raised, we need to
|
# If we got to this point without any error being raised, we need to
|
||||||
# update the last saved IP to the current one
|
# update the last saved IP to the current one
|
||||||
if SESSION_KEY_BINDING_NET in request.session or SESSION_KEY_BINDING_GEO in request.session:
|
if SESSION_KEY_BINDING_NET in request.session or SESSION_KEY_BINDING_GEO in request.session:
|
||||||
@ -111,7 +111,8 @@ class BoundSessionMiddleware(SessionMiddleware):
|
|||||||
# (== basically requires the user to be logged in)
|
# (== basically requires the user to be logged in)
|
||||||
request.session[request.session.model.Keys.LAST_IP] = new_ip
|
request.session[request.session.model.Keys.LAST_IP] = new_ip
|
||||||
|
|
||||||
def recheck_session_net(self, binding: NetworkBinding, last_ip: str, new_ip: str):
|
@staticmethod
|
||||||
|
def recheck_session_net(binding: NetworkBinding, last_ip: str, new_ip: str):
|
||||||
"""Check network/ASN binding"""
|
"""Check network/ASN binding"""
|
||||||
last_asn = ASN_CONTEXT_PROCESSOR.asn(last_ip)
|
last_asn = ASN_CONTEXT_PROCESSOR.asn(last_ip)
|
||||||
new_asn = ASN_CONTEXT_PROCESSOR.asn(new_ip)
|
new_asn = ASN_CONTEXT_PROCESSOR.asn(new_ip)
|
||||||
@ -158,7 +159,8 @@ class BoundSessionMiddleware(SessionMiddleware):
|
|||||||
new_ip,
|
new_ip,
|
||||||
)
|
)
|
||||||
|
|
||||||
def recheck_session_geo(self, binding: GeoIPBinding, last_ip: str, new_ip: str):
|
@staticmethod
|
||||||
|
def recheck_session_geo(binding: GeoIPBinding, last_ip: str, new_ip: str):
|
||||||
"""Check GeoIP binding"""
|
"""Check GeoIP binding"""
|
||||||
last_geo = GEOIP_CONTEXT_PROCESSOR.city(last_ip)
|
last_geo = GEOIP_CONTEXT_PROCESSOR.city(last_ip)
|
||||||
new_geo = GEOIP_CONTEXT_PROCESSOR.city(new_ip)
|
new_geo = GEOIP_CONTEXT_PROCESSOR.city(new_ip)
|
||||||
@ -179,8 +181,8 @@ class BoundSessionMiddleware(SessionMiddleware):
|
|||||||
if last_geo.continent != new_geo.continent:
|
if last_geo.continent != new_geo.continent:
|
||||||
raise SessionBindingBroken(
|
raise SessionBindingBroken(
|
||||||
"geoip.continent",
|
"geoip.continent",
|
||||||
last_geo.continent,
|
last_geo.continent.to_dict(),
|
||||||
new_geo.continent,
|
new_geo.continent.to_dict(),
|
||||||
last_ip,
|
last_ip,
|
||||||
new_ip,
|
new_ip,
|
||||||
)
|
)
|
||||||
@ -192,8 +194,8 @@ class BoundSessionMiddleware(SessionMiddleware):
|
|||||||
if last_geo.country != new_geo.country:
|
if last_geo.country != new_geo.country:
|
||||||
raise SessionBindingBroken(
|
raise SessionBindingBroken(
|
||||||
"geoip.country",
|
"geoip.country",
|
||||||
last_geo.country,
|
last_geo.country.to_dict(),
|
||||||
new_geo.country,
|
new_geo.country.to_dict(),
|
||||||
last_ip,
|
last_ip,
|
||||||
new_ip,
|
new_ip,
|
||||||
)
|
)
|
||||||
@ -202,8 +204,8 @@ class BoundSessionMiddleware(SessionMiddleware):
|
|||||||
if last_geo.city != new_geo.city:
|
if last_geo.city != new_geo.city:
|
||||||
raise SessionBindingBroken(
|
raise SessionBindingBroken(
|
||||||
"geoip.city",
|
"geoip.city",
|
||||||
last_geo.city,
|
last_geo.city.to_dict(),
|
||||||
new_geo.city,
|
new_geo.city.to_dict(),
|
||||||
last_ip,
|
last_ip,
|
||||||
new_ip,
|
new_ip,
|
||||||
)
|
)
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
from time import sleep
|
from time import sleep
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from django.http import HttpRequest
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
|
|
||||||
@ -17,7 +18,12 @@ 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.lib.utils.time import timedelta_from_string
|
from authentik.lib.utils.time import timedelta_from_string
|
||||||
from authentik.root.middleware import ClientIPMiddleware
|
from authentik.root.middleware import ClientIPMiddleware
|
||||||
from authentik.stages.user_login.models import UserLoginStage
|
from authentik.stages.user_login.middleware import (
|
||||||
|
BoundSessionMiddleware,
|
||||||
|
SessionBindingBroken,
|
||||||
|
logout_extra,
|
||||||
|
)
|
||||||
|
from authentik.stages.user_login.models import GeoIPBinding, NetworkBinding, UserLoginStage
|
||||||
|
|
||||||
|
|
||||||
class TestUserLoginStage(FlowTestCase):
|
class TestUserLoginStage(FlowTestCase):
|
||||||
@ -192,3 +198,52 @@ class TestUserLoginStage(FlowTestCase):
|
|||||||
self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
|
self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
|
||||||
response = self.client.get(reverse("authentik_api:application-list"))
|
response = self.client.get(reverse("authentik_api:application-list"))
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
|
def test_binding_net_break_log(self):
|
||||||
|
"""Test logout_extra with exception"""
|
||||||
|
# IPs from https://github.com/maxmind/MaxMind-DB/blob/main/source-data/GeoLite2-ASN-Test.json
|
||||||
|
for args, expect in [
|
||||||
|
[[NetworkBinding.BIND_ASN, "8.8.8.8", "8.8.8.8"], ["network.missing"]],
|
||||||
|
[[NetworkBinding.BIND_ASN, "1.0.0.1", "1.128.0.1"], ["network.asn"]],
|
||||||
|
[
|
||||||
|
[NetworkBinding.BIND_ASN_NETWORK, "12.81.96.1", "12.81.128.1"],
|
||||||
|
["network.asn_network"],
|
||||||
|
],
|
||||||
|
[[NetworkBinding.BIND_ASN_NETWORK_IP, "1.0.0.1", "1.0.0.2"], ["network.ip"]],
|
||||||
|
]:
|
||||||
|
with self.subTest(args[0]):
|
||||||
|
with self.assertRaises(SessionBindingBroken) as cm:
|
||||||
|
BoundSessionMiddleware.recheck_session_net(*args)
|
||||||
|
self.assertEqual(cm.exception.reason, expect[0])
|
||||||
|
# Ensure the request can be logged without throwing errors
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
request = HttpRequest()
|
||||||
|
request.session = self.client.session
|
||||||
|
request.user = self.user
|
||||||
|
logout_extra(request, cm.exception)
|
||||||
|
|
||||||
|
def test_binding_geo_break_log(self):
|
||||||
|
"""Test logout_extra with exception"""
|
||||||
|
# IPs from https://github.com/maxmind/MaxMind-DB/blob/main/source-data/GeoLite2-City-Test.json
|
||||||
|
for args, expect in [
|
||||||
|
[[GeoIPBinding.BIND_CONTINENT, "8.8.8.8", "8.8.8.8"], ["geoip.missing"]],
|
||||||
|
[[GeoIPBinding.BIND_CONTINENT, "2.125.160.216", "67.43.156.1"], ["geoip.continent"]],
|
||||||
|
[
|
||||||
|
[GeoIPBinding.BIND_CONTINENT_COUNTRY, "81.2.69.142", "89.160.20.112"],
|
||||||
|
["geoip.country"],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[GeoIPBinding.BIND_CONTINENT_COUNTRY_CITY, "2.125.160.216", "81.2.69.142"],
|
||||||
|
["geoip.city"],
|
||||||
|
],
|
||||||
|
]:
|
||||||
|
with self.subTest(args[0]):
|
||||||
|
with self.assertRaises(SessionBindingBroken) as cm:
|
||||||
|
BoundSessionMiddleware.recheck_session_geo(*args)
|
||||||
|
self.assertEqual(cm.exception.reason, expect[0])
|
||||||
|
# Ensure the request can be logged without throwing errors
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
request = HttpRequest()
|
||||||
|
request.session = self.client.session
|
||||||
|
request.user = self.user
|
||||||
|
logout_extra(request, cm.exception)
|
||||||
|
14162
blueprints/schema.json
14162
blueprints/schema.json
File diff suppressed because it is too large
Load Diff
@ -31,7 +31,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- redis:/data
|
- redis:/data
|
||||||
server:
|
server:
|
||||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.1}
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.2}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: server
|
command: server
|
||||||
environment:
|
environment:
|
||||||
@ -55,7 +55,7 @@ services:
|
|||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
worker:
|
worker:
|
||||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.1}
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.2}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: worker
|
command: worker
|
||||||
environment:
|
environment:
|
||||||
|
4
go.mod
4
go.mod
@ -18,7 +18,7 @@ require (
|
|||||||
github.com/gorilla/sessions v1.4.0
|
github.com/gorilla/sessions v1.4.0
|
||||||
github.com/gorilla/websocket v1.5.3
|
github.com/gorilla/websocket v1.5.3
|
||||||
github.com/grafana/pyroscope-go v1.2.2
|
github.com/grafana/pyroscope-go v1.2.2
|
||||||
github.com/jellydator/ttlcache/v3 v3.3.0
|
github.com/jellydator/ttlcache/v3 v3.4.0
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
|
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
|
||||||
github.com/pires/go-proxyproto v0.8.1
|
github.com/pires/go-proxyproto v0.8.1
|
||||||
@ -29,7 +29,7 @@ require (
|
|||||||
github.com/spf13/cobra v1.9.1
|
github.com/spf13/cobra v1.9.1
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/wwt/guac v1.3.2
|
github.com/wwt/guac v1.3.2
|
||||||
goauthentik.io/api/v3 v3.2025061.2
|
goauthentik.io/api/v3 v3.2025062.3
|
||||||
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
|
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
|
||||||
golang.org/x/oauth2 v0.30.0
|
golang.org/x/oauth2 v0.30.0
|
||||||
golang.org/x/sync v0.15.0
|
golang.org/x/sync v0.15.0
|
||||||
|
8
go.sum
8
go.sum
@ -203,8 +203,8 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6
|
|||||||
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
|
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
|
||||||
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
|
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
|
||||||
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||||
github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc=
|
github.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP4mnWdTY=
|
||||||
github.com/jellydator/ttlcache/v3 v3.3.0/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw=
|
github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4=
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
@ -298,8 +298,8 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y
|
|||||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
goauthentik.io/api/v3 v3.2025061.2 h1:bKmrl82Gz6J8lz3f+QIH9g+MEkl3MvkMXF34GktesA0=
|
goauthentik.io/api/v3 v3.2025062.3 h1:syBOKigaHyX/8Rwmh9kOSF+TzsxOzmP5i7rsFwbemzA=
|
||||||
goauthentik.io/api/v3 v3.2025061.2/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
goauthentik.io/api/v3 v3.2025062.3/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
@ -33,4 +33,4 @@ func UserAgent() string {
|
|||||||
return fmt.Sprintf("authentik@%s", FullVersion())
|
return fmt.Sprintf("authentik@%s", FullVersion())
|
||||||
}
|
}
|
||||||
|
|
||||||
const VERSION = "2025.6.1"
|
const VERSION = "2025.6.2"
|
||||||
|
8
lifecycle/aws/package-lock.json
generated
8
lifecycle/aws/package-lock.json
generated
@ -9,7 +9,7 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"aws-cdk": "^2.1018.0",
|
"aws-cdk": "^2.1019.1",
|
||||||
"cross-env": "^7.0.3"
|
"cross-env": "^7.0.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -17,9 +17,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/aws-cdk": {
|
"node_modules/aws-cdk": {
|
||||||
"version": "2.1018.0",
|
"version": "2.1019.1",
|
||||||
"resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1018.0.tgz",
|
"resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1019.1.tgz",
|
||||||
"integrity": "sha512-sppVsNtFJTW4wawS/PBudHCSNHb8xwaZ2WX1mpsfwaPNyTWm0eSUVJsRbRiRBu9O/Us8pgrd4woUjfM1lgD7Kw==",
|
"integrity": "sha512-G2jxKuTsYTrYZX80CDApCrKcZ+AuFxxd+b0dkb0KEkfUsela7RqrDGLm5wOzSCIc3iH6GocR8JDVZuJ+0nNuKg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
"node": ">=20"
|
"node": ">=20"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"aws-cdk": "^2.1018.0",
|
"aws-cdk": "^2.1019.1",
|
||||||
"cross-env": "^7.0.3"
|
"cross-env": "^7.0.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ Parameters:
|
|||||||
Description: authentik Docker image
|
Description: authentik Docker image
|
||||||
AuthentikVersion:
|
AuthentikVersion:
|
||||||
Type: String
|
Type: String
|
||||||
Default: 2025.6.1
|
Default: 2025.6.2
|
||||||
Description: authentik Docker image tag
|
Description: authentik Docker image tag
|
||||||
AuthentikServerCPU:
|
AuthentikServerCPU:
|
||||||
Type: Number
|
Type: Number
|
||||||
|
@ -7,8 +7,6 @@ from pathlib import Path
|
|||||||
from tempfile import gettempdir
|
from tempfile import gettempdir
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from cryptography.hazmat.backends.openssl.backend import backend
|
|
||||||
from defusedxml import defuse_stdlib
|
|
||||||
from prometheus_client.values import MultiProcessValue
|
from prometheus_client.values import MultiProcessValue
|
||||||
|
|
||||||
from authentik import get_full_version
|
from authentik import get_full_version
|
||||||
@ -18,6 +16,7 @@ from authentik.lib.logging import get_logger_config
|
|||||||
from authentik.lib.utils.http import get_http_session
|
from authentik.lib.utils.http import get_http_session
|
||||||
from authentik.lib.utils.reflection import get_env
|
from authentik.lib.utils.reflection import get_env
|
||||||
from authentik.root.install_id import get_install_id_raw
|
from authentik.root.install_id import get_install_id_raw
|
||||||
|
from authentik.root.setup import setup
|
||||||
from lifecycle.migrate import run_migrations
|
from lifecycle.migrate import run_migrations
|
||||||
from lifecycle.wait_for_db import wait_for_db
|
from lifecycle.wait_for_db import wait_for_db
|
||||||
from lifecycle.worker import DjangoUvicornWorker
|
from lifecycle.worker import DjangoUvicornWorker
|
||||||
@ -28,10 +27,7 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
from authentik.root.asgi import AuthentikAsgi
|
from authentik.root.asgi import AuthentikAsgi
|
||||||
|
|
||||||
defuse_stdlib()
|
setup()
|
||||||
|
|
||||||
if CONFIG.get_bool("compliance.fips.enabled", False):
|
|
||||||
backend._enable_fips()
|
|
||||||
|
|
||||||
wait_for_db()
|
wait_for_db()
|
||||||
|
|
||||||
|
@ -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-06-04 00:12+0000\n"
|
"POT-Creation-Date: 2025-06-19 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"
|
||||||
@ -763,6 +763,12 @@ msgid ""
|
|||||||
"If left empty, Notification won't ben sent."
|
"If left empty, Notification won't ben sent."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: authentik/events/models.py
|
||||||
|
msgid ""
|
||||||
|
"When enabled, notification will be sent to user the user that triggered the "
|
||||||
|
"event.When destination_group is configured, notification is sent to both."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/events/models.py
|
#: authentik/events/models.py
|
||||||
msgid "Notification Rule"
|
msgid "Notification Rule"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -6,18 +6,18 @@
|
|||||||
# Translators:
|
# Translators:
|
||||||
# jcamat, 2022
|
# jcamat, 2022
|
||||||
# Angel, 2024
|
# Angel, 2024
|
||||||
# Iamanaws, 2024
|
|
||||||
# Marcelo Elizeche Landó, 2025
|
# Marcelo Elizeche Landó, 2025
|
||||||
# Jens L. <jens@goauthentik.io>, 2025
|
# Jens L. <jens@goauthentik.io>, 2025
|
||||||
|
# Iamanaws, 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-06-04 00:12+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: Iamanaws, 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"
|
||||||
"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"
|
||||||
@ -111,7 +111,7 @@ msgstr "Certificado Web usado por el servidor web Core de authentik"
|
|||||||
|
|
||||||
#: authentik/brands/models.py
|
#: authentik/brands/models.py
|
||||||
msgid "Certificates used for client authentication."
|
msgid "Certificates used for client authentication."
|
||||||
msgstr ""
|
msgstr "Certificados utilizados para la autenticación del cliente."
|
||||||
|
|
||||||
#: authentik/brands/models.py
|
#: authentik/brands/models.py
|
||||||
msgid "Brand"
|
msgid "Brand"
|
||||||
@ -131,7 +131,7 @@ msgstr "Descripción adicional no disponible."
|
|||||||
|
|
||||||
#: authentik/core/api/groups.py
|
#: authentik/core/api/groups.py
|
||||||
msgid "Cannot set group as parent of itself."
|
msgid "Cannot set group as parent of itself."
|
||||||
msgstr "No se puede establecer el grupo como padre de sí mismo."
|
msgstr "No se puede establecer un grupo como su propio padre."
|
||||||
|
|
||||||
#: authentik/core/api/providers.py
|
#: authentik/core/api/providers.py
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -183,11 +183,11 @@ msgstr "Remueve usuario del grupo"
|
|||||||
|
|
||||||
#: authentik/core/models.py
|
#: authentik/core/models.py
|
||||||
msgid "Enable superuser status"
|
msgid "Enable superuser status"
|
||||||
msgstr "Habiliar estado de \"superusuario\""
|
msgstr "Habilitar el estado de superusuario"
|
||||||
|
|
||||||
#: authentik/core/models.py
|
#: authentik/core/models.py
|
||||||
msgid "Disable superuser status"
|
msgid "Disable superuser status"
|
||||||
msgstr "Deshabiliar estado de \"superusuario\""
|
msgstr "Deshabilitar el estado de superusuario"
|
||||||
|
|
||||||
#: authentik/core/models.py
|
#: authentik/core/models.py
|
||||||
msgid "User's display name."
|
msgid "User's display name."
|
||||||
@ -241,7 +241,7 @@ msgstr "Flujo utilizado al autorizar a este proveedor."
|
|||||||
|
|
||||||
#: authentik/core/models.py
|
#: authentik/core/models.py
|
||||||
msgid "Flow used ending the session from a provider."
|
msgid "Flow used ending the session from a provider."
|
||||||
msgstr "Flujo usado para terminar la sesión de un proveedor."
|
msgstr "Flujo utilizado para finalizar la sesión desde un proveedor."
|
||||||
|
|
||||||
#: authentik/core/models.py
|
#: authentik/core/models.py
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -273,11 +273,11 @@ msgstr "Aplicaciones"
|
|||||||
|
|
||||||
#: authentik/core/models.py
|
#: authentik/core/models.py
|
||||||
msgid "Application Entitlement"
|
msgid "Application Entitlement"
|
||||||
msgstr ""
|
msgstr "Derecho de Aplicación"
|
||||||
|
|
||||||
#: authentik/core/models.py
|
#: authentik/core/models.py
|
||||||
msgid "Application Entitlements"
|
msgid "Application Entitlements"
|
||||||
msgstr ""
|
msgstr "Derechos de Aplicación"
|
||||||
|
|
||||||
#: authentik/core/models.py
|
#: authentik/core/models.py
|
||||||
msgid "Use the source-specific identifier"
|
msgid "Use the source-specific identifier"
|
||||||
@ -288,9 +288,9 @@ msgid ""
|
|||||||
"Link to a user with identical email address. Can have security implications "
|
"Link to a user with identical email address. Can have security implications "
|
||||||
"when a source doesn't validate email addresses."
|
"when a source doesn't validate email addresses."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Apunta a un usuario con una dirección de correo electrónico idéntica. Puede "
|
"Enlace a un usuario con la misma dirección de correo electrónico. Puede "
|
||||||
"tener implicaciones de seguridad cuando una fuente no valida la dirección de"
|
"tener implicaciones de seguridad cuando una fuente no valida las direcciones"
|
||||||
" correo electrónico."
|
" de correo electrónico."
|
||||||
|
|
||||||
#: authentik/core/models.py
|
#: authentik/core/models.py
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -305,8 +305,8 @@ msgid ""
|
|||||||
"Link to a user with identical username. Can have security implications when "
|
"Link to a user with identical username. Can have security implications when "
|
||||||
"a username is used with another source."
|
"a username is used with another source."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Enlace a un usuario con un nombre de usuario idéntico. Puede tener "
|
"Enlace a un usuario con el mismo nombre de usuario. Puede tener "
|
||||||
"implicaciones de seguridad cuando se usa un nombre de usuario con otra "
|
"implicaciones de seguridad cuando un nombre de usuario se utiliza con otra "
|
||||||
"fuente."
|
"fuente."
|
||||||
|
|
||||||
#: authentik/core/models.py
|
#: authentik/core/models.py
|
||||||
@ -322,8 +322,8 @@ msgid ""
|
|||||||
"Link to a group with identical name. Can have security implications when a "
|
"Link to a group with identical name. Can have security implications when a "
|
||||||
"group name is used with another source."
|
"group name is used with another source."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Enlace a un grupo con un nombre idéntico. Puede tener implicaciones de "
|
"Enlace a un grupo con el mismo nombre. Puede tener implicaciones de "
|
||||||
"seguridad cuando se utiliza un nombre de grupo con otra fuente."
|
"seguridad cuando un nombre de grupo se utiliza con otra fuente."
|
||||||
|
|
||||||
#: authentik/core/models.py
|
#: authentik/core/models.py
|
||||||
msgid "Use the group name, but deny enrollment when the name already exists."
|
msgid "Use the group name, but deny enrollment when the name already exists."
|
||||||
@ -385,7 +385,7 @@ msgstr "Asignaciones de Propiedades"
|
|||||||
|
|
||||||
#: authentik/core/models.py
|
#: authentik/core/models.py
|
||||||
msgid "session data"
|
msgid "session data"
|
||||||
msgstr ""
|
msgstr "datos de sesión"
|
||||||
|
|
||||||
#: authentik/core/models.py
|
#: authentik/core/models.py
|
||||||
msgid "Session"
|
msgid "Session"
|
||||||
@ -424,7 +424,7 @@ msgstr "¡Autenticado exitosamente con {source}!"
|
|||||||
#: authentik/core/sources/flow_manager.py
|
#: authentik/core/sources/flow_manager.py
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Successfully linked {source}!"
|
msgid "Successfully linked {source}!"
|
||||||
msgstr "¡{source} vinculado exitosamente!"
|
msgstr "¡{source} enlazado correctamente!"
|
||||||
|
|
||||||
#: authentik/core/sources/flow_manager.py
|
#: authentik/core/sources/flow_manager.py
|
||||||
msgid "Source is not configured for enrollment."
|
msgid "Source is not configured for enrollment."
|
||||||
@ -476,11 +476,11 @@ msgstr ""
|
|||||||
|
|
||||||
#: authentik/crypto/models.py
|
#: authentik/crypto/models.py
|
||||||
msgid "Certificate-Key Pair"
|
msgid "Certificate-Key Pair"
|
||||||
msgstr "Par de claves de certificado"
|
msgstr "Par Certificado-Clave"
|
||||||
|
|
||||||
#: authentik/crypto/models.py
|
#: authentik/crypto/models.py
|
||||||
msgid "Certificate-Key Pairs"
|
msgid "Certificate-Key Pairs"
|
||||||
msgstr "Pares de claves de certificado"
|
msgstr "Pares Certificado-Clave"
|
||||||
|
|
||||||
#: authentik/enterprise/api.py
|
#: authentik/enterprise/api.py
|
||||||
msgid "Enterprise is required to create/update this object."
|
msgid "Enterprise is required to create/update this object."
|
||||||
@ -511,7 +511,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 ""
|
msgstr "Número de contraseñas contra las que verificar."
|
||||||
|
|
||||||
#: authentik/enterprise/policies/unique_password/models.py
|
#: authentik/enterprise/policies/unique_password/models.py
|
||||||
#: authentik/policies/password/models.py
|
#: authentik/policies/password/models.py
|
||||||
@ -521,18 +521,20 @@ msgstr "La contraseña no se ha establecido en 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 ""
|
msgstr ""
|
||||||
|
"Esta contraseña se ha utilizado anteriormente. Por favor, elija una "
|
||||||
|
"diferente."
|
||||||
|
|
||||||
#: authentik/enterprise/policies/unique_password/models.py
|
#: authentik/enterprise/policies/unique_password/models.py
|
||||||
msgid "Password Uniqueness Policy"
|
msgid "Password Uniqueness Policy"
|
||||||
msgstr ""
|
msgstr "Política de Unicidad de Contraseñas"
|
||||||
|
|
||||||
#: authentik/enterprise/policies/unique_password/models.py
|
#: authentik/enterprise/policies/unique_password/models.py
|
||||||
msgid "Password Uniqueness Policies"
|
msgid "Password Uniqueness Policies"
|
||||||
msgstr ""
|
msgstr "Políticas de Unicidad de Contraseñas"
|
||||||
|
|
||||||
#: authentik/enterprise/policies/unique_password/models.py
|
#: authentik/enterprise/policies/unique_password/models.py
|
||||||
msgid "User Password History"
|
msgid "User Password History"
|
||||||
msgstr ""
|
msgstr "Historial de Contraseñas del Usuario"
|
||||||
|
|
||||||
#: authentik/enterprise/policy.py
|
#: authentik/enterprise/policy.py
|
||||||
msgid "Enterprise required to access this feature."
|
msgid "Enterprise required to access this feature."
|
||||||
@ -617,39 +619,39 @@ msgstr "Clave de firma"
|
|||||||
|
|
||||||
#: 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 ""
|
msgstr "Clave utilizada para firmar los eventos SSF."
|
||||||
|
|
||||||
#: authentik/enterprise/providers/ssf/models.py
|
#: authentik/enterprise/providers/ssf/models.py
|
||||||
msgid "Shared Signals Framework Provider"
|
msgid "Shared Signals Framework Provider"
|
||||||
msgstr ""
|
msgstr "Proveedor del Marco de Señales Compartidas"
|
||||||
|
|
||||||
#: authentik/enterprise/providers/ssf/models.py
|
#: authentik/enterprise/providers/ssf/models.py
|
||||||
msgid "Shared Signals Framework Providers"
|
msgid "Shared Signals Framework Providers"
|
||||||
msgstr ""
|
msgstr "Proveedores del Marco de Señales Compartidas"
|
||||||
|
|
||||||
#: 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 ""
|
msgstr "Agregar flujo de datos al proveedor SSF"
|
||||||
|
|
||||||
#: authentik/enterprise/providers/ssf/models.py
|
#: authentik/enterprise/providers/ssf/models.py
|
||||||
msgid "SSF Stream"
|
msgid "SSF Stream"
|
||||||
msgstr ""
|
msgstr "Flujo de Datos SSF"
|
||||||
|
|
||||||
#: authentik/enterprise/providers/ssf/models.py
|
#: authentik/enterprise/providers/ssf/models.py
|
||||||
msgid "SSF Streams"
|
msgid "SSF Streams"
|
||||||
msgstr ""
|
msgstr "Flujos de Datos SSF"
|
||||||
|
|
||||||
#: authentik/enterprise/providers/ssf/models.py
|
#: authentik/enterprise/providers/ssf/models.py
|
||||||
msgid "SSF Stream Event"
|
msgid "SSF Stream Event"
|
||||||
msgstr ""
|
msgstr "Evento de Flujo de Datos SSF"
|
||||||
|
|
||||||
#: authentik/enterprise/providers/ssf/models.py
|
#: authentik/enterprise/providers/ssf/models.py
|
||||||
msgid "SSF Stream Events"
|
msgid "SSF Stream Events"
|
||||||
msgstr ""
|
msgstr "Eventos de Flujos de Datos SSF"
|
||||||
|
|
||||||
#: authentik/enterprise/providers/ssf/tasks.py
|
#: authentik/enterprise/providers/ssf/tasks.py
|
||||||
msgid "Failed to send request"
|
msgid "Failed to send request"
|
||||||
msgstr "Falló envio de petición"
|
msgstr "Error al enviar la solicitud"
|
||||||
|
|
||||||
#: 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"
|
||||||
@ -681,26 +683,29 @@ msgid ""
|
|||||||
"option has a higher priority than the `client_certificate` option on "
|
"option has a higher priority than the `client_certificate` option on "
|
||||||
"`Brand`."
|
"`Brand`."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Configura las autoridades certificadoras para validar el certificado. Esta "
|
||||||
|
"opción tiene una prioridad mayor que la opción `client_certificate` en "
|
||||||
|
"`Brand`."
|
||||||
|
|
||||||
#: authentik/enterprise/stages/mtls/models.py
|
#: authentik/enterprise/stages/mtls/models.py
|
||||||
msgid "Mutual TLS Stage"
|
msgid "Mutual TLS Stage"
|
||||||
msgstr ""
|
msgstr "Etapa de TLS mutuo"
|
||||||
|
|
||||||
#: authentik/enterprise/stages/mtls/models.py
|
#: authentik/enterprise/stages/mtls/models.py
|
||||||
msgid "Mutual TLS Stages"
|
msgid "Mutual TLS Stages"
|
||||||
msgstr ""
|
msgstr "Etapas de TLS mutuo"
|
||||||
|
|
||||||
#: authentik/enterprise/stages/mtls/models.py
|
#: authentik/enterprise/stages/mtls/models.py
|
||||||
msgid "Permissions to pass Certificates for outposts."
|
msgid "Permissions to pass Certificates for outposts."
|
||||||
msgstr ""
|
msgstr "Permisos para pasar Certificados a los puestos avanzados."
|
||||||
|
|
||||||
#: authentik/enterprise/stages/mtls/stage.py
|
#: authentik/enterprise/stages/mtls/stage.py
|
||||||
msgid "Certificate required but no certificate was given."
|
msgid "Certificate required but no certificate was given."
|
||||||
msgstr ""
|
msgstr "Se requiere certificado, pero no se proporcionó ninguno."
|
||||||
|
|
||||||
#: authentik/enterprise/stages/mtls/stage.py
|
#: authentik/enterprise/stages/mtls/stage.py
|
||||||
msgid "No user found for certificate."
|
msgid "No user found for certificate."
|
||||||
msgstr ""
|
msgstr "No se encontró usuario para el certificado."
|
||||||
|
|
||||||
#: authentik/enterprise/stages/source/models.py
|
#: authentik/enterprise/stages/source/models.py
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -753,12 +758,16 @@ 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 ""
|
||||||
|
"Personaliza el cuerpo de la solicitud. El mapeo debe devolver datos que sean"
|
||||||
|
" serializables en 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 ""
|
||||||
|
"Configura encabezados adicionales para enviar. El mapeo debe devolver un "
|
||||||
|
"diccionario de pares clave-valor"
|
||||||
|
|
||||||
#: authentik/events/models.py
|
#: authentik/events/models.py
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -786,7 +795,7 @@ msgstr "Transporte de notificaciones"
|
|||||||
|
|
||||||
#: authentik/events/models.py
|
#: authentik/events/models.py
|
||||||
msgid "Notification Transports"
|
msgid "Notification Transports"
|
||||||
msgstr "Transportes de notificación"
|
msgstr "Medios de Notificación"
|
||||||
|
|
||||||
#: authentik/events/models.py
|
#: authentik/events/models.py
|
||||||
msgid "Notice"
|
msgid "Notice"
|
||||||
@ -813,9 +822,9 @@ msgid ""
|
|||||||
"Select which transports should be used to notify the user. If none are "
|
"Select which transports should be used to notify the user. If none are "
|
||||||
"selected, the notification will only be shown in the authentik UI."
|
"selected, the notification will only be shown in the authentik UI."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Seleccione qué transportes se deben usar para notificar al usuario. Si no se"
|
"Selecciona qué medios se deben usar para notificar al usuario. Si no se "
|
||||||
" selecciona ninguno, la notificación solo se mostrará en la interfaz de "
|
"selecciona ninguno, la notificación solo se mostrará en la interfaz de "
|
||||||
"usuario de authentik."
|
"authentik."
|
||||||
|
|
||||||
#: authentik/events/models.py
|
#: authentik/events/models.py
|
||||||
msgid "Controls which severity level the created notifications will have."
|
msgid "Controls which severity level the created notifications will have."
|
||||||
@ -987,7 +996,7 @@ msgstr "Evalúa políticas durante el proceso de planeación del Flujo."
|
|||||||
|
|
||||||
#: 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 ""
|
msgstr "Evaluar las políticas cuando la Etapa se presenta al usuario."
|
||||||
|
|
||||||
#: authentik/flows/models.py
|
#: authentik/flows/models.py
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -1034,6 +1043,8 @@ msgid ""
|
|||||||
"When enabled, provider will not modify or create objects in the remote "
|
"When enabled, provider will not modify or create objects in the remote "
|
||||||
"system."
|
"system."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Cuando está habilitado, el proveedor no modificará ni creará objetos en el "
|
||||||
|
"sistema remoto."
|
||||||
|
|
||||||
#: authentik/lib/sync/outgoing/tasks.py
|
#: authentik/lib/sync/outgoing/tasks.py
|
||||||
msgid "Starting full provider sync"
|
msgid "Starting full provider sync"
|
||||||
@ -1041,20 +1052,21 @@ msgstr "Iniciando sincronización completa de proveedor"
|
|||||||
|
|
||||||
#: authentik/lib/sync/outgoing/tasks.py
|
#: authentik/lib/sync/outgoing/tasks.py
|
||||||
msgid "Syncing users"
|
msgid "Syncing users"
|
||||||
msgstr ""
|
msgstr "Sincronizando usuarios"
|
||||||
|
|
||||||
#: authentik/lib/sync/outgoing/tasks.py
|
#: authentik/lib/sync/outgoing/tasks.py
|
||||||
msgid "Syncing groups"
|
msgid "Syncing groups"
|
||||||
msgstr ""
|
msgstr "Sincronizando grupos"
|
||||||
|
|
||||||
#: authentik/lib/sync/outgoing/tasks.py
|
#: authentik/lib/sync/outgoing/tasks.py
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Syncing page {page} of groups"
|
msgid "Syncing page {page} of {object_type}"
|
||||||
msgstr "Sincronizando página {page} de grupos"
|
msgstr "Sincronizando página {page} de {object_type}"
|
||||||
|
|
||||||
#: authentik/lib/sync/outgoing/tasks.py
|
#: authentik/lib/sync/outgoing/tasks.py
|
||||||
msgid "Dropping mutating request due to dry run"
|
msgid "Dropping mutating request due to dry run"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Descartando solicitud de mutación debido a ejecución en modo de simulación"
|
||||||
|
|
||||||
#: authentik/lib/sync/outgoing/tasks.py
|
#: authentik/lib/sync/outgoing/tasks.py
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
@ -1233,7 +1245,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: authentik/policies/expiry/models.py
|
#: authentik/policies/expiry/models.py
|
||||||
msgid "Password has expired."
|
msgid "Password has expired."
|
||||||
msgstr "La contraseña ha caducado."
|
msgstr "La contraseña ha expirado."
|
||||||
|
|
||||||
#: authentik/policies/expiry/models.py
|
#: authentik/policies/expiry/models.py
|
||||||
msgid "Password Expiry Policy"
|
msgid "Password Expiry Policy"
|
||||||
@ -1271,7 +1283,7 @@ msgstr "La IP del cliente no está en un país permitido."
|
|||||||
|
|
||||||
#: authentik/policies/geoip/models.py
|
#: authentik/policies/geoip/models.py
|
||||||
msgid "Distance from previous authentication is larger than threshold."
|
msgid "Distance from previous authentication is larger than threshold."
|
||||||
msgstr "La distancia desde la autenticación previa es mayor que el límite."
|
msgstr "La distancia desde la autenticación anterior es mayor que el umbral."
|
||||||
|
|
||||||
#: authentik/policies/geoip/models.py
|
#: authentik/policies/geoip/models.py
|
||||||
msgid "Distance is further than possible."
|
msgid "Distance is further than possible."
|
||||||
@ -1320,7 +1332,7 @@ msgstr "Vinculación de Políticas"
|
|||||||
|
|
||||||
#: authentik/policies/models.py
|
#: authentik/policies/models.py
|
||||||
msgid "Policy Bindings"
|
msgid "Policy Bindings"
|
||||||
msgstr "Vinculaciones de políticas"
|
msgstr "Vinculaciones de Políticas"
|
||||||
|
|
||||||
#: authentik/policies/models.py
|
#: authentik/policies/models.py
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -1594,11 +1606,11 @@ msgstr "ES256 (Encriptación Asimétrica)"
|
|||||||
|
|
||||||
#: authentik/providers/oauth2/models.py
|
#: authentik/providers/oauth2/models.py
|
||||||
msgid "ES384 (Asymmetric Encryption)"
|
msgid "ES384 (Asymmetric Encryption)"
|
||||||
msgstr ""
|
msgstr "ES384 (Encriptación Asimétrica)"
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py
|
#: authentik/providers/oauth2/models.py
|
||||||
msgid "ES512 (Asymmetric Encryption)"
|
msgid "ES512 (Asymmetric Encryption)"
|
||||||
msgstr ""
|
msgstr "ES512 (Encriptación Asimétrica)"
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py
|
#: authentik/providers/oauth2/models.py
|
||||||
msgid "Scope used by the client"
|
msgid "Scope used by the client"
|
||||||
@ -1813,7 +1825,7 @@ msgstr "Valida Certificados SSL de servidores de origen"
|
|||||||
|
|
||||||
#: authentik/providers/proxy/models.py
|
#: authentik/providers/proxy/models.py
|
||||||
msgid "Internal host SSL Validation"
|
msgid "Internal host SSL Validation"
|
||||||
msgstr "Validación SSL de host interno"
|
msgstr "Validación SSL del host interno"
|
||||||
|
|
||||||
#: authentik/providers/proxy/models.py
|
#: authentik/providers/proxy/models.py
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -2027,7 +2039,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: authentik/providers/saml/models.py
|
#: authentik/providers/saml/models.py
|
||||||
msgid "AuthnContextClassRef Property Mapping"
|
msgid "AuthnContextClassRef Property Mapping"
|
||||||
msgstr ""
|
msgstr "Asignación de Propiedades de AuthnContextClassRef"
|
||||||
|
|
||||||
#: authentik/providers/saml/models.py
|
#: authentik/providers/saml/models.py
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -2035,6 +2047,9 @@ msgid ""
|
|||||||
"empty, the AuthnContextClassRef will be set based on which authentication "
|
"empty, the AuthnContextClassRef will be set based on which authentication "
|
||||||
"methods the user used to authenticate."
|
"methods the user used to authenticate."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Configura cómo se creará el valor de AuthnContextClassRef. Si se deja vacío,"
|
||||||
|
" el AuthnContextClassRef se establecerá según los métodos de autenticación "
|
||||||
|
"que el usuario haya utilizado para autenticarse."
|
||||||
|
|
||||||
#: authentik/providers/saml/models.py
|
#: authentik/providers/saml/models.py
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -2184,11 +2199,11 @@ msgstr "Predeterminado"
|
|||||||
|
|
||||||
#: authentik/providers/scim/models.py
|
#: authentik/providers/scim/models.py
|
||||||
msgid "AWS"
|
msgid "AWS"
|
||||||
msgstr ""
|
msgstr "AWS"
|
||||||
|
|
||||||
#: authentik/providers/scim/models.py
|
#: authentik/providers/scim/models.py
|
||||||
msgid "Slack"
|
msgid "Slack"
|
||||||
msgstr ""
|
msgstr "Slack"
|
||||||
|
|
||||||
#: 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"
|
||||||
@ -2200,11 +2215,13 @@ msgstr "Token de Autenticación"
|
|||||||
|
|
||||||
#: authentik/providers/scim/models.py
|
#: authentik/providers/scim/models.py
|
||||||
msgid "SCIM Compatibility Mode"
|
msgid "SCIM Compatibility Mode"
|
||||||
msgstr ""
|
msgstr "Modo de Compatibilidad SCIM"
|
||||||
|
|
||||||
#: 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."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Modificar el comportamiento de authentik para implementaciones SCIM "
|
||||||
|
"específicas de proveedores."
|
||||||
|
|
||||||
#: authentik/providers/scim/models.py
|
#: authentik/providers/scim/models.py
|
||||||
msgid "SCIM Provider"
|
msgid "SCIM Provider"
|
||||||
@ -2232,7 +2249,7 @@ msgstr "Roles"
|
|||||||
|
|
||||||
#: authentik/rbac/models.py
|
#: authentik/rbac/models.py
|
||||||
msgid "Initial Permissions"
|
msgid "Initial Permissions"
|
||||||
msgstr ""
|
msgstr "Permisos Iniciales"
|
||||||
|
|
||||||
#: authentik/rbac/models.py
|
#: authentik/rbac/models.py
|
||||||
msgid "System permission"
|
msgid "System permission"
|
||||||
@ -2270,7 +2287,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: authentik/recovery/views.py
|
#: authentik/recovery/views.py
|
||||||
msgid "Used recovery-link to authenticate."
|
msgid "Used recovery-link to authenticate."
|
||||||
msgstr "Se usó el enlace de recuperación para autenticarse."
|
msgstr "Se utilizó un enlace de recuperación para autenticarse."
|
||||||
|
|
||||||
#: authentik/sources/kerberos/models.py
|
#: authentik/sources/kerberos/models.py
|
||||||
msgid "Kerberos realm"
|
msgid "Kerberos realm"
|
||||||
@ -2282,7 +2299,7 @@ msgstr "krb5.conf personalizado a usar. Usa el del sistema por defecto."
|
|||||||
|
|
||||||
#: authentik/sources/kerberos/models.py
|
#: authentik/sources/kerberos/models.py
|
||||||
msgid "KAdmin server type"
|
msgid "KAdmin server type"
|
||||||
msgstr ""
|
msgstr "Tipo de servidor KAdmin"
|
||||||
|
|
||||||
#: authentik/sources/kerberos/models.py
|
#: authentik/sources/kerberos/models.py
|
||||||
msgid "Sync users from Kerberos into authentik"
|
msgid "Sync users from Kerberos into authentik"
|
||||||
@ -2290,23 +2307,24 @@ msgstr "Sincronizar usuarios desde Kerberos hacia Authentik"
|
|||||||
|
|
||||||
#: authentik/sources/kerberos/models.py
|
#: authentik/sources/kerberos/models.py
|
||||||
msgid "When a user changes their password, sync it back to Kerberos"
|
msgid "When a user changes their password, sync it back to Kerberos"
|
||||||
msgstr "Cuando un usuario cambia su contraseña, sincronizarlo hacia Kerberos"
|
msgstr ""
|
||||||
|
"Cuando un usuario cambie su contraseña, sincronizarla de vuelta a Kerberos."
|
||||||
|
|
||||||
#: authentik/sources/kerberos/models.py
|
#: authentik/sources/kerberos/models.py
|
||||||
msgid "Principal to authenticate to kadmin for sync."
|
msgid "Principal to authenticate to kadmin for sync."
|
||||||
msgstr "Principal para autenticarse como kadmin para la sincronización."
|
msgstr "Principal para autenticarse en kadmin para la sincronización."
|
||||||
|
|
||||||
#: authentik/sources/kerberos/models.py
|
#: authentik/sources/kerberos/models.py
|
||||||
msgid "Password to authenticate to kadmin for sync"
|
msgid "Password to authenticate to kadmin for sync"
|
||||||
msgstr "Contraseña para autenticarse como kadmin para la sincronización"
|
msgstr "Contraseña para autenticarse en kadmin para la sincronización"
|
||||||
|
|
||||||
#: authentik/sources/kerberos/models.py
|
#: authentik/sources/kerberos/models.py
|
||||||
msgid ""
|
msgid ""
|
||||||
"Keytab to authenticate to kadmin for sync. Must be base64-encoded or in the "
|
"Keytab to authenticate to kadmin for sync. Must be base64-encoded or in the "
|
||||||
"form TYPE:residual"
|
"form TYPE:residual"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Keytab para autenticarse como kadmin para la sincronización. Debe estar "
|
"Keytab para autenticarse en kadmin para la sincronización. Debe estar "
|
||||||
"codificado en base64 o en el formato TIPO:residual"
|
"codificado en base64 o en el formato TIPO:residuo"
|
||||||
|
|
||||||
#: authentik/sources/kerberos/models.py
|
#: authentik/sources/kerberos/models.py
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -2322,7 +2340,7 @@ msgid ""
|
|||||||
"HTTP@hostname"
|
"HTTP@hostname"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Forzar el uso de un nombre de servidor específico para SPNEGO. Debe estar en"
|
"Forzar el uso de un nombre de servidor específico para SPNEGO. Debe estar en"
|
||||||
" el formato HTTP@nombredelservidor"
|
" el formato HTTP@nombre_de_host"
|
||||||
|
|
||||||
#: authentik/sources/kerberos/models.py
|
#: authentik/sources/kerberos/models.py
|
||||||
msgid "SPNEGO keytab base64-encoded or path to keytab in the form FILE:path"
|
msgid "SPNEGO keytab base64-encoded or path to keytab in the form FILE:path"
|
||||||
@ -2339,8 +2357,8 @@ msgid ""
|
|||||||
"If enabled, the authentik-stored password will be updated upon login with "
|
"If enabled, the authentik-stored password will be updated upon login with "
|
||||||
"the Kerberos password backend"
|
"the Kerberos password backend"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Si está habilitado, la contraseña almacenada por authentik será actualizada "
|
"Si está habilitado, la contraseña almacenada en authentik se actualizará al "
|
||||||
"al iniciar sesión con el backend de contraseñas Kerberos"
|
"iniciar sesión con el backend de contraseñas de Kerberos."
|
||||||
|
|
||||||
#: authentik/sources/kerberos/models.py
|
#: authentik/sources/kerberos/models.py
|
||||||
msgid "Kerberos Source"
|
msgid "Kerberos Source"
|
||||||
@ -2388,7 +2406,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
" Asegúrate de que tienes entradas válidas\n"
|
" Asegúrate de que tienes entradas válidas\n"
|
||||||
" (se obtienen a través de kinit) \n"
|
" (obtenibles mediante kinit) \n"
|
||||||
" y de haber configurado correctamente el navegador.\n"
|
" y de haber configurado correctamente el navegador.\n"
|
||||||
" Por favor, contacta a tu administrador.\n"
|
" Por favor, contacta a tu administrador.\n"
|
||||||
" "
|
" "
|
||||||
@ -2453,6 +2471,10 @@ msgstr "DN de grupo de adición"
|
|||||||
msgid "Consider Objects matching this filter to be Users."
|
msgid "Consider Objects matching this filter to be Users."
|
||||||
msgstr "Considere que los objetos que coinciden con este filtro son usuarios."
|
msgstr "Considere que los objetos que coinciden con este filtro son usuarios."
|
||||||
|
|
||||||
|
#: authentik/sources/ldap/models.py
|
||||||
|
msgid "Attribute which matches the value of `group_membership_field`."
|
||||||
|
msgstr "Atributo que coincide con el valor de `group_membership_field`."
|
||||||
|
|
||||||
#: authentik/sources/ldap/models.py
|
#: authentik/sources/ldap/models.py
|
||||||
msgid "Field which contains members of a group."
|
msgid "Field which contains members of a group."
|
||||||
msgstr "Campo que contiene los miembros de un grupo."
|
msgstr "Campo que contiene los miembros de un grupo."
|
||||||
@ -2485,12 +2507,17 @@ msgid ""
|
|||||||
"attribute. This allows nested group resolution on systems like FreeIPA and "
|
"attribute. This allows nested group resolution on systems like FreeIPA and "
|
||||||
"Active Directory"
|
"Active Directory"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Buscar la pertenencia a grupos basándose en un atributo del usuario en lugar"
|
||||||
|
" de un atributo del grupo. Esto permite la resolución de grupos anidados en "
|
||||||
|
"sistemas como FreeIPA y Active Directory"
|
||||||
|
|
||||||
#: authentik/sources/ldap/models.py
|
#: authentik/sources/ldap/models.py
|
||||||
msgid ""
|
msgid ""
|
||||||
"Delete authentik users and groups which were previously supplied by this "
|
"Delete authentik users and groups which were previously supplied by this "
|
||||||
"source, but are now missing from it."
|
"source, but are now missing from it."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Eliminar usuarios y grupos de authentik que fueron proporcionados "
|
||||||
|
"previamente por esta fuente, pero que ahora están ausentes."
|
||||||
|
|
||||||
#: authentik/sources/ldap/models.py
|
#: authentik/sources/ldap/models.py
|
||||||
msgid "LDAP Source"
|
msgid "LDAP Source"
|
||||||
@ -2512,22 +2539,24 @@ msgstr "Asignaciones de Propiedades de Fuente de LDAP"
|
|||||||
msgid ""
|
msgid ""
|
||||||
"Unique ID used while checking if this object still exists in the directory."
|
"Unique ID used while checking if this object still exists in the directory."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"ID único utilizado para verificar si este objeto aún existe en el "
|
||||||
|
"directorio."
|
||||||
|
|
||||||
#: authentik/sources/ldap/models.py
|
#: authentik/sources/ldap/models.py
|
||||||
msgid "User LDAP Source Connection"
|
msgid "User LDAP Source Connection"
|
||||||
msgstr ""
|
msgstr "Conexión de Fuente LDAP de Usuario"
|
||||||
|
|
||||||
#: authentik/sources/ldap/models.py
|
#: authentik/sources/ldap/models.py
|
||||||
msgid "User LDAP Source Connections"
|
msgid "User LDAP Source Connections"
|
||||||
msgstr ""
|
msgstr "Conexiones de Fuente LDAP de Usuario"
|
||||||
|
|
||||||
#: authentik/sources/ldap/models.py
|
#: authentik/sources/ldap/models.py
|
||||||
msgid "Group LDAP Source Connection"
|
msgid "Group LDAP Source Connection"
|
||||||
msgstr ""
|
msgstr "Conexión de Fuente LDAP de Grupo"
|
||||||
|
|
||||||
#: authentik/sources/ldap/models.py
|
#: authentik/sources/ldap/models.py
|
||||||
msgid "Group LDAP Source Connections"
|
msgid "Group LDAP Source Connections"
|
||||||
msgstr ""
|
msgstr "Conexiones de Fuente LDAP de Grupo"
|
||||||
|
|
||||||
#: 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."
|
||||||
@ -2539,11 +2568,11 @@ msgstr "No se recibió ningún token."
|
|||||||
|
|
||||||
#: authentik/sources/oauth/models.py
|
#: authentik/sources/oauth/models.py
|
||||||
msgid "HTTP Basic Authentication"
|
msgid "HTTP Basic Authentication"
|
||||||
msgstr ""
|
msgstr "Autenticación Básica HTTP"
|
||||||
|
|
||||||
#: 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"
|
||||||
msgstr ""
|
msgstr "Incluir el ID de cliente y el secreto como parámetros de la solicitud"
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py
|
#: authentik/sources/oauth/models.py
|
||||||
msgid "Request Token URL"
|
msgid "Request Token URL"
|
||||||
@ -2590,6 +2619,8 @@ msgid ""
|
|||||||
"How to perform authentication during an authorization_code token request "
|
"How to perform authentication during an authorization_code token request "
|
||||||
"flow"
|
"flow"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Cómo realizar la autenticación durante un flujo de solicitud de token con "
|
||||||
|
"authorization_code"
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py
|
#: authentik/sources/oauth/models.py
|
||||||
msgid "OAuth Source"
|
msgid "OAuth Source"
|
||||||
@ -2907,7 +2938,7 @@ msgstr "Conexiones de Fuente de SAML de Grupo"
|
|||||||
#: authentik/sources/saml/views.py
|
#: authentik/sources/saml/views.py
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Continue to {source_name}"
|
msgid "Continue to {source_name}"
|
||||||
msgstr ""
|
msgstr "Continuar a {source_name}"
|
||||||
|
|
||||||
#: authentik/sources/scim/models.py
|
#: authentik/sources/scim/models.py
|
||||||
msgid "SCIM Source"
|
msgid "SCIM Source"
|
||||||
@ -2943,7 +2974,7 @@ msgstr "Dispositivos Duo"
|
|||||||
|
|
||||||
#: authentik/stages/authenticator_email/models.py
|
#: authentik/stages/authenticator_email/models.py
|
||||||
msgid "Email OTP"
|
msgid "Email OTP"
|
||||||
msgstr ""
|
msgstr "OTP por Correo Electrónico"
|
||||||
|
|
||||||
#: authentik/stages/authenticator_email/models.py
|
#: authentik/stages/authenticator_email/models.py
|
||||||
#: authentik/stages/email/models.py
|
#: authentik/stages/email/models.py
|
||||||
@ -2964,11 +2995,11 @@ msgstr ""
|
|||||||
|
|
||||||
#: authentik/stages/authenticator_email/models.py
|
#: authentik/stages/authenticator_email/models.py
|
||||||
msgid "Email Authenticator Setup Stage"
|
msgid "Email Authenticator Setup Stage"
|
||||||
msgstr ""
|
msgstr "Etapa de Configuración del Autenticador de Correo Electrónico"
|
||||||
|
|
||||||
#: authentik/stages/authenticator_email/models.py
|
#: authentik/stages/authenticator_email/models.py
|
||||||
msgid "Email Authenticator Setup Stages"
|
msgid "Email Authenticator Setup Stages"
|
||||||
msgstr ""
|
msgstr "Etapas de Configuración del Autenticador de Correo Electrónico"
|
||||||
|
|
||||||
#: authentik/stages/authenticator_email/models.py
|
#: authentik/stages/authenticator_email/models.py
|
||||||
#: authentik/stages/authenticator_email/stage.py
|
#: authentik/stages/authenticator_email/stage.py
|
||||||
@ -2979,11 +3010,11 @@ msgstr ""
|
|||||||
|
|
||||||
#: authentik/stages/authenticator_email/models.py
|
#: authentik/stages/authenticator_email/models.py
|
||||||
msgid "Email Device"
|
msgid "Email Device"
|
||||||
msgstr "Dispositivo de Email"
|
msgstr "Dispositivo de correo electrónico"
|
||||||
|
|
||||||
#: authentik/stages/authenticator_email/models.py
|
#: authentik/stages/authenticator_email/models.py
|
||||||
msgid "Email Devices"
|
msgid "Email Devices"
|
||||||
msgstr "Dispositivos de Email"
|
msgstr "Dispositivos de correo electrónico"
|
||||||
|
|
||||||
#: authentik/stages/authenticator_email/stage.py
|
#: authentik/stages/authenticator_email/stage.py
|
||||||
#: authentik/stages/authenticator_sms/stage.py
|
#: authentik/stages/authenticator_sms/stage.py
|
||||||
@ -2993,7 +3024,7 @@ msgstr "El código no coincide"
|
|||||||
|
|
||||||
#: authentik/stages/authenticator_email/stage.py
|
#: authentik/stages/authenticator_email/stage.py
|
||||||
msgid "Invalid email"
|
msgid "Invalid email"
|
||||||
msgstr "Email Inválido"
|
msgstr "Correo electrónico inválido"
|
||||||
|
|
||||||
#: 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
|
||||||
@ -3013,6 +3044,9 @@ msgid ""
|
|||||||
" Email MFA code.\n"
|
" Email MFA code.\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"\n"
|
||||||
|
" Código MFA por correo electrónico.\n"
|
||||||
|
" "
|
||||||
|
|
||||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -3022,7 +3056,8 @@ msgid ""
|
|||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"Si no solicitaste este código, por favor ignora este correo. El código anterior es válido por %(expires)s."
|
" Si no solicitaste este código, por favor ignora este correo. El código anterior es válido por %(expires)s.\n"
|
||||||
|
" "
|
||||||
|
|
||||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||||
#: authentik/stages/email/templates/email/password_reset.txt
|
#: authentik/stages/email/templates/email/password_reset.txt
|
||||||
@ -3035,6 +3070,8 @@ msgid ""
|
|||||||
"\n"
|
"\n"
|
||||||
"Email MFA code\n"
|
"Email MFA code\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"\n"
|
||||||
|
"Código MFA por correo electrónico\n"
|
||||||
|
|
||||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -3276,8 +3313,8 @@ msgstr "No se pudo validar el token"
|
|||||||
msgid ""
|
msgid ""
|
||||||
"Offset after which consent expires. (Format: hours=1;minutes=2;seconds=3)."
|
"Offset after which consent expires. (Format: hours=1;minutes=2;seconds=3)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Compensación después de la cual caduca el consentimiento. (Formato: horas = "
|
"Desfase después del cual expira el consentimiento. (Formato: "
|
||||||
"1; minutos = 2; segundos = 3)."
|
"hours=1;minutes=2;seconds=3)."
|
||||||
|
|
||||||
#: authentik/stages/consent/models.py
|
#: authentik/stages/consent/models.py
|
||||||
msgid "Consent Stage"
|
msgid "Consent Stage"
|
||||||
@ -3297,7 +3334,7 @@ msgstr "Consentimientos del usuario"
|
|||||||
|
|
||||||
#: authentik/stages/consent/stage.py
|
#: authentik/stages/consent/stage.py
|
||||||
msgid "Invalid consent token, re-showing prompt"
|
msgid "Invalid consent token, re-showing prompt"
|
||||||
msgstr ""
|
msgstr "Token de consentimiento inválido, mostrando el aviso nuevamente"
|
||||||
|
|
||||||
#: authentik/stages/deny/models.py
|
#: authentik/stages/deny/models.py
|
||||||
msgid "Deny Stage"
|
msgid "Deny Stage"
|
||||||
@ -3317,11 +3354,11 @@ msgstr "Etapas ficticias"
|
|||||||
|
|
||||||
#: authentik/stages/email/flow.py
|
#: authentik/stages/email/flow.py
|
||||||
msgid "Continue to confirm this email address."
|
msgid "Continue to confirm this email address."
|
||||||
msgstr ""
|
msgstr "Continúa para confirmar esta dirección de correo electrónico."
|
||||||
|
|
||||||
#: authentik/stages/email/flow.py
|
#: authentik/stages/email/flow.py
|
||||||
msgid "Link was already used, please request a new link."
|
msgid "Link was already used, please request a new link."
|
||||||
msgstr ""
|
msgstr "El enlace ya fue utilizado, por favor, solícita uno nuevo."
|
||||||
|
|
||||||
#: authentik/stages/email/models.py
|
#: authentik/stages/email/models.py
|
||||||
msgid "Password Reset"
|
msgid "Password Reset"
|
||||||
@ -3445,7 +3482,8 @@ msgid ""
|
|||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"Si no solicitaste un cambio de contraseña, por favor ignora este correo. El enlace anterior es válido por %(expires)s."
|
" Si no solicitaste un cambio de contraseña, por favor ignora este correo. El enlace anterior es válido por %(expires)s.\n"
|
||||||
|
" "
|
||||||
|
|
||||||
#: authentik/stages/email/templates/email/password_reset.txt
|
#: authentik/stages/email/templates/email/password_reset.txt
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -3529,24 +3567,26 @@ msgid ""
|
|||||||
"Show the user the 'Remember me on this device' toggle, allowing repeat users"
|
"Show the user the 'Remember me on this device' toggle, allowing repeat users"
|
||||||
" to skip straight to entering their password."
|
" to skip straight to entering their password."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Mostrar al usuario la opción \"Recordarme en este dispositivo\", permitiendo"
|
||||||
|
" que los usuarios recurrentes pasen directamente a ingresar su contraseña."
|
||||||
|
|
||||||
#: 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 ""
|
msgstr ""
|
||||||
"Flujo de inscripción opcional, que está vinculado en la parte inferior de la"
|
"Flujo de inscripción opcional, que se enlaza en la parte inferior de la "
|
||||||
" página."
|
"página."
|
||||||
|
|
||||||
#: authentik/stages/identification/models.py
|
#: authentik/stages/identification/models.py
|
||||||
msgid "Optional recovery flow, which is linked at the bottom of the page."
|
msgid "Optional recovery flow, which is linked at the bottom of the page."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Flujo de recuperación opcional, que está vinculado en la parte inferior de "
|
"Flujo de recuperación opcional, que se enlaza en la parte inferior de la "
|
||||||
"la página."
|
"página."
|
||||||
|
|
||||||
#: authentik/stages/identification/models.py
|
#: authentik/stages/identification/models.py
|
||||||
msgid "Optional passwordless flow, which is linked at the bottom of the page."
|
msgid "Optional passwordless flow, which is linked at the bottom of the page."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Flujo sin contraseña opcional, el cual está vinculado en la parte inferior "
|
"Flujo opcional sin contraseña, que se enlaza en la parte inferior de la "
|
||||||
"de la página."
|
"página."
|
||||||
|
|
||||||
#: authentik/stages/identification/models.py
|
#: authentik/stages/identification/models.py
|
||||||
msgid "Specify which sources should be shown."
|
msgid "Specify which sources should be shown."
|
||||||
@ -3780,11 +3820,11 @@ msgstr "Las contraseñas no coinciden."
|
|||||||
|
|
||||||
#: authentik/stages/redirect/api.py
|
#: authentik/stages/redirect/api.py
|
||||||
msgid "Target URL should be present when mode is Static."
|
msgid "Target URL should be present when mode is Static."
|
||||||
msgstr ""
|
msgstr "La URL de destino debe estar presente cuando el modo es Estático."
|
||||||
|
|
||||||
#: authentik/stages/redirect/api.py
|
#: authentik/stages/redirect/api.py
|
||||||
msgid "Target Flow should be present when mode is Flow."
|
msgid "Target Flow should be present when mode is Flow."
|
||||||
msgstr ""
|
msgstr "El Flujo de Destino debe estar presente cuando el modo es Flujo."
|
||||||
|
|
||||||
#: authentik/stages/redirect/models.py
|
#: authentik/stages/redirect/models.py
|
||||||
msgid "Redirect Stage"
|
msgid "Redirect Stage"
|
||||||
@ -3841,10 +3881,6 @@ msgstr "Etapas de inicio de"
|
|||||||
msgid "No Pending user to login."
|
msgid "No Pending user to login."
|
||||||
msgstr "Ningún usuario pendiente para iniciar sesión."
|
msgstr "Ningún usuario pendiente para iniciar sesión."
|
||||||
|
|
||||||
#: authentik/stages/user_login/stage.py
|
|
||||||
msgid "Successfully logged in!"
|
|
||||||
msgstr "¡Se ha iniciado sesión correctamente!"
|
|
||||||
|
|
||||||
#: authentik/stages/user_logout/models.py
|
#: authentik/stages/user_logout/models.py
|
||||||
msgid "User Logout Stage"
|
msgid "User Logout Stage"
|
||||||
msgstr "Etapa de cierre de sesión del usuario"
|
msgstr "Etapa de cierre de sesión del usuario"
|
||||||
@ -3920,10 +3956,12 @@ 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 ""
|
||||||
|
"La reputación no puede disminuir por debajo de este valor. Cero o negativo."
|
||||||
|
|
||||||
#: 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 ""
|
msgstr ""
|
||||||
|
"La reputación no puede aumentar por encima de este valor. Cero o positivo."
|
||||||
|
|
||||||
#: 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."
|
||||||
@ -3946,8 +3984,8 @@ msgstr "Personificación habilitada/deshabilitada globalmente."
|
|||||||
#: authentik/tenants/models.py
|
#: authentik/tenants/models.py
|
||||||
msgid "Require administrators to provide a reason for impersonating a user."
|
msgid "Require administrators to provide a reason for impersonating a user."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Requerir a los administradores proporcionar una razón para suplantar un "
|
"Requerir que los administradores proporcionen una razón para personificar a "
|
||||||
"usuario."
|
"un usuario."
|
||||||
|
|
||||||
#: authentik/tenants/models.py
|
#: authentik/tenants/models.py
|
||||||
msgid "Default token duration"
|
msgid "Default token duration"
|
||||||
@ -3959,7 +3997,7 @@ msgstr "Longitud predeterminada del token"
|
|||||||
|
|
||||||
#: authentik/tenants/models.py
|
#: authentik/tenants/models.py
|
||||||
msgid "Tenant"
|
msgid "Tenant"
|
||||||
msgstr "inquilino"
|
msgstr "Inquilino"
|
||||||
|
|
||||||
#: authentik/tenants/models.py
|
#: authentik/tenants/models.py
|
||||||
msgid "Tenants"
|
msgid "Tenants"
|
||||||
|
23
manage.py
23
manage.py
@ -1,35 +1,18 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
"""Django manage.py"""
|
"""Django manage.py"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
|
||||||
|
|
||||||
from authentik.lib.config import CONFIG
|
|
||||||
from cryptography.hazmat.backends.openssl.backend import backend
|
|
||||||
from defusedxml import defuse_stdlib
|
|
||||||
from django.utils.autoreload import DJANGO_AUTORELOAD_ENV
|
from django.utils.autoreload import DJANGO_AUTORELOAD_ENV
|
||||||
|
|
||||||
|
from authentik.root.setup import setup
|
||||||
from lifecycle.migrate import run_migrations
|
from lifecycle.migrate import run_migrations
|
||||||
from lifecycle.wait_for_db import wait_for_db
|
from lifecycle.wait_for_db import wait_for_db
|
||||||
|
|
||||||
warnings.filterwarnings("ignore", "SelectableGroups dict interface")
|
setup()
|
||||||
warnings.filterwarnings(
|
|
||||||
"ignore",
|
|
||||||
"defusedxml.lxml is no longer supported and will be removed in a future release.",
|
|
||||||
)
|
|
||||||
warnings.filterwarnings(
|
|
||||||
"ignore",
|
|
||||||
"defusedxml.cElementTree is deprecated, import from defusedxml.ElementTree instead.",
|
|
||||||
)
|
|
||||||
|
|
||||||
defuse_stdlib()
|
|
||||||
|
|
||||||
if CONFIG.get_bool("compliance.fips.enabled", False):
|
|
||||||
backend._enable_fips()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings")
|
|
||||||
wait_for_db()
|
wait_for_db()
|
||||||
if (
|
if (
|
||||||
len(sys.argv) > 1
|
len(sys.argv) > 1
|
||||||
|
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/authentik",
|
"name": "@goauthentik/authentik",
|
||||||
"version": "2025.6.1",
|
"version": "2025.6.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@goauthentik/authentik",
|
"name": "@goauthentik/authentik",
|
||||||
"version": "2025.6.1",
|
"version": "2025.6.2",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/authentik",
|
"name": "@goauthentik/authentik",
|
||||||
"version": "2025.6.1",
|
"version": "2025.6.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
10
packages/docusaurus-config/.prettierignore
Normal file
10
packages/docusaurus-config/.prettierignore
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Prettier Ignorefile
|
||||||
|
|
||||||
|
## Static Files
|
||||||
|
**/LICENSE
|
||||||
|
|
||||||
|
## Build asset directories
|
||||||
|
coverage
|
||||||
|
dist
|
||||||
|
out
|
||||||
|
.docusaurus
|
@ -4,3 +4,5 @@
|
|||||||
|
|
||||||
export * from "./lib/theme.js";
|
export * from "./lib/theme.js";
|
||||||
export * from "./lib/common.js";
|
export * from "./lib/common.js";
|
||||||
|
export * from "./lib/routing.js";
|
||||||
|
export * from "./lib/navbar.js";
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* @file Common Docusaurus configuration utilities.
|
* @file Common Docusaurus configuration utilities.
|
||||||
*
|
*
|
||||||
* @import { Config as DocusaurusConfig } from "@docusaurus/types"
|
* @import { Config, DocusaurusConfig } from "@docusaurus/types"
|
||||||
* @import { UserThemeConfig } from "./theme.js"
|
* @import { UserThemeConfig, UserThemeConfigExtra } from "./theme.js"
|
||||||
*/
|
*/
|
||||||
import { deepmerge } from "deepmerge-ts";
|
import { deepmerge } from "deepmerge-ts";
|
||||||
|
|
||||||
@ -11,14 +11,14 @@ import { createThemeConfig } from "./theme.js";
|
|||||||
//#region Types
|
//#region Types
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Omit<DocusaurusConfig, 'themeConfig'>} DocusaurusConfigBase
|
* @typedef {Omit<Config, 'themeConfig'>} DocusaurusConfigBase
|
||||||
*
|
*
|
||||||
* Represents the base configuration for Docusaurus, excluding the theme configuration.
|
* Represents the base configuration for Docusaurus, excluding the theme configuration.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef DocusaurusConfigBaseTheme
|
* @typedef DocusaurusConfigBaseTheme
|
||||||
* @property {UserThemeConfig} themeConfig The theme configuration.
|
* @property {UserThemeConfig & UserThemeConfigExtra} themeConfig The theme configuration.
|
||||||
*
|
*
|
||||||
* Represents a configuration object, only including the theme configuration.
|
* Represents a configuration object, only including the theme configuration.
|
||||||
*/
|
*/
|
||||||
@ -39,31 +39,66 @@ import { createThemeConfig } from "./theme.js";
|
|||||||
//#region Functions
|
//#region Functions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Docusaurus configuration.
|
* Create a default Docusaurus configuration.
|
||||||
*
|
|
||||||
* @param {DocusaurusConfigInit} [overrides] The options to override.
|
|
||||||
* @returns {DocusaurusConfig}
|
|
||||||
*/
|
*/
|
||||||
export function createDocusaurusConfig({ themeConfig, ...overrides } = {}) {
|
export function createDefaultDocusaurusConfig() {
|
||||||
|
const NodeEnvironment = process.env.AK_DOCUSAURUS_ENV || process.env.NODE_ENV || "development";
|
||||||
|
const production = NodeEnvironment === "production";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {DocusaurusConfig}
|
* @satisfies {Config}
|
||||||
*/
|
*/
|
||||||
const config = {
|
const DEFAULT_CONFIG = /** @type {const} */ ({
|
||||||
|
trailingSlash: true,
|
||||||
|
future: {
|
||||||
|
v4: {
|
||||||
|
removeLegacyPostBuildHeadAttribute: true,
|
||||||
|
useCssCascadeLayers: false,
|
||||||
|
},
|
||||||
|
experimental_faster: {
|
||||||
|
swcJsLoader: true,
|
||||||
|
rspackBundler: true,
|
||||||
|
lightningCssMinimizer: production,
|
||||||
|
swcJsMinimizer: production,
|
||||||
|
swcHtmlMinimizer: production,
|
||||||
|
ssgWorkerThreads: production,
|
||||||
|
mdxCrossCompilerCache: production,
|
||||||
|
rspackPersistentCache: production,
|
||||||
|
},
|
||||||
|
},
|
||||||
title: "authentik",
|
title: "authentik",
|
||||||
tagline: "Bring all of your authentication into a unified platform.",
|
tagline: "Bring all of your authentication into a unified platform.",
|
||||||
url: "https://docs.goauthentik.io",
|
url: "https://docs.goauthentik.io",
|
||||||
baseUrl: "/",
|
baseUrl: "/",
|
||||||
onBrokenLinks: "throw",
|
onBrokenLinks: "throw",
|
||||||
onBrokenAnchors: "throw",
|
onBrokenAnchors: "throw",
|
||||||
|
onBrokenMarkdownLinks: "throw",
|
||||||
|
onDuplicateRoutes: "throw",
|
||||||
favicon: "img/icon.png",
|
favicon: "img/icon.png",
|
||||||
organizationName: "Authentik Security Inc.",
|
organizationName: "Authentik Security Inc.",
|
||||||
projectName: "authentik",
|
projectName: "authentik",
|
||||||
markdown: {
|
markdown: {
|
||||||
mermaid: true,
|
mermaid: true,
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return DEFAULT_CONFIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Docusaurus configuration.
|
||||||
|
*
|
||||||
|
* @template {Partial<Config>} T
|
||||||
|
* @param {T} overrides The options to override.
|
||||||
|
* @returns {T & ReturnType<typeof createDefaultDocusaurusConfig>}
|
||||||
|
*/
|
||||||
|
export function createDocusaurusConfig({ themeConfig, ...overrides }) {
|
||||||
|
const config = {
|
||||||
|
...createDefaultDocusaurusConfig(),
|
||||||
themeConfig: createThemeConfig(themeConfig),
|
themeConfig: createThemeConfig(themeConfig),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
return deepmerge(config, overrides);
|
return deepmerge(config, overrides);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
110
packages/docusaurus-config/lib/navbar.js
Normal file
110
packages/docusaurus-config/lib/navbar.js
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/**
|
||||||
|
* @file Docusaurus navbar configuration for the authentik website.
|
||||||
|
*
|
||||||
|
* @import { NavbarItem } from "@docusaurus/theme-common";
|
||||||
|
*/
|
||||||
|
import { DocusaurusURL, SocialURL } from "./routing.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The navbar items for the authentik website.
|
||||||
|
*
|
||||||
|
* @type {NavbarItem[]}
|
||||||
|
*/
|
||||||
|
export const SocialNavbarItems = /** @type {const} */ ([
|
||||||
|
{
|
||||||
|
"href": SocialURL.GitHub,
|
||||||
|
"data-icon": "github",
|
||||||
|
"aria-label": "GitHub",
|
||||||
|
"position": "right",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": SocialURL.Discord,
|
||||||
|
"data-icon": "discord",
|
||||||
|
"aria-label": "Discord",
|
||||||
|
"position": "right",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The navbar items for the authentik website.
|
||||||
|
*
|
||||||
|
* @satisfies {NavbarItem[]}
|
||||||
|
*/
|
||||||
|
export const NavbarItemsTemplate = /** @type {const} */ ([
|
||||||
|
{
|
||||||
|
to: "{{WWW_URL}}/features",
|
||||||
|
label: "Features",
|
||||||
|
position: "left",
|
||||||
|
target: "_self",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: "{{INTEGRATIONS_URL}}",
|
||||||
|
label: "Integrations",
|
||||||
|
target: "_self",
|
||||||
|
position: "left",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: "{{DOCS_URL}}",
|
||||||
|
|
||||||
|
label: "Documentation",
|
||||||
|
position: "left",
|
||||||
|
target: "_self",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: "{{WWW_URL}}/pricing/",
|
||||||
|
label: "Pricing",
|
||||||
|
position: "left",
|
||||||
|
target: "_self",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: "{{WWW_URL}}/blog",
|
||||||
|
label: "Blog",
|
||||||
|
position: "left",
|
||||||
|
target: "_self",
|
||||||
|
},
|
||||||
|
...SocialNavbarItems,
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} NavbarItemOverrides
|
||||||
|
*
|
||||||
|
* @prop {string} WWW_URL The URL for the WWW environment.
|
||||||
|
* @prop {string} DOCS_URL The URL for the documentation.
|
||||||
|
* @prop {string} INTEGRATIONS_URL The URL for the integrations.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const DEFAULT_NAVBAR_REPLACEMENTS = /** @type {const} */ ({
|
||||||
|
DOCS_URL: DocusaurusURL.Docs,
|
||||||
|
INTEGRATIONS_URL: DocusaurusURL.Integrations,
|
||||||
|
WWW_URL: DocusaurusURL.WWW,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a navbar item array, replacing placeholders with the given replacements.
|
||||||
|
*
|
||||||
|
* @param {Partial<NavbarItemOverrides>} [overrides]
|
||||||
|
* @returns {NavbarItem[]}
|
||||||
|
*/
|
||||||
|
export function createNavbarItems(overrides) {
|
||||||
|
const replacements = {
|
||||||
|
...DEFAULT_NAVBAR_REPLACEMENTS,
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
|
||||||
|
return NavbarItemsTemplate.map((item) => {
|
||||||
|
if (typeof item.to !== "string") return item;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
to: item.to.replace(
|
||||||
|
/{{([^}]+)}}/g,
|
||||||
|
/**
|
||||||
|
* @param {keyof NavbarItemOverrides} key
|
||||||
|
*/
|
||||||
|
(_, key) => {
|
||||||
|
return replacements[key];
|
||||||
|
},
|
||||||
|
),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
35
packages/docusaurus-config/lib/routing.js
Normal file
35
packages/docusaurus-config/lib/routing.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* @file Docusaurus routing configuration.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {'production'|'development'} NodeEnvironment
|
||||||
|
*/
|
||||||
|
|
||||||
|
const NodeEnvironment = /** @type {NodeEnvironment} */ (process.env.NODE_ENV || "development");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @satisfies {Record<NodeEnvironment, Record<string, string>>}
|
||||||
|
*/
|
||||||
|
export const DocusaurusURLByEnvironment = /** @type {const} */ ({
|
||||||
|
development: {
|
||||||
|
Docs: "http://localhost:3000",
|
||||||
|
Integrations: "http://localhost:3001",
|
||||||
|
WWW: "http://localhost:3002",
|
||||||
|
},
|
||||||
|
production: {
|
||||||
|
Docs: "https://docs.goauthentik.io",
|
||||||
|
Integrations: "https://integrations.goauthentik.io",
|
||||||
|
WWW: "https://goauthentik.io",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const DocusaurusURL = DocusaurusURLByEnvironment[NodeEnvironment];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @satisfies {Record<string, string>}
|
||||||
|
*/
|
||||||
|
export const SocialURL = /** @type {const} */ ({
|
||||||
|
Discord: "https://goauthentik.io/discord",
|
||||||
|
GitHub: "https://github.com/goauthentik/authentik",
|
||||||
|
});
|
@ -3,16 +3,26 @@
|
|||||||
*
|
*
|
||||||
* @import { UserThemeConfig as UserThemeConfigCommon } from "@docusaurus/theme-common";
|
* @import { UserThemeConfig as UserThemeConfigCommon } from "@docusaurus/theme-common";
|
||||||
* @import { UserThemeConfig as UserThemeConfigAlgolia } from "@docusaurus/theme-search-algolia";
|
* @import { UserThemeConfig as UserThemeConfigAlgolia } from "@docusaurus/theme-search-algolia";
|
||||||
|
* @import { NavbarItemOverrides } from "./navbar.js"
|
||||||
*/
|
*/
|
||||||
import { deepmerge } from "deepmerge-ts";
|
import { deepmerge } from "deepmerge-ts";
|
||||||
import { themes as prismThemes } from "prism-react-renderer";
|
import { themes as prismThemes } from "prism-react-renderer";
|
||||||
|
|
||||||
|
import { createNavbarItems } from "./navbar.js";
|
||||||
|
|
||||||
//#region Types
|
//#region Types
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combined theme configuration for Docusaurus and Algolia.
|
* @typedef {Object} UserThemeConfigExtra
|
||||||
|
* @property {Partial<NavbarItemOverrides>} [navbarReplacements] The replacements for the navbar.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combined theme configuration for Docusaurus, Algolia, and our own configuration.
|
||||||
*
|
*
|
||||||
* @typedef {UserThemeConfigCommon & UserThemeConfigAlgolia} UserThemeConfig
|
* @typedef {UserThemeConfigCommon & UserThemeConfigAlgolia} UserThemeConfig
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
@ -57,10 +67,10 @@ export function createPrismConfig(overrides = {}) {
|
|||||||
/**
|
/**
|
||||||
* Creates a theme configuration for Docusaurus.
|
* Creates a theme configuration for Docusaurus.
|
||||||
*
|
*
|
||||||
* @param {Partial<UserThemeConfig>} overrides - Overrides for the default theme configuration.
|
* @param {Partial<UserThemeConfig & UserThemeConfigExtra>} overrides - Overrides for the default theme configuration.
|
||||||
* @returns {UserThemeConfig}
|
* @returns {UserThemeConfig}
|
||||||
*/
|
*/
|
||||||
export function createThemeConfig({ prism, ...overrides } = {}) {
|
export function createThemeConfig({ prism, navbarReplacements, ...overrides } = {}) {
|
||||||
/**
|
/**
|
||||||
* @type {UserThemeConfig}
|
* @type {UserThemeConfig}
|
||||||
*/
|
*/
|
||||||
@ -77,6 +87,17 @@ export function createThemeConfig({ prism, ...overrides } = {}) {
|
|||||||
appId: "36ROD0O0FV",
|
appId: "36ROD0O0FV",
|
||||||
apiKey: "727db511300ca9aec5425645bbbddfb5",
|
apiKey: "727db511300ca9aec5425645bbbddfb5",
|
||||||
},
|
},
|
||||||
|
footer: {
|
||||||
|
copyright: `Copyright © ${new Date().getFullYear()} Authentik Security Inc. Built with Docusaurus.`,
|
||||||
|
},
|
||||||
|
navbar: {
|
||||||
|
logo: {
|
||||||
|
alt: "authentik logo",
|
||||||
|
src: "img/icon_left_brand.svg",
|
||||||
|
},
|
||||||
|
|
||||||
|
items: createNavbarItems(navbarReplacements),
|
||||||
|
},
|
||||||
prism: createPrismConfig(prism),
|
prism: createPrismConfig(prism),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
342
packages/docusaurus-config/package-lock.json
generated
342
packages/docusaurus-config/package-lock.json
generated
@ -1,43 +1,51 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/docusaurus-config",
|
"name": "@goauthentik/docusaurus-config",
|
||||||
"version": "2.0.0",
|
"version": "2.1.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@goauthentik/docusaurus-config",
|
"name": "@goauthentik/docusaurus-config",
|
||||||
"version": "2.0.0",
|
"version": "2.1.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"deepmerge-ts": "^7.1.5",
|
"deepmerge-ts": "^7.1.5",
|
||||||
"prism-react-renderer": "^2.4.1"
|
"prism-react-renderer": "^2.4.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/theme-common": "^3.8.0",
|
"@docusaurus/theme-common": "^3.8.1",
|
||||||
"@docusaurus/theme-search-algolia": "^3.8.0",
|
"@docusaurus/theme-search-algolia": "^3.8.1",
|
||||||
"@docusaurus/types": "^3.8.0",
|
"@docusaurus/types": "^3.8.1",
|
||||||
"@goauthentik/prettier-config": "^2.0.0",
|
"@goauthentik/prettier-config": "^2.0.0",
|
||||||
"@goauthentik/tsconfig": "^1.0.4",
|
"@goauthentik/tsconfig": "^1.0.4",
|
||||||
"@types/react": "^19.1.6",
|
"@types/react": "^19.1.6",
|
||||||
"@types/react-dom": "^19.1.5",
|
"@types/react-dom": "^19.1.5",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"react": "^19.1.0",
|
|
||||||
"react-dom": "^19.1.0",
|
|
||||||
"typescript": "^5.8.3"
|
"typescript": "^5.8.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
},
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"react": ">=18",
|
||||||
|
"react-dom": ">=18"
|
||||||
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@docusaurus/theme-common": "^3.8.0",
|
"@docusaurus/theme-common": "^3.8.1",
|
||||||
"@docusaurus/theme-search-algolia": "^3.8.0",
|
"@docusaurus/theme-search-algolia": "^3.8.1",
|
||||||
"@docusaurus/types": "^3.8.0",
|
"@docusaurus/types": "^3.8.0",
|
||||||
"react": "^18.0.0 || ^19.0.0",
|
"react": ">=18",
|
||||||
"react-dom": "^18.0.0 || ^19.0.0"
|
"react-dom": ">=18"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"@docusaurus/theme-search-algolia": {
|
"@docusaurus/theme-search-algolia": {
|
||||||
"optional": true
|
"optional": true
|
||||||
|
},
|
||||||
|
"react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"react-dom": {
|
||||||
|
"optional": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -320,9 +328,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/compat-data": {
|
"node_modules/@babel/compat-data": {
|
||||||
"version": "7.27.3",
|
"version": "7.27.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.5.tgz",
|
||||||
"integrity": "sha512-V42wFfx1ymFte+ecf6iXghnnP8kWTO+ZLXIyZq+1LAXHHvTZdVxicn4yiVYdYMGaCO3tmqub11AorKkv+iodqw==",
|
"integrity": "sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -669,14 +677,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helpers": {
|
"node_modules/@babel/helpers": {
|
||||||
"version": "7.27.4",
|
"version": "7.27.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz",
|
||||||
"integrity": "sha512-Y+bO6U+I7ZKaM5G5rDUZiYfUvQPUibYmAFe7EnKdnKBbVXDZxvp+MWOH5gYciY0EPk4EScsuFMQBbEfpdRKSCQ==",
|
"integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/template": "^7.27.2",
|
"@babel/template": "^7.27.2",
|
||||||
"@babel/types": "^7.27.3"
|
"@babel/types": "^7.27.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@ -958,9 +966,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-transform-block-scoping": {
|
"node_modules/@babel/plugin-transform-block-scoping": {
|
||||||
"version": "7.27.3",
|
"version": "7.27.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.5.tgz",
|
||||||
"integrity": "sha512-+F8CnfhuLhwUACIJMLWnjz6zvzYM2r0yeIHKlbgfw7ml8rOMJsXNXV/hyRcb3nb493gRs4WvYpQAndWj/qQmkQ==",
|
"integrity": "sha512-JF6uE2s67f0y2RZcm2kpAUEbD50vH62TyWVebxwHAlbSdM49VqPz8t4a1uIjp4NIOIZ4xzLfjY5emt/RCyC7TQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -1599,9 +1607,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-transform-regenerator": {
|
"node_modules/@babel/plugin-transform-regenerator": {
|
||||||
"version": "7.27.4",
|
"version": "7.27.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.5.tgz",
|
||||||
"integrity": "sha512-Glp/0n8xuj+E1588otw5rjJkTXfzW7FjH3IIUrfqiZOPQCd2vbg8e+DQE8jK9g4V5/zrxFW+D9WM9gboRPELpQ==",
|
"integrity": "sha512-uhB8yHerfe3MWnuLAhEbeQ4afVoqv8BQsPqrTv7e/jZ9y00kJL6l9a/f4OWaKxotmjzewfEyXE1vgDJenkQ2/Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -2007,9 +2015,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime-corejs3": {
|
"node_modules/@babel/runtime-corejs3": {
|
||||||
"version": "7.27.4",
|
"version": "7.27.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.27.6.tgz",
|
||||||
"integrity": "sha512-H7QhL0ucCGOObsUETNbB2PuzF4gAvN8p32P6r91bX7M/hk4bx+3yz2hTwHL9d/Efzwu1upeb4/cd7oSxCzup3w==",
|
"integrity": "sha512-vDVrlmRAY8z9Ul/HxT+8ceAru95LQgkSKiXkSYZvqtbkPSfhZJgpRp45Cldbh1GJ1kxzQkI70AqyrTI58KpaWQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -2054,9 +2062,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/types": {
|
"node_modules/@babel/types": {
|
||||||
"version": "7.27.3",
|
"version": "7.27.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.6.tgz",
|
||||||
"integrity": "sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw==",
|
"integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -2619,9 +2627,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@csstools/postcss-is-pseudo-class": {
|
"node_modules/@csstools/postcss-is-pseudo-class": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.3.tgz",
|
||||||
"integrity": "sha512-JLp3POui4S1auhDR0n8wHd/zTOWmMsmK3nQd3hhL6FhWPaox5W7j1se6zXOG/aP07wV2ww0lxbKYGwbBszOtfQ==",
|
"integrity": "sha512-jS/TY4SpG4gszAtIg7Qnf3AS2pjcUM5SzxpApOrlndMeGhIbaTzWBzzP/IApXoNWEW7OhcjkRT48jnAUIFXhAQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -3305,9 +3313,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/babel": {
|
"node_modules/@docusaurus/babel": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.8.1.tgz",
|
||||||
"integrity": "sha512-9EJwSgS6TgB8IzGk1L8XddJLhZod8fXT4ULYMx6SKqyCBqCFpVCEjR/hNXXhnmtVM2irDuzYoVLGWv7srG/VOA==",
|
"integrity": "sha512-3brkJrml8vUbn9aeoZUlJfsI/GqyFcDgQJwQkmBtclJgWDEQBKKeagZfOgx0WfUQhagL1sQLNW0iBdxnI863Uw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -3321,8 +3329,8 @@
|
|||||||
"@babel/runtime": "^7.25.9",
|
"@babel/runtime": "^7.25.9",
|
||||||
"@babel/runtime-corejs3": "^7.25.9",
|
"@babel/runtime-corejs3": "^7.25.9",
|
||||||
"@babel/traverse": "^7.25.9",
|
"@babel/traverse": "^7.25.9",
|
||||||
"@docusaurus/logger": "3.8.0",
|
"@docusaurus/logger": "3.8.1",
|
||||||
"@docusaurus/utils": "3.8.0",
|
"@docusaurus/utils": "3.8.1",
|
||||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
@ -3332,31 +3340,31 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/bundler": {
|
"node_modules/@docusaurus/bundler": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.8.1.tgz",
|
||||||
"integrity": "sha512-Rq4Z/MSeAHjVzBLirLeMcjLIAQy92pF1OI+2rmt18fSlMARfTGLWRE8Vb+ljQPTOSfJxwDYSzsK6i7XloD2rNA==",
|
"integrity": "sha512-/z4V0FRoQ0GuSLToNjOSGsk6m2lQUG4FRn8goOVoZSRsTrU8YR2aJacX5K3RG18EaX9b+52pN4m1sL3MQZVsQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.25.9",
|
"@babel/core": "^7.25.9",
|
||||||
"@docusaurus/babel": "3.8.0",
|
"@docusaurus/babel": "3.8.1",
|
||||||
"@docusaurus/cssnano-preset": "3.8.0",
|
"@docusaurus/cssnano-preset": "3.8.1",
|
||||||
"@docusaurus/logger": "3.8.0",
|
"@docusaurus/logger": "3.8.1",
|
||||||
"@docusaurus/types": "3.8.0",
|
"@docusaurus/types": "3.8.1",
|
||||||
"@docusaurus/utils": "3.8.0",
|
"@docusaurus/utils": "3.8.1",
|
||||||
"babel-loader": "^9.2.1",
|
"babel-loader": "^9.2.1",
|
||||||
"clean-css": "^5.3.2",
|
"clean-css": "^5.3.3",
|
||||||
"copy-webpack-plugin": "^11.0.0",
|
"copy-webpack-plugin": "^11.0.0",
|
||||||
"css-loader": "^6.8.1",
|
"css-loader": "^6.11.0",
|
||||||
"css-minimizer-webpack-plugin": "^5.0.1",
|
"css-minimizer-webpack-plugin": "^5.0.1",
|
||||||
"cssnano": "^6.1.2",
|
"cssnano": "^6.1.2",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
"html-minifier-terser": "^7.2.0",
|
"html-minifier-terser": "^7.2.0",
|
||||||
"mini-css-extract-plugin": "^2.9.1",
|
"mini-css-extract-plugin": "^2.9.2",
|
||||||
"null-loader": "^4.0.1",
|
"null-loader": "^4.0.1",
|
||||||
"postcss": "^8.4.26",
|
"postcss": "^8.5.4",
|
||||||
"postcss-loader": "^7.3.3",
|
"postcss-loader": "^7.3.4",
|
||||||
"postcss-preset-env": "^10.1.0",
|
"postcss-preset-env": "^10.2.1",
|
||||||
"terser-webpack-plugin": "^5.3.9",
|
"terser-webpack-plugin": "^5.3.9",
|
||||||
"tslib": "^2.6.0",
|
"tslib": "^2.6.0",
|
||||||
"url-loader": "^4.1.1",
|
"url-loader": "^4.1.1",
|
||||||
@ -3376,19 +3384,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/core": {
|
"node_modules/@docusaurus/core": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.8.1.tgz",
|
||||||
"integrity": "sha512-c7u6zFELmSGPEP9WSubhVDjgnpiHgDqMh1qVdCB7rTflh4Jx0msTYmMiO91Ez0KtHj4sIsDsASnjwfJ2IZp3Vw==",
|
"integrity": "sha512-ENB01IyQSqI2FLtOzqSI3qxG2B/jP4gQPahl2C3XReiLebcVh5B5cB9KYFvdoOqOWPyr5gXK4sjgTKv7peXCrA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/babel": "3.8.0",
|
"@docusaurus/babel": "3.8.1",
|
||||||
"@docusaurus/bundler": "3.8.0",
|
"@docusaurus/bundler": "3.8.1",
|
||||||
"@docusaurus/logger": "3.8.0",
|
"@docusaurus/logger": "3.8.1",
|
||||||
"@docusaurus/mdx-loader": "3.8.0",
|
"@docusaurus/mdx-loader": "3.8.1",
|
||||||
"@docusaurus/utils": "3.8.0",
|
"@docusaurus/utils": "3.8.1",
|
||||||
"@docusaurus/utils-common": "3.8.0",
|
"@docusaurus/utils-common": "3.8.1",
|
||||||
"@docusaurus/utils-validation": "3.8.0",
|
"@docusaurus/utils-validation": "3.8.1",
|
||||||
"boxen": "^6.2.1",
|
"boxen": "^6.2.1",
|
||||||
"chalk": "^4.1.2",
|
"chalk": "^4.1.2",
|
||||||
"chokidar": "^3.5.3",
|
"chokidar": "^3.5.3",
|
||||||
@ -3438,14 +3446,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/cssnano-preset": {
|
"node_modules/@docusaurus/cssnano-preset": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.8.1.tgz",
|
||||||
"integrity": "sha512-UJ4hAS2T0R4WNy+phwVff2Q0L5+RXW9cwlH6AEphHR5qw3m/yacfWcSK7ort2pMMbDn8uGrD38BTm4oLkuuNoQ==",
|
"integrity": "sha512-G7WyR2N6SpyUotqhGznERBK+x84uyhfMQM2MmDLs88bw4Flom6TY46HzkRkSEzaP9j80MbTN8naiL1fR17WQug==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cssnano-preset-advanced": "^6.1.2",
|
"cssnano-preset-advanced": "^6.1.2",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.5.4",
|
||||||
"postcss-sort-media-queries": "^5.2.0",
|
"postcss-sort-media-queries": "^5.2.0",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
},
|
},
|
||||||
@ -3454,9 +3462,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/logger": {
|
"node_modules/@docusaurus/logger": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.8.1.tgz",
|
||||||
"integrity": "sha512-7eEMaFIam5Q+v8XwGqF/n0ZoCld4hV4eCCgQkfcN9Mq5inoZa6PHHW9Wu6lmgzoK5Kx3keEeABcO2SxwraoPDQ==",
|
"integrity": "sha512-2wjeGDhKcExEmjX8k1N/MRDiPKXGF2Pg+df/bDDPnnJWHXnVEZxXj80d6jcxp1Gpnksl0hF8t/ZQw9elqj2+ww==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -3468,15 +3476,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/mdx-loader": {
|
"node_modules/@docusaurus/mdx-loader": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.8.1.tgz",
|
||||||
"integrity": "sha512-mDPSzssRnpjSdCGuv7z2EIAnPS1MHuZGTaRLwPn4oQwszu4afjWZ/60sfKjTnjBjI8Vl4OgJl2vMmfmiNDX4Ng==",
|
"integrity": "sha512-DZRhagSFRcEq1cUtBMo4TKxSNo/W6/s44yhr8X+eoXqCLycFQUylebOMPseHi5tc4fkGJqwqpWJLz6JStU9L4w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/logger": "3.8.0",
|
"@docusaurus/logger": "3.8.1",
|
||||||
"@docusaurus/utils": "3.8.0",
|
"@docusaurus/utils": "3.8.1",
|
||||||
"@docusaurus/utils-validation": "3.8.0",
|
"@docusaurus/utils-validation": "3.8.1",
|
||||||
"@mdx-js/mdx": "^3.0.0",
|
"@mdx-js/mdx": "^3.0.0",
|
||||||
"@slorber/remark-comment": "^1.0.0",
|
"@slorber/remark-comment": "^1.0.0",
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
@ -3508,13 +3516,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/module-type-aliases": {
|
"node_modules/@docusaurus/module-type-aliases": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.8.1.tgz",
|
||||||
"integrity": "sha512-/uMb4Ipt5J/QnD13MpnoC/A4EYAe6DKNWqTWLlGrqsPJwJv73vSwkA25xnYunwfqWk0FlUQfGv/Swdh5eCCg7g==",
|
"integrity": "sha512-6xhvAJiXzsaq3JdosS7wbRt/PwEPWHr9eM4YNYqVlbgG1hSK3uQDXTVvQktasp3VO6BmfYWPozueLWuj4gB+vg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/types": "3.8.0",
|
"@docusaurus/types": "3.8.1",
|
||||||
"@types/history": "^4.7.11",
|
"@types/history": "^4.7.11",
|
||||||
"@types/react": "*",
|
"@types/react": "*",
|
||||||
"@types/react-router-config": "*",
|
"@types/react-router-config": "*",
|
||||||
@ -3528,21 +3536,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/plugin-content-docs": {
|
"node_modules/@docusaurus/plugin-content-docs": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.8.1.tgz",
|
||||||
"integrity": "sha512-fRDMFLbUN6eVRXcjP8s3Y7HpAt9pzPYh1F/7KKXOCxvJhjjCtbon4VJW0WndEPInVz4t8QUXn5QZkU2tGVCE2g==",
|
"integrity": "sha512-oByRkSZzeGNQByCMaX+kif5Nl2vmtj2IHQI2fWjCfCootsdKZDPFLonhIp5s3IGJO7PLUfe0POyw0Xh/RrGXJA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.8.0",
|
"@docusaurus/core": "3.8.1",
|
||||||
"@docusaurus/logger": "3.8.0",
|
"@docusaurus/logger": "3.8.1",
|
||||||
"@docusaurus/mdx-loader": "3.8.0",
|
"@docusaurus/mdx-loader": "3.8.1",
|
||||||
"@docusaurus/module-type-aliases": "3.8.0",
|
"@docusaurus/module-type-aliases": "3.8.1",
|
||||||
"@docusaurus/theme-common": "3.8.0",
|
"@docusaurus/theme-common": "3.8.1",
|
||||||
"@docusaurus/types": "3.8.0",
|
"@docusaurus/types": "3.8.1",
|
||||||
"@docusaurus/utils": "3.8.0",
|
"@docusaurus/utils": "3.8.1",
|
||||||
"@docusaurus/utils-common": "3.8.0",
|
"@docusaurus/utils-common": "3.8.1",
|
||||||
"@docusaurus/utils-validation": "3.8.0",
|
"@docusaurus/utils-validation": "3.8.1",
|
||||||
"@types/react-router-config": "^5.0.7",
|
"@types/react-router-config": "^5.0.7",
|
||||||
"combine-promises": "^1.1.0",
|
"combine-promises": "^1.1.0",
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
@ -3562,16 +3570,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/theme-common": {
|
"node_modules/@docusaurus/theme-common": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.8.1.tgz",
|
||||||
"integrity": "sha512-YqV2vAWpXGLA+A3PMLrOMtqgTHJLDcT+1Caa6RF7N4/IWgrevy5diY8oIHFkXR/eybjcrFFjUPrHif8gSGs3Tw==",
|
"integrity": "sha512-UswMOyTnPEVRvN5Qzbo+l8k4xrd5fTFu2VPPfD6FcW/6qUtVLmJTQCktbAL3KJ0BVXGm5aJXz/ZrzqFuZERGPw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/mdx-loader": "3.8.0",
|
"@docusaurus/mdx-loader": "3.8.1",
|
||||||
"@docusaurus/module-type-aliases": "3.8.0",
|
"@docusaurus/module-type-aliases": "3.8.1",
|
||||||
"@docusaurus/utils": "3.8.0",
|
"@docusaurus/utils": "3.8.1",
|
||||||
"@docusaurus/utils-common": "3.8.0",
|
"@docusaurus/utils-common": "3.8.1",
|
||||||
"@types/history": "^4.7.11",
|
"@types/history": "^4.7.11",
|
||||||
"@types/react": "*",
|
"@types/react": "*",
|
||||||
"@types/react-router-config": "*",
|
"@types/react-router-config": "*",
|
||||||
@ -3591,20 +3599,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/theme-search-algolia": {
|
"node_modules/@docusaurus/theme-search-algolia": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.8.1.tgz",
|
||||||
"integrity": "sha512-GBZ5UOcPgiu6nUw153+0+PNWvFKweSnvKIL6Rp04H9olKb475jfKjAwCCtju5D2xs5qXHvCMvzWOg5o9f6DtuQ==",
|
"integrity": "sha512-NBFH5rZVQRAQM087aYSRKQ9yGEK9eHd+xOxQjqNpxMiV85OhJDD4ZGz6YJIod26Fbooy54UWVdzNU0TFeUUUzQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docsearch/react": "^3.9.0",
|
"@docsearch/react": "^3.9.0",
|
||||||
"@docusaurus/core": "3.8.0",
|
"@docusaurus/core": "3.8.1",
|
||||||
"@docusaurus/logger": "3.8.0",
|
"@docusaurus/logger": "3.8.1",
|
||||||
"@docusaurus/plugin-content-docs": "3.8.0",
|
"@docusaurus/plugin-content-docs": "3.8.1",
|
||||||
"@docusaurus/theme-common": "3.8.0",
|
"@docusaurus/theme-common": "3.8.1",
|
||||||
"@docusaurus/theme-translations": "3.8.0",
|
"@docusaurus/theme-translations": "3.8.1",
|
||||||
"@docusaurus/utils": "3.8.0",
|
"@docusaurus/utils": "3.8.1",
|
||||||
"@docusaurus/utils-validation": "3.8.0",
|
"@docusaurus/utils-validation": "3.8.1",
|
||||||
"algoliasearch": "^5.17.1",
|
"algoliasearch": "^5.17.1",
|
||||||
"algoliasearch-helper": "^3.22.6",
|
"algoliasearch-helper": "^3.22.6",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
@ -3623,9 +3631,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/theme-translations": {
|
"node_modules/@docusaurus/theme-translations": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.8.1.tgz",
|
||||||
"integrity": "sha512-1DTy/snHicgkCkryWq54fZvsAglTdjTx4qjOXgqnXJ+DIty1B+aPQrAVUu8LiM+6BiILfmNxYsxhKTj+BS3PZg==",
|
"integrity": "sha512-OTp6eebuMcf2rJt4bqnvuwmm3NVXfzfYejL+u/Y1qwKhZPrjPoKWfk1CbOP5xH5ZOPkiAsx4dHdQBRJszK3z2g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -3637,9 +3645,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/types": {
|
"node_modules/@docusaurus/types": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.8.1.tgz",
|
||||||
"integrity": "sha512-RDEClpwNxZq02c+JlaKLWoS13qwWhjcNsi2wG1UpzmEnuti/z1Wx4SGpqbUqRPNSd8QWWePR8Cb7DvG0VN/TtA==",
|
"integrity": "sha512-ZPdW5AB+pBjiVrcLuw3dOS6BFlrG0XkS2lDGsj8TizcnREQg3J8cjsgfDviszOk4CweNfwo1AEELJkYaMUuOPg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -3674,15 +3682,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/utils": {
|
"node_modules/@docusaurus/utils": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.8.1.tgz",
|
||||||
"integrity": "sha512-2wvtG28ALCN/A1WCSLxPASFBFzXCnP0YKCAFIPcvEb6imNu1wg7ni/Svcp71b3Z2FaOFFIv4Hq+j4gD7gA0yfQ==",
|
"integrity": "sha512-P1ml0nvOmEFdmu0smSXOqTS1sxU5tqvnc0dA4MTKV39kye+bhQnjkIKEE18fNOvxjyB86k8esoCIFM3x4RykOQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/logger": "3.8.0",
|
"@docusaurus/logger": "3.8.1",
|
||||||
"@docusaurus/types": "3.8.0",
|
"@docusaurus/types": "3.8.1",
|
||||||
"@docusaurus/utils-common": "3.8.0",
|
"@docusaurus/utils-common": "3.8.1",
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
"execa": "5.1.1",
|
"execa": "5.1.1",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
@ -3707,13 +3715,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/utils-common": {
|
"node_modules/@docusaurus/utils-common": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.8.1.tgz",
|
||||||
"integrity": "sha512-3TGF+wVTGgQ3pAc9+5jVchES4uXUAhAt9pwv7uws4mVOxL4alvU3ue/EZ+R4XuGk94pDy7CNXjRXpPjlfZXQfw==",
|
"integrity": "sha512-zTZiDlvpvoJIrQEEd71c154DkcriBecm4z94OzEE9kz7ikS3J+iSlABhFXM45mZ0eN5pVqqr7cs60+ZlYLewtg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/types": "3.8.0",
|
"@docusaurus/types": "3.8.1",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -3721,15 +3729,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/utils-validation": {
|
"node_modules/@docusaurus/utils-validation": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.8.1.tgz",
|
||||||
"integrity": "sha512-MrnEbkigr54HkdFeg8e4FKc4EF+E9dlVwsY3XQZsNkbv3MKZnbHQ5LsNJDIKDROFe8PBf5C4qCAg5TPBpsjrjg==",
|
"integrity": "sha512-gs5bXIccxzEbyVecvxg6upTwaUbfa0KMmTj7HhHzc016AGyxH2o73k1/aOD0IFrdCsfJNt37MqNI47s2MgRZMA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/logger": "3.8.0",
|
"@docusaurus/logger": "3.8.1",
|
||||||
"@docusaurus/utils": "3.8.0",
|
"@docusaurus/utils": "3.8.1",
|
||||||
"@docusaurus/utils-common": "3.8.0",
|
"@docusaurus/utils-common": "3.8.1",
|
||||||
"fs-extra": "^11.2.0",
|
"fs-extra": "^11.2.0",
|
||||||
"joi": "^17.9.2",
|
"joi": "^17.9.2",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
@ -5402,9 +5410,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/browserslist": {
|
"node_modules/browserslist": {
|
||||||
"version": "4.24.5",
|
"version": "4.25.0",
|
||||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz",
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz",
|
||||||
"integrity": "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==",
|
"integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -5422,8 +5430,8 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"caniuse-lite": "^1.0.30001716",
|
"caniuse-lite": "^1.0.30001718",
|
||||||
"electron-to-chromium": "^1.5.149",
|
"electron-to-chromium": "^1.5.160",
|
||||||
"node-releases": "^2.0.19",
|
"node-releases": "^2.0.19",
|
||||||
"update-browserslist-db": "^1.1.3"
|
"update-browserslist-db": "^1.1.3"
|
||||||
},
|
},
|
||||||
@ -6177,13 +6185,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/core-js-compat": {
|
"node_modules/core-js-compat": {
|
||||||
"version": "3.42.0",
|
"version": "3.43.0",
|
||||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.42.0.tgz",
|
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.43.0.tgz",
|
||||||
"integrity": "sha512-bQasjMfyDGyaeWKBIu33lHh9qlSR0MFE/Nmc6nMjf/iU9b3rSMdAYz1Baxrv4lPdGUsTqZudHA4jIGSJy0SWZQ==",
|
"integrity": "sha512-2GML2ZsCc5LR7hZYz4AXmjQw8zuy2T//2QntwdnpuYI7jteT6GVYJL7F6C2C57R7gSYrcqVW3lAALefdbhBLDA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"browserslist": "^4.24.4"
|
"browserslist": "^4.25.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@ -6191,9 +6199,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/core-js-pure": {
|
"node_modules/core-js-pure": {
|
||||||
"version": "3.42.0",
|
"version": "3.43.0",
|
||||||
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.42.0.tgz",
|
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.43.0.tgz",
|
||||||
"integrity": "sha512-007bM04u91fF4kMgwom2I5cQxAFIy8jVulgr9eozILl/SZE53QOqnW/+vviC+wQWLv+AunBG+8Q0TLoeSsSxRQ==",
|
"integrity": "sha512-i/AgxU2+A+BbJdMxh3v7/vxi2SbFqxiFmg6VsDwYB4jkucrd1BZNA9a9gphC0fYMG5IBSgQcbQnk865VCLe7xA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -7140,9 +7148,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.5.155",
|
"version": "1.5.170",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.155.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.170.tgz",
|
||||||
"integrity": "sha512-ps5KcGGmwL8VaeJlvlDlu4fORQpv3+GIcF5I3f9tUKUlJ/wsysh6HU8P5L1XWRYeXfA0oJd4PyM8ds8zTFf6Ng==",
|
"integrity": "sha512-GP+M7aeluQo9uAyiTCxgIj/j+PrWhMlY7LFVj8prlsPljd0Fdg9AprlfUi+OCSFWy9Y5/2D/Jrj9HS8Z4rpKWA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
@ -13119,9 +13127,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.4",
|
"version": "8.5.6",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||||
"integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==",
|
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -13370,9 +13378,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-custom-properties": {
|
"node_modules/postcss-custom-properties": {
|
||||||
"version": "14.0.5",
|
"version": "14.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-14.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-14.0.6.tgz",
|
||||||
"integrity": "sha512-UWf/vhMapZatv+zOuqlfLmYXeOhhHLh8U8HAKGI2VJ00xLRYoAJh4xv8iX6FB6+TLXeDnm0DBLMi00E0hodbQw==",
|
"integrity": "sha512-fTYSp3xuk4BUeVhxCSJdIPhDLpJfNakZKoiTDx7yRGCdlZrSJR7mWKVOBS4sBF+5poPQFMj2YdXx1VHItBGihQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -14010,9 +14018,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-nesting": {
|
"node_modules/postcss-nesting": {
|
||||||
"version": "13.0.1",
|
"version": "13.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-13.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-13.0.2.tgz",
|
||||||
"integrity": "sha512-VbqqHkOBOt4Uu3G8Dm8n6lU5+9cJFxiuty9+4rcoyRPO9zZS1JIs6td49VIoix3qYqELHlJIn46Oih9SAKo+yQ==",
|
"integrity": "sha512-1YCI290TX+VP0U/K/aFxzHzQWHWURL+CtHMSbex1lCdpXD1SoR2sYuxDu5aNI9lPoXpKTCggFZiDJbwylU0LEQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -14026,7 +14034,7 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT-0",
|
"license": "MIT-0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@csstools/selector-resolve-nested": "^3.0.0",
|
"@csstools/selector-resolve-nested": "^3.1.0",
|
||||||
"@csstools/selector-specificity": "^5.0.0",
|
"@csstools/selector-specificity": "^5.0.0",
|
||||||
"postcss-selector-parser": "^7.0.0"
|
"postcss-selector-parser": "^7.0.0"
|
||||||
},
|
},
|
||||||
@ -14038,9 +14046,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-nesting/node_modules/@csstools/selector-resolve-nested": {
|
"node_modules/postcss-nesting/node_modules/@csstools/selector-resolve-nested": {
|
||||||
"version": "3.0.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.1.0.tgz",
|
||||||
"integrity": "sha512-ZoK24Yku6VJU1gS79a5PFmC8yn3wIapiKmPgun0hZgEI5AOqgH2kiPRsPz1qkGv4HL+wuDLH83yQyk6inMYrJQ==",
|
"integrity": "sha512-mf1LEW0tJLKfWyvn5KdDrhpxHyuxpbNwTIwOYLIvsTffeyOf85j5oIzfG0yosxDgx/sswlqBnESYUcQH0vgZ0g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -14342,9 +14350,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-preset-env": {
|
"node_modules/postcss-preset-env": {
|
||||||
"version": "10.2.0",
|
"version": "10.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-10.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-10.2.3.tgz",
|
||||||
"integrity": "sha512-cl13sPBbSqo1Q7Ryb19oT5NZO5IHFolRbIMdgDq4f9w1MHYiL6uZS7uSsjXJ1KzRIcX5BMjEeyxmAevVXENa3Q==",
|
"integrity": "sha512-zlQN1yYmA7lFeM1wzQI14z97mKoM8qGng+198w1+h6sCud/XxOjcKtApY9jWr7pXNS3yHDEafPlClSsWnkY8ow==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -14370,7 +14378,7 @@
|
|||||||
"@csstools/postcss-hwb-function": "^4.0.10",
|
"@csstools/postcss-hwb-function": "^4.0.10",
|
||||||
"@csstools/postcss-ic-unit": "^4.0.2",
|
"@csstools/postcss-ic-unit": "^4.0.2",
|
||||||
"@csstools/postcss-initial": "^2.0.1",
|
"@csstools/postcss-initial": "^2.0.1",
|
||||||
"@csstools/postcss-is-pseudo-class": "^5.0.1",
|
"@csstools/postcss-is-pseudo-class": "^5.0.3",
|
||||||
"@csstools/postcss-light-dark-function": "^2.0.9",
|
"@csstools/postcss-light-dark-function": "^2.0.9",
|
||||||
"@csstools/postcss-logical-float-and-clear": "^3.0.0",
|
"@csstools/postcss-logical-float-and-clear": "^3.0.0",
|
||||||
"@csstools/postcss-logical-overflow": "^2.0.0",
|
"@csstools/postcss-logical-overflow": "^2.0.0",
|
||||||
@ -14392,7 +14400,7 @@
|
|||||||
"@csstools/postcss-trigonometric-functions": "^4.0.9",
|
"@csstools/postcss-trigonometric-functions": "^4.0.9",
|
||||||
"@csstools/postcss-unset-value": "^4.0.0",
|
"@csstools/postcss-unset-value": "^4.0.0",
|
||||||
"autoprefixer": "^10.4.21",
|
"autoprefixer": "^10.4.21",
|
||||||
"browserslist": "^4.24.5",
|
"browserslist": "^4.25.0",
|
||||||
"css-blank-pseudo": "^7.0.1",
|
"css-blank-pseudo": "^7.0.1",
|
||||||
"css-has-pseudo": "^7.0.2",
|
"css-has-pseudo": "^7.0.2",
|
||||||
"css-prefers-color-scheme": "^10.0.0",
|
"css-prefers-color-scheme": "^10.0.0",
|
||||||
@ -14403,7 +14411,7 @@
|
|||||||
"postcss-color-hex-alpha": "^10.0.0",
|
"postcss-color-hex-alpha": "^10.0.0",
|
||||||
"postcss-color-rebeccapurple": "^10.0.0",
|
"postcss-color-rebeccapurple": "^10.0.0",
|
||||||
"postcss-custom-media": "^11.0.6",
|
"postcss-custom-media": "^11.0.6",
|
||||||
"postcss-custom-properties": "^14.0.5",
|
"postcss-custom-properties": "^14.0.6",
|
||||||
"postcss-custom-selectors": "^8.0.5",
|
"postcss-custom-selectors": "^8.0.5",
|
||||||
"postcss-dir-pseudo-class": "^9.0.1",
|
"postcss-dir-pseudo-class": "^9.0.1",
|
||||||
"postcss-double-position-gradients": "^6.0.2",
|
"postcss-double-position-gradients": "^6.0.2",
|
||||||
@ -14414,7 +14422,7 @@
|
|||||||
"postcss-image-set-function": "^7.0.0",
|
"postcss-image-set-function": "^7.0.0",
|
||||||
"postcss-lab-function": "^7.0.10",
|
"postcss-lab-function": "^7.0.10",
|
||||||
"postcss-logical": "^8.1.0",
|
"postcss-logical": "^8.1.0",
|
||||||
"postcss-nesting": "^13.0.1",
|
"postcss-nesting": "^13.0.2",
|
||||||
"postcss-opacity-percentage": "^3.0.0",
|
"postcss-opacity-percentage": "^3.0.0",
|
||||||
"postcss-overflow-shorthand": "^6.0.0",
|
"postcss-overflow-shorthand": "^6.0.0",
|
||||||
"postcss-page-break": "^3.0.4",
|
"postcss-page-break": "^3.0.4",
|
||||||
@ -14989,7 +14997,7 @@
|
|||||||
"version": "19.1.0",
|
"version": "19.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
|
||||||
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
|
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.26.0"
|
"scheduler": "^0.26.0"
|
||||||
@ -15788,7 +15796,7 @@
|
|||||||
"version": "0.26.0",
|
"version": "0.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
|
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
|
||||||
"integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==",
|
"integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/schema-dts": {
|
"node_modules/schema-dts": {
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/docusaurus-config",
|
"name": "@goauthentik/docusaurus-config",
|
||||||
"version": "2.0.0",
|
"version": "2.1.1",
|
||||||
"description": "authentik's Docusaurus config",
|
"description": "authentik's Docusaurus config",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc -p ."
|
"build": "tsc -p .",
|
||||||
|
"prettier": "prettier --write .",
|
||||||
|
"prettier-check": "prettier --check ."
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
@ -20,24 +22,26 @@
|
|||||||
"prism-react-renderer": "^2.4.1"
|
"prism-react-renderer": "^2.4.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/theme-common": "^3.8.0",
|
"@docusaurus/theme-common": "^3.8.1",
|
||||||
"@docusaurus/theme-search-algolia": "^3.8.0",
|
"@docusaurus/theme-search-algolia": "^3.8.1",
|
||||||
"@docusaurus/types": "^3.8.0",
|
"@docusaurus/types": "^3.8.1",
|
||||||
"@goauthentik/prettier-config": "^2.0.0",
|
"@goauthentik/prettier-config": "^2.0.0",
|
||||||
"@goauthentik/tsconfig": "^1.0.4",
|
"@goauthentik/tsconfig": "^1.0.4",
|
||||||
"@types/react": "^19.1.6",
|
"@types/react": "^19.1.6",
|
||||||
"@types/react-dom": "^19.1.5",
|
"@types/react-dom": "^19.1.5",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"react": "^19.1.0",
|
|
||||||
"react-dom": "^19.1.0",
|
|
||||||
"typescript": "^5.8.3"
|
"typescript": "^5.8.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@docusaurus/theme-common": "^3.8.0",
|
"@docusaurus/theme-common": "^3.8.1",
|
||||||
"@docusaurus/theme-search-algolia": "^3.8.0",
|
"@docusaurus/theme-search-algolia": "^3.8.1",
|
||||||
"@docusaurus/types": "^3.8.0",
|
"@docusaurus/types": "^3.8.0",
|
||||||
"react": "^18.0.0 || ^19.0.0",
|
"react": ">=18",
|
||||||
"react-dom": "^18.0.0 || ^19.0.0"
|
"react-dom": ">=18"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"react": ">=18",
|
||||||
|
"react-dom": ">=18"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
@ -53,6 +57,12 @@
|
|||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"@docusaurus/theme-search-algolia": {
|
"@docusaurus/theme-search-algolia": {
|
||||||
"optional": true
|
"optional": true
|
||||||
|
},
|
||||||
|
"react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"react-dom": {
|
||||||
|
"optional": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
182
packages/eslint-config/package-lock.json
generated
182
packages/eslint-config/package-lock.json
generated
@ -216,9 +216,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/config-array": {
|
"node_modules/@eslint/config-array": {
|
||||||
"version": "0.20.0",
|
"version": "0.20.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.1.tgz",
|
||||||
"integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==",
|
"integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint/object-schema": "^2.1.6",
|
"@eslint/object-schema": "^2.1.6",
|
||||||
@ -274,9 +274,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "9.28.0",
|
"version": "9.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.29.0.tgz",
|
||||||
"integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==",
|
"integrity": "sha512-3PIF4cBw/y+1u2EazflInpV+lYsSG0aByVIQzAgb1m1MhHFSbqTyNqtBKHgWf/9Ykud+DhILS9EGkmekVhbKoQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@ -576,17 +576,17 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.1.tgz",
|
||||||
"integrity": "sha512-QXwAlHlbcAwNlEEMKQS2RCgJsgXrTJdjXT08xEgbPFa2yYQgVjBymxP5DrfrE7X7iodSzd9qBUHUycdyVJTW1w==",
|
"integrity": "sha512-STXcN6ebF6li4PxwNeFnqF8/2BNDvBupf2OPx2yWNzr6mKNGF7q49VM00Pz5FaomJyqvbXpY6PhO+T9w139YEQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.10.0",
|
"@eslint-community/regexpp": "^4.10.0",
|
||||||
"@typescript-eslint/scope-manager": "8.34.0",
|
"@typescript-eslint/scope-manager": "8.34.1",
|
||||||
"@typescript-eslint/type-utils": "8.34.0",
|
"@typescript-eslint/type-utils": "8.34.1",
|
||||||
"@typescript-eslint/utils": "8.34.0",
|
"@typescript-eslint/utils": "8.34.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^7.0.0",
|
"ignore": "^7.0.0",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
@ -600,7 +600,7 @@
|
|||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@typescript-eslint/parser": "^8.34.0",
|
"@typescript-eslint/parser": "^8.34.1",
|
||||||
"eslint": "^8.57.0 || ^9.0.0",
|
"eslint": "^8.57.0 || ^9.0.0",
|
||||||
"typescript": ">=4.8.4 <5.9.0"
|
"typescript": ">=4.8.4 <5.9.0"
|
||||||
}
|
}
|
||||||
@ -616,16 +616,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.1.tgz",
|
||||||
"integrity": "sha512-vxXJV1hVFx3IXz/oy2sICsJukaBrtDEQSBiV48/YIV5KWjX1dO+bcIr/kCPrW6weKXvsaGKFNlwH0v2eYdRRbA==",
|
"integrity": "sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.34.0",
|
"@typescript-eslint/scope-manager": "8.34.1",
|
||||||
"@typescript-eslint/types": "8.34.0",
|
"@typescript-eslint/types": "8.34.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.34.0",
|
"@typescript-eslint/typescript-estree": "8.34.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -641,14 +641,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/project-service": {
|
"node_modules/@typescript-eslint/project-service": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.1.tgz",
|
||||||
"integrity": "sha512-iEgDALRf970/B2YExmtPMPF54NenZUf4xpL3wsCRx/lgjz6ul/l13R81ozP/ZNuXfnLCS+oPmG7JIxfdNYKELw==",
|
"integrity": "sha512-nuHlOmFZfuRwLJKDGQOVc0xnQrAmuq1Mj/ISou5044y1ajGNp2BNliIqp7F2LPQ5sForz8lempMFCovfeS1XoA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/tsconfig-utils": "^8.34.0",
|
"@typescript-eslint/tsconfig-utils": "^8.34.1",
|
||||||
"@typescript-eslint/types": "^8.34.0",
|
"@typescript-eslint/types": "^8.34.1",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -663,14 +663,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.1.tgz",
|
||||||
"integrity": "sha512-9Ac0X8WiLykl0aj1oYQNcLZjHgBojT6cW68yAgZ19letYu+Hxd0rE0veI1XznSSst1X5lwnxhPbVdwjDRIomRw==",
|
"integrity": "sha512-beu6o6QY4hJAgL1E8RaXNC071G4Kso2MGmJskCFQhRhg8VOH/FDbC8soP8NHN7e/Hdphwp8G8cE6OBzC8o41ZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.34.0",
|
"@typescript-eslint/types": "8.34.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.34.0"
|
"@typescript-eslint/visitor-keys": "8.34.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@ -681,9 +681,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.1.tgz",
|
||||||
"integrity": "sha512-+W9VYHKFIzA5cBeooqQxqNriAP0QeQ7xTiDuIOr71hzgffm3EL2hxwWBIIj4GuofIbKxGNarpKqIq6Q6YrShOA==",
|
"integrity": "sha512-K4Sjdo4/xF9NEeA2khOb7Y5nY6NSXBnod87uniVYW9kHP+hNlDV8trUSFeynA2uxWam4gIWgWoygPrv9VMWrYg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -698,14 +698,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.1.tgz",
|
||||||
"integrity": "sha512-n7zSmOcUVhcRYC75W2pnPpbO1iwhJY3NLoHEtbJwJSNlVAZuwqu05zY3f3s2SDWWDSo9FdN5szqc73DCtDObAg==",
|
"integrity": "sha512-Tv7tCCr6e5m8hP4+xFugcrwTOucB8lshffJ6zf1mF1TbU67R+ntCc6DzLNKM+s/uzDyv8gLq7tufaAhIBYeV8g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "8.34.0",
|
"@typescript-eslint/typescript-estree": "8.34.1",
|
||||||
"@typescript-eslint/utils": "8.34.0",
|
"@typescript-eslint/utils": "8.34.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ts-api-utils": "^2.1.0"
|
"ts-api-utils": "^2.1.0"
|
||||||
},
|
},
|
||||||
@ -722,9 +722,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.1.tgz",
|
||||||
"integrity": "sha512-9V24k/paICYPniajHfJ4cuAWETnt7Ssy+R0Rbcqo5sSFr3QEZ/8TSoUi9XeXVBGXCaLtwTOKSLGcInCAvyZeMA==",
|
"integrity": "sha512-rjLVbmE7HR18kDsjNIZQHxmv9RZwlgzavryL5Lnj2ujIRTeXlKtILHgRNmQ3j4daw7zd+mQgy+uyt6Zo6I0IGA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -736,16 +736,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.1.tgz",
|
||||||
"integrity": "sha512-rOi4KZxI7E0+BMqG7emPSK1bB4RICCpF7QD3KCLXn9ZvWoESsOMlHyZPAHyG04ujVplPaHbmEvs34m+wjgtVtg==",
|
"integrity": "sha512-rjCNqqYPuMUF5ODD+hWBNmOitjBWghkGKJg6hiCHzUvXRy6rK22Jd3rwbP2Xi+R7oYVvIKhokHVhH41BxPV5mA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/project-service": "8.34.0",
|
"@typescript-eslint/project-service": "8.34.1",
|
||||||
"@typescript-eslint/tsconfig-utils": "8.34.0",
|
"@typescript-eslint/tsconfig-utils": "8.34.1",
|
||||||
"@typescript-eslint/types": "8.34.0",
|
"@typescript-eslint/types": "8.34.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"fast-glob": "^3.3.2",
|
"fast-glob": "^3.3.2",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
@ -765,9 +765,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -804,16 +804,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.1.tgz",
|
||||||
"integrity": "sha512-8L4tWatGchV9A1cKbjaavS6mwYwp39jql8xUmIIKJdm+qiaeHy5KMKlBrf30akXAWBzn2SqKsNOtSENWUwg7XQ==",
|
"integrity": "sha512-mqOwUdZ3KjtGk7xJJnLbHxTuWVn3GO2WZZuM+Slhkun4+qthLdXx32C8xIXbO1kfCECb3jIs3eoxK3eryk7aoQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.7.0",
|
"@eslint-community/eslint-utils": "^4.7.0",
|
||||||
"@typescript-eslint/scope-manager": "8.34.0",
|
"@typescript-eslint/scope-manager": "8.34.1",
|
||||||
"@typescript-eslint/types": "8.34.0",
|
"@typescript-eslint/types": "8.34.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.34.0"
|
"@typescript-eslint/typescript-estree": "8.34.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@ -828,14 +828,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.1.tgz",
|
||||||
"integrity": "sha512-qHV7pW7E85A0x6qyrFn+O+q1k1p3tQCsqIZ1KZ5ESLXY57aTvUd3/a4rdPTeXisvhXn2VQG0VSKUqs8KHF2zcA==",
|
"integrity": "sha512-xoh5rJ+tgsRKoXnkBPFRLZ7rjKM0AfVbC68UZ/ECXoDbfggb9RbEySN359acY1vS3qZ0jVTVWzbtfapwm5ztxw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.34.0",
|
"@typescript-eslint/types": "8.34.1",
|
||||||
"eslint-visitor-keys": "^4.2.0"
|
"eslint-visitor-keys": "^4.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@ -846,9 +846,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.14.1",
|
"version": "8.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||||
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
@ -1554,18 +1554,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "9.28.0",
|
"version": "9.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.29.0.tgz",
|
||||||
"integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==",
|
"integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
"@eslint/config-array": "^0.20.0",
|
"@eslint/config-array": "^0.20.1",
|
||||||
"@eslint/config-helpers": "^0.2.1",
|
"@eslint/config-helpers": "^0.2.1",
|
||||||
"@eslint/core": "^0.14.0",
|
"@eslint/core": "^0.14.0",
|
||||||
"@eslint/eslintrc": "^3.3.1",
|
"@eslint/eslintrc": "^3.3.1",
|
||||||
"@eslint/js": "9.28.0",
|
"@eslint/js": "9.29.0",
|
||||||
"@eslint/plugin-kit": "^0.3.1",
|
"@eslint/plugin-kit": "^0.3.1",
|
||||||
"@humanfs/node": "^0.16.6",
|
"@humanfs/node": "^0.16.6",
|
||||||
"@humanwhocodes/module-importer": "^1.0.1",
|
"@humanwhocodes/module-importer": "^1.0.1",
|
||||||
@ -1577,9 +1577,9 @@
|
|||||||
"cross-spawn": "^7.0.6",
|
"cross-spawn": "^7.0.6",
|
||||||
"debug": "^4.3.2",
|
"debug": "^4.3.2",
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
"eslint-scope": "^8.3.0",
|
"eslint-scope": "^8.4.0",
|
||||||
"eslint-visitor-keys": "^4.2.0",
|
"eslint-visitor-keys": "^4.2.1",
|
||||||
"espree": "^10.3.0",
|
"espree": "^10.4.0",
|
||||||
"esquery": "^1.5.0",
|
"esquery": "^1.5.0",
|
||||||
"esutils": "^2.0.2",
|
"esutils": "^2.0.2",
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
@ -1792,9 +1792,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-scope": {
|
"node_modules/eslint-scope": {
|
||||||
"version": "8.3.0",
|
"version": "8.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
|
||||||
"integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==",
|
"integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esrecurse": "^4.3.0",
|
"esrecurse": "^4.3.0",
|
||||||
@ -1808,9 +1808,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-visitor-keys": {
|
"node_modules/eslint-visitor-keys": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
|
||||||
"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
|
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@ -1820,14 +1820,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/espree": {
|
"node_modules/espree": {
|
||||||
"version": "10.3.0",
|
"version": "10.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
|
||||||
"integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
|
"integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "^8.14.0",
|
"acorn": "^8.15.0",
|
||||||
"acorn-jsx": "^5.3.2",
|
"acorn-jsx": "^5.3.2",
|
||||||
"eslint-visitor-keys": "^4.2.0"
|
"eslint-visitor-keys": "^4.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@ -4035,15 +4035,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript-eslint": {
|
"node_modules/typescript-eslint": {
|
||||||
"version": "8.34.0",
|
"version": "8.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.1.tgz",
|
||||||
"integrity": "sha512-MRpfN7uYjTrTGigFCt8sRyNqJFhjN0WwZecldaqhWm+wy0gaRt8Edb/3cuUy0zdq2opJWT6iXINKAtewnDOltQ==",
|
"integrity": "sha512-XjS+b6Vg9oT1BaIUfkW3M3LvqZE++rbzAMEHuccCfO/YkP43ha6w3jTEMilQxMF92nVOYCcdjv1ZUhAa1D/0ow==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "8.34.0",
|
"@typescript-eslint/eslint-plugin": "8.34.1",
|
||||||
"@typescript-eslint/parser": "8.34.0",
|
"@typescript-eslint/parser": "8.34.1",
|
||||||
"@typescript-eslint/utils": "8.34.0"
|
"@typescript-eslint/utils": "8.34.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
9
packages/prettier-config/.prettierignore
Normal file
9
packages/prettier-config/.prettierignore
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Prettier Ignorefile
|
||||||
|
|
||||||
|
## Static Files
|
||||||
|
**/LICENSE
|
||||||
|
|
||||||
|
## Build asset directories
|
||||||
|
coverage
|
||||||
|
dist
|
||||||
|
out
|
@ -45,7 +45,6 @@ export const AuthentikPrettierConfig = {
|
|||||||
"^(@goauthentik/|#)user.+",
|
"^(@goauthentik/|#)user.+",
|
||||||
"^(@goauthentik/|#)admin.+",
|
"^(@goauthentik/|#)admin.+",
|
||||||
"^(@goauthentik/|#)flow.+",
|
"^(@goauthentik/|#)flow.+",
|
||||||
"^(@goauthentik/|#)flow.+",
|
|
||||||
|
|
||||||
"^#.+",
|
"^#.+",
|
||||||
"^@goauthentik.+",
|
"^@goauthentik.+",
|
||||||
|
32
packages/prettier-config/package-lock.json
generated
32
packages/prettier-config/package-lock.json
generated
@ -1,29 +1,29 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/prettier-config",
|
"name": "@goauthentik/prettier-config",
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@goauthentik/prettier-config",
|
"name": "@goauthentik/prettier-config",
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@goauthentik/tsconfig": "^1.0.1",
|
"@goauthentik/tsconfig": "^1.0.1",
|
||||||
"@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.15",
|
||||||
"typescript": "^5.8.2"
|
"typescript": "^5.8.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.11"
|
"node": ">=22"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@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.15"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
@ -206,9 +206,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@pkgr/core": {
|
"node_modules/@pkgr/core": {
|
||||||
"version": "0.2.4",
|
"version": "0.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.7.tgz",
|
||||||
"integrity": "sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==",
|
"integrity": "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -437,14 +437,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier-plugin-packagejson": {
|
"node_modules/prettier-plugin-packagejson": {
|
||||||
"version": "2.5.14",
|
"version": "2.5.15",
|
||||||
"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.15.tgz",
|
||||||
"integrity": "sha512-h+3tSpr2nVpp+YOK1MDIYtYhHVXr8/0V59UUbJpIJFaqi3w4fvUokJo6eV8W+vELrUXIZzJ+DKm5G7lYzrMcKQ==",
|
"integrity": "sha512-2QSx6y4IT6LTwXtCvXAopENW5IP/aujC8fobEM2pDbs0IGkiVjW/ipPuYAHuXigbNe64aGWF7vIetukuzM3CBw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"sort-package-json": "3.2.1",
|
"sort-package-json": "3.2.1",
|
||||||
"synckit": "0.11.6"
|
"synckit": "0.11.8"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"prettier": ">= 1.16.0"
|
"prettier": ">= 1.16.0"
|
||||||
@ -495,9 +495,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/synckit": {
|
"node_modules/synckit": {
|
||||||
"version": "0.11.6",
|
"version": "0.11.8",
|
||||||
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.6.tgz",
|
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.8.tgz",
|
||||||
"integrity": "sha512-2pR2ubZSV64f/vqm9eLPz/KOvR9Dm+Co/5ChLgeHl0yEDRc6h5hXHoxEQH8Y5Ljycozd3p1k5TTSVdzYGkPvLw==",
|
"integrity": "sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/prettier-config",
|
"name": "@goauthentik/prettier-config",
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"description": "authentik's Prettier config",
|
"description": "authentik's Prettier config",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc -p ."
|
"build": "tsc -p .",
|
||||||
|
"prettier": "prettier --write .",
|
||||||
|
"prettier-check": "prettier --check ."
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": "./index.js",
|
"exports": "./index.js",
|
||||||
@ -13,17 +15,17 @@
|
|||||||
"@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.15",
|
||||||
"typescript": "^5.8.2"
|
"typescript": "^5.8.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@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.15"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.11"
|
"node": ">=22"
|
||||||
},
|
},
|
||||||
"types": "./out/index.d.ts",
|
"types": "./out/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "authentik"
|
name = "authentik"
|
||||||
version = "2025.6.1"
|
version = "2025.6.2"
|
||||||
description = ""
|
description = ""
|
||||||
authors = [{ name = "authentik Team", email = "hello@goauthentik.io" }]
|
authors = [{ name = "authentik Team", email = "hello@goauthentik.io" }]
|
||||||
requires-python = "==3.13.*"
|
requires-python = "==3.13.*"
|
||||||
@ -15,17 +15,18 @@ dependencies = [
|
|||||||
"defusedxml==0.7.1",
|
"defusedxml==0.7.1",
|
||||||
"django==5.1.11",
|
"django==5.1.11",
|
||||||
"django-countries==7.6.1",
|
"django-countries==7.6.1",
|
||||||
"django-cte==1.3.3",
|
"django-cte==2.0.0",
|
||||||
"django-filter==25.1",
|
"django-filter==25.1",
|
||||||
"django-guardian==3.0.0",
|
"django-guardian==3.0.0",
|
||||||
"django-model-utils==5.0.0",
|
"django-model-utils==5.0.0",
|
||||||
"django-pglock==1.7.2",
|
"django-pglock==1.7.2",
|
||||||
"django-prometheus==2.3.1",
|
"django-prometheus==2.4.0",
|
||||||
"django-redis==5.4.0",
|
"django-redis==6.0.0",
|
||||||
"django-storages[s3]==1.14.6",
|
"django-storages[s3]==1.14.6",
|
||||||
"django-tenants==3.8.0",
|
"django-tenants==3.8.0",
|
||||||
"djangorestframework==3.16.0",
|
"djangoql==0.18.1",
|
||||||
"djangorestframework-guardian==0.3.0",
|
"djangorestframework-guardian==0.3.0",
|
||||||
|
"djangorestframework==3.16.0",
|
||||||
"docker==7.1.0",
|
"docker==7.1.0",
|
||||||
"drf-orjson-renderer==1.7.3",
|
"drf-orjson-renderer==1.7.3",
|
||||||
"drf-spectacular==0.28.0",
|
"drf-spectacular==0.28.0",
|
||||||
@ -35,40 +36,40 @@ dependencies = [
|
|||||||
"flower==2.0.1",
|
"flower==2.0.1",
|
||||||
"geoip2==5.1.0",
|
"geoip2==5.1.0",
|
||||||
"geopy==2.4.1",
|
"geopy==2.4.1",
|
||||||
"google-api-python-client==2.172.0",
|
"google-api-python-client==2.173.0",
|
||||||
"gssapi==1.9.0",
|
"gssapi==1.9.0",
|
||||||
"gunicorn==23.0.0",
|
"gunicorn==23.0.0",
|
||||||
"jsonpatch==1.33",
|
"jsonpatch==1.33",
|
||||||
"jwcrypto==1.5.6",
|
"jwcrypto==1.5.6",
|
||||||
"kubernetes==32.0.1",
|
"kubernetes==33.1.0",
|
||||||
"ldap3==2.9.1",
|
"ldap3==2.9.1",
|
||||||
"lxml==5.4.0",
|
"lxml==5.4.0",
|
||||||
"msgraph-sdk==1.33.0",
|
"msgraph-sdk==1.34.0",
|
||||||
"opencontainers==0.0.14",
|
"opencontainers==0.0.14",
|
||||||
"packaging==25.0",
|
"packaging==25.0",
|
||||||
"paramiko==3.5.1",
|
"paramiko==3.5.1",
|
||||||
"psycopg[c,pool]==3.2.9",
|
"psycopg[c,pool]==3.2.9",
|
||||||
"pydantic==2.11.5",
|
"pydantic==2.11.7",
|
||||||
"pydantic-scim==0.0.8",
|
"pydantic-scim==0.0.8",
|
||||||
"pyjwt==2.10.1",
|
"pyjwt==2.10.1",
|
||||||
"pyrad==2.4",
|
"pyrad==2.4",
|
||||||
"python-kadmin-rs==0.6.0",
|
"python-kadmin-rs==0.6.1",
|
||||||
"pyyaml==6.0.2",
|
"pyyaml==6.0.2",
|
||||||
"requests-oauthlib==2.0.0",
|
"requests-oauthlib==2.0.0",
|
||||||
"scim2-filter-parser==0.7.0",
|
"scim2-filter-parser==0.7.0",
|
||||||
"sentry-sdk==2.29.1",
|
"sentry-sdk==2.30.0",
|
||||||
"service-identity==24.2.0",
|
"service-identity==24.2.0",
|
||||||
"setproctitle==1.3.6",
|
"setproctitle==1.3.6",
|
||||||
"structlog==25.4.0",
|
"structlog==25.4.0",
|
||||||
"swagger-spec-validator==3.0.4",
|
"swagger-spec-validator==3.0.4",
|
||||||
"tenant-schemas-celery==3.0.0",
|
"tenant-schemas-celery==3.0.0",
|
||||||
"twilio==9.6.2",
|
"twilio==9.6.3",
|
||||||
"ua-parser==1.0.1",
|
"ua-parser==1.0.1",
|
||||||
"unidecode==1.4.0",
|
"unidecode==1.4.0",
|
||||||
"urllib3<3",
|
"urllib3<3",
|
||||||
"uvicorn[standard]==0.34.3",
|
"uvicorn[standard]==0.34.3",
|
||||||
"watchdog==6.0.0",
|
"watchdog==6.0.0",
|
||||||
"webauthn==2.5.2",
|
"webauthn==2.6.0",
|
||||||
"wsproto==1.2.0",
|
"wsproto==1.2.0",
|
||||||
"xmlsec==1.3.15",
|
"xmlsec==1.3.15",
|
||||||
"zxcvbn==4.5.0",
|
"zxcvbn==4.5.0",
|
||||||
|
441
schema.yml
441
schema.yml
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Binary file not shown.
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 21 KiB |
@ -7,7 +7,7 @@ services:
|
|||||||
network_mode: host
|
network_mode: host
|
||||||
restart: always
|
restart: always
|
||||||
mailpit:
|
mailpit:
|
||||||
image: docker.io/axllent/mailpit:v1.26.0
|
image: docker.io/axllent/mailpit:v1.26.1
|
||||||
ports:
|
ports:
|
||||||
- 1025:1025
|
- 1025:1025
|
||||||
- 8025:8025
|
- 8025:8025
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
from dataclasses import asdict
|
from dataclasses import asdict
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from unittest.mock import patch
|
|
||||||
|
|
||||||
from guardian.shortcuts import assign_perm
|
from guardian.shortcuts import assign_perm
|
||||||
from ldap3 import ALL, ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES, SUBTREE, Connection, Server
|
from ldap3 import ALL, ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES, SUBTREE, Connection, Server
|
||||||
@ -16,12 +15,10 @@ from authentik.flows.models import Flow
|
|||||||
from authentik.lib.generators import generate_id
|
from authentik.lib.generators import generate_id
|
||||||
from authentik.outposts.apps import MANAGED_OUTPOST
|
from authentik.outposts.apps import MANAGED_OUTPOST
|
||||||
from authentik.outposts.models import Outpost, OutpostConfig, OutpostType
|
from authentik.outposts.models import Outpost, OutpostConfig, OutpostType
|
||||||
from authentik.outposts.tests.test_ws import patched__get_ct_cached
|
|
||||||
from authentik.providers.ldap.models import APIAccessMode, LDAPProvider
|
from authentik.providers.ldap.models import APIAccessMode, LDAPProvider
|
||||||
from tests.e2e.utils import SeleniumTestCase, retry
|
from tests.e2e.utils import SeleniumTestCase, retry
|
||||||
|
|
||||||
|
|
||||||
@patch("guardian.shortcuts._get_ct_cached", patched__get_ct_cached)
|
|
||||||
class TestProviderLDAP(SeleniumTestCase):
|
class TestProviderLDAP(SeleniumTestCase):
|
||||||
"""LDAP and Outpost e2e tests"""
|
"""LDAP and Outpost e2e tests"""
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ from json import loads
|
|||||||
from sys import platform
|
from sys import platform
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from unittest.case import skip, skipUnless
|
from unittest.case import skip, skipUnless
|
||||||
from unittest.mock import patch
|
|
||||||
|
|
||||||
from channels.testing import ChannelsLiveServerTestCase
|
from channels.testing import ChannelsLiveServerTestCase
|
||||||
from jwt import decode
|
from jwt import decode
|
||||||
@ -18,12 +17,10 @@ from authentik.flows.models import Flow
|
|||||||
from authentik.lib.generators import generate_id
|
from authentik.lib.generators import generate_id
|
||||||
from authentik.outposts.models import DockerServiceConnection, Outpost, OutpostConfig, OutpostType
|
from authentik.outposts.models import DockerServiceConnection, Outpost, OutpostConfig, OutpostType
|
||||||
from authentik.outposts.tasks import outpost_connection_discovery
|
from authentik.outposts.tasks import outpost_connection_discovery
|
||||||
from authentik.outposts.tests.test_ws import patched__get_ct_cached
|
|
||||||
from authentik.providers.proxy.models import ProxyProvider
|
from authentik.providers.proxy.models import ProxyProvider
|
||||||
from tests.e2e.utils import SeleniumTestCase, retry
|
from tests.e2e.utils import SeleniumTestCase, retry
|
||||||
|
|
||||||
|
|
||||||
@patch("guardian.shortcuts._get_ct_cached", patched__get_ct_cached)
|
|
||||||
class TestProviderProxy(SeleniumTestCase):
|
class TestProviderProxy(SeleniumTestCase):
|
||||||
"""Proxy and Outpost e2e tests"""
|
"""Proxy and Outpost e2e tests"""
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ from json import loads
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from unittest import skip
|
from unittest import skip
|
||||||
from unittest.mock import patch
|
|
||||||
|
|
||||||
from selenium.webdriver.common.by import By
|
from selenium.webdriver.common.by import By
|
||||||
|
|
||||||
@ -13,12 +12,10 @@ from authentik.core.models import Application
|
|||||||
from authentik.flows.models import Flow
|
from authentik.flows.models import Flow
|
||||||
from authentik.lib.generators import generate_id
|
from authentik.lib.generators import generate_id
|
||||||
from authentik.outposts.models import Outpost, OutpostType
|
from authentik.outposts.models import Outpost, OutpostType
|
||||||
from authentik.outposts.tests.test_ws import patched__get_ct_cached
|
|
||||||
from authentik.providers.proxy.models import ProxyMode, ProxyProvider
|
from authentik.providers.proxy.models import ProxyMode, ProxyProvider
|
||||||
from tests.e2e.utils import SeleniumTestCase, retry
|
from tests.e2e.utils import SeleniumTestCase, retry
|
||||||
|
|
||||||
|
|
||||||
@patch("guardian.shortcuts._get_ct_cached", patched__get_ct_cached)
|
|
||||||
class TestProviderProxyForward(SeleniumTestCase):
|
class TestProviderProxyForward(SeleniumTestCase):
|
||||||
"""Proxy and Outpost e2e tests"""
|
"""Proxy and Outpost e2e tests"""
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
from dataclasses import asdict
|
from dataclasses import asdict
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from unittest.mock import patch
|
|
||||||
|
|
||||||
from pyrad.client import Client
|
from pyrad.client import Client
|
||||||
from pyrad.dictionary import Dictionary
|
from pyrad.dictionary import Dictionary
|
||||||
@ -13,12 +12,10 @@ from authentik.core.models import Application, User
|
|||||||
from authentik.flows.models import Flow
|
from authentik.flows.models import Flow
|
||||||
from authentik.lib.generators import generate_id, generate_key
|
from authentik.lib.generators import generate_id, generate_key
|
||||||
from authentik.outposts.models import Outpost, OutpostConfig, OutpostType
|
from authentik.outposts.models import Outpost, OutpostConfig, OutpostType
|
||||||
from authentik.outposts.tests.test_ws import patched__get_ct_cached
|
|
||||||
from authentik.providers.radius.models import RadiusProvider
|
from authentik.providers.radius.models import RadiusProvider
|
||||||
from tests.e2e.utils import SeleniumTestCase, retry
|
from tests.e2e.utils import SeleniumTestCase, retry
|
||||||
|
|
||||||
|
|
||||||
@patch("guardian.shortcuts._get_ct_cached", patched__get_ct_cached)
|
|
||||||
class TestProviderRadius(SeleniumTestCase):
|
class TestProviderRadius(SeleniumTestCase):
|
||||||
"""Radius Outpost e2e tests"""
|
"""Radius Outpost e2e tests"""
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user