完善fastapi接口
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
File service endpoints
|
||||
|
||||
Provides access to generated files (videos, images, audio).
|
||||
Provides access to generated files (videos, images, audio) and resource files.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
@@ -17,15 +17,49 @@ async def get_file(file_path: str):
|
||||
"""
|
||||
Get file by path
|
||||
|
||||
Serves files from the output directory only.
|
||||
Serves files from allowed directories:
|
||||
- output/ - Generated files (videos, images, audio)
|
||||
- workflows/ - ComfyUI workflow files
|
||||
- templates/ - HTML templates
|
||||
- bgm/ - Background music
|
||||
- data/bgm/ - Custom background music
|
||||
- data/templates/ - Custom templates
|
||||
- resources/ - Other resources (images, fonts, etc.)
|
||||
|
||||
- **file_path**: File name or path (e.g., "abc123.mp4" or "subfolder/abc123.mp4")
|
||||
- **file_path**: File path relative to allowed directories
|
||||
|
||||
Examples:
|
||||
- "abc123.mp4" → output/abc123.mp4
|
||||
- "workflows/runninghub/image_flux.json" → workflows/runninghub/image_flux.json
|
||||
- "templates/1080x1920/default.html" → templates/1080x1920/default.html
|
||||
- "bgm/default.mp3" → bgm/default.mp3
|
||||
- "resources/example.png" → resources/example.png
|
||||
|
||||
Returns file for download or preview.
|
||||
"""
|
||||
try:
|
||||
# Automatically prepend "output/" to the path
|
||||
full_path = f"output/{file_path}"
|
||||
# Define allowed directories (in priority order)
|
||||
allowed_prefixes = [
|
||||
"output/",
|
||||
"workflows/",
|
||||
"templates/",
|
||||
"bgm/",
|
||||
"data/bgm/",
|
||||
"data/templates/",
|
||||
"resources/",
|
||||
]
|
||||
|
||||
# Check if path starts with allowed prefix, otherwise try output/
|
||||
full_path = None
|
||||
for prefix in allowed_prefixes:
|
||||
if file_path.startswith(prefix):
|
||||
full_path = file_path
|
||||
break
|
||||
|
||||
# If no prefix matched, assume it's in output/ (backward compatibility)
|
||||
if full_path is None:
|
||||
full_path = f"output/{file_path}"
|
||||
|
||||
abs_path = Path.cwd() / full_path
|
||||
|
||||
if not abs_path.exists():
|
||||
@@ -34,11 +68,19 @@ async def get_file(file_path: str):
|
||||
if not abs_path.is_file():
|
||||
raise HTTPException(status_code=400, detail=f"Path is not a file: {file_path}")
|
||||
|
||||
# Security: only allow access to output directory
|
||||
# Security: only allow access to specified directories
|
||||
try:
|
||||
rel_path = abs_path.relative_to(Path.cwd())
|
||||
if not str(rel_path).startswith("output"):
|
||||
raise HTTPException(status_code=403, detail="Access denied: only output directory is accessible")
|
||||
rel_path_str = str(rel_path)
|
||||
|
||||
# Check if path starts with any allowed prefix
|
||||
is_allowed = any(rel_path_str.startswith(prefix.rstrip('/')) for prefix in allowed_prefixes)
|
||||
|
||||
if not is_allowed:
|
||||
raise HTTPException(
|
||||
status_code=403,
|
||||
detail=f"Access denied: only {', '.join(p.rstrip('/') for p in allowed_prefixes)} directories are accessible"
|
||||
)
|
||||
except ValueError:
|
||||
raise HTTPException(status_code=403, detail="Access denied")
|
||||
|
||||
@@ -52,6 +94,8 @@ async def get_file(file_path: str):
|
||||
'.jpg': 'image/jpeg',
|
||||
'.jpeg': 'image/jpeg',
|
||||
'.gif': 'image/gif',
|
||||
'.html': 'text/html',
|
||||
'.json': 'application/json',
|
||||
}
|
||||
media_type = media_types.get(suffix, 'application/octet-stream')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user