44from pathlib import Path
55from pelit .plib .log import p_logger
66from pelit .plib .route_tool import *
7+ from multiprocessing import Process
78
89def create_route (cfg : dict [str , Any ], lg : p_logger ) -> Blueprint :
910 """
@@ -172,45 +173,14 @@ def _delete(directory: str, file: str) -> tuple[Response, int]:
172173 }), 502
173174
174175 @main_route .route ('/list' , methods = ['GET' ])
175- def _list_root () -> tuple [Response , int ]:
176- """
177- 列出根目录下所有目录
178-
179- Returns:
180- JSON 格式的列表和响应码
181- """
182- info_head = f"{ request .remote_addr } { request .method } { request .path } "
183-
184- if not authenticate (cfg ):
185- lg .warn (f"{ info_head } 401: 认证失败" )
186- return jsonify ({
187- "success" : False ,
188- "message" : "认证失败"
189- }), 401
190-
191- try :
192- storage_path = Path (cfg ['storage' ]['path' ])
193- resp : dict [str , Any ] = {
194- "success" : True ,
195- "message" : "" ,
196- "list" : list_dir (storage_path )
197- }
198- lg .info (f'{ info_head } 200 列举成功' )
199- return jsonify (resp ), 200
200- except Exception as e :
201- lg .warn (f'{ info_head } 502 列举失败' )
202- lg .warn ('这是一个内部错误,请检查配置' )
203- lg .warn (f'{ e } ' )
204- return jsonify ({
205- "success" : False ,
206- "message" : "列举失败"
207- }), 502
208-
209176 @main_route .route ('/list/<directory>' , methods = ['GET' ])
210- def _list_dir (directory : str ) -> tuple [Response , int ]:
177+ def _list (directory : str = "/" ) -> tuple [Response , int ]:
211178 """
212179 列出指定目录下所有目录
213180
181+ Args:
182+ directory: 列举地址,未指定时默认为根目录
183+
214184 Returns:
215185 JSON 格式的列表和响应码
216186 """
@@ -223,6 +193,10 @@ def _list_dir(directory: str) -> tuple[Response, int]:
223193 "message" : "认证失败"
224194 }), 401
225195
196+ if is_attempting_traversal (directory ):
197+ lg .warn (f"{ info_head } 403 危险请求" )
198+ return Response ("禁止访问" ), 403
199+
226200 try :
227201 path = Path (cfg ['storage' ]['path' ]) / directory
228202 resp : dict [str , Any ] = {
@@ -306,4 +280,33 @@ def _retrieve(directory: str, file: str) -> tuple[Response, int]:
306280 lg .warn (f"{ e } " )
307281 return Response ("内部错误" ), 502
308282
283+ @main_route .route ('/backup' , methods = ['GET' ])
284+ @main_route .route ('/backup/<directory>' , methods = ['GET' ])
285+ def _backup (directory : str = '/' ) -> tuple [Response , int ]:
286+ """
287+ 创建一个备份任务,具体方式在配置文件中指定
288+
289+ Returns:
290+ 包含响应和状态码
291+ """
292+ info_head = f"{ request .remote_addr } { request .method } { request .path } "
293+
294+ bak_name = generate_file_name (cfg ['storage' ]['path' ], '.tar.gz' )
295+ bak_path = Path (cfg ['storage' ]['path' ]) / (bak_name + '.tar.gz' )
296+ bak_url = join_url (cfg ['network' ]['base_url' ], bak_name + '.tar.gz' )
297+
298+ path = Path (cfg ['storage' ]['path' ]) / directory
299+
300+ # 创建新进程压缩备份
301+ # FIXME: 由于是多进程的,这个任务失败了也不会有表示
302+ p = Process (target = backup_to_file , args = (path , bak_path ))
303+ p .start ()
304+
305+ lg .info (f"{ info_head } 200 备份任务创建成功" )
306+ return jsonify ({
307+ "success" : True ,
308+ "url" : bak_url ,
309+ "message" : "备份任务创建成功"
310+ }), 200
311+
309312 return main_route
0 commit comments