forked from CGM_Public/pretix_original
[SECURITY] Bind relevant cached file downloads to the current session
This commit is contained in:
23
src/pretix/base/migrations/0162b_auto_20201218_1810.py
Normal file
23
src/pretix/base/migrations/0162b_auto_20201218_1810.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 3.0.11 on 2020-12-18 18:10
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pretixbase', '0173_auto_20201211_1648'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='cachedfile',
|
||||||
|
name='session_key',
|
||||||
|
field=models.TextField(null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='cachedfile',
|
||||||
|
name='web_download',
|
||||||
|
field=models.BooleanField(default=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -28,6 +28,8 @@ class CachedFile(models.Model):
|
|||||||
filename = models.CharField(max_length=255)
|
filename = models.CharField(max_length=255)
|
||||||
type = models.CharField(max_length=255)
|
type = models.CharField(max_length=255)
|
||||||
file = models.FileField(null=True, blank=True, upload_to=cachedfile_name, max_length=255)
|
file = models.FileField(null=True, blank=True, upload_to=cachedfile_name, max_length=255)
|
||||||
|
web_download = models.BooleanField(default=True) # allow web download, True for backwards compatibility in plugins
|
||||||
|
session_key = models.TextField(null=True, blank=True) # only allow download in this session
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_delete, sender=CachedFile)
|
@receiver(post_delete, sender=CachedFile)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ from pretix.celery_app import app
|
|||||||
|
|
||||||
|
|
||||||
@app.task(base=ProfiledEventTask)
|
@app.task(base=ProfiledEventTask)
|
||||||
def export(event: Event, shredders: List[str]) -> None:
|
def export(event: Event, shredders: List[str], session_key=None) -> None:
|
||||||
known_shredders = event.get_data_shredders()
|
known_shredders = event.get_data_shredders()
|
||||||
|
|
||||||
with NamedTemporaryFile() as rawfile:
|
with NamedTemporaryFile() as rawfile:
|
||||||
@@ -54,7 +54,9 @@ def export(event: Event, shredders: List[str]) -> None:
|
|||||||
cf = CachedFile()
|
cf = CachedFile()
|
||||||
cf.date = now()
|
cf.date = now()
|
||||||
cf.filename = event.slug + '.zip'
|
cf.filename = event.slug + '.zip'
|
||||||
cf.type = 'application/pdf'
|
cf.type = 'application/zip'
|
||||||
|
cf.session_key = session_key
|
||||||
|
cf.web_download = True
|
||||||
cf.expires = now() + timedelta(hours=1)
|
cf.expires = now() + timedelta(hours=1)
|
||||||
cf.save()
|
cf.save()
|
||||||
cf.file.save(cachedfile_name(cf, cf.filename), rawfile)
|
cf.file.save(cachedfile_name(cf, cf.filename), rawfile)
|
||||||
|
|||||||
@@ -13,7 +13,11 @@ class DownloadView(TemplateView):
|
|||||||
@cached_property
|
@cached_property
|
||||||
def object(self) -> CachedFile:
|
def object(self) -> CachedFile:
|
||||||
try:
|
try:
|
||||||
return get_object_or_404(CachedFile, id=self.kwargs['id'])
|
o = get_object_or_404(CachedFile, id=self.kwargs['id'], web_download=True)
|
||||||
|
if o.session_key:
|
||||||
|
if o.session_key != self.request.session.session_key:
|
||||||
|
raise Http404()
|
||||||
|
return o
|
||||||
except ValueError: # Invalid URLs
|
except ValueError: # Invalid URLs
|
||||||
raise Http404()
|
raise Http404()
|
||||||
|
|
||||||
|
|||||||
@@ -1956,7 +1956,7 @@ class ExportDoView(EventPermissionRequiredMixin, ExportMixin, AsyncAction, View)
|
|||||||
messages.error(self.request, _('There was a problem processing your input. See below for error details.'))
|
messages.error(self.request, _('There was a problem processing your input. See below for error details.'))
|
||||||
return self.get(request, *args, **kwargs)
|
return self.get(request, *args, **kwargs)
|
||||||
|
|
||||||
cf = CachedFile()
|
cf = CachedFile(web_download=True, session_key=request.session.session_key)
|
||||||
cf.date = now()
|
cf.date = now()
|
||||||
cf.expires = now() + timedelta(days=3)
|
cf.expires = now() + timedelta(days=3)
|
||||||
cf.save()
|
cf.save()
|
||||||
|
|||||||
@@ -1238,7 +1238,7 @@ class ExportDoView(OrganizerPermissionRequiredMixin, ExportMixin, AsyncAction, V
|
|||||||
messages.error(self.request, _('There was a problem processing your input. See below for error details.'))
|
messages.error(self.request, _('There was a problem processing your input. See below for error details.'))
|
||||||
return self.get(request, *args, **kwargs)
|
return self.get(request, *args, **kwargs)
|
||||||
|
|
||||||
cf = CachedFile()
|
cf = CachedFile(web_download=True, session_key=request.session.session_key)
|
||||||
cf.date = now()
|
cf.date = now()
|
||||||
cf.expires = now() + timedelta(days=3)
|
cf.expires = now() + timedelta(days=3)
|
||||||
cf.save()
|
cf.save()
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ class BaseEditorView(EventPermissionRequiredMixin, TemplateView):
|
|||||||
buffer = BytesIO()
|
buffer = BytesIO()
|
||||||
p.write(buffer)
|
p.write(buffer)
|
||||||
buffer.seek(0)
|
buffer.seek(0)
|
||||||
c = CachedFile()
|
c = CachedFile(web_download=True)
|
||||||
c.expires = now() + timedelta(days=7)
|
c.expires = now() + timedelta(days=7)
|
||||||
c.date = now()
|
c.date = now()
|
||||||
c.filename = 'background_preview.pdf'
|
c.filename = 'background_preview.pdf'
|
||||||
@@ -162,7 +162,7 @@ class BaseEditorView(EventPermissionRequiredMixin, TemplateView):
|
|||||||
"status": "error",
|
"status": "error",
|
||||||
"error": error
|
"error": error
|
||||||
})
|
})
|
||||||
c = CachedFile()
|
c = CachedFile(web_download=True)
|
||||||
c.expires = now() + timedelta(days=7)
|
c.expires = now() + timedelta(days=7)
|
||||||
c.date = now()
|
c.date = now()
|
||||||
c.filename = 'background_preview.pdf'
|
c.filename = 'background_preview.pdf'
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ class ShredExportView(RecentAuthenticationRequiredMixin, EventPermissionRequired
|
|||||||
if constr:
|
if constr:
|
||||||
return self.error(ShredError(self.get_error_url()))
|
return self.error(ShredError(self.get_error_url()))
|
||||||
|
|
||||||
return self.do(self.request.event.id, request.POST.getlist("shredder"))
|
return self.do(self.request.event.id, request.POST.getlist("shredder"), self.request.session.session_key)
|
||||||
|
|
||||||
|
|
||||||
class ShredDoView(RecentAuthenticationRequiredMixin, EventPermissionRequiredMixin, ShredderMixin, AsyncAction, View):
|
class ShredDoView(RecentAuthenticationRequiredMixin, EventPermissionRequiredMixin, ShredderMixin, AsyncAction, View):
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ class OrderPrintDo(EventPermissionRequiredMixin, AsyncAction, View):
|
|||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
order = get_object_or_404(self.request.event.orders, code=request.GET.get("code"))
|
order = get_object_or_404(self.request.event.orders, code=request.GET.get("code"))
|
||||||
cf = CachedFile()
|
cf = CachedFile(web_download=True, session_key=self.request.session.session_key)
|
||||||
cf.date = now()
|
cf.date = now()
|
||||||
cf.type = 'application/pdf'
|
cf.type = 'application/pdf'
|
||||||
cf.expires = now() + timedelta(days=3)
|
cf.expires = now() + timedelta(days=3)
|
||||||
|
|||||||
Reference in New Issue
Block a user