Compare commits
6 Commits
providers/
...
files-in-d
| Author | SHA1 | Date | |
|---|---|---|---|
| d410083cfc | |||
| 6045f96a05 | |||
| c50df0f843 | |||
| c8ebd9f74b | |||
| b3f441f2cd | |||
| 647f054be3 |
@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 2025.6.2
|
current_version = 2025.6.1
|
||||||
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*))?
|
||||||
|
|||||||
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', 'package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b
|
key: ${{ runner.os }}-web-${{ hashFiles('web/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
|
||||||
|
|||||||
@ -77,7 +77,7 @@ RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
|
|||||||
# Stage 4: Download uv
|
# Stage 4: Download uv
|
||||||
FROM ghcr.io/astral-sh/uv:0.7.13 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.5-slim-bookworm-fips AS python-base
|
FROM ghcr.io/goauthentik/fips-python:3.13.4-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" \
|
||||||
|
|||||||
2
Makefile
2
Makefile
@ -94,7 +94,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 --file blueprints/schema.json
|
uv run ak make_blueprint_schema > 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.2"
|
__version__ = "2025.6.1"
|
||||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -72,33 +72,20 @@ class Command(BaseCommand):
|
|||||||
"additionalProperties": True,
|
"additionalProperties": True,
|
||||||
},
|
},
|
||||||
"entries": {
|
"entries": {
|
||||||
"anyOf": [
|
"type": "array",
|
||||||
{
|
"items": {
|
||||||
"type": "array",
|
"oneOf": [],
|
||||||
"items": {"$ref": "#/$defs/blueprint_entry"},
|
},
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {"$ref": "#/$defs/blueprint_entry"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"$defs": {"blueprint_entry": {"oneOf": []}},
|
"$defs": {},
|
||||||
}
|
}
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
|
||||||
parser.add_argument("--file", type=str)
|
|
||||||
|
|
||||||
@no_translations
|
@no_translations
|
||||||
def handle(self, *args, file: str, **options):
|
def handle(self, *args, **options):
|
||||||
"""Generate JSON Schema for blueprints"""
|
"""Generate JSON Schema for blueprints"""
|
||||||
self.build()
|
self.build()
|
||||||
with open(file, "w") as _schema:
|
self.stdout.write(dumps(self.schema, indent=4, default=Command.json_default))
|
||||||
_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:
|
||||||
@ -125,7 +112,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["$defs"]["blueprint_entry"]["oneOf"].append(
|
self.schema["properties"]["entries"]["items"]["oneOf"].append(
|
||||||
self.template_entry(model_path, model, serializer)
|
self.template_entry(model_path, model, serializer)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
version: 1
|
version: 1
|
||||||
entries:
|
entries:
|
||||||
foo:
|
- identifiers:
|
||||||
- identifiers:
|
name: "%(id)s"
|
||||||
name: "%(id)s"
|
slug: "%(id)s"
|
||||||
slug: "%(id)s"
|
model: authentik_flows.flow
|
||||||
model: authentik_flows.flow
|
state: present
|
||||||
state: present
|
attrs:
|
||||||
attrs:
|
designation: stage_configuration
|
||||||
designation: stage_configuration
|
title: foo
|
||||||
title: foo
|
|
||||||
|
|||||||
@ -191,18 +191,11 @@ 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] | dict[str, list[BlueprintEntry]] = field(default_factory=list)
|
entries: 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"""
|
||||||
@ -233,7 +226,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.iter_entries():
|
for _entry in blueprint.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.iter_entries():
|
for entry in self._import.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)
|
||||||
|
|||||||
32
authentik/core/api/files.py
Normal file
32
authentik/core/api/files.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
|
from authentik.core.api.used_by import UsedByMixin
|
||||||
|
from authentik.core.api.utils import ModelSerializer
|
||||||
|
from authentik.core.models import File
|
||||||
|
|
||||||
|
LOGGER = get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class FileSerializer(ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = File
|
||||||
|
fields = (
|
||||||
|
"pk",
|
||||||
|
"name",
|
||||||
|
"content",
|
||||||
|
"location",
|
||||||
|
"private",
|
||||||
|
"url",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FileViewSet(UsedByMixin, ModelViewSet):
|
||||||
|
queryset = File.objects.all()
|
||||||
|
serializer_class = FileSerializer
|
||||||
|
filterset_fields = ("private",)
|
||||||
|
ordering = ("name",)
|
||||||
|
search_fields = (
|
||||||
|
"name",
|
||||||
|
"location",
|
||||||
|
)
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
# Generated by Django 5.1.11 on 2025-06-13 15:12
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("authentik_core", "0048_delete_oldauthenticatedsession_content_type"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="File",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.UUIDField(
|
||||||
|
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.TextField()),
|
||||||
|
("content", models.BinaryField()),
|
||||||
|
("public", models.BooleanField(default=False)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "Files",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name="application",
|
||||||
|
old_name="meta_icon",
|
||||||
|
new_name="meta_old_icon",
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="application",
|
||||||
|
name="meta_icon",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
null=True, on_delete=django.db.models.deletion.SET_NULL, to="authentik_core.file"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
# Generated by Django 5.1.11 on 2025-06-13 15:29
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("authentik_core", "0049_file_rename_meta_icon_application_meta_old_icon"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="file",
|
||||||
|
name="location",
|
||||||
|
field=models.TextField(null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="file",
|
||||||
|
name="content",
|
||||||
|
field=models.BinaryField(null=True),
|
||||||
|
),
|
||||||
|
migrations.AddConstraint(
|
||||||
|
model_name="file",
|
||||||
|
constraint=models.CheckConstraint(
|
||||||
|
condition=models.Q(
|
||||||
|
("content__isnull", False), ("location__isnull", False), _connector="OR"
|
||||||
|
),
|
||||||
|
name="one_of_content_location_is_defined",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -29,6 +29,7 @@ from authentik.blueprints.models import ManagedModel
|
|||||||
from authentik.core.expression.exceptions import PropertyMappingExpressionException
|
from authentik.core.expression.exceptions import PropertyMappingExpressionException
|
||||||
from authentik.core.types import UILoginButton, UserSettingSerializer
|
from authentik.core.types import UILoginButton, UserSettingSerializer
|
||||||
from authentik.lib.avatars import get_avatar
|
from authentik.lib.avatars import get_avatar
|
||||||
|
from authentik.lib.config import CONFIG
|
||||||
from authentik.lib.expression.exceptions import ControlFlowException
|
from authentik.lib.expression.exceptions import ControlFlowException
|
||||||
from authentik.lib.generators import generate_id
|
from authentik.lib.generators import generate_id
|
||||||
from authentik.lib.merge import MERGE_LIST_UNIQUE
|
from authentik.lib.merge import MERGE_LIST_UNIQUE
|
||||||
@ -533,12 +534,13 @@ class Application(SerializerModel, PolicyBindingModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# For template applications, this can be set to /static/authentik/applications/*
|
# For template applications, this can be set to /static/authentik/applications/*
|
||||||
meta_icon = models.FileField(
|
meta_old_icon = models.FileField(
|
||||||
upload_to="application-icons/",
|
upload_to="application-icons/",
|
||||||
default=None,
|
default=None,
|
||||||
null=True,
|
null=True,
|
||||||
max_length=500,
|
max_length=500,
|
||||||
)
|
)
|
||||||
|
meta_icon = models.ForeignKey("File", null=True, on_delete=models.SET_NULL)
|
||||||
meta_description = models.TextField(default="", blank=True)
|
meta_description = models.TextField(default="", blank=True)
|
||||||
meta_publisher = models.TextField(default="", blank=True)
|
meta_publisher = models.TextField(default="", blank=True)
|
||||||
|
|
||||||
@ -1100,3 +1102,44 @@ class AuthenticatedSession(SerializerModel):
|
|||||||
session=Session.objects.filter(session_key=request.session.session_key).first(),
|
session=Session.objects.filter(session_key=request.session.session_key).first(),
|
||||||
user=user,
|
user=user,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class File(SerializerModel):
|
||||||
|
id = models.UUIDField(primary_key=True, editable=False, default=uuid4)
|
||||||
|
|
||||||
|
name = models.TextField()
|
||||||
|
content = models.BinaryField(null=True)
|
||||||
|
location = models.TextField(null=True)
|
||||||
|
public = models.BooleanField(default=False)
|
||||||
|
delete_on_delete = models.BooleanField(default=False)
|
||||||
|
expiry = models.DateTimeField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("File")
|
||||||
|
verbose_name = _("Files")
|
||||||
|
constraints = (
|
||||||
|
models.CheckConstraint(
|
||||||
|
condition=Q(content__isnull=False) | Q(location__isnull=False),
|
||||||
|
name="one_of_content_location_is_defined",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def serializer(self) -> type[Serializer]:
|
||||||
|
from authentik.core.api.files import FileSerializer
|
||||||
|
|
||||||
|
return FileSerializer
|
||||||
|
|
||||||
|
@property
|
||||||
|
def url(self) -> str:
|
||||||
|
if self.content:
|
||||||
|
return (
|
||||||
|
CONFIG.get("web.path", "/")[:-1]
|
||||||
|
+ f"/files/{'public' if self.public else 'private'}/{self.pk}"
|
||||||
|
)
|
||||||
|
elif self.location.startswith("/static"):
|
||||||
|
return CONFIG.get("web.path", "/")[:-1] + self.location
|
||||||
|
return self.location
|
||||||
|
|||||||
@ -8,6 +8,7 @@ from authentik.core.api.application_entitlements import ApplicationEntitlementVi
|
|||||||
from authentik.core.api.applications import ApplicationViewSet
|
from authentik.core.api.applications import ApplicationViewSet
|
||||||
from authentik.core.api.authenticated_sessions import AuthenticatedSessionViewSet
|
from authentik.core.api.authenticated_sessions import AuthenticatedSessionViewSet
|
||||||
from authentik.core.api.devices import AdminDeviceViewSet, DeviceViewSet
|
from authentik.core.api.devices import AdminDeviceViewSet, DeviceViewSet
|
||||||
|
from authentik.core.api.files import FileViewSet
|
||||||
from authentik.core.api.groups import GroupViewSet
|
from authentik.core.api.groups import GroupViewSet
|
||||||
from authentik.core.api.property_mappings import PropertyMappingViewSet
|
from authentik.core.api.property_mappings import PropertyMappingViewSet
|
||||||
from authentik.core.api.providers import ProviderViewSet
|
from authentik.core.api.providers import ProviderViewSet
|
||||||
@ -78,6 +79,7 @@ api_urlpatterns = [
|
|||||||
TransactionalApplicationView.as_view(),
|
TransactionalApplicationView.as_view(),
|
||||||
name="core-transactional-application",
|
name="core-transactional-application",
|
||||||
),
|
),
|
||||||
|
("core/files", FileViewSet),
|
||||||
("core/groups", GroupViewSet),
|
("core/groups", GroupViewSet),
|
||||||
("core/users", UserViewSet),
|
("core/users", UserViewSet),
|
||||||
("core/tokens", TokenViewSet),
|
("core/tokens", TokenViewSet),
|
||||||
|
|||||||
@ -387,7 +387,8 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
response.url,
|
response.url,
|
||||||
(
|
(
|
||||||
f"http://localhost#id_token={provider.encode(token.id_token.to_dict())}"
|
f"http://localhost#access_token={token.token}"
|
||||||
|
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}"
|
||||||
),
|
),
|
||||||
@ -562,6 +563,7 @@ 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,6 +630,7 @@ 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
|
||||||
|
|||||||
@ -20,9 +20,6 @@ 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):
|
||||||
@ -112,15 +109,10 @@ 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=settings or {},
|
settings=self.executor.plan.context.get("connection_settings", {}),
|
||||||
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,
|
||||||
|
|||||||
@ -190,7 +190,6 @@ class SAMLProviderSerializer(ProviderSerializer):
|
|||||||
"sign_response",
|
"sign_response",
|
||||||
"sp_binding",
|
"sp_binding",
|
||||||
"default_relay_state",
|
"default_relay_state",
|
||||||
"default_name_id_policy",
|
|
||||||
"url_download_metadata",
|
"url_download_metadata",
|
||||||
"url_sso_post",
|
"url_sso_post",
|
||||||
"url_sso_redirect",
|
"url_sso_redirect",
|
||||||
|
|||||||
@ -1,31 +0,0 @@
|
|||||||
# Generated by Django 5.1.11 on 2025-06-18 09:27
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("authentik_providers_saml", "0018_alter_samlprovider_acs_url"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="samlprovider",
|
|
||||||
name="default_name_id_policy",
|
|
||||||
field=models.TextField(
|
|
||||||
choices=[
|
|
||||||
("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", "Email"),
|
|
||||||
("urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", "Persistent"),
|
|
||||||
("urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName", "X509"),
|
|
||||||
(
|
|
||||||
"urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName",
|
|
||||||
"Windows",
|
|
||||||
),
|
|
||||||
("urn:oasis:names:tc:SAML:2.0:nameid-format:transient", "Transient"),
|
|
||||||
("urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", "Unspecified"),
|
|
||||||
],
|
|
||||||
default="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -12,7 +12,6 @@ from authentik.core.models import PropertyMapping, Provider
|
|||||||
from authentik.crypto.models import CertificateKeyPair
|
from authentik.crypto.models import CertificateKeyPair
|
||||||
from authentik.lib.models import DomainlessURLValidator
|
from authentik.lib.models import DomainlessURLValidator
|
||||||
from authentik.lib.utils.time import timedelta_string_validator
|
from authentik.lib.utils.time import timedelta_string_validator
|
||||||
from authentik.sources.saml.models import SAMLNameIDPolicy
|
|
||||||
from authentik.sources.saml.processors.constants import (
|
from authentik.sources.saml.processors.constants import (
|
||||||
DSA_SHA1,
|
DSA_SHA1,
|
||||||
ECDSA_SHA1,
|
ECDSA_SHA1,
|
||||||
@ -180,9 +179,6 @@ class SAMLProvider(Provider):
|
|||||||
default_relay_state = models.TextField(
|
default_relay_state = models.TextField(
|
||||||
default="", blank=True, help_text=_("Default relay_state value for IDP-initiated logins")
|
default="", blank=True, help_text=_("Default relay_state value for IDP-initiated logins")
|
||||||
)
|
)
|
||||||
default_name_id_policy = models.TextField(
|
|
||||||
choices=SAMLNameIDPolicy.choices, default=SAMLNameIDPolicy.UNSPECIFIED
|
|
||||||
)
|
|
||||||
|
|
||||||
sign_assertion = models.BooleanField(default=True)
|
sign_assertion = models.BooleanField(default=True)
|
||||||
sign_response = models.BooleanField(default=False)
|
sign_response = models.BooleanField(default=False)
|
||||||
|
|||||||
@ -205,13 +205,6 @@ class AssertionProcessor:
|
|||||||
def get_name_id(self) -> Element:
|
def get_name_id(self) -> Element:
|
||||||
"""Get NameID Element"""
|
"""Get NameID Element"""
|
||||||
name_id = Element(f"{{{NS_SAML_ASSERTION}}}NameID")
|
name_id = Element(f"{{{NS_SAML_ASSERTION}}}NameID")
|
||||||
# For requests that don't specify a NameIDPolicy, check if we
|
|
||||||
# can fall back to the provider default
|
|
||||||
if (
|
|
||||||
self.auth_n_request.name_id_policy == SAML_NAME_ID_FORMAT_UNSPECIFIED
|
|
||||||
and self.provider.default_name_id_policy != SAML_NAME_ID_FORMAT_UNSPECIFIED
|
|
||||||
):
|
|
||||||
self.auth_n_request.name_id_policy = self.provider.default_name_id_policy
|
|
||||||
name_id.attrib["Format"] = self.auth_n_request.name_id_policy
|
name_id.attrib["Format"] = self.auth_n_request.name_id_policy
|
||||||
# persistent is used as a fallback, so always generate it
|
# persistent is used as a fallback, so always generate it
|
||||||
persistent = self.http_request.user.uid
|
persistent = self.http_request.user.uid
|
||||||
|
|||||||
@ -13,7 +13,6 @@ from authentik.lib.xml import lxml_from_string
|
|||||||
from authentik.providers.saml.exceptions import CannotHandleAssertion
|
from authentik.providers.saml.exceptions import CannotHandleAssertion
|
||||||
from authentik.providers.saml.models import SAMLProvider
|
from authentik.providers.saml.models import SAMLProvider
|
||||||
from authentik.providers.saml.utils.encoding import decode_base64_and_inflate
|
from authentik.providers.saml.utils.encoding import decode_base64_and_inflate
|
||||||
from authentik.sources.saml.models import SAMLNameIDPolicy
|
|
||||||
from authentik.sources.saml.processors.constants import (
|
from authentik.sources.saml.processors.constants import (
|
||||||
DSA_SHA1,
|
DSA_SHA1,
|
||||||
NS_MAP,
|
NS_MAP,
|
||||||
@ -176,9 +175,7 @@ class AuthNRequestParser:
|
|||||||
|
|
||||||
def idp_initiated(self) -> AuthNRequest:
|
def idp_initiated(self) -> AuthNRequest:
|
||||||
"""Create IdP Initiated AuthNRequest"""
|
"""Create IdP Initiated AuthNRequest"""
|
||||||
request = AuthNRequest(relay_state=None)
|
relay_state = None
|
||||||
if self.provider.default_relay_state != "":
|
if self.provider.default_relay_state != "":
|
||||||
request.relay_state = self.provider.default_relay_state
|
relay_state = self.provider.default_relay_state
|
||||||
if self.provider.default_name_id_policy != SAMLNameIDPolicy.UNSPECIFIED:
|
return AuthNRequest(relay_state=relay_state)
|
||||||
request.name_id_policy = self.provider.default_name_id_policy
|
|
||||||
return request
|
|
||||||
|
|||||||
@ -13,7 +13,6 @@ from authentik.crypto.models import CertificateKeyPair
|
|||||||
from authentik.flows.models import Flow
|
from authentik.flows.models import Flow
|
||||||
from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider
|
from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider
|
||||||
from authentik.providers.saml.utils.encoding import PEM_FOOTER, PEM_HEADER
|
from authentik.providers.saml.utils.encoding import PEM_FOOTER, PEM_HEADER
|
||||||
from authentik.sources.saml.models import SAMLNameIDPolicy
|
|
||||||
from authentik.sources.saml.processors.constants import (
|
from authentik.sources.saml.processors.constants import (
|
||||||
NS_MAP,
|
NS_MAP,
|
||||||
NS_SAML_METADATA,
|
NS_SAML_METADATA,
|
||||||
@ -47,7 +46,6 @@ class ServiceProviderMetadata:
|
|||||||
|
|
||||||
auth_n_request_signed: bool
|
auth_n_request_signed: bool
|
||||||
assertion_signed: bool
|
assertion_signed: bool
|
||||||
name_id_policy: SAMLNameIDPolicy
|
|
||||||
|
|
||||||
signing_keypair: CertificateKeyPair | None = None
|
signing_keypair: CertificateKeyPair | None = None
|
||||||
|
|
||||||
@ -62,7 +60,6 @@ class ServiceProviderMetadata:
|
|||||||
provider.issuer = self.entity_id
|
provider.issuer = self.entity_id
|
||||||
provider.sp_binding = self.acs_binding
|
provider.sp_binding = self.acs_binding
|
||||||
provider.acs_url = self.acs_location
|
provider.acs_url = self.acs_location
|
||||||
provider.default_name_id_policy = self.name_id_policy
|
|
||||||
if self.signing_keypair and self.auth_n_request_signed:
|
if self.signing_keypair and self.auth_n_request_signed:
|
||||||
self.signing_keypair.name = f"Provider {name} - SAML Signing Certificate"
|
self.signing_keypair.name = f"Provider {name} - SAML Signing Certificate"
|
||||||
self.signing_keypair.save()
|
self.signing_keypair.save()
|
||||||
@ -151,11 +148,6 @@ class ServiceProviderMetadataParser:
|
|||||||
if signing_keypair:
|
if signing_keypair:
|
||||||
self.check_signature(root, signing_keypair)
|
self.check_signature(root, signing_keypair)
|
||||||
|
|
||||||
name_id_format = descriptor.findall(f"{{{NS_SAML_METADATA}}}NameIDFormat")
|
|
||||||
name_id_policy = SAMLNameIDPolicy.UNSPECIFIED
|
|
||||||
if len(name_id_format) > 0:
|
|
||||||
name_id_policy = SAMLNameIDPolicy(name_id_format[0].text)
|
|
||||||
|
|
||||||
return ServiceProviderMetadata(
|
return ServiceProviderMetadata(
|
||||||
entity_id=entity_id,
|
entity_id=entity_id,
|
||||||
acs_binding=acs_binding,
|
acs_binding=acs_binding,
|
||||||
@ -163,5 +155,4 @@ class ServiceProviderMetadataParser:
|
|||||||
auth_n_request_signed=auth_n_request_signed,
|
auth_n_request_signed=auth_n_request_signed,
|
||||||
assertion_signed=assertion_signed,
|
assertion_signed=assertion_signed,
|
||||||
signing_keypair=signing_keypair,
|
signing_keypair=signing_keypair,
|
||||||
name_id_policy=name_id_policy,
|
|
||||||
)
|
)
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
cacheDuration="PT604800S"
|
cacheDuration="PT604800S"
|
||||||
entityID="http://localhost:8080/saml/metadata">
|
entityID="http://localhost:8080/saml/metadata">
|
||||||
<md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
<md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
||||||
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
|
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
|
||||||
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
||||||
Location="http://localhost:8080/saml/acs"
|
Location="http://localhost:8080/saml/acs"
|
||||||
index="1" />
|
index="1" />
|
||||||
|
|||||||
@ -14,7 +14,6 @@ from authentik.lib.xml import lxml_from_string
|
|||||||
from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider
|
from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider
|
||||||
from authentik.providers.saml.processors.metadata import MetadataProcessor
|
from authentik.providers.saml.processors.metadata import MetadataProcessor
|
||||||
from authentik.providers.saml.processors.metadata_parser import ServiceProviderMetadataParser
|
from authentik.providers.saml.processors.metadata_parser import ServiceProviderMetadataParser
|
||||||
from authentik.sources.saml.models import SAMLNameIDPolicy
|
|
||||||
from authentik.sources.saml.processors.constants import ECDSA_SHA256, NS_MAP, NS_SAML_METADATA
|
from authentik.sources.saml.processors.constants import ECDSA_SHA256, NS_MAP, NS_SAML_METADATA
|
||||||
|
|
||||||
|
|
||||||
@ -87,7 +86,6 @@ class TestServiceProviderMetadataParser(TestCase):
|
|||||||
self.assertEqual(provider.acs_url, "http://localhost:8080/saml/acs")
|
self.assertEqual(provider.acs_url, "http://localhost:8080/saml/acs")
|
||||||
self.assertEqual(provider.issuer, "http://localhost:8080/saml/metadata")
|
self.assertEqual(provider.issuer, "http://localhost:8080/saml/metadata")
|
||||||
self.assertEqual(provider.sp_binding, SAMLBindings.POST)
|
self.assertEqual(provider.sp_binding, SAMLBindings.POST)
|
||||||
self.assertEqual(provider.default_name_id_policy, SAMLNameIDPolicy.EMAIL)
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
len(provider.property_mappings.all()),
|
len(provider.property_mappings.all()),
|
||||||
len(SAMLPropertyMapping.objects.exclude(managed__isnull=True)),
|
len(SAMLPropertyMapping.objects.exclude(managed__isnull=True)),
|
||||||
|
|||||||
@ -166,7 +166,6 @@ SPECTACULAR_SETTINGS = {
|
|||||||
"UserVerificationEnum": "authentik.stages.authenticator_webauthn.models.UserVerification",
|
"UserVerificationEnum": "authentik.stages.authenticator_webauthn.models.UserVerification",
|
||||||
"UserTypeEnum": "authentik.core.models.UserTypes",
|
"UserTypeEnum": "authentik.core.models.UserTypes",
|
||||||
"OutgoingSyncDeleteAction": "authentik.lib.sync.outgoing.models.OutgoingSyncDeleteAction",
|
"OutgoingSyncDeleteAction": "authentik.lib.sync.outgoing.models.OutgoingSyncDeleteAction",
|
||||||
"SAMLNameIDPolicyEnum": "authentik.sources.saml.models.SAMLNameIDPolicy",
|
|
||||||
},
|
},
|
||||||
"ENUM_ADD_EXPLICIT_BLANK_NULL_CHOICE": False,
|
"ENUM_ADD_EXPLICIT_BLANK_NULL_CHOICE": False,
|
||||||
"ENUM_GENERATE_CHOICE_DESCRIPTION": False,
|
"ENUM_GENERATE_CHOICE_DESCRIPTION": False,
|
||||||
|
|||||||
@ -1,32 +0,0 @@
|
|||||||
# Generated by Django 5.1.11 on 2025-06-18 09:27
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("authentik_sources_saml", "0019_migrate_usersamlsourceconnection_identifier"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="samlsource",
|
|
||||||
name="name_id_policy",
|
|
||||||
field=models.TextField(
|
|
||||||
choices=[
|
|
||||||
("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", "Email"),
|
|
||||||
("urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", "Persistent"),
|
|
||||||
("urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName", "X509"),
|
|
||||||
(
|
|
||||||
"urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName",
|
|
||||||
"Windows",
|
|
||||||
),
|
|
||||||
("urn:oasis:names:tc:SAML:2.0:nameid-format:transient", "Transient"),
|
|
||||||
("urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", "Unspecified"),
|
|
||||||
],
|
|
||||||
default="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
|
|
||||||
help_text="NameID Policy sent to the IdP. Can be unset, in which case no Policy is sent.",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -39,7 +39,6 @@ from authentik.sources.saml.processors.constants import (
|
|||||||
SAML_NAME_ID_FORMAT_EMAIL,
|
SAML_NAME_ID_FORMAT_EMAIL,
|
||||||
SAML_NAME_ID_FORMAT_PERSISTENT,
|
SAML_NAME_ID_FORMAT_PERSISTENT,
|
||||||
SAML_NAME_ID_FORMAT_TRANSIENT,
|
SAML_NAME_ID_FORMAT_TRANSIENT,
|
||||||
SAML_NAME_ID_FORMAT_UNSPECIFIED,
|
|
||||||
SAML_NAME_ID_FORMAT_WINDOWS,
|
SAML_NAME_ID_FORMAT_WINDOWS,
|
||||||
SAML_NAME_ID_FORMAT_X509,
|
SAML_NAME_ID_FORMAT_X509,
|
||||||
SHA1,
|
SHA1,
|
||||||
@ -74,7 +73,6 @@ class SAMLNameIDPolicy(models.TextChoices):
|
|||||||
X509 = SAML_NAME_ID_FORMAT_X509
|
X509 = SAML_NAME_ID_FORMAT_X509
|
||||||
WINDOWS = SAML_NAME_ID_FORMAT_WINDOWS
|
WINDOWS = SAML_NAME_ID_FORMAT_WINDOWS
|
||||||
TRANSIENT = SAML_NAME_ID_FORMAT_TRANSIENT
|
TRANSIENT = SAML_NAME_ID_FORMAT_TRANSIENT
|
||||||
UNSPECIFIED = SAML_NAME_ID_FORMAT_UNSPECIFIED
|
|
||||||
|
|
||||||
|
|
||||||
class SAMLSource(Source):
|
class SAMLSource(Source):
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
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.2}
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.1}
|
||||||
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.2}
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.1}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: worker
|
command: worker
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
18
go.mod
18
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.4.0
|
github.com/jellydator/ttlcache/v3 v3.3.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.2025062.1
|
goauthentik.io/api/v3 v3.2025061.2
|
||||||
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
|
||||||
@ -62,6 +62,12 @@ require (
|
|||||||
github.com/go-openapi/validate v0.24.0 // indirect
|
github.com/go-openapi/validate v0.24.0 // indirect
|
||||||
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
|
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||||
|
github.com/jackc/pgx/v5 v5.7.5 // indirect
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||||
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/klauspost/compress v1.18.0 // indirect
|
github.com/klauspost/compress v1.18.0 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
@ -77,9 +83,11 @@ require (
|
|||||||
go.opentelemetry.io/otel v1.24.0 // indirect
|
go.opentelemetry.io/otel v1.24.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.24.0 // indirect
|
go.opentelemetry.io/otel/metric v1.24.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
||||||
golang.org/x/crypto v0.36.0 // indirect
|
golang.org/x/crypto v0.39.0 // indirect
|
||||||
golang.org/x/sys v0.31.0 // indirect
|
golang.org/x/sys v0.33.0 // indirect
|
||||||
golang.org/x/text v0.24.0 // indirect
|
golang.org/x/text v0.26.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.5 // indirect
|
google.golang.org/protobuf v1.36.5 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
gorm.io/driver/postgres v1.6.0 // indirect
|
||||||
|
gorm.io/gorm v1.30.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
30
go.sum
30
go.sum
@ -191,6 +191,14 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
|
|||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.7.5 h1:JHGfMnQY+IEtGM63d+NGMjoRpysB2JBwDr5fsngwmJs=
|
||||||
|
github.com/jackc/pgx/v5 v5.7.5/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
|
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
|
||||||
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
||||||
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
|
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
|
||||||
@ -203,8 +211,12 @@ 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.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP4mnWdTY=
|
github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc=
|
||||||
github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4=
|
github.com/jellydator/ttlcache/v3 v3.3.0/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw=
|
||||||
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
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 +310,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.2025062.1 h1:spvILDpDDWJNO3pM6QGqmryx6NvSchr1E8H60J/XUCA=
|
goauthentik.io/api/v3 v3.2025061.2 h1:bKmrl82Gz6J8lz3f+QIH9g+MEkl3MvkMXF34GktesA0=
|
||||||
goauthentik.io/api/v3 v3.2025062.1/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
goauthentik.io/api/v3 v3.2025061.2/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=
|
||||||
@ -308,6 +320,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||||||
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||||
|
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
||||||
|
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@ -415,6 +429,8 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
|
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||||
|
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@ -422,6 +438,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||||
|
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||||
|
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
@ -555,6 +573,10 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
|
||||||
|
gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo=
|
||||||
|
gorm.io/gorm v1.30.0 h1:qbT5aPv1UH8gI99OsRlvDToLxW5zR7FzS9acZDOZcgs=
|
||||||
|
gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|||||||
@ -5,6 +5,7 @@ type Config struct {
|
|||||||
Storage StorageConfig `yaml:"storage"`
|
Storage StorageConfig `yaml:"storage"`
|
||||||
LogLevel string `yaml:"log_level" env:"AUTHENTIK_LOG_LEVEL, overwrite"`
|
LogLevel string `yaml:"log_level" env:"AUTHENTIK_LOG_LEVEL, overwrite"`
|
||||||
ErrorReporting ErrorReportingConfig `yaml:"error_reporting" env:", prefix=AUTHENTIK_ERROR_REPORTING__"`
|
ErrorReporting ErrorReportingConfig `yaml:"error_reporting" env:", prefix=AUTHENTIK_ERROR_REPORTING__"`
|
||||||
|
Postgresql PostgresqlConfig `yaml:"postgresql" env:", prefix=AUTHENTIK_POSTGRESQL__"`
|
||||||
Redis RedisConfig `yaml:"redis" env:", prefix=AUTHENTIK_REDIS__"`
|
Redis RedisConfig `yaml:"redis" env:", prefix=AUTHENTIK_REDIS__"`
|
||||||
Outposts OutpostConfig `yaml:"outposts" env:", prefix=AUTHENTIK_OUTPOSTS__"`
|
Outposts OutpostConfig `yaml:"outposts" env:", prefix=AUTHENTIK_OUTPOSTS__"`
|
||||||
|
|
||||||
@ -25,6 +26,16 @@ type Config struct {
|
|||||||
AuthentikInsecure bool `env:"AUTHENTIK_INSECURE"`
|
AuthentikInsecure bool `env:"AUTHENTIK_INSECURE"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: SSL
|
||||||
|
type PostgresqlConfig struct {
|
||||||
|
Host string `yaml:"host" env:"HOST, overwrite"`
|
||||||
|
Port string `yaml:"port" env:"PORT, overwrite"`
|
||||||
|
User string `yaml:"user" env:"USER, overwrite"`
|
||||||
|
Password string `yaml:"password" env:"PASSWORD, overwrite"`
|
||||||
|
Name string `yaml:"name" env:"NAME, overwrite"`
|
||||||
|
DefaultSchema string `yaml:"default_schema" env:"DEFAULT_SCHEMA, overwrite"`
|
||||||
|
}
|
||||||
|
|
||||||
type RedisConfig struct {
|
type RedisConfig struct {
|
||||||
Host string `yaml:"host" env:"HOST, overwrite"`
|
Host string `yaml:"host" env:"HOST, overwrite"`
|
||||||
Port int `yaml:"port" env:"PORT, overwrite"`
|
Port int `yaml:"port" env:"PORT, overwrite"`
|
||||||
|
|||||||
@ -33,4 +33,4 @@ func UserAgent() string {
|
|||||||
return fmt.Sprintf("authentik@%s", FullVersion())
|
return fmt.Sprintf("authentik@%s", FullVersion())
|
||||||
}
|
}
|
||||||
|
|
||||||
const VERSION = "2025.6.2"
|
const VERSION = "2025.6.1"
|
||||||
|
|||||||
62
internal/web/files.go
Normal file
62
internal/web/files.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-http-utils/etag"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
|
"goauthentik.io/internal/config"
|
||||||
|
"goauthentik.io/internal/constants"
|
||||||
|
)
|
||||||
|
|
||||||
|
type File struct {
|
||||||
|
ID string `gorm:"primaryKey"`
|
||||||
|
|
||||||
|
Name string
|
||||||
|
Content []byte
|
||||||
|
Location string
|
||||||
|
Public bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *WebServer) configureFiles() {
|
||||||
|
// Setup routers
|
||||||
|
filesRouter := ws.loggingRouter.NewRoute().Subrouter()
|
||||||
|
filesRouter.Use(ws.filesHeaderMiddleware)
|
||||||
|
|
||||||
|
filesRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/files/public/{pk}").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
|
||||||
|
pk := vars["pk"]
|
||||||
|
|
||||||
|
var file File
|
||||||
|
ws.postgresClient.First(&file, "id = ? AND public = true AND content <> NULL", pk)
|
||||||
|
|
||||||
|
// TODO: get from DB
|
||||||
|
rw.Write(file.Content)
|
||||||
|
})
|
||||||
|
|
||||||
|
filesRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/files/private/{pk}").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
|
||||||
|
// TODO: check session
|
||||||
|
|
||||||
|
pk := vars["pk"]
|
||||||
|
|
||||||
|
var file File
|
||||||
|
ws.postgresClient.First(&file, "id = ? AND content <> NULL", pk)
|
||||||
|
|
||||||
|
rw.Write([]byte(file.Content))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: anything else?
|
||||||
|
func (ws *WebServer) filesHeaderMiddleware(h http.Handler) http.Handler {
|
||||||
|
etagHandler := etag.Handler(h, false)
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Cache-Control", "public, no-transform")
|
||||||
|
w.Header().Set("X-authentik-version", constants.VERSION)
|
||||||
|
w.Header().Set("Vary", "X-authentik-version, Etag")
|
||||||
|
etagHandler.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -17,6 +17,8 @@ import (
|
|||||||
"github.com/gorilla/securecookie"
|
"github.com/gorilla/securecookie"
|
||||||
"github.com/pires/go-proxyproto"
|
"github.com/pires/go-proxyproto"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
"gorm.io/driver/postgres"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
"goauthentik.io/api/v3"
|
"goauthentik.io/api/v3"
|
||||||
"goauthentik.io/internal/config"
|
"goauthentik.io/internal/config"
|
||||||
@ -49,6 +51,7 @@ type WebServer struct {
|
|||||||
mainRouter *mux.Router
|
mainRouter *mux.Router
|
||||||
loggingRouter *mux.Router
|
loggingRouter *mux.Router
|
||||||
log *log.Entry
|
log *log.Entry
|
||||||
|
postgresClient *gorm.DB
|
||||||
upstreamClient *http.Client
|
upstreamClient *http.Client
|
||||||
upstreamURL *url.URL
|
upstreamURL *url.URL
|
||||||
|
|
||||||
@ -64,6 +67,21 @@ func NewWebServer() *WebServer {
|
|||||||
loggingHandler := mainHandler.NewRoute().Subrouter()
|
loggingHandler := mainHandler.NewRoute().Subrouter()
|
||||||
loggingHandler.Use(web.NewLoggingHandler(l, nil))
|
loggingHandler.Use(web.NewLoggingHandler(l, nil))
|
||||||
|
|
||||||
|
// TODO: ssl
|
||||||
|
postgresDsn := fmt.Sprintf(
|
||||||
|
"host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
|
||||||
|
config.Get().Postgresql.Host,
|
||||||
|
config.Get().Postgresql.Port,
|
||||||
|
config.Get().Postgresql.User,
|
||||||
|
config.Get().Postgresql.Password,
|
||||||
|
config.Get().Postgresql.Name,
|
||||||
|
)
|
||||||
|
|
||||||
|
db, err := gorm.Open(postgres.Open(postgresDsn), &gorm.Config{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
tmp := os.TempDir()
|
tmp := os.TempDir()
|
||||||
socketPath := path.Join(tmp, UnixSocketName)
|
socketPath := path.Join(tmp, UnixSocketName)
|
||||||
|
|
||||||
@ -88,6 +106,7 @@ func NewWebServer() *WebServer {
|
|||||||
mainRouter: mainHandler,
|
mainRouter: mainHandler,
|
||||||
loggingRouter: loggingHandler,
|
loggingRouter: loggingHandler,
|
||||||
log: l,
|
log: l,
|
||||||
|
postgresClient: db,
|
||||||
gunicornReady: false,
|
gunicornReady: false,
|
||||||
upstreamClient: upstreamClient,
|
upstreamClient: upstreamClient,
|
||||||
upstreamURL: u,
|
upstreamURL: u,
|
||||||
|
|||||||
@ -26,7 +26,7 @@ Parameters:
|
|||||||
Description: authentik Docker image
|
Description: authentik Docker image
|
||||||
AuthentikVersion:
|
AuthentikVersion:
|
||||||
Type: String
|
Type: String
|
||||||
Default: 2025.6.2
|
Default: 2025.6.1
|
||||||
Description: authentik Docker image tag
|
Description: authentik Docker image tag
|
||||||
AuthentikServerCPU:
|
AuthentikServerCPU:
|
||||||
Type: Number
|
Type: Number
|
||||||
|
|||||||
@ -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-06-04 00:12+0000\n"
|
"POT-Creation-Date: 2025-05-28 11:25+0000\n"
|
||||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||||
"Last-Translator: Iamanaws, 2025\n"
|
"Last-Translator: Jens L. <jens@goauthentik.io>, 2025\n"
|
||||||
"Language-Team: Spanish (https://app.transifex.com/authentik/teams/119923/es/)\n"
|
"Language-Team: Spanish (https://app.transifex.com/authentik/teams/119923/es/)\n"
|
||||||
"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 "Certificados utilizados para la autenticación del cliente."
|
msgstr ""
|
||||||
|
|
||||||
#: 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 un grupo como su propio padre."
|
msgstr "No se puede establecer el grupo como padre de sí mismo."
|
||||||
|
|
||||||
#: 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 "Habilitar el estado de superusuario"
|
msgstr "Habiliar estado de \"superusuario\""
|
||||||
|
|
||||||
#: authentik/core/models.py
|
#: authentik/core/models.py
|
||||||
msgid "Disable superuser status"
|
msgid "Disable superuser status"
|
||||||
msgstr "Deshabilitar el estado de superusuario"
|
msgstr "Deshabiliar 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 utilizado para finalizar la sesión desde un proveedor."
|
msgstr "Flujo usado para terminar la sesión de 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 "Derecho de Aplicación"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py
|
#: authentik/core/models.py
|
||||||
msgid "Application Entitlements"
|
msgid "Application Entitlements"
|
||||||
msgstr "Derechos de Aplicación"
|
msgstr ""
|
||||||
|
|
||||||
#: 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 ""
|
||||||
"Enlace a un usuario con la misma dirección de correo electrónico. Puede "
|
"Apunta a un usuario con una dirección de correo electrónico idéntica. Puede "
|
||||||
"tener implicaciones de seguridad cuando una fuente no valida las direcciones"
|
"tener implicaciones de seguridad cuando una fuente no valida la dirección de"
|
||||||
" de correo electrónico."
|
" 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 el mismo nombre de usuario. Puede tener "
|
"Enlace a un usuario con un nombre de usuario idéntico. Puede tener "
|
||||||
"implicaciones de seguridad cuando un nombre de usuario se utiliza con otra "
|
"implicaciones de seguridad cuando se usa un nombre de usuario 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 el mismo nombre. Puede tener implicaciones de "
|
"Enlace a un grupo con un nombre idéntico. Puede tener implicaciones de "
|
||||||
"seguridad cuando un nombre de grupo se utiliza con otra fuente."
|
"seguridad cuando se utiliza un nombre de grupo 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 "datos de sesión"
|
msgstr ""
|
||||||
|
|
||||||
#: 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} enlazado correctamente!"
|
msgstr "¡{source} vinculado exitosamente!"
|
||||||
|
|
||||||
#: 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 Certificado-Clave"
|
msgstr "Par de claves de certificado"
|
||||||
|
|
||||||
#: authentik/crypto/models.py
|
#: authentik/crypto/models.py
|
||||||
msgid "Certificate-Key Pairs"
|
msgid "Certificate-Key Pairs"
|
||||||
msgstr "Pares Certificado-Clave"
|
msgstr "Pares de claves de certificado"
|
||||||
|
|
||||||
#: 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 "Número de contraseñas contra las que verificar."
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/enterprise/policies/unique_password/models.py
|
#: authentik/enterprise/policies/unique_password/models.py
|
||||||
#: authentik/policies/password/models.py
|
#: authentik/policies/password/models.py
|
||||||
@ -521,20 +521,18 @@ 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 "Política de Unicidad de Contraseñas"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/enterprise/policies/unique_password/models.py
|
#: authentik/enterprise/policies/unique_password/models.py
|
||||||
msgid "Password Uniqueness Policies"
|
msgid "Password Uniqueness Policies"
|
||||||
msgstr "Políticas de Unicidad de Contraseñas"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/enterprise/policies/unique_password/models.py
|
#: authentik/enterprise/policies/unique_password/models.py
|
||||||
msgid "User Password History"
|
msgid "User Password History"
|
||||||
msgstr "Historial de Contraseñas del Usuario"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/enterprise/policy.py
|
#: authentik/enterprise/policy.py
|
||||||
msgid "Enterprise required to access this feature."
|
msgid "Enterprise required to access this feature."
|
||||||
@ -619,39 +617,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 "Clave utilizada para firmar los eventos SSF."
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/enterprise/providers/ssf/models.py
|
#: authentik/enterprise/providers/ssf/models.py
|
||||||
msgid "Shared Signals Framework Provider"
|
msgid "Shared Signals Framework Provider"
|
||||||
msgstr "Proveedor del Marco de Señales Compartidas"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/enterprise/providers/ssf/models.py
|
#: authentik/enterprise/providers/ssf/models.py
|
||||||
msgid "Shared Signals Framework Providers"
|
msgid "Shared Signals Framework Providers"
|
||||||
msgstr "Proveedores del Marco de Señales Compartidas"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/enterprise/providers/ssf/models.py
|
#: authentik/enterprise/providers/ssf/models.py
|
||||||
msgid "Add stream to SSF provider"
|
msgid "Add stream to SSF provider"
|
||||||
msgstr "Agregar flujo de datos al proveedor SSF"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/enterprise/providers/ssf/models.py
|
#: authentik/enterprise/providers/ssf/models.py
|
||||||
msgid "SSF Stream"
|
msgid "SSF Stream"
|
||||||
msgstr "Flujo de Datos SSF"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/enterprise/providers/ssf/models.py
|
#: authentik/enterprise/providers/ssf/models.py
|
||||||
msgid "SSF Streams"
|
msgid "SSF Streams"
|
||||||
msgstr "Flujos de Datos SSF"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/enterprise/providers/ssf/models.py
|
#: authentik/enterprise/providers/ssf/models.py
|
||||||
msgid "SSF Stream Event"
|
msgid "SSF Stream Event"
|
||||||
msgstr "Evento de Flujo de Datos SSF"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/enterprise/providers/ssf/models.py
|
#: authentik/enterprise/providers/ssf/models.py
|
||||||
msgid "SSF Stream Events"
|
msgid "SSF Stream Events"
|
||||||
msgstr "Eventos de Flujos de Datos SSF"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/enterprise/providers/ssf/tasks.py
|
#: authentik/enterprise/providers/ssf/tasks.py
|
||||||
msgid "Failed to send request"
|
msgid "Failed to send request"
|
||||||
msgstr "Error al enviar la solicitud"
|
msgstr "Falló envio de petición"
|
||||||
|
|
||||||
#: 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"
|
||||||
@ -683,29 +681,26 @@ 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 "Etapa de TLS mutuo"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/enterprise/stages/mtls/models.py
|
#: authentik/enterprise/stages/mtls/models.py
|
||||||
msgid "Mutual TLS Stages"
|
msgid "Mutual TLS Stages"
|
||||||
msgstr "Etapas de TLS mutuo"
|
msgstr ""
|
||||||
|
|
||||||
#: 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 "Permisos para pasar Certificados a los puestos avanzados."
|
msgstr ""
|
||||||
|
|
||||||
#: 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 "Se requiere certificado, pero no se proporcionó ninguno."
|
msgstr ""
|
||||||
|
|
||||||
#: 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 "No se encontró usuario para el certificado."
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/enterprise/stages/source/models.py
|
#: authentik/enterprise/stages/source/models.py
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -758,16 +753,12 @@ msgid ""
|
|||||||
"Customize the body of the request. Mapping should return data that is JSON-"
|
"Customize the body of the request. Mapping should return data that is JSON-"
|
||||||
"serializable."
|
"serializable."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"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 ""
|
||||||
@ -795,7 +786,7 @@ msgstr "Transporte de notificaciones"
|
|||||||
|
|
||||||
#: authentik/events/models.py
|
#: authentik/events/models.py
|
||||||
msgid "Notification Transports"
|
msgid "Notification Transports"
|
||||||
msgstr "Medios de Notificación"
|
msgstr "Transportes de notificación"
|
||||||
|
|
||||||
#: authentik/events/models.py
|
#: authentik/events/models.py
|
||||||
msgid "Notice"
|
msgid "Notice"
|
||||||
@ -822,9 +813,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 ""
|
||||||
"Selecciona qué medios se deben usar para notificar al usuario. Si no se "
|
"Seleccione qué transportes 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 "
|
||||||
"authentik."
|
"usuario de 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."
|
||||||
@ -996,7 +987,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 "Evaluar las políticas cuando la Etapa se presenta al usuario."
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/flows/models.py
|
#: authentik/flows/models.py
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -1043,8 +1034,6 @@ 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"
|
||||||
@ -1052,21 +1041,20 @@ 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 "Sincronizando usuarios"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/lib/sync/outgoing/tasks.py
|
#: authentik/lib/sync/outgoing/tasks.py
|
||||||
msgid "Syncing groups"
|
msgid "Syncing groups"
|
||||||
msgstr "Sincronizando grupos"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/lib/sync/outgoing/tasks.py
|
#: authentik/lib/sync/outgoing/tasks.py
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Syncing page {page} of {object_type}"
|
msgid "Syncing page {page} of groups"
|
||||||
msgstr "Sincronizando página {page} de {object_type}"
|
msgstr "Sincronizando página {page} de grupos"
|
||||||
|
|
||||||
#: 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
|
||||||
@ -1245,7 +1233,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 expirado."
|
msgstr "La contraseña ha caducado."
|
||||||
|
|
||||||
#: authentik/policies/expiry/models.py
|
#: authentik/policies/expiry/models.py
|
||||||
msgid "Password Expiry Policy"
|
msgid "Password Expiry Policy"
|
||||||
@ -1283,7 +1271,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 anterior es mayor que el umbral."
|
msgstr "La distancia desde la autenticación previa es mayor que el límite."
|
||||||
|
|
||||||
#: authentik/policies/geoip/models.py
|
#: authentik/policies/geoip/models.py
|
||||||
msgid "Distance is further than possible."
|
msgid "Distance is further than possible."
|
||||||
@ -1332,7 +1320,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 ""
|
||||||
@ -1606,11 +1594,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 "ES384 (Encriptación Asimétrica)"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py
|
#: authentik/providers/oauth2/models.py
|
||||||
msgid "ES512 (Asymmetric Encryption)"
|
msgid "ES512 (Asymmetric Encryption)"
|
||||||
msgstr "ES512 (Encriptación Asimétrica)"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py
|
#: authentik/providers/oauth2/models.py
|
||||||
msgid "Scope used by the client"
|
msgid "Scope used by the client"
|
||||||
@ -1825,7 +1813,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 del host interno"
|
msgstr "Validación SSL de host interno"
|
||||||
|
|
||||||
#: authentik/providers/proxy/models.py
|
#: authentik/providers/proxy/models.py
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -2039,7 +2027,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: authentik/providers/saml/models.py
|
#: authentik/providers/saml/models.py
|
||||||
msgid "AuthnContextClassRef Property Mapping"
|
msgid "AuthnContextClassRef Property Mapping"
|
||||||
msgstr "Asignación de Propiedades de AuthnContextClassRef"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/saml/models.py
|
#: authentik/providers/saml/models.py
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -2047,9 +2035,6 @@ 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 ""
|
||||||
@ -2199,11 +2184,11 @@ msgstr "Predeterminado"
|
|||||||
|
|
||||||
#: authentik/providers/scim/models.py
|
#: authentik/providers/scim/models.py
|
||||||
msgid "AWS"
|
msgid "AWS"
|
||||||
msgstr "AWS"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/scim/models.py
|
#: authentik/providers/scim/models.py
|
||||||
msgid "Slack"
|
msgid "Slack"
|
||||||
msgstr "Slack"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/scim/models.py
|
#: authentik/providers/scim/models.py
|
||||||
msgid "Base URL to SCIM requests, usually ends in /v2"
|
msgid "Base URL to SCIM requests, usually ends in /v2"
|
||||||
@ -2215,13 +2200,11 @@ msgstr "Token de Autenticación"
|
|||||||
|
|
||||||
#: authentik/providers/scim/models.py
|
#: authentik/providers/scim/models.py
|
||||||
msgid "SCIM Compatibility Mode"
|
msgid "SCIM Compatibility Mode"
|
||||||
msgstr "Modo de Compatibilidad SCIM"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/scim/models.py
|
#: authentik/providers/scim/models.py
|
||||||
msgid "Alter authentik behavior for vendor-specific SCIM implementations."
|
msgid "Alter authentik behavior for vendor-specific SCIM implementations."
|
||||||
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"
|
||||||
@ -2249,7 +2232,7 @@ msgstr "Roles"
|
|||||||
|
|
||||||
#: authentik/rbac/models.py
|
#: authentik/rbac/models.py
|
||||||
msgid "Initial Permissions"
|
msgid "Initial Permissions"
|
||||||
msgstr "Permisos Iniciales"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/rbac/models.py
|
#: authentik/rbac/models.py
|
||||||
msgid "System permission"
|
msgid "System permission"
|
||||||
@ -2287,7 +2270,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: authentik/recovery/views.py
|
#: authentik/recovery/views.py
|
||||||
msgid "Used recovery-link to authenticate."
|
msgid "Used recovery-link to authenticate."
|
||||||
msgstr "Se utilizó un enlace de recuperación para autenticarse."
|
msgstr "Se usó el enlace de recuperación para autenticarse."
|
||||||
|
|
||||||
#: authentik/sources/kerberos/models.py
|
#: authentik/sources/kerberos/models.py
|
||||||
msgid "Kerberos realm"
|
msgid "Kerberos realm"
|
||||||
@ -2299,7 +2282,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 "Tipo de servidor KAdmin"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/kerberos/models.py
|
#: authentik/sources/kerberos/models.py
|
||||||
msgid "Sync users from Kerberos into authentik"
|
msgid "Sync users from Kerberos into authentik"
|
||||||
@ -2307,24 +2290,23 @@ 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 ""
|
msgstr "Cuando un usuario cambia su contraseña, sincronizarlo hacia Kerberos"
|
||||||
"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 en kadmin para la sincronización."
|
msgstr "Principal para autenticarse como 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 en kadmin para la sincronización"
|
msgstr "Contraseña para autenticarse como 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 en kadmin para la sincronización. Debe estar "
|
"Keytab para autenticarse como kadmin para la sincronización. Debe estar "
|
||||||
"codificado en base64 o en el formato TIPO:residuo"
|
"codificado en base64 o en el formato TIPO:residual"
|
||||||
|
|
||||||
#: authentik/sources/kerberos/models.py
|
#: authentik/sources/kerberos/models.py
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -2340,7 +2322,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@nombre_de_host"
|
" el formato HTTP@nombredelservidor"
|
||||||
|
|
||||||
#: 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"
|
||||||
@ -2357,8 +2339,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 en authentik se actualizará al "
|
"Si está habilitado, la contraseña almacenada por authentik será actualizada "
|
||||||
"iniciar sesión con el backend de contraseñas de Kerberos."
|
"al iniciar sesión con el backend de contraseñas Kerberos"
|
||||||
|
|
||||||
#: authentik/sources/kerberos/models.py
|
#: authentik/sources/kerberos/models.py
|
||||||
msgid "Kerberos Source"
|
msgid "Kerberos Source"
|
||||||
@ -2406,7 +2388,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
" Asegúrate de que tienes entradas válidas\n"
|
" Asegúrate de que tienes entradas válidas\n"
|
||||||
" (obtenibles mediante kinit) \n"
|
" (se obtienen a través de 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"
|
||||||
" "
|
" "
|
||||||
@ -2471,10 +2453,6 @@ 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."
|
||||||
@ -2507,17 +2485,12 @@ 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"
|
||||||
@ -2539,24 +2512,22 @@ 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 "Conexión de Fuente LDAP de Usuario"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/ldap/models.py
|
#: authentik/sources/ldap/models.py
|
||||||
msgid "User LDAP Source Connections"
|
msgid "User LDAP Source Connections"
|
||||||
msgstr "Conexiones de Fuente LDAP de Usuario"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/ldap/models.py
|
#: authentik/sources/ldap/models.py
|
||||||
msgid "Group LDAP Source Connection"
|
msgid "Group LDAP Source Connection"
|
||||||
msgstr "Conexión de Fuente LDAP de Grupo"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/ldap/models.py
|
#: authentik/sources/ldap/models.py
|
||||||
msgid "Group LDAP Source Connections"
|
msgid "Group LDAP Source Connections"
|
||||||
msgstr "Conexiones de Fuente LDAP de Grupo"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/ldap/signals.py
|
#: authentik/sources/ldap/signals.py
|
||||||
msgid "Password does not match Active Directory Complexity."
|
msgid "Password does not match Active Directory Complexity."
|
||||||
@ -2568,11 +2539,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 "Autenticación Básica HTTP"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py
|
#: authentik/sources/oauth/models.py
|
||||||
msgid "Include the client ID and secret as request parameters"
|
msgid "Include the client ID and secret as request parameters"
|
||||||
msgstr "Incluir el ID de cliente y el secreto como parámetros de la solicitud"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py
|
#: authentik/sources/oauth/models.py
|
||||||
msgid "Request Token URL"
|
msgid "Request Token URL"
|
||||||
@ -2619,8 +2590,6 @@ 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"
|
||||||
@ -2938,7 +2907,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 "Continuar a {source_name}"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/scim/models.py
|
#: authentik/sources/scim/models.py
|
||||||
msgid "SCIM Source"
|
msgid "SCIM Source"
|
||||||
@ -2974,7 +2943,7 @@ msgstr "Dispositivos Duo"
|
|||||||
|
|
||||||
#: authentik/stages/authenticator_email/models.py
|
#: authentik/stages/authenticator_email/models.py
|
||||||
msgid "Email OTP"
|
msgid "Email OTP"
|
||||||
msgstr "OTP por Correo Electrónico"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/authenticator_email/models.py
|
#: authentik/stages/authenticator_email/models.py
|
||||||
#: authentik/stages/email/models.py
|
#: authentik/stages/email/models.py
|
||||||
@ -2995,11 +2964,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 "Etapa de Configuración del Autenticador de Correo Electrónico"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/authenticator_email/models.py
|
#: authentik/stages/authenticator_email/models.py
|
||||||
msgid "Email Authenticator Setup Stages"
|
msgid "Email Authenticator Setup Stages"
|
||||||
msgstr "Etapas de Configuración del Autenticador de Correo Electrónico"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/authenticator_email/models.py
|
#: authentik/stages/authenticator_email/models.py
|
||||||
#: authentik/stages/authenticator_email/stage.py
|
#: authentik/stages/authenticator_email/stage.py
|
||||||
@ -3010,11 +2979,11 @@ msgstr ""
|
|||||||
|
|
||||||
#: authentik/stages/authenticator_email/models.py
|
#: authentik/stages/authenticator_email/models.py
|
||||||
msgid "Email Device"
|
msgid "Email Device"
|
||||||
msgstr "Dispositivo de correo electrónico"
|
msgstr "Dispositivo de Email"
|
||||||
|
|
||||||
#: authentik/stages/authenticator_email/models.py
|
#: authentik/stages/authenticator_email/models.py
|
||||||
msgid "Email Devices"
|
msgid "Email Devices"
|
||||||
msgstr "Dispositivos de correo electrónico"
|
msgstr "Dispositivos de Email"
|
||||||
|
|
||||||
#: authentik/stages/authenticator_email/stage.py
|
#: authentik/stages/authenticator_email/stage.py
|
||||||
#: authentik/stages/authenticator_sms/stage.py
|
#: authentik/stages/authenticator_sms/stage.py
|
||||||
@ -3024,7 +2993,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 "Correo electrónico inválido"
|
msgstr "Email 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
|
||||||
@ -3044,9 +3013,6 @@ 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
|
||||||
@ -3056,8 +3022,7 @@ 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.\n"
|
"Si no solicitaste este código, por favor ignora este correo. El código anterior es válido por %(expires)s."
|
||||||
" "
|
|
||||||
|
|
||||||
#: 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
|
||||||
@ -3070,8 +3035,6 @@ 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
|
||||||
@ -3313,8 +3276,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 ""
|
||||||
"Desfase después del cual expira el consentimiento. (Formato: "
|
"Compensación después de la cual caduca el consentimiento. (Formato: horas = "
|
||||||
"hours=1;minutes=2;seconds=3)."
|
"1; minutos = 2; segundos = 3)."
|
||||||
|
|
||||||
#: authentik/stages/consent/models.py
|
#: authentik/stages/consent/models.py
|
||||||
msgid "Consent Stage"
|
msgid "Consent Stage"
|
||||||
@ -3334,7 +3297,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 "Token de consentimiento inválido, mostrando el aviso nuevamente"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/deny/models.py
|
#: authentik/stages/deny/models.py
|
||||||
msgid "Deny Stage"
|
msgid "Deny Stage"
|
||||||
@ -3354,11 +3317,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 "Continúa para confirmar esta dirección de correo electrónico."
|
msgstr ""
|
||||||
|
|
||||||
#: 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 "El enlace ya fue utilizado, por favor, solícita uno nuevo."
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/email/models.py
|
#: authentik/stages/email/models.py
|
||||||
msgid "Password Reset"
|
msgid "Password Reset"
|
||||||
@ -3482,8 +3445,7 @@ 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.\n"
|
"Si no solicitaste un cambio de contraseña, por favor ignora este correo. El enlace anterior es válido por %(expires)s."
|
||||||
" "
|
|
||||||
|
|
||||||
#: authentik/stages/email/templates/email/password_reset.txt
|
#: authentik/stages/email/templates/email/password_reset.txt
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -3567,26 +3529,24 @@ 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 se enlaza en la parte inferior de la "
|
"Flujo de inscripción opcional, que está vinculado 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 se enlaza en la parte inferior de la "
|
"Flujo de recuperación opcional, que está vinculado en la parte inferior de "
|
||||||
"página."
|
"la 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 opcional sin contraseña, que se enlaza en la parte inferior de la "
|
"Flujo sin contraseña opcional, el cual está vinculado en la parte inferior "
|
||||||
"página."
|
"de la 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."
|
||||||
@ -3820,11 +3780,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 "La URL de destino debe estar presente cuando el modo es Estático."
|
msgstr ""
|
||||||
|
|
||||||
#: 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 "El Flujo de Destino debe estar presente cuando el modo es Flujo."
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/redirect/models.py
|
#: authentik/stages/redirect/models.py
|
||||||
msgid "Redirect Stage"
|
msgid "Redirect Stage"
|
||||||
@ -3881,6 +3841,10 @@ 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"
|
||||||
@ -3956,12 +3920,10 @@ msgstr ""
|
|||||||
#: authentik/tenants/models.py
|
#: authentik/tenants/models.py
|
||||||
msgid "Reputation cannot decrease lower than this value. Zero or negative."
|
msgid "Reputation cannot decrease lower than this value. Zero or negative."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"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."
|
||||||
@ -3984,8 +3946,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 que los administradores proporcionen una razón para personificar a "
|
"Requerir a los administradores proporcionar una razón para suplantar un "
|
||||||
"un usuario."
|
"usuario."
|
||||||
|
|
||||||
#: authentik/tenants/models.py
|
#: authentik/tenants/models.py
|
||||||
msgid "Default token duration"
|
msgid "Default token duration"
|
||||||
@ -3997,7 +3959,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"
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/authentik",
|
"name": "@goauthentik/authentik",
|
||||||
"version": "2025.6.2",
|
"version": "2025.6.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@goauthentik/authentik",
|
"name": "@goauthentik/authentik",
|
||||||
"version": "2025.6.2",
|
"version": "2025.6.1",
|
||||||
"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.2",
|
"version": "2025.6.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
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.1",
|
"version": "0.20.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.1.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz",
|
||||||
"integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==",
|
"integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==",
|
||||||
"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.29.0",
|
"version": "9.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz",
|
||||||
"integrity": "sha512-3PIF4cBw/y+1u2EazflInpV+lYsSG0aByVIQzAgb1m1MhHFSbqTyNqtBKHgWf/9Ykud+DhILS9EGkmekVhbKoQ==",
|
"integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==",
|
||||||
"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.1",
|
"version": "8.34.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.0.tgz",
|
||||||
"integrity": "sha512-STXcN6ebF6li4PxwNeFnqF8/2BNDvBupf2OPx2yWNzr6mKNGF7q49VM00Pz5FaomJyqvbXpY6PhO+T9w139YEQ==",
|
"integrity": "sha512-QXwAlHlbcAwNlEEMKQS2RCgJsgXrTJdjXT08xEgbPFa2yYQgVjBymxP5DrfrE7X7iodSzd9qBUHUycdyVJTW1w==",
|
||||||
"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.1",
|
"@typescript-eslint/scope-manager": "8.34.0",
|
||||||
"@typescript-eslint/type-utils": "8.34.1",
|
"@typescript-eslint/type-utils": "8.34.0",
|
||||||
"@typescript-eslint/utils": "8.34.1",
|
"@typescript-eslint/utils": "8.34.0",
|
||||||
"@typescript-eslint/visitor-keys": "8.34.1",
|
"@typescript-eslint/visitor-keys": "8.34.0",
|
||||||
"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.1",
|
"@typescript-eslint/parser": "^8.34.0",
|
||||||
"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.1",
|
"version": "8.34.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.0.tgz",
|
||||||
"integrity": "sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==",
|
"integrity": "sha512-vxXJV1hVFx3IXz/oy2sICsJukaBrtDEQSBiV48/YIV5KWjX1dO+bcIr/kCPrW6weKXvsaGKFNlwH0v2eYdRRbA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.34.1",
|
"@typescript-eslint/scope-manager": "8.34.0",
|
||||||
"@typescript-eslint/types": "8.34.1",
|
"@typescript-eslint/types": "8.34.0",
|
||||||
"@typescript-eslint/typescript-estree": "8.34.1",
|
"@typescript-eslint/typescript-estree": "8.34.0",
|
||||||
"@typescript-eslint/visitor-keys": "8.34.1",
|
"@typescript-eslint/visitor-keys": "8.34.0",
|
||||||
"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.1",
|
"version": "8.34.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.0.tgz",
|
||||||
"integrity": "sha512-nuHlOmFZfuRwLJKDGQOVc0xnQrAmuq1Mj/ISou5044y1ajGNp2BNliIqp7F2LPQ5sForz8lempMFCovfeS1XoA==",
|
"integrity": "sha512-iEgDALRf970/B2YExmtPMPF54NenZUf4xpL3wsCRx/lgjz6ul/l13R81ozP/ZNuXfnLCS+oPmG7JIxfdNYKELw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/tsconfig-utils": "^8.34.1",
|
"@typescript-eslint/tsconfig-utils": "^8.34.0",
|
||||||
"@typescript-eslint/types": "^8.34.1",
|
"@typescript-eslint/types": "^8.34.0",
|
||||||
"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.1",
|
"version": "8.34.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.0.tgz",
|
||||||
"integrity": "sha512-beu6o6QY4hJAgL1E8RaXNC071G4Kso2MGmJskCFQhRhg8VOH/FDbC8soP8NHN7e/Hdphwp8G8cE6OBzC8o41ZA==",
|
"integrity": "sha512-9Ac0X8WiLykl0aj1oYQNcLZjHgBojT6cW68yAgZ19letYu+Hxd0rE0veI1XznSSst1X5lwnxhPbVdwjDRIomRw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.34.1",
|
"@typescript-eslint/types": "8.34.0",
|
||||||
"@typescript-eslint/visitor-keys": "8.34.1"
|
"@typescript-eslint/visitor-keys": "8.34.0"
|
||||||
},
|
},
|
||||||
"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.1",
|
"version": "8.34.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.0.tgz",
|
||||||
"integrity": "sha512-K4Sjdo4/xF9NEeA2khOb7Y5nY6NSXBnod87uniVYW9kHP+hNlDV8trUSFeynA2uxWam4gIWgWoygPrv9VMWrYg==",
|
"integrity": "sha512-+W9VYHKFIzA5cBeooqQxqNriAP0QeQ7xTiDuIOr71hzgffm3EL2hxwWBIIj4GuofIbKxGNarpKqIq6Q6YrShOA==",
|
||||||
"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.1",
|
"version": "8.34.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.0.tgz",
|
||||||
"integrity": "sha512-Tv7tCCr6e5m8hP4+xFugcrwTOucB8lshffJ6zf1mF1TbU67R+ntCc6DzLNKM+s/uzDyv8gLq7tufaAhIBYeV8g==",
|
"integrity": "sha512-n7zSmOcUVhcRYC75W2pnPpbO1iwhJY3NLoHEtbJwJSNlVAZuwqu05zY3f3s2SDWWDSo9FdN5szqc73DCtDObAg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "8.34.1",
|
"@typescript-eslint/typescript-estree": "8.34.0",
|
||||||
"@typescript-eslint/utils": "8.34.1",
|
"@typescript-eslint/utils": "8.34.0",
|
||||||
"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.1",
|
"version": "8.34.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.0.tgz",
|
||||||
"integrity": "sha512-rjLVbmE7HR18kDsjNIZQHxmv9RZwlgzavryL5Lnj2ujIRTeXlKtILHgRNmQ3j4daw7zd+mQgy+uyt6Zo6I0IGA==",
|
"integrity": "sha512-9V24k/paICYPniajHfJ4cuAWETnt7Ssy+R0Rbcqo5sSFr3QEZ/8TSoUi9XeXVBGXCaLtwTOKSLGcInCAvyZeMA==",
|
||||||
"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.1",
|
"version": "8.34.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.0.tgz",
|
||||||
"integrity": "sha512-rjCNqqYPuMUF5ODD+hWBNmOitjBWghkGKJg6hiCHzUvXRy6rK22Jd3rwbP2Xi+R7oYVvIKhokHVhH41BxPV5mA==",
|
"integrity": "sha512-rOi4KZxI7E0+BMqG7emPSK1bB4RICCpF7QD3KCLXn9ZvWoESsOMlHyZPAHyG04ujVplPaHbmEvs34m+wjgtVtg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/project-service": "8.34.1",
|
"@typescript-eslint/project-service": "8.34.0",
|
||||||
"@typescript-eslint/tsconfig-utils": "8.34.1",
|
"@typescript-eslint/tsconfig-utils": "8.34.0",
|
||||||
"@typescript-eslint/types": "8.34.1",
|
"@typescript-eslint/types": "8.34.0",
|
||||||
"@typescript-eslint/visitor-keys": "8.34.1",
|
"@typescript-eslint/visitor-keys": "8.34.0",
|
||||||
"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.2",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||||
"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.1",
|
"version": "8.34.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.0.tgz",
|
||||||
"integrity": "sha512-mqOwUdZ3KjtGk7xJJnLbHxTuWVn3GO2WZZuM+Slhkun4+qthLdXx32C8xIXbO1kfCECb3jIs3eoxK3eryk7aoQ==",
|
"integrity": "sha512-8L4tWatGchV9A1cKbjaavS6mwYwp39jql8xUmIIKJdm+qiaeHy5KMKlBrf30akXAWBzn2SqKsNOtSENWUwg7XQ==",
|
||||||
"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.1",
|
"@typescript-eslint/scope-manager": "8.34.0",
|
||||||
"@typescript-eslint/types": "8.34.1",
|
"@typescript-eslint/types": "8.34.0",
|
||||||
"@typescript-eslint/typescript-estree": "8.34.1"
|
"@typescript-eslint/typescript-estree": "8.34.0"
|
||||||
},
|
},
|
||||||
"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.1",
|
"version": "8.34.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.0.tgz",
|
||||||
"integrity": "sha512-xoh5rJ+tgsRKoXnkBPFRLZ7rjKM0AfVbC68UZ/ECXoDbfggb9RbEySN359acY1vS3qZ0jVTVWzbtfapwm5ztxw==",
|
"integrity": "sha512-qHV7pW7E85A0x6qyrFn+O+q1k1p3tQCsqIZ1KZ5ESLXY57aTvUd3/a4rdPTeXisvhXn2VQG0VSKUqs8KHF2zcA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.34.1",
|
"@typescript-eslint/types": "8.34.0",
|
||||||
"eslint-visitor-keys": "^4.2.1"
|
"eslint-visitor-keys": "^4.2.0"
|
||||||
},
|
},
|
||||||
"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.15.0",
|
"version": "8.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
|
||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
@ -1554,18 +1554,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "9.29.0",
|
"version": "9.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz",
|
||||||
"integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
|
"integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==",
|
||||||
"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.1",
|
"@eslint/config-array": "^0.20.0",
|
||||||
"@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.29.0",
|
"@eslint/js": "9.28.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.4.0",
|
"eslint-scope": "^8.3.0",
|
||||||
"eslint-visitor-keys": "^4.2.1",
|
"eslint-visitor-keys": "^4.2.0",
|
||||||
"espree": "^10.4.0",
|
"espree": "^10.3.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.4.0",
|
"version": "8.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz",
|
||||||
"integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
|
"integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==",
|
||||||
"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.1",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
|
||||||
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
|
"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
|
||||||
"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.4.0",
|
"version": "10.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
|
||||||
"integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
|
"integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "^8.15.0",
|
"acorn": "^8.14.0",
|
||||||
"acorn-jsx": "^5.3.2",
|
"acorn-jsx": "^5.3.2",
|
||||||
"eslint-visitor-keys": "^4.2.1"
|
"eslint-visitor-keys": "^4.2.0"
|
||||||
},
|
},
|
||||||
"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.1",
|
"version": "8.34.0",
|
||||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.1.tgz",
|
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.0.tgz",
|
||||||
"integrity": "sha512-XjS+b6Vg9oT1BaIUfkW3M3LvqZE++rbzAMEHuccCfO/YkP43ha6w3jTEMilQxMF92nVOYCcdjv1ZUhAa1D/0ow==",
|
"integrity": "sha512-MRpfN7uYjTrTGigFCt8sRyNqJFhjN0WwZecldaqhWm+wy0gaRt8Edb/3cuUy0zdq2opJWT6iXINKAtewnDOltQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "8.34.1",
|
"@typescript-eslint/eslint-plugin": "8.34.0",
|
||||||
"@typescript-eslint/parser": "8.34.1",
|
"@typescript-eslint/parser": "8.34.0",
|
||||||
"@typescript-eslint/utils": "8.34.1"
|
"@typescript-eslint/utils": "8.34.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "authentik"
|
name = "authentik"
|
||||||
version = "2025.6.2"
|
version = "2025.6.1"
|
||||||
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.*"
|
||||||
@ -48,7 +48,7 @@ dependencies = [
|
|||||||
"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.7",
|
"pydantic==2.11.5",
|
||||||
"pydantic-scim==0.0.8",
|
"pydantic-scim==0.0.8",
|
||||||
"pyjwt==2.10.1",
|
"pyjwt==2.10.1",
|
||||||
"pyrad==2.4",
|
"pyrad==2.4",
|
||||||
@ -68,7 +68,7 @@ dependencies = [
|
|||||||
"urllib3<3",
|
"urllib3<3",
|
||||||
"uvicorn[standard]==0.34.3",
|
"uvicorn[standard]==0.34.3",
|
||||||
"watchdog==6.0.0",
|
"watchdog==6.0.0",
|
||||||
"webauthn==2.6.0",
|
"webauthn==2.5.2",
|
||||||
"wsproto==1.2.0",
|
"wsproto==1.2.0",
|
||||||
"xmlsec==1.3.15",
|
"xmlsec==1.3.15",
|
||||||
"zxcvbn==4.5.0",
|
"zxcvbn==4.5.0",
|
||||||
|
|||||||
43
schema.yml
43
schema.yml
@ -1,7 +1,7 @@
|
|||||||
openapi: 3.0.3
|
openapi: 3.0.3
|
||||||
info:
|
info:
|
||||||
title: authentik
|
title: authentik
|
||||||
version: 2025.6.2
|
version: 2025.6.1
|
||||||
description: Making authentication simple.
|
description: Making authentication simple.
|
||||||
contact:
|
contact:
|
||||||
email: hello@goauthentik.io
|
email: hello@goauthentik.io
|
||||||
@ -22454,17 +22454,6 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
- in: query
|
|
||||||
name: default_name_id_policy
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
enum:
|
|
||||||
- urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
|
|
||||||
- urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
|
|
||||||
- urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
|
|
||||||
- urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName
|
|
||||||
- urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
|
|
||||||
- urn:oasis:names:tc:SAML:2.0:nameid-format:transient
|
|
||||||
- in: query
|
- in: query
|
||||||
name: default_relay_state
|
name: default_relay_state
|
||||||
schema:
|
schema:
|
||||||
@ -29681,7 +29670,6 @@ paths:
|
|||||||
enum:
|
enum:
|
||||||
- urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
|
- urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
|
||||||
- urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
|
- urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
|
||||||
- urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
|
|
||||||
- urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName
|
- urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName
|
||||||
- urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
|
- urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
|
||||||
- urn:oasis:names:tc:SAML:2.0:nameid-format:transient
|
- urn:oasis:names:tc:SAML:2.0:nameid-format:transient
|
||||||
@ -48757,6 +48745,14 @@ components:
|
|||||||
- mode
|
- mode
|
||||||
- name
|
- name
|
||||||
- user_attribute
|
- user_attribute
|
||||||
|
NameIdPolicyEnum:
|
||||||
|
enum:
|
||||||
|
- urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
|
||||||
|
- urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
|
||||||
|
- urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
|
||||||
|
- urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName
|
||||||
|
- urn:oasis:names:tc:SAML:2.0:nameid-format:transient
|
||||||
|
type: string
|
||||||
NetworkBindingEnum:
|
NetworkBindingEnum:
|
||||||
enum:
|
enum:
|
||||||
- no_binding
|
- no_binding
|
||||||
@ -54505,8 +54501,6 @@ components:
|
|||||||
default_relay_state:
|
default_relay_state:
|
||||||
type: string
|
type: string
|
||||||
description: Default relay_state value for IDP-initiated logins
|
description: Default relay_state value for IDP-initiated logins
|
||||||
default_name_id_policy:
|
|
||||||
$ref: '#/components/schemas/SAMLNameIDPolicyEnum'
|
|
||||||
PatchedSAMLSourcePropertyMappingRequest:
|
PatchedSAMLSourcePropertyMappingRequest:
|
||||||
type: object
|
type: object
|
||||||
description: SAMLSourcePropertyMapping Serializer
|
description: SAMLSourcePropertyMapping Serializer
|
||||||
@ -54600,7 +54594,7 @@ components:
|
|||||||
be a security risk, as no validation of the request ID is done.
|
be a security risk, as no validation of the request ID is done.
|
||||||
name_id_policy:
|
name_id_policy:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/SAMLNameIDPolicyEnum'
|
- $ref: '#/components/schemas/NameIdPolicyEnum'
|
||||||
description: NameID Policy sent to the IdP. Can be unset, in which case
|
description: NameID Policy sent to the IdP. Can be unset, in which case
|
||||||
no Policy is sent.
|
no Policy is sent.
|
||||||
binding_type:
|
binding_type:
|
||||||
@ -57311,15 +57305,6 @@ components:
|
|||||||
required:
|
required:
|
||||||
- download_url
|
- download_url
|
||||||
- metadata
|
- metadata
|
||||||
SAMLNameIDPolicyEnum:
|
|
||||||
enum:
|
|
||||||
- urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
|
|
||||||
- urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
|
|
||||||
- urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
|
|
||||||
- urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName
|
|
||||||
- urn:oasis:names:tc:SAML:2.0:nameid-format:transient
|
|
||||||
- urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
|
|
||||||
type: string
|
|
||||||
SAMLPropertyMapping:
|
SAMLPropertyMapping:
|
||||||
type: object
|
type: object
|
||||||
description: SAMLPropertyMapping Serializer
|
description: SAMLPropertyMapping Serializer
|
||||||
@ -57537,8 +57522,6 @@ components:
|
|||||||
default_relay_state:
|
default_relay_state:
|
||||||
type: string
|
type: string
|
||||||
description: Default relay_state value for IDP-initiated logins
|
description: Default relay_state value for IDP-initiated logins
|
||||||
default_name_id_policy:
|
|
||||||
$ref: '#/components/schemas/SAMLNameIDPolicyEnum'
|
|
||||||
url_download_metadata:
|
url_download_metadata:
|
||||||
type: string
|
type: string
|
||||||
description: Get metadata download URL
|
description: Get metadata download URL
|
||||||
@ -57711,8 +57694,6 @@ components:
|
|||||||
default_relay_state:
|
default_relay_state:
|
||||||
type: string
|
type: string
|
||||||
description: Default relay_state value for IDP-initiated logins
|
description: Default relay_state value for IDP-initiated logins
|
||||||
default_name_id_policy:
|
|
||||||
$ref: '#/components/schemas/SAMLNameIDPolicyEnum'
|
|
||||||
required:
|
required:
|
||||||
- acs_url
|
- acs_url
|
||||||
- authorization_flow
|
- authorization_flow
|
||||||
@ -57821,7 +57802,7 @@ components:
|
|||||||
be a security risk, as no validation of the request ID is done.
|
be a security risk, as no validation of the request ID is done.
|
||||||
name_id_policy:
|
name_id_policy:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/SAMLNameIDPolicyEnum'
|
- $ref: '#/components/schemas/NameIdPolicyEnum'
|
||||||
description: NameID Policy sent to the IdP. Can be unset, in which case
|
description: NameID Policy sent to the IdP. Can be unset, in which case
|
||||||
no Policy is sent.
|
no Policy is sent.
|
||||||
binding_type:
|
binding_type:
|
||||||
@ -58011,7 +57992,7 @@ components:
|
|||||||
be a security risk, as no validation of the request ID is done.
|
be a security risk, as no validation of the request ID is done.
|
||||||
name_id_policy:
|
name_id_policy:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/SAMLNameIDPolicyEnum'
|
- $ref: '#/components/schemas/NameIdPolicyEnum'
|
||||||
description: NameID Policy sent to the IdP. Can be unset, in which case
|
description: NameID Policy sent to the IdP. Can be unset, in which case
|
||||||
no Policy is sent.
|
no Policy is sent.
|
||||||
binding_type:
|
binding_type:
|
||||||
|
|||||||
@ -7,7 +7,7 @@ services:
|
|||||||
network_mode: host
|
network_mode: host
|
||||||
restart: always
|
restart: always
|
||||||
mailpit:
|
mailpit:
|
||||||
image: docker.io/axllent/mailpit:v1.26.1
|
image: docker.io/axllent/mailpit:v1.26.0
|
||||||
ports:
|
ports:
|
||||||
- 1025:1025
|
- 1025:1025
|
||||||
- 8025:8025
|
- 8025:8025
|
||||||
|
|||||||
18
uv.lock
generated
18
uv.lock
generated
@ -165,7 +165,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "authentik"
|
name = "authentik"
|
||||||
version = "2025.6.2"
|
version = "2025.6.1"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "argon2-cffi" },
|
{ name = "argon2-cffi" },
|
||||||
@ -309,7 +309,7 @@ requires-dist = [
|
|||||||
{ name = "packaging", specifier = "==25.0" },
|
{ name = "packaging", specifier = "==25.0" },
|
||||||
{ name = "paramiko", specifier = "==3.5.1" },
|
{ name = "paramiko", specifier = "==3.5.1" },
|
||||||
{ name = "psycopg", extras = ["c", "pool"], specifier = "==3.2.9" },
|
{ name = "psycopg", extras = ["c", "pool"], specifier = "==3.2.9" },
|
||||||
{ name = "pydantic", specifier = "==2.11.7" },
|
{ name = "pydantic", specifier = "==2.11.5" },
|
||||||
{ name = "pydantic-scim", specifier = "==0.0.8" },
|
{ name = "pydantic-scim", specifier = "==0.0.8" },
|
||||||
{ name = "pyjwt", specifier = "==2.10.1" },
|
{ name = "pyjwt", specifier = "==2.10.1" },
|
||||||
{ name = "pyrad", specifier = "==2.4" },
|
{ name = "pyrad", specifier = "==2.4" },
|
||||||
@ -329,7 +329,7 @@ requires-dist = [
|
|||||||
{ name = "urllib3", specifier = "<3" },
|
{ name = "urllib3", specifier = "<3" },
|
||||||
{ name = "uvicorn", extras = ["standard"], specifier = "==0.34.3" },
|
{ name = "uvicorn", extras = ["standard"], specifier = "==0.34.3" },
|
||||||
{ name = "watchdog", specifier = "==6.0.0" },
|
{ name = "watchdog", specifier = "==6.0.0" },
|
||||||
{ name = "webauthn", specifier = "==2.6.0" },
|
{ name = "webauthn", specifier = "==2.5.2" },
|
||||||
{ name = "wsproto", specifier = "==1.2.0" },
|
{ name = "wsproto", specifier = "==1.2.0" },
|
||||||
{ name = "xmlsec", specifier = "==1.3.15" },
|
{ name = "xmlsec", specifier = "==1.3.15" },
|
||||||
{ name = "zxcvbn", specifier = "==4.5.0" },
|
{ name = "zxcvbn", specifier = "==4.5.0" },
|
||||||
@ -2463,7 +2463,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
version = "2.11.7"
|
version = "2.11.5"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "annotated-types" },
|
{ name = "annotated-types" },
|
||||||
@ -2471,9 +2471,9 @@ dependencies = [
|
|||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
{ name = "typing-inspection" },
|
{ name = "typing-inspection" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/f0/86/8ce9040065e8f924d642c58e4a344e33163a07f6b57f836d0d734e0ad3fb/pydantic-2.11.5.tar.gz", hash = "sha256:7f853db3d0ce78ce8bbb148c401c2cdd6431b3473c0cdff2755c7690952a7b7a", size = 787102, upload-time = "2025-05-22T21:18:08.761Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" },
|
{ url = "https://files.pythonhosted.org/packages/b5/69/831ed22b38ff9b4b64b66569f0e5b7b97cf3638346eb95a2147fdb49ad5f/pydantic-2.11.5-py3-none-any.whl", hash = "sha256:f9c26ba06f9747749ca1e5c94d6a85cb84254577553c8785576fd38fa64dc0f7", size = 444229, upload-time = "2025-05-22T21:18:06.329Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.optional-dependencies]
|
[package.optional-dependencies]
|
||||||
@ -3391,7 +3391,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webauthn"
|
name = "webauthn"
|
||||||
version = "2.6.0"
|
version = "2.5.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "asn1crypto" },
|
{ name = "asn1crypto" },
|
||||||
@ -3399,9 +3399,9 @@ dependencies = [
|
|||||||
{ name = "cryptography" },
|
{ name = "cryptography" },
|
||||||
{ name = "pyopenssl" },
|
{ name = "pyopenssl" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/63/38/5792cb2034673c162a721df0ad65825699516ee0c938a65670ad3cdabf6c/webauthn-2.6.0.tar.gz", hash = "sha256:13cf5b009a64cef569599ffecf24550df1d7c0cd4fbaea870f937148484a80b4", size = 123608, upload-time = "2025-06-16T22:25:26.76Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/8d/92/8d2a4eec83d8e7feacdaad37c6eb6eb922100cecce5c14a41d8069a59a03/webauthn-2.5.2.tar.gz", hash = "sha256:09c13dfc1c68c810f32fa4d89b1d37acb9f9ae9091c9d7019e313be4525a95ef", size = 124114, upload-time = "2025-03-07T19:44:05.243Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/56/c5/b1bba7f6a50caca77f37003e098f48f8dc68d990aba8a03ac8376016430b/webauthn-2.6.0-py3-none-any.whl", hash = "sha256:459973eb5780c1f41bec42b682acf587456b185733398a0b99a0714705b79447", size = 71189, upload-time = "2025-06-16T22:25:25.535Z" },
|
{ url = "https://files.pythonhosted.org/packages/7f/fe/f6ae41de9f383439e30b303a67f6f45d2fceabedaedc34c62f74d58c5c73/webauthn-2.5.2-py3-none-any.whl", hash = "sha256:44246e496e617eb5e2f51165046b9f0197fcdf470f69cd6734061a27ba365f8e", size = 71624, upload-time = "2025-03-07T19:44:03.728Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
1707
web/package-lock.json
generated
1707
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -93,7 +93,7 @@
|
|||||||
"@floating-ui/dom": "^1.6.11",
|
"@floating-ui/dom": "^1.6.11",
|
||||||
"@formatjs/intl-listformat": "^7.7.11",
|
"@formatjs/intl-listformat": "^7.7.11",
|
||||||
"@fortawesome/fontawesome-free": "^6.7.2",
|
"@fortawesome/fontawesome-free": "^6.7.2",
|
||||||
"@goauthentik/api": "^2025.6.2-1750112513",
|
"@goauthentik/api": "^2025.6.1-1749515784",
|
||||||
"@lit/context": "^1.1.2",
|
"@lit/context": "^1.1.2",
|
||||||
"@lit/localize": "^0.12.2",
|
"@lit/localize": "^0.12.2",
|
||||||
"@lit/reactive-element": "^2.0.4",
|
"@lit/reactive-element": "^2.0.4",
|
||||||
@ -102,9 +102,10 @@
|
|||||||
"@open-wc/lit-helpers": "^0.7.0",
|
"@open-wc/lit-helpers": "^0.7.0",
|
||||||
"@patternfly/elements": "^4.1.0",
|
"@patternfly/elements": "^4.1.0",
|
||||||
"@patternfly/patternfly": "^4.224.2",
|
"@patternfly/patternfly": "^4.224.2",
|
||||||
"@sentry/browser": "^9.30.0",
|
"@sentry/browser": "^9.28.1",
|
||||||
"@spotlightjs/spotlight": "^3.0.0",
|
"@spotlightjs/spotlight": "^3.0.0",
|
||||||
"@webcomponents/webcomponentsjs": "^2.8.0",
|
"@webcomponents/webcomponentsjs": "^2.8.0",
|
||||||
|
"base64-js": "^1.5.1",
|
||||||
"change-case": "^5.4.4",
|
"change-case": "^5.4.4",
|
||||||
"chart.js": "^4.4.9",
|
"chart.js": "^4.4.9",
|
||||||
"chartjs-adapter-date-fns": "^3.0.0",
|
"chartjs-adapter-date-fns": "^3.0.0",
|
||||||
@ -136,7 +137,6 @@
|
|||||||
"trusted-types": "^2.0.0",
|
"trusted-types": "^2.0.0",
|
||||||
"ts-pattern": "^5.7.1",
|
"ts-pattern": "^5.7.1",
|
||||||
"unist-util-visit": "^5.0.0",
|
"unist-util-visit": "^5.0.0",
|
||||||
"webauthn-polyfills": "^0.1.7",
|
|
||||||
"webcomponent-qr-code": "^1.2.0",
|
"webcomponent-qr-code": "^1.2.0",
|
||||||
"yaml": "^2.8.0"
|
"yaml": "^2.8.0"
|
||||||
},
|
},
|
||||||
@ -170,16 +170,16 @@
|
|||||||
"@types/react-dom": "^19.1.5",
|
"@types/react-dom": "^19.1.5",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.8.0",
|
"@typescript-eslint/eslint-plugin": "^8.8.0",
|
||||||
"@typescript-eslint/parser": "^8.8.0",
|
"@typescript-eslint/parser": "^8.8.0",
|
||||||
"@wdio/browser-runner": "9.15",
|
"@wdio/browser-runner": "9.4",
|
||||||
"@wdio/cli": "9.15",
|
"@wdio/cli": "9.4",
|
||||||
"@wdio/spec-reporter": "^9.15.0",
|
"@wdio/spec-reporter": "^9.1.2",
|
||||||
"@web/test-runner": "^0.20.2",
|
"@web/test-runner": "^0.20.2",
|
||||||
"chromedriver": "^136.0.3",
|
"chromedriver": "^136.0.3",
|
||||||
"esbuild": "^0.25.5",
|
"esbuild": "^0.25.5",
|
||||||
"esbuild-plugin-copy": "^2.1.1",
|
"esbuild-plugin-copy": "^2.1.1",
|
||||||
"esbuild-plugin-polyfill-node": "^0.3.0",
|
"esbuild-plugin-polyfill-node": "^0.3.0",
|
||||||
"esbuild-plugins-node-modules-polyfill": "^1.7.0",
|
"esbuild-plugins-node-modules-polyfill": "^1.7.0",
|
||||||
"eslint": "^9.29.0",
|
"eslint": "^9.28.0",
|
||||||
"eslint-plugin-lit": "^2.1.1",
|
"eslint-plugin-lit": "^2.1.1",
|
||||||
"eslint-plugin-wc": "^3.0.1",
|
"eslint-plugin-wc": "^3.0.1",
|
||||||
"github-slugger": "^2.0.0",
|
"github-slugger": "^2.0.0",
|
||||||
@ -194,7 +194,7 @@
|
|||||||
"storybook-addon-mock": "^5.0.0",
|
"storybook-addon-mock": "^5.0.0",
|
||||||
"turnstile-types": "^1.2.3",
|
"turnstile-types": "^1.2.3",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"typescript-eslint": "^8.34.1",
|
"typescript-eslint": "^8.34.0",
|
||||||
"vite-plugin-lit-css": "^2.0.0",
|
"vite-plugin-lit-css": "^2.0.0",
|
||||||
"vite-tsconfig-paths": "^5.0.1",
|
"vite-tsconfig-paths": "^5.0.1",
|
||||||
"wireit": "^0.14.12"
|
"wireit": "^0.14.12"
|
||||||
|
|||||||
2
web/packages/core/types/node.d.ts
vendored
2
web/packages/core/types/node.d.ts
vendored
@ -14,7 +14,7 @@ declare module "module" {
|
|||||||
* const relativeDirname = dirname(fileURLToPath(import.meta.url));
|
* const relativeDirname = dirname(fileURLToPath(import.meta.url));
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line no-var
|
||||||
var __dirname: string;
|
var __dirname: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,11 +11,11 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@goauthentik/api": "^2024.6.0-1719577139",
|
"@goauthentik/api": "^2024.6.0-1719577139",
|
||||||
|
"base64-js": "^1.5.1",
|
||||||
"bootstrap": "^4.6.1",
|
"bootstrap": "^4.6.1",
|
||||||
"formdata-polyfill": "^4.0.10",
|
"formdata-polyfill": "^4.0.10",
|
||||||
"jquery": "^3.7.1",
|
"jquery": "^3.7.1",
|
||||||
"weakmap-polyfill": "^2.0.4",
|
"weakmap-polyfill": "^2.0.4"
|
||||||
"webauthn-polyfills": "^0.1.7"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@goauthentik/core": "^1.0.0",
|
"@goauthentik/core": "^1.0.0",
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
|
import { fromByteArray } from "base64-js";
|
||||||
import "formdata-polyfill";
|
import "formdata-polyfill";
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
import "weakmap-polyfill";
|
import "weakmap-polyfill";
|
||||||
import "webauthn-polyfills";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
type AuthenticatorValidationChallenge,
|
type AuthenticatorValidationChallenge,
|
||||||
@ -257,9 +257,47 @@ class AutosubmitStage extends Stage<AutosubmitChallenge> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Assertion {
|
||||||
|
id: string;
|
||||||
|
rawId: string;
|
||||||
|
type: string;
|
||||||
|
registrationClientExtensions: string;
|
||||||
|
response: {
|
||||||
|
clientDataJSON: string;
|
||||||
|
attestationObject: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AuthAssertion {
|
||||||
|
id: string;
|
||||||
|
rawId: string;
|
||||||
|
type: string;
|
||||||
|
assertionClientExtensions: string;
|
||||||
|
response: {
|
||||||
|
clientDataJSON: string;
|
||||||
|
authenticatorData: string;
|
||||||
|
signature: string;
|
||||||
|
userHandle: string | null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge> {
|
class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge> {
|
||||||
deviceChallenge?: DeviceChallenge;
|
deviceChallenge?: DeviceChallenge;
|
||||||
|
|
||||||
|
b64enc(buf: Uint8Array): string {
|
||||||
|
return fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
b64RawEnc(buf: Uint8Array): string {
|
||||||
|
return fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_");
|
||||||
|
}
|
||||||
|
|
||||||
|
u8arr(input: string): Uint8Array {
|
||||||
|
return Uint8Array.from(atob(input.replace(/_/g, "/").replace(/-/g, "+")), (c) =>
|
||||||
|
c.charCodeAt(0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
checkWebAuthnSupport(): boolean {
|
checkWebAuthnSupport(): boolean {
|
||||||
if ("credentials" in navigator) {
|
if ("credentials" in navigator) {
|
||||||
return true;
|
return true;
|
||||||
@ -272,6 +310,98 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms items in the credentialCreateOptions generated on the server
|
||||||
|
* into byte arrays expected by the navigator.credentials.create() call
|
||||||
|
*/
|
||||||
|
transformCredentialCreateOptions(
|
||||||
|
credentialCreateOptions: PublicKeyCredentialCreationOptions,
|
||||||
|
userId: string,
|
||||||
|
): PublicKeyCredentialCreationOptions {
|
||||||
|
const user = credentialCreateOptions.user;
|
||||||
|
// Because json can't contain raw bytes, the server base64-encodes the User ID
|
||||||
|
// So to get the base64 encoded byte array, we first need to convert it to a regular
|
||||||
|
// string, then a byte array, re-encode it and wrap that in an array.
|
||||||
|
const stringId = decodeURIComponent(window.atob(userId));
|
||||||
|
user.id = this.u8arr(this.b64enc(this.u8arr(stringId)));
|
||||||
|
const challenge = this.u8arr(credentialCreateOptions.challenge.toString());
|
||||||
|
|
||||||
|
return Object.assign({}, credentialCreateOptions, {
|
||||||
|
challenge,
|
||||||
|
user,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms the binary data in the credential into base64 strings
|
||||||
|
* for posting to the server.
|
||||||
|
* @param {PublicKeyCredential} newAssertion
|
||||||
|
*/
|
||||||
|
transformNewAssertionForServer(newAssertion: PublicKeyCredential): Assertion {
|
||||||
|
const attObj = new Uint8Array(
|
||||||
|
(newAssertion.response as AuthenticatorAttestationResponse).attestationObject,
|
||||||
|
);
|
||||||
|
const clientDataJSON = new Uint8Array(newAssertion.response.clientDataJSON);
|
||||||
|
const rawId = new Uint8Array(newAssertion.rawId);
|
||||||
|
|
||||||
|
const registrationClientExtensions = newAssertion.getClientExtensionResults();
|
||||||
|
return {
|
||||||
|
id: newAssertion.id,
|
||||||
|
rawId: this.b64enc(rawId),
|
||||||
|
type: newAssertion.type,
|
||||||
|
registrationClientExtensions: JSON.stringify(registrationClientExtensions),
|
||||||
|
response: {
|
||||||
|
clientDataJSON: this.b64enc(clientDataJSON),
|
||||||
|
attestationObject: this.b64enc(attObj),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
transformCredentialRequestOptions(
|
||||||
|
credentialRequestOptions: PublicKeyCredentialRequestOptions,
|
||||||
|
): PublicKeyCredentialRequestOptions {
|
||||||
|
const challenge = this.u8arr(credentialRequestOptions.challenge.toString());
|
||||||
|
|
||||||
|
const allowCredentials = (credentialRequestOptions.allowCredentials || []).map(
|
||||||
|
(credentialDescriptor) => {
|
||||||
|
const id = this.u8arr(credentialDescriptor.id.toString());
|
||||||
|
return Object.assign({}, credentialDescriptor, { id });
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return Object.assign({}, credentialRequestOptions, {
|
||||||
|
challenge,
|
||||||
|
allowCredentials,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes the binary data in the assertion into strings for posting to the server.
|
||||||
|
* @param {PublicKeyCredential} newAssertion
|
||||||
|
*/
|
||||||
|
transformAssertionForServer(newAssertion: PublicKeyCredential): AuthAssertion {
|
||||||
|
const response = newAssertion.response as AuthenticatorAssertionResponse;
|
||||||
|
const authData = new Uint8Array(response.authenticatorData);
|
||||||
|
const clientDataJSON = new Uint8Array(response.clientDataJSON);
|
||||||
|
const rawId = new Uint8Array(newAssertion.rawId);
|
||||||
|
const sig = new Uint8Array(response.signature);
|
||||||
|
const assertionClientExtensions = newAssertion.getClientExtensionResults();
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: newAssertion.id,
|
||||||
|
rawId: this.b64enc(rawId),
|
||||||
|
type: newAssertion.type,
|
||||||
|
assertionClientExtensions: JSON.stringify(assertionClientExtensions),
|
||||||
|
|
||||||
|
response: {
|
||||||
|
clientDataJSON: this.b64RawEnc(clientDataJSON),
|
||||||
|
signature: this.b64RawEnc(sig),
|
||||||
|
authenticatorData: this.b64RawEnc(authData),
|
||||||
|
userHandle: null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.challenge.deviceChallenges.length === 1) {
|
if (this.challenge.deviceChallenges.length === 1) {
|
||||||
this.deviceChallenge = this.challenge.deviceChallenges[0];
|
this.deviceChallenge = this.challenge.deviceChallenges[0];
|
||||||
@ -375,8 +505,8 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
|
|||||||
`);
|
`);
|
||||||
navigator.credentials
|
navigator.credentials
|
||||||
.get({
|
.get({
|
||||||
publicKey: PublicKeyCredential.parseRequestOptionsFromJSON(
|
publicKey: this.transformCredentialRequestOptions(
|
||||||
this.deviceChallenge?.challenge as PublicKeyCredentialRequestOptionsJSON,
|
this.deviceChallenge?.challenge as PublicKeyCredentialRequestOptions,
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
.then((assertion) => {
|
.then((assertion) => {
|
||||||
@ -384,9 +514,15 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
|
|||||||
throw new Error("No assertion");
|
throw new Error("No assertion");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
// we now have an authentication assertion! encode the byte arrays contained
|
||||||
|
// in the assertion data as strings for posting to the server
|
||||||
|
const transformedAssertionForServer = this.transformAssertionForServer(
|
||||||
|
assertion as PublicKeyCredential,
|
||||||
|
);
|
||||||
|
|
||||||
// post the assertion to the server for verification.
|
// post the assertion to the server for verification.
|
||||||
this.executor.submit({
|
this.executor.submit({
|
||||||
webauthn: (assertion as PublicKeyCredential).toJSON(),
|
webauthn: transformedAssertionForServer,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new Error(`Error when validating assertion on server: ${err}`);
|
throw new Error(`Error when validating assertion on server: ${err}`);
|
||||||
|
|||||||
@ -88,8 +88,7 @@ export class RecentEventsCard extends Table<Event> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return super.renderEmpty(
|
return super.renderEmpty(
|
||||||
html`<ak-empty-state
|
html`<ak-empty-state header=${msg("No Events found.")}>
|
||||||
><span slot="header">${msg("No Events found.")}</span>
|
|
||||||
<div slot="body">${msg("No matching events could be found.")}</div>
|
<div slot="body">${msg("No matching events could be found.")}</div>
|
||||||
</ak-empty-state>`,
|
</ak-empty-state>`,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import { policyEngineModes } from "@goauthentik/admin/policies/PolicyEngineModes
|
|||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import "@goauthentik/components/ak-file-input";
|
import "@goauthentik/components/ak-file-input";
|
||||||
import "@goauthentik/components/ak-radio-input";
|
import "@goauthentik/components/ak-radio-input";
|
||||||
import "@goauthentik/components/ak-slug-input";
|
|
||||||
import "@goauthentik/components/ak-switch-input";
|
import "@goauthentik/components/ak-switch-input";
|
||||||
import "@goauthentik/components/ak-text-input";
|
import "@goauthentik/components/ak-text-input";
|
||||||
import "@goauthentik/components/ak-textarea-input";
|
import "@goauthentik/components/ak-textarea-input";
|
||||||
@ -131,14 +130,14 @@ export class ApplicationForm extends WithCapabilitiesConfig(ModelForm<Applicatio
|
|||||||
required
|
required
|
||||||
help=${msg("Application's display Name.")}
|
help=${msg("Application's display Name.")}
|
||||||
></ak-text-input>
|
></ak-text-input>
|
||||||
<ak-slug-input
|
<ak-text-input
|
||||||
name="slug"
|
name="slug"
|
||||||
value=${ifDefined(this.instance?.slug)}
|
value=${ifDefined(this.instance?.slug)}
|
||||||
label=${msg("Slug")}
|
label=${msg("Slug")}
|
||||||
required
|
required
|
||||||
help=${msg("Internal application name used in URLs.")}
|
help=${msg("Internal application name used in URLs.")}
|
||||||
input-hint="code"
|
input-hint="code"
|
||||||
></ak-slug-input>
|
></ak-text-input>
|
||||||
<ak-text-input
|
<ak-text-input
|
||||||
name="group"
|
name="group"
|
||||||
value=${ifDefined(this.instance?.group)}
|
value=${ifDefined(this.instance?.group)}
|
||||||
|
|||||||
@ -117,11 +117,13 @@ export class ApplicationWizardApplicationStep extends ApplicationWizardStep {
|
|||||||
?invalid=${this.errors.has("name")}
|
?invalid=${this.errors.has("name")}
|
||||||
.errorMessages=${errors.name ?? this.errorMessages("name")}
|
.errorMessages=${errors.name ?? this.errorMessages("name")}
|
||||||
help=${msg("Application's display Name.")}
|
help=${msg("Application's display Name.")}
|
||||||
|
id="ak-application-wizard-details-name"
|
||||||
></ak-text-input>
|
></ak-text-input>
|
||||||
<ak-slug-input
|
<ak-slug-input
|
||||||
name="slug"
|
name="slug"
|
||||||
value=${ifDefined(app.slug)}
|
value=${ifDefined(app.slug)}
|
||||||
label=${msg("Slug")}
|
label=${msg("Slug")}
|
||||||
|
source="#ak-application-wizard-details-name"
|
||||||
required
|
required
|
||||||
?invalid=${errors.slug ?? this.errors.has("slug")}
|
?invalid=${errors.slug ?? this.errors.has("slug")}
|
||||||
.errorMessages=${this.errorMessages("slug")}
|
.errorMessages=${this.errorMessages("slug")}
|
||||||
|
|||||||
@ -115,8 +115,7 @@ export class ApplicationWizardBindingsStep extends ApplicationWizardStep {
|
|||||||
.columns=${COLUMNS}
|
.columns=${COLUMNS}
|
||||||
.content=${[]}
|
.content=${[]}
|
||||||
></ak-select-table>
|
></ak-select-table>
|
||||||
<ak-empty-state icon="pf-icon-module"
|
<ak-empty-state header=${msg("No bound policies.")} icon="pf-icon-module">
|
||||||
><span slot="header">${msg("No bound policies.")} </span>
|
|
||||||
<div slot="body">${msg("No policies are currently bound to this object.")}</div>
|
<div slot="body">${msg("No policies are currently bound to this object.")}</div>
|
||||||
<div slot="primary">
|
<div slot="primary">
|
||||||
<button
|
<button
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import "@goauthentik/components/ak-secret-textarea-input.js";
|
import "@goauthentik/components/ak-private-textarea-input.js";
|
||||||
import "@goauthentik/elements/CodeMirror";
|
import "@goauthentik/elements/CodeMirror";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||||
@ -46,7 +46,7 @@ export class CertificateKeyPairForm extends ModelForm<CertificateKeyPair, string
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-secret-textarea-input
|
<ak-private-textarea-input
|
||||||
label=${msg("Certificate")}
|
label=${msg("Certificate")}
|
||||||
name="certificateData"
|
name="certificateData"
|
||||||
input-hint="code"
|
input-hint="code"
|
||||||
@ -54,8 +54,8 @@ export class CertificateKeyPairForm extends ModelForm<CertificateKeyPair, string
|
|||||||
required
|
required
|
||||||
?revealed=${this.instance === undefined}
|
?revealed=${this.instance === undefined}
|
||||||
help=${msg("PEM-encoded Certificate data.")}
|
help=${msg("PEM-encoded Certificate data.")}
|
||||||
></ak-secret-textarea-input>
|
></ak-private-textarea-input>
|
||||||
<ak-secret-textarea-input
|
<ak-private-textarea-input
|
||||||
label=${msg("Private Key")}
|
label=${msg("Private Key")}
|
||||||
name="keyData"
|
name="keyData"
|
||||||
input-hint="code"
|
input-hint="code"
|
||||||
@ -63,7 +63,7 @@ export class CertificateKeyPairForm extends ModelForm<CertificateKeyPair, string
|
|||||||
help=${msg(
|
help=${msg(
|
||||||
"Optional Private Key. If this is set, you can use this keypair for encryption.",
|
"Optional Private Key. If this is set, you can use this keypair for encryption.",
|
||||||
)}
|
)}
|
||||||
></ak-secret-textarea-input>`;
|
></ak-private-textarea-input>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import { EVENT_REFRESH_ENTERPRISE } from "@goauthentik/common/constants";
|
import { EVENT_REFRESH_ENTERPRISE } from "@goauthentik/common/constants";
|
||||||
import "@goauthentik/components/ak-secret-textarea-input.js";
|
import "@goauthentik/components/ak-private-textarea-input.js";
|
||||||
import "@goauthentik/elements/CodeMirror";
|
import "@goauthentik/elements/CodeMirror";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||||
@ -62,13 +62,13 @@ export class EnterpriseLicenseForm extends ModelForm<License, string> {
|
|||||||
value="${ifDefined(this.installID)}"
|
value="${ifDefined(this.installID)}"
|
||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-secret-textarea-input
|
<ak-private-textarea-input
|
||||||
name="key"
|
name="key"
|
||||||
?revealed=${this.instance === undefined}
|
?revealed=${this.instance === undefined}
|
||||||
label=${msg("License key")}
|
label=${msg("License key")}
|
||||||
input-hint="code"
|
input-hint="code"
|
||||||
>
|
>
|
||||||
</ak-secret-textarea-input>`;
|
</ak-private-textarea-input>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -135,8 +135,7 @@ export class BoundStagesList extends Table<FlowStageBinding> {
|
|||||||
|
|
||||||
renderEmpty(): TemplateResult {
|
renderEmpty(): TemplateResult {
|
||||||
return super.renderEmpty(
|
return super.renderEmpty(
|
||||||
html`<ak-empty-state icon="pf-icon-module">
|
html`<ak-empty-state header=${msg("No Stages bound")} icon="pf-icon-module">
|
||||||
<span slot="header">${msg("No Stages bound")}</span>
|
|
||||||
<div slot="body">${msg("No stages are currently bound to this flow.")}</div>
|
<div slot="body">${msg("No stages are currently bound to this flow.")}</div>
|
||||||
<div slot="primary">
|
<div slot="primary">
|
||||||
<ak-stage-wizard
|
<ak-stage-wizard
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { DesignationToLabel, LayoutToLabel } from "@goauthentik/admin/flows/util
|
|||||||
import { policyEngineModes } from "@goauthentik/admin/policies/PolicyEngineModes";
|
import { policyEngineModes } from "@goauthentik/admin/policies/PolicyEngineModes";
|
||||||
import { AuthenticationEnum } from "@goauthentik/api/dist/models/AuthenticationEnum";
|
import { AuthenticationEnum } from "@goauthentik/api/dist/models/AuthenticationEnum";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import "@goauthentik/components/ak-slug-input.js";
|
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||||
@ -92,16 +91,17 @@ export class FlowForm extends WithCapabilitiesConfig(ModelForm<Flow, string>) {
|
|||||||
/>
|
/>
|
||||||
<p class="pf-c-form__helper-text">${msg("Shown as the Title in Flow pages.")}</p>
|
<p class="pf-c-form__helper-text">${msg("Shown as the Title in Flow pages.")}</p>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal label=${msg("Slug")} required name="slug">
|
||||||
<ak-slug-input
|
<input
|
||||||
name="slug"
|
type="text"
|
||||||
value=${ifDefined(this.instance?.slug)}
|
value="${ifDefined(this.instance?.slug)}"
|
||||||
label=${msg("Slug")}
|
class="pf-c-form-control pf-m-monospace"
|
||||||
required
|
autocomplete="off"
|
||||||
help=${msg("Visible in the URL.")}
|
spellcheck="false"
|
||||||
input-hint="code"
|
required
|
||||||
></ak-slug-input>
|
/>
|
||||||
|
<p class="pf-c-form__helper-text">${msg("Visible in the URL.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal label=${msg("Designation")} required name="designation">
|
<ak-form-element-horizontal label=${msg("Designation")} required name="designation">
|
||||||
<select class="pf-c-form-control">
|
<select class="pf-c-form-control">
|
||||||
<option value="" ?selected=${this.instance?.designation === undefined}>
|
<option value="" ?selected=${this.instance?.designation === undefined}>
|
||||||
|
|||||||
@ -198,8 +198,7 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
|
|||||||
|
|
||||||
renderEmpty(): TemplateResult {
|
renderEmpty(): TemplateResult {
|
||||||
return super.renderEmpty(
|
return super.renderEmpty(
|
||||||
html`<ak-empty-state icon="pf-icon-module"
|
html`<ak-empty-state header=${msg("No Policies bound.")} icon="pf-icon-module">
|
||||||
><span slot="header">${msg("No Policies bound.")}</span>
|
|
||||||
<div slot="body">${msg("No policies are currently bound to this object.")}</div>
|
<div slot="body">${msg("No policies are currently bound to this object.")}</div>
|
||||||
<div slot="primary">
|
<div slot="primary">
|
||||||
<ak-policy-wizard
|
<ak-policy-wizard
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import {
|
|||||||
propertyMappingsSelector,
|
propertyMappingsSelector,
|
||||||
} from "@goauthentik/admin/providers/microsoft_entra/MicrosoftEntraProviderFormHelpers.js";
|
} from "@goauthentik/admin/providers/microsoft_entra/MicrosoftEntraProviderFormHelpers.js";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import "@goauthentik/components/ak-hidden-text-input";
|
|
||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider.js";
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
@ -69,15 +68,21 @@ export class MicrosoftEntraProviderFormPage extends BaseProviderForm<MicrosoftEn
|
|||||||
${msg("Client ID for the app registration.")}
|
${msg("Client ID for the app registration.")}
|
||||||
</p>
|
</p>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-hidden-text-input
|
<ak-form-element-horizontal
|
||||||
name="clientSecret"
|
|
||||||
label=${msg("Client Secret")}
|
label=${msg("Client Secret")}
|
||||||
value="${this.instance?.clientSecret ?? ""}"
|
|
||||||
input-hint="code"
|
|
||||||
required
|
required
|
||||||
.help=${msg("Client secret for the app registration.")}
|
name="clientSecret"
|
||||||
>
|
>
|
||||||
</ak-hidden-text-input>
|
<input
|
||||||
|
type="text"
|
||||||
|
value="${this.instance?.clientSecret ?? ""}"
|
||||||
|
class="pf-c-form-control pf-m-monospace"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<p class="pf-c-form__helper-text">
|
||||||
|
${msg("Client secret for the app registration.")}
|
||||||
|
</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal label=${msg("Tenant ID")} required name="tenantId">
|
<ak-form-element-horizontal label=${msg("Tenant ID")} required name="tenantId">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import {
|
|||||||
akOAuthRedirectURIInput,
|
akOAuthRedirectURIInput,
|
||||||
} from "@goauthentik/admin/providers/oauth2/OAuth2ProviderRedirectURI";
|
} from "@goauthentik/admin/providers/oauth2/OAuth2ProviderRedirectURI";
|
||||||
import { ascii_letters, digits, randomString } from "@goauthentik/common/utils";
|
import { ascii_letters, digits, randomString } from "@goauthentik/common/utils";
|
||||||
import "@goauthentik/components/ak-hidden-text-input";
|
|
||||||
import "@goauthentik/components/ak-radio-input";
|
import "@goauthentik/components/ak-radio-input";
|
||||||
import "@goauthentik/components/ak-text-input";
|
import "@goauthentik/components/ak-text-input";
|
||||||
import "@goauthentik/components/ak-textarea-input";
|
import "@goauthentik/components/ak-textarea-input";
|
||||||
@ -167,16 +166,17 @@ export function renderForm(
|
|||||||
input-hint="code"
|
input-hint="code"
|
||||||
>
|
>
|
||||||
</ak-text-input>
|
</ak-text-input>
|
||||||
<ak-hidden-text-input
|
<ak-text-input
|
||||||
name="clientSecret"
|
name="clientSecret"
|
||||||
label=${msg("Client Secret")}
|
label=${msg("Client Secret")}
|
||||||
value="${provider?.clientSecret ?? randomString(128, ascii_letters + digits)}"
|
value="${provider?.clientSecret ?? randomString(128, ascii_letters + digits)}"
|
||||||
input-hint="code"
|
input-hint="code"
|
||||||
?hidden=${!showClientSecret}
|
?hidden=${!showClientSecret}
|
||||||
>
|
>
|
||||||
</ak-hidden-text-input>
|
</ak-text-input>
|
||||||
<ak-form-element-horizontal
|
<ak-form-element-horizontal
|
||||||
label=${msg("Redirect URIs/Origins (RegEx)")}
|
label=${msg("Redirect URIs/Origins (RegEx)")}
|
||||||
|
required
|
||||||
name="redirectUris"
|
name="redirectUris"
|
||||||
>
|
>
|
||||||
<ak-array-input
|
<ak-array-input
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
import "@goauthentik/admin/common/ak-flow-search/ak-branded-flow-search";
|
import "@goauthentik/admin/common/ak-flow-search/ak-branded-flow-search";
|
||||||
import "@goauthentik/admin/common/ak-flow-search/ak-flow-search";
|
import "@goauthentik/admin/common/ak-flow-search/ak-flow-search";
|
||||||
import { ascii_letters, digits, randomString } from "@goauthentik/common/utils";
|
import { ascii_letters, digits, randomString } from "@goauthentik/common/utils";
|
||||||
import "@goauthentik/components/ak-hidden-text-input";
|
|
||||||
import "@goauthentik/components/ak-text-input";
|
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import "@goauthentik/elements/forms/SearchSelect";
|
import "@goauthentik/elements/forms/SearchSelect";
|
||||||
@ -76,14 +74,14 @@ export function renderForm(
|
|||||||
<ak-form-group expanded>
|
<ak-form-group expanded>
|
||||||
<span slot="header"> ${msg("Protocol settings")} </span>
|
<span slot="header"> ${msg("Protocol settings")} </span>
|
||||||
<div slot="body" class="pf-c-form">
|
<div slot="body" class="pf-c-form">
|
||||||
<ak-hidden-text-input
|
<ak-text-input
|
||||||
name="sharedSecret"
|
name="sharedSecret"
|
||||||
label=${msg("Shared secret")}
|
label=${msg("Shared secret")}
|
||||||
.errorMessages=${errors?.sharedSecret ?? []}
|
.errorMessages=${errors?.sharedSecret ?? []}
|
||||||
value=${provider?.sharedSecret ?? randomString(128, ascii_letters + digits)}
|
value=${provider?.sharedSecret ?? randomString(128, ascii_letters + digits)}
|
||||||
required
|
required
|
||||||
input-hint="code"
|
input-hint="code"
|
||||||
></ak-hidden-text-input>
|
></ak-text-input>
|
||||||
<ak-text-input
|
<ak-text-input
|
||||||
name="clientNetworks"
|
name="clientNetworks"
|
||||||
label=${msg("Client Networks")}
|
label=${msg("Client Networks")}
|
||||||
|
|||||||
@ -16,7 +16,6 @@ import {
|
|||||||
FlowsInstancesListDesignationEnum,
|
FlowsInstancesListDesignationEnum,
|
||||||
PropertymappingsApi,
|
PropertymappingsApi,
|
||||||
PropertymappingsProviderSamlListRequest,
|
PropertymappingsProviderSamlListRequest,
|
||||||
SAMLNameIDPolicyEnum,
|
|
||||||
SAMLPropertyMapping,
|
SAMLPropertyMapping,
|
||||||
SAMLProvider,
|
SAMLProvider,
|
||||||
SpBindingEnum,
|
SpBindingEnum,
|
||||||
@ -317,54 +316,6 @@ export function renderForm(
|
|||||||
"When using IDP-initiated logins, the relay state will be set to this value.",
|
"When using IDP-initiated logins, the relay state will be set to this value.",
|
||||||
)}
|
)}
|
||||||
></ak-text-input>
|
></ak-text-input>
|
||||||
<ak-form-element-horizontal
|
|
||||||
label=${msg("Default NameID Policy")}
|
|
||||||
required
|
|
||||||
name="defaultNameIdPolicy"
|
|
||||||
>
|
|
||||||
<select class="pf-c-form-control">
|
|
||||||
<option
|
|
||||||
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
|
|
||||||
?selected=${provider?.defaultNameIdPolicy ===
|
|
||||||
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
|
|
||||||
>
|
|
||||||
${msg("Persistent")}
|
|
||||||
</option>
|
|
||||||
<option
|
|
||||||
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
|
|
||||||
?selected=${provider?.defaultNameIdPolicy ===
|
|
||||||
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
|
|
||||||
>
|
|
||||||
${msg("Email address")}
|
|
||||||
</option>
|
|
||||||
<option
|
|
||||||
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
|
|
||||||
?selected=${provider?.defaultNameIdPolicy ===
|
|
||||||
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
|
|
||||||
>
|
|
||||||
${msg("Windows")}
|
|
||||||
</option>
|
|
||||||
<option
|
|
||||||
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
|
|
||||||
?selected=${provider?.defaultNameIdPolicy ===
|
|
||||||
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
|
|
||||||
>
|
|
||||||
${msg("X509 Subject")}
|
|
||||||
</option>
|
|
||||||
<option
|
|
||||||
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
|
|
||||||
?selected=${provider?.defaultNameIdPolicy ===
|
|
||||||
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
|
|
||||||
>
|
|
||||||
${msg("Transient")}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
<p class="pf-c-form__helper-text">
|
|
||||||
${msg(
|
|
||||||
"Configure the default NameID Policy used by IDP-initiated logins and when an incoming assertion doesn't specify a NameID Policy (also applies when using a custom NameID Mapping).",
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</ak-form-element-horizontal>
|
|
||||||
|
|
||||||
<ak-radio-input
|
<ak-radio-input
|
||||||
name="digestAlgorithm"
|
name="digestAlgorithm"
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import "@goauthentik/components/ak-hidden-text-input";
|
|
||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
@ -51,7 +50,7 @@ export function renderForm(provider?: Partial<SCIMProvider>, errors: ValidationE
|
|||||||
>
|
>
|
||||||
</ak-switch-input>
|
</ak-switch-input>
|
||||||
|
|
||||||
<ak-hidden-text-input
|
<ak-text-input
|
||||||
name="token"
|
name="token"
|
||||||
label=${msg("Token")}
|
label=${msg("Token")}
|
||||||
value="${provider?.token ?? ""}"
|
value="${provider?.token ?? ""}"
|
||||||
@ -61,7 +60,7 @@ export function renderForm(provider?: Partial<SCIMProvider>, errors: ValidationE
|
|||||||
"Token to authenticate with. Currently only bearer authentication is supported.",
|
"Token to authenticate with. Currently only bearer authentication is supported.",
|
||||||
)}
|
)}
|
||||||
input-hint="code"
|
input-hint="code"
|
||||||
></ak-hidden-text-input>
|
></ak-text-input>
|
||||||
<ak-radio-input
|
<ak-radio-input
|
||||||
name="compatibilityMode"
|
name="compatibilityMode"
|
||||||
label=${msg("Compatibility Mode")}
|
label=${msg("Compatibility Mode")}
|
||||||
|
|||||||
@ -7,9 +7,8 @@ import {
|
|||||||
UserMatchingModeToLabel,
|
UserMatchingModeToLabel,
|
||||||
} from "@goauthentik/admin/sources/oauth/utils";
|
} from "@goauthentik/admin/sources/oauth/utils";
|
||||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
||||||
import "@goauthentik/components/ak-secret-text-input.js";
|
import "@goauthentik/components/ak-private-text-input.js";
|
||||||
import "@goauthentik/components/ak-secret-textarea-input.js";
|
import "@goauthentik/components/ak-private-textarea-input.js";
|
||||||
import "@goauthentik/components/ak-slug-input.js";
|
|
||||||
import "@goauthentik/components/ak-switch-input";
|
import "@goauthentik/components/ak-switch-input";
|
||||||
import "@goauthentik/components/ak-text-input";
|
import "@goauthentik/components/ak-text-input";
|
||||||
import "@goauthentik/components/ak-textarea-input";
|
import "@goauthentik/components/ak-textarea-input";
|
||||||
@ -88,13 +87,12 @@ export class KerberosSourceForm extends WithCapabilitiesConfig(BaseSourceForm<Ke
|
|||||||
value=${ifDefined(this.instance?.name)}
|
value=${ifDefined(this.instance?.name)}
|
||||||
required
|
required
|
||||||
></ak-text-input>
|
></ak-text-input>
|
||||||
<ak-slug-input
|
<ak-text-input
|
||||||
name="slug"
|
name="slug"
|
||||||
value=${ifDefined(this.instance?.slug)}
|
|
||||||
label=${msg("Slug")}
|
label=${msg("Slug")}
|
||||||
|
value=${ifDefined(this.instance?.slug)}
|
||||||
required
|
required
|
||||||
input-hint="code"
|
></ak-text-input>
|
||||||
></ak-slug-input>
|
|
||||||
<ak-switch-input
|
<ak-switch-input
|
||||||
name="enabled"
|
name="enabled"
|
||||||
?checked=${this.instance?.enabled ?? true}
|
?checked=${this.instance?.enabled ?? true}
|
||||||
@ -250,22 +248,22 @@ export class KerberosSourceForm extends WithCapabilitiesConfig(BaseSourceForm<Ke
|
|||||||
value=${ifDefined(this.instance?.syncPrincipal)}
|
value=${ifDefined(this.instance?.syncPrincipal)}
|
||||||
help=${msg("Principal used to authenticate to the KDC for syncing.")}
|
help=${msg("Principal used to authenticate to the KDC for syncing.")}
|
||||||
></ak-text-input>
|
></ak-text-input>
|
||||||
<ak-secret-text-input
|
<ak-private-text-input
|
||||||
name="syncPassword"
|
name="syncPassword"
|
||||||
label=${msg("Sync password")}
|
label=${msg("Sync password")}
|
||||||
?revealed=${this.instance === undefined}
|
?revealed=${this.instance === undefined}
|
||||||
help=${msg(
|
help=${msg(
|
||||||
"Password used to authenticate to the KDC for syncing. Optional if Sync keytab or Sync credentials cache is provided.",
|
"Password used to authenticate to the KDC for syncing. Optional if Sync keytab or Sync credentials cache is provided.",
|
||||||
)}
|
)}
|
||||||
></ak-secret-text-input>
|
></ak-private-text-input>
|
||||||
<ak-secret-textarea-input
|
<ak-private-textarea-input
|
||||||
name="syncKeytab"
|
name="syncKeytab"
|
||||||
label=${msg("Sync keytab")}
|
label=${msg("Sync keytab")}
|
||||||
?revealed=${this.instance === undefined}
|
?revealed=${this.instance === undefined}
|
||||||
help=${msg(
|
help=${msg(
|
||||||
"Keytab used to authenticate to the KDC for syncing. Optional if Sync password or Sync credentials cache is provided. Must be base64 encoded or in the form TYPE:residual.",
|
"Keytab used to authenticate to the KDC for syncing. Optional if Sync password or Sync credentials cache is provided. Must be base64 encoded or in the form TYPE:residual.",
|
||||||
)}
|
)}
|
||||||
></ak-secret-textarea-input>
|
></ak-private-textarea-input>
|
||||||
<ak-text-input
|
<ak-text-input
|
||||||
name="syncCcache"
|
name="syncCcache"
|
||||||
label=${msg("Sync credentials cache")}
|
label=${msg("Sync credentials cache")}
|
||||||
@ -287,14 +285,14 @@ export class KerberosSourceForm extends WithCapabilitiesConfig(BaseSourceForm<Ke
|
|||||||
"Force the use of a specific server name for SPNEGO. Must be in the form HTTP@domain",
|
"Force the use of a specific server name for SPNEGO. Must be in the form HTTP@domain",
|
||||||
)}
|
)}
|
||||||
></ak-text-input>
|
></ak-text-input>
|
||||||
<ak-secret-textarea-input
|
<ak-private-textarea-input
|
||||||
name="spnegoKeytab"
|
name="spnegoKeytab"
|
||||||
label=${msg("SPNEGO keytab")}
|
label=${msg("SPNEGO keytab")}
|
||||||
?revealed=${this.instance === undefined}
|
?revealed=${this.instance === undefined}
|
||||||
help=${msg(
|
help=${msg(
|
||||||
"Keytab used for SPNEGO. Optional if SPNEGO credentials cache is provided. Must be base64 encoded or in the form TYPE:residual.",
|
"Keytab used for SPNEGO. Optional if SPNEGO credentials cache is provided. Must be base64 encoded or in the form TYPE:residual.",
|
||||||
)}
|
)}
|
||||||
></ak-secret-textarea-input>
|
></ak-private-textarea-input>
|
||||||
<ak-text-input
|
<ak-text-input
|
||||||
name="spnegoCcache"
|
name="spnegoCcache"
|
||||||
label=${msg("SPNEGO credentials cache")}
|
label=${msg("SPNEGO credentials cache")}
|
||||||
|
|||||||
@ -2,8 +2,7 @@ import "@goauthentik/admin/common/ak-crypto-certificate-search";
|
|||||||
import { placeholderHelperText } from "@goauthentik/admin/helperText";
|
import { placeholderHelperText } from "@goauthentik/admin/helperText";
|
||||||
import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm";
|
import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import "@goauthentik/components/ak-secret-text-input.js";
|
import "@goauthentik/components/ak-private-text-input.js";
|
||||||
import "@goauthentik/components/ak-slug-input.js";
|
|
||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
@ -55,15 +54,14 @@ export class LDAPSourceForm extends BaseSourceForm<LDAPSource> {
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal label=${msg("Slug")} required name="slug">
|
||||||
<ak-slug-input
|
<input
|
||||||
name="slug"
|
type="text"
|
||||||
value=${ifDefined(this.instance?.slug)}
|
value="${ifDefined(this.instance?.slug)}"
|
||||||
label=${msg("Slug")}
|
class="pf-c-form-control"
|
||||||
required
|
required
|
||||||
input-hint="code"
|
/>
|
||||||
></ak-slug-input>
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
<ak-form-element-horizontal name="enabled">
|
<ak-form-element-horizontal name="enabled">
|
||||||
<label class="pf-c-switch">
|
<label class="pf-c-switch">
|
||||||
<input
|
<input
|
||||||
@ -262,11 +260,11 @@ export class LDAPSourceForm extends BaseSourceForm<LDAPSource> {
|
|||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-secret-text-input
|
<ak-private-text-input
|
||||||
label=${msg("Bind Password")}
|
label=${msg("Bind Password")}
|
||||||
name="bindPassword"
|
name="bindPassword"
|
||||||
?revealed=${this.instance === undefined}
|
?revealed=${this.instance === undefined}
|
||||||
></ak-secret-text-input>
|
></ak-private-text-input>
|
||||||
<ak-form-element-horizontal label=${msg("Base DN")} required name="baseDn">
|
<ak-form-element-horizontal label=${msg("Base DN")} required name="baseDn">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
|||||||
@ -8,9 +8,8 @@ import {
|
|||||||
UserMatchingModeToLabel,
|
UserMatchingModeToLabel,
|
||||||
} from "@goauthentik/admin/sources/oauth/utils";
|
} from "@goauthentik/admin/sources/oauth/utils";
|
||||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
||||||
|
import "@goauthentik/components/ak-private-textarea-input.js";
|
||||||
import "@goauthentik/components/ak-radio-input";
|
import "@goauthentik/components/ak-radio-input";
|
||||||
import "@goauthentik/components/ak-secret-textarea-input.js";
|
|
||||||
import "@goauthentik/components/ak-slug-input.js";
|
|
||||||
import "@goauthentik/elements/CodeMirror";
|
import "@goauthentik/elements/CodeMirror";
|
||||||
import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror";
|
import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror";
|
||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
@ -268,13 +267,16 @@ export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuth
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-slug-input
|
<ak-form-element-horizontal label=${msg("Slug")} required name="slug">
|
||||||
name="slug"
|
<input
|
||||||
value=${ifDefined(this.instance?.slug)}
|
type="text"
|
||||||
label=${msg("Slug")}
|
value="${ifDefined(this.instance?.slug)}"
|
||||||
required
|
class="pf-c-form-control pf-m-monospace"
|
||||||
input-hint="code"
|
autocomplete="off"
|
||||||
></ak-slug-input>
|
spellcheck="false"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal name="enabled">
|
<ak-form-element-horizontal name="enabled">
|
||||||
<label class="pf-c-switch">
|
<label class="pf-c-switch">
|
||||||
<input
|
<input
|
||||||
@ -439,14 +441,14 @@ export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuth
|
|||||||
/>
|
/>
|
||||||
<p class="pf-c-form__helper-text">${msg("Also known as Client ID.")}</p>
|
<p class="pf-c-form__helper-text">${msg("Also known as Client ID.")}</p>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-secret-textarea-input
|
<ak-private-textarea-input
|
||||||
label=${msg("Consumer secret")}
|
label=${msg("Consumer secret")}
|
||||||
name="consumerSecret"
|
name="consumerSecret"
|
||||||
input-hint="code"
|
input-hint="code"
|
||||||
help=${msg("Also known as Client Secret.")}
|
help=${msg("Also known as Client Secret.")}
|
||||||
required
|
required
|
||||||
?revealed=${this.instance === undefined}
|
?revealed=${this.instance === undefined}
|
||||||
></ak-secret-textarea-input>
|
></ak-private-textarea-input>
|
||||||
<ak-form-element-horizontal label=${msg("Scopes")} name="additionalScopes">
|
<ak-form-element-horizontal label=${msg("Scopes")} name="additionalScopes">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import {
|
|||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import { PlexAPIClient, PlexResource, popupCenterScreen } from "@goauthentik/common/helpers/plex";
|
import { PlexAPIClient, PlexResource, popupCenterScreen } from "@goauthentik/common/helpers/plex";
|
||||||
import { ascii_letters, digits, randomString } from "@goauthentik/common/utils";
|
import { ascii_letters, digits, randomString } from "@goauthentik/common/utils";
|
||||||
import "@goauthentik/components/ak-slug-input.js";
|
|
||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider.js";
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider.js";
|
||||||
@ -129,7 +128,7 @@ export class PlexSourceForm extends WithCapabilitiesConfig(BaseSourceForm<PlexSo
|
|||||||
this.doAuth();
|
this.doAuth();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
${msg("Re-authenticate with Plex")}
|
${msg("Re-authenticate with plex")}
|
||||||
</button>
|
</button>
|
||||||
<ak-form-element-horizontal name="allowFriends">
|
<ak-form-element-horizontal name="allowFriends">
|
||||||
<label class="pf-c-switch">
|
<label class="pf-c-switch">
|
||||||
@ -184,15 +183,14 @@ export class PlexSourceForm extends WithCapabilitiesConfig(BaseSourceForm<PlexSo
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal label=${msg("Slug")} required name="slug">
|
||||||
<ak-slug-input
|
<input
|
||||||
name="slug"
|
type="text"
|
||||||
value=${ifDefined(this.instance?.slug)}
|
value="${ifDefined(this.instance?.slug)}"
|
||||||
label=${msg("Slug")}
|
class="pf-c-form-control"
|
||||||
required
|
required
|
||||||
input-hint="code"
|
/>
|
||||||
></ak-slug-input>
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
<ak-form-element-horizontal name="enabled">
|
<ak-form-element-horizontal name="enabled">
|
||||||
<label class="pf-c-switch">
|
<label class="pf-c-switch">
|
||||||
<input
|
<input
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import {
|
|||||||
UserMatchingModeToLabel,
|
UserMatchingModeToLabel,
|
||||||
} from "@goauthentik/admin/sources/oauth/utils";
|
} from "@goauthentik/admin/sources/oauth/utils";
|
||||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
||||||
import "@goauthentik/components/ak-slug-input.js";
|
|
||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
@ -26,7 +25,7 @@ import {
|
|||||||
DigestAlgorithmEnum,
|
DigestAlgorithmEnum,
|
||||||
FlowsInstancesListDesignationEnum,
|
FlowsInstancesListDesignationEnum,
|
||||||
GroupMatchingModeEnum,
|
GroupMatchingModeEnum,
|
||||||
SAMLNameIDPolicyEnum,
|
NameIdPolicyEnum,
|
||||||
SAMLSource,
|
SAMLSource,
|
||||||
SignatureAlgorithmEnum,
|
SignatureAlgorithmEnum,
|
||||||
SourcesApi,
|
SourcesApi,
|
||||||
@ -90,15 +89,14 @@ export class SAMLSourceForm extends WithCapabilitiesConfig(BaseSourceForm<SAMLSo
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal label=${msg("Slug")} required name="slug">
|
||||||
<ak-slug-input
|
<input
|
||||||
name="slug"
|
type="text"
|
||||||
value=${ifDefined(this.instance?.slug)}
|
value="${ifDefined(this.instance?.slug)}"
|
||||||
label=${msg("Slug")}
|
class="pf-c-form-control"
|
||||||
required
|
required
|
||||||
input-hint="code"
|
/>
|
||||||
></ak-slug-input>
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
<ak-form-element-horizontal name="enabled">
|
<ak-form-element-horizontal name="enabled">
|
||||||
<label class="pf-c-switch">
|
<label class="pf-c-switch">
|
||||||
<input
|
<input
|
||||||
@ -353,37 +351,37 @@ export class SAMLSourceForm extends WithCapabilitiesConfig(BaseSourceForm<SAMLSo
|
|||||||
>
|
>
|
||||||
<select class="pf-c-form-control">
|
<select class="pf-c-form-control">
|
||||||
<option
|
<option
|
||||||
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
|
value=${NameIdPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
|
||||||
?selected=${this.instance?.nameIdPolicy ===
|
?selected=${this.instance?.nameIdPolicy ===
|
||||||
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
|
NameIdPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
|
||||||
>
|
>
|
||||||
${msg("Persistent")}
|
${msg("Persistent")}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
|
value=${NameIdPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
|
||||||
?selected=${this.instance?.nameIdPolicy ===
|
?selected=${this.instance?.nameIdPolicy ===
|
||||||
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
|
NameIdPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
|
||||||
>
|
>
|
||||||
${msg("Email address")}
|
${msg("Email address")}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
|
value=${NameIdPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
|
||||||
?selected=${this.instance?.nameIdPolicy ===
|
?selected=${this.instance?.nameIdPolicy ===
|
||||||
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
|
NameIdPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
|
||||||
>
|
>
|
||||||
${msg("Windows")}
|
${msg("Windows")}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
|
value=${NameIdPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
|
||||||
?selected=${this.instance?.nameIdPolicy ===
|
?selected=${this.instance?.nameIdPolicy ===
|
||||||
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
|
NameIdPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
|
||||||
>
|
>
|
||||||
${msg("X509 Subject")}
|
${msg("X509 Subject")}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
|
value=${NameIdPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
|
||||||
?selected=${this.instance?.nameIdPolicy ===
|
?selected=${this.instance?.nameIdPolicy ===
|
||||||
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
|
NameIdPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
|
||||||
>
|
>
|
||||||
${msg("Transient")}
|
${msg("Transient")}
|
||||||
</option>
|
</option>
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { placeholderHelperText } from "@goauthentik/admin/helperText";
|
import { placeholderHelperText } from "@goauthentik/admin/helperText";
|
||||||
import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm";
|
import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import "@goauthentik/components/ak-slug-input.js";
|
|
||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
@ -49,15 +48,14 @@ export class SCIMSourceForm extends BaseSourceForm<SCIMSource> {
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal label=${msg("Slug")} required name="slug">
|
||||||
<ak-slug-input
|
<input
|
||||||
name="slug"
|
type="text"
|
||||||
value=${ifDefined(this.instance?.slug)}
|
value="${ifDefined(this.instance?.slug)}"
|
||||||
label=${msg("Slug")}
|
class="pf-c-form-control"
|
||||||
required
|
required
|
||||||
input-hint="code"
|
/>
|
||||||
></ak-slug-input>
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
<ak-form-element-horizontal name="enabled">
|
<ak-form-element-horizontal name="enabled">
|
||||||
<div class="pf-c-check">
|
<div class="pf-c-check">
|
||||||
<input
|
<input
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { RenderFlowOption } from "@goauthentik/admin/flows/utils";
|
import { RenderFlowOption } from "@goauthentik/admin/flows/utils";
|
||||||
import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
|
import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import "@goauthentik/components/ak-secret-text-input.js";
|
import "@goauthentik/components/ak-private-text-input.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import "@goauthentik/elements/forms/SearchSelect";
|
import "@goauthentik/elements/forms/SearchSelect";
|
||||||
@ -95,13 +95,13 @@ export class AuthenticatorDuoStageForm extends BaseStageForm<AuthenticatorDuoSta
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-secret-text-input
|
<ak-private-text-input
|
||||||
name="clientSecret"
|
name="clientSecret"
|
||||||
label=${msg("Secret key")}
|
label=${msg("Secret key")}
|
||||||
input-hint="code"
|
input-hint="code"
|
||||||
required
|
required
|
||||||
?revealed=${this.instance === undefined}
|
?revealed=${this.instance === undefined}
|
||||||
></ak-secret-text-input>
|
></ak-private-text-input>
|
||||||
</div>
|
</div>
|
||||||
</ak-form-group>
|
</ak-form-group>
|
||||||
<ak-form-group>
|
<ak-form-group>
|
||||||
@ -125,12 +125,12 @@ export class AuthenticatorDuoStageForm extends BaseStageForm<AuthenticatorDuoSta
|
|||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-secret-text-input
|
<ak-private-text-input
|
||||||
name="adminSecretKey"
|
name="adminSecretKey"
|
||||||
label=${msg("Secret key")}
|
label=${msg("Secret key")}
|
||||||
input-hint="code"
|
input-hint="code"
|
||||||
?revealed=${this.instance === undefined}
|
?revealed=${this.instance === undefined}
|
||||||
></ak-secret-text-input>
|
></ak-private-text-input>
|
||||||
</div>
|
</div>
|
||||||
</ak-form-group>
|
</ak-form-group>
|
||||||
<ak-form-group expanded>
|
<ak-form-group expanded>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { RenderFlowOption } from "@goauthentik/admin/flows/utils";
|
import { RenderFlowOption } from "@goauthentik/admin/flows/utils";
|
||||||
import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
|
import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import "@goauthentik/components/ak-secret-text-input.js";
|
import "@goauthentik/components/ak-private-text-input.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import "@goauthentik/elements/forms/Radio";
|
import "@goauthentik/elements/forms/Radio";
|
||||||
@ -77,11 +77,11 @@ export class AuthenticatorEmailStageForm extends BaseStageForm<AuthenticatorEmai
|
|||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
<ak-secret-text-input
|
<ak-private-text-input
|
||||||
name="password"
|
name="password"
|
||||||
label=${msg("SMTP Password")}
|
label=${msg("SMTP Password")}
|
||||||
?revealed=${this.instance === undefined}
|
?revealed=${this.instance === undefined}
|
||||||
></ak-secret-text-input>
|
></ak-private-text-input>
|
||||||
|
|
||||||
<ak-form-element-horizontal name="useTls">
|
<ak-form-element-horizontal name="useTls">
|
||||||
<label class="pf-c-switch">
|
<label class="pf-c-switch">
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
|
import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import "@goauthentik/components/ak-number-input";
|
import "@goauthentik/components/ak-number-input";
|
||||||
import "@goauthentik/components/ak-secret-text-input.js";
|
import "@goauthentik/components/ak-private-text-input.js";
|
||||||
import "@goauthentik/components/ak-switch-input";
|
import "@goauthentik/components/ak-switch-input";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
@ -70,7 +70,7 @@ export class CaptchaStageForm extends BaseStageForm<CaptchaStage> {
|
|||||||
</p>
|
</p>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
<ak-secret-text-input
|
<ak-private-text-input
|
||||||
name="privateKey"
|
name="privateKey"
|
||||||
label=${msg("Private Key")}
|
label=${msg("Private Key")}
|
||||||
input-hint="code"
|
input-hint="code"
|
||||||
@ -79,7 +79,7 @@ export class CaptchaStageForm extends BaseStageForm<CaptchaStage> {
|
|||||||
help=${msg(
|
help=${msg(
|
||||||
"Private key, acquired from https://www.google.com/recaptcha/intro/v3.html.",
|
"Private key, acquired from https://www.google.com/recaptcha/intro/v3.html.",
|
||||||
)}
|
)}
|
||||||
></ak-secret-text-input>
|
></ak-private-text-input>
|
||||||
|
|
||||||
<ak-switch-input
|
<ak-switch-input
|
||||||
name="interactive"
|
name="interactive"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
|
import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import "@goauthentik/components/ak-secret-text-input.js";
|
import "@goauthentik/components/ak-private-text-input.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import "@goauthentik/elements/utils/TimeDeltaHelp";
|
import "@goauthentik/elements/utils/TimeDeltaHelp";
|
||||||
@ -73,11 +73,11 @@ export class EmailStageForm extends BaseStageForm<EmailStage> {
|
|||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-secret-text-input
|
<ak-private-text-input
|
||||||
label=${msg("SMTP Password")}
|
label=${msg("SMTP Password")}
|
||||||
name="password"
|
name="password"
|
||||||
?revealed=${this.instance === undefined}
|
?revealed=${this.instance === undefined}
|
||||||
></ak-secret-text-input>
|
></ak-private-text-input>
|
||||||
<ak-form-element-horizontal name="useTls">
|
<ak-form-element-horizontal name="useTls">
|
||||||
<label class="pf-c-switch">
|
<label class="pf-c-switch">
|
||||||
<input
|
<input
|
||||||
|
|||||||
@ -41,27 +41,14 @@ export class InvitationForm extends ModelForm<Invitation, string> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
const checkSlug = (ev: InputEvent) => {
|
return html` <ak-form-element-horizontal slugMode label=${msg("Name")} required name="name">
|
||||||
if (ev && ev.target && ev.target instanceof HTMLInputElement) {
|
|
||||||
ev.target.value = (ev.target.value ?? "").replace(/[^a-z0-9-]/g, "");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="admin-stages-invitation-name"
|
|
||||||
value="${this.instance?.name || ""}"
|
value="${this.instance?.name || ""}"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
required
|
required
|
||||||
@input=${(ev: InputEvent) => checkSlug(ev)}
|
|
||||||
data-ak-slug="true"
|
data-ak-slug="true"
|
||||||
/>
|
/>
|
||||||
<p class="pf-c-form__helper-text">
|
|
||||||
${msg(
|
|
||||||
"The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.",
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal label=${msg("Expires")} required name="expires">
|
<ak-form-element-horizontal label=${msg("Expires")} required name="expires">
|
||||||
<input
|
<input
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import { dateTimeLocal } from "@goauthentik/common/temporal";
|
import { dateTimeLocal } from "@goauthentik/common/temporal";
|
||||||
import "@goauthentik/components/ak-hidden-text-input";
|
|
||||||
import { Form } from "@goauthentik/elements/forms/Form";
|
import { Form } from "@goauthentik/elements/forms/Form";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import { ModalForm } from "@goauthentik/elements/forms/ModalForm";
|
import { ModalForm } from "@goauthentik/elements/forms/ModalForm";
|
||||||
@ -125,14 +124,19 @@ export class ServiceAccountForm extends Form<UserServiceAccountRequest> {
|
|||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-hidden-text-input
|
<ak-form-element-horizontal label=${msg("Password")}>
|
||||||
label=${msg("Password")}
|
<input
|
||||||
value="${this.result?.token ?? ""}"
|
type="text"
|
||||||
.help=${msg(
|
readonly
|
||||||
"Valid for 360 days, after which the password will automatically rotate. You can copy the password from the Token List.",
|
value=${ifDefined(this.result?.token)}
|
||||||
)}
|
class="pf-c-form-control"
|
||||||
>
|
/>
|
||||||
</ak-hidden-text-input>
|
<p class="pf-c-form__helper-text">
|
||||||
|
${msg(
|
||||||
|
"Valid for 360 days, after which the password will automatically rotate. You can copy the password from the Token List.",
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
</form>`;
|
</form>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,21 @@
|
|||||||
|
import * as base64js from "base64-js";
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
|
|
||||||
|
export function b64enc(buf: Uint8Array): string {
|
||||||
|
return base64js.fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function b64RawEnc(buf: Uint8Array): string {
|
||||||
|
return base64js.fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function u8arr(input: string): Uint8Array {
|
||||||
|
return Uint8Array.from(atob(input.replace(/_/g, "/").replace(/-/g, "+")), (c) =>
|
||||||
|
c.charCodeAt(0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function checkWebAuthnSupport() {
|
export function checkWebAuthnSupport() {
|
||||||
if ("credentials" in navigator) {
|
if ("credentials" in navigator) {
|
||||||
return;
|
return;
|
||||||
@ -9,3 +25,121 @@ export function checkWebAuthnSupport() {
|
|||||||
}
|
}
|
||||||
throw new Error(msg("WebAuthn not supported by browser."));
|
throw new Error(msg("WebAuthn not supported by browser."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms items in the credentialCreateOptions generated on the server
|
||||||
|
* into byte arrays expected by the navigator.credentials.create() call
|
||||||
|
*/
|
||||||
|
export function transformCredentialCreateOptions(
|
||||||
|
credentialCreateOptions: PublicKeyCredentialCreationOptions,
|
||||||
|
userId: string,
|
||||||
|
): PublicKeyCredentialCreationOptions {
|
||||||
|
const user = credentialCreateOptions.user;
|
||||||
|
// Because json can't contain raw bytes, the server base64-encodes the User ID
|
||||||
|
// So to get the base64 encoded byte array, we first need to convert it to a regular
|
||||||
|
// string, then a byte array, re-encode it and wrap that in an array.
|
||||||
|
const stringId = decodeURIComponent(window.atob(userId));
|
||||||
|
user.id = u8arr(b64enc(u8arr(stringId)));
|
||||||
|
const challenge = u8arr(credentialCreateOptions.challenge.toString());
|
||||||
|
|
||||||
|
return {
|
||||||
|
...credentialCreateOptions,
|
||||||
|
challenge,
|
||||||
|
user,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Assertion {
|
||||||
|
id: string;
|
||||||
|
rawId: string;
|
||||||
|
type: string;
|
||||||
|
registrationClientExtensions: string;
|
||||||
|
response: {
|
||||||
|
clientDataJSON: string;
|
||||||
|
attestationObject: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms the binary data in the credential into base64 strings
|
||||||
|
* for posting to the server.
|
||||||
|
* @param {PublicKeyCredential} newAssertion
|
||||||
|
*/
|
||||||
|
export function transformNewAssertionForServer(newAssertion: PublicKeyCredential): Assertion {
|
||||||
|
const attObj = new Uint8Array(
|
||||||
|
(newAssertion.response as AuthenticatorAttestationResponse).attestationObject,
|
||||||
|
);
|
||||||
|
const clientDataJSON = new Uint8Array(newAssertion.response.clientDataJSON);
|
||||||
|
const rawId = new Uint8Array(newAssertion.rawId);
|
||||||
|
|
||||||
|
const registrationClientExtensions = newAssertion.getClientExtensionResults();
|
||||||
|
return {
|
||||||
|
id: newAssertion.id,
|
||||||
|
rawId: b64enc(rawId),
|
||||||
|
type: newAssertion.type,
|
||||||
|
registrationClientExtensions: JSON.stringify(registrationClientExtensions),
|
||||||
|
response: {
|
||||||
|
clientDataJSON: b64enc(clientDataJSON),
|
||||||
|
attestationObject: b64enc(attObj),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transformCredentialRequestOptions(
|
||||||
|
credentialRequestOptions: PublicKeyCredentialRequestOptions,
|
||||||
|
): PublicKeyCredentialRequestOptions {
|
||||||
|
const challenge = u8arr(credentialRequestOptions.challenge.toString());
|
||||||
|
|
||||||
|
const allowCredentials = (credentialRequestOptions.allowCredentials || []).map(
|
||||||
|
(credentialDescriptor) => {
|
||||||
|
const id = u8arr(credentialDescriptor.id.toString());
|
||||||
|
return Object.assign({}, credentialDescriptor, { id });
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...credentialRequestOptions,
|
||||||
|
challenge,
|
||||||
|
allowCredentials,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AuthAssertion {
|
||||||
|
id: string;
|
||||||
|
rawId: string;
|
||||||
|
type: string;
|
||||||
|
assertionClientExtensions: string;
|
||||||
|
response: {
|
||||||
|
clientDataJSON: string;
|
||||||
|
authenticatorData: string;
|
||||||
|
signature: string;
|
||||||
|
userHandle: string | null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes the binary data in the assertion into strings for posting to the server.
|
||||||
|
* @param {PublicKeyCredential} newAssertion
|
||||||
|
*/
|
||||||
|
export function transformAssertionForServer(newAssertion: PublicKeyCredential): AuthAssertion {
|
||||||
|
const response = newAssertion.response as AuthenticatorAssertionResponse;
|
||||||
|
const authData = new Uint8Array(response.authenticatorData);
|
||||||
|
const clientDataJSON = new Uint8Array(response.clientDataJSON);
|
||||||
|
const rawId = new Uint8Array(newAssertion.rawId);
|
||||||
|
const sig = new Uint8Array(response.signature);
|
||||||
|
const assertionClientExtensions = newAssertion.getClientExtensionResults();
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: newAssertion.id,
|
||||||
|
rawId: b64enc(rawId),
|
||||||
|
type: newAssertion.type,
|
||||||
|
assertionClientExtensions: JSON.stringify(assertionClientExtensions),
|
||||||
|
|
||||||
|
response: {
|
||||||
|
clientDataJSON: b64RawEnc(clientDataJSON),
|
||||||
|
signature: b64RawEnc(sig),
|
||||||
|
authenticatorData: b64RawEnc(authData),
|
||||||
|
userHandle: null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import { me } from "@goauthentik/common/users.js";
|
import { me } from "@goauthentik/common/users.js";
|
||||||
import { isUserRoute } from "@goauthentik/elements/router/utils.js";
|
import { isUserRoute } from "@goauthentik/elements/router/utils.js";
|
||||||
import { deepmerge, deepmergeInto } from "deepmerge-ts";
|
|
||||||
|
|
||||||
import { UiThemeEnum, UserSelf } from "@goauthentik/api";
|
import { UiThemeEnum, UserSelf } from "@goauthentik/api";
|
||||||
import { CurrentBrand } from "@goauthentik/api";
|
import { CurrentBrand } from "@goauthentik/api";
|
||||||
@ -97,12 +96,13 @@ export class DefaultUIConfig implements UIConfig {
|
|||||||
let globalUiConfig: Promise<UIConfig>;
|
let globalUiConfig: Promise<UIConfig>;
|
||||||
|
|
||||||
export function getConfigForUser(user: UserSelf): UIConfig {
|
export function getConfigForUser(user: UserSelf): UIConfig {
|
||||||
const settings = user.settings as UIConfig;
|
const settings = user.settings;
|
||||||
const config = new DefaultUIConfig();
|
let config = new DefaultUIConfig();
|
||||||
if (!settings) {
|
if (!settings) {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
return deepmerge({ ...config }, settings);
|
config = Object.assign(new DefaultUIConfig(), settings);
|
||||||
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function uiConfig(): Promise<UIConfig> {
|
export function uiConfig(): Promise<UIConfig> {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { AKElement, type AKElementProps } from "@goauthentik/elements/Base";
|
import { AKElement } from "@goauthentik/elements/Base";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement.js";
|
import "@goauthentik/elements/forms/HorizontalFormElement.js";
|
||||||
|
|
||||||
import { TemplateResult, html, nothing } from "lit";
|
import { TemplateResult, html, nothing } from "lit";
|
||||||
@ -6,19 +6,6 @@ import { property } from "lit/decorators.js";
|
|||||||
|
|
||||||
type HelpType = TemplateResult | typeof nothing;
|
type HelpType = TemplateResult | typeof nothing;
|
||||||
|
|
||||||
export interface HorizontalLightComponentProps<T> extends AKElementProps {
|
|
||||||
name: string;
|
|
||||||
label?: string;
|
|
||||||
required?: boolean;
|
|
||||||
help?: string;
|
|
||||||
bighelp?: TemplateResult | TemplateResult[];
|
|
||||||
hidden?: boolean;
|
|
||||||
invalid?: boolean;
|
|
||||||
errorMessages?: string[];
|
|
||||||
value?: T;
|
|
||||||
inputHint?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class HorizontalLightComponent<T> extends AKElement {
|
export class HorizontalLightComponent<T> extends AKElement {
|
||||||
// Render into the lightDOM. This effectively erases the shadowDOM nature of this component, but
|
// Render into the lightDOM. This effectively erases the shadowDOM nature of this component, but
|
||||||
// we're not actually using that and, for the meantime, we need the form handlers to be able to
|
// we're not actually using that and, for the meantime, we need the form handlers to be able to
|
||||||
@ -31,81 +18,37 @@ export class HorizontalLightComponent<T> extends AKElement {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The name attribute for the form element
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: String, reflect: true })
|
@property({ type: String, reflect: true })
|
||||||
name!: string;
|
name!: string;
|
||||||
|
|
||||||
/**
|
|
||||||
* The label for the input control
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: String, reflect: true })
|
@property({ type: String, reflect: true })
|
||||||
label = "";
|
label = "";
|
||||||
|
|
||||||
/**
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: Boolean, reflect: true })
|
@property({ type: Boolean, reflect: true })
|
||||||
required = false;
|
required = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Help text to display below the form element. Optional
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: String, reflect: true })
|
@property({ type: String, reflect: true })
|
||||||
help = "";
|
help = "";
|
||||||
|
|
||||||
/**
|
|
||||||
* Extended help content. Optional. Expects to be a TemplateResult
|
|
||||||
* @property
|
|
||||||
*/
|
|
||||||
@property({ type: Object })
|
@property({ type: Object })
|
||||||
bighelp?: TemplateResult | TemplateResult[];
|
bighelp?: TemplateResult | TemplateResult[];
|
||||||
|
|
||||||
/**
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: Boolean, reflect: true })
|
@property({ type: Boolean, reflect: true })
|
||||||
hidden = false;
|
hidden = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: Boolean, reflect: true })
|
@property({ type: Boolean, reflect: true })
|
||||||
invalid = false;
|
invalid = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* @property
|
|
||||||
*/
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
errorMessages: string[] = [];
|
errorMessages: string[] = [];
|
||||||
|
|
||||||
/**
|
|
||||||
* @attribute
|
|
||||||
* @property
|
|
||||||
*/
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
value?: T;
|
value?: T;
|
||||||
|
|
||||||
/**
|
|
||||||
* Input hint.
|
|
||||||
* - `code`: uses a monospace font and disables spellcheck & autocomplete
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: String, attribute: "input-hint" })
|
@property({ type: String, attribute: "input-hint" })
|
||||||
inputHint = "";
|
inputHint = "";
|
||||||
|
|
||||||
protected renderControl() {
|
renderControl() {
|
||||||
throw new Error("Must be implemented in a subclass");
|
throw new Error("Must be implemented in a subclass");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,159 +0,0 @@
|
|||||||
import { bound } from "#elements/decorators/bound";
|
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
|
||||||
import { css, html } from "lit";
|
|
||||||
import { customElement, property, query } from "lit/decorators.js";
|
|
||||||
import { classMap } from "lit/directives/class-map.js";
|
|
||||||
import { ifDefined } from "lit/directives/if-defined.js";
|
|
||||||
|
|
||||||
import {
|
|
||||||
HorizontalLightComponent,
|
|
||||||
HorizontalLightComponentProps,
|
|
||||||
} from "./HorizontalLightComponent";
|
|
||||||
import "./ak-visibility-toggle.js";
|
|
||||||
import type { VisibilityToggleProps } from "./ak-visibility-toggle.js";
|
|
||||||
|
|
||||||
type BaseProps = HorizontalLightComponentProps<string> &
|
|
||||||
Pick<VisibilityToggleProps, "showMessage" | "hideMessage">;
|
|
||||||
|
|
||||||
export interface AkHiddenTextInputProps extends BaseProps {
|
|
||||||
revealed: boolean;
|
|
||||||
placeholder?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type InputLike = HTMLTextAreaElement | HTMLInputElement;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @element ak-hidden-text-input
|
|
||||||
* @class AkHiddenTextInput
|
|
||||||
*
|
|
||||||
* A text-input field with a visibility control, so you can show/hide sensitive fields.
|
|
||||||
*
|
|
||||||
* ## CSS Parts
|
|
||||||
* @csspart container - The main container div
|
|
||||||
* @csspart input - The input element
|
|
||||||
* @csspart toggle - The visibility toggle button
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@customElement("ak-hidden-text-input")
|
|
||||||
export class AkHiddenTextInput<T extends InputLike = HTMLInputElement>
|
|
||||||
extends HorizontalLightComponent<string>
|
|
||||||
implements AkHiddenTextInputProps
|
|
||||||
{
|
|
||||||
public static get styles() {
|
|
||||||
return [
|
|
||||||
css`
|
|
||||||
main {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: String, reflect: true })
|
|
||||||
public value = "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: Boolean, reflect: true })
|
|
||||||
public revealed = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Text for when the input has no set value
|
|
||||||
*
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: String })
|
|
||||||
public placeholder?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify kind of help the browser should try to provide
|
|
||||||
*
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: String })
|
|
||||||
public autocomplete?: "none" | AutoFill;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: String, attribute: "show-message" })
|
|
||||||
public showMessage = msg("Show field content");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: String, attribute: "hide-message" })
|
|
||||||
public hideMessage = msg("Hide field content");
|
|
||||||
|
|
||||||
@query("#main > input")
|
|
||||||
protected inputField!: T;
|
|
||||||
|
|
||||||
@bound
|
|
||||||
private handleToggleVisibility() {
|
|
||||||
this.revealed = !this.revealed;
|
|
||||||
|
|
||||||
// Maintain focus on input after toggle
|
|
||||||
this.updateComplete.then(() => {
|
|
||||||
if (this.inputField && document.activeElement === this) {
|
|
||||||
this.inputField.focus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Because of the peculiarities of how HorizontalLightComponent works, keeping its content
|
|
||||||
// in the LightDom so the inner components actually inherit styling, the normal `css` options
|
|
||||||
// aren't available. Embedding styles is bad styling, and we'll fix it in the next style
|
|
||||||
// refresh.
|
|
||||||
protected renderInputField(setValue: (ev: InputEvent) => void, code: boolean) {
|
|
||||||
return html` <input
|
|
||||||
style="flex: 1 1 auto; min-width: 0;"
|
|
||||||
part="input"
|
|
||||||
type=${this.revealed ? "text" : "password"}
|
|
||||||
@input=${setValue}
|
|
||||||
value=${ifDefined(this.value)}
|
|
||||||
placeholder=${ifDefined(this.placeholder)}
|
|
||||||
class="${classMap({
|
|
||||||
"pf-c-form-control": true,
|
|
||||||
"pf-m-monospace": code,
|
|
||||||
})}"
|
|
||||||
spellcheck=${code ? "false" : "true"}
|
|
||||||
?required=${this.required}
|
|
||||||
/>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override renderControl() {
|
|
||||||
const code = this.inputHint === "code";
|
|
||||||
const setValue = (ev: InputEvent) => {
|
|
||||||
this.value = (ev.target as T).value;
|
|
||||||
};
|
|
||||||
return html` <div style="display: flex; gap: 0.25rem">
|
|
||||||
${this.renderInputField(setValue, code)}
|
|
||||||
<!-- -->
|
|
||||||
<ak-visibility-toggle
|
|
||||||
part="toggle"
|
|
||||||
style="flex: 0 0 auto; align-self: flex-start"
|
|
||||||
?open=${this.revealed}
|
|
||||||
show-message=${this.showMessage}
|
|
||||||
hide-message=${this.hideMessage}
|
|
||||||
@click=${() => (this.revealed = !this.revealed)}
|
|
||||||
></ak-visibility-toggle>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"ak-hidden-text-input": AkHiddenTextInput;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,128 +0,0 @@
|
|||||||
import { css, html } from "lit";
|
|
||||||
import { customElement, property, query } from "lit/decorators.js";
|
|
||||||
import { classMap } from "lit/directives/class-map.js";
|
|
||||||
import { ifDefined } from "lit/directives/if-defined.js";
|
|
||||||
|
|
||||||
import { AkHiddenTextInput, type AkHiddenTextInputProps } from "./ak-hidden-text-input.js";
|
|
||||||
|
|
||||||
export interface AkHiddenTextAreaInputProps extends AkHiddenTextInputProps {
|
|
||||||
/**
|
|
||||||
* Number of visible text lines (rows)
|
|
||||||
*/
|
|
||||||
rows?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of visible character width (cols)
|
|
||||||
*/
|
|
||||||
cols?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* How the textarea can be resized
|
|
||||||
*/
|
|
||||||
resize?: "none" | "both" | "horizontal" | "vertical";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether text should wrap
|
|
||||||
*/
|
|
||||||
wrap?: "soft" | "hard" | "off";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @element ak-hidden-text-input
|
|
||||||
* @class AkHiddenTextInput
|
|
||||||
*
|
|
||||||
* A text-input field with a visibility control, so you can show/hide sensitive fields.
|
|
||||||
*
|
|
||||||
* ## CSS Parts
|
|
||||||
* @csspart container - The main container div
|
|
||||||
* @csspart input - The input element
|
|
||||||
* @csspart toggle - The visibility toggle button
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@customElement("ak-hidden-textarea-input")
|
|
||||||
export class AkHiddenTextAreaInput
|
|
||||||
extends AkHiddenTextInput<HTMLTextAreaElement>
|
|
||||||
implements AkHiddenTextAreaInputProps
|
|
||||||
{
|
|
||||||
/* These are mostly just forwarded to the textarea component. */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: Number })
|
|
||||||
rows?: number = 4;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: Number })
|
|
||||||
cols?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*
|
|
||||||
* You want `resize=true` so that the resize value is visible in the component tag, activating
|
|
||||||
* the CSS associated with these values.
|
|
||||||
*/
|
|
||||||
@property({ type: String, reflect: true })
|
|
||||||
resize?: "none" | "both" | "horizontal" | "vertical" = "vertical";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: String })
|
|
||||||
wrap?: "soft" | "hard" | "off" = "soft";
|
|
||||||
|
|
||||||
@query("#main > textarea")
|
|
||||||
protected inputField!: HTMLTextAreaElement;
|
|
||||||
|
|
||||||
get displayValue() {
|
|
||||||
const value = this.value ?? "";
|
|
||||||
if (this.revealed) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value
|
|
||||||
.split("\n")
|
|
||||||
.reduce((acc: string[], line: string) => [...acc, "*".repeat(line.length)], [])
|
|
||||||
.join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Because of the peculiarities of how HorizontalLightComponent works, keeping its content
|
|
||||||
// in the LightDom so the inner components actually inherit styling, the normal `css` options
|
|
||||||
// aren't available. Embedding styles is bad styling, and we'll fix it in the next style
|
|
||||||
// refresh.
|
|
||||||
protected override renderInputField(setValue: (ev: InputEvent) => void, code: boolean) {
|
|
||||||
const wrap = this.revealed ? this.wrap : "soft";
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<textarea
|
|
||||||
style="flex: 1 1 auto; min-width: 0;"
|
|
||||||
part="textarea"
|
|
||||||
@input=${setValue}
|
|
||||||
placeholder=${ifDefined(this.placeholder)}
|
|
||||||
rows=${ifDefined(this.rows)}
|
|
||||||
cols=${ifDefined(this.cols)}
|
|
||||||
wrap=${ifDefined(wrap)}
|
|
||||||
class=${classMap({
|
|
||||||
"pf-c-form-control": true,
|
|
||||||
"pf-m-monospace": code,
|
|
||||||
})}
|
|
||||||
spellcheck=${code ? "false" : "true"}
|
|
||||||
?required=${this.required}
|
|
||||||
>
|
|
||||||
${this.displayValue}</textarea
|
|
||||||
>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"ak-hidden-textarea-input": AkHiddenTextAreaInput;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -8,8 +8,8 @@ import { ifDefined } from "lit/directives/if-defined.js";
|
|||||||
|
|
||||||
import { HorizontalLightComponent } from "./HorizontalLightComponent";
|
import { HorizontalLightComponent } from "./HorizontalLightComponent";
|
||||||
|
|
||||||
@customElement("ak-secret-text-input")
|
@customElement("ak-private-text-input")
|
||||||
export class AkSecretTextInput extends HorizontalLightComponent<string> {
|
export class AkPrivateTextInput extends HorizontalLightComponent<string> {
|
||||||
@property({ type: String, reflect: true })
|
@property({ type: String, reflect: true })
|
||||||
public value = "";
|
public value = "";
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ export class AkSecretTextInput extends HorizontalLightComponent<string> {
|
|||||||
this.revealed = true;
|
this.revealed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#renderSecretInput() {
|
#renderPrivateInput() {
|
||||||
return html`<div class="pf-c-form__horizontal-group" @click=${() => this.#onReveal()}>
|
return html`<div class="pf-c-form__horizontal-group" @click=${() => this.#onReveal()}>
|
||||||
<input
|
<input
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
@ -60,14 +60,14 @@ export class AkSecretTextInput extends HorizontalLightComponent<string> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override renderControl() {
|
public override renderControl() {
|
||||||
return this.revealed ? this.renderVisibleInput() : this.#renderSecretInput();
|
return this.revealed ? this.renderVisibleInput() : this.#renderPrivateInput();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AkSecretTextInput;
|
export default AkPrivateTextInput;
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"ak-secret-text-input": AkSecretTextInput;
|
"ak-private-text-input": AkPrivateTextInput;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5,10 +5,10 @@ import { customElement, property } from "lit/decorators.js";
|
|||||||
import { classMap } from "lit/directives/class-map.js";
|
import { classMap } from "lit/directives/class-map.js";
|
||||||
import { ifDefined } from "lit/directives/if-defined.js";
|
import { ifDefined } from "lit/directives/if-defined.js";
|
||||||
|
|
||||||
import { AkSecretTextInput } from "./ak-secret-text-input.js";
|
import { AkPrivateTextInput } from "./ak-private-text-input.js";
|
||||||
|
|
||||||
@customElement("ak-secret-textarea-input")
|
@customElement("ak-private-textarea-input")
|
||||||
export class AkSecretTextAreaInput extends AkSecretTextInput {
|
export class AkPrivateTextAreaInput extends AkPrivateTextInput {
|
||||||
protected override renderVisibleInput() {
|
protected override renderVisibleInput() {
|
||||||
const code = this.inputHint === "code";
|
const code = this.inputHint === "code";
|
||||||
const setValue = (ev: InputEvent) => {
|
const setValue = (ev: InputEvent) => {
|
||||||
@ -34,10 +34,10 @@ export class AkSecretTextAreaInput extends AkSecretTextInput {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AkSecretTextAreaInput;
|
export default AkPrivateTextAreaInput;
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"ak-secret-textarea-input": AkSecretTextAreaInput;
|
"ak-private-textarea-input": AkPrivateTextAreaInput;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,5 +1,4 @@
|
|||||||
import { bound } from "@goauthentik/elements/decorators/bound.js";
|
import { formatSlug } from "@goauthentik/elements/router/utils.js";
|
||||||
import { kebabCase } from "change-case";
|
|
||||||
|
|
||||||
import { html } from "lit";
|
import { html } from "lit";
|
||||||
import { customElement, property, query } from "lit/decorators.js";
|
import { customElement, property, query } from "lit/decorators.js";
|
||||||
@ -7,83 +6,59 @@ import { ifDefined } from "lit/directives/if-defined.js";
|
|||||||
|
|
||||||
import { HorizontalLightComponent } from "./HorizontalLightComponent";
|
import { HorizontalLightComponent } from "./HorizontalLightComponent";
|
||||||
|
|
||||||
const slugify = (s: string) => kebabCase(s, { suffixCharacters: "-" });
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @element ak-slug-input
|
|
||||||
* @class AkSlugInput
|
|
||||||
*
|
|
||||||
* A wrapper around `ak-form-element-horizontal` and a text input control that listens for input on
|
|
||||||
* a peer text input control and automatically mirrors that control's value, transforming the value
|
|
||||||
* into a slug and displaying it separately.
|
|
||||||
*
|
|
||||||
* If the user manually changes the slug, mirroring and transformation stop. If, after that, both
|
|
||||||
* fields are cleared manually, mirroring and transformation resume.
|
|
||||||
*
|
|
||||||
* ## Limitations:
|
|
||||||
*
|
|
||||||
* Both the source text field and the slug field must be rendered in the same render pass (i.e.,
|
|
||||||
* part of the same singular call to a `render` function) so that the slug field can find its
|
|
||||||
* source.
|
|
||||||
*
|
|
||||||
* For the same reason, both the source text field and the slug field must share the same immediate
|
|
||||||
* parent DOM object.
|
|
||||||
*
|
|
||||||
* Since we expect the source text field and the slug to be part of the same form and rendered not
|
|
||||||
* just in the same form but in the same form group, these are not considered burdensome
|
|
||||||
* restrictions.
|
|
||||||
*/
|
|
||||||
@customElement("ak-slug-input")
|
@customElement("ak-slug-input")
|
||||||
export class AkSlugInput extends HorizontalLightComponent<string> {
|
export class AkSlugInput extends HorizontalLightComponent<string> {
|
||||||
/**
|
|
||||||
* A selector indicating the source text input control. Must be unique within the whole DOM
|
|
||||||
* context of the slug and source controls. The most common use in authentik is the default:
|
|
||||||
* slugifying the "name" of something.
|
|
||||||
*/
|
|
||||||
@property({ type: String })
|
|
||||||
public source = "[name='name']";
|
|
||||||
|
|
||||||
@property({ type: String, reflect: true })
|
@property({ type: String, reflect: true })
|
||||||
public value = "";
|
value = "";
|
||||||
|
|
||||||
|
@property({ type: String })
|
||||||
|
source = "";
|
||||||
|
|
||||||
|
origin?: HTMLInputElement | null;
|
||||||
|
|
||||||
@query("input")
|
@query("input")
|
||||||
private input!: HTMLInputElement;
|
input!: HTMLInputElement;
|
||||||
|
|
||||||
#origin?: HTMLInputElement | null;
|
touched: boolean = false;
|
||||||
|
|
||||||
#touched: boolean = false;
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.slugify = this.slugify.bind(this);
|
||||||
|
this.handleTouch = this.handleTouch.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
this.input.addEventListener("input", this.handleTouch);
|
||||||
|
}
|
||||||
|
|
||||||
// Do not stop propagation of this event; it must be sent up the tree so that a parent
|
// Do not stop propagation of this event; it must be sent up the tree so that a parent
|
||||||
// component, such as a custom forms manager, may receive it.
|
// component, such as a custom forms manager, may receive it.
|
||||||
protected handleTouch(ev: Event) {
|
handleTouch(ev: Event) {
|
||||||
this.value = this.input.value = slugify(this.input.value);
|
this.input.value = formatSlug(this.input.value);
|
||||||
|
this.value = this.input.value;
|
||||||
|
|
||||||
// Reset 'touched' status if the slug & target have been reset
|
if (this.origin && this.origin.value === "" && this.input.value === "") {
|
||||||
if (this.#origin && this.#origin.value === "" && this.input.value === "") {
|
this.touched = false;
|
||||||
this.#touched = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ev && ev.target && ev.target instanceof HTMLInputElement) {
|
if (ev && ev.target && ev.target instanceof HTMLInputElement) {
|
||||||
this.#touched = true;
|
this.touched = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@bound
|
slugify(ev: Event) {
|
||||||
protected slugify(ev: Event) {
|
|
||||||
if (!(ev && ev.target && ev.target instanceof HTMLInputElement)) {
|
if (!(ev && ev.target && ev.target instanceof HTMLInputElement)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset 'touched' status if the slug & target have been reset
|
// Reset 'touched' status if the slug & target have been reset
|
||||||
if (ev.target.value === "" && this.input.value === "") {
|
if (ev.target.value === "" && this.input.value === "") {
|
||||||
this.#touched = false;
|
this.touched = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't proceed if the user has hand-modified the slug. (Note the order of statements: if
|
// Don't proceed if the user has hand-modified the slug
|
||||||
// the user hand modified the slug to be empty as part of resetting the slug/source
|
if (this.touched) {
|
||||||
// relationship, that's a "not-touched" condition and falls through.)
|
|
||||||
if (this.#touched) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +67,7 @@ export class AkSlugInput extends HorizontalLightComponent<string> {
|
|||||||
// "any event which adds or removes a character but leaves the rest of the slug looking like
|
// "any event which adds or removes a character but leaves the rest of the slug looking like
|
||||||
// the previous iteration, set it to the current iteration."
|
// the previous iteration, set it to the current iteration."
|
||||||
|
|
||||||
const newSlug = slugify(ev.target.value);
|
const newSlug = formatSlug(ev.target.value);
|
||||||
const oldSlug = this.input.value;
|
const oldSlug = this.input.value;
|
||||||
const [shorter, longer] =
|
const [shorter, longer] =
|
||||||
newSlug.length < oldSlug.length ? [newSlug, oldSlug] : [oldSlug, newSlug];
|
newSlug.length < oldSlug.length ? [newSlug, oldSlug] : [oldSlug, newSlug];
|
||||||
@ -106,6 +81,7 @@ export class AkSlugInput extends HorizontalLightComponent<string> {
|
|||||||
// to listeners, both the name and value of the host must match those of the target
|
// to listeners, both the name and value of the host must match those of the target
|
||||||
// input. The name is already handled since it's both required and automatically
|
// input. The name is already handled since it's both required and automatically
|
||||||
// forwarded to our templated input, but the value must also be set.
|
// forwarded to our templated input, but the value must also be set.
|
||||||
|
|
||||||
this.value = this.input.value = newSlug;
|
this.value = this.input.value = newSlug;
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new Event("input", {
|
new Event("input", {
|
||||||
@ -115,36 +91,38 @@ export class AkSlugInput extends HorizontalLightComponent<string> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override disconnectedCallback() {
|
connectedCallback() {
|
||||||
if (this.#origin) {
|
super.connectedCallback();
|
||||||
this.#origin.removeEventListener("input", this.slugify);
|
|
||||||
|
// Set up listener on source element, so we can slugify the content.
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.source) {
|
||||||
|
const rootNode = this.getRootNode();
|
||||||
|
if (rootNode instanceof ShadowRoot || rootNode instanceof Document) {
|
||||||
|
this.origin = rootNode.querySelector(this.source);
|
||||||
|
}
|
||||||
|
if (this.origin) {
|
||||||
|
this.origin.addEventListener("input", this.slugify);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectedCallback() {
|
||||||
|
if (this.origin) {
|
||||||
|
this.origin.removeEventListener("input", this.slugify);
|
||||||
}
|
}
|
||||||
super.disconnectedCallback();
|
super.disconnectedCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override renderControl() {
|
renderControl() {
|
||||||
return html`<input
|
return html`<input
|
||||||
@input=${(ev: Event) => this.handleTouch(ev)}
|
|
||||||
type="text"
|
type="text"
|
||||||
value=${ifDefined(this.value)}
|
value=${ifDefined(this.value)}
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
?required=${this.required}
|
?required=${this.required}
|
||||||
/>`;
|
/>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override firstUpdated() {
|
|
||||||
if (!this.source) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const rootNode = this.getRootNode();
|
|
||||||
if (rootNode instanceof ShadowRoot || rootNode instanceof Document) {
|
|
||||||
this.#origin = rootNode.querySelector(this.source);
|
|
||||||
}
|
|
||||||
if (this.#origin) {
|
|
||||||
this.#origin.addEventListener("input", this.slugify);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AkSlugInput;
|
export default AkSlugInput;
|
||||||
|
|||||||
@ -1,89 +0,0 @@
|
|||||||
import { AKElement } from "@goauthentik/elements/Base.js";
|
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
|
||||||
import { html } from "lit";
|
|
||||||
import { customElement, property } from "lit/decorators.js";
|
|
||||||
|
|
||||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
|
||||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
|
||||||
|
|
||||||
export interface VisibilityToggleProps {
|
|
||||||
open: boolean;
|
|
||||||
disabled: boolean;
|
|
||||||
showMessage: string;
|
|
||||||
hideMessage: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @component ak-visibility-toggle
|
|
||||||
* @class VisibilityToggle
|
|
||||||
*
|
|
||||||
* A straightforward two-state iconic button we use in a few places as way of telling users to hide
|
|
||||||
* or show something secret, such as a password or private key. Expects the client to manage its
|
|
||||||
* state.
|
|
||||||
*
|
|
||||||
* @events
|
|
||||||
* - click: when the toggle is clicked.
|
|
||||||
*/
|
|
||||||
@customElement("ak-visibility-toggle")
|
|
||||||
export class VisibilityToggle extends AKElement implements VisibilityToggleProps {
|
|
||||||
static get styles() {
|
|
||||||
return [PFBase, PFButton];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: Boolean, reflect: true })
|
|
||||||
open = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: Boolean, reflect: true })
|
|
||||||
disabled = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: String, attribute: "show-message" })
|
|
||||||
showMessage = msg("Show field content");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @property
|
|
||||||
* @attribute
|
|
||||||
*/
|
|
||||||
@property({ type: String, attribute: "hide-message" })
|
|
||||||
hideMessage = msg("Hide field content");
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const [label, icon] = this.open
|
|
||||||
? [this.hideMessage, "fa-eye"]
|
|
||||||
: [this.showMessage, "fa-eye-slash"];
|
|
||||||
|
|
||||||
const onClick = (ev: PointerEvent) => {
|
|
||||||
ev.stopPropagation();
|
|
||||||
this.dispatchEvent(new PointerEvent(ev.type, ev));
|
|
||||||
};
|
|
||||||
|
|
||||||
return html`<button
|
|
||||||
aria-label=${label}
|
|
||||||
title=${label}
|
|
||||||
@click=${onClick}
|
|
||||||
?disabled=${this.disabled}
|
|
||||||
class="pf-c-button pf-m-control"
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<i class="fas ${icon}" aria-hidden="true"></i>
|
|
||||||
</button>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"ak-visibility-toggle": VisibilityToggle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -94,8 +94,7 @@ export class ObjectChangelog extends Table<Event> {
|
|||||||
|
|
||||||
renderEmpty(): TemplateResult {
|
renderEmpty(): TemplateResult {
|
||||||
return super.renderEmpty(
|
return super.renderEmpty(
|
||||||
html`<ak-empty-state
|
html`<ak-empty-state header=${msg("No Events found.")}>
|
||||||
><span slot="header">${msg("No Events found.")}</span>
|
|
||||||
<div slot="body">${msg("No matching events could be found.")}</div>
|
<div slot="body">${msg("No matching events could be found.")}</div>
|
||||||
</ak-empty-state>`,
|
</ak-empty-state>`,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -66,8 +66,7 @@ export class UserEvents extends Table<Event> {
|
|||||||
|
|
||||||
renderEmpty(): TemplateResult {
|
renderEmpty(): TemplateResult {
|
||||||
return super.renderEmpty(
|
return super.renderEmpty(
|
||||||
html`<ak-empty-state
|
html`<ak-empty-state header=${msg("No Events found.")}>
|
||||||
><span slot="header">${msg("No Events found.")}</span>
|
|
||||||
<div slot="body">${msg("No matching events could be found.")}</div>
|
<div slot="body">${msg("No matching events could be found.")}</div>
|
||||||
</ak-empty-state>`,
|
</ak-empty-state>`,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,93 +0,0 @@
|
|||||||
import type { Meta, StoryObj } from "@storybook/web-components";
|
|
||||||
|
|
||||||
import { html, nothing } from "lit";
|
|
||||||
import { ifDefined } from "lit/directives/if-defined.js";
|
|
||||||
|
|
||||||
import "../ak-hidden-text-input";
|
|
||||||
import { type AkHiddenTextInput, type AkHiddenTextInputProps } from "../ak-hidden-text-input.js";
|
|
||||||
|
|
||||||
const metadata: Meta<AkHiddenTextInputProps> = {
|
|
||||||
title: "Components / <ak-hidden-text-input>",
|
|
||||||
component: "ak-hidden-text-input",
|
|
||||||
tags: ["autodocs"],
|
|
||||||
parameters: {
|
|
||||||
docs: {
|
|
||||||
description: {
|
|
||||||
component: `
|
|
||||||
# Hidden Text Input Component
|
|
||||||
|
|
||||||
A text-input field with a visibility control, so you can show/hide sensitive fields.
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
layout: "padded",
|
|
||||||
},
|
|
||||||
argTypes: {
|
|
||||||
label: {
|
|
||||||
control: "text",
|
|
||||||
description: "Label text for the input field",
|
|
||||||
},
|
|
||||||
value: {
|
|
||||||
control: "text",
|
|
||||||
description: "Current value of the input",
|
|
||||||
},
|
|
||||||
revealed: {
|
|
||||||
control: "boolean",
|
|
||||||
description: "Whether the text is currently visible",
|
|
||||||
},
|
|
||||||
placeholder: {
|
|
||||||
control: "text",
|
|
||||||
description: "Placeholder text for the input",
|
|
||||||
},
|
|
||||||
required: {
|
|
||||||
control: "boolean",
|
|
||||||
description: "Whether the input is required",
|
|
||||||
},
|
|
||||||
inputHint: {
|
|
||||||
control: "select",
|
|
||||||
options: ["text", "code"],
|
|
||||||
description: "Input type hint for styling and behavior",
|
|
||||||
},
|
|
||||||
showMessage: {
|
|
||||||
control: "text",
|
|
||||||
description: "Custom message for show action",
|
|
||||||
},
|
|
||||||
hideMessage: {
|
|
||||||
control: "text",
|
|
||||||
description: "Custom message for hide action",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default metadata;
|
|
||||||
|
|
||||||
type Story = StoryObj<AkHiddenTextInput>;
|
|
||||||
|
|
||||||
const Template: Story = {
|
|
||||||
args: {
|
|
||||||
label: "Hidden Text Input",
|
|
||||||
value: "",
|
|
||||||
revealed: false,
|
|
||||||
},
|
|
||||||
render: (args) => html`
|
|
||||||
<ak-hidden-text-input
|
|
||||||
label=${ifDefined(args.label)}
|
|
||||||
value=${ifDefined(args.value)}
|
|
||||||
?revealed=${args.revealed}
|
|
||||||
placeholder=${ifDefined(args.placeholder)}
|
|
||||||
?required=${args.required}
|
|
||||||
input-hint=${ifDefined(args.inputHint)}
|
|
||||||
show-message=${ifDefined(args.showMessage)}
|
|
||||||
hide-message=${ifDefined(args.hideMessage)}
|
|
||||||
></ak-hidden-text-input>
|
|
||||||
`,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Password: Story = {
|
|
||||||
...Template,
|
|
||||||
args: {
|
|
||||||
label: "Password",
|
|
||||||
placeholder: "Enter your password",
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@ -1,140 +0,0 @@
|
|||||||
import type { Meta, StoryObj } from "@storybook/web-components";
|
|
||||||
|
|
||||||
import { html, nothing } from "lit";
|
|
||||||
import { ifDefined } from "lit/directives/if-defined.js";
|
|
||||||
|
|
||||||
import "../ak-hidden-textarea-input";
|
|
||||||
import {
|
|
||||||
type AkHiddenTextAreaInput,
|
|
||||||
type AkHiddenTextAreaInputProps,
|
|
||||||
} from "../ak-hidden-textarea-input.js";
|
|
||||||
|
|
||||||
const metadata: Meta<AkHiddenTextAreaInputProps> = {
|
|
||||||
title: "Components / <ak-hidden-textarea-input>",
|
|
||||||
component: "ak-hidden-textarea-input",
|
|
||||||
tags: ["autodocs"],
|
|
||||||
parameters: {
|
|
||||||
docs: {
|
|
||||||
description: {
|
|
||||||
component: `
|
|
||||||
# Hidden Textarea Input Component
|
|
||||||
|
|
||||||
A textarea input field with a visibility control, so you can show/hide sensitive fields.
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
layout: "padded",
|
|
||||||
},
|
|
||||||
argTypes: {
|
|
||||||
label: {
|
|
||||||
control: "text",
|
|
||||||
description: "Label text for the input field",
|
|
||||||
},
|
|
||||||
value: {
|
|
||||||
control: "text",
|
|
||||||
description: "Current value of the input",
|
|
||||||
},
|
|
||||||
revealed: {
|
|
||||||
control: "boolean",
|
|
||||||
description: "Whether the text is currently visible",
|
|
||||||
},
|
|
||||||
placeholder: {
|
|
||||||
control: "text",
|
|
||||||
description: "Placeholder text for the input",
|
|
||||||
},
|
|
||||||
required: {
|
|
||||||
control: "boolean",
|
|
||||||
description: "Whether the input is required",
|
|
||||||
},
|
|
||||||
inputHint: {
|
|
||||||
control: "select",
|
|
||||||
options: ["text", "code"],
|
|
||||||
description: "Input type hint for styling and behavior",
|
|
||||||
},
|
|
||||||
showMessage: {
|
|
||||||
control: "text",
|
|
||||||
description: "Custom message for show action",
|
|
||||||
},
|
|
||||||
hideMessage: {
|
|
||||||
control: "text",
|
|
||||||
description: "Custom message for hide action",
|
|
||||||
},
|
|
||||||
rows: {
|
|
||||||
control: { type: "number", min: 1, max: 50 },
|
|
||||||
description: "Number of visible text lines",
|
|
||||||
},
|
|
||||||
cols: {
|
|
||||||
control: { type: "number", min: 10, max: 200 },
|
|
||||||
description: "Number of visible character width",
|
|
||||||
},
|
|
||||||
resize: {
|
|
||||||
control: "select",
|
|
||||||
options: ["none", "both", "horizontal", "vertical"],
|
|
||||||
description: "How the textarea can be resized",
|
|
||||||
},
|
|
||||||
wrap: {
|
|
||||||
control: "select",
|
|
||||||
options: ["soft", "hard", "off"],
|
|
||||||
description: "Text wrapping behavior",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default metadata;
|
|
||||||
|
|
||||||
type Story = StoryObj<AkHiddenTextAreaInput>;
|
|
||||||
|
|
||||||
const Template: Story = {
|
|
||||||
args: {
|
|
||||||
label: "Hidden Textarea Input",
|
|
||||||
value: "",
|
|
||||||
revealed: false,
|
|
||||||
rows: 4,
|
|
||||||
},
|
|
||||||
render: (args) => html`
|
|
||||||
<ak-hidden-textarea-input
|
|
||||||
label=${ifDefined(args.label)}
|
|
||||||
value=${ifDefined(args.value)}
|
|
||||||
?revealed=${args.revealed}
|
|
||||||
placeholder=${ifDefined(args.placeholder)}
|
|
||||||
rows=${ifDefined(args.rows)}
|
|
||||||
cols=${ifDefined(args.cols)}
|
|
||||||
resize=${ifDefined(args.resize)}
|
|
||||||
wrap=${ifDefined(args.wrap)}
|
|
||||||
?required=${args.required}
|
|
||||||
input-hint=${ifDefined(args.inputHint)}
|
|
||||||
show-message=${ifDefined(args.showMessage)}
|
|
||||||
hide-message=${ifDefined(args.hideMessage)}
|
|
||||||
></ak-hidden-textarea-input>
|
|
||||||
`,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const SslCertificate: Story = {
|
|
||||||
...Template,
|
|
||||||
args: {
|
|
||||||
label: "SSL Certificate",
|
|
||||||
value: `-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDXTCCAkWgAwIBAgIJAKoK/heBjcOuMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
|
|
||||||
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
|
|
||||||
aWRnaXRzIFB0eSBMdGQwHhcNMTcwNTEwMTk0MDA2WhcNMTgwNTEwMTk0MDA2WjBF
|
|
||||||
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
|
|
||||||
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE3MDUxMDE5NDAwNloXDTE4MDUxMDE5
|
|
||||||
NDAwNlowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNV
|
|
||||||
BAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQAD
|
|
||||||
ggEPADCCAQoCggEBALdUlNS31SzxwoFShahGfjHj6GgpcVbzL1Siq0Pqnf82T6M2
|
|
||||||
EDuneMLzAgMBAAECggEBAJkPFn6jeMHyiq0Pqnf82T6M2EDuneMLzAgMBAAECggE
|
|
||||||
BAJkPFn6jeMHyiq0Pqnf82T6M2EDuneMLzAgMBAAECggEBAJkPFn6jeMHyiq0Pqn
|
|
||||||
f82T6M2EDuneMLzAgMBAAECggEBAJkPFn6jeMHyiq0Pqnf82T6M2EDuneMLzAgM
|
|
||||||
BAAECggEBAJkPFn6jeMHyiq0Pqnf82T6M2EDuneMLzAgMBAAECggEBAJkPFn6jeM
|
|
||||||
Hyiq0Pqnf82T6M2EDuneMLzAgMBAAECggEBAJkPFn6jeMHyiq0Pqnf82T6M2EDu
|
|
||||||
neMLzAgMBAAECggEBAJkPFn6jeMHyiq0Pqnf82T6M2EDuneMLzAgMBAAECggEBAJ
|
|
||||||
kPFn6jeMHyiq0Pqnf82T6M2EDuneMLzAgMBAAE=
|
|
||||||
-----END CERTIFICATE-----`,
|
|
||||||
inputHint: "code",
|
|
||||||
rows: 15,
|
|
||||||
resize: "vertical",
|
|
||||||
showMessage: "Show certificate content",
|
|
||||||
hideMessage: "Hide certificate content",
|
|
||||||
autocomplete: "off",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@ -1,121 +0,0 @@
|
|||||||
import type { Meta, StoryObj } from "@storybook/web-components";
|
|
||||||
|
|
||||||
import { html, nothing } from "lit";
|
|
||||||
import { ifDefined } from "lit/directives/if-defined.js";
|
|
||||||
|
|
||||||
import "../ak-visibility-toggle";
|
|
||||||
import { type VisibilityToggle, type VisibilityToggleProps } from "../ak-visibility-toggle.js";
|
|
||||||
|
|
||||||
const metadata: Meta<VisibilityToggleProps> = {
|
|
||||||
title: "Elements/<ak-visibility-toggle>",
|
|
||||||
component: "ak-visibility-toggle",
|
|
||||||
tags: ["autodocs"],
|
|
||||||
parameters: {
|
|
||||||
docs: {
|
|
||||||
description: {
|
|
||||||
component: `
|
|
||||||
# Visibility Toggle Component
|
|
||||||
|
|
||||||
A straightforward two-state iconic button for toggling the visibility of sensitive content such as passwords, private keys, or other secret information.
|
|
||||||
|
|
||||||
- Use for sensitive content that users might want to temporarily reveal
|
|
||||||
- There are default hide/show messages for screen readers, but they can be overridden
|
|
||||||
- Clients always handle the state
|
|
||||||
- The \`open\` state is false by default; we assume you want sensitive content hidden at start
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
layout: "padded",
|
|
||||||
},
|
|
||||||
argTypes: {
|
|
||||||
open: {
|
|
||||||
control: "boolean",
|
|
||||||
description: "Whether the toggle is in the 'show' state (true) or 'hide' state (false)",
|
|
||||||
},
|
|
||||||
showMessage: {
|
|
||||||
control: "text",
|
|
||||||
description:
|
|
||||||
'Message for screen readers when in hide state (default: "Show field content")',
|
|
||||||
},
|
|
||||||
hideMessage: {
|
|
||||||
control: "text",
|
|
||||||
description:
|
|
||||||
'Message for screen readers when in show state (default: "Hide field content")',
|
|
||||||
},
|
|
||||||
disabled: {
|
|
||||||
control: "boolean",
|
|
||||||
description: "Whether the button should be disabled (for demo purposes)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default metadata;
|
|
||||||
|
|
||||||
type Story = StoryObj<VisibilityToggle>;
|
|
||||||
|
|
||||||
const Template: Story = {
|
|
||||||
args: {
|
|
||||||
open: false,
|
|
||||||
showMessage: "Show field content",
|
|
||||||
hideMessage: "Hide field content",
|
|
||||||
},
|
|
||||||
render: (args) => html`
|
|
||||||
<ak-visibility-toggle
|
|
||||||
?open=${args.open}
|
|
||||||
show-message=${ifDefined(args.showMessage)}
|
|
||||||
hide-message=${ifDefined(args.hideMessage)}
|
|
||||||
@click=${(e: Event) => {
|
|
||||||
const target = e.target as VisibilityToggle;
|
|
||||||
target.open = !target.open;
|
|
||||||
// In a real application, you would also toggle the visibility
|
|
||||||
// of the associated content here
|
|
||||||
}}
|
|
||||||
></ak-visibility-toggle>
|
|
||||||
`,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Password field integration example
|
|
||||||
export const PasswordFieldExample: Story = {
|
|
||||||
args: {
|
|
||||||
showMessage: "Reveal password",
|
|
||||||
hideMessage: "Conceal password",
|
|
||||||
},
|
|
||||||
render: () => {
|
|
||||||
let isVisible = false;
|
|
||||||
|
|
||||||
const toggleVisibility = (e: Event) => {
|
|
||||||
isVisible = !isVisible;
|
|
||||||
const toggle = e.target as VisibilityToggle;
|
|
||||||
const passwordField = document.querySelector("#demo-password") as HTMLInputElement;
|
|
||||||
|
|
||||||
toggle.open = isVisible;
|
|
||||||
if (passwordField) {
|
|
||||||
passwordField.type = isVisible ? "text" : "password";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<div style="display: flex; flex-direction: column; gap: 1rem; max-width: 300px;">
|
|
||||||
<label for="demo-password" style="font-weight: bold;">Password:</label>
|
|
||||||
<div style="display: flex; align-items: center; gap: 0.5rem;">
|
|
||||||
<input
|
|
||||||
id="demo-password"
|
|
||||||
type="password"
|
|
||||||
value="supersecretpassword123"
|
|
||||||
style="flex: 1; padding: 0.5rem; border: 1px solid #ccc; border-radius: 4px;"
|
|
||||||
readonly
|
|
||||||
/>
|
|
||||||
<ak-visibility-toggle
|
|
||||||
?open=${isVisible}
|
|
||||||
show-message="Show password"
|
|
||||||
hide-message="Hide password"
|
|
||||||
@click=${toggleVisibility}
|
|
||||||
></ak-visibility-toggle>
|
|
||||||
</div>
|
|
||||||
<p style="font-size: 0.875rem; color: #666;">
|
|
||||||
Click the eye icon to toggle password visibility
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@ -16,12 +16,8 @@ import { property } from "lit/decorators.js";
|
|||||||
|
|
||||||
import { UiThemeEnum } from "@goauthentik/api";
|
import { UiThemeEnum } from "@goauthentik/api";
|
||||||
|
|
||||||
export interface AKElementProps {
|
|
||||||
activeTheme: ResolvedUITheme;
|
|
||||||
}
|
|
||||||
|
|
||||||
@localized()
|
@localized()
|
||||||
export class AKElement extends LitElement implements AKElementProps {
|
export class AKElement extends LitElement {
|
||||||
//#region Static Properties
|
//#region Static Properties
|
||||||
|
|
||||||
public static styles?: Array<CSSResult | CSSModule>;
|
public static styles?: Array<CSSResult | CSSModule>;
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { AKElement } from "@goauthentik/elements/Base";
|
|||||||
import "@goauthentik/elements/Spinner";
|
import "@goauthentik/elements/Spinner";
|
||||||
import { type SlottedTemplateResult, type Spread } from "@goauthentik/elements/types";
|
import { type SlottedTemplateResult, type Spread } from "@goauthentik/elements/types";
|
||||||
import { spread } from "@open-wc/lit-helpers";
|
import { spread } from "@open-wc/lit-helpers";
|
||||||
import { SlotController } from "@patternfly/pfe-core/controllers/slot-controller.js";
|
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { css, html, nothing } from "lit";
|
import { css, html, nothing } from "lit";
|
||||||
@ -34,8 +33,6 @@ export class EmptyState extends AKElement implements IEmptyState {
|
|||||||
@property()
|
@property()
|
||||||
header?: string;
|
header?: string;
|
||||||
|
|
||||||
slots = new SlotController(this, "header", "body", "primary");
|
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return [
|
return [
|
||||||
PFBase,
|
PFBase,
|
||||||
@ -51,12 +48,6 @@ export class EmptyState extends AKElement implements IEmptyState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const showHeader = this.loading || this.slots.hasSlotted("header");
|
|
||||||
const header = () =>
|
|
||||||
this.slots.hasSlotted("header")
|
|
||||||
? html`<slot name="header"></slot>`
|
|
||||||
: html`<span>${msg("Loading")}</span>`;
|
|
||||||
|
|
||||||
return html`<div class="pf-c-empty-state ${this.fullHeight && "pf-m-full-height"}">
|
return html`<div class="pf-c-empty-state ${this.fullHeight && "pf-m-full-height"}">
|
||||||
<div class="pf-c-empty-state__content">
|
<div class="pf-c-empty-state__content">
|
||||||
${this.loading
|
${this.loading
|
||||||
@ -68,17 +59,15 @@ export class EmptyState extends AKElement implements IEmptyState {
|
|||||||
"fa-question-circle"} pf-c-empty-state__icon"
|
"fa-question-circle"} pf-c-empty-state__icon"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>`}
|
></i>`}
|
||||||
${showHeader ? html` <h1 class="pf-c-title pf-m-lg">${header()}</h1>` : nothing}
|
<h1 class="pf-c-title pf-m-lg">
|
||||||
${this.slots.hasSlotted("body")
|
${this.loading && this.header === undefined ? msg("Loading") : this.header}
|
||||||
? html` <div class="pf-c-empty-state__body">
|
</h1>
|
||||||
<slot name="body"></slot>
|
<div class="pf-c-empty-state__body">
|
||||||
</div>`
|
<slot name="body"></slot>
|
||||||
: nothing}
|
</div>
|
||||||
${this.slots.hasSlotted("primary")
|
<div class="pf-c-empty-state__primary">
|
||||||
? html` <div class="pf-c-empty-state__primary">
|
<slot name="primary"></slot>
|
||||||
<slot name="primary"></slot>
|
</div>
|
||||||
</div>`
|
|
||||||
: nothing}
|
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,7 @@ import {
|
|||||||
|
|
||||||
function localeComparator(a: DualSelectPair, b: DualSelectPair) {
|
function localeComparator(a: DualSelectPair, b: DualSelectPair) {
|
||||||
const aSortBy = a[2] || a[0];
|
const aSortBy = a[2] || a[0];
|
||||||
const bSortBy = b[2] || b[0];
|
const bSortBy = b[2] || a[0];
|
||||||
|
|
||||||
return aSortBy.localeCompare(bSortBy);
|
return aSortBy.localeCompare(bSortBy);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -200,8 +200,7 @@ export abstract class AKChart<T> extends AKElement {
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
${this.error
|
${this.error
|
||||||
? html`
|
? html`
|
||||||
<ak-empty-state icon="fa-times"
|
<ak-empty-state header="${msg("Failed to fetch data.")}" icon="fa-times">
|
||||||
><span slot="header">${msg("Failed to fetch data.")}</span>
|
|
||||||
<p slot="body">${pluckErrorDetail(this.error)}</p>
|
<p slot="body">${pluckErrorDetail(this.error)}</p>
|
||||||
</ak-empty-state>
|
</ak-empty-state>
|
||||||
`
|
`
|
||||||
|
|||||||
@ -40,9 +40,7 @@ export class LogViewer extends Table<LogEvent> {
|
|||||||
|
|
||||||
renderEmpty(): TemplateResult {
|
renderEmpty(): TemplateResult {
|
||||||
return super.renderEmpty(
|
return super.renderEmpty(
|
||||||
html`<ak-empty-state
|
html`<ak-empty-state header=${msg("No log messages.")}> </ak-empty-state>`,
|
||||||
><span slot="header">${msg("No log messages.")}</span>
|
|
||||||
</ak-empty-state>`,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { AKElement } from "@goauthentik/elements/Base";
|
|||||||
import { HorizontalFormElement } from "@goauthentik/elements/forms/HorizontalFormElement";
|
import { HorizontalFormElement } from "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import { PreventFormSubmit } from "@goauthentik/elements/forms/helpers";
|
import { PreventFormSubmit } from "@goauthentik/elements/forms/helpers";
|
||||||
import { showMessage } from "@goauthentik/elements/messages/MessageContainer";
|
import { showMessage } from "@goauthentik/elements/messages/MessageContainer";
|
||||||
|
import { formatSlug } from "@goauthentik/elements/router/utils.js";
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||||
@ -196,6 +197,39 @@ export abstract class Form<T> extends AKElement {
|
|||||||
return this.successMessage;
|
return this.successMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After rendering the form, if there is both a `name` and `slug` element within the form,
|
||||||
|
* events the `name` element so that the slug will always have a slugified version of the
|
||||||
|
* `name.`. This duplicates functionality within ak-form-element-horizontal.
|
||||||
|
*/
|
||||||
|
updated(): void {
|
||||||
|
this.shadowRoot
|
||||||
|
?.querySelectorAll("ak-form-element-horizontal[name=name]")
|
||||||
|
.forEach((nameInput) => {
|
||||||
|
const input = nameInput.firstElementChild as HTMLInputElement;
|
||||||
|
const form = nameInput.closest("form");
|
||||||
|
if (form === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const slugFieldWrapper = form.querySelector(
|
||||||
|
"ak-form-element-horizontal[name=slug]",
|
||||||
|
);
|
||||||
|
if (!slugFieldWrapper) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const slugField = slugFieldWrapper.firstElementChild as HTMLInputElement;
|
||||||
|
// Only attach handler if the slug is already equal to the name
|
||||||
|
// if not, they are probably completely different and shouldn't update
|
||||||
|
// each other
|
||||||
|
if (formatSlug(input.value) !== slugField.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nameInput.addEventListener("input", () => {
|
||||||
|
slugField.value = formatSlug(input.value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
resetForm(): void {
|
resetForm(): void {
|
||||||
const form = this.shadowRoot?.querySelector<HTMLFormElement>("form");
|
const form = this.shadowRoot?.querySelector<HTMLFormElement>("form");
|
||||||
form?.reset();
|
form?.reset();
|
||||||
|
|||||||
@ -77,6 +77,9 @@ export class HorizontalFormElement extends AKElement {
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
errorMessages: string[] | string[][] = [];
|
errorMessages: string[] | string[][] = [];
|
||||||
|
|
||||||
|
@property({ type: Boolean })
|
||||||
|
slugMode = false;
|
||||||
|
|
||||||
_invalid = false;
|
_invalid = false;
|
||||||
|
|
||||||
/* If this property changes, we want to make sure the parent control is "opened" so
|
/* If this property changes, we want to make sure the parent control is "opened" so
|
||||||
@ -106,6 +109,13 @@ export class HorizontalFormElement extends AKElement {
|
|||||||
this.querySelectorAll<HTMLInputElement>("input[autofocus]").forEach((input) => {
|
this.querySelectorAll<HTMLInputElement>("input[autofocus]").forEach((input) => {
|
||||||
input.focus();
|
input.focus();
|
||||||
});
|
});
|
||||||
|
if (this.name === "slug" || this.slugMode) {
|
||||||
|
this.querySelectorAll<HTMLInputElement>("input[type='text']").forEach((input) => {
|
||||||
|
input.addEventListener("keyup", () => {
|
||||||
|
input.value = formatSlug(input.value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
this.querySelectorAll("*").forEach((input) => {
|
this.querySelectorAll("*").forEach((input) => {
|
||||||
if (isAkControl(input) && !input.getAttribute("name")) {
|
if (isAkControl(input) && !input.getAttribute("name")) {
|
||||||
input.setAttribute("name", this.name);
|
input.setAttribute("name", this.name);
|
||||||
|
|||||||
@ -163,8 +163,7 @@ export class NotificationDrawer extends AKElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderEmpty() {
|
renderEmpty() {
|
||||||
return html`<ak-empty-state
|
return html`<ak-empty-state header=${msg("No notifications found.")}>
|
||||||
><span slot="header">${msg("No notifications found.")}</span>
|
|
||||||
<div slot="body">${msg("You don't have any notifications currently.")}</div>
|
<div slot="body">${msg("You don't have any notifications currently.")}</div>
|
||||||
</ak-empty-state>`;
|
</ak-empty-state>`;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -288,9 +288,7 @@ export abstract class Table<T> extends AKElement implements TableLike {
|
|||||||
return html`<tr role="row">
|
return html`<tr role="row">
|
||||||
<td role="cell" colspan="25">
|
<td role="cell" colspan="25">
|
||||||
<div class="pf-l-bullseye">
|
<div class="pf-l-bullseye">
|
||||||
<ak-empty-state loading
|
<ak-empty-state loading header=${msg("Loading")}></ak-empty-state>
|
||||||
><span slot="header">${msg("Loading")}</span></ak-empty-state
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>`;
|
</tr>`;
|
||||||
@ -302,9 +300,8 @@ export abstract class Table<T> extends AKElement implements TableLike {
|
|||||||
<td role="cell" colspan="8">
|
<td role="cell" colspan="8">
|
||||||
<div class="pf-l-bullseye">
|
<div class="pf-l-bullseye">
|
||||||
${inner ??
|
${inner ??
|
||||||
html`<ak-empty-state
|
html`<ak-empty-state header="${msg("No objects found.")}"
|
||||||
><span slot="header">${msg("No objects found.")}</span> >
|
><div slot="primary">${this.renderObjectCreate()}</div>
|
||||||
<div slot="primary">${this.renderObjectCreate()}</div>
|
|
||||||
</ak-empty-state>`}
|
</ak-empty-state>`}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@ -319,8 +316,7 @@ export abstract class Table<T> extends AKElement implements TableLike {
|
|||||||
renderError(): SlottedTemplateResult {
|
renderError(): SlottedTemplateResult {
|
||||||
if (!this.error) return nothing;
|
if (!this.error) return nothing;
|
||||||
|
|
||||||
return html`<ak-empty-state icon="fa-ban"
|
return html`<ak-empty-state header="${msg("Failed to fetch objects.")}" icon="fa-ban">
|
||||||
><span slot="header">${msg("Failed to fetch objects.")}</span>
|
|
||||||
<div slot="body">${pluckErrorDetail(this.error)}</div>
|
<div slot="body">${pluckErrorDetail(this.error)}</div>
|
||||||
</ak-empty-state>`;
|
</ak-empty-state>`;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user