mirror of
https://github.com/goauthentik/authentik
synced 2026-05-06 07:02:51 +02:00
Compare commits
79 Commits
website/do
...
docs/invit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29d71e8b83 | ||
|
|
731163200a | ||
|
|
a8db2882ec | ||
|
|
befc15ad92 | ||
|
|
2b48c27760 | ||
|
|
6be7b2f7b7 | ||
|
|
7cffbb4d07 | ||
|
|
5d629bec9b | ||
|
|
5357f42029 | ||
|
|
716bc6e136 | ||
|
|
60355fdf80 | ||
|
|
828a380569 | ||
|
|
b04f8a6177 | ||
|
|
ff190847f2 | ||
|
|
a7339c7f87 | ||
|
|
38ae472f6c | ||
|
|
7d0656c6fa | ||
|
|
0bbe415b5b | ||
|
|
e52c1b2bdc | ||
|
|
5064167f28 | ||
|
|
bca0f51b53 | ||
|
|
67c197e5a5 | ||
|
|
32b17da699 | ||
|
|
c75eed630a | ||
|
|
9f17d6df96 | ||
|
|
13c8ad5c56 | ||
|
|
28209c03e2 | ||
|
|
f47cf08d8a | ||
|
|
d69433b314 | ||
|
|
849a6053ad | ||
|
|
abdbe0269f | ||
|
|
55384c384a | ||
|
|
06fd68f076 | ||
|
|
d35ab99b2d | ||
|
|
a3b0180049 | ||
|
|
88a545f4fb | ||
|
|
ba62507fc2 | ||
|
|
82fc2e2c80 | ||
|
|
80b3739640 | ||
|
|
1258e1eada | ||
|
|
96ed17e760 | ||
|
|
4b17468b6e | ||
|
|
c834681251 | ||
|
|
9edd7cfbda | ||
|
|
4851179522 | ||
|
|
685f920de2 | ||
|
|
3b4d51b0c5 | ||
|
|
a1098d00b7 | ||
|
|
0d4984b964 | ||
|
|
38330df1f9 | ||
|
|
8b03c36d5a | ||
|
|
07a53a101c | ||
|
|
a3db2ce6a3 | ||
|
|
5487cdb874 | ||
|
|
2d5160d09b | ||
|
|
973fe0bd65 | ||
|
|
58b5e605de | ||
|
|
626e23b87a | ||
|
|
3559beba9c | ||
|
|
0b6d3a2850 | ||
|
|
56ca192391 | ||
|
|
6df62aaa2a | ||
|
|
ca344a64c4 | ||
|
|
a0cdd81f71 | ||
|
|
8eff4c7e0b | ||
|
|
d241a0e8f1 | ||
|
|
ebfc01fcda | ||
|
|
4b0e8a411b | ||
|
|
9bf6595fc6 | ||
|
|
5c07e845d2 | ||
|
|
4f76232e7c | ||
|
|
846f8a7e30 | ||
|
|
fa1c3490c3 | ||
|
|
a35edf7d0f | ||
|
|
9d4d5b7133 | ||
|
|
8d91a76bc9 | ||
|
|
6910428a93 | ||
|
|
cb181d388a | ||
|
|
aad4b6f925 |
2
.github/actions/setup/action.yml
vendored
2
.github/actions/setup/action.yml
vendored
@@ -64,7 +64,7 @@ runs:
|
||||
rustflags: ""
|
||||
- name: Setup rust dependencies
|
||||
if: ${{ contains(inputs.dependencies, 'rust') }}
|
||||
uses: taiki-e/install-action@481c34c1cf3a84c68b5e46f4eccfc82af798415a # v2
|
||||
uses: taiki-e/install-action@b5fddbb5361bce8a06fb168c9d403a6cc552b084 # v2
|
||||
with:
|
||||
tool: cargo-deny cargo-machete cargo-llvm-cov nextest
|
||||
- name: Setup node (web)
|
||||
|
||||
2
.github/workflows/_reusable-docker-build.yml
vendored
2
.github/workflows/_reusable-docker-build.yml
vendored
@@ -90,7 +90,7 @@ jobs:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: int128/docker-manifest-create-action@7df7f9e221d927eaadf87db231ddf728047308a4 # v2
|
||||
- uses: int128/docker-manifest-create-action@fa55f72001a6c74b0f4997dca65c70d334905180 # v2
|
||||
id: build
|
||||
with:
|
||||
tags: ${{ matrix.tag }}
|
||||
|
||||
16
.github/workflows/ci-main.yml
vendored
16
.github/workflows/ci-main.yml
vendored
@@ -282,10 +282,18 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
- name: basic
|
||||
glob: tests/openid_conformance/test_basic.py
|
||||
- name: implicit
|
||||
glob: tests/openid_conformance/test_implicit.py
|
||||
- name: oidc_basic
|
||||
glob: tests/openid_conformance/test_oidc_basic.py
|
||||
- name: oidc_implicit
|
||||
glob: tests/openid_conformance/test_oidc_implicit.py
|
||||
- name: oidc_rp-initiated
|
||||
glob: tests/openid_conformance/test_oidc_rp_initiated.py
|
||||
- name: oidc_frontchannel
|
||||
glob: tests/openid_conformance/test_oidc_frontchannel.py
|
||||
- name: oidc_backchannel
|
||||
glob: tests/openid_conformance/test_oidc_backchannel.py
|
||||
- name: ssf_transmitter
|
||||
glob: tests/openid_conformance/test_ssf_transmitter.py
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- name: Setup authentik env
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -229,6 +229,11 @@ source_docs/
|
||||
|
||||
### Golang ###
|
||||
/vendor/
|
||||
server
|
||||
proxy
|
||||
ldap
|
||||
rac
|
||||
radius
|
||||
|
||||
### Docker ###
|
||||
tests/openid_conformance/exports/*.zip
|
||||
|
||||
108
Cargo.lock
generated
108
Cargo.lock
generated
@@ -17,18 +17,6 @@ version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.4"
|
||||
@@ -203,6 +191,7 @@ dependencies = [
|
||||
"tokio",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1014,6 +1003,17 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "evmap"
|
||||
version = "11.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b8874945f036109c72242964c1174cf99434e30cfa45bf45fedc983f50046f8"
|
||||
dependencies = [
|
||||
"hashbag",
|
||||
"left-right",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eyre"
|
||||
version = "0.6.12"
|
||||
@@ -1230,6 +1230,21 @@ dependencies = [
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generator"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"log",
|
||||
"rustversion",
|
||||
"windows-link",
|
||||
"windows-result",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
@@ -1311,6 +1326,12 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbag"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7040a10f52cba493ddb09926e15d10a9d8a28043708a405931fe4c6f19fac064"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.5"
|
||||
@@ -1868,6 +1889,17 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
||||
|
||||
[[package]]
|
||||
name = "left-right"
|
||||
version = "0.11.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f0c21e4c8ff95f487fb34e6f9182875f42c84cef966d29216bf115d9bba835a"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
"loom",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.183"
|
||||
@@ -1939,6 +1971,19 @@ version = "0.4.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||
|
||||
[[package]]
|
||||
name = "loom"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"generator",
|
||||
"scoped-tls",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lru-slab"
|
||||
version = "0.1.2"
|
||||
@@ -1978,21 +2023,22 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||
|
||||
[[package]]
|
||||
name = "metrics"
|
||||
version = "0.24.3"
|
||||
version = "0.24.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d5312e9ba3771cfa961b585728215e3d972c950a3eed9252aa093d6301277e8"
|
||||
checksum = "ff56c2e7dce6bd462e3b8919986a617027481b1dcc703175b58cf9dd98a2f071"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"portable-atomic",
|
||||
"rapidhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "metrics-exporter-prometheus"
|
||||
version = "0.18.1"
|
||||
version = "0.18.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3589659543c04c7dc5526ec858591015b87cd8746583b51b48ef4353f99dbcda"
|
||||
checksum = "1db0d8f1fc9e62caebd0319e11eaec5822b0186c171568f0480b46a0137f9108"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"evmap",
|
||||
"indexmap",
|
||||
"metrics",
|
||||
"metrics-util",
|
||||
@@ -2813,6 +2859,15 @@ dependencies = [
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rapidhash"
|
||||
version = "4.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e48930979c155e2f33aa36ab3119b5ee81332beb6482199a8ecd6029b80b59"
|
||||
dependencies = [
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raw-cpuid"
|
||||
version = "11.6.0"
|
||||
@@ -2871,9 +2926,9 @@ checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.13.2"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801"
|
||||
checksum = "62e0021ea2c22aed41653bc7e1419abb2c97e038ff2c33d0e1309e49a97deec0"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
@@ -3105,6 +3160,12 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
@@ -4515,6 +4576,15 @@ dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "8.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81995fafaaaf6ae47a7d0cc83c67caf92aeb7e5331650ae6ff856f7c0c60c459"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "whoami"
|
||||
version = "1.6.1"
|
||||
|
||||
@@ -43,15 +43,15 @@ hyper-unix-socket = "= 0.6.1"
|
||||
hyper-util = "= 0.1.20"
|
||||
ipnet = { version = "= 2.12.0", features = ["serde"] }
|
||||
json-subscriber = "= 0.2.8"
|
||||
metrics = "= 0.24.3"
|
||||
metrics-exporter-prometheus = { version = "= 0.18.1", default-features = false }
|
||||
metrics = "= 0.24.5"
|
||||
metrics-exporter-prometheus = { version = "= 0.18.3", default-features = false }
|
||||
nix = { version = "= 0.31.2", features = ["hostname", "signal"] }
|
||||
notify = "= 8.2.0"
|
||||
pin-project-lite = "= 0.2.17"
|
||||
pyo3 = "= 0.28.3"
|
||||
pyo3-build-config = "= 0.28.3"
|
||||
regex = "= 1.12.3"
|
||||
reqwest = { version = "= 0.13.2", features = [
|
||||
reqwest = { version = "= 0.13.3", features = [
|
||||
"form",
|
||||
"json",
|
||||
"multipart",
|
||||
@@ -113,6 +113,7 @@ tracing-subscriber = { version = "= 0.3.23", features = [
|
||||
] }
|
||||
url = "= 2.5.8"
|
||||
uuid = { version = "= 1.23.1", features = ["serde", "v4"] }
|
||||
which = "= 8.0.2"
|
||||
|
||||
ak-axum = { package = "authentik-axum", version = "2026.5.0-rc1", path = "./packages/ak-axum" }
|
||||
ak-client = { package = "authentik-client", version = "2026.5.0-rc1", path = "./packages/client-rust" }
|
||||
@@ -282,6 +283,7 @@ sqlx = { workspace = true, optional = true }
|
||||
tokio.workspace = true
|
||||
tracing.workspace = true
|
||||
uuid.workspace = true
|
||||
which.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
11
Makefile
11
Makefile
@@ -109,14 +109,11 @@ i18n-extract: core-i18n-extract web-i18n-extract ## Extract strings that requir
|
||||
aws-cfn:
|
||||
cd lifecycle/aws && npm i && $(UV) run npm run aws-cfn
|
||||
|
||||
run-server: ## Run the main authentik server process
|
||||
$(UV) run ak server
|
||||
run: ## Run the main authentik server and worker processes
|
||||
$(UV) run ak allinone
|
||||
|
||||
run-worker: ## Run the main authentik worker process
|
||||
$(UV) run ak worker
|
||||
|
||||
run-worker-watch: ## Run the authentik worker, with auto reloading
|
||||
watchexec --on-busy-update=restart --stop-signal=SIGINT --exts py,rs --no-meta --notify -- $(UV) run ak worker
|
||||
run-watch: ## Run the authentik server and worker, with auto reloading
|
||||
watchexec --on-busy-update=restart --stop-signal=SIGINT --exts py,rs,go --no-meta --notify -- $(UV) run ak allinone
|
||||
|
||||
core-i18n-extract:
|
||||
$(UV) run ak makemessages \
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"""Serializer mixin for managed models"""
|
||||
|
||||
from json import JSONDecodeError, loads
|
||||
from typing import cast
|
||||
|
||||
from django.conf import settings
|
||||
@@ -44,6 +45,7 @@ class BlueprintUploadSerializer(PassiveSerializer):
|
||||
|
||||
file = FileField(required=False)
|
||||
path = CharField(required=False)
|
||||
context = CharField(required=False, allow_blank=True)
|
||||
|
||||
def validate_path(self, path: str) -> str:
|
||||
"""Ensure the path (if set) specified is retrievable"""
|
||||
@@ -54,6 +56,18 @@ class BlueprintUploadSerializer(PassiveSerializer):
|
||||
raise ValidationError(_("Blueprint file does not exist"))
|
||||
return path
|
||||
|
||||
def validate_context(self, context: str) -> dict:
|
||||
"""Parse context as a JSON object"""
|
||||
if not context:
|
||||
return {}
|
||||
try:
|
||||
parsed = loads(context)
|
||||
except JSONDecodeError as exc:
|
||||
raise ValidationError(_("Context must be valid JSON")) from exc
|
||||
if not isinstance(parsed, dict):
|
||||
raise ValidationError(_("Context must be a JSON object"))
|
||||
return parsed
|
||||
|
||||
|
||||
class ManagedSerializer:
|
||||
"""Managed Serializer"""
|
||||
@@ -224,7 +238,8 @@ class BlueprintInstanceViewSet(UsedByMixin, ModelViewSet):
|
||||
).retrieve_file()
|
||||
else:
|
||||
raise ValidationError("Either path or file must be set")
|
||||
importer = Importer.from_string(string_contents)
|
||||
context = body.validated_data.get("context") or {}
|
||||
importer = Importer.from_string(string_contents, context)
|
||||
|
||||
check_blueprint_perms(importer.blueprint, request.user)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Test blueprints v1 api"""
|
||||
|
||||
from json import loads
|
||||
from json import dumps, loads
|
||||
from tempfile import NamedTemporaryFile, mkdtemp
|
||||
|
||||
from django.urls import reverse
|
||||
@@ -8,7 +8,11 @@ from rest_framework.test import APITestCase
|
||||
from yaml import dump
|
||||
|
||||
from authentik.core.tests.utils import create_test_admin_user
|
||||
from authentik.flows.models import Flow
|
||||
from authentik.lib.config import CONFIG
|
||||
from authentik.lib.generators import generate_id
|
||||
from authentik.stages.invitation.models import InvitationStage
|
||||
from authentik.stages.user_write.models import UserWriteStage
|
||||
|
||||
TMP = mkdtemp("authentik-blueprints")
|
||||
|
||||
@@ -80,3 +84,107 @@ class TestBlueprintsV1API(APITestCase):
|
||||
res.content.decode(),
|
||||
{"content": ["Failed to validate blueprint", "- Invalid blueprint version"]},
|
||||
)
|
||||
|
||||
def test_api_import_with_context(self):
|
||||
"""Test that the import endpoint applies the supplied context to the real blueprint"""
|
||||
slug = f"invitation-enrollment-{generate_id()}"
|
||||
flow_name = f"Invitation Enrollment {generate_id()}"
|
||||
stage_name = f"invitation-stage-{generate_id()}"
|
||||
user_type = "internal"
|
||||
continue_without_invitation = True
|
||||
|
||||
res = self.client.post(
|
||||
reverse("authentik_api:blueprintinstance-import-"),
|
||||
data={
|
||||
"path": "example/flows-invitation-enrollment-minimal.yaml",
|
||||
"context": dumps(
|
||||
{
|
||||
"flow_slug": slug,
|
||||
"flow_name": flow_name,
|
||||
"stage_name": stage_name,
|
||||
"continue_flow_without_invitation": continue_without_invitation,
|
||||
"user_type": user_type,
|
||||
}
|
||||
),
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertTrue(res.json()["success"])
|
||||
|
||||
flow = Flow.objects.get(slug=slug)
|
||||
self.assertEqual(flow.name, flow_name)
|
||||
self.assertEqual(flow.title, flow_name)
|
||||
|
||||
invitation_stage = InvitationStage.objects.get(name=stage_name)
|
||||
self.assertEqual(
|
||||
invitation_stage.continue_flow_without_invitation,
|
||||
continue_without_invitation,
|
||||
)
|
||||
|
||||
user_write_stage = UserWriteStage.objects.get(
|
||||
name=f"invitation-enrollment-user-write-{slug}"
|
||||
)
|
||||
self.assertEqual(user_write_stage.user_type, user_type)
|
||||
self.assertEqual(user_write_stage.user_path_template, f"users/{user_type}")
|
||||
|
||||
def test_api_import_blank_path(self):
|
||||
"""Validator returns empty path unchanged (covers api.py:53)."""
|
||||
with NamedTemporaryFile(mode="w+", suffix=".yaml") as file:
|
||||
file.write(dump({"version": 1, "entries": []}))
|
||||
file.flush()
|
||||
file.seek(0)
|
||||
res = self.client.post(
|
||||
reverse("authentik_api:blueprintinstance-import-"),
|
||||
data={"path": "", "file": file},
|
||||
format="multipart",
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
def test_api_import_unknown_path(self):
|
||||
"""Path not in available blueprints is rejected (covers api.py:56)."""
|
||||
res = self.client.post(
|
||||
reverse("authentik_api:blueprintinstance-import-"),
|
||||
data={"path": "does/not/exist.yaml"},
|
||||
format="multipart",
|
||||
)
|
||||
self.assertEqual(res.status_code, 400)
|
||||
self.assertIn("Blueprint file does not exist", res.content.decode())
|
||||
|
||||
def test_api_import_blank_context(self):
|
||||
"""Blank context is normalized to empty dict (covers api.py:62)."""
|
||||
res = self.client.post(
|
||||
reverse("authentik_api:blueprintinstance-import-"),
|
||||
data={
|
||||
"path": "example/flows-invitation-enrollment-minimal.yaml",
|
||||
"context": "",
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
def test_api_import_invalid_json_context(self):
|
||||
"""Malformed JSON context raises ValidationError (covers api.py:65-66)."""
|
||||
res = self.client.post(
|
||||
reverse("authentik_api:blueprintinstance-import-"),
|
||||
data={
|
||||
"path": "example/flows-invitation-enrollment-minimal.yaml",
|
||||
"context": "{not json",
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
self.assertEqual(res.status_code, 400)
|
||||
self.assertIn("Context must be valid JSON", res.content.decode())
|
||||
|
||||
def test_api_import_non_object_context(self):
|
||||
"""JSON context that isn't an object is rejected (covers api.py:68)."""
|
||||
res = self.client.post(
|
||||
reverse("authentik_api:blueprintinstance-import-"),
|
||||
data={
|
||||
"path": "example/flows-invitation-enrollment-minimal.yaml",
|
||||
"context": "[1, 2, 3]",
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
self.assertEqual(res.status_code, 400)
|
||||
self.assertIn("Context must be a JSON object", res.content.decode())
|
||||
|
||||
@@ -32,19 +32,19 @@ from authentik.rbac.decorators import permission_required
|
||||
class UserAgentDeviceDict(TypedDict):
|
||||
"""User agent device"""
|
||||
|
||||
brand: str
|
||||
brand: str | None = None
|
||||
family: str
|
||||
model: str
|
||||
model: str | None = None
|
||||
|
||||
|
||||
class UserAgentOSDict(TypedDict):
|
||||
"""User agent os"""
|
||||
|
||||
family: str
|
||||
major: str
|
||||
minor: str
|
||||
patch: str
|
||||
patch_minor: str
|
||||
major: str | None = None
|
||||
minor: str | None = None
|
||||
patch: str | None = None
|
||||
patch_minor: str | None = None
|
||||
|
||||
|
||||
class UserAgentBrowserDict(TypedDict):
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"""authentik core signals"""
|
||||
|
||||
from asgiref.sync import async_to_sync
|
||||
from channels.layers import get_channel_layer
|
||||
from django.contrib.auth.signals import user_logged_in
|
||||
from django.core.cache import cache
|
||||
@@ -59,7 +58,7 @@ def user_logged_in_session(sender, request: HttpRequest, user: User, **_):
|
||||
layer = get_channel_layer()
|
||||
device_cookie = request.COOKIES.get("authentik_device")
|
||||
if device_cookie:
|
||||
async_to_sync(layer.group_send)(
|
||||
layer.group_send_blocking(
|
||||
build_device_group(device_cookie),
|
||||
{"type": "event.session.authenticated"},
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Generated by Django 5.2.12 on 2026-04-04 16:58
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.contrib.postgres.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
@@ -40,4 +41,109 @@ class Migration(migrations.Migration):
|
||||
]
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="stream",
|
||||
name="events_requested",
|
||||
field=django.contrib.postgres.fields.ArrayField(
|
||||
base_field=models.TextField(
|
||||
choices=[
|
||||
(
|
||||
"https://schemas.openid.net/secevent/caep/event-type/session-revoked",
|
||||
"Caep Session Revoked",
|
||||
),
|
||||
(
|
||||
"https://schemas.openid.net/secevent/caep/event-type/token-claims-change",
|
||||
"Caep Token Claims Change",
|
||||
),
|
||||
(
|
||||
"https://schemas.openid.net/secevent/caep/event-type/credential-change",
|
||||
"Caep Credential Change",
|
||||
),
|
||||
(
|
||||
"https://schemas.openid.net/secevent/caep/event-type/assurance-level-change",
|
||||
"Caep Assurance Level Change",
|
||||
),
|
||||
(
|
||||
"https://schemas.openid.net/secevent/caep/event-type/device-compliance-change",
|
||||
"Caep Device Compliance Change",
|
||||
),
|
||||
(
|
||||
"https://schemas.openid.net/secevent/caep/event-type/session-established",
|
||||
"Caep Session Established",
|
||||
),
|
||||
(
|
||||
"https://schemas.openid.net/secevent/caep/event-type/session-presented",
|
||||
"Caep Session Presented",
|
||||
),
|
||||
(
|
||||
"https://schemas.openid.net/secevent/caep/event-type/risk-level-change",
|
||||
"Caep Risk Level Change",
|
||||
),
|
||||
(
|
||||
"https://schemas.openid.net/secevent/ssf/event-type/verification",
|
||||
"Set Verification",
|
||||
),
|
||||
]
|
||||
),
|
||||
default=list,
|
||||
size=None,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="stream",
|
||||
name="status",
|
||||
field=models.TextField(
|
||||
choices=[
|
||||
("enabled", "Enabled"),
|
||||
("paused", "Paused"),
|
||||
("disabled", "Disabled"),
|
||||
("disabled_deleted", "Disabled Deleted"),
|
||||
],
|
||||
default="enabled",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="streamevent",
|
||||
name="type",
|
||||
field=models.TextField(
|
||||
choices=[
|
||||
(
|
||||
"https://schemas.openid.net/secevent/caep/event-type/session-revoked",
|
||||
"Caep Session Revoked",
|
||||
),
|
||||
(
|
||||
"https://schemas.openid.net/secevent/caep/event-type/token-claims-change",
|
||||
"Caep Token Claims Change",
|
||||
),
|
||||
(
|
||||
"https://schemas.openid.net/secevent/caep/event-type/credential-change",
|
||||
"Caep Credential Change",
|
||||
),
|
||||
(
|
||||
"https://schemas.openid.net/secevent/caep/event-type/assurance-level-change",
|
||||
"Caep Assurance Level Change",
|
||||
),
|
||||
(
|
||||
"https://schemas.openid.net/secevent/caep/event-type/device-compliance-change",
|
||||
"Caep Device Compliance Change",
|
||||
),
|
||||
(
|
||||
"https://schemas.openid.net/secevent/caep/event-type/session-established",
|
||||
"Caep Session Established",
|
||||
),
|
||||
(
|
||||
"https://schemas.openid.net/secevent/caep/event-type/session-presented",
|
||||
"Caep Session Presented",
|
||||
),
|
||||
(
|
||||
"https://schemas.openid.net/secevent/caep/event-type/risk-level-change",
|
||||
"Caep Risk Level Change",
|
||||
),
|
||||
(
|
||||
"https://schemas.openid.net/secevent/ssf/event-type/verification",
|
||||
"Set Verification",
|
||||
),
|
||||
]
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -24,8 +24,31 @@ class EventTypes(models.TextChoices):
|
||||
"""SSF Event types supported by authentik"""
|
||||
|
||||
CAEP_SESSION_REVOKED = "https://schemas.openid.net/secevent/caep/event-type/session-revoked"
|
||||
"""https://openid.net/specs/openid-caep-1_0-final.html#section-3.1"""
|
||||
CAEP_TOKEN_CLAIMS_CHANGE = (
|
||||
"https://schemas.openid.net/secevent/caep/event-type/token-claims-change"
|
||||
)
|
||||
"""https://openid.net/specs/openid-caep-1_0-final.html#section-3.2"""
|
||||
CAEP_CREDENTIAL_CHANGE = "https://schemas.openid.net/secevent/caep/event-type/credential-change"
|
||||
"""https://openid.net/specs/openid-caep-1_0-final.html#section-3.3"""
|
||||
CAEP_ASSURANCE_LEVEL_CHANGE = (
|
||||
"https://schemas.openid.net/secevent/caep/event-type/assurance-level-change"
|
||||
)
|
||||
"""https://openid.net/specs/openid-caep-1_0-final.html#section-3.4"""
|
||||
CAEP_DEVICE_COMPLIANCE_CHANGE = (
|
||||
"https://schemas.openid.net/secevent/caep/event-type/device-compliance-change"
|
||||
)
|
||||
"""https://openid.net/specs/openid-caep-1_0-final.html#section-3.5"""
|
||||
CAEP_SESSION_ESTABLISHED = (
|
||||
"https://schemas.openid.net/secevent/caep/event-type/session-established"
|
||||
)
|
||||
"""https://openid.net/specs/openid-caep-1_0-final.html#section-3.6"""
|
||||
CAEP_SESSION_PRESENTED = "https://schemas.openid.net/secevent/caep/event-type/session-presented"
|
||||
"""https://openid.net/specs/openid-caep-1_0-final.html#section-3.7"""
|
||||
CAEP_RISK_LEVEL_CHANGE = "https://schemas.openid.net/secevent/caep/event-type/risk-level-change"
|
||||
"""https://openid.net/specs/openid-caep-1_0-final.html#section-3.8"""
|
||||
SET_VERIFICATION = "https://schemas.openid.net/secevent/ssf/event-type/verification"
|
||||
"""https://openid.net/specs/openid-sharedsignals-framework-1_0.html#section-8.1.4.1"""
|
||||
|
||||
|
||||
class DeliveryMethods(models.TextChoices):
|
||||
@@ -46,10 +69,12 @@ class SSFEventStatus(models.TextChoices):
|
||||
|
||||
|
||||
class StreamStatus(models.TextChoices):
|
||||
"""SSF Stream status"""
|
||||
|
||||
ENABLED = "enabled"
|
||||
PAUSED = "paused"
|
||||
DISABLED = "disabled"
|
||||
DISABLED_DELETED = "disabled_deleted"
|
||||
|
||||
|
||||
class SSFProvider(TasksModel, BackchannelProvider):
|
||||
|
||||
@@ -108,13 +108,13 @@ def send_ssf_event(stream_uuid: UUID, event_data: dict[str, Any]):
|
||||
event.save()
|
||||
self.info("Event successfully sent", status=response.status_code)
|
||||
# Cleanup, if we were the last pending message for this stream and it has been deleted
|
||||
# (status=StreamStatus.DISABLED), then we can delete the stream
|
||||
# (status=StreamStatus.DISABLED_DELETED), then we can delete the stream
|
||||
if (
|
||||
not StreamEvent.objects.filter(
|
||||
stream=stream,
|
||||
status__in=[SSFEventStatus.PENDING_FAILED, SSFEventStatus.PENDING_NEW],
|
||||
).exists()
|
||||
and stream.status == StreamStatus.DISABLED
|
||||
and stream.status == StreamStatus.DISABLED_DELETED
|
||||
):
|
||||
LOGGER.info(
|
||||
"Deleting inactive stream as all pending messages were sent.", stream=stream
|
||||
|
||||
@@ -62,7 +62,7 @@ class TestSSFAuth(APITestCase):
|
||||
self.assertEqual(event.status, SSFEventStatus.PENDING_FAILED)
|
||||
self.assertEqual(
|
||||
event.payload["events"],
|
||||
{"https://schemas.openid.net/secevent/ssf/event-type/verification": {"state": None}},
|
||||
{"https://schemas.openid.net/secevent/ssf/event-type/verification": {}},
|
||||
)
|
||||
|
||||
def test_stream_add_oidc(self):
|
||||
@@ -115,7 +115,7 @@ class TestSSFAuth(APITestCase):
|
||||
self.assertEqual(event.status, SSFEventStatus.PENDING_FAILED)
|
||||
self.assertEqual(
|
||||
event.payload["events"],
|
||||
{"https://schemas.openid.net/secevent/ssf/event-type/verification": {"state": None}},
|
||||
{"https://schemas.openid.net/secevent/ssf/event-type/verification": {}},
|
||||
)
|
||||
|
||||
def test_token_invalid(self):
|
||||
|
||||
@@ -54,7 +54,7 @@ class TestStream(APITestCase):
|
||||
self.assertEqual(event.status, SSFEventStatus.PENDING_FAILED)
|
||||
self.assertEqual(
|
||||
event.payload["events"],
|
||||
{"https://schemas.openid.net/secevent/ssf/event-type/verification": {"state": None}},
|
||||
{"https://schemas.openid.net/secevent/ssf/event-type/verification": {}},
|
||||
)
|
||||
|
||||
def test_stream_add_poll(self):
|
||||
@@ -96,7 +96,7 @@ class TestStream(APITestCase):
|
||||
)
|
||||
self.assertEqual(res.status_code, 204)
|
||||
stream.refresh_from_db()
|
||||
self.assertEqual(stream.status, StreamStatus.DISABLED)
|
||||
self.assertEqual(stream.status, StreamStatus.DISABLED_DELETED)
|
||||
|
||||
def test_stream_get(self):
|
||||
"""get stream"""
|
||||
@@ -225,3 +225,26 @@ class TestStream(APITestCase):
|
||||
HTTP_AUTHORIZATION=f"Bearer {self.provider.token.key}",
|
||||
)
|
||||
self.assertEqual(res.status_code, 404)
|
||||
|
||||
def test_stream_status_update(self):
|
||||
stream = Stream.objects.create(provider=self.provider)
|
||||
res = self.client.post(
|
||||
reverse(
|
||||
"authentik_providers_ssf:stream-status",
|
||||
kwargs={"application_slug": self.application.slug},
|
||||
),
|
||||
data={
|
||||
"stream_id": str(stream.pk),
|
||||
"status": StreamStatus.DISABLED,
|
||||
},
|
||||
HTTP_AUTHORIZATION=f"Bearer {self.provider.token.key}",
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
stream.refresh_from_db()
|
||||
self.assertJSONEqual(
|
||||
res.content,
|
||||
{
|
||||
"stream_id": str(stream.pk),
|
||||
"status": str(stream.status),
|
||||
},
|
||||
)
|
||||
|
||||
@@ -33,7 +33,7 @@ class TestTasks(APITestCase):
|
||||
)
|
||||
event_data = stream.prepare_event_payload(
|
||||
EventTypes.SET_VERIFICATION,
|
||||
{"state": None},
|
||||
{},
|
||||
sub_id={"format": "opaque", "id": str(stream.uuid)},
|
||||
)
|
||||
with Mocker() as mocker:
|
||||
@@ -46,7 +46,7 @@ class TestTasks(APITestCase):
|
||||
)
|
||||
jwt = decode_complete(mocker.request_history[0].body, options={"verify_signature": False})
|
||||
self.assertEqual(jwt["header"]["typ"], "secevent+jwt")
|
||||
self.assertIsNone(jwt["payload"]["events"][EventTypes.SET_VERIFICATION]["state"])
|
||||
self.assertEqual(jwt["payload"]["events"][EventTypes.SET_VERIFICATION], {})
|
||||
|
||||
def test_push_auth(self):
|
||||
auth = generate_id()
|
||||
@@ -58,7 +58,7 @@ class TestTasks(APITestCase):
|
||||
)
|
||||
event_data = stream.prepare_event_payload(
|
||||
EventTypes.SET_VERIFICATION,
|
||||
{"state": None},
|
||||
{},
|
||||
sub_id={"format": "opaque", "id": str(stream.uuid)},
|
||||
)
|
||||
with Mocker() as mocker:
|
||||
@@ -72,7 +72,7 @@ class TestTasks(APITestCase):
|
||||
)
|
||||
jwt = decode_complete(mocker.request_history[0].body, options={"verify_signature": False})
|
||||
self.assertEqual(jwt["header"]["typ"], "secevent+jwt")
|
||||
self.assertIsNone(jwt["payload"]["events"][EventTypes.SET_VERIFICATION]["state"])
|
||||
self.assertEqual(jwt["payload"]["events"][EventTypes.SET_VERIFICATION], {})
|
||||
|
||||
def test_push_stream_disable(self):
|
||||
auth = generate_id()
|
||||
@@ -81,11 +81,11 @@ class TestTasks(APITestCase):
|
||||
delivery_method=DeliveryMethods.RFC_PUSH,
|
||||
endpoint_url="http://localhost/ssf-push",
|
||||
authorization_header=auth,
|
||||
status=StreamStatus.DISABLED,
|
||||
status=StreamStatus.DISABLED_DELETED,
|
||||
)
|
||||
event_data = stream.prepare_event_payload(
|
||||
EventTypes.SET_VERIFICATION,
|
||||
{"state": None},
|
||||
{},
|
||||
sub_id={"format": "opaque", "id": str(stream.uuid)},
|
||||
)
|
||||
with Mocker() as mocker:
|
||||
@@ -95,7 +95,7 @@ class TestTasks(APITestCase):
|
||||
).get_result(block=True, timeout=1)
|
||||
jwt = decode_complete(mocker.request_history[0].body, options={"verify_signature": False})
|
||||
self.assertEqual(jwt["header"]["typ"], "secevent+jwt")
|
||||
self.assertIsNone(jwt["payload"]["events"][EventTypes.SET_VERIFICATION]["state"])
|
||||
self.assertEqual(jwt["payload"]["events"][EventTypes.SET_VERIFICATION], {})
|
||||
self.assertFalse(Stream.objects.filter(pk=stream.pk).exists())
|
||||
|
||||
def test_push_error(self):
|
||||
@@ -106,7 +106,7 @@ class TestTasks(APITestCase):
|
||||
)
|
||||
event_data = stream.prepare_event_payload(
|
||||
EventTypes.SET_VERIFICATION,
|
||||
{"state": None},
|
||||
{},
|
||||
sub_id={"format": "opaque", "id": str(stream.uuid)},
|
||||
)
|
||||
with Mocker() as mocker:
|
||||
|
||||
@@ -24,10 +24,10 @@ class SSFView(APIView):
|
||||
|
||||
|
||||
class SSFStreamView(SSFView):
|
||||
def get_object(self, any_status=False) -> Stream:
|
||||
streams = Stream.objects.filter(provider=self.provider)
|
||||
if not any_status:
|
||||
streams = streams.filter(status__in=[StreamStatus.ENABLED, StreamStatus.PAUSED])
|
||||
def get_object(self) -> Stream:
|
||||
streams = Stream.objects.filter(provider=self.provider).exclude(
|
||||
status=StreamStatus.DISABLED_DELETED
|
||||
)
|
||||
if "stream_id" in self.request.query_params:
|
||||
streams = streams.filter(pk=self.request.query_params["stream_id"])
|
||||
if "stream_id" in self.request.data:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from uuid import uuid4
|
||||
|
||||
from django.http import HttpRequest
|
||||
from django.http import Http404, HttpRequest
|
||||
from django.urls import reverse
|
||||
from rest_framework.exceptions import PermissionDenied, ValidationError
|
||||
from rest_framework.fields import CharField, ChoiceField, ListField, SerializerMethodField
|
||||
@@ -106,7 +106,11 @@ class StreamResponseSerializer(PassiveSerializer):
|
||||
}
|
||||
|
||||
def get_events_supported(self, instance: Stream) -> list[str]:
|
||||
return [x.value for x in EventTypes]
|
||||
return [
|
||||
EventTypes.CAEP_SESSION_REVOKED,
|
||||
EventTypes.CAEP_CREDENTIAL_CHANGE,
|
||||
EventTypes.SET_VERIFICATION,
|
||||
]
|
||||
|
||||
|
||||
class StreamView(SSFStreamView):
|
||||
@@ -128,10 +132,9 @@ class StreamView(SSFStreamView):
|
||||
LOGGER.info("Sending verification event", stream=instance)
|
||||
send_ssf_events(
|
||||
EventTypes.SET_VERIFICATION,
|
||||
{
|
||||
"state": None,
|
||||
},
|
||||
{},
|
||||
stream_filter={"pk": instance.uuid},
|
||||
request=request,
|
||||
sub_id={"format": "opaque", "id": str(instance.uuid)},
|
||||
)
|
||||
response = StreamResponseSerializer(instance=instance, context={"request": request}).data
|
||||
@@ -159,7 +162,9 @@ class StreamView(SSFStreamView):
|
||||
|
||||
def delete(self, request: Request, *args, **kwargs) -> Response:
|
||||
stream = self.get_object()
|
||||
stream.status = StreamStatus.DISABLED
|
||||
if stream.status == StreamStatus.DISABLED_DELETED:
|
||||
raise Http404
|
||||
stream.status = StreamStatus.DISABLED_DELETED
|
||||
stream.save()
|
||||
return Response(status=204)
|
||||
|
||||
@@ -175,6 +180,7 @@ class StreamVerifyView(SSFStreamView):
|
||||
"state": state,
|
||||
},
|
||||
stream_filter={"pk": stream.uuid},
|
||||
request=request,
|
||||
sub_id={"format": "opaque", "id": str(stream.uuid)},
|
||||
)
|
||||
return Response(status=204)
|
||||
@@ -182,8 +188,25 @@ class StreamVerifyView(SSFStreamView):
|
||||
|
||||
class StreamStatusView(SSFStreamView):
|
||||
|
||||
class StreamStatusSerializer(PassiveSerializer):
|
||||
stream_id = CharField()
|
||||
status = ChoiceField(choices=StreamStatus.choices)
|
||||
|
||||
def get(self, request: Request, *args, **kwargs):
|
||||
stream = self.get_object(any_status=True)
|
||||
stream = self.get_object()
|
||||
return Response(
|
||||
{
|
||||
"stream_id": str(stream.pk),
|
||||
"status": str(stream.status),
|
||||
}
|
||||
)
|
||||
|
||||
def post(self, request: Request, *args, **kwargs):
|
||||
stream = self.get_object()
|
||||
serializer = self.StreamStatusSerializer(stream, data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
stream.status = serializer.validated_data["status"]
|
||||
stream.save()
|
||||
return Response(
|
||||
{
|
||||
"stream_id": str(stream.pk),
|
||||
|
||||
@@ -8,7 +8,6 @@ from inspect import currentframe
|
||||
from typing import Any
|
||||
from uuid import uuid4
|
||||
|
||||
from asgiref.sync import async_to_sync
|
||||
from channels.layers import get_channel_layer
|
||||
from django.apps import apps
|
||||
from django.db import models
|
||||
@@ -410,7 +409,7 @@ class NotificationTransport(TasksModel, SerializerModel):
|
||||
)
|
||||
notification.save()
|
||||
layer = get_channel_layer()
|
||||
async_to_sync(layer.group_send)(
|
||||
layer.group_send_blocking(
|
||||
build_user_group(notification.user),
|
||||
{
|
||||
"type": "event.notification",
|
||||
|
||||
@@ -29,6 +29,7 @@ class RefreshOtherFlowsAfterAuthentication(Flag[bool], key="flows_refresh_others
|
||||
default = False
|
||||
visibility = "public"
|
||||
description = _("Refresh other tabs after successful authentication.")
|
||||
deprecated = True
|
||||
|
||||
|
||||
class ContinuousLogin(Flag[bool], key="flows_continuous_login"):
|
||||
|
||||
@@ -53,6 +53,16 @@ class TestEndSessionView(OAuthTestCase):
|
||||
self.brand.flow_invalidation = self.invalidation_flow
|
||||
self.brand.save()
|
||||
|
||||
def _id_token_hint(self, host: str) -> str:
|
||||
"""Issue a valid id_token_hint for the test provider under the given host."""
|
||||
return self.provider.encode(
|
||||
{
|
||||
"iss": f"http://{host}/application/o/{self.app.slug}/",
|
||||
"aud": self.provider.client_id,
|
||||
"sub": str(self.user.pk),
|
||||
}
|
||||
)
|
||||
|
||||
def test_post_logout_redirect_uri_strict_match(self):
|
||||
"""Test strict URI matching redirects to flow"""
|
||||
self.client.force_login(self.user)
|
||||
@@ -61,7 +71,10 @@ class TestEndSessionView(OAuthTestCase):
|
||||
"authentik_providers_oauth2:end-session",
|
||||
kwargs={"application_slug": self.app.slug},
|
||||
),
|
||||
{"post_logout_redirect_uri": "http://testserver/logout"},
|
||||
{
|
||||
"post_logout_redirect_uri": "http://testserver/logout",
|
||||
"id_token_hint": self._id_token_hint(self.brand.domain),
|
||||
},
|
||||
HTTP_HOST=self.brand.domain,
|
||||
)
|
||||
# Should redirect to the invalidation flow
|
||||
@@ -69,7 +82,12 @@ class TestEndSessionView(OAuthTestCase):
|
||||
self.assertIn(self.invalidation_flow.slug, response.url)
|
||||
|
||||
def test_post_logout_redirect_uri_strict_no_match(self):
|
||||
"""Test strict URI not matching still proceeds with flow (no redirect URI in context)"""
|
||||
"""Test strict URI not matching returns an error and does not start logout flow.
|
||||
|
||||
Required by OIDC RP-Initiated Logout 1.0: on an unregistered
|
||||
post_logout_redirect_uri, the OP MUST NOT redirect and MUST NOT proceed with
|
||||
logout that targets the RP.
|
||||
"""
|
||||
self.client.force_login(self.user)
|
||||
invalid_uri = "http://testserver/other"
|
||||
response = self.client.get(
|
||||
@@ -77,12 +95,14 @@ class TestEndSessionView(OAuthTestCase):
|
||||
"authentik_providers_oauth2:end-session",
|
||||
kwargs={"application_slug": self.app.slug},
|
||||
),
|
||||
{"post_logout_redirect_uri": invalid_uri},
|
||||
{
|
||||
"post_logout_redirect_uri": invalid_uri,
|
||||
"id_token_hint": self._id_token_hint(self.brand.domain),
|
||||
},
|
||||
HTTP_HOST=self.brand.domain,
|
||||
)
|
||||
# Should still redirect to flow, but invalid URI should not be in response
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertNotIn(invalid_uri, response.url)
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertNotIn(invalid_uri, response.content.decode())
|
||||
|
||||
def test_post_logout_redirect_uri_regex_match(self):
|
||||
"""Test regex URI matching redirects to flow"""
|
||||
@@ -92,7 +112,10 @@ class TestEndSessionView(OAuthTestCase):
|
||||
"authentik_providers_oauth2:end-session",
|
||||
kwargs={"application_slug": self.app.slug},
|
||||
),
|
||||
{"post_logout_redirect_uri": "https://app.example.com/logout"},
|
||||
{
|
||||
"post_logout_redirect_uri": "https://app.example.com/logout",
|
||||
"id_token_hint": self._id_token_hint(self.brand.domain),
|
||||
},
|
||||
HTTP_HOST=self.brand.domain,
|
||||
)
|
||||
# Should redirect to the invalidation flow
|
||||
@@ -100,7 +123,7 @@ class TestEndSessionView(OAuthTestCase):
|
||||
self.assertIn(self.invalidation_flow.slug, response.url)
|
||||
|
||||
def test_post_logout_redirect_uri_regex_no_match(self):
|
||||
"""Test regex URI not matching"""
|
||||
"""Test regex URI not matching returns an error and does not start logout flow."""
|
||||
self.client.force_login(self.user)
|
||||
invalid_uri = "https://malicious.com/logout"
|
||||
response = self.client.get(
|
||||
@@ -108,12 +131,14 @@ class TestEndSessionView(OAuthTestCase):
|
||||
"authentik_providers_oauth2:end-session",
|
||||
kwargs={"application_slug": self.app.slug},
|
||||
),
|
||||
{"post_logout_redirect_uri": invalid_uri},
|
||||
{
|
||||
"post_logout_redirect_uri": invalid_uri,
|
||||
"id_token_hint": self._id_token_hint(self.brand.domain),
|
||||
},
|
||||
HTTP_HOST=self.brand.domain,
|
||||
)
|
||||
# Should still proceed to flow, but invalid URI should not be in response
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertNotIn(invalid_uri, response.url)
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertNotIn(invalid_uri, response.content.decode())
|
||||
|
||||
def test_state_parameter_appended_to_uri(self):
|
||||
"""Test state parameter is appended to validated redirect URI"""
|
||||
@@ -123,6 +148,7 @@ class TestEndSessionView(OAuthTestCase):
|
||||
{
|
||||
"post_logout_redirect_uri": "http://testserver/logout",
|
||||
"state": "test-state-123",
|
||||
"id_token_hint": self._id_token_hint("testserver"),
|
||||
},
|
||||
)
|
||||
request.user = self.user
|
||||
@@ -132,6 +158,7 @@ class TestEndSessionView(OAuthTestCase):
|
||||
view.request = request
|
||||
view.kwargs = {"application_slug": self.app.slug}
|
||||
view.resolve_provider_application()
|
||||
view.validate()
|
||||
|
||||
self.assertIn("state=test-state-123", view.post_logout_redirect_uri)
|
||||
|
||||
@@ -146,6 +173,7 @@ class TestEndSessionView(OAuthTestCase):
|
||||
{
|
||||
"post_logout_redirect_uri": "http://testserver/logout",
|
||||
"state": "xyz789",
|
||||
"id_token_hint": self._id_token_hint(self.brand.domain),
|
||||
},
|
||||
HTTP_HOST=self.brand.domain,
|
||||
)
|
||||
|
||||
@@ -5,6 +5,8 @@ from urllib.parse import quote, urlparse
|
||||
|
||||
from django.http import Http404, HttpRequest, HttpResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from jwt import PyJWTError
|
||||
from jwt import decode as jwt_decode
|
||||
|
||||
from authentik.common.oauth.constants import (
|
||||
FORBIDDEN_URI_SCHEMES,
|
||||
@@ -21,11 +23,14 @@ from authentik.flows.planner import (
|
||||
from authentik.flows.stage import SessionEndStage
|
||||
from authentik.flows.views.executor import SESSION_KEY_PLAN
|
||||
from authentik.lib.views import bad_request_message
|
||||
from authentik.policies.views import PolicyAccessView, RequestValidationError
|
||||
from authentik.policies.views import PolicyAccessView
|
||||
from authentik.providers.iframe_logout import IframeLogoutStageView
|
||||
from authentik.providers.oauth2.errors import TokenError
|
||||
from authentik.providers.oauth2.models import (
|
||||
AccessToken,
|
||||
JWTAlgorithms,
|
||||
OAuth2LogoutMethod,
|
||||
OAuth2Provider,
|
||||
RedirectURIMatchingMode,
|
||||
)
|
||||
from authentik.providers.oauth2.tasks import send_backchannel_logout_request
|
||||
@@ -47,21 +52,45 @@ class EndSessionView(PolicyAccessView):
|
||||
if not self.flow:
|
||||
raise Http404
|
||||
|
||||
def validate(self):
|
||||
# Parse end session parameters
|
||||
query_dict = self.request.POST if self.request.method == "POST" else self.request.GET
|
||||
state = query_dict.get("state")
|
||||
request_redirect_uri = query_dict.get("post_logout_redirect_uri")
|
||||
id_token_hint = query_dict.get("id_token_hint")
|
||||
self.post_logout_redirect_uri = None
|
||||
|
||||
# OIDC Certification: Verify id_token_hint. If invalid or missing, throw an error
|
||||
if id_token_hint:
|
||||
# Load a fresh provider instance that's not part of the flow
|
||||
# since it'll have the cryptography Certificate that can't be pickled
|
||||
provider = OAuth2Provider.objects.get(pk=self.provider.pk)
|
||||
key, alg = provider.jwt_key
|
||||
if alg != JWTAlgorithms.HS256:
|
||||
key = provider.signing_key.public_key
|
||||
try:
|
||||
jwt_decode(
|
||||
id_token_hint,
|
||||
key,
|
||||
algorithms=[alg],
|
||||
audience=provider.client_id,
|
||||
issuer=provider.get_issuer(self.request),
|
||||
# ID Tokens are short-lived; a logout request arriving
|
||||
# after expiry is still legitimate and must succeed.
|
||||
options={"verify_exp": False},
|
||||
)
|
||||
except PyJWTError:
|
||||
raise TokenError("invalid_request").with_cause(
|
||||
"id_token_hint_decode_failed"
|
||||
) from None
|
||||
|
||||
# Validate post_logout_redirect_uri against registered URIs
|
||||
if request_redirect_uri:
|
||||
# OIDC Certification: id_token_hint required with post_logout_redirect_uri
|
||||
if not id_token_hint:
|
||||
raise TokenError("invalid_request").with_cause("id_token_hint_missing")
|
||||
if urlparse(request_redirect_uri).scheme in FORBIDDEN_URI_SCHEMES:
|
||||
raise RequestValidationError(
|
||||
bad_request_message(
|
||||
self.request,
|
||||
"Forbidden URI scheme in post_logout_redirect_uri",
|
||||
)
|
||||
)
|
||||
raise TokenError("invalid_request").with_cause("post_logout_redirect_uri")
|
||||
for allowed in self.provider.post_logout_redirect_uris:
|
||||
if allowed.matching_mode == RedirectURIMatchingMode.STRICT:
|
||||
if request_redirect_uri == allowed.url:
|
||||
@@ -71,6 +100,10 @@ class EndSessionView(PolicyAccessView):
|
||||
if fullmatch(allowed.url, request_redirect_uri):
|
||||
self.post_logout_redirect_uri = request_redirect_uri
|
||||
break
|
||||
# OIDC Certification: OP MUST NOT perform post-logout redirection
|
||||
# if the supplied URI does not exactly match a registered one
|
||||
if self.post_logout_redirect_uri is None:
|
||||
raise TokenError("invalid_request").with_cause("invalid_post_logout_redirect_uri")
|
||||
|
||||
# Append state to the redirect URI if both are present
|
||||
if self.post_logout_redirect_uri and state:
|
||||
@@ -91,50 +124,43 @@ class EndSessionView(PolicyAccessView):
|
||||
"<html><body>Logout successful</body></html>", content_type="text/html", status=200
|
||||
)
|
||||
|
||||
# Otherwise, continue with normal policy checks
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||
"""Dispatch the flow planner for the invalidation flow"""
|
||||
try:
|
||||
self.validate()
|
||||
except TokenError as exc:
|
||||
return bad_request_message(
|
||||
self.request,
|
||||
exc.description,
|
||||
)
|
||||
planner = FlowPlanner(self.flow)
|
||||
planner.allow_empty_flows = True
|
||||
|
||||
# Build flow context with logout parameters
|
||||
context = {
|
||||
PLAN_CONTEXT_APPLICATION: self.application,
|
||||
}
|
||||
|
||||
# Get session info for logout notifications and token invalidation
|
||||
auth_session = AuthenticatedSession.from_request(request, request.user)
|
||||
|
||||
# Add validated redirect URI (with state appended) to context if available
|
||||
if self.post_logout_redirect_uri:
|
||||
context[PLAN_CONTEXT_POST_LOGOUT_REDIRECT_URI] = self.post_logout_redirect_uri
|
||||
# Invalidate tokens for this provider/session (RP-initiated logout:
|
||||
# user stays logged into authentik, only this provider's tokens are revoked)
|
||||
if request.user.is_authenticated and auth_session:
|
||||
AccessToken.objects.filter(
|
||||
user=request.user,
|
||||
provider=self.provider,
|
||||
session=auth_session,
|
||||
).delete()
|
||||
|
||||
session_key = (
|
||||
auth_session.session.session_key if auth_session and auth_session.session else None
|
||||
)
|
||||
|
||||
# Handle frontchannel logout
|
||||
frontchannel_logout_url = None
|
||||
if self.provider.logout_method == OAuth2LogoutMethod.FRONTCHANNEL:
|
||||
frontchannel_logout_url = build_frontchannel_logout_url(
|
||||
self.provider, request, session_key
|
||||
)
|
||||
|
||||
# Handle backchannel logout
|
||||
if (
|
||||
self.provider.logout_method == OAuth2LogoutMethod.BACKCHANNEL
|
||||
and self.provider.logout_uri
|
||||
):
|
||||
# Find access token to get iss and sub for the logout token
|
||||
access_token = AccessToken.objects.filter(
|
||||
user=request.user,
|
||||
provider=self.provider,
|
||||
@@ -163,9 +189,16 @@ class EndSessionView(PolicyAccessView):
|
||||
}
|
||||
]
|
||||
|
||||
access_tokens = AccessToken.objects.filter(
|
||||
user=request.user,
|
||||
provider=self.provider,
|
||||
)
|
||||
if auth_session:
|
||||
access_tokens = access_tokens.filter(session=auth_session)
|
||||
access_tokens.delete()
|
||||
|
||||
plan = planner.plan(request, context)
|
||||
|
||||
# Inject iframe logout stage if frontchannel logout is configured
|
||||
if frontchannel_logout_url:
|
||||
plan.insert_stage(in_memory_stage(IframeLogoutStageView))
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"""RAC Signals"""
|
||||
|
||||
from asgiref.sync import async_to_sync
|
||||
from channels.layers import get_channel_layer
|
||||
from django.core.cache import cache
|
||||
from django.db.models.signals import post_delete, post_save, pre_delete
|
||||
@@ -18,7 +17,7 @@ from authentik.providers.rac.models import ConnectionToken, Endpoint
|
||||
@receiver(pre_delete, sender=AuthenticatedSession)
|
||||
def user_session_deleted(sender, instance: AuthenticatedSession, **_):
|
||||
layer = get_channel_layer()
|
||||
async_to_sync(layer.group_send)(
|
||||
layer.group_send_blocking(
|
||||
build_rac_client_group_session(instance.session.session_key),
|
||||
{"type": "event.disconnect", "reason": "session_logout"},
|
||||
)
|
||||
@@ -28,7 +27,7 @@ def user_session_deleted(sender, instance: AuthenticatedSession, **_):
|
||||
def pre_delete_connection_token_disconnect(sender, instance: ConnectionToken, **_):
|
||||
"""Disconnect session when connection token is deleted"""
|
||||
layer = get_channel_layer()
|
||||
async_to_sync(layer.group_send)(
|
||||
layer.group_send_blocking(
|
||||
build_rac_client_group_token(instance.token),
|
||||
{"type": "event.disconnect", "reason": "token_delete"},
|
||||
)
|
||||
|
||||
@@ -6,6 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_core", "0056_user_roles"), # must run before group field is removed
|
||||
("authentik_rbac", "0009_remove_initialpermissions_mode"),
|
||||
]
|
||||
|
||||
|
||||
@@ -187,6 +187,7 @@ SPECTACULAR_SETTINGS = {
|
||||
"PolicyEngineMode": "authentik.policies.models.PolicyEngineMode",
|
||||
"PromptTypeEnum": "authentik.stages.prompt.models.FieldTypes",
|
||||
"ProxyMode": "authentik.providers.proxy.models.ProxyMode",
|
||||
"RedirectURITypeEnum": "authentik.providers.oauth2.models.RedirectURIType",
|
||||
"SAMLBindingsEnum": "authentik.providers.saml.models.SAMLBindings",
|
||||
"SAMLLogoutMethods": "authentik.providers.saml.models.SAMLLogoutMethods",
|
||||
"SAMLNameIDPolicyEnum": "authentik.sources.saml.models.SAMLNameIDPolicy",
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -16,7 +16,7 @@ class RedirectMode(models.TextChoices):
|
||||
|
||||
|
||||
class RedirectStage(Stage):
|
||||
"""Redirect the user to another flow, potentially with all gathered context."""
|
||||
"""Redirect the user to a static URL or another flow, optionally with all gathered context."""
|
||||
|
||||
keep_context = models.BooleanField(default=True)
|
||||
mode = models.TextField(choices=RedirectMode.choices)
|
||||
|
||||
@@ -59,6 +59,8 @@ class FlagsJSONExtension(OpenApiSerializerFieldExtension):
|
||||
props[_flag.key] = build_basic_type(get_args(_flag.__orig_bases__[0])[0])
|
||||
if _flag.description:
|
||||
props[_flag.key]["description"] = _flag.description
|
||||
if _flag.deprecated:
|
||||
props[_flag.key]["deprecated"] = _flag.deprecated
|
||||
return build_object_type(props, required=props.keys())
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ class Flag[T]:
|
||||
Literal["none"] | Literal["public"] | Literal["authenticated"] | Literal["system"]
|
||||
) = "none"
|
||||
description: str | None = None
|
||||
deprecated = False
|
||||
|
||||
def __init_subclass__(cls, key: str, **kwargs):
|
||||
cls.__key = key
|
||||
|
||||
211
blueprints/example/flows-invitation-enrollment-minimal.yaml
Normal file
211
blueprints/example/flows-invitation-enrollment-minimal.yaml
Normal file
@@ -0,0 +1,211 @@
|
||||
# Minimal Invitation-based Enrollment Blueprint
|
||||
#
|
||||
# Companion to flows-invitation-enrollment.yaml, intended for the "New Invitation"
|
||||
# wizard in the admin UI. Creates a single enrollment flow with an invitation stage
|
||||
# bound to it, plus the supporting prompt/user-write/user-login stages.
|
||||
#
|
||||
# All user-facing fields are parameterized via !Context with fallback defaults, so
|
||||
# this blueprint can be imported directly (without context) or through the wizard
|
||||
# with custom values.
|
||||
#
|
||||
# Context keys (all optional):
|
||||
# flow_name Display name of the enrollment flow.
|
||||
# flow_slug URL slug of the flow and suffix for sub-entity
|
||||
# identifiers (so repeated imports with different
|
||||
# slugs don't overwrite each other).
|
||||
# stage_name Name of the invitation stage.
|
||||
# continue_flow_without_invitation Whether the flow continues when no invitation
|
||||
# is supplied (default: false).
|
||||
# user_type "external" or "internal" (default: "external").
|
||||
# Drives the user-write stage's user_type and
|
||||
# user_path_template.
|
||||
version: 1
|
||||
metadata:
|
||||
labels:
|
||||
blueprints.goauthentik.io/instantiate: "false"
|
||||
name: Invitation-based Enrollment (minimal)
|
||||
entries:
|
||||
- identifiers:
|
||||
slug: !Context [flow_slug, invitation-enrollment-flow]
|
||||
model: authentik_flows.flow
|
||||
id: flow
|
||||
attrs:
|
||||
name: !Context [flow_name, Invitation Enrollment Flow]
|
||||
title: !Context [flow_name, Invitation Enrollment Flow]
|
||||
designation: enrollment
|
||||
authentication: require_unauthenticated
|
||||
|
||||
- identifiers:
|
||||
name: !Context [stage_name, invitation-stage]
|
||||
id: invitation-stage
|
||||
model: authentik_stages_invitation.invitationstage
|
||||
attrs:
|
||||
continue_flow_without_invitation: !Context [continue_flow_without_invitation, false]
|
||||
|
||||
- identifiers:
|
||||
name:
|
||||
!Format [
|
||||
"invitation-enrollment-field-username-%s",
|
||||
!Context [flow_slug, invitation-enrollment-flow],
|
||||
]
|
||||
id: prompt-field-username
|
||||
model: authentik_stages_prompt.prompt
|
||||
attrs:
|
||||
field_key: username
|
||||
label: Username
|
||||
type: username
|
||||
required: true
|
||||
placeholder: Username
|
||||
placeholder_expression: false
|
||||
order: 0
|
||||
|
||||
- identifiers:
|
||||
name:
|
||||
!Format [
|
||||
"invitation-enrollment-field-password-%s",
|
||||
!Context [flow_slug, invitation-enrollment-flow],
|
||||
]
|
||||
id: prompt-field-password
|
||||
model: authentik_stages_prompt.prompt
|
||||
attrs:
|
||||
field_key: password
|
||||
label: Password
|
||||
type: password
|
||||
required: true
|
||||
placeholder: Password
|
||||
placeholder_expression: false
|
||||
order: 1
|
||||
|
||||
- identifiers:
|
||||
name:
|
||||
!Format [
|
||||
"invitation-enrollment-field-password-repeat-%s",
|
||||
!Context [flow_slug, invitation-enrollment-flow],
|
||||
]
|
||||
id: prompt-field-password-repeat
|
||||
model: authentik_stages_prompt.prompt
|
||||
attrs:
|
||||
field_key: password_repeat
|
||||
label: Password (repeat)
|
||||
type: password
|
||||
required: true
|
||||
placeholder: Password (repeat)
|
||||
placeholder_expression: false
|
||||
order: 2
|
||||
|
||||
- identifiers:
|
||||
name:
|
||||
!Format [
|
||||
"invitation-enrollment-field-name-%s",
|
||||
!Context [flow_slug, invitation-enrollment-flow],
|
||||
]
|
||||
id: prompt-field-name
|
||||
model: authentik_stages_prompt.prompt
|
||||
attrs:
|
||||
field_key: name
|
||||
label: Name
|
||||
type: text
|
||||
required: true
|
||||
placeholder: Name
|
||||
placeholder_expression: false
|
||||
order: 0
|
||||
|
||||
- identifiers:
|
||||
name:
|
||||
!Format [
|
||||
"invitation-enrollment-field-email-%s",
|
||||
!Context [flow_slug, invitation-enrollment-flow],
|
||||
]
|
||||
id: prompt-field-email
|
||||
model: authentik_stages_prompt.prompt
|
||||
attrs:
|
||||
field_key: email
|
||||
label: Email
|
||||
type: email
|
||||
required: true
|
||||
placeholder: Email
|
||||
placeholder_expression: false
|
||||
order: 1
|
||||
|
||||
- identifiers:
|
||||
name:
|
||||
!Format [
|
||||
"invitation-enrollment-prompt-credentials-%s",
|
||||
!Context [flow_slug, invitation-enrollment-flow],
|
||||
]
|
||||
id: prompt-stage-credentials
|
||||
model: authentik_stages_prompt.promptstage
|
||||
attrs:
|
||||
fields:
|
||||
- !KeyOf prompt-field-username
|
||||
- !KeyOf prompt-field-password
|
||||
- !KeyOf prompt-field-password-repeat
|
||||
|
||||
- identifiers:
|
||||
name:
|
||||
!Format [
|
||||
"invitation-enrollment-prompt-details-%s",
|
||||
!Context [flow_slug, invitation-enrollment-flow],
|
||||
]
|
||||
id: prompt-stage-details
|
||||
model: authentik_stages_prompt.promptstage
|
||||
attrs:
|
||||
fields:
|
||||
- !KeyOf prompt-field-name
|
||||
- !KeyOf prompt-field-email
|
||||
|
||||
- identifiers:
|
||||
name:
|
||||
!Format [
|
||||
"invitation-enrollment-user-write-%s",
|
||||
!Context [flow_slug, invitation-enrollment-flow],
|
||||
]
|
||||
id: user-write-stage
|
||||
model: authentik_stages_user_write.userwritestage
|
||||
attrs:
|
||||
user_creation_mode: always_create
|
||||
user_type: !Context [user_type, external]
|
||||
user_path_template:
|
||||
!Format ["users/%s", !Context [user_type, external]]
|
||||
|
||||
- identifiers:
|
||||
name:
|
||||
!Format [
|
||||
"invitation-enrollment-user-login-%s",
|
||||
!Context [flow_slug, invitation-enrollment-flow],
|
||||
]
|
||||
id: user-login-stage
|
||||
model: authentik_stages_user_login.userloginstage
|
||||
|
||||
- identifiers:
|
||||
target: !KeyOf flow
|
||||
stage: !KeyOf invitation-stage
|
||||
order: 5
|
||||
model: authentik_flows.flowstagebinding
|
||||
attrs:
|
||||
evaluate_on_plan: true
|
||||
re_evaluate_policies: true
|
||||
|
||||
- identifiers:
|
||||
target: !KeyOf flow
|
||||
stage: !KeyOf prompt-stage-credentials
|
||||
order: 10
|
||||
model: authentik_flows.flowstagebinding
|
||||
|
||||
- identifiers:
|
||||
target: !KeyOf flow
|
||||
stage: !KeyOf prompt-stage-details
|
||||
order: 15
|
||||
model: authentik_flows.flowstagebinding
|
||||
|
||||
- identifiers:
|
||||
target: !KeyOf flow
|
||||
stage: !KeyOf user-write-stage
|
||||
order: 20
|
||||
model: authentik_flows.flowstagebinding
|
||||
|
||||
- identifiers:
|
||||
target: !KeyOf flow
|
||||
stage: !KeyOf user-login-stage
|
||||
order: 100
|
||||
model: authentik_flows.flowstagebinding
|
||||
@@ -73,8 +73,16 @@ entries:
|
||||
redirect_uris:
|
||||
- matching_mode: strict
|
||||
url: https://localhost:8443/test/a/authentik/callback
|
||||
redirect_uri_type: authorization
|
||||
- matching_mode: strict
|
||||
url: https://host.docker.internal:8443/test/a/authentik/callback
|
||||
redirect_uri_type: authorization
|
||||
- matching_mode: strict
|
||||
url: https://localhost:8443/test/a/authentik/post_logout_redirect
|
||||
redirect_uri_type: logout
|
||||
- matching_mode: strict
|
||||
url: https://host.docker.internal:8443/test/a/authentik/post_logout_redirect
|
||||
redirect_uri_type: logout
|
||||
grant_types:
|
||||
- authorization_code
|
||||
- implicit
|
||||
@@ -108,8 +116,16 @@ entries:
|
||||
redirect_uris:
|
||||
- matching_mode: strict
|
||||
url: https://localhost:8443/test/a/authentik/callback
|
||||
redirect_uri_type: authorization
|
||||
- matching_mode: strict
|
||||
url: https://host.docker.internal:8443/test/a/authentik/callback
|
||||
redirect_uri_type: authorization
|
||||
- matching_mode: strict
|
||||
url: https://localhost:8443/test/a/authentik/post_logout_redirect
|
||||
redirect_uri_type: logout
|
||||
- matching_mode: strict
|
||||
url: https://host.docker.internal:8443/test/a/authentik/post_logout_redirect
|
||||
redirect_uri_type: logout
|
||||
grant_types:
|
||||
- authorization_code
|
||||
- implicit
|
||||
|
||||
@@ -26,6 +26,8 @@ var healthcheckCmd = &cobra.Command{
|
||||
exitCode := 1
|
||||
log.WithField("mode", mode).Debug("checking health")
|
||||
switch strings.ToLower(mode) {
|
||||
case "allinone":
|
||||
fallthrough
|
||||
case "server":
|
||||
exitCode = check(fmt.Sprintf("http://localhost%s-/health/live/", config.Get().Web.Path))
|
||||
case "worker":
|
||||
|
||||
2
go.mod
2
go.mod
@@ -7,7 +7,7 @@ require (
|
||||
beryju.io/radius-eap v0.1.0
|
||||
github.com/avast/retry-go/v4 v4.7.0
|
||||
github.com/coreos/go-oidc/v3 v3.18.0
|
||||
github.com/getsentry/sentry-go v0.46.0
|
||||
github.com/getsentry/sentry-go v0.46.1
|
||||
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
|
||||
github.com/go-ldap/ldap/v3 v3.4.13
|
||||
github.com/go-openapi/runtime v0.29.4
|
||||
|
||||
4
go.sum
4
go.sum
@@ -20,8 +20,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
||||
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/getsentry/sentry-go v0.46.0 h1:mbdDaarbUdOt9X+dx6kDdntkShLEX3/+KyOsVDTPDj0=
|
||||
github.com/getsentry/sentry-go v0.46.0/go.mod h1:evVbw2qotNUdYG8KxXbAdjOQWWvWIwKxpjdZZIvcIPw=
|
||||
github.com/getsentry/sentry-go v0.46.1 h1:mZyQFaQYkPxAdDG4HR8gDg6j4CnKYVWt4TF92N7i3XY=
|
||||
github.com/getsentry/sentry-go v0.46.1/go.mod h1:evVbw2qotNUdYG8KxXbAdjOQWWvWIwKxpjdZZIvcIPw=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||
|
||||
@@ -31,7 +31,7 @@ function run_authentik {
|
||||
echo go run ./cmd/server "$@"
|
||||
fi
|
||||
;;
|
||||
worker)
|
||||
allinone | worker)
|
||||
if [[ -x "$(command -v authentik)" ]]; then
|
||||
echo authentik "$@"
|
||||
else
|
||||
@@ -105,7 +105,7 @@ elif [[ "$1" == "test-all" ]]; then
|
||||
prepare_debug
|
||||
chmod 777 /root
|
||||
check_if_root_and_run manage test authentik
|
||||
elif [[ "$1" == "server" ]] || [[ "$1" == "worker" ]]; then
|
||||
elif [[ "$1" == "allinone" ]] || [[ "$1" == "server" ]] || [[ "$1" == "worker" ]]; then
|
||||
wait_for_db
|
||||
check_if_root_and_run "$@"
|
||||
elif [[ "$1" == "healthcheck" ]]; then
|
||||
|
||||
8
lifecycle/aws/package-lock.json
generated
8
lifecycle/aws/package-lock.json
generated
@@ -9,7 +9,7 @@
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"aws-cdk": "^2.1118.4",
|
||||
"aws-cdk": "^2.1119.0",
|
||||
"cross-env": "^10.1.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -25,9 +25,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/aws-cdk": {
|
||||
"version": "2.1118.4",
|
||||
"resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1118.4.tgz",
|
||||
"integrity": "sha512-wJfRQdvb+FJ2cni059mYdmjhfwhMskP+PAB59BL9jhon+jYtjy8X3pbj3uzHgAOJwNhh6jGkP8xq36Cffccbbw==",
|
||||
"version": "2.1119.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1119.0.tgz",
|
||||
"integrity": "sha512-XBxZEKH3BY4M1EX6x0qBkmOAj8viErjpww14iH6Z3z6nI0YzjZeJ05eEl7eJwzUgv7NTGagWBS9m/eDJW5+dAg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"aws-cfn": "cross-env CI=false cdk synth --version-reporting=false > template.yaml"
|
||||
},
|
||||
"devDependencies": {
|
||||
"aws-cdk": "^2.1118.4",
|
||||
"aws-cdk": "^2.1119.0",
|
||||
"cross-env": "^10.1.0"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -28,20 +28,45 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||
_ = db_conn.cursor()
|
||||
|
||||
def do_GET(self):
|
||||
if self.path == "/-/metrics/":
|
||||
from authentik.root.monitoring import monitoring_set
|
||||
from django.db import (
|
||||
DatabaseError,
|
||||
InterfaceError,
|
||||
OperationalError,
|
||||
connections,
|
||||
)
|
||||
from psycopg.errors import AdminShutdown
|
||||
|
||||
monitoring_set.send_robust(self)
|
||||
self.send_response(200)
|
||||
from authentik.root.monitoring import monitoring_set
|
||||
|
||||
DATABASE_ERRORS = (
|
||||
AdminShutdown,
|
||||
InterfaceError,
|
||||
DatabaseError,
|
||||
ConnectionError,
|
||||
OperationalError,
|
||||
)
|
||||
|
||||
if self.path == "/-/metrics/":
|
||||
try:
|
||||
monitoring_set.send(self)
|
||||
except DATABASE_ERRORS as exc:
|
||||
LOGGER.warning("failed to send monitoring_set", exc=exc)
|
||||
for db_conn in connections.all():
|
||||
db_conn.close()
|
||||
self.send_response(503)
|
||||
else:
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
elif self.path == "/-/health/ready/":
|
||||
from django.db.utils import OperationalError
|
||||
|
||||
try:
|
||||
self.check_db()
|
||||
except OperationalError:
|
||||
except DATABASE_ERRORS as exc:
|
||||
LOGGER.warning("failed to check database health", exc=exc)
|
||||
for db_conn in connections.all():
|
||||
db_conn.close()
|
||||
self.send_response(503)
|
||||
self.send_response(200)
|
||||
else:
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
else:
|
||||
self.send_response(200)
|
||||
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-04-30 00:27+0000\n"
|
||||
"POT-Creation-Date: 2026-05-01 03:47+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -872,10 +872,6 @@ msgstr ""
|
||||
msgid "Grace period must be shorter than the interval."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/lifecycle/api/rules.py
|
||||
msgid "Only one type-wide rule for each object type is allowed."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/lifecycle/models.py
|
||||
msgid ""
|
||||
"Select which transports should be used to notify the reviewers. If none are "
|
||||
@@ -903,7 +899,8 @@ msgid "Go to {self._get_model_name()}"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/lifecycle/models.py
|
||||
msgid "Access review is due for {self.content_type.name} {str(self.object)}"
|
||||
msgid ""
|
||||
"Access review is due for {self.content_type.name.lower()} {object_label}"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/lifecycle/models.py
|
||||
@@ -916,7 +913,7 @@ msgid "Access review completed for {self.content_type.name} {str(self.object)}"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/lifecycle/tasks.py
|
||||
msgid "Dispatch tasks to validate lifecycle rules."
|
||||
msgid "Dispatch tasks to apply lifecycle rules."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/lifecycle/tasks.py
|
||||
@@ -1229,6 +1226,78 @@ msgstr ""
|
||||
msgid "Generate data export."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/api.py
|
||||
msgid "User to lock. If omitted, locks the current user (self-service)."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/api.py
|
||||
msgid "No lockdown flow configured."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/api.py
|
||||
msgid "Lockdown flow is not applicable."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/api.py
|
||||
msgid "Choose the target account, then return a flow link."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/api.py
|
||||
msgid "No lockdown flow configured or the flow is not applicable"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/api.py
|
||||
msgid "Permission denied (when targeting another user)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/models.py
|
||||
msgid "Deactivate the user account (set is_active to False)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/models.py
|
||||
msgid "Set an unusable password for the user"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/models.py
|
||||
msgid "Delete all active sessions for the user"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/models.py
|
||||
msgid ""
|
||||
"Revoke all tokens for the user (API, app password, recovery, verification, "
|
||||
"OAuth)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/models.py
|
||||
msgid ""
|
||||
"Flow to redirect users to after self-service lockdown. This flow should not "
|
||||
"require authentication since the user's session is deleted."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/models.py
|
||||
msgid "Account Lockdown Stage"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/models.py
|
||||
msgid "Account Lockdown Stages"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/stage.py
|
||||
msgid "No target user specified for account lockdown"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/stage.py
|
||||
msgid "You do not have permission to lock down this account."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/stage.py
|
||||
msgid "Account lockdown failed for this account."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/stage.py
|
||||
msgid "Self-service account lockdown requires a completion flow."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/authenticator_endpoint_gdtc/models.py
|
||||
msgid "Endpoint Authenticator Google Device Trust Connector Stage"
|
||||
msgstr ""
|
||||
@@ -4456,6 +4525,18 @@ msgstr ""
|
||||
msgid "Static: Static value, displayed as-is."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/prompt/models.py
|
||||
msgid "Alert (Info): Static alert box with info styling"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/prompt/models.py
|
||||
msgid "Alert (Warning): Static alert box with warning styling"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/prompt/models.py
|
||||
msgid "Alert (Danger): Static alert box with danger styling"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/prompt/models.py
|
||||
msgid "authentik: Selection of locales authentik supports"
|
||||
msgstr ""
|
||||
|
||||
@@ -53,6 +53,7 @@ Relatedly
|
||||
Sidero
|
||||
snipeit
|
||||
sonarqube
|
||||
Technitium
|
||||
Terrakube
|
||||
Ueberauth
|
||||
Veeam
|
||||
|
||||
Binary file not shown.
@@ -15,7 +15,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-04-08 00:28+0000\n"
|
||||
"POT-Creation-Date: 2026-05-01 03:47+0000\n"
|
||||
"PO-Revision-Date: 2025-12-01 19:09+0000\n"
|
||||
"Last-Translator: Sp P, 2026\n"
|
||||
"Language-Team: French (France) (https://app.transifex.com/authentik/teams/119923/fr_FR/)\n"
|
||||
@@ -263,6 +263,18 @@ msgstr ""
|
||||
"fournisseurs backchannels sont retournés. Si faux, les fournisseurs "
|
||||
"backchannels sont exclus"
|
||||
|
||||
#: authentik/core/api/users.py
|
||||
msgid "Invalid password hash format. Must be a valid Django password hash."
|
||||
msgstr ""
|
||||
"Format de hachage de mot de passe invalide. Cela doit être un hachage de mot"
|
||||
" de passe Django valide."
|
||||
|
||||
#: authentik/core/api/users.py
|
||||
msgid "Cannot set both password and password_hash. Use only one."
|
||||
msgstr ""
|
||||
"Impossible de définir à la fois password (mot de passe) et password_hash "
|
||||
"(hachage de mot de passe). N'en utiliser qu'un seul."
|
||||
|
||||
#: authentik/core/api/users.py
|
||||
msgid "No leading or trailing slashes allowed."
|
||||
msgstr ""
|
||||
@@ -443,6 +455,11 @@ msgid "Open launch URL in a new browser tab or window."
|
||||
msgstr ""
|
||||
"Ouvrir l'URL de lancement dans une nouvelle fenêtre ou un nouvel onglet."
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Hide this application from the user's My applications page."
|
||||
msgstr ""
|
||||
"Masquer cette application dans la page Mes applications de l'utilisateur."
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Application"
|
||||
msgstr "Application"
|
||||
@@ -810,6 +827,14 @@ msgstr "Nonce Apple"
|
||||
msgid "Apple Nonces"
|
||||
msgstr "Nonces Apple"
|
||||
|
||||
#: authentik/endpoints/connectors/agent/models.py
|
||||
msgid "Apple Independent Secure Enclave"
|
||||
msgstr "Secure Enclave indépendante d'Apple"
|
||||
|
||||
#: authentik/endpoints/connectors/agent/models.py
|
||||
msgid "Apple Independent Secure Enclaves"
|
||||
msgstr "Secure Enclaves indépendantes d'Apple"
|
||||
|
||||
#: authentik/endpoints/facts.py
|
||||
msgid "Operating System name, such as 'Server 2022' or 'Ubuntu'"
|
||||
msgstr "Nom du système d'exploitation, comme 'Server 2022' ou 'Ubuntu'"
|
||||
@@ -936,12 +961,6 @@ msgstr "Soit un groupe de réviseurs soit un réviseur doit être défini."
|
||||
msgid "Grace period must be shorter than the interval."
|
||||
msgstr "La période de grâce doit être plus courte que l'intervalle."
|
||||
|
||||
#: authentik/enterprise/lifecycle/api/rules.py
|
||||
msgid "Only one type-wide rule for each object type is allowed."
|
||||
msgstr ""
|
||||
"Une seule règle pour l'ensemble du type est autorisée pour chaque type "
|
||||
"d'objet."
|
||||
|
||||
#: authentik/enterprise/lifecycle/models.py
|
||||
msgid ""
|
||||
"Select which transports should be used to notify the reviewers. If none are "
|
||||
@@ -972,10 +991,11 @@ msgid "Go to {self._get_model_name()}"
|
||||
msgstr "Aller à {self._get_model_name()}"
|
||||
|
||||
#: authentik/enterprise/lifecycle/models.py
|
||||
msgid "Access review is due for {self.content_type.name} {str(self.object)}"
|
||||
msgid ""
|
||||
"Access review is due for {self.content_type.name.lower()} {object_label}"
|
||||
msgstr ""
|
||||
"La révision d'accès est attendue pour {self.content_type.name} "
|
||||
"{str(self.object)}"
|
||||
"La révision de l'accès doit être effectuée pour "
|
||||
"{self.content_type.name.lower()} {object_label}"
|
||||
|
||||
#: authentik/enterprise/lifecycle/models.py
|
||||
msgid ""
|
||||
@@ -992,8 +1012,8 @@ msgstr ""
|
||||
"{str(self.object)}"
|
||||
|
||||
#: authentik/enterprise/lifecycle/tasks.py
|
||||
msgid "Dispatch tasks to validate lifecycle rules."
|
||||
msgstr "Déclenche les tâches pour valider les règles de cycle de vie"
|
||||
msgid "Dispatch tasks to apply lifecycle rules."
|
||||
msgstr "Déclencher les tâches pour appliquer les règles de cycle de vie"
|
||||
|
||||
#: authentik/enterprise/lifecycle/tasks.py
|
||||
msgid "Apply lifecycle rule."
|
||||
@@ -1336,6 +1356,86 @@ msgstr "Télécharger"
|
||||
msgid "Generate data export."
|
||||
msgstr "Générer un export de données."
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/api.py
|
||||
msgid "User to lock. If omitted, locks the current user (self-service)."
|
||||
msgstr ""
|
||||
"Utilisateur à bloquer. Si non renseigné, bloque l'utilisateur actuel (libre "
|
||||
"service)."
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/api.py
|
||||
msgid "No lockdown flow configured."
|
||||
msgstr "Aucun flux de blocage configuré."
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/api.py
|
||||
msgid "Lockdown flow is not applicable."
|
||||
msgstr "Le flux de blocage n'est pas applicable."
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/api.py
|
||||
msgid "Choose the target account, then return a flow link."
|
||||
msgstr "Choisit le compte cible, puis renvoie un lien de flux."
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/api.py
|
||||
msgid "No lockdown flow configured or the flow is not applicable"
|
||||
msgstr "Aucun flux de blocage configuré, ou le flux n'est pas applicable"
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/api.py
|
||||
msgid "Permission denied (when targeting another user)"
|
||||
msgstr "Permission refusée (lors du ciblage d'un autre utilisateur)"
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/models.py
|
||||
msgid "Deactivate the user account (set is_active to False)"
|
||||
msgstr "Désactiver le compte de l'utilisateur (définir is_active à False)."
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/models.py
|
||||
msgid "Set an unusable password for the user"
|
||||
msgstr "Définit un mot de passe inutilisable pour cet utilisateur."
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/models.py
|
||||
msgid "Delete all active sessions for the user"
|
||||
msgstr "Supprimer toutes les sessions actives pour cet utilisateur."
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/models.py
|
||||
msgid ""
|
||||
"Revoke all tokens for the user (API, app password, recovery, verification, "
|
||||
"OAuth)"
|
||||
msgstr ""
|
||||
"Révoquer tous les jetons pour cet utilisateur (API, mot de passe applicatif,"
|
||||
" récupération, vérification, OAuth)"
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/models.py
|
||||
msgid ""
|
||||
"Flow to redirect users to after self-service lockdown. This flow should not "
|
||||
"require authentication since the user's session is deleted."
|
||||
msgstr ""
|
||||
"Flux vers lequel rediriger les utilisateurs après le blocage en libre "
|
||||
"service. Ce flux ne doit pas nécessiter d'authentification car la session "
|
||||
"utilisateur est supprimée."
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/models.py
|
||||
msgid "Account Lockdown Stage"
|
||||
msgstr "Etape de blocage de compte"
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/models.py
|
||||
msgid "Account Lockdown Stages"
|
||||
msgstr "Etapes de blocage de compte"
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/stage.py
|
||||
msgid "No target user specified for account lockdown"
|
||||
msgstr "Aucun utilisateur ciblé défini pour le blocage de compte"
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/stage.py
|
||||
msgid "You do not have permission to lock down this account."
|
||||
msgstr "Vous n'avez pas la permission de bloquer ce compte."
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/stage.py
|
||||
msgid "Account lockdown failed for this account."
|
||||
msgstr "Echec du blocage de compte pour ce compte."
|
||||
|
||||
#: authentik/enterprise/stages/account_lockdown/stage.py
|
||||
msgid "Self-service account lockdown requires a completion flow."
|
||||
msgstr ""
|
||||
"Le blocage de compte en libre service nécessite un flux de finalisation."
|
||||
|
||||
#: authentik/enterprise/stages/authenticator_endpoint_gdtc/models.py
|
||||
msgid "Endpoint Authenticator Google Device Trust Connector Stage"
|
||||
msgstr ""
|
||||
@@ -1469,11 +1569,11 @@ msgstr "Évènement utilisateur"
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid "Notification Transport"
|
||||
msgstr "Transport de Notification"
|
||||
msgstr "Transport de notification"
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid "Notification Transports"
|
||||
msgstr "Transports de notification"
|
||||
msgstr "Transports de notifications"
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid "Notice"
|
||||
@@ -1745,6 +1845,10 @@ msgstr "Jeton du flux"
|
||||
msgid "Flow Tokens"
|
||||
msgstr "Jetons du flux"
|
||||
|
||||
#: authentik/flows/planner.py
|
||||
msgid "This link is invalid or has expired. Please request a new one."
|
||||
msgstr "Ce lien est invalide ou a expiré. Veuillez un demander un nouveau."
|
||||
|
||||
#: authentik/flows/views/executor.py
|
||||
msgid "Invalid next URL"
|
||||
msgstr "URL suivante invalide"
|
||||
@@ -2772,8 +2876,12 @@ msgstr ""
|
||||
"restriction d'audience ne sera ajoutée."
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid "Also known as EntityID"
|
||||
msgstr "Aussi appelé EntityID"
|
||||
msgid ""
|
||||
"Also known as EntityID. Providing a value overrides the default issuer "
|
||||
"generated by authentik."
|
||||
msgstr ""
|
||||
"Aussi appelé EntityID. Fournir une valeur remplace l'émetteur par défaut "
|
||||
"généré par authentik."
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid "SLS URL"
|
||||
@@ -2994,6 +3102,10 @@ msgstr "SAML NameID pour cette session"
|
||||
msgid "SAML NameID format"
|
||||
msgstr "Format SAML NameID"
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid "SAML Issuer used for this session"
|
||||
msgstr "Émetteur SAML utilisé pour cette session"
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid "SAML Session"
|
||||
msgstr "Session SAML"
|
||||
@@ -3026,6 +3138,10 @@ msgstr "Salesforce"
|
||||
msgid "Webex"
|
||||
msgstr "Webex"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "vCenter"
|
||||
msgstr "vCenter"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Group filters used to define sync-scope for groups."
|
||||
msgstr ""
|
||||
@@ -3749,8 +3865,8 @@ msgid ""
|
||||
"Which servers a user has to be a member of to be granted access. Empty list "
|
||||
"allows every server."
|
||||
msgstr ""
|
||||
"De quels serveurs un utilisateur doit être membre afin d'être autorisé. Une "
|
||||
"liste vide autorise tous les serveurs."
|
||||
"De quels serveurs un utilisateur doit être membre afin d'obtenir l'accès. "
|
||||
"Une liste vide autorise tous les serveurs."
|
||||
|
||||
#: authentik/sources/plex/models.py
|
||||
msgid "Allow friends to authenticate, even if you don't share a server."
|
||||
@@ -4455,11 +4571,11 @@ msgstr "Activer les utilisateurs à la complétion de l'étape."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Email Stage"
|
||||
msgstr "Étape Courriel"
|
||||
msgstr "Étape de Courriel"
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Email Stages"
|
||||
msgstr "Étapes Courriel"
|
||||
msgstr "Étapes de Courriel"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Successfully verified Email."
|
||||
@@ -4933,6 +5049,19 @@ msgstr ""
|
||||
msgid "Static: Static value, displayed as-is."
|
||||
msgstr "Statique : valeur statique, affichée comme telle."
|
||||
|
||||
#: authentik/stages/prompt/models.py
|
||||
msgid "Alert (Info): Static alert box with info styling"
|
||||
msgstr "Alerte (Info) : message d'alerte statique au format information"
|
||||
|
||||
#: authentik/stages/prompt/models.py
|
||||
msgid "Alert (Warning): Static alert box with warning styling"
|
||||
msgstr ""
|
||||
"Alerte (Avertissement) : message d'alerte statique au format avertissement"
|
||||
|
||||
#: authentik/stages/prompt/models.py
|
||||
msgid "Alert (Danger): Static alert box with danger styling"
|
||||
msgstr "Alerte (Danger) : message d'alerte statique au format danger"
|
||||
|
||||
#: authentik/stages/prompt/models.py
|
||||
msgid "authentik: Selection of locales authentik supports"
|
||||
msgstr "authentik : sélection des locales prises en charges par authentik"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Utilities to run an axum server.
|
||||
|
||||
use std::{net, os::unix};
|
||||
use std::{net, os::unix, path::PathBuf};
|
||||
|
||||
use ak_common::arbiter::{Arbiter, Tasks};
|
||||
use axum::Router;
|
||||
@@ -21,26 +21,20 @@ async fn run_plain(
|
||||
name: &str,
|
||||
router: Router,
|
||||
addr: net::SocketAddr,
|
||||
allow_failure: bool,
|
||||
) -> Result<()> {
|
||||
info!(addr = addr.to_string(), "starting {name} server");
|
||||
|
||||
let handle = Handle::new();
|
||||
arbiter.add_net_handle(handle.clone()).await;
|
||||
|
||||
let res = axum_server::Server::bind(addr)
|
||||
axum_server::Server::bind(addr)
|
||||
.acceptor(CatchPanicAcceptor::new(
|
||||
ProxyProtocolAcceptor::new().acceptor(DefaultAcceptor::new()),
|
||||
arbiter.clone(),
|
||||
))
|
||||
.handle(handle)
|
||||
.serve(router.into_make_service_with_connect_info::<net::SocketAddr>())
|
||||
.await;
|
||||
if res.is_err() && allow_failure {
|
||||
arbiter.shutdown().await;
|
||||
return Ok(());
|
||||
}
|
||||
res?;
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -49,60 +43,59 @@ async fn run_plain(
|
||||
///
|
||||
/// `name` is only used for observability purposes and should describe which module is starting the
|
||||
/// server.
|
||||
///
|
||||
/// `allow_failure` allows the server to fail silently.
|
||||
pub fn start_plain(
|
||||
tasks: &mut Tasks,
|
||||
name: &'static str,
|
||||
router: Router,
|
||||
addr: net::SocketAddr,
|
||||
allow_failure: bool,
|
||||
) -> Result<()> {
|
||||
let arbiter = tasks.arbiter();
|
||||
tasks
|
||||
.build_task()
|
||||
.name(&format!("{}::run_plain({name}, {addr})", module_path!()))
|
||||
.spawn(run_plain(arbiter, name, router, addr, allow_failure))?;
|
||||
.spawn(run_plain(arbiter, name, router, addr))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct UnixSocketGuard(PathBuf);
|
||||
|
||||
impl Drop for UnixSocketGuard {
|
||||
fn drop(&mut self) {
|
||||
trace!(path = ?self.0, "removing socket");
|
||||
if let Err(err) = std::fs::remove_file(&self.0) {
|
||||
trace!(?err, "failed to remove socket, ignoring");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn run_unix(
|
||||
arbiter: Arbiter,
|
||||
name: &str,
|
||||
router: Router,
|
||||
addr: unix::net::SocketAddr,
|
||||
allow_failure: bool,
|
||||
) -> Result<()> {
|
||||
info!(?addr, "starting {name} server");
|
||||
|
||||
let handle = Handle::new();
|
||||
arbiter.add_unix_handle(handle.clone()).await;
|
||||
|
||||
if !allow_failure && let Some(path) = addr.as_pathname() {
|
||||
let _guard = if let Some(path) = addr.as_pathname() {
|
||||
trace!(?addr, "removing socket");
|
||||
if let Err(err) = std::fs::remove_file(path) {
|
||||
trace!(?err, "failed to remove socket, ignoring");
|
||||
}
|
||||
}
|
||||
let res = axum_server::Server::bind(addr.clone())
|
||||
Some(UnixSocketGuard(path.to_owned()))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
axum_server::Server::bind(addr.clone())
|
||||
.acceptor(CatchPanicAcceptor::new(
|
||||
DefaultAcceptor::new(),
|
||||
arbiter.clone(),
|
||||
))
|
||||
.handle(handle)
|
||||
.serve(router.into_make_service())
|
||||
.await;
|
||||
if !allow_failure && let Some(path) = addr.as_pathname() {
|
||||
trace!(?addr, "removing socket");
|
||||
if let Err(err) = std::fs::remove_file(path) {
|
||||
trace!(?err, "failed to remove socket, ignoring");
|
||||
}
|
||||
}
|
||||
if res.is_err() && allow_failure {
|
||||
arbiter.shutdown().await;
|
||||
return Ok(());
|
||||
}
|
||||
res?;
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -111,20 +104,17 @@ pub(crate) async fn run_unix(
|
||||
///
|
||||
/// `name` is only used for observability purposes and should describe which module is starting the
|
||||
/// server.
|
||||
///
|
||||
/// `allow_failure` allows the server to fail silently.
|
||||
pub fn start_unix(
|
||||
tasks: &mut Tasks,
|
||||
name: &'static str,
|
||||
router: Router,
|
||||
addr: unix::net::SocketAddr,
|
||||
allow_failure: bool,
|
||||
) -> Result<()> {
|
||||
let arbiter = tasks.arbiter();
|
||||
tasks
|
||||
.build_task()
|
||||
.name(&format!("{}::run_unix({name}, {addr:?})", module_path!()))
|
||||
.spawn(run_unix(arbiter, name, router, addr, allow_failure))?;
|
||||
.spawn(run_unix(arbiter, name, router, addr))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
5
packages/client-ts/src/apis/ManagedApi.ts
generated
5
packages/client-ts/src/apis/ManagedApi.ts
generated
@@ -47,6 +47,7 @@ export interface ManagedBlueprintsDestroyRequest {
|
||||
export interface ManagedBlueprintsImportCreateRequest {
|
||||
file?: Blob;
|
||||
path?: string;
|
||||
context?: string;
|
||||
}
|
||||
|
||||
export interface ManagedBlueprintsListRequest {
|
||||
@@ -369,6 +370,10 @@ export class ManagedApi extends runtime.BaseAPI {
|
||||
formParams.append("path", requestParameters["path"] as any);
|
||||
}
|
||||
|
||||
if (requestParameters["context"] != null) {
|
||||
formParams.append("context", requestParameters["context"] as any);
|
||||
}
|
||||
|
||||
let urlPath = `/managed/blueprints/import/`;
|
||||
|
||||
return {
|
||||
|
||||
@@ -23,7 +23,7 @@ export interface AuthenticatedSessionUserAgentDevice {
|
||||
* @type {string}
|
||||
* @memberof AuthenticatedSessionUserAgentDevice
|
||||
*/
|
||||
brand: string;
|
||||
brand: string | null;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
@@ -35,7 +35,7 @@ export interface AuthenticatedSessionUserAgentDevice {
|
||||
* @type {string}
|
||||
* @memberof AuthenticatedSessionUserAgentDevice
|
||||
*/
|
||||
model: string;
|
||||
model: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,25 +29,25 @@ export interface AuthenticatedSessionUserAgentOs {
|
||||
* @type {string}
|
||||
* @memberof AuthenticatedSessionUserAgentOs
|
||||
*/
|
||||
major: string;
|
||||
major: string | null;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof AuthenticatedSessionUserAgentOs
|
||||
*/
|
||||
minor: string;
|
||||
minor: string | null;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof AuthenticatedSessionUserAgentOs
|
||||
*/
|
||||
patch: string;
|
||||
patch: string | null;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof AuthenticatedSessionUserAgentOs
|
||||
*/
|
||||
patchMinor: string;
|
||||
patchMinor: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,6 +40,7 @@ export interface CurrentBrandFlags {
|
||||
* Refresh other tabs after successful authentication.
|
||||
* @type {boolean}
|
||||
* @memberof CurrentBrandFlags
|
||||
* @deprecated
|
||||
*/
|
||||
flowsRefreshOthers: boolean;
|
||||
}
|
||||
|
||||
12
packages/client-ts/src/models/EventsRequestedEnum.ts
generated
12
packages/client-ts/src/models/EventsRequestedEnum.ts
generated
@@ -19,8 +19,20 @@
|
||||
export const EventsRequestedEnum = {
|
||||
HttpsSchemasOpenidNetSeceventCaepEventTypeSessionRevoked:
|
||||
"https://schemas.openid.net/secevent/caep/event-type/session-revoked",
|
||||
HttpsSchemasOpenidNetSeceventCaepEventTypeTokenClaimsChange:
|
||||
"https://schemas.openid.net/secevent/caep/event-type/token-claims-change",
|
||||
HttpsSchemasOpenidNetSeceventCaepEventTypeCredentialChange:
|
||||
"https://schemas.openid.net/secevent/caep/event-type/credential-change",
|
||||
HttpsSchemasOpenidNetSeceventCaepEventTypeAssuranceLevelChange:
|
||||
"https://schemas.openid.net/secevent/caep/event-type/assurance-level-change",
|
||||
HttpsSchemasOpenidNetSeceventCaepEventTypeDeviceComplianceChange:
|
||||
"https://schemas.openid.net/secevent/caep/event-type/device-compliance-change",
|
||||
HttpsSchemasOpenidNetSeceventCaepEventTypeSessionEstablished:
|
||||
"https://schemas.openid.net/secevent/caep/event-type/session-established",
|
||||
HttpsSchemasOpenidNetSeceventCaepEventTypeSessionPresented:
|
||||
"https://schemas.openid.net/secevent/caep/event-type/session-presented",
|
||||
HttpsSchemasOpenidNetSeceventCaepEventTypeRiskLevelChange:
|
||||
"https://schemas.openid.net/secevent/caep/event-type/risk-level-change",
|
||||
HttpsSchemasOpenidNetSeceventSsfEventTypeVerification:
|
||||
"https://schemas.openid.net/secevent/ssf/event-type/verification",
|
||||
UnknownDefaultOpenApi: "11184809",
|
||||
|
||||
@@ -40,6 +40,7 @@ export interface PatchedSettingsRequestFlags {
|
||||
* Refresh other tabs after successful authentication.
|
||||
* @type {boolean}
|
||||
* @memberof PatchedSettingsRequestFlags
|
||||
* @deprecated
|
||||
*/
|
||||
flowsRefreshOthers: boolean;
|
||||
}
|
||||
|
||||
12
packages/client-ts/src/models/RedirectURI.ts
generated
12
packages/client-ts/src/models/RedirectURI.ts
generated
@@ -14,8 +14,8 @@
|
||||
|
||||
import type { MatchingModeEnum } from "./MatchingModeEnum";
|
||||
import { MatchingModeEnumFromJSON, MatchingModeEnumToJSON } from "./MatchingModeEnum";
|
||||
import type { RedirectUriTypeEnum } from "./RedirectUriTypeEnum";
|
||||
import { RedirectUriTypeEnumFromJSON, RedirectUriTypeEnumToJSON } from "./RedirectUriTypeEnum";
|
||||
import type { RedirectURITypeEnum } from "./RedirectURITypeEnum";
|
||||
import { RedirectURITypeEnumFromJSON, RedirectURITypeEnumToJSON } from "./RedirectURITypeEnum";
|
||||
|
||||
/**
|
||||
* A single allowed redirect URI entry
|
||||
@@ -37,10 +37,10 @@ export interface RedirectURI {
|
||||
url: string;
|
||||
/**
|
||||
*
|
||||
* @type {RedirectUriTypeEnum}
|
||||
* @type {RedirectURITypeEnum}
|
||||
* @memberof RedirectURI
|
||||
*/
|
||||
redirectUriType?: RedirectUriTypeEnum;
|
||||
redirectUriType?: RedirectURITypeEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,7 +66,7 @@ export function RedirectURIFromJSONTyped(json: any, ignoreDiscriminator: boolean
|
||||
redirectUriType:
|
||||
json["redirect_uri_type"] == null
|
||||
? undefined
|
||||
: RedirectUriTypeEnumFromJSON(json["redirect_uri_type"]),
|
||||
: RedirectURITypeEnumFromJSON(json["redirect_uri_type"]),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -85,6 +85,6 @@ export function RedirectURIToJSONTyped(
|
||||
return {
|
||||
matching_mode: MatchingModeEnumToJSON(value["matchingMode"]),
|
||||
url: value["url"],
|
||||
redirect_uri_type: RedirectUriTypeEnumToJSON(value["redirectUriType"]),
|
||||
redirect_uri_type: RedirectURITypeEnumToJSON(value["redirectUriType"]),
|
||||
};
|
||||
}
|
||||
|
||||
12
packages/client-ts/src/models/RedirectURIRequest.ts
generated
12
packages/client-ts/src/models/RedirectURIRequest.ts
generated
@@ -14,8 +14,8 @@
|
||||
|
||||
import type { MatchingModeEnum } from "./MatchingModeEnum";
|
||||
import { MatchingModeEnumFromJSON, MatchingModeEnumToJSON } from "./MatchingModeEnum";
|
||||
import type { RedirectUriTypeEnum } from "./RedirectUriTypeEnum";
|
||||
import { RedirectUriTypeEnumFromJSON, RedirectUriTypeEnumToJSON } from "./RedirectUriTypeEnum";
|
||||
import type { RedirectURITypeEnum } from "./RedirectURITypeEnum";
|
||||
import { RedirectURITypeEnumFromJSON, RedirectURITypeEnumToJSON } from "./RedirectURITypeEnum";
|
||||
|
||||
/**
|
||||
* A single allowed redirect URI entry
|
||||
@@ -37,10 +37,10 @@ export interface RedirectURIRequest {
|
||||
url: string;
|
||||
/**
|
||||
*
|
||||
* @type {RedirectUriTypeEnum}
|
||||
* @type {RedirectURITypeEnum}
|
||||
* @memberof RedirectURIRequest
|
||||
*/
|
||||
redirectUriType?: RedirectUriTypeEnum;
|
||||
redirectUriType?: RedirectURITypeEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,7 +69,7 @@ export function RedirectURIRequestFromJSONTyped(
|
||||
redirectUriType:
|
||||
json["redirect_uri_type"] == null
|
||||
? undefined
|
||||
: RedirectUriTypeEnumFromJSON(json["redirect_uri_type"]),
|
||||
: RedirectURITypeEnumFromJSON(json["redirect_uri_type"]),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -88,6 +88,6 @@ export function RedirectURIRequestToJSONTyped(
|
||||
return {
|
||||
matching_mode: MatchingModeEnumToJSON(value["matchingMode"]),
|
||||
url: value["url"],
|
||||
redirect_uri_type: RedirectUriTypeEnumToJSON(value["redirectUriType"]),
|
||||
redirect_uri_type: RedirectURITypeEnumToJSON(value["redirectUriType"]),
|
||||
};
|
||||
}
|
||||
|
||||
57
packages/client-ts/src/models/RedirectURITypeEnum.ts
generated
Normal file
57
packages/client-ts/src/models/RedirectURITypeEnum.ts
generated
Normal file
@@ -0,0 +1,57 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* authentik
|
||||
* Making authentication simple.
|
||||
*
|
||||
* The version of the OpenAPI document: 2026.5.0-rc1
|
||||
* Contact: hello@goauthentik.io
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const RedirectURITypeEnum = {
|
||||
Authorization: "authorization",
|
||||
Logout: "logout",
|
||||
UnknownDefaultOpenApi: "11184809",
|
||||
} as const;
|
||||
export type RedirectURITypeEnum = (typeof RedirectURITypeEnum)[keyof typeof RedirectURITypeEnum];
|
||||
|
||||
export function instanceOfRedirectURITypeEnum(value: any): boolean {
|
||||
for (const key in RedirectURITypeEnum) {
|
||||
if (Object.prototype.hasOwnProperty.call(RedirectURITypeEnum, key)) {
|
||||
if (RedirectURITypeEnum[key as keyof typeof RedirectURITypeEnum] === value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function RedirectURITypeEnumFromJSON(json: any): RedirectURITypeEnum {
|
||||
return RedirectURITypeEnumFromJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function RedirectURITypeEnumFromJSONTyped(
|
||||
json: any,
|
||||
ignoreDiscriminator: boolean,
|
||||
): RedirectURITypeEnum {
|
||||
return json as RedirectURITypeEnum;
|
||||
}
|
||||
|
||||
export function RedirectURITypeEnumToJSON(value?: RedirectURITypeEnum | null): any {
|
||||
return value as any;
|
||||
}
|
||||
|
||||
export function RedirectURITypeEnumToJSONTyped(
|
||||
value: any,
|
||||
ignoreDiscriminator: boolean,
|
||||
): RedirectURITypeEnum {
|
||||
return value as RedirectURITypeEnum;
|
||||
}
|
||||
57
packages/client-ts/src/models/RedirectUriTypeEnum.ts
generated
57
packages/client-ts/src/models/RedirectUriTypeEnum.ts
generated
@@ -1,57 +0,0 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* authentik
|
||||
* Making authentication simple.
|
||||
*
|
||||
* The version of the OpenAPI document: 2026.5.0-rc1
|
||||
* Contact: hello@goauthentik.io
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const RedirectUriTypeEnum = {
|
||||
Authorization: "authorization",
|
||||
Logout: "logout",
|
||||
UnknownDefaultOpenApi: "11184809",
|
||||
} as const;
|
||||
export type RedirectUriTypeEnum = (typeof RedirectUriTypeEnum)[keyof typeof RedirectUriTypeEnum];
|
||||
|
||||
export function instanceOfRedirectUriTypeEnum(value: any): boolean {
|
||||
for (const key in RedirectUriTypeEnum) {
|
||||
if (Object.prototype.hasOwnProperty.call(RedirectUriTypeEnum, key)) {
|
||||
if (RedirectUriTypeEnum[key as keyof typeof RedirectUriTypeEnum] === value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function RedirectUriTypeEnumFromJSON(json: any): RedirectUriTypeEnum {
|
||||
return RedirectUriTypeEnumFromJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function RedirectUriTypeEnumFromJSONTyped(
|
||||
json: any,
|
||||
ignoreDiscriminator: boolean,
|
||||
): RedirectUriTypeEnum {
|
||||
return json as RedirectUriTypeEnum;
|
||||
}
|
||||
|
||||
export function RedirectUriTypeEnumToJSON(value?: RedirectUriTypeEnum | null): any {
|
||||
return value as any;
|
||||
}
|
||||
|
||||
export function RedirectUriTypeEnumToJSONTyped(
|
||||
value: any,
|
||||
ignoreDiscriminator: boolean,
|
||||
): RedirectUriTypeEnum {
|
||||
return value as RedirectUriTypeEnum;
|
||||
}
|
||||
@@ -20,6 +20,7 @@ export const SSFStreamStatusEnum = {
|
||||
Enabled: "enabled",
|
||||
Paused: "paused",
|
||||
Disabled: "disabled",
|
||||
DisabledDeleted: "disabled_deleted",
|
||||
UnknownDefaultOpenApi: "11184809",
|
||||
} as const;
|
||||
export type SSFStreamStatusEnum = (typeof SSFStreamStatusEnum)[keyof typeof SSFStreamStatusEnum];
|
||||
|
||||
2
packages/client-ts/src/models/index.ts
generated
2
packages/client-ts/src/models/index.ts
generated
@@ -707,7 +707,7 @@ export * from "./RedirectStageModeEnum";
|
||||
export * from "./RedirectStageRequest";
|
||||
export * from "./RedirectURI";
|
||||
export * from "./RedirectURIRequest";
|
||||
export * from "./RedirectUriTypeEnum";
|
||||
export * from "./RedirectURITypeEnum";
|
||||
export * from "./RelatedGroup";
|
||||
export * from "./RelatedRule";
|
||||
export * from "./Reputation";
|
||||
|
||||
@@ -9,7 +9,7 @@ dependencies = [
|
||||
"argon2-cffi==25.1.0",
|
||||
"cachetools==7.0.6",
|
||||
"channels==4.3.2",
|
||||
"cryptography==47.0.0",
|
||||
"cryptography==48.0.0",
|
||||
"dacite==1.9.2",
|
||||
"deepmerge==2.0",
|
||||
"defusedxml==0.7.1",
|
||||
@@ -25,7 +25,7 @@ dependencies = [
|
||||
"django-prometheus==2.4.1",
|
||||
"django-storages[s3]==1.14.6",
|
||||
"django-tenants==3.10.1",
|
||||
"django==5.2.13",
|
||||
"django==5.2.14",
|
||||
"djangoql==0.19.1",
|
||||
"djangorestframework==3.17.1",
|
||||
"docker==7.1.0",
|
||||
@@ -46,9 +46,9 @@ dependencies = [
|
||||
"lxml==6.1.0",
|
||||
"msgraph-sdk==1.56.0",
|
||||
"opencontainers==0.0.15",
|
||||
"packaging==26.1",
|
||||
"packaging==26.2",
|
||||
"paramiko==4.0.0",
|
||||
"psycopg[c,pool]==3.3.3",
|
||||
"psycopg[c,pool]==3.3.4",
|
||||
"pydantic-scim==0.0.8",
|
||||
"pydantic==2.13.3",
|
||||
"pyjwt==2.11.0",
|
||||
@@ -66,7 +66,7 @@ dependencies = [
|
||||
"ua-parser==1.0.2",
|
||||
"unidecode==1.4.0",
|
||||
"urllib3<3",
|
||||
"uvicorn[standard]==0.45.0",
|
||||
"uvicorn[standard]==0.46.0",
|
||||
"watchdog==6.0.0",
|
||||
"webauthn==2.7.1",
|
||||
"wsproto==1.3.2",
|
||||
@@ -76,7 +76,7 @@ dependencies = [
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"aws-cdk-lib==2.250.0",
|
||||
"aws-cdk-lib==2.251.0",
|
||||
"bandit==1.9.4",
|
||||
"black==26.3.1",
|
||||
"bpython==0.26",
|
||||
|
||||
25
schema.yml
25
schema.yml
@@ -34608,10 +34608,12 @@ components:
|
||||
properties:
|
||||
brand:
|
||||
type: string
|
||||
nullable: true
|
||||
family:
|
||||
type: string
|
||||
model:
|
||||
type: string
|
||||
nullable: true
|
||||
required:
|
||||
- brand
|
||||
- family
|
||||
@@ -34624,12 +34626,16 @@ components:
|
||||
type: string
|
||||
major:
|
||||
type: string
|
||||
nullable: true
|
||||
minor:
|
||||
type: string
|
||||
nullable: true
|
||||
patch:
|
||||
type: string
|
||||
nullable: true
|
||||
patch_minor:
|
||||
type: string
|
||||
nullable: true
|
||||
required:
|
||||
- family
|
||||
- major
|
||||
@@ -36044,6 +36050,8 @@ components:
|
||||
path:
|
||||
type: string
|
||||
minLength: 1
|
||||
context:
|
||||
type: string
|
||||
Brand:
|
||||
type: object
|
||||
description: Brand Serializer
|
||||
@@ -37183,6 +37191,7 @@ components:
|
||||
flows_refresh_others:
|
||||
type: boolean
|
||||
description: Refresh other tabs after successful authentication.
|
||||
deprecated: true
|
||||
required:
|
||||
- core_default_app_access
|
||||
- enterprise_audit_include_expanded_diff
|
||||
@@ -39031,7 +39040,13 @@ components:
|
||||
EventsRequestedEnum:
|
||||
enum:
|
||||
- https://schemas.openid.net/secevent/caep/event-type/session-revoked
|
||||
- https://schemas.openid.net/secevent/caep/event-type/token-claims-change
|
||||
- https://schemas.openid.net/secevent/caep/event-type/credential-change
|
||||
- https://schemas.openid.net/secevent/caep/event-type/assurance-level-change
|
||||
- https://schemas.openid.net/secevent/caep/event-type/device-compliance-change
|
||||
- https://schemas.openid.net/secevent/caep/event-type/session-established
|
||||
- https://schemas.openid.net/secevent/caep/event-type/session-presented
|
||||
- https://schemas.openid.net/secevent/caep/event-type/risk-level-change
|
||||
- https://schemas.openid.net/secevent/ssf/event-type/verification
|
||||
type: string
|
||||
ExpiringBaseGrantModel:
|
||||
@@ -51187,6 +51202,7 @@ components:
|
||||
flows_refresh_others:
|
||||
type: boolean
|
||||
description: Refresh other tabs after successful authentication.
|
||||
deprecated: true
|
||||
required:
|
||||
- core_default_app_access
|
||||
- enterprise_audit_include_expanded_diff
|
||||
@@ -53627,7 +53643,7 @@ components:
|
||||
type: string
|
||||
redirect_uri_type:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/RedirectUriTypeEnum'
|
||||
- $ref: '#/components/schemas/RedirectURITypeEnum'
|
||||
default: authorization
|
||||
required:
|
||||
- matching_mode
|
||||
@@ -53643,12 +53659,12 @@ components:
|
||||
minLength: 1
|
||||
redirect_uri_type:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/RedirectUriTypeEnum'
|
||||
- $ref: '#/components/schemas/RedirectURITypeEnum'
|
||||
default: authorization
|
||||
required:
|
||||
- matching_mode
|
||||
- url
|
||||
RedirectUriTypeEnum:
|
||||
RedirectURITypeEnum:
|
||||
enum:
|
||||
- authorization
|
||||
- logout
|
||||
@@ -55618,6 +55634,7 @@ components:
|
||||
- enabled
|
||||
- paused
|
||||
- disabled
|
||||
- disabled_deleted
|
||||
type: string
|
||||
Schedule:
|
||||
type: object
|
||||
@@ -55968,6 +55985,7 @@ components:
|
||||
flows_refresh_others:
|
||||
type: boolean
|
||||
description: Refresh other tabs after successful authentication.
|
||||
deprecated: true
|
||||
required:
|
||||
- core_default_app_access
|
||||
- enterprise_audit_include_expanded_diff
|
||||
@@ -56056,6 +56074,7 @@ components:
|
||||
flows_refresh_others:
|
||||
type: boolean
|
||||
description: Refresh other tabs after successful authentication.
|
||||
deprecated: true
|
||||
required:
|
||||
- core_default_app_access
|
||||
- enterprise_audit_include_expanded_diff
|
||||
|
||||
27
src/main.rs
27
src/main.rs
@@ -23,10 +23,23 @@ struct Cli {
|
||||
#[derive(Debug, FromArgs, PartialEq)]
|
||||
#[argh(subcommand)]
|
||||
enum Command {
|
||||
#[cfg(feature = "core")]
|
||||
AllInOne(AllInOne),
|
||||
#[cfg(feature = "core")]
|
||||
Server(server::Cli),
|
||||
#[cfg(feature = "core")]
|
||||
Worker(worker::Cli),
|
||||
}
|
||||
|
||||
#[derive(Debug, FromArgs, PartialEq)]
|
||||
/// Run both the authentik server and worker.
|
||||
#[argh(subcommand, name = "allinone")]
|
||||
#[expect(
|
||||
clippy::empty_structs_with_brackets,
|
||||
reason = "argh doesn't support unit structs"
|
||||
)]
|
||||
pub(crate) struct AllInOne {}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let tracing_crude = ak_tracing::install_crude();
|
||||
info!(version = authentik_full_version(), "authentik is starting");
|
||||
@@ -34,6 +47,10 @@ fn main() -> Result<()> {
|
||||
let cli: Cli = argh::from_env();
|
||||
|
||||
match &cli.command {
|
||||
#[cfg(feature = "core")]
|
||||
Command::AllInOne(_) => Mode::set(Mode::AllInOne)?,
|
||||
#[cfg(feature = "core")]
|
||||
Command::Server(_) => Mode::set(Mode::Server)?,
|
||||
#[cfg(feature = "core")]
|
||||
Command::Worker(_) => Mode::set(Mode::Worker)?,
|
||||
}
|
||||
@@ -76,6 +93,16 @@ fn main() -> Result<()> {
|
||||
}
|
||||
|
||||
match cli.command {
|
||||
#[cfg(feature = "core")]
|
||||
Command::AllInOne(_) => {
|
||||
server::start(server::Cli::default(), &mut tasks).await?;
|
||||
let workers = worker::start(worker::Cli::default(), &mut tasks)?;
|
||||
metrics.workers.store(Some(workers));
|
||||
}
|
||||
#[cfg(feature = "core")]
|
||||
Command::Server(args) => {
|
||||
server::start(args, &mut tasks).await?;
|
||||
}
|
||||
#[cfg(feature = "core")]
|
||||
Command::Worker(args) => {
|
||||
let workers = worker::start(args, &mut tasks)?;
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::{env::temp_dir, os::unix, path::PathBuf, sync::Arc};
|
||||
|
||||
use ak_axum::{router::wrap_router, server};
|
||||
use ak_common::{
|
||||
Mode,
|
||||
arbiter::{Arbiter, Tasks},
|
||||
config,
|
||||
};
|
||||
@@ -77,25 +78,20 @@ pub(crate) fn start(tasks: &mut Tasks) -> Result<Arc<Metrics>> {
|
||||
.name(&format!("{}::run_upkeep", module_path!()))
|
||||
.spawn(run_upkeep(arbiter, Arc::clone(&metrics)))?;
|
||||
|
||||
for addr in config::get().listen.metrics.iter().copied() {
|
||||
server::start_plain(
|
||||
// Only run HTTP server in worker mode, in server or allinone mode, they're handled by the
|
||||
// server.
|
||||
if Mode::get() == Mode::Worker {
|
||||
for addr in config::get().listen.metrics.iter().copied() {
|
||||
server::start_plain(tasks, "metrics", router.clone(), addr)?;
|
||||
}
|
||||
|
||||
server::start_unix(
|
||||
tasks,
|
||||
"metrics",
|
||||
router.clone(),
|
||||
addr,
|
||||
config::get().debug, /* Allow failure in case the server is running on the same
|
||||
* machine, like in dev */
|
||||
router,
|
||||
unix::net::SocketAddr::from_pathname(socket_path())?,
|
||||
)?;
|
||||
}
|
||||
|
||||
server::start_unix(
|
||||
tasks,
|
||||
"metrics",
|
||||
router,
|
||||
unix::net::SocketAddr::from_pathname(socket_path())?,
|
||||
config::get().debug, /* Allow failure in case the server is running on the same machine,
|
||||
* like in dev */
|
||||
)?;
|
||||
|
||||
Ok(metrics)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,124 @@
|
||||
use std::{env::temp_dir, path::PathBuf};
|
||||
use std::{env::temp_dir, path::PathBuf, process::Stdio, sync::Arc};
|
||||
|
||||
use ak_common::{Arbiter, Tasks, config};
|
||||
use argh::FromArgs;
|
||||
use eyre::{Result, eyre};
|
||||
use nix::{
|
||||
sys::signal::{Signal, kill},
|
||||
unistd::Pid,
|
||||
};
|
||||
use tokio::{
|
||||
process::{Child, Command},
|
||||
sync::Mutex,
|
||||
time::{Duration, sleep, timeout},
|
||||
};
|
||||
use tracing::{info, warn};
|
||||
|
||||
#[derive(Debug, Default, FromArgs, PartialEq, Eq)]
|
||||
/// Run the authentik server.
|
||||
#[argh(subcommand, name = "server")]
|
||||
#[expect(
|
||||
clippy::empty_structs_with_brackets,
|
||||
reason = "argh doesn't support unit structs"
|
||||
)]
|
||||
pub(crate) struct Cli {}
|
||||
|
||||
pub(crate) fn socket_path() -> PathBuf {
|
||||
temp_dir().join("authentik.sock")
|
||||
}
|
||||
|
||||
pub(crate) struct Server {
|
||||
server: Mutex<Child>,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
async fn new() -> Result<Self> {
|
||||
info!("starting server");
|
||||
|
||||
let server = if config::get().debug && which::which("authentik-server").is_err() {
|
||||
let build_status = Command::new("go")
|
||||
.args(["build", "-o", "server", "./cmd/server"])
|
||||
.stdin(Stdio::null())
|
||||
.status()
|
||||
.await?;
|
||||
if !build_status.success() {
|
||||
return Err(eyre!("golang server failed to compile"));
|
||||
}
|
||||
Command::new("./server")
|
||||
.kill_on_drop(true)
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::inherit())
|
||||
.stderr(Stdio::inherit())
|
||||
.spawn()?
|
||||
} else {
|
||||
Command::new("authentik-server")
|
||||
.kill_on_drop(true)
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::inherit())
|
||||
.stderr(Stdio::inherit())
|
||||
.spawn()?
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
server: Mutex::new(server),
|
||||
})
|
||||
}
|
||||
|
||||
async fn shutdown(&self) -> Result<()> {
|
||||
info!("shutting down server");
|
||||
let mut server = self.server.lock().await;
|
||||
if let Some(id) = server.id() {
|
||||
kill(Pid::from_raw(id.cast_signed()), Signal::SIGINT)?;
|
||||
}
|
||||
timeout(Duration::from_secs(1), server.wait()).await??;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn is_alive(&self) -> bool {
|
||||
let try_wait = self.server.lock().await.try_wait();
|
||||
match try_wait {
|
||||
Ok(Some(code)) => {
|
||||
warn!(?code, "server has exited");
|
||||
false
|
||||
}
|
||||
Ok(None) => true,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
?err,
|
||||
"failed to check the status of server process, ignoring"
|
||||
);
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn watch_server(arbiter: Arbiter, server: Arc<Server>) -> Result<()> {
|
||||
info!("starting server watcher");
|
||||
loop {
|
||||
tokio::select! {
|
||||
() = sleep(Duration::from_secs(5)) => {
|
||||
if !server.is_alive().await {
|
||||
return Err(eyre!("server has exited unexpectedly"));
|
||||
}
|
||||
}
|
||||
() = arbiter.shutdown() => {
|
||||
server.shutdown().await?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn start(_cli: Cli, tasks: &mut Tasks) -> Result<Arc<Server>> {
|
||||
let arbiter = tasks.arbiter();
|
||||
|
||||
let server = Arc::new(Server::new().await?);
|
||||
|
||||
tasks
|
||||
.build_task()
|
||||
.name(&format!("{}::watch_server", module_path!()))
|
||||
.spawn(watch_server(arbiter.clone(), Arc::clone(&server)))?;
|
||||
|
||||
Ok(server)
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ const INITIAL_WORKER_ID: usize = 1000;
|
||||
static INITIAL_WORKER_READY: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
pub(crate) struct Worker {
|
||||
worker_id: usize,
|
||||
worker: Child,
|
||||
client: Client<UnixSocketConnector<PathBuf>, Body>,
|
||||
socket_path: PathBuf,
|
||||
@@ -75,6 +76,7 @@ impl Worker {
|
||||
.build(UnixSocketConnector::new(socket_path.clone()));
|
||||
|
||||
Ok(Self {
|
||||
worker_id,
|
||||
worker: cmd
|
||||
.kill_on_drop(true)
|
||||
.stdin(Stdio::null())
|
||||
@@ -108,7 +110,7 @@ impl Worker {
|
||||
self.shutdown(Signal::SIGINT).await
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
#[instrument(skip(self), fields(worker_id = self.worker_id))]
|
||||
fn is_alive(&mut self) -> bool {
|
||||
let try_wait = self.worker.try_wait();
|
||||
match try_wait {
|
||||
@@ -133,34 +135,52 @@ impl Worker {
|
||||
result.is_ok()
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
#[instrument(skip(self), fields(worker_id = self.worker_id))]
|
||||
async fn health_live(&self) -> Result<bool> {
|
||||
trace!("sending health live request to worker");
|
||||
let req = Request::builder()
|
||||
.method("GET")
|
||||
.uri("http://localhost:8000/-/health/live/")
|
||||
.header(HOST, "localhost")
|
||||
.body(Body::from(""))?;
|
||||
Ok(self.client.request(req).await?.status().is_success())
|
||||
Ok(self
|
||||
.client
|
||||
.request(req)
|
||||
.await
|
||||
.inspect_err(|err| warn!(?err, "failed to send health live request to worker"))?
|
||||
.status()
|
||||
.is_success())
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
#[instrument(skip(self), fields(worker_id = self.worker_id))]
|
||||
async fn health_ready(&self) -> Result<bool> {
|
||||
trace!("sending health ready request to worker");
|
||||
let req = Request::builder()
|
||||
.method("GET")
|
||||
.uri("http://localhost:8000/-/health/ready/")
|
||||
.header(HOST, "localhost")
|
||||
.body(Body::from(""))?;
|
||||
Ok(self.client.request(req).await?.status().is_success())
|
||||
Ok(self
|
||||
.client
|
||||
.request(req)
|
||||
.await
|
||||
.inspect_err(|err| warn!(?err, "failed to send health ready request to worker"))?
|
||||
.status()
|
||||
.is_success())
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
#[instrument(skip(self), fields(worker_id = self.worker_id))]
|
||||
async fn notify_metrics(&self) -> Result<()> {
|
||||
trace!("sending metrics request to worker");
|
||||
let req = Request::builder()
|
||||
.method("GET")
|
||||
.uri("http://localhost:8000/-/metrics/")
|
||||
.header(HOST, "localhost")
|
||||
.body(Body::from(""))?;
|
||||
self.client.request(req).await?;
|
||||
self.client
|
||||
.request(req)
|
||||
.await
|
||||
.inspect_err(|err| warn!(?err, "failed to send metrics request to worker"))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -323,14 +343,7 @@ pub(crate) fn start(_cli: Cli, tasks: &mut Tasks) -> Result<Arc<Workers>> {
|
||||
let router = healthcheck::build_router(Arc::clone(&workers));
|
||||
|
||||
for addr in config::get().listen.http.iter().copied() {
|
||||
ak_axum::server::start_plain(
|
||||
tasks,
|
||||
"worker",
|
||||
router.clone(),
|
||||
addr,
|
||||
config::get().debug, /* Allow failure in case the server is running on the same
|
||||
* machine, like in dev. */
|
||||
)?;
|
||||
ak_axum::server::start_plain(tasks, "worker", router.clone(), addr)?;
|
||||
}
|
||||
|
||||
ak_axum::server::start_unix(
|
||||
@@ -338,8 +351,6 @@ pub(crate) fn start(_cli: Cli, tasks: &mut Tasks) -> Result<Arc<Workers>> {
|
||||
"worker",
|
||||
router,
|
||||
unix::net::SocketAddr::from_pathname(socket_path())?,
|
||||
config::get().debug, /* Allow failure in case the server is running on the same
|
||||
* machine, like in dev. */
|
||||
)?;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
from os import unlink, write
|
||||
from sys import stderr
|
||||
from tempfile import mkstemp
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from channels.testing import ChannelsLiveServerTestCase
|
||||
from django.apps import apps
|
||||
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
|
||||
from django.urls import reverse
|
||||
from docker.types import Healthcheck
|
||||
from dramatiq import get_broker
|
||||
from structlog.stdlib import get_logger
|
||||
from yaml import safe_dump
|
||||
|
||||
from authentik.core.apps import Setup
|
||||
from authentik.core.models import User
|
||||
@@ -47,6 +53,84 @@ class E2ETestMixin(DockerTestCase):
|
||||
print("::endgroup::", file=stderr)
|
||||
super().tearDown()
|
||||
|
||||
def url(self, view: str, query: dict | None = None, **kwargs) -> str:
|
||||
"""reverse `view` with `**kwargs` into full URL using live_server_url"""
|
||||
url = self.live_server_url + reverse(view, kwargs=kwargs)
|
||||
if query:
|
||||
return url + "?" + urlencode(query)
|
||||
return url
|
||||
|
||||
|
||||
class SSLLiveMixin(DockerTestCase):
|
||||
"""Mixin to provide an SSL-enabled webserver for integration/e2e tests that require it.
|
||||
|
||||
Overrides `live_server_url` and as such other all usual helper functions will return an HTTPS
|
||||
URL. Certificate is self-signed and random on each run."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self._setup_traefik()
|
||||
|
||||
def tearDown(self):
|
||||
super().tearDown()
|
||||
unlink(self._traefik_config)
|
||||
|
||||
@property
|
||||
def live_server_url(self):
|
||||
return f"https://{self.host}:{self._traefik_port}"
|
||||
|
||||
def _setup_traefik(self):
|
||||
config = {
|
||||
"http": {
|
||||
"routers": {
|
||||
"authentik": {
|
||||
"rule": "PathPrefix(`/`)",
|
||||
"entryPoints": ["websecure"],
|
||||
"service": "authentik",
|
||||
"tls": {},
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"authentik": {"loadBalancer": {"servers": [{"url": super().live_server_url}]}}
|
||||
},
|
||||
}
|
||||
}
|
||||
fd, self._traefik_config = mkstemp()
|
||||
write(fd, safe_dump(config).encode())
|
||||
traefik = self.run_container(
|
||||
image="docker.io/library/traefik:3.1",
|
||||
command=[
|
||||
"--providers.file.filename=/etc/traefik/dynamic.yml",
|
||||
"--providers.file.watch=true",
|
||||
"--entrypoints.websecure.address=:9443",
|
||||
"--log.level=DEBUG",
|
||||
"--api=true",
|
||||
"--api.dashboard=true",
|
||||
"--api.insecure=true",
|
||||
"--ping=true",
|
||||
],
|
||||
healthcheck=Healthcheck(
|
||||
test=["CMD", "traefik", "healthcheck", "--ping"],
|
||||
interval=5 * 1_000 * 1_000_000,
|
||||
start_period=1 * 1_000 * 1_000_000,
|
||||
),
|
||||
ports={
|
||||
"9443": None,
|
||||
},
|
||||
volumes={
|
||||
self._traefik_config: {
|
||||
"bind": "/etc/traefik/dynamic.yml",
|
||||
}
|
||||
},
|
||||
)
|
||||
# {
|
||||
# "8443/tcp": [
|
||||
# {"HostIp": "0.0.0.0", "HostPort": "8443"},
|
||||
# {"HostIp": "::", "HostPort": "8443"},
|
||||
# ],
|
||||
# }
|
||||
self._traefik_port = traefik.ports["9443/tcp"][0]["HostPort"]
|
||||
|
||||
|
||||
class E2ETestCase(E2ETestMixin, StaticLiveServerTestCase):
|
||||
"""E2E Test case with django static live server"""
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
from os import makedirs
|
||||
from pathlib import Path
|
||||
from time import sleep
|
||||
from typing import Any
|
||||
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support import expected_conditions as ec
|
||||
|
||||
from authentik.blueprints.tests import apply_blueprint, reconcile_app
|
||||
from authentik.providers.oauth2.models import OAuth2Provider
|
||||
from tests.live import SSLLiveMixin
|
||||
from tests.openid_conformance.conformance import Conformance
|
||||
from tests.selenium import SeleniumTestCase
|
||||
|
||||
|
||||
class TestOpenIDConformance(SeleniumTestCase):
|
||||
class TestOpenIDConformance(SSLLiveMixin, SeleniumTestCase):
|
||||
|
||||
conformance: Conformance
|
||||
|
||||
@@ -59,32 +61,28 @@ class TestOpenIDConformance(SeleniumTestCase):
|
||||
},
|
||||
"consent": {},
|
||||
}
|
||||
self.test_variant = {
|
||||
"server_metadata": "discovery",
|
||||
"client_registration": "static_client",
|
||||
}
|
||||
|
||||
def run_test(self, test_name: str, test_plan_config: dict):
|
||||
# Create a Conformance instance...
|
||||
def run_test(
|
||||
self, test_name: str, test_plan_config: dict[str, Any], test_variant: dict[str, Any]
|
||||
):
|
||||
self.conformance = Conformance(f"https://{self.host}:8443/", None, verify_ssl=False)
|
||||
|
||||
test_plan = self.conformance.create_test_plan(
|
||||
test_name,
|
||||
test_plan_config,
|
||||
self.test_variant,
|
||||
test_variant,
|
||||
)
|
||||
plan_id = test_plan["id"]
|
||||
for test in test_plan["modules"]:
|
||||
with self.subTest(test["testModule"], **test["variant"]):
|
||||
# Fetch name and variant of the next test to run
|
||||
module_name = test["testModule"]
|
||||
variant = test["variant"]
|
||||
module_instance = self.conformance.create_test_from_plan_with_variant(
|
||||
plan_id, module_name, variant
|
||||
)
|
||||
module_id = module_instance["id"]
|
||||
self.run_single_test(module_id)
|
||||
self.conformance.wait_for_state(module_id, ["FINISHED"], timeout=self.wait_timeout)
|
||||
# Fetch name and variant of the next test to run
|
||||
module_name = test["testModule"]
|
||||
variant = test["variant"]
|
||||
module_instance = self.conformance.create_test_from_plan_with_variant(
|
||||
plan_id, module_name, variant
|
||||
)
|
||||
module_id = module_instance["id"]
|
||||
self.run_single_test(module_id)
|
||||
self.conformance.wait_for_state(module_id, ["FINISHED"], timeout=self.wait_timeout)
|
||||
sleep(2)
|
||||
self.conformance.export_html(plan_id, Path(__file__).parent / "exports")
|
||||
|
||||
|
||||
@@ -2,14 +2,14 @@ services:
|
||||
mongodb:
|
||||
image: mongo:6.0.13
|
||||
nginx:
|
||||
image: ghcr.io/beryju/oidc-conformance-suite-nginx:v5.1.41
|
||||
image: ghcr.io/beryju/oidc-conformance-suite-nginx:v5.1.43
|
||||
ports:
|
||||
- "8443:8443"
|
||||
- "8444:8444"
|
||||
depends_on:
|
||||
- server
|
||||
server:
|
||||
image: ghcr.io/beryju/oidc-conformance-suite-server:v5.1.41
|
||||
image: ghcr.io/beryju/oidc-conformance-suite-server:v5.1.43
|
||||
ports:
|
||||
- "9999:9999"
|
||||
extra_hosts:
|
||||
@@ -19,8 +19,8 @@ services:
|
||||
-Xdebug -Xrunjdwp:transport=dt_socket,address=*:9999,server=y,suspend=n
|
||||
-jar /server/fapi-test-suite.jar
|
||||
-Djdk.tls.maxHandshakeMessageSize=65536
|
||||
--fintechlabs.base_url=https://host.docker.internal:8443
|
||||
--fintechlabs.base_mtls_url=https://host.docker.internal:8444
|
||||
--fintechlabs.base_url=https://localhost:8443
|
||||
--fintechlabs.base_mtls_url=https://localhost:8444
|
||||
--fintechlabs.devmode=true
|
||||
--fintechlabs.startredir=true
|
||||
links:
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
from tests.decorators import retry
|
||||
from tests.openid_conformance.base import TestOpenIDConformance
|
||||
|
||||
|
||||
class TestOpenIDConformanceBasic(TestOpenIDConformance):
|
||||
|
||||
@retry()
|
||||
def test_oidcc_basic_certification_test(self):
|
||||
test_plan_name = "oidcc-basic-certification-test-plan"
|
||||
self.run_test(test_plan_name, self.test_plan_config)
|
||||
@@ -1,10 +0,0 @@
|
||||
from tests.decorators import retry
|
||||
from tests.openid_conformance.base import TestOpenIDConformance
|
||||
|
||||
|
||||
class TestOpenIDConformanceImplicit(TestOpenIDConformance):
|
||||
|
||||
@retry()
|
||||
def test_oidcc_implicit_certification_test_plan(self):
|
||||
test_plan_name = "oidcc-implicit-certification-test-plan"
|
||||
self.run_test(test_plan_name, self.test_plan_config)
|
||||
39
tests/openid_conformance/test_oidc_backchannel.py
Normal file
39
tests/openid_conformance/test_oidc_backchannel.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from unittest.mock import patch
|
||||
|
||||
import urllib3
|
||||
|
||||
from authentik.flows.models import Flow
|
||||
from authentik.lib.utils.http import get_http_session as real_get_http_session
|
||||
from authentik.providers.oauth2.models import OAuth2LogoutMethod, OAuth2Provider
|
||||
from tests.decorators import retry
|
||||
from tests.openid_conformance.base import TestOpenIDConformance
|
||||
|
||||
|
||||
def _insecure_http_session():
|
||||
session = real_get_http_session()
|
||||
session.verify = False
|
||||
return session
|
||||
|
||||
|
||||
@patch("authentik.providers.oauth2.tasks.get_http_session", _insecure_http_session)
|
||||
class TestOpenIDConformanceBackchannel(TestOpenIDConformance):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
OAuth2Provider.objects.filter(name__startswith="oidc-conformance-").update(
|
||||
invalidation_flow=Flow.objects.get(slug="default-invalidation-flow"),
|
||||
logout_method=OAuth2LogoutMethod.BACKCHANNEL,
|
||||
logout_uri="https://localhost:8443/test/a/authentik/backchannel_logout",
|
||||
)
|
||||
# We are unable to use https for this at the current time
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
@retry()
|
||||
def test_oidcc_backchannel_logout_certification_test_plan(self):
|
||||
self.run_test(
|
||||
"oidcc-backchannel-rp-initiated-logout-certification-test-plan",
|
||||
self.test_plan_config,
|
||||
{
|
||||
"client_registration": "static_client",
|
||||
"response_type": "code",
|
||||
},
|
||||
)
|
||||
16
tests/openid_conformance/test_oidc_basic.py
Normal file
16
tests/openid_conformance/test_oidc_basic.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from tests.decorators import retry
|
||||
from tests.openid_conformance.base import TestOpenIDConformance
|
||||
|
||||
|
||||
class TestOpenIDConformanceBasic(TestOpenIDConformance):
|
||||
|
||||
@retry()
|
||||
def test_oidcc_basic_certification_test(self):
|
||||
self.run_test(
|
||||
"oidcc-basic-certification-test-plan",
|
||||
self.test_plan_config,
|
||||
{
|
||||
"server_metadata": "discovery",
|
||||
"client_registration": "static_client",
|
||||
},
|
||||
)
|
||||
26
tests/openid_conformance/test_oidc_frontchannel.py
Normal file
26
tests/openid_conformance/test_oidc_frontchannel.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from authentik.flows.models import Flow
|
||||
from authentik.providers.oauth2.models import OAuth2LogoutMethod, OAuth2Provider
|
||||
from tests.decorators import retry
|
||||
from tests.openid_conformance.base import TestOpenIDConformance
|
||||
|
||||
|
||||
class TestOpenIDConformanceFrontchannel(TestOpenIDConformance):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
OAuth2Provider.objects.filter(name__startswith="oidc-conformance-").update(
|
||||
invalidation_flow=Flow.objects.get(slug="default-invalidation-flow"),
|
||||
logout_method=OAuth2LogoutMethod.FRONTCHANNEL,
|
||||
logout_uri="https://localhost:8443/test/a/authentik/frontchannel_logout",
|
||||
)
|
||||
|
||||
@retry()
|
||||
def test_oidcc_frontchannel_logout_certification_test_plan(self):
|
||||
self.run_test(
|
||||
"oidcc-frontchannel-rp-initiated-logout-certification-test-plan",
|
||||
self.test_plan_config,
|
||||
{
|
||||
"client_registration": "static_client",
|
||||
"response_type": "code",
|
||||
},
|
||||
)
|
||||
16
tests/openid_conformance/test_oidc_implicit.py
Normal file
16
tests/openid_conformance/test_oidc_implicit.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from tests.decorators import retry
|
||||
from tests.openid_conformance.base import TestOpenIDConformance
|
||||
|
||||
|
||||
class TestOpenIDConformanceImplicit(TestOpenIDConformance):
|
||||
|
||||
@retry()
|
||||
def test_oidcc_implicit_certification_test_plan(self):
|
||||
self.run_test(
|
||||
"oidcc-implicit-certification-test-plan",
|
||||
self.test_plan_config,
|
||||
{
|
||||
"server_metadata": "discovery",
|
||||
"client_registration": "static_client",
|
||||
},
|
||||
)
|
||||
24
tests/openid_conformance/test_oidc_rp_initiated.py
Normal file
24
tests/openid_conformance/test_oidc_rp_initiated.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from authentik.flows.models import Flow
|
||||
from authentik.providers.oauth2.models import OAuth2Provider
|
||||
from tests.decorators import retry
|
||||
from tests.openid_conformance.base import TestOpenIDConformance
|
||||
|
||||
|
||||
class TestOpenIDConformanceRPInitiated(TestOpenIDConformance):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
OAuth2Provider.objects.filter(name__startswith="oidc-conformance-").update(
|
||||
invalidation_flow=Flow.objects.get(slug="default-invalidation-flow"),
|
||||
)
|
||||
|
||||
@retry()
|
||||
def test_oidcc_rp_initiated_certification_test_plan(self):
|
||||
self.run_test(
|
||||
"oidcc-rp-initiated-logout-certification-test-plan",
|
||||
self.test_plan_config,
|
||||
{
|
||||
"client_registration": "static_client",
|
||||
"response_type": "code",
|
||||
},
|
||||
)
|
||||
49
tests/openid_conformance/test_ssf_transmitter.py
Normal file
49
tests/openid_conformance/test_ssf_transmitter.py
Normal file
@@ -0,0 +1,49 @@
|
||||
from authentik.core.models import Application
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
from authentik.enterprise.providers.ssf.models import SSFProvider
|
||||
from authentik.lib.generators import generate_id
|
||||
from tests.decorators import retry
|
||||
from tests.live import SSLLiveMixin
|
||||
from tests.openid_conformance.base import TestOpenIDConformance
|
||||
|
||||
|
||||
class TestOpenIDConformanceSSFTransmitter(TestOpenIDConformance, SSLLiveMixin):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.provider = SSFProvider.objects.create(
|
||||
name=generate_id(),
|
||||
signing_key=CertificateKeyPair.objects.get(name="authentik Self-signed Certificate"),
|
||||
backchannel_application=Application.objects.get(slug="oidc-conformance-1"),
|
||||
push_verify_certificates=False,
|
||||
)
|
||||
|
||||
@retry()
|
||||
def test_openid_ssf_transmitter_test_plan(self):
|
||||
iss = self.url(
|
||||
"authentik_providers_ssf:configuration",
|
||||
application_slug="oidc-conformance-1",
|
||||
)
|
||||
self.run_test(
|
||||
"openid-ssf-transmitter-test-plan",
|
||||
{
|
||||
"alias": "authentik",
|
||||
"description": "authentik",
|
||||
"ssf": {
|
||||
"transmitter": {
|
||||
"issuer": iss,
|
||||
"configuration_metadata_endpoint": iss,
|
||||
"access_token": self.provider.token.key,
|
||||
}
|
||||
},
|
||||
},
|
||||
test_variant={
|
||||
"client_auth_type": "client_secret_post",
|
||||
"ssf_server_metadata": "static",
|
||||
"server_metadata": "static",
|
||||
"ssf_auth_mode": "static",
|
||||
"ssf_delivery_mode": "push",
|
||||
"ssf_profile": "caep_interop",
|
||||
"client_registration": "static_client",
|
||||
},
|
||||
)
|
||||
@@ -5,10 +5,8 @@ from json import JSONDecodeError, dumps, loads
|
||||
from pathlib import Path
|
||||
from tempfile import gettempdir
|
||||
from time import sleep
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
|
||||
from django.urls import reverse
|
||||
from docker.models.containers import Container
|
||||
from requests import RequestException
|
||||
from selenium import webdriver
|
||||
@@ -131,13 +129,6 @@ class SeleniumTestMixin(E2ETestMixin):
|
||||
f"HTML: {self.driver.page_source[:1000]}"
|
||||
) from exc
|
||||
|
||||
def url(self, view: str, query: dict | None = None, **kwargs) -> str:
|
||||
"""reverse `view` with `**kwargs` into full URL using live_server_url"""
|
||||
url = self.live_server_url + reverse(view, kwargs=kwargs)
|
||||
if query:
|
||||
return url + "?" + urlencode(query)
|
||||
return url
|
||||
|
||||
def if_user_url(self, path: str | None = None) -> str:
|
||||
"""same as self.url() but show URL in shell"""
|
||||
url = self.url("authentik_core:if-user")
|
||||
|
||||
146
uv.lock
generated
146
uv.lock
generated
@@ -318,11 +318,11 @@ requires-dist = [
|
||||
{ name = "argon2-cffi", specifier = "==25.1.0" },
|
||||
{ name = "cachetools", specifier = "==7.0.6" },
|
||||
{ name = "channels", specifier = "==4.3.2" },
|
||||
{ name = "cryptography", specifier = "==47.0.0" },
|
||||
{ name = "cryptography", specifier = "==48.0.0" },
|
||||
{ name = "dacite", specifier = "==1.9.2" },
|
||||
{ name = "deepmerge", specifier = "==2.0" },
|
||||
{ name = "defusedxml", specifier = "==0.7.1" },
|
||||
{ name = "django", specifier = "==5.2.13" },
|
||||
{ name = "django", specifier = "==5.2.14" },
|
||||
{ name = "django-channels-postgres", editable = "packages/django-channels-postgres" },
|
||||
{ name = "django-countries", specifier = "==8.2.0" },
|
||||
{ name = "django-dramatiq-postgres", editable = "packages/django-dramatiq-postgres" },
|
||||
@@ -355,9 +355,9 @@ requires-dist = [
|
||||
{ name = "lxml", specifier = "==6.1.0" },
|
||||
{ name = "msgraph-sdk", specifier = "==1.56.0" },
|
||||
{ name = "opencontainers", git = "https://github.com/vsoch/oci-python?rev=ceb4fcc090851717a3069d78e85ceb1e86c2740c" },
|
||||
{ name = "packaging", specifier = "==26.1" },
|
||||
{ name = "packaging", specifier = "==26.2" },
|
||||
{ name = "paramiko", specifier = "==4.0.0" },
|
||||
{ name = "psycopg", extras = ["c", "pool"], specifier = "==3.3.3" },
|
||||
{ name = "psycopg", extras = ["c", "pool"], specifier = "==3.3.4" },
|
||||
{ name = "pydantic", specifier = "==2.13.3" },
|
||||
{ name = "pydantic-scim", specifier = "==0.0.8" },
|
||||
{ name = "pyjwt", specifier = "==2.11.0" },
|
||||
@@ -375,7 +375,7 @@ requires-dist = [
|
||||
{ name = "ua-parser", specifier = "==1.0.2" },
|
||||
{ name = "unidecode", specifier = "==1.4.0" },
|
||||
{ name = "urllib3", specifier = "<3" },
|
||||
{ name = "uvicorn", extras = ["standard"], specifier = "==0.45.0" },
|
||||
{ name = "uvicorn", extras = ["standard"], specifier = "==0.46.0" },
|
||||
{ name = "watchdog", specifier = "==6.0.0" },
|
||||
{ name = "webauthn", specifier = "==2.7.1" },
|
||||
{ name = "wsproto", specifier = "==1.3.2" },
|
||||
@@ -385,7 +385,7 @@ requires-dist = [
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [
|
||||
{ name = "aws-cdk-lib", specifier = "==2.250.0" },
|
||||
{ name = "aws-cdk-lib", specifier = "==2.251.0" },
|
||||
{ name = "bandit", specifier = "==1.9.4" },
|
||||
{ name = "black", specifier = "==26.3.1" },
|
||||
{ name = "bpython", specifier = "==0.26" },
|
||||
@@ -481,21 +481,21 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-cdk-cloud-assembly-schema"
|
||||
version = "53.9.0"
|
||||
version = "53.20.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "jsii" },
|
||||
{ name = "publication" },
|
||||
{ name = "typeguard" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7c/95/afd7bd310b7eb64bfa51700e283a297a57692d8ca5a3a289d9bfe6ca92f6/aws_cdk_cloud_assembly_schema-53.9.0.tar.gz", hash = "sha256:0a9a537c6cdfebbf3e97f250aaff92d811a6be94394a4673784a50660889a3cb", size = 210905, upload-time = "2026-03-26T18:44:01.266Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/bf/8a/3b94fbba0d8ca4123eb015ea12a1c8fc5193a1eddcc4d69d31b9575546c8/aws_cdk_cloud_assembly_schema-53.20.0.tar.gz", hash = "sha256:c5d884f7211fd18cc0ce8c4349902ab6a6b3cd8f3c2259c56616a59218c221eb", size = 212292, upload-time = "2026-04-30T11:34:29.29Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6e/d0/4dbd2020f8fa6991f6469ed1851981f3160965393ea4cef19a59bf8c938b/aws_cdk_cloud_assembly_schema-53.9.0-py3-none-any.whl", hash = "sha256:41e75541d3ea3d46edbe67ade491d974f0472ac62c3856596e3029fe384a9a44", size = 210649, upload-time = "2026-03-26T18:43:59.951Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b5/eb/7bf100ad3603d5fbbebb49b3d48add58abda59c3fa44a4a7eae40da5b8d0/aws_cdk_cloud_assembly_schema-53.20.0-py3-none-any.whl", hash = "sha256:b68ea0754ec830751d4a375ebe84d4c077dc488a2498c3607a2f998bc7e91d73", size = 212140, upload-time = "2026-04-30T11:34:27.044Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aws-cdk-lib"
|
||||
version = "2.250.0"
|
||||
version = "2.251.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "aws-cdk-asset-awscli-v1" },
|
||||
@@ -506,9 +506,9 @@ dependencies = [
|
||||
{ name = "publication" },
|
||||
{ name = "typeguard" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d5/7b/98c66b6ea6d4f84b70d86ec391bbcd2856a82b384a97adc223f36b36dfd6/aws_cdk_lib-2.250.0.tar.gz", hash = "sha256:6e5cb8def9208a45cede1376a81d7508b3889879ccc7e9cddaa4fd807da0b144", size = 49146123, upload-time = "2026-04-14T21:43:07.309Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b8/6c/d60d96e1848aabf1882e6a1d30a27de4a592affc9437d6918848f0e06497/aws_cdk_lib-2.251.0.tar.gz", hash = "sha256:ed69e7ea6896c62ac2ce01857083601baf541d5d875370bee6d213d641e8921e", size = 49353237, upload-time = "2026-04-24T23:21:04.805Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/e7/b64389b59215a42d0d7538a1d9a8006edb2eefb297ccbdcd4c55ff2cffba/aws_cdk_lib-2.250.0-py3-none-any.whl", hash = "sha256:427c9a062f350c16e301326fd6ca0440428f9cc0e85421aaa69a9afa57228acc", size = 49827287, upload-time = "2026-04-14T21:42:21.21Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/fb/ab682b518e3ca5d18b23b252832e0fade4e6617a2c0f2b0ae0d8d2e74312/aws_cdk_lib-2.251.0-py3-none-any.whl", hash = "sha256:a684f3461d096443ac688adbf559abe1af2d50dd5c8e0fa7dbf4a5f361702db8", size = 50035969, upload-time = "2026-04-24T23:20:18.952Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -917,55 +917,55 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "47.0.0"
|
||||
version = "48.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ef/b2/7ffa7fe8207a8c42147ffe70c3e360b228160c1d85dc3faff16aaa3244c0/cryptography-47.0.0.tar.gz", hash = "sha256:9f8e55fe4e63613a5e1cc5819030f27b97742d720203a087802ce4ce9ceb52bb", size = 830863, upload-time = "2026-04-24T19:54:57.056Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9f/a9/db8f313fdcd85d767d4973515e1db101f9c71f95fced83233de224673757/cryptography-48.0.0.tar.gz", hash = "sha256:5c3932f4436d1cccb036cb0eaef46e6e2db91035166f1ad6505c3c9d5a635920", size = 832984, upload-time = "2026-05-04T22:59:38.133Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/98/40dfe932134bdcae4f6ab5927c87488754bf9eb79297d7e0070b78dd58e9/cryptography-47.0.0-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:160ad728f128972d362e714054f6ba0067cab7fb350c5202a9ae8ae4ce3ef1a0", size = 7912214, upload-time = "2026-04-24T19:53:03.864Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/c6/2733531243fba725f58611b918056b277692f1033373dcc8bd01af1c05d4/cryptography-47.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b9a8943e359b7615db1a3ba587994618e094ff3d6fa5a390c73d079ce18b3973", size = 4644617, upload-time = "2026-04-24T19:53:06.909Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/e3/b27be1a670a9b87f855d211cf0e1174a5d721216b7616bd52d8581d912ed/cryptography-47.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f5c15764f261394b22aef6b00252f5195f46f2ca300bec57149474e2538b31f8", size = 4668186, upload-time = "2026-04-24T19:53:09.053Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/b9/8443cfe5d17d482d348cee7048acf502bb89a51b6382f06240fd290d4ca3/cryptography-47.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9c59ab0e0fa3a180a5a9c59f3a5abe3ef90d474bc56d7fadfbe80359491b615b", size = 4651244, upload-time = "2026-04-24T19:53:11.217Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/5e/13ed0cdd0eb88ba159d6dd5ebfece8cb901dbcf1ae5ac4072e28b55d3153/cryptography-47.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:34b4358b925a5ea3e14384ca781a2c0ef7ac219b57bb9eacc4457078e2b19f92", size = 5252906, upload-time = "2026-04-24T19:53:13.532Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/64/16/ed058e1df0f33d440217cd120d41d5dda9dd215a80b8187f68483185af82/cryptography-47.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0024b87d47ae2399165a6bfb20d24888881eeab83ae2566d62467c5ff0030ce7", size = 4701842, upload-time = "2026-04-24T19:53:15.618Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/e0/3d30986b30fdbd9e969abbdf8ba00ed0618615144341faeb57f395a084fe/cryptography-47.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:1e47422b5557bb82d3fff997e8d92cff4e28b9789576984f08c248d2b3535d93", size = 4289313, upload-time = "2026-04-24T19:53:17.755Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/fd/32db38e3ad0cb331f0691cb4c7a8a6f176f679124dee746b3af6633db4d9/cryptography-47.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:6f29f36582e6151d9686235e586dd35bb67491f024767d10b842e520dc6a07ac", size = 4650964, upload-time = "2026-04-24T19:53:20.062Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/53/5395d944dfd48cb1f67917f533c609c34347185ef15eb4308024c876f274/cryptography-47.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:a9b761f012a943b7de0e828843c5688d0de94a0578d44d6c85a1bae32f87791f", size = 5207817, upload-time = "2026-04-24T19:53:22.498Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/4f/e5711b28e1901f7d480a2b1b688b645aa4c77c73f10731ed17e7f7db3f0d/cryptography-47.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4e1de79e047e25d6e9f8cea71c86b4a53aced64134f0f003bbcbf3655fd172c8", size = 4701544, upload-time = "2026-04-24T19:53:24.356Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/22/c8ddc25de3010fc8da447648f5a092c40e7a8fadf01dd6d255d9c0b9373d/cryptography-47.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef6b3634087f18d2155b1e8ce264e5345a753da2c5fa9815e7d41315c90f8318", size = 4783536, upload-time = "2026-04-24T19:53:26.665Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/b6/d4a68f4ea999c6d89e8498579cba1c5fcba4276284de7773b17e4fa69293/cryptography-47.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:11dbb9f50a0f1bb9757b3d8c27c1101780efb8f0bdecfb12439c22a74d64c001", size = 4926106, upload-time = "2026-04-24T19:53:28.686Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/ed/5f524db1fade9c013aa618e1c99c6ed05e8ffc9ceee6cda22fed22dda3f4/cryptography-47.0.0-cp311-abi3-win32.whl", hash = "sha256:7fda2f02c9015db3f42bb8a22324a454516ed10a8c29ca6ece6cdbb5efe2a203", size = 3258581, upload-time = "2026-04-24T19:53:31.058Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b2/dc/1b901990b174786569029f67542b3edf72ac068b6c3c8683c17e6a2f5363/cryptography-47.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:f5c3296dab66202f1b18a91fa266be93d6aa0c2806ea3d67762c69f60adc71aa", size = 3775309, upload-time = "2026-04-24T19:53:33.054Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/88/7aa18ad9c11bc87689affa5ce4368d884b517502d75739d475fc6f4a03c7/cryptography-47.0.0-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:be12cb6a204f77ed968bcefe68086eb061695b540a3dd05edac507a3111b25f0", size = 7904299, upload-time = "2026-04-24T19:53:35.003Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/55/c18f75724544872f234678fdedc871391722cb34a2aee19faa9f63100bb2/cryptography-47.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2ebd84adf0728c039a3be2700289378e1c164afc6748df1a5ed456767bef9ba7", size = 4631180, upload-time = "2026-04-24T19:53:37.517Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/65/31a5cc0eaca99cec5bafffe155d407115d96136bb161e8b49e0ef73f09a7/cryptography-47.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7f68d6fbc7fbbcfb0939fea72c3b96a9f9a6edfc0e1b1d29778a2066030418b1", size = 4653529, upload-time = "2026-04-24T19:53:39.775Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/bc/641c0519a495f3bfd0421b48d7cd325c4336578523ccd76ea322b6c29c7a/cryptography-47.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:6651d32eff255423503aa276739da98c30f26c40cbeffcc6048e0d54ef704c0c", size = 4638570, upload-time = "2026-04-24T19:53:42.129Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/f2/300327b0a47f6dc94dd8b71b57052aefe178bb51745073d73d80604f11ab/cryptography-47.0.0-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:3fb8fa48075fad7193f2e5496135c6a76ac4b2aa5a38433df0a539296b377829", size = 5238019, upload-time = "2026-04-24T19:53:44.577Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/5a/5b5cf994391d4bf9d9c7efd4c66aabe4d95227256627f8fea6cff7dfadbd/cryptography-47.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:11438c7518132d95f354fa01a4aa2f806d172a061a7bed18cf18cbdacdb204d7", size = 4686832, upload-time = "2026-04-24T19:53:47.015Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dc/2c/ae950e28fd6475c852fc21a44db3e6b5bcc1261d1e370f2b6e42fa800fef/cryptography-47.0.0-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:8c1a736bbb3288005796c3f7ccb9453360d7fed483b13b9f468aea5171432923", size = 4269301, upload-time = "2026-04-24T19:53:48.97Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/fb/6a39782e150ffe5cc1b0018cb6ddc48bf7ca62b498d7539ffc8a758e977d/cryptography-47.0.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:f1557695e5c2b86e204f6ce9470497848634100787935ab7adc5397c54abd7ab", size = 4638110, upload-time = "2026-04-24T19:53:51.011Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/d7/0b3c71090a76e5c203164a47688b697635ece006dcd2499ab3a4dbd3f0bd/cryptography-47.0.0-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:f9a034b642b960767fb343766ae5ba6ad653f2e890ddd82955aef288ffea8736", size = 5194988, upload-time = "2026-04-24T19:53:52.962Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/63/33/63a961498a9df51721ab578c5a2622661411fc520e00bd83b0cc64eb20c4/cryptography-47.0.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:b1c76fca783aa7698eb21eb14f9c4aa09452248ee54a627d125025a43f83e7a7", size = 4686563, upload-time = "2026-04-24T19:53:55.274Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/bf/5ee5b145248f92250de86145d1c1d6edebbd57a7fe7caa4dedb5d4cf06a1/cryptography-47.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4f7722c97826770bab8ae92959a2e7b20a5e9e9bf4deae68fd86c3ca457bab52", size = 4770094, upload-time = "2026-04-24T19:53:57.753Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/43/21d220b2da5d517773894dacdcdb5c682c28d3fffce65548cb06e87d5501/cryptography-47.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:09f6d7bf6724f8db8b32f11eccf23efc8e759924bc5603800335cf8859a3ddbd", size = 4913811, upload-time = "2026-04-24T19:54:00.236Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/98/dc4ad376ac5f1a1a7d4a83f7b0c6f2bcad36b5d2d8f30aeb482d3a7d9582/cryptography-47.0.0-cp314-cp314t-win32.whl", hash = "sha256:6eebcaf0df1d21ce1f90605c9b432dd2c4f4ab665ac29a40d5e3fc68f51b5e63", size = 3237158, upload-time = "2026-04-24T19:54:02.606Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/da/97f62d18306b5133468bc3f8cc73a3111e8cdc8cf8d3e69474d6e5fd2d1b/cryptography-47.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:51c9313e90bd1690ec5a75ed047c27c0b8e6c570029712943d6116ef9a90620b", size = 3758706, upload-time = "2026-04-24T19:54:04.433Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:14432c8a9bcb37009784f9594a62fae211a2ae9543e96c92b2a8e4c3cd5cd0c4", size = 7904072, upload-time = "2026-04-24T19:54:06.411Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/01/64/d7b1e54fdb69f22d24a64bb3e88dc718b31c7fb10ef0b9691a3cf7eeea6e/cryptography-47.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:07efe86201817e7d3c18781ca9770bc0db04e1e48c994be384e4602bc38f8f27", size = 4635767, upload-time = "2026-04-24T19:54:08.519Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8b/7b/cca826391fb2a94efdcdfe4631eb69306ee1cff0b22f664a412c90713877/cryptography-47.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2b45761c6ec22b7c726d6a829558777e32d0f1c8be7c3f3480f9c912d5ee8a10", size = 4654350, upload-time = "2026-04-24T19:54:10.795Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/65/4b57bcc823f42a991627c51c2f68c9fd6eb1393c1756aac876cba2accae2/cryptography-47.0.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:edd4da498015da5b9f26d38d3bfc2e90257bfa9cbed1f6767c282a0025ae649b", size = 4643394, upload-time = "2026-04-24T19:54:13.275Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/c4/2c5fbeea70adbbca2bbae865e1d605d6a4a7f8dbd9d33eaf69645087f06c/cryptography-47.0.0-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9af828c0d5a65c70ec729cd7495a4bf1a67ecb66417b8f02ff125ab8a6326a74", size = 5225777, upload-time = "2026-04-24T19:54:15.18Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/b8/ac57107ef32749d2b244e36069bb688792a363aaaa3acc9e3cf84c130315/cryptography-47.0.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:256d07c78a04d6b276f5df935a9923275f53bd1522f214447fdf365494e2d515", size = 4688771, upload-time = "2026-04-24T19:54:17.835Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/56/fc/9f1de22ff8be99d991f240a46863c52d475404c408886c5a38d2b5c3bb26/cryptography-47.0.0-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:5d0e362ff51041b0c0d219cc7d6924d7b8996f57ce5712bdcef71eb3c65a59cc", size = 4270753, upload-time = "2026-04-24T19:54:19.963Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/68/d70c852797aa68e8e48d12e5a87170c43f67bb4a59403627259dd57d15de/cryptography-47.0.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:1581aef4219f7ca2849d0250edaa3866212fb74bf5667284f46aa92f9e65c1ca", size = 4642911, upload-time = "2026-04-24T19:54:21.818Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/51/661cbee74f594c5d97ff82d34f10d5551c085ca4668645f4606ebd22bd5d/cryptography-47.0.0-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:a49a3eb5341b9503fa3000a9a0db033161db90d47285291f53c2a9d2cd1b7f76", size = 5181411, upload-time = "2026-04-24T19:54:24.376Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/87/f2b6c374a82cf076cfa1416992ac8e8ec94d79facc37aec87c1a5cb72352/cryptography-47.0.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2207a498b03275d0051589e326b79d4cf59985c99031b05bb292ac52631c37fe", size = 4688262, upload-time = "2026-04-24T19:54:26.946Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/e2/8b7462f4acf21ec509616f0245018bb197194ab0b65c2ea21a0bdd53c0eb/cryptography-47.0.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7a02675e2fabd0c0fc04c868b8781863cbf1967691543c22f5470500ff840b31", size = 4775506, upload-time = "2026-04-24T19:54:28.926Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/75/158e494e4c08dc05e039da5bb48553826bd26c23930cf8d3cd5f21fa8921/cryptography-47.0.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80887c5cbd1774683cb126f0ab4184567f080071d5acf62205acb354b4b753b7", size = 4912060, upload-time = "2026-04-24T19:54:30.869Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/bd/0a9d3edbf5eadbac926d7b9b3cd0c4be584eeeae4a003d24d9eda4affbbd/cryptography-47.0.0-cp38-abi3-win32.whl", hash = "sha256:ed67ea4e0cfb5faa5bc7ecb6e2b8838f3807a03758eec239d6c21c8769355310", size = 3248487, upload-time = "2026-04-24T19:54:33.494Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/60/80/5681af756d0da3a599b7bdb586fac5a1540f1bcefd2717a20e611ddade45/cryptography-47.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:835d2d7f47cdc53b3224e90810fb1d36ca94ea29cc1801fb4c1bc43876735769", size = 3755737, upload-time = "2026-04-24T19:54:35.408Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/3d/01f6dd9190170a5a241e0e98c2d04be3664a9e6f5b9b872cde63aff1c3dd/cryptography-48.0.0-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:0c558d2cdffd8f4bbb30fc7134c74d2ca9a476f830bb053074498fbc86f41ed6", size = 8001587, upload-time = "2026-05-04T22:57:36.803Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b2/6e/e90527eef33f309beb811cf7c982c3aeffcce8e3edb178baa4ca3ae4a6fa/cryptography-48.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f5333311663ea94f75dd408665686aaf426563556bb5283554a3539177e03b8c", size = 4690433, upload-time = "2026-05-04T22:57:40.373Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/90/04/673510ed51ddff56575f306cf1617d80411ee76831ccd3097599140efdfe/cryptography-48.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7995ef305d7165c3f11ae07f2517e5a4f1d5c18da1376a0a9ed496336b69e5f3", size = 4710620, upload-time = "2026-05-04T22:57:42.935Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/d5/e9c4ef932c8d800490c34d8bd589d64a31d5890e27ec9e9ad532be893294/cryptography-48.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:40ba1f85eaa6959837b1d51c9767e230e14612eea4ef110ee8854ada22da1bf5", size = 4696283, upload-time = "2026-05-04T22:57:45.294Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/29/174b9dfb60b12d59ecfc6cfa04bc88c21b42a54f01b8aae09bb6e51e4c7f/cryptography-48.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:369a6348999f94bbd53435c894377b20ab95f25a9065c283570e70150d8abc3c", size = 5296573, upload-time = "2026-05-04T22:57:47.933Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/38/0d29a6fd7d0d1373f0c0c88a04ba20e359b257753ac497564cd660fc1d55/cryptography-48.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a0e692c683f4df67815a2d258b324e66f4738bd7a96a218c826dce4f4bd05d8f", size = 4743677, upload-time = "2026-05-04T22:57:50.067Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/be/eef653013d5c63b6a490529e0316f9ac14a37602965d4903efed1399f32b/cryptography-48.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:18349bbc56f4743c8b12dc32e2bccb2cf83ee8b69a3bba74ef8ae857e26b3d25", size = 4330808, upload-time = "2026-05-04T22:57:52.301Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/84/9e/500463e87abb7a0a0f9f256ec21123ecde0a7b5541a15e840ea54551fd81/cryptography-48.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:7e8eac43dfca5c4cccc6dad9a80504436fca53bb9bc3100a2386d730fbe6b602", size = 4695941, upload-time = "2026-05-04T22:57:54.603Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e3/dc/7303087450c2ec9e7fbb750e17c2abfbc658f23cbd0e54009509b7cc4091/cryptography-48.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9ccdac7d40688ecb5a3b4a604b8a88c8002e3442d6c60aead1db2a89a041560c", size = 5252579, upload-time = "2026-05-04T22:57:57.207Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/c0/7101d3b7215edcdc90c45da544961fd8ed2d6448f77577460fa75a8443f7/cryptography-48.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:bd72e68b06bb1e96913f97dd4901119bc17f39d4586a5adf2d3e47bc2b9d58b5", size = 4743326, upload-time = "2026-05-04T22:57:59.535Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/d8/5b833bad13016f562ab9d063d68199a4bd121d18458e439515601d3357ec/cryptography-48.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:59baa2cb386c4f0b9905bd6eb4c2a79a69a128408fd31d32ca4d7102d4156321", size = 4826672, upload-time = "2026-05-04T22:58:01.996Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/98/e1/7074eb8bf3c135558c73fc2bcf0f5633f912e6fb87e868a55c454080ef09/cryptography-48.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9249e3cd978541d665967ac2cb2787fd6a62bddf1e75b3e347a594d7dacf4f74", size = 4972574, upload-time = "2026-05-04T22:58:03.968Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/04/70/e5a1b41d325f797f39427aa44ef8baf0be500065ab6d8e10369d850d4a4f/cryptography-48.0.0-cp311-abi3-win32.whl", hash = "sha256:9c459db21422be75e2809370b829a87eb37f74cd785fc4aa9ea1e5f43b47cda4", size = 3294868, upload-time = "2026-05-04T22:58:06.467Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/ac/8ac51b4a5fc5932eb7ee5c517ba7dc8cd834f0048962b6b352f00f41ebf9/cryptography-48.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:5b012212e08b8dd5edc78ef54da83dd9892fd9105323b3993eff6bea65dc21d7", size = 3817107, upload-time = "2026-05-04T22:58:08.845Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/84/70e3feea9feea87fd7cbe77efb2712ae1e3e6edf10749dc6e95f4e60e455/cryptography-48.0.0-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:3cb07a3ed6431663cd321ea8a000a1314c74211f823e4177fefa2255e057d1ec", size = 7986556, upload-time = "2026-05-04T22:58:11.172Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/6e/18e07a618bb5442ba10cf4df16e99c071365528aa570dfcb8c02e25a303b/cryptography-48.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8c7378637d7d88016fa6791c159f698b3d3eed28ebf844ac36b9dc04a14dae18", size = 4684776, upload-time = "2026-05-04T22:58:13.712Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/6a/4ea3b4c6c6759794d5ee2103c304a5076dc4b19ae1f9fe47dba439e159e9/cryptography-48.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc90c0b39b2e3c65ef52c804b72e3c58f8a04ab2a1871272798e5f9572c17d20", size = 4698121, upload-time = "2026-05-04T22:58:16.448Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2f/59/6ff6ad6cae03bb887da2a5860b2c9805f8dac969ef01ce563336c49bd1d1/cryptography-48.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:76341972e1eff8b4bea859f09c0d3e64b96ce931b084f9b9b7db8ef364c30eff", size = 4690042, upload-time = "2026-05-04T22:58:18.544Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/b4/fc334ed8cfd705aca282fe4d8f5ae64a8e0f74932e9feecb344610cf6e4d/cryptography-48.0.0-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:55b7718303bf06a5753dcdccf2f3945cf18ad7bffde41b61226e4db31ab89a9c", size = 5282526, upload-time = "2026-05-04T22:58:20.75Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/11/08/9f8c5386cc4cd90d8255c7cdd0f5baf459a08502a09de30dc51f553d38dc/cryptography-48.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:a64697c641c7b1b2178e573cbc31c7c6684cd56883a478d75143dbb7118036db", size = 4733116, upload-time = "2026-05-04T22:58:23.627Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/77/99307d7574045699f8805aa500fa0fb83422d115b5400a064ddd306d7750/cryptography-48.0.0-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:561215ea3879cb1cbbf272867e2efda62476f240fb58c64de6b393ae19246741", size = 4316030, upload-time = "2026-05-04T22:58:25.581Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/36/a608b98337af3cb2aff4818e406649d30572b7031918b04c87d979495348/cryptography-48.0.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:ad64688338ed4bc1a6618076ba75fd7194a5f1797ac60b47afe926285adb3166", size = 4689640, upload-time = "2026-05-04T22:58:27.747Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dd/a6/825010a291b4438aecc1f568bc428189fc1175515223632477c07dc0a6df/cryptography-48.0.0-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:906cbf0670286c6e0044156bc7d4af9cbb0ef6db9f73e52c3ec56ba6bdde5336", size = 5237657, upload-time = "2026-05-04T22:58:29.848Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/09/4e76a09b4caa29aad535ddc806f5d4c5d01885bd978bd984fbc6ca032cae/cryptography-48.0.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:ea8990436d914540a40ab24b6a77c0969695ed52f4a4874c5137ccf7045a7057", size = 4732362, upload-time = "2026-05-04T22:58:32.009Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/78/444fa04a77d0cb95f417dda20d450e13c56ba8e5220fc892a1658f44f882/cryptography-48.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c18684a7f0cc9a3cb60328f496b8e3372def7c5d2df39ac267878b05565aaaae", size = 4819580, upload-time = "2026-05-04T22:58:34.254Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/38/85/ea67067c70a1fd4be2c63d35eeed82658023021affccc7b17705f8527dd2/cryptography-48.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9be5aafa5736574f8f15f262adc81b2a9869e2cfe9014d52a44633905b40d52c", size = 4963283, upload-time = "2026-05-04T22:58:36.376Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/54/cc6d0f3deac3e81c7f847e8a189a12b6cdd65059b43dad25d4316abd849a/cryptography-48.0.0-cp314-cp314t-win32.whl", hash = "sha256:c17dfe85494deaeddc5ce251aebd1d60bbe6afc8b62071bb0b469431a000124f", size = 3270954, upload-time = "2026-05-04T22:58:38.791Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/67/cc947e288c0758a4e5473d1dcb743037ab7785541265a969240b8885441a/cryptography-48.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27241b1dc9962e056062a8eef1991d02c3a24569c95975bd2322a8a52c6e5e12", size = 3797313, upload-time = "2026-05-04T22:58:40.746Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/63/61d4a4e1c6b6bab6ce1e213cd36a24c415d90e76d78c5eb8577c5541d2e8/cryptography-48.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:58d00498e8933e4a194f3076aee1b4a97dfec1a6da444535755822fe5d8b0b86", size = 7983482, upload-time = "2026-05-04T22:58:43.769Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/ac/f5b5995b87770c693e2596559ffafe195b4033a57f14a82268a2842953f3/cryptography-48.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:614d0949f4790582d2cc25553abd09dd723025f0c0e7c67376a1d77196743d6e", size = 4683266, upload-time = "2026-05-04T22:58:46.064Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/c6/8b14f67e18338fbc4adb76f66c001f5c3610b3e2d1837f268f47a347dbbb/cryptography-48.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7ce4bfae76319a532a2dc68f82cc32f5676ee792a983187dac07183690e5c66f", size = 4696228, upload-time = "2026-05-04T22:58:48.22Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/73/f808fbae9514bd91b47875b003f13e284c8c6bdfd904b7944e803937eec1/cryptography-48.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:2eb992bbd4661238c5a397594c83f5b4dc2bc5b848c365c8f991b6780efcc5c7", size = 4689097, upload-time = "2026-05-04T22:58:50.9Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/93/01/d86632d7d28db8ae83221995752eeb6639ffb374c2d22955648cf8d52797/cryptography-48.0.0-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:22a5cb272895dce158b2cacdfdc3debd299019659f42947dbdac6f32d68fe832", size = 5283582, upload-time = "2026-05-04T22:58:53.017Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/e1/50edc7a50334807cc4791fc4a0ce7468b4a1416d9138eab358bfc9a3d70b/cryptography-48.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2b4d59804e8408e2fea7d1fbaf218e5ec984325221db76e6a241a9abd6cdd95c", size = 4730479, upload-time = "2026-05-04T22:58:55.611Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/af/99a582b1b1641ff5911ac559beb45097cf79efd4ead4657f578ef1af2d47/cryptography-48.0.0-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:984a20b0f62a26f48a3396c72e4bc34c66e356d356bf370053066b3b6d54634a", size = 4326481, upload-time = "2026-05-04T22:58:57.607Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/90/ee/89aa26a06ef0a7d7611788ffd571a7c50e368cc6a4d5eef8b4884e866edb/cryptography-48.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5a5ed8fde7a1d09376ca0b40e68cd59c69fe23b1f9768bd5824f54681626032a", size = 4688713, upload-time = "2026-05-04T22:59:00.077Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/ba/bcb1b0bb7a33d4c7c0c4d4c7874b4a62ae4f56113a5f4baefa362dfb1f0f/cryptography-48.0.0-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:8cd666227ef7af430aa5914a9910e0ddd703e75f039cef0825cd0da71b6b711a", size = 5238165, upload-time = "2026-05-04T22:59:02.317Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c9/70/ca4003b1ce5ca3dc3186ada51908c8a9b9ff7d5cab83cc0d43ee14ec144f/cryptography-48.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:9071196d81abc88b3516ac8cdfad32e2b66dd4a5393a8e68a961e9161ddc6239", size = 4729947, upload-time = "2026-05-04T22:59:05.255Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/a0/4ec7cf774207905aef1a8d11c3750d5a1db805eb380ee4e16df317870128/cryptography-48.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1e2d54c8be6152856a36f0882ab231e70f8ec7f14e93cf87db8a2ed056bf160c", size = 4822059, upload-time = "2026-05-04T22:59:07.802Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/75/a2e55f99c16fcac7b5d6c1eb19ad8e00799854d6be5ca845f9259eae1681/cryptography-48.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a5da777e32ffed6f85a7b2b3f7c5cbc88c146bfcd0a1d7baf5fcc6c52ee35dd4", size = 4960575, upload-time = "2026-05-04T22:59:09.851Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/23/6e6f32143ab5d8b36ca848a502c4bcd477ae75b9e1677e3530d669062578/cryptography-48.0.0-cp39-abi3-win32.whl", hash = "sha256:77a2ccbbe917f6710e05ba9adaa25fb5075620bf3ea6fb751997875aff4ae4bd", size = 3279117, upload-time = "2026-05-04T22:59:12.019Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/9a/0fea98a70cf1749d41d738836f6349d97945f7c89433a259a6c2642eefeb/cryptography-48.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:16cd65b9330583e4619939b3a3843eec1e6e789744bb01e7c7e2e62e33c239c8", size = 3792100, upload-time = "2026-05-04T22:59:14.884Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1075,16 +1075,16 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "django"
|
||||
version = "5.2.13"
|
||||
version = "5.2.14"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "asgiref" },
|
||||
{ name = "sqlparse" },
|
||||
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1f/c5/c69e338eb2959f641045802e5ea87ca4bf5ac90c5fd08953ca10742fad51/django-5.2.13.tar.gz", hash = "sha256:a31589db5188d074c63f0945c3888fad104627dfcc236fb2b97f71f89da33bc4", size = 10890368, upload-time = "2026-04-07T14:02:15.072Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/65/95/95f7faa0950867afaa0bef2460c6263afd6a2c78cc9434046ed28160b015/django-5.2.14.tar.gz", hash = "sha256:58a63ba841662e5c686b57ba1fec52ddd68c0b93bd96ac3029d55728f00bf8a2", size = 10895118, upload-time = "2026-05-05T13:57:31.104Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/59/b1/51ab36b2eefcf8cdb9338c7188668a157e29e30306bfc98a379704c9e10d/django-5.2.13-py3-none-any.whl", hash = "sha256:5788fce61da23788a8ce6f02583765ab060d396720924789f97fa42119d37f7a", size = 8310982, upload-time = "2026-04-07T14:02:08.883Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/44/f172870cf87aa25afef48fb72adba89ee8b77fcab6f3b23d240b923f1528/django-5.2.14-py3-none-any.whl", hash = "sha256:6f712143bd3064310d1f50fac859c3e9a274bdcfc9595339853be7779297fc76", size = 8311320, upload-time = "2026-05-05T13:57:25.795Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2583,11 +2583,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "26.1"
|
||||
version = "26.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/df/de/0d2b39fb4af88a0258f3bac87dfcbb48e73fbdea4a2ed0e2213f9a4c2f9a/packaging-26.1.tar.gz", hash = "sha256:f042152b681c4bfac5cae2742a55e103d27ab2ec0f3d88037136b6bfe7c9c5de", size = 215519, upload-time = "2026-04-14T21:12:49.362Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/c2/920ef838e2f0028c8262f16101ec09ebd5969864e5a64c4c05fad0617c56/packaging-26.1-py3-none-any.whl", hash = "sha256:5d9c0669c6285e491e0ced2eee587eaf67b670d94a19e94e3984a481aba6802f", size = 95831, upload-time = "2026-04-14T21:12:47.56Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2733,14 +2733,14 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "psycopg"
|
||||
version = "3.3.3"
|
||||
version = "3.3.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d3/b6/379d0a960f8f435ec78720462fd94c4863e7a31237cf81bf76d0af5883bf/psycopg-3.3.3.tar.gz", hash = "sha256:5e9a47458b3c1583326513b2556a2a9473a1001a56c9efe9e587245b43148dd9", size = 165624, upload-time = "2026-02-18T16:52:16.546Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/db/2f/cb91e5502ec9de1de6f1b76cfbf69531932725361168bb06963620c77e2e/psycopg-3.3.4.tar.gz", hash = "sha256:e21207764952cff81b6b8bdacad9a3939f2793367fdac2987b3aac36a651b5bc", size = 165799, upload-time = "2026-05-01T23:31:55.179Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/5b/181e2e3becb7672b502f0ed7f16ed7352aca7c109cfb94cf3878a9186db9/psycopg-3.3.3-py3-none-any.whl", hash = "sha256:f96525a72bcfade6584ab17e89de415ff360748c766f0106959144dcbb38c698", size = 212768, upload-time = "2026-02-18T16:46:27.365Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/e0/7b3dee031daae7743609ce3c746565d4a3ed7c2c186479eb48e34e838c64/psycopg-3.3.4-py3-none-any.whl", hash = "sha256:b6bbc25ccf05c8fad3b061d9db2ef0909a555171b84b07f29458a447253d679a", size = 213001, upload-time = "2026-05-01T23:20:50.816Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
@@ -2753,9 +2753,9 @@ pool = [
|
||||
|
||||
[[package]]
|
||||
name = "psycopg-c"
|
||||
version = "3.3.3"
|
||||
version = "3.3.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/cb/a0/8feb0ca8c7c20a8b9ac4d46b335ddd57e48e593b714262f006880f34fee5/psycopg_c-3.3.3.tar.gz", hash = "sha256:86ef6f4424348247828e83fb0882c9f8acb33e64d0a5ce66c1b4a5107ee73edd", size = 631965, upload-time = "2026-02-18T16:52:18.084Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/21/7c/c08364f2eab2913e4068b3b955d963e7a3491986a85429990969525def30/psycopg_c-3.3.4.tar.gz", hash = "sha256:ed8106128b2d04359c185fc9641b4409abfce4d0b6fb1d1ff6800646e27f1a22", size = 647111, upload-time = "2026-05-01T23:31:58.032Z" }
|
||||
|
||||
[[package]]
|
||||
name = "psycopg-pool"
|
||||
@@ -2947,14 +2947,14 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "pyopenssl"
|
||||
version = "26.1.0"
|
||||
version = "26.2.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cryptography" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8c/a8/26d36401e3ab8eed9030ad33f381da7856fcfad5691780fccd1b019718fc/pyopenssl-26.1.0.tar.gz", hash = "sha256:737f0a2275c5bc54f3b02137687e1a765931fb3949b9a92a825e4d33b9eec08b", size = 186181, upload-time = "2026-04-24T20:23:48.115Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1a/51/27a5ad5f939d08f690a326ef9582cda7140555180db71695f6fb747d6a36/pyopenssl-26.2.0.tar.gz", hash = "sha256:8c6fcecd1183a7fc897548dfe388b0cdb7f37e018200d8409cf33959dbe35387", size = 182195, upload-time = "2026-05-04T23:06:09.72Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/41/52f3a3e812b816a91e89aa504199d8bf989a1f873192b10762be66cf2009/pyopenssl-26.1.0-py3-none-any.whl", hash = "sha256:115563879b2c8ccb207975705d3e491434d8c9d7c79667c902ecbf5f3bbd2ece", size = 58109, upload-time = "2026-04-24T20:23:46.273Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/73/b8/a0e2790ae249d6f38c9f66de7a211621a7ab2650217bcd04e1262f578a56/pyopenssl-26.2.0-py3-none-any.whl", hash = "sha256:4f9d971bc5298b8bc1fab282803da04bf000c755d4ad9d99b52de2569ca19a70", size = 55823, upload-time = "2026-05-04T23:06:08.395Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3808,15 +3808,15 @@ socks = [
|
||||
|
||||
[[package]]
|
||||
name = "uvicorn"
|
||||
version = "0.45.0"
|
||||
version = "0.46.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "click" },
|
||||
{ name = "h11" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/62b0d9a2cfc8b4de6771322dae30f2db76c66dae9ec32e94e176a44ad563/uvicorn-0.45.0.tar.gz", hash = "sha256:3fe650df136c5bd2b9b06efc5980636344a2fbb840e9ddd86437d53144fa335d", size = 87818, upload-time = "2026-04-21T10:43:46.815Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1f/93/041fca8274050e40e6791f267d82e0e2e27dd165627bd640d3e0e378d877/uvicorn-0.46.0.tar.gz", hash = "sha256:fb9da0926999cc6cb22dc7cd71a94a632f078e6ae47ff683c5c420750fb7413d", size = 88758, upload-time = "2026-04-23T07:16:00.151Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/88/d0f7512465b166a4e931ccf7e77792be60fb88466a43964c7566cbaff752/uvicorn-0.45.0-py3-none-any.whl", hash = "sha256:2db26f588131aeec7439de00f2dd52d5f210710c1f01e407a52c90b880d1fd4f", size = 69838, upload-time = "2026-04-21T10:43:45.029Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/a3/5b1562db76a5a488274b2332a97199b32d0442aca0ed193697fd47786316/uvicorn-0.46.0-py3-none-any.whl", hash = "sha256:bbebbcbed972d162afca128605223022bedd345b7bc7855ce66deb31487a9048", size = 70926, upload-time = "2026-04-23T07:15:58.355Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
|
||||
502
web/package-lock.json
generated
502
web/package-lock.json
generated
@@ -21,7 +21,7 @@
|
||||
"@codemirror/theme-one-dark": "^6.1.3",
|
||||
"@eslint/js": "^9.39.3",
|
||||
"@floating-ui/dom": "^1.7.6",
|
||||
"@formatjs/intl-listformat": "^8.3.2",
|
||||
"@formatjs/intl-listformat": "^8.3.4",
|
||||
"@fortawesome/fontawesome-free": "^7.2.0",
|
||||
"@goauthentik/api": "0.0.0",
|
||||
"@goauthentik/core": "^1.0.0",
|
||||
@@ -43,11 +43,11 @@
|
||||
"@patternfly/elements": "^4.4.0",
|
||||
"@patternfly/patternfly": "^4.224.2",
|
||||
"@playwright/test": "^1.59.1",
|
||||
"@sentry/browser": "^10.49.0",
|
||||
"@storybook/addon-docs": "^10.3.5",
|
||||
"@storybook/addon-links": "^10.3.5",
|
||||
"@storybook/web-components": "^10.3.5",
|
||||
"@storybook/web-components-vite": "^10.3.5",
|
||||
"@sentry/browser": "^10.50.0",
|
||||
"@storybook/addon-docs": "^10.3.6",
|
||||
"@storybook/addon-links": "^10.3.6",
|
||||
"@storybook/web-components": "^10.3.6",
|
||||
"@storybook/web-components-vite": "^10.3.6",
|
||||
"@types/codemirror": "^5.60.17",
|
||||
"@types/grecaptcha": "^3.0.9",
|
||||
"@types/guacamole-common-js": "^1.5.5",
|
||||
@@ -69,7 +69,7 @@
|
||||
"country-flag-icons": "^1.6.16",
|
||||
"date-fns": "^4.1.0",
|
||||
"deepmerge-ts": "^7.1.5",
|
||||
"dompurify": "^3.4.1",
|
||||
"dompurify": "^3.4.2",
|
||||
"esbuild": "^0.28.0",
|
||||
"eslint": "^9.39.3",
|
||||
"eslint-plugin-lit": "^2.2.1",
|
||||
@@ -78,7 +78,7 @@
|
||||
"globals": "^17.5.0",
|
||||
"guacamole-common-js": "^1.5.0",
|
||||
"hastscript": "^9.0.1",
|
||||
"knip": "^6.6.3",
|
||||
"knip": "^6.7.0",
|
||||
"lex": "^2025.11.0",
|
||||
"lit": "^3.3.2",
|
||||
"lit-analyzer": "^2.0.3",
|
||||
@@ -114,7 +114,7 @@
|
||||
"typescript": "^6.0.3",
|
||||
"typescript-eslint": "^8.57.2",
|
||||
"unist-util-visit": "^5.1.0",
|
||||
"vite": "^8.0.8",
|
||||
"vite": "^8.0.10",
|
||||
"vitest": "^4.1.1",
|
||||
"webcomponent-qr-code": "^1.3.0",
|
||||
"wireit": "^0.14.12",
|
||||
@@ -1305,27 +1305,27 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@formatjs/fast-memoize": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-3.1.2.tgz",
|
||||
"integrity": "sha512-vPnriihkfK0lzoQGaXq+qXH23VsYyansRTkTgo2aTG0k1NjLFyZimFVdfj4C9JkSE5dm7CEngcQ5TTc1yAyBfQ==",
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-3.1.3.tgz",
|
||||
"integrity": "sha512-Ocd1vPuD68rW6BJDuAOtnnc1GPeVepY5kZXML1psGVFQ+1Q8CfkftT3Tnam+Mxx97Pz08jIEDCotl/GV+Naccg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@formatjs/intl-listformat": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-8.3.2.tgz",
|
||||
"integrity": "sha512-PH8V1YVSm+AcrQ1D9Th5wxWo74vDs1V1rRGz9PCFm1HTBtZLVMN3P/+tDcpizQBvvdGNwUqHBOdxN5ZZtlq2bQ==",
|
||||
"version": "8.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-8.3.4.tgz",
|
||||
"integrity": "sha512-q7WskvO6C/Cyq7ryyM9maDL2FJzt6u39MMBrxmTHZtpTMZukG5Lw0kl9sZaCOR9tYP34xOdWp4JNUrfrkdLGXQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@formatjs/intl-localematcher": "0.8.3"
|
||||
"@formatjs/intl-localematcher": "0.8.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@formatjs/intl-localematcher": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.8.3.tgz",
|
||||
"integrity": "sha512-pHUjWb9NuhnMs8+PxQdzBtZRFJHlGhrURGAbm6Ltwl82BFajeuiIR3jblSa7ia3r62rXe/0YtVpUG3xWr5bFCA==",
|
||||
"version": "0.8.5",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.8.5.tgz",
|
||||
"integrity": "sha512-TEW/NR367c3PcQ2AXfkNig9jC740+qbkM0LgKl7UCE7Xtv7C5Uk1mvlu86MjQZBmscUai8HSWjcEETpwaVvJ6A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@formatjs/fast-memoize": "3.1.2"
|
||||
"@formatjs/fast-memoize": "3.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/fontawesome-free": {
|
||||
@@ -2895,9 +2895,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@rolldown/binding-android-arm64": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2911,9 +2911,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-darwin-arm64": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2927,9 +2927,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-darwin-x64": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2943,9 +2943,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-freebsd-x64": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2959,9 +2959,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -2975,9 +2975,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2991,9 +2991,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -3007,9 +3007,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -3023,9 +3023,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -3039,9 +3039,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -3055,9 +3055,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-x64-musl": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -3071,9 +3071,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-openharmony-arm64": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -3087,27 +3087,48 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-wasm32-wasi": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/core": "1.9.2",
|
||||
"@emnapi/runtime": "1.9.2",
|
||||
"@napi-rs/wasm-runtime": "^1.1.3"
|
||||
"@emnapi/core": "1.10.0",
|
||||
"@emnapi/runtime": "1.10.0",
|
||||
"@napi-rs/wasm-runtime": "^1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/core": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
|
||||
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/wasi-threads": "1.2.1",
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/runtime": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
|
||||
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -3121,9 +3142,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -3137,9 +3158,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/pluginutils": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@rollup/plugin-commonjs": {
|
||||
@@ -3593,75 +3614,75 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@sentry-internal/browser-utils": {
|
||||
"version": "10.49.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.49.0.tgz",
|
||||
"integrity": "sha512-n0QRx0Ysx6mPfIydTkz7VP0FmwM+/EqMZiRqdsU3aTYsngE9GmEDV0OL1bAy6a8N/C1xf9vntkuAtj6N/8Z51w==",
|
||||
"version": "10.50.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.50.0.tgz",
|
||||
"integrity": "sha512-42bxyRTxnCmYlWnvz4CxikuQNanw8UNma2WJrtxJ0f1MAJV2GhQGSHDLnA+lvFlmiz6qct3pfen/NXGyOTegTA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry/core": "10.49.0"
|
||||
"@sentry/core": "10.50.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/feedback": {
|
||||
"version": "10.49.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.49.0.tgz",
|
||||
"integrity": "sha512-JNsUBGv0faCFE7MeZUH99Y9lU9qq3LBALbLxpE1x7ngNrQnVYRlcFgdqaD/btNBKr8awjYL8gmcSkHBWskGqLQ==",
|
||||
"version": "10.50.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.50.0.tgz",
|
||||
"integrity": "sha512-0k9XZF0wn86f77mIO2U3gNNyDZooy139CnEanRzHinrN106vVzvBZ6TUEQoHtoO1fqQxr+nWWVrqV/PXUqk47w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry/core": "10.49.0"
|
||||
"@sentry/core": "10.50.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/replay": {
|
||||
"version": "10.49.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.49.0.tgz",
|
||||
"integrity": "sha512-IEy4lwHVMiRE3JAcn+kFKjsTgalDOCSTf20SoFd+nkt6rN/k1RDyr4xpdfF//Kj3UdeTmbuibYjK5H/FLhhnGg==",
|
||||
"version": "10.50.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.50.0.tgz",
|
||||
"integrity": "sha512-51FYNfnvVLAWw1rrEWPFfwHuMRb9mkVCFGA4J9/un7SpeGBsQDziGB0Di4fsCxI7+EdSBpfLHPF0csKtCCw0oQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry-internal/browser-utils": "10.49.0",
|
||||
"@sentry/core": "10.49.0"
|
||||
"@sentry-internal/browser-utils": "10.50.0",
|
||||
"@sentry/core": "10.50.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/replay-canvas": {
|
||||
"version": "10.49.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.49.0.tgz",
|
||||
"integrity": "sha512-7D/NrgH1Qwx5trDYaaTSSJmCb1yVQQLqFG4G/S9x2ltzl9876lSGJL8UeW8ReNQgF3CDAcwbmm/9aXaVSBUNZA==",
|
||||
"version": "10.50.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.50.0.tgz",
|
||||
"integrity": "sha512-jx6RKBmcJSWdI92qDGS/sBv1w+7Cww879Z/moX7bw7ipHa/Ts3iDcB3rgZwvhmi17U+mvYsbJeL2DXkPo3TjPw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry-internal/replay": "10.49.0",
|
||||
"@sentry/core": "10.49.0"
|
||||
"@sentry-internal/replay": "10.50.0",
|
||||
"@sentry/core": "10.50.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/browser": {
|
||||
"version": "10.49.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.49.0.tgz",
|
||||
"integrity": "sha512-bGCHc+wK2Dx67YoSbmtlt04alqWfQ+dasD/GVipVOq50gvw/BBIDHTEWRJEjACl+LrvszeY54V+24p8z4IgysA==",
|
||||
"version": "10.50.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.50.0.tgz",
|
||||
"integrity": "sha512-1f6rAvET6myiTaSeYqvaaBwvq1LfxqWjAPIoAW/NVC9bPMkeEcuvgDajHrnZMrBeWoJ81NMyoLkyX+iOc7MoFA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry-internal/browser-utils": "10.49.0",
|
||||
"@sentry-internal/feedback": "10.49.0",
|
||||
"@sentry-internal/replay": "10.49.0",
|
||||
"@sentry-internal/replay-canvas": "10.49.0",
|
||||
"@sentry/core": "10.49.0"
|
||||
"@sentry-internal/browser-utils": "10.50.0",
|
||||
"@sentry-internal/feedback": "10.50.0",
|
||||
"@sentry-internal/replay": "10.50.0",
|
||||
"@sentry-internal/replay-canvas": "10.50.0",
|
||||
"@sentry/core": "10.50.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/core": {
|
||||
"version": "10.49.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.49.0.tgz",
|
||||
"integrity": "sha512-UaFeum3LUM1mB0d67jvKnqId1yWQjyqmaDV6kWngG03x+jqXb08tJdGpSoxjXZe13jFBbiBL/wKDDYIK7rCK4g==",
|
||||
"version": "10.50.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.50.0.tgz",
|
||||
"integrity": "sha512-J4A+vzUO3adl0TkFCjaN1+4miamrjHiEIYuLHiuu1lmAjq5WIVw32ObvAh4yMwNtxyaEMosTrrh5M6f12XSJFg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
@@ -3698,15 +3719,15 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@storybook/addon-docs": {
|
||||
"version": "10.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-10.3.5.tgz",
|
||||
"integrity": "sha512-WuHbxia/o5TX4Rg/IFD0641K5qId/Nk0dxhmAUNoFs5L0+yfZUwh65XOBbzXqrkYmYmcVID4v7cgDRmzstQNkA==",
|
||||
"version": "10.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-10.3.6.tgz",
|
||||
"integrity": "sha512-TvIdADVPtauxW0LzXIpIv7X6GxwetorhyNh+6+7MHC27XSBCWVxxRUwL63YeLlHTuXsIk0quG3b1xgwVRzWOJA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@mdx-js/react": "^3.0.0",
|
||||
"@storybook/csf-plugin": "10.3.5",
|
||||
"@storybook/csf-plugin": "10.3.6",
|
||||
"@storybook/icons": "^2.0.1",
|
||||
"@storybook/react-dom-shim": "10.3.5",
|
||||
"@storybook/react-dom-shim": "10.3.6",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"ts-dedent": "^2.0.0"
|
||||
@@ -3716,13 +3737,13 @@
|
||||
"url": "https://opencollective.com/storybook"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"storybook": "^10.3.5"
|
||||
"storybook": "^10.3.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/addon-links": {
|
||||
"version": "10.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-10.3.5.tgz",
|
||||
"integrity": "sha512-Xe2wCGZ+hpZ0cDqAIBHk+kPc8nODNbu585ghd5bLrlYJMDVXoNM/fIlkrLgjIDVbfpgeJLUEg7vldJrn+FyOLw==",
|
||||
"version": "10.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-10.3.6.tgz",
|
||||
"integrity": "sha512-tv9Xd68qRGBAvEubaxNo3FuFq4GwuMiBriD+gLGuFK0+/u3cnkuA264aoR1v6YCH3sT3er3+MBimuyKM3jLDxg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@storybook/global": "^5.0.0"
|
||||
@@ -3733,7 +3754,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"storybook": "^10.3.5"
|
||||
"storybook": "^10.3.6"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react": {
|
||||
@@ -3742,12 +3763,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/builder-vite": {
|
||||
"version": "10.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-10.3.5.tgz",
|
||||
"integrity": "sha512-i4KwCOKbhtlbQIbhm53+Kk7bMnxa0cwTn1pxmtA/x5wm1Qu7FrrBQV0V0DNjkUqzcSKo1CjspASJV/HlY0zYlw==",
|
||||
"version": "10.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-10.3.6.tgz",
|
||||
"integrity": "sha512-gpvR/sE4BcrFtmQZ+Ker7zD23oQzoVeqD9nF6cK6yzY+Q0svJXyX2EPmFG4y+EwygD5/vNzDpP84gGMut8VRwg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@storybook/csf-plugin": "10.3.5",
|
||||
"@storybook/csf-plugin": "10.3.6",
|
||||
"ts-dedent": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
@@ -3755,14 +3776,14 @@
|
||||
"url": "https://opencollective.com/storybook"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"storybook": "^10.3.5",
|
||||
"storybook": "^10.3.6",
|
||||
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/csf-plugin": {
|
||||
"version": "10.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-10.3.5.tgz",
|
||||
"integrity": "sha512-qlEzNKxOjq86pvrbuMwiGD/bylnsXk1dg7ve0j77YFjEEchqtl7qTlrXvFdNaLA89GhW6D/EV6eOCu/eobPDgw==",
|
||||
"version": "10.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-10.3.6.tgz",
|
||||
"integrity": "sha512-9kBf7VRdRqTSIYo+rPtVn5yjYYyK8kP2QhEYx3oiXvfwy4RexmbJnhk/tXa/lNiTqukA1TqaWQ2+5MqF4fu6YQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"unplugin": "^2.3.5"
|
||||
@@ -3774,7 +3795,7 @@
|
||||
"peerDependencies": {
|
||||
"esbuild": "*",
|
||||
"rollup": "*",
|
||||
"storybook": "^10.3.5",
|
||||
"storybook": "^10.3.6",
|
||||
"vite": "*",
|
||||
"webpack": "*"
|
||||
},
|
||||
@@ -3810,9 +3831,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/react-dom-shim": {
|
||||
"version": "10.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-10.3.5.tgz",
|
||||
"integrity": "sha512-Gw8R7XZm0zSUH0XAuxlQJhmizsLzyD6x00KOlP6l7oW9eQHXGfxg3seNDG3WrSAcW07iP1/P422kuiriQlOv7g==",
|
||||
"version": "10.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-10.3.6.tgz",
|
||||
"integrity": "sha512-/Tu1gPu+Fw+zOnAGmxRmOD30FX3a04LxcTAKflEtdpmtIMVR5bA3qpjy+f5YhoyDCecbXyKmL1OeIU2FIIZHqQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -3821,13 +3842,13 @@
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"storybook": "^10.3.5"
|
||||
"storybook": "^10.3.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/web-components": {
|
||||
"version": "10.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/web-components/-/web-components-10.3.5.tgz",
|
||||
"integrity": "sha512-tSppZagFCeZ+bWsaHUvdiw17ATWgfGDBz0mFicgEj0/eNuxQH2OvXyRIQUXY39b/55TBwSGeoIX3tOW91WIqpw==",
|
||||
"version": "10.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/web-components/-/web-components-10.3.6.tgz",
|
||||
"integrity": "sha512-femDZGYBGQDckL7F6ZCl2S+dNNBjvd9lp6rQrwBdbNprjctLd6d3EB4HyNM502QxtdEo7laq8y1goDu8KwIV3A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@storybook/global": "^5.0.0",
|
||||
@@ -3840,24 +3861,24 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"lit": "^2.0.0 || ^3.0.0",
|
||||
"storybook": "^10.3.5"
|
||||
"storybook": "^10.3.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/web-components-vite": {
|
||||
"version": "10.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/web-components-vite/-/web-components-vite-10.3.5.tgz",
|
||||
"integrity": "sha512-6uAw6KAUXFsAPzp8KchcMp3gatEnEAd8ylIvzoMzvsIMiHmzXwvDNmoFZnAJ2tmsQGvF4dZRDCBg7PvWdTx8Rg==",
|
||||
"version": "10.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/web-components-vite/-/web-components-vite-10.3.6.tgz",
|
||||
"integrity": "sha512-VeDEAJuOOQV6VAqEF0pilXucS6kp+1ILJVkI+ets6Ku2D+RKeu167YrQAzh1NwzRTv0e5H0anDDNke+sWvg2dg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@storybook/builder-vite": "10.3.5",
|
||||
"@storybook/web-components": "10.3.5"
|
||||
"@storybook/builder-vite": "10.3.6",
|
||||
"@storybook/web-components": "10.3.6"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/storybook"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"storybook": "^10.3.5"
|
||||
"storybook": "^10.3.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@swagger-api/apidom-ast": {
|
||||
@@ -4556,9 +4577,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core": {
|
||||
"version": "1.15.30",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.30.tgz",
|
||||
"integrity": "sha512-R8VQbQY1BZcbIF2p3gjlTCwAQzx1A194ugWfwld5y+WgVVWqVKm7eURGGOVbQVubgKWzidP2agomBbg96rZilQ==",
|
||||
"version": "1.15.32",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.32.tgz",
|
||||
"integrity": "sha512-/eWL0n43D64QWEUHLtTE+jDqjkJhyidjkDhv6f0uJohOUAhywxQ9wXYp845DNNds0JpCdI4Uo0a9bl+vbXf+ew==",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@@ -4573,18 +4594,18 @@
|
||||
"url": "https://opencollective.com/swc"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@swc/core-darwin-arm64": "1.15.30",
|
||||
"@swc/core-darwin-x64": "1.15.30",
|
||||
"@swc/core-linux-arm-gnueabihf": "1.15.30",
|
||||
"@swc/core-linux-arm64-gnu": "1.15.30",
|
||||
"@swc/core-linux-arm64-musl": "1.15.30",
|
||||
"@swc/core-linux-ppc64-gnu": "1.15.30",
|
||||
"@swc/core-linux-s390x-gnu": "1.15.30",
|
||||
"@swc/core-linux-x64-gnu": "1.15.30",
|
||||
"@swc/core-linux-x64-musl": "1.15.30",
|
||||
"@swc/core-win32-arm64-msvc": "1.15.30",
|
||||
"@swc/core-win32-ia32-msvc": "1.15.30",
|
||||
"@swc/core-win32-x64-msvc": "1.15.30"
|
||||
"@swc/core-darwin-arm64": "1.15.32",
|
||||
"@swc/core-darwin-x64": "1.15.32",
|
||||
"@swc/core-linux-arm-gnueabihf": "1.15.32",
|
||||
"@swc/core-linux-arm64-gnu": "1.15.32",
|
||||
"@swc/core-linux-arm64-musl": "1.15.32",
|
||||
"@swc/core-linux-ppc64-gnu": "1.15.32",
|
||||
"@swc/core-linux-s390x-gnu": "1.15.32",
|
||||
"@swc/core-linux-x64-gnu": "1.15.32",
|
||||
"@swc/core-linux-x64-musl": "1.15.32",
|
||||
"@swc/core-win32-arm64-msvc": "1.15.32",
|
||||
"@swc/core-win32-ia32-msvc": "1.15.32",
|
||||
"@swc/core-win32-x64-msvc": "1.15.32"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@swc/helpers": ">=0.5.17"
|
||||
@@ -4596,9 +4617,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-darwin-arm64": {
|
||||
"version": "1.15.30",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.30.tgz",
|
||||
"integrity": "sha512-VvpP+vq08HmGYewMWvrdsxh9s2lthz/808zXm8Yu5kaqeR8Yia2b0eYXleHQ3VAjoStUDk6LzTheBW9KXYQdMA==",
|
||||
"version": "1.15.32",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.32.tgz",
|
||||
"integrity": "sha512-/YWMvJDPu+AAwuUsM2G+DNQ/7zhodURGzdQyewEqcvgklAdDHs3LwQmLLnyn6SJl8DT8UOxkbzK+D1PmPeelRg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -4612,9 +4633,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-darwin-x64": {
|
||||
"version": "1.15.30",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.30.tgz",
|
||||
"integrity": "sha512-WiJA0hiZI3nwQAO6mu5RqigtWGDtth4Hiq6rbZxAaQyhIcqKIg5IoMRc1Y071lrNJn29eEDMC86Rq58xgUxlDg==",
|
||||
"version": "1.15.32",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.32.tgz",
|
||||
"integrity": "sha512-KOTXJXdAhWL+hZ77MYP3z+4pcMFaQhQ74yqyN1uz093q0YnbxpqMtYpPISbYvMHzVRNNx5kN+9RZAXEaadhWVA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -4628,9 +4649,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm-gnueabihf": {
|
||||
"version": "1.15.30",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.30.tgz",
|
||||
"integrity": "sha512-YANuFUo48kIT6plJgCD0keae9HFXfjxsbvsgevqc0hr/07X/p7sAWTFOGYEc2SXcASaK7UvuQqzlbW8pr7R79g==",
|
||||
"version": "1.15.32",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.32.tgz",
|
||||
"integrity": "sha512-oOoxLweljlc0A4X8ybsgxV7cVaYTwBOg2iMDJcFR3Sr48C+lsv9VzSmqdK/IVIXF4W4GjLc3VqTAdSMXlfVLuQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -4644,9 +4665,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm64-gnu": {
|
||||
"version": "1.15.30",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.30.tgz",
|
||||
"integrity": "sha512-VndG8jaR4ugY6u+iVOT0Q+d2fZd7sLgjPgN8W/Le+3EbZKl+cRfFxV7Eoz4gfLqhmneZPdcIzf9T3LkgkmqNLg==",
|
||||
"version": "1.15.32",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.32.tgz",
|
||||
"integrity": "sha512-oDzEkdl6D6BAWdMtU5KGO7y3HR5fJcvByNLyEk9+ugj8nP5Ovb7P4kBcStBXc4MPExFGQryehiINMlmY8HlclA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -4660,9 +4681,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm64-musl": {
|
||||
"version": "1.15.30",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.30.tgz",
|
||||
"integrity": "sha512-1SYGs2l0Yyyi0pR/P/NKz/x0kqxkoiw+BXeJjLUdecSk/KasncWlJrc6hOvFSgKHOBrzgM5jwuluKtlT8dnrcA==",
|
||||
"version": "1.15.32",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.32.tgz",
|
||||
"integrity": "sha512-omcqjoZP/b8D8PuczVoRwJieC6ibj7qIxTftNYokz4/aSmKFHvsd7nIFfPk5ZvtzncbH4AY7+Dkr/Lp2gWxYeA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -4676,9 +4697,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-ppc64-gnu": {
|
||||
"version": "1.15.30",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.30.tgz",
|
||||
"integrity": "sha512-TXREtiXeRhbfDFbmhnkIsXpKfzbfT73YkV2ZF6w0sfxgjC5zI2ZAbaCOq25qxvegofj2K93DtOpm9RLaBgqR2g==",
|
||||
"version": "1.15.32",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.32.tgz",
|
||||
"integrity": "sha512-KGkTMyz/Tbn3PBNu0AVZ4GTDFKnICrYcTiNPZq8DrvK42pnFsf3GNDrIG9E5AtQlTmC0YigkWKmu0eMcfTrmgA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -4692,9 +4713,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-s390x-gnu": {
|
||||
"version": "1.15.30",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.30.tgz",
|
||||
"integrity": "sha512-DCR2YYeyd6DQE4OuDhImouuNcjXEiEdnn1Y0DyGteugPEDvVuvYk8Xddi+4o2SgWH6jiW8/I+3emZvbep1NC+g==",
|
||||
"version": "1.15.32",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.32.tgz",
|
||||
"integrity": "sha512-G3Aa4tVS/3OGZBkoNIwUF9F6RAy+Osb4GOlo62SinLmDiErz/ykmM7KH0wkz6l9kM8jJq1HyAM6atJTUEbBk7g==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -4708,9 +4729,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-x64-gnu": {
|
||||
"version": "1.15.30",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.30.tgz",
|
||||
"integrity": "sha512-5Pizw3NgfOJ5BJOBK8TIRa59xFW2avESTOBDPTAYwZYa1JNDs+KMF9lUfjJiJLM5HiMs/wPheA9eiT0q9m2AoA==",
|
||||
"version": "1.15.32",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.32.tgz",
|
||||
"integrity": "sha512-ERsjfGcj6CBmj3vJnGDO8m8rTvw6RqMcWo1dogOtNx3/+/0+NNpJiXDobJrr1GwInI/BHAEkvSFIH6d2LqPcUQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -4724,9 +4745,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-x64-musl": {
|
||||
"version": "1.15.30",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.30.tgz",
|
||||
"integrity": "sha512-qyqydP/wyH8alcIP4a2hnGSjHLJjm9H7yDFup+CPy9oTahFgLLwnNcv5UHXqO2Qs3AIND+cls5f/Bb6hqpxdgA==",
|
||||
"version": "1.15.32",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.32.tgz",
|
||||
"integrity": "sha512-N4Ggahe/8SUbTX50P6EdhbW9YWcgbZVb52R4cq6MK+zsoMjRq7rGvV5ztA05QnbaCYqMYx8rTY7KAIA3Crdo4Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -4740,9 +4761,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-win32-arm64-msvc": {
|
||||
"version": "1.15.30",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.30.tgz",
|
||||
"integrity": "sha512-CaQENgDHVGOg1mSF5sQVgvfFHG9kjMor2rkLMLeLOkfZYNj13ppnJ9+lfaBZLZUMMbnlGQnavCJb8PVBUOso7Q==",
|
||||
"version": "1.15.32",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.32.tgz",
|
||||
"integrity": "sha512-01yN0o9jvo8xBTP12aPK2wW8b41jmOlGbDDlAnoynotc4pO6xA0zby9f1z6j++qXDpGBttLySq1omgVrlQKYcw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -4756,9 +4777,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-win32-ia32-msvc": {
|
||||
"version": "1.15.30",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.30.tgz",
|
||||
"integrity": "sha512-30VdLeGk6fugiUs/kUdJ/pAg7z/zpvVbR11RH60jZ0Z42WIeIniYx0rLEWN7h/pKJ3CopqsQ3RsogCAkRKiA2g==",
|
||||
"version": "1.15.32",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.32.tgz",
|
||||
"integrity": "sha512-fLagI9XZYNpTcmlqAcp3KBtmj7E19WCmYD80Jxj1Kn5tGNa7yxNLd3NNdWxuZGUPl5iC0/KqZru7g08gF6Fsrw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -4772,9 +4793,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-win32-x64-msvc": {
|
||||
"version": "1.15.30",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.30.tgz",
|
||||
"integrity": "sha512-4iObHPR+Q4oDY110EF5SF5eIaaVJNpMdG9C0q3Q92BsJ5y467uHz7sYQhP60WYlLFsLQ1el2YrIPUItUAQGOKg==",
|
||||
"version": "1.15.32",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.32.tgz",
|
||||
"integrity": "sha512-gbc2bQ/T2CiR+w0OvcVKwLOFAcPZBvmWmolbwpg1E8UrpeC03DGtyMUApOHNXNYWA3SHFrYXCQtosrcMza1YFg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -6527,12 +6548,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz",
|
||||
"integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==",
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.16.0.tgz",
|
||||
"integrity": "sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.11",
|
||||
"follow-redirects": "^1.16.0",
|
||||
"form-data": "^4.0.5",
|
||||
"proxy-from-env": "^2.1.0"
|
||||
}
|
||||
@@ -8380,9 +8401,9 @@
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.1.tgz",
|
||||
"integrity": "sha512-JahakDAIg1gyOm7dlgWSDjV4n7Ip2PKR55NIT6jrMfIgLFgWo81vdr1/QGqWtFNRqXP9UV71oVePtjqS2ebnPw==",
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.2.tgz",
|
||||
"integrity": "sha512-lHeS9SA/IKeIFFyYciHBr2n0v1VMPlSj843HdLOwjb2OxNwdq9Xykxqhk+FE42MzAdHvInbAolSE4mhahPpjXA==",
|
||||
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||
"optionalDependencies": {
|
||||
"@types/trusted-types": "^2.0.7"
|
||||
@@ -11569,9 +11590,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/knip": {
|
||||
"version": "6.6.3",
|
||||
"resolved": "https://registry.npmjs.org/knip/-/knip-6.6.3.tgz",
|
||||
"integrity": "sha512-7HSf5bLx6r66+sjXwSvSiDEE9RjRzHuAkrEFLE6XXHqaPDY97tdzNvyRVF9DeusbiV72kStAFiNnhj72rxJNGQ==",
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/knip/-/knip-6.7.0.tgz",
|
||||
"integrity": "sha512-ckL51NDH1YJxnv1kNB0iUdDngB4f/e9Igz8uIqYfmNDoyOFmmk1V0WFv3LQ7/hzC63b2Z9X41gGUE9eOWrZpaA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -15811,13 +15832,13 @@
|
||||
"license": "Unlicense"
|
||||
},
|
||||
"node_modules/rolldown": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@oxc-project/types": "=0.124.0",
|
||||
"@rolldown/pluginutils": "1.0.0-rc.15"
|
||||
"@oxc-project/types": "=0.127.0",
|
||||
"@rolldown/pluginutils": "1.0.0-rc.17"
|
||||
},
|
||||
"bin": {
|
||||
"rolldown": "bin/cli.mjs"
|
||||
@@ -15826,30 +15847,21 @@
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rolldown/binding-android-arm64": "1.0.0-rc.15",
|
||||
"@rolldown/binding-darwin-arm64": "1.0.0-rc.15",
|
||||
"@rolldown/binding-darwin-x64": "1.0.0-rc.15",
|
||||
"@rolldown/binding-freebsd-x64": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-x64-musl": "1.0.0-rc.15",
|
||||
"@rolldown/binding-openharmony-arm64": "1.0.0-rc.15",
|
||||
"@rolldown/binding-wasm32-wasi": "1.0.0-rc.15",
|
||||
"@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15",
|
||||
"@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15"
|
||||
}
|
||||
},
|
||||
"node_modules/rolldown/node_modules/@oxc-project/types": {
|
||||
"version": "0.124.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz",
|
||||
"integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/Boshen"
|
||||
"@rolldown/binding-android-arm64": "1.0.0-rc.17",
|
||||
"@rolldown/binding-darwin-arm64": "1.0.0-rc.17",
|
||||
"@rolldown/binding-darwin-x64": "1.0.0-rc.17",
|
||||
"@rolldown/binding-freebsd-x64": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-x64-musl": "1.0.0-rc.17",
|
||||
"@rolldown/binding-openharmony-arm64": "1.0.0-rc.17",
|
||||
"@rolldown/binding-wasm32-wasi": "1.0.0-rc.17",
|
||||
"@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17",
|
||||
"@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
@@ -16598,9 +16610,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/storybook": {
|
||||
"version": "10.3.5",
|
||||
"resolved": "https://registry.npmjs.org/storybook/-/storybook-10.3.5.tgz",
|
||||
"integrity": "sha512-uBSZu/GZa9aEIW3QMGvdQPMZWhGxSe4dyRWU8B3/Vd47Gy/XLC7tsBxRr13txmmPOEDHZR94uLuq0H50fvuqBw==",
|
||||
"version": "10.3.6",
|
||||
"resolved": "https://registry.npmjs.org/storybook/-/storybook-10.3.6.tgz",
|
||||
"integrity": "sha512-vbSz7g/1rGMC1uAULqMZjALkIuLu2QABqfhRYhyr/11kzyesi+vAmwyJLukZP1FfecxGOgMwOh6GS0YsGpHAvQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@storybook/global": "^5.0.0",
|
||||
@@ -16625,11 +16637,15 @@
|
||||
"url": "https://opencollective.com/storybook"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"prettier": "^2 || ^3"
|
||||
"prettier": "^2 || ^3",
|
||||
"vite-plus": "^0.1.15"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"prettier": {
|
||||
"optional": true
|
||||
},
|
||||
"vite-plus": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -18400,16 +18416,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "8.0.8",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.8.tgz",
|
||||
"integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==",
|
||||
"version": "8.0.10",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz",
|
||||
"integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lightningcss": "^1.32.0",
|
||||
"picomatch": "^4.0.4",
|
||||
"postcss": "^8.5.8",
|
||||
"rolldown": "1.0.0-rc.15",
|
||||
"tinyglobby": "^0.2.15"
|
||||
"postcss": "^8.5.10",
|
||||
"rolldown": "1.0.0-rc.17",
|
||||
"tinyglobby": "^0.2.16"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
@@ -18490,6 +18506,22 @@
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vite/node_modules/tinyglobby": {
|
||||
"version": "0.2.16",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
|
||||
"integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fdir": "^6.5.0",
|
||||
"picomatch": "^4.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||
}
|
||||
},
|
||||
"node_modules/vitest": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.5.tgz",
|
||||
@@ -19248,7 +19280,7 @@
|
||||
"@rollup/plugin-node-resolve": "^16.0.3",
|
||||
"@rollup/plugin-swc": "^0.4.0",
|
||||
"@swc/cli": "^0.8.1",
|
||||
"@swc/core": "^1.15.30",
|
||||
"@swc/core": "^1.15.32",
|
||||
"@webcomponents/template": "^1.5.1",
|
||||
"base64-js": "^1.5.1",
|
||||
"core-js": "^3.49.0",
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
"@codemirror/theme-one-dark": "^6.1.3",
|
||||
"@eslint/js": "^9.39.3",
|
||||
"@floating-ui/dom": "^1.7.6",
|
||||
"@formatjs/intl-listformat": "^8.3.2",
|
||||
"@formatjs/intl-listformat": "^8.3.4",
|
||||
"@fortawesome/fontawesome-free": "^7.2.0",
|
||||
"@goauthentik/api": "0.0.0",
|
||||
"@goauthentik/core": "^1.0.0",
|
||||
@@ -119,11 +119,11 @@
|
||||
"@patternfly/elements": "^4.4.0",
|
||||
"@patternfly/patternfly": "^4.224.2",
|
||||
"@playwright/test": "^1.59.1",
|
||||
"@sentry/browser": "^10.49.0",
|
||||
"@storybook/addon-docs": "^10.3.5",
|
||||
"@storybook/addon-links": "^10.3.5",
|
||||
"@storybook/web-components": "^10.3.5",
|
||||
"@storybook/web-components-vite": "^10.3.5",
|
||||
"@sentry/browser": "^10.50.0",
|
||||
"@storybook/addon-docs": "^10.3.6",
|
||||
"@storybook/addon-links": "^10.3.6",
|
||||
"@storybook/web-components": "^10.3.6",
|
||||
"@storybook/web-components-vite": "^10.3.6",
|
||||
"@types/codemirror": "^5.60.17",
|
||||
"@types/grecaptcha": "^3.0.9",
|
||||
"@types/guacamole-common-js": "^1.5.5",
|
||||
@@ -145,7 +145,7 @@
|
||||
"country-flag-icons": "^1.6.16",
|
||||
"date-fns": "^4.1.0",
|
||||
"deepmerge-ts": "^7.1.5",
|
||||
"dompurify": "^3.4.1",
|
||||
"dompurify": "^3.4.2",
|
||||
"esbuild": "^0.28.0",
|
||||
"eslint": "^9.39.3",
|
||||
"eslint-plugin-lit": "^2.2.1",
|
||||
@@ -154,7 +154,7 @@
|
||||
"globals": "^17.5.0",
|
||||
"guacamole-common-js": "^1.5.0",
|
||||
"hastscript": "^9.0.1",
|
||||
"knip": "^6.6.3",
|
||||
"knip": "^6.7.0",
|
||||
"lex": "^2025.11.0",
|
||||
"lit": "^3.3.2",
|
||||
"lit-analyzer": "^2.0.3",
|
||||
@@ -190,7 +190,7 @@
|
||||
"typescript": "^6.0.3",
|
||||
"typescript-eslint": "^8.57.2",
|
||||
"unist-util-visit": "^5.1.0",
|
||||
"vite": "^8.0.8",
|
||||
"vite": "^8.0.10",
|
||||
"vitest": "^4.1.1",
|
||||
"webcomponent-qr-code": "^1.3.0",
|
||||
"wireit": "^0.14.12",
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"@rollup/plugin-node-resolve": "^16.0.3",
|
||||
"@rollup/plugin-swc": "^0.4.0",
|
||||
"@swc/cli": "^0.8.1",
|
||||
"@swc/core": "^1.15.30",
|
||||
"@swc/core": "^1.15.32",
|
||||
"@webcomponents/template": "^1.5.1",
|
||||
"base64-js": "^1.5.1",
|
||||
"core-js": "^3.49.0",
|
||||
|
||||
@@ -8,6 +8,7 @@ import "#elements/forms/Radio";
|
||||
import "#elements/forms/SearchSelect/index";
|
||||
import "#elements/utils/TimeDeltaHelp";
|
||||
import "./AdminSettingsFooterLinks.js";
|
||||
import "#elements/Alert";
|
||||
|
||||
import { akFooterLinkInput, IFooterLinkInput } from "./AdminSettingsFooterLinks.js";
|
||||
|
||||
@@ -287,6 +288,9 @@ export class AdminSettingsForm extends Form<SettingsRequest> {
|
||||
help=${msg(
|
||||
"When enabled, other flow tabs in a session will refresh upon a successful authentication.",
|
||||
)}
|
||||
.bighelp=${html`<ak-alert class="pf-c-radio__description" inline plain>
|
||||
${msg("This flag is deprecated.")}
|
||||
</ak-alert>`}
|
||||
>
|
||||
</ak-switch-input>
|
||||
<ak-switch-input
|
||||
|
||||
@@ -52,10 +52,6 @@ export class AboutModal extends WithLicenseSummary(WithBrandConfig(AKModal)) {
|
||||
...AKModal.styles,
|
||||
PFAbout,
|
||||
css`
|
||||
:host {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.pf-c-about-modal-box {
|
||||
--pf-c-about-modal-box--BackgroundColor: var(--ak-c-dialog--BackgroundColor);
|
||||
width: unset;
|
||||
|
||||
@@ -135,7 +135,7 @@ export class AdminInterface extends WithCapabilitiesConfig(
|
||||
|
||||
WebsocketClient.connect();
|
||||
|
||||
this.#sidebarMatcher = window.matchMedia("(width >= 1200px)");
|
||||
this.#sidebarMatcher = window.matchMedia("(width > 1210px)");
|
||||
this.sidebarOpen = this.#sidebarMatcher.matches;
|
||||
}
|
||||
|
||||
|
||||
@@ -322,30 +322,6 @@ export class ApplicationViewPage extends WithLicenseSummary(AKElement) {
|
||||
id="page-app-entitlements"
|
||||
aria-label="${msg("Application entitlements")}"
|
||||
>
|
||||
<div
|
||||
slot="header"
|
||||
class="pf-c-banner pf-m-info"
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
>
|
||||
<div class="pf-l-flex pf-m-space-items-sm">
|
||||
<div class="pf-l-flex__item">
|
||||
<i class="fas fa-info-circle" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="pf-l-flex__item">
|
||||
${msg("Application entitlements are in preview.", {
|
||||
id: "application.entitlements.preview.info",
|
||||
})}
|
||||
</div>
|
||||
<div class="pf-l-flex__item">
|
||||
<a href="mailto:hello+feature/app-ent@goauthentik.io"
|
||||
>${msg("Send us feedback!", {
|
||||
id: "preview.send-us-feedback",
|
||||
})}</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__title">
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
RACProvider,
|
||||
RadiusProvider,
|
||||
RedirectURI,
|
||||
RedirectUriTypeEnum,
|
||||
RedirectURITypeEnum,
|
||||
SAMLProvider,
|
||||
SCIMProvider,
|
||||
WSFederationProvider,
|
||||
@@ -87,7 +87,7 @@ function formatRedirectUris(uris: RedirectURI[] = []) {
|
||||
(${uri.matchingMode === MatchingModeEnum.Strict
|
||||
? msg("strict")
|
||||
: msg("regexp")},
|
||||
${uri.redirectUriType === RedirectUriTypeEnum.Logout
|
||||
${uri.redirectUriType === RedirectURITypeEnum.Logout
|
||||
? msg("post logout")
|
||||
: msg("authorization")})
|
||||
</li>`,
|
||||
|
||||
@@ -124,19 +124,22 @@ export class ApplicationWizardBindingsStep extends ApplicationWizardStep {
|
||||
order="order"
|
||||
.columns=${COLUMNS}
|
||||
.content=${[]}
|
||||
></ak-select-table>
|
||||
<ak-empty-state icon="pf-icon-module"
|
||||
><span>${msg("No bound policies.")}</span>
|
||||
<div slot="body">${msg("No policies are currently bound to this object.")}</div>
|
||||
<div slot="primary">
|
||||
<button
|
||||
@click=${() => this.onBindingEvent()}
|
||||
class="pf-c-button pf-m-primary"
|
||||
>
|
||||
${msg("Bind policy/group/user")}
|
||||
</button>
|
||||
</div>
|
||||
</ak-empty-state>
|
||||
>
|
||||
<ak-empty-state slot="empty-table" icon="pf-icon-module"
|
||||
><span>${msg("No bound policies.")}</span>
|
||||
<div slot="body">
|
||||
${msg("No policies are currently bound to this object.")}
|
||||
</div>
|
||||
<div slot="primary">
|
||||
<button
|
||||
@click=${() => this.onBindingEvent()}
|
||||
class="pf-c-button pf-m-primary"
|
||||
>
|
||||
${msg("Bind policy/group/user")}
|
||||
</button>
|
||||
</div>
|
||||
</ak-empty-state>
|
||||
</ak-select-table>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ export class ApplicationWizardEditBindingStep extends ApplicationWizardStep<Poli
|
||||
<ak-switch-input
|
||||
name="negate"
|
||||
?checked=${instance?.negate ?? false}
|
||||
label=${msg("Negate result")}
|
||||
label=${msg("Negate Result")}
|
||||
help=${msg("Negates the outcome of the binding. Messages are unaffected.")}
|
||||
></ak-switch-input>
|
||||
<ak-number-input
|
||||
@@ -218,8 +218,9 @@ export class ApplicationWizardEditBindingStep extends ApplicationWizardStep<Poli
|
||||
></ak-number-input>
|
||||
<ak-radio-input
|
||||
name="failureResult"
|
||||
label=${msg("Failure result")}
|
||||
label=${msg("Failure Result")}
|
||||
.options=${createPassFailOptions}
|
||||
required
|
||||
></ak-radio-input>
|
||||
</form>`;
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ export class ApplicationWizardSubmitStep extends CustomEmitterElement(Applicatio
|
||||
return html`<h2 class="pf-c-wizard__main-title">
|
||||
${msg("Review the Application and Provider")}
|
||||
</h2>
|
||||
<fieldset>
|
||||
<fieldset class="ak-c-fieldset" name="application-details">
|
||||
<legend>${msg("Application Details")}</legend>
|
||||
<dl class="pf-c-description-list">
|
||||
<div class="pf-c-description-list__group">
|
||||
@@ -419,7 +419,7 @@ export class ApplicationWizardSubmitStep extends CustomEmitterElement(Applicatio
|
||||
|
||||
${
|
||||
renderer
|
||||
? html`<fieldset>
|
||||
? html`<fieldset class="ak-c-fieldset" name="provider-details">
|
||||
<legend>${msg("Provider Details")}</legend>
|
||||
${renderer(provider)}
|
||||
</fieldset>`
|
||||
|
||||
@@ -80,7 +80,7 @@ export class BrandListPage extends TablePage<Brand> {
|
||||
return [
|
||||
item.domain,
|
||||
item.brandingTitle || msg("-"),
|
||||
html`<ak-status-label ?good=${item._default}></ak-status-label>`,
|
||||
html`<ak-status-label ?good=${item._default} type="neutral"></ak-status-label>`,
|
||||
html`<div class="ak-c-table__actions">
|
||||
${IconEditButton(BrandForm, item.brandUuid, item.brandingTitle)}
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ export class ConfigModal extends ModalButton {
|
||||
></ak-codemirror>
|
||||
</ak-expand>
|
||||
</div>
|
||||
<fieldset class="pf-c-modal-box__footer">
|
||||
<fieldset class="ak-c-fieldset pf-c-modal-box__footer">
|
||||
<legend class="sr-only">${msg("Form actions")}</legend>
|
||||
<button
|
||||
class="pf-c-button pf-m-plain"
|
||||
|
||||
@@ -65,7 +65,7 @@ export class DeviceAddHowTo extends ModalButton {
|
||||
})}
|
||||
</ak-tabs>`}
|
||||
</div>
|
||||
<fieldset class="pf-c-modal-box__footer">
|
||||
<fieldset class="ak-c-fieldset pf-c-modal-box__footer">
|
||||
<legend class="sr-only">${msg("Form actions")}</legend>
|
||||
<button
|
||||
class="pf-c-button pf-m-primary"
|
||||
|
||||
@@ -175,6 +175,21 @@ export class BoundPoliciesList<T extends PolicyBinding = PolicyBinding> extends
|
||||
}
|
||||
|
||||
protected renderNewPolicyButton(): SlottedTemplateResult {
|
||||
if (!this.allowedTypes.includes(PolicyBindingCheckTarget.Policy)) {
|
||||
return html`<button
|
||||
type="button"
|
||||
class="pf-c-button pf-m-primary"
|
||||
${modalInvoker(() => {
|
||||
return StrictUnsafe<PolicyBindingForm>(this.bindingEditForm, {
|
||||
allowedTypes: this.allowedTypes,
|
||||
typeNotices: this.typeNotices,
|
||||
targetPk: this.target || "",
|
||||
});
|
||||
})}
|
||||
>
|
||||
${msg("Bind existing group/user")}
|
||||
</button>`;
|
||||
}
|
||||
return html`<button
|
||||
class="pf-c-button pf-m-primary"
|
||||
type="button"
|
||||
|
||||
@@ -272,7 +272,7 @@ export class PolicyBindingForm<T extends PolicyBinding = PolicyBinding> extends
|
||||
</ak-switch-input>
|
||||
<ak-switch-input
|
||||
name="negate"
|
||||
label=${msg("Negate result")}
|
||||
label=${msg("Negate Result")}
|
||||
?checked=${this.instance?.negate ?? false}
|
||||
help=${msg("Negates the outcome of the binding. Messages are unaffected.")}
|
||||
>
|
||||
@@ -293,7 +293,11 @@ export class PolicyBindingForm<T extends PolicyBinding = PolicyBinding> extends
|
||||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="failureResult" label=${msg("Failure result")}>
|
||||
<ak-form-element-horizontal
|
||||
name="failureResult"
|
||||
label=${msg("Failure Result")}
|
||||
required
|
||||
>
|
||||
<ak-radio .options=${createPassFailOptions} .value=${this.instance?.failureResult}>
|
||||
</ak-radio>
|
||||
<p class="pf-c-form__helper-text">
|
||||
|
||||
@@ -46,7 +46,7 @@ export class PolicyWizard extends CreateWizard {
|
||||
@property()
|
||||
public bindingTarget: string | null = null;
|
||||
|
||||
public override groupLabel = msg("Bind New Policy");
|
||||
public override groupLabel = msg("Choose Policy Type");
|
||||
public override groupDescription = msg("Select the type of policy you want to create.");
|
||||
|
||||
public override initialSteps = this.showBindingPage
|
||||
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
OAuth2Provider,
|
||||
OAuth2ProviderLogoutMethodEnum,
|
||||
RedirectURI,
|
||||
RedirectUriTypeEnum,
|
||||
RedirectURITypeEnum,
|
||||
SubModeEnum,
|
||||
ValidationError,
|
||||
} from "@goauthentik/api";
|
||||
@@ -270,7 +270,7 @@ export function renderForm({
|
||||
.newItem=${() => ({
|
||||
matchingMode: MatchingModeEnum.Strict,
|
||||
url: "",
|
||||
redirectUriType: RedirectUriTypeEnum.Authorization,
|
||||
redirectUriType: RedirectURITypeEnum.Authorization,
|
||||
})}
|
||||
.row=${(redirectURI: RedirectURI, idx: number) => {
|
||||
return html`<ak-provider-oauth2-redirect-uri
|
||||
|
||||
@@ -4,7 +4,7 @@ import { AKControlElement } from "#elements/ControlElement";
|
||||
import { LitPropertyRecord } from "#elements/types";
|
||||
import { ifPresent } from "#elements/utils/attributes";
|
||||
|
||||
import { MatchingModeEnum, RedirectURI, RedirectUriTypeEnum } from "@goauthentik/api";
|
||||
import { MatchingModeEnum, RedirectURI, RedirectURITypeEnum } from "@goauthentik/api";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { css, html } from "lit";
|
||||
@@ -37,7 +37,7 @@ export class OAuth2ProviderRedirectURI extends AKControlElement<RedirectURI> {
|
||||
public redirectURI: RedirectURI = {
|
||||
matchingMode: MatchingModeEnum.Strict,
|
||||
url: "",
|
||||
redirectUriType: RedirectUriTypeEnum.Authorization,
|
||||
redirectUriType: RedirectURITypeEnum.Authorization,
|
||||
};
|
||||
|
||||
@property({ type: String, useDefault: true })
|
||||
@@ -89,15 +89,15 @@ export class OAuth2ProviderRedirectURI extends AKControlElement<RedirectURI> {
|
||||
@change=${onChange}
|
||||
>
|
||||
<option
|
||||
value="${RedirectUriTypeEnum.Authorization}"
|
||||
value="${RedirectURITypeEnum.Authorization}"
|
||||
?selected=${(this.redirectURI.redirectUriType ??
|
||||
RedirectUriTypeEnum.Authorization) === RedirectUriTypeEnum.Authorization}
|
||||
RedirectURITypeEnum.Authorization) === RedirectURITypeEnum.Authorization}
|
||||
>
|
||||
${msg("Authorization")}
|
||||
</option>
|
||||
<option
|
||||
value="${RedirectUriTypeEnum.Logout}"
|
||||
?selected=${this.redirectURI.redirectUriType === RedirectUriTypeEnum.Logout}
|
||||
value="${RedirectURITypeEnum.Logout}"
|
||||
?selected=${this.redirectURI.redirectUriType === RedirectURITypeEnum.Logout}
|
||||
>
|
||||
${msg("Post Logout")}
|
||||
</option>
|
||||
|
||||
@@ -174,7 +174,7 @@ export class LDAPSourceForm extends BaseSourceForm<LDAPSource> {
|
||||
></ak-crypto-certificate-search>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"When connecting to an LDAP Server with TLS, certificates are not checked by default. Specify a keypair to validate the remote certificate.",
|
||||
"Leave empty to skip certificate validation, or select a certificate/keypair containing the LDAP server CA chain to validate the remote certificate.",
|
||||
)}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
|
||||
@@ -18,6 +18,8 @@ import { DEFAULT_CONFIG } from "#common/api/config";
|
||||
|
||||
import { DataProvision, DualSelectPair } from "#elements/ak-dual-select/types";
|
||||
|
||||
import { AKLabel } from "#components/ak-label";
|
||||
|
||||
import { deviceTypeRestrictionPair } from "#admin/stages/authenticator_webauthn/utils";
|
||||
import { BaseStageForm } from "#admin/stages/BaseStageForm";
|
||||
|
||||
@@ -114,11 +116,20 @@ export class AuthenticatorValidateStageForm extends BaseStageForm<AuthenticatorV
|
||||
></ak-text-input>
|
||||
<ak-form-group open label="${msg("Stage-specific settings")}">
|
||||
<div class="pf-c-form">
|
||||
<ak-form-element-horizontal
|
||||
label=${msg("Device classes")}
|
||||
required
|
||||
name="deviceClasses"
|
||||
>
|
||||
<ak-form-element-horizontal required name="deviceClasses">
|
||||
${AKLabel(
|
||||
{
|
||||
slot: "label",
|
||||
className: "pf-c-form__group-label",
|
||||
htmlFor: "deviceClasses",
|
||||
required: true,
|
||||
},
|
||||
msg("Device Classes"),
|
||||
)}
|
||||
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg("Device classes which can be used to authenticate.")}
|
||||
</p>
|
||||
<ak-checkbox-group
|
||||
name="users"
|
||||
class="user-field-select"
|
||||
@@ -129,9 +140,6 @@ export class AuthenticatorValidateStageForm extends BaseStageForm<AuthenticatorV
|
||||
this.isDeviceClassSelected(name as DeviceClassesEnum),
|
||||
)}
|
||||
></ak-checkbox-group>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg("Device classes which can be used to authenticate.")}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${msg("Last validation threshold")}
|
||||
|
||||
@@ -158,24 +158,33 @@ export class AuthenticatorWebAuthnStageForm extends BaseStageForm<AuthenticatorW
|
||||
<ak-radio
|
||||
.options=${[
|
||||
{
|
||||
label: msg("No preference is sent"),
|
||||
label: msg(
|
||||
"No preference: the browser may offer any available authenticator",
|
||||
),
|
||||
value: null,
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
label: msg(
|
||||
"A non-removable authenticator, like TouchID or Windows Hello",
|
||||
"Platform: a non-removable authenticator built into the device, such as Touch ID, Face ID, or Windows Hello",
|
||||
),
|
||||
value: AuthenticatorAttachmentEnum.Platform,
|
||||
},
|
||||
{
|
||||
label: msg('A "roaming" authenticator, like a YubiKey'),
|
||||
label: msg(
|
||||
"Cross-platform: a roaming authenticator, such as a YubiKey or Google Titan",
|
||||
),
|
||||
value: AuthenticatorAttachmentEnum.CrossPlatform,
|
||||
},
|
||||
]}
|
||||
.value=${this.instance?.authenticatorAttachment}
|
||||
>
|
||||
</ak-radio>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"Controls the authenticatorAttachment parameter sent to the browser during WebAuthn registration. If Hints are configured and this is left as 'No preference', a value is inferred from the selected hints for backward compatibility with older browsers.",
|
||||
)}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${msg("Hints")} name="hints">
|
||||
<ak-dual-select-provider
|
||||
|
||||
@@ -11,6 +11,8 @@ import { sourcesProvider, sourcesSelector } from "./IdentificationStageFormHelpe
|
||||
import { DEFAULT_CONFIG } from "#common/api/config";
|
||||
import { groupBy } from "#common/utils";
|
||||
|
||||
import { AKLabel } from "#components/ak-label";
|
||||
|
||||
import { BaseStageForm } from "#admin/stages/BaseStageForm";
|
||||
|
||||
import {
|
||||
@@ -87,7 +89,22 @@ export class IdentificationStageForm extends BaseStageForm<IdentificationStage>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-group open label="${msg("Stage-specific settings")}">
|
||||
<div class="pf-c-form">
|
||||
<ak-form-element-horizontal label=${msg("User fields")} name="userFields">
|
||||
<ak-form-element-horizontal name="userFields">
|
||||
${AKLabel(
|
||||
{
|
||||
slot: "label",
|
||||
className: "pf-c-form__group-label",
|
||||
htmlFor: "userFields",
|
||||
},
|
||||
msg("User Fields"),
|
||||
)}
|
||||
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources.",
|
||||
)}
|
||||
</p>
|
||||
|
||||
<ak-checkbox-group
|
||||
class="user-field-select"
|
||||
.options=${userSelectFields}
|
||||
@@ -95,11 +112,6 @@ export class IdentificationStageForm extends BaseStageForm<IdentificationStage>
|
||||
.map(({ name }) => name)
|
||||
.filter((name) => this.isUserFieldSelected(name))}
|
||||
></ak-checkbox-group>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources.",
|
||||
)}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${msg("Password stage")} name="passwordStage">
|
||||
<ak-search-select
|
||||
|
||||
@@ -10,7 +10,7 @@ import { AKElement } from "#elements/Base";
|
||||
import { Invitation, StagesApi } from "@goauthentik/api";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { CSSResult, html, nothing, TemplateResult } from "lit";
|
||||
import { css, CSSResult, html, nothing, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { until } from "lit/directives/until.js";
|
||||
|
||||
@@ -27,7 +27,30 @@ export class InvitationListLink extends AKElement {
|
||||
@property()
|
||||
selectedFlow?: string;
|
||||
|
||||
static styles: CSSResult[] = [PFForm, PFFormControl, PFDescriptionList, PFButton];
|
||||
/**
|
||||
* When true, the "Send via Email" button dispatches the
|
||||
* `ak-invitation-send-email-inline` event instead of opening the nested
|
||||
* email modal. Used by the invitation wizard's success step so the email
|
||||
* form can be rendered as its own wizard step.
|
||||
*/
|
||||
@property({ type: Boolean, attribute: "inline-send-email" })
|
||||
inlineSendEmail = false;
|
||||
|
||||
static styles: CSSResult[] = [
|
||||
PFForm,
|
||||
PFFormControl,
|
||||
PFDescriptionList,
|
||||
PFButton,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
input.pf-c-form-control {
|
||||
width: 100%;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
renderLink(): string {
|
||||
if (this.invitation?.flowObj) {
|
||||
@@ -103,6 +126,7 @@ export class InvitationListLink extends AKElement {
|
||||
class="pf-c-form-control"
|
||||
readonly
|
||||
type="text"
|
||||
style="width: 100%;"
|
||||
value=${this.renderLink()}
|
||||
/>
|
||||
</div>
|
||||
@@ -122,18 +146,32 @@ export class InvitationListLink extends AKElement {
|
||||
>
|
||||
${msg("Copy Link")}
|
||||
</button>
|
||||
<ak-forms-modal>
|
||||
<span slot="submit">${msg("Send")}</span>
|
||||
<span slot="header">${msg("Send Invitation via Email")}</span>
|
||||
<ak-invitation-send-email-form
|
||||
slot="form"
|
||||
.invitation=${this.invitation}
|
||||
>
|
||||
</ak-invitation-send-email-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
${msg("Send via Email")}
|
||||
</button>
|
||||
</ak-forms-modal>
|
||||
${this.inlineSendEmail
|
||||
? html`<button
|
||||
class="pf-c-button pf-m-secondary"
|
||||
@click=${() => {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("ak-invitation-send-email-inline", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}),
|
||||
);
|
||||
}}
|
||||
>
|
||||
${msg("Send via Email")}
|
||||
</button>`
|
||||
: html`<ak-forms-modal>
|
||||
<span slot="submit">${msg("Send")}</span>
|
||||
<span slot="header">${msg("Send Invitation via Email")}</span>
|
||||
<ak-invitation-send-email-form
|
||||
slot="form"
|
||||
.invitation=${this.invitation}
|
||||
>
|
||||
</ak-invitation-send-email-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
${msg("Send via Email")}
|
||||
</button>
|
||||
</ak-forms-modal>`}
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import "#admin/rbac/ObjectPermissionModal";
|
||||
import "#admin/stages/invitation/InvitationForm";
|
||||
import "#admin/stages/invitation/InvitationListLink";
|
||||
import "#admin/stages/invitation/wizard/InvitationWizard";
|
||||
import "#elements/buttons/Dropdown";
|
||||
import "#elements/buttons/ModalButton";
|
||||
import "#elements/buttons/SpinnerButton/ak-spinner-button";
|
||||
import "#elements/forms/DeleteBulkForm";
|
||||
@@ -9,7 +11,7 @@ import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
|
||||
|
||||
import { DEFAULT_CONFIG } from "#common/api/config";
|
||||
|
||||
import { IconEditButton, ModalInvokerButton } from "#elements/dialogs";
|
||||
import { IconEditButton, modalInvoker } from "#elements/dialogs";
|
||||
import { PFColor } from "#elements/Label";
|
||||
import { PaginatedResponse, TableColumn } from "#elements/table/Table";
|
||||
import { TablePage } from "#elements/table/TablePage";
|
||||
@@ -18,11 +20,12 @@ import { SlottedTemplateResult } from "#elements/types";
|
||||
import { setPageDetails } from "#components/ak-page-navbar";
|
||||
|
||||
import { InvitationForm } from "#admin/stages/invitation/InvitationForm";
|
||||
import { InvitationWizard } from "#admin/stages/invitation/wizard/InvitationWizard";
|
||||
|
||||
import { FlowDesignationEnum, Invitation, ModelEnum, StagesApi } from "@goauthentik/api";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { CSSResult, html, PropertyValues } from "lit";
|
||||
import { CSSResult, html, PropertyValues, TemplateResult } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
|
||||
import PFBanner from "@patternfly/patternfly/components/Banner/banner.css";
|
||||
@@ -139,7 +142,66 @@ export class InvitationListPage extends TablePage<Invitation> {
|
||||
}
|
||||
|
||||
protected override renderObjectCreate(): SlottedTemplateResult {
|
||||
return ModalInvokerButton(InvitationForm);
|
||||
return html`${this.renderNewInvitationDropdown()}`;
|
||||
}
|
||||
|
||||
protected renderNewInvitationDropdown(): TemplateResult {
|
||||
return html`<ak-dropdown class="pf-c-dropdown">
|
||||
<div class="pf-c-dropdown__toggle pf-m-primary pf-m-split-button pf-m-action">
|
||||
<button
|
||||
class="pf-c-dropdown__toggle-button"
|
||||
type="button"
|
||||
${modalInvoker(InvitationWizard, { mode: "existing" })}
|
||||
>
|
||||
${msg("New Invitation")}
|
||||
</button>
|
||||
<button
|
||||
class="pf-c-dropdown__toggle-button"
|
||||
type="button"
|
||||
id="new-invitation-toggle"
|
||||
aria-haspopup="menu"
|
||||
aria-controls="new-invitation-menu"
|
||||
tabindex="0"
|
||||
aria-label=${msg("New Invitation options")}
|
||||
>
|
||||
<i class="fas fa-caret-down" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
<menu
|
||||
class="pf-c-dropdown__menu"
|
||||
hidden
|
||||
id="new-invitation-menu"
|
||||
aria-labelledby="new-invitation-toggle"
|
||||
tabindex="-1"
|
||||
>
|
||||
<li role="presentation">
|
||||
<button
|
||||
type="button"
|
||||
role="menuitem"
|
||||
class="pf-c-dropdown__menu-item"
|
||||
${modalInvoker(InvitationWizard, { mode: "existing" })}
|
||||
aria-description=${msg(
|
||||
"Opens the new invitation wizard and binds the invitation to an existing enrollment flow.",
|
||||
)}
|
||||
>
|
||||
${msg("with Existing Enrollment Flow...")}
|
||||
</button>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<button
|
||||
type="button"
|
||||
role="menuitem"
|
||||
class="pf-c-dropdown__menu-item"
|
||||
${modalInvoker(InvitationWizard, { mode: "create" })}
|
||||
aria-description=${msg(
|
||||
"Opens the new invitation wizard, which will create a new enrollment flow and invitation stage.",
|
||||
)}
|
||||
>
|
||||
${msg("with New Enrollment Flow and Invitation Stage...")}
|
||||
</button>
|
||||
</li>
|
||||
</menu>
|
||||
</ak-dropdown>`;
|
||||
}
|
||||
|
||||
protected override render(): SlottedTemplateResult {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user