| 
									
										
										
										
											2024-11-01 15:51:22 +08:00
										 |  |  | import urllib.parse | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-07 14:35:58 +08:00
										 |  |  | import httpx | 
					
						
							| 
									
										
										
										
											2024-11-01 15:51:22 +08:00
										 |  |  | from flask_restful import marshal_with, reqparse | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-07 14:35:58 +08:00
										 |  |  | import services | 
					
						
							| 
									
										
										
										
											2024-11-01 15:51:22 +08:00
										 |  |  | from controllers.common import helpers | 
					
						
							|  |  |  | from controllers.web.wraps import WebApiResource | 
					
						
							|  |  |  | from core.file import helpers as file_helpers | 
					
						
							|  |  |  | from core.helper import ssrf_proxy | 
					
						
							|  |  |  | from fields.file_fields import file_fields_with_signed_url, remote_file_info_fields | 
					
						
							|  |  |  | from services.file_service import FileService | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-07 14:35:58 +08:00
										 |  |  | from .error import FileTooLargeError, UnsupportedFileTypeError | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-01 15:51:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | class RemoteFileInfoApi(WebApiResource): | 
					
						
							|  |  |  |     @marshal_with(remote_file_info_fields) | 
					
						
							| 
									
										
										
										
											2024-11-07 08:55:19 +03:00
										 |  |  |     def get(self, app_model, end_user, url): | 
					
						
							| 
									
										
										
										
											2024-11-01 15:51:22 +08:00
										 |  |  |         decoded_url = urllib.parse.unquote(url) | 
					
						
							| 
									
										
										
										
											2024-11-07 14:35:58 +08:00
										 |  |  |         resp = ssrf_proxy.head(decoded_url) | 
					
						
							|  |  |  |         if resp.status_code != httpx.codes.OK: | 
					
						
							|  |  |  |             # failed back to get method | 
					
						
							|  |  |  |             resp = ssrf_proxy.get(decoded_url, timeout=3) | 
					
						
							|  |  |  |         resp.raise_for_status() | 
					
						
							|  |  |  |         return { | 
					
						
							|  |  |  |             "file_type": resp.headers.get("Content-Type", "application/octet-stream"), | 
					
						
							|  |  |  |             "file_length": int(resp.headers.get("Content-Length", -1)), | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-11-01 15:51:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class RemoteFileUploadApi(WebApiResource): | 
					
						
							|  |  |  |     @marshal_with(file_fields_with_signed_url) | 
					
						
							| 
									
										
										
										
											2024-11-02 17:03:00 +08:00
										 |  |  |     def post(self, app_model, end_user):  # Add app_model and end_user parameters | 
					
						
							| 
									
										
										
										
											2024-11-01 15:51:22 +08:00
										 |  |  |         parser = reqparse.RequestParser() | 
					
						
							|  |  |  |         parser.add_argument("url", type=str, required=True, help="URL is required") | 
					
						
							|  |  |  |         args = parser.parse_args() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         url = args["url"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-07 14:35:58 +08:00
										 |  |  |         resp = ssrf_proxy.head(url=url) | 
					
						
							|  |  |  |         if resp.status_code != httpx.codes.OK: | 
					
						
							|  |  |  |             resp = ssrf_proxy.get(url=url, timeout=3) | 
					
						
							|  |  |  |         resp.raise_for_status() | 
					
						
							| 
									
										
										
										
											2024-11-01 15:51:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-07 14:35:58 +08:00
										 |  |  |         file_info = helpers.guess_file_info_from_response(resp) | 
					
						
							| 
									
										
										
										
											2024-11-01 15:51:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if not FileService.is_file_size_within_limit(extension=file_info.extension, file_size=file_info.size): | 
					
						
							| 
									
										
										
										
											2024-11-07 14:35:58 +08:00
										 |  |  |             raise FileTooLargeError | 
					
						
							| 
									
										
										
										
											2024-11-01 15:51:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-07 14:35:58 +08:00
										 |  |  |         content = resp.content if resp.request.method == "GET" else ssrf_proxy.get(url).content | 
					
						
							| 
									
										
										
										
											2024-11-01 15:51:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             upload_file = FileService.upload_file( | 
					
						
							|  |  |  |                 filename=file_info.filename, | 
					
						
							|  |  |  |                 content=content, | 
					
						
							|  |  |  |                 mimetype=file_info.mimetype, | 
					
						
							| 
									
										
										
										
											2024-11-07 14:35:58 +08:00
										 |  |  |                 user=end_user, | 
					
						
							| 
									
										
										
										
											2024-11-01 15:51:22 +08:00
										 |  |  |                 source_url=url, | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2024-11-07 14:35:58 +08:00
										 |  |  |         except services.errors.file.FileTooLargeError as file_too_large_error: | 
					
						
							|  |  |  |             raise FileTooLargeError(file_too_large_error.description) | 
					
						
							|  |  |  |         except services.errors.file.UnsupportedFileTypeError: | 
					
						
							|  |  |  |             raise UnsupportedFileTypeError | 
					
						
							| 
									
										
										
										
											2024-11-01 15:51:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return { | 
					
						
							|  |  |  |             "id": upload_file.id, | 
					
						
							|  |  |  |             "name": upload_file.name, | 
					
						
							|  |  |  |             "size": upload_file.size, | 
					
						
							|  |  |  |             "extension": upload_file.extension, | 
					
						
							|  |  |  |             "url": file_helpers.get_signed_file_url(upload_file_id=upload_file.id), | 
					
						
							|  |  |  |             "mime_type": upload_file.mime_type, | 
					
						
							|  |  |  |             "created_by": upload_file.created_by, | 
					
						
							|  |  |  |             "created_at": upload_file.created_at, | 
					
						
							|  |  |  |         }, 201 |