summaryrefslogtreecommitdiff
path: root/matweb/rest_api.py
diff options
context:
space:
mode:
authorJan Friedli2020-07-13 09:52:34 +0200
committerJan Friedli2020-07-13 09:52:34 +0200
commitb39d16eaf84c293c8bd3c3c21e47eb4b3f90a878 (patch)
tree57c0cd3bf6f055c4f1ee4f35af53a47b2e957fbf /matweb/rest_api.py
parente258b3084d62c9d028f5b92ca242d8a975a2af86 (diff)
added baspath used for fuzzing and use blueprints for api routes
Diffstat (limited to '')
-rw-r--r--matweb/rest_api.py59
1 files changed, 33 insertions, 26 deletions
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
5import zipfile 5import zipfile
6from uuid import uuid4 6from uuid import uuid4
7 7
8from flask import after_this_request, send_from_directory 8from flask import after_this_request, send_from_directory, Blueprint, current_app
9from flask_restful import Resource, reqparse, abort, request, url_for 9from flask_restful import Resource, reqparse, abort, request, url_for, Api
10from cerberus import Validator 10from cerberus import Validator
11from werkzeug.datastructures import FileStorage 11from werkzeug.datastructures import FileStorage
12from flasgger import swag_from 12from flasgger import swag_from
@@ -15,14 +15,14 @@ from flasgger import swag_from
15from matweb import file_removal_scheduler, utils 15from matweb import file_removal_scheduler, utils
16 16
17 17
18class APIUpload(Resource): 18api_bp = Blueprint('api_bp', __name__, url_prefix='/api/')
19 19api = Api(api_bp)
20 def __init__(self, **kwargs): 20
21 self.upload_folder = kwargs['upload_folder']
22 21
22class APIUpload(Resource):
23 @swag_from('./oas/upload.yml') 23 @swag_from('./oas/upload.yml')
24 def post(self): 24 def post(self):
25 utils.check_upload_folder(self.upload_folder) 25 utils.check_upload_folder(current_app.config['UPLOAD_FOLDER'])
26 req_parser = reqparse.RequestParser() 26 req_parser = reqparse.RequestParser()
27 req_parser.add_argument('file_name', type=str, required=True, help='Post parameter is not specified: file_name') 27 req_parser.add_argument('file_name', type=str, required=True, help='Post parameter is not specified: file_name')
28 req_parser.add_argument('file', type=str, required=True, help='Post parameter is not specified: file') 28 req_parser.add_argument('file', type=str, required=True, help='Post parameter is not specified: file')
@@ -35,7 +35,7 @@ class APIUpload(Resource):
35 35
36 file = FileStorage(stream=io.BytesIO(file_data), filename=args['file_name']) 36 file = FileStorage(stream=io.BytesIO(file_data), filename=args['file_name'])
37 try: 37 try:
38 filename, filepath = utils.save_file(file, self.upload_folder) 38 filename, filepath = utils.save_file(file, current_app.config['UPLOAD_FOLDER'])
39 except ValueError: 39 except ValueError:
40 abort(400, message='Invalid Filename') 40 abort(400, message='Invalid Filename')
41 41
@@ -48,7 +48,7 @@ class APIUpload(Resource):
48 if not parser.remove_all(): 48 if not parser.remove_all():
49 abort(500, message='Unable to clean %s' % mime) 49 abort(500, message='Unable to clean %s' % mime)
50 50
51 key, secret, meta_after, output_filename = utils.cleanup(parser, filepath, self.upload_folder) 51 key, secret, meta_after, output_filename = utils.cleanup(parser, filepath, current_app.config['UPLOAD_FOLDER'])
52 return utils.return_file_created_response( 52 return utils.return_file_created_response(
53 utils.get_file_removal_max_age_sec(), 53 utils.get_file_removal_max_age_sec(),
54 output_filename, 54 output_filename,
@@ -58,7 +58,7 @@ class APIUpload(Resource):
58 meta, 58 meta,
59 meta_after, 59 meta_after,
60 url_for( 60 url_for(
61 'apidownload', 61 'api_bp.apidownload',
62 key=key, 62 key=key,
63 secret=secret, 63 secret=secret,
64 filename=output_filename, 64 filename=output_filename,
@@ -68,16 +68,12 @@ class APIUpload(Resource):
68 68
69 69
70class APIDownload(Resource): 70class APIDownload(Resource):
71
72 def __init__(self, **kwargs):
73 self.upload_folder = kwargs['upload_folder']
74
75 @swag_from('./oas/download.yml') 71 @swag_from('./oas/download.yml')
76 def get(self, key: str, secret: str, filename: str): 72 def get(self, key: str, secret: str, filename: str):
77 complete_path, filepath = utils.is_valid_api_download_file(filename, key, secret, self.upload_folder) 73 complete_path, filepath = utils.is_valid_api_download_file(filename, key, secret, current_app.config['UPLOAD_FOLDER'])
78 # Make sure the file is NOT deleted on HEAD requests 74 # Make sure the file is NOT deleted on HEAD requests
79 if request.method == 'GET': 75 if request.method == 'GET':
80 file_removal_scheduler.run_file_removal_job(self.upload_folder) 76 file_removal_scheduler.run_file_removal_job(current_app.config['UPLOAD_FOLDER'])
81 77
82 @after_this_request 78 @after_this_request
83 def remove_file(response): 79 def remove_file(response):
@@ -85,14 +81,10 @@ class APIDownload(Resource):
85 os.remove(complete_path) 81 os.remove(complete_path)
86 return response 82 return response
87 83
88 return send_from_directory(self.upload_folder, filepath, as_attachment=True) 84 return send_from_directory(current_app.config['UPLOAD_FOLDER'], filepath, as_attachment=True)
89 85
90 86
91class APIBulkDownloadCreator(Resource): 87class APIBulkDownloadCreator(Resource):
92
93 def __init__(self, **kwargs):
94 self.upload_folder = kwargs['upload_folder']
95
96 schema = { 88 schema = {
97 'download_list': { 89 'download_list': {
98 'type': 'list', 90 'type': 'list',
@@ -112,13 +104,13 @@ class APIBulkDownloadCreator(Resource):
112 104
113 @swag_from('./oas/bulk.yml') 105 @swag_from('./oas/bulk.yml')
114 def post(self): 106 def post(self):
115 utils.check_upload_folder(self.upload_folder) 107 utils.check_upload_folder(current_app.config['UPLOAD_FOLDER'])
116 data = request.json 108 data = request.json
117 if not self.v.validate(data): 109 if not self.v.validate(data):
118 abort(400, message=self.v.errors) 110 abort(400, message=self.v.errors)
119 # prevent the zip file from being overwritten 111 # prevent the zip file from being overwritten
120 zip_filename = 'files.' + str(uuid4()) + '.zip' 112 zip_filename = 'files.' + str(uuid4()) + '.zip'
121 zip_path = os.path.join(self.upload_folder, zip_filename) 113 zip_path = os.path.join(current_app.config['UPLOAD_FOLDER'], zip_filename)
122 cleaned_files_zip = zipfile.ZipFile(zip_path, 'w') 114 cleaned_files_zip = zipfile.ZipFile(zip_path, 'w')
123 with cleaned_files_zip: 115 with cleaned_files_zip:
124 for file_candidate in data['download_list']: 116 for file_candidate in data['download_list']:
@@ -126,7 +118,7 @@ class APIBulkDownloadCreator(Resource):
126 file_candidate['file_name'], 118 file_candidate['file_name'],
127 file_candidate['key'], 119 file_candidate['key'],
128 file_candidate['secret'], 120 file_candidate['secret'],
129 self.upload_folder 121 current_app.config['UPLOAD_FOLDER']
130 ) 122 )
131 try: 123 try:
132 cleaned_files_zip.write(complete_path) 124 cleaned_files_zip.write(complete_path)
@@ -142,7 +134,7 @@ class APIBulkDownloadCreator(Resource):
142 parser, mime = utils.get_file_parser(zip_path) 134 parser, mime = utils.get_file_parser(zip_path)
143 if not parser.remove_all(): 135 if not parser.remove_all():
144 abort(500, message='Unable to clean %s' % mime) 136 abort(500, message='Unable to clean %s' % mime)
145 key, secret, meta_after, output_filename = utils.cleanup(parser, zip_path, self.upload_folder) 137 key, secret, meta_after, output_filename = utils.cleanup(parser, zip_path, current_app.config['UPLOAD_FOLDER'])
146 return { 138 return {
147 'inactive_after_sec': utils.get_file_removal_max_age_sec(), 139 'inactive_after_sec': utils.get_file_removal_max_age_sec(),
148 'output_filename': output_filename, 140 'output_filename': output_filename,
@@ -151,7 +143,7 @@ class APIBulkDownloadCreator(Resource):
151 'secret': secret, 143 'secret': secret,
152 'meta_after': meta_after, 144 'meta_after': meta_after,
153 'download_link': url_for( 145 'download_link': url_for(
154 'apidownload', 146 'api_bp.apidownload',
155 key=key, 147 key=key,
156 secret=secret, 148 secret=secret,
157 filename=output_filename, 149 filename=output_filename,
@@ -164,3 +156,18 @@ class APISupportedExtensions(Resource):
164 @swag_from('./oas/extension.yml') 156 @swag_from('./oas/extension.yml')
165 def get(self): 157 def get(self):
166 return utils.get_supported_extensions() 158 return utils.get_supported_extensions()
159
160
161api.add_resource(
162 APIUpload,
163 '/upload'
164 )
165api.add_resource(
166 APIDownload,
167 '/download/<string:key>/<string:secret>/<string:filename>'
168)
169api.add_resource(
170 APIBulkDownloadCreator,
171 '/download/bulk'
172)
173api.add_resource(APISupportedExtensions, '/extension')