mirror of
https://github.com/Av0idD4rk/firegex.git
synced 2026-10-25 03:29:24 +00:00
CRITICAL: fix possible path traversal
This commit is contained in:
parent
16f96aa6f6
commit
16d0bfd169
@ -6,13 +6,14 @@ import psutil
|
|||||||
import sys
|
import sys
|
||||||
import nftables
|
import nftables
|
||||||
from socketio import AsyncServer
|
from socketio import AsyncServer
|
||||||
from fastapi import Path
|
from typing import Annotated, List, Union
|
||||||
from typing import Annotated
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from pydantic import BaseModel, ValidationError
|
from pydantic import BaseModel, ValidationError, Field
|
||||||
import traceback
|
import traceback
|
||||||
from utils.models import StatusMessageModel
|
from utils.models import StatusMessageModel
|
||||||
from typing import List
|
from pathlib import Path
|
||||||
|
|
||||||
|
from fastapi import HTTPException, status
|
||||||
|
|
||||||
LOCALHOST_IP = socket.gethostbyname(os.getenv("LOCALHOST_IP","127.0.0.1"))
|
LOCALHOST_IP = socket.gethostbyname(os.getenv("LOCALHOST_IP","127.0.0.1"))
|
||||||
|
|
||||||
@ -31,7 +32,32 @@ FIREGEX_SOCKET = os.path.join(FIREGEX_SOCKET_DIR, "firegex.sock") if FIREGEX_SOC
|
|||||||
JWT_ALGORITHM: str = "HS256"
|
JWT_ALGORITHM: str = "HS256"
|
||||||
API_VERSION = "{{VERSION_PLACEHOLDER}}" if "{" not in "{{VERSION_PLACEHOLDER}}" else "0.0.0"
|
API_VERSION = "{{VERSION_PLACEHOLDER}}" if "{" not in "{{VERSION_PLACEHOLDER}}" else "0.0.0"
|
||||||
|
|
||||||
PortType = Annotated[int, Path(gt=0, lt=65536)]
|
PortType = Annotated[int, Field(gt=0, lt=65536)]
|
||||||
|
|
||||||
|
def safe_join(base_dir: Union[str, Path], *paths: str) -> Path:
|
||||||
|
"""
|
||||||
|
Safely join a base directory with one or more path components.
|
||||||
|
|
||||||
|
Returns the resolved Path object if safe.
|
||||||
|
Raises HTTPException 403 if a directory traversal attack is detected.
|
||||||
|
"""
|
||||||
|
# 1. Convert base_dir to a resolved, absolute Path
|
||||||
|
base_path = Path(base_dir).resolve()
|
||||||
|
|
||||||
|
# 2. Join the parts and resolve the result (removes symbols like '../')
|
||||||
|
# If the user input is an absolute path (starting with /),
|
||||||
|
# joinpath handles it correctly or we can strip leading slashes.
|
||||||
|
clean_paths = [p.lstrip("/") for p in paths]
|
||||||
|
target_path = base_path.joinpath(*clean_paths).resolve()
|
||||||
|
|
||||||
|
# 3. Security check
|
||||||
|
if not target_path.is_relative_to(base_path):
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
|
detail="Access denied: Path is invalid."
|
||||||
|
)
|
||||||
|
|
||||||
|
return target_path
|
||||||
|
|
||||||
async def run_func(func, *args, **kwargs):
|
async def run_func(func, *args, **kwargs):
|
||||||
if asyncio.iscoroutinefunction(func):
|
if asyncio.iscoroutinefunction(func):
|
||||||
|
|||||||
@ -5,7 +5,7 @@ from typing import Callable
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from starlette.responses import StreamingResponse
|
from starlette.responses import StreamingResponse
|
||||||
from fastapi.responses import FileResponse
|
from fastapi.responses import FileResponse
|
||||||
from utils import DEBUG, ON_DOCKER, ROUTERS_DIR, list_files, run_func
|
from utils import DEBUG, ON_DOCKER, ROUTERS_DIR, list_files, run_func, safe_join
|
||||||
from utils.models import ResetRequest
|
from utils.models import ResetRequest
|
||||||
import asyncio
|
import asyncio
|
||||||
import traceback
|
import traceback
|
||||||
@ -20,7 +20,7 @@ async def frontend_debug_proxy(path):
|
|||||||
return StreamingResponse(resp.aiter_bytes(),status_code=resp.status_code, headers=resp.headers)
|
return StreamingResponse(resp.aiter_bytes(),status_code=resp.status_code, headers=resp.headers)
|
||||||
|
|
||||||
async def react_deploy(path):
|
async def react_deploy(path):
|
||||||
file_request = os.path.join(REACT_BUILD_DIR, path)
|
file_request = safe_join(REACT_BUILD_DIR, path)
|
||||||
if not os.path.isfile(file_request):
|
if not os.path.isfile(file_request):
|
||||||
return FileResponse(REACT_HTML_PATH, media_type='text/html')
|
return FileResponse(REACT_HTML_PATH, media_type='text/html')
|
||||||
else:
|
else:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user