diff --git a/authentik/api/v2/config.py b/authentik/api/v2/config.py index 078f0e5a3..d1f45167a 100644 --- a/authentik/api/v2/config.py +++ b/authentik/api/v2/config.py @@ -1,6 +1,10 @@ """core Configs API""" +from os import path + +from django.conf import settings +from django.db import models from drf_spectacular.utils import extend_schema -from rest_framework.fields import BooleanField, CharField, ListField +from rest_framework.fields import BooleanField, CharField, ChoiceField, ListField from rest_framework.permissions import AllowAny from rest_framework.request import Request from rest_framework.response import Response @@ -17,6 +21,12 @@ class FooterLinkSerializer(PassiveSerializer): name = CharField(read_only=True) +class Capabilities(models.TextChoices): + """Define capabilities which influence which APIs can/should be used""" + + CAN_SAVE_MEDIA = "can_save_media" + + class ConfigSerializer(PassiveSerializer): """Serialize authentik Config into DRF Object""" @@ -28,12 +38,22 @@ class ConfigSerializer(PassiveSerializer): error_reporting_environment = CharField(read_only=True) error_reporting_send_pii = BooleanField(read_only=True) + capabilities = ListField(child=ChoiceField(choices=Capabilities.choices)) + class ConfigView(APIView): """Read-only view set that returns the current session's Configs""" permission_classes = [AllowAny] + def get_capabilities(self) -> list[Capabilities]: + """Get all capabilities this server instance supports""" + caps = [] + deb_test = settings.DEBUG or settings.TEST + if path.ismount(settings.MEDIA_ROOT) or deb_test: + caps.append(Capabilities.CAN_SAVE_MEDIA) + return caps + @extend_schema(responses={200: ConfigSerializer(many=False)}) def get(self, request: Request) -> Response: """Retrive public configuration options""" @@ -45,6 +65,7 @@ class ConfigView(APIView): "error_reporting_environment": CONFIG.y("error_reporting.environment"), "error_reporting_send_pii": CONFIG.y("error_reporting.send_pii"), "ui_footer_links": CONFIG.y("authentik.footer_links"), + "capabilities": self.get_capabilities(), } ) return Response(config.data) diff --git a/schema.yml b/schema.yml index f3c304bb1..56c8b7997 100644 --- a/schema.yml +++ b/schema.yml @@ -15179,6 +15179,10 @@ components: readOnly: true required: - count + CapabilitiesEnum: + enum: + - can_save_media + type: string CaptchaStage: type: object description: CaptchaStage Serializer @@ -15362,9 +15366,14 @@ components: error_reporting_send_pii: type: boolean readOnly: true + capabilities: + type: array + items: + $ref: '#/components/schemas/CapabilitiesEnum' required: - branding_logo - branding_title + - capabilities - error_reporting_enabled - error_reporting_environment - error_reporting_send_pii diff --git a/web/src/elements/sidebar/SidebarBrand.ts b/web/src/elements/sidebar/SidebarBrand.ts index fb20160d9..c4a1a8f7d 100644 --- a/web/src/elements/sidebar/SidebarBrand.ts +++ b/web/src/elements/sidebar/SidebarBrand.ts @@ -22,6 +22,7 @@ export const DefaultConfig: Config = { errorReportingEnvironment: "", errorReportingSendPii: false, uiFooterLinks: [], + capabilities: [], }; @customElement("ak-sidebar-brand")