diff --git a/CTFd/utils/uploads/uploaders.py b/CTFd/utils/uploads/uploaders.py index 1b90c201..f802edf4 100644 --- a/CTFd/utils/uploads/uploaders.py +++ b/CTFd/utils/uploads/uploaders.py @@ -1,6 +1,8 @@ +import datetime import os import posixpath import string +import time from pathlib import PurePath from shutil import copyfileobj, rmtree @@ -8,6 +10,7 @@ import boto3 from botocore.client import Config from flask import current_app, redirect, send_file from flask.helpers import safe_join +from freezegun import freeze_time from werkzeug.utils import secure_filename from CTFd.utils import get_app_config @@ -119,18 +122,25 @@ class S3Uploader(BaseUploader): return dst def download(self, filename): + # S3 URLs by default are valid for one hour. + # We round the timestamp down to the previous hour and generate the link at that time + current_timestamp = int(time.time()) + truncated_timestamp = current_timestamp - (current_timestamp % 3600) key = filename filename = filename.split("/").pop() - url = self.s3.generate_presigned_url( - "get_object", - Params={ - "Bucket": self.bucket, - "Key": key, - "ResponseContentDisposition": "attachment; filename={}".format( - filename - ), - }, - ) + with freeze_time(datetime.datetime.fromtimestamp(truncated_timestamp)): + url = self.s3.generate_presigned_url( + "get_object", + Params={ + "Bucket": self.bucket, + "Key": key, + "ResponseContentDisposition": "attachment; filename={}".format( + filename + ), + "ResponseCacheControl": "max-age=3600", + }, + ExpiresIn=3600, + ) return redirect(url) def delete(self, filename): diff --git a/development.txt b/development.txt index 13b33105..100f2b01 100644 --- a/development.txt +++ b/development.txt @@ -4,7 +4,6 @@ pytest==5.4.2 pytest-randomly==3.4.0 coverage==5.1 flake8==3.8.2 -freezegun==0.3.15 psycopg2-binary==2.8.6 codecov==2.1.7 moto==1.3.16 diff --git a/requirements.in b/requirements.in index db8f653a..cc1e253c 100644 --- a/requirements.in +++ b/requirements.in @@ -29,3 +29,4 @@ python-geoacumen-city==2023.1.15 maxminddb==1.5.4 tenacity==6.2.0 pybluemonday==0.0.9 +freezegun==1.2.2 diff --git a/requirements.txt b/requirements.txt index f9db78da..1b8a81a4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -59,6 +59,8 @@ flask-sqlalchemy==2.4.3 # via # -r requirements.in # flask-migrate +freezegun==1.2.2 + # via -r requirements.in gevent==22.10.2 # via -r requirements.in greenlet==2.0.1 @@ -115,6 +117,7 @@ python-dateutil==2.8.1 # via # alembic # botocore + # freezegun python-dotenv==0.13.0 # via -r requirements.in python-editor==1.0.4