Merge branch 'next' into form-refresh-on-save

This commit is contained in:
Jens Langhammer 2021-05-11 11:47:29 +02:00
commit fd44765ff4
60 changed files with 755 additions and 535 deletions

View File

@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 2021.4.5 current_version = 2021.5.1-rc7
tag = True tag = True
commit = True commit = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-?(?P<release>.*) parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-?(?P<release>.*)

View File

@ -1,5 +1,13 @@
version: 2 version: 2
updates: updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: daily
time: "04:00"
open-pull-requests-limit: 10
assignees:
- BeryJu
- package-ecosystem: gomod - package-ecosystem: gomod
directory: "/outpost" directory: "/outpost"
schedule: schedule:

View File

@ -3,36 +3,49 @@ name: authentik-on-release
on: on:
release: release:
types: [published, created] types: [published, created]
push:
branches:
- version-*
jobs: jobs:
# Build # Build
build-server: build-server:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v1 uses: docker/setup-qemu-action@v1.1.0
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1 uses: docker/setup-buildx-action@v1
- name: Docker Login Registry - name: Docker Login Registry
uses: docker/login-action@v1 uses: docker/login-action@v1
with: with:
username: ${{ secrets.DOCKER_PASSWORD }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: prepare ts api client
run: |
docker run --rm -v $(pwd):/local openapitools/openapi-generator-cli generate -i /local/swagger.yaml -g typescript-fetch -o /local/web/api --additional-properties=typescriptThreePlus=true,supportsES6=true,npmName=authentik-api,npmVersion=1.0.0
- name: Building Docker Image - name: Building Docker Image
uses: docker/build-push-action@v2 uses: docker/build-push-action@v2
with: with:
push: true push: ${{ github.event_name == 'release' }}
tags: | tags: |
beryju/authentik:2021.4.5, beryju/authentik:2021.5.1-rc7,
beryju/authentik:latest, beryju/authentik:latest,
ghcr.io/goauthentik/server:2021.4.5, ghcr.io/goauthentik/server:2021.5.1-rc7,
ghcr.io/goauthentik/server:latest ghcr.io/goauthentik/server:latest
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v8 platforms: linux/amd64,linux/arm64
context: .
build-proxy: build-proxy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- uses: actions/setup-go@v2 - uses: actions/setup-go@v2
with: with:
go-version: "^1.15" go-version: "^1.15"
@ -41,32 +54,38 @@ jobs:
cd outpost cd outpost
go get -u github.com/go-swagger/go-swagger/cmd/swagger go get -u github.com/go-swagger/go-swagger/cmd/swagger
swagger generate client -f ../swagger.yaml -A authentik -t pkg/ swagger generate client -f ../swagger.yaml -A authentik -t pkg/
go build -v . go build -v ./cmd/proxy/server.go
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v1 uses: docker/setup-qemu-action@v1.1.0
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1 uses: docker/setup-buildx-action@v1
- name: Docker Login Registry - name: Docker Login Registry
uses: docker/login-action@v1 uses: docker/login-action@v1
with: with:
username: ${{ secrets.DOCKER_PASSWORD }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Building Docker Image - name: Building Docker Image
uses: docker/build-push-action@v2 uses: docker/build-push-action@v2
with: with:
push: true push: ${{ github.event_name == 'release' }}
tags: | tags: |
beryju/authentik-proxy:2021.4.5, beryju/authentik-proxy:2021.5.1-rc7,
beryju/authentik-proxy:latest, beryju/authentik-proxy:latest,
ghcr.io/goauthentik/proxy:2021.4.5, ghcr.io/goauthentik/proxy:2021.5.1-rc7,
ghcr.io/goauthentik/proxy:latest ghcr.io/goauthentik/proxy:latest
context: outpost/ context: outpost/
file: outpost/proxy.Dockerfile file: outpost/proxy.Dockerfile
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v8 platforms: linux/amd64,linux/arm64
build-ldap: build-ldap:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- uses: actions/setup-go@v2 - uses: actions/setup-go@v2
with: with:
go-version: "^1.15" go-version: "^1.15"
@ -75,36 +94,43 @@ jobs:
cd outpost cd outpost
go get -u github.com/go-swagger/go-swagger/cmd/swagger go get -u github.com/go-swagger/go-swagger/cmd/swagger
swagger generate client -f ../swagger.yaml -A authentik -t pkg/ swagger generate client -f ../swagger.yaml -A authentik -t pkg/
go build -v . go build -v ./cmd/ldap/server.go
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v1 uses: docker/setup-qemu-action@v1.1.0
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1 uses: docker/setup-buildx-action@v1
- name: Docker Login Registry - name: Docker Login Registry
uses: docker/login-action@v1 uses: docker/login-action@v1
with: with:
username: ${{ secrets.DOCKER_PASSWORD }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Building Docker Image - name: Building Docker Image
uses: docker/build-push-action@v2 uses: docker/build-push-action@v2
with: with:
push: true push: ${{ github.event_name == 'release' }}
tags: | tags: |
beryju/authentik-ldap:2021.4.5, beryju/authentik-ldap:2021.5.1-rc7,
beryju/authentik-ldap:latest, beryju/authentik-ldap:latest,
ghcr.io/goauthentik/ldap:2021.4.5, ghcr.io/goauthentik/ldap:2021.5.1-rc7,
ghcr.io/goauthentik/ldap:latest ghcr.io/goauthentik/ldap:latest
context: outpost/ context: outpost/
file: outpost/ldap.Dockerfile file: outpost/ldap.Dockerfile
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v8 platforms: linux/amd64,linux/arm64
test-release: test-release:
if: ${{ github.event_name == 'release' }}
needs: needs:
- build-server - build-server
- build-proxy - build-proxy
- build-ldap - build-ldap
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- name: Run test suite in final docker images - name: Run test suite in final docker images
run: | run: |
sudo apt-get install -y pwgen sudo apt-get install -y pwgen
@ -115,11 +141,12 @@ jobs:
docker-compose start postgresql redis docker-compose start postgresql redis
docker-compose run -u root --entrypoint /bin/bash server -c "pip install --no-cache -r requirements-dev.txt && ./manage.py test authentik" docker-compose run -u root --entrypoint /bin/bash server -c "pip install --no-cache -r requirements-dev.txt && ./manage.py test authentik"
sentry-release: sentry-release:
if: ${{ github.event_name == 'release' }}
needs: needs:
- test-release - test-release
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- name: Create a Sentry.io release - name: Create a Sentry.io release
uses: getsentry/action-release@v1 uses: getsentry/action-release@v1
env: env:
@ -128,5 +155,5 @@ jobs:
SENTRY_PROJECT: authentik SENTRY_PROJECT: authentik
SENTRY_URL: https://sentry.beryju.org SENTRY_URL: https://sentry.beryju.org
with: with:
version: authentik@2021.4.5 version: authentik@2021.5.1-rc7
environment: beryjuorg-prod environment: beryjuorg-prod

View File

@ -10,7 +10,10 @@ jobs:
name: Create Release from Tag name: Create Release from Tag
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@v2
- name: prepare ts api client
run: |
docker run --rm -v $(pwd):/local openapitools/openapi-generator-cli generate -i /local/swagger.yaml -g typescript-fetch -o /local/web/api --additional-properties=typescriptThreePlus=true,supportsES6=true,npmName=authentik-api,npmVersion=1.0.0
- name: Pre-release test - name: Pre-release test
run: | run: |
sudo apt-get install -y pwgen sudo apt-get install -y pwgen

View File

@ -52,11 +52,12 @@ RUN apt-get update && \
curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \ curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \
echo "deb http://apt.postgresql.org/pub/repos/apt buster-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \ echo "deb http://apt.postgresql.org/pub/repos/apt buster-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
apt-get update && \ apt-get update && \
apt-get install -y --no-install-recommends postgresql-client-12 postgresql-client-11 build-essential libxmlsec1-dev pkg-config libmaxminddb0 && \ apt-get install -y --no-install-recommends libpq-dev postgresql-client build-essential libxmlsec1-dev pkg-config libmaxminddb0 && \
apt-get clean && \
pip install -r /requirements.txt --no-cache-dir && \ pip install -r /requirements.txt --no-cache-dir && \
apt-get remove --purge -y build-essential && \ apt-get remove --purge -y build-essential && \
apt-get autoremove --purge -y && \ apt-get autoremove --purge -y && \
apt-get clean && \
rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/ && \
# This is quite hacky, but docker has no guaranteed Group ID # This is quite hacky, but docker has no guaranteed Group ID
# we could instead check for the GID of the socket and add the user dynamically, # we could instead check for the GID of the socket and add the user dynamically,
# but then we have to drop permmissions later # but then we have to drop permmissions later

36
Pipfile.lock generated
View File

@ -88,10 +88,10 @@
}, },
"attrs": { "attrs": {
"hashes": [ "hashes": [
"sha256:3901be1cb7c2a780f14668691474d9252c070a756be0a9ead98cfeabfa11aeb8", "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
"sha256:8ee1e5f5a1afc5b19bdfae4fdf0c35ed324074bdce3500c939842c8f818645d9" "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
], ],
"version": "==21.1.0" "version": "==21.2.0"
}, },
"autobahn": { "autobahn": {
"hashes": [ "hashes": [
@ -116,18 +116,18 @@
}, },
"boto3": { "boto3": {
"hashes": [ "hashes": [
"sha256:56f1766f1271b6b4e979c7b56225377f8912050e5935adc5c1c9e3a0338b949e", "sha256:6c8c9c173a8d6c5127a9812ec4b9369280caec4f574e297900dc8e735a92f71f",
"sha256:c61c809d288e88b9a0d926f56f803d0128b498aa9b45a42a6e03cd9a83e5c124" "sha256:8bdbe29bc9308124e7e96ef912dfa1d656400499edcf398b677db739939e9ba6"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.17.68" "version": "==1.17.70"
}, },
"botocore": { "botocore": {
"hashes": [ "hashes": [
"sha256:0f693f5ad6348ec1a62b3a66fee2840d3b722d66b44896022d644275ff8b143d", "sha256:3dea2656b5555a1bcb299a83fdefe6f0ef331ffae55cc8f8edf06557342738c0",
"sha256:eb3544911cb0316a33b328a27d137130af278a9c0006be0c95e5e402b01d9865" "sha256:9bc8bd5f601d35658b2aaa78ebeef154fd092e64b37059e8eeef51648a3936c8"
], ],
"version": "==1.20.68" "version": "==1.20.70"
}, },
"cachetools": { "cachetools": {
"hashes": [ "hashes": [
@ -351,11 +351,11 @@
}, },
"django-otp": { "django-otp": {
"hashes": [ "hashes": [
"sha256:04852c5301befb02d1d8ba4a31d375eb08d7c2cb6fe86b5f840867435ab1309c", "sha256:75a815747a0542cc5442e3a6396dfd272c49a0866bee2149ac57ecc36ddd3961",
"sha256:3916fc7652c2f934b1cf3807dd8ed257ce7605c10dfefa27fadda5628d9a9c9e" "sha256:cc657a0e7266cda6ab42f861bdc3840ed24f7e441bc7f249916174dd1a6375a0"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.0.4" "version": "==1.0.5"
}, },
"django-prometheus": { "django-prometheus": {
"hashes": [ "hashes": [
@ -1101,11 +1101,11 @@
}, },
"service-identity": { "service-identity": {
"hashes": [ "hashes": [
"sha256:001c0707759cb3de7e49c078a7c0c9cd12594161d3bf06b9c254fdcb1a60dc36", "sha256:6e6c6086ca271dc11b033d17c3a8bea9f24ebff920c587da090afc9519419d34",
"sha256:0858a54aabc5b459d1aafa8a518ed2081a285087f349fe3e55197989232e2e2d" "sha256:f0b0caac3d40627c3c04d7a51b6e06721857a0e10a8775f2d1d7e72901b3a7db"
], ],
"index": "pypi", "index": "pypi",
"version": "==18.1.0" "version": "==21.1.0"
}, },
"six": { "six": {
"hashes": [ "hashes": [
@ -1424,10 +1424,10 @@
}, },
"attrs": { "attrs": {
"hashes": [ "hashes": [
"sha256:3901be1cb7c2a780f14668691474d9252c070a756be0a9ead98cfeabfa11aeb8", "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
"sha256:8ee1e5f5a1afc5b19bdfae4fdf0c35ed324074bdce3500c939842c8f818645d9" "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
], ],
"version": "==21.1.0" "version": "==21.2.0"
}, },
"bandit": { "bandit": {
"hashes": [ "hashes": [

View File

@ -1,3 +1,3 @@
"""authentik""" """authentik"""
__version__ = "2021.4.5" __version__ = "2021.5.1-rc7"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH" ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"

View File

@ -7,6 +7,7 @@ from django.urls import reverse
from authentik import __version__ from authentik import __version__
from authentik.core.models import Group, User from authentik.core.models import Group, User
from authentik.core.tasks import clean_expired_models from authentik.core.tasks import clean_expired_models
from authentik.events.monitored_tasks import TaskResultStatus
class TestAdminAPI(TestCase): class TestAdminAPI(TestCase):
@ -30,6 +31,26 @@ class TestAdminAPI(TestCase):
any(task["task_name"] == "clean_expired_models" for task in body) any(task["task_name"] == "clean_expired_models" for task in body)
) )
def test_tasks_single(self):
"""Test Task API (read single)"""
clean_expired_models.delay()
response = self.client.get(
reverse(
"authentik_api:admin_system_tasks-detail",
kwargs={"pk": "clean_expired_models"},
)
)
self.assertEqual(response.status_code, 200)
body = loads(response.content)
self.assertEqual(body["status"], TaskResultStatus.SUCCESSFUL.name)
self.assertEqual(body["task_name"], "clean_expired_models")
response = self.client.get(
reverse(
"authentik_api:admin_system_tasks-detail", kwargs={"pk": "qwerqwer"}
)
)
self.assertEqual(response.status_code, 404)
def test_tasks_retry(self): def test_tasks_retry(self):
"""Test Task API (retry)""" """Test Task API (retry)"""
clean_expired_models.delay() clean_expired_models.delay()

View File

@ -54,4 +54,4 @@ class AuthentikTokenAuthentication(BaseAuthentication):
if not token: if not token:
return None return None
return (token.user, None) return (token.user, None) # pragma: no cover

View File

@ -22,3 +22,10 @@ class TestSwaggerGeneration(APITestCase):
reverse("authentik_api:schema-json", kwargs={"format": ".json"}), reverse("authentik_api:schema-json", kwargs={"format": ".json"}),
) )
self.assertTrue(loads(response.content.decode())) self.assertTrue(loads(response.content.decode()))
def test_browser(self):
"""Test API Browser"""
response = self.client.get(
reverse("authentik_api:swagger"),
)
self.assertEqual(response.status_code, 200)

View File

@ -3,6 +3,7 @@ from enum import Enum
from typing import Any, Optional, Type from typing import Any, Optional, Type
from django.contrib import messages from django.contrib import messages
from django.db import IntegrityError
from django.db.models.query_utils import Q from django.db.models.query_utils import Q
from django.http import HttpRequest, HttpResponse, HttpResponseBadRequest from django.http import HttpRequest, HttpResponse, HttpResponseBadRequest
from django.shortcuts import redirect from django.shortcuts import redirect
@ -116,9 +117,11 @@ class SourceFlowManager:
) )
return Action.DENY, None return Action.DENY, None
query = Q(username__exact=self.enroll_info.get("username", None)) query = Q(username__exact=self.enroll_info.get("username", None))
self._logger.debug("trying to link with existing user", query=query)
matching_users = User.objects.filter(query) matching_users = User.objects.filter(query)
# No matching users, always enroll # No matching users, always enroll
if not matching_users.exists(): if not matching_users.exists():
self._logger.debug("no matching users found, enrolling")
return Action.ENROLL, self.update_connection(new_connection, **kwargs) return Action.ENROLL, self.update_connection(new_connection, **kwargs)
user = matching_users.first() user = matching_users.first()
@ -147,7 +150,11 @@ class SourceFlowManager:
def get_flow(self, **kwargs) -> HttpResponse: def get_flow(self, **kwargs) -> HttpResponse:
"""Get the flow response based on user_matching_mode""" """Get the flow response based on user_matching_mode"""
try:
action, connection = self.get_action(**kwargs) action, connection = self.get_action(**kwargs)
except IntegrityError as exc:
self._logger.warning("failed to get action", exc=exc)
return redirect("/")
self._logger.debug("get_action() says", action=action, connection=connection) self._logger.debug("get_action() says", action=action, connection=connection)
if connection: if connection:
if action == Action.LINK: if action == Action.LINK:

View File

@ -1,7 +1,9 @@
"""Notification API Views""" """Notification API Views"""
from django_filters.rest_framework import DjangoFilterBackend
from guardian.utils import get_anonymous_user from guardian.utils import get_anonymous_user
from rest_framework import mixins from rest_framework import mixins
from rest_framework.fields import ReadOnlyField from rest_framework.fields import ReadOnlyField
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import GenericViewSet from rest_framework.viewsets import GenericViewSet
@ -47,6 +49,11 @@ class NotificationViewSet(
"event", "event",
"seen", "seen",
] ]
filter_backends = [
DjangoFilterBackend,
OrderingFilter,
SearchFilter,
]
def get_queryset(self): def get_queryset(self):
user = self.request.user if self.request else get_anonymous_user() user = self.request.user if self.request else get_anonymous_user()

View File

@ -0,0 +1,13 @@
"""Fix dbbackup quoting the password"""
from dbbackup.db.postgresql import PgDumpConnector
class PgCustom(PgDumpConnector):
"""Fix dbbackup quoting the password"""
def run_command(self, *args, **kwargs):
if self.settings.get("PASSWORD"):
env = kwargs.get("env", {})
env["PGPASSWORD"] = self.settings["PASSWORD"]
kwargs["env"] = env
return super(PgDumpConnector, self).run_command(*args, **kwargs)

View File

@ -3,6 +3,7 @@ postgresql:
host: localhost host: localhost
name: authentik name: authentik
user: authentik user: authentik
port: 5432
password: 'env://POSTGRES_PASSWORD' password: 'env://POSTGRES_PASSWORD'
web: web:

View File

@ -1,23 +1,35 @@
"""Outpost API Views""" """Outpost API Views"""
from dacite.core import from_dict
from dacite.exceptions import DaciteError
from drf_yasg.utils import swagger_auto_schema from drf_yasg.utils import swagger_auto_schema
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.fields import BooleanField, CharField, DateTimeField from rest_framework.fields import BooleanField, CharField, DateTimeField
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.serializers import JSONField, ModelSerializer from rest_framework.serializers import JSONField, ModelSerializer, ValidationError
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from authentik.core.api.providers import ProviderSerializer from authentik.core.api.providers import ProviderSerializer
from authentik.core.api.utils import PassiveSerializer, is_dict from authentik.core.api.utils import PassiveSerializer, is_dict
from authentik.outposts.models import Outpost, default_outpost_config from authentik.outposts.models import Outpost, OutpostConfig, default_outpost_config
class OutpostSerializer(ModelSerializer): class OutpostSerializer(ModelSerializer):
"""Outpost Serializer""" """Outpost Serializer"""
_config = JSONField(validators=[is_dict]) config = JSONField(validators=[is_dict], source="_config")
# TODO: Remove _config again, this is only here for legacy with older outposts
_config = JSONField(validators=[is_dict], read_only=True)
providers_obj = ProviderSerializer(source="providers", many=True, read_only=True) providers_obj = ProviderSerializer(source="providers", many=True, read_only=True)
def validate_config(self, config) -> dict:
"""Check that the config has all required fields"""
try:
from_dict(OutpostConfig, config)
except DaciteError as exc:
raise ValidationError(f"Failed to validate config: {str(exc)}") from exc
return config
class Meta: class Meta:
model = Outpost model = Outpost
@ -29,6 +41,7 @@ class OutpostSerializer(ModelSerializer):
"providers_obj", "providers_obj",
"service_connection", "service_connection",
"token_identifier", "token_identifier",
"config",
"_config", "_config",
] ]

View File

@ -56,6 +56,12 @@ class BaseController:
"""Handler to delete everything we've created""" """Handler to delete everything we've created"""
raise NotImplementedError raise NotImplementedError
def down_with_logs(self) -> list[str]:
"""Call .down() but capture all log output and return it."""
with capture_logs() as logs:
self.down()
return [x["event"] for x in logs]
def get_static_deployment(self) -> str: def get_static_deployment(self) -> str:
"""Return a static deployment configuration""" """Return a static deployment configuration"""
raise NotImplementedError raise NotImplementedError

View File

@ -30,11 +30,6 @@ class NeedsUpdate(ReconcileTrigger):
"""Exception to trigger an update to the Kubernetes Object""" """Exception to trigger an update to the Kubernetes Object"""
class Disabled(SentryIgnoredException):
"""Exception which can be thrown in a reconciler to signal than an
object should not be created."""
class KubernetesObjectReconciler(Generic[T]): class KubernetesObjectReconciler(Generic[T]):
"""Base Kubernetes Reconciler, handles the basic logic.""" """Base Kubernetes Reconciler, handles the basic logic."""
@ -45,22 +40,29 @@ class KubernetesObjectReconciler(Generic[T]):
self.namespace = controller.outpost.config.kubernetes_namespace self.namespace = controller.outpost.config.kubernetes_namespace
self.logger = get_logger().bind(type=self.__class__.__name__) self.logger = get_logger().bind(type=self.__class__.__name__)
@property
def noop(self) -> bool:
"""Return true if this object should not be created/updated/deleted in this cluster"""
return False
@property @property
def name(self) -> str: def name(self) -> str:
"""Get the name of the object this reconciler manages""" """Get the name of the object this reconciler manages"""
return self.controller.outpost.config.object_naming_template % { return (
self.controller.outpost.config.object_naming_template
% {
"name": slugify(self.controller.outpost.name), "name": slugify(self.controller.outpost.name),
"uuid": self.controller.outpost.uuid.hex, "uuid": self.controller.outpost.uuid.hex,
} }
).lower()
def up(self): def up(self):
"""Create object if it doesn't exist, update if needed or recreate if needed.""" """Create object if it doesn't exist, update if needed or recreate if needed."""
current = None current = None
try: if self.noop:
reference = self.get_reference_object() self.logger.debug("Object is noop")
except Disabled:
self.logger.debug("Object not required")
return return
reference = self.get_reference_object()
try: try:
try: try:
current = self.retrieve() current = self.retrieve()
@ -89,11 +91,8 @@ class KubernetesObjectReconciler(Generic[T]):
def down(self): def down(self):
"""Delete object if found""" """Delete object if found"""
# Call self.get_reference_object to check if we even need to do anything if self.noop:
try: self.logger.debug("Object is noop")
self.get_reference_object()
except Disabled:
self.logger.debug("Object not required")
return return
try: try:
current = self.retrieve() current = self.retrieve()

View File

@ -0,0 +1,11 @@
"""k8s utils"""
from pathlib import Path
def get_namespace() -> str:
"""Get the namespace if we're running in a pod, otherwise default to default"""
path = Path("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
if path.exists():
with open(path, "r") as _namespace_file:
return _namespace_file.read()
return "default"

View File

@ -8,7 +8,7 @@ from structlog.testing import capture_logs
from yaml import dump_all from yaml import dump_all
from authentik.outposts.controllers.base import BaseController, ControllerException from authentik.outposts.controllers.base import BaseController, ControllerException
from authentik.outposts.controllers.k8s.base import Disabled, KubernetesObjectReconciler from authentik.outposts.controllers.k8s.base import KubernetesObjectReconciler
from authentik.outposts.controllers.k8s.deployment import DeploymentReconciler from authentik.outposts.controllers.k8s.deployment import DeploymentReconciler
from authentik.outposts.controllers.k8s.secret import SecretReconciler from authentik.outposts.controllers.k8s.secret import SecretReconciler
from authentik.outposts.controllers.k8s.service import ServiceReconciler from authentik.outposts.controllers.k8s.service import ServiceReconciler
@ -49,6 +49,9 @@ class KubernetesController(BaseController):
try: try:
all_logs = [] all_logs = []
for reconcile_key in self.reconcile_order: for reconcile_key in self.reconcile_order:
if reconcile_key in self.outpost.config.kubernetes_disabled_components:
all_logs += [f"{reconcile_key.title()}: Disabled"]
continue
with capture_logs() as logs: with capture_logs() as logs:
reconciler = self.reconcilers[reconcile_key](self) reconciler = self.reconcilers[reconcile_key](self)
reconciler.up() reconciler.up()
@ -61,19 +64,34 @@ class KubernetesController(BaseController):
try: try:
for reconcile_key in self.reconcile_order: for reconcile_key in self.reconcile_order:
reconciler = self.reconcilers[reconcile_key](self) reconciler = self.reconcilers[reconcile_key](self)
self.logger.debug("Tearing down object", name=reconcile_key)
reconciler.down() reconciler.down()
except ApiException as exc: except ApiException as exc:
raise ControllerException(str(exc)) from exc raise ControllerException(str(exc)) from exc
def down_with_logs(self) -> list[str]:
try:
all_logs = []
for reconcile_key in self.reconcile_order:
if reconcile_key in self.outpost.config.kubernetes_disabled_components:
all_logs += [f"{reconcile_key.title()}: Disabled"]
continue
with capture_logs() as logs:
reconciler = self.reconcilers[reconcile_key](self)
reconciler.down()
all_logs += [f"{reconcile_key.title()}: {x['event']}" for x in logs]
return all_logs
except ApiException as exc:
raise ControllerException(str(exc)) from exc
def get_static_deployment(self) -> str: def get_static_deployment(self) -> str:
documents = [] documents = []
for reconcile_key in self.reconcile_order: for reconcile_key in self.reconcile_order:
reconciler = self.reconcilers[reconcile_key](self) reconciler = self.reconcilers[reconcile_key](self)
try: if reconciler.noop:
documents.append(reconciler.get_reference_object().to_dict())
except Disabled:
continue continue
documents.append(reconciler.get_reference_object().to_dict())
with StringIO() as _str: with StringIO() as _str:
dump_all( dump_all(

View File

@ -33,6 +33,7 @@ from authentik.lib.config import CONFIG
from authentik.lib.models import InheritanceForeignKey from authentik.lib.models import InheritanceForeignKey
from authentik.lib.sentry import SentryIgnoredException from authentik.lib.sentry import SentryIgnoredException
from authentik.lib.utils.http import USER_ATTRIBUTE_CAN_OVERRIDE_IP from authentik.lib.utils.http import USER_ATTRIBUTE_CAN_OVERRIDE_IP
from authentik.outposts.controllers.k8s.utils import get_namespace
from authentik.outposts.docker_tls import DockerInlineTLS from authentik.outposts.docker_tls import DockerInlineTLS
OUR_VERSION = parse(__version__) OUR_VERSION = parse(__version__)
@ -59,10 +60,11 @@ class OutpostConfig:
object_naming_template: str = field(default="ak-outpost-%(name)s") object_naming_template: str = field(default="ak-outpost-%(name)s")
kubernetes_replicas: int = field(default=1) kubernetes_replicas: int = field(default=1)
kubernetes_namespace: str = field(default="default") kubernetes_namespace: str = field(default_factory=get_namespace)
kubernetes_ingress_annotations: dict[str, str] = field(default_factory=dict) kubernetes_ingress_annotations: dict[str, str] = field(default_factory=dict)
kubernetes_ingress_secret_name: str = field(default="authentik-outpost-tls") kubernetes_ingress_secret_name: str = field(default="authentik-outpost-tls")
kubernetes_service_type: str = field(default="ClusterIP") kubernetes_service_type: str = field(default="ClusterIP")
kubernetes_disabled_components: list[str] = field(default_factory=list)
class OutpostModel(Model): class OutpostModel(Model):

View File

@ -1,5 +1,5 @@
"""authentik outpost signals""" """authentik outpost signals"""
from django.conf import settings from django.core.cache import cache
from django.db.models import Model from django.db.models import Model
from django.db.models.signals import post_save, pre_delete, pre_save from django.db.models.signals import post_save, pre_delete, pre_save
from django.dispatch import receiver from django.dispatch import receiver
@ -8,9 +8,12 @@ from structlog.stdlib import get_logger
from authentik.core.models import Provider from authentik.core.models import Provider
from authentik.crypto.models import CertificateKeyPair from authentik.crypto.models import CertificateKeyPair
from authentik.lib.utils.reflection import class_to_path from authentik.lib.utils.reflection import class_to_path
from authentik.outposts.controllers.base import ControllerException
from authentik.outposts.models import Outpost, OutpostServiceConnection from authentik.outposts.models import Outpost, OutpostServiceConnection
from authentik.outposts.tasks import outpost_controller_down, outpost_post_save from authentik.outposts.tasks import (
CACHE_KEY_OUTPOST_DOWN,
outpost_controller,
outpost_post_save,
)
LOGGER = get_logger() LOGGER = get_logger()
UPDATE_TRIGGERING_MODELS = ( UPDATE_TRIGGERING_MODELS = (
@ -39,7 +42,8 @@ def pre_save_outpost(sender, instance: Outpost, **_):
) )
if bool(dirty): if bool(dirty):
LOGGER.info("Outpost needs re-deployment due to changes", instance=instance) LOGGER.info("Outpost needs re-deployment due to changes", instance=instance)
outpost_controller_down_wrapper(old_instance) cache.set(CACHE_KEY_OUTPOST_DOWN % instance.pk.hex, old_instance)
outpost_controller.delay(instance.pk.hex, action="down", from_cache=True)
@receiver(post_save) @receiver(post_save)
@ -63,23 +67,5 @@ def post_save_update(sender, instance: Model, **_):
def pre_delete_cleanup(sender, instance: Outpost, **_): def pre_delete_cleanup(sender, instance: Outpost, **_):
"""Ensure that Outpost's user is deleted (which will delete the token through cascade)""" """Ensure that Outpost's user is deleted (which will delete the token through cascade)"""
instance.user.delete() instance.user.delete()
outpost_controller_down_wrapper(instance) cache.set(CACHE_KEY_OUTPOST_DOWN % instance.pk.hex, instance)
outpost_controller.delay(instance.pk.hex, action="down", from_cache=True)
def outpost_controller_down_wrapper(instance: Outpost):
"""To ensure that deployment is cleaned up *consistently* we call the controller, and wait
for it to finish. We don't want to call it in this thread, as we don't have the Outpost
Service connection here"""
try:
outpost_controller_down.delay(instance.pk.hex).get()
except RuntimeError: # pragma: no cover
# In e2e/integration tests, this might run inside a thread/process and
# trigger the celery `Never call result.get() within a task` detection
if settings.TEST:
pass
else:
raise
except ControllerException as exc:
LOGGER.warning(
"failed to cleanup outpost deployment", exc=exc, instance=instance
)

View File

@ -36,6 +36,7 @@ from authentik.providers.proxy.controllers.kubernetes import ProxyKubernetesCont
from authentik.root.celery import CELERY_APP from authentik.root.celery import CELERY_APP
LOGGER = get_logger() LOGGER = get_logger()
CACHE_KEY_OUTPOST_DOWN = "outpost_teardown_%s"
def controller_for_outpost(outpost: Outpost) -> Optional[BaseController]: def controller_for_outpost(outpost: Outpost) -> Optional[BaseController]:
@ -56,13 +57,6 @@ def controller_for_outpost(outpost: Outpost) -> Optional[BaseController]:
return None return None
@CELERY_APP.task()
def outpost_controller_all():
"""Launch Controller for all Outposts which support it"""
for outpost in Outpost.objects.exclude(service_connection=None):
outpost_controller.delay(outpost.pk.hex)
@CELERY_APP.task() @CELERY_APP.task()
def outpost_service_connection_state(connection_pk: Any): def outpost_service_connection_state(connection_pk: Any):
"""Update cached state of a service connection""" """Update cached state of a service connection"""
@ -89,17 +83,29 @@ def outpost_service_connection_monitor(self: MonitoredTask):
) )
@CELERY_APP.task()
def outpost_controller_all():
"""Launch Controller for all Outposts which support it"""
for outpost in Outpost.objects.exclude(service_connection=None):
outpost_controller.delay(outpost.pk.hex, "up", from_cache=False)
@CELERY_APP.task(bind=True, base=MonitoredTask) @CELERY_APP.task(bind=True, base=MonitoredTask)
def outpost_controller(self: MonitoredTask, outpost_pk: str): def outpost_controller(
"""Create/update/monitor the deployment of an Outpost""" self: MonitoredTask, outpost_pk: str, action: str = "up", from_cache: bool = False
):
"""Create/update/monitor/delete the deployment of an Outpost"""
logs = [] logs = []
if from_cache:
outpost: Outpost = cache.get(CACHE_KEY_OUTPOST_DOWN % outpost_pk)
else:
outpost: Outpost = Outpost.objects.get(pk=outpost_pk) outpost: Outpost = Outpost.objects.get(pk=outpost_pk)
self.set_uid(slugify(outpost.name)) self.set_uid(slugify(outpost.name))
try: try:
controller = controller_for_outpost(outpost) controller = controller_for_outpost(outpost)
if not controller: if not controller:
return return
logs = controller.up_with_logs() logs = getattr(controller, f"{action}_with_logs")()
LOGGER.debug("---------------Outpost Controller logs starting----------------") LOGGER.debug("---------------Outpost Controller logs starting----------------")
for log in logs: for log in logs:
LOGGER.debug(log) LOGGER.debug(log)
@ -110,16 +116,6 @@ def outpost_controller(self: MonitoredTask, outpost_pk: str):
self.set_status(TaskResult(TaskResultStatus.SUCCESSFUL, logs)) self.set_status(TaskResult(TaskResultStatus.SUCCESSFUL, logs))
@CELERY_APP.task()
def outpost_controller_down(outpost_pk: str):
"""Delete outpost objects before deleting the DB Object"""
outpost = Outpost.objects.get(pk=outpost_pk)
controller = controller_for_outpost(outpost)
if not controller:
return
controller.down()
@CELERY_APP.task(bind=True, base=MonitoredTask) @CELERY_APP.task(bind=True, base=MonitoredTask)
def outpost_token_ensurer(self: MonitoredTask): def outpost_token_ensurer(self: MonitoredTask):
"""Periodically ensure that all Outposts have valid Service Accounts """Periodically ensure that all Outposts have valid Service Accounts

View File

@ -3,6 +3,10 @@ from django.urls import reverse
from rest_framework.test import APITestCase from rest_framework.test import APITestCase
from authentik.core.models import PropertyMapping, User from authentik.core.models import PropertyMapping, User
from authentik.flows.models import Flow
from authentik.outposts.api.outposts import OutpostSerializer
from authentik.outposts.models import default_outpost_config
from authentik.providers.proxy.models import ProxyProvider
class TestOutpostServiceConnectionsAPI(APITestCase): class TestOutpostServiceConnectionsAPI(APITestCase):
@ -22,3 +26,22 @@ class TestOutpostServiceConnectionsAPI(APITestCase):
reverse("authentik_api:outpostserviceconnection-types"), reverse("authentik_api:outpostserviceconnection-types"),
) )
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
def test_outpost_config(self):
"""Test Outpost's config field"""
provider = ProxyProvider.objects.create(
name="test", authorization_flow=Flow.objects.first()
)
invalid = OutpostSerializer(
data={"name": "foo", "providers": [provider.pk], "config": {}}
)
self.assertFalse(invalid.is_valid())
self.assertIn("config", invalid.errors)
valid = OutpostSerializer(
data={
"name": "foo",
"providers": [provider.pk],
"config": default_outpost_config("foo"),
}
)
self.assertTrue(valid.is_valid())

View File

@ -1,7 +1,9 @@
"""OAuth2Provider API Views""" """OAuth2Provider API Views"""
from django_filters.rest_framework import DjangoFilterBackend
from guardian.utils import get_anonymous_user from guardian.utils import get_anonymous_user
from rest_framework import mixins from rest_framework import mixins
from rest_framework.fields import CharField, ListField from rest_framework.fields import CharField, ListField
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import GenericViewSet from rest_framework.viewsets import GenericViewSet
@ -37,6 +39,11 @@ class AuthorizationCodeViewSet(
serializer_class = ExpiringBaseGrantModelSerializer serializer_class = ExpiringBaseGrantModelSerializer
filterset_fields = ["user", "provider"] filterset_fields = ["user", "provider"]
ordering = ["provider", "expires"] ordering = ["provider", "expires"]
filter_backends = [
DjangoFilterBackend,
OrderingFilter,
SearchFilter,
]
def get_queryset(self): def get_queryset(self):
user = self.request.user if self.request else get_anonymous_user() user = self.request.user if self.request else get_anonymous_user()
@ -57,6 +64,11 @@ class RefreshTokenViewSet(
serializer_class = ExpiringBaseGrantModelSerializer serializer_class = ExpiringBaseGrantModelSerializer
filterset_fields = ["user", "provider"] filterset_fields = ["user", "provider"]
ordering = ["provider", "expires"] ordering = ["provider", "expires"]
filter_backends = [
DjangoFilterBackend,
OrderingFilter,
SearchFilter,
]
def get_queryset(self): def get_queryset(self):
user = self.request.user if self.request else get_anonymous_user() user = self.request.user if self.request else get_anonymous_user()

View File

@ -17,7 +17,6 @@ from kubernetes.client.models.networking_v1beta1_ingress_rule import (
from authentik.outposts.controllers.base import FIELD_MANAGER from authentik.outposts.controllers.base import FIELD_MANAGER
from authentik.outposts.controllers.k8s.base import ( from authentik.outposts.controllers.k8s.base import (
Disabled,
KubernetesObjectReconciler, KubernetesObjectReconciler,
NeedsUpdate, NeedsUpdate,
) )
@ -137,9 +136,6 @@ class IngressReconciler(KubernetesObjectReconciler[NetworkingV1beta1Ingress]):
), ),
) )
rules.append(rule) rules.append(rule)
if not rules:
self.logger.debug("No providers use proxying, no ingress needed")
raise Disabled()
tls_config = None tls_config = None
if tls_hosts: if tls_hosts:
tls_config = NetworkingV1beta1IngressTLS( tls_config = NetworkingV1beta1IngressTLS(

View File

@ -7,7 +7,6 @@ from kubernetes.client import ApiextensionsV1Api, CustomObjectsApi
from authentik.outposts.controllers.base import FIELD_MANAGER from authentik.outposts.controllers.base import FIELD_MANAGER
from authentik.outposts.controllers.k8s.base import ( from authentik.outposts.controllers.k8s.base import (
Disabled,
KubernetesObjectReconciler, KubernetesObjectReconciler,
NeedsUpdate, NeedsUpdate,
) )
@ -70,6 +69,19 @@ class TraefikMiddlewareReconciler(KubernetesObjectReconciler[TraefikMiddleware])
self.api_ex = ApiextensionsV1Api(controller.client) self.api_ex = ApiextensionsV1Api(controller.client)
self.api = CustomObjectsApi(controller.client) self.api = CustomObjectsApi(controller.client)
@property
def noop(self) -> bool:
if not ProxyProvider.objects.filter(
outpost__in=[self.controller.outpost],
forward_auth_mode=True,
).exists():
self.logger.debug("No providers with forward auth enabled.")
return True
if not self._crd_exists():
self.logger.debug("CRD doesn't exist")
return True
return False
def _crd_exists(self) -> bool: def _crd_exists(self) -> bool:
"""Check if the traefik middleware exists""" """Check if the traefik middleware exists"""
return bool( return bool(
@ -87,15 +99,6 @@ class TraefikMiddlewareReconciler(KubernetesObjectReconciler[TraefikMiddleware])
def get_reference_object(self) -> TraefikMiddleware: def get_reference_object(self) -> TraefikMiddleware:
"""Get deployment object for outpost""" """Get deployment object for outpost"""
if not ProxyProvider.objects.filter(
outpost__in=[self.controller.outpost],
forward_auth_mode=True,
).exists():
self.logger.debug("No providers with forward auth enabled.")
raise Disabled()
if not self._crd_exists():
self.logger.debug("CRD doesn't exist")
raise Disabled()
return TraefikMiddleware( return TraefikMiddleware(
apiVersion=f"{CRD_GROUP}/{CRD_VERSION}", apiVersion=f"{CRD_GROUP}/{CRD_VERSION}",
kind="Middleware", kind="Middleware",

View File

@ -248,6 +248,7 @@ DATABASES = {
"NAME": CONFIG.y("postgresql.name"), "NAME": CONFIG.y("postgresql.name"),
"USER": CONFIG.y("postgresql.user"), "USER": CONFIG.y("postgresql.user"),
"PASSWORD": CONFIG.y("postgresql.password"), "PASSWORD": CONFIG.y("postgresql.password"),
"PORT": int(CONFIG.y("postgresql.port")),
} }
} }
@ -320,7 +321,8 @@ CELERY_RESULT_BACKEND = (
DBBACKUP_STORAGE = "django.core.files.storage.FileSystemStorage" DBBACKUP_STORAGE = "django.core.files.storage.FileSystemStorage"
DBBACKUP_STORAGE_OPTIONS = {"location": "./backups" if DEBUG else "/backups"} DBBACKUP_STORAGE_OPTIONS = {"location": "./backups" if DEBUG else "/backups"}
DBBACKUP_CONNECTOR_MAPPING = { DBBACKUP_CONNECTOR_MAPPING = {
"django_prometheus.db.backends.postgresql": "dbbackup.db.postgresql.PgDumpConnector" "django_prometheus.db.backends.postgresql": "authentik.lib.connector.PgCustom",
"django.db.backends.postgresql": "authentik.lib.connector.PgCustom",
} }
if CONFIG.y("postgresql.s3_backup"): if CONFIG.y("postgresql.s3_backup"):
DBBACKUP_STORAGE = "storages.backends.s3boto3.S3Boto3Storage" DBBACKUP_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
@ -331,9 +333,10 @@ if CONFIG.y("postgresql.s3_backup"):
"region_name": CONFIG.y("postgresql.s3_backup.region", "eu-central-1"), "region_name": CONFIG.y("postgresql.s3_backup.region", "eu-central-1"),
"default_acl": "private", "default_acl": "private",
"endpoint_url": CONFIG.y("postgresql.s3_backup.host"), "endpoint_url": CONFIG.y("postgresql.s3_backup.host"),
"location": CONFIG.y("postgresql.s3_backup.location", ""),
} }
j_print( j_print(
"Database backup to S3 is configured.", "Database backup to S3 is configured",
host=CONFIG.y("postgresql.s3_backup.host"), host=CONFIG.y("postgresql.s3_backup.host"),
) )
@ -355,7 +358,7 @@ if _ERROR_REPORTING:
send_default_pii=CONFIG.y_bool("error_reporting.send_pii", False), send_default_pii=CONFIG.y_bool("error_reporting.send_pii", False),
) )
j_print( j_print(
"Error reporting is enabled.", "Error reporting is enabled",
env=CONFIG.y("error_reporting.environment", "customer"), env=CONFIG.y("error_reporting.environment", "customer"),
) )

View File

@ -75,6 +75,7 @@ class OAuthSourceSerializer(SourceSerializer):
"callback_url", "callback_url",
"type", "type",
] ]
extra_kwargs = {"consumer_secret": {"write_only": True}}
class OAuthSourceViewSet(ModelViewSet): class OAuthSourceViewSet(ModelViewSet):

View File

@ -1,5 +1,7 @@
"""OAuth Source Serializer""" """OAuth Source Serializer"""
from django_filters.rest_framework import DjangoFilterBackend
from guardian.utils import get_anonymous_user from guardian.utils import get_anonymous_user
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from authentik.core.api.sources import SourceSerializer from authentik.core.api.sources import SourceSerializer
@ -25,6 +27,11 @@ class UserOAuthSourceConnectionViewSet(ModelViewSet):
queryset = UserOAuthSourceConnection.objects.all() queryset = UserOAuthSourceConnection.objects.all()
serializer_class = UserOAuthSourceConnectionSerializer serializer_class = UserOAuthSourceConnectionSerializer
filterset_fields = ["source__slug"] filterset_fields = ["source__slug"]
filter_backends = [
DjangoFilterBackend,
OrderingFilter,
SearchFilter,
]
def get_queryset(self): def get_queryset(self):
user = self.request.user if self.request else get_anonymous_user() user = self.request.user if self.request else get_anonymous_user()

View File

@ -33,6 +33,5 @@ class TestTypeGoogle(TestCase):
def test_enroll_context(self): def test_enroll_context(self):
"""Test Google Enrollment context""" """Test Google Enrollment context"""
ak_context = GoogleOAuth2Callback().get_user_enroll_context(GOOGLE_USER) ak_context = GoogleOAuth2Callback().get_user_enroll_context(GOOGLE_USER)
self.assertEqual(ak_context["username"], GOOGLE_USER["email"])
self.assertEqual(ak_context["email"], GOOGLE_USER["email"]) self.assertEqual(ak_context["email"], GOOGLE_USER["email"])
self.assertEqual(ak_context["name"], GOOGLE_USER["name"]) self.assertEqual(ak_context["name"], GOOGLE_USER["name"])

View File

@ -23,7 +23,6 @@ class GoogleOAuth2Callback(OAuthCallback):
info: dict[str, Any], info: dict[str, Any],
) -> dict[str, Any]: ) -> dict[str, Any]:
return { return {
"username": info.get("email"),
"email": info.get("email"), "email": info.get("email"),
"name": info.get("name"), "name": info.get("name"),
} }

View File

@ -1,6 +1,9 @@
"""AuthenticatorStaticStage API Views""" """AuthenticatorStaticStage API Views"""
from django_filters import OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend
from django_otp.plugins.otp_static.models import StaticDevice from django_otp.plugins.otp_static.models import StaticDevice
from guardian.utils import get_anonymous_user from guardian.utils import get_anonymous_user
from rest_framework.filters import SearchFilter
from rest_framework.permissions import IsAdminUser from rest_framework.permissions import IsAdminUser
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
@ -43,6 +46,11 @@ class StaticDeviceViewSet(ModelViewSet):
search_fields = ["name"] search_fields = ["name"]
filterset_fields = ["name"] filterset_fields = ["name"]
ordering = ["name"] ordering = ["name"]
filter_backends = [
DjangoFilterBackend,
OrderingFilter,
SearchFilter,
]
def get_queryset(self): def get_queryset(self):
user = self.request.user if self.request else get_anonymous_user() user = self.request.user if self.request else get_anonymous_user()

View File

@ -1,6 +1,8 @@
"""AuthenticatorTOTPStage API Views""" """AuthenticatorTOTPStage API Views"""
from django_filters.rest_framework import DjangoFilterBackend
from django_otp.plugins.otp_totp.models import TOTPDevice from django_otp.plugins.otp_totp.models import TOTPDevice
from guardian.utils import get_anonymous_user from guardian.utils import get_anonymous_user
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import IsAdminUser from rest_framework.permissions import IsAdminUser
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
@ -46,6 +48,11 @@ class TOTPDeviceViewSet(ModelViewSet):
search_fields = ["name"] search_fields = ["name"]
filterset_fields = ["name"] filterset_fields = ["name"]
ordering = ["name"] ordering = ["name"]
filter_backends = [
DjangoFilterBackend,
OrderingFilter,
SearchFilter,
]
def get_queryset(self): def get_queryset(self):
user = self.request.user if self.request else get_anonymous_user() user = self.request.user if self.request else get_anonymous_user()

View File

@ -1,5 +1,7 @@
"""AuthenticateWebAuthnStage API Views""" """AuthenticateWebAuthnStage API Views"""
from django_filters.rest_framework import DjangoFilterBackend
from guardian.utils import get_anonymous_user from guardian.utils import get_anonymous_user
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import IsAdminUser from rest_framework.permissions import IsAdminUser
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
@ -45,6 +47,11 @@ class WebAuthnDeviceViewSet(ModelViewSet):
search_fields = ["name"] search_fields = ["name"]
filterset_fields = ["name"] filterset_fields = ["name"]
ordering = ["name"] ordering = ["name"]
filter_backends = [
DjangoFilterBackend,
OrderingFilter,
SearchFilter,
]
def get_queryset(self): def get_queryset(self):
user = self.request.user if self.request else get_anonymous_user() user = self.request.user if self.request else get_anonymous_user()

View File

@ -1,6 +1,8 @@
"""ConsentStage API Views""" """ConsentStage API Views"""
from django_filters.rest_framework import DjangoFilterBackend
from guardian.utils import get_anonymous_user from guardian.utils import get_anonymous_user
from rest_framework import mixins from rest_framework import mixins
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.viewsets import GenericViewSet, ModelViewSet from rest_framework.viewsets import GenericViewSet, ModelViewSet
from authentik.core.api.applications import ApplicationSerializer from authentik.core.api.applications import ApplicationSerializer
@ -49,6 +51,11 @@ class UserConsentViewSet(
serializer_class = UserConsentSerializer serializer_class = UserConsentSerializer
filterset_fields = ["user", "application"] filterset_fields = ["user", "application"]
ordering = ["application", "expires"] ordering = ["application", "expires"]
filter_backends = [
DjangoFilterBackend,
OrderingFilter,
SearchFilter,
]
def get_queryset(self): def get_queryset(self):
user = self.request.user if self.request else get_anonymous_user() user = self.request.user if self.request else get_anonymous_user()

View File

@ -19,7 +19,7 @@ variables:
branchName: ${{ replace(variables['Build.SourceBranchName'], 'refs/heads/', '') }} branchName: ${{ replace(variables['Build.SourceBranchName'], 'refs/heads/', '') }}
stages: stages:
- stage: Lint - stage: Lint_and_test
jobs: jobs:
- job: pylint - job: pylint
pool: pool:
@ -118,8 +118,6 @@ stages:
- task: CmdLine@2 - task: CmdLine@2
inputs: inputs:
script: pipenv run pyright e2e lifecycle script: pipenv run pyright e2e lifecycle
- stage: Test
jobs:
- job: migrations - job: migrations
pool: pool:
vmImage: 'ubuntu-latest' vmImage: 'ubuntu-latest'

View File

@ -21,7 +21,7 @@ services:
networks: networks:
- internal - internal
server: server:
image: ${AUTHENTIK_IMAGE:-beryju/authentik}:${AUTHENTIK_TAG:-2021.4.5} image: ${AUTHENTIK_IMAGE:-beryju/authentik}:${AUTHENTIK_TAG:-2021.5.1-rc7}
restart: unless-stopped restart: unless-stopped
command: server command: server
environment: environment:
@ -52,7 +52,7 @@ services:
- "0.0.0.0:9000:9000" - "0.0.0.0:9000:9000"
- "0.0.0.0:9443:9443" - "0.0.0.0:9443:9443"
worker: worker:
image: ${AUTHENTIK_IMAGE:-beryju/authentik}:${AUTHENTIK_TAG:-2021.4.5} image: ${AUTHENTIK_IMAGE:-beryju/authentik}:${AUTHENTIK_TAG:-2021.5.1-rc7}
restart: unless-stopped restart: unless-stopped
command: worker command: worker
networks: networks:

View File

@ -1,3 +1,3 @@
package constants package constants
const VERSION = "2021.4.5" const VERSION = "2021.5.1-rc7"

View File

@ -41,11 +41,9 @@ while True:
while True: while True:
try: try:
redis = Redis( redis = Redis.from_url(
host=CONFIG.y("redis.host"), f"redis://:{CONFIG.y('redis.password')}@{CONFIG.y('redis.host')}:6379"
port=6379, f"/{CONFIG.y('redis.ws_db')}"
db=CONFIG.y("redis.message_queue_db"),
password=CONFIG.y("redis.password"),
) )
redis.ping() redis.ping()
break break

View File

@ -90,6 +90,10 @@ func (a *APIController) Start() error {
a.logger.Debug("Starting WS Health notifier...") a.logger.Debug("Starting WS Health notifier...")
a.startWSHealth() a.startWSHealth()
}() }()
go func() {
a.logger.Debug("Starting Interval updater...")
a.startIntervalUpdater()
}()
go func() { go func() {
err := a.Server.Start() err := a.Server.Start()
if err != nil { if err != nil {

View File

@ -111,3 +111,14 @@ func (ac *APIController) startWSHealth() {
} }
} }
} }
func (ac *APIController) startIntervalUpdater() {
logger := ac.logger.WithField("loop", "interval-updater")
ticker := time.NewTicker(time.Second * 150)
for ; true; <-ticker.C {
err := ac.Server.Refresh()
if err != nil {
logger.WithError(err).Debug("Failed to update")
}
}
}

View File

@ -20,6 +20,8 @@ func doGlobalSetup(config map[string]interface{}) {
}, },
}) })
switch config[ConfigLogLevel].(string) { switch config[ConfigLogLevel].(string) {
case "trace":
log.SetLevel(log.TraceLevel)
case "debug": case "debug":
log.SetLevel(log.DebugLevel) log.SetLevel(log.DebugLevel)
case "info": case "info":

View File

@ -344,7 +344,11 @@ func (p *OAuthProxy) AuthenticateOnly(rw http.ResponseWriter, req *http.Request)
} }
if _, ok := req.URL.Query()["traefik"]; ok { if _, ok := req.URL.Query()["traefik"]; ok {
host := getHost(req) host := getHost(req)
http.Redirect(rw, req, fmt.Sprintf("//%s%s", host, p.OAuthStartPath), http.StatusTemporaryRedirect) proto := req.Header.Get("X-Forwarded-Proto")
if proto != "" {
proto = proto + ":"
}
http.Redirect(rw, req, fmt.Sprintf("%s//%s%s", proto, host, p.OAuthStartPath), http.StatusTemporaryRedirect)
return return
} }
} }

