- Add max-h-[90vh] and flex-col to modal content container - Wrap tools grid in max-h-[50vh] overflow-y-auto container - Add overscroll-contain for smooth scroll behavior on mobile - Fixes issue where 21 PDF tools overflow viewport on small screens
97 lines
4.1 KiB
Python
97 lines
4.1 KiB
Python
"""Tests for file download route."""
|
|
import os
|
|
|
|
from app.services.account_service import create_user
|
|
from app.utils.auth import TASK_ACCESS_SESSION_KEY
|
|
|
|
|
|
class TestDownload:
|
|
def test_download_anonymous_returns_401(self, client):
|
|
"""Anonymous users should be blocked by the download gate."""
|
|
response = client.get('/api/download/some-task-id/output.pdf')
|
|
assert response.status_code == 401
|
|
assert response.get_json()['error'] == 'signup_required'
|
|
|
|
def test_download_nonexistent_file(self, client, app):
|
|
"""Should return 404 for missing file when authenticated."""
|
|
with app.app_context():
|
|
user = create_user('download-test@example.com', 'pass12345')
|
|
with client.session_transaction() as session:
|
|
session['user_id'] = user['id']
|
|
session[TASK_ACCESS_SESSION_KEY] = ['some-task-id']
|
|
response = client.get('/api/download/some-task-id/output.pdf')
|
|
assert response.status_code == 404
|
|
|
|
def test_download_path_traversal_task_id(self, client):
|
|
"""Should reject task_id with path traversal characters."""
|
|
response = client.get('/api/download/../etc/output.pdf')
|
|
# Flask will handle this — either 400 or 404
|
|
assert response.status_code in (400, 404)
|
|
|
|
def test_download_path_traversal_filename(self, client):
|
|
"""Should reject filename with path traversal characters."""
|
|
response = client.get('/api/download/valid-id/../../etc/passwd')
|
|
assert response.status_code in (400, 404)
|
|
|
|
def test_download_valid_file(self, client, app):
|
|
"""Should serve file if it exists and user is authenticated."""
|
|
task_id = 'test-download-id'
|
|
filename = 'output.pdf'
|
|
|
|
with app.app_context():
|
|
user = create_user('download-valid@example.com', 'pass12345')
|
|
|
|
# Create the file in the output directory
|
|
output_dir = os.path.join(app.config['OUTPUT_FOLDER'], task_id)
|
|
os.makedirs(output_dir, exist_ok=True)
|
|
file_path = os.path.join(output_dir, filename)
|
|
with open(file_path, 'wb') as f:
|
|
f.write(b'%PDF-1.4 test content')
|
|
|
|
with client.session_transaction() as session:
|
|
session['user_id'] = user['id']
|
|
session[TASK_ACCESS_SESSION_KEY] = [task_id]
|
|
|
|
response = client.get(f'/api/download/{task_id}/{filename}')
|
|
assert response.status_code == 200
|
|
assert response.data == b'%PDF-1.4 test content'
|
|
|
|
def test_download_with_custom_name(self, client, app):
|
|
"""Should use the ?name= parameter as download filename."""
|
|
task_id = 'test-name-id'
|
|
filename = 'output.pdf'
|
|
|
|
with app.app_context():
|
|
user = create_user('download-name@example.com', 'pass12345')
|
|
|
|
output_dir = os.path.join(app.config['OUTPUT_FOLDER'], task_id)
|
|
os.makedirs(output_dir, exist_ok=True)
|
|
with open(os.path.join(output_dir, filename), 'wb') as f:
|
|
f.write(b'%PDF-1.4')
|
|
|
|
with client.session_transaction() as session:
|
|
session['user_id'] = user['id']
|
|
session[TASK_ACCESS_SESSION_KEY] = [task_id]
|
|
|
|
response = client.get(f'/api/download/{task_id}/{filename}?name=my-document.pdf')
|
|
assert response.status_code == 200
|
|
|
|
def test_download_requires_task_access(self, client, app):
|
|
"""Should not serve an existing file without task access, even if authenticated."""
|
|
task_id = 'protected-download-id'
|
|
filename = 'output.pdf'
|
|
|
|
with app.app_context():
|
|
user = create_user('download-noaccess@example.com', 'pass12345')
|
|
|
|
output_dir = os.path.join(app.config['OUTPUT_FOLDER'], task_id)
|
|
os.makedirs(output_dir, exist_ok=True)
|
|
with open(os.path.join(output_dir, filename), 'wb') as f:
|
|
f.write(b'%PDF-1.4 protected')
|
|
|
|
with client.session_transaction() as session:
|
|
session['user_id'] = user['id']
|
|
# No TASK_ACCESS_SESSION_KEY set — user can't access this task
|
|
|
|
response = client.get(f'/api/download/{task_id}/{filename}')
|
|
assert response.status_code == 404 |