Compare commits
	
		
			72 Commits
		
	
	
		
			version/20
			...
			web/sdk/em
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| a407d903ab | |||
| 7e6f36b0b4 | |||
| 8dd7b0569c | |||
| 616be78e10 | |||
| 7125db1fbd | |||
| 8c7c7c3fee | |||
| bbbd00db22 | |||
| 6d60c5f7c7 | |||
| accf25a626 | |||
| 5f261bed96 | |||
| 4d51671f88 | |||
| 1c570b2502 | |||
| 78e4370b98 | |||
| 9a26111f1c | |||
| 02ae099bdf | |||
| 05fe4e5e7b | |||
| 24c289fdd1 | |||
| cd8de3e526 | |||
| 243bd03785 | |||
| e02cf0b3bd | |||
| 3018735579 | |||
| 6a956d149a | |||
| 3fd1bc6673 | |||
| 6bc4877702 | |||
| 9592b42501 | |||
| 517a5bc689 | |||
| a19e350ca6 | |||
| 88577145fb | |||
| bc93df1e29 | |||
| 9d5eb54504 | |||
| d95c433027 | |||
| 7416c90efb | |||
| 34a073b0f7 | |||
| 86eb112a03 | |||
| e48d001ea6 | |||
| 2070372f03 | |||
| bea4679192 | |||
| 32d1488a56 | |||
| 1003c79d8c | |||
| a05ed7e237 | |||
| 087d4f6a48 | |||
| 141cfe75d8 | |||
| a3a13d265b | |||
| 9c45ec1918 | |||
| 59fa449abe | |||
| f83c84b04d | |||
| 835a4097eb | |||
| da43df44b2 | |||
| d03b14aac4 | |||
| 62d990e91b | |||
| 6c8cfc9ef7 | |||
| e93d8b1646 | |||
| 6faa250574 | |||
| c8e4b187b8 | |||
| 98acca896a | |||
| 7dc4b70ee1 | |||
| 8f55d3fc07 | |||
| 17fb90e0af | |||
| 870ed99097 | |||
| 1c5af88ea9 | |||
| 461856d067 | |||
| cdbf448769 | |||
| 0fcac0e165 | |||
| 40e857fdb3 | |||
| 7d86593d05 | |||
| c95ce0a5d4 | |||
| a7b31ce6de | |||
| b5f4303fbd | |||
| 29f04ea801 | |||
| 7141702c9e | |||
| 0f30d135b6 | |||
| 73f326b21b | 
| @ -1,5 +1,5 @@ | |||||||
| [bumpversion] | [bumpversion] | ||||||
| current_version = 2024.6.4 | current_version = 2024.8.0 | ||||||
| tag = True | tag = True | ||||||
| commit = True | commit = True | ||||||
| parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))? | parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))? | ||||||
|  | |||||||
| @ -29,9 +29,9 @@ outputs: | |||||||
|   imageTags: |   imageTags: | ||||||
|     description: "Docker image tags" |     description: "Docker image tags" | ||||||
|     value: ${{ steps.ev.outputs.imageTags }} |     value: ${{ steps.ev.outputs.imageTags }} | ||||||
|   imageNames: |   attestImageNames: | ||||||
|     description: "Docker image names" |     description: "Docker image names used for attestation" | ||||||
|     value: ${{ steps.ev.outputs.imageNames }} |     value: ${{ steps.ev.outputs.attestImageNames }} | ||||||
|   imageMainTag: |   imageMainTag: | ||||||
|     description: "Docker image main tag" |     description: "Docker image main tag" | ||||||
|     value: ${{ steps.ev.outputs.imageMainTag }} |     value: ${{ steps.ev.outputs.imageMainTag }} | ||||||
|  | |||||||
| @ -51,15 +51,24 @@ else: | |||||||
|         ] |         ] | ||||||
|  |  | ||||||
| image_main_tag = image_tags[0].split(":")[-1] | image_main_tag = image_tags[0].split(":")[-1] | ||||||
| image_tags_rendered = ",".join(image_tags) |  | ||||||
| image_names_rendered = ",".join(set(name.split(":")[0] for name in image_tags)) |  | ||||||
|  | def get_attest_image_names(image_with_tags: list[str]): | ||||||
|  |     """Attestation only for GHCR""" | ||||||
|  |     image_tags = [] | ||||||
|  |     for image_name in set(name.split(":")[0] for name in image_with_tags): | ||||||
|  |         if not image_name.startswith("ghcr.io"): | ||||||
|  |             continue | ||||||
|  |         image_tags.append(image_name) | ||||||
|  |     return ",".join(set(image_tags)) | ||||||
|  |  | ||||||
|  |  | ||||||
| with open(os.environ["GITHUB_OUTPUT"], "a+", encoding="utf-8") as _output: | with open(os.environ["GITHUB_OUTPUT"], "a+", encoding="utf-8") as _output: | ||||||
|     print(f"shouldBuild={should_build}", file=_output) |     print(f"shouldBuild={should_build}", file=_output) | ||||||
|     print(f"sha={sha}", file=_output) |     print(f"sha={sha}", file=_output) | ||||||
|     print(f"version={version}", file=_output) |     print(f"version={version}", file=_output) | ||||||
|     print(f"prerelease={prerelease}", file=_output) |     print(f"prerelease={prerelease}", file=_output) | ||||||
|     print(f"imageTags={image_tags_rendered}", file=_output) |     print(f"imageTags={','.join(image_tags)}", file=_output) | ||||||
|     print(f"imageNames={image_names_rendered}", file=_output) |     print(f"attestImageNames={get_attest_image_names(image_tags)}", file=_output) | ||||||
|     print(f"imageMainTag={image_main_tag}", file=_output) |     print(f"imageMainTag={image_main_tag}", file=_output) | ||||||
|     print(f"imageMainName={image_tags[0]}", file=_output) |     print(f"imageMainName={image_tags[0]}", file=_output) | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								.github/workflows/ci-main.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/ci-main.yml
									
									
									
									
										vendored
									
									
								
							| @ -261,7 +261,7 @@ jobs: | |||||||
|         id: attest |         id: attest | ||||||
|         if: ${{ steps.ev.outputs.shouldBuild == 'true' }} |         if: ${{ steps.ev.outputs.shouldBuild == 'true' }} | ||||||
|         with: |         with: | ||||||
|           subject-name: ${{ steps.ev.outputs.imageNames }} |           subject-name: ${{ steps.ev.outputs.attestImageNames }} | ||||||
|           subject-digest: ${{ steps.push.outputs.digest }} |           subject-digest: ${{ steps.push.outputs.digest }} | ||||||
|           push-to-registry: true |           push-to-registry: true | ||||||
|   pr-comment: |   pr-comment: | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								.github/workflows/ci-outpost.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/ci-outpost.yml
									
									
									
									
										vendored
									
									
								
							| @ -115,7 +115,7 @@ jobs: | |||||||
|         id: attest |         id: attest | ||||||
|         if: ${{ steps.ev.outputs.shouldBuild == 'true' }} |         if: ${{ steps.ev.outputs.shouldBuild == 'true' }} | ||||||
|         with: |         with: | ||||||
|           subject-name: ${{ steps.ev.outputs.imageNames }} |           subject-name: ${{ steps.ev.outputs.attestImageNames }} | ||||||
|           subject-digest: ${{ steps.push.outputs.digest }} |           subject-digest: ${{ steps.push.outputs.digest }} | ||||||
|           push-to-registry: true |           push-to-registry: true | ||||||
|   build-binary: |   build-binary: | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								.github/workflows/release-publish.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/release-publish.yml
									
									
									
									
										vendored
									
									
								
							| @ -58,7 +58,7 @@ jobs: | |||||||
