API & Client: set file size limit for upload - fix #33

This commit is contained in:
Sam
2019-08-31 14:11:00 +02:00
parent b72f4e8313
commit 8fc71ed178
11 changed files with 120 additions and 22 deletions

View File

@ -11,7 +11,7 @@ from ..users.utils import (
User,
authenticate,
can_view_activity,
verify_extension,
verify_extension_and_size,
)
from .models import Activity
from .utils import (
@ -818,12 +818,15 @@ def post_activity(auth_user_id):
- Provide a valid auth token.
- Signature expired. Please log in again.
- Invalid token. Please log in again.
:statuscode 413: Error during picture update: file size exceeds 1.0MB.
:statuscode 500:
"""
response_object = verify_extension('activity', request)
response_object, response_code = verify_extension_and_size(
'activity', request
)
if response_object['status'] != 'success':
return jsonify(response_object), 400
return jsonify(response_object), response_code
activity_data = json.loads(request.form["data"])
if not activity_data or activity_data.get('sport_id') is None:

View File

@ -2,6 +2,8 @@ import os
from flask import current_app
MAX_FILE_SIZE = 1 * 1024 * 1024 # 1MB
class BaseConfig:
"""Base configuration"""
@ -13,6 +15,14 @@ class BaseConfig:
TOKEN_EXPIRATION_DAYS = 30
TOKEN_EXPIRATION_SECONDS = 0
UPLOAD_FOLDER = os.path.join(current_app.root_path, 'uploads')
# for gpx zip
MAX_CONTENT_LENGTH = int(
os.environ.get('REACT_APP_MAX_ZIP_FILE_SIZE', MAX_FILE_SIZE * 10)
)
# for single file (gpx or picture)
MAX_SINGLE_FILE = int(
os.environ.get('REACT_APP_MAX_SINGLE_FILE_SIZE', MAX_FILE_SIZE)
)
PICTURE_ALLOWED_EXTENSIONS = {'jpg', 'png', 'gif'}
ACTIVITY_ALLOWED_EXTENSIONS = {'gpx', 'zip'}
REGISTRATION_ALLOWED = (

View File

@ -4,11 +4,17 @@ import os
from fittrackee_api import appLog, bcrypt, db
from flask import Blueprint, current_app, jsonify, request
from sqlalchemy import exc, or_
from werkzeug.exceptions import RequestEntityTooLarge
from werkzeug.utils import secure_filename
from ..activities.utils_files import get_absolute_file_path
from .models import User
from .utils import authenticate, register_controls, verify_extension
from .utils import (
authenticate,
display_readable_file_size,
register_controls,
verify_extension_and_size,
)
auth_blueprint = Blueprint('auth', __name__)
@ -529,13 +535,25 @@ def edit_picture(user_id):
- Provide a valid auth token.
- Signature expired. Please log in again.
- Invalid token. Please log in again.
:statuscode 413: Error during picture update: file size exceeds 1.0MB.
:statuscode 500: Error during picture update.
"""
code = 400
response_object = verify_extension('picture', request)
try:
response_object, response_code = verify_extension_and_size(
'picture', request
)
except RequestEntityTooLarge as e:
appLog.error(e)
max_file_size = current_app.config['MAX_CONTENT_LENGTH']
response_object = {
'status': 'fail',
'message': 'Error during picture update: file size exceeds '
f'{display_readable_file_size(max_file_size)}.',
}
return jsonify(response_object), 413
if response_object['status'] != 'success':
return jsonify(response_object), code
return jsonify(response_object), response_code
file = request.files['file']
filename = secure_filename(file.filename)

View File

@ -29,17 +29,18 @@ def register_controls(username, email, password, password_conf):
return ret
def verify_extension(file_type, req):
def verify_extension_and_size(file_type, req):
response_object = {'status': 'success'}
code = 400
if 'file' not in req.files:
response_object = {'status': 'fail', 'message': 'No file part.'}
return response_object
return response_object, code
file = req.files['file']
if file.filename == '':
response_object = {'status': 'fail', 'message': 'No selected file.'}
return response_object
return response_object, code
allowed_extensions = (
'ACTIVITY_ALLOWED_EXTENSIONS'
@ -47,17 +48,30 @@ def verify_extension(file_type, req):
else 'PICTURE_ALLOWED_EXTENSIONS'
)
file_extension = (
file.filename.rsplit('.', 1)[1].lower()
if '.' in file.filename
else None
)
max_file_size = current_app.config['MAX_SINGLE_FILE']
if not (
'.' in file.filename
and file.filename.rsplit('.', 1)[1].lower()
in current_app.config.get(allowed_extensions)
file_extension
and file_extension in current_app.config.get(allowed_extensions)
):
response_object = {
'status': 'fail',
'message': 'File extension not allowed.',
}
elif file_extension != 'zip' and req.content_length > max_file_size:
response_object = {
'status': 'fail',
'message': 'Error during picture update: file size exceeds '
f'{display_readable_file_size(max_file_size)}.',
}
code = 413
return response_object
return response_object, code
def verify_user(current_request, verify_admin):
@ -116,3 +130,15 @@ def can_view_activity(auth_user_id, activity_user_id):
}
return response_object, 403
return None, None
def display_readable_file_size(size_in_bytes):
if size_in_bytes == 0:
return '0 bytes'
if size_in_bytes == 1:
return '1 byte'
for unit in [' bytes', 'KB', 'MB', 'GB', 'TB']:
if abs(size_in_bytes) < 1024.0:
return f"{size_in_bytes:3.1f}{unit}"
size_in_bytes /= 1024.0
return f"{size_in_bytes} bytes"