Compare commits
	
		
			6 Commits
		
	
	
		
			dependabot
			...
			files-in-d
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| d410083cfc | |||
| 6045f96a05 | |||
| c50df0f843 | |||
| c8ebd9f74b | |||
| b3f441f2cd | |||
| 647f054be3 | 
							
								
								
									
										32
									
								
								authentik/core/api/files.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								authentik/core/api/files.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
from rest_framework.viewsets import ModelViewSet
 | 
			
		||||
from structlog.stdlib import get_logger
 | 
			
		||||
 | 
			
		||||
from authentik.core.api.used_by import UsedByMixin
 | 
			
		||||
from authentik.core.api.utils import ModelSerializer
 | 
			
		||||
from authentik.core.models import File
 | 
			
		||||
 | 
			
		||||
LOGGER = get_logger()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FileSerializer(ModelSerializer):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = File
 | 
			
		||||
        fields = (
 | 
			
		||||
            "pk",
 | 
			
		||||
            "name",
 | 
			
		||||
            "content",
 | 
			
		||||
            "location",
 | 
			
		||||
            "private",
 | 
			
		||||
            "url",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FileViewSet(UsedByMixin, ModelViewSet):
 | 
			
		||||
    queryset = File.objects.all()
 | 
			
		||||
    serializer_class = FileSerializer
 | 
			
		||||
    filterset_fields = ("private",)
 | 
			
		||||
    ordering = ("name",)
 | 
			
		||||
    search_fields = (
 | 
			
		||||
        "name",
 | 
			
		||||
        "location",
 | 
			
		||||
    )
 | 
			
		||||
@ -0,0 +1,44 @@
 | 
			
		||||
# Generated by Django 5.1.11 on 2025-06-13 15:12
 | 
			
		||||
 | 
			
		||||
import uuid
 | 
			
		||||
import django.db.models.deletion
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ("authentik_core", "0048_delete_oldauthenticatedsession_content_type"),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.CreateModel(
 | 
			
		||||
            name="File",
 | 
			
		||||
            fields=[
 | 
			
		||||
                (
 | 
			
		||||
                    "id",
 | 
			
		||||
                    models.UUIDField(
 | 
			
		||||
                        default=uuid.uuid4, editable=False, primary_key=True, serialize=False
 | 
			
		||||
                    ),
 | 
			
		||||
                ),
 | 
			
		||||
                ("name", models.TextField()),
 | 
			
		||||
                ("content", models.BinaryField()),
 | 
			
		||||
                ("public", models.BooleanField(default=False)),
 | 
			
		||||
            ],
 | 
			
		||||
            options={
 | 
			
		||||
                "verbose_name": "Files",
 | 
			
		||||
            },
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.RenameField(
 | 
			
		||||
            model_name="application",
 | 
			
		||||
            old_name="meta_icon",
 | 
			
		||||
            new_name="meta_old_icon",
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name="application",
 | 
			
		||||
            name="meta_icon",
 | 
			
		||||
            field=models.ForeignKey(
 | 
			
		||||
                null=True, on_delete=django.db.models.deletion.SET_NULL, to="authentik_core.file"
 | 
			
		||||
            ),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@ -0,0 +1,32 @@
 | 
			
		||||
# Generated by Django 5.1.11 on 2025-06-13 15:29
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ("authentik_core", "0049_file_rename_meta_icon_application_meta_old_icon"),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name="file",
 | 
			
		||||
            name="location",
 | 
			
		||||
            field=models.TextField(null=True),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name="file",
 | 
			
		||||
            name="content",
 | 
			
		||||
            field=models.BinaryField(null=True),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AddConstraint(
 | 
			
		||||
            model_name="file",
 | 
			
		||||
            constraint=models.CheckConstraint(
 | 
			
		||||
                condition=models.Q(
 | 
			
		||||
                    ("content__isnull", False), ("location__isnull", False), _connector="OR"
 | 
			
		||||
                ),
 | 
			
		||||
                name="one_of_content_location_is_defined",
 | 
			
		||||
            ),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@ -29,6 +29,7 @@ from authentik.blueprints.models import ManagedModel
 | 
			
		||||
from authentik.core.expression.exceptions import PropertyMappingExpressionException
 | 
			
		||||
from authentik.core.types import UILoginButton, UserSettingSerializer
 | 
			
		||||
from authentik.lib.avatars import get_avatar
 | 
			
		||||
from authentik.lib.config import CONFIG
 | 
			
		||||
from authentik.lib.expression.exceptions import ControlFlowException
 | 
			
		||||
from authentik.lib.generators import generate_id
 | 
			
		||||
from authentik.lib.merge import MERGE_LIST_UNIQUE
 | 
			
		||||
@ -533,12 +534,13 @@ class Application(SerializerModel, PolicyBindingModel):
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # For template applications, this can be set to /static/authentik/applications/*
 | 
			
		||||
    meta_icon = models.FileField(
 | 
			
		||||
    meta_old_icon = models.FileField(
 | 
			
		||||
        upload_to="application-icons/",
 | 
			
		||||
        default=None,
 | 
			
		||||
        null=True,
 | 
			
		||||
        max_length=500,
 | 
			
		||||
    )
 | 
			
		||||
    meta_icon = models.ForeignKey("File", null=True, on_delete=models.SET_NULL)
 | 
			
		||||
    meta_description = models.TextField(default="", blank=True)
 | 
			
		||||
    meta_publisher = models.TextField(default="", blank=True)
 | 
			
		||||
 | 
			
		||||
@ -1100,3 +1102,44 @@ class AuthenticatedSession(SerializerModel):
 | 
			
		||||
            session=Session.objects.filter(session_key=request.session.session_key).first(),
 | 
			
		||||
            user=user,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class File(SerializerModel):
 | 
			
		||||
    id = models.UUIDField(primary_key=True, editable=False, default=uuid4)
 | 
			
		||||
 | 
			
		||||
    name = models.TextField()
 | 
			
		||||
    content = models.BinaryField(null=True)
 | 
			
		||||
    location = models.TextField(null=True)
 | 
			
		||||
    public = models.BooleanField(default=False)
 | 
			
		||||
    delete_on_delete = models.BooleanField(default=False)
 | 
			
		||||
    expiry = models.DateTimeField()
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        verbose_name = _("File")
 | 
			
		||||
        verbose_name = _("Files")
 | 
			
		||||
        constraints = (
 | 
			
		||||
            models.CheckConstraint(
 | 
			
		||||
                condition=Q(content__isnull=False) | Q(location__isnull=False),
 | 
			
		||||
                name="one_of_content_location_is_defined",
 | 
			
		||||
            ),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def __str__(self) -> str:
 | 
			
		||||
        return self.name
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def serializer(self) -> type[Serializer]:
 | 
			
		||||
        from authentik.core.api.files import FileSerializer
 | 
			
		||||
 | 
			
		||||
        return FileSerializer
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def url(self) -> str:
 | 
			
		||||
        if self.content:
 | 
			
		||||
            return (
 | 
			
		||||
                CONFIG.get("web.path", "/")[:-1]
 | 
			
		||||
                + f"/files/{'public' if self.public else 'private'}/{self.pk}"
 | 
			
		||||
            )
 | 
			
		||||
        elif self.location.startswith("/static"):
 | 
			
		||||
            return CONFIG.get("web.path", "/")[:-1] + self.location
 | 
			
		||||
        return self.location
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,7 @@ from authentik.core.api.application_entitlements import ApplicationEntitlementVi
 | 
			
		||||
from authentik.core.api.applications import ApplicationViewSet
 | 
			
		||||
from authentik.core.api.authenticated_sessions import AuthenticatedSessionViewSet
 | 
			
		||||
from authentik.core.api.devices import AdminDeviceViewSet, DeviceViewSet
 | 
			
		||||
from authentik.core.api.files import FileViewSet
 | 
			
		||||
from authentik.core.api.groups import GroupViewSet
 | 
			
		||||
from authentik.core.api.property_mappings import PropertyMappingViewSet
 | 
			
		||||
from authentik.core.api.providers import ProviderViewSet
 | 
			
		||||
@ -78,6 +79,7 @@ api_urlpatterns = [
 | 
			
		||||
        TransactionalApplicationView.as_view(),
 | 
			
		||||
        name="core-transactional-application",
 | 
			
		||||
    ),
 | 
			
		||||
    ("core/files", FileViewSet),
 | 
			
		||||
    ("core/groups", GroupViewSet),
 | 
			
		||||
    ("core/users", UserViewSet),
 | 
			
		||||
    ("core/tokens", TokenViewSet),
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								go.mod
									
									
									
									
									
								
							@ -62,6 +62,12 @@ require (
 | 
			
		||||
	github.com/go-openapi/validate v0.24.0 // indirect
 | 
			
		||||
	github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
 | 
			
		||||
	github.com/inconshreveable/mousetrap v1.1.0 // indirect
 | 
			
		||||
	github.com/jackc/pgpassfile v1.0.0 // indirect
 | 
			
		||||
	github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
 | 
			
		||||
	github.com/jackc/pgx/v5 v5.7.5 // indirect
 | 
			
		||||
	github.com/jackc/puddle/v2 v2.2.2 // indirect
 | 
			
		||||
	github.com/jinzhu/inflection v1.0.0 // indirect
 | 
			
		||||
	github.com/jinzhu/now v1.1.5 // indirect
 | 
			
		||||
	github.com/josharian/intern v1.0.0 // indirect
 | 
			
		||||
	github.com/klauspost/compress v1.18.0 // indirect
 | 
			
		||||
	github.com/mailru/easyjson v0.7.7 // indirect
 | 
			
		||||
@ -77,9 +83,11 @@ require (
 | 
			
		||||
	go.opentelemetry.io/otel v1.24.0 // indirect
 | 
			
		||||
	go.opentelemetry.io/otel/metric v1.24.0 // indirect
 | 
			
		||||
	go.opentelemetry.io/otel/trace v1.24.0 // indirect
 | 
			
		||||
	golang.org/x/crypto v0.36.0 // indirect
 | 
			
		||||
	golang.org/x/sys v0.31.0 // indirect
 | 
			
		||||
	golang.org/x/text v0.24.0 // indirect
 | 
			
		||||
	golang.org/x/crypto v0.39.0 // indirect
 | 
			
		||||
	golang.org/x/sys v0.33.0 // indirect
 | 
			
		||||
	golang.org/x/text v0.26.0 // indirect
 | 
			
		||||
	google.golang.org/protobuf v1.36.5 // indirect
 | 
			
		||||
	gopkg.in/yaml.v3 v3.0.1 // indirect
 | 
			
		||||
	gorm.io/driver/postgres v1.6.0 // indirect
 | 
			
		||||
	gorm.io/gorm v1.30.0 // indirect
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										22
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								go.sum
									
									
									
									
									
								
							@ -191,6 +191,14 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
 | 
			
		||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 | 
			
		||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
 | 
			
		||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
 | 
			
		||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
 | 
			
		||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
 | 
			
		||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
 | 
			
		||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
 | 
			
		||||
github.com/jackc/pgx/v5 v5.7.5 h1:JHGfMnQY+IEtGM63d+NGMjoRpysB2JBwDr5fsngwmJs=
 | 
			
		||||
github.com/jackc/pgx/v5 v5.7.5/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
 | 
			
		||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
 | 
			
		||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
 | 
			
		||||
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
 | 
			
		||||
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
 | 
			
		||||
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
 | 
			
		||||
@ -205,6 +213,10 @@ github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZ
 | 
			
		||||
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
 | 
			
		||||
github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc=
 | 
			
		||||
github.com/jellydator/ttlcache/v3 v3.3.0/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw=
 | 
			
		||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
 | 
			
		||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
 | 
			
		||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
 | 
			
		||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
 | 
			
		||||
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/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 | 
			
		||||
@ -308,6 +320,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
 | 
			
		||||
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 | 
			
		||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
 | 
			
		||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
 | 
			
		||||
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
 | 
			
		||||
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
 | 
			
		||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 | 
			
		||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 | 
			
		||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
 | 
			
		||||
@ -415,6 +429,8 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w
 | 
			
		||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
 | 
			
		||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
 | 
			
		||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
 | 
			
		||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
 | 
			
		||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
			
		||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
			
		||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
			
		||||
@ -422,6 +438,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 | 
			
		||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
			
		||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
 | 
			
		||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
 | 
			
		||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
 | 
			
		||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
 | 
			
		||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 | 
			
		||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 | 
			
		||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 | 
			
		||||
@ -555,6 +573,10 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
			
		||||
gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
 | 
			
		||||
gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo=
 | 
			
		||||
gorm.io/gorm v1.30.0 h1:qbT5aPv1UH8gI99OsRlvDToLxW5zR7FzS9acZDOZcgs=
 | 
			
		||||
gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
 | 
			
		||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 | 
			
		||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 | 
			
		||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ type Config struct {
 | 
			
		||||
	Storage        StorageConfig        `yaml:"storage"`
 | 
			
		||||
	LogLevel       string               `yaml:"log_level" env:"AUTHENTIK_LOG_LEVEL, overwrite"`
 | 
			
		||||
	ErrorReporting ErrorReportingConfig `yaml:"error_reporting" env:", prefix=AUTHENTIK_ERROR_REPORTING__"`
 | 
			
		||||
	Postgresql     PostgresqlConfig     `yaml:"postgresql" env:", prefix=AUTHENTIK_POSTGRESQL__"`
 | 
			
		||||
	Redis          RedisConfig          `yaml:"redis" env:", prefix=AUTHENTIK_REDIS__"`
 | 
			
		||||
	Outposts       OutpostConfig        `yaml:"outposts" env:", prefix=AUTHENTIK_OUTPOSTS__"`
 | 
			
		||||
 | 
			
		||||
@ -25,6 +26,16 @@ type Config struct {
 | 
			
		||||
	AuthentikInsecure    bool   `env:"AUTHENTIK_INSECURE"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: SSL
 | 
			
		||||
type PostgresqlConfig struct {
 | 
			
		||||
	Host          string `yaml:"host" env:"HOST, overwrite"`
 | 
			
		||||
	Port          string `yaml:"port" env:"PORT, overwrite"`
 | 
			
		||||
	User          string `yaml:"user" env:"USER, overwrite"`
 | 
			
		||||
	Password      string `yaml:"password" env:"PASSWORD, overwrite"`
 | 
			
		||||
	Name          string `yaml:"name" env:"NAME, overwrite"`
 | 
			
		||||
	DefaultSchema string `yaml:"default_schema" env:"DEFAULT_SCHEMA, overwrite"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RedisConfig struct {
 | 
			
		||||
	Host      string `yaml:"host" env:"HOST, overwrite"`
 | 
			
		||||
	Port      int    `yaml:"port" env:"PORT, overwrite"`
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										62
									
								
								internal/web/files.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								internal/web/files.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
			
		||||
package web
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-http-utils/etag"
 | 
			
		||||
	"github.com/gorilla/mux"
 | 
			
		||||
 | 
			
		||||
	"goauthentik.io/internal/config"
 | 
			
		||||
	"goauthentik.io/internal/constants"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type File struct {
 | 
			
		||||
	ID string `gorm:"primaryKey"`
 | 
			
		||||
 | 
			
		||||
	Name     string
 | 
			
		||||
	Content  []byte
 | 
			
		||||
	Location string
 | 
			
		||||
	Public   bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ws *WebServer) configureFiles() {
 | 
			
		||||
	// Setup routers
 | 
			
		||||
	filesRouter := ws.loggingRouter.NewRoute().Subrouter()
 | 
			
		||||
	filesRouter.Use(ws.filesHeaderMiddleware)
 | 
			
		||||
 | 
			
		||||
	filesRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/files/public/{pk}").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		vars := mux.Vars(r)
 | 
			
		||||
 | 
			
		||||
		pk := vars["pk"]
 | 
			
		||||
 | 
			
		||||
		var file File
 | 
			
		||||
		ws.postgresClient.First(&file, "id = ? AND public = true AND content <> NULL", pk)
 | 
			
		||||
 | 
			
		||||
		// TODO: get from DB
 | 
			
		||||
		rw.Write(file.Content)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	filesRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/files/private/{pk}").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		vars := mux.Vars(r)
 | 
			
		||||
 | 
			
		||||
		// TODO: check session
 | 
			
		||||
 | 
			
		||||
		pk := vars["pk"]
 | 
			
		||||
 | 
			
		||||
		var file File
 | 
			
		||||
		ws.postgresClient.First(&file, "id = ? AND content <> NULL", pk)
 | 
			
		||||
 | 
			
		||||
		rw.Write([]byte(file.Content))
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: anything else?
 | 
			
		||||
func (ws *WebServer) filesHeaderMiddleware(h http.Handler) http.Handler {
 | 
			
		||||
	etagHandler := etag.Handler(h, false)
 | 
			
		||||
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		w.Header().Set("Cache-Control", "public, no-transform")
 | 
			
		||||
		w.Header().Set("X-authentik-version", constants.VERSION)
 | 
			
		||||
		w.Header().Set("Vary", "X-authentik-version, Etag")
 | 
			
		||||
		etagHandler.ServeHTTP(w, r)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
@ -17,6 +17,8 @@ import (
 | 
			
		||||
	"github.com/gorilla/securecookie"
 | 
			
		||||
	"github.com/pires/go-proxyproto"
 | 
			
		||||
	log "github.com/sirupsen/logrus"
 | 
			
		||||
	"gorm.io/driver/postgres"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
 | 
			
		||||
	"goauthentik.io/api/v3"
 | 
			
		||||
	"goauthentik.io/internal/config"
 | 
			
		||||
@ -49,6 +51,7 @@ type WebServer struct {
 | 
			
		||||
	mainRouter     *mux.Router
 | 
			
		||||
	loggingRouter  *mux.Router
 | 
			
		||||
	log            *log.Entry
 | 
			
		||||
	postgresClient *gorm.DB
 | 
			
		||||
	upstreamClient *http.Client
 | 
			
		||||
	upstreamURL    *url.URL
 | 
			
		||||
 | 
			
		||||
@ -64,6 +67,21 @@ func NewWebServer() *WebServer {
 | 
			
		||||
	loggingHandler := mainHandler.NewRoute().Subrouter()
 | 
			
		||||
	loggingHandler.Use(web.NewLoggingHandler(l, nil))
 | 
			
		||||
 | 
			
		||||
	// TODO: ssl
 | 
			
		||||
	postgresDsn := fmt.Sprintf(
 | 
			
		||||
		"host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
 | 
			
		||||
		config.Get().Postgresql.Host,
 | 
			
		||||
		config.Get().Postgresql.Port,
 | 
			
		||||
		config.Get().Postgresql.User,
 | 
			
		||||
		config.Get().Postgresql.Password,
 | 
			
		||||
		config.Get().Postgresql.Name,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	db, err := gorm.Open(postgres.Open(postgresDsn), &gorm.Config{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tmp := os.TempDir()
 | 
			
		||||
	socketPath := path.Join(tmp, UnixSocketName)
 | 
			
		||||
 | 
			
		||||
@ -88,6 +106,7 @@ func NewWebServer() *WebServer {
 | 
			
		||||
		mainRouter:     mainHandler,
 | 
			
		||||
		loggingRouter:  loggingHandler,
 | 
			
		||||
		log:            l,
 | 
			
		||||
		postgresClient: db,
 | 
			
		||||
		gunicornReady:  false,
 | 
			
		||||
		upstreamClient: upstreamClient,
 | 
			
		||||
		upstreamURL:    u,
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user