Compare commits
78 Commits
version/20
...
version/20
| Author | SHA1 | Date | |
|---|---|---|---|
| dae6493a3e | |||
| ad07984158 | |||
| f909b86338 | |||
| 327df6529b | |||
| 658dc63c4c | |||
| 4edec5f666 | |||
| d150a0c135 | |||
| d4242781a0 | |||
| 7369ca0b25 | |||
| 561f427cc5 | |||
| 8049ab703a | |||
| 9c2a97263a | |||
| 345504c1a4 | |||
| 549f6f2077 | |||
| 35c6decc75 | |||
| b3abeb78ff | |||
| 0562a1ad42 | |||
| febb0920fd | |||
| 549662beb0 | |||
| 1ea4440c5d | |||
| 787abdff5b | |||
| 2237807241 | |||
| e9d9d658c4 | |||
| e704092d19 | |||
| 305f72c197 | |||
| fb6b6b4476 | |||
| 791cc74dbb | |||
| 41f139589c | |||
| df24e3020b | |||
| e44c716cbe | |||
| d35302923d | |||
| 4d928368bc | |||
| c055d7a470 | |||
| 9e1b49e181 | |||
| db6a9ede1b | |||
| 86df0a448e | |||
| 5ec052bd92 | |||
| 6f7984d05a | |||
| f6d64d1d4b | |||
| ef0c7a5a57 | |||
| 34dfbf8e9e | |||
| 71d38e6fd0 | |||
| 9a9ba2560b | |||
| 2432e51970 | |||
| 47434cd62d | |||
| ff500b44a6 | |||
| 4c14c7f3a4 | |||
| 019c4bf182 | |||
| 2cbc291f04 | |||
| 5197a3a461 | |||
| 52be87785f | |||
| 8e19fb3a8c | |||
| 0448dcf655 | |||
| b8f74ab9e7 | |||
| 501ce5cebb | |||
| b896ca7ef6 | |||
| d497db3010 | |||
| 24f95fdeaa | |||
| d1c4818724 | |||
| 9f736a9d99 | |||
| 49cce6a968 | |||
| 713337130b | |||
| 0a73e7ac9f | |||
| 3344af72c2 | |||
| 41eb44137e | |||
| 94a9667d86 | |||
| 8b56a7defb | |||
| 5a4b9b4239 | |||
| f37308461c | |||
| 9721098178 | |||
| 0ca5e67dad | |||
| da94564d5e | |||
| 1f33237659 | |||
| 62e5979c13 | |||
| 8a1e18e087 | |||
| a951daddce | |||
| 690f6d444a | |||
| b733930745 |
@ -1,5 +1,5 @@
|
||||
[bumpversion]
|
||||
current_version = 2022.7.1
|
||||
current_version = 2022.7.3
|
||||
tag = True
|
||||
commit = True
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)
|
||||
|
||||
2
.github/workflows/ci-outpost.yml
vendored
2
.github/workflows/ci-outpost.yml
vendored
@ -111,7 +111,7 @@ jobs:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "^1.17"
|
||||
- uses: actions/setup-node@v3.3.0
|
||||
- uses: actions/setup-node@v3.4.1
|
||||
with:
|
||||
node-version: '16'
|
||||
cache: 'npm'
|
||||
|
||||
8
.github/workflows/ci-web.yml
vendored
8
.github/workflows/ci-web.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3.3.0
|
||||
- uses: actions/setup-node@v3.4.1
|
||||
with:
|
||||
node-version: '16'
|
||||
cache: 'npm'
|
||||
@ -31,7 +31,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3.3.0
|
||||
- uses: actions/setup-node@v3.4.1
|
||||
with:
|
||||
node-version: '16'
|
||||
cache: 'npm'
|
||||
@ -47,7 +47,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3.3.0
|
||||
- uses: actions/setup-node@v3.4.1
|
||||
with:
|
||||
node-version: '16'
|
||||
cache: 'npm'
|
||||
@ -78,7 +78,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3.3.0
|
||||
- uses: actions/setup-node@v3.4.1
|
||||
with:
|
||||
node-version: '16'
|
||||
cache: 'npm'
|
||||
|
||||
2
.github/workflows/ci-website.yml
vendored
2
.github/workflows/ci-website.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3.3.0
|
||||
- uses: actions/setup-node@v3.4.1
|
||||
with:
|
||||
node-version: '16'
|
||||
cache: 'npm'
|
||||
|
||||
2
.github/workflows/release-publish.yml
vendored
2
.github/workflows/release-publish.yml
vendored
@ -100,7 +100,7 @@ jobs:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "^1.17"
|
||||
- uses: actions/setup-node@v3.3.0
|
||||
- uses: actions/setup-node@v3.4.1
|
||||
with:
|
||||
node-version: '16'
|
||||
cache: 'npm'
|
||||
|
||||
2
.github/workflows/web-api-publish.yml
vendored
2
.github/workflows/web-api-publish.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
# Setup .npmrc file to publish to npm
|
||||
- uses: actions/setup-node@v3.3.0
|
||||
- uses: actions/setup-node@v3.4.1
|
||||
with:
|
||||
node-version: '16'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -24,7 +24,7 @@
|
||||
"*.akflow": "json"
|
||||
},
|
||||
"typescript.preferences.importModuleSpecifier": "non-relative",
|
||||
"typescript.preferences.importModuleSpecifierEnding": "js",
|
||||
"typescript.preferences.importModuleSpecifierEnding": "index",
|
||||
"typescript.tsdk": "./web/node_modules/typescript/lib",
|
||||
"typescript.enablePromptUseWorkspaceTsdk": true
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ RUN pip install --no-cache-dir poetry && \
|
||||
poetry export -f requirements.txt --dev --output requirements-dev.txt
|
||||
|
||||
# Stage 4: Build go proxy
|
||||
FROM docker.io/golang:1.18.3-bullseye AS builder
|
||||
FROM docker.io/golang:1.18.4-bullseye AS builder
|
||||
|
||||
WORKDIR /work
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
from os import environ
|
||||
from typing import Optional
|
||||
|
||||
__version__ = "2022.7.1"
|
||||
__version__ = "2022.7.3"
|
||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ class RequestIDMiddleware:
|
||||
response[RESPONSE_HEADER_ID] = request.request_id
|
||||
setattr(response, "ak_context", {})
|
||||
response.ak_context.update(LOCAL.authentik)
|
||||
response.ak_context[KEY_USER] = request.user.username
|
||||
response.ak_context.setdefault(KEY_USER, request.user.username)
|
||||
for key in list(LOCAL.authentik.keys()):
|
||||
del LOCAL.authentik[key]
|
||||
return response
|
||||
|
||||
@ -482,8 +482,9 @@ class ExpiringModel(models.Model):
|
||||
def filter_not_expired(cls, **kwargs) -> QuerySet:
|
||||
"""Filer for tokens which are not expired yet or are not expiring,
|
||||
and match filters in `kwargs`"""
|
||||
expired = Q(expires__lt=now(), expiring=True)
|
||||
return cls.objects.exclude(expired).filter(**kwargs)
|
||||
for obj in cls.objects.filter(**kwargs).filter(Q(expires__lt=now(), expiring=True)):
|
||||
obj.delete()
|
||||
return cls.objects.filter(**kwargs)
|
||||
|
||||
@property
|
||||
def is_expired(self) -> bool:
|
||||
|
||||
@ -10,7 +10,9 @@
|
||||
<script>ShadyDOM = { force: !navigator.webdriver };</script>
|
||||
{% endif %}
|
||||
<script>
|
||||
window.authentik = {};
|
||||
window.authentik = {
|
||||
"locale": "{{ tenant.default_locale }}",
|
||||
};
|
||||
window.authentik.flow = {
|
||||
"layout": "{{ flow.layout }}",
|
||||
};
|
||||
|
||||
@ -14,7 +14,7 @@ return not akadmin.has_usable_password()"""
|
||||
PREFILL_POLICY_EXPRESSION = """# This policy sets the user for the currently running flow
|
||||
# by injecting "pending_user"
|
||||
akadmin = ak_user_by(username="akadmin")
|
||||
context["pending_user"] = akadmin
|
||||
context["flow_plan"].context["pending_user"] = akadmin
|
||||
return True"""
|
||||
|
||||
|
||||
|
||||
@ -8,3 +8,8 @@ class AuthentikManagedConfig(AppConfig):
|
||||
name = "authentik.managed"
|
||||
label = "authentik_managed"
|
||||
verbose_name = "authentik Managed"
|
||||
|
||||
def ready(self) -> None:
|
||||
from authentik.managed.tasks import managed_reconcile
|
||||
|
||||
managed_reconcile.delay()
|
||||
|
||||
@ -11,7 +11,11 @@ from authentik.events.monitored_tasks import (
|
||||
from authentik.managed.manager import ObjectManager
|
||||
|
||||
|
||||
@CELERY_APP.task(bind=True, base=MonitoredTask)
|
||||
@CELERY_APP.task(
|
||||
bind=True,
|
||||
base=MonitoredTask,
|
||||
retry_backoff=True,
|
||||
)
|
||||
@prefill_task
|
||||
def managed_reconcile(self: MonitoredTask):
|
||||
"""Run ObjectManager to ensure objects are up-to-date"""
|
||||
@ -22,3 +26,4 @@ def managed_reconcile(self: MonitoredTask):
|
||||
)
|
||||
except DatabaseError as exc: # pragma: no cover
|
||||
self.set_status(TaskResult(TaskResultStatus.WARNING, [str(exc)]))
|
||||
self.retry()
|
||||
|
||||
@ -331,20 +331,18 @@ class Outpost(ManagedModel):
|
||||
@property
|
||||
def user(self) -> User:
|
||||
"""Get/create user with access to all required objects"""
|
||||
users = User.objects.filter(username=self.user_identifier)
|
||||
should_create_user = not users.exists()
|
||||
if should_create_user:
|
||||
user = User.objects.filter(username=self.user_identifier).first()
|
||||
user_created = False
|
||||
if not user:
|
||||
user: User = User.objects.create(username=self.user_identifier)
|
||||
user.set_unusable_password()
|
||||
user.save()
|
||||
else:
|
||||
user = users.first()
|
||||
user_created = True
|
||||
user.attributes[USER_ATTRIBUTE_SA] = True
|
||||
user.attributes[USER_ATTRIBUTE_CAN_OVERRIDE_IP] = True
|
||||
user.name = f"Outpost {self.name} Service-Account"
|
||||
user.path = USER_PATH_OUTPOSTS
|
||||
user.save()
|
||||
if should_create_user:
|
||||
if user_created:
|
||||
self.build_user_permissions(user)
|
||||
return user
|
||||
|
||||
|
||||
@ -5,7 +5,6 @@ from drf_spectacular.utils import OpenApiResponse, extend_schema
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from rest_framework import mixins
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.serializers import ModelSerializer, SerializerMethodField
|
||||
@ -158,7 +157,7 @@ class PolicyViewSet(
|
||||
pk=test_params.validated_data["user"].pk
|
||||
)
|
||||
if not users.exists():
|
||||
raise PermissionDenied()
|
||||
return Response(status=400)
|
||||
|
||||
p_request = PolicyRequest(users.first())
|
||||
p_request.debug = True
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
"""Test policies API"""
|
||||
from json import loads
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from django.urls import reverse
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.tests.utils import create_test_admin_user
|
||||
from authentik.policies.dummy.models import DummyPolicy
|
||||
from authentik.policies.types import PolicyResult
|
||||
|
||||
|
||||
class TestPoliciesAPI(APITestCase):
|
||||
@ -17,8 +19,10 @@ class TestPoliciesAPI(APITestCase):
|
||||
self.user = create_test_admin_user()
|
||||
self.client.force_login(self.user)
|
||||
|
||||
def test_test_call(self):
|
||||
@patch("authentik.policies.dummy.models.DummyPolicy.passes")
|
||||
def test_test_call(self, passes_mock: MagicMock):
|
||||
"""Test Policy's test endpoint"""
|
||||
passes_mock.return_value = PolicyResult(True, "dummy")
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:policy-test", kwargs={"pk": self.policy.pk}),
|
||||
data={
|
||||
@ -28,6 +32,22 @@ class TestPoliciesAPI(APITestCase):
|
||||
body = loads(response.content.decode())
|
||||
self.assertEqual(body["passing"], True)
|
||||
self.assertEqual(body["messages"], ["dummy"])
|
||||
self.assertEqual(body["log_messages"], [])
|
||||
|
||||
def test_test_call_invalid(self):
|
||||
"""Test invalid policy test"""
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:policy-test", kwargs={"pk": self.policy.pk}),
|
||||
data={},
|
||||
)
|
||||
self.assertEqual(response.status_code, 400)
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:policy-test", kwargs={"pk": self.policy.pk}),
|
||||
data={
|
||||
"user": self.user.pk + 1,
|
||||
},
|
||||
)
|
||||
self.assertEqual(response.status_code, 400)
|
||||
|
||||
def test_types(self):
|
||||
"""Test Policy's types endpoint"""
|
||||
@ -35,3 +55,17 @@ class TestPoliciesAPI(APITestCase):
|
||||
reverse("authentik_api:policy-types"),
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_cache_info(self):
|
||||
"""Test Policy's cache_info endpoint"""
|
||||
response = self.client.get(
|
||||
reverse("authentik_api:policy-cache-info"),
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_cache_clear(self):
|
||||
"""Test Policy's cache_clear endpoint"""
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:policy-cache-clear"),
|
||||
)
|
||||
self.assertEqual(response.status_code, 204)
|
||||
|
||||
@ -10,6 +10,7 @@ from django.http.response import HttpResponseRedirect
|
||||
from django.utils.cache import patch_vary_headers
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.core.middleware import KEY_USER
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.providers.oauth2.errors import BearerTokenError
|
||||
from authentik.providers.oauth2.models import OAuth2Provider, RefreshToken
|
||||
@ -165,7 +166,10 @@ def protected_resource_view(scopes: list[str]):
|
||||
] = f'error="{error.code}", error_description="{error.description}"'
|
||||
return response
|
||||
kwargs["token"] = token
|
||||
return view(request, *args, **kwargs)
|
||||
response = view(request, *args, **kwargs)
|
||||
setattr(response, "ak_context", {})
|
||||
response.ak_context[KEY_USER] = token.user.username
|
||||
return response
|
||||
|
||||
return view_wrapper
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ class OpenIDConnectOAuth2Callback(OAuthCallback):
|
||||
info: dict[str, Any],
|
||||
) -> dict[str, Any]:
|
||||
return {
|
||||
"username": info.get("nickname"),
|
||||
"username": info.get("nickname", info.get("prefered_username")),
|
||||
"email": info.get("email"),
|
||||
"name": info.get("name"),
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ from rest_framework import mixins
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
||||
|
||||
from authentik.api.authorization import OwnerFilter, OwnerSuperuserPermissions
|
||||
from authentik.core.api.applications import ApplicationSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.core.api.users import UserSerializer
|
||||
@ -56,12 +57,9 @@ class UserConsentViewSet(
|
||||
serializer_class = UserConsentSerializer
|
||||
filterset_fields = ["user", "application"]
|
||||
ordering = ["application", "expires"]
|
||||
filter_backends = [
|
||||
DjangoFilterBackend,
|
||||
OrderingFilter,
|
||||
SearchFilter,
|
||||
]
|
||||
search_fields = ["user__username"]
|
||||
permission_classes = [OwnerSuperuserPermissions]
|
||||
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user if self.request else get_anonymous_user()
|
||||
|
||||
48
authentik/stages/prompt/migrations/0008_alter_prompt_type.py
Normal file
48
authentik/stages/prompt/migrations/0008_alter_prompt_type.py
Normal file
@ -0,0 +1,48 @@
|
||||
# Generated by Django 4.0.5 on 2022-06-26 21:27
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_stages_prompt", "0007_prompt_placeholder_expression"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="prompt",
|
||||
name="type",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("text", "Text: Simple Text input"),
|
||||
(
|
||||
"text_read_only",
|
||||
"Text (read-only): Simple Text input, but cannot be edited.",
|
||||
),
|
||||
(
|
||||
"username",
|
||||
"Username: Same as Text input, but checks for and prevents duplicate usernames.",
|
||||
),
|
||||
("email", "Email: Text field with Email type."),
|
||||
(
|
||||
"password",
|
||||
"Password: Masked input, password is validated against sources. Policies still have to be applied to this Stage. If two of these are used in the same stage, they are ensured to be identical.",
|
||||
),
|
||||
("number", "Number"),
|
||||
("checkbox", "Checkbox"),
|
||||
("date", "Date"),
|
||||
("date-time", "Date Time"),
|
||||
(
|
||||
"file",
|
||||
"File: File upload for arbitrary files. File content will be available in flow context as data-URI",
|
||||
),
|
||||
("separator", "Separator: Static Separator Line"),
|
||||
("hidden", "Hidden: Hidden field, can be used to insert data into form."),
|
||||
("static", "Static: Static value, displayed as-is."),
|
||||
("ak-locale", "authentik: Selection of locales authentik supports"),
|
||||
],
|
||||
max_length=100,
|
||||
),
|
||||
),
|
||||
]
|
||||
@ -1,11 +1,15 @@
|
||||
"""prompt models"""
|
||||
from base64 import b64decode
|
||||
from binascii import Error
|
||||
from typing import Any, Optional
|
||||
from urllib.parse import urlparse
|
||||
from uuid import uuid4
|
||||
|
||||
from django.db import models
|
||||
from django.http import HttpRequest
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views import View
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.fields import (
|
||||
BooleanField,
|
||||
CharField,
|
||||
@ -32,7 +36,7 @@ LOGGER = get_logger()
|
||||
class FieldTypes(models.TextChoices):
|
||||
"""Field types an Prompt can be"""
|
||||
|
||||
# update website/docs/flow/stages/prompt.index.md
|
||||
# update website/docs/flow/stages/prompt/index.md
|
||||
|
||||
# Simple text field
|
||||
TEXT = "text", _("Text: Simple Text input")
|
||||
@ -61,6 +65,14 @@ class FieldTypes(models.TextChoices):
|
||||
DATE = "date"
|
||||
DATE_TIME = "date-time"
|
||||
|
||||
FILE = (
|
||||
"file",
|
||||
_(
|
||||
"File: File upload for arbitrary files. File content will be available in flow "
|
||||
"context as data-URI"
|
||||
),
|
||||
)
|
||||
|
||||
SEPARATOR = "separator", _("Separator: Static Separator Line")
|
||||
HIDDEN = "hidden", _("Hidden: Hidden field, can be used to insert data into form.")
|
||||
STATIC = "static", _("Static: Static value, displayed as-is.")
|
||||
@ -68,6 +80,25 @@ class FieldTypes(models.TextChoices):
|
||||
AK_LOCALE = "ak-locale", _("authentik: Selection of locales authentik supports")
|
||||
|
||||
|
||||
class InlineFileField(CharField):
|
||||
"""Field for inline data-URI base64 encoded files"""
|
||||
|
||||
def to_internal_value(self, data: str):
|
||||
uri = urlparse(data)
|
||||
if uri.scheme != "data":
|
||||
raise ValidationError("Invalid scheme")
|
||||
header, encoded = uri.path.split(",", 1)
|
||||
_mime, _, enc = header.partition(";")
|
||||
if enc != "base64":
|
||||
raise ValidationError("Invalid encoding")
|
||||
try:
|
||||
data = b64decode(encoded.encode()).decode()
|
||||
except (UnicodeDecodeError, UnicodeEncodeError, ValueError, Error):
|
||||
LOGGER.info("failed to decode base64 of file field, keeping base64")
|
||||
data = encoded
|
||||
return super().to_internal_value(data)
|
||||
|
||||
|
||||
class Prompt(SerializerModel):
|
||||
"""Single Prompt, part of a prompt stage."""
|
||||
|
||||
@ -122,6 +153,8 @@ class Prompt(SerializerModel):
|
||||
kwargs["allow_blank"] = not self.required
|
||||
if self.type == FieldTypes.TEXT_READ_ONLY:
|
||||
field_class = ReadOnlyField
|
||||
# required can't be set for ReadOnlyField
|
||||
kwargs["required"] = False
|
||||
if self.type == FieldTypes.EMAIL:
|
||||
field_class = EmailField
|
||||
kwargs["allow_blank"] = not self.required
|
||||
@ -134,6 +167,8 @@ class Prompt(SerializerModel):
|
||||
field_class = DateField
|
||||
if self.type == FieldTypes.DATE_TIME:
|
||||
field_class = DateTimeField
|
||||
if self.type == FieldTypes.FILE:
|
||||
field_class = InlineFileField
|
||||
|
||||
if self.type == FieldTypes.SEPARATOR:
|
||||
kwargs["required"] = False
|
||||
|
||||
@ -3,7 +3,7 @@ from unittest.mock import MagicMock, patch
|
||||
|
||||
from django.test import RequestFactory
|
||||
from django.urls import reverse
|
||||
from rest_framework.exceptions import ErrorDetail
|
||||
from rest_framework.exceptions import ErrorDetail, ValidationError
|
||||
|
||||
from authentik.core.tests.utils import create_test_admin_user
|
||||
from authentik.flows.markers import StageMarker
|
||||
@ -13,7 +13,7 @@ from authentik.flows.tests import FlowTestCase
|
||||
from authentik.flows.views.executor import SESSION_KEY_PLAN
|
||||
from authentik.lib.generators import generate_id
|
||||
from authentik.policies.expression.models import ExpressionPolicy
|
||||
from authentik.stages.prompt.models import FieldTypes, Prompt, PromptStage
|
||||
from authentik.stages.prompt.models import FieldTypes, InlineFileField, Prompt, PromptStage
|
||||
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT, PromptChallengeResponse
|
||||
|
||||
|
||||
@ -110,6 +110,21 @@ class TestPromptStage(FlowTestCase):
|
||||
|
||||
self.binding = FlowStageBinding.objects.create(target=self.flow, stage=self.stage, order=2)
|
||||
|
||||
def test_inline_file_field(self):
|
||||
"""test InlineFileField"""
|
||||
with self.assertRaises(ValidationError):
|
||||
InlineFileField().to_internal_value("foo")
|
||||
with self.assertRaises(ValidationError):
|
||||
InlineFileField().to_internal_value("data:foo/bar;foo,qwer")
|
||||
self.assertEqual(
|
||||
InlineFileField().to_internal_value("data:mine/type;base64,Zm9v"),
|
||||
"foo",
|
||||
)
|
||||
self.assertEqual(
|
||||
InlineFileField().to_internal_value("data:mine/type;base64,Zm9vqwer"),
|
||||
"Zm9vqwer",
|
||||
)
|
||||
|
||||
def test_render(self):
|
||||
"""Test render of form, check if all prompts are rendered correctly"""
|
||||
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
|
||||
|
||||
@ -4,7 +4,7 @@ from typing import Any
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.fields import CharField, ListField
|
||||
from rest_framework.fields import CharField, ListField, ReadOnlyField
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
@ -76,6 +76,8 @@ class CurrentTenantSerializer(PassiveSerializer):
|
||||
flow_unenrollment = CharField(source="flow_unenrollment.slug", required=False)
|
||||
flow_user_settings = CharField(source="flow_user_settings.slug", required=False)
|
||||
|
||||
default_locale = ReadOnlyField()
|
||||
|
||||
|
||||
class TenantViewSet(UsedByMixin, ModelViewSet):
|
||||
"""Tenant Viewset"""
|
||||
|
||||
@ -65,6 +65,11 @@ class Tenant(models.Model):
|
||||
|
||||
attributes = models.JSONField(default=dict, blank=True)
|
||||
|
||||
@property
|
||||
def default_locale(self) -> str:
|
||||
"""Get default locale"""
|
||||
return self.attributes.get("settings", {}).get("locale", "")
|
||||
|
||||
def __str__(self) -> str:
|
||||
if self.default:
|
||||
return "Default tenant"
|
||||
|
||||
@ -24,6 +24,7 @@ class TestTenants(APITestCase):
|
||||
"branding_title": "authentik",
|
||||
"matched_domain": tenant.domain,
|
||||
"ui_footer_links": CONFIG.y("footer_links"),
|
||||
"default_locale": "",
|
||||
},
|
||||
)
|
||||
|
||||
@ -41,6 +42,7 @@ class TestTenants(APITestCase):
|
||||
"branding_title": "custom",
|
||||
"matched_domain": "bar.baz",
|
||||
"ui_footer_links": CONFIG.y("footer_links"),
|
||||
"default_locale": "",
|
||||
},
|
||||
)
|
||||
|
||||
@ -55,6 +57,7 @@ class TestTenants(APITestCase):
|
||||
"branding_title": "authentik",
|
||||
"matched_domain": "fallback",
|
||||
"ui_footer_links": CONFIG.y("footer_links"),
|
||||
"default_locale": "",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@ services:
|
||||
retries: 5
|
||||
timeout: 3s
|
||||
server:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2022.7.1}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2022.7.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.7.1}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2022.7.3}
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
environment:
|
||||
|
||||
10
go.mod
10
go.mod
@ -8,7 +8,7 @@ require (
|
||||
github.com/getsentry/sentry-go v0.13.0
|
||||
github.com/go-ldap/ldap/v3 v3.4.3
|
||||
github.com/go-openapi/runtime v0.24.1
|
||||
github.com/go-openapi/strfmt v0.21.2
|
||||
github.com/go-openapi/strfmt v0.21.3
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/handlers v1.5.1
|
||||
@ -21,12 +21,11 @@ require (
|
||||
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
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.12.2
|
||||
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/stretchr/testify v1.8.0
|
||||
goauthentik.io/api/v3 v3.2022063.5
|
||||
goauthentik.io/api/v3 v3.2022072.1
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
gopkg.in/boj/redistore.v1 v1.0.0-20160128113310-fc113767cd6b
|
||||
@ -52,7 +51,6 @@ require (
|
||||
github.com/go-openapi/spec v0.20.4 // indirect
|
||||
github.com/go-openapi/swag v0.21.1 // indirect
|
||||
github.com/go-openapi/validate v0.21.0 // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
@ -65,8 +63,8 @@ require (
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
go.mongodb.org/mongo-driver v1.8.3 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 // indirect
|
||||
go.mongodb.org/mongo-driver v1.10.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
|
||||
16
go.sum
16
go.sum
@ -112,8 +112,9 @@ github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1
|
||||
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
|
||||
github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg=
|
||||
github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k=
|
||||
github.com/go-openapi/strfmt v0.21.2 h1:5NDNgadiX1Vhemth/TH4gCGopWSTdDjxl60H3B7f+os=
|
||||
github.com/go-openapi/strfmt v0.21.2/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k=
|
||||
github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o=
|
||||
github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU=
|
||||
@ -121,7 +122,6 @@ github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/e
|
||||
github.com/go-openapi/validate v0.21.0 h1:+Wqk39yKOhfpLqNLEC0/eViCkzM5FVXVqrvt526+wcI=
|
||||
github.com/go-openapi/validate v0.21.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
|
||||
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
|
||||
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
|
||||
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
|
||||
@ -345,23 +345,26 @@ github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
|
||||
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
|
||||
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
|
||||
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg=
|
||||
go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
|
||||
go.mongodb.org/mongo-driver v1.8.3 h1:TDKlTkGDKm9kkJVUOAXDK5/fkqKHJVwYQSpoRfB43R4=
|
||||
go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
|
||||
go.mongodb.org/mongo-driver v1.10.0 h1:UtV6N5k14upNp4LTduX0QCufG124fSu25Wz9tu94GLg=
|
||||
go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
|
||||
goauthentik.io/api/v3 v3.2022063.5 h1:509uD/IdZp2yaYzJpHERAaX5vPU3KTuFFDxOi6U8KtY=
|
||||
goauthentik.io/api/v3 v3.2022063.5/go.mod h1:QM9J32HgYE4gL71lWAfAoXSPdSmLVLW08itfLI3Mo10=
|
||||
goauthentik.io/api/v3 v3.2022072.1 h1:VOtw22wuRNNDgfg4eLZ3ZToy1hejqY7NbrzyyRMwSo4=
|
||||
goauthentik.io/api/v3 v3.2022072.1/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=
|
||||
@ -371,8 +374,9 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o=
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
env "github.com/Netflix/go-env"
|
||||
"github.com/imdario/mergo"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
@ -35,15 +35,15 @@ func DefaultConfig() {
|
||||
func LoadConfig(path string) error {
|
||||
raw, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to load config file")
|
||||
return fmt.Errorf("Failed to load config file: %w", err)
|
||||
}
|
||||
nc := Config{}
|
||||
err = yaml.Unmarshal(raw, &nc)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to parse YAML")
|
||||
return fmt.Errorf("Failed to parse YAML: %w", err)
|
||||
}
|
||||
if err := mergo.Merge(&G, nc, mergo.WithOverride); err != nil {
|
||||
return errors.Wrap(err, "failed to overlay config")
|
||||
return fmt.Errorf("failed to overlay config: %w", err)
|
||||
}
|
||||
log.WithField("path", path).Debug("Loaded config")
|
||||
return nil
|
||||
@ -53,10 +53,10 @@ func FromEnv() error {
|
||||
nc := Config{}
|
||||
_, err := env.UnmarshalFromEnviron(&nc)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to load environment variables")
|
||||
return fmt.Errorf("failed to load environment variables: %w", err)
|
||||
}
|
||||
if err := mergo.Merge(&G, nc, mergo.WithOverride); err != nil {
|
||||
return errors.Wrap(err, "failed to overlay config")
|
||||
return fmt.Errorf("failed to overlay config: %w", err)
|
||||
}
|
||||
log.Debug("Loaded config from environment")
|
||||
return nil
|
||||
|
||||
@ -29,4 +29,4 @@ func UserAgent() string {
|
||||
return fmt.Sprintf("authentik@%s", FullVersion())
|
||||
}
|
||||
|
||||
const VERSION = "2022.7.1"
|
||||
const VERSION = "2022.7.3"
|
||||
|
||||
@ -17,7 +17,6 @@ import (
|
||||
sentryhttp "github.com/getsentry/sentry-go/http"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/api/v3"
|
||||
@ -155,13 +154,13 @@ func NewApplication(p api.ProxyOutpostConfig, c *http.Client, cs *ak.CryptoStore
|
||||
err = a.configureForward()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to configure application mode")
|
||||
return nil, fmt.Errorf("failed to configure application mode: %w", err)
|
||||
}
|
||||
|
||||
if kp := p.Certificate.Get(); kp != nil {
|
||||
err := cs.AddKeypair(*kp)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to initially fetch certificate")
|
||||
return nil, fmt.Errorf("failed to initially fetch certificate: %w", err)
|
||||
}
|
||||
a.Cert = cs.Get(*kp)
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
# Stage 1: Build
|
||||
FROM docker.io/golang:1.18.3-bullseye AS builder
|
||||
FROM docker.io/golang:1.18.4-bullseye AS builder
|
||||
|
||||
WORKDIR /go/src/goauthentik.io
|
||||
|
||||
|
||||
@ -51,7 +51,6 @@ def release_lock():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
conn = connect(
|
||||
dbname=CONFIG.y("postgresql.name"),
|
||||
user=CONFIG.y("postgresql.user"),
|
||||
|
||||
115
poetry.lock
generated
115
poetry.lock
generated
@ -369,7 +369,7 @@ tests = ["pytest", "pytest-django", "pytest-asyncio", "async-timeout", "coverage
|
||||
|
||||
[[package]]
|
||||
name = "channels-redis"
|
||||
version = "3.4.0"
|
||||
version = "3.4.1"
|
||||
description = "Redis-backed ASGI channel layer implementation"
|
||||
category = "main"
|
||||
optional = false
|
||||
@ -475,7 +475,7 @@ python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "coverage"
|
||||
version = "6.4.1"
|
||||
version = "6.4.2"
|
||||
description = "Code coverage measurement for Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
@ -666,7 +666,7 @@ hiredis = ["redis[hiredis] (>=3,!=4.0.0,!=4.0.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "django-silk"
|
||||
version = "5.0.0"
|
||||
version = "5.0.1"
|
||||
description = "Silky smooth profiling for the Django Framework"
|
||||
category = "dev"
|
||||
optional = false
|
||||
@ -1322,7 +1322,7 @@ tests = ["pytest (>=6.0.0,<7.0.0)", "coverage[toml] (==5.0.4)"]
|
||||
|
||||
[[package]]
|
||||
name = "pylint"
|
||||
version = "2.14.4"
|
||||
version = "2.14.5"
|
||||
description = "python code static checker"
|
||||
category = "dev"
|
||||
optional = false
|
||||
@ -1611,7 +1611,7 @@ urllib3 = {version = ">=1.26,<2.0", extras = ["secure", "socks"]}
|
||||
|
||||
[[package]]
|
||||
name = "sentry-sdk"
|
||||
version = "1.6.0"
|
||||
version = "1.7.2"
|
||||
description = "Python client for Sentry (https://sentry.io)"
|
||||
category = "main"
|
||||
optional = false
|
||||
@ -1965,7 +1965,7 @@ python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "webauthn"
|
||||
version = "1.5.2"
|
||||
version = "1.6.0"
|
||||
description = "Pythonic WebAuthn"
|
||||
category = "main"
|
||||
optional = false
|
||||
@ -2350,8 +2350,8 @@ channels = [
|
||||
{file = "channels-3.0.5.tar.gz", hash = "sha256:a3dc3339cc033e7c2afe083fb3dedf74fc5009815967e317e080e7bfdc92ea26"},
|
||||
]
|
||||
channels-redis = [
|
||||
{file = "channels_redis-3.4.0-py3-none-any.whl", hash = "sha256:6e4565b7c11c6bcde5d48556cb83bd043779697ff03811867d2f895aa6170d56"},
|
||||
{file = "channels_redis-3.4.0.tar.gz", hash = "sha256:5dffd4cc16174125bd4043fc8fe7462ca7403cf801d59a9fa7410ed101fa6a57"},
|
||||
{file = "channels_redis-3.4.1-py3-none-any.whl", hash = "sha256:ba7e2ad170f273c372812dd32aaac102d68d4e508172abb1cfda3160b7333890"},
|
||||
{file = "channels_redis-3.4.1.tar.gz", hash = "sha256:78e4a2f2b2a744fe5a87848ec36b5ee49f522c6808cefe6c583663d0d531faa8"},
|
||||
]
|
||||
charset-normalizer = [
|
||||
{file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"},
|
||||
@ -2386,47 +2386,47 @@ constantly = [
|
||||
{file = "constantly-15.1.0.tar.gz", hash = "sha256:586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35"},
|
||||
]
|
||||
coverage = [
|
||||
{file = "coverage-6.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f1d5aa2703e1dab4ae6cf416eb0095304f49d004c39e9db1d86f57924f43006b"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4ce1b258493cbf8aec43e9b50d89982346b98e9ffdfaae8ae5793bc112fb0068"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83c4e737f60c6936460c5be330d296dd5b48b3963f48634c53b3f7deb0f34ec4"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84e65ef149028516c6d64461b95a8dbcfce95cfd5b9eb634320596173332ea84"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f69718750eaae75efe506406c490d6fc5a6161d047206cc63ce25527e8a3adad"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e57816f8ffe46b1df8f12e1b348f06d164fd5219beba7d9433ba79608ef011cc"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:01c5615d13f3dd3aa8543afc069e5319cfa0c7d712f6e04b920431e5c564a749"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:75ab269400706fab15981fd4bd5080c56bd5cc07c3bccb86aab5e1d5a88dc8f4"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-win32.whl", hash = "sha256:a7f3049243783df2e6cc6deafc49ea123522b59f464831476d3d1448e30d72df"},
|
||||
{file = "coverage-6.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:ee2ddcac99b2d2aec413e36d7a429ae9ebcadf912946b13ffa88e7d4c9b712d6"},
|
||||
{file = "coverage-6.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb73e0011b8793c053bfa85e53129ba5f0250fdc0392c1591fd35d915ec75c46"},
|
||||
{file = "coverage-6.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106c16dfe494de3193ec55cac9640dd039b66e196e4641fa8ac396181578b982"},
|
||||
{file = "coverage-6.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87f4f3df85aa39da00fd3ec4b5abeb7407e82b68c7c5ad181308b0e2526da5d4"},
|
||||
{file = "coverage-6.4.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:961e2fb0680b4f5ad63234e0bf55dfb90d302740ae9c7ed0120677a94a1590cb"},
|
||||
{file = "coverage-6.4.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:cec3a0f75c8f1031825e19cd86ee787e87cf03e4fd2865c79c057092e69e3a3b"},
|
||||
{file = "coverage-6.4.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:129cd05ba6f0d08a766d942a9ed4b29283aff7b2cccf5b7ce279d50796860bb3"},
|
||||
{file = "coverage-6.4.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bf5601c33213d3cb19d17a796f8a14a9eaa5e87629a53979a5981e3e3ae166f6"},
|
||||
{file = "coverage-6.4.1-cp37-cp37m-win32.whl", hash = "sha256:269eaa2c20a13a5bf17558d4dc91a8d078c4fa1872f25303dddcbba3a813085e"},
|
||||
{file = "coverage-6.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f02cbbf8119db68455b9d763f2f8737bb7db7e43720afa07d8eb1604e5c5ae28"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ffa9297c3a453fba4717d06df579af42ab9a28022444cae7fa605af4df612d54"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:145f296d00441ca703a659e8f3eb48ae39fb083baba2d7ce4482fb2723e050d9"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d44996140af8b84284e5e7d398e589574b376fb4de8ccd28d82ad8e3bea13"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2bd9a6fc18aab8d2e18f89b7ff91c0f34ff4d5e0ba0b33e989b3cd4194c81fd9"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3384f2a3652cef289e38100f2d037956194a837221edd520a7ee5b42d00cc605"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9b3e07152b4563722be523e8cd0b209e0d1a373022cfbde395ebb6575bf6790d"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1480ff858b4113db2718848d7b2d1b75bc79895a9c22e76a221b9d8d62496428"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:865d69ae811a392f4d06bde506d531f6a28a00af36f5c8649684a9e5e4a85c83"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-win32.whl", hash = "sha256:664a47ce62fe4bef9e2d2c430306e1428ecea207ffd68649e3b942fa8ea83b0b"},
|
||||
{file = "coverage-6.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:26dff09fb0d82693ba9e6231248641d60ba606150d02ed45110f9ec26404ed1c"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d9c80df769f5ec05ad21ea34be7458d1dc51ff1fb4b2219e77fe24edf462d6df"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:39ee53946bf009788108b4dd2894bf1349b4e0ca18c2016ffa7d26ce46b8f10d"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5b66caa62922531059bc5ac04f836860412f7f88d38a476eda0a6f11d4724f4"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd180ed867e289964404051a958f7cccabdeed423f91a899829264bb7974d3d3"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84631e81dd053e8a0d4967cedab6db94345f1c36107c71698f746cb2636c63e3"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8c08da0bd238f2970230c2a0d28ff0e99961598cb2e810245d7fc5afcf1254e8"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d42c549a8f41dc103a8004b9f0c433e2086add8a719da00e246e17cbe4056f72"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:309ce4a522ed5fca432af4ebe0f32b21d6d7ccbb0f5fcc99290e71feba67c264"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-win32.whl", hash = "sha256:fdb6f7bd51c2d1714cea40718f6149ad9be6a2ee7d93b19e9f00934c0f2a74d9"},
|
||||
{file = "coverage-6.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:342d4aefd1c3e7f620a13f4fe563154d808b69cccef415415aece4c786665397"},
|
||||
{file = "coverage-6.4.1-pp36.pp37.pp38-none-any.whl", hash = "sha256:4803e7ccf93230accb928f3a68f00ffa80a88213af98ed338a57ad021ef06815"},
|
||||
{file = "coverage-6.4.1.tar.gz", hash = "sha256:4321f075095a096e70aff1d002030ee612b65a205a0a0f5b815280d5dc58100c"},
|
||||
{file = "coverage-6.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a9032f9b7d38bdf882ac9f66ebde3afb8145f0d4c24b2e600bc4c6304aafb87e"},
|
||||
{file = "coverage-6.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e0524adb49c716ca763dbc1d27bedce36b14f33e6b8af6dba56886476b42957c"},
|
||||
{file = "coverage-6.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4548be38a1c810d79e097a38107b6bf2ff42151900e47d49635be69943763d8"},
|
||||
{file = "coverage-6.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f23876b018dfa5d3e98e96f5644b109090f16a4acb22064e0f06933663005d39"},
|
||||
{file = "coverage-6.4.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fe75dcfcb889b6800f072f2af5a331342d63d0c1b3d2bf0f7b4f6c353e8c9c0"},
|
||||
{file = "coverage-6.4.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2f8553878a24b00d5ab04b7a92a2af50409247ca5c4b7a2bf4eabe94ed20d3ee"},
|
||||
{file = "coverage-6.4.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:d774d9e97007b018a651eadc1b3970ed20237395527e22cbeb743d8e73e0563d"},
|
||||
{file = "coverage-6.4.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d56f105592188ce7a797b2bd94b4a8cb2e36d5d9b0d8a1d2060ff2a71e6b9bbc"},
|
||||
{file = "coverage-6.4.2-cp310-cp310-win32.whl", hash = "sha256:d230d333b0be8042ac34808ad722eabba30036232e7a6fb3e317c49f61c93386"},
|
||||
{file = "coverage-6.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:5ef42e1db047ca42827a85e34abe973971c635f83aed49611b7f3ab49d0130f0"},
|
||||
{file = "coverage-6.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:25b7ec944f114f70803d6529394b64f8749e93cbfac0fe6c5ea1b7e6c14e8a46"},
|
||||
{file = "coverage-6.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bb00521ab4f99fdce2d5c05a91bddc0280f0afaee0e0a00425e28e209d4af07"},
|
||||
{file = "coverage-6.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dff52b3e7f76ada36f82124703f4953186d9029d00d6287f17c68a75e2e6039"},
|
||||
{file = "coverage-6.4.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:147605e1702d996279bb3cc3b164f408698850011210d133a2cb96a73a2f7996"},
|
||||
{file = "coverage-6.4.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:422fa44070b42fef9fb8dabd5af03861708cdd6deb69463adc2130b7bf81332f"},
|
||||
{file = "coverage-6.4.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:8af6c26ba8df6338e57bedbf916d76bdae6308e57fc8f14397f03b5da8622b4e"},
|
||||
{file = "coverage-6.4.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5336e0352c0b12c7e72727d50ff02557005f79a0b8dcad9219c7c4940a930083"},
|
||||
{file = "coverage-6.4.2-cp37-cp37m-win32.whl", hash = "sha256:0f211df2cba951ffcae210ee00e54921ab42e2b64e0bf2c0befc977377fb09b7"},
|
||||
{file = "coverage-6.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a13772c19619118903d65a91f1d5fea84be494d12fd406d06c849b00d31bf120"},
|
||||
{file = "coverage-6.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f7bd0ffbcd03dc39490a1f40b2669cc414fae0c4e16b77bb26806a4d0b7d1452"},
|
||||
{file = "coverage-6.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0895ea6e6f7f9939166cc835df8fa4599e2d9b759b02d1521b574e13b859ac32"},
|
||||
{file = "coverage-6.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e7ced84a11c10160c0697a6cc0b214a5d7ab21dfec1cd46e89fbf77cc66fae"},
|
||||
{file = "coverage-6.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80db4a47a199c4563d4a25919ff29c97c87569130375beca3483b41ad5f698e8"},
|
||||
{file = "coverage-6.4.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3def6791adf580d66f025223078dc84c64696a26f174131059ce8e91452584e1"},
|
||||
{file = "coverage-6.4.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4f89d8e03c8a3757aae65570d14033e8edf192ee9298303db15955cadcff0c63"},
|
||||
{file = "coverage-6.4.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6d0b48aff8e9720bdec315d67723f0babd936a7211dc5df453ddf76f89c59933"},
|
||||
{file = "coverage-6.4.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2b20286c2b726f94e766e86a3fddb7b7e37af5d0c635bdfa7e4399bc523563de"},
|
||||
{file = "coverage-6.4.2-cp38-cp38-win32.whl", hash = "sha256:d714af0bdba67739598849c9f18efdcc5a0412f4993914a0ec5ce0f1e864d783"},
|
||||
{file = "coverage-6.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:5f65e5d3ff2d895dab76b1faca4586b970a99b5d4b24e9aafffc0ce94a6022d6"},
|
||||
{file = "coverage-6.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a697977157adc052284a7160569b36a8bbec09db3c3220642e6323b47cec090f"},
|
||||
{file = "coverage-6.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c77943ef768276b61c96a3eb854eba55633c7a3fddf0a79f82805f232326d33f"},
|
||||
{file = "coverage-6.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54d8d0e073a7f238f0666d3c7c0d37469b2aa43311e4024c925ee14f5d5a1cbe"},
|
||||
{file = "coverage-6.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f22325010d8824594820d6ce84fa830838f581a7fd86a9235f0d2ed6deb61e29"},
|
||||
{file = "coverage-6.4.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24b04d305ea172ccb21bee5bacd559383cba2c6fcdef85b7701cf2de4188aa55"},
|
||||
{file = "coverage-6.4.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:866ebf42b4c5dbafd64455b0a1cd5aa7b4837a894809413b930026c91e18090b"},
|
||||
{file = "coverage-6.4.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e36750fbbc422c1c46c9d13b937ab437138b998fe74a635ec88989afb57a3978"},
|
||||
{file = "coverage-6.4.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:79419370d6a637cb18553ecb25228893966bd7935a9120fa454e7076f13b627c"},
|
||||
{file = "coverage-6.4.2-cp39-cp39-win32.whl", hash = "sha256:b5e28db9199dd3833cc8a07fa6cf429a01227b5d429facb56eccd765050c26cd"},
|
||||
{file = "coverage-6.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:edfdabe7aa4f97ed2b9dd5dde52d2bb29cb466993bb9d612ddd10d0085a683cf"},
|
||||
{file = "coverage-6.4.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:e2618cb2cf5a7cc8d698306e42ebcacd02fb7ef8cfc18485c59394152c70be97"},
|
||||
{file = "coverage-6.4.2.tar.gz", hash = "sha256:6c3ccfe89c36f3e5b9837b9ee507472310164f352c9fe332120b764c9d60adbe"},
|
||||
]
|
||||
cryptography = [
|
||||
{file = "cryptography-37.0.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:ef15c2df7656763b4ff20a9bc4381d8352e6640cfeb95c2972c38ef508e75181"},
|
||||
@ -2505,8 +2505,8 @@ django-redis = [
|
||||
{file = "django_redis-5.2.0-py3-none-any.whl", hash = "sha256:1d037dc02b11ad7aa11f655d26dac3fb1af32630f61ef4428860a2e29ff92026"},
|
||||
]
|
||||
django-silk = [
|
||||
{file = "django-silk-5.0.0.tar.gz", hash = "sha256:d60f71dde2662917eeaf2f579ccd114a1eb1d47c796c146d2e4537457fcb1416"},
|
||||
{file = "django_silk-5.0.0-py3-none-any.whl", hash = "sha256:66060bc58a2c708303f8a97dffeec2b276fc50d25400955e5e63ddd865fa5463"},
|
||||
{file = "django-silk-5.0.1.tar.gz", hash = "sha256:3bdf188256fff00d1ce741f9ffa7cfa1f37f6941f07c23bc85ff26466170eb30"},
|
||||
{file = "django_silk-5.0.1-py3-none-any.whl", hash = "sha256:9dad85e783fcaaa1c97bebfa7ea01899428ded55b517d363f25ba87e43b5ce50"},
|
||||
]
|
||||
djangorestframework = [
|
||||
{file = "djangorestframework-3.13.1-py3-none-any.whl", hash = "sha256:24c4bf58ed7e85d1fe4ba250ab2da926d263cd57d64b03e8dcef0ac683f8b1aa"},
|
||||
@ -2797,7 +2797,6 @@ lxml = [
|
||||
{file = "lxml-4.9.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4cfbe42c686f33944e12f45a27d25a492cc0e43e1dc1da5d6a87cbcaf2e95627"},
|
||||
{file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dad7b164905d3e534883281c050180afcf1e230c3d4a54e8038aa5cfcf312b84"},
|
||||
{file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a614e4afed58c14254e67862456d212c4dcceebab2eaa44d627c2ca04bf86837"},
|
||||
{file = "lxml-4.9.1-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:49a866923e69bc7da45a0565636243707c22752fc38f6b9d5c8428a86121022c"},
|
||||
{file = "lxml-4.9.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f9ced82717c7ec65a67667bb05865ffe38af0e835cdd78728f1209c8fffe0cad"},
|
||||
{file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:d9fc0bf3ff86c17348dfc5d322f627d78273eba545db865c3cd14b3f19e57fa5"},
|
||||
{file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e5f66bdf0976ec667fc4594d2812a00b07ed14d1b44259d19a41ae3fff99f2b8"},
|
||||
@ -3244,8 +3243,8 @@ pyjwt = [
|
||||
{file = "PyJWT-2.4.0.tar.gz", hash = "sha256:d42908208c699b3b973cbeb01a969ba6a96c821eefb1c5bfe4c390c01d67abba"},
|
||||
]
|
||||
pylint = [
|
||||
{file = "pylint-2.14.4-py3-none-any.whl", hash = "sha256:89b61867db16eefb7b3c5b84afc94081edaf11544189e2b238154677529ad69f"},
|
||||
{file = "pylint-2.14.4.tar.gz", hash = "sha256:47705453aa9dce520e123a7d51843d5f0032cbfa06870f89f00927aa1f735a4a"},
|
||||
{file = "pylint-2.14.5-py3-none-any.whl", hash = "sha256:fabe30000de7d07636d2e82c9a518ad5ad7908590fe135ace169b44839c15f90"},
|
||||
{file = "pylint-2.14.5.tar.gz", hash = "sha256:487ce2192eee48211269a0e976421f334cf94de1806ca9d0a99449adcdf0285e"},
|
||||
]
|
||||
pylint-django = [
|
||||
{file = "pylint-django-2.5.3.tar.gz", hash = "sha256:0ac090d106c62fe33782a1d01bda1610b761bb1c9bf5035ced9d5f23a13d8591"},
|
||||
@ -3400,8 +3399,8 @@ selenium = [
|
||||
{file = "selenium-4.3.0-py3-none-any.whl", hash = "sha256:f67402b8f973aaa98d9c55b8f9aa63532009cd1859b2222a8b9800354942d8bc"},
|
||||
]
|
||||
sentry-sdk = [
|
||||
{file = "sentry-sdk-1.6.0.tar.gz", hash = "sha256:b82ad57306d5546713f15d5d70daea0408cf7f998c7566db16e0e6257e51e561"},
|
||||
{file = "sentry_sdk-1.6.0-py2.py3-none-any.whl", hash = "sha256:ddbd191b6f4e696b7845b4d87389898ae1207981faf114f968a57363aa6be03c"},
|
||||
{file = "sentry-sdk-1.7.2.tar.gz", hash = "sha256:95fd321f583dfcfaf279a0b2cdc83d8d28c8b7cca4d2959fc4539bb4fecb56a0"},
|
||||
{file = "sentry_sdk-1.7.2-py2.py3-none-any.whl", hash = "sha256:6f460da98b730d671510af18f119f96d01e3ba027ac0e985871abb3aede1c514"},
|
||||
]
|
||||
service-identity = [
|
||||
{file = "service-identity-21.1.0.tar.gz", hash = "sha256:6e6c6086ca271dc11b033d17c3a8bea9f24ebff920c587da090afc9519419d34"},
|
||||
@ -3546,8 +3545,8 @@ wcwidth = [
|
||||
{file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
|
||||
]
|
||||
webauthn = [
|
||||
{file = "webauthn-1.5.2-py3-none-any.whl", hash = "sha256:85b0780329755d3bb0cf9bf456002cddddf8718daa42293316d26c09c1eceec4"},
|
||||
{file = "webauthn-1.5.2.tar.gz", hash = "sha256:44d57d953d712ac3db543b77ad69f176dc7ec531bd677e779951e3380ee6f5e6"},
|
||||
{file = "webauthn-1.6.0-py3-none-any.whl", hash = "sha256:6811b3f1b5ff627dadfe9685a1eaf80cbb5689c35f9ae00d4ee63681c0dd64b2"},
|
||||
{file = "webauthn-1.6.0.tar.gz", hash = "sha256:9c74b0e4aea4579fbf0ecb77a72d0b1cb7d7dcab7ca2d105474925b731178686"},
|
||||
]
|
||||
websocket-client = [
|
||||
{file = "websocket-client-1.3.2.tar.gz", hash = "sha256:50b21db0058f7a953d67cc0445be4b948d7fc196ecbeb8083d68d94628e4abf6"},
|
||||
|
||||
@ -7,7 +7,7 @@ ENV NODE_ENV=production
|
||||
RUN cd /static && npm ci && npm run build-proxy
|
||||
|
||||
# Stage 2: Build
|
||||
FROM docker.io/golang:1.18.3-bullseye AS builder
|
||||
FROM docker.io/golang:1.18.4-bullseye AS builder
|
||||
|
||||
WORKDIR /go/src/goauthentik.io
|
||||
|
||||
|
||||
@ -90,7 +90,7 @@ addopts = "-p no:celery --junitxml=unittest.xml"
|
||||
|
||||
[tool.poetry]
|
||||
name = "authentik"
|
||||
version = "2022.7.1"
|
||||
version = "2022.7.3"
|
||||
description = ""
|
||||
authors = ["authentik Team <hello@goauthentik.io>"]
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: authentik
|
||||
version: 2022.7.1
|
||||
version: 2022.7.3
|
||||
description: Making authentication simple.
|
||||
contact:
|
||||
email: hello@goauthentik.io
|
||||
@ -17741,6 +17741,7 @@ paths:
|
||||
- date
|
||||
- date-time
|
||||
- email
|
||||
- file
|
||||
- hidden
|
||||
- number
|
||||
- password
|
||||
@ -20658,10 +20659,14 @@ components:
|
||||
type: string
|
||||
flow_user_settings:
|
||||
type: string
|
||||
default_locale:
|
||||
type: string
|
||||
readOnly: true
|
||||
required:
|
||||
- branding_favicon
|
||||
- branding_logo
|
||||
- branding_title
|
||||
- default_locale
|
||||
- matched_domain
|
||||
- ui_footer_links
|
||||
DeniedActionEnum:
|
||||
@ -29238,6 +29243,7 @@ components:
|
||||
- checkbox
|
||||
- date
|
||||
- date-time
|
||||
- file
|
||||
- separator
|
||||
- hidden
|
||||
- static
|
||||
|
||||
1874
web/package-lock.json
generated
1874
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -52,20 +52,20 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.18.6",
|
||||
"@babel/plugin-proposal-decorators": "^7.18.6",
|
||||
"@babel/plugin-transform-runtime": "^7.18.6",
|
||||
"@babel/preset-env": "^7.18.6",
|
||||
"@babel/core": "^7.18.9",
|
||||
"@babel/plugin-proposal-decorators": "^7.18.9",
|
||||
"@babel/plugin-transform-runtime": "^7.18.9",
|
||||
"@babel/preset-env": "^7.18.9",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@codemirror/lang-html": "^6.1.0",
|
||||
"@codemirror/lang-javascript": "^6.0.1",
|
||||
"@codemirror/lang-python": "^6.0.0",
|
||||
"@codemirror/lang-xml": "^6.0.0",
|
||||
"@codemirror/legacy-modes": "^6.1.0",
|
||||
"@formatjs/intl-listformat": "^7.0.2",
|
||||
"@formatjs/intl-listformat": "^7.0.3",
|
||||
"@fortawesome/fontawesome-free": "^6.1.1",
|
||||
"@goauthentik/api": "^2022.6.3-1656957989",
|
||||
"@jackfranklin/rollup-plugin-markdown": "^0.3.0",
|
||||
"@goauthentik/api": "^2022.7.2-1657137907",
|
||||
"@jackfranklin/rollup-plugin-markdown": "^0.4.0",
|
||||
"@lingui/cli": "^3.14.0",
|
||||
"@lingui/core": "^3.14.0",
|
||||
"@lingui/detect-locale": "^3.14.0",
|
||||
@ -78,15 +78,15 @@
|
||||
"@rollup/plugin-node-resolve": "^13.3.0",
|
||||
"@rollup/plugin-replace": "^4.0.0",
|
||||
"@rollup/plugin-typescript": "^8.3.3",
|
||||
"@sentry/browser": "^7.4.1",
|
||||
"@sentry/tracing": "^7.4.1",
|
||||
"@sentry/browser": "^7.7.0",
|
||||
"@sentry/tracing": "^7.7.0",
|
||||
"@squoosh/cli": "^0.7.2",
|
||||
"@trivago/prettier-plugin-sort-imports": "^3.2.0",
|
||||
"@trivago/prettier-plugin-sort-imports": "^3.3.0",
|
||||
"@types/chart.js": "^2.9.37",
|
||||
"@types/codemirror": "5.60.5",
|
||||
"@types/grecaptcha": "^3.0.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.30.4",
|
||||
"@typescript-eslint/parser": "^5.30.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.30.7",
|
||||
"@typescript-eslint/parser": "^5.30.7",
|
||||
"@webcomponents/webcomponentsjs": "^2.6.0",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
"babel-plugin-tsconfig-paths": "^1.0.3",
|
||||
@ -96,17 +96,17 @@
|
||||
"codemirror": "^6.0.1",
|
||||
"construct-style-sheets-polyfill": "^3.1.0",
|
||||
"country-flag-icons": "^1.5.5",
|
||||
"eslint": "^8.19.0",
|
||||
"eslint": "^8.20.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-custom-elements": "0.0.6",
|
||||
"eslint-plugin-lit": "^1.6.1",
|
||||
"flowchart.js": "^1.17.1",
|
||||
"fuse.js": "^6.6.2",
|
||||
"lit": "^2.2.7",
|
||||
"moment": "^2.29.3",
|
||||
"moment": "^2.29.4",
|
||||
"prettier": "^2.7.1",
|
||||
"rapidoc": "^9.3.2",
|
||||
"rollup": "^2.75.7",
|
||||
"rapidoc": "^9.3.3",
|
||||
"rollup": "^2.77.0",
|
||||
"rollup-plugin-copy": "^3.4.0",
|
||||
"rollup-plugin-cssimport": "^1.0.2",
|
||||
"rollup-plugin-minify-html-literals": "^1.2.6",
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { VERSION } from "@goauthentik/web/constants";
|
||||
import { MessageMiddleware } from "@goauthentik/web/elements/messages/Middleware";
|
||||
import { APIMiddleware } from "@goauthentik/web/elements/notifications/APIDrawer";
|
||||
import { activateLocale } from "@goauthentik/web/interfaces/locale";
|
||||
import { getCookie } from "@goauthentik/web/utils";
|
||||
|
||||
import {
|
||||
@ -34,28 +35,39 @@ export function config(): Promise<Config> {
|
||||
return globalConfigPromise;
|
||||
}
|
||||
|
||||
export function tenantSetFavicon(tenant: CurrentTenant) {
|
||||
/**
|
||||
* <link rel="icon" href="/static/dist/assets/icons/icon.png">
|
||||
* <link rel="shortcut icon" href="/static/dist/assets/icons/icon.png">
|
||||
*/
|
||||
const rels = ["icon", "shortcut icon"];
|
||||
rels.forEach((rel) => {
|
||||
let relIcon = document.head.querySelector<HTMLLinkElement>(`link[rel='${rel}']`);
|
||||
if (!relIcon) {
|
||||
relIcon = document.createElement("link");
|
||||
relIcon.rel = rel;
|
||||
document.getElementsByTagName("head")[0].appendChild(relIcon);
|
||||
}
|
||||
relIcon.href = tenant.brandingFavicon;
|
||||
});
|
||||
}
|
||||
|
||||
export function tenantSetLocale(tenant: CurrentTenant) {
|
||||
if (tenant.defaultLocale === "") {
|
||||
return;
|
||||
}
|
||||
console.debug("authentik/locale: setting locale from tenant default");
|
||||
activateLocale(tenant.defaultLocale);
|
||||
}
|
||||
|
||||
let globalTenantPromise: Promise<CurrentTenant>;
|
||||
export function tenant(): Promise<CurrentTenant> {
|
||||
if (!globalTenantPromise) {
|
||||
globalTenantPromise = new CoreApi(DEFAULT_CONFIG)
|
||||
.coreTenantsCurrentRetrieve()
|
||||
.then((tenant) => {
|
||||
/**
|
||||
* <link rel="icon" href="/static/dist/assets/icons/icon.png">
|
||||
* <link rel="shortcut icon" href="/static/dist/assets/icons/icon.png">
|
||||
*/
|
||||
const rels = ["icon", "shortcut icon"];
|
||||
rels.forEach((rel) => {
|
||||
let relIcon = document.head.querySelector<HTMLLinkElement>(
|
||||
`link[rel='${rel}']`,
|
||||
);
|
||||
if (!relIcon) {
|
||||
relIcon = document.createElement("link");
|
||||
relIcon.rel = rel;
|
||||
document.getElementsByTagName("head")[0].appendChild(relIcon);
|
||||
}
|
||||
relIcon.href = tenant.brandingFavicon;
|
||||
});
|
||||
tenantSetFavicon(tenant);
|
||||
tenantSetLocale(tenant);
|
||||
return tenant;
|
||||
});
|
||||
}
|
||||
|
||||
14
web/src/api/Global.ts
Normal file
14
web/src/api/Global.ts
Normal file
@ -0,0 +1,14 @@
|
||||
export interface GlobalAuthentik {
|
||||
locale?: string;
|
||||
flow?: {
|
||||
layout: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface AuthentikWindow {
|
||||
authentik?: GlobalAuthentik;
|
||||
}
|
||||
|
||||
export function globalAK(): GlobalAuthentik | undefined {
|
||||
return (window as unknown as AuthentikWindow).authentik;
|
||||
}
|
||||
@ -3,7 +3,7 @@ export const SUCCESS_CLASS = "pf-m-success";
|
||||
export const ERROR_CLASS = "pf-m-danger";
|
||||
export const PROGRESS_CLASS = "pf-m-in-progress";
|
||||
export const CURRENT_CLASS = "pf-m-current";
|
||||
export const VERSION = "2022.7.1";
|
||||
export const VERSION = "2022.7.3";
|
||||
export const TITLE_DEFAULT = "authentik";
|
||||
export const ROUTE_SEPARATOR = ";";
|
||||
|
||||
|
||||
@ -85,8 +85,22 @@ export class CodeMirrorTextarea extends LitElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.theme = new Compartment();
|
||||
this.themeLight = EditorView.theme({}, { dark: false });
|
||||
this.themeDark = EditorView.theme({}, { dark: true });
|
||||
this.themeLight = EditorView.theme(
|
||||
{
|
||||
"&": {
|
||||
backgroundColor: "var(--pf-global--BackgroundColor--light-300)",
|
||||
},
|
||||
},
|
||||
{ dark: false },
|
||||
);
|
||||
this.themeDark = EditorView.theme(
|
||||
{
|
||||
"&": {
|
||||
backgroundColor: "var(--ak-dark-background-light)",
|
||||
},
|
||||
},
|
||||
{ dark: true },
|
||||
);
|
||||
}
|
||||
|
||||
private getInnerValue(): string {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { DEFAULT_CONFIG, tenant } from "@goauthentik/web/api/Config";
|
||||
import { globalAK } from "@goauthentik/web/api/Global";
|
||||
import { configureSentry } from "@goauthentik/web/api/Sentry";
|
||||
import { WebsocketClient } from "@goauthentik/web/common/ws";
|
||||
import { EVENT_FLOW_ADVANCE, TITLE_DEFAULT } from "@goauthentik/web/constants";
|
||||
@ -46,14 +47,6 @@ import {
|
||||
|
||||
import { StageHost } from "./stages/base";
|
||||
|
||||
export interface FlowWindow extends Window {
|
||||
authentik: {
|
||||
flow: {
|
||||
layout: LayoutEnum;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@customElement("ak-flow-executor")
|
||||
export class FlowExecutor extends LitElement implements StageHost {
|
||||
flowSlug?: string;
|
||||
@ -435,7 +428,7 @@ export class FlowExecutor extends LitElement implements StageHost {
|
||||
}
|
||||
|
||||
getLayout(): string {
|
||||
const prefilledFlow = (window as unknown as FlowWindow).authentik.flow.layout;
|
||||
const prefilledFlow = globalAK().flow?.layout || LayoutEnum.Stacked;
|
||||
if (this.challenge) {
|
||||
return this.challenge?.flowInfo?.layout || prefilledFlow;
|
||||
}
|
||||
|
||||
@ -12,6 +12,17 @@ export interface StageHost {
|
||||
readonly tenant: CurrentTenant;
|
||||
}
|
||||
|
||||
export function readFileAsync(file: Blob) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
resolve(reader.result);
|
||||
};
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
export class BaseStage<Tin, Tout> extends LitElement {
|
||||
host!: StageHost;
|
||||
|
||||
@ -24,7 +35,14 @@ export class BaseStage<Tin, Tout> extends LitElement {
|
||||
[key: string]: unknown;
|
||||
} = {};
|
||||
const form = new FormData(this.shadowRoot?.querySelector("form") || undefined);
|
||||
form.forEach((value, key) => (object[key] = value));
|
||||
|
||||
for await (const [key, value] of form.entries()) {
|
||||
if (value instanceof Blob) {
|
||||
object[key] = await readFileAsync(value);
|
||||
} else {
|
||||
object[key] = value;
|
||||
}
|
||||
}
|
||||
return this.host?.submit(object as unknown as Tout).then((successful) => {
|
||||
if (successful) {
|
||||
this.cleanup();
|
||||
|
||||
@ -96,6 +96,13 @@ export class PromptStage extends BaseStage<PromptChallenge, PromptChallengeRespo
|
||||
placeholder="${prompt.placeholder}"
|
||||
class="pf-c-form-control"
|
||||
?required=${prompt.required}>`;
|
||||
case PromptTypeEnum.File:
|
||||
return `<input
|
||||
type="file"
|
||||
name="${prompt.fieldKey}"
|
||||
placeholder="${prompt.placeholder}"
|
||||
class="pf-c-form-control"
|
||||
?required=${prompt.required}>`;
|
||||
case PromptTypeEnum.Separator:
|
||||
return `<ak-divider>${prompt.placeholder}</ak-divider>`;
|
||||
case PromptTypeEnum.Hidden:
|
||||
@ -133,7 +140,7 @@ export class PromptStage extends BaseStage<PromptChallenge, PromptChallengeRespo
|
||||
return html`<p class="pf-c-form__helper-text">${unsafeHTML(prompt.subText)}</p>`;
|
||||
}
|
||||
|
||||
shouldRenderInWrapper(prompt: StagePrompt): bool {
|
||||
shouldRenderInWrapper(prompt: StagePrompt): boolean {
|
||||
// Special types that aren't rendered in a wrapper
|
||||
if (
|
||||
prompt.type === PromptTypeEnum.Static ||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { globalAK } from "@goauthentik/web/api/Global";
|
||||
|
||||
import { Messages, i18n } from "@lingui/core";
|
||||
import { detect, fromNavigator, fromUrl } from "@lingui/detect-locale";
|
||||
import { t } from "@lingui/macro";
|
||||
@ -121,7 +123,14 @@ const DEFAULT_FALLBACK = () => "en";
|
||||
|
||||
export function autoDetectLanguage() {
|
||||
const detected =
|
||||
detect(fromUrl("locale"), fromNavigator(), DEFAULT_FALLBACK) || DEFAULT_FALLBACK();
|
||||
detect(
|
||||
() => {
|
||||
return globalAK()?.locale;
|
||||
},
|
||||
fromUrl("locale"),
|
||||
fromNavigator(),
|
||||
DEFAULT_FALLBACK,
|
||||
) || DEFAULT_FALLBACK();
|
||||
const locales = [detected];
|
||||
// For now we only care about the first locale part
|
||||
if (detected.includes("_")) {
|
||||
|
||||
@ -97,6 +97,12 @@ export class PromptForm extends ModelForm<Prompt, string> {
|
||||
>
|
||||
${t`Date Time`}
|
||||
</option>
|
||||
<option
|
||||
value=${PromptTypeEnum.File}
|
||||
?selected=${this.instance?.type === PromptTypeEnum.File}
|
||||
>
|
||||
${t`File`}
|
||||
</option>
|
||||
<option
|
||||
value=${PromptTypeEnum.Separator}
|
||||
?selected=${this.instance?.type === PromptTypeEnum.Separator}
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
"ES2020",
|
||||
"ESNext",
|
||||
"DOM",
|
||||
"DOM.Iterable",
|
||||
"WebWorker"
|
||||
],
|
||||
"plugins": [
|
||||
|
||||
@ -13,11 +13,11 @@ By default, the email is sent to the currently pending user. To override this, y
|
||||
For example, create this expression policy and bind it to the email stage:
|
||||
|
||||
```python
|
||||
request.context["email"] = "foo@bar.baz"
|
||||
request.context["flow_plan"].context["email"] = "foo@bar.baz"
|
||||
# Or get it from a prompt
|
||||
# request.context["email"] = request.context["prompt_data"]["email"]
|
||||
# request.context["flow_plan"].context["email"] = request.context["prompt_data"]["email"]
|
||||
# Or another user attribute
|
||||
# request.context["email"] = request.context["pending_user"].attributes.get("otherEmail")
|
||||
# request.context["flow_plan"].context["email"] = request.context["pending_user"].attributes.get("otherEmail")
|
||||
return True
|
||||
```
|
||||
|
||||
|
||||
@ -8,21 +8,22 @@ This stage is used to show the user arbitrary prompts.
|
||||
|
||||
The prompt can be any of the following types:
|
||||
|
||||
| Type | Description |
|
||||
| ----------------- | ---------------------------------------------------------------------------------------- |
|
||||
| Text | Arbitrary text. No client-side validation is done. |
|
||||
| Text (Read only) | Same as above, but cannot be edited. |
|
||||
| Username | Same as text, except the username is validated to be unique. |
|
||||
| Email | Text input, ensures the value is an email address (validation is only done client-side). |
|
||||
| Password | Same as text, shown as a password field client-side, and custom validation (see below). |
|
||||
| Number | Numerical textbox. |
|
||||
| Checkbox | Simple checkbox. |
|
||||
| Date | Same as text, except the client renders a date-picker |
|
||||
| Date-time | Same as text, except the client renders a date-time-picker |
|
||||
| Separator | Passive element to group surrounding elements |
|
||||
| Hidden | Hidden input field. Allows for the pre-setting of default values. |
|
||||
| Static | Display arbitrary value as is |
|
||||
| authentik: Locale | Display a list of all locales authentik supports. |
|
||||
| Type | Description |
|
||||
| ----------------- | ------------------------------------------------------------------------------------------ |
|
||||
| Text | Arbitrary text. No client-side validation is done. |
|
||||
| Text (Read only) | Same as above, but cannot be edited. |
|
||||
| Username | Same as text, except the username is validated to be unique. |
|
||||
| Email | Text input, ensures the value is an email address (validation is only done client-side). |
|
||||
| Password | Same as text, shown as a password field client-side, and custom validation (see below). |
|
||||
| Number | Numerical textbox. |
|
||||
| Checkbox | Simple checkbox. |
|
||||
| Date | Same as text, except the client renders a date-picker |
|
||||
| Date-time | Same as text, except the client renders a date-time-picker |
|
||||
| File | Allow users to upload a file, which will be available as base64-encoded data in the flow . |
|
||||
| Separator | Passive element to group surrounding elements |
|
||||
| Hidden | Hidden input field. Allows for the pre-setting of default values. |
|
||||
| Static | Display arbitrary value as is |
|
||||
| authentik: Locale | Display a list of all locales authentik supports. |
|
||||
|
||||
Some types have special behaviors:
|
||||
|
||||
|
||||
@ -14,6 +14,6 @@ Starting with authentik 2022.5, users can be added to dynamic groups. To do so,
|
||||
from authentik.core.models import Group
|
||||
group, _ = Group.objects.get_or_create(name="some-group")
|
||||
# ["groups"] *must* be set to an array of Group objects, names alone are not enough.
|
||||
request.context["groups"] = [group]
|
||||
request.context["flow_plan"].context["groups"] = [group]
|
||||
return True
|
||||
```
|
||||
|
||||
@ -14,6 +14,10 @@ slug: "2022.7"
|
||||
In earlier versions, cyclic group relations can lead to a deadlock when one of groups in the relationship are bound to an application/flow/etc.
|
||||
This is now limited to 20 levels of recursion.
|
||||
|
||||
- Change in context behaviour for policies executed within flows
|
||||
|
||||
In previous versions, the policy context would be set to a reference to the currently active flow plan context. This makes it so any changes to `context` wre directly reflected in the flow context. The context has been changed to only include the values, and as such updates like this won't be reflected in the flow. Instead, `context['flow_plan']` is now set, which contains a full reference to the flow Plan, allowing for more customisability than previously. Context changes can be mad by modifying `context['flow_plan'].context`.
|
||||
|
||||
## New features
|
||||
|
||||
- User paths
|
||||
@ -77,6 +81,22 @@ slug: "2022.7"
|
||||
- web/flows: remove autofocus from password field of identifications stage
|
||||
- web/flows: statically import webauthn-related stages for safari issues
|
||||
|
||||
## Fixed in 2022.7.2
|
||||
|
||||
- flows: fix OOB flow incorrectly setting pending user
|
||||
- stages/prompt: add basic file field (#3156)
|
||||
- tenants: add default_locale read only field, pre-hydrate in flows and read in autodetect as first choice
|
||||
|
||||
## Fixed in 2022.7.3
|
||||
|
||||
- core: delete expired models when filtering instead of excluding them
|
||||
- providers/oauth2: correctly log authenticated user for OAuth views using protected_resource_view
|
||||
- sources/oauth: use oidc preferred_username if set, otherwise nickname
|
||||
- stages/consent: fix permissions for consent API (allow owner to delete)
|
||||
- stages/prompt: force required to false when using readonlyfield
|
||||
- stages/prompt: try to base64 decode file, fallback to keeping value as-is
|
||||
- web/elements: improve contrast for codemirror backgrounds
|
||||
|
||||
## Upgrading
|
||||
|
||||
This release does not introduce any new requirements.
|
||||
|
||||
106
website/integrations/services/node-red/index.md
Normal file
106
website/integrations/services/node-red/index.md
Normal file
@ -0,0 +1,106 @@
|
||||
---
|
||||
title: Node-RED
|
||||
---
|
||||
|
||||
<span class="badge badge--secondary">Support level: Community</span>
|
||||
|
||||
## What is Node-RED
|
||||
|
||||
From https://nodered.org/
|
||||
|
||||
:::note
|
||||
Node-RED is a programming tool for wiring together hardware devices, APIs and online services in new and interesting ways.
|
||||
|
||||
It provides a browser-based editor that makes it easy to wire together flows using the wide range of nodes in the palette that can be deployed to its runtime in a single-click.
|
||||
:::
|
||||
|
||||
:::warning
|
||||
This requires modification of the Node-RED settings.js and installing additional Passport-js packages, see [Securing Node-RED](https://nodered.org/docs/user-guide/runtime/securing-node-red#oauthopenid-based-authentication) documentation for further details.
|
||||
:::
|
||||
|
||||
## Preparation
|
||||
|
||||
The following placeholders will be used:
|
||||
|
||||
- `authentik.company` is the FQDN of authentik.
|
||||
- `nodred.company` is the FQDN of Node-RED.
|
||||
|
||||
### Step 1
|
||||
|
||||
In authentik, create an _OAuth2/OpenID Provider_ (under _Resources/Providers_) with these settings:
|
||||
|
||||
:::note
|
||||
Only settings that have been modified from default have been listed.
|
||||
:::
|
||||
|
||||
- Name: Node-RED
|
||||
|
||||
**Protocol Settings**
|
||||
|
||||
- Redirect URIs/Origins (RegEx): https://nodred.company/auth/strategy/callback/
|
||||
- Signing Key: Select any available key
|
||||
|
||||
:::note
|
||||
Take note of the `Client ID` and `Client Secret`, you'll need to give them to Node-RED in _Step 3_.
|
||||
:::
|
||||
|
||||
### Step 2
|
||||
|
||||
In authentik, create an application (under _Resources/Applications_) which uses this provider. Optionally apply access restrictions to the application using policy bindings.
|
||||
|
||||
:::note
|
||||
Only settings that have been modified from default have been listed.
|
||||
:::
|
||||
|
||||
- Name: Node-RED
|
||||
- Slug: nodered-slug
|
||||
- Provider: Node-RED
|
||||
|
||||
Optionally you can link directly to the authentication strategy
|
||||
|
||||
- Launch URL: https://nodred.company/auth/strategy/
|
||||
|
||||
### Step 3
|
||||
|
||||
:::note
|
||||
Group based permissions are not implemented in the below example
|
||||
:::
|
||||
|
||||
Use npm to install passport-openidconnect
|
||||
|
||||
Navigate to the node-red `node_modules` directory, this is dependant on your chosen install method. In the official Node-RED docker container the `node_modules` directory is located in the data volume `data/node_modules/`. Alternatively enter the docker container `docker exec -it nodered bash` and `cd /data/node_modules` to utilise npm within the docker container.
|
||||
|
||||
Run the command `npm install passport-openidconnect`
|
||||
|
||||
### Step 4
|
||||
|
||||
Edit the node-red settings.js file `/data/settings.js` to use the external authentication source via passport-openidconnect.
|
||||
|
||||
```js
|
||||
adminAuth: {
|
||||
type:"strategy",
|
||||
strategy: {
|
||||
name: "openidconnect",
|
||||
label: 'Sign in with authentik',
|
||||
icon:"fa-cloud",
|
||||
strategy: require("passport-openidconnect").Strategy,
|
||||
options: {
|
||||
issuer: 'https://authentik.company/application/o/<application-slug>/',
|
||||
authorizationURL: 'https://authentik.company/application/o/authorize/',
|
||||
tokenURL: 'https://authentik.company/application/o/token/',
|
||||
userInfoURL: 'https://authentik.company/application/o/userinfo/',
|
||||
clientID: '<Client ID (Key): Step 2>',
|
||||
clientSecret: '<Client Secret: Step 2>',
|
||||
callbackURL: 'https://nodered.company/auth/strategy/callback/',
|
||||
scope: ['email', 'profile', 'openid'],
|
||||
proxy: true,
|
||||
verify: function(issuer, profile, done) {
|
||||
done(null, profile)
|
||||
}
|
||||
}
|
||||
},
|
||||
users: function(user) {
|
||||
return Promise.resolve({ username: user, permissions: "*" });
|
||||
}
|
||||
},
|
||||
```
|
||||
@ -26,7 +26,9 @@ Under _Property Mappings_, create a _SAML Property Mapping_. Give it a name like
|
||||
return f"{user.pk}-{user.username}"
|
||||
```
|
||||
|
||||
Create an application in authentik. Create a SAML provider with the following parameters:
|
||||
Create an application in authentik. Set the Launch URL to `https://rancher.company`, as Rancher does not currently support IdP-initiated logins.
|
||||
|
||||
Create a SAML provider with the following parameters:
|
||||
|
||||
- ACS URL: `https://rancher.company/v1-saml/adfs/saml/acs`
|
||||
- Audience: `https://rancher.company/v1-saml/adfs/saml/metadata`
|
||||
|
||||
4917
website/package-lock.json
generated
4917
website/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -14,17 +14,17 @@
|
||||
"prettier": "prettier --write ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/plugin-client-redirects": "2.0.0-beta.21",
|
||||
"@docusaurus/preset-classic": "2.0.0-beta.21",
|
||||
"@docusaurus/plugin-client-redirects": "2.0.0-rc.1",
|
||||
"@docusaurus/preset-classic": "2.0.0-rc.1",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"clsx": "^1.2.0",
|
||||
"clsx": "^1.2.1",
|
||||
"postcss": "^8.4.14",
|
||||
"rapidoc": "^9.3.2",
|
||||
"rapidoc": "^9.3.3",
|
||||
"react": "^17.0.2",
|
||||
"react-before-after-slider-component": "^1.1.3",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-feather": "^2.0.10",
|
||||
"react-toggle": "^4.1.2"
|
||||
"react-toggle": "^4.1.3"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
||||
@ -205,13 +205,14 @@ module.exports = {
|
||||
description: "Release notes for recent authentik versions",
|
||||
},
|
||||
items: [
|
||||
"releases/v2022.7",
|
||||
"releases/v2022.6",
|
||||
"releases/v2022.5",
|
||||
"releases/v2022.4",
|
||||
{
|
||||
type: "category",
|
||||
label: "Previous versions",
|
||||
items: [
|
||||
"releases/v2022.4",
|
||||
"releases/v2022.2",
|
||||
"releases/v2022.1",
|
||||
"releases/v2021.12",
|
||||
|
||||
@ -88,6 +88,7 @@ module.exports = {
|
||||
],
|
||||
},
|
||||
"services/home-assistant/index",
|
||||
"services/node-red/index",
|
||||
"services/kimai/index",
|
||||
"services/sonarr/index",
|
||||
"services/tautulli/index",
|
||||
|
||||
Reference in New Issue
Block a user