GooDrive/backend/drive/views_content.py
Louis Mazin 97a25e4df8 nice
2026-10-13 21:15:53 +02:00

51 lines
2.4 KiB
Python

"""Expiring download links and secure file streaming endpoints."""
from pathlib import Path
from django.conf import settings
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
from django.http import FileResponse, Http404
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from .services import error, get_item, readable, chain
@api_view(['POST'])
def content_url(request,item_id):
item=get_item(item_id)
if item.is_folder or not readable(item,request.user):return error('Fichier inaccessible.',403)
inline=bool(request.data.get('inline',False))
safe_types={'image/jpeg','image/png','image/gif','image/webp','application/pdf',
'audio/mpeg','audio/ogg','audio/wav','audio/mp4'}
if inline and item.mime_type not in safe_types:
return error('Aperçu non disponible pour ce type de fichier.')
token=TimestampSigner(salt='drive-content').sign(f'{item.pk}:{1 if inline else 0}')
return Response({'url':f'/api/drive/items/{item.pk}/content/?token={token}',
'expires_in':300})
@api_view(['GET'])
@permission_classes([AllowAny])
def content(request,item_id):
# A short-lived signed URL permits native streaming/inline display without storing a JWT in the URL.
token=request.query_params.get('token','')
try:
value=TimestampSigner(salt='drive-content').unsign(token,max_age=300)
expected,inline=value.rsplit(':',1)
if expected!=str(item_id) or inline not in ('0','1'):raise BadSignature()
except (BadSignature,SignatureExpired,ValueError):
raise Http404
item=get_item(item_id)
if item.is_folder or item.trashed_at:raise Http404
if any(n.trashed_at for n in chain(item)):raise Http404
# Authorization performed when URL was minted, 5-minute token is a bearer credential.
key=item.storage_key
if not key or len(key)!=36:
raise Http404
path=Path(settings.DRIVE_STORAGE_ROOT)/key[:2]/key
if not path.is_file():raise Http404
response=FileResponse(open(path,'rb'),as_attachment=inline=='0',filename=item.name,
content_type=item.mime_type if inline=='1' else 'application/octet-stream')
response['Cache-Control']='private, no-store'
response['X-Content-Type-Options']='nosniff'
return response