From b39d16eaf84c293c8bd3c3c21e47eb4b3f90a878 Mon Sep 17 00:00:00 2001 From: Jan Friedli Date: Mon, 13 Jul 2020 09:52:34 +0200 Subject: [PATCH] added baspath used for fuzzing and use blueprints for api routes --- main.py | 19 ++------------- matweb/rest_api.py | 59 ++++++++++++++++++++++++++-------------------- 2 files changed, 35 insertions(+), 43 deletions(-) diff --git a/main.py b/main.py index a836c13..87e9c16 100644 --- a/main.py +++ b/main.py @@ -17,6 +17,7 @@ def create_app(test_config=None): app.config['SWAGGER'] = { 'title': 'Mat2 Web API', 'version': '1.0.0', + 'basePath': '/api' } # optionally load settings from config.py app.config.from_object('config') @@ -32,25 +33,9 @@ def create_app(test_config=None): app.register_blueprint(frontend.routes) # Restful API hookup - api = Api(app) + app.register_blueprint(rest_api.api_bp) Swagger(app) CORS(app, resources={r"/api/*": {"origins": utils.get_allow_origin_header_value()}}) - api.add_resource( - rest_api.APIUpload, - '/api/upload', - resource_class_kwargs={'upload_folder': app.config['UPLOAD_FOLDER']} - ) - api.add_resource( - rest_api.APIDownload, - '/api/download///', - resource_class_kwargs={'upload_folder': app.config['UPLOAD_FOLDER']} - ) - api.add_resource( - rest_api.APIBulkDownloadCreator, - '/api/download/bulk', - resource_class_kwargs={'upload_folder': app.config['UPLOAD_FOLDER']} - ) - api.add_resource(rest_api.APISupportedExtensions, '/api/extension') return app diff --git a/matweb/rest_api.py b/matweb/rest_api.py index 2bf44f0..4910b44 100644 --- a/matweb/rest_api.py +++ b/matweb/rest_api.py @@ -5,8 +5,8 @@ import binascii import zipfile from uuid import uuid4 -from flask import after_this_request, send_from_directory -from flask_restful import Resource, reqparse, abort, request, url_for +from flask import after_this_request, send_from_directory, Blueprint, current_app +from flask_restful import Resource, reqparse, abort, request, url_for, Api from cerberus import Validator from werkzeug.datastructures import FileStorage from flasgger import swag_from @@ -15,14 +15,14 @@ from flasgger import swag_from from matweb import file_removal_scheduler, utils -class APIUpload(Resource): - - def __init__(self, **kwargs): - self.upload_folder = kwargs['upload_folder'] +api_bp = Blueprint('api_bp', __name__, url_prefix='/api/') +api = Api(api_bp) + +class APIUpload(Resource): @swag_from('./oas/upload.yml') def post(self): - utils.check_upload_folder(self.upload_folder) + utils.check_upload_folder(current_app.config['UPLOAD_FOLDER']) req_parser = reqparse.RequestParser() req_parser.add_argument('file_name', type=str, required=True, help='Post parameter is not specified: file_name') req_parser.add_argument('file', type=str, required=True, help='Post parameter is not specified: file') @@ -35,7 +35,7 @@ class APIUpload(Resource): file = FileStorage(stream=io.BytesIO(file_data), filename=args['file_name']) try: - filename, filepath = utils.save_file(file, self.upload_folder) + filename, filepath = utils.save_file(file, current_app.config['UPLOAD_FOLDER']) except ValueError: abort(400, message='Invalid Filename') @@ -48,7 +48,7 @@ class APIUpload(Resource): if not parser.remove_all(): abort(500, message='Unable to clean %s' % mime) - key, secret, meta_after, output_filename = utils.cleanup(parser, filepath, self.upload_folder) + key, secret, meta_after, output_filename = utils.cleanup(parser, filepath, current_app.config['UPLOAD_FOLDER']) return utils.return_file_created_response( utils.get_file_removal_max_age_sec(), output_filename, @@ -58,7 +58,7 @@ class APIUpload(Resource): meta, meta_after, url_for( - 'apidownload', + 'api_bp.apidownload', key=key, secret=secret, filename=output_filename, @@ -68,16 +68,12 @@ class APIUpload(Resource): class APIDownload(Resource): - - def __init__(self, **kwargs): - self.upload_folder = kwargs['upload_folder'] - @swag_from('./oas/download.yml') def get(self, key: str, secret: str, filename: str): - complete_path, filepath = utils.is_valid_api_download_file(filename, key, secret, self.upload_folder) + complete_path, filepath = utils.is_valid_api_download_file(filename, key, secret, current_app.config['UPLOAD_FOLDER']) # Make sure the file is NOT deleted on HEAD requests if request.method == 'GET': - file_removal_scheduler.run_file_removal_job(self.upload_folder) + file_removal_scheduler.run_file_removal_job(current_app.config['UPLOAD_FOLDER']) @after_this_request def remove_file(response): @@ -85,14 +81,10 @@ class APIDownload(Resource): os.remove(complete_path) return response - return send_from_directory(self.upload_folder, filepath, as_attachment=True) + return send_from_directory(current_app.config['UPLOAD_FOLDER'], filepath, as_attachment=True) class APIBulkDownloadCreator(Resource): - - def __init__(self, **kwargs): - self.upload_folder = kwargs['upload_folder'] - schema = { 'download_list': { 'type': 'list', @@ -112,13 +104,13 @@ class APIBulkDownloadCreator(Resource): @swag_from('./oas/bulk.yml') def post(self): - utils.check_upload_folder(self.upload_folder) + utils.check_upload_folder(current_app.config['UPLOAD_FOLDER']) data = request.json if not self.v.validate(data): abort(400, message=self.v.errors) # prevent the zip file from being overwritten zip_filename = 'files.' + str(uuid4()) + '.zip' - zip_path = os.path.join(self.upload_folder, zip_filename) + zip_path = os.path.join(current_app.config['UPLOAD_FOLDER'], zip_filename) cleaned_files_zip = zipfile.ZipFile(zip_path, 'w') with cleaned_files_zip: for file_candidate in data['download_list']: @@ -126,7 +118,7 @@ class APIBulkDownloadCreator(Resource): file_candidate['file_name'], file_candidate['key'], file_candidate['secret'], - self.upload_folder + current_app.config['UPLOAD_FOLDER'] ) try: cleaned_files_zip.write(complete_path) @@ -142,7 +134,7 @@ class APIBulkDownloadCreator(Resource): parser, mime = utils.get_file_parser(zip_path) if not parser.remove_all(): abort(500, message='Unable to clean %s' % mime) - key, secret, meta_after, output_filename = utils.cleanup(parser, zip_path, self.upload_folder) + key, secret, meta_after, output_filename = utils.cleanup(parser, zip_path, current_app.config['UPLOAD_FOLDER']) return { 'inactive_after_sec': utils.get_file_removal_max_age_sec(), 'output_filename': output_filename, @@ -151,7 +143,7 @@ class APIBulkDownloadCreator(Resource): 'secret': secret, 'meta_after': meta_after, 'download_link': url_for( - 'apidownload', + 'api_bp.apidownload', key=key, secret=secret, filename=output_filename, @@ -164,3 +156,18 @@ class APISupportedExtensions(Resource): @swag_from('./oas/extension.yml') def get(self): return utils.get_supported_extensions() + + +api.add_resource( + APIUpload, + '/upload' + ) +api.add_resource( + APIDownload, + '/download///' +) +api.add_resource( + APIBulkDownloadCreator, + '/download/bulk' +) +api.add_resource(APISupportedExtensions, '/extension')