View File

@ -1,3 +1,3 @@
package pkg package pkg
const VERSION = "2021.4.5" const VERSION = "2021.5.1-rc7"

View File

@ -531,11 +531,6 @@ paths:
description: '' description: ''
required: false required: false
type: string type: string
- name: ordering
in: query
description: Which field to use when ordering the results.
required: false
type: string
- name: search - name: search
in: query in: query
description: A search term. description: A search term.
@ -16203,7 +16198,7 @@ definitions:
required: required:
- name - name
- providers - providers
- _config - config
type: object type: object
properties: properties:
pk: pk:
@ -16242,8 +16237,8 @@ definitions:
title: Token identifier title: Token identifier
type: string type: string
readOnly: true readOnly: true
_config: config:
title: config title: Config
type: object type: object
OutpostDefaultConfig: OutpostDefaultConfig:
type: object type: object

View File

@ -81,7 +81,7 @@ http {
location /static/ { location /static/ {
expires 31d; expires 31d;
add_header Cache-Control "public, no-transform"; add_header Cache-Control "public, no-transform";
add_header X-authentik-version "2021.4.5"; add_header X-authentik-version "2021.5.1-rc7";
add_header Vary X-authentik-version; add_header Vary X-authentik-version;
} }

485
web/package-lock.json generated
View File

@ -24,13 +24,13 @@
"@rollup/plugin-babel": "^5.3.0", "@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-replace": "^2.4.2", "@rollup/plugin-replace": "^2.4.2",
"@rollup/plugin-typescript": "^8.2.1", "@rollup/plugin-typescript": "^8.2.1",
"@sentry/browser": "^6.3.5", "@sentry/browser": "^6.3.6",
"@sentry/tracing": "^6.3.5", "@sentry/tracing": "^6.3.6",
"@types/chart.js": "^2.9.32", "@types/chart.js": "^2.9.32",
"@types/codemirror": "5.60.0", "@types/codemirror": "5.60.0",
"@types/grecaptcha": "^3.0.2", "@types/grecaptcha": "^3.0.2",
"@typescript-eslint/eslint-plugin": "^4.22.1", "@typescript-eslint/eslint-plugin": "^4.23.0",
"@typescript-eslint/parser": "^4.22.1", "@typescript-eslint/parser": "^4.23.0",
"@webcomponents/webcomponentsjs": "^2.5.0", "@webcomponents/webcomponentsjs": "^2.5.0",
"authentik-api": "file:api", "authentik-api": "file:api",
"babel-plugin-macros": "^3.1.0", "babel-plugin-macros": "^3.1.0",
@ -39,10 +39,10 @@
"chartjs-adapter-moment": "^1.0.0", "chartjs-adapter-moment": "^1.0.0",
"codemirror": "^5.61.0", "codemirror": "^5.61.0",
"construct-style-sheets-polyfill": "^2.4.16", "construct-style-sheets-polyfill": "^2.4.16",
"eslint": "^7.25.0", "eslint": "^7.26.0",
"eslint-config-google": "^0.14.0", "eslint-config-google": "^0.14.0",
"eslint-plugin-custom-elements": "0.0.2", "eslint-plugin-custom-elements": "0.0.2",
"eslint-plugin-lit": "^1.3.0", "eslint-plugin-lit": "^1.4.0",
"flowchart.js": "^1.15.0", "flowchart.js": "^1.15.0",
"lit-element": "^2.5.1", "lit-element": "^2.5.1",
"lit-html": "^1.4.1", "lit-html": "^1.4.1",
@ -61,13 +61,12 @@
"typescript": "^4.2.4", "typescript": "^4.2.4",
"webcomponent-qr-code": "^1.0.5", "webcomponent-qr-code": "^1.0.5",
"yaml": "^1.10.2" "yaml": "^1.10.2"
}, }
"devDependencies": {}
}, },
"api": { "api": {
"name": "authentik-api", "name": "authentik-api",
"version": "1.0.0", "version": "0.0.1",
"devDependencies": { "dependencies": {
"typescript": "^3.6" "typescript": "^3.6"
} }
}, },
@ -75,7 +74,6 @@
"version": "3.9.9", "version": "3.9.9",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz",
"integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==",
"dev": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@ -1725,9 +1723,9 @@
} }
}, },
"node_modules/@eslint/eslintrc": { "node_modules/@eslint/eslintrc": {
"version": "0.4.0", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz",
"integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==", "integrity": "sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==",
"dependencies": { "dependencies": {
"ajv": "^6.12.4", "ajv": "^6.12.4",
"debug": "^4.1.1", "debug": "^4.1.1",
@ -1752,6 +1750,9 @@
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/@eslint/eslintrc/node_modules/ignore": { "node_modules/@eslint/eslintrc/node_modules/ignore": {
@ -2337,33 +2338,13 @@
"integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg=="
}, },
"node_modules/@sentry/browser": { "node_modules/@sentry/browser": {
"version": "6.3.5", "version": "6.3.6",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.3.5.tgz", "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.3.6.tgz",
"integrity": "sha512-fjkhPR5gLCGVWhbWjEoN64hnmTvfTLRCgWmYTc9SiGchWFoFEmLqZyF2uJFyt27+qamLQ9fN58nnv4Ly2yyxqg==", "integrity": "sha512-l4323jxuBOArki6Wf+EHes39IEyJ2Zj/CIUaTY7GWh7CntpfHQAfFmZWQw3Ozq+ka1u8lVp25RPhb4Wng3azNA==",
"dependencies": { "dependencies": {
"@sentry/core": "6.3.5", "@sentry/core": "6.3.6",
"@sentry/types": "6.3.5", "@sentry/types": "6.3.6",
"@sentry/utils": "6.3.5", "@sentry/utils": "6.3.6",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/browser/node_modules/@sentry/types": {
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.3.5.tgz",
"integrity": "sha512-tY/3pkAmGYJ3F0BtwInsdt/uclNvF8aNG7XHsTPQNzk7BkNVWjCXx0sjxi6CILirl5nwNxYxVeTr2ZYAEZ/dSQ==",
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/browser/node_modules/@sentry/utils": {
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.3.5.tgz",
"integrity": "sha512-kHUcZ37QYlNzz7c9LVdApITXHaNmQK7+sw/If3M/qpff1fd5XoecA8laLfcYuz+Cw5mRhVmdhPcCRM3Xi1IGXg==",
"dependencies": {
"@sentry/types": "6.3.5",
"tslib": "^1.9.3" "tslib": "^1.9.3"
}, },
"engines": { "engines": {
@ -2376,60 +2357,14 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}, },
"node_modules/@sentry/core": { "node_modules/@sentry/core": {
"version": "6.3.5", "version": "6.3.6",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.3.5.tgz", "resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.3.6.tgz",
"integrity": "sha512-VR2ibDy33mryD0mT6d9fGhKjdNzS2FSwwZPe9GvmNOjkyjly/oV91BKVoYJneCqOeq8fyj2lvkJGKuupdJNDqg==", "integrity": "sha512-w6BRizAqh7BaiM9oeKzO6aACXwRijUPacYaVLX/OfhqCSueF9uDxpMRT7+4D/eCeDVqgJYhBJ4Vsu2NSstkk4A==",
"dependencies": { "dependencies": {
"@sentry/hub": "6.3.5", "@sentry/hub": "6.3.6",
"@sentry/minimal": "6.3.5", "@sentry/minimal": "6.3.6",
"@sentry/types": "6.3.5", "@sentry/types": "6.3.6",
"@sentry/utils": "6.3.5", "@sentry/utils": "6.3.6",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/core/node_modules/@sentry/hub": {
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.3.5.tgz",
"integrity": "sha512-ZYFo7VYKwdPVjuV9BDFiYn+MpANn6eZMz5QDBfZ2dugIvIVbuOyOOLx8PSa3ZXJoVTZZ7s2wD2fi/ZxKjNjZOQ==",
"dependencies": {
"@sentry/types": "6.3.5",
"@sentry/utils": "6.3.5",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/core/node_modules/@sentry/minimal": {
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.3.5.tgz",
"integrity": "sha512-4RqIGAU0+8iI/1sw0GYPTr4SUA88/i2+JPjFJ+qloh5ANVaNwhFPRChw+Ys9xpre8LV9JZrEsEf8AvQr4fkNbA==",
"dependencies": {
"@sentry/hub": "6.3.5",
"@sentry/types": "6.3.5",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/core/node_modules/@sentry/types": {
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.3.5.tgz",
"integrity": "sha512-tY/3pkAmGYJ3F0BtwInsdt/uclNvF8aNG7XHsTPQNzk7BkNVWjCXx0sjxi6CILirl5nwNxYxVeTr2ZYAEZ/dSQ==",
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/core/node_modules/@sentry/utils": {
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.3.5.tgz",
"integrity": "sha512-kHUcZ37QYlNzz7c9LVdApITXHaNmQK7+sw/If3M/qpff1fd5XoecA8laLfcYuz+Cw5mRhVmdhPcCRM3Xi1IGXg==",
"dependencies": {
"@sentry/types": "6.3.5",
"tslib": "^1.9.3" "tslib": "^1.9.3"
}, },
"engines": { "engines": {
@ -2442,12 +2377,12 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}, },
"node_modules/@sentry/hub": { "node_modules/@sentry/hub": {
"version": "6.3.5", "version": "6.3.6",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.3.5.tgz", "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.3.6.tgz",
"integrity": "sha512-ZYFo7VYKwdPVjuV9BDFiYn+MpANn6eZMz5QDBfZ2dugIvIVbuOyOOLx8PSa3ZXJoVTZZ7s2wD2fi/ZxKjNjZOQ==", "integrity": "sha512-foBZ3ilMnm9Gf9OolrAxYHK8jrA6IF72faDdJ3Al+1H27qcpnBaMdrdEp2/jzwu/dgmwuLmbBaMjEPXaGH/0JQ==",
"dependencies": { "dependencies": {
"@sentry/types": "6.3.5", "@sentry/types": "6.3.6",
"@sentry/utils": "6.3.5", "@sentry/utils": "6.3.6",
"tslib": "^1.9.3" "tslib": "^1.9.3"
}, },
"engines": { "engines": {
@ -2460,12 +2395,12 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}, },
"node_modules/@sentry/minimal": { "node_modules/@sentry/minimal": {
"version": "6.3.5", "version": "6.3.6",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.3.5.tgz", "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.3.6.tgz",
"integrity": "sha512-4RqIGAU0+8iI/1sw0GYPTr4SUA88/i2+JPjFJ+qloh5ANVaNwhFPRChw+Ys9xpre8LV9JZrEsEf8AvQr4fkNbA==", "integrity": "sha512-uM2/dH0a6zfvI5f+vg+/mST+uTBdN6Jgpm585ipH84ckCYQwIIDRg6daqsen4S1sy/xgg1P1YyC3zdEC4G6b1Q==",
"dependencies": { "dependencies": {
"@sentry/hub": "6.3.5", "@sentry/hub": "6.3.6",
"@sentry/types": "6.3.5", "@sentry/types": "6.3.6",
"tslib": "^1.9.3" "tslib": "^1.9.3"
}, },
"engines": { "engines": {
@ -2478,14 +2413,14 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}, },
"node_modules/@sentry/tracing": { "node_modules/@sentry/tracing": {
"version": "6.3.5", "version": "6.3.6",
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.3.5.tgz", "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.3.6.tgz",
"integrity": "sha512-TNKAST1ge2g24BlTfVxNp4gP5t3drbi0OVCh8h8ah+J7UjHSfdiqhd9W2h5qv1GO61gGlpWeN/TyioyQmOxu0Q==", "integrity": "sha512-dfyYY2eESJGt5Qbigmfmb2U9ntqbwPhLNAOcjKaVg9WQRV5q2RkHCVctPoYk7TEAvfNeNRXCD8SnuFOZhttt8g==",
"dependencies": { "dependencies": {
"@sentry/hub": "6.3.5", "@sentry/hub": "6.3.6",
"@sentry/minimal": "6.3.5", "@sentry/minimal": "6.3.6",
"@sentry/types": "6.3.5", "@sentry/types": "6.3.6",
"@sentry/utils": "6.3.5", "@sentry/utils": "6.3.6",
"tslib": "^1.9.3" "tslib": "^1.9.3"
}, },
"engines": { "engines": {
@ -2498,19 +2433,19 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}, },
"node_modules/@sentry/types": { "node_modules/@sentry/types": {
"version": "6.3.5", "version": "6.3.6",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.3.5.tgz", "resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.3.6.tgz",
"integrity": "sha512-tY/3pkAmGYJ3F0BtwInsdt/uclNvF8aNG7XHsTPQNzk7BkNVWjCXx0sjxi6CILirl5nwNxYxVeTr2ZYAEZ/dSQ==", "integrity": "sha512-93cFJdJkWyCfyZeWFARSU11qnoHVOS/R2h5WIsEf+jbQmkqG2C+TXVz/19s6nHVsfDrwpvYpwALPv4/nrxfU7g==",
"engines": { "engines": {
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/@sentry/utils": { "node_modules/@sentry/utils": {
"version": "6.3.5", "version": "6.3.6",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.3.5.tgz", "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.3.6.tgz",
"integrity": "sha512-kHUcZ37QYlNzz7c9LVdApITXHaNmQK7+sw/If3M/qpff1fd5XoecA8laLfcYuz+Cw5mRhVmdhPcCRM3Xi1IGXg==", "integrity": "sha512-HnYlDBf8Dq8MEv7AulH7B6R1D/2LAooVclGdjg48tSrr9g+31kmtj+SAj2WWVHP9+bp29BWaC7i5nkfKrOibWw==",
"dependencies": { "dependencies": {
"@sentry/types": "6.3.5", "@sentry/types": "6.3.6",
"tslib": "^1.9.3" "tslib": "^1.9.3"
}, },
"engines": { "engines": {
@ -2668,12 +2603,12 @@
"integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==" "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA=="
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "4.22.1", "version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.22.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.23.0.tgz",
"integrity": "sha512-kVTAghWDDhsvQ602tHBc6WmQkdaYbkcTwZu+7l24jtJiYvm9l+/y/b2BZANEezxPDiX5MK2ZecE+9BFi/YJryw==", "integrity": "sha512-tGK1y3KIvdsQEEgq6xNn1DjiFJtl+wn8JJQiETtCbdQxw1vzjXyAaIkEmO2l6Nq24iy3uZBMFQjZ6ECf1QdgGw==",
"dependencies": { "dependencies": {
"@typescript-eslint/experimental-utils": "4.22.1", "@typescript-eslint/experimental-utils": "4.23.0",
"@typescript-eslint/scope-manager": "4.22.1", "@typescript-eslint/scope-manager": "4.23.0",
"debug": "^4.1.1", "debug": "^4.1.1",
"functional-red-black-tree": "^1.0.1", "functional-red-black-tree": "^1.0.1",
"lodash": "^4.17.15", "lodash": "^4.17.15",
@ -2699,14 +2634,14 @@
} }
}, },
"node_modules/@typescript-eslint/experimental-utils": { "node_modules/@typescript-eslint/experimental-utils": {
"version": "4.22.1", "version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.23.0.tgz",
"integrity": "sha512-svYlHecSMCQGDO2qN1v477ax/IDQwWhc7PRBiwAdAMJE7GXk5stF4Z9R/8wbRkuX/5e9dHqbIWxjeOjckK3wLQ==", "integrity": "sha512-WAFNiTDnQfrF3Z2fQ05nmCgPsO5o790vOhmWKXbbYQTO9erE1/YsFot5/LnOUizLzU2eeuz6+U/81KV5/hFTGA==",
"dependencies": { "dependencies": {
"@types/json-schema": "^7.0.3", "@types/json-schema": "^7.0.3",
"@typescript-eslint/scope-manager": "4.22.1", "@typescript-eslint/scope-manager": "4.23.0",
"@typescript-eslint/types": "4.22.1", "@typescript-eslint/types": "4.23.0",
"@typescript-eslint/typescript-estree": "4.22.1", "@typescript-eslint/typescript-estree": "4.23.0",
"eslint-scope": "^5.0.0", "eslint-scope": "^5.0.0",
"eslint-utils": "^2.0.0" "eslint-utils": "^2.0.0"
}, },
@ -2722,13 +2657,13 @@
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "4.22.1", "version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.22.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.23.0.tgz",
"integrity": "sha512-l+sUJFInWhuMxA6rtirzjooh8cM/AATAe3amvIkqKFeMzkn85V+eLzb1RyuXkHak4dLfYzOmF6DXPyflJvjQnw==", "integrity": "sha512-wsvjksHBMOqySy/Pi2Q6UuIuHYbgAMwLczRl4YanEPKW5KVxI9ZzDYh3B5DtcZPQTGRWFJrfcbJ6L01Leybwug==",
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "4.22.1", "@typescript-eslint/scope-manager": "4.23.0",
"@typescript-eslint/types": "4.22.1", "@typescript-eslint/types": "4.23.0",
"@typescript-eslint/typescript-estree": "4.22.1", "@typescript-eslint/typescript-estree": "4.23.0",
"debug": "^4.1.1" "debug": "^4.1.1"
}, },
"engines": { "engines": {
@ -2748,12 +2683,12 @@
} }
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "4.22.1", "version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.22.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.23.0.tgz",
"integrity": "sha512-d5bAiPBiessSmNi8Amq/RuLslvcumxLmyhf1/Xa9IuaoFJ0YtshlJKxhlbY7l2JdEk3wS0EnmnfeJWSvADOe0g==", "integrity": "sha512-ZZ21PCFxPhI3n0wuqEJK9omkw51wi2bmeKJvlRZPH5YFkcawKOuRMQMnI8mH6Vo0/DoHSeZJnHiIx84LmVQY+w==",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "4.22.1", "@typescript-eslint/types": "4.23.0",
"@typescript-eslint/visitor-keys": "4.22.1" "@typescript-eslint/visitor-keys": "4.23.0"
}, },
"engines": { "engines": {
"node": "^8.10.0 || ^10.13.0 || >=11.10.1" "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
@ -2764,9 +2699,9 @@
} }
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "4.22.1", "version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.22.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.23.0.tgz",
"integrity": "sha512-2HTkbkdAeI3OOcWbqA8hWf/7z9c6gkmnWNGz0dKSLYLWywUlkOAQ2XcjhlKLj5xBFDf8FgAOF5aQbnLRvgNbCw==", "integrity": "sha512-oqkNWyG2SLS7uTWLZf6Sr7Dm02gA5yxiz1RP87tvsmDsguVATdpVguHr4HoGOcFOpCvx9vtCSCyQUGfzq28YCw==",
"engines": { "engines": {
"node": "^8.10.0 || ^10.13.0 || >=11.10.1" "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
}, },
@ -2776,12 +2711,12 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "4.22.1", "version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.23.0.tgz",
"integrity": "sha512-p3We0pAPacT+onSGM+sPR+M9CblVqdA9F1JEdIqRVlxK5Qth4ochXQgIyb9daBomyQKAXbygxp1aXQRV0GC79A==", "integrity": "sha512-5Sty6zPEVZF5fbvrZczfmLCOcby3sfrSPu30qKoY1U3mca5/jvU5cwsPb/CO6Q3ByRjixTMIVsDkqwIxCf/dMw==",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "4.22.1", "@typescript-eslint/types": "4.23.0",
"@typescript-eslint/visitor-keys": "4.22.1", "@typescript-eslint/visitor-keys": "4.23.0",
"debug": "^4.1.1", "debug": "^4.1.1",
"globby": "^11.0.1", "globby": "^11.0.1",
"is-glob": "^4.0.1", "is-glob": "^4.0.1",
@ -2821,11 +2756,11 @@
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "4.22.1", "version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.23.0.tgz",
"integrity": "sha512-WPkOrIRm+WCLZxXQHCi+WG8T2MMTUFR70rWjdWYddLT7cEfb2P4a3O/J2U1FBVsSFTocXLCoXWY6MZGejeStvQ==", "integrity": "sha512-5PNe5cmX9pSifit0H+nPoQBXdbNzi5tOEec+3riK+ku4e3er37pKxMKDH5Ct5Y4fhWxcD4spnlYjxi9vXbSpwg==",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "4.22.1", "@typescript-eslint/types": "4.23.0",
"eslint-visitor-keys": "^2.0.0" "eslint-visitor-keys": "^2.0.0"
}, },
"engines": { "engines": {
@ -2860,7 +2795,10 @@
"node_modules/acorn-jsx": { "node_modules/acorn-jsx": {
"version": "5.3.1", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
"integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==" "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
"peerDependencies": {
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
}, },
"node_modules/ajv": { "node_modules/ajv": {
"version": "6.12.6", "version": "6.12.6",
@ -2871,6 +2809,10 @@
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1", "json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2" "uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
} }
}, },
"node_modules/ansi-colors": { "node_modules/ansi-colors": {
@ -3906,12 +3848,12 @@
} }
}, },
"node_modules/eslint": { "node_modules/eslint": {
"version": "7.25.0", "version": "7.26.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.25.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.26.0.tgz",
"integrity": "sha512-TVpSovpvCNpLURIScDRB6g5CYu/ZFq9GfX2hLNIV4dSBKxIWojeDODvYl3t0k0VtMxYeR8OXPCFE5+oHMlGfhw==", "integrity": "sha512-4R1ieRf52/izcZE7AlLy56uIHHDLT74Yzz2Iv2l6kDaYvEu9x+wMB5dZArVL8SYGXSYV2YAg70FcW5Y5nGGNIg==",
"dependencies": { "dependencies": {
"@babel/code-frame": "7.12.11", "@babel/code-frame": "7.12.11",
"@eslint/eslintrc": "^0.4.0", "@eslint/eslintrc": "^0.4.1",
"ajv": "^6.10.0", "ajv": "^6.10.0",
"chalk": "^4.0.0", "chalk": "^4.0.0",
"cross-spawn": "^7.0.2", "cross-spawn": "^7.0.2",
@ -3953,6 +3895,9 @@
}, },
"engines": { "engines": {
"node": "^10.12.0 || >=12.0.0" "node": "^10.12.0 || >=12.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
} }
}, },
"node_modules/eslint-config-google": { "node_modules/eslint-config-google": {
@ -3972,13 +3917,16 @@
} }
}, },
"node_modules/eslint-plugin-lit": { "node_modules/eslint-plugin-lit": {
"version": "1.3.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.3.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.4.0.tgz",
"integrity": "sha512-fy6Lr5vYI3kvCYaDXA20lwyKAp1keS9UjR5ntj8U2TeV+1yUta3S7xxXe+rABKRPbcNzi1ZvQLE1LmNKc9yr4Q==", "integrity": "sha512-3PJCC1p4pvDBKtFmg1g2cGzAgJF4IDqhb9NJUh95nYc+QXExa/O/0fILF4WB6X7qdNQKm+gW6nYtSKTyYPHtXw==",
"dependencies": { "dependencies": {
"parse5": "^6.0.1", "parse5": "^6.0.1",
"parse5-htmlparser2-tree-adapter": "^6.0.1", "parse5-htmlparser2-tree-adapter": "^6.0.1",
"requireindex": "^1.2.0" "requireindex": "^1.2.0"
},
"peerDependencies": {
"eslint": ">= 5"
} }
}, },
"node_modules/eslint-rule-documentation": { "node_modules/eslint-rule-documentation": {
@ -7355,6 +7303,9 @@
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"engines": { "engines": {
"node": ">=8" "node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/supports-color": { "node_modules/supports-color": {
@ -9632,9 +9583,9 @@
} }
}, },
"@eslint/eslintrc": { "@eslint/eslintrc": {
"version": "0.4.0", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz",
"integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==", "integrity": "sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==",
"requires": { "requires": {
"ajv": "^6.12.4", "ajv": "^6.12.4",
"debug": "^4.1.1", "debug": "^4.1.1",
@ -10146,30 +10097,16 @@
} }
}, },
"@sentry/browser": { "@sentry/browser": {
"version": "6.3.5", "version": "6.3.6",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.3.5.tgz", "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.3.6.tgz",
"integrity": "sha512-fjkhPR5gLCGVWhbWjEoN64hnmTvfTLRCgWmYTc9SiGchWFoFEmLqZyF2uJFyt27+qamLQ9fN58nnv4Ly2yyxqg==", "integrity": "sha512-l4323jxuBOArki6Wf+EHes39IEyJ2Zj/CIUaTY7GWh7CntpfHQAfFmZWQw3Ozq+ka1u8lVp25RPhb4Wng3azNA==",
"requires": { "requires": {
"@sentry/core": "6.3.5", "@sentry/core": "6.3.6",
"@sentry/types": "6.3.5", "@sentry/types": "6.3.6",
"@sentry/utils": "6.3.5", "@sentry/utils": "6.3.6",
"tslib": "^1.9.3" "tslib": "^1.9.3"
}, },
"dependencies": { "dependencies": {
"@sentry/types": {
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.3.5.tgz",
"integrity": "sha512-tY/3pkAmGYJ3F0BtwInsdt/uclNvF8aNG7XHsTPQNzk7BkNVWjCXx0sjxi6CILirl5nwNxYxVeTr2ZYAEZ/dSQ=="
},
"@sentry/utils": {
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.3.5.tgz",
"integrity": "sha512-kHUcZ37QYlNzz7c9LVdApITXHaNmQK7+sw/If3M/qpff1fd5XoecA8laLfcYuz+Cw5mRhVmdhPcCRM3Xi1IGXg==",
"requires": {
"@sentry/types": "6.3.5",
"tslib": "^1.9.3"
}
},
"tslib": { "tslib": {
"version": "1.14.1", "version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
@ -10178,51 +10115,17 @@
} }
}, },
"@sentry/core": { "@sentry/core": {
"version": "6.3.5", "version": "6.3.6",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.3.5.tgz", "resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.3.6.tgz",
"integrity": "sha512-VR2ibDy33mryD0mT6d9fGhKjdNzS2FSwwZPe9GvmNOjkyjly/oV91BKVoYJneCqOeq8fyj2lvkJGKuupdJNDqg==", "integrity": "sha512-w6BRizAqh7BaiM9oeKzO6aACXwRijUPacYaVLX/OfhqCSueF9uDxpMRT7+4D/eCeDVqgJYhBJ4Vsu2NSstkk4A==",
"requires": { "requires": {
"@sentry/hub": "6.3.5", "@sentry/hub": "6.3.6",
"@sentry/minimal": "6.3.5", "@sentry/minimal": "6.3.6",
"@sentry/types": "6.3.5", "@sentry/types": "6.3.6",
"@sentry/utils": "6.3.5", "@sentry/utils": "6.3.6",
"tslib": "^1.9.3" "tslib": "^1.9.3"
}, },
"dependencies": { "dependencies": {
"@sentry/hub": {
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.3.5.tgz",
"integrity": "sha512-ZYFo7VYKwdPVjuV9BDFiYn+MpANn6eZMz5QDBfZ2dugIvIVbuOyOOLx8PSa3ZXJoVTZZ7s2wD2fi/ZxKjNjZOQ==",
"requires": {
"@sentry/types": "6.3.5",
"@sentry/utils": "6.3.5",
"tslib": "^1.9.3"
}
},
"@sentry/minimal": {
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.3.5.tgz",
"integrity": "sha512-4RqIGAU0+8iI/1sw0GYPTr4SUA88/i2+JPjFJ+qloh5ANVaNwhFPRChw+Ys9xpre8LV9JZrEsEf8AvQr4fkNbA==",
"requires": {
"@sentry/hub": "6.3.5",
"@sentry/types": "6.3.5",
"tslib": "^1.9.3"
}
},
"@sentry/types": {
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.3.5.tgz",
"integrity": "sha512-tY/3pkAmGYJ3F0BtwInsdt/uclNvF8aNG7XHsTPQNzk7BkNVWjCXx0sjxi6CILirl5nwNxYxVeTr2ZYAEZ/dSQ=="
},
"@sentry/utils": {
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.3.5.tgz",
"integrity": "sha512-kHUcZ37QYlNzz7c9LVdApITXHaNmQK7+sw/If3M/qpff1fd5XoecA8laLfcYuz+Cw5mRhVmdhPcCRM3Xi1IGXg==",
"requires": {
"@sentry/types": "6.3.5",
"tslib": "^1.9.3"
}
},
"tslib": { "tslib": {
"version": "1.14.1", "version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
@ -10231,12 +10134,12 @@
} }
}, },
"@sentry/hub": { "@sentry/hub": {
"version": "6.3.5", "version": "6.3.6",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.3.5.tgz", "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.3.6.tgz",
"integrity": "sha512-ZYFo7VYKwdPVjuV9BDFiYn+MpANn6eZMz5QDBfZ2dugIvIVbuOyOOLx8PSa3ZXJoVTZZ7s2wD2fi/ZxKjNjZOQ==", "integrity": "sha512-foBZ3ilMnm9Gf9OolrAxYHK8jrA6IF72faDdJ3Al+1H27qcpnBaMdrdEp2/jzwu/dgmwuLmbBaMjEPXaGH/0JQ==",
"requires": { "requires": {
"@sentry/types": "6.3.5", "@sentry/types": "6.3.6",
"@sentry/utils": "6.3.5", "@sentry/utils": "6.3.6",
"tslib": "^1.9.3" "tslib": "^1.9.3"
}, },
"dependencies": { "dependencies": {
@ -10248,12 +10151,12 @@
} }
}, },
"@sentry/minimal": { "@sentry/minimal": {
"version": "6.3.5", "version": "6.3.6",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.3.5.tgz", "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.3.6.tgz",
"integrity": "sha512-4RqIGAU0+8iI/1sw0GYPTr4SUA88/i2+JPjFJ+qloh5ANVaNwhFPRChw+Ys9xpre8LV9JZrEsEf8AvQr4fkNbA==", "integrity": "sha512-uM2/dH0a6zfvI5f+vg+/mST+uTBdN6Jgpm585ipH84ckCYQwIIDRg6daqsen4S1sy/xgg1P1YyC3zdEC4G6b1Q==",
"requires": { "requires": {
"@sentry/hub": "6.3.5", "@sentry/hub": "6.3.6",
"@sentry/types": "6.3.5", "@sentry/types": "6.3.6",
"tslib": "^1.9.3" "tslib": "^1.9.3"
}, },
"dependencies": { "dependencies": {
@ -10265,14 +10168,14 @@
} }
}, },
"@sentry/tracing": { "@sentry/tracing": {
"version": "6.3.5", "version": "6.3.6",
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.3.5.tgz", "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.3.6.tgz",
"integrity": "sha512-TNKAST1ge2g24BlTfVxNp4gP5t3drbi0OVCh8h8ah+J7UjHSfdiqhd9W2h5qv1GO61gGlpWeN/TyioyQmOxu0Q==", "integrity": "sha512-dfyYY2eESJGt5Qbigmfmb2U9ntqbwPhLNAOcjKaVg9WQRV5q2RkHCVctPoYk7TEAvfNeNRXCD8SnuFOZhttt8g==",
"requires": { "requires": {
"@sentry/hub": "6.3.5", "@sentry/hub": "6.3.6",
"@sentry/minimal": "6.3.5", "@sentry/minimal": "6.3.6",
"@sentry/types": "6.3.5", "@sentry/types": "6.3.6",
"@sentry/utils": "6.3.5", "@sentry/utils": "6.3.6",
"tslib": "^1.9.3" "tslib": "^1.9.3"
}, },
"dependencies": { "dependencies": {
@ -10284,16 +10187,16 @@
} }
}, },
"@sentry/types": { "@sentry/types": {
"version": "6.3.5", "version": "6.3.6",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.3.5.tgz", "resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.3.6.tgz",
"integrity": "sha512-tY/3pkAmGYJ3F0BtwInsdt/uclNvF8aNG7XHsTPQNzk7BkNVWjCXx0sjxi6CILirl5nwNxYxVeTr2ZYAEZ/dSQ==" "integrity": "sha512-93cFJdJkWyCfyZeWFARSU11qnoHVOS/R2h5WIsEf+jbQmkqG2C+TXVz/19s6nHVsfDrwpvYpwALPv4/nrxfU7g=="
}, },
"@sentry/utils": { "@sentry/utils": {
"version": "6.3.5", "version": "6.3.6",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.3.5.tgz", "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.3.6.tgz",
"integrity": "sha512-kHUcZ37QYlNzz7c9LVdApITXHaNmQK7+sw/If3M/qpff1fd5XoecA8laLfcYuz+Cw5mRhVmdhPcCRM3Xi1IGXg==", "integrity": "sha512-HnYlDBf8Dq8MEv7AulH7B6R1D/2LAooVclGdjg48tSrr9g+31kmtj+SAj2WWVHP9+bp29BWaC7i5nkfKrOibWw==",
"requires": { "requires": {
"@sentry/types": "6.3.5", "@sentry/types": "6.3.6",
"tslib": "^1.9.3" "tslib": "^1.9.3"
}, },
"dependencies": { "dependencies": {
@ -10450,12 +10353,12 @@
"integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==" "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA=="
}, },
"@typescript-eslint/eslint-plugin": { "@typescript-eslint/eslint-plugin": {
"version": "4.22.1", "version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.22.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.23.0.tgz",
"integrity": "sha512-kVTAghWDDhsvQ602tHBc6WmQkdaYbkcTwZu+7l24jtJiYvm9l+/y/b2BZANEezxPDiX5MK2ZecE+9BFi/YJryw==", "integrity": "sha512-tGK1y3KIvdsQEEgq6xNn1DjiFJtl+wn8JJQiETtCbdQxw1vzjXyAaIkEmO2l6Nq24iy3uZBMFQjZ6ECf1QdgGw==",
"requires": { "requires": {
"@typescript-eslint/experimental-utils": "4.22.1", "@typescript-eslint/experimental-utils": "4.23.0",
"@typescript-eslint/scope-manager": "4.22.1", "@typescript-eslint/scope-manager": "4.23.0",
"debug": "^4.1.1", "debug": "^4.1.1",
"functional-red-black-tree": "^1.0.1", "functional-red-black-tree": "^1.0.1",
"lodash": "^4.17.15", "lodash": "^4.17.15",
@ -10465,50 +10368,50 @@
} }
}, },
"@typescript-eslint/experimental-utils": { "@typescript-eslint/experimental-utils": {
"version": "4.22.1", "version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.23.0.tgz",
"integrity": "sha512-svYlHecSMCQGDO2qN1v477ax/IDQwWhc7PRBiwAdAMJE7GXk5stF4Z9R/8wbRkuX/5e9dHqbIWxjeOjckK3wLQ==", "integrity": "sha512-WAFNiTDnQfrF3Z2fQ05nmCgPsO5o790vOhmWKXbbYQTO9erE1/YsFot5/LnOUizLzU2eeuz6+U/81KV5/hFTGA==",
"requires": { "requires": {
"@types/json-schema": "^7.0.3", "@types/json-schema": "^7.0.3",
"@typescript-eslint/scope-manager": "4.22.1", "@typescript-eslint/scope-manager": "4.23.0",
"@typescript-eslint/types": "4.22.1", "@typescript-eslint/types": "4.23.0",
"@typescript-eslint/typescript-estree": "4.22.1", "@typescript-eslint/typescript-estree": "4.23.0",
"eslint-scope": "^5.0.0", "eslint-scope": "^5.0.0",
"eslint-utils": "^2.0.0" "eslint-utils": "^2.0.0"
} }
}, },
"@typescript-eslint/parser": { "@typescript-eslint/parser": {
"version": "4.22.1", "version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.22.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.23.0.tgz",
"integrity": "sha512-l+sUJFInWhuMxA6rtirzjooh8cM/AATAe3amvIkqKFeMzkn85V+eLzb1RyuXkHak4dLfYzOmF6DXPyflJvjQnw==", "integrity": "sha512-wsvjksHBMOqySy/Pi2Q6UuIuHYbgAMwLczRl4YanEPKW5KVxI9ZzDYh3B5DtcZPQTGRWFJrfcbJ6L01Leybwug==",
"requires": { "requires": {
"@typescript-eslint/scope-manager": "4.22.1", "@typescript-eslint/scope-manager": "4.23.0",
"@typescript-eslint/types": "4.22.1", "@typescript-eslint/types": "4.23.0",
"@typescript-eslint/typescript-estree": "4.22.1", "@typescript-eslint/typescript-estree": "4.23.0",
"debug": "^4.1.1" "debug": "^4.1.1"
} }
}, },
"@typescript-eslint/scope-manager": { "@typescript-eslint/scope-manager": {
"version": "4.22.1", "version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.22.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.23.0.tgz",
"integrity": "sha512-d5bAiPBiessSmNi8Amq/RuLslvcumxLmyhf1/Xa9IuaoFJ0YtshlJKxhlbY7l2JdEk3wS0EnmnfeJWSvADOe0g==", "integrity": "sha512-ZZ21PCFxPhI3n0wuqEJK9omkw51wi2bmeKJvlRZPH5YFkcawKOuRMQMnI8mH6Vo0/DoHSeZJnHiIx84LmVQY+w==",
"requires": { "requires": {
"@typescript-eslint/types": "4.22.1", "@typescript-eslint/types": "4.23.0",
"@typescript-eslint/visitor-keys": "4.22.1" "@typescript-eslint/visitor-keys": "4.23.0"
} }
}, },
"@typescript-eslint/types": { "@typescript-eslint/types": {
"version": "4.22.1", "version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.22.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.23.0.tgz",
"integrity": "sha512-2HTkbkdAeI3OOcWbqA8hWf/7z9c6gkmnWNGz0dKSLYLWywUlkOAQ2XcjhlKLj5xBFDf8FgAOF5aQbnLRvgNbCw==" "integrity": "sha512-oqkNWyG2SLS7uTWLZf6Sr7Dm02gA5yxiz1RP87tvsmDsguVATdpVguHr4HoGOcFOpCvx9vtCSCyQUGfzq28YCw=="
}, },
"@typescript-eslint/typescript-estree": { "@typescript-eslint/typescript-estree": {
"version": "4.22.1", "version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.23.0.tgz",
"integrity": "sha512-p3We0pAPacT+onSGM+sPR+M9CblVqdA9F1JEdIqRVlxK5Qth4ochXQgIyb9daBomyQKAXbygxp1aXQRV0GC79A==", "integrity": "sha512-5Sty6zPEVZF5fbvrZczfmLCOcby3sfrSPu30qKoY1U3mca5/jvU5cwsPb/CO6Q3ByRjixTMIVsDkqwIxCf/dMw==",
"requires": { "requires": {
"@typescript-eslint/types": "4.22.1", "@typescript-eslint/types": "4.23.0",
"@typescript-eslint/visitor-keys": "4.22.1", "@typescript-eslint/visitor-keys": "4.23.0",
"debug": "^4.1.1", "debug": "^4.1.1",
"globby": "^11.0.1", "globby": "^11.0.1",
"is-glob": "^4.0.1", "is-glob": "^4.0.1",
@ -10532,11 +10435,11 @@
} }
}, },
"@typescript-eslint/visitor-keys": { "@typescript-eslint/visitor-keys": {
"version": "4.22.1", "version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.23.0.tgz",
"integrity": "sha512-WPkOrIRm+WCLZxXQHCi+WG8T2MMTUFR70rWjdWYddLT7cEfb2P4a3O/J2U1FBVsSFTocXLCoXWY6MZGejeStvQ==", "integrity": "sha512-5PNe5cmX9pSifit0H+nPoQBXdbNzi5tOEec+3riK+ku4e3er37pKxMKDH5Ct5Y4fhWxcD4spnlYjxi9vXbSpwg==",
"requires": { "requires": {
"@typescript-eslint/types": "4.22.1", "@typescript-eslint/types": "4.23.0",
"eslint-visitor-keys": "^2.0.0" "eslint-visitor-keys": "^2.0.0"
} }
}, },
@ -10558,7 +10461,8 @@
"acorn-jsx": { "acorn-jsx": {
"version": "5.3.1", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
"integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==" "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
"requires": {}
}, },
"ajv": { "ajv": {
"version": "6.12.6", "version": "6.12.6",
@ -10685,8 +10589,7 @@
"typescript": { "typescript": {
"version": "3.9.9", "version": "3.9.9",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz",
"integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w=="
"dev": true
} }
} }
}, },
@ -11415,12 +11318,12 @@
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
}, },
"eslint": { "eslint": {
"version": "7.25.0", "version": "7.26.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.25.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.26.0.tgz",
"integrity": "sha512-TVpSovpvCNpLURIScDRB6g5CYu/ZFq9GfX2hLNIV4dSBKxIWojeDODvYl3t0k0VtMxYeR8OXPCFE5+oHMlGfhw==", "integrity": "sha512-4R1ieRf52/izcZE7AlLy56uIHHDLT74Yzz2Iv2l6kDaYvEu9x+wMB5dZArVL8SYGXSYV2YAg70FcW5Y5nGGNIg==",
"requires": { "requires": {
"@babel/code-frame": "7.12.11", "@babel/code-frame": "7.12.11",
"@eslint/eslintrc": "^0.4.0", "@eslint/eslintrc": "^0.4.1",
"ajv": "^6.10.0", "ajv": "^6.10.0",
"chalk": "^4.0.0", "chalk": "^4.0.0",
"cross-spawn": "^7.0.2", "cross-spawn": "^7.0.2",
@ -11535,9 +11438,9 @@
} }
}, },
"eslint-plugin-lit": { "eslint-plugin-lit": {
"version": "1.3.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.3.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.4.0.tgz",
"integrity": "sha512-fy6Lr5vYI3kvCYaDXA20lwyKAp1keS9UjR5ntj8U2TeV+1yUta3S7xxXe+rABKRPbcNzi1ZvQLE1LmNKc9yr4Q==", "integrity": "sha512-3PJCC1p4pvDBKtFmg1g2cGzAgJF4IDqhb9NJUh95nYc+QXExa/O/0fILF4WB6X7qdNQKm+gW6nYtSKTyYPHtXw==",
"requires": { "requires": {
"parse5": "^6.0.1", "parse5": "^6.0.1",
"parse5-htmlparser2-tree-adapter": "^6.0.1", "parse5-htmlparser2-tree-adapter": "^6.0.1",

View File

@ -50,13 +50,13 @@
"@rollup/plugin-babel": "^5.3.0", "@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-replace": "^2.4.2", "@rollup/plugin-replace": "^2.4.2",
"@rollup/plugin-typescript": "^8.2.1", "@rollup/plugin-typescript": "^8.2.1",
"@sentry/browser": "^6.3.5", "@sentry/browser": "^6.3.6",
"@sentry/tracing": "^6.3.5", "@sentry/tracing": "^6.3.6",
"@types/chart.js": "^2.9.32", "@types/chart.js": "^2.9.32",
"@types/codemirror": "5.60.0", "@types/codemirror": "5.60.0",
"@types/grecaptcha": "^3.0.2", "@types/grecaptcha": "^3.0.2",
"@typescript-eslint/eslint-plugin": "^4.22.1", "@typescript-eslint/eslint-plugin": "^4.23.0",
"@typescript-eslint/parser": "^4.22.1", "@typescript-eslint/parser": "^4.23.0",
"@webcomponents/webcomponentsjs": "^2.5.0", "@webcomponents/webcomponentsjs": "^2.5.0",
"authentik-api": "file:api", "authentik-api": "file:api",
"babel-plugin-macros": "^3.1.0", "babel-plugin-macros": "^3.1.0",
@ -65,10 +65,10 @@
"chartjs-adapter-moment": "^1.0.0", "chartjs-adapter-moment": "^1.0.0",
"codemirror": "^5.61.0", "codemirror": "^5.61.0",
"construct-style-sheets-polyfill": "^2.4.16", "construct-style-sheets-polyfill": "^2.4.16",
"eslint": "^7.25.0", "eslint": "^7.26.0",
"eslint-config-google": "^0.14.0", "eslint-config-google": "^0.14.0",
"eslint-plugin-custom-elements": "0.0.2", "eslint-plugin-custom-elements": "0.0.2",
"eslint-plugin-lit": "^1.3.0", "eslint-plugin-lit": "^1.4.0",
"flowchart.js": "^1.15.0", "flowchart.js": "^1.15.0",
"lit-element": "^2.5.1", "lit-element": "^2.5.1",
"lit-html": "^1.4.1", "lit-html": "^1.4.1",

View File

@ -3,7 +3,7 @@ export const SUCCESS_CLASS = "pf-m-success";
export const ERROR_CLASS = "pf-m-danger"; export const ERROR_CLASS = "pf-m-danger";
export const PROGRESS_CLASS = "pf-m-in-progress"; export const PROGRESS_CLASS = "pf-m-in-progress";
export const CURRENT_CLASS = "pf-m-current"; export const CURRENT_CLASS = "pf-m-current";
export const VERSION = "2021.4.5"; export const VERSION = "2021.5.1-rc7";
export const PAGE_SIZE = 20; export const PAGE_SIZE = 20;
export const EVENT_REFRESH = "ak-refresh"; export const EVENT_REFRESH = "ak-refresh";
export const EVENT_NOTIFICATION_TOGGLE = "ak-notification-toggle"; export const EVENT_NOTIFICATION_TOGGLE = "ak-notification-toggle";

View File

@ -6,6 +6,7 @@ import { ArcElement, BarElement } from "chart.js";
import { TimeScale, LinearScale } from "chart.js"; import { TimeScale, LinearScale } from "chart.js";
import "chartjs-adapter-moment"; import "chartjs-adapter-moment";
import { FONT_COLOUR_DARK_MODE, FONT_COLOUR_LIGHT_MODE } from "../../pages/flows/FlowDiagram"; import { FONT_COLOUR_DARK_MODE, FONT_COLOUR_LIGHT_MODE } from "../../pages/flows/FlowDiagram";
import {EVENT_REFRESH} from "../../constants";
Chart.register(Legend, Tooltip); Chart.register(Legend, Tooltip);
Chart.register(LineController, BarController, DoughnutController); Chart.register(LineController, BarController, DoughnutController);
@ -43,6 +44,13 @@ export abstract class AKChart<T> extends LitElement {
this.chart.resize(); this.chart.resize();
} }
}); });
window.addEventListener(EVENT_REFRESH, () => {
this.apiRequest().then((r: T) => {
if (!this.chart) return;
this.chart.data = this.getChartData(r);
this.chart.update();
});
});
const matcher = window.matchMedia("(prefers-color-scheme: light)"); const matcher = window.matchMedia("(prefers-color-scheme: light)");
const handler = (ev?: MediaQueryListEvent) => { const handler = (ev?: MediaQueryListEvent) => {
if (ev?.matches || matcher.matches) { if (ev?.matches || matcher.matches) {
@ -56,6 +64,22 @@ export abstract class AKChart<T> extends LitElement {
handler(); handler();
} }
firstUpdated(): void {
this.apiRequest().then((r) => {
const canvas = <HTMLCanvasElement>this.shadowRoot?.querySelector("canvas");
if (!canvas) {
console.warn("Failed to get canvas element");
return false;
}
const ctx = canvas.getContext("2d");
if (!ctx) {
console.warn("failed to get 2d context");
return false;
}
this.chart = this.configureChart(r, ctx);
});
}
getChartType(): string { getChartType(): string {
return "bar"; return "bar";
} }
@ -129,23 +153,6 @@ export abstract class AKChart<T> extends LitElement {
return new Chart(ctx, config as ChartConfiguration); return new Chart(ctx, config as ChartConfiguration);
} }
firstUpdated(): void {
this.apiRequest().then((r) => {
const canvas = <HTMLCanvasElement>this.shadowRoot?.querySelector("canvas");
if (!canvas) {
console.warn("Failed to get canvas element");
return false;
}
const ctx = canvas.getContext("2d");
if (!ctx) {
console.warn("failed to get 2d context");
return false;
}
this.chart = this.configureChart(r, ctx);
});
}
render(): TemplateResult { render(): TemplateResult {
return html` return html`
<div class="container"> <div class="container">

View File

@ -102,18 +102,18 @@ export class OutpostForm extends Form<Outpost> {
</select> </select>
<p class="pf-c-form__helper-text">${t`Hold control/command to select multiple items.`}</p> <p class="pf-c-form__helper-text">${t`Hold control/command to select multiple items.`}</p>
</ak-form-element-horizontal> </ak-form-element-horizontal>
${until(new OutpostsApi(DEFAULT_CONFIG).outpostsOutpostsDefaultSettings({}).then(config => { <ak-form-element-horizontal
label=${t`Configuration`}
name="config">
<ak-codemirror mode="yaml" value="${until(new OutpostsApi(DEFAULT_CONFIG).outpostsOutpostsDefaultSettings({}).then(config => {
let fc = config.config; let fc = config.config;
if (this.outpost) { if (this.outpost) {
fc = this.outpost.config; fc = this.outpost.config;
} }
return html`<ak-form-element-horizontal return YAML.stringify(fc);
label=${t`Configuration`} }))}"></ak-codemirror>
name="config">
<ak-codemirror mode="yaml" value="${YAML.stringify(fc)}"></ak-codemirror>
<p class="pf-c-form__helper-text">${t`Set custom attributes using YAML or JSON.`}</p> <p class="pf-c-form__helper-text">${t`Set custom attributes using YAML or JSON.`}</p>
</ak-form-element-horizontal>`; </ak-form-element-horizontal>
}))}
</form>`; </form>`;
} }

View File

@ -17,10 +17,9 @@ import TabItem from '@theme/TabItem';
Add the following block to your `.env` file: Add the following block to your `.env` file:
```shell ```shell
AUTHENTIK_IMAGE=docker.beryju.org/authentik/server AUTHENTIK_IMAGE=beryju.org/authentik/server
AUTHENTIK_IMAGE_STATIC=docker.beryju.org/authentik/static
AUTHENTIK_TAG=gh-next AUTHENTIK_TAG=gh-next
AUTHENTIK_OUTPOSTS__DOCKER_IMAGE_BASE=docker.beryju.org/authentik/outpost-%(type)s:gh-next AUTHENTIK_OUTPOSTS__DOCKER_IMAGE_BASE=beryju.org/authentik/outpost-%(type)s:gh-next
``` ```
Afterwards, run the upgrade commands from the latest releasae notes. Afterwards, run the upgrade commands from the latest releasae notes.
@ -30,9 +29,8 @@ Add the following block to your `values.yml` file:
```yaml ```yaml
image: image:
name: docker.beryju.org/authentik/server name: beryju.org/authentik/server
name_static: docker.beryju.org/authentik/static name_outposts: beryju.org/authentik/outpost-%(type)s:gh-next
name_outposts: docker.beryju.org/authentik/outpost-%(type)s:gh-next
tag: gh-next tag: gh-next
# pullPolicy: Always to ensure you always get the latest version # pullPolicy: Always to ensure you always get the latest version
pullPolicy: Always pullPolicy: Always

View File

@ -16,7 +16,7 @@ Download the latest `docker-compose.yml` from [here](https://raw.githubuserconte
To optionally enable error-reporting, run `echo AUTHENTIK_ERROR_REPORTING__ENABLED=true >> .env` To optionally enable error-reporting, run `echo AUTHENTIK_ERROR_REPORTING__ENABLED=true >> .env`
To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.4.5 >> .env` To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.5.1-rc7 >> .env`
If this is a fresh authentik install run the following commands to generate a password: If this is a fresh authentik install run the following commands to generate a password:

View File

@ -22,9 +22,9 @@ See all configurable values on [artifacthub](https://artifacthub.io/packages/hel
Afterwards, run these commands to install authentik: Afterwards, run these commands to install authentik:
``` ```
helm repo add authentik https://helm.goauthentik.io helm repo add authentik https://charts.goauthentik.io
helm repo update helm repo update
helm install authentik/authentik -f values.yaml helm install authentik authentik/authentik -f values.yaml
``` ```
This installation automatically applies database migrations on startup. After the installation is done, navigate to the `https://<ingress you've specified>/if/flow/initial-setup/`, to set a password for the akadmin user. This installation automatically applies database migrations on startup. After the installation is done, navigate to the `https://<ingress you've specified>/if/flow/initial-setup/`, to set a password for the akadmin user.

View File

@ -11,7 +11,7 @@ version: "3.5"
services: services:
authentik_proxy: authentik_proxy:
image: beryju/authentik-proxy:2021.4.5 image: beryju/authentik-proxy:2021.5.1-rc7
ports: ports:
- 4180:4180 - 4180:4180
- 4443:4443 - 4443:4443

View File

@ -14,7 +14,7 @@ metadata:
app.kubernetes.io/instance: __OUTPOST_NAME__ app.kubernetes.io/instance: __OUTPOST_NAME__
app.kubernetes.io/managed-by: goauthentik.io app.kubernetes.io/managed-by: goauthentik.io
app.kubernetes.io/name: authentik-proxy app.kubernetes.io/name: authentik-proxy
app.kubernetes.io/version: 2021.4.5 app.kubernetes.io/version: 2021.5.1-rc7
name: authentik-outpost-api name: authentik-outpost-api
stringData: stringData:
authentik_host: "__AUTHENTIK_URL__" authentik_host: "__AUTHENTIK_URL__"
@ -29,7 +29,7 @@ metadata:
app.kubernetes.io/instance: __OUTPOST_NAME__ app.kubernetes.io/instance: __OUTPOST_NAME__
app.kubernetes.io/managed-by: goauthentik.io app.kubernetes.io/managed-by: goauthentik.io
app.kubernetes.io/name: authentik-proxy app.kubernetes.io/name: authentik-proxy
app.kubernetes.io/version: 2021.4.5 app.kubernetes.io/version: 2021.5.1-rc7
name: authentik-outpost name: authentik-outpost
spec: spec:
ports: ports:
@ -54,7 +54,7 @@ metadata:
app.kubernetes.io/instance: __OUTPOST_NAME__ app.kubernetes.io/instance: __OUTPOST_NAME__
app.kubernetes.io/managed-by: goauthentik.io app.kubernetes.io/managed-by: goauthentik.io
app.kubernetes.io/name: authentik-proxy app.kubernetes.io/name: authentik-proxy
app.kubernetes.io/version: 2021.4.5 app.kubernetes.io/version: 2021.5.1-rc7
name: authentik-outpost name: authentik-outpost
spec: spec:
selector: selector:
@ -62,14 +62,14 @@ spec:
app.kubernetes.io/instance: __OUTPOST_NAME__ app.kubernetes.io/instance: __OUTPOST_NAME__
app.kubernetes.io/managed-by: goauthentik.io app.kubernetes.io/managed-by: goauthentik.io
app.kubernetes.io/name: authentik-proxy app.kubernetes.io/name: authentik-proxy
app.kubernetes.io/version: 2021.4.5 app.kubernetes.io/version: 2021.5.1-rc7
template: template:
metadata: metadata:
labels: labels:
app.kubernetes.io/instance: __OUTPOST_NAME__ app.kubernetes.io/instance: __OUTPOST_NAME__
app.kubernetes.io/managed-by: goauthentik.io app.kubernetes.io/managed-by: goauthentik.io
app.kubernetes.io/name: authentik-proxy app.kubernetes.io/name: authentik-proxy
app.kubernetes.io/version: 2021.4.5 app.kubernetes.io/version: 2021.5.1-rc7
spec: spec:
containers: containers:
- env: - env:
@ -88,7 +88,7 @@ spec:
secretKeyRef: secretKeyRef:
key: authentik_host_insecure key: authentik_host_insecure
name: authentik-outpost-api name: authentik-outpost-api
image: beryju/authentik-proxy:2021.4.5 image: beryju/authentik-proxy:2021.5.1-rc7
name: proxy name: proxy
ports: ports:
- containerPort: 4180 - containerPort: 4180
@ -110,7 +110,7 @@ metadata:
app.kubernetes.io/instance: __OUTPOST_NAME__ app.kubernetes.io/instance: __OUTPOST_NAME__
app.kubernetes.io/managed-by: goauthentik.io app.kubernetes.io/managed-by: goauthentik.io
app.kubernetes.io/name: authentik-proxy app.kubernetes.io/name: authentik-proxy
app.kubernetes.io/version: 2021.4.5 app.kubernetes.io/version: 2021.5.1-rc7
name: authentik-outpost name: authentik-outpost
spec: spec:
rules: rules:

View File

@ -72,7 +72,7 @@ The public port of the compose stack has been changed from 443 to 9000 and 9443
### Kubernetes ### Kubernetes
The helm chart has been rewritten by [@dirtycajunrice](https://github.com/dirtycajunrice) and now lives on `https://helm.goauthentik.io`. The helm chart has been rewritten by [@dirtycajunrice](https://github.com/dirtycajunrice) and now lives on `https://charts.goauthentik.io`.
Please upgrade to the new chart using values from [ArtifactHub](https://artifacthub.io/packages/helm/goauthentik/authentik). Please upgrade to the new chart using values from [ArtifactHub](https://artifacthub.io/packages/helm/goauthentik/authentik).

View File

@ -11,7 +11,7 @@
"@docusaurus/preset-classic": "2.0.0-alpha.75", "@docusaurus/preset-classic": "2.0.0-alpha.75",
"@mdx-js/react": "^1.6.22", "@mdx-js/react": "^1.6.22",
"clsx": "^1.1.1", "clsx": "^1.1.1",
"postcss": "^8.2.14", "postcss": "^8.2.15",
"rapidoc": "^9.0.0", "rapidoc": "^9.0.0",
"react": "^17.0.2", "react": "^17.0.2",
"react-before-after-slider": "^1.0.4", "react-before-after-slider": "^1.0.4",
@ -20,7 +20,7 @@
"react-toggle": "^4.1.2" "react-toggle": "^4.1.2"
}, },
"devDependencies": { "devDependencies": {
"prettier": "2.2.1" "prettier": "2.3.0"
} }
}, },
"node_modules/@algolia/autocomplete-core": { "node_modules/@algolia/autocomplete-core": {
@ -8004,9 +8004,9 @@
"optional": true "optional": true
}, },
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "3.1.22", "version": "3.1.23",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.22.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
"integrity": "sha512-/2ZUaJX2ANuLtTvqTlgqBQNJoQO398KyJgZloL0PZkC0dpysjncRUPsFe3DUPzz/y3h+u7C46np8RMuvF3jsSQ==", "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==",
"bin": { "bin": {
"nanoid": "bin/nanoid.cjs" "nanoid": "bin/nanoid.cjs"
}, },
@ -8823,12 +8823,12 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.2.14", "version": "8.2.15",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.14.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.15.tgz",
"integrity": "sha512-+jD0ZijcvyCqPQo/m/CW0UcARpdFylq04of+Q7RKX6f/Tu+dvpUI/9Sp81+i6/vJThnOBX09Quw0ZLOVwpzX3w==", "integrity": "sha512-2zO3b26eJD/8rb106Qu2o7Qgg52ND5HPjcyQiK2B98O388h43A448LCslC0dI2P97wCAQRJsFvwTRcXxTKds+Q==",
"dependencies": { "dependencies": {
"colorette": "^1.2.2", "colorette": "^1.2.2",
"nanoid": "^3.1.22", "nanoid": "^3.1.23",
"source-map": "^0.6.1" "source-map": "^0.6.1"
}, },
"engines": { "engines": {
@ -9306,9 +9306,9 @@
} }
}, },
"node_modules/prettier": { "node_modules/prettier": {
"version": "2.2.1", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.0.tgz",
"integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", "integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==",
"dev": true, "dev": true,
"bin": { "bin": {
"prettier": "bin-prettier.js" "prettier": "bin-prettier.js"
@ -20240,9 +20240,9 @@
"optional": true "optional": true
}, },
"nanoid": { "nanoid": {
"version": "3.1.22", "version": "3.1.23",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.22.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
"integrity": "sha512-/2ZUaJX2ANuLtTvqTlgqBQNJoQO398KyJgZloL0PZkC0dpysjncRUPsFe3DUPzz/y3h+u7C46np8RMuvF3jsSQ==" "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw=="
}, },
"nanomatch": { "nanomatch": {
"version": "1.2.13", "version": "1.2.13",
@ -20895,12 +20895,12 @@
"integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
}, },
"postcss": { "postcss": {
"version": "8.2.14", "version": "8.2.15",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.14.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.15.tgz",
"integrity": "sha512-+jD0ZijcvyCqPQo/m/CW0UcARpdFylq04of+Q7RKX6f/Tu+dvpUI/9Sp81+i6/vJThnOBX09Quw0ZLOVwpzX3w==", "integrity": "sha512-2zO3b26eJD/8rb106Qu2o7Qgg52ND5HPjcyQiK2B98O388h43A448LCslC0dI2P97wCAQRJsFvwTRcXxTKds+Q==",
"requires": { "requires": {
"colorette": "^1.2.2", "colorette": "^1.2.2",
"nanoid": "^3.1.22", "nanoid": "^3.1.23",
"source-map": "^0.6.1" "source-map": "^0.6.1"
}, },
"dependencies": { "dependencies": {
@ -21255,9 +21255,9 @@
"integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc="
}, },
"prettier": { "prettier": {
"version": "2.2.1", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.0.tgz",
"integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", "integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==",
"dev": true "dev": true
}, },
"pretty-error": { "pretty-error": {

View File

@ -14,7 +14,7 @@
"@docusaurus/preset-classic": "2.0.0-alpha.75", "@docusaurus/preset-classic": "2.0.0-alpha.75",
"@mdx-js/react": "^1.6.22", "@mdx-js/react": "^1.6.22",
"clsx": "^1.1.1", "clsx": "^1.1.1",
"postcss": "^8.2.14", "postcss": "^8.2.15",
"rapidoc": "^9.0.0", "rapidoc": "^9.0.0",
"react": "^17.0.2", "react": "^17.0.2",
"react-before-after-slider": "^1.0.4", "react-before-after-slider": "^1.0.4",
@ -35,6 +35,6 @@
] ]
}, },
"devDependencies": { "devDependencies": {
"prettier": "2.2.1" "prettier": "2.3.0"
} }
} }

View File

@ -0,0 +1,102 @@
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: authentik
namespace: ##NAMESPACE##
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: authentik
namespace: ##NAMESPACE##
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: authentik
subjects:
- kind: ServiceAccount
name: authentik
namespace: ##NAMESPACE##
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: authentik
namespace: ##NAMESPACE##
rules:
- apiGroups:
- ""
resources:
- secrets
- services
- configmaps
verbs:
- get
- create
- delete
- list
- patch
- apiGroups:
- extensions
- apps
resources:
- deployments
verbs:
- get
- create
- delete
- list
- patch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- create
- delete
- list
- patch
- apiGroups:
- traefik.containo.us
resources:
- middlewares
verbs:
- get
- create
- delete
- list
- patch
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- list
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: authentik
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: authentik
subjects:
- kind: ServiceAccount
name: authentik
namespace: ingress
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: authentik
rules:
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- list