Compare commits
103 Commits
version/20
...
version/20
Author | SHA1 | Date | |
---|---|---|---|
3665e2fefa | |||
3dbe35cf9e | |||
c7f0ea8a4b | |||
0620324702 | |||
5a802bcf83 | |||
00c8054893 | |||
dc2538f59d | |||
5a0e78c698 | |||
fd4e8a59f4 | |||
dd1a6a81c8 | |||
84dfbcaaae | |||
e649e9fb03 | |||
266ef66a6f | |||
842fdb0b0c | |||
a270a84aae | |||
36f7cad23b | |||
e441ac1e43 | |||
24f2932777 | |||
a6c6f22221 | |||
abd5db8ad4 | |||
124ce80694 | |||
4352960f83 | |||
4e2443d60b | |||
34a8408a4f | |||
17b65adcc5 | |||
6f8d129dea | |||
59f339beda | |||
ce1c400022 | |||
c99afe0ad4 | |||
ff9ff18c11 | |||
4d11d82c6e | |||
b4d750174f | |||
fd44765ff4 | |||
190ebb27e4 | |||
fb3c04d0c7 | |||
3ba8de61e0 | |||
d4d2be84a3 | |||
96ea7ae09c | |||
172bfceb31 | |||
932b19999e | |||
0f1cc86e71 | |||
788fd00390 | |||
f602e202b8 | |||
9b60fcb08b | |||
a293a14f2a | |||
65bfa589eb | |||
defca51d24 | |||
d862028134 | |||
c19d7c37aa | |||
6fb3102d25 | |||
51e3453dca | |||
6f58fdf158 | |||
5d4051f547 | |||
219b8d1a57 | |||
c7d4e69669 | |||
cd629dfbaa | |||
8eaaaae2a7 | |||
3d0a853449 | |||
c2f8ff55cf | |||
4b52697cfe | |||
80fae44f47 | |||
afd7af557d | |||
73eb97ca6e | |||
ebe90d8886 | |||
a1a1b113b1 | |||
9adf8e88ba | |||
72d87ee51d | |||
9654285535 | |||
6e47e69c62 | |||
1ba89a02ee | |||
1fb3642701 | |||
847d97b813 | |||
253060def2 | |||
2e70ea799a | |||
7364914ae8 | |||
1f1d322958 | |||
e4841ce1a4 | |||
af30b781b6 | |||
5f490c563e | |||
e33a5528f7 | |||
d4de243e3b | |||
317117ee68 | |||
40d03a6124 | |||
9cfeeb35ba | |||
b7d828702d | |||
19dfeec782 | |||
07eef2869f | |||
f7fd31cc84 | |||
465d9c2b93 | |||
04aae8f584 | |||
bbca90c93a | |||
dda1d4e0fb | |||
f072c600cc | |||
65b8a5bb8d | |||
92537a6c8d | |||
72836ecd9d | |||
251a97c77e | |||
7f7046f0e4 | |||
20e59158c2 | |||
9a9e55ae32 | |||
481260a5ca | |||
436adcce2e | |||
d4493c0ee9 |
@ -1,5 +1,5 @@
|
||||
[bumpversion]
|
||||
current_version = 2021.5.1-rc3
|
||||
current_version = 2021.5.1-rc8
|
||||
tag = True
|
||||
commit = True
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-?(?P<release>.*)
|
||||
|
8
.github/dependabot.yml
vendored
8
.github/dependabot.yml
vendored
@ -1,5 +1,13 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
||||
assignees:
|
||||
- BeryJu
|
||||
- package-ecosystem: gomod
|
||||
directory: "/outpost"
|
||||
schedule:
|
||||
|
66
.github/workflows/release.yml
vendored
66
.github/workflows/release.yml
vendored
@ -3,15 +3,18 @@ name: authentik-on-release
|
||||
on:
|
||||
release:
|
||||
types: [published, created]
|
||||
push:
|
||||
branches:
|
||||
- version-*
|
||||
|
||||
jobs:
|
||||
# Build
|
||||
build-server:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v1.1.0
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- name: Docker Login Registry
|
||||
@ -19,23 +22,30 @@ jobs:
|
||||
with:
|
||||
username: ${{ 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
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
push: true
|
||||
push: ${{ github.event_name == 'release' }}
|
||||
tags: |
|
||||
beryju/authentik:2021.5.1-rc3,
|
||||
beryju/authentik:2021.5.1-rc8,
|
||||
beryju/authentik:latest,
|
||||
ghcr.io/goauthentik/server:2021.5.1-rc3,
|
||||
ghcr.io/goauthentik/server:2021.5.1-rc8,
|
||||
ghcr.io/goauthentik/server:latest
|
||||
platforms: linux/amd64,linux/arm64,linux/arm
|
||||
platforms: linux/amd64,linux/arm64
|
||||
context: .
|
||||
build-proxy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: "^1.15"
|
||||
@ -46,7 +56,7 @@ jobs:
|
||||
swagger generate client -f ../swagger.yaml -A authentik -t pkg/
|
||||
go build -v ./cmd/proxy/server.go
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v1.1.0
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- name: Docker Login Registry
|
||||
@ -54,22 +64,28 @@ jobs:
|
||||
with:
|
||||
username: ${{ 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
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
push: true
|
||||
push: ${{ github.event_name == 'release' }}
|
||||
tags: |
|
||||
beryju/authentik-proxy:2021.5.1-rc3,
|
||||
beryju/authentik-proxy:2021.5.1-rc8,
|
||||
beryju/authentik-proxy:latest,
|
||||
ghcr.io/goauthentik/proxy:2021.5.1-rc3,
|
||||
ghcr.io/goauthentik/proxy:2021.5.1-rc8,
|
||||
ghcr.io/goauthentik/proxy:latest
|
||||
context: outpost/
|
||||
file: outpost/proxy.Dockerfile
|
||||
platforms: linux/amd64,linux/arm64,linux/arm
|
||||
platforms: linux/amd64,linux/arm64
|
||||
build-ldap:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: "^1.15"
|
||||
@ -80,7 +96,7 @@ jobs:
|
||||
swagger generate client -f ../swagger.yaml -A authentik -t pkg/
|
||||
go build -v ./cmd/ldap/server.go
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v1.1.0
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- name: Docker Login Registry
|
||||
@ -88,26 +104,33 @@ jobs:
|
||||
with:
|
||||
username: ${{ 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
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
push: true
|
||||
push: ${{ github.event_name == 'release' }}
|
||||
tags: |
|
||||
beryju/authentik-ldap:2021.5.1-rc3,
|
||||
beryju/authentik-ldap:2021.5.1-rc8,
|
||||
beryju/authentik-ldap:latest,
|
||||
ghcr.io/goauthentik/ldap:2021.5.1-rc3,
|
||||
ghcr.io/goauthentik/ldap:2021.5.1-rc8,
|
||||
ghcr.io/goauthentik/ldap:latest
|
||||
context: outpost/
|
||||
file: outpost/ldap.Dockerfile
|
||||
platforms: linux/amd64,linux/arm64,linux/arm
|
||||
platforms: linux/amd64,linux/arm64
|
||||
test-release:
|
||||
if: ${{ github.event_name == 'release' }}
|
||||
needs:
|
||||
- build-server
|
||||
- build-proxy
|
||||
- build-ldap
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run test suite in final docker images
|
||||
run: |
|
||||
sudo apt-get install -y pwgen
|
||||
@ -118,11 +141,12 @@ jobs:
|
||||
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"
|
||||
sentry-release:
|
||||
if: ${{ github.event_name == 'release' }}
|
||||
needs:
|
||||
- test-release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
- name: Create a Sentry.io release
|
||||
uses: getsentry/action-release@v1
|
||||
env:
|
||||
@ -131,5 +155,5 @@ jobs:
|
||||
SENTRY_PROJECT: authentik
|
||||
SENTRY_URL: https://sentry.beryju.org
|
||||
with:
|
||||
version: authentik@2021.5.1-rc3
|
||||
version: authentik@2021.5.1-rc8
|
||||
environment: beryjuorg-prod
|
||||
|
2
.github/workflows/tag.yml
vendored
2
.github/workflows/tag.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
||||
name: Create Release from Tag
|
||||
runs-on: ubuntu-latest
|
||||
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
|
||||
|
@ -48,15 +48,16 @@ ARG GIT_BUILD_HASH
|
||||
ENV GIT_BUILD_HASH=$GIT_BUILD_HASH
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends curl ca-certificates gnupg && \
|
||||
apt-get install -y --no-install-recommends curl ca-certificates gnupg git && \
|
||||
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 && \
|
||||
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 clean && \
|
||||
apt-get install -y --no-install-recommends libpq-dev postgresql-client build-essential libxmlsec1-dev pkg-config libmaxminddb0 && \
|
||||
pip install -r /requirements.txt --no-cache-dir && \
|
||||
apt-get remove --purge -y build-essential && \
|
||||
apt-get remove --purge -y build-essential git && \
|
||||
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
|
||||
# we could instead check for the GID of the socket and add the user dynamically,
|
||||
# but then we have to drop permmissions later
|
||||
|
11
Makefile
11
Makefile
@ -1,3 +1,6 @@
|
||||
.SHELLFLAGS += -x -e
|
||||
PWD = $(shell pwd)
|
||||
|
||||
all: lint-fix lint test gen
|
||||
|
||||
test-integration:
|
||||
@ -24,6 +27,14 @@ lint:
|
||||
|
||||
gen:
|
||||
./manage.py generate_swagger -o swagger.yaml -f yaml
|
||||
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
|
||||
cd web/api && npx tsc
|
||||
|
||||
local-stack:
|
||||
export AUTHENTIK_TAG=testing
|
||||
|
4
Pipfile
4
Pipfile
@ -11,7 +11,7 @@ channels-redis = "*"
|
||||
dacite = "*"
|
||||
defusedxml = "*"
|
||||
django = "*"
|
||||
django-dbbackup = "*"
|
||||
django-dbbackup = { git = 'https://github.com/django-dbbackup/django-dbbackup.git', ref = '9d1909c30a3271c8c9c8450add30d6e0b996e145' }
|
||||
django-filter = "*"
|
||||
django-guardian = "*"
|
||||
django-model-utils = "*"
|
||||
@ -50,7 +50,7 @@ python_version = "3.9"
|
||||
|
||||
[dev-packages]
|
||||
bandit = "*"
|
||||
black = "==20.8b1"
|
||||
black = "==21.5b1"
|
||||
bump2version = "*"
|
||||
colorama = "*"
|
||||
coverage = "*"
|
||||
|
282
Pipfile.lock
generated
282
Pipfile.lock
generated
@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "17be2923cf8d281e430ec1467aea723806ac6f7c58fc6553ede92317e43f4d14"
|
||||
"sha256": "8a32708c1c04f8da03c817df973de28c37c97ee773f571ce0b3f3f834e1b7094"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
@ -56,6 +56,7 @@
|
||||
"sha256:f881853d2643a29e643609da57b96d5f9c9b93f62429dcc1cbb413c7d07f0e1a",
|
||||
"sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.7.4.post0"
|
||||
},
|
||||
"aioredis": {
|
||||
@ -70,6 +71,7 @@
|
||||
"sha256:03e16e94f2b34c31f8bf1206d8ddd3ccaa4c315f7f6a1879b7b1210d229568c2",
|
||||
"sha256:493a2ac6788ce270a2f6a765b017299f60c1998f5a8617908ee9be082f7300fb"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==5.0.6"
|
||||
},
|
||||
"asgiref": {
|
||||
@ -77,6 +79,7 @@
|
||||
"sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee",
|
||||
"sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.3.4"
|
||||
},
|
||||
"async-timeout": {
|
||||
@ -84,20 +87,23 @@
|
||||
"sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f",
|
||||
"sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"
|
||||
],
|
||||
"markers": "python_full_version >= '3.5.3'",
|
||||
"version": "==3.0.1"
|
||||
},
|
||||
"attrs": {
|
||||
"hashes": [
|
||||
"sha256:3901be1cb7c2a780f14668691474d9252c070a756be0a9ead98cfeabfa11aeb8",
|
||||
"sha256:8ee1e5f5a1afc5b19bdfae4fdf0c35ed324074bdce3500c939842c8f818645d9"
|
||||
"sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
|
||||
"sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
|
||||
],
|
||||
"version": "==21.1.0"
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==21.2.0"
|
||||
},
|
||||
"autobahn": {
|
||||
"hashes": [
|
||||
"sha256:9195df8af03b0ff29ccd4b7f5abbde957ee90273465942205f9a1bad6c3f07ac",
|
||||
"sha256:e126c1f583e872fb59e79d36977cfa1f2d0a8a79f90ae31f406faae7664b8e03"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==21.3.1"
|
||||
},
|
||||
"automat": {
|
||||
@ -116,24 +122,26 @@
|
||||
},
|
||||
"boto3": {
|
||||
"hashes": [
|
||||
"sha256:56f1766f1271b6b4e979c7b56225377f8912050e5935adc5c1c9e3a0338b949e",
|
||||
"sha256:c61c809d288e88b9a0d926f56f803d0128b498aa9b45a42a6e03cd9a83e5c124"
|
||||
"sha256:bcb1b76ca5a60586181ad202b19f4c50cb7c22ac68cae20f997abe311e22bf2a",
|
||||
"sha256:edf9b3b36e08cd575a9458bf59871852335aceb5db2d07bfc8530bae3a97d045"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.17.68"
|
||||
"version": "==1.17.71"
|
||||
},
|
||||
"botocore": {
|
||||
"hashes": [
|
||||
"sha256:0f693f5ad6348ec1a62b3a66fee2840d3b722d66b44896022d644275ff8b143d",
|
||||
"sha256:eb3544911cb0316a33b328a27d137130af278a9c0006be0c95e5e402b01d9865"
|
||||
"sha256:414e1721d381095767db1cf673257fdfec639da3be9405a41d49cc859b817d68",
|
||||
"sha256:b7afebca1fd6ca1f8af79f377a445d474e3bd2cf88e704169d6713a6362a304f"
|
||||
],
|
||||
"version": "==1.20.68"
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||
"version": "==1.20.71"
|
||||
},
|
||||
"cachetools": {
|
||||
"hashes": [
|
||||
"sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001",
|
||||
"sha256:61b5ed1e22a0924aed1d23b478f37e8d52549ff8a961de2909c69bf950020cff"
|
||||
],
|
||||
"markers": "python_version ~= '3.5'",
|
||||
"version": "==4.2.2"
|
||||
},
|
||||
"cbor2": {
|
||||
@ -220,6 +228,7 @@
|
||||
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
|
||||
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==4.0.0"
|
||||
},
|
||||
"click": {
|
||||
@ -227,6 +236,7 @@
|
||||
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
|
||||
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==7.1.2"
|
||||
},
|
||||
"click-didyoumean": {
|
||||
@ -300,6 +310,7 @@
|
||||
"sha256:76ffae916ba3aa66b46996c14fa713e46004788167a4873d647544e750e0e99f",
|
||||
"sha256:a9af943c79717bc52fe64a3c236ae5d3adccc8b5be19c881b442d2c3db233393"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.0.2"
|
||||
},
|
||||
"defusedxml": {
|
||||
@ -319,11 +330,11 @@
|
||||
"version": "==3.2.2"
|
||||
},
|
||||
"django-dbbackup": {
|
||||
"git": "https://github.com/django-dbbackup/django-dbbackup.git",
|
||||
"hashes": [
|
||||
"sha256:bb109735cae98b64ad084e5b461b7aca2d7b39992f10c9ed9435e3ebb6fb76c8"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.3.0"
|
||||
"ref": "9d1909c30a3271c8c9c8450add30d6e0b996e145"
|
||||
},
|
||||
"django-filter": {
|
||||
"hashes": [
|
||||
@ -351,11 +362,11 @@
|
||||
},
|
||||
"django-otp": {
|
||||
"hashes": [
|
||||
"sha256:04852c5301befb02d1d8ba4a31d375eb08d7c2cb6fe86b5f840867435ab1309c",
|
||||
"sha256:3916fc7652c2f934b1cf3807dd8ed257ce7605c10dfefa27fadda5628d9a9c9e"
|
||||
"sha256:75a815747a0542cc5442e3a6396dfd272c49a0866bee2149ac57ecc36ddd3961",
|
||||
"sha256:cc657a0e7266cda6ab42f861bdc3840ed24f7e441bc7f249916174dd1a6375a0"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.0.4"
|
||||
"version": "==1.0.5"
|
||||
},
|
||||
"django-prometheus": {
|
||||
"hashes": [
|
||||
@ -425,6 +436,7 @@
|
||||
"hashes": [
|
||||
"sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.18.2"
|
||||
},
|
||||
"geoip2": {
|
||||
@ -440,6 +452,7 @@
|
||||
"sha256:588bdb03a41ecb4978472b847881e5518b5d9ec6153d3d679aa127a55e13b39f",
|
||||
"sha256:9ad25fba07f46a628ad4d0ca09f38dcb262830df2ac95b217f9b0129c9e42206"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||
"version": "==1.30.0"
|
||||
},
|
||||
"gunicorn": {
|
||||
@ -455,6 +468,7 @@
|
||||
"sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6",
|
||||
"sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==0.12.0"
|
||||
},
|
||||
"hiredis": {
|
||||
@ -501,6 +515,7 @@
|
||||
"sha256:f52010e0a44e3d8530437e7da38d11fb822acfb0d5b12e9cd5ba655509937ca0",
|
||||
"sha256:f8196f739092a78e4f6b1b2172679ed3343c39c61a3e9d722ce6fcf1dac2824a"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.0"
|
||||
},
|
||||
"httptools": {
|
||||
@ -549,6 +564,7 @@
|
||||
"sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417",
|
||||
"sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==0.5.1"
|
||||
},
|
||||
"itypes": {
|
||||
@ -560,16 +576,18 @@
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419",
|
||||
"sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"
|
||||
"sha256:2f2de5285cf37f33d33ecd4a9080b75c87cd0c1994d5a9c6df17131ea1f049c6",
|
||||
"sha256:ea8d7dd814ce9df6de6a761ec7f1cac98afe305b8cdc4aaae4e114b8d8ce24c5"
|
||||
],
|
||||
"version": "==2.11.3"
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.0.0"
|
||||
},
|
||||
"jmespath": {
|
||||
"hashes": [
|
||||
"sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9",
|
||||
"sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.10.0"
|
||||
},
|
||||
"jsonschema": {
|
||||
@ -584,6 +602,7 @@
|
||||
"sha256:6dc509178ac4269b0e66ab4881f70a2035c33d3a622e20585f965986a5182006",
|
||||
"sha256:f4965fba0a4718d47d470beeb5d6446e3357a62402b16c510b6a2f251e05ac3c"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==5.0.2"
|
||||
},
|
||||
"kubernetes": {
|
||||
@ -597,6 +616,9 @@
|
||||
"ldap3": {
|
||||
"hashes": [
|
||||
"sha256:18c3ee656a6775b9b0d60f7c6c5b094d878d1d90fc03d56731039f0a4b546a91",
|
||||
"sha256:4139c91f0eef9782df7b77c8cbc6243086affcb6a8a249b768a9658438e5da59",
|
||||
"sha256:8c949edbad2be8a03e719ba48bd6779f327ec156929562814b3e84ab56889c8c",
|
||||
"sha256:afc6fc0d01f02af82cd7bfabd3bbfd5dc96a6ae91e97db0a2dab8a0f1b436056",
|
||||
"sha256:c1df41d89459be6f304e0ceec4b00fdea533dbbcd83c802b1272dcdb94620b57"
|
||||
],
|
||||
"index": "pypi",
|
||||
@ -656,65 +678,49 @@
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
|
||||
"sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
|
||||
"sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
|
||||
"sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
|
||||
"sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42",
|
||||
"sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f",
|
||||
"sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39",
|
||||
"sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
|
||||
"sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
|
||||
"sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014",
|
||||
"sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f",
|
||||
"sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
|
||||
"sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
|
||||
"sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
|
||||
"sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
|
||||
"sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b",
|
||||
"sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
|
||||
"sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15",
|
||||
"sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
|
||||
"sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85",
|
||||
"sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1",
|
||||
"sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
|
||||
"sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
|
||||
"sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
|
||||
"sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850",
|
||||
"sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0",
|
||||
"sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
|
||||
"sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
|
||||
"sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb",
|
||||
"sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
|
||||
"sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
|
||||
"sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
|
||||
"sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1",
|
||||
"sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2",
|
||||
"sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
|
||||
"sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
|
||||
"sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
|
||||
"sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7",
|
||||
"sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
|
||||
"sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8",
|
||||
"sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
|
||||
"sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193",
|
||||
"sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
|
||||
"sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b",
|
||||
"sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
|
||||
"sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2",
|
||||
"sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5",
|
||||
"sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c",
|
||||
"sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032",
|
||||
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7",
|
||||
"sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be",
|
||||
"sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621"
|
||||
"sha256:007dc055dbce5b1104876acee177dbfd18757e19d562cd440182e1f492e96b95",
|
||||
"sha256:031bf79a27d1c42f69c276d6221172417b47cb4b31cdc73d362a9bf5a1889b9f",
|
||||
"sha256:161d575fa49395860b75da5135162481768b11208490d5a2143ae6785123e77d",
|
||||
"sha256:24bbc3507fb6dfff663af7900a631f2aca90d5a445f272db5fc84999fa5718bc",
|
||||
"sha256:2efaeb1baff547063bad2b2893a8f5e9c459c4624e1a96644bbba08910ae34e0",
|
||||
"sha256:32200f562daaab472921a11cbb63780f1654552ae49518196fc361ed8e12e901",
|
||||
"sha256:3261fae28155e5c8634dd7710635fe540a05b58f160cef7713c7700cb9980e66",
|
||||
"sha256:3b54a9c68995ef4164567e2cd1a5e16db5dac30b2a50c39c82db8d4afaf14f63",
|
||||
"sha256:3c352ff634e289061711608f5e474ec38dbaa21e3e168820d53d5f4015e5b91b",
|
||||
"sha256:3fb47f97f1d338b943126e90b79cad50d4fcfa0b80637b5a9f468941dbbd9ce5",
|
||||
"sha256:441ce2a8c17683d97e06447fcbccbdb057cbf587c78eb75ae43ea7858042fe2c",
|
||||
"sha256:45535241baa0fc0ba2a43961a1ac7562ca3257f46c4c3e9c0de38b722be41bd1",
|
||||
"sha256:4aca81a687975b35e3e80bcf9aa93fe10cd57fac37bf18b2314c186095f57e05",
|
||||
"sha256:4cc563836f13c57f1473bc02d1e01fc37bab70ad4ee6be297d58c1d66bc819bf",
|
||||
"sha256:4fae0677f712ee090721d8b17f412f1cbceefbf0dc180fe91bab3232f38b4527",
|
||||
"sha256:58bc9fce3e1557d463ef5cee05391a05745fd95ed660f23c1742c711712c0abb",
|
||||
"sha256:664832fb88b8162268928df233f4b12a144a0c78b01d38b81bdcf0fc96668ecb",
|
||||
"sha256:70820a1c96311e02449591cbdf5cd1c6a34d5194d5b55094ab725364375c9eb2",
|
||||
"sha256:79b2ae94fa991be023832e6bcc00f41dbc8e5fe9d997a02db965831402551730",
|
||||
"sha256:83cf0228b2f694dcdba1374d5312f2277269d798e65f40344964f642935feac1",
|
||||
"sha256:87de598edfa2230ff274c4de7fcf24c73ffd96208c8e1912d5d0fee459767d75",
|
||||
"sha256:8f806bfd0f218477d7c46a11d3e52dc7f5fdfaa981b18202b7dc84bbc287463b",
|
||||
"sha256:90053234a6479738fd40d155268af631c7fca33365f964f2208867da1349294b",
|
||||
"sha256:a00dce2d96587651ef4fa192c17e039e8cfab63087c67e7d263a5533c7dad715",
|
||||
"sha256:a08cd07d3c3c17cd33d9e66ea9dee8f8fc1c48e2d11bd88fd2dc515a602c709b",
|
||||
"sha256:a19d39b02a24d3082856a5b06490b714a9d4179321225bbf22809ff1e1887cc8",
|
||||
"sha256:d00a669e4a5bec3ee6dbeeeedd82a405ced19f8aeefb109a012ea88a45afff96",
|
||||
"sha256:dab0c685f21f4a6c95bfc2afd1e7eae0033b403dd3d8c1b6d13a652ada75b348",
|
||||
"sha256:df561f65049ed3556e5b52541669310e88713fdae2934845ec3606f283337958",
|
||||
"sha256:e4570d16f88c7f3032ed909dc9e905a17da14a1c4cfd92608e3fda4cb1208bbd",
|
||||
"sha256:e77e4b983e2441aff0c0d07ee711110c106b625f440292dfe02a2f60c8218bd6",
|
||||
"sha256:e79212d09fc0e224d20b43ad44bb0a0a3416d1e04cf6b45fed265114a5d43d20",
|
||||
"sha256:f58b5ba13a5689ca8317b98439fccfbcc673acaaf8241c1869ceea40f5d585bf",
|
||||
"sha256:fef86115fdad7ae774720d7103aa776144cf9b66673b4afa9bcaa7af990ed07b"
|
||||
],
|
||||
"version": "==1.1.1"
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.0"
|
||||
},
|
||||
"maxminddb": {
|
||||
"hashes": [
|
||||
"sha256:47e86a084dd814fac88c99ea34ba3278a74bc9de5a25f4b815b608798747c7dc"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.3"
|
||||
},
|
||||
"msgpack": {
|
||||
@ -790,6 +796,7 @@
|
||||
"sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281",
|
||||
"sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==5.1.0"
|
||||
},
|
||||
"oauthlib": {
|
||||
@ -797,6 +804,7 @@
|
||||
"sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889",
|
||||
"sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==3.1.0"
|
||||
},
|
||||
"packaging": {
|
||||
@ -812,6 +820,7 @@
|
||||
"sha256:030e4f9df5f53db2292eec37c6255957eb76168c6f974e4176c711cf91ed34aa",
|
||||
"sha256:b6c5a9643e3545bcbfd9451766cbaa5d9c67e7303c7bc32c750b6fa70ecb107d"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.10.1"
|
||||
},
|
||||
"prompt-toolkit": {
|
||||
@ -819,6 +828,7 @@
|
||||
"sha256:bf00f22079f5fadc949f42ae8ff7f05702826a97059ffcc6281036ad40ac6f04",
|
||||
"sha256:e1b4f11b9336a28fa11810bc623c357420f69dfdb6d2dac41ca2c21a55c033bc"
|
||||
],
|
||||
"markers": "python_full_version >= '3.6.1'",
|
||||
"version": "==3.0.18"
|
||||
},
|
||||
"psycopg2-binary": {
|
||||
@ -864,15 +874,37 @@
|
||||
},
|
||||
"pyasn1": {
|
||||
"hashes": [
|
||||
"sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359",
|
||||
"sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576",
|
||||
"sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf",
|
||||
"sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7",
|
||||
"sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d",
|
||||
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"
|
||||
"sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00",
|
||||
"sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8",
|
||||
"sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86",
|
||||
"sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12",
|
||||
"sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776",
|
||||
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba",
|
||||
"sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2",
|
||||
"sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"
|
||||
],
|
||||
"version": "==0.4.8"
|
||||
},
|
||||
"pyasn1-modules": {
|
||||
"hashes": [
|
||||
"sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8",
|
||||
"sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199",
|
||||
"sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811",
|
||||
"sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed",
|
||||
"sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4",
|
||||
"sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e",
|
||||
"sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"
|
||||
"sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74",
|
||||
"sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb",
|
||||
"sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45",
|
||||
"sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd",
|
||||
"sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0",
|
||||
"sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d",
|
||||
"sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405"
|
||||
],
|
||||
"version": "==0.2.8"
|
||||
},
|
||||
@ -881,6 +913,7 @@
|
||||
"sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0",
|
||||
"sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.20"
|
||||
},
|
||||
"pycryptodome": {
|
||||
@ -924,6 +957,7 @@
|
||||
"sha256:412e00137858f04bde0729913874a48485665f2d36fe9ee449f26be864af9316",
|
||||
"sha256:7ead136e03655af85069b6f47b23eb7c3e5c221aa9f022a4fbb499f5b7308f29"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==2.0.2"
|
||||
},
|
||||
"pyjwt": {
|
||||
@ -946,12 +980,14 @@
|
||||
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
|
||||
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.4.7"
|
||||
},
|
||||
"pyrsistent": {
|
||||
"hashes": [
|
||||
"sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==0.17.3"
|
||||
},
|
||||
"python-dateutil": {
|
||||
@ -959,6 +995,7 @@
|
||||
"sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
|
||||
"sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.8.1"
|
||||
},
|
||||
"python-dotenv": {
|
||||
@ -1015,6 +1052,7 @@
|
||||
"sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2",
|
||||
"sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==3.5.3"
|
||||
},
|
||||
"requests": {
|
||||
@ -1022,12 +1060,14 @@
|
||||
"sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
|
||||
"sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==2.25.1"
|
||||
},
|
||||
"requests-oauthlib": {
|
||||
"hashes": [
|
||||
"sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d",
|
||||
"sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a"
|
||||
"sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a",
|
||||
"sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.3.0"
|
||||
@ -1045,6 +1085,7 @@
|
||||
"sha256:44bc6b54fddd45e4bc0619059196679f9e8b79c027f4131bb072e6a22f4d5e28",
|
||||
"sha256:ac79fb25f5476e8e9ed1c53b8a2286d2c3f5dde49eb37dbcee5c7eb6a8415a22"
|
||||
],
|
||||
"markers": "python_version >= '3'",
|
||||
"version": "==0.17.4"
|
||||
},
|
||||
"ruamel.yaml.clib": {
|
||||
@ -1081,7 +1122,7 @@
|
||||
"sha256:e9f7d1d8c26a6a12c23421061f9022bb62704e38211fe375c645485f38df34a2",
|
||||
"sha256:f6061a31880c1ed6b6ce341215336e2f3d0c1deccd84957b6fa8ca474b41e89f"
|
||||
],
|
||||
"markers": "platform_python_implementation == 'CPython' and python_version < '3.10'",
|
||||
"markers": "python_version < '3.10' and platform_python_implementation == 'CPython'",
|
||||
"version": "==0.2.2"
|
||||
},
|
||||
"s3transfer": {
|
||||
@ -1101,17 +1142,18 @@
|
||||
},
|
||||
"service-identity": {
|
||||
"hashes": [
|
||||
"sha256:001c0707759cb3de7e49c078a7c0c9cd12594161d3bf06b9c254fdcb1a60dc36",
|
||||
"sha256:0858a54aabc5b459d1aafa8a518ed2081a285087f349fe3e55197989232e2e2d"
|
||||
"sha256:6e6c6086ca271dc11b033d17c3a8bea9f24ebff920c587da090afc9519419d34",
|
||||
"sha256:f0b0caac3d40627c3c04d7a51b6e06721857a0e10a8775f2d1d7e72901b3a7db"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==18.1.0"
|
||||
"version": "==21.1.0"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"sqlparse": {
|
||||
@ -1119,6 +1161,7 @@
|
||||
"sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0",
|
||||
"sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==0.4.1"
|
||||
},
|
||||
"structlog": {
|
||||
@ -1174,6 +1217,7 @@
|
||||
"sha256:7d6f89745680233f1c4db9ddb748df5e88d2a7a37962be174c0fd04c8dba1dc8",
|
||||
"sha256:c16b55f9a67b2419cfdf8846576e2ec9ba94fe6978a83080c352a80db31c93fb"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==21.2.1"
|
||||
},
|
||||
"typing-extensions": {
|
||||
@ -1189,6 +1233,7 @@
|
||||
"sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f",
|
||||
"sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==3.0.1"
|
||||
},
|
||||
"urllib3": {
|
||||
@ -1233,6 +1278,7 @@
|
||||
"sha256:4c9dceab6f76ed92105027c49c823800dd33cacce13bdedc5b914e3514b7fb30",
|
||||
"sha256:7d3b1624a953da82ef63462013bbd271d3eb75751489f9807598e8f340bd637e"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==5.0.0"
|
||||
},
|
||||
"watchgod": {
|
||||
@ -1262,6 +1308,7 @@
|
||||
"sha256:2e50d26ca593f70aba7b13a489435ef88b8fc3b5c5643c1ce8808ff9b40f0b32",
|
||||
"sha256:d376bd60eace9d437ab6d7ee16f4ab4e821c9dae591e1b783c58ebd8aaf80c5c"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.59.0"
|
||||
},
|
||||
"websockets": {
|
||||
@ -1348,6 +1395,7 @@
|
||||
"sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a",
|
||||
"sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==1.6.3"
|
||||
},
|
||||
"zope.interface": {
|
||||
@ -1404,6 +1452,7 @@
|
||||
"sha256:f44e517131a98f7a76696a7b21b164bcb85291cee106a23beccce454e1f433a4",
|
||||
"sha256:f7ee479e96f7ee350db1cf24afa5685a5899e2b34992fb99e1f7c1b0b758d263"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==5.4.0"
|
||||
}
|
||||
},
|
||||
@ -1420,14 +1469,16 @@
|
||||
"sha256:4db03ab5fc3340cf619dbc25e42c2cc3755154ce6009469766d7143d1fc2ee4e",
|
||||
"sha256:8a398dfce302c13f14bab13e2b14fe385d32b73f4e4853b9bdfb64598baa1975"
|
||||
],
|
||||
"markers": "python_version ~= '3.6'",
|
||||
"version": "==2.5.6"
|
||||
},
|
||||
"attrs": {
|
||||
"hashes": [
|
||||
"sha256:3901be1cb7c2a780f14668691474d9252c070a756be0a9ead98cfeabfa11aeb8",
|
||||
"sha256:8ee1e5f5a1afc5b19bdfae4fdf0c35ed324074bdce3500c939842c8f818645d9"
|
||||
"sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
|
||||
"sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
|
||||
],
|
||||
"version": "==21.1.0"
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==21.2.0"
|
||||
},
|
||||
"bandit": {
|
||||
"hashes": [
|
||||
@ -1439,10 +1490,11 @@
|
||||
},
|
||||
"black": {
|
||||
"hashes": [
|
||||
"sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"
|
||||
"sha256:23695358dbcb3deafe7f0a3ad89feee5999a46be5fec21f4f1d108be0bcdb3b1",
|
||||
"sha256:8a60071a0043876a4ae96e6c69bd3a127dad2c1ca7c8083573eb82f92705d008"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==20.8b1"
|
||||
"version": "==21.5b1"
|
||||
},
|
||||
"bump2version": {
|
||||
"hashes": [
|
||||
@ -1464,6 +1516,7 @@
|
||||
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
|
||||
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==4.0.0"
|
||||
},
|
||||
"click": {
|
||||
@ -1471,6 +1524,7 @@
|
||||
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
|
||||
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==7.1.2"
|
||||
},
|
||||
"colorama": {
|
||||
@ -1544,14 +1598,16 @@
|
||||
"sha256:6c4cc71933456991da20917998acbe6cf4fb41eeaab7d6d67fbc05ecd4c865b0",
|
||||
"sha256:96bf5c08b157a666fec41129e6d327235284cca4c81e92109260f353ba138005"
|
||||
],
|
||||
"markers": "python_version >= '3.4'",
|
||||
"version": "==4.0.7"
|
||||
},
|
||||
"gitpython": {
|
||||
"hashes": [
|
||||
"sha256:05af150f47a5cca3f4b0af289b73aef8cf3c4fe2385015b06220cbcdee48bb6e",
|
||||
"sha256:a77824e516d3298b04fb36ec7845e92747df8fcfee9cacc32dd6239f9652f867"
|
||||
"sha256:3283ae2fba31c913d857e12e5ba5f9a7772bbc064ae2bb09efafa71b0dd4939b",
|
||||
"sha256:be27633e7509e58391f10207cd32b2a6cf5b908f92d9cd30da2e514e1137af61"
|
||||
],
|
||||
"version": "==3.1.15"
|
||||
"markers": "python_version >= '3.4'",
|
||||
"version": "==3.1.14"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
@ -1572,6 +1628,7 @@
|
||||
"sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6",
|
||||
"sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"
|
||||
],
|
||||
"markers": "python_version >= '3.6' and python_version < '4.0'",
|
||||
"version": "==5.8.0"
|
||||
},
|
||||
"lazy-object-proxy": {
|
||||
@ -1599,6 +1656,7 @@
|
||||
"sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93",
|
||||
"sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||
"version": "==1.6.0"
|
||||
},
|
||||
"mccabe": {
|
||||
@ -1635,6 +1693,7 @@
|
||||
"sha256:42df03e7797b796625b1029c0400279c7c34fd7df24a7d7818a1abb5b38710dd",
|
||||
"sha256:c68c661ac5cc81058ac94247278eeda6d2e6aecb3e227b0387c30d277e7ef8d4"
|
||||
],
|
||||
"markers": "python_version >= '2.6'",
|
||||
"version": "==5.6.0"
|
||||
},
|
||||
"pluggy": {
|
||||
@ -1642,6 +1701,7 @@
|
||||
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
|
||||
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.13.1"
|
||||
},
|
||||
"py": {
|
||||
@ -1649,6 +1709,7 @@
|
||||
"sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3",
|
||||
"sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.10.0"
|
||||
},
|
||||
"pylint": {
|
||||
@ -1679,6 +1740,7 @@
|
||||
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
|
||||
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.4.7"
|
||||
},
|
||||
"pytest": {
|
||||
@ -1783,6 +1845,7 @@
|
||||
"sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
|
||||
"sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==2.25.1"
|
||||
},
|
||||
"requests-mock": {
|
||||
@ -1806,6 +1869,7 @@
|
||||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"smmap": {
|
||||
@ -1813,6 +1877,7 @@
|
||||
"sha256:7e65386bd122d45405ddf795637b7f7d2b532e7e401d46bbe3fb49b9986d5182",
|
||||
"sha256:a9a7479e4c572e2e775c404dcd3080c8dc49f39918c2cf74913d30c4c478e3c2"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==4.0.0"
|
||||
},
|
||||
"stevedore": {
|
||||
@ -1820,6 +1885,7 @@
|
||||
"sha256:3a5bbd0652bf552748871eaa73a4a8dc2899786bc497a2aa1fcb4dcdb0debeee",
|
||||
"sha256:50d7b78fbaf0d04cd62411188fa7eedcb03eb7f4c4b37005615ceebe582aa82a"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.3.0"
|
||||
},
|
||||
"toml": {
|
||||
@ -1827,51 +1893,9 @@
|
||||
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
|
||||
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.10.2"
|
||||
},
|
||||
"typed-ast": {
|
||||
"hashes": [
|
||||
"sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace",
|
||||
"sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff",
|
||||
"sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266",
|
||||
"sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528",
|
||||
"sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6",
|
||||
"sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808",
|
||||
"sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4",
|
||||
"sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363",
|
||||
"sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341",
|
||||
"sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04",
|
||||
"sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41",
|
||||
"sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e",
|
||||
"sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3",
|
||||
"sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899",
|
||||
"sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805",
|
||||
"sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c",
|
||||
"sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c",
|
||||
"sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39",
|
||||
"sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a",
|
||||
"sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3",
|
||||
"sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7",
|
||||
"sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f",
|
||||
"sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075",
|
||||
"sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0",
|
||||
"sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40",
|
||||
"sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428",
|
||||
"sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927",
|
||||
"sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3",
|
||||
"sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f",
|
||||
"sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"
|
||||
],
|
||||
"version": "==1.4.3"
|
||||
},
|
||||
"typing-extensions": {
|
||||
"hashes": [
|
||||
"sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497",
|
||||
"sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342",
|
||||
"sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"
|
||||
],
|
||||
"version": "==3.10.0.0"
|
||||
},
|
||||
"urllib3": {
|
||||
"extras": [
|
||||
"secure"
|
||||
|
@ -1,3 +1,3 @@
|
||||
"""authentik"""
|
||||
__version__ = "2021.5.1-rc3"
|
||||
__version__ = "2021.5.1-rc8"
|
||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||
|
@ -7,6 +7,7 @@ from django.urls import reverse
|
||||
from authentik import __version__
|
||||
from authentik.core.models import Group, User
|
||||
from authentik.core.tasks import clean_expired_models
|
||||
from authentik.events.monitored_tasks import TaskResultStatus
|
||||
|
||||
|
||||
class TestAdminAPI(TestCase):
|
||||
@ -30,6 +31,26 @@ class TestAdminAPI(TestCase):
|
||||
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):
|
||||
"""Test Task API (retry)"""
|
||||
clean_expired_models.delay()
|
||||
|
@ -54,4 +54,4 @@ class AuthentikTokenAuthentication(BaseAuthentication):
|
||||
if not token:
|
||||
return None
|
||||
|
||||
return (token.user, None)
|
||||
return (token.user, None) # pragma: no cover
|
||||
|
@ -22,3 +22,10 @@ class TestSwaggerGeneration(APITestCase):
|
||||
reverse("authentik_api:schema-json", kwargs={"format": ".json"}),
|
||||
)
|
||||
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)
|
||||
|
@ -4,6 +4,7 @@ from typing import Optional
|
||||
from django.core.cache import cache
|
||||
from django.db.models import QuerySet
|
||||
from django.http.response import HttpResponseBadRequest
|
||||
from django.shortcuts import get_object_or_404
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import no_body, swagger_auto_schema
|
||||
from rest_framework.decorators import action
|
||||
@ -101,7 +102,9 @@ class ApplicationViewSet(ModelViewSet):
|
||||
# pylint: disable=unused-argument
|
||||
def check_access(self, request: Request, slug: str) -> Response:
|
||||
"""Check access to a single application by slug"""
|
||||
application = self.get_object()
|
||||
# Don't use self.get_object as that checks for view_application permission
|
||||
# which the user might not have, even if they have access
|
||||
application = get_object_or_404(Application, slug=slug)
|
||||
engine = PolicyEngine(application, self.request.user, self.request)
|
||||
engine.build()
|
||||
if engine.passing:
|
||||
|
@ -3,6 +3,7 @@ from enum import Enum
|
||||
from typing import Any, Optional, Type
|
||||
|
||||
from django.contrib import messages
|
||||
from django.db import IntegrityError
|
||||
from django.db.models.query_utils import Q
|
||||
from django.http import HttpRequest, HttpResponse, HttpResponseBadRequest
|
||||
from django.shortcuts import redirect
|
||||
@ -116,9 +117,11 @@ class SourceFlowManager:
|
||||
)
|
||||
return Action.DENY, 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)
|
||||
# No matching users, always enroll
|
||||
if not matching_users.exists():
|
||||
self._logger.debug("no matching users found, enrolling")
|
||||
return Action.ENROLL, self.update_connection(new_connection, **kwargs)
|
||||
|
||||
user = matching_users.first()
|
||||
@ -147,7 +150,11 @@ class SourceFlowManager:
|
||||
|
||||
def get_flow(self, **kwargs) -> HttpResponse:
|
||||
"""Get the flow response based on user_matching_mode"""
|
||||
action, connection = self.get_action(**kwargs)
|
||||
try:
|
||||
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)
|
||||
if connection:
|
||||
if action == Action.LINK:
|
||||
|
@ -24,7 +24,7 @@ class TestApplicationsAPI(APITestCase):
|
||||
)
|
||||
|
||||
def test_check_access(self):
|
||||
"""Test check_access operation """
|
||||
"""Test check_access operation"""
|
||||
self.client.force_login(self.user)
|
||||
response = self.client.get(
|
||||
reverse(
|
||||
|
@ -21,7 +21,7 @@ class TestModels(TestCase):
|
||||
self.assertTrue(token.is_expired)
|
||||
|
||||
def test_token_expire_no_expire(self):
|
||||
"""Test token expiring with "expiring" set """
|
||||
"""Test token expiring with "expiring" set"""
|
||||
token = Token.objects.create(
|
||||
expires=now(), user=get_anonymous_user(), expiring=False
|
||||
)
|
||||
|
@ -3,7 +3,9 @@ import django_filters
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives.serialization import load_pem_private_key
|
||||
from cryptography.x509 import load_pem_x509_certificate
|
||||
from django.http.response import HttpResponse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import (
|
||||
@ -145,7 +147,16 @@ class CertificateKeyPairViewSet(ModelViewSet):
|
||||
serializer = self.get_serializer(instance)
|
||||
return Response(serializer.data)
|
||||
|
||||
@swagger_auto_schema(responses={200: CertificateDataSerializer(many=False)})
|
||||
@swagger_auto_schema(
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
name="download",
|
||||
in_=openapi.IN_QUERY,
|
||||
type=openapi.TYPE_BOOLEAN,
|
||||
)
|
||||
],
|
||||
responses={200: CertificateDataSerializer(many=False)},
|
||||
)
|
||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||
# pylint: disable=invalid-name, unused-argument
|
||||
def view_certificate(self, request: Request, pk: str) -> Response:
|
||||
@ -156,11 +167,29 @@ class CertificateKeyPairViewSet(ModelViewSet):
|
||||
secret=certificate,
|
||||
type="certificate",
|
||||
).from_http(request)
|
||||
if "download" in request._request.GET:
|
||||
# Mime type from https://pki-tutorial.readthedocs.io/en/latest/mime.html
|
||||
response = HttpResponse(
|
||||
certificate.certificate_data, content_type="application/x-pem-file"
|
||||
)
|
||||
response[
|
||||
"Content-Disposition"
|
||||
] = f'attachment; filename="{certificate.name}_certificate.pem"'
|
||||
return response
|
||||
return Response(
|
||||
CertificateDataSerializer({"data": certificate.certificate_data}).data
|
||||
)
|
||||
|
||||
@swagger_auto_schema(responses={200: CertificateDataSerializer(many=False)})
|
||||
@swagger_auto_schema(
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
name="download",
|
||||
in_=openapi.IN_QUERY,
|
||||
type=openapi.TYPE_BOOLEAN,
|
||||
)
|
||||
],
|
||||
responses={200: CertificateDataSerializer(many=False)},
|
||||
)
|
||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||
# pylint: disable=invalid-name, unused-argument
|
||||
def view_private_key(self, request: Request, pk: str) -> Response:
|
||||
@ -171,4 +200,13 @@ class CertificateKeyPairViewSet(ModelViewSet):
|
||||
secret=certificate,
|
||||
type="private_key",
|
||||
).from_http(request)
|
||||
if "download" in request._request.GET:
|
||||
# Mime type from https://pki-tutorial.readthedocs.io/en/latest/mime.html
|
||||
response = HttpResponse(
|
||||
certificate.key_data, content_type="application/x-pem-file"
|
||||
)
|
||||
response[
|
||||
"Content-Disposition"
|
||||
] = f'attachment; filename="{certificate.name}_private_key.pem"'
|
||||
return response
|
||||
return Response(CertificateDataSerializer({"data": certificate.key_data}).data)
|
||||
|
@ -2,7 +2,9 @@
|
||||
import datetime
|
||||
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.crypto.api import CertificateKeyPairSerializer
|
||||
from authentik.crypto.builder import CertificateBuilder
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
@ -47,3 +49,45 @@ class TestCrypto(TestCase):
|
||||
now = datetime.datetime.today()
|
||||
self.assertEqual(instance.name, "test-cert")
|
||||
self.assertEqual((instance.certificate.not_valid_after - now).days, 2)
|
||||
|
||||
def test_certificate_download(self):
|
||||
"""Test certificate export (download)"""
|
||||
self.client.force_login(User.objects.get(username="akadmin"))
|
||||
keypair = CertificateKeyPair.objects.first()
|
||||
response = self.client.get(
|
||||
reverse(
|
||||
"authentik_api:certificatekeypair-view-certificate",
|
||||
kwargs={"pk": keypair.pk},
|
||||
)
|
||||
)
|
||||
self.assertEqual(200, response.status_code)
|
||||
response = self.client.get(
|
||||
reverse(
|
||||
"authentik_api:certificatekeypair-view-certificate",
|
||||
kwargs={"pk": keypair.pk},
|
||||
)
|
||||
+ "?download",
|
||||
)
|
||||
self.assertEqual(200, response.status_code)
|
||||
self.assertIn("Content-Disposition", response)
|
||||
|
||||
def test_private_key_download(self):
|
||||
"""Test private_key export (download)"""
|
||||
self.client.force_login(User.objects.get(username="akadmin"))
|
||||
keypair = CertificateKeyPair.objects.first()
|
||||
response = self.client.get(
|
||||
reverse(
|
||||
"authentik_api:certificatekeypair-view-private-key",
|
||||
kwargs={"pk": keypair.pk},
|
||||
)
|
||||
)
|
||||
self.assertEqual(200, response.status_code)
|
||||
response = self.client.get(
|
||||
reverse(
|
||||
"authentik_api:certificatekeypair-view-private-key",
|
||||
kwargs={"pk": keypair.pk},
|
||||
)
|
||||
+ "?download",
|
||||
)
|
||||
self.assertEqual(200, response.status_code)
|
||||
self.assertIn("Content-Disposition", response)
|
||||
|
@ -1,7 +1,9 @@
|
||||
"""Notification API Views"""
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from guardian.utils import get_anonymous_user
|
||||
from rest_framework import mixins
|
||||
from rest_framework.fields import ReadOnlyField
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
|
||||
@ -47,6 +49,11 @@ class NotificationViewSet(
|
||||
"event",
|
||||
"seen",
|
||||
]
|
||||
filter_backends = [
|
||||
DjangoFilterBackend,
|
||||
OrderingFilter,
|
||||
SearchFilter,
|
||||
]
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user if self.request else get_anonymous_user()
|
||||
|
@ -298,7 +298,7 @@ class CancelView(View):
|
||||
if SESSION_KEY_PLAN in request.session:
|
||||
del request.session[SESSION_KEY_PLAN]
|
||||
LOGGER.debug("Canceled current plan")
|
||||
return redirect("authentik_core:root-redirect")
|
||||
return redirect("authentik_core:default-invalidation")
|
||||
|
||||
|
||||
class ToDefaultFlow(View):
|
||||
|
@ -3,6 +3,7 @@ postgresql:
|
||||
host: localhost
|
||||
name: authentik
|
||||
user: authentik
|
||||
port: 5432
|
||||
password: 'env://POSTGRES_PASSWORD'
|
||||
|
||||
web:
|
||||
|
@ -1,23 +1,35 @@
|
||||
"""Outpost API Views"""
|
||||
from dacite.core import from_dict
|
||||
from dacite.exceptions import DaciteError
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import BooleanField, CharField, DateTimeField
|
||||
from rest_framework.request import Request
|
||||
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 authentik.core.api.providers import ProviderSerializer
|
||||
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):
|
||||
"""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)
|
||||
|
||||
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:
|
||||
|
||||
model = Outpost
|
||||
@ -29,6 +41,7 @@ class OutpostSerializer(ModelSerializer):
|
||||
"providers_obj",
|
||||
"service_connection",
|
||||
"token_identifier",
|
||||
"config",
|
||||
"_config",
|
||||
]
|
||||
|
||||
|
@ -42,6 +42,8 @@ class OutpostConsumer(AuthJsonConsumer):
|
||||
|
||||
outpost: Optional[Outpost] = None
|
||||
|
||||
last_uid: Optional[str] = None
|
||||
|
||||
def connect(self):
|
||||
super().connect()
|
||||
uuid = self.scope["url_route"]["kwargs"]["pk"]
|
||||
@ -52,9 +54,7 @@ class OutpostConsumer(AuthJsonConsumer):
|
||||
raise DenyConnection()
|
||||
self.accept()
|
||||
self.outpost = outpost.first()
|
||||
OutpostState(
|
||||
uid=self.channel_name, last_seen=datetime.now(), _outpost=self.outpost
|
||||
).save(timeout=OUTPOST_HELLO_INTERVAL * 1.5)
|
||||
self.last_uid = self.channel_name
|
||||
LOGGER.debug(
|
||||
"added outpost instace to cache",
|
||||
outpost=self.outpost,
|
||||
@ -63,18 +63,20 @@ class OutpostConsumer(AuthJsonConsumer):
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def disconnect(self, close_code):
|
||||
if self.outpost:
|
||||
OutpostState.for_channel(self.outpost, self.channel_name).delete()
|
||||
if self.outpost and self.last_uid:
|
||||
OutpostState.for_channel(self.outpost, self.last_uid).delete()
|
||||
LOGGER.debug(
|
||||
"removed outpost instance from cache",
|
||||
outpost=self.outpost,
|
||||
channel_name=self.channel_name,
|
||||
instance_uuid=self.last_uid,
|
||||
)
|
||||
|
||||
def receive_json(self, content: Data):
|
||||
msg = from_dict(WebsocketMessage, content)
|
||||
uid = msg.args.get("uuid", self.channel_name)
|
||||
self.last_uid = uid
|
||||
state = OutpostState(
|
||||
uid=self.channel_name,
|
||||
uid=uid,
|
||||
last_seen=datetime.now(),
|
||||
_outpost=self.outpost,
|
||||
)
|
||||
@ -82,8 +84,7 @@ class OutpostConsumer(AuthJsonConsumer):
|
||||
state.version = msg.args.get("version", None)
|
||||
elif msg.instruction == WebsocketMessageInstruction.ACK:
|
||||
return
|
||||
if state.version:
|
||||
state.save(timeout=OUTPOST_HELLO_INTERVAL * 1.5)
|
||||
state.save(timeout=OUTPOST_HELLO_INTERVAL * 1.5)
|
||||
|
||||
response = WebsocketMessage(instruction=WebsocketMessageInstruction.ACK)
|
||||
self.send_json(asdict(response))
|
||||
|
@ -56,6 +56,12 @@ class BaseController:
|
||||
"""Handler to delete everything we've created"""
|
||||
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:
|
||||
"""Return a static deployment configuration"""
|
||||
raise NotImplementedError
|
||||
|
@ -30,11 +30,6 @@ class NeedsUpdate(ReconcileTrigger):
|
||||
"""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]):
|
||||
"""Base Kubernetes Reconciler, handles the basic logic."""
|
||||
|
||||
@ -45,22 +40,29 @@ class KubernetesObjectReconciler(Generic[T]):
|
||||
self.namespace = controller.outpost.config.kubernetes_namespace
|
||||
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
|
||||
def name(self) -> str:
|
||||
"""Get the name of the object this reconciler manages"""
|
||||
return self.controller.outpost.config.object_naming_template % {
|
||||
"name": slugify(self.controller.outpost.name),
|
||||
"uuid": self.controller.outpost.uuid.hex,
|
||||
}
|
||||
return (
|
||||
self.controller.outpost.config.object_naming_template
|
||||
% {
|
||||
"name": slugify(self.controller.outpost.name),
|
||||
"uuid": self.controller.outpost.uuid.hex,
|
||||
}
|
||||
).lower()
|
||||
|
||||
def up(self):
|
||||
"""Create object if it doesn't exist, update if needed or recreate if needed."""
|
||||
current = None
|
||||
try:
|
||||
reference = self.get_reference_object()
|
||||
except Disabled:
|
||||
self.logger.debug("Object not required")
|
||||
if self.noop:
|
||||
self.logger.debug("Object is noop")
|
||||
return
|
||||
reference = self.get_reference_object()
|
||||
try:
|
||||
try:
|
||||
current = self.retrieve()
|
||||
@ -89,11 +91,8 @@ class KubernetesObjectReconciler(Generic[T]):
|
||||
|
||||
def down(self):
|
||||
"""Delete object if found"""
|
||||
# Call self.get_reference_object to check if we even need to do anything
|
||||
try:
|
||||
self.get_reference_object()
|
||||
except Disabled:
|
||||
self.logger.debug("Object not required")
|
||||
if self.noop:
|
||||
self.logger.debug("Object is noop")
|
||||
return
|
||||
try:
|
||||
current = self.retrieve()
|
||||
|
11
authentik/outposts/controllers/k8s/utils.py
Normal file
11
authentik/outposts/controllers/k8s/utils.py
Normal 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"
|
@ -8,7 +8,7 @@ from structlog.testing import capture_logs
|
||||
from yaml import dump_all
|
||||
|
||||
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.secret import SecretReconciler
|
||||
from authentik.outposts.controllers.k8s.service import ServiceReconciler
|
||||
@ -49,6 +49,9 @@ class KubernetesController(BaseController):
|
||||
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.up()
|
||||
@ -61,19 +64,34 @@ class KubernetesController(BaseController):
|
||||
try:
|
||||
for reconcile_key in self.reconcile_order:
|
||||
reconciler = self.reconcilers[reconcile_key](self)
|
||||
self.logger.debug("Tearing down object", name=reconcile_key)
|
||||
reconciler.down()
|
||||
|
||||
except ApiException as 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:
|
||||
documents = []
|
||||
for reconcile_key in self.reconcile_order:
|
||||
reconciler = self.reconcilers[reconcile_key](self)
|
||||
try:
|
||||
documents.append(reconciler.get_reference_object().to_dict())
|
||||
except Disabled:
|
||||
if reconciler.noop:
|
||||
continue
|
||||
documents.append(reconciler.get_reference_object().to_dict())
|
||||
|
||||
with StringIO() as _str:
|
||||
dump_all(
|
||||
|
@ -33,6 +33,7 @@ from authentik.lib.config import CONFIG
|
||||
from authentik.lib.models import InheritanceForeignKey
|
||||
from authentik.lib.sentry import SentryIgnoredException
|
||||
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
|
||||
|
||||
OUR_VERSION = parse(__version__)
|
||||
@ -41,7 +42,7 @@ LOGGER = get_logger()
|
||||
|
||||
|
||||
class ServiceConnectionInvalid(SentryIgnoredException):
|
||||
""""Exception raised when a Service Connection has invalid parameters"""
|
||||
"""Exception raised when a Service Connection has invalid parameters"""
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -59,10 +60,11 @@ class OutpostConfig:
|
||||
|
||||
object_naming_template: str = field(default="ak-outpost-%(name)s")
|
||||
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_secret_name: str = field(default="authentik-outpost-tls")
|
||||
kubernetes_service_type: str = field(default="ClusterIP")
|
||||
kubernetes_disabled_components: list[str] = field(default_factory=list)
|
||||
|
||||
|
||||
class OutpostModel(Model):
|
||||
|
@ -1,5 +1,5 @@
|
||||
"""authentik outpost signals"""
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
from django.db.models import Model
|
||||
from django.db.models.signals import post_save, pre_delete, pre_save
|
||||
from django.dispatch import receiver
|
||||
@ -8,9 +8,12 @@ from structlog.stdlib import get_logger
|
||||
from authentik.core.models import Provider
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
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.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()
|
||||
UPDATE_TRIGGERING_MODELS = (
|
||||
@ -39,7 +42,8 @@ def pre_save_outpost(sender, instance: Outpost, **_):
|
||||
)
|
||||
if bool(dirty):
|
||||
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)
|
||||
@ -63,23 +67,5 @@ def post_save_update(sender, instance: Model, **_):
|
||||
def pre_delete_cleanup(sender, instance: Outpost, **_):
|
||||
"""Ensure that Outpost's user is deleted (which will delete the token through cascade)"""
|
||||
instance.user.delete()
|
||||
outpost_controller_down_wrapper(instance)
|
||||
|
||||
|
||||
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
|
||||
)
|
||||
cache.set(CACHE_KEY_OUTPOST_DOWN % instance.pk.hex, instance)
|
||||
outpost_controller.delay(instance.pk.hex, action="down", from_cache=True)
|
||||
|
@ -36,6 +36,7 @@ from authentik.providers.proxy.controllers.kubernetes import ProxyKubernetesCont
|
||||
from authentik.root.celery import CELERY_APP
|
||||
|
||||
LOGGER = get_logger()
|
||||
CACHE_KEY_OUTPOST_DOWN = "outpost_teardown_%s"
|
||||
|
||||
|
||||
def controller_for_outpost(outpost: Outpost) -> Optional[BaseController]:
|
||||
@ -56,13 +57,6 @@ def controller_for_outpost(outpost: Outpost) -> Optional[BaseController]:
|
||||
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()
|
||||
def outpost_service_connection_state(connection_pk: Any):
|
||||
"""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)
|
||||
def outpost_controller(self: MonitoredTask, outpost_pk: str):
|
||||
"""Create/update/monitor the deployment of an Outpost"""
|
||||
def outpost_controller(
|
||||
self: MonitoredTask, outpost_pk: str, action: str = "up", from_cache: bool = False
|
||||
):
|
||||
"""Create/update/monitor/delete the deployment of an Outpost"""
|
||||
logs = []
|
||||
outpost: Outpost = Outpost.objects.get(pk=outpost_pk)
|
||||
if from_cache:
|
||||
outpost: Outpost = cache.get(CACHE_KEY_OUTPOST_DOWN % outpost_pk)
|
||||
else:
|
||||
outpost: Outpost = Outpost.objects.get(pk=outpost_pk)
|
||||
self.set_uid(slugify(outpost.name))
|
||||
try:
|
||||
controller = controller_for_outpost(outpost)
|
||||
if not controller:
|
||||
return
|
||||
logs = controller.up_with_logs()
|
||||
logs = getattr(controller, f"{action}_with_logs")()
|
||||
LOGGER.debug("---------------Outpost Controller logs starting----------------")
|
||||
for log in logs:
|
||||
LOGGER.debug(log)
|
||||
@ -110,16 +116,6 @@ def outpost_controller(self: MonitoredTask, outpost_pk: str):
|
||||
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)
|
||||
def outpost_token_ensurer(self: MonitoredTask):
|
||||
"""Periodically ensure that all Outposts have valid Service Accounts
|
||||
|
@ -3,6 +3,10 @@ from django.urls import reverse
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
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):
|
||||
@ -22,3 +26,22 @@ class TestOutpostServiceConnectionsAPI(APITestCase):
|
||||
reverse("authentik_api:outpostserviceconnection-types"),
|
||||
)
|
||||
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())
|
||||
|
@ -1,7 +1,9 @@
|
||||
"""OAuth2Provider API Views"""
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from guardian.utils import get_anonymous_user
|
||||
from rest_framework import mixins
|
||||
from rest_framework.fields import CharField, ListField
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
|
||||
@ -37,6 +39,11 @@ class AuthorizationCodeViewSet(
|
||||
serializer_class = ExpiringBaseGrantModelSerializer
|
||||
filterset_fields = ["user", "provider"]
|
||||
ordering = ["provider", "expires"]
|
||||
filter_backends = [
|
||||
DjangoFilterBackend,
|
||||
OrderingFilter,
|
||||
SearchFilter,
|
||||
]
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user if self.request else get_anonymous_user()
|
||||
@ -57,6 +64,11 @@ class RefreshTokenViewSet(
|
||||
serializer_class = ExpiringBaseGrantModelSerializer
|
||||
filterset_fields = ["user", "provider"]
|
||||
ordering = ["provider", "expires"]
|
||||
filter_backends = [
|
||||
DjangoFilterBackend,
|
||||
OrderingFilter,
|
||||
SearchFilter,
|
||||
]
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user if self.request else get_anonymous_user()
|
||||
|
@ -33,6 +33,8 @@ class OpenIDConnectConfigurationSerializer(PassiveSerializer):
|
||||
class ProxyProviderSerializer(ProviderSerializer):
|
||||
"""ProxyProvider Serializer"""
|
||||
|
||||
redirect_uris = CharField(read_only=True)
|
||||
|
||||
def validate(self, attrs) -> dict[Any, str]:
|
||||
"""Check that internal_host is set when forward_auth_mode is disabled"""
|
||||
if (
|
||||
@ -67,6 +69,7 @@ class ProxyProviderSerializer(ProviderSerializer):
|
||||
"basic_auth_password_attribute",
|
||||
"basic_auth_user_attribute",
|
||||
"forward_auth_mode",
|
||||
"redirect_uris",
|
||||
]
|
||||
|
||||
|
||||
|
@ -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.k8s.base import (
|
||||
Disabled,
|
||||
KubernetesObjectReconciler,
|
||||
NeedsUpdate,
|
||||
)
|
||||
@ -137,9 +136,6 @@ class IngressReconciler(KubernetesObjectReconciler[NetworkingV1beta1Ingress]):
|
||||
),
|
||||
)
|
||||
rules.append(rule)
|
||||
if not rules:
|
||||
self.logger.debug("No providers use proxying, no ingress needed")
|
||||
raise Disabled()
|
||||
tls_config = None
|
||||
if tls_hosts:
|
||||
tls_config = NetworkingV1beta1IngressTLS(
|
||||
|
@ -7,7 +7,6 @@ from kubernetes.client import ApiextensionsV1Api, CustomObjectsApi
|
||||
|
||||
from authentik.outposts.controllers.base import FIELD_MANAGER
|
||||
from authentik.outposts.controllers.k8s.base import (
|
||||
Disabled,
|
||||
KubernetesObjectReconciler,
|
||||
NeedsUpdate,
|
||||
)
|
||||
@ -70,6 +69,19 @@ class TraefikMiddlewareReconciler(KubernetesObjectReconciler[TraefikMiddleware])
|
||||
self.api_ex = ApiextensionsV1Api(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:
|
||||
"""Check if the traefik middleware exists"""
|
||||
return bool(
|
||||
@ -87,15 +99,6 @@ class TraefikMiddlewareReconciler(KubernetesObjectReconciler[TraefikMiddleware])
|
||||
|
||||
def get_reference_object(self) -> TraefikMiddleware:
|
||||
"""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(
|
||||
apiVersion=f"{CRD_GROUP}/{CRD_VERSION}",
|
||||
kind="Middleware",
|
||||
|
@ -5,6 +5,7 @@ from defusedxml.ElementTree import fromstring
|
||||
from django.http.response import HttpResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import CharField, FileField, ReadOnlyField
|
||||
@ -83,7 +84,14 @@ class SAMLProviderViewSet(ModelViewSet):
|
||||
responses={
|
||||
200: SAMLMetadataSerializer(many=False),
|
||||
404: "Provider has no application assigned",
|
||||
}
|
||||
},
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
name="download",
|
||||
in_=openapi.IN_QUERY,
|
||||
type=openapi.TYPE_BOOLEAN,
|
||||
)
|
||||
],
|
||||
)
|
||||
@action(methods=["GET"], detail=True, permission_classes=[AllowAny])
|
||||
# pylint: disable=invalid-name, unused-argument
|
||||
|
@ -23,7 +23,7 @@ def deflate_and_base64_encode(inflated: str, encoding="utf-8"):
|
||||
|
||||
|
||||
def nice64(src: str) -> str:
|
||||
"""Returns src base64-encoded and formatted nicely for our XML. """
|
||||
"""Returns src base64-encoded and formatted nicely for our XML."""
|
||||
return base64.b64encode(src.encode()).decode("utf-8").replace("\n", "")
|
||||
|
||||
|
||||
|
@ -248,6 +248,7 @@ DATABASES = {
|
||||
"NAME": CONFIG.y("postgresql.name"),
|
||||
"USER": CONFIG.y("postgresql.user"),
|
||||
"PASSWORD": CONFIG.y("postgresql.password"),
|
||||
"PORT": int(CONFIG.y("postgresql.port")),
|
||||
}
|
||||
}
|
||||
|
||||
@ -319,9 +320,6 @@ CELERY_RESULT_BACKEND = (
|
||||
# Database backup
|
||||
DBBACKUP_STORAGE = "django.core.files.storage.FileSystemStorage"
|
||||
DBBACKUP_STORAGE_OPTIONS = {"location": "./backups" if DEBUG else "/backups"}
|
||||
DBBACKUP_CONNECTOR_MAPPING = {
|
||||
"django_prometheus.db.backends.postgresql": "dbbackup.db.postgresql.PgDumpConnector"
|
||||
}
|
||||
if CONFIG.y("postgresql.s3_backup"):
|
||||
DBBACKUP_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
|
||||
DBBACKUP_STORAGE_OPTIONS = {
|
||||
@ -331,9 +329,10 @@ if CONFIG.y("postgresql.s3_backup"):
|
||||
"region_name": CONFIG.y("postgresql.s3_backup.region", "eu-central-1"),
|
||||
"default_acl": "private",
|
||||
"endpoint_url": CONFIG.y("postgresql.s3_backup.host"),
|
||||
"location": CONFIG.y("postgresql.s3_backup.location", ""),
|
||||
}
|
||||
j_print(
|
||||
"Database backup to S3 is configured.",
|
||||
"Database backup to S3 is configured",
|
||||
host=CONFIG.y("postgresql.s3_backup.host"),
|
||||
)
|
||||
|
||||
@ -355,7 +354,7 @@ if _ERROR_REPORTING:
|
||||
send_default_pii=CONFIG.y_bool("error_reporting.send_pii", False),
|
||||
)
|
||||
j_print(
|
||||
"Error reporting is enabled.",
|
||||
"Error reporting is enabled",
|
||||
env=CONFIG.y("error_reporting.environment", "customer"),
|
||||
)
|
||||
|
||||
|
@ -75,6 +75,7 @@ class OAuthSourceSerializer(SourceSerializer):
|
||||
"callback_url",
|
||||
"type",
|
||||
]
|
||||
extra_kwargs = {"consumer_secret": {"write_only": True}}
|
||||
|
||||
|
||||
class OAuthSourceViewSet(ModelViewSet):
|
||||
|
@ -1,5 +1,7 @@
|
||||
"""OAuth Source Serializer"""
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from guardian.utils import get_anonymous_user
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.core.api.sources import SourceSerializer
|
||||
@ -25,6 +27,11 @@ class UserOAuthSourceConnectionViewSet(ModelViewSet):
|
||||
queryset = UserOAuthSourceConnection.objects.all()
|
||||
serializer_class = UserOAuthSourceConnectionSerializer
|
||||
filterset_fields = ["source__slug"]
|
||||
filter_backends = [
|
||||
DjangoFilterBackend,
|
||||
OrderingFilter,
|
||||
SearchFilter,
|
||||
]
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user if self.request else get_anonymous_user()
|
||||
|
@ -33,6 +33,5 @@ class TestTypeGoogle(TestCase):
|
||||
def test_enroll_context(self):
|
||||
"""Test Google Enrollment context"""
|
||||
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["name"], GOOGLE_USER["name"])
|
||||
|
@ -23,7 +23,6 @@ class GoogleOAuth2Callback(OAuthCallback):
|
||||
info: dict[str, Any],
|
||||
) -> dict[str, Any]:
|
||||
return {
|
||||
"username": info.get("email"),
|
||||
"email": info.get("email"),
|
||||
"name": info.get("name"),
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ class PlexSourceSerializer(SourceSerializer):
|
||||
"allow_friends",
|
||||
"plex_token",
|
||||
]
|
||||
extra_kwargs = {"plex_token": {"write_only": True}}
|
||||
|
||||
|
||||
class PlexTokenRedeemSerializer(PassiveSerializer):
|
||||
|
@ -1,6 +1,9 @@
|
||||
"""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 guardian.utils import get_anonymous_user
|
||||
from rest_framework.filters import SearchFilter
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
|
||||
@ -43,6 +46,11 @@ class StaticDeviceViewSet(ModelViewSet):
|
||||
search_fields = ["name"]
|
||||
filterset_fields = ["name"]
|
||||
ordering = ["name"]
|
||||
filter_backends = [
|
||||
DjangoFilterBackend,
|
||||
OrderingFilter,
|
||||
SearchFilter,
|
||||
]
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user if self.request else get_anonymous_user()
|
||||
|
@ -1,6 +1,8 @@
|
||||
"""AuthenticatorTOTPStage API Views"""
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from django_otp.plugins.otp_totp.models import TOTPDevice
|
||||
from guardian.utils import get_anonymous_user
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
|
||||
@ -46,6 +48,11 @@ class TOTPDeviceViewSet(ModelViewSet):
|
||||
search_fields = ["name"]
|
||||
filterset_fields = ["name"]
|
||||
ordering = ["name"]
|
||||
filter_backends = [
|
||||
DjangoFilterBackend,
|
||||
OrderingFilter,
|
||||
SearchFilter,
|
||||
]
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user if self.request else get_anonymous_user()
|
||||
|
@ -1,5 +1,7 @@
|
||||
"""AuthenticateWebAuthnStage API Views"""
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from guardian.utils import get_anonymous_user
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
|
||||
@ -45,6 +47,11 @@ class WebAuthnDeviceViewSet(ModelViewSet):
|
||||
search_fields = ["name"]
|
||||
filterset_fields = ["name"]
|
||||
ordering = ["name"]
|
||||
filter_backends = [
|
||||
DjangoFilterBackend,
|
||||
OrderingFilter,
|
||||
SearchFilter,
|
||||
]
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user if self.request else get_anonymous_user()
|
||||
|
@ -1,6 +1,8 @@
|
||||
"""ConsentStage API Views"""
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from guardian.utils import get_anonymous_user
|
||||
from rest_framework import mixins
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
||||
|
||||
from authentik.core.api.applications import ApplicationSerializer
|
||||
@ -49,6 +51,11 @@ class UserConsentViewSet(
|
||||
serializer_class = UserConsentSerializer
|
||||
filterset_fields = ["user", "application"]
|
||||
ordering = ["application", "expires"]
|
||||
filter_backends = [
|
||||
DjangoFilterBackend,
|
||||
OrderingFilter,
|
||||
SearchFilter,
|
||||
]
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user if self.request else get_anonymous_user()
|
||||
|
@ -3,6 +3,7 @@ from rest_framework.fields import JSONField
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.core.api.users import UserSerializer
|
||||
from authentik.core.api.utils import is_dict
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.invitation.models import Invitation, InvitationStage
|
||||
@ -29,6 +30,7 @@ class InvitationStageViewSet(ModelViewSet):
|
||||
class InvitationSerializer(ModelSerializer):
|
||||
"""Invitation Serializer"""
|
||||
|
||||
created_by = UserSerializer(read_only=True)
|
||||
fixed_data = JSONField(validators=[is_dict], required=False)
|
||||
|
||||
class Meta:
|
||||
@ -41,7 +43,6 @@ class InvitationSerializer(ModelSerializer):
|
||||
"created_by",
|
||||
"single_use",
|
||||
]
|
||||
depth = 2
|
||||
|
||||
|
||||
class InvitationViewSet(ModelViewSet):
|
||||
|
@ -33,7 +33,7 @@ class UserLoginStageView(StageView):
|
||||
backend=backend,
|
||||
)
|
||||
delta = timedelta_from_string(self.executor.current_stage.session_duration)
|
||||
if delta.seconds == 0:
|
||||
if delta.total_seconds() == 0:
|
||||
self.request.session.set_expiry(0)
|
||||
else:
|
||||
self.request.session.set_expiry(delta)
|
||||
|
@ -19,7 +19,7 @@ variables:
|
||||
branchName: ${{ replace(variables['Build.SourceBranchName'], 'refs/heads/', '') }}
|
||||
|
||||
stages:
|
||||
- stage: Lint
|
||||
- stage: Lint_and_test
|
||||
jobs:
|
||||
- job: pylint
|
||||
pool:
|
||||
@ -118,8 +118,6 @@ stages:
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: pipenv run pyright e2e lifecycle
|
||||
- stage: Test
|
||||
jobs:
|
||||
- job: migrations
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
@ -21,7 +21,7 @@ services:
|
||||
networks:
|
||||
- internal
|
||||
server:
|
||||
image: ${AUTHENTIK_IMAGE:-beryju/authentik}:${AUTHENTIK_TAG:-2021.5.1-rc3}
|
||||
image: ${AUTHENTIK_IMAGE:-beryju/authentik}:${AUTHENTIK_TAG:-2021.5.1-rc8}
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment:
|
||||
@ -52,7 +52,7 @@ services:
|
||||
- "0.0.0.0:9000:9000"
|
||||
- "0.0.0.0:9443:9443"
|
||||
worker:
|
||||
image: ${AUTHENTIK_IMAGE:-beryju/authentik}:${AUTHENTIK_TAG:-2021.5.1-rc3}
|
||||
image: ${AUTHENTIK_IMAGE:-beryju/authentik}:${AUTHENTIK_TAG:-2021.5.1-rc8}
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
networks:
|
||||
|
@ -1,3 +1,3 @@
|
||||
package constants
|
||||
|
||||
const VERSION = "2021.5.1-rc3"
|
||||
const VERSION = "2021.5.1-rc8"
|
||||
|
@ -41,11 +41,9 @@ while True:
|
||||
|
||||
while True:
|
||||
try:
|
||||
redis = Redis(
|
||||
host=CONFIG.y("redis.host"),
|
||||
port=6379,
|
||||
db=CONFIG.y("redis.message_queue_db"),
|
||||
password=CONFIG.y("redis.password"),
|
||||
redis = Redis.from_url(
|
||||
f"redis://:{CONFIG.y('redis.password')}@{CONFIG.y('redis.host')}:6379"
|
||||
f"/{CONFIG.y('redis.ws_db')}"
|
||||
)
|
||||
redis.ping()
|
||||
break
|
||||
|
@ -17,6 +17,7 @@ require (
|
||||
github.com/go-redis/redis/v7 v7.4.0 // indirect
|
||||
github.com/go-swagger/go-swagger v0.27.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/uuid v1.2.0 // indirect
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
|
||||
github.com/justinas/alice v1.2.0
|
||||
|
@ -352,6 +352,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/recws-org/recws"
|
||||
"goauthentik.io/outpost/pkg"
|
||||
@ -35,7 +36,8 @@ type APIController struct {
|
||||
|
||||
reloadOffset time.Duration
|
||||
|
||||
wsConn *recws.RecConn
|
||||
wsConn *recws.RecConn
|
||||
instanceUUID uuid.UUID
|
||||
}
|
||||
|
||||
// NewAPIController initialise new API Controller instance from URL and API token
|
||||
@ -70,6 +72,7 @@ func NewAPIController(akURL url.URL, token string) *APIController {
|
||||
logger: log,
|
||||
|
||||
reloadOffset: time.Duration(rand.Intn(10)) * time.Second,
|
||||
instanceUUID: uuid.New(),
|
||||
}
|
||||
ac.logger.Debugf("HA Reload offset: %s", ac.reloadOffset)
|
||||
ac.initWS(akURL, outpost.Pk)
|
||||
@ -90,6 +93,10 @@ func (a *APIController) Start() error {
|
||||
a.logger.Debug("Starting WS Health notifier...")
|
||||
a.startWSHealth()
|
||||
}()
|
||||
go func() {
|
||||
a.logger.Debug("Starting Interval updater...")
|
||||
a.startIntervalUpdater()
|
||||
}()
|
||||
go func() {
|
||||
err := a.Server.Start()
|
||||
if err != nil {
|
||||
|
@ -47,6 +47,7 @@ func (ac *APIController) initWS(akURL url.URL, outpostUUID strfmt.UUID) {
|
||||
Instruction: WebsocketInstructionHello,
|
||||
Args: map[string]interface{}{
|
||||
"version": pkg.VERSION,
|
||||
"uuid": ac.instanceUUID.String(),
|
||||
},
|
||||
}
|
||||
err := ws.WriteJSON(msg)
|
||||
@ -100,6 +101,7 @@ func (ac *APIController) startWSHealth() {
|
||||
Instruction: WebsocketInstructionHello,
|
||||
Args: map[string]interface{}{
|
||||
"version": pkg.VERSION,
|
||||
"uuid": ac.instanceUUID.String(),
|
||||
},
|
||||
}
|
||||
err := ac.wsConn.WriteJSON(aliveMsg)
|
||||
@ -111,3 +113,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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ func doGlobalSetup(config map[string]interface{}) {
|
||||
},
|
||||
})
|
||||
switch config[ConfigLogLevel].(string) {
|
||||
case "trace":
|
||||
log.SetLevel(log.TraceLevel)
|
||||
case "debug":
|
||||
log.SetLevel(log.DebugLevel)
|
||||
case "info":
|
||||
|
@ -344,7 +344,11 @@ func (p *OAuthProxy) AuthenticateOnly(rw http.ResponseWriter, req *http.Request)
|
||||
}
|
||||
if _, ok := req.URL.Query()["traefik"]; ok {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ func (s *Server) handler(w http.ResponseWriter, r *http.Request) {
|
||||
for k := range s.Handlers {
|
||||
hostKeys = append(hostKeys, k)
|
||||
}
|
||||
s.logger.WithField("host", host).WithField("known-hosts", strings.Join(hostKeys, ", ")).Debug("Host header does not match any we know of")
|
||||
s.logger.WithField("host", host).WithField("known-hosts", strings.Join(hostKeys, ",")).Debug("Host header does not match any we know of")
|
||||
w.WriteHeader(404)
|
||||
return
|
||||
}
|
||||
|
@ -1,12 +1,20 @@
|
||||
package proxy
|
||||
|
||||
import "net/http"
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var xForwardedHost = http.CanonicalHeaderKey("X-Forwarded-Host")
|
||||
|
||||
func getHost(req *http.Request) string {
|
||||
host := req.Host
|
||||
if req.Header.Get(xForwardedHost) != "" {
|
||||
return req.Header.Get(xForwardedHost)
|
||||
host = req.Header.Get(xForwardedHost)
|
||||
}
|
||||
return req.Host
|
||||
hostOnly, _, err := net.SplitHostPort(host)
|
||||
if err != nil {
|
||||
return host
|
||||
}
|
||||
return hostOnly
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
package pkg
|
||||
|
||||
const VERSION = "2021.5.1-rc3"
|
||||
const VERSION = "2021.5.1-rc8"
|
||||
|
263
swagger.yaml
263
swagger.yaml
@ -531,11 +531,6 @@ paths:
|
||||
description: ''
|
||||
required: false
|
||||
type: string
|
||||
- name: ordering
|
||||
in: query
|
||||
description: Which field to use when ordering the results.
|
||||
required: false
|
||||
type: string
|
||||
- name: search
|
||||
in: query
|
||||
description: A search term.
|
||||
@ -2532,7 +2527,10 @@ paths:
|
||||
get:
|
||||
operationId: crypto_certificatekeypairs_view_certificate
|
||||
description: Return certificate-key pairs certificate and log access
|
||||
parameters: []
|
||||
parameters:
|
||||
- name: download
|
||||
in: query
|
||||
type: boolean
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
@ -2560,7 +2558,10 @@ paths:
|
||||
get:
|
||||
operationId: crypto_certificatekeypairs_view_private_key
|
||||
description: Return certificate-key pairs private key and log access
|
||||
parameters: []
|
||||
parameters:
|
||||
- name: download
|
||||
in: query
|
||||
type: boolean
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
@ -9701,7 +9702,10 @@ paths:
|
||||
get:
|
||||
operationId: providers_saml_metadata
|
||||
description: Return metadata as XML string
|
||||
parameters: []
|
||||
parameters:
|
||||
- name: download
|
||||
in: query
|
||||
type: boolean
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
@ -16203,7 +16207,7 @@ definitions:
|
||||
required:
|
||||
- name
|
||||
- providers
|
||||
- _config
|
||||
- config
|
||||
type: object
|
||||
properties:
|
||||
pk:
|
||||
@ -16242,8 +16246,8 @@ definitions:
|
||||
title: Token identifier
|
||||
type: string
|
||||
readOnly: true
|
||||
_config:
|
||||
title: config
|
||||
config:
|
||||
title: Config
|
||||
type: object
|
||||
OutpostDefaultConfig:
|
||||
type: object
|
||||
@ -17494,6 +17498,11 @@ definitions:
|
||||
description: Enable support for forwardAuth in traefik and nginx auth_request.
|
||||
Exclusive with internal_host.
|
||||
type: boolean
|
||||
redirect_uris:
|
||||
title: Redirect uris
|
||||
type: string
|
||||
readOnly: true
|
||||
minLength: 1
|
||||
SAMLProvider:
|
||||
required:
|
||||
- name
|
||||
@ -18878,237 +18887,7 @@ definitions:
|
||||
title: Fixed data
|
||||
type: object
|
||||
created_by:
|
||||
required:
|
||||
- password
|
||||
- username
|
||||
- name
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
title: ID
|
||||
type: integer
|
||||
readOnly: true
|
||||
password:
|
||||
title: Password
|
||||
type: string
|
||||
maxLength: 128
|
||||
minLength: 1
|
||||
last_login:
|
||||
title: Last login
|
||||
type: string
|
||||
format: date-time
|
||||
x-nullable: true
|
||||
username:
|
||||
title: Username
|
||||
description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_
|
||||
only.
|
||||
type: string
|
||||
pattern: ^[\w.@+-]+$
|
||||
maxLength: 150
|
||||
minLength: 1
|
||||
first_name:
|
||||
title: First name
|
||||
type: string
|
||||
maxLength: 150
|
||||
last_name:
|
||||
title: Last name
|
||||
type: string
|
||||
maxLength: 150
|
||||
email:
|
||||
title: Email address
|
||||
type: string
|
||||
format: email
|
||||
maxLength: 254
|
||||
is_active:
|
||||
title: Active
|
||||
description: Designates whether this user should be treated as active.
|
||||
Unselect this instead of deleting accounts.
|
||||
type: boolean
|
||||
date_joined:
|
||||
title: Date joined
|
||||
type: string
|
||||
format: date-time
|
||||
uuid:
|
||||
title: Uuid
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
name:
|
||||
title: Name
|
||||
description: User's display name.
|
||||
type: string
|
||||
minLength: 1
|
||||
password_change_date:
|
||||
title: Password change date
|
||||
type: string
|
||||
format: date-time
|
||||
readOnly: true
|
||||
attributes:
|
||||
title: Attributes
|
||||
type: object
|
||||
groups:
|
||||
type: array
|
||||
items:
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
title: ID
|
||||
type: integer
|
||||
readOnly: true
|
||||
name:
|
||||
title: Name
|
||||
type: string
|
||||
maxLength: 150
|
||||
minLength: 1
|
||||
permissions:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
uniqueItems: true
|
||||
readOnly: true
|
||||
user_permissions:
|
||||
type: array
|
||||
items:
|
||||
required:
|
||||
- name
|
||||
- codename
|
||||
- content_type
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
title: ID
|
||||
type: integer
|
||||
readOnly: true
|
||||
name:
|
||||
title: Name
|
||||
type: string
|
||||
maxLength: 255
|
||||
minLength: 1
|
||||
codename:
|
||||
title: Codename
|
||||
type: string
|
||||
maxLength: 100
|
||||
minLength: 1
|
||||
content_type:
|
||||
title: Content type
|
||||
type: integer
|
||||
readOnly: true
|
||||
sources:
|
||||
type: array
|
||||
items:
|
||||
required:
|
||||
- name
|
||||
- slug
|
||||
type: object
|
||||
properties:
|
||||
pbm_uuid:
|
||||
title: Pbm uuid
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
policy_engine_mode:
|
||||
title: Policy engine mode
|
||||
type: string
|
||||
enum:
|
||||
- all
|
||||
- any
|
||||
managed:
|
||||
title: Managed by authentik
|
||||
description: Objects which are managed by authentik. These objects
|
||||
are created and updated automatically. This is flag only indicates
|
||||
that an object can be overwritten by migrations. You can still
|
||||
modify the objects via the API, but expect changes to be overwritten
|
||||
in a later update.
|
||||
type: string
|
||||
minLength: 1
|
||||
x-nullable: true
|
||||
name:
|
||||
title: Name
|
||||
description: Source's display Name.
|
||||
type: string
|
||||
minLength: 1
|
||||
slug:
|
||||
title: Slug
|
||||
description: Internal source name, used in URLs.
|
||||
type: string
|
||||
format: slug
|
||||
pattern: ^[-a-zA-Z0-9_]+$
|
||||
maxLength: 50
|
||||
minLength: 1
|
||||
enabled:
|
||||
title: Enabled
|
||||
type: boolean
|
||||
user_matching_mode:
|
||||
title: User matching mode
|
||||
description: How the source determines if an existing user should
|
||||
be authenticated or a new user enrolled.
|
||||
type: string
|
||||
enum:
|
||||
- identifier
|
||||
- email_link
|
||||
- email_deny
|
||||
- username_link
|
||||
- username_deny
|
||||
authentication_flow:
|
||||
title: Authentication flow
|
||||
description: Flow to use when authenticating existing users.
|
||||
type: string
|
||||
format: uuid
|
||||
x-nullable: true
|
||||
enrollment_flow:
|
||||
title: Enrollment flow
|
||||
description: Flow to use when enrolling new users.
|
||||
type: string
|
||||
format: uuid
|
||||
x-nullable: true
|
||||
policies:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
uniqueItems: true
|
||||
property_mappings:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: uuid
|
||||
uniqueItems: true
|
||||
readOnly: true
|
||||
ak_groups:
|
||||
type: array
|
||||
items:
|
||||
required:
|
||||
- name
|
||||
- parent
|
||||
type: object
|
||||
properties:
|
||||
group_uuid:
|
||||
title: Group uuid
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
name:
|
||||
title: Name
|
||||
type: string
|
||||
maxLength: 80
|
||||
minLength: 1
|
||||
is_superuser:
|
||||
title: Is superuser
|
||||
description: Users added to this group will be superusers.
|
||||
type: boolean
|
||||
attributes:
|
||||
title: Attributes
|
||||
type: object
|
||||
parent:
|
||||
title: Parent
|
||||
type: string
|
||||
format: uuid
|
||||
x-nullable: true
|
||||
readOnly: true
|
||||
readOnly: true
|
||||
$ref: '#/definitions/User'
|
||||
single_use:
|
||||
title: Single use
|
||||
description: When enabled, the invitation will be deleted after usage.
|
||||
|
@ -81,7 +81,7 @@ http {
|
||||
location /static/ {
|
||||
expires 31d;
|
||||
add_header Cache-Control "public, no-transform";
|
||||
add_header X-authentik-version "2021.5.1-rc3";
|
||||
add_header X-authentik-version "2021.5.1-rc8";
|
||||
add_header Vary X-authentik-version;
|
||||
}
|
||||
|
||||
|
485
web/package-lock.json
generated
485
web/package-lock.json
generated
@ -24,13 +24,13 @@
|
||||
"@rollup/plugin-babel": "^5.3.0",
|
||||
"@rollup/plugin-replace": "^2.4.2",
|
||||
"@rollup/plugin-typescript": "^8.2.1",
|
||||
"@sentry/browser": "^6.3.5",
|
||||
"@sentry/tracing": "^6.3.5",
|
||||
"@sentry/browser": "^6.3.6",
|
||||
"@sentry/tracing": "^6.3.6",
|
||||
"@types/chart.js": "^2.9.32",
|
||||
"@types/codemirror": "5.60.0",
|
||||
"@types/grecaptcha": "^3.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^4.22.1",
|
||||
"@typescript-eslint/parser": "^4.22.1",
|
||||
"@typescript-eslint/eslint-plugin": "^4.23.0",
|
||||
"@typescript-eslint/parser": "^4.23.0",
|
||||
"@webcomponents/webcomponentsjs": "^2.5.0",
|
||||
"authentik-api": "file:api",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
@ -39,10 +39,10 @@
|
||||
"chartjs-adapter-moment": "^1.0.0",
|
||||
"codemirror": "^5.61.0",
|
||||
"construct-style-sheets-polyfill": "^2.4.16",
|
||||
"eslint": "^7.25.0",
|
||||
"eslint": "^7.26.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-custom-elements": "0.0.2",
|
||||
"eslint-plugin-lit": "^1.3.0",
|
||||
"eslint-plugin-lit": "^1.4.0",
|
||||
"flowchart.js": "^1.15.0",
|
||||
"lit-element": "^2.5.1",
|
||||
"lit-html": "^1.4.1",
|
||||
@ -61,13 +61,12 @@
|
||||
"typescript": "^4.2.4",
|
||||
"webcomponent-qr-code": "^1.0.5",
|
||||
"yaml": "^1.10.2"
|
||||
},
|
||||
"devDependencies": {}
|
||||
}
|
||||
},
|
||||
"api": {
|
||||
"name": "authentik-api",
|
||||
"version": "1.0.0",
|
||||
"devDependencies": {
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"typescript": "^3.6"
|
||||
}
|
||||
},
|
||||
@ -75,7 +74,6 @@
|
||||
"version": "3.9.9",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz",
|
||||
"integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@ -1725,9 +1723,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz",
|
||||
"integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==",
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz",
|
||||
"integrity": "sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==",
|
||||
"dependencies": {
|
||||
"ajv": "^6.12.4",
|
||||
"debug": "^4.1.1",
|
||||
@ -1752,6 +1750,9 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/ignore": {
|
||||
@ -2337,33 +2338,13 @@
|
||||
"integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg=="
|
||||
},
|
||||
"node_modules/@sentry/browser": {
|
||||
"version": "6.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.3.5.tgz",
|
||||
"integrity": "sha512-fjkhPR5gLCGVWhbWjEoN64hnmTvfTLRCgWmYTc9SiGchWFoFEmLqZyF2uJFyt27+qamLQ9fN58nnv4Ly2yyxqg==",
|
||||
"version": "6.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.3.6.tgz",
|
||||
"integrity": "sha512-l4323jxuBOArki6Wf+EHes39IEyJ2Zj/CIUaTY7GWh7CntpfHQAfFmZWQw3Ozq+ka1u8lVp25RPhb4Wng3azNA==",
|
||||
"dependencies": {
|
||||
"@sentry/core": "6.3.5",
|
||||
"@sentry/types": "6.3.5",
|
||||
"@sentry/utils": "6.3.5",
|
||||
"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",
|
||||
"@sentry/core": "6.3.6",
|
||||
"@sentry/types": "6.3.6",
|
||||
"@sentry/utils": "6.3.6",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -2376,60 +2357,14 @@
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/core": {
|
||||
"version": "6.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.3.5.tgz",
|
||||
"integrity": "sha512-VR2ibDy33mryD0mT6d9fGhKjdNzS2FSwwZPe9GvmNOjkyjly/oV91BKVoYJneCqOeq8fyj2lvkJGKuupdJNDqg==",
|
||||
"version": "6.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.3.6.tgz",
|
||||
"integrity": "sha512-w6BRizAqh7BaiM9oeKzO6aACXwRijUPacYaVLX/OfhqCSueF9uDxpMRT7+4D/eCeDVqgJYhBJ4Vsu2NSstkk4A==",
|
||||
"dependencies": {
|
||||
"@sentry/hub": "6.3.5",
|
||||
"@sentry/minimal": "6.3.5",
|
||||
"@sentry/types": "6.3.5",
|
||||
"@sentry/utils": "6.3.5",
|
||||
"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",
|
||||
"@sentry/hub": "6.3.6",
|
||||
"@sentry/minimal": "6.3.6",
|
||||
"@sentry/types": "6.3.6",
|
||||
"@sentry/utils": "6.3.6",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -2442,12 +2377,12 @@
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"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==",
|
||||
"version": "6.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.3.6.tgz",
|
||||
"integrity": "sha512-foBZ3ilMnm9Gf9OolrAxYHK8jrA6IF72faDdJ3Al+1H27qcpnBaMdrdEp2/jzwu/dgmwuLmbBaMjEPXaGH/0JQ==",
|
||||
"dependencies": {
|
||||
"@sentry/types": "6.3.5",
|
||||
"@sentry/utils": "6.3.5",
|
||||
"@sentry/types": "6.3.6",
|
||||
"@sentry/utils": "6.3.6",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -2460,12 +2395,12 @@
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"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==",
|
||||
"version": "6.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.3.6.tgz",
|
||||
"integrity": "sha512-uM2/dH0a6zfvI5f+vg+/mST+uTBdN6Jgpm585ipH84ckCYQwIIDRg6daqsen4S1sy/xgg1P1YyC3zdEC4G6b1Q==",
|
||||
"dependencies": {
|
||||
"@sentry/hub": "6.3.5",
|
||||
"@sentry/types": "6.3.5",
|
||||
"@sentry/hub": "6.3.6",
|
||||
"@sentry/types": "6.3.6",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -2478,14 +2413,14 @@
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/tracing": {
|
||||
"version": "6.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.3.5.tgz",
|
||||
"integrity": "sha512-TNKAST1ge2g24BlTfVxNp4gP5t3drbi0OVCh8h8ah+J7UjHSfdiqhd9W2h5qv1GO61gGlpWeN/TyioyQmOxu0Q==",
|
||||
"version": "6.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.3.6.tgz",
|
||||
"integrity": "sha512-dfyYY2eESJGt5Qbigmfmb2U9ntqbwPhLNAOcjKaVg9WQRV5q2RkHCVctPoYk7TEAvfNeNRXCD8SnuFOZhttt8g==",
|
||||
"dependencies": {
|
||||
"@sentry/hub": "6.3.5",
|
||||
"@sentry/minimal": "6.3.5",
|
||||
"@sentry/types": "6.3.5",
|
||||
"@sentry/utils": "6.3.5",
|
||||
"@sentry/hub": "6.3.6",
|
||||
"@sentry/minimal": "6.3.6",
|
||||
"@sentry/types": "6.3.6",
|
||||
"@sentry/utils": "6.3.6",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -2498,19 +2433,19 @@
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"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==",
|
||||
"version": "6.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.3.6.tgz",
|
||||
"integrity": "sha512-93cFJdJkWyCfyZeWFARSU11qnoHVOS/R2h5WIsEf+jbQmkqG2C+TXVz/19s6nHVsfDrwpvYpwALPv4/nrxfU7g==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "6.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.3.6.tgz",
|
||||
"integrity": "sha512-HnYlDBf8Dq8MEv7AulH7B6R1D/2LAooVclGdjg48tSrr9g+31kmtj+SAj2WWVHP9+bp29BWaC7i5nkfKrOibWw==",
|
||||
"dependencies": {
|
||||
"@sentry/types": "6.3.5",
|
||||
"@sentry/types": "6.3.6",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -2668,12 +2603,12 @@
|
||||
"integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA=="
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "4.22.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.22.1.tgz",
|
||||
"integrity": "sha512-kVTAghWDDhsvQ602tHBc6WmQkdaYbkcTwZu+7l24jtJiYvm9l+/y/b2BZANEezxPDiX5MK2ZecE+9BFi/YJryw==",
|
||||
"version": "4.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.23.0.tgz",
|
||||
"integrity": "sha512-tGK1y3KIvdsQEEgq6xNn1DjiFJtl+wn8JJQiETtCbdQxw1vzjXyAaIkEmO2l6Nq24iy3uZBMFQjZ6ECf1QdgGw==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/experimental-utils": "4.22.1",
|
||||
"@typescript-eslint/scope-manager": "4.22.1",
|
||||
"@typescript-eslint/experimental-utils": "4.23.0",
|
||||
"@typescript-eslint/scope-manager": "4.23.0",
|
||||
"debug": "^4.1.1",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"lodash": "^4.17.15",
|
||||
@ -2699,14 +2634,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/experimental-utils": {
|
||||
"version": "4.22.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.1.tgz",
|
||||
"integrity": "sha512-svYlHecSMCQGDO2qN1v477ax/IDQwWhc7PRBiwAdAMJE7GXk5stF4Z9R/8wbRkuX/5e9dHqbIWxjeOjckK3wLQ==",
|
||||
"version": "4.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.23.0.tgz",
|
||||
"integrity": "sha512-WAFNiTDnQfrF3Z2fQ05nmCgPsO5o790vOhmWKXbbYQTO9erE1/YsFot5/LnOUizLzU2eeuz6+U/81KV5/hFTGA==",
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.3",
|
||||
"@typescript-eslint/scope-manager": "4.22.1",
|
||||
"@typescript-eslint/types": "4.22.1",
|
||||
"@typescript-eslint/typescript-estree": "4.22.1",
|
||||
"@typescript-eslint/scope-manager": "4.23.0",
|
||||
"@typescript-eslint/types": "4.23.0",
|
||||
"@typescript-eslint/typescript-estree": "4.23.0",
|
||||
"eslint-scope": "^5.0.0",
|
||||
"eslint-utils": "^2.0.0"
|
||||
},
|
||||
@ -2722,13 +2657,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "4.22.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.22.1.tgz",
|
||||
"integrity": "sha512-l+sUJFInWhuMxA6rtirzjooh8cM/AATAe3amvIkqKFeMzkn85V+eLzb1RyuXkHak4dLfYzOmF6DXPyflJvjQnw==",
|
||||
"version": "4.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.23.0.tgz",
|
||||
"integrity": "sha512-wsvjksHBMOqySy/Pi2Q6UuIuHYbgAMwLczRl4YanEPKW5KVxI9ZzDYh3B5DtcZPQTGRWFJrfcbJ6L01Leybwug==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "4.22.1",
|
||||
"@typescript-eslint/types": "4.22.1",
|
||||
"@typescript-eslint/typescript-estree": "4.22.1",
|
||||
"@typescript-eslint/scope-manager": "4.23.0",
|
||||
"@typescript-eslint/types": "4.23.0",
|
||||
"@typescript-eslint/typescript-estree": "4.23.0",
|
||||
"debug": "^4.1.1"
|
||||
},
|
||||
"engines": {
|
||||
@ -2748,12 +2683,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "4.22.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.22.1.tgz",
|
||||
"integrity": "sha512-d5bAiPBiessSmNi8Amq/RuLslvcumxLmyhf1/Xa9IuaoFJ0YtshlJKxhlbY7l2JdEk3wS0EnmnfeJWSvADOe0g==",
|
||||
"version": "4.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.23.0.tgz",
|
||||
"integrity": "sha512-ZZ21PCFxPhI3n0wuqEJK9omkw51wi2bmeKJvlRZPH5YFkcawKOuRMQMnI8mH6Vo0/DoHSeZJnHiIx84LmVQY+w==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "4.22.1",
|
||||
"@typescript-eslint/visitor-keys": "4.22.1"
|
||||
"@typescript-eslint/types": "4.23.0",
|
||||
"@typescript-eslint/visitor-keys": "4.23.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
|
||||
@ -2764,9 +2699,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "4.22.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.22.1.tgz",
|
||||
"integrity": "sha512-2HTkbkdAeI3OOcWbqA8hWf/7z9c6gkmnWNGz0dKSLYLWywUlkOAQ2XcjhlKLj5xBFDf8FgAOF5aQbnLRvgNbCw==",
|
||||
"version": "4.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.23.0.tgz",
|
||||
"integrity": "sha512-oqkNWyG2SLS7uTWLZf6Sr7Dm02gA5yxiz1RP87tvsmDsguVATdpVguHr4HoGOcFOpCvx9vtCSCyQUGfzq28YCw==",
|
||||
"engines": {
|
||||
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
|
||||
},
|
||||
@ -2776,12 +2711,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "4.22.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.1.tgz",
|
||||
"integrity": "sha512-p3We0pAPacT+onSGM+sPR+M9CblVqdA9F1JEdIqRVlxK5Qth4ochXQgIyb9daBomyQKAXbygxp1aXQRV0GC79A==",
|
||||
"version": "4.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.23.0.tgz",
|
||||
"integrity": "sha512-5Sty6zPEVZF5fbvrZczfmLCOcby3sfrSPu30qKoY1U3mca5/jvU5cwsPb/CO6Q3ByRjixTMIVsDkqwIxCf/dMw==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "4.22.1",
|
||||
"@typescript-eslint/visitor-keys": "4.22.1",
|
||||
"@typescript-eslint/types": "4.23.0",
|
||||
"@typescript-eslint/visitor-keys": "4.23.0",
|
||||
"debug": "^4.1.1",
|
||||
"globby": "^11.0.1",
|
||||
"is-glob": "^4.0.1",
|
||||
@ -2821,11 +2756,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "4.22.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.1.tgz",
|
||||
"integrity": "sha512-WPkOrIRm+WCLZxXQHCi+WG8T2MMTUFR70rWjdWYddLT7cEfb2P4a3O/J2U1FBVsSFTocXLCoXWY6MZGejeStvQ==",
|
||||
"version": "4.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.23.0.tgz",
|
||||
"integrity": "sha512-5PNe5cmX9pSifit0H+nPoQBXdbNzi5tOEec+3riK+ku4e3er37pKxMKDH5Ct5Y4fhWxcD4spnlYjxi9vXbSpwg==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "4.22.1",
|
||||
"@typescript-eslint/types": "4.23.0",
|
||||
"eslint-visitor-keys": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -2860,7 +2795,10 @@
|
||||
"node_modules/acorn-jsx": {
|
||||
"version": "5.3.1",
|
||||
"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": {
|
||||
"version": "6.12.6",
|
||||
@ -2871,6 +2809,10 @@
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-colors": {
|
||||
@ -3906,12 +3848,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.25.0.tgz",
|
||||
"integrity": "sha512-TVpSovpvCNpLURIScDRB6g5CYu/ZFq9GfX2hLNIV4dSBKxIWojeDODvYl3t0k0VtMxYeR8OXPCFE5+oHMlGfhw==",
|
||||
"version": "7.26.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.26.0.tgz",
|
||||
"integrity": "sha512-4R1ieRf52/izcZE7AlLy56uIHHDLT74Yzz2Iv2l6kDaYvEu9x+wMB5dZArVL8SYGXSYV2YAg70FcW5Y5nGGNIg==",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "7.12.11",
|
||||
"@eslint/eslintrc": "^0.4.0",
|
||||
"@eslint/eslintrc": "^0.4.1",
|
||||
"ajv": "^6.10.0",
|
||||
"chalk": "^4.0.0",
|
||||
"cross-spawn": "^7.0.2",
|
||||
@ -3953,6 +3895,9 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10.12.0 || >=12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-config-google": {
|
||||
@ -3972,13 +3917,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-lit": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.3.0.tgz",
|
||||
"integrity": "sha512-fy6Lr5vYI3kvCYaDXA20lwyKAp1keS9UjR5ntj8U2TeV+1yUta3S7xxXe+rABKRPbcNzi1ZvQLE1LmNKc9yr4Q==",
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.4.0.tgz",
|
||||
"integrity": "sha512-3PJCC1p4pvDBKtFmg1g2cGzAgJF4IDqhb9NJUh95nYc+QXExa/O/0fILF4WB6X7qdNQKm+gW6nYtSKTyYPHtXw==",
|
||||
"dependencies": {
|
||||
"parse5": "^6.0.1",
|
||||
"parse5-htmlparser2-tree-adapter": "^6.0.1",
|
||||
"requireindex": "^1.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">= 5"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-rule-documentation": {
|
||||
@ -7355,6 +7303,9 @@
|
||||
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
@ -9632,9 +9583,9 @@
|
||||
}
|
||||
},
|
||||
"@eslint/eslintrc": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz",
|
||||
"integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==",
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz",
|
||||
"integrity": "sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==",
|
||||
"requires": {
|
||||
"ajv": "^6.12.4",
|
||||
"debug": "^4.1.1",
|
||||
@ -10146,30 +10097,16 @@
|
||||
}
|
||||
},
|
||||
"@sentry/browser": {
|
||||
"version": "6.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.3.5.tgz",
|
||||
"integrity": "sha512-fjkhPR5gLCGVWhbWjEoN64hnmTvfTLRCgWmYTc9SiGchWFoFEmLqZyF2uJFyt27+qamLQ9fN58nnv4Ly2yyxqg==",
|
||||
"version": "6.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.3.6.tgz",
|
||||
"integrity": "sha512-l4323jxuBOArki6Wf+EHes39IEyJ2Zj/CIUaTY7GWh7CntpfHQAfFmZWQw3Ozq+ka1u8lVp25RPhb4Wng3azNA==",
|
||||
"requires": {
|
||||
"@sentry/core": "6.3.5",
|
||||
"@sentry/types": "6.3.5",
|
||||
"@sentry/utils": "6.3.5",
|
||||
"@sentry/core": "6.3.6",
|
||||
"@sentry/types": "6.3.6",
|
||||
"@sentry/utils": "6.3.6",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"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": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
@ -10178,51 +10115,17 @@
|
||||
}
|
||||
},
|
||||
"@sentry/core": {
|
||||
"version": "6.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.3.5.tgz",
|
||||
"integrity": "sha512-VR2ibDy33mryD0mT6d9fGhKjdNzS2FSwwZPe9GvmNOjkyjly/oV91BKVoYJneCqOeq8fyj2lvkJGKuupdJNDqg==",
|
||||
"version": "6.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.3.6.tgz",
|
||||
"integrity": "sha512-w6BRizAqh7BaiM9oeKzO6aACXwRijUPacYaVLX/OfhqCSueF9uDxpMRT7+4D/eCeDVqgJYhBJ4Vsu2NSstkk4A==",
|
||||
"requires": {
|
||||
"@sentry/hub": "6.3.5",
|
||||
"@sentry/minimal": "6.3.5",
|
||||
"@sentry/types": "6.3.5",
|
||||
"@sentry/utils": "6.3.5",
|
||||
"@sentry/hub": "6.3.6",
|
||||
"@sentry/minimal": "6.3.6",
|
||||
"@sentry/types": "6.3.6",
|
||||
"@sentry/utils": "6.3.6",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"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": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
@ -10231,12 +10134,12 @@
|
||||
}
|
||||
},
|
||||
"@sentry/hub": {
|
||||
"version": "6.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.3.5.tgz",
|
||||
"integrity": "sha512-ZYFo7VYKwdPVjuV9BDFiYn+MpANn6eZMz5QDBfZ2dugIvIVbuOyOOLx8PSa3ZXJoVTZZ7s2wD2fi/ZxKjNjZOQ==",
|
||||
"version": "6.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.3.6.tgz",
|
||||
"integrity": "sha512-foBZ3ilMnm9Gf9OolrAxYHK8jrA6IF72faDdJ3Al+1H27qcpnBaMdrdEp2/jzwu/dgmwuLmbBaMjEPXaGH/0JQ==",
|
||||
"requires": {
|
||||
"@sentry/types": "6.3.5",
|
||||
"@sentry/utils": "6.3.5",
|
||||
"@sentry/types": "6.3.6",
|
||||
"@sentry/utils": "6.3.6",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -10248,12 +10151,12 @@
|
||||
}
|
||||
},
|
||||
"@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==",
|
||||
"version": "6.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.3.6.tgz",
|
||||
"integrity": "sha512-uM2/dH0a6zfvI5f+vg+/mST+uTBdN6Jgpm585ipH84ckCYQwIIDRg6daqsen4S1sy/xgg1P1YyC3zdEC4G6b1Q==",
|
||||
"requires": {
|
||||
"@sentry/hub": "6.3.5",
|
||||
"@sentry/types": "6.3.5",
|
||||
"@sentry/hub": "6.3.6",
|
||||
"@sentry/types": "6.3.6",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -10265,14 +10168,14 @@
|
||||
}
|
||||
},
|
||||
"@sentry/tracing": {
|
||||
"version": "6.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.3.5.tgz",
|
||||
"integrity": "sha512-TNKAST1ge2g24BlTfVxNp4gP5t3drbi0OVCh8h8ah+J7UjHSfdiqhd9W2h5qv1GO61gGlpWeN/TyioyQmOxu0Q==",
|
||||
"version": "6.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.3.6.tgz",
|
||||
"integrity": "sha512-dfyYY2eESJGt5Qbigmfmb2U9ntqbwPhLNAOcjKaVg9WQRV5q2RkHCVctPoYk7TEAvfNeNRXCD8SnuFOZhttt8g==",
|
||||
"requires": {
|
||||
"@sentry/hub": "6.3.5",
|
||||
"@sentry/minimal": "6.3.5",
|
||||
"@sentry/types": "6.3.5",
|
||||
"@sentry/utils": "6.3.5",
|
||||
"@sentry/hub": "6.3.6",
|
||||
"@sentry/minimal": "6.3.6",
|
||||
"@sentry/types": "6.3.6",
|
||||
"@sentry/utils": "6.3.6",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -10284,16 +10187,16 @@
|
||||
}
|
||||
},
|
||||
"@sentry/types": {
|
||||
"version": "6.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.3.5.tgz",
|
||||
"integrity": "sha512-tY/3pkAmGYJ3F0BtwInsdt/uclNvF8aNG7XHsTPQNzk7BkNVWjCXx0sjxi6CILirl5nwNxYxVeTr2ZYAEZ/dSQ=="
|
||||
"version": "6.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.3.6.tgz",
|
||||
"integrity": "sha512-93cFJdJkWyCfyZeWFARSU11qnoHVOS/R2h5WIsEf+jbQmkqG2C+TXVz/19s6nHVsfDrwpvYpwALPv4/nrxfU7g=="
|
||||
},
|
||||
"@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==",
|
||||
"version": "6.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.3.6.tgz",
|
||||
"integrity": "sha512-HnYlDBf8Dq8MEv7AulH7B6R1D/2LAooVclGdjg48tSrr9g+31kmtj+SAj2WWVHP9+bp29BWaC7i5nkfKrOibWw==",
|
||||
"requires": {
|
||||
"@sentry/types": "6.3.5",
|
||||
"@sentry/types": "6.3.6",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -10450,12 +10353,12 @@
|
||||
"integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA=="
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "4.22.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.22.1.tgz",
|
||||
"integrity": "sha512-kVTAghWDDhsvQ602tHBc6WmQkdaYbkcTwZu+7l24jtJiYvm9l+/y/b2BZANEezxPDiX5MK2ZecE+9BFi/YJryw==",
|
||||
"version": "4.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.23.0.tgz",
|
||||
"integrity": "sha512-tGK1y3KIvdsQEEgq6xNn1DjiFJtl+wn8JJQiETtCbdQxw1vzjXyAaIkEmO2l6Nq24iy3uZBMFQjZ6ECf1QdgGw==",
|
||||
"requires": {
|
||||
"@typescript-eslint/experimental-utils": "4.22.1",
|
||||
"@typescript-eslint/scope-manager": "4.22.1",
|
||||
"@typescript-eslint/experimental-utils": "4.23.0",
|
||||
"@typescript-eslint/scope-manager": "4.23.0",
|
||||
"debug": "^4.1.1",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"lodash": "^4.17.15",
|
||||
@ -10465,50 +10368,50 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/experimental-utils": {
|
||||
"version": "4.22.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.1.tgz",
|
||||
"integrity": "sha512-svYlHecSMCQGDO2qN1v477ax/IDQwWhc7PRBiwAdAMJE7GXk5stF4Z9R/8wbRkuX/5e9dHqbIWxjeOjckK3wLQ==",
|
||||
"version": "4.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.23.0.tgz",
|
||||
"integrity": "sha512-WAFNiTDnQfrF3Z2fQ05nmCgPsO5o790vOhmWKXbbYQTO9erE1/YsFot5/LnOUizLzU2eeuz6+U/81KV5/hFTGA==",
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.3",
|
||||
"@typescript-eslint/scope-manager": "4.22.1",
|
||||
"@typescript-eslint/types": "4.22.1",
|
||||
"@typescript-eslint/typescript-estree": "4.22.1",
|
||||
"@typescript-eslint/scope-manager": "4.23.0",
|
||||
"@typescript-eslint/types": "4.23.0",
|
||||
"@typescript-eslint/typescript-estree": "4.23.0",
|
||||
"eslint-scope": "^5.0.0",
|
||||
"eslint-utils": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "4.22.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.22.1.tgz",
|
||||
"integrity": "sha512-l+sUJFInWhuMxA6rtirzjooh8cM/AATAe3amvIkqKFeMzkn85V+eLzb1RyuXkHak4dLfYzOmF6DXPyflJvjQnw==",
|
||||
"version": "4.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.23.0.tgz",
|
||||
"integrity": "sha512-wsvjksHBMOqySy/Pi2Q6UuIuHYbgAMwLczRl4YanEPKW5KVxI9ZzDYh3B5DtcZPQTGRWFJrfcbJ6L01Leybwug==",
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "4.22.1",
|
||||
"@typescript-eslint/types": "4.22.1",
|
||||
"@typescript-eslint/typescript-estree": "4.22.1",
|
||||
"@typescript-eslint/scope-manager": "4.23.0",
|
||||
"@typescript-eslint/types": "4.23.0",
|
||||
"@typescript-eslint/typescript-estree": "4.23.0",
|
||||
"debug": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "4.22.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.22.1.tgz",
|
||||
"integrity": "sha512-d5bAiPBiessSmNi8Amq/RuLslvcumxLmyhf1/Xa9IuaoFJ0YtshlJKxhlbY7l2JdEk3wS0EnmnfeJWSvADOe0g==",
|
||||
"version": "4.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.23.0.tgz",
|
||||
"integrity": "sha512-ZZ21PCFxPhI3n0wuqEJK9omkw51wi2bmeKJvlRZPH5YFkcawKOuRMQMnI8mH6Vo0/DoHSeZJnHiIx84LmVQY+w==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "4.22.1",
|
||||
"@typescript-eslint/visitor-keys": "4.22.1"
|
||||
"@typescript-eslint/types": "4.23.0",
|
||||
"@typescript-eslint/visitor-keys": "4.23.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "4.22.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.22.1.tgz",
|
||||
"integrity": "sha512-2HTkbkdAeI3OOcWbqA8hWf/7z9c6gkmnWNGz0dKSLYLWywUlkOAQ2XcjhlKLj5xBFDf8FgAOF5aQbnLRvgNbCw=="
|
||||
"version": "4.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.23.0.tgz",
|
||||
"integrity": "sha512-oqkNWyG2SLS7uTWLZf6Sr7Dm02gA5yxiz1RP87tvsmDsguVATdpVguHr4HoGOcFOpCvx9vtCSCyQUGfzq28YCw=="
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "4.22.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.1.tgz",
|
||||
"integrity": "sha512-p3We0pAPacT+onSGM+sPR+M9CblVqdA9F1JEdIqRVlxK5Qth4ochXQgIyb9daBomyQKAXbygxp1aXQRV0GC79A==",
|
||||
"version": "4.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.23.0.tgz",
|
||||
"integrity": "sha512-5Sty6zPEVZF5fbvrZczfmLCOcby3sfrSPu30qKoY1U3mca5/jvU5cwsPb/CO6Q3ByRjixTMIVsDkqwIxCf/dMw==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "4.22.1",
|
||||
"@typescript-eslint/visitor-keys": "4.22.1",
|
||||
"@typescript-eslint/types": "4.23.0",
|
||||
"@typescript-eslint/visitor-keys": "4.23.0",
|
||||
"debug": "^4.1.1",
|
||||
"globby": "^11.0.1",
|
||||
"is-glob": "^4.0.1",
|
||||
@ -10532,11 +10435,11 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "4.22.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.1.tgz",
|
||||
"integrity": "sha512-WPkOrIRm+WCLZxXQHCi+WG8T2MMTUFR70rWjdWYddLT7cEfb2P4a3O/J2U1FBVsSFTocXLCoXWY6MZGejeStvQ==",
|
||||
"version": "4.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.23.0.tgz",
|
||||
"integrity": "sha512-5PNe5cmX9pSifit0H+nPoQBXdbNzi5tOEec+3riK+ku4e3er37pKxMKDH5Ct5Y4fhWxcD4spnlYjxi9vXbSpwg==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "4.22.1",
|
||||
"@typescript-eslint/types": "4.23.0",
|
||||
"eslint-visitor-keys": "^2.0.0"
|
||||
}
|
||||
},
|
||||
@ -10558,7 +10461,8 @@
|
||||
"acorn-jsx": {
|
||||
"version": "5.3.1",
|
||||
"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": {
|
||||
"version": "6.12.6",
|
||||
@ -10685,8 +10589,7 @@
|
||||
"typescript": {
|
||||
"version": "3.9.9",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz",
|
||||
"integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -11415,12 +11318,12 @@
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
},
|
||||
"eslint": {
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.25.0.tgz",
|
||||
"integrity": "sha512-TVpSovpvCNpLURIScDRB6g5CYu/ZFq9GfX2hLNIV4dSBKxIWojeDODvYl3t0k0VtMxYeR8OXPCFE5+oHMlGfhw==",
|
||||
"version": "7.26.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.26.0.tgz",
|
||||
"integrity": "sha512-4R1ieRf52/izcZE7AlLy56uIHHDLT74Yzz2Iv2l6kDaYvEu9x+wMB5dZArVL8SYGXSYV2YAg70FcW5Y5nGGNIg==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "7.12.11",
|
||||
"@eslint/eslintrc": "^0.4.0",
|
||||
"@eslint/eslintrc": "^0.4.1",
|
||||
"ajv": "^6.10.0",
|
||||
"chalk": "^4.0.0",
|
||||
"cross-spawn": "^7.0.2",
|
||||
@ -11535,9 +11438,9 @@
|
||||
}
|
||||
},
|
||||
"eslint-plugin-lit": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.3.0.tgz",
|
||||
"integrity": "sha512-fy6Lr5vYI3kvCYaDXA20lwyKAp1keS9UjR5ntj8U2TeV+1yUta3S7xxXe+rABKRPbcNzi1ZvQLE1LmNKc9yr4Q==",
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.4.0.tgz",
|
||||
"integrity": "sha512-3PJCC1p4pvDBKtFmg1g2cGzAgJF4IDqhb9NJUh95nYc+QXExa/O/0fILF4WB6X7qdNQKm+gW6nYtSKTyYPHtXw==",
|
||||
"requires": {
|
||||
"parse5": "^6.0.1",
|
||||
"parse5-htmlparser2-tree-adapter": "^6.0.1",
|
||||
|
@ -50,13 +50,13 @@
|
||||
"@rollup/plugin-babel": "^5.3.0",
|
||||
"@rollup/plugin-replace": "^2.4.2",
|
||||
"@rollup/plugin-typescript": "^8.2.1",
|
||||
"@sentry/browser": "^6.3.5",
|
||||
"@sentry/tracing": "^6.3.5",
|
||||
"@sentry/browser": "^6.3.6",
|
||||
"@sentry/tracing": "^6.3.6",
|
||||
"@types/chart.js": "^2.9.32",
|
||||
"@types/codemirror": "5.60.0",
|
||||
"@types/grecaptcha": "^3.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^4.22.1",
|
||||
"@typescript-eslint/parser": "^4.22.1",
|
||||
"@typescript-eslint/eslint-plugin": "^4.23.0",
|
||||
"@typescript-eslint/parser": "^4.23.0",
|
||||
"@webcomponents/webcomponentsjs": "^2.5.0",
|
||||
"authentik-api": "file:api",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
@ -65,10 +65,10 @@
|
||||
"chartjs-adapter-moment": "^1.0.0",
|
||||
"codemirror": "^5.61.0",
|
||||
"construct-style-sheets-polyfill": "^2.4.16",
|
||||
"eslint": "^7.25.0",
|
||||
"eslint": "^7.26.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-custom-elements": "0.0.2",
|
||||
"eslint-plugin-lit": "^1.3.0",
|
||||
"eslint-plugin-lit": "^1.4.0",
|
||||
"flowchart.js": "^1.15.0",
|
||||
"lit-element": "^2.5.1",
|
||||
"lit-html": "^1.4.1",
|
||||
|
@ -204,6 +204,9 @@ body {
|
||||
.pf-c-form__field-group-header-title-text {
|
||||
color: var(--ak-dark-foreground);
|
||||
}
|
||||
.pf-c-form__field-group {
|
||||
border-bottom: 0;
|
||||
}
|
||||
/* inputs */
|
||||
optgroup, option {
|
||||
color: var(--ak-dark-foreground);
|
||||
|
@ -3,7 +3,7 @@ export const SUCCESS_CLASS = "pf-m-success";
|
||||
export const ERROR_CLASS = "pf-m-danger";
|
||||
export const PROGRESS_CLASS = "pf-m-in-progress";
|
||||
export const CURRENT_CLASS = "pf-m-current";
|
||||
export const VERSION = "2021.5.1-rc3";
|
||||
export const VERSION = "2021.5.1-rc8";
|
||||
export const PAGE_SIZE = 20;
|
||||
export const EVENT_REFRESH = "ak-refresh";
|
||||
export const EVENT_NOTIFICATION_TOGGLE = "ak-notification-toggle";
|
||||
|
@ -5,11 +5,6 @@ import { MessageLevel } from "../messages/Message";
|
||||
|
||||
@customElement("ak-action-button")
|
||||
export class ActionButton extends SpinnerButton {
|
||||
@property()
|
||||
url = "";
|
||||
|
||||
@property()
|
||||
method = "POST";
|
||||
|
||||
@property({attribute: false})
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
@ -6,6 +6,7 @@ import { ArcElement, BarElement } from "chart.js";
|
||||
import { TimeScale, LinearScale } from "chart.js";
|
||||
import "chartjs-adapter-moment";
|
||||
import { FONT_COLOUR_DARK_MODE, FONT_COLOUR_LIGHT_MODE } from "../../pages/flows/FlowDiagram";
|
||||
import {EVENT_REFRESH} from "../../constants";
|
||||
|
||||
Chart.register(Legend, Tooltip);
|
||||
Chart.register(LineController, BarController, DoughnutController);
|
||||
@ -43,6 +44,13 @@ export abstract class AKChart<T> extends LitElement {
|
||||
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 handler = (ev?: MediaQueryListEvent) => {
|
||||
if (ev?.matches || matcher.matches) {
|
||||
@ -56,6 +64,22 @@ export abstract class AKChart<T> extends LitElement {
|
||||
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 {
|
||||
return "bar";
|
||||
}
|
||||
@ -129,23 +153,6 @@ export abstract class AKChart<T> extends LitElement {
|
||||
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 {
|
||||
return html`
|
||||
<div class="container">
|
||||
|
@ -15,6 +15,7 @@ import { MessageLevel } from "../messages/Message";
|
||||
import { IronFormElement } from "@polymer/iron-form/iron-form";
|
||||
import { camelToSnake, convertToSlug } from "../../utils";
|
||||
import { ValidationError } from "authentik-api/src";
|
||||
import { EVENT_REFRESH } from "../../constants";
|
||||
|
||||
export class APIError extends Error {
|
||||
|
||||
@ -140,6 +141,12 @@ export class Form<T> extends LitElement {
|
||||
level: MessageLevel.success,
|
||||
message: this.getSuccessMessage()
|
||||
});
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EVENT_REFRESH, {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
})
|
||||
);
|
||||
return r;
|
||||
}).catch((ex: Response) => {
|
||||
if (ex.status > 399 && ex.status < 500) {
|
||||
|
36
web/src/elements/forms/ModelForm.ts
Normal file
36
web/src/elements/forms/ModelForm.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { property } from "lit-element";
|
||||
import { EVENT_REFRESH } from "../../constants";
|
||||
import { Form } from "./Form";
|
||||
|
||||
export abstract class ModelForm<T, PKT extends string | number> extends Form<T> {
|
||||
|
||||
abstract loadInstance(pk: PKT): Promise<T>;
|
||||
|
||||
@property({attribute: false})
|
||||
set instancePk(value: PKT) {
|
||||
this._instancePk = value;
|
||||
this.loadInstance(value).then(instance => {
|
||||
this.instance = instance;
|
||||
});
|
||||
}
|
||||
|
||||
private _instancePk?: PKT;
|
||||
|
||||
@property({ attribute: false })
|
||||
instance?: T = this.defaultInstance;
|
||||
|
||||
get defaultInstance(): T | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.addEventListener(EVENT_REFRESH, () => {
|
||||
if (!this._instancePk) return;
|
||||
this.loadInstance(this._instancePk).then(instance => {
|
||||
this.instance = instance;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,6 @@ import { t } from "@lingui/macro";
|
||||
import { CSSResult, customElement, property } from "lit-element";
|
||||
import { html, TemplateResult } from "lit-html";
|
||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
||||
import { Form } from "../../elements/forms/Form";
|
||||
import { until } from "lit-html/directives/until";
|
||||
import { ifDefined } from "lit-html/directives/if-defined";
|
||||
import "../../elements/buttons/Dropdown";
|
||||
@ -13,18 +12,22 @@ import "../../elements/forms/ModalForm";
|
||||
import "../../elements/forms/HorizontalFormElement";
|
||||
import "../../elements/forms/FormGroup";
|
||||
import PFDropdown from "@patternfly/patternfly/components/Dropdown/dropdown.css";
|
||||
import { ModelForm } from "../../elements/forms/ModelForm";
|
||||
|
||||
@customElement("ak-application-form")
|
||||
export class ApplicationForm extends Form<Application> {
|
||||
export class ApplicationForm extends ModelForm<Application, string> {
|
||||
|
||||
@property({ attribute: false })
|
||||
application?: Application;
|
||||
loadInstance(pk: string): Promise<Application> {
|
||||
return new CoreApi(DEFAULT_CONFIG).coreApplicationsRead({
|
||||
slug: pk
|
||||
});
|
||||
}
|
||||
|
||||
@property({ attribute: false })
|
||||
provider?: number;
|
||||
|
||||
getSuccessMessage(): string {
|
||||
if (this.application) {
|
||||
if (this.instance) {
|
||||
return t`Successfully updated application.`;
|
||||
} else {
|
||||
return t`Successfully created application.`;
|
||||
@ -37,9 +40,9 @@ export class ApplicationForm extends Form<Application> {
|
||||
|
||||
send = (data: Application): Promise<Application | void> => {
|
||||
let writeOp: Promise<Application>;
|
||||
if (this.application) {
|
||||
if (this.instance) {
|
||||
writeOp = new CoreApi(DEFAULT_CONFIG).coreApplicationsUpdate({
|
||||
slug: this.application.slug,
|
||||
slug: this.instance.slug,
|
||||
data: data
|
||||
});
|
||||
} else {
|
||||
@ -72,7 +75,7 @@ export class ApplicationForm extends Form<Application> {
|
||||
${Array.from(m).map(([group, providers]) => {
|
||||
return html`<optgroup label=${group}>
|
||||
${providers.map(p => {
|
||||
const selected = (this.application?.provider === p.pk) || (this.provider === p.pk);
|
||||
const selected = (this.instance?.provider === p.pk) || (this.provider === p.pk);
|
||||
return html`<option ?selected=${selected} value=${ifDefined(p.pk)}>${p.name}</option>`;
|
||||
})}
|
||||
</optgroup>`;
|
||||
@ -86,21 +89,21 @@ export class ApplicationForm extends Form<Application> {
|
||||
label=${t`Name`}
|
||||
?required=${true}
|
||||
name="name">
|
||||
<input type="text" value="${ifDefined(this.application?.name)}" class="pf-c-form-control" required>
|
||||
<input type="text" value="${ifDefined(this.instance?.name)}" class="pf-c-form-control" required>
|
||||
<p class="pf-c-form__helper-text">${t`Application's display Name.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Slug`}
|
||||
?required=${true}
|
||||
name="slug">
|
||||
<input type="text" value="${ifDefined(this.application?.slug)}" class="pf-c-form-control" required>
|
||||
<input type="text" value="${ifDefined(this.instance?.slug)}" class="pf-c-form-control" required>
|
||||
<p class="pf-c-form__helper-text">${t`Internal application name, used in URLs.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Provider`}
|
||||
name="provider">
|
||||
<select class="pf-c-form-control">
|
||||
<option value="" ?selected=${this.application?.provider === undefined}>---------</option>
|
||||
<option value="" ?selected=${this.instance?.provider === undefined}>---------</option>
|
||||
${until(new ProvidersApi(DEFAULT_CONFIG).providersAllList({}).then(providers => {
|
||||
return this.groupProviders(providers.results);
|
||||
}), html`<option>${t`Loading...`}</option>`)}
|
||||
@ -142,10 +145,10 @@ export class ApplicationForm extends Form<Application> {
|
||||
?required=${true}
|
||||
name="policyEngineMode">
|
||||
<select class="pf-c-form-control">
|
||||
<option value=${ApplicationPolicyEngineModeEnum.Any} ?selected=${this.application?.policyEngineMode === ApplicationPolicyEngineModeEnum.Any}>
|
||||
<option value=${ApplicationPolicyEngineModeEnum.Any} ?selected=${this.instance?.policyEngineMode === ApplicationPolicyEngineModeEnum.Any}>
|
||||
${t`ANY, any policy must match to grant access.`}
|
||||
</option>
|
||||
<option value=${ApplicationPolicyEngineModeEnum.All} ?selected=${this.application?.policyEngineMode === ApplicationPolicyEngineModeEnum.All}>
|
||||
<option value=${ApplicationPolicyEngineModeEnum.All} ?selected=${this.instance?.policyEngineMode === ApplicationPolicyEngineModeEnum.All}>
|
||||
${t`ALL, all policies must match to grant access.`}
|
||||
</option>
|
||||
</select>
|
||||
@ -158,23 +161,23 @@ export class ApplicationForm extends Form<Application> {
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Launch URL`}
|
||||
name="metaLaunchUrl">
|
||||
<input type="text" value="${ifDefined(this.application?.metaLaunchUrl)}" class="pf-c-form-control">
|
||||
<input type="text" value="${ifDefined(this.instance?.metaLaunchUrl)}" class="pf-c-form-control">
|
||||
<p class="pf-c-form__helper-text">${t`If left empty, authentik will try to extract the launch URL based on the selected provider.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Icon`}
|
||||
name="metaIcon">
|
||||
<input type="file" value="${ifDefined(this.application?.metaIcon)}" class="pf-c-form-control">
|
||||
<input type="file" value="${ifDefined(this.instance?.metaIcon)}" class="pf-c-form-control">
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Description`}
|
||||
name="metaDescription">
|
||||
<textarea class="pf-c-form-control">${ifDefined(this.application?.metaDescription)}</textarea>
|
||||
<textarea class="pf-c-form-control">${ifDefined(this.instance?.metaDescription)}</textarea>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Publisher`}
|
||||
name="metaPublisher">
|
||||
<input type="text" value="${ifDefined(this.application?.metaPublisher)}" class="pf-c-form-control">
|
||||
<input type="text" value="${ifDefined(this.instance?.metaPublisher)}" class="pf-c-form-control">
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
|
@ -89,7 +89,7 @@ export class ApplicationListPage extends TablePage<Application> {
|
||||
<span slot="header">
|
||||
${t`Update Application`}
|
||||
</span>
|
||||
<ak-application-form slot="form" .application=${item}>
|
||||
<ak-application-form slot="form" .instancePk=${item.slug}>
|
||||
</ak-application-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
${t`Edit`}
|
||||
|
@ -102,7 +102,7 @@ export class ApplicationViewPage extends LitElement {
|
||||
<span slot="header">
|
||||
${t`Update Application`}
|
||||
</span>
|
||||
<ak-application-form slot="form" .application=${this.application}>
|
||||
<ak-application-form slot="form" .instancePk=${this.application.slug}>
|
||||
</ak-application-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
${t`Edit`}
|
||||
|
@ -1,21 +1,24 @@
|
||||
import { CertificateKeyPair, CryptoApi } from "authentik-api";
|
||||
import { t } from "@lingui/macro";
|
||||
import { customElement, property } from "lit-element";
|
||||
import { customElement } from "lit-element";
|
||||
import { html, TemplateResult } from "lit-html";
|
||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
||||
import { Form } from "../../elements/forms/Form";
|
||||
import { ifDefined } from "lit-html/directives/if-defined";
|
||||
import "../../elements/forms/HorizontalFormElement";
|
||||
import "../../elements/CodeMirror";
|
||||
import { ModelForm } from "../../elements/forms/ModelForm";
|
||||
|
||||
@customElement("ak-crypto-certificate-form")
|
||||
export class CertificateKeyPairForm extends Form<CertificateKeyPair> {
|
||||
export class CertificateKeyPairForm extends ModelForm<CertificateKeyPair, string> {
|
||||
|
||||
@property({attribute: false})
|
||||
keyPair?: CertificateKeyPair;
|
||||
loadInstance(pk: string): Promise<CertificateKeyPair> {
|
||||
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsRead({
|
||||
kpUuid: pk,
|
||||
});
|
||||
}
|
||||
|
||||
getSuccessMessage(): string {
|
||||
if (this.keyPair) {
|
||||
if (this.instance) {
|
||||
return t`Successfully updated certificate-key pair.`;
|
||||
} else {
|
||||
return t`Successfully created certificate-key pair.`;
|
||||
@ -23,9 +26,9 @@ export class CertificateKeyPairForm extends Form<CertificateKeyPair> {
|
||||
}
|
||||
|
||||
send = (data: CertificateKeyPair): Promise<CertificateKeyPair> => {
|
||||
if (this.keyPair) {
|
||||
if (this.instance) {
|
||||
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsPartialUpdate({
|
||||
kpUuid: this.keyPair.pk || "",
|
||||
kpUuid: this.instance.pk || "",
|
||||
data: data
|
||||
});
|
||||
} else {
|
||||
@ -41,21 +44,21 @@ export class CertificateKeyPairForm extends Form<CertificateKeyPair> {
|
||||
label=${t`Name`}
|
||||
name="name"
|
||||
?required=${true}>
|
||||
<input type="text" value="${ifDefined(this.keyPair?.name)}" class="pf-c-form-control" required>
|
||||
<input type="text" value="${ifDefined(this.instance?.name)}" class="pf-c-form-control" required>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Certificate`}
|
||||
name="certificateData"
|
||||
?writeOnly=${this.keyPair !== undefined}
|
||||
?writeOnly=${this.instance !== undefined}
|
||||
?required=${true}>
|
||||
<textarea class="pf-c-form-control" required>${ifDefined(this.keyPair?.certificateData)}</textarea>
|
||||
<textarea class="pf-c-form-control" required>${ifDefined(this.instance?.certificateData)}</textarea>
|
||||
<p class="pf-c-form__helper-text">${t`PEM-encoded Certificate data.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
name="keyData"
|
||||
?writeOnly=${this.keyPair !== undefined}
|
||||
?writeOnly=${this.instance !== undefined}
|
||||
label=${t`Private Key`}>
|
||||
<textarea class="pf-c-form-control" >${ifDefined(this.keyPair?.keyData)}</textarea>
|
||||
<textarea class="pf-c-form-control" >${ifDefined(this.instance?.keyData)}</textarea>
|
||||
<p class="pf-c-form__helper-text">${t`Optional Private Key. If this is set, you can use this keypair for encryption.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
</form>`;
|
||||
|
@ -70,7 +70,7 @@ export class CertificateKeyPairListPage extends TablePage<CertificateKeyPair> {
|
||||
<span slot="header">
|
||||
${t`Update Certificate-Key Pair`}
|
||||
</span>
|
||||
<ak-crypto-certificate-form slot="form" .keyPair=${item}>
|
||||
<ak-crypto-certificate-form slot="form" .instancePk=${item.pk}>
|
||||
</ak-crypto-certificate-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
${t`Edit`}
|
||||
@ -112,6 +112,23 @@ export class CertificateKeyPairListPage extends TablePage<CertificateKeyPair> {
|
||||
<div class="pf-c-description-list__text">${item.certSubject}</div>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="pf-c-description-list__group">
|
||||
<dt class="pf-c-description-list__term">
|
||||
<span class="pf-c-description-list__text">${t`Download`}</span>
|
||||
</dt>
|
||||
<dd class="pf-c-description-list__description">
|
||||
<div class="pf-c-description-list__text">
|
||||
<a class="pf-c-button pf-m-secondary" target="_blank"
|
||||
href="/api/v2beta/crypto/certificatekeypairs/${item.pk}/view_certificate/?download">
|
||||
${t`Download Certificate`}
|
||||
</a>
|
||||
${item.privateKeyAvailable ? html`<a class="pf-c-button pf-m-secondary" target="_blank"
|
||||
href="/api/v2beta/crypto/certificatekeypairs/${item.pk}/view_private_key/?download">
|
||||
${t`Download Private key`}
|
||||
</a>` : html``}
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</td>
|
||||
|
@ -1,21 +1,24 @@
|
||||
import { CoreApi, EventsApi, NotificationRule, NotificationRuleSeverityEnum } from "authentik-api";
|
||||
import { t } from "@lingui/macro";
|
||||
import { customElement, property } from "lit-element";
|
||||
import { customElement } from "lit-element";
|
||||
import { html, TemplateResult } from "lit-html";
|
||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
||||
import { Form } from "../../elements/forms/Form";
|
||||
import { ifDefined } from "lit-html/directives/if-defined";
|
||||
import "../../elements/forms/HorizontalFormElement";
|
||||
import { until } from "lit-html/directives/until";
|
||||
import { ModelForm } from "../../elements/forms/ModelForm";
|
||||
|
||||
@customElement("ak-event-rule-form")
|
||||
export class RuleForm extends Form<NotificationRule> {
|
||||
export class RuleForm extends ModelForm<NotificationRule, string> {
|
||||
|
||||
@property({attribute: false})
|
||||
rule?: NotificationRule;
|
||||
loadInstance(pk: string): Promise<NotificationRule> {
|
||||
return new EventsApi(DEFAULT_CONFIG).eventsRulesRead({
|
||||
pbmUuid: pk,
|
||||
});
|
||||
}
|
||||
|
||||
getSuccessMessage(): string {
|
||||
if (this.rule) {
|
||||
if (this.instance) {
|
||||
return t`Successfully updated rule.`;
|
||||
} else {
|
||||
return t`Successfully created rule.`;
|
||||
@ -23,9 +26,9 @@ export class RuleForm extends Form<NotificationRule> {
|
||||
}
|
||||
|
||||
send = (data: NotificationRule): Promise<NotificationRule> => {
|
||||
if (this.rule) {
|
||||
if (this.instance) {
|
||||
return new EventsApi(DEFAULT_CONFIG).eventsRulesUpdate({
|
||||
pbmUuid: this.rule.pk || "",
|
||||
pbmUuid: this.instance.pk || "",
|
||||
data: data
|
||||
});
|
||||
} else {
|
||||
@ -37,13 +40,13 @@ export class RuleForm extends Form<NotificationRule> {
|
||||
|
||||
renderSeverity(): TemplateResult {
|
||||
return html`
|
||||
<option value=${NotificationRuleSeverityEnum.Alert} ?selected=${this.rule?.severity === NotificationRuleSeverityEnum.Alert}>
|
||||
<option value=${NotificationRuleSeverityEnum.Alert} ?selected=${this.instance?.severity === NotificationRuleSeverityEnum.Alert}>
|
||||
${t`Alert`}
|
||||
</option>
|
||||
<option value=${NotificationRuleSeverityEnum.Warning} ?selected=${this.rule?.severity === NotificationRuleSeverityEnum.Warning}>
|
||||
<option value=${NotificationRuleSeverityEnum.Warning} ?selected=${this.instance?.severity === NotificationRuleSeverityEnum.Warning}>
|
||||
${t`Warning`}
|
||||
</option>
|
||||
<option value=${NotificationRuleSeverityEnum.Notice} ?selected=${this.rule?.severity === NotificationRuleSeverityEnum.Notice}>
|
||||
<option value=${NotificationRuleSeverityEnum.Notice} ?selected=${this.instance?.severity === NotificationRuleSeverityEnum.Notice}>
|
||||
${t`Notice`}
|
||||
</option>
|
||||
`;
|
||||
@ -55,16 +58,16 @@ export class RuleForm extends Form<NotificationRule> {
|
||||
label=${t`Name`}
|
||||
?required=${true}
|
||||
name="name">
|
||||
<input type="text" value="${ifDefined(this.rule?.name)}" class="pf-c-form-control" required>
|
||||
<input type="text" value="${ifDefined(this.instance?.name)}" class="pf-c-form-control" required>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Group`}
|
||||
name="group">
|
||||
<select class="pf-c-form-control">
|
||||
<option value="" ?selected=${this.rule?.group === undefined}>---------</option>
|
||||
<option value="" ?selected=${this.instance?.group === undefined}>---------</option>
|
||||
${until(new CoreApi(DEFAULT_CONFIG).coreGroupsList({}).then(groups => {
|
||||
return groups.results.map(group => {
|
||||
return html`<option value=${ifDefined(group.pk)} ?selected=${this.rule?.group?.groupUuid === group.pk}>${group.name}</option>`;
|
||||
return html`<option value=${ifDefined(group.pk)} ?selected=${this.instance?.group?.groupUuid === group.pk}>${group.name}</option>`;
|
||||
});
|
||||
}), html`<option>${t`Loading...`}</option>`)}
|
||||
</select>
|
||||
@ -76,7 +79,7 @@ export class RuleForm extends Form<NotificationRule> {
|
||||
<select name="users" class="pf-c-form-control" multiple>
|
||||
${until(new EventsApi(DEFAULT_CONFIG).eventsTransportsList({}).then(transports => {
|
||||
return transports.results.map(transport => {
|
||||
const selected = Array.from(this.rule?.transports || []).some(su => {
|
||||
const selected = Array.from(this.instance?.transports || []).some(su => {
|
||||
return su.uuid == transport.pk;
|
||||
});
|
||||
return html`<option value=${ifDefined(transport.pk)} ?selected=${selected}>${transport.name}</option>`;
|
||||
|
@ -64,7 +64,7 @@ export class RuleListPage extends TablePage<NotificationRule> {
|
||||
<span slot="header">
|
||||
${t`Update Notification Rule`}
|
||||
</span>
|
||||
<ak-event-rule-form slot="form" .rule=${item}>
|
||||
<ak-event-rule-form slot="form" .instancePk=${item.pk}>
|
||||
</ak-event-rule-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
${t`Edit`}
|
||||
|
@ -3,22 +3,25 @@ import { t } from "@lingui/macro";
|
||||
import { customElement, property } from "lit-element";
|
||||
import { html, TemplateResult } from "lit-html";
|
||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
||||
import { Form } from "../../elements/forms/Form";
|
||||
import { ifDefined } from "lit-html/directives/if-defined";
|
||||
import "../../elements/forms/HorizontalFormElement";
|
||||
import { first } from "../../utils";
|
||||
import { ModelForm } from "../../elements/forms/ModelForm";
|
||||
|
||||
@customElement("ak-event-transport-form")
|
||||
export class TransportForm extends Form<NotificationTransport> {
|
||||
export class TransportForm extends ModelForm<NotificationTransport, string> {
|
||||
|
||||
@property({attribute: false})
|
||||
transport?: NotificationTransport;
|
||||
loadInstance(pk: string): Promise<NotificationTransport> {
|
||||
return new EventsApi(DEFAULT_CONFIG).eventsTransportsRead({
|
||||
uuid: pk,
|
||||
});
|
||||
}
|
||||
|
||||
@property({type: Boolean})
|
||||
showWebhook = false;
|
||||
|
||||
getSuccessMessage(): string {
|
||||
if (this.transport) {
|
||||
if (this.instance) {
|
||||
return t`Successfully updated transport.`;
|
||||
} else {
|
||||
return t`Successfully created transport.`;
|
||||
@ -26,9 +29,9 @@ export class TransportForm extends Form<NotificationTransport> {
|
||||
}
|
||||
|
||||
send = (data: NotificationTransport): Promise<NotificationTransport> => {
|
||||
if (this.transport) {
|
||||
if (this.instance) {
|
||||
return new EventsApi(DEFAULT_CONFIG).eventsTransportsUpdate({
|
||||
uuid: this.transport.pk || "",
|
||||
uuid: this.instance.pk || "",
|
||||
data: data
|
||||
});
|
||||
} else {
|
||||
@ -40,21 +43,21 @@ export class TransportForm extends Form<NotificationTransport> {
|
||||
|
||||
renderTransportModes(): TemplateResult {
|
||||
return html`
|
||||
<option value=${NotificationTransportModeEnum.Email} ?selected=${this.transport?.mode === NotificationTransportModeEnum.Email}>
|
||||
<option value=${NotificationTransportModeEnum.Email} ?selected=${this.instance?.mode === NotificationTransportModeEnum.Email}>
|
||||
${t`Email`}
|
||||
</option>
|
||||
<option value=${NotificationTransportModeEnum.Webhook} ?selected=${this.transport?.mode === NotificationTransportModeEnum.Webhook}>
|
||||
<option value=${NotificationTransportModeEnum.Webhook} ?selected=${this.instance?.mode === NotificationTransportModeEnum.Webhook}>
|
||||
${t`Webhook (generic)`}
|
||||
</option>
|
||||
<option value=${NotificationTransportModeEnum.WebhookSlack} ?selected=${this.transport?.mode === NotificationTransportModeEnum.WebhookSlack}>
|
||||
<option value=${NotificationTransportModeEnum.WebhookSlack} ?selected=${this.instance?.mode === NotificationTransportModeEnum.WebhookSlack}>
|
||||
${t`Webhook (Slack/Discord)`}
|
||||
</option>
|
||||
`;
|
||||
}
|
||||
|
||||
firstUpdated(): void {
|
||||
if (this.transport) {
|
||||
this.onModeChange(this.transport.mode);
|
||||
if (this.instance) {
|
||||
this.onModeChange(this.instance.mode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,7 +75,7 @@ export class TransportForm extends Form<NotificationTransport> {
|
||||
label=${t`Name`}
|
||||
?required=${true}
|
||||
name="name">
|
||||
<input type="text" value="${ifDefined(this.transport?.name)}" class="pf-c-form-control" required>
|
||||
<input type="text" value="${ifDefined(this.instance?.name)}" class="pf-c-form-control" required>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Mode`}
|
||||
@ -89,11 +92,11 @@ export class TransportForm extends Form<NotificationTransport> {
|
||||
?hidden=${!this.showWebhook}
|
||||
label=${t`Webhook URL`}
|
||||
name="webhookUrl">
|
||||
<input type="text" value="${ifDefined(this.transport?.webhookUrl)}" class="pf-c-form-control">
|
||||
<input type="text" value="${ifDefined(this.instance?.webhookUrl)}" class="pf-c-form-control">
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="sendOnce">
|
||||
<div class="pf-c-check">
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.transport?.sendOnce, false)}>
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.instance?.sendOnce, false)}>
|
||||
<label class="pf-c-check__label">
|
||||
${t`Send once`}
|
||||
</label>
|
||||
|
@ -68,7 +68,7 @@ export class TransportListPage extends TablePage<NotificationTransport> {
|
||||
<span slot="header">
|
||||
${t`Update Notification Transport`}
|
||||
</span>
|
||||
<ak-event-transport-form slot="form" .transport=${item}>
|
||||
<ak-event-transport-form slot="form" .instancePk=${item.pk}>
|
||||
</ak-event-transport-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
${t`Edit`}
|
||||
|
@ -58,7 +58,7 @@ export class BoundStagesList extends Table<FlowStageBinding> {
|
||||
<ak-proxy-form
|
||||
slot="form"
|
||||
.args=${{
|
||||
"stageUUID": item.stage
|
||||
"instancePk": item.stage
|
||||
}}
|
||||
type=${ifDefined(item.stageObj?.component)}>
|
||||
</ak-proxy-form>
|
||||
@ -73,7 +73,7 @@ export class BoundStagesList extends Table<FlowStageBinding> {
|
||||
<span slot="header">
|
||||
${t`Update Stage binding`}
|
||||
</span>
|
||||
<ak-stage-binding-form slot="form" .fsb=${item}>
|
||||
<ak-stage-binding-form slot="form" .instancePk=${item.pk}>
|
||||
</ak-stage-binding-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
${t`Edit Binding`}
|
||||
|
@ -1,20 +1,23 @@
|
||||
import { Flow, FlowDesignationEnum, FlowPolicyEngineModeEnum, FlowsApi } from "authentik-api";
|
||||
import { t } from "@lingui/macro";
|
||||
import { customElement, property } from "lit-element";
|
||||
import { customElement } from "lit-element";
|
||||
import { html, TemplateResult } from "lit-html";
|
||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
||||
import { Form } from "../../elements/forms/Form";
|
||||
import { ifDefined } from "lit-html/directives/if-defined";
|
||||
import "../../elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "../../elements/forms/ModelForm";
|
||||
|
||||
@customElement("ak-flow-form")
|
||||
export class FlowForm extends Form<Flow> {
|
||||
export class FlowForm extends ModelForm<Flow, string> {
|
||||
|
||||
@property({attribute: false})
|
||||
flow?: Flow;
|
||||
loadInstance(pk: string): Promise<Flow> {
|
||||
return new FlowsApi(DEFAULT_CONFIG).flowsInstancesRead({
|
||||
slug: pk,
|
||||
});
|
||||
}
|
||||
|
||||
getSuccessMessage(): string {
|
||||
if (this.flow) {
|
||||
if (this.instance) {
|
||||
return t`Successfully updated flow.`;
|
||||
} else {
|
||||
return t`Successfully created flow.`;
|
||||
@ -23,9 +26,9 @@ export class FlowForm extends Form<Flow> {
|
||||
|
||||
send = (data: Flow): Promise<void | Flow> => {
|
||||
let writeOp: Promise<Flow>;
|
||||
if (this.flow) {
|
||||
if (this.instance) {
|
||||
writeOp = new FlowsApi(DEFAULT_CONFIG).flowsInstancesUpdate({
|
||||
slug: this.flow.slug,
|
||||
slug: this.instance.slug,
|
||||
data: data
|
||||
});
|
||||
} else {
|
||||
@ -47,25 +50,25 @@ export class FlowForm extends Form<Flow> {
|
||||
|
||||
renderDesignations(): TemplateResult {
|
||||
return html`
|
||||
<option value=${FlowDesignationEnum.Authentication} ?selected=${this.flow?.designation === FlowDesignationEnum.Authentication}>
|
||||
<option value=${FlowDesignationEnum.Authentication} ?selected=${this.instance?.designation === FlowDesignationEnum.Authentication}>
|
||||
${t`Authentication`}
|
||||
</option>
|
||||
<option value=${FlowDesignationEnum.Authorization} ?selected=${this.flow?.designation === FlowDesignationEnum.Authorization}>
|
||||
<option value=${FlowDesignationEnum.Authorization} ?selected=${this.instance?.designation === FlowDesignationEnum.Authorization}>
|
||||
${t`Authorization`}
|
||||
</option>
|
||||
<option value=${FlowDesignationEnum.Enrollment} ?selected=${this.flow?.designation === FlowDesignationEnum.Enrollment}>
|
||||
<option value=${FlowDesignationEnum.Enrollment} ?selected=${this.instance?.designation === FlowDesignationEnum.Enrollment}>
|
||||
${t`Enrollment`}
|
||||
</option>
|
||||
<option value=${FlowDesignationEnum.Invalidation} ?selected=${this.flow?.designation === FlowDesignationEnum.Invalidation}>
|
||||
<option value=${FlowDesignationEnum.Invalidation} ?selected=${this.instance?.designation === FlowDesignationEnum.Invalidation}>
|
||||
${t`Invalidation`}
|
||||
</option>
|
||||
<option value=${FlowDesignationEnum.Recovery} ?selected=${this.flow?.designation === FlowDesignationEnum.Recovery}>
|
||||
<option value=${FlowDesignationEnum.Recovery} ?selected=${this.instance?.designation === FlowDesignationEnum.Recovery}>
|
||||
${t`Recovery`}
|
||||
</option>
|
||||
<option value=${FlowDesignationEnum.StageConfiguration} ?selected=${this.flow?.designation === FlowDesignationEnum.StageConfiguration}>
|
||||
<option value=${FlowDesignationEnum.StageConfiguration} ?selected=${this.instance?.designation === FlowDesignationEnum.StageConfiguration}>
|
||||
${t`Stage Configuration`}
|
||||
</option>
|
||||
<option value=${FlowDesignationEnum.Unenrollment} ?selected=${this.flow?.designation === FlowDesignationEnum.Unenrollment}>
|
||||
<option value=${FlowDesignationEnum.Unenrollment} ?selected=${this.instance?.designation === FlowDesignationEnum.Unenrollment}>
|
||||
${t`Unenrollment`}
|
||||
</option>
|
||||
`;
|
||||
@ -77,20 +80,20 @@ export class FlowForm extends Form<Flow> {
|
||||
label=${t`Name`}
|
||||
?required=${true}
|
||||
name="name">
|
||||
<input type="text" value="${ifDefined(this.flow?.name)}" class="pf-c-form-control" required>
|
||||
<input type="text" value="${ifDefined(this.instance?.name)}" class="pf-c-form-control" required>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Title`}
|
||||
?required=${true}
|
||||
name="title">
|
||||
<input type="text" value="${ifDefined(this.flow?.title)}" class="pf-c-form-control" required>
|
||||
<input type="text" value="${ifDefined(this.instance?.title)}" class="pf-c-form-control" required>
|
||||
<p class="pf-c-form__helper-text">${t`Shown as the Title in Flow pages.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Slug`}
|
||||
?required=${true}
|
||||
name="slug">
|
||||
<input type="text" value="${ifDefined(this.flow?.slug)}" class="pf-c-form-control" required>
|
||||
<input type="text" value="${ifDefined(this.instance?.slug)}" class="pf-c-form-control" required>
|
||||
<p class="pf-c-form__helper-text">${t`Visible in the URL.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
@ -98,10 +101,10 @@ export class FlowForm extends Form<Flow> {
|
||||
?required=${true}
|
||||
name="policyEngineMode">
|
||||
<select class="pf-c-form-control">
|
||||
<option value=${FlowPolicyEngineModeEnum.Any} ?selected=${this.flow?.policyEngineMode === FlowPolicyEngineModeEnum.Any}>
|
||||
<option value=${FlowPolicyEngineModeEnum.Any} ?selected=${this.instance?.policyEngineMode === FlowPolicyEngineModeEnum.Any}>
|
||||
${t`ANY, any policy must match to grant access.`}
|
||||
</option>
|
||||
<option value=${FlowPolicyEngineModeEnum.All} ?selected=${this.flow?.policyEngineMode === FlowPolicyEngineModeEnum.All}>
|
||||
<option value=${FlowPolicyEngineModeEnum.All} ?selected=${this.instance?.policyEngineMode === FlowPolicyEngineModeEnum.All}>
|
||||
${t`ALL, all policies must match to grant access.`}
|
||||
</option>
|
||||
</select>
|
||||
@ -111,7 +114,7 @@ export class FlowForm extends Form<Flow> {
|
||||
?required=${true}
|
||||
name="designation">
|
||||
<select class="pf-c-form-control">
|
||||
<option value="" ?selected=${this.flow?.designation === undefined}>---------</option>
|
||||
<option value="" ?selected=${this.instance?.designation === undefined}>---------</option>
|
||||
${this.renderDesignations()}
|
||||
</select>
|
||||
<p class="pf-c-form__helper-text">${t`Decides what this Flow is used for. For example, the Authentication flow is redirect to when an un-authenticated user visits authentik.`}</p>
|
||||
@ -119,7 +122,7 @@ export class FlowForm extends Form<Flow> {
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Background`}
|
||||
name="background">
|
||||
<input type="file" value="${ifDefined(this.flow?.background)}" class="pf-c-form-control">
|
||||
<input type="file" value="${ifDefined(this.instance?.background)}" class="pf-c-form-control">
|
||||
<p class="pf-c-form__helper-text">${t`Background shown during execution.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
</form>`;
|
||||
|
@ -68,7 +68,7 @@ export class FlowListPage extends TablePage<Flow> {
|
||||
<span slot="header">
|
||||
${t`Update Flow`}
|
||||
</span>
|
||||
<ak-flow-form slot="form" .flow=${item}>
|
||||
<ak-flow-form slot="form" .instancePk=${item.pk}>
|
||||
</ak-flow-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
${t`Edit`}
|
||||
|
@ -3,23 +3,26 @@ import { t } from "@lingui/macro";
|
||||
import { customElement, property } from "lit-element";
|
||||
import { html, TemplateResult } from "lit-html";
|
||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
||||
import { Form } from "../../elements/forms/Form";
|
||||
import { until } from "lit-html/directives/until";
|
||||
import { ifDefined } from "lit-html/directives/if-defined";
|
||||
import "../../elements/forms/HorizontalFormElement";
|
||||
import { first, groupBy } from "../../utils";
|
||||
import { ModelForm } from "../../elements/forms/ModelForm";
|
||||
|
||||
@customElement("ak-stage-binding-form")
|
||||
export class StageBindingForm extends Form<FlowStageBinding> {
|
||||
export class StageBindingForm extends ModelForm<FlowStageBinding, string> {
|
||||
|
||||
@property({attribute: false})
|
||||
fsb?: FlowStageBinding;
|
||||
loadInstance(pk: string): Promise<FlowStageBinding> {
|
||||
return new FlowsApi(DEFAULT_CONFIG).flowsBindingsRead({
|
||||
fsbUuid: pk,
|
||||
});
|
||||
}
|
||||
|
||||
@property()
|
||||
targetPk?: string;
|
||||
|
||||
getSuccessMessage(): string {
|
||||
if (this.fsb) {
|
||||
if (this.instance) {
|
||||
return t`Successfully updated binding.`;
|
||||
} else {
|
||||
return t`Successfully created binding.`;
|
||||
@ -27,9 +30,9 @@ export class StageBindingForm extends Form<FlowStageBinding> {
|
||||
}
|
||||
|
||||
send = (data: FlowStageBinding): Promise<FlowStageBinding> => {
|
||||
if (this.fsb) {
|
||||
if (this.instance) {
|
||||
return new FlowsApi(DEFAULT_CONFIG).flowsBindingsUpdate({
|
||||
fsbUuid: this.fsb.pk || "",
|
||||
fsbUuid: this.instance.pk || "",
|
||||
data: data
|
||||
});
|
||||
} else {
|
||||
@ -45,7 +48,7 @@ export class StageBindingForm extends Form<FlowStageBinding> {
|
||||
${groupBy<Stage>(stages, (s => s.verboseName || "")).map(([group, stages]) => {
|
||||
return html`<optgroup label=${group}>
|
||||
${stages.map(stage => {
|
||||
const selected = (this.fsb?.stage === stage.pk);
|
||||
const selected = (this.instance?.stage === stage.pk);
|
||||
return html`<option ?selected=${selected} value=${ifDefined(stage.pk)}>${stage.name}</option>`;
|
||||
})}
|
||||
</optgroup>`;
|
||||
@ -54,8 +57,8 @@ export class StageBindingForm extends Form<FlowStageBinding> {
|
||||
}
|
||||
|
||||
getOrder(): Promise<number> {
|
||||
if (this.fsb) {
|
||||
return Promise.resolve(this.fsb.order);
|
||||
if (this.instance) {
|
||||
return Promise.resolve(this.instance.order);
|
||||
}
|
||||
return new FlowsApi(DEFAULT_CONFIG).flowsBindingsList({
|
||||
target: this.targetPk || "",
|
||||
@ -69,9 +72,9 @@ export class StageBindingForm extends Form<FlowStageBinding> {
|
||||
}
|
||||
|
||||
renderTarget(): TemplateResult {
|
||||
if (this.fsb?.target || this.targetPk) {
|
||||
if (this.instance?.target || this.targetPk) {
|
||||
return html`
|
||||
<input required name="target" type="hidden" value=${ifDefined(this.fsb?.target || this.targetPk)}>
|
||||
<input required name="target" type="hidden" value=${ifDefined(this.instance?.target || this.targetPk)}>
|
||||
`;
|
||||
}
|
||||
return html`<ak-form-element-horizontal
|
||||
@ -114,7 +117,7 @@ export class StageBindingForm extends Form<FlowStageBinding> {
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="evaluateOnPlan">
|
||||
<div class="pf-c-check">
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.fsb?.evaluateOnPlan, true)}>
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.instance?.evaluateOnPlan, true)}>
|
||||
<label class="pf-c-check__label">
|
||||
${t`Evaluate on plan`}
|
||||
</label>
|
||||
@ -125,7 +128,7 @@ export class StageBindingForm extends Form<FlowStageBinding> {
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="reEvaluatePolicies">
|
||||
<div class="pf-c-check">
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.fsb?.reEvaluatePolicies, false)}>
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.instance?.reEvaluatePolicies, false)}>
|
||||
<label class="pf-c-check__label">
|
||||
${t`Re-evaluate policies`}
|
||||
</label>
|
||||
@ -137,10 +140,10 @@ export class StageBindingForm extends Form<FlowStageBinding> {
|
||||
?required=${true}
|
||||
name="policyEngineMode">
|
||||
<select class="pf-c-form-control">
|
||||
<option value=${FlowStageBindingPolicyEngineModeEnum.Any} ?selected=${this.fsb?.policyEngineMode === FlowStageBindingPolicyEngineModeEnum.Any}>
|
||||
<option value=${FlowStageBindingPolicyEngineModeEnum.Any} ?selected=${this.instance?.policyEngineMode === FlowStageBindingPolicyEngineModeEnum.Any}>
|
||||
${t`ANY, any policy must match to include this stage access.`}
|
||||
</option>
|
||||
<option value=${FlowStageBindingPolicyEngineModeEnum.All} ?selected=${this.fsb?.policyEngineMode === FlowStageBindingPolicyEngineModeEnum.All}>
|
||||
<option value=${FlowStageBindingPolicyEngineModeEnum.All} ?selected=${this.instance?.policyEngineMode === FlowStageBindingPolicyEngineModeEnum.All}>
|
||||
${t`ALL, all policies must match to include this stage access.`}
|
||||
</option>
|
||||
</select>
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { CoreApi, Group, User } from "authentik-api";
|
||||
import { t } from "@lingui/macro";
|
||||
import { customElement, property } from "lit-element";
|
||||
import { customElement } from "lit-element";
|
||||
import { html, TemplateResult } from "lit-html";
|
||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
||||
import { Form } from "../../elements/forms/Form";
|
||||
import { until } from "lit-html/directives/until";
|
||||
import { ifDefined } from "lit-html/directives/if-defined";
|
||||
import "../../elements/forms/HorizontalFormElement";
|
||||
@ -13,15 +12,19 @@ import "../../elements/chips/Chip";
|
||||
import "./MemberSelectModal";
|
||||
import YAML from "yaml";
|
||||
import { first } from "../../utils";
|
||||
import { ModelForm } from "../../elements/forms/ModelForm";
|
||||
|
||||
@customElement("ak-group-form")
|
||||
export class GroupForm extends Form<Group> {
|
||||
export class GroupForm extends ModelForm<Group, string> {
|
||||
|
||||
@property({attribute: false})
|
||||
group?: Group;
|
||||
loadInstance(pk: string): Promise<Group> {
|
||||
return new CoreApi(DEFAULT_CONFIG).coreGroupsRead({
|
||||
groupUuid: pk
|
||||
});
|
||||
}
|
||||
|
||||
getSuccessMessage(): string {
|
||||
if (this.group) {
|
||||
if (this.instance) {
|
||||
return t`Successfully updated group.`;
|
||||
} else {
|
||||
return t`Successfully created group.`;
|
||||
@ -29,13 +32,13 @@ export class GroupForm extends Form<Group> {
|
||||
}
|
||||
|
||||
send = (data: Group): Promise<Group> => {
|
||||
if (this.group?.pk) {
|
||||
if (this.instance?.pk) {
|
||||
return new CoreApi(DEFAULT_CONFIG).coreGroupsUpdate({
|
||||
groupUuid: this.group.pk || "",
|
||||
groupUuid: this.instance.pk || "",
|
||||
data: data
|
||||
});
|
||||
} else {
|
||||
data.users = Array.from(this.group?.users || []) as unknown as Set<number>;
|
||||
data.users = Array.from(this.instance?.users || []) as unknown as Set<number>;
|
||||
return new CoreApi(DEFAULT_CONFIG).coreGroupsCreate({
|
||||
data: data
|
||||
});
|
||||
@ -48,11 +51,11 @@ export class GroupForm extends Form<Group> {
|
||||
label=${t`Name`}
|
||||
?required=${true}
|
||||
name="name">
|
||||
<input type="text" value="${ifDefined(this.group?.name)}" class="pf-c-form-control" required>
|
||||
<input type="text" value="${ifDefined(this.instance?.name)}" class="pf-c-form-control" required>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="isSuperuser">
|
||||
<div class="pf-c-check">
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.group?.isSuperuser, false)}>
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.instance?.isSuperuser, false)}>
|
||||
<label class="pf-c-check__label">
|
||||
${t`Is superuser`}
|
||||
</label>
|
||||
@ -63,10 +66,10 @@ export class GroupForm extends Form<Group> {
|
||||
label=${t`Parent`}
|
||||
name="parent">
|
||||
<select class="pf-c-form-control">
|
||||
<option value="" ?selected=${this.group?.parent === undefined}>---------</option>
|
||||
<option value="" ?selected=${this.instance?.parent === undefined}>---------</option>
|
||||
${until(new CoreApi(DEFAULT_CONFIG).coreGroupsList({}).then(groups => {
|
||||
return groups.results.map(group => {
|
||||
return html`<option value=${ifDefined(group.pk)} ?selected=${this.group?.parent === group.pk}>${group.name}</option>`;
|
||||
return html`<option value=${ifDefined(group.pk)} ?selected=${this.instance?.parent === group.pk}>${group.name}</option>`;
|
||||
});
|
||||
}), html`<option>${t`Loading...`}</option>`)}
|
||||
</select>
|
||||
@ -79,8 +82,8 @@ export class GroupForm extends Form<Group> {
|
||||
.confirm=${(items: User[]) => {
|
||||
// Because the model only has the IDs, map the user list to IDs
|
||||
const ids = items.map(u => u.pk || 0);
|
||||
if (!this.group) this.group = {} as Group;
|
||||
this.group.users = new Set(Array.from(this.group?.users || []).concat(ids));
|
||||
if (!this.instance) this.instance = {} as Group;
|
||||
this.instance.users = new Set(Array.from(this.instance?.users || []).concat(ids));
|
||||
this.requestUpdate();
|
||||
return Promise.resolve();
|
||||
}}>
|
||||
@ -94,7 +97,7 @@ export class GroupForm extends Form<Group> {
|
||||
ordering: "username",
|
||||
}).then(users => {
|
||||
return users.results.map(user => {
|
||||
const selected = Array.from(this.group?.users || []).some(su => {
|
||||
const selected = Array.from(this.instance?.users || []).some(su => {
|
||||
return su == user.pk;
|
||||
});
|
||||
if (!selected) return;
|
||||
@ -102,11 +105,11 @@ export class GroupForm extends Form<Group> {
|
||||
.removable=${true}
|
||||
value=${ifDefined(user.pk)}
|
||||
@remove=${() => {
|
||||
if (!this.group) return;
|
||||
const users = Array.from(this.group?.users || []);
|
||||
if (!this.instance) return;
|
||||
const users = Array.from(this.instance?.users || []);
|
||||
const idx = users.indexOf(user.pk || 0);
|
||||
users.splice(idx, 1);
|
||||
this.group.users = new Set(users);
|
||||
this.instance.users = new Set(users);
|
||||
this.requestUpdate();
|
||||
}}>
|
||||
${user.username}
|
||||
@ -122,7 +125,7 @@ export class GroupForm extends Form<Group> {
|
||||
label=${t`Attributes`}
|
||||
?required=${true}
|
||||
name="attributes">
|
||||
<ak-codemirror mode="yaml" value="${YAML.stringify(first(this.group?.attributes, {}))}">
|
||||
<ak-codemirror mode="yaml" value="${YAML.stringify(first(this.instance?.attributes, {}))}">
|
||||
</ak-codemirror>
|
||||
<p class="pf-c-form__helper-text">${t`Set custom attributes using YAML or JSON.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
|
@ -63,7 +63,7 @@ export class GroupListPage extends TablePage<Group> {
|
||||
<span slot="header">
|
||||
${t`Update Group`}
|
||||
</span>
|
||||
<ak-group-form slot="form" .group=${item}>
|
||||
<ak-group-form slot="form" .instancePk=${item.pk}>
|
||||
</ak-group-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
${t`Edit`}
|
||||
|
@ -1,23 +1,26 @@
|
||||
import { Outpost, OutpostsApi, OutpostTypeEnum, ProvidersApi } from "authentik-api";
|
||||
import { t } from "@lingui/macro";
|
||||
import { customElement, property } from "lit-element";
|
||||
import { customElement } from "lit-element";
|
||||
import { html, TemplateResult } from "lit-html";
|
||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
||||
import { Form } from "../../elements/forms/Form";
|
||||
import { until } from "lit-html/directives/until";
|
||||
import { ifDefined } from "lit-html/directives/if-defined";
|
||||
import "../../elements/forms/HorizontalFormElement";
|
||||
import "../../elements/CodeMirror";
|
||||
import YAML from "yaml";
|
||||
import { ModelForm } from "../../elements/forms/ModelForm";
|
||||
|
||||
@customElement("ak-outpost-form")
|
||||
export class OutpostForm extends Form<Outpost> {
|
||||
export class OutpostForm extends ModelForm<Outpost, string> {
|
||||
|
||||
@property({attribute: false})
|
||||
outpost?: Outpost;
|
||||
loadInstance(pk: string): Promise<Outpost> {
|
||||
return new OutpostsApi(DEFAULT_CONFIG).outpostsInstancesRead({
|
||||
uuid: pk
|
||||
});
|
||||
}
|
||||
|
||||
getSuccessMessage(): string {
|
||||
if (this.outpost) {
|
||||
if (this.instance) {
|
||||
return t`Successfully updated outpost.`;
|
||||
} else {
|
||||
return t`Successfully created outpost.`;
|
||||
@ -25,9 +28,9 @@ export class OutpostForm extends Form<Outpost> {
|
||||
}
|
||||
|
||||
send = (data: Outpost): Promise<Outpost> => {
|
||||
if (this.outpost) {
|
||||
if (this.instance) {
|
||||
return new OutpostsApi(DEFAULT_CONFIG).outpostsOutpostsUpdate({
|
||||
uuid: this.outpost.pk || "",
|
||||
uuid: this.instance.pk || "",
|
||||
data: data
|
||||
});
|
||||
} else {
|
||||
@ -43,27 +46,27 @@ export class OutpostForm extends Form<Outpost> {
|
||||
label=${t`Name`}
|
||||
?required=${true}
|
||||
name="name">
|
||||
<input type="text" value="${ifDefined(this.outpost?.name)}" class="pf-c-form-control" required>
|
||||
<input type="text" value="${ifDefined(this.instance?.name)}" class="pf-c-form-control" required>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Type`}
|
||||
?required=${true}
|
||||
name="type">
|
||||
<select class="pf-c-form-control">
|
||||
<option value=${OutpostTypeEnum.Proxy} ?selected=${this.outpost?.type === OutpostTypeEnum.Proxy}>${t`Proxy`}</option>
|
||||
<option value=${OutpostTypeEnum.Ldap} ?selected=${this.outpost?.type === OutpostTypeEnum.Ldap}>${t`LDAP (Technical preview)`}</option>
|
||||
<option value=${OutpostTypeEnum.Proxy} ?selected=${this.instance?.type === OutpostTypeEnum.Proxy}>${t`Proxy`}</option>
|
||||
<option value=${OutpostTypeEnum.Ldap} ?selected=${this.instance?.type === OutpostTypeEnum.Ldap}>${t`LDAP (Technical preview)`}</option>
|
||||
</select>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Service connection`}
|
||||
name="serviceConnection">
|
||||
<select class="pf-c-form-control">
|
||||
<option value="" ?selected=${this.outpost?.serviceConnection === undefined}>---------</option>
|
||||
<option value="" ?selected=${this.instance?.serviceConnection === undefined}>---------</option>
|
||||
${until(new OutpostsApi(DEFAULT_CONFIG).outpostsServiceConnectionsAllList({
|
||||
ordering: "pk"
|
||||
}).then(scs => {
|
||||
return scs.results.map(sc => {
|
||||
return html`<option value=${ifDefined(sc.pk)} ?selected=${this.outpost?.serviceConnection === sc.pk}>
|
||||
return html`<option value=${ifDefined(sc.pk)} ?selected=${this.instance?.serviceConnection === sc.pk}>
|
||||
${sc.name} (${sc.verboseName})
|
||||
</option>`;
|
||||
});
|
||||
@ -83,7 +86,7 @@ export class OutpostForm extends Form<Outpost> {
|
||||
ordering: "pk"
|
||||
}).then(providers => {
|
||||
return providers.results.map(provider => {
|
||||
const selected = Array.from(this.outpost?.providers || []).some(sp => {
|
||||
const selected = Array.from(this.instance?.providers || []).some(sp => {
|
||||
return sp == provider.pk;
|
||||
});
|
||||
return html`<option value=${ifDefined(provider.pk)} ?selected=${selected}>${provider.verboseName} ${provider.name}</option>`;
|
||||
@ -93,7 +96,7 @@ export class OutpostForm extends Form<Outpost> {
|
||||
ordering: "pk"
|
||||
}).then(providers => {
|
||||
return providers.results.map(provider => {
|
||||
const selected = Array.from(this.outpost?.providers || []).some(sp => {
|
||||
const selected = Array.from(this.instance?.providers || []).some(sp => {
|
||||
return sp == provider.pk;
|
||||
});
|
||||
return html`<option value=${ifDefined(provider.pk)} ?selected=${selected}>${provider.verboseName} ${provider.name}</option>`;
|
||||
@ -102,18 +105,18 @@ export class OutpostForm extends Form<Outpost> {
|
||||
</select>
|
||||
<p class="pf-c-form__helper-text">${t`Hold control/command to select multiple items.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
${until(new OutpostsApi(DEFAULT_CONFIG).outpostsOutpostsDefaultSettings({}).then(config => {
|
||||
let fc = config.config;
|
||||
if (this.outpost) {
|
||||
fc = this.outpost.config;
|
||||
}
|
||||
return html`<ak-form-element-horizontal
|
||||
label=${t`Configuration`}
|
||||
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>
|
||||
</ak-form-element-horizontal>`;
|
||||
}))}
|
||||
<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;
|
||||
if (this.instance) {
|
||||
fc = this.instance.config;
|
||||
}
|
||||
return YAML.stringify(fc);
|
||||
}))}"></ak-codemirror>
|
||||
<p class="pf-c-form__helper-text">${t`Set custom attributes using YAML or JSON.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
</form>`;
|
||||
}
|
||||
|
||||
|
@ -1,55 +1,70 @@
|
||||
import { t } from "@lingui/macro";
|
||||
import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||
import { until } from "lit-html/directives/until";
|
||||
import { OutpostsApi } from "authentik-api";
|
||||
import { OutpostHealth, OutpostsApi } from "authentik-api";
|
||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
import "../../elements/Spinner";
|
||||
import AKGlobal from "../../authentik.css";
|
||||
import { PFColor } from "../../elements/Label";
|
||||
import { EVENT_REFRESH } from "../../constants";
|
||||
|
||||
@customElement("ak-outpost-health")
|
||||
export class OutpostHealth extends LitElement {
|
||||
export class OutpostHealthElement extends LitElement {
|
||||
|
||||
@property()
|
||||
outpostId?: string;
|
||||
|
||||
@property({attribute: false})
|
||||
outpostHealth: OutpostHealth[] = [];
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [PFBase, AKGlobal];
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.addEventListener(EVENT_REFRESH, () => {
|
||||
this.firstUpdated();
|
||||
});
|
||||
}
|
||||
|
||||
firstUpdated(): void {
|
||||
if (!this.outpostId) return;
|
||||
new OutpostsApi(DEFAULT_CONFIG).outpostsOutpostsHealth({
|
||||
uuid: this.outpostId
|
||||
}).then(health => {
|
||||
this.outpostHealth = health;
|
||||
});
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.outpostId) {
|
||||
return html`<ak-spinner></ak-spinner>`;
|
||||
}
|
||||
return html`<ul>${until(new OutpostsApi(DEFAULT_CONFIG).outpostsOutpostsHealth({
|
||||
uuid: this.outpostId
|
||||
}).then((oh) => {
|
||||
if (oh.length === 0) {
|
||||
return html`<li>
|
||||
<ul>
|
||||
<li role="cell">
|
||||
<ak-label color=${PFColor.Grey} text=${t`Not available`}></ak-label>
|
||||
</li>
|
||||
</ul>
|
||||
</li>`;
|
||||
}
|
||||
return oh.map((h) => {
|
||||
return html`<li>
|
||||
<ul>
|
||||
<li role="cell">
|
||||
<ak-label color=${PFColor.Green} text=${t`Last seen: ${h.lastSeen?.toLocaleTimeString()}`}></ak-label>
|
||||
</li>
|
||||
<li role="cell">
|
||||
${h.versionOutdated ?
|
||||
html`<ak-label color=${PFColor.Red}
|
||||
text=${t`${h.version}, should be ${h.versionShould}`}></ak-label>` :
|
||||
html`<ak-label color=${PFColor.Green} text=${t`Version: ${h.version || ""}`}></ak-label>`}
|
||||
</li>
|
||||
</ul>
|
||||
</li>`;
|
||||
});
|
||||
}), html`<ak-spinner></ak-spinner>`)}</ul>`;
|
||||
if (this.outpostHealth.length === 0) {
|
||||
return html`<li>
|
||||
<ul>
|
||||
<li role="cell">
|
||||
<ak-label color=${PFColor.Grey} text=${t`Not available`}></ak-label>
|
||||
</li>
|
||||
</ul>
|
||||
</li>`;
|
||||
}
|
||||
return html`<ul>${this.outpostHealth.map((h) => {
|
||||
return html`<li>
|
||||
<ul>
|
||||
<li role="cell">
|
||||
<ak-label color=${PFColor.Green} text=${t`Last seen: ${h.lastSeen?.toLocaleTimeString()}`}></ak-label>
|
||||
</li>
|
||||
<li role="cell">
|
||||
${h.versionOutdated ?
|
||||
html`<ak-label color=${PFColor.Red}
|
||||
text=${t`${h.version}, should be ${h.versionShould}`}></ak-label>` :
|
||||
html`<ak-label color=${PFColor.Green} text=${t`Version: ${h.version || ""}`}></ak-label>`}
|
||||
</li>
|
||||
</ul>
|
||||
</li>`;
|
||||
})}</ul>`;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ export class OutpostListPage extends TablePage<Outpost> {
|
||||
<span slot="header">
|
||||
${t`Update Outpost`}
|
||||
</span>
|
||||
<ak-outpost-form slot="form" .outpost=${item}>
|
||||
<ak-outpost-form slot="form" .instancePk=${item.pk}>
|
||||
</ak-outpost-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
${t`Edit`}
|
||||
|
@ -1,30 +1,25 @@
|
||||
import { CryptoApi, DockerServiceConnection, OutpostsApi } from "authentik-api";
|
||||
import { t } from "@lingui/macro";
|
||||
import { customElement, property } from "lit-element";
|
||||
import { customElement } from "lit-element";
|
||||
import { html, TemplateResult } from "lit-html";
|
||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
||||
import { Form } from "../../elements/forms/Form";
|
||||
import { until } from "lit-html/directives/until";
|
||||
import { ifDefined } from "lit-html/directives/if-defined";
|
||||
import "../../elements/forms/HorizontalFormElement";
|
||||
import { first } from "../../utils";
|
||||
import { ModelForm } from "../../elements/forms/ModelForm";
|
||||
|
||||
@customElement("ak-service-connection-docker-form")
|
||||
export class ServiceConnectionDockerForm extends Form<DockerServiceConnection> {
|
||||
export class ServiceConnectionDockerForm extends ModelForm<DockerServiceConnection, string> {
|
||||
|
||||
set scUUID(value: string) {
|
||||
new OutpostsApi(DEFAULT_CONFIG).outpostsServiceConnectionsDockerRead({
|
||||
uuid: value,
|
||||
}).then(sc => {
|
||||
this.sc = sc;
|
||||
loadInstance(pk: string): Promise<DockerServiceConnection> {
|
||||
return new OutpostsApi(DEFAULT_CONFIG).outpostsServiceConnectionsDockerRead({
|
||||
uuid: pk,
|
||||
});
|
||||
}
|
||||
|
||||
@property({attribute: false})
|
||||
sc?: DockerServiceConnection;
|
||||
|
||||
getSuccessMessage(): string {
|
||||
if (this.sc) {
|
||||
if (this.instance) {
|
||||
return t`Successfully updated service-connection.`;
|
||||
} else {
|
||||
return t`Successfully created service-connection.`;
|
||||
@ -32,9 +27,9 @@ export class ServiceConnectionDockerForm extends Form<DockerServiceConnection> {
|
||||
}
|
||||
|
||||
send = (data: DockerServiceConnection): Promise<DockerServiceConnection> => {
|
||||
if (this.sc) {
|
||||
if (this.instance) {
|
||||
return new OutpostsApi(DEFAULT_CONFIG).outpostsServiceConnectionsDockerUpdate({
|
||||
uuid: this.sc.pk || "",
|
||||
uuid: this.instance.pk || "",
|
||||
data: data
|
||||
});
|
||||
} else {
|
||||
@ -50,11 +45,11 @@ export class ServiceConnectionDockerForm extends Form<DockerServiceConnection> {
|
||||
label=${t`Name`}
|
||||
?required=${true}
|
||||
name="name">
|
||||
<input type="text" value="${ifDefined(this.sc?.name)}" class="pf-c-form-control" required>
|
||||
<input type="text" value="${ifDefined(this.instance?.name)}" class="pf-c-form-control" required>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="local">
|
||||
<div class="pf-c-check">
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.sc?.local, false)}>
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.instance?.local, false)}>
|
||||
<label class="pf-c-check__label">
|
||||
${t`Local`}
|
||||
</label>
|
||||
@ -65,19 +60,19 @@ export class ServiceConnectionDockerForm extends Form<DockerServiceConnection> {
|
||||
label=${t`Docker URL`}
|
||||
?required=${true}
|
||||
name="url">
|
||||
<input type="text" value="${ifDefined(this.sc?.url)}" class="pf-c-form-control" required>
|
||||
<input type="text" value="${ifDefined(this.instance?.url)}" class="pf-c-form-control" required>
|
||||
<p class="pf-c-form__helper-text">${t`Can be in the format of 'unix://' when connecting to a local docker daemon, or 'https://:2376' when connecting to a remote system.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`TLS Verification Certificate`}
|
||||
name="tlsVerification">
|
||||
<select class="pf-c-form-control">
|
||||
<option value="" ?selected=${this.sc?.tlsVerification === undefined}>---------</option>
|
||||
<option value="" ?selected=${this.instance?.tlsVerification === undefined}>---------</option>
|
||||
${until(new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsList({
|
||||
ordering: "pk"
|
||||
}).then(certs => {
|
||||
return certs.results.map(cert => {
|
||||
return html`<option value=${ifDefined(cert.pk)} ?selected=${this.sc?.tlsVerification === cert.pk}>${cert.name}</option>`;
|
||||
return html`<option value=${ifDefined(cert.pk)} ?selected=${this.instance?.tlsVerification === cert.pk}>${cert.name}</option>`;
|
||||
});
|
||||
}), html`<option>${t`Loading...`}</option>`)}
|
||||
</select>
|
||||
@ -87,12 +82,12 @@ export class ServiceConnectionDockerForm extends Form<DockerServiceConnection> {
|
||||
label=${t`TLS Authentication Certificate`}
|
||||
name="tlsAuthentication">
|
||||
<select class="pf-c-form-control">
|
||||
<option value="" ?selected=${this.sc?.tlsAuthentication === undefined}>---------</option>
|
||||
<option value="" ?selected=${this.instance?.tlsAuthentication === undefined}>---------</option>
|
||||
${until(new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsList({
|
||||
ordering: "pk"
|
||||
}).then(certs => {
|
||||
return certs.results.map(cert => {
|
||||
return html`<option value=${ifDefined(cert.pk)} ?selected=${this.sc?.tlsAuthentication === cert.pk}>${cert.name}</option>`;
|
||||
return html`<option value=${ifDefined(cert.pk)} ?selected=${this.instance?.tlsAuthentication === cert.pk}>${cert.name}</option>`;
|
||||
});
|
||||
}), html`<option>${t`Loading...`}</option>`)}
|
||||
</select>
|
||||
|
@ -1,31 +1,26 @@
|
||||
import { KubernetesServiceConnection, OutpostsApi } from "authentik-api";
|
||||
import { t } from "@lingui/macro";
|
||||
import { customElement, property } from "lit-element";
|
||||
import { customElement } from "lit-element";
|
||||
import { html, TemplateResult } from "lit-html";
|
||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
||||
import { Form } from "../../elements/forms/Form";
|
||||
import { ifDefined } from "lit-html/directives/if-defined";
|
||||
import "../../elements/forms/HorizontalFormElement";
|
||||
import "../../elements/CodeMirror";
|
||||
import YAML from "yaml";
|
||||
import { first } from "../../utils";
|
||||
import { ModelForm } from "../../elements/forms/ModelForm";
|
||||
|
||||
@customElement("ak-service-connection-kubernetes-form")
|
||||
export class ServiceConnectionKubernetesForm extends Form<KubernetesServiceConnection> {
|
||||
export class ServiceConnectionKubernetesForm extends ModelForm<KubernetesServiceConnection, string> {
|
||||
|
||||
set scUUID(value: string) {
|
||||
new OutpostsApi(DEFAULT_CONFIG).outpostsServiceConnectionsKubernetesRead({
|
||||
uuid: value,
|
||||
}).then(sc => {
|
||||
this.sc = sc;
|
||||
loadInstance(pk: string): Promise<KubernetesServiceConnection> {
|
||||
return new OutpostsApi(DEFAULT_CONFIG).outpostsServiceConnectionsKubernetesRead({
|
||||
uuid: pk,
|
||||
});
|
||||
}
|
||||
|
||||
@property({attribute: false})
|
||||
sc?: KubernetesServiceConnection;
|
||||
|
||||
getSuccessMessage(): string {
|
||||
if (this.sc) {
|
||||
if (this.instance) {
|
||||
return t`Successfully updated service-connection.`;
|
||||
} else {
|
||||
return t`Successfully created service-connection.`;
|
||||
@ -33,9 +28,9 @@ export class ServiceConnectionKubernetesForm extends Form<KubernetesServiceConne
|
||||
}
|
||||
|
||||
send = (data: KubernetesServiceConnection): Promise<KubernetesServiceConnection> => {
|
||||
if (this.sc) {
|
||||
if (this.instance) {
|
||||
return new OutpostsApi(DEFAULT_CONFIG).outpostsServiceConnectionsKubernetesUpdate({
|
||||
uuid: this.sc.pk || "",
|
||||
uuid: this.instance.pk || "",
|
||||
data: data
|
||||
});
|
||||
} else {
|
||||
@ -51,11 +46,11 @@ export class ServiceConnectionKubernetesForm extends Form<KubernetesServiceConne
|
||||
label=${t`Name`}
|
||||
?required=${true}
|
||||
name="name">
|
||||
<input type="text" value="${ifDefined(this.sc?.name)}" class="pf-c-form-control" required>
|
||||
<input type="text" value="${ifDefined(this.instance?.name)}" class="pf-c-form-control" required>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="local">
|
||||
<div class="pf-c-check">
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.sc?.local, false)}>
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.instance?.local, false)}>
|
||||
<label class="pf-c-check__label">
|
||||
${t`Local`}
|
||||
</label>
|
||||
@ -65,7 +60,7 @@ export class ServiceConnectionKubernetesForm extends Form<KubernetesServiceConne
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Kubeconfig`}
|
||||
name="kubeconfig">
|
||||
<ak-codemirror mode="yaml" value="${YAML.stringify(first(this.sc?.kubeconfig, {}))}">
|
||||
<ak-codemirror mode="yaml" value="${YAML.stringify(first(this.instance?.kubeconfig, {}))}">
|
||||
</ak-codemirror>
|
||||
<p class="pf-c-form__helper-text">${t`Set custom attributes using YAML or JSON.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
|
@ -82,7 +82,7 @@ export class OutpostServiceConnectionListPage extends TablePage<ServiceConnectio
|
||||
<ak-proxy-form
|
||||
slot="form"
|
||||
.args=${{
|
||||
"scUUID": item.pk
|
||||
"instancePk": item.pk
|
||||
}}
|
||||
type=${ifDefined(item.component)}>
|
||||
</ak-proxy-form>
|
||||
|
@ -88,7 +88,7 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
|
||||
<span slot="header">
|
||||
${t`Update Group`}
|
||||
</span>
|
||||
<ak-group-form slot="form" .group=${item.groupObj}>
|
||||
<ak-group-form slot="form" .instancePk=${item.groupObj?.pk}>
|
||||
</ak-group-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
${t`Edit Group`}
|
||||
@ -102,7 +102,7 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
|
||||
<span slot="header">
|
||||
${t`Update User`}
|
||||
</span>
|
||||
<ak-user-form slot="form" .user=${item.userObj}>
|
||||
<ak-user-form slot="form" .instancePk=${item.userObj?.pk}>
|
||||
</ak-user-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
${t`Edit User`}
|
||||
@ -128,7 +128,7 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
|
||||
<span slot="header">
|
||||
${t`Update Binding`}
|
||||
</span>
|
||||
<ak-policy-binding-form slot="form" .binding=${item} targetPk=${ifDefined(this.target)} ?policyOnly=${this.policyOnly}>
|
||||
<ak-policy-binding-form slot="form" .instancePk=${item.pk} targetPk=${ifDefined(this.target)} ?policyOnly=${this.policyOnly}>
|
||||
</ak-policy-binding-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
${t`Edit Binding`}
|
||||
|
@ -3,41 +3,38 @@ import { t } from "@lingui/macro";
|
||||
import { css, CSSResult, customElement, property } from "lit-element";
|
||||
import { html, TemplateResult } from "lit-html";
|
||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
||||
import { Form } from "../../elements/forms/Form";
|
||||
import { until } from "lit-html/directives/until";
|
||||
import { ifDefined } from "lit-html/directives/if-defined";
|
||||
import { first, groupBy } from "../../utils";
|
||||
import "../../elements/forms/HorizontalFormElement";
|
||||
import PFToggleGroup from "@patternfly/patternfly/components/ToggleGroup/toggle-group.css";
|
||||
import PFContent from "@patternfly/patternfly/components/Content/content.css";
|
||||
import { ModelForm } from "../../elements/forms/ModelForm";
|
||||
|
||||
enum target {
|
||||
policy, group, user
|
||||
}
|
||||
|
||||
@customElement("ak-policy-binding-form")
|
||||
export class PolicyBindingForm extends Form<PolicyBinding> {
|
||||
export class PolicyBindingForm extends ModelForm<PolicyBinding, string> {
|
||||
|
||||
@property({attribute: false})
|
||||
set binding(value: PolicyBinding | undefined) {
|
||||
this._binding = value;
|
||||
if (value?.policyObj) {
|
||||
this.policyGroupUser = target.policy;
|
||||
}
|
||||
if (value?.groupObj) {
|
||||
this.policyGroupUser = target.group;
|
||||
}
|
||||
if (value?.userObj) {
|
||||
this.policyGroupUser = target.user;
|
||||
}
|
||||
loadInstance(pk: string): Promise<PolicyBinding> {
|
||||
return new PoliciesApi(DEFAULT_CONFIG).policiesBindingsRead({
|
||||
policyBindingUuid: pk
|
||||
}).then(binding => {
|
||||
if (binding?.policyObj) {
|
||||
this.policyGroupUser = target.policy;
|
||||
}
|
||||
if (binding?.groupObj) {
|
||||
this.policyGroupUser = target.group;
|
||||
}
|
||||
if (binding?.userObj) {
|
||||
this.policyGroupUser = target.user;
|
||||
}
|
||||
return binding;
|
||||
});
|
||||
}
|
||||
|
||||
get binding(): PolicyBinding | undefined {
|
||||
return this._binding;
|
||||
}
|
||||
|
||||
_binding?: PolicyBinding;
|
||||
|
||||
@property()
|
||||
targetPk?: string;
|
||||
|
||||
@ -48,7 +45,7 @@ export class PolicyBindingForm extends Form<PolicyBinding> {
|
||||
policyOnly = false;
|
||||
|
||||
getSuccessMessage(): string {
|
||||
if (this.binding) {
|
||||
if (this.instance) {
|
||||
return t`Successfully updated binding.`;
|
||||
} else {
|
||||
return t`Successfully created binding.`;
|
||||
@ -64,9 +61,9 @@ export class PolicyBindingForm extends Form<PolicyBinding> {
|
||||
}
|
||||
|
||||
send = (data: PolicyBinding): Promise<PolicyBinding> => {
|
||||
if (this.binding) {
|
||||
if (this.instance) {
|
||||
return new PoliciesApi(DEFAULT_CONFIG).policiesBindingsUpdate({
|
||||
policyBindingUuid: this.binding.pk || "",
|
||||
policyBindingUuid: this.instance.pk || "",
|
||||
data: data
|
||||
});
|
||||
} else {
|
||||
@ -81,7 +78,7 @@ export class PolicyBindingForm extends Form<PolicyBinding> {
|
||||
${groupBy<Policy>(policies, (p => p.verboseName || "")).map(([group, policies]) => {
|
||||
return html`<optgroup label=${group}>
|
||||
${policies.map(p => {
|
||||
const selected = (this.binding?.policy === p.pk);
|
||||
const selected = (this.instance?.policy === p.pk);
|
||||
return html`<option ?selected=${selected} value=${ifDefined(p.pk)}>${p.name}</option>`;
|
||||
})}
|
||||
</optgroup>`;
|
||||
@ -90,8 +87,8 @@ export class PolicyBindingForm extends Form<PolicyBinding> {
|
||||
}
|
||||
|
||||
getOrder(): Promise<number> {
|
||||
if (this.binding) {
|
||||
return Promise.resolve(this.binding.order);
|
||||
if (this.instance) {
|
||||
return Promise.resolve(this.instance.order);
|
||||
}
|
||||
return new PoliciesApi(DEFAULT_CONFIG).policiesBindingsList({
|
||||
target: this.targetPk || "",
|
||||
@ -154,7 +151,7 @@ export class PolicyBindingForm extends Form<PolicyBinding> {
|
||||
name="policy"
|
||||
?hidden=${this.policyGroupUser !== target.policy}>
|
||||
<select class="pf-c-form-control">
|
||||
<option value="" ?selected=${this.binding?.policy === undefined}>---------</option>
|
||||
<option value="" ?selected=${this.instance?.policy === undefined}>---------</option>
|
||||
${until(new PoliciesApi(DEFAULT_CONFIG).policiesAllList({
|
||||
ordering: "pk"
|
||||
}).then(policies => {
|
||||
@ -167,12 +164,12 @@ export class PolicyBindingForm extends Form<PolicyBinding> {
|
||||
name="group"
|
||||
?hidden=${this.policyGroupUser !== target.group}>
|
||||
<select class="pf-c-form-control">
|
||||
<option value="" ?selected=${this.binding?.group === undefined}>---------</option>
|
||||
<option value="" ?selected=${this.instance?.group === undefined}>---------</option>
|
||||
${until(new CoreApi(DEFAULT_CONFIG).coreGroupsList({
|
||||
ordering: "pk"
|
||||
}).then(groups => {
|
||||
return groups.results.map(group => {
|
||||
return html`<option value=${ifDefined(group.pk)} ?selected=${group.pk === this.binding?.group}>${group.name}</option>`;
|
||||
return html`<option value=${ifDefined(group.pk)} ?selected=${group.pk === this.instance?.group}>${group.name}</option>`;
|
||||
});
|
||||
}), html`<option>${t`Loading...`}</option>`)}
|
||||
</select>
|
||||
@ -182,22 +179,22 @@ export class PolicyBindingForm extends Form<PolicyBinding> {
|
||||
name="user"
|
||||
?hidden=${this.policyGroupUser !== target.user}>
|
||||
<select class="pf-c-form-control">
|
||||
<option value="" ?selected=${this.binding?.user === undefined}>---------</option>
|
||||
<option value="" ?selected=${this.instance?.user === undefined}>---------</option>
|
||||
${until(new CoreApi(DEFAULT_CONFIG).coreUsersList({
|
||||
ordering: "pk"
|
||||
}).then(users => {
|
||||
return users.results.map(user => {
|
||||
return html`<option value=${ifDefined(user.pk)} ?selected=${user.pk === this.binding?.user}>${user.name}</option>`;
|
||||
return html`<option value=${ifDefined(user.pk)} ?selected=${user.pk === this.instance?.user}>${user.name}</option>`;
|
||||
});
|
||||
}), html`<option>${t`Loading...`}</option>`)}
|
||||
</select>
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</div>
|
||||
<input required name="target" type="hidden" value=${ifDefined(this.binding?.target || this.targetPk)}>
|
||||
<input required name="target" type="hidden" value=${ifDefined(this.instance?.target || this.targetPk)}>
|
||||
<ak-form-element-horizontal name="enabled">
|
||||
<div class="pf-c-check">
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.binding?.enabled, true)}>
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.instance?.enabled, true)}>
|
||||
<label class="pf-c-check__label">
|
||||
${t`Enabled`}
|
||||
</label>
|
||||
@ -213,7 +210,7 @@ export class PolicyBindingForm extends Form<PolicyBinding> {
|
||||
label=${t`Timeout`}
|
||||
?required=${true}
|
||||
name="timeout">
|
||||
<input type="number" value="${first(this.binding?.timeout, 30)}" class="pf-c-form-control" required>
|
||||
<input type="number" value="${first(this.instance?.timeout, 30)}" class="pf-c-form-control" required>
|
||||
</ak-form-element-horizontal>
|
||||
</form>`;
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ export class PolicyListPage extends TablePage<Policy> {
|
||||
<ak-proxy-form
|
||||
slot="form"
|
||||
.args=${{
|
||||
"policyUUID": item.pk
|
||||
"instancePk": item.pk
|
||||
}}
|
||||
type=${ifDefined(item.component)}>
|
||||
</ak-proxy-form>
|
||||
|
@ -1,30 +1,25 @@
|
||||
import { DummyPolicy, PoliciesApi } from "authentik-api";
|
||||
import { t } from "@lingui/macro";
|
||||
import { customElement, property } from "lit-element";
|
||||
import { customElement } from "lit-element";
|
||||
import { html, TemplateResult } from "lit-html";
|
||||
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||
import { Form } from "../../../elements/forms/Form";
|
||||
import { ifDefined } from "lit-html/directives/if-defined";
|
||||
import "../../../elements/forms/HorizontalFormElement";
|
||||
import "../../../elements/forms/FormGroup";
|
||||
import { first } from "../../../utils";
|
||||
import { ModelForm } from "../../../elements/forms/ModelForm";
|
||||
|
||||
@customElement("ak-policy-dummy-form")
|
||||
export class DummyPolicyForm extends Form<DummyPolicy> {
|
||||
export class DummyPolicyForm extends ModelForm<DummyPolicy, string> {
|
||||
|
||||
set policyUUID(value: string) {
|
||||
new PoliciesApi(DEFAULT_CONFIG).policiesDummyRead({
|
||||
policyUuid: value,
|
||||
}).then(policy => {
|
||||
this.policy = policy;
|
||||
loadInstance(pk: string): Promise<DummyPolicy> {
|
||||
return new PoliciesApi(DEFAULT_CONFIG).policiesDummyRead({
|
||||
policyUuid: pk,
|
||||
});
|
||||
}
|
||||
|
||||
@property({attribute: false})
|
||||
policy?: DummyPolicy;
|
||||
|
||||
getSuccessMessage(): string {
|
||||
if (this.policy) {
|
||||
if (this.instance) {
|
||||
return t`Successfully updated policy.`;
|
||||
} else {
|
||||
return t`Successfully created policy.`;
|
||||
@ -32,9 +27,9 @@ export class DummyPolicyForm extends Form<DummyPolicy> {
|
||||
}
|
||||
|
||||
send = (data: DummyPolicy): Promise<DummyPolicy> => {
|
||||
if (this.policy) {
|
||||
if (this.instance) {
|
||||
return new PoliciesApi(DEFAULT_CONFIG).policiesDummyUpdate({
|
||||
policyUuid: this.policy.pk || "",
|
||||
policyUuid: this.instance.pk || "",
|
||||
data: data
|
||||
});
|
||||
} else {
|
||||
@ -53,11 +48,11 @@ export class DummyPolicyForm extends Form<DummyPolicy> {
|
||||
label=${t`Name`}
|
||||
?required=${true}
|
||||
name="name">
|
||||
<input type="text" value="${ifDefined(this.policy?.name || "")}" class="pf-c-form-control" required>
|
||||
<input type="text" value="${ifDefined(this.instance?.name || "")}" class="pf-c-form-control" required>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="executionLogging">
|
||||
<div class="pf-c-check">
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.policy?.executionLogging, false)}>
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.instance?.executionLogging, false)}>
|
||||
<label class="pf-c-check__label">
|
||||
${t`Execution logging`}
|
||||
</label>
|
||||
@ -73,7 +68,7 @@ export class DummyPolicyForm extends Form<DummyPolicy> {
|
||||
<div slot="body" class="pf-c-form">
|
||||
<ak-form-element-horizontal name="result">
|
||||
<div class="pf-c-check">
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.policy?.result, false)}>
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.instance?.result, false)}>
|
||||
<label class="pf-c-check__label">
|
||||
${t`Pass policy?`}
|
||||
</label>
|
||||
@ -83,14 +78,14 @@ export class DummyPolicyForm extends Form<DummyPolicy> {
|
||||
label=${t`Wait (min)`}
|
||||
?required=${true}
|
||||
name="waitMin">
|
||||
<input type="number" value="${first(this.policy?.waitMin, 1)}" class="pf-c-form-control" required>
|
||||
<input type="number" value="${first(this.instance?.waitMin, 1)}" class="pf-c-form-control" required>
|
||||
<p class="pf-c-form__helper-text">${t`The policy takes a random time to execute. This controls the minimum time it will take.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Wait (max)`}
|
||||
?required=${true}
|
||||
name="waitMax">
|
||||
<input type="number" value="${first(this.policy?.waitMax, 5)}" class="pf-c-form-control" required>
|
||||
<input type="number" value="${first(this.instance?.waitMax, 5)}" class="pf-c-form-control" required>
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
|
@ -1,31 +1,26 @@
|
||||
import { AdminApi, EventMatcherPolicy, EventsApi, PoliciesApi } from "authentik-api";
|
||||
import { t } from "@lingui/macro";
|
||||
import { customElement, property } from "lit-element";
|
||||
import { customElement } from "lit-element";
|
||||
import { html, TemplateResult } from "lit-html";
|
||||
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||
import { Form } from "../../../elements/forms/Form";
|
||||
import { ifDefined } from "lit-html/directives/if-defined";
|
||||
import "../../../elements/forms/HorizontalFormElement";
|
||||
import "../../../elements/forms/FormGroup";
|
||||
import { until } from "lit-html/directives/until";
|
||||
import { first } from "../../../utils";
|
||||
import { ModelForm } from "../../../elements/forms/ModelForm";
|
||||
|
||||
@customElement("ak-policy-event-matcher-form")
|
||||
export class EventMatcherPolicyForm extends Form<EventMatcherPolicy> {
|
||||
export class EventMatcherPolicyForm extends ModelForm<EventMatcherPolicy, string> {
|
||||
|
||||
set policyUUID(value: string) {
|
||||
new PoliciesApi(DEFAULT_CONFIG).policiesEventMatcherRead({
|
||||
policyUuid: value,
|
||||
}).then(policy => {
|
||||
this.policy = policy;
|
||||
loadInstance(pk: string): Promise<EventMatcherPolicy> {
|
||||
return new PoliciesApi(DEFAULT_CONFIG).policiesEventMatcherRead({
|
||||
policyUuid: pk,
|
||||
});
|
||||
}
|
||||
|
||||
@property({attribute: false})
|
||||
policy?: EventMatcherPolicy;
|
||||
|
||||
getSuccessMessage(): string {
|
||||
if (this.policy) {
|
||||
if (this.instance) {
|
||||
return t`Successfully updated policy.`;
|
||||
} else {
|
||||
return t`Successfully created policy.`;
|
||||
@ -33,9 +28,9 @@ export class EventMatcherPolicyForm extends Form<EventMatcherPolicy> {
|
||||
}
|
||||
|
||||
send = (data: EventMatcherPolicy): Promise<EventMatcherPolicy> => {
|
||||
if (this.policy) {
|
||||
if (this.instance) {
|
||||
return new PoliciesApi(DEFAULT_CONFIG).policiesEventMatcherUpdate({
|
||||
policyUuid: this.policy.pk || "",
|
||||
policyUuid: this.instance.pk || "",
|
||||
data: data
|
||||
});
|
||||
} else {
|
||||
@ -54,11 +49,11 @@ export class EventMatcherPolicyForm extends Form<EventMatcherPolicy> {
|
||||
label=${t`Name`}
|
||||
?required=${true}
|
||||
name="name">
|
||||
<input type="text" value="${ifDefined(this.policy?.name || "")}" class="pf-c-form-control" required>
|
||||
<input type="text" value="${ifDefined(this.instance?.name || "")}" class="pf-c-form-control" required>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="executionLogging">
|
||||
<div class="pf-c-check">
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.policy?.executionLogging, false)}>
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.instance?.executionLogging, false)}>
|
||||
<label class="pf-c-check__label">
|
||||
${t`Execution logging`}
|
||||
</label>
|
||||
@ -76,10 +71,10 @@ export class EventMatcherPolicyForm extends Form<EventMatcherPolicy> {
|
||||
label=${t`Action`}
|
||||
name="action">
|
||||
<select class="pf-c-form-control">
|
||||
<option value="" ?selected=${this.policy?.action === undefined}>---------</option>
|
||||
<option value="" ?selected=${this.instance?.action === undefined}>---------</option>
|
||||
${until(new EventsApi(DEFAULT_CONFIG).eventsEventsActions().then(actions => {
|
||||
return actions.map(action => {
|
||||
return html`<option value=${action.component} ?selected=${this.policy?.action === action.component}>${action.name}</option>`;
|
||||
return html`<option value=${action.component} ?selected=${this.instance?.action === action.component}>${action.name}</option>`;
|
||||
});
|
||||
}), html`<option>${t`Loading...`}</option>`)}
|
||||
</select>
|
||||
@ -88,17 +83,17 @@ export class EventMatcherPolicyForm extends Form<EventMatcherPolicy> {
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Client IP`}
|
||||
name="clientIp">
|
||||
<input type="text" value="${ifDefined(this.policy?.clientIp || "")}" class="pf-c-form-control">
|
||||
<input type="text" value="${ifDefined(this.instance?.clientIp || "")}" class="pf-c-form-control">
|
||||
<p class="pf-c-form__helper-text">${t`Matches Event's Client IP (strict matching, for network matching use an Expression Policy.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`App`}
|
||||
name="app">
|
||||
<select class="pf-c-form-control">
|
||||
<option value="" ?selected=${this.policy?.app === undefined}>---------</option>
|
||||
<option value="" ?selected=${this.instance?.app === undefined}>---------</option>
|
||||
${until(new AdminApi(DEFAULT_CONFIG).adminAppsList().then(apps => {
|
||||
return apps.map(app => {
|
||||
return html`<option value=${app.name} ?selected=${this.policy?.app === app.name}>${app.label}</option>`;
|
||||
return html`<option value=${app.name} ?selected=${this.instance?.app === app.name}>${app.label}</option>`;
|
||||
});
|
||||
}), html`<option>${t`Loading...`}</option>`)}
|
||||
</select>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user