11import logging
2+ import asyncio
23from pathlib import Path
34
45from fastapi import APIRouter , Depends , HTTPException
56from fastapi .responses import FileResponse , JSONResponse
6- from sqlalchemy .util .concurrency import asyncio
77
88from module .database import Database , engine
99from module .manager import BangumiManager
@@ -97,7 +97,7 @@ async def delete_rule(bangumi_id: str, file: bool = False):
9797 response_model = APIResponse ,
9898 dependencies = [Depends (get_current_user )],
9999)
100- async def delete_many_rule (bangumi_id : list , file : bool = False ):
100+ async def delete_many_rule (bangumi_id : list [ int ] , file : bool = False ):
101101 tasks = []
102102 for i in bangumi_id :
103103 tasks .append (BangumiManager ().delete_rule (i , file ))
@@ -185,29 +185,6 @@ async def refresh_poster():
185185 return u_response (resp )
186186
187187
188- @router .get (
189- path = "/refresh/poster/{bangumi_id}" ,
190- response_model = APIResponse ,
191- dependencies = [Depends (get_current_user )],
192- )
193- async def refresh_single_poster (bangumi_id : int ):
194- resp = await BangumiManager ().refind_poster (bangumi_id )
195- if resp :
196- resp = ResponseModel (
197- status_code = 200 ,
198- status = True ,
199- msg_en = "Refresh poster link successfully." ,
200- msg_zh = "刷新海报链接成功。" ,
201- )
202- else :
203- resp = ResponseModel (
204- status_code = 406 ,
205- status = False ,
206- msg_en = f"Can't find id { bangumi_id } " ,
207- msg_zh = f"无法找到 id { bangumi_id } " ,
208- )
209- return u_response (resp )
210-
211188
212189@router .get ("/reset/all" , response_model = APIResponse , dependencies = [Depends (get_current_user )])
213190async def reset_all ():
@@ -224,42 +201,22 @@ async def reset_all():
224201
225202@router .get ("/posters/{path:path}" , dependencies = [Depends (get_current_user )])
226203async def get_poster (path : str ):
227- """
228- 安全的poster图片访问端点
229- - 添加了用户鉴权
230- - 防止路径遍历攻击
231- - 限制只能访问posters目录下的文件
232- """
233- # 验证路径安全性 - 阻止路径遍历
234- if ".." in path or path .startswith ("/" ) or "\\ " in path :
235- logger .warning (f"[Poster] Blocked path traversal attempt: { path } " )
236- raise HTTPException (status_code = 400 , detail = "Invalid path" )
237-
238- # 构建安全的文件路径
239- poster_dir = Path ("data" ) / Path ("posters" )
240- post_path = poster_dir / Path (path )
204+ poster_dir = (Path ("data" ) / "posters" ).resolve ()
205+ post_path = (poster_dir / path ).resolve ()
241206
242- # 确保解析后的路径仍在预期目录内
243- try :
244- post_path .resolve ().relative_to (poster_dir .resolve ())
245- except ValueError :
246- logger .warning (f"[Poster] Path outside allowed directory: { path } " )
247- raise HTTPException (status_code = 400 , detail = "Path outside allowed directory" )
207+ if not post_path .is_relative_to (poster_dir ):
208+ raise HTTPException (status_code = 400 , detail = "Invalid path" )
248209
249- # 如果文件不存在,尝试下载
250210 if not post_path .exists ():
251211 try :
252212 await load_image (path )
253213 except Exception as e :
254214 logger .warning (f"[Poster] Failed to load image { path } : { e } " )
255215
256- # 返回文件
257- if post_path .exists () and post_path .is_file ():
216+ if post_path .is_file ():
258217 return FileResponse (
259218 post_path ,
260219 media_type = "image/jpeg" ,
261- headers = {"Cache-Control" : "public, max-age=86400" }, # 缓存1天
220+ headers = {"Cache-Control" : "public, max-age=86400" },
262221 )
263- else :
264- logger .warning (f"[Poster] File not found: { post_path } " )
265- raise HTTPException (status_code = 404 , detail = "Poster not found" )
222+ raise HTTPException (status_code = 404 , detail = "Poster not found" )
0 commit comments