Compare commits
60 Commits
version/20
...
version-20
Author | SHA1 | Date | |
---|---|---|---|
4d791f4fef | |||
c03a069f02 | |||
040adb8ce7 | |||
ac07833688 | |||
be473470a4 | |||
445cd5b2c4 | |||
805a4b766a | |||
730139e43c | |||
24e8915e0a | |||
1e01e9813d | |||
119a268eb7 | |||
e887a315be | |||
c4bb51469b | |||
6edc043775 | |||
4379f5bc8e | |||
1ad56f4a13 | |||
f54e82781a | |||
e334d8ab00 | |||
e1c0f74152 | |||
e8f850285e | |||
4b93f40c5e | |||
57400925a4 | |||
ffed653cae | |||
ba5cd6e719 | |||
9564894eda | |||
042cd0b2cb | |||
049a97a800 | |||
aa6668f8cb | |||
13a129bb01 | |||
0974f58367 | |||
1d59bfd16e | |||
ebd73ec34f | |||
0629dee23b | |||
2dc0792d9e | |||
fde848ee51 | |||
e9d52282b7 | |||
c810628fe3 | |||
de0a5191f7 | |||
f6794829e4 | |||
475853fb14 | |||
1c1319927e | |||
964fdf171b | |||
93e20bce2e | |||
960a2aab74 | |||
2cae6596eb | |||
11b1eb4173 | |||
ee615c2d22 | |||
aef9a22331 | |||
3980eea7c6 | |||
d6d72489a7 | |||
9fdfb8c99b | |||
b9bb27008e | |||
82184b2882 | |||
f90a52c7d6 | |||
9ea0441559 | |||
5cab280759 | |||
a03a64b35c | |||
780b986be8 | |||
9d422918b3 | |||
b548ccca6e |
@ -1,5 +1,5 @@
|
||||
[bumpversion]
|
||||
current_version = 2022.12.1
|
||||
current_version = 2022.12.3
|
||||
tag = True
|
||||
commit = True
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)
|
||||
|
17
.github/workflows/ci-web.yml
vendored
17
.github/workflows/ci-web.yml
vendored
@ -27,6 +27,22 @@ jobs:
|
||||
- name: Eslint
|
||||
working-directory: web/
|
||||
run: npm run lint
|
||||
lint-build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3.5.1
|
||||
with:
|
||||
node-version: '16'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: web/package-lock.json
|
||||
- working-directory: web/
|
||||
run: npm ci
|
||||
- name: Generate API
|
||||
run: make gen-client-ts
|
||||
- name: TSC
|
||||
working-directory: web/
|
||||
run: npm run tsc
|
||||
lint-prettier:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@ -69,6 +85,7 @@ jobs:
|
||||
- lint-eslint
|
||||
- lint-prettier
|
||||
- lint-lit-analyse
|
||||
- lint-build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo mark
|
||||
|
5
Makefile
5
Makefile
@ -126,7 +126,7 @@ gen: gen-build gen-clean gen-client-ts
|
||||
web-build: web-install
|
||||
cd web && npm run build
|
||||
|
||||
web: web-lint-fix web-lint
|
||||
web: web-lint-fix web-lint web-check-compile
|
||||
|
||||
web-install:
|
||||
cd web && npm ci
|
||||
@ -144,6 +144,9 @@ web-lint:
|
||||
cd web && npm run lint
|
||||
cd web && npm run lit-analyse
|
||||
|
||||
web-check-compile:
|
||||
cd web && npm run tsc
|
||||
|
||||
web-extract:
|
||||
cd web && npm run extract
|
||||
|
||||
|
@ -2,16 +2,14 @@
|
||||
from os import environ
|
||||
from typing import Optional
|
||||
|
||||
__version__ = "2022.12.1"
|
||||
__version__ = "2022.12.3"
|
||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||
|
||||
|
||||
def get_build_hash(fallback: Optional[str] = None) -> str:
|
||||
"""Get build hash"""
|
||||
build_hash = environ.get(ENV_GIT_HASH_KEY, fallback if fallback else "")
|
||||
if build_hash == "" and fallback:
|
||||
return fallback
|
||||
return build_hash
|
||||
return fallback if build_hash == "" and fallback else build_hash
|
||||
|
||||
|
||||
def get_full_version() -> str:
|
||||
|
@ -8,7 +8,6 @@ from typing import TypedDict
|
||||
from django.utils.timezone import now
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from gunicorn import version_info as gunicorn_version
|
||||
from kubernetes.config.incluster_config import SERVICE_HOST_ENV_NAME
|
||||
from rest_framework.fields import SerializerMethodField
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rest_framework.request import Request
|
||||
@ -16,6 +15,7 @@ from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from authentik.core.api.utils import PassiveSerializer
|
||||
from authentik.lib.utils.reflection import get_env
|
||||
from authentik.outposts.apps import MANAGED_OUTPOST
|
||||
from authentik.outposts.models import Outpost
|
||||
|
||||
@ -69,7 +69,7 @@ class SystemSerializer(PassiveSerializer):
|
||||
return {
|
||||
"python_version": python_version,
|
||||
"gunicorn_version": ".".join(str(x) for x in gunicorn_version),
|
||||
"environment": "kubernetes" if SERVICE_HOST_ENV_NAME in os.environ else "compose",
|
||||
"environment": get_env(),
|
||||
"architecture": platform.machine(),
|
||||
"platform": platform.platform(),
|
||||
"uname": " ".join(platform.uname()),
|
||||
|
@ -68,7 +68,7 @@ class ConfigView(APIView):
|
||||
caps.append(Capabilities.CAN_GEO_IP)
|
||||
if CONFIG.y_bool("impersonation"):
|
||||
caps.append(Capabilities.CAN_IMPERSONATE)
|
||||
if settings.DEBUG:
|
||||
if settings.DEBUG: # pragma: no cover
|
||||
caps.append(Capabilities.CAN_DEBUG)
|
||||
return caps
|
||||
|
||||
|
@ -16,7 +16,7 @@ def serializer_tester_factory(test_model: Type[SerializerModel]) -> Callable:
|
||||
"""Test serializer"""
|
||||
|
||||
def tester(self: TestModels):
|
||||
if test_model._meta.abstract:
|
||||
if test_model._meta.abstract: # pragma: no cover
|
||||
return
|
||||
model_class = test_model()
|
||||
self.assertTrue(isinstance(model_class, SerializerModel))
|
||||
|
@ -26,8 +26,8 @@ class TestBlueprintOCI(TransactionTestCase):
|
||||
|
||||
self.assertEqual(
|
||||
BlueprintInstance(
|
||||
path="https://ghcr.io/goauthentik/blueprints/test:latest"
|
||||
).retrieve_oci(),
|
||||
path="oci://ghcr.io/goauthentik/blueprints/test:latest"
|
||||
).retrieve(),
|
||||
"foo",
|
||||
)
|
||||
|
||||
@ -40,7 +40,7 @@ class TestBlueprintOCI(TransactionTestCase):
|
||||
|
||||
with self.assertRaises(BlueprintRetrievalFailed):
|
||||
BlueprintInstance(
|
||||
path="https://ghcr.io/goauthentik/blueprints/test:latest"
|
||||
path="oci://ghcr.io/goauthentik/blueprints/test:latest"
|
||||
).retrieve_oci()
|
||||
|
||||
def test_manifests_error_response(self):
|
||||
@ -53,7 +53,7 @@ class TestBlueprintOCI(TransactionTestCase):
|
||||
|
||||
with self.assertRaises(BlueprintRetrievalFailed):
|
||||
BlueprintInstance(
|
||||
path="https://ghcr.io/goauthentik/blueprints/test:latest"
|
||||
path="oci://ghcr.io/goauthentik/blueprints/test:latest"
|
||||
).retrieve_oci()
|
||||
|
||||
def test_no_matching_blob(self):
|
||||
@ -72,7 +72,7 @@ class TestBlueprintOCI(TransactionTestCase):
|
||||
)
|
||||
with self.assertRaises(BlueprintRetrievalFailed):
|
||||
BlueprintInstance(
|
||||
path="https://ghcr.io/goauthentik/blueprints/test:latest"
|
||||
path="oci://ghcr.io/goauthentik/blueprints/test:latest"
|
||||
).retrieve_oci()
|
||||
|
||||
def test_blob_error(self):
|
||||
@ -93,5 +93,5 @@ class TestBlueprintOCI(TransactionTestCase):
|
||||
|
||||
with self.assertRaises(BlueprintRetrievalFailed):
|
||||
BlueprintInstance(
|
||||
path="https://ghcr.io/goauthentik/blueprints/test:latest"
|
||||
path="oci://ghcr.io/goauthentik/blueprints/test:latest"
|
||||
).retrieve_oci()
|
||||
|
@ -5,7 +5,7 @@ from django.db.models.query import QuerySet
|
||||
from django.http import Http404
|
||||
from django_filters.filters import CharFilter, ModelMultipleChoiceFilter
|
||||
from django_filters.filterset import FilterSet
|
||||
from drf_spectacular.utils import OpenApiResponse, extend_schema, inline_serializer
|
||||
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import CharField, IntegerField, JSONField
|
||||
@ -17,7 +17,7 @@ from rest_framework_guardian.filters import ObjectPermissionsFilter
|
||||
|
||||
from authentik.api.decorators import permission_required
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.core.api.utils import is_dict
|
||||
from authentik.core.api.utils import PassiveSerializer, is_dict
|
||||
from authentik.core.models import Group, User
|
||||
|
||||
|
||||
@ -120,6 +120,12 @@ class GroupFilter(FilterSet):
|
||||
fields = ["name", "is_superuser", "members_by_pk", "attributes", "members_by_username"]
|
||||
|
||||
|
||||
class UserAccountSerializer(PassiveSerializer):
|
||||
"""Account adding/removing operations"""
|
||||
|
||||
pk = IntegerField(required=True)
|
||||
|
||||
|
||||
class GroupViewSet(UsedByMixin, ModelViewSet):
|
||||
"""Group Viewset"""
|
||||
|
||||
@ -144,12 +150,7 @@ class GroupViewSet(UsedByMixin, ModelViewSet):
|
||||
|
||||
@permission_required(None, ["authentik_core.add_user"])
|
||||
@extend_schema(
|
||||
request=inline_serializer(
|
||||
"UserAccountSerializer",
|
||||
{
|
||||
"pk": IntegerField(required=True),
|
||||
},
|
||||
),
|
||||
request=UserAccountSerializer,
|
||||
responses={
|
||||
204: OpenApiResponse(description="User added"),
|
||||
404: OpenApiResponse(description="User not found"),
|
||||
@ -174,12 +175,7 @@ class GroupViewSet(UsedByMixin, ModelViewSet):
|
||||
|
||||
@permission_required(None, ["authentik_core.add_user"])
|
||||
@extend_schema(
|
||||
request=inline_serializer(
|
||||
"UserAccountSerializer",
|
||||
{
|
||||
"pk": IntegerField(required=True),
|
||||
},
|
||||
),
|
||||
request=UserAccountSerializer,
|
||||
responses={
|
||||
204: OpenApiResponse(description="User added"),
|
||||
404: OpenApiResponse(description="User not found"),
|
||||
|
@ -1,5 +1,4 @@
|
||||
"""Property Mapping Evaluator"""
|
||||
from traceback import format_tb
|
||||
from typing import Optional
|
||||
|
||||
from django.db.models import Model
|
||||
@ -8,6 +7,7 @@ from django.http import HttpRequest
|
||||
from authentik.core.models import User
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.lib.expression.evaluator import BaseEvaluator
|
||||
from authentik.lib.utils.errors import exception_to_string
|
||||
from authentik.policies.types import PolicyRequest
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@ class PropertyMappingEvaluator(BaseEvaluator):
|
||||
|
||||
def handle_error(self, exc: Exception, expression_source: str):
|
||||
"""Exception Handler"""
|
||||
error_string = "\n".join(format_tb(exc.__traceback__) + [str(exc)])
|
||||
error_string = exception_to_string(exc)
|
||||
event = Event.new(
|
||||
EventAction.PROPERTY_MAPPING_EXCEPTION,
|
||||
expression=expression_source,
|
||||
|
@ -35,7 +35,7 @@ def source_tester_factory(test_model: type[Stage]) -> Callable:
|
||||
|
||||
def tester(self: TestModels):
|
||||
model_class = None
|
||||
if test_model._meta.abstract:
|
||||
if test_model._meta.abstract: # pragma: no cover
|
||||
model_class = test_model.__bases__[0]()
|
||||
else:
|
||||
model_class = test_model()
|
||||
|
@ -209,6 +209,13 @@ class CertificateKeyPairViewSet(UsedByMixin, ModelViewSet):
|
||||
|
||||
@extend_schema(
|
||||
parameters=[
|
||||
# Override the type for `has_key` above
|
||||
OpenApiParameter(
|
||||
"has_key",
|
||||
bool,
|
||||
required=False,
|
||||
description="Only return certificate-key pairs with keys",
|
||||
),
|
||||
OpenApiParameter("include_details", bool, default=True),
|
||||
]
|
||||
)
|
||||
|
@ -39,6 +39,11 @@ def on_user_logged_in(sender, request: HttpRequest, user: User, **_):
|
||||
request.session[SESSION_LOGIN_EVENT] = event
|
||||
|
||||
|
||||
def get_login_event(request: HttpRequest) -> Optional[Event]:
|
||||
"""Wrapper to get login event that can be mocked in tests"""
|
||||
return request.session.get(SESSION_LOGIN_EVENT, None)
|
||||
|
||||
|
||||
@receiver(user_logged_out)
|
||||
# pylint: disable=unused-argument
|
||||
def on_user_logged_out(sender, request: HttpRequest, user: User, **_):
|
||||
|
@ -1,7 +1,6 @@
|
||||
"""Challenge helpers"""
|
||||
from dataclasses import asdict, is_dataclass
|
||||
from enum import Enum
|
||||
from traceback import format_tb
|
||||
from typing import TYPE_CHECKING, Optional, TypedDict
|
||||
from uuid import UUID
|
||||
|
||||
@ -9,8 +8,10 @@ from django.core.serializers.json import DjangoJSONEncoder
|
||||
from django.db import models
|
||||
from django.http import JsonResponse
|
||||
from rest_framework.fields import CharField, ChoiceField, DictField
|
||||
from rest_framework.request import Request
|
||||
|
||||
from authentik.core.api.utils import PassiveSerializer
|
||||
from authentik.lib.utils.errors import exception_to_string
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from authentik.flows.stage import StageView
|
||||
@ -90,32 +91,31 @@ class WithUserInfoChallenge(Challenge):
|
||||
pending_user_avatar = CharField()
|
||||
|
||||
|
||||
class FlowErrorChallenge(WithUserInfoChallenge):
|
||||
class FlowErrorChallenge(Challenge):
|
||||
"""Challenge class when an unhandled error occurs during a stage. Normal users
|
||||
are shown an error message, superusers are shown a full stacktrace."""
|
||||
|
||||
component = CharField(default="xak-flow-error")
|
||||
type = CharField(default=ChallengeTypes.NATIVE.value)
|
||||
component = CharField(default="ak-stage-flow-error")
|
||||
|
||||
request_id = CharField()
|
||||
|
||||
error = CharField(required=False)
|
||||
traceback = CharField(required=False)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
request = kwargs.pop("request", None)
|
||||
error = kwargs.pop("error", None)
|
||||
super().__init__(*args, **kwargs)
|
||||
def __init__(self, request: Optional[Request] = None, error: Optional[Exception] = None):
|
||||
super().__init__(data={})
|
||||
if not request or not error:
|
||||
return
|
||||
self.request_id = request.request_id
|
||||
self.initial_data["request_id"] = request.request_id
|
||||
from authentik.core.models import USER_ATTRIBUTE_DEBUG
|
||||
|
||||
if request.user and request.user.is_authenticated:
|
||||
if request.user.is_superuser or request.user.group_attributes(request).get(
|
||||
USER_ATTRIBUTE_DEBUG, False
|
||||
):
|
||||
self.error = error
|
||||
self.traceback = "".join(format_tb(self.error.__traceback__))
|
||||
self.initial_data["error"] = str(error)
|
||||
self.initial_data["traceback"] = exception_to_string(error)
|
||||
|
||||
|
||||
class AccessDeniedChallenge(WithUserInfoChallenge):
|
||||
|
@ -162,7 +162,7 @@ class FlowExecutorView(APIView):
|
||||
token.delete()
|
||||
if not isinstance(plan, FlowPlan):
|
||||
return None
|
||||
plan.context[PLAN_CONTEXT_IS_RESTORED] = True
|
||||
plan.context[PLAN_CONTEXT_IS_RESTORED] = token
|
||||
self._logger.debug("f(exec): restored flow plan from token", plan=plan)
|
||||
return plan
|
||||
|
||||
@ -255,7 +255,7 @@ class FlowExecutorView(APIView):
|
||||
message=exception_to_string(exc),
|
||||
).from_http(self.request)
|
||||
challenge = FlowErrorChallenge(self.request, exc)
|
||||
challenge.is_valid()
|
||||
challenge.is_valid(raise_exception=True)
|
||||
return to_stage_response(self.request, HttpChallengeResponse(challenge))
|
||||
|
||||
@extend_schema(
|
||||
|
@ -19,7 +19,7 @@ def model_tester_factory(test_model: type[Stage]) -> Callable:
|
||||
def tester(self: TestModels):
|
||||
try:
|
||||
model_class = None
|
||||
if test_model._meta.abstract:
|
||||
if test_model._meta.abstract: # pragma: no cover
|
||||
return
|
||||
model_class = test_model()
|
||||
self.assertTrue(issubclass(model_class.serializer, BaseSerializer))
|
||||
|
@ -48,14 +48,14 @@ def get_apps():
|
||||
|
||||
def get_env() -> str:
|
||||
"""Get environment in which authentik is currently running"""
|
||||
if SERVICE_HOST_ENV_NAME in os.environ:
|
||||
return "kubernetes"
|
||||
if "CI" in os.environ:
|
||||
return "ci"
|
||||
if Path("/tmp/authentik-mode").exists(): # nosec
|
||||
return "compose"
|
||||
if CONFIG.y_bool("debug"):
|
||||
return "dev"
|
||||
if SERVICE_HOST_ENV_NAME in os.environ:
|
||||
return "kubernetes"
|
||||
if Path("/tmp/authentik-mode").exists(): # nosec
|
||||
return "compose"
|
||||
if "AK_APPLIANCE" in os.environ:
|
||||
return os.environ["AK_APPLIANCE"]
|
||||
return "custom"
|
||||
|
@ -22,8 +22,7 @@ from rest_framework.serializers import Serializer
|
||||
|
||||
from authentik.core.models import ExpiringModel, PropertyMapping, Provider, User
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
from authentik.events.models import Event
|
||||
from authentik.events.signals import SESSION_LOGIN_EVENT
|
||||
from authentik.events.signals import get_login_event
|
||||
from authentik.lib.generators import generate_code_fixed_length, generate_id, generate_key
|
||||
from authentik.lib.models import SerializerModel
|
||||
from authentik.lib.utils.time import timedelta_string_validator
|
||||
@ -419,6 +418,8 @@ class IDToken:
|
||||
id_dict.pop("nonce")
|
||||
if not self.c_hash:
|
||||
id_dict.pop("c_hash")
|
||||
if not self.amr:
|
||||
id_dict.pop("amr")
|
||||
id_dict.pop("claims")
|
||||
id_dict.update(self.claims)
|
||||
return id_dict
|
||||
@ -503,8 +504,8 @@ class RefreshToken(SerializerModel, ExpiringModel, BaseGrantModel):
|
||||
# We use the timestamp of the user's last successful login (EventAction.LOGIN) for auth_time
|
||||
# Fallback in case we can't find any login events
|
||||
auth_time = now
|
||||
if SESSION_LOGIN_EVENT in request.session:
|
||||
auth_event: Event = request.session[SESSION_LOGIN_EVENT]
|
||||
auth_event = get_login_event(request)
|
||||
if auth_event:
|
||||
auth_time = auth_event.created
|
||||
# Also check which method was used for authentication
|
||||
method = auth_event.context.get(PLAN_CONTEXT_METHOD, "")
|
||||
@ -526,6 +527,7 @@ class RefreshToken(SerializerModel, ExpiringModel, BaseGrantModel):
|
||||
exp=exp_time,
|
||||
iat=iat_time,
|
||||
auth_time=auth_timestamp,
|
||||
amr=amr if amr else None,
|
||||
)
|
||||
|
||||
# Include (or not) user standard claims in the id_token.
|
||||
|
@ -1,10 +1,13 @@
|
||||
"""Test authorize view"""
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from django.test import RequestFactory
|
||||
from django.urls import reverse
|
||||
from django.utils.timezone import now
|
||||
|
||||
from authentik.core.models import Application
|
||||
from authentik.core.tests.utils import create_test_admin_user, create_test_flow
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.flows.challenge import ChallengeTypes
|
||||
from authentik.lib.generators import generate_id, generate_key
|
||||
from authentik.lib.utils.time import timedelta_from_string
|
||||
@ -17,6 +20,7 @@ from authentik.providers.oauth2.models import (
|
||||
)
|
||||
from authentik.providers.oauth2.tests.utils import OAuthTestCase
|
||||
from authentik.providers.oauth2.views.authorize import OAuthAuthorizationParams
|
||||
from authentik.stages.password.stage import PLAN_CONTEXT_METHOD
|
||||
|
||||
|
||||
class TestAuthorize(OAuthTestCase):
|
||||
@ -302,40 +306,51 @@ class TestAuthorize(OAuthTestCase):
|
||||
state = generate_id()
|
||||
user = create_test_admin_user()
|
||||
self.client.force_login(user)
|
||||
# Step 1, initiate params and get redirect to flow
|
||||
self.client.get(
|
||||
reverse("authentik_providers_oauth2:authorize"),
|
||||
data={
|
||||
"response_type": "id_token",
|
||||
"client_id": "test",
|
||||
"state": state,
|
||||
"scope": "openid",
|
||||
"redirect_uri": "http://localhost",
|
||||
},
|
||||
)
|
||||
response = self.client.get(
|
||||
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
|
||||
)
|
||||
token: RefreshToken = RefreshToken.objects.filter(user=user).first()
|
||||
expires = timedelta_from_string(provider.access_code_validity).total_seconds()
|
||||
self.assertJSONEqual(
|
||||
response.content.decode(),
|
||||
{
|
||||
"component": "xak-flow-redirect",
|
||||
"type": ChallengeTypes.REDIRECT.value,
|
||||
"to": (
|
||||
f"http://localhost#access_token={token.access_token}"
|
||||
f"&id_token={provider.encode(token.id_token.to_dict())}&token_type=bearer"
|
||||
f"&expires_in={int(expires)}&state={state}"
|
||||
),
|
||||
},
|
||||
)
|
||||
jwt = self.validate_jwt(token, provider)
|
||||
self.assertAlmostEqual(
|
||||
jwt["exp"] - now().timestamp(),
|
||||
expires,
|
||||
delta=5,
|
||||
)
|
||||
with patch(
|
||||
"authentik.providers.oauth2.models.get_login_event",
|
||||
MagicMock(
|
||||
return_value=Event(
|
||||
action=EventAction.LOGIN,
|
||||
context={PLAN_CONTEXT_METHOD: "password"},
|
||||
created=now(),
|
||||
)
|
||||
),
|
||||
):
|
||||
# Step 1, initiate params and get redirect to flow
|
||||
self.client.get(
|
||||
reverse("authentik_providers_oauth2:authorize"),
|
||||
data={
|
||||
"response_type": "id_token",
|
||||
"client_id": "test",
|
||||
"state": state,
|
||||
"scope": "openid",
|
||||
"redirect_uri": "http://localhost",
|
||||
},
|
||||
)
|
||||
response = self.client.get(
|
||||
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
|
||||
)
|
||||
token: RefreshToken = RefreshToken.objects.filter(user=user).first()
|
||||
expires = timedelta_from_string(provider.access_code_validity).total_seconds()
|
||||
self.assertJSONEqual(
|
||||
response.content.decode(),
|
||||
{
|
||||
"component": "xak-flow-redirect",
|
||||
"type": ChallengeTypes.REDIRECT.value,
|
||||
"to": (
|
||||
f"http://localhost#access_token={token.access_token}"
|
||||
f"&id_token={provider.encode(token.id_token.to_dict())}&token_type=bearer"
|
||||
f"&expires_in={int(expires)}&state={state}"
|
||||
),
|
||||
},
|
||||
)
|
||||
jwt = self.validate_jwt(token, provider)
|
||||
self.assertEqual(jwt["amr"], ["pwd"])
|
||||
self.assertAlmostEqual(
|
||||
jwt["exp"] - now().timestamp(),
|
||||
expires,
|
||||
delta=5,
|
||||
)
|
||||
|
||||
def test_full_form_post_id_token(self):
|
||||
"""Test full authorization (form_post response)"""
|
||||
|
@ -27,6 +27,11 @@ class OAuthTestCase(TestCase):
|
||||
cls.keypair = create_test_cert()
|
||||
super().setUpClass()
|
||||
|
||||
def assert_non_none_or_unset(self, container: dict, key: str):
|
||||
"""Check that a key, if set, is not none"""
|
||||
if key in container:
|
||||
self.assertIsNotNone(container[key])
|
||||
|
||||
def validate_jwt(self, token: RefreshToken, provider: OAuth2Provider) -> dict[str, Any]:
|
||||
"""Validate that all required fields are set"""
|
||||
key, alg = provider.jwt_key
|
||||
@ -39,6 +44,10 @@ class OAuthTestCase(TestCase):
|
||||
audience=provider.client_id,
|
||||
)
|
||||
id_token = token.id_token.to_dict()
|
||||
self.assert_non_none_or_unset(id_token, "at_hash")
|
||||
self.assert_non_none_or_unset(id_token, "nonce")
|
||||
self.assert_non_none_or_unset(id_token, "c_hash")
|
||||
self.assert_non_none_or_unset(id_token, "amr")
|
||||
for key in self.required_jwt_keys:
|
||||
self.assertIsNotNone(jwt[key], f"Key {key} is missing in access_token")
|
||||
self.assertIsNotNone(id_token[key], f"Key {key} is missing in id_token")
|
||||
|
@ -17,7 +17,12 @@ from authentik.providers.oauth2.constants import (
|
||||
GRANT_TYPE_REFRESH_TOKEN,
|
||||
SCOPE_OPENID,
|
||||
)
|
||||
from authentik.providers.oauth2.models import OAuth2Provider, ResponseTypes, ScopeMapping
|
||||
from authentik.providers.oauth2.models import (
|
||||
OAuth2Provider,
|
||||
ResponseMode,
|
||||
ResponseTypes,
|
||||
ScopeMapping,
|
||||
)
|
||||
from authentik.providers.oauth2.utils import cors_allow
|
||||
|
||||
LOGGER = get_logger()
|
||||
@ -73,6 +78,11 @@ class ProviderInfoView(View):
|
||||
ResponseTypes.CODE_ID_TOKEN,
|
||||
ResponseTypes.CODE_ID_TOKEN_TOKEN,
|
||||
],
|
||||
"response_modes_supported": [
|
||||
ResponseMode.QUERY,
|
||||
ResponseMode.FRAGMENT,
|
||||
ResponseMode.FORM_POST,
|
||||
],
|
||||
"jwks_uri": self.request.build_absolute_uri(
|
||||
reverse(
|
||||
"authentik_providers_oauth2:jwks",
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""ProxyProvider API Views"""
|
||||
from typing import Any, Optional
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_spectacular.utils import extend_schema_field
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.fields import CharField, ListField, ReadOnlyField, SerializerMethodField
|
||||
@ -39,22 +40,34 @@ class ProxyProviderSerializer(ProviderSerializer):
|
||||
redirect_uris = CharField(read_only=True)
|
||||
outpost_set = ListField(child=CharField(), read_only=True, source="outpost_set.all")
|
||||
|
||||
def validate_basic_auth_enabled(self, value: bool) -> bool:
|
||||
"""Ensure user and password attributes are set"""
|
||||
if value:
|
||||
if (
|
||||
self.initial_data.get("basic_auth_password_attribute", "") == ""
|
||||
or self.initial_data.get("basic_auth_user_attribute", "") == ""
|
||||
):
|
||||
raise ValidationError(
|
||||
_("User and password attributes must be set when basic auth is enabled.")
|
||||
)
|
||||
return value
|
||||
|
||||
def validate(self, attrs) -> dict[Any, str]:
|
||||
"""Check that internal_host is set when mode is Proxy"""
|
||||
if (
|
||||
attrs.get("mode", ProxyMode.PROXY) == ProxyMode.PROXY
|
||||
and attrs.get("internal_host", "") == ""
|
||||
):
|
||||
raise ValidationError("Internal host cannot be empty when forward auth is disabled.")
|
||||
raise ValidationError(_("Internal host cannot be empty when forward auth is disabled."))
|
||||
return attrs
|
||||
|
||||
def create(self, validated_data):
|
||||
def create(self, validated_data: dict):
|
||||
instance: ProxyProvider = super().create(validated_data)
|
||||
instance.set_oauth_defaults()
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
def update(self, instance: ProxyProvider, validated_data):
|
||||
def update(self, instance: ProxyProvider, validated_data: dict):
|
||||
instance = super().update(instance, validated_data)
|
||||
instance.set_oauth_defaults()
|
||||
instance.save()
|
||||
|
122
authentik/providers/proxy/tests.py
Normal file
122
authentik/providers/proxy/tests.py
Normal file
@ -0,0 +1,122 @@
|
||||
"""proxy provider tests"""
|
||||
from django.urls import reverse
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.tests.utils import create_test_admin_user, create_test_flow
|
||||
from authentik.lib.generators import generate_id
|
||||
from authentik.providers.oauth2.models import ClientTypes
|
||||
from authentik.providers.proxy.models import ProxyMode, ProxyProvider
|
||||
|
||||
|
||||
class ProxyProviderTests(APITestCase):
|
||||
"""proxy provider tests"""
|
||||
|
||||
def setUp(self) -> None:
|
||||
self.user = create_test_admin_user()
|
||||
self.client.force_login(self.user)
|
||||
|
||||
def test_basic_auth(self):
|
||||
"""Test basic_auth_enabled"""
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:proxyprovider-list"),
|
||||
{
|
||||
"name": generate_id(),
|
||||
"mode": ProxyMode.PROXY,
|
||||
"authorization_flow": create_test_flow().pk.hex,
|
||||
"external_host": "http://localhost",
|
||||
"internal_host": "http://localhost",
|
||||
"basic_auth_enabled": True,
|
||||
"basic_auth_user_attribute": generate_id(),
|
||||
"basic_auth_password_attribute": generate_id(),
|
||||
},
|
||||
)
|
||||
self.assertEqual(response.status_code, 201)
|
||||
|
||||
def test_basic_auth_invalid(self):
|
||||
"""Test basic_auth_enabled"""
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:proxyprovider-list"),
|
||||
{
|
||||
"name": generate_id(),
|
||||
"mode": ProxyMode.PROXY,
|
||||
"authorization_flow": create_test_flow().pk.hex,
|
||||
"external_host": "http://localhost",
|
||||
"internal_host": "http://localhost",
|
||||
"basic_auth_enabled": True,
|
||||
},
|
||||
)
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertJSONEqual(
|
||||
response.content.decode(),
|
||||
{
|
||||
"basic_auth_enabled": [
|
||||
"User and password attributes must be set when basic auth is enabled."
|
||||
]
|
||||
},
|
||||
)
|
||||
|
||||
def test_validate(self):
|
||||
"""Test validate"""
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:proxyprovider-list"),
|
||||
{
|
||||
"name": generate_id(),
|
||||
"mode": ProxyMode.PROXY,
|
||||
"authorization_flow": create_test_flow().pk.hex,
|
||||
"external_host": "http://localhost",
|
||||
},
|
||||
)
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertJSONEqual(
|
||||
response.content.decode(),
|
||||
{"non_field_errors": ["Internal host cannot be empty when forward auth is disabled."]},
|
||||
)
|
||||
|
||||
def test_create_defaults(self):
|
||||
"""Test create"""
|
||||
name = generate_id()
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:proxyprovider-list"),
|
||||
{
|
||||
"name": name,
|
||||
"mode": ProxyMode.PROXY,
|
||||
"authorization_flow": create_test_flow().pk.hex,
|
||||
"external_host": "http://localhost",
|
||||
"internal_host": "http://localhost",
|
||||
},
|
||||
)
|
||||
self.assertEqual(response.status_code, 201)
|
||||
provider: ProxyProvider = ProxyProvider.objects.get(name=name)
|
||||
self.assertEqual(provider.client_type, ClientTypes.CONFIDENTIAL)
|
||||
|
||||
def test_update_defaults(self):
|
||||
"""Test create"""
|
||||
name = generate_id()
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:proxyprovider-list"),
|
||||
{
|
||||
"name": name,
|
||||
"mode": ProxyMode.PROXY,
|
||||
"authorization_flow": create_test_flow().pk.hex,
|
||||
"external_host": "http://localhost",
|
||||
"internal_host": "http://localhost",
|
||||
},
|
||||
)
|
||||
self.assertEqual(response.status_code, 201)
|
||||
provider: ProxyProvider = ProxyProvider.objects.get(name=name)
|
||||
self.assertEqual(provider.client_type, ClientTypes.CONFIDENTIAL)
|
||||
provider.client_type = ClientTypes.PUBLIC
|
||||
provider.save()
|
||||
response = self.client.put(
|
||||
reverse("authentik_api:proxyprovider-detail", kwargs={"pk": provider.pk}),
|
||||
{
|
||||
"name": name,
|
||||
"mode": ProxyMode.PROXY,
|
||||
"authorization_flow": create_test_flow().pk.hex,
|
||||
"external_host": "http://localhost",
|
||||
"internal_host": "http://localhost",
|
||||
},
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
provider: ProxyProvider = ProxyProvider.objects.get(name=name)
|
||||
self.assertEqual(provider.client_type, ClientTypes.CONFIDENTIAL)
|
@ -47,6 +47,8 @@ class SAMLProviderSerializer(ProviderSerializer):
|
||||
|
||||
def get_url_download_metadata(self, instance: SAMLProvider) -> str:
|
||||
"""Get metadata download URL"""
|
||||
if "request" not in self._context:
|
||||
return ""
|
||||
request: HttpRequest = self._context["request"]._request
|
||||
return request.build_absolute_uri(
|
||||
reverse("authentik_api:samlprovider-metadata", kwargs={"pk": instance.pk}) + "?download"
|
||||
@ -54,6 +56,8 @@ class SAMLProviderSerializer(ProviderSerializer):
|
||||
|
||||
def get_url_sso_post(self, instance: SAMLProvider) -> str:
|
||||
"""Get SSO Post URL"""
|
||||
if "request" not in self._context:
|
||||
return ""
|
||||
request: HttpRequest = self._context["request"]._request
|
||||
try:
|
||||
return request.build_absolute_uri(
|
||||
@ -67,6 +71,8 @@ class SAMLProviderSerializer(ProviderSerializer):
|
||||
|
||||
def get_url_sso_redirect(self, instance: SAMLProvider) -> str:
|
||||
"""Get SSO Redirect URL"""
|
||||
if "request" not in self._context:
|
||||
return ""
|
||||
request: HttpRequest = self._context["request"]._request
|
||||
try:
|
||||
return request.build_absolute_uri(
|
||||
@ -80,6 +86,8 @@ class SAMLProviderSerializer(ProviderSerializer):
|
||||
|
||||
def get_url_sso_init(self, instance: SAMLProvider) -> str:
|
||||
"""Get SSO IDP-Initiated URL"""
|
||||
if "request" not in self._context:
|
||||
return ""
|
||||
request: HttpRequest = self._context["request"]._request
|
||||
try:
|
||||
return request.build_absolute_uri(
|
||||
|
@ -10,7 +10,7 @@ from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.core.exceptions import PropertyMappingExpressionException
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.events.signals import SESSION_LOGIN_EVENT
|
||||
from authentik.events.signals import get_login_event
|
||||
from authentik.lib.utils.time import timedelta_from_string
|
||||
from authentik.providers.saml.models import SAMLPropertyMapping, SAMLProvider
|
||||
from authentik.providers.saml.processors.request_parser import AuthNRequest
|
||||
@ -132,8 +132,8 @@ class AssertionProcessor:
|
||||
auth_n_context, f"{{{NS_SAML_ASSERTION}}}AuthnContextClassRef"
|
||||
)
|
||||
auth_n_context_class_ref.text = "urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified"
|
||||
if SESSION_LOGIN_EVENT in self.http_request.session:
|
||||
event: Event = self.http_request.session[SESSION_LOGIN_EVENT]
|
||||
event = get_login_event(self.http_request)
|
||||
if event:
|
||||
method = event.context.get(PLAN_CONTEXT_METHOD, "")
|
||||
method_args = event.context.get(PLAN_CONTEXT_METHOD_ARGS, {})
|
||||
if method == "password":
|
||||
|
@ -13,6 +13,7 @@ from authentik.sources.saml.processors.constants import (
|
||||
DIGEST_ALGORITHM_TRANSLATION_MAP,
|
||||
NS_MAP,
|
||||
NS_SAML_METADATA,
|
||||
NS_SAML_PROTOCOL,
|
||||
NS_SIGNATURE,
|
||||
SAML_BINDING_POST,
|
||||
SAML_BINDING_REDIRECT,
|
||||
@ -35,7 +36,7 @@ class MetadataProcessor:
|
||||
self.provider = provider
|
||||
self.http_request = request
|
||||
self.force_binding = None
|
||||
self.xml_id = sha256(f"{provider.name}-{provider.pk}".encode("ascii")).hexdigest()
|
||||
self.xml_id = "_" + sha256(f"{provider.name}-{provider.pk}".encode("ascii")).hexdigest()
|
||||
|
||||
def get_signing_key_descriptor(self) -> Optional[Element]:
|
||||
"""Get Signing KeyDescriptor, if enabled for the provider"""
|
||||
@ -143,9 +144,7 @@ class MetadataProcessor:
|
||||
idp_sso_descriptor = SubElement(
|
||||
entity_descriptor, f"{{{NS_SAML_METADATA}}}IDPSSODescriptor"
|
||||
)
|
||||
idp_sso_descriptor.attrib[
|
||||
"protocolSupportEnumeration"
|
||||
] = "urn:oasis:names:tc:SAML:2.0:protocol"
|
||||
idp_sso_descriptor.attrib["protocolSupportEnumeration"] = NS_SAML_PROTOCOL
|
||||
|
||||
signing_descriptor = self.get_signing_key_descriptor()
|
||||
if signing_descriptor is not None:
|
||||
|
@ -20,7 +20,7 @@ class CaptchaChallenge(WithUserInfoChallenge):
|
||||
"""Site public key"""
|
||||
|
||||
site_key = CharField()
|
||||
js_url = CharField(read_only=True)
|
||||
js_url = CharField()
|
||||
component = CharField(default="ak-stage-captcha")
|
||||
|
||||
|
||||
|
@ -22,7 +22,7 @@ class TestCaptchaStage(FlowTestCase):
|
||||
self.user = create_test_admin_user()
|
||||
self.flow = create_test_flow(FlowDesignation.AUTHENTICATION)
|
||||
|
||||
self.stage = CaptchaStage.objects.create(
|
||||
self.stage: CaptchaStage = CaptchaStage.objects.create(
|
||||
name="captcha",
|
||||
public_key=RECAPTCHA_PUBLIC_KEY,
|
||||
private_key=RECAPTCHA_PRIVATE_KEY,
|
||||
@ -41,3 +41,22 @@ class TestCaptchaStage(FlowTestCase):
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
|
||||
|
||||
def test_urls(self):
|
||||
"""Test URLs captcha"""
|
||||
self.stage.js_url = "https://test.goauthentik.io/test.js"
|
||||
self.stage.api_url = "https://test.goauthentik.io/test"
|
||||
self.stage.save()
|
||||
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
|
||||
session = self.client.session
|
||||
session[SESSION_KEY_PLAN] = plan
|
||||
session.save()
|
||||
response = self.client.get(
|
||||
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertStageResponse(
|
||||
response,
|
||||
self.flow,
|
||||
js_url="https://test.goauthentik.io/test.js",
|
||||
)
|
||||
|
@ -12,7 +12,7 @@ class DummyStageSerializer(StageSerializer):
|
||||
class Meta:
|
||||
|
||||
model = DummyStage
|
||||
fields = StageSerializer.Meta.fields
|
||||
fields = StageSerializer.Meta.fields + ["throw_error"]
|
||||
|
||||
|
||||
class DummyStageViewSet(UsedByMixin, ModelViewSet):
|
||||
|
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.1.4 on 2023-01-01 19:31
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_stages_dummy", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="dummystage",
|
||||
name="throw_error",
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
@ -1,5 +1,5 @@
|
||||
"""dummy stage models"""
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views import View
|
||||
from rest_framework.serializers import BaseSerializer
|
||||
@ -10,6 +10,8 @@ from authentik.flows.models import Stage
|
||||
class DummyStage(Stage):
|
||||
"""Used for debugging."""
|
||||
|
||||
throw_error = models.BooleanField(default=False)
|
||||
|
||||
__debug_only__ = True
|
||||
|
||||
@property
|
||||
|
@ -4,6 +4,7 @@ from rest_framework.fields import CharField
|
||||
|
||||
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes
|
||||
from authentik.flows.stage import ChallengeStageView
|
||||
from authentik.lib.sentry import SentryIgnoredException
|
||||
|
||||
|
||||
class DummyChallenge(Challenge):
|
||||
@ -27,6 +28,8 @@ class DummyStageView(ChallengeStageView):
|
||||
return self.executor.stage_ok()
|
||||
|
||||
def get_challenge(self, *args, **kwargs) -> Challenge:
|
||||
if self.executor.current_stage.throw_error:
|
||||
raise SentryIgnoredException("Test error")
|
||||
return DummyChallenge(
|
||||
data={
|
||||
"type": ChallengeTypes.NATIVE.value,
|
||||
|
@ -11,12 +11,11 @@ from django.utils.translation import gettext as _
|
||||
from rest_framework.fields import CharField
|
||||
from rest_framework.serializers import ValidationError
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes
|
||||
from authentik.flows.models import FlowToken
|
||||
from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED, PLAN_CONTEXT_PENDING_USER
|
||||
from authentik.flows.stage import ChallengeStageView
|
||||
from authentik.flows.views.executor import QS_KEY_TOKEN, SESSION_KEY_GET
|
||||
from authentik.flows.views.executor import QS_KEY_TOKEN
|
||||
from authentik.stages.email.models import EmailStage
|
||||
from authentik.stages.email.tasks import send_mails
|
||||
from authentik.stages.email.utils import TemplateEmailMessage
|
||||
@ -57,7 +56,7 @@ class EmailStageView(ChallengeStageView):
|
||||
|
||||
def get_token(self) -> FlowToken:
|
||||
"""Get token"""
|
||||
pending_user = self.executor.plan.context[PLAN_CONTEXT_PENDING_USER]
|
||||
pending_user = self.get_pending_user()
|
||||
current_stage: EmailStage = self.executor.current_stage
|
||||
valid_delta = timedelta(
|
||||
minutes=current_stage.token_expiry + 1
|
||||
@ -82,7 +81,7 @@ class EmailStageView(ChallengeStageView):
|
||||
def send_email(self):
|
||||
"""Helper function that sends the actual email. Implies that you've
|
||||
already checked that there is a pending user."""
|
||||
pending_user: User = self.executor.plan.context[PLAN_CONTEXT_PENDING_USER]
|
||||
pending_user = self.get_pending_user()
|
||||
email = self.executor.plan.context.get(PLAN_CONTEXT_EMAIL_OVERRIDE, None)
|
||||
if not email:
|
||||
email = pending_user.email
|
||||
@ -104,13 +103,16 @@ class EmailStageView(ChallengeStageView):
|
||||
|
||||
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||
# Check if the user came back from the email link to verify
|
||||
if QS_KEY_TOKEN in request.session.get(
|
||||
SESSION_KEY_GET, {}
|
||||
) and self.executor.plan.context.get(PLAN_CONTEXT_IS_RESTORED, False):
|
||||
restore_token: FlowToken = self.executor.plan.context.get(PLAN_CONTEXT_IS_RESTORED, None)
|
||||
user = self.get_pending_user()
|
||||
if restore_token:
|
||||
if restore_token.user != user:
|
||||
self.logger.warning("Flow token for non-matching user, denying request")
|
||||
return self.executor.stage_invalid()
|
||||
messages.success(request, _("Successfully verified Email."))
|
||||
if self.executor.current_stage.activate_user_on_success:
|
||||
self.executor.plan.context[PLAN_CONTEXT_PENDING_USER].is_active = True
|
||||
self.executor.plan.context[PLAN_CONTEXT_PENDING_USER].save()
|
||||
user.is_active = True
|
||||
user.save()
|
||||
return self.executor.stage_ok()
|
||||
if PLAN_CONTEXT_PENDING_USER not in self.executor.plan.context:
|
||||
self.logger.debug("No pending user")
|
||||
|
@ -7,10 +7,9 @@ from django.core.mail.backends.smtp import EmailBackend as SMTPEmailBackend
|
||||
from django.urls import reverse
|
||||
from django.utils.http import urlencode
|
||||
|
||||
from authentik.core.models import Token
|
||||
from authentik.core.tests.utils import create_test_admin_user, create_test_flow
|
||||
from authentik.flows.markers import StageMarker
|
||||
from authentik.flows.models import FlowDesignation, FlowStageBinding
|
||||
from authentik.flows.models import FlowDesignation, FlowStageBinding, FlowToken
|
||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan
|
||||
from authentik.flows.tests import FlowTestCase
|
||||
from authentik.flows.views.executor import SESSION_KEY_PLAN
|
||||
@ -136,7 +135,7 @@ class TestEmailStage(FlowTestCase):
|
||||
session = self.client.session
|
||||
session[SESSION_KEY_PLAN] = plan
|
||||
session.save()
|
||||
token: Token = Token.objects.get(user=self.user)
|
||||
token: FlowToken = FlowToken.objects.get(user=self.user)
|
||||
|
||||
with patch("authentik.flows.views.executor.FlowExecutorView.cancel", MagicMock()):
|
||||
# Call the executor shell to preseed the session
|
||||
@ -167,3 +166,43 @@ class TestEmailStage(FlowTestCase):
|
||||
plan: FlowPlan = session[SESSION_KEY_PLAN]
|
||||
self.assertEqual(plan.context[PLAN_CONTEXT_PENDING_USER], self.user)
|
||||
self.assertTrue(plan.context[PLAN_CONTEXT_PENDING_USER].is_active)
|
||||
|
||||
def test_token_invalid_user(self):
|
||||
"""Test with token with invalid user"""
|
||||
# Make sure token exists
|
||||
self.test_pending_user()
|
||||
self.user.is_active = False
|
||||
self.user.save()
|
||||
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
|
||||
session = self.client.session
|
||||
session[SESSION_KEY_PLAN] = plan
|
||||
session.save()
|
||||
# Set flow token user to a different user
|
||||
token: FlowToken = FlowToken.objects.get(user=self.user)
|
||||
token.user = create_test_admin_user()
|
||||
token.save()
|
||||
|
||||
with patch("authentik.flows.views.executor.FlowExecutorView.cancel", MagicMock()):
|
||||
# Call the executor shell to preseed the session
|
||||
url = reverse(
|
||||
"authentik_api:flow-executor",
|
||||
kwargs={"flow_slug": self.flow.slug},
|
||||
)
|
||||
url_query = urlencode(
|
||||
{
|
||||
QS_KEY_TOKEN: token.key,
|
||||
}
|
||||
)
|
||||
url += f"?query={url_query}"
|
||||
self.client.get(url)
|
||||
|
||||
# Call the actual executor to get the JSON Response
|
||||
response = self.client.get(
|
||||
reverse(
|
||||
"authentik_api:flow-executor",
|
||||
kwargs={"flow_slug": self.flow.slug},
|
||||
)
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertStageResponse(response, component="ak-stage-access-denied")
|
||||
|
@ -1,7 +1,8 @@
|
||||
"""email tests"""
|
||||
from os import chmod, unlink
|
||||
from pathlib import Path
|
||||
from tempfile import gettempdir, mkstemp
|
||||
from shutil import rmtree
|
||||
from tempfile import mkdtemp, mkstemp
|
||||
from typing import Any
|
||||
|
||||
from django.conf import settings
|
||||
@ -20,11 +21,17 @@ def get_templates_setting(temp_dir: str) -> dict[str, Any]:
|
||||
class TestEmailStageTemplates(TestCase):
|
||||
"""Email tests"""
|
||||
|
||||
def setUp(self) -> None:
|
||||
self.dir = mkdtemp()
|
||||
|
||||
def tearDown(self) -> None:
|
||||
rmtree(self.dir)
|
||||
|
||||
def test_custom_template(self):
|
||||
"""Test with custom template"""
|
||||
with self.settings(TEMPLATES=get_templates_setting(gettempdir())):
|
||||
_, file = mkstemp(suffix=".html")
|
||||
_, file2 = mkstemp(suffix=".html")
|
||||
with self.settings(TEMPLATES=get_templates_setting(self.dir)):
|
||||
_, file = mkstemp(suffix=".html", dir=self.dir)
|
||||
_, file2 = mkstemp(suffix=".html", dir=self.dir)
|
||||
chmod(file2, 0o000) # Remove all permissions so we can't read the file
|
||||
choices = get_template_choices()
|
||||
self.assertEqual(choices[-1][0], Path(file).name)
|
||||
|
@ -7,14 +7,13 @@ from django.db.models.query import QuerySet
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.http.request import QueryDict
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from guardian.shortcuts import get_anonymous_user
|
||||
from rest_framework.fields import BooleanField, CharField, ChoiceField, IntegerField, empty
|
||||
from rest_framework.serializers import ValidationError
|
||||
|
||||
from authentik.core.api.utils import PassiveSerializer
|
||||
from authentik.core.models import User
|
||||
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes
|
||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan
|
||||
from authentik.flows.planner import FlowPlan
|
||||
from authentik.flows.stage import ChallengeStageView
|
||||
from authentik.policies.engine import PolicyEngine
|
||||
from authentik.policies.models import PolicyBinding, PolicyBindingModel, PolicyEngineMode
|
||||
@ -47,21 +46,23 @@ class PromptChallengeResponse(ChallengeResponse):
|
||||
"""Validate response, fields are dynamically created based
|
||||
on the stage"""
|
||||
|
||||
stage_instance: PromptStage
|
||||
|
||||
component = CharField(default="ak-stage-prompt")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
stage: PromptStage = kwargs.pop("stage", None)
|
||||
stage: PromptStage = kwargs.pop("stage_instance", None)
|
||||
plan: FlowPlan = kwargs.pop("plan", None)
|
||||
request: HttpRequest = kwargs.pop("request", None)
|
||||
user: User = kwargs.pop("user", None)
|
||||
super().__init__(*args, **kwargs)
|
||||
self.stage = stage
|
||||
self.stage_instance = stage
|
||||
self.plan = plan
|
||||
self.request = request
|
||||
if not self.stage:
|
||||
if not self.stage_instance:
|
||||
return
|
||||
# list() is called so we only load the fields once
|
||||
fields = list(self.stage.fields.all())
|
||||
fields = list(self.stage_instance.fields.all())
|
||||
for field in fields:
|
||||
field: Prompt
|
||||
current = field.get_placeholder(
|
||||
@ -97,7 +98,7 @@ class PromptChallengeResponse(ChallengeResponse):
|
||||
def validate(self, attrs: dict[str, Any]) -> dict[str, Any]:
|
||||
# Check if we have any static or hidden fields, and ensure they
|
||||
# still have the same value
|
||||
static_hidden_fields: QuerySet[Prompt] = self.stage.fields.filter(
|
||||
static_hidden_fields: QuerySet[Prompt] = self.stage_instance.fields.filter(
|
||||
type__in=[FieldTypes.HIDDEN, FieldTypes.STATIC, FieldTypes.TEXT_READ_ONLY]
|
||||
)
|
||||
for static_hidden in static_hidden_fields:
|
||||
@ -109,12 +110,17 @@ class PromptChallengeResponse(ChallengeResponse):
|
||||
attrs[static_hidden.field_key] = default
|
||||
|
||||
# Check if we have two password fields, and make sure they are the same
|
||||
password_fields: QuerySet[Prompt] = self.stage.fields.filter(type=FieldTypes.PASSWORD)
|
||||
password_fields: QuerySet[Prompt] = self.stage_instance.fields.filter(
|
||||
type=FieldTypes.PASSWORD
|
||||
)
|
||||
if password_fields.exists() and password_fields.count() == 2:
|
||||
self._validate_password_fields(*[field.field_key for field in password_fields])
|
||||
|
||||
user = self.plan.context.get(PLAN_CONTEXT_PENDING_USER, get_anonymous_user())
|
||||
engine = ListPolicyEngine(self.stage.validation_policies.all(), user, self.request)
|
||||
engine = ListPolicyEngine(
|
||||
self.stage_instance.validation_policies.all(),
|
||||
self.stage.get_pending_user(),
|
||||
self.request,
|
||||
)
|
||||
engine.mode = PolicyEngineMode.MODE_ALL
|
||||
engine.request.context[PLAN_CONTEXT_PROMPT] = attrs
|
||||
engine.use_cache = False
|
||||
@ -194,7 +200,8 @@ class PromptStageView(ChallengeStageView):
|
||||
instance=None,
|
||||
data=data,
|
||||
request=self.request,
|
||||
stage=self.executor.current_stage,
|
||||
stage_instance=self.executor.current_stage,
|
||||
stage=self,
|
||||
plan=self.executor.plan,
|
||||
user=self.get_pending_user(),
|
||||
)
|
||||
|
@ -10,11 +10,15 @@ from authentik.flows.markers import StageMarker
|
||||
from authentik.flows.models import FlowStageBinding
|
||||
from authentik.flows.planner import FlowPlan
|
||||
from authentik.flows.tests import FlowTestCase
|
||||
from authentik.flows.views.executor import SESSION_KEY_PLAN
|
||||
from authentik.flows.views.executor import SESSION_KEY_PLAN, FlowExecutorView
|
||||
from authentik.lib.generators import generate_id
|
||||
from authentik.policies.expression.models import ExpressionPolicy
|
||||
from authentik.stages.prompt.models import FieldTypes, InlineFileField, Prompt, PromptStage
|
||||
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT, PromptChallengeResponse
|
||||
from authentik.stages.prompt.stage import (
|
||||
PLAN_CONTEXT_PROMPT,
|
||||
PromptChallengeResponse,
|
||||
PromptStageView,
|
||||
)
|
||||
|
||||
|
||||
class TestPromptStage(FlowTestCase):
|
||||
@ -106,6 +110,11 @@ class TestPromptStage(FlowTestCase):
|
||||
|
||||
self.binding = FlowStageBinding.objects.create(target=self.flow, stage=self.stage, order=2)
|
||||
|
||||
self.request = RequestFactory().get("/")
|
||||
self.request.user = create_test_admin_user()
|
||||
self.flow_executor = FlowExecutorView(request=self.request)
|
||||
self.stage_view = PromptStageView(self.flow_executor, request=self.request)
|
||||
|
||||
def test_inline_file_field(self):
|
||||
"""test InlineFileField"""
|
||||
with self.assertRaises(ValidationError):
|
||||
@ -148,7 +157,11 @@ class TestPromptStage(FlowTestCase):
|
||||
self.stage.validation_policies.set([expr_policy])
|
||||
self.stage.save()
|
||||
challenge_response = PromptChallengeResponse(
|
||||
None, stage=self.stage, plan=plan, data=self.prompt_data
|
||||
None,
|
||||
stage_instance=self.stage,
|
||||
plan=plan,
|
||||
data=self.prompt_data,
|
||||
stage=self.stage_view,
|
||||
)
|
||||
self.assertEqual(challenge_response.is_valid(), True)
|
||||
|
||||
@ -160,7 +173,7 @@ class TestPromptStage(FlowTestCase):
|
||||
self.stage.validation_policies.set([expr_policy])
|
||||
self.stage.save()
|
||||
challenge_response = PromptChallengeResponse(
|
||||
None, stage=self.stage, plan=plan, data=self.prompt_data
|
||||
None, stage_instance=self.stage, plan=plan, data=self.prompt_data, stage=self.stage_view
|
||||
)
|
||||
self.assertEqual(challenge_response.is_valid(), False)
|
||||
|
||||
@ -180,7 +193,7 @@ class TestPromptStage(FlowTestCase):
|
||||
self.stage.validation_policies.set([expr_policy])
|
||||
self.stage.save()
|
||||
challenge_response = PromptChallengeResponse(
|
||||
None, stage=self.stage, plan=plan, data=self.prompt_data
|
||||
None, stage_instance=self.stage, plan=plan, data=self.prompt_data, stage=self.stage_view
|
||||
)
|
||||
self.assertEqual(challenge_response.is_valid(), True)
|
||||
|
||||
@ -208,7 +221,7 @@ class TestPromptStage(FlowTestCase):
|
||||
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
|
||||
self.prompt_data["password2_prompt"] = "qwerqwerqr"
|
||||
challenge_response = PromptChallengeResponse(
|
||||
None, stage=self.stage, plan=plan, data=self.prompt_data
|
||||
None, stage_instance=self.stage, plan=plan, data=self.prompt_data, stage=self.stage_view
|
||||
)
|
||||
self.assertEqual(challenge_response.is_valid(), False)
|
||||
self.assertEqual(
|
||||
@ -222,7 +235,7 @@ class TestPromptStage(FlowTestCase):
|
||||
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
|
||||
self.prompt_data["username_prompt"] = user.username
|
||||
challenge_response = PromptChallengeResponse(
|
||||
None, stage=self.stage, plan=plan, data=self.prompt_data
|
||||
None, stage_instance=self.stage, plan=plan, data=self.prompt_data, stage=self.stage_view
|
||||
)
|
||||
self.assertEqual(challenge_response.is_valid(), False)
|
||||
self.assertEqual(
|
||||
@ -237,7 +250,7 @@ class TestPromptStage(FlowTestCase):
|
||||
self.prompt_data["hidden_prompt"] = "foo"
|
||||
self.prompt_data["static_prompt"] = "foo"
|
||||
challenge_response = PromptChallengeResponse(
|
||||
None, stage=self.stage, plan=plan, data=self.prompt_data
|
||||
None, stage_instance=self.stage, plan=plan, data=self.prompt_data, stage=self.stage_view
|
||||
)
|
||||
self.assertEqual(challenge_response.is_valid(), True)
|
||||
self.assertNotEqual(challenge_response.validated_data["hidden_prompt"], "foo")
|
||||
|
@ -73,6 +73,9 @@ class TestUserWriteStage(FlowTestCase):
|
||||
"username": "test-user-new",
|
||||
"password": new_password,
|
||||
"attributes.some.custom-attribute": "test",
|
||||
"attributes": {
|
||||
"foo": "bar",
|
||||
},
|
||||
"some_ignored_attribute": "bar",
|
||||
}
|
||||
session = self.client.session
|
||||
@ -89,6 +92,7 @@ class TestUserWriteStage(FlowTestCase):
|
||||
self.assertTrue(user_qs.exists())
|
||||
self.assertTrue(user_qs.first().check_password(new_password))
|
||||
self.assertEqual(user_qs.first().attributes["some"]["custom-attribute"], "test")
|
||||
self.assertEqual(user_qs.first().attributes["foo"], "bar")
|
||||
self.assertNotIn("some_ignored_attribute", user_qs.first().attributes)
|
||||
|
||||
@patch(
|
||||
|
@ -154,6 +154,7 @@ entries:
|
||||
policy: !KeyOf default-recovery-skip-if-restored
|
||||
target: !KeyOf flow-binding-email
|
||||
order: 0
|
||||
state: absent
|
||||
model: authentik_policies.policybinding
|
||||
attrs:
|
||||
negate: false
|
||||
|
@ -32,7 +32,7 @@ services:
|
||||
volumes:
|
||||
- redis:/data
|
||||
server:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2022.12.1}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2022.12.3}
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment:
|
||||
@ -50,7 +50,7 @@ services:
|
||||
- "0.0.0.0:${AUTHENTIK_PORT_HTTP:-9000}:9000"
|
||||
- "0.0.0.0:${AUTHENTIK_PORT_HTTPS:-9443}:9443"
|
||||
worker:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2022.12.1}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2022.12.3}
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
environment:
|
||||
|
4
go.mod
4
go.mod
@ -17,7 +17,7 @@ require (
|
||||
github.com/gorilla/securecookie v1.1.1
|
||||
github.com/gorilla/sessions v1.2.1
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/jellydator/ttlcache/v3 v3.0.0
|
||||
github.com/jellydator/ttlcache/v3 v3.0.1
|
||||
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
|
||||
github.com/nmcclain/ldap v0.0.0-20210720162743-7f8d1e44eeba
|
||||
github.com/pires/go-proxyproto v0.6.2
|
||||
@ -25,7 +25,7 @@ require (
|
||||
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/stretchr/testify v1.8.1
|
||||
goauthentik.io/api/v3 v3.2022120.3
|
||||
goauthentik.io/api/v3 v3.2022121.4
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
|
||||
gopkg.in/boj/redistore.v1 v1.0.0-20160128113310-fc113767cd6b
|
||||
|
8
go.sum
8
go.sum
@ -232,8 +232,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jellydator/ttlcache/v3 v3.0.0 h1:zmFhqrB/4sKiEiJHhtseJsNRE32IMVmJSs4++4gaQO4=
|
||||
github.com/jellydator/ttlcache/v3 v3.0.0/go.mod h1:WwTaEmcXQ3MTjOm4bsZoDFiCu/hMvNWLO1w67RXz6h4=
|
||||
github.com/jellydator/ttlcache/v3 v3.0.1 h1:cHgCSMS7TdQcoprXnWUptJZzyFsqs18Lt8VVhRuZYVU=
|
||||
github.com/jellydator/ttlcache/v3 v3.0.1/go.mod h1:WwTaEmcXQ3MTjOm4bsZoDFiCu/hMvNWLO1w67RXz6h4=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
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=
|
||||
@ -382,8 +382,8 @@ go.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZp
|
||||
go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ=
|
||||
go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk=
|
||||
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
|
||||
goauthentik.io/api/v3 v3.2022120.3 h1:1HnMlz9IQViazSIdGB7WuFVSCyoHNlwj9V/Yg9LPtSU=
|
||||
goauthentik.io/api/v3 v3.2022120.3/go.mod h1:QM9J32HgYE4gL71lWAfAoXSPdSmLVLW08itfLI3Mo10=
|
||||
goauthentik.io/api/v3 v3.2022121.4 h1:WCwbjXB6Q2VkASkgNc2SFaW36tEBhvOR2tIzmSnheYk=
|
||||
goauthentik.io/api/v3 v3.2022121.4/go.mod h1:QM9J32HgYE4gL71lWAfAoXSPdSmLVLW08itfLI3Mo10=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
|
@ -29,4 +29,4 @@ func UserAgent() string {
|
||||
return fmt.Sprintf("authentik@%s", FullVersion())
|
||||
}
|
||||
|
||||
const VERSION = "2022.12.1"
|
||||
const VERSION = "2022.12.3"
|
||||
|
174
poetry.lock
generated
174
poetry.lock
generated
@ -454,7 +454,7 @@ python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "coverage"
|
||||
version = "7.0.1"
|
||||
version = "7.0.3"
|
||||
description = "Code coverage measurement for Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
@ -552,7 +552,7 @@ graph = ["objgraph (>=1.7.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "django"
|
||||
version = "4.1.4"
|
||||
version = "4.1.5"
|
||||
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
|
||||
category = "main"
|
||||
optional = false
|
||||
@ -906,7 +906,7 @@ python-versions = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "importlib-metadata"
|
||||
version = "5.2.0"
|
||||
version = "6.0.0"
|
||||
description = "Read metadata from Python packages"
|
||||
category = "dev"
|
||||
optional = false
|
||||
@ -1979,7 +1979,7 @@ python-versions = ">=3.6"
|
||||
|
||||
[[package]]
|
||||
name = "watchdog"
|
||||
version = "2.2.0"
|
||||
version = "2.2.1"
|
||||
description = "Filesystem events monitoring"
|
||||
category = "main"
|
||||
optional = false
|
||||
@ -2461,57 +2461,57 @@ constantly = [
|
||||
{file = "constantly-15.1.0.tar.gz", hash = "sha256:586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35"},
|
||||
]
|
||||
coverage = [
|
||||
{file = "coverage-7.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b3695c4f4750bca943b3e1f74ad4be8d29e4aeab927d50772c41359107bd5d5c"},
|
||||
{file = "coverage-7.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fa6a5a224b7f4cfb226f4fc55a57e8537fcc096f42219128c2c74c0e7d0953e1"},
|
||||
{file = "coverage-7.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74f70cd92669394eaf8d7756d1b195c8032cf7bbbdfce3bc489d4e15b3b8cf73"},
|
||||
{file = "coverage-7.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b66bb21a23680dee0be66557dc6b02a3152ddb55edf9f6723fa4a93368f7158d"},
|
||||
{file = "coverage-7.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d87717959d4d0ee9db08a0f1d80d21eb585aafe30f9b0a54ecf779a69cb015f6"},
|
||||
{file = "coverage-7.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:854f22fa361d1ff914c7efa347398374cc7d567bdafa48ac3aa22334650dfba2"},
|
||||
{file = "coverage-7.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:1e414dc32ee5c3f36544ea466b6f52f28a7af788653744b8570d0bf12ff34bc0"},
|
||||
{file = "coverage-7.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6c5ad996c6fa4d8ed669cfa1e8551348729d008a2caf81489ab9ea67cfbc7498"},
|
||||
{file = "coverage-7.0.1-cp310-cp310-win32.whl", hash = "sha256:691571f31ace1837838b7e421d3a09a8c00b4aac32efacb4fc9bd0a5c647d25a"},
|
||||
{file = "coverage-7.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:89caf4425fe88889e2973a8e9a3f6f5f9bbe5dd411d7d521e86428c08a873a4a"},
|
||||
{file = "coverage-7.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:63d56165a7c76265468d7e0c5548215a5ba515fc2cba5232d17df97bffa10f6c"},
|
||||
{file = "coverage-7.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f943a3b2bc520102dd3e0bb465e1286e12c9a54f58accd71b9e65324d9c7c01"},
|
||||
{file = "coverage-7.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:830525361249dc4cd013652b0efad645a385707a5ae49350c894b67d23fbb07c"},
|
||||
{file = "coverage-7.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd1b9c5adc066db699ccf7fa839189a649afcdd9e02cb5dc9d24e67e7922737d"},
|
||||
{file = "coverage-7.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e00c14720b8b3b6c23b487e70bd406abafc976ddc50490f645166f111c419c39"},
|
||||
{file = "coverage-7.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6d55d840e1b8c0002fce66443e124e8581f30f9ead2e54fbf6709fb593181f2c"},
|
||||
{file = "coverage-7.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:66b18c3cf8bbab0cce0d7b9e4262dc830e93588986865a8c78ab2ae324b3ed56"},
|
||||
{file = "coverage-7.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:12a5aa77783d49e05439fbe6e6b427484f8a0f9f456b46a51d8aac022cfd024d"},
|
||||
{file = "coverage-7.0.1-cp311-cp311-win32.whl", hash = "sha256:b77015d1cb8fe941be1222a5a8b4e3fbca88180cfa7e2d4a4e58aeabadef0ab7"},
|
||||
{file = "coverage-7.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb992c47cb1e5bd6a01e97182400bcc2ba2077080a17fcd7be23aaa6e572e390"},
|
||||
{file = "coverage-7.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e78e9dcbf4f3853d3ae18a8f9272111242531535ec9e1009fa8ec4a2b74557dc"},
|
||||
{file = "coverage-7.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e60bef2e2416f15fdc05772bf87db06c6a6f9870d1db08fdd019fbec98ae24a9"},
|
||||
{file = "coverage-7.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9823e4789ab70f3ec88724bba1a203f2856331986cd893dedbe3e23a6cfc1e4e"},
|
||||
{file = "coverage-7.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9158f8fb06747ac17bd237930c4372336edc85b6e13bdc778e60f9d685c3ca37"},
|
||||
{file = "coverage-7.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:486ee81fa694b4b796fc5617e376326a088f7b9729c74d9defa211813f3861e4"},
|
||||
{file = "coverage-7.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1285648428a6101b5f41a18991c84f1c3959cee359e51b8375c5882fc364a13f"},
|
||||
{file = "coverage-7.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2c44fcfb3781b41409d0f060a4ed748537557de9362a8a9282182fafb7a76ab4"},
|
||||
{file = "coverage-7.0.1-cp37-cp37m-win32.whl", hash = "sha256:d6814854c02cbcd9c873c0f3286a02e3ac1250625cca822ca6bc1018c5b19f1c"},
|
||||
{file = "coverage-7.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f66460f17c9319ea4f91c165d46840314f0a7c004720b20be58594d162a441d8"},
|
||||
{file = "coverage-7.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9b373c9345c584bb4b5f5b8840df7f4ab48c4cbb7934b58d52c57020d911b856"},
|
||||
{file = "coverage-7.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d3022c3007d3267a880b5adcf18c2a9bf1fc64469b394a804886b401959b8742"},
|
||||
{file = "coverage-7.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92651580bd46519067e36493acb394ea0607b55b45bd81dd4e26379ed1871f55"},
|
||||
{file = "coverage-7.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cfc595d2af13856505631be072835c59f1acf30028d1c860b435c5fc9c15b69"},
|
||||
{file = "coverage-7.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b4b3a4d9915b2be879aff6299c0a6129f3d08a775d5a061f503cf79571f73e4"},
|
||||
{file = "coverage-7.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b6f22bb64cc39bcb883e5910f99a27b200fdc14cdd79df8696fa96b0005c9444"},
|
||||
{file = "coverage-7.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:72d1507f152abacea81f65fee38e4ef3ac3c02ff8bc16f21d935fd3a8a4ad910"},
|
||||
{file = "coverage-7.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0a79137fc99815fff6a852c233628e735ec15903cfd16da0f229d9c4d45926ab"},
|
||||
{file = "coverage-7.0.1-cp38-cp38-win32.whl", hash = "sha256:b3763e7fcade2ff6c8e62340af9277f54336920489ceb6a8cd6cc96da52fcc62"},
|
||||
{file = "coverage-7.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:09f6b5a8415b6b3e136d5fec62b552972187265cb705097bf030eb9d4ffb9b60"},
|
||||
{file = "coverage-7.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:978258fec36c154b5e250d356c59af7d4c3ba02bef4b99cda90b6029441d797d"},
|
||||
{file = "coverage-7.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:19ec666533f0f70a0993f88b8273057b96c07b9d26457b41863ccd021a043b9a"},
|
||||
{file = "coverage-7.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfded268092a84605f1cc19e5c737f9ce630a8900a3589e9289622db161967e9"},
|
||||
{file = "coverage-7.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07bcfb1d8ac94af886b54e18a88b393f6a73d5959bb31e46644a02453c36e475"},
|
||||
{file = "coverage-7.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b4a923cc7566bbc7ae2dfd0ba5a039b61d19c740f1373791f2ebd11caea59"},
|
||||
{file = "coverage-7.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:aec2d1515d9d39ff270059fd3afbb3b44e6ec5758af73caf18991807138c7118"},
|
||||
{file = "coverage-7.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c20cfebcc149a4c212f6491a5f9ff56f41829cd4f607b5be71bb2d530ef243b1"},
|
||||
{file = "coverage-7.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:fd556ff16a57a070ce4f31c635953cc44e25244f91a0378c6e9bdfd40fdb249f"},
|
||||
{file = "coverage-7.0.1-cp39-cp39-win32.whl", hash = "sha256:b9ea158775c7c2d3e54530a92da79496fb3fb577c876eec761c23e028f1e216c"},
|
||||
{file = "coverage-7.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:d1991f1dd95eba69d2cd7708ff6c2bbd2426160ffc73c2b81f617a053ebcb1a8"},
|
||||
{file = "coverage-7.0.1-pp37.pp38.pp39-none-any.whl", hash = "sha256:3dd4ee135e08037f458425b8842d24a95a0961831a33f89685ff86b77d378f89"},
|
||||
{file = "coverage-7.0.1.tar.gz", hash = "sha256:a4a574a19eeb67575a5328a5760bbbb737faa685616586a9f9da4281f940109c"},
|
||||
{file = "coverage-7.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f7c51b6074a8a3063c341953dffe48fd6674f8e4b1d3c8aa8a91f58d6e716a8"},
|
||||
{file = "coverage-7.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:628f47eaf66727fc986d3b190d6fa32f5e6b7754a243919d28bc0fd7974c449f"},
|
||||
{file = "coverage-7.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e89d5abf86c104de808108a25d171ad646c07eda96ca76c8b237b94b9c71e518"},
|
||||
{file = "coverage-7.0.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75e43c6f4ea4d122dac389aabdf9d4f0e160770a75e63372f88005d90f5bcc80"},
|
||||
{file = "coverage-7.0.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49da0ff241827ebb52d5d6d5a36d33b455fa5e721d44689c95df99fd8db82437"},
|
||||
{file = "coverage-7.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0bce4ad5bdd0b02e177a085d28d2cea5fc57bb4ba2cead395e763e34cf934eb1"},
|
||||
{file = "coverage-7.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f79691335257d60951638dd43576b9bcd6f52baa5c1c2cd07a509bb003238372"},
|
||||
{file = "coverage-7.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5722269ed05fbdb94eef431787c66b66260ff3125d1a9afcc00facff8c45adf9"},
|
||||
{file = "coverage-7.0.3-cp310-cp310-win32.whl", hash = "sha256:bdbda870e0fda7dd0fe7db7135ca226ec4c1ade8aa76e96614829b56ca491012"},
|
||||
{file = "coverage-7.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:e56fae4292e216b8deeee38ace84557b9fa85b52db005368a275427cdabb8192"},
|
||||
{file = "coverage-7.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b82343a5bc51627b9d606f0b6b6b9551db7b6311a5dd920fa52a94beae2e8959"},
|
||||
{file = "coverage-7.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fd0a8aa431f9b7ad9eb8264f55ef83cbb254962af3775092fb6e93890dea9ca2"},
|
||||
{file = "coverage-7.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:112cfead1bd22eada8a8db9ed387bd3e8be5528debc42b5d3c1f7da4ffaf9fb5"},
|
||||
{file = "coverage-7.0.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af87e906355fa42447be5c08c5d44e6e1c005bf142f303f726ddf5ed6e0c8a4d"},
|
||||
{file = "coverage-7.0.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f30090e22a301952c5abd0e493a1c8358b4f0b368b49fa3e4568ed3ed68b8d1f"},
|
||||
{file = "coverage-7.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ae871d09901911eedda1981ea6fd0f62a999107293cdc4c4fd612321c5b34745"},
|
||||
{file = "coverage-7.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ed7c9debf7bfc63c9b9f8b595409237774ff4b061bf29fba6f53b287a2fdeab9"},
|
||||
{file = "coverage-7.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:13121fa22dcd2c7b19c5161e3fd725692448f05377b788da4502a383573227b3"},
|
||||
{file = "coverage-7.0.3-cp311-cp311-win32.whl", hash = "sha256:037b51ee86bc600f99b3b957c20a172431c35c2ef9c1ca34bc813ab5b51fd9f5"},
|
||||
{file = "coverage-7.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:25fde928306034e8deecd5fc91a07432dcc282c8acb76749581a28963c9f4f3f"},
|
||||
{file = "coverage-7.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7e8b0642c38b3d3b3c01417643ccc645345b03c32a2e84ef93cdd6844d6fe530"},
|
||||
{file = "coverage-7.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18b09811f849cc958d23f733a350a66b54a8de3fed1e6128ba55a5c97ffb6f65"},
|
||||
{file = "coverage-7.0.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:349d0b545520e8516f7b4f12373afc705d17d901e1de6a37a20e4ec9332b61f7"},
|
||||
{file = "coverage-7.0.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5b38813eee5b4739f505d94247604c72eae626d5088a16dd77b08b8b1724ab3"},
|
||||
{file = "coverage-7.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ba9af1218fa01b1f11c72271bc7290b701d11ad4dbc2ae97c445ecacf6858dba"},
|
||||
{file = "coverage-7.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c5648c7eec5cf1ba5db1cf2d6c10036a582d7f09e172990474a122e30c841361"},
|
||||
{file = "coverage-7.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d0df04495b76a885bfef009f45eebe8fe2fbf815ad7a83dabcf5aced62f33162"},
|
||||
{file = "coverage-7.0.3-cp37-cp37m-win32.whl", hash = "sha256:af6cef3796b8068713a48dd67d258dc9a6e2ebc3bd4645bfac03a09672fa5d20"},
|
||||
{file = "coverage-7.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:62ef3800c4058844e2e3fa35faa9dd0ccde8a8aba6c763aae50342e00d4479d4"},
|
||||
{file = "coverage-7.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:acef7f3a3825a2d218a03dd02f5f3cc7f27aa31d882dd780191d1ad101120d74"},
|
||||
{file = "coverage-7.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a530663a361eb27375cec28aea5cd282089b5e4b022ae451c4c3493b026a68a5"},
|
||||
{file = "coverage-7.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c58cd6bb46dcb922e0d5792850aab5964433d511b3a020867650f8d930dde4f4"},
|
||||
{file = "coverage-7.0.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f918e9ef4c98f477a5458238dde2a1643aed956c7213873ab6b6b82e32b8ef61"},
|
||||
{file = "coverage-7.0.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b865aa679bee7fbd1c55960940dbd3252621dd81468268786c67122bbd15343"},
|
||||
{file = "coverage-7.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c5d9b480ebae60fc2cbc8d6865194136bc690538fa542ba58726433bed6e04cc"},
|
||||
{file = "coverage-7.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:985ad2af5ec3dbb4fd75d5b0735752c527ad183455520055a08cf8d6794cabfc"},
|
||||
{file = "coverage-7.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ca15308ef722f120967af7474ba6a453e0f5b6f331251e20b8145497cf1bc14a"},
|
||||
{file = "coverage-7.0.3-cp38-cp38-win32.whl", hash = "sha256:c1cee10662c25c94415bbb987f2ec0e6ba9e8fce786334b10be7e6a7ab958f69"},
|
||||
{file = "coverage-7.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:44d6a556de4418f1f3bfd57094b8c49f0408df5a433cf0d253eeb3075261c762"},
|
||||
{file = "coverage-7.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e6dcc70a25cb95df0ae33dfc701de9b09c37f7dd9f00394d684a5b57257f8246"},
|
||||
{file = "coverage-7.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bf76d79dfaea802f0f28f50153ffbc1a74ae1ee73e480baeda410b4f3e7ab25f"},
|
||||
{file = "coverage-7.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88834e5d56d01c141c29deedacba5773fe0bed900b1edc957595a8a6c0da1c3c"},
|
||||
{file = "coverage-7.0.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef001a60e888f8741e42e5aa79ae55c91be73761e4df5e806efca1ddd62fd400"},
|
||||
{file = "coverage-7.0.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4959dc506be74e4963bd2c42f7b87d8e4b289891201e19ec551e64c6aa5441f8"},
|
||||
{file = "coverage-7.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b791beb17b32ac019a78cfbe6184f992b6273fdca31145b928ad2099435e2fcb"},
|
||||
{file = "coverage-7.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b07651e3b9af8f1a092861d88b4c74d913634a7f1f2280fca0ad041ad84e9e96"},
|
||||
{file = "coverage-7.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:55e46fa4168ccb7497c9be78627fcb147e06f474f846a10d55feeb5108a24ef0"},
|
||||
{file = "coverage-7.0.3-cp39-cp39-win32.whl", hash = "sha256:e3f1cd1cd65695b1540b3cf7828d05b3515974a9d7c7530f762ac40f58a18161"},
|
||||
{file = "coverage-7.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:d8249666c23683f74f8f93aeaa8794ac87cc61c40ff70374a825f3352a4371dc"},
|
||||
{file = "coverage-7.0.3-pp37.pp38.pp39-none-any.whl", hash = "sha256:b1ffc8f58b81baed3f8962e28c30d99442079b82ce1ec836a1f67c0accad91c1"},
|
||||
{file = "coverage-7.0.3.tar.gz", hash = "sha256:d5be4e93acce64f516bf4fd239c0e6118fc913c93fa1a3f52d15bdcc60d97b2d"},
|
||||
]
|
||||
cryptography = [
|
||||
{file = "cryptography-38.0.3-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:984fe150f350a3c91e84de405fe49e688aa6092b3525f407a18b9646f6612320"},
|
||||
@ -2566,8 +2566,8 @@ dill = [
|
||||
{file = "dill-0.3.6.tar.gz", hash = "sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373"},
|
||||
]
|
||||
django = [
|
||||
{file = "Django-4.1.4-py3-none-any.whl", hash = "sha256:0b223bfa55511f950ff741983d408d78d772351284c75e9f77d2b830b6b4d148"},
|
||||
{file = "Django-4.1.4.tar.gz", hash = "sha256:d38a4e108d2386cb9637da66a82dc8d0733caede4c83c4afdbda78af4214211b"},
|
||||
{file = "Django-4.1.5-py3-none-any.whl", hash = "sha256:4b214a05fe4c99476e99e2445c8b978c8369c18d4dea8e22ec412862715ad763"},
|
||||
{file = "Django-4.1.5.tar.gz", hash = "sha256:ff56ebd7ead0fd5dbe06fe157b0024a7aaea2e0593bb3785fb594cf94dad58ef"},
|
||||
]
|
||||
django-filter = [
|
||||
{file = "django-filter-22.1.tar.gz", hash = "sha256:ed473b76e84f7e83b2511bb2050c3efb36d135207d0128dfe3ae4b36e3594ba5"},
|
||||
@ -2792,8 +2792,8 @@ idna = [
|
||||
{file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
|
||||
]
|
||||
importlib-metadata = [
|
||||
{file = "importlib_metadata-5.2.0-py3-none-any.whl", hash = "sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f"},
|
||||
{file = "importlib_metadata-5.2.0.tar.gz", hash = "sha256:404d48d62bba0b7a77ff9d405efd91501bef2e67ff4ace0bed40a0cf28c3c7cd"},
|
||||
{file = "importlib_metadata-6.0.0-py3-none-any.whl", hash = "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad"},
|
||||
{file = "importlib_metadata-6.0.0.tar.gz", hash = "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"},
|
||||
]
|
||||
incremental = [
|
||||
{file = "incremental-22.10.0-py2.py3-none-any.whl", hash = "sha256:b864a1f30885ee72c5ac2835a761b8fe8aa9c28b9395cacf27286602688d3e51"},
|
||||
@ -3628,34 +3628,34 @@ vine = [
|
||||
{file = "vine-5.0.0.tar.gz", hash = "sha256:7d3b1624a953da82ef63462013bbd271d3eb75751489f9807598e8f340bd637e"},
|
||||
]
|
||||
watchdog = [
|
||||
{file = "watchdog-2.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ed91c3ccfc23398e7aa9715abf679d5c163394b8cad994f34f156d57a7c163dc"},
|
||||
{file = "watchdog-2.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:76a2743402b794629a955d96ea2e240bd0e903aa26e02e93cd2d57b33900962b"},
|
||||
{file = "watchdog-2.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:920a4bda7daa47545c3201a3292e99300ba81ca26b7569575bd086c865889090"},
|
||||
{file = "watchdog-2.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ceaa9268d81205876bedb1069f9feab3eccddd4b90d9a45d06a0df592a04cae9"},
|
||||
{file = "watchdog-2.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1893d425ef4fb4f129ee8ef72226836619c2950dd0559bba022b0818c63a7b60"},
|
||||
{file = "watchdog-2.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9e99c1713e4436d2563f5828c8910e5ff25abd6ce999e75f15c15d81d41980b6"},
|
||||
{file = "watchdog-2.2.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a5bd9e8656d07cae89ac464ee4bcb6f1b9cecbedc3bf1334683bed3d5afd39ba"},
|
||||
{file = "watchdog-2.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a048865c828389cb06c0bebf8a883cec3ae58ad3e366bcc38c61d8455a3138f"},
|
||||
{file = "watchdog-2.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e722755d995035dd32177a9c633d158f2ec604f2a358b545bba5bed53ab25bca"},
|
||||
{file = "watchdog-2.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:af4b5c7ba60206759a1d99811b5938ca666ea9562a1052b410637bb96ff97512"},
|
||||
{file = "watchdog-2.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:619d63fa5be69f89ff3a93e165e602c08ed8da402ca42b99cd59a8ec115673e1"},
|
||||
{file = "watchdog-2.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1f2b0665c57358ce9786f06f5475bc083fea9d81ecc0efa4733fd0c320940a37"},
|
||||
{file = "watchdog-2.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:441024df19253bb108d3a8a5de7a186003d68564084576fecf7333a441271ef7"},
|
||||
{file = "watchdog-2.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1a410dd4d0adcc86b4c71d1317ba2ea2c92babaf5b83321e4bde2514525544d5"},
|
||||
{file = "watchdog-2.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28704c71afdb79c3f215c90231e41c52b056ea880b6be6cee035c6149d658ed1"},
|
||||
{file = "watchdog-2.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2ac0bd7c206bb6df78ef9e8ad27cc1346f2b41b1fef610395607319cdab89bc1"},
|
||||
{file = "watchdog-2.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:27e49268735b3c27310883012ab3bd86ea0a96dcab90fe3feb682472e30c90f3"},
|
||||
{file = "watchdog-2.2.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:2af1a29fd14fc0a87fb6ed762d3e1ae5694dcde22372eebba50e9e5be47af03c"},
|
||||
{file = "watchdog-2.2.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:c7bd98813d34bfa9b464cf8122e7d4bec0a5a427399094d2c17dd5f70d59bc61"},
|
||||
{file = "watchdog-2.2.0-py3-none-manylinux2014_i686.whl", hash = "sha256:56fb3f40fc3deecf6e518303c7533f5e2a722e377b12507f6de891583f1b48aa"},
|
||||
{file = "watchdog-2.2.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:74535e955359d79d126885e642d3683616e6d9ab3aae0e7dcccd043bd5a3ff4f"},
|
||||
{file = "watchdog-2.2.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:cf05e6ff677b9655c6e9511d02e9cc55e730c4e430b7a54af9c28912294605a4"},
|
||||
{file = "watchdog-2.2.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:d6ae890798a3560688b441ef086bb66e87af6b400a92749a18b856a134fc0318"},
|
||||
{file = "watchdog-2.2.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:e5aed2a700a18c194c39c266900d41f3db0c1ebe6b8a0834b9995c835d2ca66e"},
|
||||
{file = "watchdog-2.2.0-py3-none-win32.whl", hash = "sha256:d0fb5f2b513556c2abb578c1066f5f467d729f2eb689bc2db0739daf81c6bb7e"},
|
||||
{file = "watchdog-2.2.0-py3-none-win_amd64.whl", hash = "sha256:1f8eca9d294a4f194ce9df0d97d19b5598f310950d3ac3dd6e8d25ae456d4c8a"},
|
||||
{file = "watchdog-2.2.0-py3-none-win_ia64.whl", hash = "sha256:ad0150536469fa4b693531e497ffe220d5b6cd76ad2eda474a5e641ee204bbb6"},
|
||||
{file = "watchdog-2.2.0.tar.gz", hash = "sha256:83cf8bc60d9c613b66a4c018051873d6273d9e45d040eed06d6a96241bd8ec01"},
|
||||
{file = "watchdog-2.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a09483249d25cbdb4c268e020cb861c51baab2d1affd9a6affc68ffe6a231260"},
|
||||
{file = "watchdog-2.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5100eae58133355d3ca6c1083a33b81355c4f452afa474c2633bd2fbbba398b3"},
|
||||
{file = "watchdog-2.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e618a4863726bc7a3c64f95c218437f3349fb9d909eb9ea3a1ed3b567417c661"},
|
||||
{file = "watchdog-2.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:102a60093090fc3ff76c983367b19849b7cc24ec414a43c0333680106e62aae1"},
|
||||
{file = "watchdog-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:748ca797ff59962e83cc8e4b233f87113f3cf247c23e6be58b8a2885c7337aa3"},
|
||||
{file = "watchdog-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6ccd8d84b9490a82b51b230740468116b8205822ea5fdc700a553d92661253a3"},
|
||||
{file = "watchdog-2.2.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6e01d699cd260d59b84da6bda019dce0a3353e3fcc774408ae767fe88ee096b7"},
|
||||
{file = "watchdog-2.2.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8586d98c494690482c963ffb24c49bf9c8c2fe0589cec4dc2f753b78d1ec301d"},
|
||||
{file = "watchdog-2.2.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:adaf2ece15f3afa33a6b45f76b333a7da9256e1360003032524d61bdb4c422ae"},
|
||||
{file = "watchdog-2.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83a7cead445008e880dbde833cb9e5cc7b9a0958edb697a96b936621975f15b9"},
|
||||
{file = "watchdog-2.2.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f8ac23ff2c2df4471a61af6490f847633024e5aa120567e08d07af5718c9d092"},
|
||||
{file = "watchdog-2.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d0f29fd9f3f149a5277929de33b4f121a04cf84bb494634707cfa8ea8ae106a8"},
|
||||
{file = "watchdog-2.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:967636031fa4c4955f0f3f22da3c5c418aa65d50908d31b73b3b3ffd66d60640"},
|
||||
{file = "watchdog-2.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:96cbeb494e6cbe3ae6aacc430e678ce4b4dd3ae5125035f72b6eb4e5e9eb4f4e"},
|
||||
{file = "watchdog-2.2.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:61fdb8e9c57baf625e27e1420e7ca17f7d2023929cd0065eb79c83da1dfbeacd"},
|
||||
{file = "watchdog-2.2.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4cb5ecc332112017fbdb19ede78d92e29a8165c46b68a0b8ccbd0a154f196d5e"},
|
||||
{file = "watchdog-2.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a480d122740debf0afac4ddd583c6c0bb519c24f817b42ed6f850e2f6f9d64a8"},
|
||||
{file = "watchdog-2.2.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:978a1aed55de0b807913b7482d09943b23a2d634040b112bdf31811a422f6344"},
|
||||
{file = "watchdog-2.2.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:8c28c23972ec9c524967895ccb1954bc6f6d4a557d36e681a36e84368660c4ce"},
|
||||
{file = "watchdog-2.2.1-py3-none-manylinux2014_i686.whl", hash = "sha256:c27d8c1535fd4474e40a4b5e01f4ba6720bac58e6751c667895cbc5c8a7af33c"},
|
||||
{file = "watchdog-2.2.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d6b87477752bd86ac5392ecb9eeed92b416898c30bd40c7e2dd03c3146105646"},
|
||||
{file = "watchdog-2.2.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:cece1aa596027ff56369f0b50a9de209920e1df9ac6d02c7f9e5d8162eb4f02b"},
|
||||
{file = "watchdog-2.2.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:8b5cde14e5c72b2df5d074774bdff69e9b55da77e102a91f36ef26ca35f9819c"},
|
||||
{file = "watchdog-2.2.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:e038be858425c4f621900b8ff1a3a1330d9edcfeaa1c0468aeb7e330fb87693e"},
|
||||
{file = "watchdog-2.2.1-py3-none-win32.whl", hash = "sha256:bc43c1b24d2f86b6e1cc15f68635a959388219426109233e606517ff7d0a5a73"},
|
||||
{file = "watchdog-2.2.1-py3-none-win_amd64.whl", hash = "sha256:17f1708f7410af92ddf591e94ae71a27a13974559e72f7e9fde3ec174b26ba2e"},
|
||||
{file = "watchdog-2.2.1-py3-none-win_ia64.whl", hash = "sha256:195ab1d9d611a4c1e5311cbf42273bc541e18ea8c32712f2fb703cfc6ff006f9"},
|
||||
{file = "watchdog-2.2.1.tar.gz", hash = "sha256:cdcc23c9528601a8a293eb4369cbd14f6b4f34f07ae8769421252e9c22718b6f"},
|
||||
]
|
||||
watchfiles = [
|
||||
{file = "watchfiles-0.18.1-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:9891d3c94272108bcecf5597a592e61105279def1313521e637f2d5acbe08bc9"},
|
||||
|
@ -100,7 +100,7 @@ addopts = "-p no:celery --junitxml=unittest.xml"
|
||||
|
||||
[tool.poetry]
|
||||
name = "authentik"
|
||||
version = "2022.12.1"
|
||||
version = "2022.12.3"
|
||||
description = ""
|
||||
authors = ["authentik Team <hello@goauthentik.io>"]
|
||||
|
||||
|
37
schema.yml
37
schema.yml
@ -1,7 +1,7 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: authentik
|
||||
version: 2022.12.1
|
||||
version: 2022.12.3
|
||||
description: Making authentication simple.
|
||||
contact:
|
||||
email: hello@goauthentik.io
|
||||
@ -5021,12 +5021,11 @@ paths:
|
||||
operationId: crypto_certificatekeypairs_list
|
||||
description: CertificateKeyPair Viewset
|
||||
parameters:
|
||||
- name: has_key
|
||||
required: false
|
||||
in: query
|
||||
description: Only return certificate-key pairs with keys
|
||||
- in: query
|
||||
name: has_key
|
||||
schema:
|
||||
type: string
|
||||
type: boolean
|
||||
description: Only return certificate-key pairs with keys
|
||||
- in: query
|
||||
name: include_details
|
||||
schema:
|
||||
@ -21607,6 +21606,10 @@ paths:
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
- in: query
|
||||
name: throw_error
|
||||
schema:
|
||||
type: boolean
|
||||
tags:
|
||||
- stages
|
||||
security:
|
||||
@ -26358,7 +26361,6 @@ components:
|
||||
type: string
|
||||
js_url:
|
||||
type: string
|
||||
readOnly: true
|
||||
required:
|
||||
- js_url
|
||||
- pending_user
|
||||
@ -26608,7 +26610,7 @@ components:
|
||||
ak-stage-consent: '#/components/schemas/ConsentChallenge'
|
||||
ak-stage-dummy: '#/components/schemas/DummyChallenge'
|
||||
ak-stage-email: '#/components/schemas/EmailChallenge'
|
||||
xak-flow-error: '#/components/schemas/FlowErrorChallenge'
|
||||
ak-stage-flow-error: '#/components/schemas/FlowErrorChallenge'
|
||||
ak-stage-identification: '#/components/schemas/IdentificationChallenge'
|
||||
ak-provider-oauth2-device-code: '#/components/schemas/OAuthDeviceCodeChallenge'
|
||||
ak-provider-oauth2-device-code-finish: '#/components/schemas/OAuthDeviceCodeFinishChallenge'
|
||||
@ -27178,6 +27180,8 @@ components:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/FlowSet'
|
||||
throw_error:
|
||||
type: boolean
|
||||
required:
|
||||
- component
|
||||
- meta_model_name
|
||||
@ -27196,6 +27200,8 @@ components:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/FlowSetRequest'
|
||||
throw_error:
|
||||
type: boolean
|
||||
required:
|
||||
- name
|
||||
DuoDevice:
|
||||
@ -27869,22 +27875,19 @@ components:
|
||||
are shown an error message, superusers are shown a full stacktrace.
|
||||
properties:
|
||||
type:
|
||||
$ref: '#/components/schemas/ChallengeChoices'
|
||||
type: string
|
||||
default: native
|
||||
flow_info:
|
||||
$ref: '#/components/schemas/ContextualFlowInfo'
|
||||
component:
|
||||
type: string
|
||||
default: xak-flow-error
|
||||
default: ak-stage-flow-error
|
||||
response_errors:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ErrorDetail'
|
||||
pending_user:
|
||||
type: string
|
||||
pending_user_avatar:
|
||||
type: string
|
||||
request_id:
|
||||
type: string
|
||||
error:
|
||||
@ -27892,10 +27895,7 @@ components:
|
||||
traceback:
|
||||
type: string
|
||||
required:
|
||||
- pending_user
|
||||
- pending_user_avatar
|
||||
- request_id
|
||||
- type
|
||||
FlowImportResult:
|
||||
type: object
|
||||
description: Logs of an attempted flow import
|
||||
@ -33740,6 +33740,8 @@ components:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/FlowSetRequest'
|
||||
throw_error:
|
||||
type: boolean
|
||||
PatchedDuoDeviceRequest:
|
||||
type: object
|
||||
description: Serializer for Duo authenticator devices
|
||||
@ -37938,6 +37940,7 @@ components:
|
||||
- username
|
||||
UserAccountRequest:
|
||||
type: object
|
||||
description: Account adding/removing operations
|
||||
properties:
|
||||
pk:
|
||||
type: integer
|
||||
|
@ -47,7 +47,6 @@ class TestProviderLDAP(SeleniumTestCase):
|
||||
|
||||
def _prepare(self) -> User:
|
||||
"""prepare user, provider, app and container"""
|
||||
# set additionalHeaders to test later
|
||||
self.user.attributes["extraAttribute"] = "bar"
|
||||
self.user.save()
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
"""Proxy and Outpost e2e tests"""
|
||||
from base64 import b64encode
|
||||
from dataclasses import asdict
|
||||
from sys import platform
|
||||
from time import sleep
|
||||
@ -14,6 +15,7 @@ from authentik import __version__
|
||||
from authentik.blueprints.tests import apply_blueprint, reconcile_app
|
||||
from authentik.core.models import Application
|
||||
from authentik.flows.models import Flow
|
||||
from authentik.lib.generators import generate_id
|
||||
from authentik.outposts.models import DockerServiceConnection, Outpost, OutpostConfig, OutpostType
|
||||
from authentik.outposts.tasks import outpost_local_connection
|
||||
from authentik.providers.proxy.models import ProxyProvider
|
||||
@ -119,6 +121,78 @@ class TestProviderProxy(SeleniumTestCase):
|
||||
full_body_text = self.driver.find_element(By.CSS_SELECTOR, ".pf-c-title.pf-m-3xl").text
|
||||
self.assertIn("You've logged out of proxy.", full_body_text)
|
||||
|
||||
@retry()
|
||||
@apply_blueprint(
|
||||
"default/10-flow-default-authentication-flow.yaml",
|
||||
"default/10-flow-default-invalidation-flow.yaml",
|
||||
)
|
||||
@apply_blueprint(
|
||||
"default/20-flow-default-provider-authorization-explicit-consent.yaml",
|
||||
"default/20-flow-default-provider-authorization-implicit-consent.yaml",
|
||||
)
|
||||
@apply_blueprint(
|
||||
"system/providers-oauth2.yaml",
|
||||
"system/providers-proxy.yaml",
|
||||
)
|
||||
@reconcile_app("authentik_crypto")
|
||||
def test_proxy_basic_auth(self):
|
||||
"""Test simple outpost setup with single provider"""
|
||||
cred = generate_id()
|
||||
attr = "basic-password" # nosec
|
||||
self.user.attributes["basic-username"] = cred
|
||||
self.user.attributes[attr] = cred
|
||||
self.user.save()
|
||||
|
||||
proxy: ProxyProvider = ProxyProvider.objects.create(
|
||||
name="proxy_provider",
|
||||
authorization_flow=Flow.objects.get(
|
||||
slug="default-provider-authorization-implicit-consent"
|
||||
),
|
||||
internal_host="http://localhost",
|
||||
external_host="http://localhost:9000",
|
||||
basic_auth_enabled=True,
|
||||
basic_auth_user_attribute="basic-username",
|
||||
basic_auth_password_attribute=attr,
|
||||
)
|
||||
# Ensure OAuth2 Params are set
|
||||
proxy.set_oauth_defaults()
|
||||
proxy.save()
|
||||
# we need to create an application to actually access the proxy
|
||||
Application.objects.create(name="proxy", slug="proxy", provider=proxy)
|
||||
outpost: Outpost = Outpost.objects.create(
|
||||
name="proxy_outpost",
|
||||
type=OutpostType.PROXY,
|
||||
)
|
||||
outpost.providers.add(proxy)
|
||||
outpost.build_user_permissions(outpost.user)
|
||||
|
||||
self.proxy_container = self.start_proxy(outpost)
|
||||
|
||||
# Wait until outpost healthcheck succeeds
|
||||
healthcheck_retries = 0
|
||||
while healthcheck_retries < 50:
|
||||
if len(outpost.state) > 0:
|
||||
state = outpost.state[0]
|
||||
if state.last_seen:
|
||||
break
|
||||
healthcheck_retries += 1
|
||||
sleep(0.5)
|
||||
sleep(5)
|
||||
|
||||
self.driver.get("http://localhost:9000")
|
||||
self.login()
|
||||
sleep(1)
|
||||
|
||||
full_body_text = self.driver.find_element(By.CSS_SELECTOR, "pre").text
|
||||
self.assertIn(f"X-Authentik-Username: {self.user.username}", full_body_text)
|
||||
auth_header = b64encode(f"{cred}:{cred}".encode()).decode()
|
||||
self.assertIn(f"Authorization: Basic {auth_header}", full_body_text)
|
||||
|
||||
self.driver.get("http://localhost:9000/outpost.goauthentik.io/sign_out")
|
||||
sleep(2)
|
||||
full_body_text = self.driver.find_element(By.CSS_SELECTOR, ".pf-c-title.pf-m-3xl").text
|
||||
self.assertIn("You've logged out of proxy.", full_body_text)
|
||||
|
||||
|
||||
@skipUnless(platform.startswith("linux"), "requires local docker")
|
||||
class TestProviderProxyConnect(ChannelsLiveServerTestCase):
|
||||
|
286
web/package-lock.json
generated
286
web/package-lock.json
generated
@ -21,7 +21,8 @@
|
||||
"@codemirror/legacy-modes": "^6.3.1",
|
||||
"@formatjs/intl-listformat": "^7.1.7",
|
||||
"@fortawesome/fontawesome-free": "^6.2.1",
|
||||
"@goauthentik/api": "^2022.12.0-1672308901",
|
||||
"@goauthentik/api": "^2022.12.1-1672612412",
|
||||
"@hcaptcha/types": "^1.0.3",
|
||||
"@jackfranklin/rollup-plugin-markdown": "^0.4.0",
|
||||
"@lingui/cli": "^3.15.0",
|
||||
"@lingui/core": "^3.15.0",
|
||||
@ -37,13 +38,13 @@
|
||||
"@rollup/plugin-typescript": "^10.0.1",
|
||||
"@sentry/browser": "^7.28.1",
|
||||
"@sentry/tracing": "^7.28.1",
|
||||
"@squoosh/cli": "^0.7.2",
|
||||
"@squoosh/cli": "^0.7.3",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.0.0",
|
||||
"@types/chart.js": "^2.9.37",
|
||||
"@types/codemirror": "5.60.5",
|
||||
"@types/codemirror": "5.60.6",
|
||||
"@types/grecaptcha": "^3.0.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.1",
|
||||
"@typescript-eslint/parser": "^5.47.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.48.0",
|
||||
"@typescript-eslint/parser": "^5.48.0",
|
||||
"@webcomponents/webcomponentsjs": "^2.7.0",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
"babel-plugin-tsconfig-paths": "^1.0.3",
|
||||
@ -53,9 +54,9 @@
|
||||
"codemirror": "^6.0.1",
|
||||
"construct-style-sheets-polyfill": "^3.1.0",
|
||||
"country-flag-icons": "^1.5.5",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint": "^8.31.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-custom-elements": "0.0.6",
|
||||
"eslint-plugin-custom-elements": "0.0.7",
|
||||
"eslint-plugin-lit": "^1.7.2",
|
||||
"fuse.js": "^6.6.2",
|
||||
"lit": "^2.5.0",
|
||||
@ -71,9 +72,10 @@
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"ts-lit-plugin": "^1.2.1",
|
||||
"tslib": "^2.4.1",
|
||||
"turnstile-types": "^1.0.2",
|
||||
"typescript": "^4.9.4",
|
||||
"webcomponent-qr-code": "^1.1.0",
|
||||
"yaml": "^2.2.0"
|
||||
"yaml": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
@ -1874,9 +1876,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.0.tgz",
|
||||
"integrity": "sha512-7yfvXy6MWLgWSFsLhz5yH3iQ52St8cdUY6FoGieKkRDVxuxmrNuUetIuu6cmjNWwniUHiWXjxCr5tTXDrbYS5A==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
|
||||
"integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==",
|
||||
"dependencies": {
|
||||
"ajv": "^6.12.4",
|
||||
"debug": "^4.3.2",
|
||||
@ -1957,9 +1959,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@goauthentik/api": {
|
||||
"version": "2022.12.0-1672308901",
|
||||
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2022.12.0-1672308901.tgz",
|
||||
"integrity": "sha512-Wj3dzxiR83cOLyTEbr4T8MQZ2Vb7Oaq3ub6oWZXNv7zsk3sn7w7YN1/vXBU74KCbZk569zRIAAR+QLL+i2UNEw=="
|
||||
"version": "2022.12.1-1672612412",
|
||||
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2022.12.1-1672612412.tgz",
|
||||
"integrity": "sha512-fyAk76avWt0KzBfcrUPPopwRW2KWw/yo+MYva3ocWcU+4dbYlwEiT3LehToPMOOHoM81vRbyP9oVE5f472TyUQ=="
|
||||
},
|
||||
"node_modules/@hcaptcha/types": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@hcaptcha/types/-/types-1.0.3.tgz",
|
||||
"integrity": "sha512-1mbU6eSGawRrqeahRrOzZo/SVLI6oZ5/azuBpSyVrRRR96CnS3fOVDWfzxpngfxKD0/I9Rwu6c/3ITqD8rXeTQ=="
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.11.8",
|
||||
@ -3047,9 +3054,9 @@
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@squoosh/cli": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@squoosh/cli/-/cli-0.7.2.tgz",
|
||||
"integrity": "sha512-uMnUWMx4S8UApO/EfPyRyvUmw+0jI9wwAfdHfGjvVg4DAIvEgsA+VWK2KOBnJiChvVd768K27g09ESzptyX93w==",
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@squoosh/cli/-/cli-0.7.3.tgz",
|
||||
"integrity": "sha512-mU/iWbVWqLXX+gJJa4RBl5U4LdKYaiD9cmxW7bjyw8EEFAuMXFDGAQcq7hEvUZwoP5Em5s7sjimBPirSBJQ87g==",
|
||||
"dependencies": {
|
||||
"@squoosh/lib": "^0.4.0",
|
||||
"commander": "^7.2.0",
|
||||
@ -3234,9 +3241,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/codemirror": {
|
||||
"version": "5.60.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.5.tgz",
|
||||
"integrity": "sha512-TiECZmm8St5YxjFUp64LK0c8WU5bxMDt9YaAek1UqUb9swrSCoJhh92fWu1p3mTEqlHjhB5sY7OFBhWroJXZVg==",
|
||||
"version": "5.60.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.6.tgz",
|
||||
"integrity": "sha512-JIDPSvkYRlcv/2F0erqD+de2ni/Mz6FJMEGb0vwF6ByQOcHIKfiEfwrO4d6dSRwYeHyNUMpGjev0PyjX2M0XWw==",
|
||||
"dependencies": {
|
||||
"@types/tern": "*"
|
||||
}
|
||||
@ -3382,13 +3389,13 @@
|
||||
"integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.1.tgz",
|
||||
"integrity": "sha512-r4RZ2Jl9kcQN7K/dcOT+J7NAimbiis4sSM9spvWimsBvDegMhKLA5vri2jG19PmIPbDjPeWzfUPQ2hjEzA4Nmg==",
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.0.tgz",
|
||||
"integrity": "sha512-SVLafp0NXpoJY7ut6VFVUU9I+YeFsDzeQwtK0WZ+xbRN3mtxJ08je+6Oi2N89qDn087COdO0u3blKZNv9VetRQ==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "5.47.1",
|
||||
"@typescript-eslint/type-utils": "5.47.1",
|
||||
"@typescript-eslint/utils": "5.47.1",
|
||||
"@typescript-eslint/scope-manager": "5.48.0",
|
||||
"@typescript-eslint/type-utils": "5.48.0",
|
||||
"@typescript-eslint/utils": "5.48.0",
|
||||
"debug": "^4.3.4",
|
||||
"ignore": "^5.2.0",
|
||||
"natural-compare-lite": "^1.4.0",
|
||||
@ -3428,13 +3435,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.47.1.tgz",
|
||||
"integrity": "sha512-9Vb+KIv29r6GPu4EboWOnQM7T+UjpjXvjCPhNORlgm40a9Ia9bvaPJswvtae1gip2QEeVeGh6YquqAzEgoRAlw==",
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.0.tgz",
|
||||
"integrity": "sha512-1mxNA8qfgxX8kBvRDIHEzrRGrKHQfQlbW6iHyfHYS0Q4X1af+S6mkLNtgCOsGVl8+/LUPrqdHMssAemkrQ01qg==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "5.47.1",
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/typescript-estree": "5.47.1",
|
||||
"@typescript-eslint/scope-manager": "5.48.0",
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"@typescript-eslint/typescript-estree": "5.48.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@ -3454,12 +3461,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.1.tgz",
|
||||
"integrity": "sha512-9hsFDsgUwrdOoW1D97Ewog7DYSHaq4WKuNs0LHF9RiCmqB0Z+XRR4Pf7u7u9z/8CciHuJ6yxNws1XznI3ddjEw==",
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.0.tgz",
|
||||
"integrity": "sha512-0AA4LviDtVtZqlyUQnZMVHydDATpD9SAX/RC5qh6cBd3xmyWvmXYF+WT1oOmxkeMnWDlUVTwdODeucUnjz3gow==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/visitor-keys": "5.47.1"
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"@typescript-eslint/visitor-keys": "5.48.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@ -3470,12 +3477,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.47.1.tgz",
|
||||
"integrity": "sha512-/UKOeo8ee80A7/GJA427oIrBi/Gd4osk/3auBUg4Rn9EahFpevVV1mUK8hjyQD5lHPqX397x6CwOk5WGh1E/1w==",
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.0.tgz",
|
||||
"integrity": "sha512-vbtPO5sJyFjtHkGlGK4Sthmta0Bbls4Onv0bEqOGm7hP9h8UpRsHJwsrCiWtCUndTRNQO/qe6Ijz9rnT/DB+7g==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "5.47.1",
|
||||
"@typescript-eslint/utils": "5.47.1",
|
||||
"@typescript-eslint/typescript-estree": "5.48.0",
|
||||
"@typescript-eslint/utils": "5.48.0",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
@ -3496,9 +3503,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.1.tgz",
|
||||
"integrity": "sha512-CmALY9YWXEpwuu6377ybJBZdtSAnzXLSQcxLSqSQSbC7VfpMu/HLVdrnVJj7ycI138EHqocW02LPJErE35cE9A==",
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz",
|
||||
"integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw==",
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
@ -3508,12 +3515,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.1.tgz",
|
||||
"integrity": "sha512-4+ZhFSuISAvRi2xUszEj0xXbNTHceV9GbH9S8oAD2a/F9SW57aJNQVOCxG8GPfSWH/X4eOPdMEU2jYVuWKEpWA==",
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.0.tgz",
|
||||
"integrity": "sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/visitor-keys": "5.47.1",
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"@typescript-eslint/visitor-keys": "5.48.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
@ -3548,15 +3555,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.47.1.tgz",
|
||||
"integrity": "sha512-l90SdwqfmkuIVaREZ2ykEfCezepCLxzWMo5gVfcJsJCaT4jHT+QjgSkYhs5BMQmWqE9k3AtIfk4g211z/sTMVw==",
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.0.tgz",
|
||||
"integrity": "sha512-x2jrMcPaMfsHRRIkL+x96++xdzvrdBCnYRd5QiW5Wgo1OB4kDYPbC1XjWP/TNqlfK93K/lUL92erq5zPLgFScQ==",
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@typescript-eslint/scope-manager": "5.47.1",
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/typescript-estree": "5.47.1",
|
||||
"@typescript-eslint/scope-manager": "5.48.0",
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"@typescript-eslint/typescript-estree": "5.48.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"semver": "^7.3.7"
|
||||
@ -3587,11 +3594,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.1.tgz",
|
||||
"integrity": "sha512-rF3pmut2JCCjh6BLRhNKdYjULMb1brvoaiWDlHfLNVgmnZ0sBVJrs3SyaKE1XoDDnJuAx/hDQryHYmPUuNq0ig==",
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz",
|
||||
"integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -5181,11 +5188,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "8.30.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.30.0.tgz",
|
||||
"integrity": "sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ==",
|
||||
"version": "8.31.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz",
|
||||
"integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==",
|
||||
"dependencies": {
|
||||
"@eslint/eslintrc": "^1.4.0",
|
||||
"@eslint/eslintrc": "^1.4.1",
|
||||
"@humanwhocodes/config-array": "^0.11.8",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@nodelib/fs.walk": "^1.2.8",
|
||||
@ -5247,9 +5254,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-custom-elements": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-custom-elements/-/eslint-plugin-custom-elements-0.0.6.tgz",
|
||||
"integrity": "sha512-JwPHRSOUe7y8dpC5hg90ySHejsfnQ3yqprv0902VMZ3j8FRZDudj+yzxqqkRDhZTNFUxP3r+0TWuveZhLgJONg==",
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-custom-elements/-/eslint-plugin-custom-elements-0.0.7.tgz",
|
||||
"integrity": "sha512-s37mXujv/fAsPlvoLbO8jiZDM2gc/dFXIDf7wK52LMrsTsLpE5ITugQCwPM8lmcONjYdswS5kneX9LzJlt7aTA==",
|
||||
"peerDependencies": {
|
||||
"eslint": ">=4.19.0"
|
||||
}
|
||||
@ -9511,6 +9518,11 @@
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/turnstile-types": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/turnstile-types/-/turnstile-types-1.0.2.tgz",
|
||||
"integrity": "sha512-Y98xYhxf9xtYuu1QCrQm7og0o2zw2bGdsyUNXeWgPVXsHFkJIwTrRY6o3Oioa9PjFtoYM+oHe1n23V+oE27WUQ=="
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||
@ -9961,9 +9973,9 @@
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.0.tgz",
|
||||
"integrity": "sha512-auf7Gi6QwO7HW//GA9seGvTXVGWl1CM/ADWh1+RxtXr6XOxnT65ovDl9fTi4e0monEyJxCHqDpF6QnFDXmJE4g==",
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz",
|
||||
"integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==",
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
@ -11333,9 +11345,9 @@
|
||||
}
|
||||
},
|
||||
"@eslint/eslintrc": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.0.tgz",
|
||||
"integrity": "sha512-7yfvXy6MWLgWSFsLhz5yH3iQ52St8cdUY6FoGieKkRDVxuxmrNuUetIuu6cmjNWwniUHiWXjxCr5tTXDrbYS5A==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
|
||||
"integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==",
|
||||
"requires": {
|
||||
"ajv": "^6.12.4",
|
||||
"debug": "^4.3.2",
|
||||
@ -11396,9 +11408,14 @@
|
||||
"integrity": "sha512-viouXhegu/TjkvYQoiRZK3aax69dGXxgEjpvZW81wIJdxm5Fnvp3VVIP4VHKqX4SvFw6qpmkILkD4RJWAdrt7A=="
|
||||
},
|
||||
"@goauthentik/api": {
|
||||
"version": "2022.12.0-1672308901",
|
||||
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2022.12.0-1672308901.tgz",
|
||||
"integrity": "sha512-Wj3dzxiR83cOLyTEbr4T8MQZ2Vb7Oaq3ub6oWZXNv7zsk3sn7w7YN1/vXBU74KCbZk569zRIAAR+QLL+i2UNEw=="
|
||||
"version": "2022.12.1-1672612412",
|
||||
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2022.12.1-1672612412.tgz",
|
||||
"integrity": "sha512-fyAk76avWt0KzBfcrUPPopwRW2KWw/yo+MYva3ocWcU+4dbYlwEiT3LehToPMOOHoM81vRbyP9oVE5f472TyUQ=="
|
||||
},
|
||||
"@hcaptcha/types": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@hcaptcha/types/-/types-1.0.3.tgz",
|
||||
"integrity": "sha512-1mbU6eSGawRrqeahRrOzZo/SVLI6oZ5/azuBpSyVrRRR96CnS3fOVDWfzxpngfxKD0/I9Rwu6c/3ITqD8rXeTQ=="
|
||||
},
|
||||
"@humanwhocodes/config-array": {
|
||||
"version": "0.11.8",
|
||||
@ -12217,9 +12234,9 @@
|
||||
}
|
||||
},
|
||||
"@squoosh/cli": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@squoosh/cli/-/cli-0.7.2.tgz",
|
||||
"integrity": "sha512-uMnUWMx4S8UApO/EfPyRyvUmw+0jI9wwAfdHfGjvVg4DAIvEgsA+VWK2KOBnJiChvVd768K27g09ESzptyX93w==",
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@squoosh/cli/-/cli-0.7.3.tgz",
|
||||
"integrity": "sha512-mU/iWbVWqLXX+gJJa4RBl5U4LdKYaiD9cmxW7bjyw8EEFAuMXFDGAQcq7hEvUZwoP5Em5s7sjimBPirSBJQ87g==",
|
||||
"requires": {
|
||||
"@squoosh/lib": "^0.4.0",
|
||||
"commander": "^7.2.0",
|
||||
@ -12368,9 +12385,9 @@
|
||||
}
|
||||
},
|
||||
"@types/codemirror": {
|
||||
"version": "5.60.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.5.tgz",
|
||||
"integrity": "sha512-TiECZmm8St5YxjFUp64LK0c8WU5bxMDt9YaAek1UqUb9swrSCoJhh92fWu1p3mTEqlHjhB5sY7OFBhWroJXZVg==",
|
||||
"version": "5.60.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.6.tgz",
|
||||
"integrity": "sha512-JIDPSvkYRlcv/2F0erqD+de2ni/Mz6FJMEGb0vwF6ByQOcHIKfiEfwrO4d6dSRwYeHyNUMpGjev0PyjX2M0XWw==",
|
||||
"requires": {
|
||||
"@types/tern": "*"
|
||||
}
|
||||
@ -12515,13 +12532,13 @@
|
||||
"integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.1.tgz",
|
||||
"integrity": "sha512-r4RZ2Jl9kcQN7K/dcOT+J7NAimbiis4sSM9spvWimsBvDegMhKLA5vri2jG19PmIPbDjPeWzfUPQ2hjEzA4Nmg==",
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.0.tgz",
|
||||
"integrity": "sha512-SVLafp0NXpoJY7ut6VFVUU9I+YeFsDzeQwtK0WZ+xbRN3mtxJ08je+6Oi2N89qDn087COdO0u3blKZNv9VetRQ==",
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "5.47.1",
|
||||
"@typescript-eslint/type-utils": "5.47.1",
|
||||
"@typescript-eslint/utils": "5.47.1",
|
||||
"@typescript-eslint/scope-manager": "5.48.0",
|
||||
"@typescript-eslint/type-utils": "5.48.0",
|
||||
"@typescript-eslint/utils": "5.48.0",
|
||||
"debug": "^4.3.4",
|
||||
"ignore": "^5.2.0",
|
||||
"natural-compare-lite": "^1.4.0",
|
||||
@ -12541,48 +12558,48 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.47.1.tgz",
|
||||
"integrity": "sha512-9Vb+KIv29r6GPu4EboWOnQM7T+UjpjXvjCPhNORlgm40a9Ia9bvaPJswvtae1gip2QEeVeGh6YquqAzEgoRAlw==",
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.0.tgz",
|
||||
"integrity": "sha512-1mxNA8qfgxX8kBvRDIHEzrRGrKHQfQlbW6iHyfHYS0Q4X1af+S6mkLNtgCOsGVl8+/LUPrqdHMssAemkrQ01qg==",
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "5.47.1",
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/typescript-estree": "5.47.1",
|
||||
"@typescript-eslint/scope-manager": "5.48.0",
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"@typescript-eslint/typescript-estree": "5.48.0",
|
||||
"debug": "^4.3.4"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.1.tgz",
|
||||
"integrity": "sha512-9hsFDsgUwrdOoW1D97Ewog7DYSHaq4WKuNs0LHF9RiCmqB0Z+XRR4Pf7u7u9z/8CciHuJ6yxNws1XznI3ddjEw==",
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.0.tgz",
|
||||
"integrity": "sha512-0AA4LviDtVtZqlyUQnZMVHydDATpD9SAX/RC5qh6cBd3xmyWvmXYF+WT1oOmxkeMnWDlUVTwdODeucUnjz3gow==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/visitor-keys": "5.47.1"
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"@typescript-eslint/visitor-keys": "5.48.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/type-utils": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.47.1.tgz",
|
||||
"integrity": "sha512-/UKOeo8ee80A7/GJA427oIrBi/Gd4osk/3auBUg4Rn9EahFpevVV1mUK8hjyQD5lHPqX397x6CwOk5WGh1E/1w==",
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.0.tgz",
|
||||
"integrity": "sha512-vbtPO5sJyFjtHkGlGK4Sthmta0Bbls4Onv0bEqOGm7hP9h8UpRsHJwsrCiWtCUndTRNQO/qe6Ijz9rnT/DB+7g==",
|
||||
"requires": {
|
||||
"@typescript-eslint/typescript-estree": "5.47.1",
|
||||
"@typescript-eslint/utils": "5.47.1",
|
||||
"@typescript-eslint/typescript-estree": "5.48.0",
|
||||
"@typescript-eslint/utils": "5.48.0",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.1.tgz",
|
||||
"integrity": "sha512-CmALY9YWXEpwuu6377ybJBZdtSAnzXLSQcxLSqSQSbC7VfpMu/HLVdrnVJj7ycI138EHqocW02LPJErE35cE9A=="
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz",
|
||||
"integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw=="
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.1.tgz",
|
||||
"integrity": "sha512-4+ZhFSuISAvRi2xUszEj0xXbNTHceV9GbH9S8oAD2a/F9SW57aJNQVOCxG8GPfSWH/X4eOPdMEU2jYVuWKEpWA==",
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.0.tgz",
|
||||
"integrity": "sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/visitor-keys": "5.47.1",
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"@typescript-eslint/visitor-keys": "5.48.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
@ -12601,15 +12618,15 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.47.1.tgz",
|
||||
"integrity": "sha512-l90SdwqfmkuIVaREZ2ykEfCezepCLxzWMo5gVfcJsJCaT4jHT+QjgSkYhs5BMQmWqE9k3AtIfk4g211z/sTMVw==",
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.0.tgz",
|
||||
"integrity": "sha512-x2jrMcPaMfsHRRIkL+x96++xdzvrdBCnYRd5QiW5Wgo1OB4kDYPbC1XjWP/TNqlfK93K/lUL92erq5zPLgFScQ==",
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@typescript-eslint/scope-manager": "5.47.1",
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/typescript-estree": "5.47.1",
|
||||
"@typescript-eslint/scope-manager": "5.48.0",
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"@typescript-eslint/typescript-estree": "5.48.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"semver": "^7.3.7"
|
||||
@ -12626,11 +12643,11 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.1.tgz",
|
||||
"integrity": "sha512-rF3pmut2JCCjh6BLRhNKdYjULMb1brvoaiWDlHfLNVgmnZ0sBVJrs3SyaKE1XoDDnJuAx/hDQryHYmPUuNq0ig==",
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz",
|
||||
"integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -13796,11 +13813,11 @@
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
},
|
||||
"eslint": {
|
||||
"version": "8.30.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.30.0.tgz",
|
||||
"integrity": "sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ==",
|
||||
"version": "8.31.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz",
|
||||
"integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==",
|
||||
"requires": {
|
||||
"@eslint/eslintrc": "^1.4.0",
|
||||
"@eslint/eslintrc": "^1.4.1",
|
||||
"@humanwhocodes/config-array": "^0.11.8",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@nodelib/fs.walk": "^1.2.8",
|
||||
@ -13976,9 +13993,9 @@
|
||||
"requires": {}
|
||||
},
|
||||
"eslint-plugin-custom-elements": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-custom-elements/-/eslint-plugin-custom-elements-0.0.6.tgz",
|
||||
"integrity": "sha512-JwPHRSOUe7y8dpC5hg90ySHejsfnQ3yqprv0902VMZ3j8FRZDudj+yzxqqkRDhZTNFUxP3r+0TWuveZhLgJONg==",
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-custom-elements/-/eslint-plugin-custom-elements-0.0.7.tgz",
|
||||
"integrity": "sha512-s37mXujv/fAsPlvoLbO8jiZDM2gc/dFXIDf7wK52LMrsTsLpE5ITugQCwPM8lmcONjYdswS5kneX9LzJlt7aTA==",
|
||||
"requires": {}
|
||||
},
|
||||
"eslint-plugin-lit": {
|
||||
@ -17025,6 +17042,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"turnstile-types": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/turnstile-types/-/turnstile-types-1.0.2.tgz",
|
||||
"integrity": "sha512-Y98xYhxf9xtYuu1QCrQm7og0o2zw2bGdsyUNXeWgPVXsHFkJIwTrRY6o3Oioa9PjFtoYM+oHe1n23V+oE27WUQ=="
|
||||
},
|
||||
"type-check": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||
@ -17374,9 +17396,9 @@
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"yaml": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.0.tgz",
|
||||
"integrity": "sha512-auf7Gi6QwO7HW//GA9seGvTXVGWl1CM/ADWh1+RxtXr6XOxnT65ovDl9fTi4e0monEyJxCHqDpF6QnFDXmJE4g=="
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz",
|
||||
"integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw=="
|
||||
},
|
||||
"yargs": {
|
||||
"version": "15.4.1",
|
||||
|
@ -12,6 +12,7 @@
|
||||
"lit-analyse": "lit-analyzer src",
|
||||
"prettier-check": "prettier --check .",
|
||||
"prettier": "prettier --write .",
|
||||
"tsc": "lingui compile && tsc --noEmit -p .",
|
||||
"background-image": "npx @squoosh/cli -d src/assets/images --resize '{\"enabled\":true,\"width\":2560,\"method\":\"lanczos3\",\"fitMethod\":\"contain\",\"premultiply\":true,\"linearRGB\":true}' --mozjpeg '{\"quality\":75,\"baseline\":false,\"arithmetic\":false,\"progressive\":true,\"optimize_coding\":true,\"smoothing\":0,\"color_space\":3,\"quant_table\":3,\"trellis_multipass\":false,\"trellis_opt_zero\":false,\"trellis_opt_table\":false,\"trellis_loops\":1,\"auto_subsample\":true,\"chroma_subsample\":2,\"separate_chroma_quality\":false,\"chroma_quality\":75}' src/assets/images/flow_background.jpg"
|
||||
},
|
||||
"lingui": {
|
||||
@ -64,7 +65,8 @@
|
||||
"@codemirror/legacy-modes": "^6.3.1",
|
||||
"@formatjs/intl-listformat": "^7.1.7",
|
||||
"@fortawesome/fontawesome-free": "^6.2.1",
|
||||
"@goauthentik/api": "^2022.12.0-1672308901",
|
||||
"@goauthentik/api": "^2022.12.1-1672612412",
|
||||
"@hcaptcha/types": "^1.0.3",
|
||||
"@jackfranklin/rollup-plugin-markdown": "^0.4.0",
|
||||
"@lingui/cli": "^3.15.0",
|
||||
"@lingui/core": "^3.15.0",
|
||||
@ -80,13 +82,13 @@
|
||||
"@rollup/plugin-typescript": "^10.0.1",
|
||||
"@sentry/browser": "^7.28.1",
|
||||
"@sentry/tracing": "^7.28.1",
|
||||
"@squoosh/cli": "^0.7.2",
|
||||
"@squoosh/cli": "^0.7.3",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.0.0",
|
||||
"@types/chart.js": "^2.9.37",
|
||||
"@types/codemirror": "5.60.5",
|
||||
"@types/codemirror": "5.60.6",
|
||||
"@types/grecaptcha": "^3.0.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.1",
|
||||
"@typescript-eslint/parser": "^5.47.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.48.0",
|
||||
"@typescript-eslint/parser": "^5.48.0",
|
||||
"@webcomponents/webcomponentsjs": "^2.7.0",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
"babel-plugin-tsconfig-paths": "^1.0.3",
|
||||
@ -96,9 +98,9 @@
|
||||
"codemirror": "^6.0.1",
|
||||
"construct-style-sheets-polyfill": "^3.1.0",
|
||||
"country-flag-icons": "^1.5.5",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint": "^8.31.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-custom-elements": "0.0.6",
|
||||
"eslint-plugin-custom-elements": "0.0.7",
|
||||
"eslint-plugin-lit": "^1.7.2",
|
||||
"fuse.js": "^6.6.2",
|
||||
"lit": "^2.5.0",
|
||||
@ -114,8 +116,9 @@
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"ts-lit-plugin": "^1.2.1",
|
||||
"tslib": "^2.4.1",
|
||||
"turnstile-types": "^1.0.2",
|
||||
"typescript": "^4.9.4",
|
||||
"webcomponent-qr-code": "^1.1.0",
|
||||
"yaml": "^2.2.0"
|
||||
"yaml": "^2.2.1"
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import { AdminApi, LoginMetrics } from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-charts-admin-login-authorization")
|
||||
export class AdminLoginAuthorizeChart extends AKChart<LoginMetrics> {
|
||||
apiRequest(): Promise<LoginMetrics> {
|
||||
async apiRequest(): Promise<LoginMetrics> {
|
||||
return new AdminApi(DEFAULT_CONFIG).adminMetricsRetrieve();
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import { Form } from "@goauthentik/elements/forms/Form";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
@ -34,14 +34,13 @@ export class ApplicationCheckAccessForm extends Form<{ forUser: number }> {
|
||||
return t`Successfully sent test-request.`;
|
||||
}
|
||||
|
||||
send = (data: { forUser: number }): Promise<PolicyTestResult> => {
|
||||
send = async (data: { forUser: number }): Promise<PolicyTestResult> => {
|
||||
this.request = data.forUser;
|
||||
return new CoreApi(DEFAULT_CONFIG)
|
||||
.coreApplicationsCheckAccessRetrieve({
|
||||
slug: this.application?.slug,
|
||||
forUser: data.forUser,
|
||||
})
|
||||
.then((result) => (this.result = result));
|
||||
const result = await new CoreApi(DEFAULT_CONFIG).coreApplicationsCheckAccessRetrieve({
|
||||
slug: this.application?.slug,
|
||||
forUser: data.forUser,
|
||||
});
|
||||
return (this.result = result);
|
||||
};
|
||||
|
||||
resetForm(): void {
|
||||
|
@ -1,12 +1,13 @@
|
||||
import "@goauthentik/admin/providers/ProviderWizard";
|
||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
||||
import { first, groupBy } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/ModalForm";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/ProxyForm";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
@ -153,20 +154,23 @@ export class ApplicationForm extends ModelForm<Application, string> {
|
||||
?required=${true}
|
||||
name="policyEngineMode"
|
||||
>
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value=${PolicyEngineMode.Any}
|
||||
?selected=${this.instance?.policyEngineMode === PolicyEngineMode.Any}
|
||||
>
|
||||
${t`ANY, any policy must match to grant access.`}
|
||||
</option>
|
||||
<option
|
||||
value=${PolicyEngineMode.All}
|
||||
?selected=${this.instance?.policyEngineMode === PolicyEngineMode.All}
|
||||
>
|
||||
${t`ALL, all policies must match to grant access.`}
|
||||
</option>
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: "ANY",
|
||||
value: PolicyEngineMode.Any,
|
||||
default: true,
|
||||
description: html`${t`Any policy must match to grant access`}`,
|
||||
},
|
||||
{
|
||||
label: "ALL",
|
||||
value: PolicyEngineMode.All,
|
||||
description: html`${t`All policies must match to grant access`}`,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.policyEngineMode}
|
||||
>
|
||||
</ak-radio>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-group .expanded=${true}>
|
||||
<span slot="header"> ${t`UI settings`} </span>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import { KeyUnknown } from "@goauthentik/elements/forms/Form";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
import { WizardFormPage } from "@goauthentik/elements/wizard/WizardFormPage";
|
||||
import "@goauthentik/elements/wizard/WizardFormPage";
|
||||
|
||||
|
@ -2,10 +2,10 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { docLink } from "@goauthentik/common/global";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/CodeMirror";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
import YAML from "yaml";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
@ -48,29 +49,6 @@ export class RuleForm extends ModelForm<NotificationRule, string> {
|
||||
}
|
||||
};
|
||||
|
||||
renderSeverity(): TemplateResult {
|
||||
return html`
|
||||
<option
|
||||
value=${SeverityEnum.Alert}
|
||||
?selected=${this.instance?.severity === SeverityEnum.Alert}
|
||||
>
|
||||
${t`Alert`}
|
||||
</option>
|
||||
<option
|
||||
value=${SeverityEnum.Warning}
|
||||
?selected=${this.instance?.severity === SeverityEnum.Warning}
|
||||
>
|
||||
${t`Warning`}
|
||||
</option>
|
||||
<option
|
||||
value=${SeverityEnum.Notice}
|
||||
?selected=${this.instance?.severity === SeverityEnum.Notice}
|
||||
>
|
||||
${t`Notice`}
|
||||
</option>
|
||||
`;
|
||||
}
|
||||
|
||||
renderForm(): TemplateResult {
|
||||
return html`<form class="pf-c-form pf-m-horizontal">
|
||||
<ak-form-element-horizontal label=${t`Name`} ?required=${true} name="name">
|
||||
@ -107,10 +85,12 @@ export class RuleForm extends ModelForm<NotificationRule, string> {
|
||||
</ak-search-select>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${t`Transports`} ?required=${true} name="transports">
|
||||
<select name="users" class="pf-c-form-control" multiple>
|
||||
<select class="pf-c-form-control" multiple>
|
||||
${until(
|
||||
new EventsApi(DEFAULT_CONFIG)
|
||||
.eventsTransportsList({})
|
||||
.eventsTransportsList({
|
||||
ordering: "name",
|
||||
})
|
||||
.then((transports) => {
|
||||
return transports.results.map((transport) => {
|
||||
const selected = Array.from(
|
||||
@ -137,9 +117,25 @@ export class RuleForm extends ModelForm<NotificationRule, string> {
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${t`Severity`} ?required=${true} name="severity">
|
||||
<select class="pf-c-form-control">
|
||||
${this.renderSeverity()}
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: "Alert",
|
||||
value: SeverityEnum.Alert,
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
label: t`Warning`,
|
||||
value: SeverityEnum.Warning,
|
||||
},
|
||||
{
|
||||
label: t`Notice`,
|
||||
value: SeverityEnum.Notice,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.severity}
|
||||
>
|
||||
</ak-radio>
|
||||
</ak-form-element-horizontal>
|
||||
</form>`;
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
|
@ -2,8 +2,10 @@ import { DesignationToLabel, LayoutToLabel } from "@goauthentik/admin/flows/util
|
||||
import { AuthenticationEnum } from "@goauthentik/api/dist/models/AuthenticationEnum";
|
||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
@ -74,140 +76,6 @@ export class FlowForm extends ModelForm<Flow, string> {
|
||||
return flow;
|
||||
};
|
||||
|
||||
renderDesignations(): TemplateResult {
|
||||
return html`
|
||||
<option
|
||||
value=${FlowDesignationEnum.Authentication}
|
||||
?selected=${this.instance?.designation === FlowDesignationEnum.Authentication}
|
||||
>
|
||||
${DesignationToLabel(FlowDesignationEnum.Authentication)}
|
||||
</option>
|
||||
<option
|
||||
value=${FlowDesignationEnum.Authorization}
|
||||
?selected=${this.instance?.designation === FlowDesignationEnum.Authorization}
|
||||
>
|
||||
${DesignationToLabel(FlowDesignationEnum.Authorization)}
|
||||
</option>
|
||||
<option
|
||||
value=${FlowDesignationEnum.Enrollment}
|
||||
?selected=${this.instance?.designation === FlowDesignationEnum.Enrollment}
|
||||
>
|
||||
${DesignationToLabel(FlowDesignationEnum.Enrollment)}
|
||||
</option>
|
||||
<option
|
||||
value=${FlowDesignationEnum.Invalidation}
|
||||
?selected=${this.instance?.designation === FlowDesignationEnum.Invalidation}
|
||||
>
|
||||
${DesignationToLabel(FlowDesignationEnum.Invalidation)}
|
||||
</option>
|
||||
<option
|
||||
value=${FlowDesignationEnum.Recovery}
|
||||
?selected=${this.instance?.designation === FlowDesignationEnum.Recovery}
|
||||
>
|
||||
${DesignationToLabel(FlowDesignationEnum.Recovery)}
|
||||
</option>
|
||||
<option
|
||||
value=${FlowDesignationEnum.StageConfiguration}
|
||||
?selected=${this.instance?.designation === FlowDesignationEnum.StageConfiguration}
|
||||
>
|
||||
${DesignationToLabel(FlowDesignationEnum.StageConfiguration)}
|
||||
</option>
|
||||
<option
|
||||
value=${FlowDesignationEnum.Unenrollment}
|
||||
?selected=${this.instance?.designation === FlowDesignationEnum.Unenrollment}
|
||||
>
|
||||
${DesignationToLabel(FlowDesignationEnum.Unenrollment)}
|
||||
</option>
|
||||
`;
|
||||
}
|
||||
|
||||
renderDeniedAction(): TemplateResult {
|
||||
return html` <option
|
||||
value=${DeniedActionEnum.MessageContinue}
|
||||
?selected=${this.instance?.deniedAction === DeniedActionEnum.MessageContinue}
|
||||
>
|
||||
${t`MESSAGE_CONTINUE will follow the ?next parameter if set, otherwise show a message.`}
|
||||
</option>
|
||||
<option
|
||||
value=${DeniedActionEnum.Continue}
|
||||
?selected=${this.instance?.deniedAction === DeniedActionEnum.Continue}
|
||||
>
|
||||
${t`CONTINUE will either follow the ?next parameter or redirect to the default interface.`}
|
||||
</option>
|
||||
<option
|
||||
value=${DeniedActionEnum.Message}
|
||||
?selected=${this.instance?.deniedAction === DeniedActionEnum.Message}
|
||||
>
|
||||
${t`MESSAGE will notify the user the flow isn't applicable.`}
|
||||
</option>`;
|
||||
}
|
||||
|
||||
renderAuthentication(): TemplateResult {
|
||||
return html`
|
||||
<option
|
||||
value=${AuthenticationEnum.None}
|
||||
?selected=${this.instance?.authentication === AuthenticationEnum.None}
|
||||
>
|
||||
${t`No requirement`}
|
||||
</option>
|
||||
<option
|
||||
value=${AuthenticationEnum.RequireAuthenticated}
|
||||
?selected=${this.instance?.authentication ===
|
||||
AuthenticationEnum.RequireAuthenticated}
|
||||
>
|
||||
${t`Require authentication`}
|
||||
</option>
|
||||
<option
|
||||
value=${AuthenticationEnum.RequireUnauthenticated}
|
||||
?selected=${this.instance?.authentication ===
|
||||
AuthenticationEnum.RequireUnauthenticated}
|
||||
>
|
||||
${t`Require no authentication.`}
|
||||
</option>
|
||||
<option
|
||||
value=${AuthenticationEnum.RequireSuperuser}
|
||||
?selected=${this.instance?.authentication === AuthenticationEnum.RequireSuperuser}
|
||||
>
|
||||
${t`Require superuser.`}
|
||||
</option>
|
||||
`;
|
||||
}
|
||||
|
||||
renderLayout(): TemplateResult {
|
||||
return html`
|
||||
<option
|
||||
value=${LayoutEnum.Stacked}
|
||||
?selected=${this.instance?.layout === LayoutEnum.Stacked}
|
||||
>
|
||||
${LayoutToLabel(LayoutEnum.Stacked)}
|
||||
</option>
|
||||
<option
|
||||
value=${LayoutEnum.ContentLeft}
|
||||
?selected=${this.instance?.layout === LayoutEnum.ContentLeft}
|
||||
>
|
||||
${LayoutToLabel(LayoutEnum.ContentLeft)}
|
||||
</option>
|
||||
<option
|
||||
value=${LayoutEnum.ContentRight}
|
||||
?selected=${this.instance?.layout === LayoutEnum.ContentRight}
|
||||
>
|
||||
${LayoutToLabel(LayoutEnum.ContentRight)}
|
||||
</option>
|
||||
<option
|
||||
value=${LayoutEnum.SidebarLeft}
|
||||
?selected=${this.instance?.layout === LayoutEnum.SidebarLeft}
|
||||
>
|
||||
${LayoutToLabel(LayoutEnum.SidebarLeft)}
|
||||
</option>
|
||||
<option
|
||||
value=${LayoutEnum.SidebarRight}
|
||||
?selected=${this.instance?.layout === LayoutEnum.SidebarRight}
|
||||
>
|
||||
${LayoutToLabel(LayoutEnum.SidebarRight)}
|
||||
</option>
|
||||
`;
|
||||
}
|
||||
|
||||
renderForm(): TemplateResult {
|
||||
return html`<form class="pf-c-form pf-m-horizontal">
|
||||
<ak-form-element-horizontal label=${t`Name`} ?required=${true} name="name">
|
||||
@ -236,38 +104,6 @@ export class FlowForm extends ModelForm<Flow, string> {
|
||||
/>
|
||||
<p class="pf-c-form__helper-text">${t`Visible in the URL.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Policy engine mode`}
|
||||
?required=${true}
|
||||
name="policyEngineMode"
|
||||
>
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value=${PolicyEngineMode.Any}
|
||||
?selected=${this.instance?.policyEngineMode === PolicyEngineMode.Any}
|
||||
>
|
||||
${t`ANY, any policy must match to grant access.`}
|
||||
</option>
|
||||
<option
|
||||
value=${PolicyEngineMode.All}
|
||||
?selected=${this.instance?.policyEngineMode === PolicyEngineMode.All}
|
||||
>
|
||||
${t`ALL, all policies must match to grant access.`}
|
||||
</option>
|
||||
</select>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Authentication`}
|
||||
?required=${true}
|
||||
name="authentication"
|
||||
>
|
||||
<select class="pf-c-form-control">
|
||||
${this.renderAuthentication()}
|
||||
</select>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`Required authentication level for this flow.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Designation`}
|
||||
?required=${true}
|
||||
@ -277,99 +113,264 @@ export class FlowForm extends ModelForm<Flow, string> {
|
||||
<option value="" ?selected=${this.instance?.designation === undefined}>
|
||||
---------
|
||||
</option>
|
||||
${this.renderDesignations()}
|
||||
<option
|
||||
value=${FlowDesignationEnum.Authentication}
|
||||
?selected=${this.instance?.designation ===
|
||||
FlowDesignationEnum.Authentication}
|
||||
>
|
||||
${DesignationToLabel(FlowDesignationEnum.Authentication)}
|
||||
</option>
|
||||
<option
|
||||
value=${FlowDesignationEnum.Authorization}
|
||||
?selected=${this.instance?.designation ===
|
||||
FlowDesignationEnum.Authorization}
|
||||
>
|
||||
${DesignationToLabel(FlowDesignationEnum.Authorization)}
|
||||
</option>
|
||||
<option
|
||||
value=${FlowDesignationEnum.Enrollment}
|
||||
?selected=${this.instance?.designation === FlowDesignationEnum.Enrollment}
|
||||
>
|
||||
${DesignationToLabel(FlowDesignationEnum.Enrollment)}
|
||||
</option>
|
||||
<option
|
||||
value=${FlowDesignationEnum.Invalidation}
|
||||
?selected=${this.instance?.designation === FlowDesignationEnum.Invalidation}
|
||||
>
|
||||
${DesignationToLabel(FlowDesignationEnum.Invalidation)}
|
||||
</option>
|
||||
<option
|
||||
value=${FlowDesignationEnum.Recovery}
|
||||
?selected=${this.instance?.designation === FlowDesignationEnum.Recovery}
|
||||
>
|
||||
${DesignationToLabel(FlowDesignationEnum.Recovery)}
|
||||
</option>
|
||||
<option
|
||||
value=${FlowDesignationEnum.StageConfiguration}
|
||||
?selected=${this.instance?.designation ===
|
||||
FlowDesignationEnum.StageConfiguration}
|
||||
>
|
||||
${DesignationToLabel(FlowDesignationEnum.StageConfiguration)}
|
||||
</option>
|
||||
<option
|
||||
value=${FlowDesignationEnum.Unenrollment}
|
||||
?selected=${this.instance?.designation === FlowDesignationEnum.Unenrollment}
|
||||
>
|
||||
${DesignationToLabel(FlowDesignationEnum.Unenrollment)}
|
||||
</option>
|
||||
</select>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`Decides what this Flow is used for. For example, the Authentication flow is redirect to when an un-authenticated user visits authentik.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Denied action`}
|
||||
label=${t`Authentication`}
|
||||
?required=${true}
|
||||
name="deniedAction"
|
||||
name="authentication"
|
||||
>
|
||||
<select class="pf-c-form-control">
|
||||
${this.renderDeniedAction()}
|
||||
<option
|
||||
value=${AuthenticationEnum.None}
|
||||
?selected=${this.instance?.authentication === AuthenticationEnum.None}
|
||||
>
|
||||
${t`No requirement`}
|
||||
</option>
|
||||
<option
|
||||
value=${AuthenticationEnum.RequireAuthenticated}
|
||||
?selected=${this.instance?.authentication ===
|
||||
AuthenticationEnum.RequireAuthenticated}
|
||||
>
|
||||
${t`Require authentication`}
|
||||
</option>
|
||||
<option
|
||||
value=${AuthenticationEnum.RequireUnauthenticated}
|
||||
?selected=${this.instance?.authentication ===
|
||||
AuthenticationEnum.RequireUnauthenticated}
|
||||
>
|
||||
${t`Require no authentication.`}
|
||||
</option>
|
||||
<option
|
||||
value=${AuthenticationEnum.RequireSuperuser}
|
||||
?selected=${this.instance?.authentication ===
|
||||
AuthenticationEnum.RequireSuperuser}
|
||||
>
|
||||
${t`Require superuser.`}
|
||||
</option>
|
||||
</select>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`Decides the response when a policy denies access to this flow for a user.`}
|
||||
${t`Required authentication level for this flow.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${t`Layout`} ?required=${true} name="layout">
|
||||
<select class="pf-c-form-control">
|
||||
${this.renderLayout()}
|
||||
</select>
|
||||
</ak-form-element-horizontal>
|
||||
${until(
|
||||
config().then((c) => {
|
||||
if (c.capabilities.includes(CapabilitiesEnum.SaveMedia)) {
|
||||
return html`<ak-form-element-horizontal
|
||||
<ak-form-group>
|
||||
<span slot="header"> ${t`Behavior settings`} </span>
|
||||
<div slot="body" class="pf-c-form">
|
||||
<ak-form-element-horizontal name="compatibilityMode">
|
||||
<div class="pf-c-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="pf-c-check__input"
|
||||
?checked=${first(this.instance?.compatibilityMode, false)}
|
||||
/>
|
||||
<label class="pf-c-check__label"> ${t`Compatibility mode`} </label>
|
||||
</div>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`Increases compatibility with password managers and mobile devices.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Denied action`}
|
||||
?required=${true}
|
||||
name="deniedAction"
|
||||
>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: "MESSAGE_CONTINUE",
|
||||
value: DeniedActionEnum.MessageContinue,
|
||||
default: true,
|
||||
description: html`${t`Will follow the ?next parameter if set, otherwise show a message`}`,
|
||||
},
|
||||
{
|
||||
label: "CONTINUE",
|
||||
value: DeniedActionEnum.Continue,
|
||||
description: html`${t`Will either follow the ?next parameter or redirect to the default interface`}`,
|
||||
},
|
||||
{
|
||||
label: "MESSAGE",
|
||||
value: DeniedActionEnum.Message,
|
||||
description: html`${t`Will notify the user the flow isn't applicable`}`,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.deniedAction}
|
||||
>
|
||||
</ak-radio>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`Decides the response when a policy denies access to this flow for a user.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Policy engine mode`}
|
||||
?required=${true}
|
||||
name="policyEngineMode"
|
||||
>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: "ANY",
|
||||
value: PolicyEngineMode.Any,
|
||||
default: true,
|
||||
description: html`${t`Any policy must match to grant access`}`,
|
||||
},
|
||||
{
|
||||
label: "ALL",
|
||||
value: PolicyEngineMode.All,
|
||||
description: html`${t`All policies must match to grant access`}`,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.policyEngineMode}
|
||||
>
|
||||
</ak-radio>
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
<ak-form-group>
|
||||
<span slot="header"> ${t`Appearance settings`} </span>
|
||||
<div slot="body" class="pf-c-form">
|
||||
<ak-form-element-horizontal label=${t`Layout`} ?required=${true} name="layout">
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value=${LayoutEnum.Stacked}
|
||||
?selected=${this.instance?.layout === LayoutEnum.Stacked}
|
||||
>
|
||||
${LayoutToLabel(LayoutEnum.Stacked)}
|
||||
</option>
|
||||
<option
|
||||
value=${LayoutEnum.ContentLeft}
|
||||
?selected=${this.instance?.layout === LayoutEnum.ContentLeft}
|
||||
>
|
||||
${LayoutToLabel(LayoutEnum.ContentLeft)}
|
||||
</option>
|
||||
<option
|
||||
value=${LayoutEnum.ContentRight}
|
||||
?selected=${this.instance?.layout === LayoutEnum.ContentRight}
|
||||
>
|
||||
${LayoutToLabel(LayoutEnum.ContentRight)}
|
||||
</option>
|
||||
<option
|
||||
value=${LayoutEnum.SidebarLeft}
|
||||
?selected=${this.instance?.layout === LayoutEnum.SidebarLeft}
|
||||
>
|
||||
${LayoutToLabel(LayoutEnum.SidebarLeft)}
|
||||
</option>
|
||||
<option
|
||||
value=${LayoutEnum.SidebarRight}
|
||||
?selected=${this.instance?.layout === LayoutEnum.SidebarRight}
|
||||
>
|
||||
${LayoutToLabel(LayoutEnum.SidebarRight)}
|
||||
</option>
|
||||
</select>
|
||||
</ak-form-element-horizontal>
|
||||
${until(
|
||||
config().then((c) => {
|
||||
if (c.capabilities.includes(CapabilitiesEnum.SaveMedia)) {
|
||||
return html`<ak-form-element-horizontal
|
||||
label=${t`Background`}
|
||||
name="background"
|
||||
>
|
||||
<input type="file" value="" class="pf-c-form-control" />
|
||||
${this.instance?.background
|
||||
? html`
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`Currently set to:`}
|
||||
${this.instance?.background}
|
||||
</p>
|
||||
`
|
||||
: html``}
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`Background shown during execution.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
${this.instance?.background
|
||||
? html`
|
||||
<ak-form-element-horizontal>
|
||||
<div class="pf-c-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="pf-c-check__input"
|
||||
@change=${(ev: Event) => {
|
||||
const target =
|
||||
ev.target as HTMLInputElement;
|
||||
this.clearBackground = target.checked;
|
||||
}}
|
||||
/>
|
||||
<label class="pf-c-check__label">
|
||||
${t`Clear background image`}
|
||||
</label>
|
||||
</div>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`Delete currently set background image.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
`
|
||||
: html``}`;
|
||||
}
|
||||
return html`<ak-form-element-horizontal
|
||||
label=${t`Background`}
|
||||
name="background"
|
||||
>
|
||||
<input type="file" value="" class="pf-c-form-control" />
|
||||
${this.instance?.background
|
||||
? html`
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`Currently set to:`} ${this.instance?.background}
|
||||
</p>
|
||||
`
|
||||
: html``}
|
||||
<input
|
||||
type="text"
|
||||
value="${first(this.instance?.background, "")}"
|
||||
class="pf-c-form-control"
|
||||
/>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`Background shown during execution.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
${this.instance?.background
|
||||
? html`
|
||||
<ak-form-element-horizontal>
|
||||
<div class="pf-c-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="pf-c-check__input"
|
||||
@change=${(ev: Event) => {
|
||||
const target = ev.target as HTMLInputElement;
|
||||
this.clearBackground = target.checked;
|
||||
}}
|
||||
/>
|
||||
<label class="pf-c-check__label">
|
||||
${t`Clear background image`}
|
||||
</label>
|
||||
</div>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`Delete currently set background image.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
`
|
||||
: html``}`;
|
||||
}
|
||||
return html`<ak-form-element-horizontal
|
||||
label=${t`Background`}
|
||||
name="background"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
value="${first(this.instance?.background, "")}"
|
||||
class="pf-c-form-control"
|
||||
/>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`Background shown during execution.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>`;
|
||||
}),
|
||||
)}
|
||||
<ak-form-element-horizontal name="compatibilityMode">
|
||||
<div class="pf-c-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="pf-c-check__input"
|
||||
?checked=${first(this.instance?.compatibilityMode, false)}
|
||||
/>
|
||||
<label class="pf-c-check__label"> ${t`Compatibility mode`} </label>
|
||||
</ak-form-element-horizontal>`;
|
||||
}),
|
||||
)}
|
||||
</div>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`Enable compatibility mode, increases compatibility with password managers on mobile devices.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
</ak-form-group>
|
||||
</form>`;
|
||||
}
|
||||
}
|
||||
|
@ -26,23 +26,19 @@ export class FlowImportForm extends Form<Flow> {
|
||||
return super.styles.concat(PFDescriptionList);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line
|
||||
send = (data: Flow): Promise<FlowImportResult> => {
|
||||
send = async (): Promise<FlowImportResult> => {
|
||||
const file = this.getFormFiles()["flow"];
|
||||
if (!file) {
|
||||
throw new SentryIgnoredError("No form data");
|
||||
}
|
||||
return new FlowsApi(DEFAULT_CONFIG)
|
||||
.flowsInstancesImportCreate({
|
||||
file: file,
|
||||
})
|
||||
.then((result) => {
|
||||
if (!result.success) {
|
||||
this.result = result;
|
||||
throw new SentryIgnoredError("Failed to import flow");
|
||||
}
|
||||
return result;
|
||||
});
|
||||
const result = await new FlowsApi(DEFAULT_CONFIG).flowsInstancesImportCreate({
|
||||
file: file,
|
||||
});
|
||||
if (!result.success) {
|
||||
this.result = result;
|
||||
throw new SentryIgnoredError("Failed to import flow");
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
renderResult(): TemplateResult {
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first, groupBy } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
@ -165,35 +166,34 @@ export class StageBindingForm extends ModelForm<FlowStageBinding, string> {
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Invalid response action`}
|
||||
label=${t`Invalid response behavior`}
|
||||
?required=${true}
|
||||
name="invalidResponseAction"
|
||||
>
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value=${InvalidResponseActionEnum.Retry}
|
||||
?selected=${this.instance?.invalidResponseAction ===
|
||||
InvalidResponseActionEnum.Retry}
|
||||
>
|
||||
${t`RETRY returns the error message and a similar challenge to the executor.`}
|
||||
</option>
|
||||
<option
|
||||
value=${InvalidResponseActionEnum.Restart}
|
||||
?selected=${this.instance?.invalidResponseAction ===
|
||||
InvalidResponseActionEnum.Restart}
|
||||
>
|
||||
${t`RESTART restarts the flow from the beginning.`}
|
||||
</option>
|
||||
<option
|
||||
value=${InvalidResponseActionEnum.RestartWithContext}
|
||||
?selected=${this.instance?.invalidResponseAction ===
|
||||
InvalidResponseActionEnum.RestartWithContext}
|
||||
>
|
||||
${t`RESTART_WITH_CONTEXT restarts the flow from the beginning, while keeping the flow context.`}
|
||||
</option>
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: "RETRY",
|
||||
value: InvalidResponseActionEnum.Retry,
|
||||
default: true,
|
||||
description: html`${t`Returns the error message and a similar challenge to the executor`}`,
|
||||
},
|
||||
{
|
||||
label: "RESTART",
|
||||
value: InvalidResponseActionEnum.Restart,
|
||||
description: html`${t`Restarts the flow from the beginning`}`,
|
||||
},
|
||||
{
|
||||
label: "RESTART_WITH_CONTEXT",
|
||||
value: InvalidResponseActionEnum.RestartWithContext,
|
||||
description: html`${t`Restarts the flow from the beginning, while keeping the flow context`}`,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.invalidResponseAction}
|
||||
>
|
||||
</ak-radio>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`Configure how the flow executor should handle an invalid response to a challenge.`}
|
||||
${t`Configure how the flow executor should handle an invalid response to a challenge given by this bound stage.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
@ -201,20 +201,23 @@ export class StageBindingForm extends ModelForm<FlowStageBinding, string> {
|
||||
?required=${true}
|
||||
name="policyEngineMode"
|
||||
>
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value=${PolicyEngineMode.Any}
|
||||
?selected=${this.instance?.policyEngineMode === PolicyEngineMode.Any}
|
||||
>
|
||||
${t`ANY, any policy must match to include this stage access.`}
|
||||
</option>
|
||||
<option
|
||||
value=${PolicyEngineMode.All}
|
||||
?selected=${this.instance?.policyEngineMode === PolicyEngineMode.All}
|
||||
>
|
||||
${t`ALL, all policies must match to include this stage access.`}
|
||||
</option>
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: "ANY",
|
||||
value: PolicyEngineMode.Any,
|
||||
default: true,
|
||||
description: html`${t`Any policy must match to grant access`}`,
|
||||
},
|
||||
{
|
||||
label: "ALL",
|
||||
value: PolicyEngineMode.All,
|
||||
description: html`${t`All policies must match to grant access`}`,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.policyEngineMode}
|
||||
>
|
||||
</ak-radio>
|
||||
</ak-form-element-horizontal>
|
||||
</form>`;
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ export function DesignationToLabel(designation: FlowDesignationEnum): string {
|
||||
return t`Stage Configuration`;
|
||||
case FlowDesignationEnum.Unenrollment:
|
||||
return t`Unenrollment`;
|
||||
case FlowDesignationEnum.UnknownDefaultOpenApi:
|
||||
return t`Unknown designation`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,5 +35,7 @@ export function LayoutToLabel(layout: LayoutEnum): string {
|
||||
return t`Sidebar left`;
|
||||
case LayoutEnum.SidebarRight:
|
||||
return t`Sidebar right`;
|
||||
case LayoutEnum.UnknownDefaultOpenApi:
|
||||
return t`Unknown layout`;
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,11 @@ import "@goauthentik/admin/groups/MemberSelectModal";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/CodeMirror";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/chips/Chip";
|
||||
import "@goauthentik/elements/chips/ChipGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
import { UserOption } from "@goauthentik/elements/user/utils";
|
||||
import YAML from "yaml";
|
||||
|
||||
|
@ -32,8 +32,8 @@ export class RelatedGroupAdd extends Form<{ groups: string[] }> {
|
||||
return t`Successfully added user to group(s).`;
|
||||
}
|
||||
|
||||
send = (data: { groups: string[] }): Promise<{ groups: string[] }> => {
|
||||
return Promise.all(
|
||||
send = async (data: { groups: string[] }): Promise<{ groups: string[] }> => {
|
||||
await Promise.all(
|
||||
data.groups.map((group) => {
|
||||
return new CoreApi(DEFAULT_CONFIG).coreGroupsAddUserCreate({
|
||||
groupUuid: group,
|
||||
@ -42,9 +42,8 @@ export class RelatedGroupAdd extends Form<{ groups: string[] }> {
|
||||
},
|
||||
});
|
||||
}),
|
||||
).then(() => {
|
||||
return data;
|
||||
});
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
renderForm(): TemplateResult {
|
||||
|
@ -2,9 +2,9 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { docLink } from "@goauthentik/common/global";
|
||||
import { groupBy } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/CodeMirror";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
import YAML from "yaml";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
@ -107,6 +107,10 @@ export class OutpostForm extends ModelForm<Outpost, string> {
|
||||
</option>`;
|
||||
});
|
||||
});
|
||||
case OutpostTypeEnum.UnknownDefaultOpenApi:
|
||||
return Promise.resolve([
|
||||
html` <option value="">${t`Unknown outpost type`}</option>`,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,7 +170,7 @@ export class OutpostForm extends ModelForm<Outpost, string> {
|
||||
return groupBy(items, (item) => item.verboseName);
|
||||
}}
|
||||
.selected=${(item: ServiceConnection, items: ServiceConnection[]): boolean => {
|
||||
let selected = this.instance?.serviceConnection === sc.pk;
|
||||
let selected = this.instance?.serviceConnection === item.pk;
|
||||
if (items.length === 1 && !this.instance) {
|
||||
selected = true;
|
||||
}
|
||||
|
@ -33,6 +33,8 @@ export function TypeToLabel(type?: OutpostTypeEnum): string {
|
||||
return t`Proxy`;
|
||||
case OutpostTypeEnum.Ldap:
|
||||
return t`LDAP`;
|
||||
case OutpostTypeEnum.UnknownDefaultOpenApi:
|
||||
return t`Unknown type`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first, groupBy } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
|
@ -2,9 +2,9 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/CodeMirror";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import { Form } from "@goauthentik/elements/forms/Form";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
import YAML from "yaml";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
@ -39,14 +39,13 @@ export class PolicyTestForm extends Form<PolicyTestRequest> {
|
||||
return t`Successfully sent test-request.`;
|
||||
}
|
||||
|
||||
send = (data: PolicyTestRequest): Promise<PolicyTestResult> => {
|
||||
send = async (data: PolicyTestRequest): Promise<PolicyTestResult> => {
|
||||
this.request = data;
|
||||
return new PoliciesApi(DEFAULT_CONFIG)
|
||||
.policiesAllTestCreate({
|
||||
policyUuid: this.policy?.pk || "",
|
||||
policyTestRequest: data,
|
||||
})
|
||||
.then((result) => (this.result = result));
|
||||
const result = await new PoliciesApi(DEFAULT_CONFIG).policiesAllTestCreate({
|
||||
policyUuid: this.policy?.pk || "",
|
||||
policyTestRequest: data,
|
||||
});
|
||||
return (this.result = result);
|
||||
};
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/CodeMirror";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import { Form } from "@goauthentik/elements/forms/Form";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
import YAML from "yaml";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
@ -37,15 +37,14 @@ export class PolicyTestForm extends Form<PolicyTestRequest> {
|
||||
return t`Successfully sent test-request.`;
|
||||
}
|
||||
|
||||
send = (data: PolicyTestRequest): Promise<PropertyMappingTestResult> => {
|
||||
send = async (data: PolicyTestRequest): Promise<PropertyMappingTestResult> => {
|
||||
this.request = data;
|
||||
return new PropertymappingsApi(DEFAULT_CONFIG)
|
||||
.propertymappingsAllTestCreate({
|
||||
pmUuid: this.mapping?.pk || "",
|
||||
policyTestRequest: data,
|
||||
formatResult: true,
|
||||
})
|
||||
.then((result) => (this.result = result));
|
||||
const result = await new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsAllTestCreate({
|
||||
pmUuid: this.mapping?.pk || "",
|
||||
policyTestRequest: data,
|
||||
formatResult: true,
|
||||
});
|
||||
return (this.result = result);
|
||||
};
|
||||
|
||||
renderResult(): TemplateResult {
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { DEFAULT_CONFIG, tenant } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
@ -146,44 +147,49 @@ export class LDAPProviderFormPage extends ModelForm<LDAPProvider, number> {
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${t`Bind mode`} name="bindMode">
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value="${LDAPAPIAccessMode.Cached}"
|
||||
?selected=${this.instance?.bindMode === LDAPAPIAccessMode.Cached}
|
||||
>
|
||||
${t`Cached binding, flow is executed and session is cached in memory. Flow is executed when session expires.`}
|
||||
</option>
|
||||
<option
|
||||
value="${LDAPAPIAccessMode.Direct}"
|
||||
?selected=${this.instance?.bindMode === LDAPAPIAccessMode.Direct}
|
||||
>
|
||||
${t`Direct binding, always execute the configured bind flow to authenticate the user.`}
|
||||
</option>
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: t`Cached binding`,
|
||||
value: LDAPAPIAccessMode.Cached,
|
||||
default: true,
|
||||
description: html`${t`Flow is executed and session is cached in memory. Flow is executed when session expires`}`,
|
||||
},
|
||||
{
|
||||
label: t`Direct binding`,
|
||||
value: LDAPAPIAccessMode.Direct,
|
||||
description: html`${t`Always execute the configured bind flow to authenticate the user`}`,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.bindMode}
|
||||
>
|
||||
</ak-radio>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`Configure how the outpost authenticates requests.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${t`Search mode`} name="searchMode">
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value="${LDAPAPIAccessMode.Cached}"
|
||||
?selected=${this.instance?.searchMode === LDAPAPIAccessMode.Cached}
|
||||
>
|
||||
${t`Cached querying, the outpost holds all users and groups in-memory and will refresh every 5 Minutes.`}
|
||||
</option>
|
||||
<option
|
||||
value="${LDAPAPIAccessMode.Direct}"
|
||||
?selected=${this.instance?.searchMode === LDAPAPIAccessMode.Direct}
|
||||
>
|
||||
${t`Direct querying, always returns the latest data, but slower than cached querying.`}
|
||||
</option>
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: t`Cached querying`,
|
||||
value: LDAPAPIAccessMode.Cached,
|
||||
default: true,
|
||||
description: html`${t`The outpost holds all users and groups in-memory and will refresh every 5 Minutes`}`,
|
||||
},
|
||||
{
|
||||
label: t`Direct querying`,
|
||||
value: LDAPAPIAccessMode.Direct,
|
||||
description: html`${t`Always returns the latest data, but slower than cached querying`}`,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.searchMode}
|
||||
>
|
||||
</ak-radio>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`Configure how the outpost queries the core authentik server's users.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
|
||||
<ak-form-group .expanded=${true}>
|
||||
<span slot="header"> ${t`Protocol settings`} </span>
|
||||
<div slot="body" class="pf-c-form">
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first, randomString } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
import "@goauthentik/elements/utils/TimeDeltaHelp";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
@ -365,21 +366,21 @@ ${this.instance?.redirectUris}</textarea
|
||||
?required=${true}
|
||||
name="issuerMode"
|
||||
>
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value="${IssuerModeEnum.PerProvider}"
|
||||
?selected=${this.instance?.issuerMode ===
|
||||
IssuerModeEnum.PerProvider}
|
||||
>
|
||||
${t`Each provider has a different issuer, based on the application slug.`}
|
||||
</option>
|
||||
<option
|
||||
value="${IssuerModeEnum.Global}"
|
||||
?selected=${this.instance?.issuerMode === IssuerModeEnum.Global}
|
||||
>
|
||||
${t`Same identifier is used for all providers`}
|
||||
</option>
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: t`Each provider has a different issuer, based on the application slug`,
|
||||
value: IssuerModeEnum.PerProvider,
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
label: t`Same identifier is used for all providers`,
|
||||
value: IssuerModeEnum.Global,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.issuerMode}
|
||||
>
|
||||
</ak-radio>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`Configure how the issuer field of the ID Token should be filled.`}
|
||||
</p>
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
import "@goauthentik/elements/utils/TimeDeltaHelp";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
@ -279,6 +279,8 @@ export class ProxyProviderFormPage extends ModelForm<ProxyProvider, number> {
|
||||
${t`Set this to the domain you wish the authentication to be valid for. Must be a parent domain of the URL above. If you're running applications as app1.domain.tld, app2.domain.tld, set this to 'domain.tld'.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>`;
|
||||
case ProxyMode.UnknownDefaultOpenApi:
|
||||
return html`<p>${t`Unknown proxy mode`}</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,8 @@ export function ModeToLabel(action?: ProxyMode): string {
|
||||
return t`Forward auth (single application)`;
|
||||
case ProxyMode.ForwardDomain:
|
||||
return t`Forward auth (domain-level)`;
|
||||
case ProxyMode.UnknownDefaultOpenApi:
|
||||
return t`Unknown proxy mode`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,6 +59,8 @@ export function isForward(mode: ProxyMode): boolean {
|
||||
case ProxyMode.ForwardSingle:
|
||||
case ProxyMode.ForwardDomain:
|
||||
return true;
|
||||
case ProxyMode.UnknownDefaultOpenApi:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
import "@goauthentik/elements/utils/TimeDeltaHelp";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
@ -130,20 +131,21 @@ export class SAMLProviderFormPage extends ModelForm<SAMLProvider, number> {
|
||||
?required=${true}
|
||||
name="spBinding"
|
||||
>
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value=${SpBindingEnum.Redirect}
|
||||
?selected=${this.instance?.spBinding === SpBindingEnum.Redirect}
|
||||
>
|
||||
${t`Redirect`}
|
||||
</option>
|
||||
<option
|
||||
value=${SpBindingEnum.Post}
|
||||
?selected=${this.instance?.spBinding === SpBindingEnum.Post}
|
||||
>
|
||||
${t`Post`}
|
||||
</option>
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: t`Redirect`,
|
||||
value: SpBindingEnum.Redirect,
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
label: t`Post`,
|
||||
value: SpBindingEnum.Post,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.spBinding}
|
||||
>
|
||||
</ak-radio>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`Determines how authentik sends the response back to the Service Provider.`}
|
||||
</p>
|
||||
@ -366,81 +368,62 @@ export class SAMLProviderFormPage extends ModelForm<SAMLProvider, number> {
|
||||
?required=${true}
|
||||
name="digestAlgorithm"
|
||||
>
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value=${DigestAlgorithmEnum._200009Xmldsigsha1}
|
||||
?selected=${this.instance?.digestAlgorithm ===
|
||||
DigestAlgorithmEnum._200009Xmldsigsha1}
|
||||
>
|
||||
${t`SHA1`}
|
||||
</option>
|
||||
<option
|
||||
value=${DigestAlgorithmEnum._200104Xmlencsha256}
|
||||
?selected=${this.instance?.digestAlgorithm ===
|
||||
DigestAlgorithmEnum._200104Xmlencsha256 ||
|
||||
this.instance?.digestAlgorithm === undefined}
|
||||
>
|
||||
${t`SHA256`}
|
||||
</option>
|
||||
<option
|
||||
value=${DigestAlgorithmEnum._200104XmldsigMoresha384}
|
||||
?selected=${this.instance?.digestAlgorithm ===
|
||||
DigestAlgorithmEnum._200104XmldsigMoresha384}
|
||||
>
|
||||
${t`SHA384`}
|
||||
</option>
|
||||
<option
|
||||
value=${DigestAlgorithmEnum._200104Xmlencsha512}
|
||||
?selected=${this.instance?.digestAlgorithm ===
|
||||
DigestAlgorithmEnum._200104Xmlencsha512}
|
||||
>
|
||||
${t`SHA512`}
|
||||
</option>
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: "SHA1",
|
||||
value: DigestAlgorithmEnum._200009Xmldsigsha1,
|
||||
},
|
||||
{
|
||||
label: "SHA256",
|
||||
value: DigestAlgorithmEnum._200104Xmlencsha256,
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
label: "SHA384",
|
||||
value: DigestAlgorithmEnum._200104XmldsigMoresha384,
|
||||
},
|
||||
{
|
||||
label: "SHA512",
|
||||
value: DigestAlgorithmEnum._200104Xmlencsha512,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.digestAlgorithm}
|
||||
>
|
||||
</ak-radio>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Signature algorithm`}
|
||||
?required=${true}
|
||||
name="signatureAlgorithm"
|
||||
>
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value=${SignatureAlgorithmEnum._200009XmldsigrsaSha1}
|
||||
?selected=${this.instance?.signatureAlgorithm ===
|
||||
SignatureAlgorithmEnum._200009XmldsigrsaSha1}
|
||||
>
|
||||
${t`RSA-SHA1`}
|
||||
</option>
|
||||
<option
|
||||
value=${SignatureAlgorithmEnum._200104XmldsigMorersaSha256}
|
||||
?selected=${this.instance?.signatureAlgorithm ===
|
||||
SignatureAlgorithmEnum._200104XmldsigMorersaSha256 ||
|
||||
this.instance?.signatureAlgorithm === undefined}
|
||||
>
|
||||
${t`RSA-SHA256`}
|
||||
</option>
|
||||
<option
|
||||
value=${SignatureAlgorithmEnum._200104XmldsigMorersaSha384}
|
||||
?selected=${this.instance?.signatureAlgorithm ===
|
||||
SignatureAlgorithmEnum._200104XmldsigMorersaSha384}
|
||||
>
|
||||
${t`RSA-SHA384`}
|
||||
</option>
|
||||
<option
|
||||
value=${SignatureAlgorithmEnum._200104XmldsigMorersaSha512}
|
||||
?selected=${this.instance?.signatureAlgorithm ===
|
||||
SignatureAlgorithmEnum._200104XmldsigMorersaSha512}
|
||||
>
|
||||
${t`RSA-SHA512`}
|
||||
</option>
|
||||
<option
|
||||
value=${SignatureAlgorithmEnum._200009XmldsigdsaSha1}
|
||||
?selected=${this.instance?.signatureAlgorithm ===
|
||||
SignatureAlgorithmEnum._200009XmldsigdsaSha1}
|
||||
>
|
||||
${t`DSA-SHA1`}
|
||||
</option>
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: "RSA-SHA1",
|
||||
value: SignatureAlgorithmEnum._200009XmldsigrsaSha1,
|
||||
},
|
||||
{
|
||||
label: "RSA-SHA256",
|
||||
value: SignatureAlgorithmEnum._200104XmldsigMorersaSha256,
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
label: "RSA-SHA384",
|
||||
value: SignatureAlgorithmEnum._200104XmldsigMorersaSha384,
|
||||
},
|
||||
{
|
||||
label: "RSA-SHA512",
|
||||
value: SignatureAlgorithmEnum._200104XmldsigMorersaSha512,
|
||||
},
|
||||
{
|
||||
label: "DSA-SHA1",
|
||||
value: SignatureAlgorithmEnum._200009XmldsigdsaSha1,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.signatureAlgorithm}
|
||||
>
|
||||
</ak-radio>
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { SentryIgnoredError } from "@goauthentik/common/errors";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import { Form } from "@goauthentik/elements/forms/Form";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
@ -24,7 +24,6 @@ export class SAMLProviderImportForm extends Form<SAMLProvider> {
|
||||
return t`Successfully imported provider.`;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line
|
||||
send = (data: SAMLProvider): Promise<void> => {
|
||||
const file = this.getFormFiles()["metadata"];
|
||||
if (!file) {
|
||||
@ -66,7 +65,7 @@ export class SAMLProviderImportForm extends Form<SAMLProvider> {
|
||||
return html`${flow.name}`;
|
||||
}}
|
||||
.value=${(flow: Flow | undefined): string | undefined => {
|
||||
return flow?.pk;
|
||||
return flow?.slug;
|
||||
}}
|
||||
>
|
||||
</ak-search-select>
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
|
@ -2,10 +2,10 @@ import { UserMatchingModeToLabel } from "@goauthentik/admin/sources/oauth/utils"
|
||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/CodeMirror";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
|
@ -27,8 +27,9 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
import { OAuthSource, ProviderTypeEnum, SourcesApi } from "@goauthentik/api";
|
||||
|
||||
export function ProviderToLabel(provider?: ProviderTypeEnum): string {
|
||||
if (!provider) return "";
|
||||
switch (provider) {
|
||||
case undefined:
|
||||
return "";
|
||||
case ProviderTypeEnum.Apple:
|
||||
return "Apple";
|
||||
case ProviderTypeEnum.Azuread:
|
||||
@ -51,6 +52,10 @@ export function ProviderToLabel(provider?: ProviderTypeEnum): string {
|
||||
return "Reddit";
|
||||
case ProviderTypeEnum.Twitter:
|
||||
return "Twitter";
|
||||
case ProviderTypeEnum.Twitch:
|
||||
return "Twitch";
|
||||
case ProviderTypeEnum.UnknownDefaultOpenApi:
|
||||
return t`Unknown provider type`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,5 +15,7 @@ export function UserMatchingModeToLabel(mode?: UserMatchingModeEnum): string {
|
||||
return t`Link to a user with identical username. Can have security implications when a username is used with another source`;
|
||||
case UserMatchingModeEnum.UsernameDeny:
|
||||
return t`Use the user's username, but deny enrollment when the username already exists`;
|
||||
case UserMatchingModeEnum.UnknownDefaultOpenApi:
|
||||
return t`Unknown user matching mode`;
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,10 @@ import { UserMatchingModeToLabel } from "@goauthentik/admin/sources/oauth/utils"
|
||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
||||
import { PlexAPIClient, PlexResource, popupCenterScreen } from "@goauthentik/common/helpers/plex";
|
||||
import { first, randomString } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
|
@ -4,6 +4,7 @@ import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
import "@goauthentik/elements/utils/TimeDeltaHelp";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
@ -242,26 +243,26 @@ export class SAMLSourceForm extends ModelForm<SAMLSource, string> {
|
||||
?required=${true}
|
||||
name="bindingType"
|
||||
>
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value=${BindingTypeEnum.Redirect}
|
||||
?selected=${this.instance?.bindingType === BindingTypeEnum.Redirect}
|
||||
>
|
||||
${t`Redirect binding`}
|
||||
</option>
|
||||
<option
|
||||
value=${BindingTypeEnum.PostAuto}
|
||||
?selected=${this.instance?.bindingType === BindingTypeEnum.PostAuto}
|
||||
>
|
||||
${t`Post binding (auto-submit)`}
|
||||
</option>
|
||||
<option
|
||||
value=${BindingTypeEnum.Post}
|
||||
?selected=${this.instance?.bindingType === BindingTypeEnum.Post}
|
||||
>
|
||||
${t`Post binding`}
|
||||
</option>
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: t`Redirect binding`,
|
||||
value: BindingTypeEnum.Redirect,
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
label: t`Post-auto binding`,
|
||||
value: BindingTypeEnum.PostAuto,
|
||||
description: html`${t`Post binding but the request is automatically sent and the user doesn't have to confirm.`}`,
|
||||
},
|
||||
{
|
||||
label: t`Post binding`,
|
||||
value: BindingTypeEnum.Post,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.bindingType}
|
||||
>
|
||||
</ak-radio>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${t`Signing keypair`} name="signingKp">
|
||||
<ak-search-select
|
||||
@ -394,81 +395,62 @@ export class SAMLSourceForm extends ModelForm<SAMLSource, string> {
|
||||
?required=${true}
|
||||
name="digestAlgorithm"
|
||||
>
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value=${DigestAlgorithmEnum._200009Xmldsigsha1}
|
||||
?selected=${this.instance?.digestAlgorithm ===
|
||||
DigestAlgorithmEnum._200009Xmldsigsha1}
|
||||
>
|
||||
${t`SHA1`}
|
||||
</option>
|
||||
<option
|
||||
value=${DigestAlgorithmEnum._200104Xmlencsha256}
|
||||
?selected=${this.instance?.digestAlgorithm ===
|
||||
DigestAlgorithmEnum._200104Xmlencsha256 ||
|
||||
this.instance?.digestAlgorithm === undefined}
|
||||
>
|
||||
${t`SHA256`}
|
||||
</option>
|
||||
<option
|
||||
value=${DigestAlgorithmEnum._200104XmldsigMoresha384}
|
||||
?selected=${this.instance?.digestAlgorithm ===
|
||||
DigestAlgorithmEnum._200104XmldsigMoresha384}
|
||||
>
|
||||
${t`SHA384`}
|
||||
</option>
|
||||
<option
|
||||
value=${DigestAlgorithmEnum._200104Xmlencsha512}
|
||||
?selected=${this.instance?.digestAlgorithm ===
|
||||
DigestAlgorithmEnum._200104Xmlencsha512}
|
||||
>
|
||||
${t`SHA512`}
|
||||
</option>
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: "SHA1",
|
||||
value: DigestAlgorithmEnum._200009Xmldsigsha1,
|
||||
},
|
||||
{
|
||||
label: "SHA256",
|
||||
value: DigestAlgorithmEnum._200104Xmlencsha256,
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
label: "SHA384",
|
||||
value: DigestAlgorithmEnum._200104XmldsigMoresha384,
|
||||
},
|
||||
{
|
||||
label: "SHA512",
|
||||
value: DigestAlgorithmEnum._200104Xmlencsha512,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.digestAlgorithm}
|
||||
>
|
||||
</ak-radio>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Signature algorithm`}
|
||||
?required=${true}
|
||||
name="signatureAlgorithm"
|
||||
>
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value=${SignatureAlgorithmEnum._200009XmldsigrsaSha1}
|
||||
?selected=${this.instance?.signatureAlgorithm ===
|
||||
SignatureAlgorithmEnum._200009XmldsigrsaSha1}
|
||||
>
|
||||
${t`RSA-SHA1`}
|
||||
</option>
|
||||
<option
|
||||
value=${SignatureAlgorithmEnum._200104XmldsigMorersaSha256}
|
||||
?selected=${this.instance?.signatureAlgorithm ===
|
||||
SignatureAlgorithmEnum._200104XmldsigMorersaSha256 ||
|
||||
this.instance?.signatureAlgorithm === undefined}
|
||||
>
|
||||
${t`RSA-SHA256`}
|
||||
</option>
|
||||
<option
|
||||
value=${SignatureAlgorithmEnum._200104XmldsigMorersaSha384}
|
||||
?selected=${this.instance?.signatureAlgorithm ===
|
||||
SignatureAlgorithmEnum._200104XmldsigMorersaSha384}
|
||||
>
|
||||
${t`RSA-SHA384`}
|
||||
</option>
|
||||
<option
|
||||
value=${SignatureAlgorithmEnum._200104XmldsigMorersaSha512}
|
||||
?selected=${this.instance?.signatureAlgorithm ===
|
||||
SignatureAlgorithmEnum._200104XmldsigMorersaSha512}
|
||||
>
|
||||
${t`RSA-SHA512`}
|
||||
</option>
|
||||
<option
|
||||
value=${SignatureAlgorithmEnum._200009XmldsigdsaSha1}
|
||||
?selected=${this.instance?.signatureAlgorithm ===
|
||||
SignatureAlgorithmEnum._200009XmldsigdsaSha1}
|
||||
>
|
||||
${t`DSA-SHA1`}
|
||||
</option>
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: "RSA-SHA1",
|
||||
value: SignatureAlgorithmEnum._200009XmldsigrsaSha1,
|
||||
},
|
||||
{
|
||||
label: "RSA-SHA256",
|
||||
value: SignatureAlgorithmEnum._200104XmldsigMorersaSha256,
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
label: "RSA-SHA384",
|
||||
value: SignatureAlgorithmEnum._200104XmldsigMorersaSha384,
|
||||
},
|
||||
{
|
||||
label: "RSA-SHA512",
|
||||
value: SignatureAlgorithmEnum._200104XmldsigMorersaSha512,
|
||||
},
|
||||
{
|
||||
label: "DSA-SHA1",
|
||||
value: SignatureAlgorithmEnum._200009XmldsigdsaSha1,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.signatureAlgorithm}
|
||||
>
|
||||
</ak-radio>
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { MessageLevel } from "@goauthentik/common/messages";
|
||||
import "@goauthentik/elements/Divider";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/buttons/ActionButton";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModalForm } from "@goauthentik/elements/forms/ModalForm";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
import { showMessage } from "@goauthentik/elements/messages/MessageContainer";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
@ -106,20 +107,21 @@ export class AuthenticatorSMSStageForm extends ModelForm<AuthenticatorSMSStage,
|
||||
?required=${true}
|
||||
name="authType"
|
||||
>
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value="${AuthTypeEnum.Basic}"
|
||||
?selected=${this.instance?.authType === AuthTypeEnum.Basic}
|
||||
>
|
||||
${t`Basic Auth`}
|
||||
</option>
|
||||
<option
|
||||
value="${AuthTypeEnum.Bearer}"
|
||||
?selected=${this.instance?.authType === AuthTypeEnum.Bearer}
|
||||
>
|
||||
${t`Bearer Token`}
|
||||
</option>
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: t`Basic Auth`,
|
||||
value: AuthTypeEnum.Basic,
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
label: t`Bearer Token`,
|
||||
value: AuthTypeEnum.Bearer,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.authType}
|
||||
>
|
||||
</ak-radio>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`External API URL`}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
|
@ -2,6 +2,7 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
import "@goauthentik/elements/utils/TimeDeltaHelp";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
@ -188,29 +189,25 @@ export class AuthenticatorValidateStageForm extends ModelForm<AuthenticatorValid
|
||||
?required=${true}
|
||||
name="webauthnUserVerification"
|
||||
>
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value="${UserVerificationEnum.Required}"
|
||||
?selected=${this.instance?.webauthnUserVerification ===
|
||||
UserVerificationEnum.Required}
|
||||
>
|
||||
${t`User verification must occur.`}
|
||||
</option>
|
||||
<option
|
||||
value="${UserVerificationEnum.Preferred}"
|
||||
?selected=${this.instance?.webauthnUserVerification ===
|
||||
UserVerificationEnum.Preferred}
|
||||
>
|
||||
${t`User verification is preferred if available, but not required.`}
|
||||
</option>
|
||||
<option
|
||||
value="${UserVerificationEnum.Discouraged}"
|
||||
?selected=${this.instance?.webauthnUserVerification ===
|
||||
UserVerificationEnum.Discouraged}
|
||||
>
|
||||
${t`User verification should not occur.`}
|
||||
</option>
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: t`User verification must occur.`,
|
||||
value: UserVerificationEnum.Required,
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
label: t`User verification is preferred if available, but not required.`,
|
||||
value: UserVerificationEnum.Preferred,
|
||||
},
|
||||
{
|
||||
label: t`User verification should not occur.`,
|
||||
value: UserVerificationEnum.Discouraged,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.webauthnUserVerification}
|
||||
>
|
||||
</ak-radio>
|
||||
</ak-form-element-horizontal>
|
||||
${this.showConfigurationStages
|
||||
? html`
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
@ -74,86 +75,75 @@ export class AuthenticateWebAuthnStageForm extends ModelForm<AuthenticateWebAuth
|
||||
?required=${true}
|
||||
name="userVerification"
|
||||
>
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value="${UserVerificationEnum.Required}"
|
||||
?selected=${this.instance?.userVerification ===
|
||||
UserVerificationEnum.Required}
|
||||
>
|
||||
${t`User verification must occur.`}
|
||||
</option>
|
||||
<option
|
||||
value="${UserVerificationEnum.Preferred}"
|
||||
?selected=${this.instance?.userVerification ===
|
||||
UserVerificationEnum.Preferred}
|
||||
>
|
||||
${t`User verification is preferred if available, but not required.`}
|
||||
</option>
|
||||
<option
|
||||
value="${UserVerificationEnum.Discouraged}"
|
||||
?selected=${this.instance?.userVerification ===
|
||||
UserVerificationEnum.Discouraged}
|
||||
>
|
||||
${t`User verification should not occur.`}
|
||||
</option>
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: t`User verification must occur.`,
|
||||
value: UserVerificationEnum.Required,
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
label: t`User verification is preferred if available, but not required.`,
|
||||
value: UserVerificationEnum.Preferred,
|
||||
},
|
||||
{
|
||||
label: t`User verification should not occur.`,
|
||||
value: UserVerificationEnum.Discouraged,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.userVerification}
|
||||
>
|
||||
</ak-radio>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Resident key requirement`}
|
||||
?required=${true}
|
||||
name="residentKeyRequirement"
|
||||
>
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value="${ResidentKeyRequirementEnum.Discouraged}"
|
||||
?selected=${this.instance?.residentKeyRequirement ===
|
||||
ResidentKeyRequirementEnum.Discouraged}
|
||||
>
|
||||
${t`The authenticator should not create a dedicated credential`}
|
||||
</option>
|
||||
<option
|
||||
value="${ResidentKeyRequirementEnum.Preferred}"
|
||||
?selected=${this.instance?.residentKeyRequirement ===
|
||||
ResidentKeyRequirementEnum.Preferred}
|
||||
>
|
||||
${t`The authenticator can create and store a dedicated credential, but if it doesn't that's alright too`}
|
||||
</option>
|
||||
<option
|
||||
value="${ResidentKeyRequirementEnum.Required}"
|
||||
?selected=${this.instance?.residentKeyRequirement ===
|
||||
ResidentKeyRequirementEnum.Required}
|
||||
>
|
||||
${t`The authenticator MUST create a dedicated credential. If it cannot, the RP is prepared for an error to occur`}
|
||||
</option>
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: t`The authenticator should not create a dedicated credential`,
|
||||
value: ResidentKeyRequirementEnum.Required,
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
label: t`The authenticator can create and store a dedicated credential, but if it doesn't that's alright too`,
|
||||
value: ResidentKeyRequirementEnum.Preferred,
|
||||
},
|
||||
{
|
||||
label: t`The authenticator MUST create a dedicated credential. If it cannot, the RP is prepared for an error to occur`,
|
||||
value: ResidentKeyRequirementEnum.Discouraged,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.residentKeyRequirement}
|
||||
>
|
||||
</ak-radio>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Authenticator Attachment`}
|
||||
?required=${true}
|
||||
name="authenticatorAttachment"
|
||||
>
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value=""
|
||||
?selected=${this.instance?.authenticatorAttachment === null}
|
||||
>
|
||||
${t`No preference is sent`}
|
||||
</option>
|
||||
<option
|
||||
value="${AuthenticatorAttachmentEnum.Platform}"
|
||||
?selected=${this.instance?.authenticatorAttachment ===
|
||||
AuthenticatorAttachmentEnum.Platform}
|
||||
>
|
||||
${t`A non-removable authenticator, like TouchID or Windows Hello`}
|
||||
</option>
|
||||
<option
|
||||
value="${AuthenticatorAttachmentEnum.CrossPlatform}"
|
||||
?selected=${this.instance?.authenticatorAttachment ===
|
||||
AuthenticatorAttachmentEnum.CrossPlatform}
|
||||
>
|
||||
${t`A "roaming" authenticator, like a YubiKey`}
|
||||
</option>
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: t`No preference is sent`,
|
||||
value: null,
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
label: t`A non-removable authenticator, like TouchID or Windows Hello`,
|
||||
value: AuthenticatorAttachmentEnum.Platform,
|
||||
},
|
||||
{
|
||||
label: t`A "roaming" authenticator, like a YubiKey`,
|
||||
value: AuthenticatorAttachmentEnum.CrossPlatform,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.authenticatorAttachment}
|
||||
>
|
||||
</ak-radio>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${t`Configuration flow`} name="configureFlow">
|
||||
<ak-search-select
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
|
||||
@ -52,6 +53,16 @@ export class DummyStageForm extends ModelForm<DummyStage, string> {
|
||||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="throwError">
|
||||
<div class="pf-c-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="pf-c-check__input"
|
||||
?checked=${first(this.instance?.throwError, false)}
|
||||
/>
|
||||
<label class="pf-c-check__label"> ${t`Throw error?`} </label>
|
||||
</div>
|
||||
</ak-form-element-horizontal>
|
||||
</form>`;
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first, groupBy } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
@ -154,6 +154,24 @@ export class IdentificationStageForm extends ModelForm<IdentificationStage, stri
|
||||
${t`When enabled, user fields are matched regardless of their casing.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="showMatchedUser">
|
||||
<div class="pf-c-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="pf-c-check__input"
|
||||
?checked=${first(this.instance?.showMatchedUser, true)}
|
||||
/>
|
||||
<label class="pf-c-check__label"> ${t`Show matched user`} </label>
|
||||
</div>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`When a valid username/email has been entered, and this option is enabled, the user's username and avatar will be shown. Otherwise, the text that the user entered will be shown.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
<ak-form-group>
|
||||
<span slot="header"> ${t`Source settings`} </span>
|
||||
<div slot="body" class="pf-c-form">
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Sources`}
|
||||
?required=${true}
|
||||
@ -210,19 +228,6 @@ export class IdentificationStageForm extends ModelForm<IdentificationStage, stri
|
||||
${t`By default, only icons are shown for sources. Enable this to show their full names.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="showMatchedUser">
|
||||
<div class="pf-c-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="pf-c-check__input"
|
||||
?checked=${first(this.instance?.showMatchedUser, true)}
|
||||
/>
|
||||
<label class="pf-c-check__label"> ${t`Show matched user`} </label>
|
||||
</div>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`When a valid username/email has been entered, and this option is enabled, the user's username and avatar will be shown. Otherwise, the text that the user entered will be shown.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
<ak-form-group>
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { dateTimeLocal, first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/CodeMirror";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
import YAML from "yaml";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/CodeMirror";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
import { DefaultTenant } from "@goauthentik/elements/sidebar/SidebarBrand";
|
||||
import YAML from "yaml";
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { dateTimeLocal, first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
@ -82,20 +83,23 @@ export class TokenForm extends ModelForm<Token, string> {
|
||||
</ak-search-select>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${t`Intent`} ?required=${true} name="intent">
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value=${IntentEnum.Api}
|
||||
?selected=${this.instance?.intent === IntentEnum.Api}
|
||||
>
|
||||
${t`API Token (can be used to access the API programmatically)`}
|
||||
</option>
|
||||
<option
|
||||
value=${IntentEnum.AppPassword}
|
||||
?selected=${this.instance?.intent === IntentEnum.AppPassword}
|
||||
>
|
||||
${t`App password (can be used to login using a flow executor)`}
|
||||
</option>
|
||||
</select>
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: t`API Token`,
|
||||
value: IntentEnum.Api,
|
||||
default: true,
|
||||
description: html`${t`Used to access the API programmatically`}`,
|
||||
},
|
||||
{
|
||||
label: t`App password.`,
|
||||
value: IntentEnum.AppPassword,
|
||||
description: html`${t`Used to login using a flow executor`}`,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.intent}
|
||||
>
|
||||
</ak-radio>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${t`Description`} name="description">
|
||||
<input
|
||||
|
@ -27,6 +27,8 @@ export function IntentToLabel(intent: IntentEnum): string {
|
||||
return t`Recovery`;
|
||||
case IntentEnum.Verification:
|
||||
return t`Verification`;
|
||||
case IntentEnum.UnknownDefaultOpenApi:
|
||||
return t`Unknown intent`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,8 +44,8 @@ export class RelatedUserAdd extends Form<{ users: number[] }> {
|
||||
return t`Successfully added user(s).`;
|
||||
}
|
||||
|
||||
send = (data: { users: number[] }): Promise<{ users: number[] }> => {
|
||||
return Promise.all(
|
||||
send = async (data: { users: number[] }): Promise<{ users: number[] }> => {
|
||||
await Promise.all(
|
||||
data.users.map((user) => {
|
||||
return new CoreApi(DEFAULT_CONFIG).coreGroupsAddUserCreate({
|
||||
groupUuid: this.group?.pk || "",
|
||||
@ -54,9 +54,8 @@ export class RelatedUserAdd extends Form<{ users: number[] }> {
|
||||
},
|
||||
});
|
||||
}),
|
||||
).then(() => {
|
||||
return data;
|
||||
});
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
renderForm(): TemplateResult {
|
||||
|
@ -20,16 +20,13 @@ export class ServiceAccountForm extends Form<UserServiceAccountRequest> {
|
||||
return t`Successfully created user.`;
|
||||
}
|
||||
|
||||
send = (data: UserServiceAccountRequest): Promise<UserServiceAccountResponse> => {
|
||||
return new CoreApi(DEFAULT_CONFIG)
|
||||
.coreUsersServiceAccountCreate({
|
||||
userServiceAccountRequest: data,
|
||||
})
|
||||
.then((result) => {
|
||||
this.result = result;
|
||||
(this.parentElement as ModalForm).showSubmitButton = false;
|
||||
return result;
|
||||
});
|
||||
send = async (data: UserServiceAccountRequest): Promise<UserServiceAccountResponse> => {
|
||||
const result = await new CoreApi(DEFAULT_CONFIG).coreUsersServiceAccountCreate({
|
||||
userServiceAccountRequest: data,
|
||||
});
|
||||
this.result = result;
|
||||
(this.parentElement as ModalForm).showSubmitButton = false;
|
||||
return result;
|
||||
};
|
||||
|
||||
resetForm(): void {
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { groupBy } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/SearchSelect";
|
||||
import { Form } from "@goauthentik/elements/forms/Form";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user