|       - uses: actions/attest-build-provenance@v1 |       - uses: actions/attest-build-provenance@v1 | ||||||
|         id: attest |         id: attest | ||||||
|         with: |         with: | ||||||
|           subject-name: ${{ steps.ev.outputs.imageNames }} |           subject-name: ${{ steps.ev.outputs.attestImageNames }} | ||||||
|           subject-digest: ${{ steps.push.outputs.digest }} |           subject-digest: ${{ steps.push.outputs.digest }} | ||||||
|           push-to-registry: true |           push-to-registry: true | ||||||
|   build-outpost: |   build-outpost: | ||||||
| @ -122,7 +122,7 @@ jobs: | |||||||
|       - uses: actions/attest-build-provenance@v1 |       - uses: actions/attest-build-provenance@v1 | ||||||
|         id: attest |         id: attest | ||||||
|         with: |         with: | ||||||
|           subject-name: ${{ steps.ev.outputs.imageNames }} |           subject-name: ${{ steps.ev.outputs.attestImageNames }} | ||||||
|           subject-digest: ${{ steps.push.outputs.digest }} |           subject-digest: ${{ steps.push.outputs.digest }} | ||||||
|           push-to-registry: true |           push-to-registry: true | ||||||
|   build-outpost-binary: |   build-outpost-binary: | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ | |||||||
|  |  | ||||||
| from os import environ | from os import environ | ||||||
|  |  | ||||||
| __version__ = "2024.6.4" | __version__ = "2024.8.0" | ||||||
| ENV_GIT_HASH_KEY = "GIT_BUILD_HASH" | ENV_GIT_HASH_KEY = "GIT_BUILD_HASH" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | |||||||
| @ -25,3 +25,31 @@ class BrandMiddleware: | |||||||
|             if locale != "": |             if locale != "": | ||||||
|                 activate(locale) |                 activate(locale) | ||||||
|         return self.get_response(request) |         return self.get_response(request) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class BrandCORSAPIMiddleware: | ||||||
|  |     """CORS for API requests depending on Brand""" | ||||||
|  |  | ||||||
|  |     get_response: Callable[[HttpRequest], HttpResponse] | ||||||
|  |  | ||||||
|  |     def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]): | ||||||
|  |         self.get_response = get_response | ||||||
|  |  | ||||||
|  |     def set_headers(self, request: HttpRequest, response: HttpResponse): | ||||||
|  |         response["Access-Control-Allow-Origin"] = "http://localhost:8080" | ||||||
|  |         response["Access-Control-Allow-Credentials"] = "true" | ||||||
|  |  | ||||||
|  |     def __call__(self, request: HttpRequest) -> HttpResponse: | ||||||
|  |         if request.method == "OPTIONS": | ||||||
|  |             response = HttpResponse( | ||||||
|  |                 status=200, | ||||||
|  |             ) | ||||||
|  |             self.set_headers(request, response) | ||||||
|  |             response["Access-Control-Allow-Headers"] = ( | ||||||
|  |                 "authorization,sentry-trace,x-authentik-csrf,content-type" | ||||||
|  |             ) | ||||||
|  |             response["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS" | ||||||
|  |             return response | ||||||
|  |         response = self.get_response(request) | ||||||
|  |         self.set_headers(request, response) | ||||||
|  |         return response | ||||||
|  | |||||||
| @ -9,10 +9,11 @@ class Command(TenantCommand): | |||||||
|  |  | ||||||
|     def add_arguments(self, parser): |     def add_arguments(self, parser): | ||||||
|         parser.add_argument("--type", type=str, required=True) |         parser.add_argument("--type", type=str, required=True) | ||||||
|         parser.add_argument("--all", action="store_true") |         parser.add_argument("--all", action="store_true", default=False) | ||||||
|         parser.add_argument("usernames", nargs="+", type=str) |         parser.add_argument("usernames", nargs="*", type=str) | ||||||
|  |  | ||||||
|     def handle_per_tenant(self, **options): |     def handle_per_tenant(self, **options): | ||||||
|  |         print(options) | ||||||
|         new_type = UserTypes(options["type"]) |         new_type = UserTypes(options["type"]) | ||||||
|         qs = ( |         qs = ( | ||||||
|             User.objects.exclude_anonymous() |             User.objects.exclude_anonymous() | ||||||
| @ -22,6 +23,9 @@ class Command(TenantCommand): | |||||||
|         if options["usernames"] and options["all"]: |         if options["usernames"] and options["all"]: | ||||||
|             self.stderr.write("--all and usernames specified, only one can be specified") |             self.stderr.write("--all and usernames specified, only one can be specified") | ||||||
|             return |             return | ||||||
|  |         if not options["usernames"] and not options["all"]: | ||||||
|  |             self.stderr.write("--all or usernames must be specified") | ||||||
|  |             return | ||||||
|         if options["usernames"] and not options["all"]: |         if options["usernames"] and not options["all"]: | ||||||
|             qs = qs.filter(username__in=options["usernames"]) |             qs = qs.filter(username__in=options["usernames"]) | ||||||
|         updated = qs.update(type=new_type) |         updated = qs.update(type=new_type) | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ | |||||||
|         <link rel="shortcut icon" href="{{ brand.branding_favicon }}"> |         <link rel="shortcut icon" href="{{ brand.branding_favicon }}"> | ||||||
|         {% block head_before %} |         {% block head_before %} | ||||||
|         {% endblock %} |         {% endblock %} | ||||||
|  |         <link rel="stylesheet" type="text/css" href="{% static 'dist/patternfly-base.css' %}"> | ||||||
|         <link rel="stylesheet" type="text/css" href="{% static 'dist/authentik.css' %}"> |         <link rel="stylesheet" type="text/css" href="{% static 'dist/authentik.css' %}"> | ||||||
|         <link rel="stylesheet" type="text/css" href="{% static 'dist/custom.css' %}" data-inject> |         <link rel="stylesheet" type="text/css" href="{% static 'dist/custom.css' %}" data-inject> | ||||||
|         {% versioned_script "dist/poly-%v.js" %} |         {% versioned_script "dist/poly-%v.js" %} | ||||||
|  | |||||||
| @ -25,4 +25,4 @@ class AuthentikEnterpriseConfig(EnterpriseConfig): | |||||||
|         """Actual enterprise check, cached""" |         """Actual enterprise check, cached""" | ||||||
|         from authentik.enterprise.license import LicenseKey |         from authentik.enterprise.license import LicenseKey | ||||||
|  |  | ||||||
|         return LicenseKey.cached_summary().status |         return LicenseKey.cached_summary().status.is_valid | ||||||
|  | |||||||
| @ -117,7 +117,7 @@ class LicenseKey: | |||||||
|                     our_cert.public_key(), |                     our_cert.public_key(), | ||||||
|                     algorithms=["ES512"], |                     algorithms=["ES512"], | ||||||
|                     audience=get_license_aud(), |                     audience=get_license_aud(), | ||||||
|                     options={"verify_exp": check_expiry}, |                     options={"verify_exp": check_expiry, "verify_signature": check_expiry}, | ||||||
|                 ), |                 ), | ||||||
|             ) |             ) | ||||||
|         except PyJWTError: |         except PyJWTError: | ||||||
| @ -134,7 +134,7 @@ class LicenseKey: | |||||||
|             exp_ts = int(mktime(lic.expiry.timetuple())) |             exp_ts = int(mktime(lic.expiry.timetuple())) | ||||||
|             if total.exp == 0: |             if total.exp == 0: | ||||||
|                 total.exp = exp_ts |                 total.exp = exp_ts | ||||||
|             total.exp = min(total.exp, exp_ts) |             total.exp = max(total.exp, exp_ts) | ||||||
|             total.license_flags.extend(lic.status.license_flags) |             total.license_flags.extend(lic.status.license_flags) | ||||||
|         return total |         return total | ||||||
|  |  | ||||||
|  | |||||||
| @ -16,12 +16,14 @@ from django.views.decorators.clickjacking import xframe_options_sameorigin | |||||||
| from django.views.generic import View | from django.views.generic import View | ||||||
| from drf_spectacular.types import OpenApiTypes | from drf_spectacular.types import OpenApiTypes | ||||||
| from drf_spectacular.utils import OpenApiParameter, PolymorphicProxySerializer, extend_schema | from drf_spectacular.utils import OpenApiParameter, PolymorphicProxySerializer, extend_schema | ||||||
|  | from rest_framework.exceptions import AuthenticationFailed | ||||||
| from rest_framework.permissions import AllowAny | from rest_framework.permissions import AllowAny | ||||||
| from rest_framework.views import APIView | from rest_framework.views import APIView | ||||||
| from sentry_sdk import capture_exception, start_span | from sentry_sdk import capture_exception, start_span | ||||||
| from sentry_sdk.api import set_tag | from sentry_sdk.api import set_tag | ||||||
| from structlog.stdlib import BoundLogger, get_logger | from structlog.stdlib import BoundLogger, get_logger | ||||||
|  |  | ||||||
|  | from authentik.api.authentication import bearer_auth, get_authorization_header | ||||||
| from authentik.brands.models import Brand | from authentik.brands.models import Brand | ||||||
| from authentik.core.models import Application | from authentik.core.models import Application | ||||||
| from authentik.events.models import Event, EventAction, cleanse_dict | from authentik.events.models import Event, EventAction, cleanse_dict | ||||||
| @ -116,6 +118,14 @@ class FlowExecutorView(APIView): | |||||||
|         super().setup(request, flow_slug=flow_slug) |         super().setup(request, flow_slug=flow_slug) | ||||||
|         self.flow = get_object_or_404(Flow.objects.select_related(), slug=flow_slug) |         self.flow = get_object_or_404(Flow.objects.select_related(), slug=flow_slug) | ||||||
|         self._logger = get_logger().bind(flow_slug=flow_slug) |         self._logger = get_logger().bind(flow_slug=flow_slug) | ||||||
|  |         # Usually flows are authenticated by session, we don't really use rest_framework's | ||||||
|  |         # authentication method. | ||||||
|  |         try: | ||||||
|  |             user = bearer_auth(get_authorization_header(request)) | ||||||
|  |             if user: | ||||||
|  |                 request.user = user | ||||||
|  |         except AuthenticationFailed: | ||||||
|  |             pass | ||||||
|         set_tag("authentik.flow", self.flow.slug) |         set_tag("authentik.flow", self.flow.slug) | ||||||
|  |  | ||||||
|     def handle_invalid_flow(self, exc: FlowNonApplicableException) -> HttpResponse: |     def handle_invalid_flow(self, exc: FlowNonApplicableException) -> HttpResponse: | ||||||
|  | |||||||
| @ -22,6 +22,8 @@ def migrate_search_group(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): | |||||||
|     LDAPProvider = apps.get_model("authentik_providers_ldap", "ldapprovider") |     LDAPProvider = apps.get_model("authentik_providers_ldap", "ldapprovider") | ||||||
|  |  | ||||||
|     for provider in LDAPProvider.objects.using(db_alias).all(): |     for provider in LDAPProvider.objects.using(db_alias).all(): | ||||||
|  |         if not provider.search_group: | ||||||
|  |             continue | ||||||
|         for user_pk in ( |         for user_pk in ( | ||||||
|             provider.search_group.users.using(db_alias).all().values_list("pk", flat=True) |             provider.search_group.users.using(db_alias).all().values_list("pk", flat=True) | ||||||
|         ): |         ): | ||||||
|  | |||||||
| @ -433,20 +433,21 @@ class TokenParams: | |||||||
|         app = Application.objects.filter(provider=self.provider).first() |         app = Application.objects.filter(provider=self.provider).first() | ||||||
|         if not app or not app.provider: |         if not app or not app.provider: | ||||||
|             raise TokenError("invalid_grant") |             raise TokenError("invalid_grant") | ||||||
|         self.user, _ = User.objects.update_or_create( |         with audit_ignore(): | ||||||
|             # trim username to ensure the entire username is max 150 chars |             self.user, _ = User.objects.update_or_create( | ||||||
|             # (22 chars being the length of the "template") |                 # trim username to ensure the entire username is max 150 chars | ||||||
|             username=f"ak-{self.provider.name[:150-22]}-client_credentials", |                 # (22 chars being the length of the "template") | ||||||
|             defaults={ |                 username=f"ak-{self.provider.name[:150-22]}-client_credentials", | ||||||
|                 "attributes": { |                 defaults={ | ||||||
|                     USER_ATTRIBUTE_GENERATED: True, |                     "attributes": { | ||||||
|  |                         USER_ATTRIBUTE_GENERATED: True, | ||||||
|  |                     }, | ||||||
|  |                     "last_login": timezone.now(), | ||||||
|  |                     "name": f"Autogenerated user from application {app.name} (client credentials)", | ||||||
|  |                     "path": f"{USER_PATH_SYSTEM_PREFIX}/apps/{app.slug}", | ||||||
|  |                     "type": UserTypes.SERVICE_ACCOUNT, | ||||||
|                 }, |                 }, | ||||||
|                 "last_login": timezone.now(), |             ) | ||||||
|                 "name": f"Autogenerated user from application {app.name} (client credentials)", |  | ||||||
|                 "path": f"{USER_PATH_SYSTEM_PREFIX}/apps/{app.slug}", |  | ||||||
|                 "type": UserTypes.SERVICE_ACCOUNT, |  | ||||||
|             }, |  | ||||||
|         ) |  | ||||||
|         self.__check_policy_access(app, request) |         self.__check_policy_access(app, request) | ||||||
|  |  | ||||||
|         Event.new( |         Event.new( | ||||||
|  | |||||||
| @ -164,7 +164,7 @@ class SAMLProvider(Provider): | |||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     sign_assertion = models.BooleanField(default=True) |     sign_assertion = models.BooleanField(default=True) | ||||||
|     sign_response = models.BooleanField(default=True) |     sign_response = models.BooleanField(default=False) | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def launch_url(self) -> str | None: |     def launch_url(self) -> str | None: | ||||||
|  | |||||||
| @ -54,7 +54,11 @@ class TestServiceProviderMetadataParser(TestCase): | |||||||
|         request = self.factory.get("/") |         request = self.factory.get("/") | ||||||
|         metadata = lxml_from_string(MetadataProcessor(provider, request).build_entity_descriptor()) |         metadata = lxml_from_string(MetadataProcessor(provider, request).build_entity_descriptor()) | ||||||
|  |  | ||||||
|         schema = etree.XMLSchema(etree.parse("schemas/saml-schema-metadata-2.0.xsd"))  # nosec |         schema = etree.XMLSchema( | ||||||
|  |             etree.parse( | ||||||
|  |                 source="schemas/saml-schema-metadata-2.0.xsd", parser=etree.XMLParser() | ||||||
|  |             )  # nosec | ||||||
|  |         ) | ||||||
|         self.assertTrue(schema.validate(metadata)) |         self.assertTrue(schema.validate(metadata)) | ||||||
|  |  | ||||||
|     def test_schema_want_authn_requests_signed(self): |     def test_schema_want_authn_requests_signed(self): | ||||||
|  | |||||||
| @ -47,7 +47,9 @@ class TestSchema(TestCase): | |||||||
|  |  | ||||||
|         metadata = lxml_from_string(request) |         metadata = lxml_from_string(request) | ||||||
|  |  | ||||||
|         schema = etree.XMLSchema(etree.parse("schemas/saml-schema-protocol-2.0.xsd"))  # nosec |         schema = etree.XMLSchema( | ||||||
|  |             etree.parse("schemas/saml-schema-protocol-2.0.xsd", parser=etree.XMLParser())  # nosec | ||||||
|  |         ) | ||||||
|         self.assertTrue(schema.validate(metadata)) |         self.assertTrue(schema.validate(metadata)) | ||||||
|  |  | ||||||
|     def test_response_schema(self): |     def test_response_schema(self): | ||||||
| @ -68,5 +70,7 @@ class TestSchema(TestCase): | |||||||
|  |  | ||||||
|         metadata = lxml_from_string(response) |         metadata = lxml_from_string(response) | ||||||
|  |  | ||||||
|         schema = etree.XMLSchema(etree.parse("schemas/saml-schema-protocol-2.0.xsd"))  # nosec |         schema = etree.XMLSchema( | ||||||
|  |             etree.parse("schemas/saml-schema-protocol-2.0.xsd", parser=etree.XMLParser())  # nosec | ||||||
|  |         ) | ||||||
|         self.assertTrue(schema.validate(metadata)) |         self.assertTrue(schema.validate(metadata)) | ||||||
|  | |||||||
| @ -248,6 +248,7 @@ MIDDLEWARE = [ | |||||||
|     "django.contrib.auth.middleware.AuthenticationMiddleware", |     "django.contrib.auth.middleware.AuthenticationMiddleware", | ||||||
|     "authentik.core.middleware.RequestIDMiddleware", |     "authentik.core.middleware.RequestIDMiddleware", | ||||||
|     "authentik.brands.middleware.BrandMiddleware", |     "authentik.brands.middleware.BrandMiddleware", | ||||||
|  |     "authentik.brands.middleware.BrandCORSAPIMiddleware", | ||||||
|     "authentik.events.middleware.AuditMiddleware", |     "authentik.events.middleware.AuditMiddleware", | ||||||
|     "django.middleware.security.SecurityMiddleware", |     "django.middleware.security.SecurityMiddleware", | ||||||
|     "django.middleware.common.CommonMiddleware", |     "django.middleware.common.CommonMiddleware", | ||||||
|  | |||||||
| @ -30,7 +30,9 @@ class TestMetadataProcessor(TestCase): | |||||||
|         xml = MetadataProcessor(self.source, request).build_entity_descriptor() |         xml = MetadataProcessor(self.source, request).build_entity_descriptor() | ||||||
|         metadata = lxml_from_string(xml) |         metadata = lxml_from_string(xml) | ||||||
|  |  | ||||||
|         schema = etree.XMLSchema(etree.parse("schemas/saml-schema-metadata-2.0.xsd"))  # nosec |         schema = etree.XMLSchema( | ||||||
|  |             etree.parse("schemas/saml-schema-metadata-2.0.xsd", parser=etree.XMLParser())  # nosec | ||||||
|  |         ) | ||||||
|         self.assertTrue(schema.validate(metadata)) |         self.assertTrue(schema.validate(metadata)) | ||||||
|  |  | ||||||
|     def test_metadata_consistent(self): |     def test_metadata_consistent(self): | ||||||
|  | |||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -2,7 +2,7 @@ | |||||||
|     "$schema": "http://json-schema.org/draft-07/schema", |     "$schema": "http://json-schema.org/draft-07/schema", | ||||||
|     "$id": "https://goauthentik.io/blueprints/schema.json", |     "$id": "https://goauthentik.io/blueprints/schema.json", | ||||||
|     "type": "object", |     "type": "object", | ||||||
|     "title": "authentik 2024.6.4 Blueprint schema", |     "title": "authentik 2024.8.0 Blueprint schema", | ||||||
|     "required": [ |     "required": [ | ||||||
|         "version", |         "version", | ||||||
|         "entries" |         "entries" | ||||||
|  | |||||||
| @ -31,7 +31,7 @@ services: | |||||||
|     volumes: |     volumes: | ||||||
|       - redis:/data |       - redis:/data | ||||||
|   server: |   server: | ||||||
|     image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.6.4} |     image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.8.0} | ||||||
|     restart: unless-stopped |     restart: unless-stopped | ||||||
|     command: server |     command: server | ||||||
|     environment: |     environment: | ||||||
| @ -52,7 +52,7 @@ services: | |||||||
|       - postgresql |       - postgresql | ||||||
|       - redis |       - redis | ||||||
|   worker: |   worker: | ||||||
|     image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.6.4} |     image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.8.0} | ||||||
|     restart: unless-stopped |     restart: unless-stopped | ||||||
|     command: worker |     command: worker | ||||||
|     environment: |     environment: | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							| @ -18,7 +18,7 @@ require ( | |||||||
| 	github.com/gorilla/securecookie v1.1.2 | 	github.com/gorilla/securecookie v1.1.2 | ||||||
| 	github.com/gorilla/sessions v1.4.0 | 	github.com/gorilla/sessions v1.4.0 | ||||||
| 	github.com/gorilla/websocket v1.5.3 | 	github.com/gorilla/websocket v1.5.3 | ||||||
| 	github.com/jellydator/ttlcache/v3 v3.2.1 | 	github.com/jellydator/ttlcache/v3 v3.3.0 | ||||||
| 	github.com/mitchellh/mapstructure v1.5.0 | 	github.com/mitchellh/mapstructure v1.5.0 | ||||||
| 	github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 | 	github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 | ||||||
| 	github.com/pires/go-proxyproto v0.7.0 | 	github.com/pires/go-proxyproto v0.7.0 | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							| @ -200,8 +200,8 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6 | |||||||
| github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= | github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= | ||||||
| github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= | github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= | ||||||
| github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= | github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= | ||||||
| github.com/jellydator/ttlcache/v3 v3.2.1 h1:eS8ljnYY7BllYGkXw/TfczWZrXUu/CH7SIkC6ugn9Js= | github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc= | ||||||
| github.com/jellydator/ttlcache/v3 v3.2.1/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw= | github.com/jellydator/ttlcache/v3 v3.3.0/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw= | ||||||
| github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= | github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= | ||||||
| github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= | github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= | ||||||
| github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= | ||||||
|  | |||||||
| @ -29,4 +29,4 @@ func UserAgent() string { | |||||||
| 	return fmt.Sprintf("authentik@%s", FullVersion()) | 	return fmt.Sprintf("authentik@%s", FullVersion()) | ||||||
| } | } | ||||||
|  |  | ||||||
| const VERSION = "2024.6.4" | const VERSION = "2024.8.0" | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ msgid "" | |||||||
| msgstr "" | msgstr "" | ||||||
| "Project-Id-Version: PACKAGE VERSION\n" | "Project-Id-Version: PACKAGE VERSION\n" | ||||||
| "Report-Msgid-Bugs-To: \n" | "Report-Msgid-Bugs-To: \n" | ||||||
| "POT-Creation-Date: 2024-08-15 00:09+0000\n" | "POT-Creation-Date: 2024-08-18 00:08+0000\n" | ||||||
| "PO-Revision-Date: 2022-09-26 16:47+0000\n" | "PO-Revision-Date: 2022-09-26 16:47+0000\n" | ||||||
| "Last-Translator: Anton Babenko, 2024\n" | "Last-Translator: Anton Babenko, 2024\n" | ||||||
| "Language-Team: Russian (https://app.transifex.com/authentik/teams/119923/ru/)\n" | "Language-Team: Russian (https://app.transifex.com/authentik/teams/119923/ru/)\n" | ||||||
| @ -739,7 +739,7 @@ msgstr "Правило Уведомления" | |||||||
|  |  | ||||||
| #: authentik/events/models.py | #: authentik/events/models.py | ||||||
| msgid "Notification Rules" | msgid "Notification Rules" | ||||||
| msgstr "Правило Уведомлений" | msgstr "Правила уведомлений" | ||||||
|  |  | ||||||
| #: authentik/events/models.py | #: authentik/events/models.py | ||||||
| msgid "Webhook Mapping" | msgid "Webhook Mapping" | ||||||
| @ -1771,6 +1771,14 @@ msgstr "Сопоставление свойства Radius провайдера" | |||||||
| msgid "Radius Provider Property Mappings" | msgid "Radius Provider Property Mappings" | ||||||
| msgstr "Сопоставление свойств Radius провайдера" | msgstr "Сопоставление свойств Radius провайдера" | ||||||
|  |  | ||||||
|  | #: authentik/providers/saml/api/providers.py | ||||||
|  | msgid "" | ||||||
|  | "With a signing keypair selected, at least one of 'Sign assertion' and 'Sign " | ||||||
|  | "Response' must be selected." | ||||||
|  | msgstr "" | ||||||
|  | "При выборе пары ключей для подписи необходимо выбрать как минимум один из " | ||||||
|  | "вариантов: 'Подписывать утверждение' или 'Подписывать ответ'." | ||||||
|  |  | ||||||
| #: authentik/providers/saml/api/providers.py | #: authentik/providers/saml/api/providers.py | ||||||
| msgid "Invalid XML Syntax" | msgid "Invalid XML Syntax" | ||||||
| msgstr "Некорректный синтаксис XML" | msgstr "Некорректный синтаксис XML" | ||||||
| @ -1918,6 +1926,21 @@ msgstr "" | |||||||
| msgid "Signing Keypair" | msgid "Signing Keypair" | ||||||
| msgstr "Пара ключей для подписи" | msgstr "Пара ключей для подписи" | ||||||
|  |  | ||||||
|  | #: authentik/providers/saml/models.py authentik/sources/saml/models.py | ||||||
|  | msgid "" | ||||||
|  | "When selected, incoming assertions are encrypted by the IdP using the public" | ||||||
|  | " key of the encryption keypair. The assertion is decrypted by the SP using " | ||||||
|  | "the the private key." | ||||||
|  | msgstr "" | ||||||
|  | "При выборе этого варианта, входящие утверждения шифруются поставщиком " | ||||||
|  | "идентификации (IdP) с использованием открытого ключа из пары ключей " | ||||||
|  | "шифрования. Утверждение расшифровывается поставщиком услуг (SP) с " | ||||||
|  | "использованием закрытого ключа." | ||||||
|  |  | ||||||
|  | #: authentik/providers/saml/models.py authentik/sources/saml/models.py | ||||||
|  | msgid "Encryption Keypair" | ||||||
|  | msgstr "Пара ключей шифрования" | ||||||
|  |  | ||||||
| #: authentik/providers/saml/models.py | #: authentik/providers/saml/models.py | ||||||
| msgid "Default relay_state value for IDP-initiated logins" | msgid "Default relay_state value for IDP-initiated logins" | ||||||
| msgstr "Значение relay_state по умолчанию для логинов, инициированных IDP" | msgstr "Значение relay_state по умолчанию для логинов, инициированных IDP" | ||||||
| @ -2446,21 +2469,6 @@ msgstr "" | |||||||
| "Пара ключей, используемая для подписи исходящих ответов, направляемых " | "Пара ключей, используемая для подписи исходящих ответов, направляемых " | ||||||
| "провайдеру идентификационных данных." | "провайдеру идентификационных данных." | ||||||
|  |  | ||||||
| #: authentik/sources/saml/models.py |  | ||||||
| msgid "" |  | ||||||
| "When selected, incoming assertions are encrypted by the IdP using the public" |  | ||||||
| " key of the encryption keypair. The assertion is decrypted by the SP using " |  | ||||||
| "the the private key." |  | ||||||
| msgstr "" |  | ||||||
| "При выборе этого варианта, входящие утверждения шифруются поставщиком " |  | ||||||
| "идентификации (IdP) с использованием открытого ключа из пары ключей " |  | ||||||
| "шифрования. Утверждение расшифровывается поставщиком услуг (SP) с " |  | ||||||
| "использованием закрытого ключа." |  | ||||||
|  |  | ||||||
| #: authentik/sources/saml/models.py |  | ||||||
| msgid "Encryption Keypair" |  | ||||||
| msgstr "Пара ключей шифрования" |  | ||||||
|  |  | ||||||
| #: authentik/sources/saml/models.py | #: authentik/sources/saml/models.py | ||||||
| msgid "SAML Source" | msgid "SAML Source" | ||||||
| msgstr "Источник SAML" | msgstr "Источник SAML" | ||||||
|  | |||||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| @ -1,5 +1,5 @@ | |||||||
| { | { | ||||||
|     "name": "@goauthentik/authentik", |     "name": "@goauthentik/authentik", | ||||||
|     "version": "2024.6.4", |     "version": "2024.8.0", | ||||||
|     "private": true |     "private": true | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										233
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										233
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							| @ -1165,15 +1165,18 @@ files = [ | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "deepmerge" | name = "deepmerge" | ||||||
| version = "1.1.1" | version = "2.0" | ||||||
| description = "a toolset to deeply merge python dictionaries." | description = "A toolset for deeply merging Python dictionaries." | ||||||
| optional = false | optional = false | ||||||
| python-versions = "*" | python-versions = ">=3.8" | ||||||
| files = [ | files = [ | ||||||
|     {file = "deepmerge-1.1.1-py3-none-any.whl", hash = "sha256:7219dad9763f15be9dcd4bcb53e00f48e4eed6f5ed8f15824223eb934bb35977"}, |     {file = "deepmerge-2.0-py3-none-any.whl", hash = "sha256:6de9ce507115cff0bed95ff0ce9ecc31088ef50cbdf09bc90a09349a318b3d00"}, | ||||||
|     {file = "deepmerge-1.1.1.tar.gz", hash = "sha256:53a489dc9449636e480a784359ae2aab3191748c920649551c8e378622f0eca4"}, |     {file = "deepmerge-2.0.tar.gz", hash = "sha256:5c3d86081fbebd04dd5de03626a0607b809a98fb6ccba5770b62466fe940ff20"}, | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | [package.extras] | ||||||
|  | dev = ["black", "build", "mypy", "pytest", "pyupgrade", "twine", "validate-pyproject[all]"] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "defusedxml" | name = "defusedxml" | ||||||
| version = "0.7.1" | version = "0.7.1" | ||||||
| @ -1758,13 +1761,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "google-api-python-client" | name = "google-api-python-client" | ||||||
| version = "2.142.0" | version = "2.143.0" | ||||||
| description = "Google API Client Library for Python" | description = "Google API Client Library for Python" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=3.7" | python-versions = ">=3.7" | ||||||
| files = [ | files = [ | ||||||
|     {file = "google_api_python_client-2.142.0-py2.py3-none-any.whl", hash = "sha256:266799082bb8301f423ec204dffbffb470b502abbf29efd1f83e644d36eb5a8f"}, |     {file = "google_api_python_client-2.143.0-py2.py3-none-any.whl", hash = "sha256:d5654134522b9b574b82234e96f7e0aeeabcbf33643fbabcd449ef0068e3a476"}, | ||||||
|     {file = "google_api_python_client-2.142.0.tar.gz", hash = "sha256:a1101ac9e24356557ca22f07ff48b7f61fa5d4b4e7feeef3bda16e5dcb86350e"}, |     {file = "google_api_python_client-2.143.0.tar.gz", hash = "sha256:6a75441f9078e6e2fcdf4946a153fda1e2cc81b5e9c8d6e8c0750c85c7f8a566"}, | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [package.dependencies] | [package.dependencies] | ||||||
| @ -2047,13 +2050,13 @@ files = [ | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "importlib-metadata" | name = "importlib-metadata" | ||||||
| version = "8.0.0" | version = "8.4.0" | ||||||
| description = "Read metadata from Python packages" | description = "Read metadata from Python packages" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=3.8" | python-versions = ">=3.8" | ||||||
| files = [ | files = [ | ||||||
|     {file = "importlib_metadata-8.0.0-py3-none-any.whl", hash = "sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f"}, |     {file = "importlib_metadata-8.4.0-py3-none-any.whl", hash = "sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1"}, | ||||||
|     {file = "importlib_metadata-8.0.0.tar.gz", hash = "sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812"}, |     {file = "importlib_metadata-8.4.0.tar.gz", hash = "sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5"}, | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [package.dependencies] | [package.dependencies] | ||||||
| @ -3025,49 +3028,49 @@ resolved_reference = "20d69d9cc50a0fef31605b46f06da0c94f1ec3cf" | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "opentelemetry-api" | name = "opentelemetry-api" | ||||||
| version = "1.26.0" | version = "1.27.0" | ||||||
| description = "OpenTelemetry Python API" | description = "OpenTelemetry Python API" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=3.8" | python-versions = ">=3.8" | ||||||
| files = [ | files = [ | ||||||
|     {file = "opentelemetry_api-1.26.0-py3-none-any.whl", hash = "sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064"}, |     {file = "opentelemetry_api-1.27.0-py3-none-any.whl", hash = "sha256:953d5871815e7c30c81b56d910c707588000fff7a3ca1c73e6531911d53065e7"}, | ||||||
|     {file = "opentelemetry_api-1.26.0.tar.gz", hash = "sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce"}, |     {file = "opentelemetry_api-1.27.0.tar.gz", hash = "sha256:ed673583eaa5f81b5ce5e86ef7cdaf622f88ef65f0b9aab40b843dcae5bef342"}, | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [package.dependencies] | [package.dependencies] | ||||||
| deprecated = ">=1.2.6" | deprecated = ">=1.2.6" | ||||||
| importlib-metadata = ">=6.0,<=8.0.0" | importlib-metadata = ">=6.0,<=8.4.0" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "opentelemetry-sdk" | name = "opentelemetry-sdk" | ||||||
| version = "1.26.0" | version = "1.27.0" | ||||||
| description = "OpenTelemetry Python SDK" | description = "OpenTelemetry Python SDK" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=3.8" | python-versions = ">=3.8" | ||||||
| files = [ | files = [ | ||||||
|     {file = "opentelemetry_sdk-1.26.0-py3-none-any.whl", hash = "sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897"}, |     {file = "opentelemetry_sdk-1.27.0-py3-none-any.whl", hash = "sha256:365f5e32f920faf0fd9e14fdfd92c086e317eaa5f860edba9cdc17a380d9197d"}, | ||||||
|     {file = "opentelemetry_sdk-1.26.0.tar.gz", hash = "sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85"}, |     {file = "opentelemetry_sdk-1.27.0.tar.gz", hash = "sha256:d525017dea0ccce9ba4e0245100ec46ecdc043f2d7b8315d56b19aff0904fa6f"}, | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [package.dependencies] | [package.dependencies] | ||||||
| opentelemetry-api = "1.26.0" | opentelemetry-api = "1.27.0" | ||||||
| opentelemetry-semantic-conventions = "0.47b0" | opentelemetry-semantic-conventions = "0.48b0" | ||||||
| typing-extensions = ">=3.7.4" | typing-extensions = ">=3.7.4" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "opentelemetry-semantic-conventions" | name = "opentelemetry-semantic-conventions" | ||||||
| version = "0.47b0" | version = "0.48b0" | ||||||
| description = "OpenTelemetry Semantic Conventions" | description = "OpenTelemetry Semantic Conventions" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=3.8" | python-versions = ">=3.8" | ||||||
| files = [ | files = [ | ||||||
|     {file = "opentelemetry_semantic_conventions-0.47b0-py3-none-any.whl", hash = "sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063"}, |     {file = "opentelemetry_semantic_conventions-0.48b0-py3-none-any.whl", hash = "sha256:a0de9f45c413a8669788a38569c7e0a11ce6ce97861a628cca785deecdc32a1f"}, | ||||||
|     {file = "opentelemetry_semantic_conventions-0.47b0.tar.gz", hash = "sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e"}, |     {file = "opentelemetry_semantic_conventions-0.48b0.tar.gz", hash = "sha256:12d74983783b6878162208be57c9effcb89dc88691c64992d70bb89dc00daa1a"}, | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [package.dependencies] | [package.dependencies] | ||||||
| deprecated = ">=1.2.6" | deprecated = ">=1.2.6" | ||||||
| opentelemetry-api = "1.26.0" | opentelemetry-api = "1.27.0" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "orjson" | name = "orjson" | ||||||
| @ -3201,13 +3204,13 @@ files = [ | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "pdoc" | name = "pdoc" | ||||||
| version = "14.6.0" | version = "14.6.1" | ||||||
| description = "API Documentation for Python Projects" | description = "API Documentation for Python Projects" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=3.8" | python-versions = ">=3.8" | ||||||
| files = [ | files = [ | ||||||
|     {file = "pdoc-14.6.0-py3-none-any.whl", hash = "sha256:36c42c546a317d8e3e8c0b39645f24161374de0c7066ccaae76628d721e49ba5"}, |     {file = "pdoc-14.6.1-py3-none-any.whl", hash = "sha256:efbed433655264392c60551615a3d42b8f21e492373419756d20234c667b54bc"}, | ||||||
|     {file = "pdoc-14.6.0.tar.gz", hash = "sha256:6e98a24c5e0ca5d188397969cf82581836eaef13f172fc3820047bfe15c61c9a"}, |     {file = "pdoc-14.6.1.tar.gz", hash = "sha256:ee598f30d5c55dd4702086dabc412a26022acc35aa88aa382cda8ac655fead98"}, | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [package.dependencies] | [package.dependencies] | ||||||
| @ -3781,13 +3784,13 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "pytest-django" | name = "pytest-django" | ||||||
| version = "4.8.0" | version = "4.9.0" | ||||||
| description = "A Django plugin for pytest." | description = "A Django plugin for pytest." | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=3.8" | python-versions = ">=3.8" | ||||||
| files = [ | files = [ | ||||||
|     {file = "pytest-django-4.8.0.tar.gz", hash = "sha256:5d054fe011c56f3b10f978f41a8efb2e5adfc7e680ef36fb571ada1f24779d90"}, |     {file = "pytest_django-4.9.0-py3-none-any.whl", hash = "sha256:1d83692cb39188682dbb419ff0393867e9904094a549a7d38a3154d5731b2b99"}, | ||||||
|     {file = "pytest_django-4.8.0-py3-none-any.whl", hash = "sha256:ca1ddd1e0e4c227cf9e3e40a6afc6d106b3e70868fd2ac5798a22501271cd0c7"}, |     {file = "pytest_django-4.9.0.tar.gz", hash = "sha256:8bf7bc358c9ae6f6fc51b6cebb190fe20212196e6807121f11bd6a3b03428314"}, | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [package.dependencies] | [package.dependencies] | ||||||
| @ -4195,29 +4198,29 @@ pyasn1 = ">=0.1.3" | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "ruff" | name = "ruff" | ||||||
| version = "0.6.2" | version = "0.6.3" | ||||||
| description = "An extremely fast Python linter and code formatter, written in Rust." | description = "An extremely fast Python linter and code formatter, written in Rust." | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=3.7" | python-versions = ">=3.7" | ||||||
| files = [ | files = [ | ||||||
|     {file = "ruff-0.6.2-py3-none-linux_armv6l.whl", hash = "sha256:5c8cbc6252deb3ea840ad6a20b0f8583caab0c5ef4f9cca21adc5a92b8f79f3c"}, |     {file = "ruff-0.6.3-py3-none-linux_armv6l.whl", hash = "sha256:97f58fda4e309382ad30ede7f30e2791d70dd29ea17f41970119f55bdb7a45c3"}, | ||||||
|     {file = "ruff-0.6.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:17002fe241e76544448a8e1e6118abecbe8cd10cf68fde635dad480dba594570"}, |     {file = "ruff-0.6.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3b061e49b5cf3a297b4d1c27ac5587954ccb4ff601160d3d6b2f70b1622194dc"}, | ||||||
|     {file = "ruff-0.6.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3dbeac76ed13456f8158b8f4fe087bf87882e645c8e8b606dd17b0b66c2c1158"}, |     {file = "ruff-0.6.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:34e2824a13bb8c668c71c1760a6ac7d795ccbd8d38ff4a0d8471fdb15de910b1"}, | ||||||
|     {file = "ruff-0.6.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:094600ee88cda325988d3f54e3588c46de5c18dae09d683ace278b11f9d4d534"}, |     {file = "ruff-0.6.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bddfbb8d63c460f4b4128b6a506e7052bad4d6f3ff607ebbb41b0aa19c2770d1"}, | ||||||
|     {file = "ruff-0.6.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:316d418fe258c036ba05fbf7dfc1f7d3d4096db63431546163b472285668132b"}, |     {file = "ruff-0.6.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ced3eeb44df75353e08ab3b6a9e113b5f3f996bea48d4f7c027bc528ba87b672"}, | ||||||
|     {file = "ruff-0.6.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d72b8b3abf8a2d51b7b9944a41307d2f442558ccb3859bbd87e6ae9be1694a5d"}, |     {file = "ruff-0.6.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47021dff5445d549be954eb275156dfd7c37222acc1e8014311badcb9b4ec8c1"}, | ||||||
|     {file = "ruff-0.6.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2aed7e243be68487aa8982e91c6e260982d00da3f38955873aecd5a9204b1d66"}, |     {file = "ruff-0.6.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d7bd20dc07cebd68cc8bc7b3f5ada6d637f42d947c85264f94b0d1cd9d87384"}, | ||||||
|     {file = "ruff-0.6.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d371f7fc9cec83497fe7cf5eaf5b76e22a8efce463de5f775a1826197feb9df8"}, |     {file = "ruff-0.6.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:500f166d03fc6d0e61c8e40a3ff853fa8a43d938f5d14c183c612df1b0d6c58a"}, | ||||||
|     {file = "ruff-0.6.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8f310d63af08f583363dfb844ba8f9417b558199c58a5999215082036d795a1"}, |     {file = "ruff-0.6.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42844ff678f9b976366b262fa2d1d1a3fe76f6e145bd92c84e27d172e3c34500"}, | ||||||
|     {file = "ruff-0.6.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7db6880c53c56addb8638fe444818183385ec85eeada1d48fc5abe045301b2f1"}, |     {file = "ruff-0.6.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70452a10eb2d66549de8e75f89ae82462159855e983ddff91bc0bce6511d0470"}, | ||||||
|     {file = "ruff-0.6.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1175d39faadd9a50718f478d23bfc1d4da5743f1ab56af81a2b6caf0a2394f23"}, |     {file = "ruff-0.6.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:65a533235ed55f767d1fc62193a21cbf9e3329cf26d427b800fdeacfb77d296f"}, | ||||||
|     {file = "ruff-0.6.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5b939f9c86d51635fe486585389f54582f0d65b8238e08c327c1534844b3bb9a"}, |     {file = "ruff-0.6.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d2e2c23cef30dc3cbe9cc5d04f2899e7f5e478c40d2e0a633513ad081f7361b5"}, | ||||||
|     {file = "ruff-0.6.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d0d62ca91219f906caf9b187dea50d17353f15ec9bb15aae4a606cd697b49b4c"}, |     {file = "ruff-0.6.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d8a136aa7d228975a6aee3dd8bea9b28e2b43e9444aa678fb62aeb1956ff2351"}, | ||||||
|     {file = "ruff-0.6.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7438a7288f9d67ed3c8ce4d059e67f7ed65e9fe3aa2ab6f5b4b3610e57e3cb56"}, |     {file = "ruff-0.6.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:f92fe93bc72e262b7b3f2bba9879897e2d58a989b4714ba6a5a7273e842ad2f8"}, | ||||||
|     {file = "ruff-0.6.2-py3-none-win32.whl", hash = "sha256:279d5f7d86696df5f9549b56b9b6a7f6c72961b619022b5b7999b15db392a4da"}, |     {file = "ruff-0.6.3-py3-none-win32.whl", hash = "sha256:7a62d3b5b0d7f9143d94893f8ba43aa5a5c51a0ffc4a401aa97a81ed76930521"}, | ||||||
|     {file = "ruff-0.6.2-py3-none-win_amd64.whl", hash = "sha256:d9f3469c7dd43cd22eb1c3fc16926fb8258d50cb1b216658a07be95dd117b0f2"}, |     {file = "ruff-0.6.3-py3-none-win_amd64.whl", hash = "sha256:746af39356fee2b89aada06c7376e1aa274a23493d7016059c3a72e3b296befb"}, | ||||||
|     {file = "ruff-0.6.2-py3-none-win_arm64.whl", hash = "sha256:f28fcd2cd0e02bdf739297516d5643a945cc7caf09bd9bcb4d932540a5ea4fa9"}, |     {file = "ruff-0.6.3-py3-none-win_arm64.whl", hash = "sha256:14a9528a8b70ccc7a847637c29e56fd1f9183a9db743bbc5b8e0c4ad60592a82"}, | ||||||
|     {file = "ruff-0.6.2.tar.gz", hash = "sha256:239ee6beb9e91feb8e0ec384204a763f36cb53fb895a1a364618c6abb076b3be"}, |     {file = "ruff-0.6.3.tar.gz", hash = "sha256:183b99e9edd1ef63be34a3b51fee0a9f4ab95add123dbf89a71f7b1f0c991983"}, | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| @ -4256,13 +4259,13 @@ django-query = ["django (>=3.2)"] | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "selenium" | name = "selenium" | ||||||
| version = "4.23.1" | version = "4.24.0" | ||||||
| description = "Official Python bindings for Selenium WebDriver" | description = "Official Python bindings for Selenium WebDriver" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=3.8" | python-versions = ">=3.8" | ||||||
| files = [ | files = [ | ||||||
|     {file = "selenium-4.23.1-py3-none-any.whl", hash = "sha256:3a8d9f23dc636bd3840dd56f00c2739e32ec0c1e34a821dd553e15babef24477"}, |     {file = "selenium-4.24.0-py3-none-any.whl", hash = "sha256:42c23f60753d5415b261b236cecbd69bd4eb5271e1563915f546b443cb6b71c6"}, | ||||||
|     {file = "selenium-4.23.1.tar.gz", hash = "sha256:128d099e66284437e7128d2279176ec7a06e6ec7426e167f5d34987166bd8f46"}, |     {file = "selenium-4.24.0.tar.gz", hash = "sha256:88281e5b5b90fe231868905d5ea745b9ee5e30db280b33498cc73fb0fa06d571"}, | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [package.dependencies] | [package.dependencies] | ||||||
| @ -4652,13 +4655,13 @@ wsproto = ">=0.14" | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "twilio" | name = "twilio" | ||||||
| version = "9.2.3" | version = "9.2.4" | ||||||
| description = "Twilio API client and TwiML generator" | description = "Twilio API client and TwiML generator" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=3.7.0" | python-versions = ">=3.7.0" | ||||||
| files = [ | files = [ | ||||||
|     {file = "twilio-9.2.3-py2.py3-none-any.whl", hash = "sha256:76bfc39aa8d854510907cb7f9465814dfdea9e91ec199bb44f0785f05746f4cc"}, |     {file = "twilio-9.2.4-py2.py3-none-any.whl", hash = "sha256:490da2518c0da370d738d436f9086b2463902707a811cd306ec8dcc8ce831758"}, | ||||||
|     {file = "twilio-9.2.3.tar.gz", hash = "sha256:da2255b5f3753cb3bf647fc6c50edbdb367ebc3cde6802806f6f863058a65f75"}, |     {file = "twilio-9.2.4.tar.gz", hash = "sha256:454b7d075c6bee3b64c81c39151be1f9105c695df6dbb0021b0c43e2930263e7"}, | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [package.dependencies] | [package.dependencies] | ||||||
| @ -4669,13 +4672,13 @@ requests = ">=2.0.0" | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "twisted" | name = "twisted" | ||||||
| version = "24.3.0" | version = "24.7.0" | ||||||
| description = "An asynchronous networking framework written in Python" | description = "An asynchronous networking framework written in Python" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=3.8.0" | python-versions = ">=3.8.0" | ||||||
| files = [ | files = [ | ||||||
|     {file = "twisted-24.3.0-py3-none-any.whl", hash = "sha256:039f2e6a49ab5108abd94de187fa92377abe5985c7a72d68d0ad266ba19eae63"}, |     {file = "twisted-24.7.0-py3-none-any.whl", hash = "sha256:734832ef98108136e222b5230075b1079dad8a3fc5637319615619a7725b0c81"}, | ||||||
|     {file = "twisted-24.3.0.tar.gz", hash = "sha256:6b38b6ece7296b5e122c9eb17da2eeab3d98a198f50ca9efd00fb03e5b4fd4ae"}, |     {file = "twisted-24.7.0.tar.gz", hash = "sha256:5a60147f044187a127ec7da96d170d49bcce50c6fd36f594e60f4587eff4d394"}, | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [package.dependencies] | [package.dependencies] | ||||||
| @ -4684,55 +4687,26 @@ automat = ">=0.8.0" | |||||||
| constantly = ">=15.1" | constantly = ">=15.1" | ||||||
| hyperlink = ">=17.1.1" | hyperlink = ">=17.1.1" | ||||||
| idna = {version = ">=2.4", optional = true, markers = "extra == \"tls\""} | idna = {version = ">=2.4", optional = true, markers = "extra == \"tls\""} | ||||||
| incremental = ">=22.10.0" | incremental = ">=24.7.0" | ||||||
| pyopenssl = {version = ">=21.0.0", optional = true, markers = "extra == \"tls\""} | pyopenssl = {version = ">=21.0.0", optional = true, markers = "extra == \"tls\""} | ||||||
| service-identity = {version = ">=18.1.0", optional = true, markers = "extra == \"tls\""} | service-identity = {version = ">=18.1.0", optional = true, markers = "extra == \"tls\""} | ||||||
| twisted-iocpsupport = {version = ">=1.0.2,<2", markers = "platform_system == \"Windows\""} |  | ||||||
| typing-extensions = ">=4.2.0" | typing-extensions = ">=4.2.0" | ||||||
| zope-interface = ">=5" | zope-interface = ">=5" | ||||||
|  |  | ||||||
| [package.extras] | [package.extras] | ||||||
| all-non-platform = ["twisted[conch,http2,serial,test,tls]", "twisted[conch,http2,serial,test,tls]"] | all-non-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)"] | ||||||
| conch = ["appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)"] | conch = ["appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)"] | ||||||
| dev = ["coverage (>=6b1,<7)", "pyflakes (>=2.2,<3.0)", "python-subunit (>=1.4,<2.0)", "twisted[dev-release]", "twistedchecker (>=0.7,<1.0)"] | dev = ["coverage (>=7.5,<8.0)", "cython-test-exception-raiser (>=1.0.2,<2)", "hypothesis (>=6.56)", "pydoctor (>=23.9.0,<23.10.0)", "pyflakes (>=2.2,<3.0)", "pyhamcrest (>=2)", "python-subunit (>=1.4,<2.0)", "sphinx (>=6,<7)", "sphinx-rtd-theme (>=1.3,<2.0)", "towncrier (>=23.6,<24.0)", "twistedchecker (>=0.7,<1.0)"] | ||||||
| dev-release = ["pydoctor (>=23.9.0,<23.10.0)", "pydoctor (>=23.9.0,<23.10.0)", "sphinx (>=6,<7)", "sphinx (>=6,<7)", "sphinx-rtd-theme (>=1.3,<2.0)", "sphinx-rtd-theme (>=1.3,<2.0)", "towncrier (>=23.6,<24.0)", "towncrier (>=23.6,<24.0)"] | dev-release = ["pydoctor (>=23.9.0,<23.10.0)", "pydoctor (>=23.9.0,<23.10.0)", "sphinx (>=6,<7)", "sphinx (>=6,<7)", "sphinx-rtd-theme (>=1.3,<2.0)", "sphinx-rtd-theme (>=1.3,<2.0)", "towncrier (>=23.6,<24.0)", "towncrier (>=23.6,<24.0)"] | ||||||
| gtk-platform = ["pygobject", "pygobject", "twisted[all-non-platform]", "twisted[all-non-platform]"] | gtk-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pygobject", "pygobject", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)"] | ||||||
| http2 = ["h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)"] | http2 = ["h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)"] | ||||||
| macos-platform = ["pyobjc-core", "pyobjc-core", "pyobjc-framework-cfnetwork", "pyobjc-framework-cfnetwork", "pyobjc-framework-cocoa", "pyobjc-framework-cocoa", "twisted[all-non-platform]", "twisted[all-non-platform]"] | macos-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyobjc-core", "pyobjc-core", "pyobjc-framework-cfnetwork", "pyobjc-framework-cfnetwork", "pyobjc-framework-cocoa", "pyobjc-framework-cocoa", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)"] | ||||||
| mypy = ["mypy (>=1.8,<2.0)", "mypy-zope (>=1.0.3,<1.1.0)", "twisted[all-non-platform,dev]", "types-pyopenssl", "types-setuptools"] | mypy = ["appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "coverage (>=7.5,<8.0)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.56)", "idna (>=2.4)", "mypy (>=1.8,<2.0)", "mypy-zope (>=1.0.3,<1.1.0)", "priority (>=1.1.0,<2.0)", "pydoctor (>=23.9.0,<23.10.0)", "pyflakes (>=2.2,<3.0)", "pyhamcrest (>=2)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "python-subunit (>=1.4,<2.0)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "sphinx (>=6,<7)", "sphinx-rtd-theme (>=1.3,<2.0)", "towncrier (>=23.6,<24.0)", "twistedchecker (>=0.7,<1.0)", "types-pyopenssl", "types-setuptools"] | ||||||
| osx-platform = ["twisted[macos-platform]", "twisted[macos-platform]"] | osx-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyobjc-core", "pyobjc-core", "pyobjc-framework-cfnetwork", "pyobjc-framework-cfnetwork", "pyobjc-framework-cocoa", "pyobjc-framework-cocoa", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)"] | ||||||
| serial = ["pyserial (>=3.0)", "pywin32 (!=226)"] | serial = ["pyserial (>=3.0)", "pywin32 (!=226)"] | ||||||
| test = ["cython-test-exception-raiser (>=1.0.2,<2)", "hypothesis (>=6.56)", "pyhamcrest (>=2)"] | test = ["cython-test-exception-raiser (>=1.0.2,<2)", "hypothesis (>=6.56)", "pyhamcrest (>=2)"] | ||||||
| tls = ["idna (>=2.4)", "pyopenssl (>=21.0.0)", "service-identity (>=18.1.0)"] | tls = ["idna (>=2.4)", "pyopenssl (>=21.0.0)", "service-identity (>=18.1.0)"] | ||||||
| windows-platform = ["pywin32 (!=226)", "pywin32 (!=226)", "twisted[all-non-platform]", "twisted[all-non-platform]"] | windows-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)", "twisted-iocpsupport (>=1.0.2)", "twisted-iocpsupport (>=1.0.2)"] | ||||||
|  |  | ||||||
| [[package]] |  | ||||||
| name = "twisted-iocpsupport" |  | ||||||
| version = "1.0.4" |  | ||||||
| description = "An extension for use in the twisted I/O Completion Ports reactor." |  | ||||||
| optional = false |  | ||||||
| python-versions = "*" |  | ||||||
| files = [ |  | ||||||
|     {file = "twisted-iocpsupport-1.0.4.tar.gz", hash = "sha256:858096c0d15e33f15ac157f455d8f86f2f2cdd223963e58c0f682a3af8362d89"}, |  | ||||||
|     {file = "twisted_iocpsupport-1.0.4-cp310-cp310-win32.whl", hash = "sha256:afa2b630797f9ed2f27f3d9f55e3f72b4244911e45a8c82756f44babbf0b243e"}, |  | ||||||
|     {file = "twisted_iocpsupport-1.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:0058c963c8957bcd3deda62122e89953c9de1e867a274facc9b15dde1a9f31e8"}, |  | ||||||
|     {file = "twisted_iocpsupport-1.0.4-cp311-cp311-win32.whl", hash = "sha256:196f7c7ccad4ba4d1783b1c4e1d1b22d93c04275cd780bf7498d16c77319ad6e"}, |  | ||||||
|     {file = "twisted_iocpsupport-1.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:4e5f97bcbabdd79cbaa969b63439b89801ea560f11d42b0a387634275c633623"}, |  | ||||||
|     {file = "twisted_iocpsupport-1.0.4-cp312-cp312-win32.whl", hash = "sha256:6081bd7c2f4fcf9b383dcdb3b3385d75a26a7c9d2be25b6950c3d8ea652d2d2d"}, |  | ||||||
|     {file = "twisted_iocpsupport-1.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:76f7e67cec1f1d097d1f4ed7de41be3d74546e1a4ede0c7d56e775c4dce5dfb0"}, |  | ||||||
|     {file = "twisted_iocpsupport-1.0.4-cp36-cp36m-win32.whl", hash = "sha256:3d306fc4d88a6bcf61ce9d572c738b918578121bfd72891625fab314549024b5"}, |  | ||||||
|     {file = "twisted_iocpsupport-1.0.4-cp36-cp36m-win_amd64.whl", hash = "sha256:391ac4d6002a80e15f35adc4ad6056f4fe1c17ceb0d1f98ba01b0f4f917adfd7"}, |  | ||||||
|     {file = "twisted_iocpsupport-1.0.4-cp37-cp37m-win32.whl", hash = "sha256:0c1b5cf37f0b2d96cc3c9bc86fff16613b9f5d0ca565c96cf1f1fb8cfca4b81c"}, |  | ||||||
|     {file = "twisted_iocpsupport-1.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:3c5dc11d72519e55f727320e3cee535feedfaee09c0f0765ed1ca7badff1ab3c"}, |  | ||||||
|     {file = "twisted_iocpsupport-1.0.4-cp38-cp38-win32.whl", hash = "sha256:cc86c2ef598c15d824a243c2541c29459881c67fc3c0adb6efe2242f8f0ec3af"}, |  | ||||||
|     {file = "twisted_iocpsupport-1.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:c27985e949b9b1a1fb4c20c71d315c10ea0f93fdf3ccdd4a8c158b5926edd8c8"}, |  | ||||||
|     {file = "twisted_iocpsupport-1.0.4-cp39-cp39-win32.whl", hash = "sha256:e311dfcb470696e3c077249615893cada598e62fa7c4e4ca090167bd2b7d331f"}, |  | ||||||
|     {file = "twisted_iocpsupport-1.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:4574eef1f3bb81501fb02f911298af3c02fe8179c31a33b361dd49180c3e644d"}, |  | ||||||
|     {file = "twisted_iocpsupport-1.0.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:872747a3b64e2909aee59c803ccd0bceb9b75bf27915520ebd32d69687040fa2"}, |  | ||||||
|     {file = "twisted_iocpsupport-1.0.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:c2712b778bacf1db434e3e065adfed3db300754186a29aecac1efae9ef4bcaff"}, |  | ||||||
|     {file = "twisted_iocpsupport-1.0.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7c66fa0aa4236b27b3c61cb488662d85dae746a6d1c7b0d91cf7aae118445adf"}, |  | ||||||
|     {file = "twisted_iocpsupport-1.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:300437af17396a945a58dcfffd77863303a8b6d9e65c6e81f1d2eed55b50d444"}, |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "txaio" | name = "txaio" | ||||||
| @ -4896,46 +4870,41 @@ files = [ | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "watchdog" | name = "watchdog" | ||||||
| version = "4.0.2" | version = "5.0.1" | ||||||
| description = "Filesystem events monitoring" | description = "Filesystem events monitoring" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=3.8" | python-versions = ">=3.9" | ||||||
| files = [ | files = [ | ||||||
|     {file = "watchdog-4.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ede7f010f2239b97cc79e6cb3c249e72962404ae3865860855d5cbe708b0fd22"}, |     {file = "watchdog-5.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a6b8c6c82ada78479a0df568d27d69aa07105aba9301ac66d1ae162645f4ba34"}, | ||||||
|     {file = "watchdog-4.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a2cffa171445b0efa0726c561eca9a27d00a1f2b83846dbd5a4f639c4f8ca8e1"}, |     {file = "watchdog-5.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1e8ca9b7f5f03d2f0556a43db1e9adf1e5af6adf52e0890f781324514b67a612"}, | ||||||
|     {file = "watchdog-4.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c50f148b31b03fbadd6d0b5980e38b558046b127dc483e5e4505fcef250f9503"}, |     {file = "watchdog-5.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c92812a358eabebe92b12b9290d16dc95c8003654658f6b2676c9a2103a73ceb"}, | ||||||
|     {file = "watchdog-4.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7c7d4bf585ad501c5f6c980e7be9c4f15604c7cc150e942d82083b31a7548930"}, |     {file = "watchdog-5.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a03a6ccb846ead406a25a0b702d0a6b88fdfa77becaf907cfcfce7737ebbda1f"}, | ||||||
|     {file = "watchdog-4.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:914285126ad0b6eb2258bbbcb7b288d9dfd655ae88fa28945be05a7b475a800b"}, |     {file = "watchdog-5.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:39f0de161a822402f0f00c68b82349a4d71c9814e749148ca2b083a25606dbf9"}, | ||||||
|     {file = "watchdog-4.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:984306dc4720da5498b16fc037b36ac443816125a3705dfde4fd90652d8028ef"}, |     {file = "watchdog-5.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5541a8765c4090decb4dba55d3dceb57724748a717ceaba8dc4f213edb0026e0"}, | ||||||
|     {file = "watchdog-4.0.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1cdcfd8142f604630deef34722d695fb455d04ab7cfe9963055df1fc69e6727a"}, |     {file = "watchdog-5.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e321f1561adea30e447130882efe451af519646178d04189d6ba91a8cd7d88a5"}, | ||||||
|     {file = "watchdog-4.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d7ab624ff2f663f98cd03c8b7eedc09375a911794dfea6bf2a359fcc266bff29"}, |     {file = "watchdog-5.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c4ae0b3e95455fa9d959aa3b253c87845ad454ef188a4bf5a69cab287c131216"}, | ||||||
|     {file = "watchdog-4.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:132937547a716027bd5714383dfc40dc66c26769f1ce8a72a859d6a48f371f3a"}, |     {file = "watchdog-5.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b2d56425dfa0c1e6f8a510f21d3d54ef7fe50bbc29638943c2cb1394b7b49156"}, | ||||||
|     {file = "watchdog-4.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:cd67c7df93eb58f360c43802acc945fa8da70c675b6fa37a241e17ca698ca49b"}, |     {file = "watchdog-5.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:70e30116849f4ec52240eb1fad83d27e525eae179bfe1c09b3bf120163d731b6"}, | ||||||
|     {file = "watchdog-4.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcfd02377be80ef3b6bc4ce481ef3959640458d6feaae0bd43dd90a43da90a7d"}, |     {file = "watchdog-5.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f66df2c152edf5a2fe472bb2f8a5d562165bcf6cf9686cee5d75e524c21ca895"}, | ||||||
|     {file = "watchdog-4.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:980b71510f59c884d684b3663d46e7a14b457c9611c481e5cef08f4dd022eed7"}, |     {file = "watchdog-5.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6bb68d9adb9c45f0dc1c2b12f4fb6eab0463a8f9741e371e4ede6769064e0785"}, | ||||||
|     {file = "watchdog-4.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:aa160781cafff2719b663c8a506156e9289d111d80f3387cf3af49cedee1f040"}, |     {file = "watchdog-5.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6fbb4dd5ace074a2969825fde10034b35b31efcb6973defb22eb945b1d3acc37"}, | ||||||
|     {file = "watchdog-4.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f6ee8dedd255087bc7fe82adf046f0b75479b989185fb0bdf9a98b612170eac7"}, |     {file = "watchdog-5.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:753c6a4c1eea9d3b96cd58159b49103e66cb288216a414ab9ad234ccc7642ec2"}, | ||||||
|     {file = "watchdog-4.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0b4359067d30d5b864e09c8597b112fe0a0a59321a0f331498b013fb097406b4"}, |     {file = "watchdog-5.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:20a28c8b0b3edf4ea2b27fb3527fc0a348e983f22a4317d316bb561524391932"}, | ||||||
|     {file = "watchdog-4.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:770eef5372f146997638d737c9a3c597a3b41037cfbc5c41538fc27c09c3a3f9"}, |     {file = "watchdog-5.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a1cd7c919940b15f253db8279a579fb81e4e4e434b39b11a1cb7f54fe3fa46a6"}, | ||||||
|     {file = "watchdog-4.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eeea812f38536a0aa859972d50c76e37f4456474b02bd93674d1947cf1e39578"}, |     {file = "watchdog-5.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a791dfc050ed24b82f7f100ae794192594fe863a7e9bdafcdfa5c6e405a981e5"}, | ||||||
|     {file = "watchdog-4.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b2c45f6e1e57ebb4687690c05bc3a2c1fb6ab260550c4290b8abb1335e0fd08b"}, |     {file = "watchdog-5.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8ba1472b5fa7c644e49641f70d7ccc567f70b54d776defa5d6f755dc2edc3fbb"}, | ||||||
|     {file = "watchdog-4.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:10b6683df70d340ac3279eff0b2766813f00f35a1d37515d2c99959ada8f05fa"}, |     {file = "watchdog-5.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b21e6601efe8453514c2fc21aca57fb5413c3d8b157bfe520b05b57b1788a167"}, | ||||||
|     {file = "watchdog-4.0.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:f7c739888c20f99824f7aa9d31ac8a97353e22d0c0e54703a547a218f6637eb3"}, |     {file = "watchdog-5.0.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:763c6f82bb65504b47d4aea268462b2fb662676676356e04787f332a11f03eb0"}, | ||||||
|     {file = "watchdog-4.0.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c100d09ac72a8a08ddbf0629ddfa0b8ee41740f9051429baa8e31bb903ad7508"}, |     {file = "watchdog-5.0.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:664917cd513538728875a42d5654584b533da88cf06680452c98e73b45466968"}, | ||||||
|     {file = "watchdog-4.0.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:f5315a8c8dd6dd9425b974515081fc0aadca1d1d61e078d2246509fd756141ee"}, |     {file = "watchdog-5.0.1-py3-none-manylinux2014_i686.whl", hash = "sha256:39e828c4270452b966bc9d814911a3c7e24c62d726d2a3245f5841664ff56b5e"}, | ||||||
|     {file = "watchdog-4.0.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:2d468028a77b42cc685ed694a7a550a8d1771bb05193ba7b24006b8241a571a1"}, |     {file = "watchdog-5.0.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:59ec6111f3750772badae3403ef17263489ed6f27ac01ec50c0244b2afa258fb"}, | ||||||
|     {file = "watchdog-4.0.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:f15edcae3830ff20e55d1f4e743e92970c847bcddc8b7509bcd172aa04de506e"}, |     {file = "watchdog-5.0.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f3006361dba2005552cc8aa49c44d16a10e0a1939bb3286e888a14f722122808"}, | ||||||
|     {file = "watchdog-4.0.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:936acba76d636f70db8f3c66e76aa6cb5136a936fc2a5088b9ce1c7a3508fc83"}, |     {file = "watchdog-5.0.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:72dbdffe4aa0c36c59f4a5190bceeb7fdfdf849ab98a562b3a783a64cc6dacdd"}, | ||||||
|     {file = "watchdog-4.0.2-py3-none-manylinux2014_armv7l.whl", hash = "sha256:e252f8ca942a870f38cf785aef420285431311652d871409a64e2a0a52a2174c"}, |     {file = "watchdog-5.0.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:c93aa24899cb4e8a51492c7ccc420bea45ced502fe9ef2e83f9ab1107e5a13b5"}, | ||||||
|     {file = "watchdog-4.0.2-py3-none-manylinux2014_i686.whl", hash = "sha256:0e83619a2d5d436a7e58a1aea957a3c1ccbf9782c43c0b4fed80580e5e4acd1a"}, |     {file = "watchdog-5.0.1-py3-none-win32.whl", hash = "sha256:2b8cd627b76194e725ed6f48d9524b1ad93a51a0dc3bd0225c56023716245091"}, | ||||||
|     {file = "watchdog-4.0.2-py3-none-manylinux2014_ppc64.whl", hash = "sha256:88456d65f207b39f1981bf772e473799fcdc10801062c36fd5ad9f9d1d463a73"}, |     {file = "watchdog-5.0.1-py3-none-win_amd64.whl", hash = "sha256:4eaebff2f938f5325788cef26521891b2d8ecc8e7852aa123a9b458815f93875"}, | ||||||
|     {file = "watchdog-4.0.2-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:32be97f3b75693a93c683787a87a0dc8db98bb84701539954eef991fb35f5fbc"}, |     {file = "watchdog-5.0.1-py3-none-win_ia64.whl", hash = "sha256:9b1b32f89f95162f09aea6e15d9384f6e0490152f10d7ed241f8a85cddc50658"}, | ||||||
|     {file = "watchdog-4.0.2-py3-none-manylinux2014_s390x.whl", hash = "sha256:c82253cfc9be68e3e49282831afad2c1f6593af80c0daf1287f6a92657986757"}, |     {file = "watchdog-5.0.1.tar.gz", hash = "sha256:f0180e84e6493ef7c82e051334e8c9b00ffd89fa9de5e0613d3c267f6ccf2d38"}, | ||||||
|     {file = "watchdog-4.0.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:c0b14488bd336c5b1845cee83d3e631a1f8b4e9c5091ec539406e4a324f882d8"}, |  | ||||||
|     {file = "watchdog-4.0.2-py3-none-win32.whl", hash = "sha256:0d8a7e523ef03757a5aa29f591437d64d0d894635f8a50f370fe37f913ce4e19"}, |  | ||||||
|     {file = "watchdog-4.0.2-py3-none-win_amd64.whl", hash = "sha256:c344453ef3bf875a535b0488e3ad28e341adbd5a9ffb0f7d62cefacc8824ef2b"}, |  | ||||||
|     {file = "watchdog-4.0.2-py3-none-win_ia64.whl", hash = "sha256:baececaa8edff42cd16558a639a9b0ddf425f93d892e8392a56bf904f5eff22c"}, |  | ||||||
|     {file = "watchdog-4.0.2.tar.gz", hash = "sha256:b4dfbb6c49221be4535623ea4474a4d6ee0a9cef4a80b20c28db4d858b64e270"}, |  | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [package.extras] | [package.extras] | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| [tool.poetry] | [tool.poetry] | ||||||
| name = "authentik" | name = "authentik" | ||||||
| version = "2024.6.4" | version = "2024.8.0" | ||||||
| description = "" | description = "" | ||||||
| authors = ["authentik Team <hello@goauthentik.io>"] | authors = ["authentik Team <hello@goauthentik.io>"] | ||||||
|  |  | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| openapi: 3.0.3 | openapi: 3.0.3 | ||||||
| info: | info: | ||||||
|   title: authentik |   title: authentik | ||||||
|   version: 2024.6.4 |   version: 2024.8.0 | ||||||
|   description: Making authentication simple. |   description: Making authentication simple. | ||||||
|   contact: |   contact: | ||||||
|     email: hello@goauthentik.io |     email: hello@goauthentik.io | ||||||
|  | |||||||
							
								
								
									
										4270
									
								
								tests/wdio/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4270
									
								
								tests/wdio/package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,9 +1,13 @@ | |||||||
| { | { | ||||||
|     "name": "@goauthentik/web-tests", |     "name": "@goauthentik/web-tests", | ||||||
|     "private": true, |     "dependencies": { | ||||||
|     "type": "module", |         "chromedriver": "^128.0.1", | ||||||
|  |         "lockfile-lint": "^4.14.0", | ||||||
|  |         "syncpack": "^13.0.0" | ||||||
|  |     }, | ||||||
|     "devDependencies": { |     "devDependencies": { | ||||||
|         "@trivago/prettier-plugin-sort-imports": "^4.3.0", |         "@trivago/prettier-plugin-sort-imports": "^4.3.0", | ||||||
|  |         "@types/mocha": "^10.0.7", | ||||||
|         "@typescript-eslint/eslint-plugin": "^7.17.0", |         "@typescript-eslint/eslint-plugin": "^7.17.0", | ||||||
|         "@typescript-eslint/parser": "^7.17.0", |         "@typescript-eslint/parser": "^7.17.0", | ||||||
|         "@wdio/cli": "^9.0.3", |         "@wdio/cli": "^9.0.3", | ||||||
| @ -19,19 +23,20 @@ | |||||||
|         "typescript": "^5.5.4", |         "typescript": "^5.5.4", | ||||||
|         "wdio-wait-for": "^3.0.11" |         "wdio-wait-for": "^3.0.11" | ||||||
|     }, |     }, | ||||||
|     "scripts": { |  | ||||||
|         "wdio": "wdio run ./wdio.conf.ts", |  | ||||||
|         "lint:precommit": "eslint --max-warnings 0 --config ./.eslintrc.precommit.json $(git status --porcelain . | grep '^[AM?][M?]' | cut -d'/' -f3- | grep -E '\\.(ts|js|tsx|jsx)$')", |  | ||||||
|         "lint": "eslint . --max-warnings 0 --fix", |  | ||||||
|         "lint:spelling": "codespell -D - -D $(git rev-parse --show-toplevel 2> /dev/null)/.github/codespell-dictionary.txt -I $(git rev-parse --show-toplevel 2> /dev/null)/.github/codespell-words.txt ./test -s", |  | ||||||
|         "precommit": "run-s lint:precommit lint:spelling prettier", |  | ||||||
|         "prettier-check": "prettier --check .", |  | ||||||
|         "prettier": "prettier --write ." |  | ||||||
|     }, |  | ||||||
|     "engines": { |     "engines": { | ||||||
|         "node": ">=20" |         "node": ">=20" | ||||||
|     }, |     }, | ||||||
|     "dependencies": { |     "private": true, | ||||||
|         "chromedriver": "^128.0.0" |     "scripts": { | ||||||
|     } |         "lint": "eslint . --max-warnings 0 --fix", | ||||||
|  |         "lint:lockfile": "lockfile-lint --path package.json --type npm --allowed-hosts npm --validate-https", | ||||||
|  |         "lint:package": "syncpack format -i '    '", | ||||||
|  |         "lint:precommit": "eslint --max-warnings 0 --config ./.eslintrc.precommit.json $(git status --porcelain . | grep '^[AM?][M?]' | cut -d'/' -f3- | grep -E '\\.(ts|js|tsx|jsx)$')", | ||||||
|  |         "lint:spelling": "codespell -D - -D $(git rev-parse --show-toplevel 2> /dev/null)/.github/codespell-dictionary.txt -I $(git rev-parse --show-toplevel 2> /dev/null)/.github/codespell-words.txt ./test -s", | ||||||
|  |         "precommit": "run-s lint:precommit lint:spelling prettier", | ||||||
|  |         "prettier": "prettier --write .", | ||||||
|  |         "prettier-check": "prettier --check .", | ||||||
|  |         "wdio": "wdio run ./wdio.conf.ts" | ||||||
|  |     }, | ||||||
|  |     "type": "module" | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,25 +1,11 @@ | |||||||
| import Page from "../pageobjects/page.js"; | import Page from "../pageobjects/page.js"; | ||||||
| import { browser } from "@wdio/globals"; |  | ||||||
|  |  | ||||||
| const CLICK_TIME_DELAY = 250; |  | ||||||
|  |  | ||||||
| export default class AdminPage extends Page { | export default class AdminPage extends Page { | ||||||
|     public get pageHeader() { |     public async pageHeader() { | ||||||
|         return $('>>>ak-page-header slot[name="header"]'); |         return await $("ak-page-header").$('slot[name="header"]'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async openApplicationsListPage() { |     async openApplicationsListPage() { | ||||||
|         await this.open("if/admin/#/core/applications"); |         await this.open("if/admin/#/core/applications"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public open(path: string) { |  | ||||||
|         return browser.url(`http://localhost:9000/${path}`); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public pause(selector?: string) { |  | ||||||
|         if (selector) { |  | ||||||
|             return $(selector).waitForDisplayed(); |  | ||||||
|         } |  | ||||||
|         return browser.pause(CLICK_TIME_DELAY); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -27,24 +27,24 @@ class ApplicationWizardView extends AdminPage { | |||||||
|     radius = RadiusForm; |     radius = RadiusForm; | ||||||
|     app = ApplicationForm; |     app = ApplicationForm; | ||||||
|  |  | ||||||
|     get wizardTitle() { |     async wizardTitle() { | ||||||
|         return $(">>>ak-wizard-frame .pf-c-wizard__header h1.pf-c-title"); |         return await $("ak-wizard-frame").$(".pf-c-wizard__title"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     get providerList() { |     async providerList() { | ||||||
|         return $(">>>ak-application-wizard-authentication-method-choice"); |         return await $("ak-application-wizard-authentication-method-choice"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     get nextButton() { |     async nextButton() { | ||||||
|         return $(">>>ak-wizard-frame footer button.pf-m-primary"); |         return await $("ak-wizard-frame").$("footer button.pf-m-primary"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async getProviderType(type: string) { |     async getProviderType(type: string) { | ||||||
|         return await this.providerList.$(`>>>input[value="${type}"]`); |         return await this.providerList().$(`input[value="${type}"]`); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     get successMessage() { |     async successMessage() { | ||||||
|         return $('>>>[data-commit-state="success"]'); |         return await $('[data-commit-state="success"]'); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -65,8 +65,10 @@ const providerValues: Pair[] = [ | |||||||
| providerValues.forEach(([value, name]: Pair) => { | providerValues.forEach(([value, name]: Pair) => { | ||||||
|     Object.defineProperties(ApplicationWizardView.prototype, { |     Object.defineProperties(ApplicationWizardView.prototype, { | ||||||
|         [name]: { |         [name]: { | ||||||
|             get: function () { |             get: async function () { | ||||||
|                 return this.providerList.$(`>>>input[value="${value}"]`); |                 return await ( | ||||||
|  |                     await this.providerList() | ||||||
|  |                 ).$(`div[data-ouid-component-name="${value}"]`); | ||||||
|             }, |             }, | ||||||
|         }, |         }, | ||||||
|     }); |     }); | ||||||
|  | |||||||
| @ -9,8 +9,8 @@ class ApplicationsListPage extends AdminPage { | |||||||
|      * define selectors using getter methods |      * define selectors using getter methods | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|     get startWizardButton() { |     async startWizardButton() { | ||||||
|         return $('>>>ak-wizard-frame button[slot="trigger"]'); |         return await $("ak-application-wizard").$('button[slot="trigger"]'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async open() { |     async open() { | ||||||
|  | |||||||
| @ -2,16 +2,16 @@ import Page from "../page.js"; | |||||||
| import { $ } from "@wdio/globals"; | import { $ } from "@wdio/globals"; | ||||||
|  |  | ||||||
| export class ApplicationForm extends Page { | export class ApplicationForm extends Page { | ||||||
|     get name() { |     async name() { | ||||||
|         return $('>>>ak-form-element-horizontal input[name="name"]'); |         return await $('ak-text-input[name="name"]').$("input"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     get uiSettings() { |     async uiSettings() { | ||||||
|         return $('>>>ak-form-group button[aria-label="UI Settings"]'); |         return await $("ak-form-group").$('button[aria-label="UI Settings"]'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     get launchUrl() { |     async launchUrl() { | ||||||
|         return $('>>>input[name="metaLaunchUrl"]'); |         return await $('input[name="metaLaunchUrl"]'); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -4,14 +4,14 @@ import { $ } from "@wdio/globals"; | |||||||
| export class ForwardProxyForm extends Page { | export class ForwardProxyForm extends Page { | ||||||
|     async setAuthorizationFlow(selector: string) { |     async setAuthorizationFlow(selector: string) { | ||||||
|         await this.searchSelect( |         await this.searchSelect( | ||||||
|             '>>>ak-flow-search[name="authorizationFlow"] input[type="text"]', |             'ak-flow-search[name="authorizationFlow"]', | ||||||
|             "authorizationFlow", |             "authorizationFlow", | ||||||
|             `button*=${selector}`, |             selector, | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     get externalHost() { |     get externalHost() { | ||||||
|         return $('>>>input[name="externalHost"]'); |         return $('input[name="externalHost"]'); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -1,11 +1,11 @@ | |||||||
| import Page from "../page.js"; | import Page from "../page.js"; | ||||||
|  |  | ||||||
| export class LdapForm extends Page { | export class LdapForm extends Page { | ||||||
|     async setBindFlow(selector: string) { |     async setBindFlow(_selector: string) { | ||||||
|         await this.searchSelect( |         await this.searchSelect( | ||||||
|             '>>>ak-branded-flow-search[name="authorizationFlow"] input[type="text"]', |             'ak-search-select-view[name="authorizationFlow"]', | ||||||
|             "authorizationFlow", |             "authorizationFlow", | ||||||
|             `button*=${selector}`, |             "default-authentication-flow", | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,14 +4,14 @@ import { $ } from "@wdio/globals"; | |||||||
| export class OauthForm extends Page { | export class OauthForm extends Page { | ||||||
|     async setAuthorizationFlow(selector: string) { |     async setAuthorizationFlow(selector: string) { | ||||||
|         await this.searchSelect( |         await this.searchSelect( | ||||||
|             '>>>ak-flow-search[name="authorizationFlow"] input[type="text"]', |             'ak-flow-search[name="authorizationFlow"]', | ||||||
|             "authorizationFlow", |             "authorizationFlow", | ||||||
|             `button*=${selector}`, |             `${selector}`, | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     get providerName() { |     async providerName() { | ||||||
|         return $('>>>ak-form-element-horizontal[name="name"] input'); |         return await $('ak-form-element-horizontal[name="name"]').$("input"); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -3,9 +3,9 @@ import Page from "../page.js"; | |||||||
| export class RadiusForm extends Page { | export class RadiusForm extends Page { | ||||||
|     async setAuthenticationFlow(selector: string) { |     async setAuthenticationFlow(selector: string) { | ||||||
|         await this.searchSelect( |         await this.searchSelect( | ||||||
|             '>>>ak-branded-flow-search[name="authorizationFlow"] input[type="text"]', |             'ak-branded-flow-search[name="authorizationFlow"]', | ||||||
|             "authorizationFlow", |             "authorizationFlow", | ||||||
|             `button*=${selector}`, |             selector, | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,14 +4,14 @@ import { $ } from "@wdio/globals"; | |||||||
| export class SamlForm extends Page { | export class SamlForm extends Page { | ||||||
|     async setAuthorizationFlow(selector: string) { |     async setAuthorizationFlow(selector: string) { | ||||||
|         await this.searchSelect( |         await this.searchSelect( | ||||||
|             '>>>ak-flow-search[name="authorizationFlow"] input[type="text"]', |             'ak-flow-search[name="authorizationFlow"]', | ||||||
|             "authorizationFlow", |             "authorizationFlow", | ||||||
|             `button*=${selector}`, |             selector, | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     get acsUrl() { |     get acsUrl() { | ||||||
|         return $('>>>input[name="acsUrl"]'); |         return $('input[name="acsUrl"]'); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -2,11 +2,11 @@ import Page from "../page.js"; | |||||||
|  |  | ||||||
| export class ScimForm extends Page { | export class ScimForm extends Page { | ||||||
|     get url() { |     get url() { | ||||||
|         return $('>>>input[name="url"]'); |         return $('input[name="url"]'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     get token() { |     get token() { | ||||||
|         return $('>>>input[name="token"]'); |         return $('input[name="token"]'); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -4,18 +4,18 @@ import { $ } from "@wdio/globals"; | |||||||
| export class TransparentProxyForm extends Page { | export class TransparentProxyForm extends Page { | ||||||
|     async setAuthorizationFlow(selector: string) { |     async setAuthorizationFlow(selector: string) { | ||||||
|         await this.searchSelect( |         await this.searchSelect( | ||||||
|             '>>>ak-flow-search[name="authorizationFlow"] input[type="text"]', |             'ak-flow-search[name="authorizationFlow"]', | ||||||
|             "authorizationFlow", |             "authorizationFlow", | ||||||
|             `button*=${selector}`, |             selector, | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     get externalHost() { |     get externalHost() { | ||||||
|         return $('>>>input[name="externalHost"]'); |         return $('input[name="externalHost"]'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     get internalHost() { |     get internalHost() { | ||||||
|         return $('>>>input[name="internalHost"]'); |         return $('input[name="internalHost"]'); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -9,20 +9,20 @@ class LoginPage extends Page { | |||||||
|     /** |     /** | ||||||
|      * Selectors |      * Selectors | ||||||
|      */ |      */ | ||||||
|     get inputUsername() { |     async inputUsername() { | ||||||
|         return $('>>>input[name="uidField"]'); |         return await $('input[name="uidField"]'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     get inputPassword() { |     async inputPassword() { | ||||||
|         return $('>>>input[name="password"]'); |         return await $('input[name="password"]'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     get btnSubmit() { |     async btnSubmit() { | ||||||
|         return $('>>>button[type="submit"]'); |         return await $('button[type="submit"]'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     get authFailure() { |     async authFailure() { | ||||||
|         return $(">>>h4.pf-c-alert__title"); |         return await $(".pf-m-error"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @ -30,17 +30,15 @@ class LoginPage extends Page { | |||||||
|      */ |      */ | ||||||
|  |  | ||||||
|     async username(username: string) { |     async username(username: string) { | ||||||
|         await this.inputUsername.waitForClickable(); |         await (await this.inputUsername()).setValue(username); | ||||||
|         await this.inputUsername.setValue(username); |         await (await this.btnSubmit()).waitForEnabled(); | ||||||
|         await this.btnSubmit.waitForEnabled(); |         await (await this.btnSubmit()).click(); | ||||||
|         await this.btnSubmit.click(); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async password(password: string) { |     async password(password: string) { | ||||||
|         await this.inputPassword.waitForClickable(); |         await (await this.inputPassword()).setValue(password); | ||||||
|         await this.inputPassword.setValue(password); |         await (await this.btnSubmit()).waitForEnabled(); | ||||||
|         await this.btnSubmit.waitForEnabled(); |         await (await this.btnSubmit()).click(); | ||||||
|         await this.btnSubmit.click(); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async login(username: string, password: string) { |     async login(username: string, password: string) { | ||||||
| @ -48,7 +46,7 @@ class LoginPage extends Page { | |||||||
|         await this.pause(); |         await this.pause(); | ||||||
|         await this.password(password); |         await this.password(password); | ||||||
|         await this.pause(); |         await this.pause(); | ||||||
|         await this.pause(">>>div.header h1"); |         await this.pause("div.header h1"); | ||||||
|         return UserLibraryPage; |         return UserLibraryPage; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| import { browser } from "@wdio/globals"; | import { browser } from "@wdio/globals"; | ||||||
|  | import { Key } from "webdriverio"; | ||||||
|  |  | ||||||
| const CLICK_TIME_DELAY = 250; | const CLICK_TIME_DELAY = 250; | ||||||
|  |  | ||||||
| @ -11,15 +12,15 @@ export default class Page { | |||||||
|      * Opens a sub page of the page |      * Opens a sub page of the page | ||||||
|      * @param path path of the sub page (e.g. /path/to/page.html) |      * @param path path of the sub page (e.g. /path/to/page.html) | ||||||
|      */ |      */ | ||||||
|     public open(path: string) { |     public async open(path: string) { | ||||||
|         return browser.url(`http://localhost:9000/${path}`); |         return await browser.url(`http://localhost:9000/${path}`); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public pause(selector?: string) { |     public async pause(selector?: string) { | ||||||
|         if (selector) { |         if (selector) { | ||||||
|             return $(selector).waitForDisplayed(); |             return await $(selector).waitForDisplayed(); | ||||||
|         } |         } | ||||||
|         return browser.pause(CLICK_TIME_DELAY); |         return await browser.pause(CLICK_TIME_DELAY); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @ -33,10 +34,20 @@ export default class Page { | |||||||
|  |  | ||||||
|     async searchSelect(searchSelector: string, managedSelector: string, buttonSelector: string) { |     async searchSelect(searchSelector: string, managedSelector: string, buttonSelector: string) { | ||||||
|         const inputBind = await $(searchSelector); |         const inputBind = await $(searchSelector); | ||||||
|         await inputBind.click(); |         const inputMain = await inputBind.$('input[type="text"]'); | ||||||
|         const searchBlock = await $(`>>>div[data-managed-for="${managedSelector}"]`); |         await inputMain.click(); | ||||||
|         const target = searchBlock.$(buttonSelector); |         const searchBlock = await ( | ||||||
|         return await target.click(); |             await $(`div[data-managed-for="${managedSelector}"]`).$("ak-list-select") | ||||||
|  |         ).shadow$$("button"); | ||||||
|  |         let target: WebdriverIO.Element; | ||||||
|  |         for (const button of searchBlock) { | ||||||
|  |             if ((await button.getText()).includes(buttonSelector)) { | ||||||
|  |                 target = button; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         await (await target).click(); | ||||||
|  |         await browser.keys(Key.Tab); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public async logout() { |     public async logout() { | ||||||
|  | |||||||
| @ -9,13 +9,13 @@ class UserLibraryPage extends Page { | |||||||
|      * define selectors using getter methods |      * define selectors using getter methods | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|     public get pageHeader() { |     public async pageHeader() { | ||||||
|         return $('>>>h1[aria-level="1"]'); |         return await $('h1[aria-level="1"]'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public async goToAdmin() { |     public async goToAdmin() { | ||||||
|         await $('>>>a[href="/if/admin"]').click(); |         await $('a[href="/if/admin"]').click(); | ||||||
|         await $(">>>ak-admin-overview").waitForDisplayed(); |         return await $("ak-admin-overview").waitForDisplayed(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
							
								
								
									
										15
									
								
								tests/wdio/test/specs/bad-logins-2.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								tests/wdio/test/specs/bad-logins-2.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | import LoginPage from "../pageobjects/login.page.js"; | ||||||
|  | import { BAD_PASSWORD, GOOD_USERNAME } from "../utils/constants.js"; | ||||||
|  | import { expect } from "@wdio/globals"; | ||||||
|  |  | ||||||
|  | describe("Log into authentik", () => { | ||||||
|  |     it("should fail on a bad password", async () => { | ||||||
|  |         await LoginPage.open(); | ||||||
|  |         await LoginPage.username(GOOD_USERNAME); | ||||||
|  |         await LoginPage.pause(); | ||||||
|  |         await LoginPage.password(BAD_PASSWORD); | ||||||
|  |         const failure = await LoginPage.authFailure(); | ||||||
|  |         await expect(failure).toBeDisplayedInViewport(); | ||||||
|  |         await expect(failure).toHaveText("Invalid password"); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
| @ -1,21 +1,15 @@ | |||||||
| import LoginPage from "../pageobjects/login.page.js"; | import LoginPage from "../pageobjects/login.page.js"; | ||||||
| import { BAD_PASSWORD, BAD_USERNAME, GOOD_USERNAME } from "../utils/constants.js"; | import { BAD_USERNAME, GOOD_PASSWORD } from "../utils/constants.js"; | ||||||
| import { expect } from "@wdio/globals"; | import { expect } from "@wdio/globals"; | ||||||
|  |  | ||||||
| describe("Log into authentik", () => { | describe("Log into authentik", () => { | ||||||
|     it("should fail on a bad username", async () => { |     it("should fail on a bad username", async () => { | ||||||
|         await LoginPage.open(); |         await LoginPage.open(); | ||||||
|         await LoginPage.username(BAD_USERNAME); |         await LoginPage.username(BAD_USERNAME); | ||||||
|         const failure = await LoginPage.authFailure; |  | ||||||
|         expect(failure).toHaveText("Failed to authenticate."); |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     it("should fail on a bad password", async () => { |  | ||||||
|         await LoginPage.open(); |  | ||||||
|         await LoginPage.username(GOOD_USERNAME); |  | ||||||
|         await LoginPage.pause(); |         await LoginPage.pause(); | ||||||
|         await LoginPage.password(BAD_PASSWORD); |         await LoginPage.password(GOOD_PASSWORD); | ||||||
|         const failure = await LoginPage.authFailure; |         const failure = await LoginPage.authFailure(); | ||||||
|         expect(failure).toHaveText("Failed to authenticate."); |         await expect(failure).toBeDisplayedInViewport(); | ||||||
|  |         await expect(failure).toHaveText("Invalid password"); | ||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
|  | |||||||
| @ -10,25 +10,27 @@ async function reachTheProvider(title: string) { | |||||||
|     await ApplicationsListPage.logout(); |     await ApplicationsListPage.logout(); | ||||||
|     await login(); |     await login(); | ||||||
|     await ApplicationsListPage.open(); |     await ApplicationsListPage.open(); | ||||||
|     await expect(await ApplicationsListPage.pageHeader).toHaveText("Applications"); |     await ApplicationsListPage.pause("ak-page-header"); | ||||||
|  |     await expect(await ApplicationsListPage.pageHeader()).toBeDisplayed(); | ||||||
|  |     await expect(await ApplicationsListPage.pageHeader()).toHaveText("Applications"); | ||||||
|  |  | ||||||
|     await ApplicationsListPage.startWizardButton.click(); |     await (await ApplicationsListPage.startWizardButton()).click(); | ||||||
|     await ApplicationWizardView.wizardTitle.waitForDisplayed(); |     await (await ApplicationWizardView.wizardTitle()).waitForDisplayed(); | ||||||
|     await expect(await ApplicationWizardView.wizardTitle).toHaveText("New application"); |     await expect(await ApplicationWizardView.wizardTitle()).toHaveText("New application"); | ||||||
|  |  | ||||||
|     await ApplicationWizardView.app.name.setValue(`${title} - ${newPrefix}`); |     await (await ApplicationWizardView.app.name()).setValue(`${title} - ${newPrefix}`); | ||||||
|     await ApplicationWizardView.app.uiSettings.scrollIntoView(); |     await (await ApplicationWizardView.app.uiSettings()).scrollIntoView(); | ||||||
|     await ApplicationWizardView.app.uiSettings.click(); |     await (await ApplicationWizardView.app.uiSettings()).click(); | ||||||
|     await ApplicationWizardView.app.launchUrl.scrollIntoView(); |     await (await ApplicationWizardView.app.launchUrl()).scrollIntoView(); | ||||||
|     await ApplicationWizardView.app.launchUrl.setValue("http://example.goauthentik.io"); |     await (await ApplicationWizardView.app.launchUrl()).setValue("http://example.goauthentik.io"); | ||||||
|  |  | ||||||
|     await ApplicationWizardView.nextButton.click(); |     await (await ApplicationWizardView.nextButton()).click(); | ||||||
|     return await ApplicationWizardView.pause(); |     return await ApplicationWizardView.pause(); | ||||||
| } | } | ||||||
|  |  | ||||||
| async function getCommitMessage() { | async function getCommitMessage() { | ||||||
|     await ApplicationWizardView.successMessage.waitForDisplayed(); |     await (await ApplicationWizardView.successMessage()).waitForDisplayed(); | ||||||
|     return await ApplicationWizardView.successMessage; |     return await ApplicationWizardView.successMessage(); | ||||||
| } | } | ||||||
|  |  | ||||||
| const SUCCESS_MESSAGE = "Your application has been saved"; | const SUCCESS_MESSAGE = "Your application has been saved"; | ||||||
| @ -38,97 +40,97 @@ describe("Configure Applications with the Application Wizard", () => { | |||||||
|     it("Should configure a simple LDAP Application", async () => { |     it("Should configure a simple LDAP Application", async () => { | ||||||
|         await reachTheProvider("New LDAP Application"); |         await reachTheProvider("New LDAP Application"); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.providerList.waitForDisplayed(); |         await (await ApplicationWizardView.providerList()).waitForDisplayed(); | ||||||
|         await ApplicationWizardView.ldapProvider.scrollIntoView(); |         await (await ApplicationWizardView.ldapProvider).scrollIntoView(); | ||||||
|         await ApplicationWizardView.ldapProvider.click(); |         await (await ApplicationWizardView.ldapProvider).click(); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.nextButton.click(); |         await (await ApplicationWizardView.nextButton()).click(); | ||||||
|         await ApplicationWizardView.pause(); |         await ApplicationWizardView.pause(); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.ldap.setBindFlow("default-authentication-flow"); |         await ApplicationWizardView.ldap.setBindFlow("default-authentication-flow"); | ||||||
|         await ApplicationWizardView.nextButton.click(); |         await (await ApplicationWizardView.nextButton()).click(); | ||||||
|         await ApplicationWizardView.pause(); |         await ApplicationWizardView.pause(); | ||||||
|  |  | ||||||
|         await expect(getCommitMessage()).toHaveText(SUCCESS_MESSAGE); |         await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     it("Should configure a simple Oauth2 Application", async () => { |     it("Should configure a simple Oauth2 Application", async () => { | ||||||
|         await reachTheProvider("New Oauth2 Application"); |         await reachTheProvider("New Oauth2 Application"); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.providerList.waitForDisplayed(); |         await (await ApplicationWizardView.providerList()).waitForDisplayed(); | ||||||
|         await ApplicationWizardView.oauth2Provider.scrollIntoView(); |         await (await ApplicationWizardView.oauth2Provider).scrollIntoView(); | ||||||
|         await ApplicationWizardView.oauth2Provider.click(); |         await (await ApplicationWizardView.oauth2Provider).click(); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.nextButton.click(); |         await (await ApplicationWizardView.nextButton()).click(); | ||||||
|         await ApplicationWizardView.pause(); |         await ApplicationWizardView.pause(); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.oauth.setAuthorizationFlow(EXPLICIT_CONSENT); |         await ApplicationWizardView.oauth.setAuthorizationFlow(EXPLICIT_CONSENT); | ||||||
|         await ApplicationWizardView.nextButton.click(); |         await (await ApplicationWizardView.nextButton()).click(); | ||||||
|         await ApplicationWizardView.pause(); |         await ApplicationWizardView.pause(); | ||||||
|  |  | ||||||
|         await expect(getCommitMessage()).toHaveText(SUCCESS_MESSAGE); |         await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     it("Should configure a simple SAML Application", async () => { |     it("Should configure a simple SAML Application", async () => { | ||||||
|         await reachTheProvider("New SAML Application"); |         await reachTheProvider("New SAML Application"); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.providerList.waitForDisplayed(); |         await (await ApplicationWizardView.providerList()).waitForDisplayed(); | ||||||
|         await ApplicationWizardView.samlProvider.scrollIntoView(); |         await (await ApplicationWizardView.samlProvider).scrollIntoView(); | ||||||
|         await ApplicationWizardView.samlProvider.click(); |         await (await ApplicationWizardView.samlProvider).click(); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.nextButton.click(); |         await (await ApplicationWizardView.nextButton()).click(); | ||||||
|         await ApplicationWizardView.pause(); |         await ApplicationWizardView.pause(); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.saml.setAuthorizationFlow(EXPLICIT_CONSENT); |         await ApplicationWizardView.saml.setAuthorizationFlow(EXPLICIT_CONSENT); | ||||||
|         await ApplicationWizardView.saml.acsUrl.setValue("http://example.com:8000/"); |         await ApplicationWizardView.saml.acsUrl.setValue("http://example.com:8000/"); | ||||||
|         await ApplicationWizardView.nextButton.click(); |         await (await ApplicationWizardView.nextButton()).click(); | ||||||
|         await ApplicationWizardView.pause(); |         await ApplicationWizardView.pause(); | ||||||
|  |  | ||||||
|         await expect(getCommitMessage()).toHaveText(SUCCESS_MESSAGE); |         await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     it("Should configure a simple SCIM Application", async () => { |     it("Should configure a simple SCIM Application", async () => { | ||||||
|         await reachTheProvider("New SCIM Application"); |         await reachTheProvider("New SCIM Application"); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.providerList.waitForDisplayed(); |         await (await ApplicationWizardView.providerList()).waitForDisplayed(); | ||||||
|         await ApplicationWizardView.scimProvider.scrollIntoView(); |         await (await ApplicationWizardView.scimProvider).scrollIntoView(); | ||||||
|         await ApplicationWizardView.scimProvider.click(); |         await (await ApplicationWizardView.scimProvider).click(); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.nextButton.click(); |         await (await ApplicationWizardView.nextButton()).click(); | ||||||
|         await ApplicationWizardView.pause(); |         await ApplicationWizardView.pause(); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.scim.url.setValue("http://example.com:8000/"); |         await ApplicationWizardView.scim.url.setValue("http://example.com:8000/"); | ||||||
|         await ApplicationWizardView.scim.token.setValue("a-very-basic-token"); |         await ApplicationWizardView.scim.token.setValue("a-very-basic-token"); | ||||||
|         await ApplicationWizardView.nextButton.click(); |         await (await ApplicationWizardView.nextButton()).click(); | ||||||
|         await ApplicationWizardView.pause(); |         await ApplicationWizardView.pause(); | ||||||
|  |  | ||||||
|         await expect(getCommitMessage()).toHaveText(SUCCESS_MESSAGE); |         await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     it("Should configure a simple Radius Application", async () => { |     it("Should configure a simple Radius Application", async () => { | ||||||
|         await reachTheProvider("New Radius Application"); |         await reachTheProvider("New Radius Application"); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.providerList.waitForDisplayed(); |         await (await ApplicationWizardView.providerList()).waitForDisplayed(); | ||||||
|         await ApplicationWizardView.radiusProvider.scrollIntoView(); |         await (await ApplicationWizardView.radiusProvider).scrollIntoView(); | ||||||
|         await ApplicationWizardView.radiusProvider.click(); |         await (await ApplicationWizardView.radiusProvider).click(); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.nextButton.click(); |         await (await ApplicationWizardView.nextButton()).click(); | ||||||
|         await ApplicationWizardView.pause(); |         await ApplicationWizardView.pause(); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.radius.setAuthenticationFlow("default-authentication-flow"); |         await ApplicationWizardView.radius.setAuthenticationFlow("default-authentication-flow"); | ||||||
|         await ApplicationWizardView.nextButton.click(); |         await (await ApplicationWizardView.nextButton()).click(); | ||||||
|         await ApplicationWizardView.pause(); |         await ApplicationWizardView.pause(); | ||||||
|  |  | ||||||
|         await expect(getCommitMessage()).toHaveText(SUCCESS_MESSAGE); |         await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     it("Should configure a simple Transparent Proxy Application", async () => { |     it("Should configure a simple Transparent Proxy Application", async () => { | ||||||
|         await reachTheProvider("New Transparent Proxy Application"); |         await reachTheProvider("New Transparent Proxy Application"); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.providerList.waitForDisplayed(); |         await (await ApplicationWizardView.providerList()).waitForDisplayed(); | ||||||
|         await ApplicationWizardView.proxyProviderProxy.scrollIntoView(); |         await (await ApplicationWizardView.proxyProviderProxy).scrollIntoView(); | ||||||
|         await ApplicationWizardView.proxyProviderProxy.click(); |         await (await ApplicationWizardView.proxyProviderProxy).click(); | ||||||
|         await ApplicationWizardView.nextButton.click(); |         await (await ApplicationWizardView.nextButton()).click(); | ||||||
|         await ApplicationWizardView.pause(); |         await ApplicationWizardView.pause(); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.transparentProxy.setAuthorizationFlow(EXPLICIT_CONSENT); |         await ApplicationWizardView.transparentProxy.setAuthorizationFlow(EXPLICIT_CONSENT); | ||||||
| @ -139,19 +141,19 @@ describe("Configure Applications with the Application Wizard", () => { | |||||||
|             "http://internal.example.com", |             "http://internal.example.com", | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.nextButton.click(); |         await (await ApplicationWizardView.nextButton()).click(); | ||||||
|         await ApplicationWizardView.pause(); |         await ApplicationWizardView.pause(); | ||||||
|  |  | ||||||
|         await expect(getCommitMessage()).toHaveText(SUCCESS_MESSAGE); |         await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     it("Should configure a simple Forward Proxy Application", async () => { |     it("Should configure a simple Forward Proxy Application", async () => { | ||||||
|         await reachTheProvider("New Forward Proxy Application"); |         await reachTheProvider("New Forward Proxy Application"); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.providerList.waitForDisplayed(); |         await (await ApplicationWizardView.providerList()).waitForDisplayed(); | ||||||
|         await ApplicationWizardView.proxyProviderForwardsingle.scrollIntoView(); |         await (await ApplicationWizardView.proxyProviderForwardsingle).scrollIntoView(); | ||||||
|         await ApplicationWizardView.proxyProviderForwardsingle.click(); |         await (await ApplicationWizardView.proxyProviderForwardsingle).click(); | ||||||
|         await ApplicationWizardView.nextButton.click(); |         await (await ApplicationWizardView.nextButton()).click(); | ||||||
|         await ApplicationWizardView.pause(); |         await ApplicationWizardView.pause(); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.forwardProxy.setAuthorizationFlow(EXPLICIT_CONSENT); |         await ApplicationWizardView.forwardProxy.setAuthorizationFlow(EXPLICIT_CONSENT); | ||||||
| @ -159,9 +161,9 @@ describe("Configure Applications with the Application Wizard", () => { | |||||||
|             "http://external.example.com", |             "http://external.example.com", | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|         await ApplicationWizardView.nextButton.click(); |         await (await ApplicationWizardView.nextButton()).click(); | ||||||
|         await ApplicationWizardView.pause(); |         await ApplicationWizardView.pause(); | ||||||
|  |  | ||||||
|         await expect(getCommitMessage()).toHaveText(SUCCESS_MESSAGE); |         await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE); | ||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
|  | |||||||
| @ -6,5 +6,5 @@ import { expect } from "@wdio/globals"; | |||||||
| export const login = async () => { | export const login = async () => { | ||||||
|     await LoginPage.open(); |     await LoginPage.open(); | ||||||
|     await LoginPage.login(GOOD_USERNAME, GOOD_PASSWORD); |     await LoginPage.login(GOOD_USERNAME, GOOD_PASSWORD); | ||||||
|     await expect(UserLibraryPage.pageHeader).toHaveText("My applications"); |     await expect(await UserLibraryPage.pageHeader()).toHaveText("My applications"); | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ | |||||||
|         "moduleResolution": "node", |         "moduleResolution": "node", | ||||||
|         "module": "ESNext", |         "module": "ESNext", | ||||||
|         "target": "es2022", |         "target": "es2022", | ||||||
|         "types": ["node", "@wdio/globals/types", "expect-webdriverio", "@wdio/mocha-framework"], |         "types": ["node", "@wdio/globals/types", "expect-webdriverio", "@wdio/mocha-framework", "@types/mocha"], | ||||||
|         "skipLibCheck": true, |         "skipLibCheck": true, | ||||||
|         "noEmit": true, |         "noEmit": true, | ||||||
|         "allowImportingTsExtensions": true, |         "allowImportingTsExtensions": true, | ||||||
|  | |||||||
| @ -41,6 +41,7 @@ const definitions = { | |||||||
|  |  | ||||||
| const otherFiles = [ | const otherFiles = [ | ||||||
|     ["node_modules/@patternfly/patternfly/patternfly.min.css", "."], |     ["node_modules/@patternfly/patternfly/patternfly.min.css", "."], | ||||||
|  |     ["node_modules/@patternfly/patternfly/patternfly-base.css", "."], | ||||||
|     ["node_modules/@patternfly/patternfly/assets/**", ".", "node_modules/@patternfly/patternfly/"], |     ["node_modules/@patternfly/patternfly/assets/**", ".", "node_modules/@patternfly/patternfly/"], | ||||||
|     ["src/custom.css", "."], |     ["src/custom.css", "."], | ||||||
|     ["src/common/styles/**", "."], |     ["src/common/styles/**", "."], | ||||||
| @ -79,6 +80,12 @@ const interfaces = [ | |||||||
|     ["polyfill/poly.ts", "."], |     ["polyfill/poly.ts", "."], | ||||||
| ]; | ]; | ||||||
|  |  | ||||||
|  | const extraTargets = [ | ||||||
|  |     ["sdk/index.ts", "sdk", { entryNames: "[dir]/[name]" }], | ||||||
|  |     ["sdk/user-settings.ts", "sdk/user-settings", { entryNames: "[dir]/[name]" }], | ||||||
|  |     ["sdk/flow.ts", "sdk/flow", { entryNames: "[dir]/[name]" }], | ||||||
|  | ]; | ||||||
|  |  | ||||||
| const baseArgs = { | const baseArgs = { | ||||||
|     bundle: true, |     bundle: true, | ||||||
|     write: true, |     write: true, | ||||||
| @ -101,7 +108,11 @@ function getVersion() { | |||||||
|     return version; |     return version; | ||||||
| } | } | ||||||
|  |  | ||||||
| async function buildOneSource(source, dest) { | function getAllTargets() { | ||||||
|  |     return [...interfaces, ...extraTargets]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | async function buildSingleTarget(source, dest, options) { | ||||||
|     const DIST = path.join(__dirname, "./dist", dest); |     const DIST = path.join(__dirname, "./dist", dest); | ||||||
|     console.log(`[${new Date(Date.now()).toISOString()}] Starting build for target ${source}`); |     console.log(`[${new Date(Date.now()).toISOString()}] Starting build for target ${source}`); | ||||||
|  |  | ||||||
| @ -112,6 +123,7 @@ async function buildOneSource(source, dest) { | |||||||
|             entryPoints: [`./src/${source}`], |             entryPoints: [`./src/${source}`], | ||||||
|             entryNames: `[dir]/[name]-${getVersion()}`, |             entryNames: `[dir]/[name]-${getVersion()}`, | ||||||
|             outdir: DIST, |             outdir: DIST, | ||||||
|  |             ...options, | ||||||
|         }); |         }); | ||||||
|         const end = Date.now(); |         const end = Date.now(); | ||||||
|         console.log( |         console.log( | ||||||
| @ -124,8 +136,10 @@ async function buildOneSource(source, dest) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| async function buildAuthentik(interfaces) { | async function buildTargets(targets) { | ||||||
|     await Promise.allSettled(interfaces.map(([source, dest]) => buildOneSource(source, dest))); |     await Promise.allSettled( | ||||||
|  |         targets.map(([source, dest, options]) => buildSingleTarget(source, dest, options)), | ||||||
|  |     ); | ||||||
| } | } | ||||||
|  |  | ||||||
| let timeoutId = null; | let timeoutId = null; | ||||||
| @ -135,7 +149,7 @@ function debouncedBuild() { | |||||||
|     } |     } | ||||||
|     timeoutId = setTimeout(() => { |     timeoutId = setTimeout(() => { | ||||||
|         console.clear(); |         console.clear(); | ||||||
|         buildAuthentik(interfaces); |         buildTargets(getAllTargets()); | ||||||
|     }, 250); |     }, 250); | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -143,7 +157,7 @@ if (process.argv.length > 2 && (process.argv[2] === "-h" || process.argv[2] === | |||||||
|     console.log(`Build the authentikUI |     console.log(`Build the authentikUI | ||||||
|  |  | ||||||
| options: | options: | ||||||
|   -w, --watch: Build all ${interfaces.length} interfaces |   -w, --watch: Build all ${getAllTargets().length} interfaces | ||||||
|   -p, --proxy: Build only the polyfills and the loading application |   -p, --proxy: Build only the polyfills and the loading application | ||||||
|   -h, --help: This help message |   -h, --help: This help message | ||||||
| `); | `); | ||||||
| @ -163,11 +177,11 @@ if (process.argv.length > 2 && (process.argv[2] === "-w" || process.argv[2] === | |||||||
|     }); |     }); | ||||||
| } else if (process.argv.length > 2 && (process.argv[2] === "-p" || process.argv[2] === "--proxy")) { | } else if (process.argv.length > 2 && (process.argv[2] === "-p" || process.argv[2] === "--proxy")) { | ||||||
|     // There's no watch-for-proxy, sorry. |     // There's no watch-for-proxy, sorry. | ||||||
|     await buildAuthentik( |     await buildTargets( | ||||||
|         interfaces.filter(([_, dest]) => ["standalone/loading", "."].includes(dest)), |         interfaces.filter(([_, dest]) => ["standalone/loading", "."].includes(dest)), | ||||||
|     ); |     ); | ||||||
|     process.exit(0); |     process.exit(0); | ||||||
| } else { | } else { | ||||||
|     // And the fallback: just build it. |     // And the fallback: just build it. | ||||||
|     await buildAuthentik(interfaces); |     await buildTargets(interfaces); | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										994
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										994
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -11,15 +11,15 @@ | |||||||
|         "@floating-ui/dom": "^1.6.9", |         "@floating-ui/dom": "^1.6.9", | ||||||
|         "@formatjs/intl-listformat": "^7.5.7", |         "@formatjs/intl-listformat": "^7.5.7", | ||||||
|         "@fortawesome/fontawesome-free": "^6.6.0", |         "@fortawesome/fontawesome-free": "^6.6.0", | ||||||
|         "@goauthentik/api": "^2024.6.3-1724414734", |         "@goauthentik/api": "^2024.8.0-1725367323", | ||||||
|         "@lit/context": "^1.1.2", |         "@lit/context": "^1.1.2", | ||||||
|         "@lit/localize": "^0.12.2", |         "@lit/localize": "^0.12.2", | ||||||
|         "@lit/reactive-element": "^2.0.4", |         "@lit/reactive-element": "^2.0.4", | ||||||
|         "@lit/task": "^1.0.1", |         "@lit/task": "^1.0.1", | ||||||
|         "@open-wc/lit-helpers": "^0.7.0", |         "@open-wc/lit-helpers": "^0.7.0", | ||||||
|         "@patternfly/elements": "^4.0.0", |         "@patternfly/elements": "^4.0.1", | ||||||
|         "@patternfly/patternfly": "^4.224.2", |         "@patternfly/patternfly": "^4.224.2", | ||||||
|         "@sentry/browser": "^8.26.0", |         "@sentry/browser": "^8.27.0", | ||||||
|         "@webcomponents/webcomponentsjs": "^2.8.0", |         "@webcomponents/webcomponentsjs": "^2.8.0", | ||||||
|         "base64-js": "^1.5.1", |         "base64-js": "^1.5.1", | ||||||
|         "chart.js": "^4.4.4", |         "chart.js": "^4.4.4", | ||||||
| @ -32,7 +32,7 @@ | |||||||
|         "guacamole-common-js": "^1.5.0", |         "guacamole-common-js": "^1.5.0", | ||||||
|         "lit": "^3.2.0", |         "lit": "^3.2.0", | ||||||
|         "md-front-matter": "^1.0.4", |         "md-front-matter": "^1.0.4", | ||||||
|         "mermaid": "^11.0.2", |         "mermaid": "^11.1.0", | ||||||
|         "rapidoc": "^9.3.4", |         "rapidoc": "^9.3.4", | ||||||
|         "showdown": "^2.1.0", |         "showdown": "^2.1.0", | ||||||
|         "style-mod": "^4.1.2", |         "style-mod": "^4.1.2", | ||||||
| @ -57,7 +57,7 @@ | |||||||
|         "@jeysal/storybook-addon-css-user-preferences": "^0.2.0", |         "@jeysal/storybook-addon-css-user-preferences": "^0.2.0", | ||||||
|         "@lit/localize-tools": "^0.8.0", |         "@lit/localize-tools": "^0.8.0", | ||||||
|         "@rollup/plugin-replace": "^5.0.7", |         "@rollup/plugin-replace": "^5.0.7", | ||||||
|         "@spotlightjs/spotlight": "^2.3.0", |         "@spotlightjs/spotlight": "^2.3.2", | ||||||
|         "@storybook/addon-essentials": "^8.2.9", |         "@storybook/addon-essentials": "^8.2.9", | ||||||
|         "@storybook/addon-links": "^8.2.9", |         "@storybook/addon-links": "^8.2.9", | ||||||
|         "@storybook/api": "^7.6.17", |         "@storybook/api": "^7.6.17", | ||||||
| @ -71,6 +71,7 @@ | |||||||
|         "@types/eslint__js": "^8.42.3", |         "@types/eslint__js": "^8.42.3", | ||||||
|         "@types/grecaptcha": "^3.0.9", |         "@types/grecaptcha": "^3.0.9", | ||||||
|         "@types/guacamole-common-js": "1.5.2", |         "@types/guacamole-common-js": "1.5.2", | ||||||
|  |         "@types/node": "^22.5.0", | ||||||
|         "@types/showdown": "^2.0.6", |         "@types/showdown": "^2.0.6", | ||||||
|         "@typescript-eslint/eslint-plugin": "^8.0.1", |         "@typescript-eslint/eslint-plugin": "^8.0.1", | ||||||
|         "@typescript-eslint/parser": "^8.0.1", |         "@typescript-eslint/parser": "^8.0.1", | ||||||
| @ -90,6 +91,7 @@ | |||||||
|         "github-slugger": "^2.0.0", |         "github-slugger": "^2.0.0", | ||||||
|         "glob": "^11.0.0", |         "glob": "^11.0.0", | ||||||
|         "globals": "^15.9.0", |         "globals": "^15.9.0", | ||||||
|  |         "knip": "^5.27.4", | ||||||
|         "lit-analyzer": "^2.0.3", |         "lit-analyzer": "^2.0.3", | ||||||
|         "lockfile-lint": "^4.14.0", |         "lockfile-lint": "^4.14.0", | ||||||
|         "npm-run-all": "^4.1.5", |         "npm-run-all": "^4.1.5", | ||||||
| @ -107,7 +109,7 @@ | |||||||
|         "tslib": "^2.7.0", |         "tslib": "^2.7.0", | ||||||
|         "turnstile-types": "^1.2.2", |         "turnstile-types": "^1.2.2", | ||||||
|         "typescript": "^5.5.4", |         "typescript": "^5.5.4", | ||||||
|         "typescript-eslint": "^8.2.0", |         "typescript-eslint": "^8.4.0", | ||||||
|         "vite-tsconfig-paths": "^5.0.1", |         "vite-tsconfig-paths": "^5.0.1", | ||||||
|         "wdio-wait-for": "^3.0.11", |         "wdio-wait-for": "^3.0.11", | ||||||
|         "wireit": "^0.14.8" |         "wireit": "^0.14.8" | ||||||
| @ -120,9 +122,9 @@ | |||||||
|         "@esbuild/darwin-arm64": "^0.23.0", |         "@esbuild/darwin-arm64": "^0.23.0", | ||||||
|         "@esbuild/linux-amd64": "^0.18.11", |         "@esbuild/linux-amd64": "^0.18.11", | ||||||
|         "@esbuild/linux-arm64": "^0.23.0", |         "@esbuild/linux-arm64": "^0.23.0", | ||||||
|         "@rollup/rollup-darwin-arm64": "4.21.0", |         "@rollup/rollup-darwin-arm64": "4.21.2", | ||||||
|         "@rollup/rollup-linux-arm64-gnu": "4.21.0", |         "@rollup/rollup-linux-arm64-gnu": "4.21.2", | ||||||
|         "@rollup/rollup-linux-x64-gnu": "4.21.0" |         "@rollup/rollup-linux-x64-gnu": "4.21.2" | ||||||
|     }, |     }, | ||||||
|     "private": true, |     "private": true, | ||||||
|     "scripts": { |     "scripts": { | ||||||
| @ -135,6 +137,7 @@ | |||||||
|         "extract-locales": "wireit", |         "extract-locales": "wireit", | ||||||
|         "format": "wireit", |         "format": "wireit", | ||||||
|         "lint": "wireit", |         "lint": "wireit", | ||||||
|  |         "lint:imports": "wireit", | ||||||
|         "lint:lockfile": "wireit", |         "lint:lockfile": "wireit", | ||||||
|         "lint:nightmare": "wireit", |         "lint:nightmare": "wireit", | ||||||
|         "lint:package": "wireit", |         "lint:package": "wireit", | ||||||
| @ -149,8 +152,7 @@ | |||||||
|         "storybook:build": "wireit", |         "storybook:build": "wireit", | ||||||
|         "storybook:build-import-map": "wireit", |         "storybook:build-import-map": "wireit", | ||||||
|         "test": "wireit", |         "test": "wireit", | ||||||
|         "test-view": "wireit", |         "test-watch": "wireit", | ||||||
|         "test-watch": "npx wdio run ./wdio.conf.ts --autoCompileOpts.tsNodeOpts.project=tsconfig.test.json --watch", |  | ||||||
|         "tsc": "wireit", |         "tsc": "wireit", | ||||||
|         "watch": "run-s build-locales esbuild:watch" |         "watch": "run-s build-locales esbuild:watch" | ||||||
|     }, |     }, | ||||||
| @ -250,6 +252,9 @@ | |||||||
|         "lint:components": { |         "lint:components": { | ||||||
|             "command": "lit-analyzer src" |             "command": "lit-analyzer src" | ||||||
|         }, |         }, | ||||||
|  |         "lint:imports": { | ||||||
|  |             "command": "knip --config scripts/knip.config.ts" | ||||||
|  |         }, | ||||||
|         "lint:types": { |         "lint:types": { | ||||||
|             "command": "tsc --noEmit -p .", |             "command": "tsc --noEmit -p .", | ||||||
|             "dependencies": [ |             "dependencies": [ | ||||||
| @ -330,7 +335,7 @@ | |||||||
|                 "TS_NODE_PROJECT": "tsconfig.test.json" |                 "TS_NODE_PROJECT": "tsconfig.test.json" | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         "test-view": { |         "test-watch": { | ||||||
|             "command": "wdio run ./wdio.conf.ts", |             "command": "wdio run ./wdio.conf.ts", | ||||||
|             "env": { |             "env": { | ||||||
|                 "TS_NODE_PROJECT": "tsconfig.test.json" |                 "TS_NODE_PROJECT": "tsconfig.test.json" | ||||||
|  | |||||||
| @ -14,18 +14,18 @@ | |||||||
|         "@rollup/plugin-node-resolve": "^15.2.3", |         "@rollup/plugin-node-resolve": "^15.2.3", | ||||||
|         "@rollup/plugin-swc": "^0.3.1", |         "@rollup/plugin-swc": "^0.3.1", | ||||||
|         "@swc/cli": "^0.4.0", |         "@swc/cli": "^0.4.0", | ||||||
|         "@swc/core": "^1.7.18", |         "@swc/core": "^1.7.23", | ||||||
|         "@trivago/prettier-plugin-sort-imports": "^4.3.0", |         "@trivago/prettier-plugin-sort-imports": "^4.3.0", | ||||||
|         "@types/jquery": "^3.5.30", |         "@types/jquery": "^3.5.30", | ||||||
|         "lockfile-lint": "^4.14.0", |         "lockfile-lint": "^4.14.0", | ||||||
|         "prettier": "^3.3.2", |         "prettier": "^3.3.2", | ||||||
|         "rollup": "^4.21.0", |         "rollup": "^4.21.2", | ||||||
|         "rollup-plugin-copy": "^3.5.0", |         "rollup-plugin-copy": "^3.5.0", | ||||||
|         "wireit": "^0.14.8" |         "wireit": "^0.14.8" | ||||||
|     }, |     }, | ||||||
|     "license": "MIT", |     "license": "MIT", | ||||||
|     "optionalDependencies": { |     "optionalDependencies": { | ||||||
|         "@swc/core": "^1.7.18", |         "@swc/core": "^1.7.23", | ||||||
|         "@swc/core-darwin-arm64": "^1.6.13", |         "@swc/core-darwin-arm64": "^1.6.13", | ||||||
|         "@swc/core-darwin-x64": "^1.6.13", |         "@swc/core-darwin-x64": "^1.6.13", | ||||||
|         "@swc/core-linux-arm-gnueabihf": "^1.6.13", |         "@swc/core-linux-arm-gnueabihf": "^1.6.13", | ||||||
|  | |||||||
							
								
								
									
										48
									
								
								web/scripts/knip.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								web/scripts/knip.config.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | |||||||
|  | import { type KnipConfig } from "knip"; | ||||||
|  |  | ||||||
|  | const config: KnipConfig = { | ||||||
|  |     "entry": [ | ||||||
|  |         "./src/admin/AdminInterface/AdminInterface.ts", | ||||||
|  |         "./src/user/UserInterface.ts", | ||||||
|  |         "./src/flow/FlowInterface.ts", | ||||||
|  |         "./src/standalone/api-browser/index.ts", | ||||||
|  |         "./src/enterprise/rac/index.ts", | ||||||
|  |         "./src/standalone/loading/index.ts", | ||||||
|  |         "./src/polyfill/poly.ts", | ||||||
|  |     ], | ||||||
|  |     "project": ["src/**/*.ts", "src/**/*.js", "./scripts/*.mjs", ".storybook/*.ts"], | ||||||
|  |     // "ignore": ["src/**/*.test.ts", "src/**/*.stories.ts"], | ||||||
|  |     // Prevent Knip from complaining about web components, which export their classes but also | ||||||
|  |     // export their registration, and we don't always use both. | ||||||
|  |     "ignoreExportsUsedInFile": true, | ||||||
|  |     "typescript": { | ||||||
|  |         config: ["tsconfig.json"], | ||||||
|  |     }, | ||||||
|  |     "wireit": { | ||||||
|  |         config: ["package.json"], | ||||||
|  |     }, | ||||||
|  |     "storybook": { | ||||||
|  |         config: [".storybook/{main,test-runner}.{js,ts}"], | ||||||
|  |         entry: [ | ||||||
|  |             ".storybook/{manager,preview}.{js,jsx,ts,tsx}", | ||||||
|  |             "**/*.@(mdx|stories.@(mdx|js|jsx|mjs|ts|tsx))", | ||||||
|  |         ], | ||||||
|  |         project: [".storybook/**/*.{js,jsx,ts,tsx}"], | ||||||
|  |     }, | ||||||
|  |     "eslint": { | ||||||
|  |         entry: [ | ||||||
|  |             "eslint.config.mjs", | ||||||
|  |             "scripts/eslint.precommit.mjs", | ||||||
|  |             "scripts/eslint.nightmare.mjs", | ||||||
|  |             "scripts/eslint-precommit.mjs", | ||||||
|  |             "scripts/eslint-nightmare.mjs", | ||||||
|  |             "scripts/eslint.mjs", | ||||||
|  |         ], | ||||||
|  |         config: ["package.json"], | ||||||
|  |     }, | ||||||
|  |     "webdriver-io": { | ||||||
|  |         config: ["wdio.conf.js"], | ||||||
|  |     }, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export default config; | ||||||
							
								
								
									
										3057
									
								
								web/sfe/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										3057
									
								
								web/sfe/package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,28 +0,0 @@ | |||||||
| { |  | ||||||
|     "name": "@goauthentik/web-sfe", |  | ||||||
|     "version": "0.0.0", |  | ||||||
|     "private": true, |  | ||||||
|     "license": "MIT", |  | ||||||
|     "dependencies": { |  | ||||||
|         "@goauthentik/api": "^2024.6.3-1724414734", |  | ||||||
|         "base64-js": "^1.5.1", |  | ||||||
|         "bootstrap": "^4.6.1", |  | ||||||
|         "formdata-polyfill": "^4.0.10", |  | ||||||
|         "jquery": "^3.7.1", |  | ||||||
|         "weakmap-polyfill": "^2.0.4" |  | ||||||
|     }, |  | ||||||
|     "scripts": { |  | ||||||
|         "build": "rollup -c rollup.config.js --bundleConfigAsCjs", |  | ||||||
|         "watch": "rollup -w -c rollup.config.js --bundleConfigAsCjs" |  | ||||||
|     }, |  | ||||||
|     "devDependencies": { |  | ||||||
|         "@rollup/plugin-commonjs": "^26.0.1", |  | ||||||
|         "@rollup/plugin-node-resolve": "^15.2.3", |  | ||||||
|         "@rollup/plugin-swc": "^0.3.1", |  | ||||||
|         "@swc/cli": "^0.4.0", |  | ||||||
|         "@swc/core": "^1.7.18", |  | ||||||
|         "@types/jquery": "^3.5.30", |  | ||||||
|         "rollup": "^4.21.0", |  | ||||||
|         "rollup-plugin-copy": "^3.5.0" |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -21,10 +21,20 @@ export class ApplicationWizardAuthenticationMethodChoice extends WithLicenseSumm | |||||||
|         const selectedTypes = providerModelsList.filter( |         const selectedTypes = providerModelsList.filter( | ||||||
|             (t) => t.formName === this.wizard.providerModel, |             (t) => t.formName === this.wizard.providerModel, | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|  |         // As a hack, the Application wizard has separate provider paths for our three types of | ||||||
|  |         // proxy providers. This patch swaps the form we want to be directed to on page 3 from the | ||||||
|  |         // modelName to the formName, so we get the right one.  This information isn't modified | ||||||
|  |         // or forwarded, so the proxy-plus-subtype is correctly mapped on submission. | ||||||
|  |         const typesForWizard = providerModelsList.map((provider) => ({ | ||||||
|  |             ...provider, | ||||||
|  |             modelName: provider.formName, | ||||||
|  |         })); | ||||||
|  |  | ||||||
|         return providerModelsList.length > 0 |         return providerModelsList.length > 0 | ||||||
|             ? html`<form class="pf-c-form pf-m-horizontal"> |             ? html`<form class="pf-c-form pf-m-horizontal"> | ||||||
|                   <ak-wizard-page-type-create |                   <ak-wizard-page-type-create | ||||||
|                       .types=${providerModelsList} |                       .types=${typesForWizard} | ||||||
|                       layout=${TypeCreateWizardPageLayouts.grid} |                       layout=${TypeCreateWizardPageLayouts.grid} | ||||||
|                       .selectedType=${selectedTypes.length > 0 ? selectedTypes[0] : undefined} |                       .selectedType=${selectedTypes.length > 0 ? selectedTypes[0] : undefined} | ||||||
|                       @select=${(ev: CustomEvent<LocalTypeCreate>) => { |                       @select=${(ev: CustomEvent<LocalTypeCreate>) => { | ||||||
|  | |||||||
| @ -265,7 +265,7 @@ export class ApplicationWizardAuthenticationByOauth extends BaseProviderPanel { | |||||||
|                         > |                         > | ||||||
|                             <ak-dual-select-provider |                             <ak-dual-select-provider | ||||||
|                                 .provider=${oauth2SourcesProvider} |                                 .provider=${oauth2SourcesProvider} | ||||||
|                                 .selected=${provider?.jwksSources} |                                 .selected=${provider?.jwksSources ?? []} | ||||||
|                                 available-label=${msg("Available Sources")} |                                 available-label=${msg("Available Sources")} | ||||||
|                                 selected-label=${msg("Selected Sources")} |                                 selected-label=${msg("Selected Sources")} | ||||||
|                             ></ak-dual-select-provider> |                             ></ak-dual-select-provider> | ||||||
|  | |||||||
| @ -230,7 +230,7 @@ export class AkTypeProxyApplicationWizardPage extends BaseProviderPanel { | |||||||
|                         > |                         > | ||||||
|                             <ak-dual-select-provider |                             <ak-dual-select-provider | ||||||
|                                 .provider=${oauth2SourcesProvider} |                                 .provider=${oauth2SourcesProvider} | ||||||
|                                 .selected=${this.instance?.jwksSources} |                                 .selected=${this.instance?.jwksSources ?? []} | ||||||
|                                 available-label=${msg("Available Sources")} |                                 available-label=${msg("Available Sources")} | ||||||
|                                 selected-label=${msg("Selected Sources")} |                                 selected-label=${msg("Selected Sources")} | ||||||
|                             ></ak-dual-select-provider> |                             ></ak-dual-select-provider> | ||||||
|  | |||||||
| @ -97,7 +97,8 @@ export class OutpostForm extends ModelForm<Outpost, string> { | |||||||
|     embedded = false; |     embedded = false; | ||||||
|  |  | ||||||
|     @state() |     @state() | ||||||
|     providers?: DataProvider; |     providers: DataProvider = providerProvider(this.type); | ||||||
|  |  | ||||||
|     defaultConfig?: OutpostDefaultConfig; |     defaultConfig?: OutpostDefaultConfig; | ||||||
|  |  | ||||||
|     async loadInstance(pk: string): Promise<Outpost> { |     async loadInstance(pk: string): Promise<Outpost> { | ||||||
| @ -113,6 +114,7 @@ export class OutpostForm extends ModelForm<Outpost, string> { | |||||||
|         this.defaultConfig = await new OutpostsApi( |         this.defaultConfig = await new OutpostsApi( | ||||||
|             DEFAULT_CONFIG, |             DEFAULT_CONFIG, | ||||||
|         ).outpostsInstancesDefaultSettingsRetrieve(); |         ).outpostsInstancesDefaultSettingsRetrieve(); | ||||||
|  |         this.providers = providerProvider(this.type); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     getSuccessMessage(): string { |     getSuccessMessage(): string { | ||||||
|  | |||||||
| @ -117,7 +117,7 @@ export class EventMatcherPolicyForm extends BasePolicyForm<EventMatcherPolicy> { | |||||||
|                         /> |                         /> | ||||||
|                         <p class="pf-c-form__helper-text"> |                         <p class="pf-c-form__helper-text"> | ||||||
|                             ${msg( |                             ${msg( | ||||||
|                                 "Matches Event's Client IP (strict matching, for network matching use an Expression Policy.", |                                 "Matches Event's Client IP (strict matching, for network matching use an Expression Policy).", | ||||||
|                             )} |                             )} | ||||||
|                         </p> |                         </p> | ||||||
|                     </ak-form-element-horizontal> |                     </ak-form-element-horizontal> | ||||||
|  | |||||||
| @ -7,6 +7,9 @@ export function renderSourceIcon(name: string, iconUrl: string | undefined | nul | |||||||
|             const url = iconUrl.replaceAll("fa://", ""); |             const url = iconUrl.replaceAll("fa://", ""); | ||||||
|             return html`<i class="fas ${url}" title="${name}"></i>`; |             return html`<i class="fas ${url}" title="${name}"></i>`; | ||||||
|         } |         } | ||||||
|  |         if (window.authentik_sdk?.base) { | ||||||
|  |             return html`<img src="${window.authentik_sdk?.base}${iconUrl}" alt="${name}" />`; | ||||||
|  |         } | ||||||
|         return html`<img src="${iconUrl}" alt="${name}" />`; |         return html`<img src="${iconUrl}" alt="${name}" />`; | ||||||
|     } |     } | ||||||
|     return icon; |     return icon; | ||||||
|  | |||||||
| @ -46,7 +46,8 @@ async function makeSourcesSelector(instanceSources: string[] | undefined) { | |||||||
|  |  | ||||||
|     return localSources |     return localSources | ||||||
|         ? ([pk, _]: DualSelectPair) => localSources.has(pk) |         ? ([pk, _]: DualSelectPair) => localSources.has(pk) | ||||||
|         : ([_0, _1, _2, source]: DualSelectPair<Source>) => |         : // Creating a new instance, auto-select built-in source only when no other sources exist | ||||||
|  |           ([_0, _1, _2, source]: DualSelectPair<Source>) => | ||||||
|               source !== undefined && source.component === ""; |               source !== undefined && source.component === ""; | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -75,11 +76,11 @@ export class IdentificationStageForm extends BaseStageForm<IdentificationStage> | |||||||
|                 stageUuid: this.instance.pk || "", |                 stageUuid: this.instance.pk || "", | ||||||
|                 identificationStageRequest: data, |                 identificationStageRequest: data, | ||||||
|             }); |             }); | ||||||
|         } else { |  | ||||||
|             return new StagesApi(DEFAULT_CONFIG).stagesIdentificationCreate({ |  | ||||||
|                 identificationStageRequest: data, |  | ||||||
|             }); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         return new StagesApi(DEFAULT_CONFIG).stagesIdentificationCreate({ | ||||||
|  |             identificationStageRequest: data, | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     isUserFieldSelected(field: UserFieldsEnum): boolean { |     isUserFieldSelected(field: UserFieldsEnum): boolean { | ||||||
| @ -232,12 +233,12 @@ export class IdentificationStageForm extends BaseStageForm<IdentificationStage> | |||||||
|                         ?required=${true} |                         ?required=${true} | ||||||
|                         name="sources" |                         name="sources" | ||||||
|                     > |                     > | ||||||
|                         <ak-dual-select-provider-dynamic-selected |                         <ak-dual-select-dynamic-selected | ||||||
|                             .provider=${sourcesProvider} |                             .provider=${sourcesProvider} | ||||||
|                             .selected=${makeSourcesSelector(this.instance?.sources)} |                             .selector=${makeSourcesSelector(this.instance?.sources)} | ||||||
|                             available-label="${msg("Available Stages")}" |                             available-label="${msg("Available Stages")}" | ||||||
|                             selected-label="${msg("Selected Stages")}" |                             selected-label="${msg("Selected Stages")}" | ||||||
|                         ></ak-dual-select-provider-dynamic-selected> |                         ></ak-dual-select-dynamic-selected> | ||||||
|                         <p class="pf-c-form__helper-text"> |                         <p class="pf-c-form__helper-text"> | ||||||
|                             ${msg( |                             ${msg( | ||||||
|                                 "Select sources should be shown for users to authenticate with. This only affects web-based sources, not LDAP.", |                                 "Select sources should be shown for users to authenticate with. This only affects web-based sources, not LDAP.", | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ import { | |||||||
|     CSRFMiddleware, |     CSRFMiddleware, | ||||||
|     EventMiddleware, |     EventMiddleware, | ||||||
|     LoggingMiddleware, |     LoggingMiddleware, | ||||||
|  |     SDKMiddleware, | ||||||
| } from "@goauthentik/common/api/middleware"; | } from "@goauthentik/common/api/middleware"; | ||||||
| import { EVENT_LOCALE_REQUEST, VERSION } from "@goauthentik/common/constants"; | import { EVENT_LOCALE_REQUEST, VERSION } from "@goauthentik/common/constants"; | ||||||
| import { globalAK } from "@goauthentik/common/global"; | import { globalAK } from "@goauthentik/common/global"; | ||||||
| @ -67,8 +68,18 @@ export function getMetaContent(key: string): string { | |||||||
|     return metaEl.content; |     return metaEl.content; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export function apiBase(): string { | ||||||
|  |     if (process.env.AK_API_BASE_PATH) { | ||||||
|  |         return process.env.AK_API_BASE_PATH; | ||||||
|  |     } | ||||||
|  |     if (window.authentik_sdk?.base) { | ||||||
|  |         return window.authentik_sdk?.base; | ||||||
|  |     } | ||||||
|  |     return window.location.origin; | ||||||
|  | } | ||||||
|  |  | ||||||
| export const DEFAULT_CONFIG = new Configuration({ | export const DEFAULT_CONFIG = new Configuration({ | ||||||
|     basePath: (process.env.AK_API_BASE_PATH || window.location.origin) + "/api/v3", |     basePath: `${apiBase()}/api/v3`, | ||||||
|     headers: { |     headers: { | ||||||
|         "sentry-trace": getMetaContent("sentry-trace"), |         "sentry-trace": getMetaContent("sentry-trace"), | ||||||
|     }, |     }, | ||||||
| @ -76,6 +87,7 @@ export const DEFAULT_CONFIG = new Configuration({ | |||||||
|         new CSRFMiddleware(), |         new CSRFMiddleware(), | ||||||
|         new EventMiddleware(), |         new EventMiddleware(), | ||||||
|         new LoggingMiddleware(globalAK().brand), |         new LoggingMiddleware(globalAK().brand), | ||||||
|  |         new SDKMiddleware(), | ||||||
|     ], |     ], | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | |||||||
| @ -44,6 +44,21 @@ export class CSRFMiddleware implements Middleware { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export class SDKMiddleware implements Middleware { | ||||||
|  |     token?: string; | ||||||
|  |     constructor() { | ||||||
|  |         this.token = window.authentik_sdk?.token; | ||||||
|  |     } | ||||||
|  |     pre?(context: RequestContext): Promise<FetchParams | void> { | ||||||
|  |         if (this.token) { | ||||||
|  |             context.init.credentials = "include"; | ||||||
|  |             // @ts-ignore | ||||||
|  |             context.init.headers["Authorization"] = `Bearer ${this.token}`; | ||||||
|  |         } | ||||||
|  |         return Promise.resolve(context); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| export class EventMiddleware implements Middleware { | export class EventMiddleware implements Middleware { | ||||||
|     post?(context: ResponseContext): Promise<Response | void> { |     post?(context: ResponseContext): Promise<Response | void> { | ||||||
|         const request: RequestInfo = { |         const request: RequestInfo = { | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ export const SUCCESS_CLASS = "pf-m-success"; | |||||||
| export const ERROR_CLASS = "pf-m-danger"; | export const ERROR_CLASS = "pf-m-danger"; | ||||||
| export const PROGRESS_CLASS = "pf-m-in-progress"; | export const PROGRESS_CLASS = "pf-m-in-progress"; | ||||||
| export const CURRENT_CLASS = "pf-m-current"; | export const CURRENT_CLASS = "pf-m-current"; | ||||||
| export const VERSION = "2024.6.4"; | export const VERSION = "2024.8.0"; | ||||||
| export const TITLE_DEFAULT = "authentik"; | export const TITLE_DEFAULT = "authentik"; | ||||||
| export const ROUTE_SEPARATOR = ";"; | export const ROUTE_SEPARATOR = ";"; | ||||||
|  |  | ||||||
|  | |||||||
| @ -1,4 +1,11 @@ | |||||||
| import { Config, ConfigFromJSON, CurrentBrand, CurrentBrandFromJSON } from "@goauthentik/api"; | import { | ||||||
|  |     Config, | ||||||
|  |     ConfigFromJSON, | ||||||
|  |     CurrentBrand, | ||||||
|  |     CurrentBrandFromJSON, | ||||||
|  |     ErrorReportingConfigFromJSON, | ||||||
|  |     UiThemeEnum, | ||||||
|  | } from "@goauthentik/api"; | ||||||
|  |  | ||||||
| export interface GlobalAuthentik { | export interface GlobalAuthentik { | ||||||
|     _converted?: boolean; |     _converted?: boolean; | ||||||
| @ -28,9 +35,12 @@ export function globalAK(): GlobalAuthentik { | |||||||
|         return { |         return { | ||||||
|             config: ConfigFromJSON({ |             config: ConfigFromJSON({ | ||||||
|                 capabilities: [], |                 capabilities: [], | ||||||
|  |                 error_reporting: ErrorReportingConfigFromJSON({}), | ||||||
|             }), |             }), | ||||||
|             brand: CurrentBrandFromJSON({ |             brand: CurrentBrandFromJSON({ | ||||||
|  |                 matched_domain: window.location.host, | ||||||
|                 ui_footer_links: [], |                 ui_footer_links: [], | ||||||
|  |                 ui_theme: window.authentik_sdk?.forceTheme ?? UiThemeEnum.Automatic, | ||||||
|             }), |             }), | ||||||
|             versionFamily: "", |             versionFamily: "", | ||||||
|             versionSubdomain: "", |             versionSubdomain: "", | ||||||
| @ -40,6 +50,10 @@ export function globalAK(): GlobalAuthentik { | |||||||
|     return ak; |     return ak; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export function isEmbedded() { | ||||||
|  |     return !!window.authentik_sdk; | ||||||
|  | } | ||||||
|  |  | ||||||
| export function docLink(path: string): string { | export function docLink(path: string): string { | ||||||
|     const ak = globalAK(); |     const ak = globalAK(); | ||||||
|     // Default case or beta build which should always point to latest |     // Default case or beta build which should always point to latest | ||||||
|  | |||||||
| @ -21,9 +21,12 @@ export class WebsocketClient { | |||||||
|  |  | ||||||
|     connect(): void { |     connect(): void { | ||||||
|         if (navigator.webdriver) return; |         if (navigator.webdriver) return; | ||||||
|         const wsUrl = `${window.location.protocol.replace("http", "ws")}//${ |         let wsUrl = `${window.location.protocol.replace("http", "ws")}//${ | ||||||
|             window.location.host |             window.location.host | ||||||
|         }/ws/client/`; |         }/ws/client/`; | ||||||
|  |         if (window.authentik_sdk?.base) { | ||||||
|  |             wsUrl = `${window.authentik_sdk?.base.replace("http", "ws")}/ws/client/`; | ||||||
|  |         } | ||||||
|         this.messageSocket = new WebSocket(wsUrl); |         this.messageSocket = new WebSocket(wsUrl); | ||||||
|         this.messageSocket.addEventListener("open", () => { |         this.messageSocket.addEventListener("open", () => { | ||||||
|             console.debug(`authentik/ws: connected to ${wsUrl}`); |             console.debug(`authentik/ws: connected to ${wsUrl}`); | ||||||
|  | |||||||
| @ -1,10 +1,11 @@ | |||||||
|  | import { isEmbedded } from "@goauthentik/common/global"; | ||||||
| import { UIConfig, uiConfig } from "@goauthentik/common/ui/config"; | import { UIConfig, uiConfig } from "@goauthentik/common/ui/config"; | ||||||
| import { ModalOrchestrationController } from "@goauthentik/elements/controllers/ModalOrchestrationController.js"; | import { ModalOrchestrationController } from "@goauthentik/elements/controllers/ModalOrchestrationController.js"; | ||||||
| import { ensureCSSStyleSheet } from "@goauthentik/elements/utils/ensureCSSStyleSheet"; | import { ensureCSSStyleSheet } from "@goauthentik/elements/utils/ensureCSSStyleSheet"; | ||||||
|  |  | ||||||
| import { state } from "lit/decorators.js"; | import { state } from "lit/decorators.js"; | ||||||
|  |  | ||||||
| import PFBase from "@patternfly/patternfly/patternfly-base.css"; | import PFVariables from "@patternfly/patternfly/base/patternfly-variables.css"; | ||||||
|  |  | ||||||
| import type { Config, CurrentBrand, LicenseSummary } from "@goauthentik/api"; | import type { Config, CurrentBrand, LicenseSummary } from "@goauthentik/api"; | ||||||
| import { UiThemeEnum } from "@goauthentik/api"; | import { UiThemeEnum } from "@goauthentik/api"; | ||||||
| @ -43,7 +44,10 @@ export class Interface extends AKElement implements AkInterface { | |||||||
|  |  | ||||||
|     constructor() { |     constructor() { | ||||||
|         super(); |         super(); | ||||||
|         document.adoptedStyleSheets = [...document.adoptedStyleSheets, ensureCSSStyleSheet(PFBase)]; |         document.adoptedStyleSheets = [ | ||||||
|  |             ...document.adoptedStyleSheets, | ||||||
|  |             ensureCSSStyleSheet(PFVariables), | ||||||
|  |         ]; | ||||||
|         this[brandContext] = new BrandContextController(this); |         this[brandContext] = new BrandContextController(this); | ||||||
|         this[configContext] = new ConfigContextController(this); |         this[configContext] = new ConfigContextController(this); | ||||||
|         this[modalController] = new ModalOrchestrationController(this); |         this[modalController] = new ModalOrchestrationController(this); | ||||||
| @ -61,7 +65,9 @@ export class Interface extends AKElement implements AkInterface { | |||||||
|         // Instead of calling ._activateTheme() twice, we insert the root document in the call |         // Instead of calling ._activateTheme() twice, we insert the root document in the call | ||||||
|         // since multiple calls to ._activateTheme() would not do anything after the first call |         // since multiple calls to ._activateTheme() would not do anything after the first call | ||||||
|         // as the theme is already enabled. |         // as the theme is already enabled. | ||||||
|         roots.unshift(document as unknown as DocumentOrShadowRoot); |         if (!isEmbedded()) { | ||||||
|  |             roots.unshift(document as unknown as DocumentOrShadowRoot); | ||||||
|  |         } | ||||||
|         super._activateTheme(theme, ...roots); |         super._activateTheme(theme, ...roots); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | |||||||
| @ -50,3 +50,9 @@ export class AkDualSelectDynamic extends AkDualSelectProvider { | |||||||
|         ></ak-dual-select>`; |         ></ak-dual-select>`; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | declare global { | ||||||
|  |     interface HTMLElementTagNameMap { | ||||||
|  |         "ak-dual-select-dynamic-selected": AkDualSelectDynamic; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
| @ -69,9 +69,19 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     renderGrid(): TemplateResult { |     renderGrid(): TemplateResult { | ||||||
|         return html`<div class="pf-l-grid pf-m-gutter"> |         return html`<div | ||||||
|  |             class="pf-l-grid pf-m-gutter" | ||||||
|  |             data-ouid-component-type="ak-type-create-grid" | ||||||
|  |         > | ||||||
|             ${this.types.map((type, idx) => { |             ${this.types.map((type, idx) => { | ||||||
|                 const requiresEnterprise = type.requiresEnterprise && !this.hasEnterpriseLicense; |                 const requiresEnterprise = type.requiresEnterprise && !this.hasEnterpriseLicense; | ||||||
|  |  | ||||||
|  |                 // It's valid to pass in a local modelName or the full name with application | ||||||
|  |                 // part.  If the latter, we only want the part after the dot to appear as our | ||||||
|  |                 // OUIA tag for test automation. | ||||||
|  |                 const componentName = type.modelName.includes(".") | ||||||
|  |                     ? (type.modelName.split(".")[1] ?? "--unknown--") | ||||||
|  |                     : type.modelName; | ||||||
|                 return html`<div |                 return html`<div | ||||||
|                     class="pf-l-grid__item pf-m-3-col pf-c-card ${requiresEnterprise |                     class="pf-l-grid__item pf-m-3-col pf-c-card ${requiresEnterprise | ||||||
|                         ? "pf-m-non-selectable-raised" |                         ? "pf-m-non-selectable-raised" | ||||||
| @ -79,6 +89,8 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) { | |||||||
|                         ? "pf-m-selected-raised" |                         ? "pf-m-selected-raised" | ||||||
|                         : ""}" |                         : ""}" | ||||||
|                     tabindex=${idx} |                     tabindex=${idx} | ||||||
|  |                     data-ouid-component-type="ak-type-create-grid-card" | ||||||
|  |                     data-ouid-component-name=${componentName} | ||||||
|                     @click=${() => { |                     @click=${() => { | ||||||
|                         if (requiresEnterprise) { |                         if (requiresEnterprise) { | ||||||
|                             return; |                             return; | ||||||
| @ -107,10 +119,17 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     renderList(): TemplateResult { |     renderList(): TemplateResult { | ||||||
|         return html`<form class="pf-c-form pf-m-horizontal"> |         return html`<form | ||||||
|  |             class="pf-c-form pf-m-horizontal" | ||||||
|  |             data-ouid-component-type="ak-type-create-list" | ||||||
|  |         > | ||||||
|             ${this.types.map((type) => { |             ${this.types.map((type) => { | ||||||
|                 const requiresEnterprise = type.requiresEnterprise && !this.hasEnterpriseLicense; |                 const requiresEnterprise = type.requiresEnterprise && !this.hasEnterpriseLicense; | ||||||
|                 return html`<div class="pf-c-radio"> |                 return html`<div | ||||||
|  |                     class="pf-c-radio" | ||||||
|  |                     data-ouid-component-type="ak-type-create-list-card" | ||||||
|  |                     data-ouid-component-name=${type.modelName.split(".")[1] ?? "--unknown--"} | ||||||
|  |                 > | ||||||
|                     <input |                     <input | ||||||
|                         class="pf-c-radio__input" |                         class="pf-c-radio__input" | ||||||
|                         type="radio" |                         type="radio" | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ import { | |||||||
|     EVENT_FLOW_INSPECTOR_TOGGLE, |     EVENT_FLOW_INSPECTOR_TOGGLE, | ||||||
|     TITLE_DEFAULT, |     TITLE_DEFAULT, | ||||||
| } from "@goauthentik/common/constants"; | } from "@goauthentik/common/constants"; | ||||||
| import { globalAK } from "@goauthentik/common/global"; | import { globalAK, isEmbedded } from "@goauthentik/common/global"; | ||||||
| import { configureSentry } from "@goauthentik/common/sentry"; | import { configureSentry } from "@goauthentik/common/sentry"; | ||||||
| import { first } from "@goauthentik/common/utils"; | import { first } from "@goauthentik/common/utils"; | ||||||
| import { WebsocketClient } from "@goauthentik/common/ws"; | import { WebsocketClient } from "@goauthentik/common/ws"; | ||||||
| @ -84,6 +84,7 @@ export class FlowExecutor extends Interface implements StageHost { | |||||||
|         return [PFBase, PFLogin, PFDrawer, PFButton, PFTitle, PFList, PFBackgroundImage].concat(css` |         return [PFBase, PFLogin, PFDrawer, PFButton, PFTitle, PFList, PFBackgroundImage].concat(css` | ||||||
|             :host { |             :host { | ||||||
|                 --pf-c-login__main-body--PaddingBottom: var(--pf-global--spacer--2xl); |                 --pf-c-login__main-body--PaddingBottom: var(--pf-global--spacer--2xl); | ||||||
|  |                 position: relative; | ||||||
|             } |             } | ||||||
|             .pf-c-background-image::before { |             .pf-c-background-image::before { | ||||||
|                 --pf-c-background-image--BackgroundImage: var(--ak-flow-background); |                 --pf-c-background-image--BackgroundImage: var(--ak-flow-background); | ||||||
| @ -95,9 +96,6 @@ export class FlowExecutor extends Interface implements StageHost { | |||||||
|             .ak-hidden { |             .ak-hidden { | ||||||
|                 display: none; |                 display: none; | ||||||
|             } |             } | ||||||
|             :host { |  | ||||||
|                 position: relative; |  | ||||||
|             } |  | ||||||
|             .pf-c-drawer__content { |             .pf-c-drawer__content { | ||||||
|                 background-color: transparent; |                 background-color: transparent; | ||||||
|             } |             } | ||||||
| @ -262,10 +260,13 @@ export class FlowExecutor extends Interface implements StageHost { | |||||||
|         this.challenge = challenge as ChallengeTypes; |         this.challenge = challenge as ChallengeTypes; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     setShadowStyles(value: ContextualFlowInfo) { |     setBackgroundImage(value: ContextualFlowInfo) { | ||||||
|         if (!value) { |         if (!value) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |         if (isEmbedded()) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|         this.shadowRoot |         this.shadowRoot | ||||||
|             ?.querySelectorAll<HTMLDivElement>(".pf-c-background-image") |             ?.querySelectorAll<HTMLDivElement>(".pf-c-background-image") | ||||||
|             .forEach((bg) => { |             .forEach((bg) => { | ||||||
| @ -276,7 +277,7 @@ export class FlowExecutor extends Interface implements StageHost { | |||||||
|     // DOM post-processing has to happen after the render. |     // DOM post-processing has to happen after the render. | ||||||
|     updated(changedProperties: PropertyValues<this>) { |     updated(changedProperties: PropertyValues<this>) { | ||||||
|         if (changedProperties.has("flowInfo") && this.flowInfo !== undefined) { |         if (changedProperties.has("flowInfo") && this.flowInfo !== undefined) { | ||||||
|             this.setShadowStyles(this.flowInfo); |             this.setBackgroundImage(this.flowInfo); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -459,56 +460,63 @@ export class FlowExecutor extends Interface implements StageHost { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     renderCard() { | ||||||
|  |         return html`<div class="pf-c-login ${this.getLayout()}"> | ||||||
|  |             <div class="${this.getLayoutClass()}"> | ||||||
|  |                 <div class="pf-c-login__main"> | ||||||
|  |                     ${this.loading && this.challenge | ||||||
|  |                         ? html`<ak-loading-overlay></ak-loading-overlay>` | ||||||
|  |                         : nothing} | ||||||
|  |                     ${isEmbedded() | ||||||
|  |                         ? nothing | ||||||
|  |                         : html` <div class="pf-c-login__main-header pf-c-brand ak-brand"> | ||||||
|  |                               <img | ||||||
|  |                                   src="${themeImage( | ||||||
|  |                                       first( | ||||||
|  |                                           this.brand?.brandingLogo, | ||||||
|  |                                           globalAK()?.brand.brandingLogo, | ||||||
|  |                                           DefaultBrand.brandingLogo, | ||||||
|  |                                       ), | ||||||
|  |                                   )}" | ||||||
|  |                                   alt="authentik Logo" | ||||||
|  |                               /> | ||||||
|  |                           </div>`} | ||||||
|  |                     ${until(this.renderChallenge())} | ||||||
|  |                 </div> | ||||||
|  |                 ${isEmbedded() | ||||||
|  |                     ? nothing | ||||||
|  |                     : html` <footer class="pf-c-login__footer"> | ||||||
|  |                           <ul class="pf-c-list pf-m-inline"> | ||||||
|  |                               ${this.brand?.uiFooterLinks?.map((link) => { | ||||||
|  |                                   if (link.href) { | ||||||
|  |                                       return html`<li> | ||||||
|  |                                           <a href="${link.href}">${link.name}</a> | ||||||
|  |                                       </li>`; | ||||||
|  |                                   } | ||||||
|  |                                   return html`<li> | ||||||
|  |                                       <span>${link.name}</span> | ||||||
|  |                                   </li>`; | ||||||
|  |                               })} | ||||||
|  |                               <li> | ||||||
|  |                                   <span>${msg("Powered by authentik")}</span> | ||||||
|  |                               </li> | ||||||
|  |                           </ul> | ||||||
|  |                       </footer>`} | ||||||
|  |             </div> | ||||||
|  |         </div>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     render(): TemplateResult { |     render(): TemplateResult { | ||||||
|  |         if (isEmbedded()) { | ||||||
|  |             return this.renderCard(); | ||||||
|  |         } | ||||||
|         return html` <ak-locale-context> |         return html` <ak-locale-context> | ||||||
|             <div class="pf-c-background-image"></div> |             <div class="pf-c-background-image"></div> | ||||||
|             <div class="pf-c-page__drawer"> |             <div class="pf-c-page__drawer"> | ||||||
|                 <div class="pf-c-drawer ${this.inspectorOpen ? "pf-m-expanded" : "pf-m-collapsed"}"> |                 <div class="pf-c-drawer ${this.inspectorOpen ? "pf-m-expanded" : "pf-m-collapsed"}"> | ||||||
|                     <div class="pf-c-drawer__main"> |                     <div class="pf-c-drawer__main"> | ||||||
|                         <div class="pf-c-drawer__content"> |                         <div class="pf-c-drawer__content"> | ||||||
|                             <div class="pf-c-drawer__body"> |                             <div class="pf-c-drawer__body">${this.renderCard()}</div> | ||||||
|                                 <div class="pf-c-login ${this.getLayout()}"> |  | ||||||
|                                     <div class="${this.getLayoutClass()}"> |  | ||||||
|                                         <div class="pf-c-login__main"> |  | ||||||
|                                             ${this.loading && this.challenge |  | ||||||
|                                                 ? html`<ak-loading-overlay></ak-loading-overlay>` |  | ||||||
|                                                 : nothing} |  | ||||||
|                                             <div |  | ||||||
|                                                 class="pf-c-login__main-header pf-c-brand ak-brand" |  | ||||||
|                                             > |  | ||||||
|                                                 <img |  | ||||||
|                                                     src="${themeImage( |  | ||||||
|                                                         first( |  | ||||||
|                                                             this.brand?.brandingLogo, |  | ||||||
|                                                             globalAK()?.brand.brandingLogo, |  | ||||||
|                                                             DefaultBrand.brandingLogo, |  | ||||||
|                                                         ), |  | ||||||
|                                                     )}" |  | ||||||
|                                                     alt="authentik Logo" |  | ||||||
|                                                 /> |  | ||||||
|                                             </div> |  | ||||||
|                                             ${until(this.renderChallenge())} |  | ||||||
|                                         </div> |  | ||||||
|                                         <footer class="pf-c-login__footer"> |  | ||||||
|                                             <ul class="pf-c-list pf-m-inline"> |  | ||||||
|                                                 ${this.brand?.uiFooterLinks?.map((link) => { |  | ||||||
|                                                     if (link.href) { |  | ||||||
|                                                         return html`<li> |  | ||||||
|                                                             <a href="${link.href}">${link.name}</a> |  | ||||||
|                                                         </li>`; |  | ||||||
|                                                     } |  | ||||||
|                                                     return html`<li> |  | ||||||
|                                                         <span>${link.name}</span> |  | ||||||
|                                                     </li>`; |  | ||||||
|                                                 })} |  | ||||||
|                                                 <li> |  | ||||||
|                                                     <span>${msg("Powered by authentik")}</span> |  | ||||||
|                                                 </li> |  | ||||||
|                                             </ul> |  | ||||||
|                                         </footer> |  | ||||||
|                                     </div> |  | ||||||
|                                 </div> |  | ||||||
|                             </div> |  | ||||||
|                         </div> |                         </div> | ||||||
|                         ${until(this.renderInspector())} |                         ${until(this.renderInspector())} | ||||||
|                     </div> |                     </div> | ||||||
|  | |||||||
| @ -99,6 +99,7 @@ export class IdentificationStage extends BaseStage< | |||||||
|     createHelperForm(): void { |     createHelperForm(): void { | ||||||
|         const compatMode = "ShadyDOM" in window; |         const compatMode = "ShadyDOM" in window; | ||||||
|         this.form = document.createElement("form"); |         this.form = document.createElement("form"); | ||||||
|  |         this.form.style.display = "none"; | ||||||
|         document.documentElement.appendChild(this.form); |         document.documentElement.appendChild(this.form); | ||||||
|         // Only add the additional username input if we're in a shadow dom |         // Only add the additional username input if we're in a shadow dom | ||||||
|         // otherwise it just confuses browsers |         // otherwise it just confuses browsers | ||||||
|  | |||||||
							
								
								
									
										8
									
								
								web/src/global.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								web/src/global.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -12,3 +12,11 @@ declare namespace Intl { | |||||||
|         public format: (items: string[]) => string; |         public format: (items: string[]) => string; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | declare interface Window { | ||||||
|  |     authentik_sdk?: { | ||||||
|  |         base: string; | ||||||
|  |         token?: string; | ||||||
|  |         forceTheme?: string; | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | |||||||
							
								
								
									
										19
									
								
								web/src/sdk/common.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								web/src/sdk/common.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | import { Interface } from "@goauthentik/elements/Interface/Interface"; | ||||||
|  |  | ||||||
|  | import { html } from "lit"; | ||||||
|  | import { customElement } from "lit/decorators.js"; | ||||||
|  |  | ||||||
|  | import { UiThemeEnum, UiThemeEnumFromJSON } from "@goauthentik/api"; | ||||||
|  |  | ||||||
|  | @customElement("ak-sdk-interface") | ||||||
|  | export class SDKInterface extends Interface { | ||||||
|  |     constructor() { | ||||||
|  |         super(); | ||||||
|  |     } | ||||||
|  |     render() { | ||||||
|  |         return html`<slot></slot>`; | ||||||
|  |     } | ||||||
|  |     async getTheme(): Promise<UiThemeEnum> { | ||||||
|  |         return UiThemeEnumFromJSON(window.authentik_sdk?.forceTheme) || UiThemeEnum.Automatic; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										34
									
								
								web/src/sdk/flow.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								web/src/sdk/flow.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | |||||||
|  | import "@goauthentik/elements/messages/MessageContainer"; | ||||||
|  | import { FlowExecutor } from "@goauthentik/flow/FlowExecutor"; | ||||||
|  | // Statically import some stages to speed up load speed | ||||||
|  | import "@goauthentik/flow/stages/access_denied/AccessDeniedStage"; | ||||||
|  | // Import webauthn-related stages to prevent issues on safari | ||||||
|  | // Which is overly sensitive to allowing things only in the context of a | ||||||
|  | // user interaction | ||||||
|  | import "@goauthentik/flow/stages/authenticator_validate/AuthenticatorValidateStage"; | ||||||
|  | import "@goauthentik/flow/stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage"; | ||||||
|  | import "@goauthentik/flow/stages/autosubmit/AutosubmitStage"; | ||||||
|  | import "@goauthentik/flow/stages/captcha/CaptchaStage"; | ||||||
|  | import "@goauthentik/flow/stages/identification/IdentificationStage"; | ||||||
|  | import "@goauthentik/flow/stages/password/PasswordStage"; | ||||||
|  | import "@goauthentik/sdk/common"; | ||||||
|  | // end of stage import | ||||||
|  |  | ||||||
|  | import { html, nothing } from "lit"; | ||||||
|  | import { customElement } from "lit/decorators.js"; | ||||||
|  | import { until } from "lit/directives/until.js"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @customElement("ak-embedded-flow-executor") | ||||||
|  | export class EmbeddedFlowExecutor extends FlowExecutor { | ||||||
|  |     renderCard() { | ||||||
|  |         return html`<div class="pf-c-login"> | ||||||
|  |             <div class="pf-c-login__main"> | ||||||
|  |                 ${this.loading && this.challenge | ||||||
|  |                     ? html`<ak-loading-overlay></ak-loading-overlay>` | ||||||
|  |                     : nothing} | ||||||
|  |                 ${until(this.renderChallenge())} | ||||||
|  |             </div> | ||||||
|  |         </div>`; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										2
									
								
								web/src/sdk/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								web/src/sdk/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | |||||||
|  | import "@goauthentik/sdk/flow"; | ||||||
|  | import "@goauthentik/sdk/user-settings"; | ||||||
							
								
								
									
										3
									
								
								web/src/sdk/user-settings.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								web/src/sdk/user-settings.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | import "@goauthentik/elements/messages/MessageContainer"; | ||||||
|  | import "@goauthentik/sdk/common"; | ||||||
|  | import "@goauthentik/user/user-settings/UserSettingsPage"; | ||||||
| @ -21,6 +21,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css"; | |||||||
|  |  | ||||||
| import { | import { | ||||||
|     ChallengeTypes, |     ChallengeTypes, | ||||||
|  |     CoreApi, | ||||||
|     FlowChallengeResponseRequest, |     FlowChallengeResponseRequest, | ||||||
|     FlowErrorChallenge, |     FlowErrorChallenge, | ||||||
|     FlowsApi, |     FlowsApi, | ||||||
| @ -82,8 +83,11 @@ export class UserSettingsFlowExecutor | |||||||
|             }); |             }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     firstUpdated(): void { |     async firstUpdated(): Promise<void> { | ||||||
|         this.flowSlug = this.brand?.flowUserSettings; |         if (!this.brand) { | ||||||
|  |             this.brand = await new CoreApi(DEFAULT_CONFIG).coreBrandsCurrentRetrieve(); | ||||||
|  |         } | ||||||
|  |         this.flowSlug = this.brand.flowUserSettings; | ||||||
|         if (!this.flowSlug) { |         if (!this.flowSlug) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ | |||||||
|             "@goauthentik/flow/*": ["./src/flow/*"], |             "@goauthentik/flow/*": ["./src/flow/*"], | ||||||
|             "@goauthentik/locales/*": ["./src/locales/*"], |             "@goauthentik/locales/*": ["./src/locales/*"], | ||||||
|             "@goauthentik/polyfill/*": ["./src/polyfill/*"], |             "@goauthentik/polyfill/*": ["./src/polyfill/*"], | ||||||
|  |             "@goauthentik/sdk/*": ["./src/sdk/*"], | ||||||
|             "@goauthentik/standalone/*": ["./src/standalone/*"], |             "@goauthentik/standalone/*": ["./src/standalone/*"], | ||||||
|             "@goauthentik/user/*": ["./src/user/*"] |             "@goauthentik/user/*": ["./src/user/*"] | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -8,6 +8,12 @@ import tsconfigPaths from "vite-tsconfig-paths"; | |||||||
| const isProdBuild = process.env.NODE_ENV === "production"; | const isProdBuild = process.env.NODE_ENV === "production"; | ||||||
| const apiBasePath = process.env.AK_API_BASE_PATH || ""; | const apiBasePath = process.env.AK_API_BASE_PATH || ""; | ||||||
| const runHeadless = process.env.CI !== undefined; | const runHeadless = process.env.CI !== undefined; | ||||||
|  | const maxInstances = | ||||||
|  |     process.env.MAX_INSTANCES !== undefined | ||||||
|  |         ? parseInt(process.env.MAX_INSTANCES, 10) | ||||||
|  |         : runHeadless | ||||||
|  |           ? 10 | ||||||
|  |           : 1; | ||||||
|  |  | ||||||
| export const config: Options.Testrunner = { | export const config: Options.Testrunner = { | ||||||
|     // |     // | ||||||
| @ -81,7 +87,7 @@ export const config: Options.Testrunner = { | |||||||
|     // and 30 processes will get spawned. The property handles how many capabilities |     // and 30 processes will get spawned. The property handles how many capabilities | ||||||
|     // from the same test should run tests. |     // from the same test should run tests. | ||||||
|     // |     // | ||||||
|     maxInstances: 10, |     maxInstances, | ||||||
|     // |     // | ||||||
|     // If you have trouble getting all important capabilities together, check out the |     // If you have trouble getting all important capabilities together, check out the | ||||||
|     // Sauce Labs platform configurator - a great tool to configure your capabilities: |     // Sauce Labs platform configurator - a great tool to configure your capabilities: | ||||||
|  | |||||||
| @ -1831,10 +1831,6 @@ | |||||||
|         <source>Match created events with this action type. When left empty, all action types will be matched.</source> |         <source>Match created events with this action type. When left empty, all action types will be matched.</source> | ||||||
|         <target>Ordnen Sie erstellte Ereignisse diesem Aktionstyp zu. Wenn es leer gelassen wird, werden alle Aktionstypen abgeglichen.</target> |         <target>Ordnen Sie erstellte Ereignisse diesem Aktionstyp zu. Wenn es leer gelassen wird, werden alle Aktionstypen abgeglichen.</target> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="sfab527528ea64618"> |  | ||||||
|         <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy.</source> |  | ||||||
|         <target>Stimmt mit der Client-IP des Ereignisses überein (strenge Übereinstimmung, verwenden Sie für die Netzwerkübereinstimmung eine Ausdrucksrichtlinie.</target> |  | ||||||
|       </trans-unit> |  | ||||||
|       <trans-unit id="s5a15a8f39c699273"> |       <trans-unit id="s5a15a8f39c699273"> | ||||||
|         <source>Match events created by selected application. When left empty, all applications are matched.</source> |         <source>Match events created by selected application. When left empty, all applications are matched.</source> | ||||||
|         <target>Übereinstimmungsereignisse, die von der ausgewählten Anwendung erstellt wurden. Wenn es leer gelassen wird, werden alle Anwendungen abgeglichen.</target> |         <target>Übereinstimmungsereignisse, die von der ausgewählten Anwendung erstellt wurden. Wenn es leer gelassen wird, werden alle Anwendungen abgeglichen.</target> | ||||||
| @ -6890,6 +6886,9 @@ Bindings to groups/users are checked against the user of the event.</source> | |||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sae72e1569d34fb02"> | <trans-unit id="sae72e1569d34fb02"> | ||||||
|   <source>External user usage</source> |   <source>External user usage</source> | ||||||
|  | </trans-unit> | ||||||
|  | <trans-unit id="sa82f8948649d0989"> | ||||||
|  |   <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy).</source> | ||||||
| </trans-unit> | </trans-unit> | ||||||
|     </body> |     </body> | ||||||
|   </file> |   </file> | ||||||
|  | |||||||
| @ -1917,10 +1917,6 @@ | |||||||
|         <source>Match created events with this action type. When left empty, all action types will be matched.</source> |         <source>Match created events with this action type. When left empty, all action types will be matched.</source> | ||||||
|         <target>Match created events with this action type. When left empty, all action types will be matched.</target> |         <target>Match created events with this action type. When left empty, all action types will be matched.</target> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="sfab527528ea64618"> |  | ||||||
|         <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy.</source> |  | ||||||
|         <target>Matches Event's Client IP (strict matching, for network matching use an Expression Policy.</target> |  | ||||||
|       </trans-unit> |  | ||||||
|       <trans-unit id="s5a15a8f39c699273"> |       <trans-unit id="s5a15a8f39c699273"> | ||||||
|         <source>Match events created by selected application. When left empty, all applications are matched.</source> |         <source>Match events created by selected application. When left empty, all applications are matched.</source> | ||||||
|         <target>Match events created by selected application. When left empty, all applications are matched.</target> |         <target>Match events created by selected application. When left empty, all applications are matched.</target> | ||||||
| @ -7155,6 +7151,9 @@ Bindings to groups/users are checked against the user of the event.</source> | |||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sae72e1569d34fb02"> | <trans-unit id="sae72e1569d34fb02"> | ||||||
|   <source>External user usage</source> |   <source>External user usage</source> | ||||||
|  | </trans-unit> | ||||||
|  | <trans-unit id="sa82f8948649d0989"> | ||||||
|  |   <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy).</source> | ||||||
| </trans-unit> | </trans-unit> | ||||||
|     </body> |     </body> | ||||||
|   </file> |   </file> | ||||||
|  | |||||||
| @ -1799,10 +1799,6 @@ | |||||||
|         <source>Match created events with this action type. When left empty, all action types will be matched.</source> |         <source>Match created events with this action type. When left empty, all action types will be matched.</source> | ||||||
|         <target>Haga coincidir los eventos creados con este tipo de acción. Cuando se deja vacío, todos los tipos de acción coincidirán.</target> |         <target>Haga coincidir los eventos creados con este tipo de acción. Cuando se deja vacío, todos los tipos de acción coincidirán.</target> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="sfab527528ea64618"> |  | ||||||
|         <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy.</source> |  | ||||||
|         <target>Coincide con la IP del cliente del evento (coincidencia estricta, para la coincidencia de red, use una política de expresión</target> |  | ||||||
|       </trans-unit> |  | ||||||
|       <trans-unit id="s5a15a8f39c699273"> |       <trans-unit id="s5a15a8f39c699273"> | ||||||
|         <source>Match events created by selected application. When left empty, all applications are matched.</source> |         <source>Match events created by selected application. When left empty, all applications are matched.</source> | ||||||
|         <target>Coincidir con eventos creados por la aplicación seleccionada. Cuando se deja vacío, todas las solicitudes coinciden.</target> |         <target>Coincidir con eventos creados por la aplicación seleccionada. Cuando se deja vacío, todas las solicitudes coinciden.</target> | ||||||
| @ -6807,6 +6803,9 @@ Bindings to groups/users are checked against the user of the event.</source> | |||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sae72e1569d34fb02"> | <trans-unit id="sae72e1569d34fb02"> | ||||||
|   <source>External user usage</source> |   <source>External user usage</source> | ||||||
|  | </trans-unit> | ||||||
|  | <trans-unit id="sa82f8948649d0989"> | ||||||
|  |   <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy).</source> | ||||||
| </trans-unit> | </trans-unit> | ||||||
|     </body> |     </body> | ||||||
|   </file> |   </file> | ||||||
|  | |||||||
| @ -2389,11 +2389,6 @@ | |||||||
|         <source>Match created events with this action type. When left empty, all action types will be matched.</source> |         <source>Match created events with this action type. When left empty, all action types will be matched.</source> | ||||||
|         <target>Inclure les événements créés avec ce type d'action. S'il est laissé vide, tous les types d'action seront inclus.</target> |         <target>Inclure les événements créés avec ce type d'action. S'il est laissé vide, tous les types d'action seront inclus.</target> | ||||||
|          |          | ||||||
|       </trans-unit> |  | ||||||
|       <trans-unit id="sfab527528ea64618"> |  | ||||||
|         <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy.</source> |  | ||||||
|         <target>Inclure l'adresse IP du client de l'évènement (correspondante stricte, pour un correspondance sur le réseau utiliser une politique d'expression)</target> |  | ||||||
|          |  | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="s5a15a8f39c699273"> |       <trans-unit id="s5a15a8f39c699273"> | ||||||
|         <source>Match events created by selected application. When left empty, all applications are matched.</source> |         <source>Match events created by selected application. When left empty, all applications are matched.</source> | ||||||
| @ -9052,6 +9047,9 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti | |||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sae72e1569d34fb02"> | <trans-unit id="sae72e1569d34fb02"> | ||||||
|   <source>External user usage</source> |   <source>External user usage</source> | ||||||
|  | </trans-unit> | ||||||
|  | <trans-unit id="sa82f8948649d0989"> | ||||||
|  |   <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy).</source> | ||||||
| </trans-unit> | </trans-unit> | ||||||
|     </body> |     </body> | ||||||
|   </file> |   </file> | ||||||
|  | |||||||
| @ -2383,11 +2383,6 @@ | |||||||
|         <source>Match created events with this action type. When left empty, all action types will be matched.</source> |         <source>Match created events with this action type. When left empty, all action types will be matched.</source> | ||||||
|         <target>생성된 이벤트를 이 작업 유형과 일치시킵니다. 비워두면 모든 액션 유형이 일치합니다.</target> |         <target>생성된 이벤트를 이 작업 유형과 일치시킵니다. 비워두면 모든 액션 유형이 일치합니다.</target> | ||||||
|  |  | ||||||
|       </trans-unit> |  | ||||||
|       <trans-unit id="sfab527528ea64618"> |  | ||||||
|         <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy.</source> |  | ||||||
|         <target>이벤트의 클라이언트 IP를 일치시킵니다 (엄격 일치, 네트워크 일치의 경우 표현식 정책 사용.</target> |  | ||||||
|  |  | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="s5a15a8f39c699273"> |       <trans-unit id="s5a15a8f39c699273"> | ||||||
|         <source>Match events created by selected application. When left empty, all applications are matched.</source> |         <source>Match events created by selected application. When left empty, all applications are matched.</source> | ||||||
| @ -8726,6 +8721,9 @@ Bindings to groups/users are checked against the user of the event.</source> | |||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sae72e1569d34fb02"> | <trans-unit id="sae72e1569d34fb02"> | ||||||
|   <source>External user usage</source> |   <source>External user usage</source> | ||||||
|  | </trans-unit> | ||||||
|  | <trans-unit id="sa82f8948649d0989"> | ||||||
|  |   <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy).</source> | ||||||
| </trans-unit> | </trans-unit> | ||||||
|     </body> |     </body> | ||||||
|   </file> |   </file> | ||||||
|  | |||||||
| @ -2371,11 +2371,6 @@ | |||||||
|         <source>Match created events with this action type. When left empty, all action types will be matched.</source> |         <source>Match created events with this action type. When left empty, all action types will be matched.</source> | ||||||
|         <target>Match gecreëerde gebeurtenissen met dit actietype. Wanneer leeg gelaten, worden alle actietypen gematcht.</target> |         <target>Match gecreëerde gebeurtenissen met dit actietype. Wanneer leeg gelaten, worden alle actietypen gematcht.</target> | ||||||
|  |  | ||||||
|       </trans-unit> |  | ||||||
|       <trans-unit id="sfab527528ea64618"> |  | ||||||
|         <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy.</source> |  | ||||||
|         <target>Matcht de cliënt IP van een gebeurtenis (strikt matchen, voor netwerk matchen gebruik een Expressie Beleid).</target> |  | ||||||
|  |  | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="s5a15a8f39c699273"> |       <trans-unit id="s5a15a8f39c699273"> | ||||||
|         <source>Match events created by selected application. When left empty, all applications are matched.</source> |         <source>Match events created by selected application. When left empty, all applications are matched.</source> | ||||||
| @ -8571,6 +8566,9 @@ Bindingen naar groepen/gebruikers worden gecontroleerd tegen de gebruiker van de | |||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sae72e1569d34fb02"> | <trans-unit id="sae72e1569d34fb02"> | ||||||
|   <source>External user usage</source> |   <source>External user usage</source> | ||||||
|  | </trans-unit> | ||||||
|  | <trans-unit id="sa82f8948649d0989"> | ||||||
|  |   <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy).</source> | ||||||
| </trans-unit> | </trans-unit> | ||||||
|     </body> |     </body> | ||||||
|   </file> |   </file> | ||||||
|  | |||||||
| @ -2391,11 +2391,6 @@ | |||||||
|         <source>Match created events with this action type. When left empty, all action types will be matched.</source> |         <source>Match created events with this action type. When left empty, all action types will be matched.</source> | ||||||
|         <target>Dopasuj utworzone zdarzenia do tego typu akcji. Jeśli pozostawisz to puste, wszystkie typy akcji zostaną dopasowane.</target> |         <target>Dopasuj utworzone zdarzenia do tego typu akcji. Jeśli pozostawisz to puste, wszystkie typy akcji zostaną dopasowane.</target> | ||||||
|          |          | ||||||
|       </trans-unit> |  | ||||||
|       <trans-unit id="sfab527528ea64618"> |  | ||||||
|         <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy.</source> |  | ||||||
|         <target>Dopasowuje adres IP klienta zdarzenia (ścisłe dopasowanie, do dopasowywania sieci należy użyć zasady wyrażeń.</target> |  | ||||||
|          |  | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="s5a15a8f39c699273"> |       <trans-unit id="s5a15a8f39c699273"> | ||||||
|         <source>Match events created by selected application. When left empty, all applications are matched.</source> |         <source>Match events created by selected application. When left empty, all applications are matched.</source> | ||||||
| @ -8991,6 +8986,9 @@ Powiązania z grupami/użytkownikami są sprawdzane względem użytkownika zdarz | |||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sae72e1569d34fb02"> | <trans-unit id="sae72e1569d34fb02"> | ||||||
|   <source>External user usage</source> |   <source>External user usage</source> | ||||||
|  | </trans-unit> | ||||||
|  | <trans-unit id="sa82f8948649d0989"> | ||||||
|  |   <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy).</source> | ||||||
| </trans-unit> | </trans-unit> | ||||||
|     </body> |     </body> | ||||||
|   </file> |   </file> | ||||||
|  | |||||||
| @ -2371,11 +2371,6 @@ | |||||||
|         <source>Match created events with this action type. When left empty, all action types will be matched.</source> |         <source>Match created events with this action type. When left empty, all action types will be matched.</source> | ||||||
|   <target>Màţćĥ ćŕēàţēď ēvēńţś ŵĩţĥ ţĥĩś àćţĩōń ţŷƥē. Ŵĥēń ĺēƒţ ēmƥţŷ, àĺĺ àćţĩōń ţŷƥēś ŵĩĺĺ ƀē màţćĥēď.</target> |   <target>Màţćĥ ćŕēàţēď ēvēńţś ŵĩţĥ ţĥĩś àćţĩōń ţŷƥē. Ŵĥēń ĺēƒţ ēmƥţŷ, àĺĺ àćţĩōń ţŷƥēś ŵĩĺĺ ƀē màţćĥēď.</target> | ||||||
|  |  | ||||||
|       </trans-unit> |  | ||||||
|       <trans-unit id="sfab527528ea64618"> |  | ||||||
|         <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy.</source> |  | ||||||
|   <target>Màţćĥēś Ēvēńţ'ś Ćĺĩēńţ ĨƤ (śţŕĩćţ màţćĥĩńĝ, ƒōŕ ńēţŵōŕķ màţćĥĩńĝ ũśē àń Ēxƥŕēśśĩōń Ƥōĺĩćŷ.</target> |  | ||||||
|  |  | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="s5a15a8f39c699273"> |       <trans-unit id="s5a15a8f39c699273"> | ||||||
|         <source>Match events created by selected application. When left empty, all applications are matched.</source> |         <source>Match events created by selected application. When left empty, all applications are matched.</source> | ||||||
| @ -8954,4 +8949,7 @@ Bindings to groups/users are checked against the user of the event.</source> | |||||||
| <trans-unit id="sae72e1569d34fb02"> | <trans-unit id="sae72e1569d34fb02"> | ||||||
|   <source>External user usage</source> |   <source>External user usage</source> | ||||||
| </trans-unit> | </trans-unit> | ||||||
|  | <trans-unit id="sa82f8948649d0989"> | ||||||
|  |   <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy).</source> | ||||||
|  | </trans-unit> | ||||||
| </body></file></xliff> | </body></file></xliff> | ||||||
|  | |||||||
| @ -2391,11 +2391,6 @@ | |||||||
|         <source>Match created events with this action type. When left empty, all action types will be matched.</source> |         <source>Match created events with this action type. When left empty, all action types will be matched.</source> | ||||||
|         <target>Сопоставлять созданные события с данным типом действия. Если оставить пустым, будут сопоставлены все типы действий.</target> |         <target>Сопоставлять созданные события с данным типом действия. Если оставить пустым, будут сопоставлены все типы действий.</target> | ||||||
|          |          | ||||||
|       </trans-unit> |  | ||||||
|       <trans-unit id="sfab527528ea64618"> |  | ||||||
|         <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy.</source> |  | ||||||
|         <target>Сопоставляет IP-адрес клиента события (строгое сопоставление, для сетевого сопоставления используйте политику выражений.</target> |  | ||||||
|          |  | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="s5a15a8f39c699273"> |       <trans-unit id="s5a15a8f39c699273"> | ||||||
|         <source>Match events created by selected application. When left empty, all applications are matched.</source> |         <source>Match events created by selected application. When left empty, all applications are matched.</source> | ||||||
| @ -9055,6 +9050,9 @@ Bindings to groups/users are checked against the user of the event.</source> | |||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sae72e1569d34fb02"> | <trans-unit id="sae72e1569d34fb02"> | ||||||
|   <source>External user usage</source> |   <source>External user usage</source> | ||||||
|  | </trans-unit> | ||||||
|  | <trans-unit id="sa82f8948649d0989"> | ||||||
|  |   <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy).</source> | ||||||
| </trans-unit> | </trans-unit> | ||||||
|     </body> |     </body> | ||||||
|   </file> |   </file> | ||||||
|  | |||||||
| @ -1798,10 +1798,6 @@ | |||||||
|         <source>Match created events with this action type. When left empty, all action types will be matched.</source> |         <source>Match created events with this action type. When left empty, all action types will be matched.</source> | ||||||
|         <target>Oluşturulan olayları bu eylem türüyle eşleştirin. Boş bırakıldığında tüm eylem türleri eşleştirilir.</target> |         <target>Oluşturulan olayları bu eylem türüyle eşleştirin. Boş bırakıldığında tüm eylem türleri eşleştirilir.</target> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="sfab527528ea64618"> |  | ||||||
|         <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy.</source> |  | ||||||
|         <target>Olayın İstemci IP'siyle eşleşir (katı eşleştirme, ağ eşleştirme için bir İfade İlkesi kullanın.</target> |  | ||||||
|       </trans-unit> |  | ||||||
|       <trans-unit id="s5a15a8f39c699273"> |       <trans-unit id="s5a15a8f39c699273"> | ||||||
|         <source>Match events created by selected application. When left empty, all applications are matched.</source> |         <source>Match events created by selected application. When left empty, all applications are matched.</source> | ||||||
|         <target>Seçilen uygulama tarafından oluşturulan olayları eşleştir. Boş bırakıldığında, tüm uygulamalar eşleştirilir.</target> |         <target>Seçilen uygulama tarafından oluşturulan olayları eşleştir. Boş bırakıldığında, tüm uygulamalar eşleştirilir.</target> | ||||||
| @ -6800,6 +6796,9 @@ Bindings to groups/users are checked against the user of the event.</source> | |||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sae72e1569d34fb02"> | <trans-unit id="sae72e1569d34fb02"> | ||||||
|   <source>External user usage</source> |   <source>External user usage</source> | ||||||
|  | </trans-unit> | ||||||
|  | <trans-unit id="sa82f8948649d0989"> | ||||||
|  |   <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy).</source> | ||||||
| </trans-unit> | </trans-unit> | ||||||
|     </body> |     </body> | ||||||
|   </file> |   </file> | ||||||
|  | |||||||
| @ -1666,9 +1666,6 @@ | |||||||
| <trans-unit id="s890810efbe103cbc"> | <trans-unit id="s890810efbe103cbc"> | ||||||
|   <source>Match created events with this action type. When left empty, all action types will be matched.</source> |   <source>Match created events with this action type. When left empty, all action types will be matched.</source> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sfab527528ea64618"> |  | ||||||
|   <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy.</source> |  | ||||||
| </trans-unit> |  | ||||||
| <trans-unit id="s5a15a8f39c699273"> | <trans-unit id="s5a15a8f39c699273"> | ||||||
|   <source>Match events created by selected application. When left empty, all applications are matched.</source> |   <source>Match events created by selected application. When left empty, all applications are matched.</source> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| @ -5737,6 +5734,9 @@ Bindings to groups/users are checked against the user of the event.</source> | |||||||
| <trans-unit id="sae72e1569d34fb02"> | <trans-unit id="sae72e1569d34fb02"> | ||||||
|   <source>External user usage</source> |   <source>External user usage</source> | ||||||
| </trans-unit> | </trans-unit> | ||||||
|  | <trans-unit id="sa82f8948649d0989"> | ||||||
|  |   <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy).</source> | ||||||
|  | </trans-unit> | ||||||
| </body> | </body> | ||||||
| </file> | </file> | ||||||
| </xliff> | </xliff> | ||||||
|  | |||||||
| @ -2390,11 +2390,6 @@ | |||||||
|         <source>Match created events with this action type. When left empty, all action types will be matched.</source> |         <source>Match created events with this action type. When left empty, all action types will be matched.</source> | ||||||
|         <target>将创建的事件与此操作类型匹配。留空时,所有操作类型都将匹配。</target> |         <target>将创建的事件与此操作类型匹配。留空时,所有操作类型都将匹配。</target> | ||||||
|          |          | ||||||
|       </trans-unit> |  | ||||||
|       <trans-unit id="sfab527528ea64618"> |  | ||||||
|         <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy.</source> |  | ||||||
|         <target>匹配事件的客户端 IP(严格匹配,要网络匹配请使用表达式策略)。</target> |  | ||||||
|          |  | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="s5a15a8f39c699273"> |       <trans-unit id="s5a15a8f39c699273"> | ||||||
|         <source>Match events created by selected application. When left empty, all applications are matched.</source> |         <source>Match events created by selected application. When left empty, all applications are matched.</source> | ||||||
| @ -8998,66 +8993,91 @@ Bindings to groups/users are checked against the user of the event.</source> | |||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sa42be520242dec2a"> | <trans-unit id="sa42be520242dec2a"> | ||||||
|   <source>Available Sources</source> |   <source>Available Sources</source> | ||||||
|  |   <target>可用源</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="s876e75cf2c07b38e"> | <trans-unit id="s876e75cf2c07b38e"> | ||||||
|   <source>Selected Sources</source> |   <source>Selected Sources</source> | ||||||
|  |   <target>已选源</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="s3b579c4bb6b447ae"> | <trans-unit id="s3b579c4bb6b447ae"> | ||||||
|   <source>Successfully triggered sync.</source> |   <source>Successfully triggered sync.</source> | ||||||
|  |   <target>已成功触发同步。</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="s05073d2537b45d1a"> | <trans-unit id="s05073d2537b45d1a"> | ||||||
|   <source>Sync</source> |   <source>Sync</source> | ||||||
|  |   <target>同步</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="se9da93aa2e6cce21"> | <trans-unit id="se9da93aa2e6cce21"> | ||||||
|   <source>Sync User</source> |   <source>Sync User</source> | ||||||
|  |   <target>同步用户</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="s7bd456df0becbbff"> | <trans-unit id="s7bd456df0becbbff"> | ||||||
|   <source>Available Stages</source> |   <source>Available Stages</source> | ||||||
|  |   <target>可用阶段</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sf80798d2f56b540b"> | <trans-unit id="sf80798d2f56b540b"> | ||||||
|   <source>Selected Stages</source> |   <source>Selected Stages</source> | ||||||
|  |   <target>已选阶段</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sf651943c3ddff635"> | <trans-unit id="sf651943c3ddff635"> | ||||||
|   <source>Available Fields</source> |   <source>Available Fields</source> | ||||||
|  |   <target>可用字段</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="s80ba9c5ebb7826a9"> | <trans-unit id="s80ba9c5ebb7826a9"> | ||||||
|   <source>Selected Fields</source> |   <source>Selected Fields</source> | ||||||
|  |   <target>已选字段</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="s26733a6289ca6f1a"> | <trans-unit id="s26733a6289ca6f1a"> | ||||||
|   <source>Available Transports</source> |   <source>Available Transports</source> | ||||||
|  |   <target>可用传输</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sa65f772cfc5aa67e"> | <trans-unit id="sa65f772cfc5aa67e"> | ||||||
|   <source>Selected Transports</source> |   <source>Selected Transports</source> | ||||||
|  |   <target>已选传输</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sd923f95605fed7b2"> | <trans-unit id="sd923f95605fed7b2"> | ||||||
|   <source>Expired</source> |   <source>Expired</source> | ||||||
|  |   <target>已过期</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="s86959994f28077dc"> | <trans-unit id="s86959994f28077dc"> | ||||||
|   <source>Expiring soon</source> |   <source>Expiring soon</source> | ||||||
|  |   <target>即将过期</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sc60a5fba70bf5a53"> | <trans-unit id="sc60a5fba70bf5a53"> | ||||||
|   <source>Unlicensed</source> |   <source>Unlicensed</source> | ||||||
|  |   <target>未许可</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="s4f9880ce82953741"> | <trans-unit id="s4f9880ce82953741"> | ||||||
|   <source>Read Only</source> |   <source>Read Only</source> | ||||||
|  |   <target>只读</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="s4220dda46d622211"> | <trans-unit id="s4220dda46d622211"> | ||||||
|   <source>Valid</source> |   <source>Valid</source> | ||||||
|  |   <target>有效</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sdc94711a2eb66a45"> | <trans-unit id="sdc94711a2eb66a45"> | ||||||
|   <source>Current license status</source> |   <source>Current license status</source> | ||||||
|  |   <target>当前许可证状态</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="se10fb73c1f1039c5"> | <trans-unit id="se10fb73c1f1039c5"> | ||||||
|   <source>Overall license status</source> |   <source>Overall license status</source> | ||||||
|  |   <target>总体许可证状态</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sc4804358f202968c"> | <trans-unit id="sc4804358f202968c"> | ||||||
|   <source>Internal user usage</source> |   <source>Internal user usage</source> | ||||||
|  |   <target>内部用户用量</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="s087d6f07b52b30ec"> | <trans-unit id="s087d6f07b52b30ec"> | ||||||
|   <source><x id="0" equiv-text="${internalUserPercentage < Infinity ? internalUserPercentage : "∞"}"/>%</source> |   <source><x id="0" equiv-text="${internalUserPercentage < Infinity ? internalUserPercentage : "∞"}"/>%</source> | ||||||
|  |   <target><x id="0" equiv-text="${internalUserPercentage < Infinity ? internalUserPercentage : "∞"}"/>%</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sae72e1569d34fb02"> | <trans-unit id="sae72e1569d34fb02"> | ||||||
|   <source>External user usage</source> |   <source>External user usage</source> | ||||||
|  |   <target>外部用户用量</target> | ||||||
|  | </trans-unit> | ||||||
|  | <trans-unit id="sa82f8948649d0989"> | ||||||
|  |   <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy).</source> | ||||||
|  |   <target>匹配事件的客户端 IP(严格匹配,要网络匹配请使用表达式策略)。</target> | ||||||
| </trans-unit> | </trans-unit> | ||||||
|     </body> |     </body> | ||||||
|   </file> |   </file> | ||||||
|  | |||||||
| @ -1816,10 +1816,6 @@ | |||||||
|         <source>Match created events with this action type. When left empty, all action types will be matched.</source> |         <source>Match created events with this action type. When left empty, all action types will be matched.</source> | ||||||
|         <target>将创建的事件与此操作类型匹配。留空时,所有操作类型都将匹配。</target> |         <target>将创建的事件与此操作类型匹配。留空时,所有操作类型都将匹配。</target> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="sfab527528ea64618"> |  | ||||||
|         <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy.</source> |  | ||||||
|         <target>匹配事件的客户端 IP(严格匹配),对于网络匹配,请使用表达式策略。</target> |  | ||||||
|       </trans-unit> |  | ||||||
|       <trans-unit id="s5a15a8f39c699273"> |       <trans-unit id="s5a15a8f39c699273"> | ||||||
|         <source>Match events created by selected application. When left empty, all applications are matched.</source> |         <source>Match events created by selected application. When left empty, all applications are matched.</source> | ||||||
|         <target>匹配选定应用程序创建的事件。如果留空,则匹配所有应用程序。</target> |         <target>匹配选定应用程序创建的事件。如果留空,则匹配所有应用程序。</target> | ||||||
| @ -6848,6 +6844,9 @@ Bindings to groups/users are checked against the user of the event.</source> | |||||||
| </trans-unit> | </trans-unit> | ||||||
| <trans-unit id="sae72e1569d34fb02"> | <trans-unit id="sae72e1569d34fb02"> | ||||||
|   <source>External user usage</source> |   <source>External user usage</source> | ||||||
|  | </trans-unit> | ||||||
|  | <trans-unit id="sa82f8948649d0989"> | ||||||
|  |   <source>Matches Event's Client IP (strict matching, for network matching use an Expression Policy).</source> | ||||||
| </trans-unit> | </trans-unit> | ||||||
|     </body> |     </body> | ||||||
|   </file> |   </file> | ||||||
|  | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	