ForgeFix и новые фичи в интерфейсе

This commit is contained in:
SashegDev
2026-07-13 13:16:51 +00:00
parent 0d61ad1107
commit 201269efea
23 changed files with 1166 additions and 327 deletions
+49 -10
View File
@@ -19,7 +19,7 @@ from uvicorn.protocols.http.httptools_impl import HttpToolsProtocol
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("httpcore").setLevel(logging.WARNING)
from pack_manager import DATA_DIR, scan_pack, get_cached_manifest, PACKS_DIR
from pack_manager import DATA_DIR, scan_pack, get_cached_manifest, PACKS_DIR, is_pack_disabled, get_pack_presets, get_merged_manifest
from models import PackMeta
from middleware import LoggingMiddleware
from cli import parse_args, run_test_mode, run_production_mode, run_development_mode, run_sync_mode
@@ -1026,7 +1026,9 @@ async def list_packs(
"loader_type": meta.get("loader_type", "vanilla"),
"loader_version": meta.get("loader_version"),
"asset_index": meta.get("asset_index"),
"description": description
"description": description,
"disabled": is_pack_disabled(pack_dir.name),
"presets": get_pack_presets(pack_dir.name)
})
except Exception as e:
logger.error(f"Failed to load pack meta for {pack_dir.name}: {e}")
@@ -1047,7 +1049,8 @@ async def list_packs(
async def get_pack_diff(
pack_name: str,
request: Request,
current_user: dict = Depends(get_current_user) # Добавляем зависимость
current_user: dict = Depends(get_current_user),
preset: Optional[str] = None
):
"""Client sends: { "mods/jei.jar": "sha256_hash", ... }
Server returns diff information
@@ -1060,6 +1063,10 @@ async def get_pack_diff(
detail="Для скачивания сборок требуется активная проходка. Обратитесь к администратору."
)
# Check if pack is disabled
if is_pack_disabled(pack_name):
raise HTTPException(403, "Pack is disabled by administrator")
client_ip = request.client.host if request.client else "unknown"
# Читаем тело запроса
@@ -1071,13 +1078,17 @@ async def get_pack_diff(
logger.info("Received diff request",
pack=pack_name,
preset=preset,
client_files_count=len(body),
client_ip=client_ip)
try:
meta = get_cached_manifest(pack_name)
if not meta:
meta = await scan_pack(pack_name)
if preset:
meta = get_merged_manifest(pack_name, preset)
else:
meta = get_cached_manifest(pack_name)
if not meta:
meta = await scan_pack(pack_name)
except FileNotFoundError:
logger.warning("Pack not found", pack=pack_name, client_ip=client_ip)
raise HTTPException(404, "Pack not found")
@@ -1095,6 +1106,8 @@ async def get_pack_diff(
client_hash = body.get(path)
if client_hash is None or client_hash != entry.hash:
url = f"/pack/{pack_name}/file/{path}"
if preset:
url += f"?preset={preset}"
to_download.append({
"path": path,
"url": url,
@@ -1127,6 +1140,9 @@ async def get_pack_diff(
@app.get("/pack/{pack_name}")
async def get_pack_manifest(pack_name: str, request: Request, current_user: dict = Depends(get_current_user)):
"""Get pack manifest with caching"""
if is_pack_disabled(pack_name):
raise HTTPException(403, "Pack is disabled by administrator")
client_ip = request.client.host if request.client else "unknown"
cached_meta = get_cached_manifest(pack_name)
@@ -1166,13 +1182,34 @@ async def get_pack_manifest(pack_name: str, request: Request, current_user: dict
@app.get("/pack/{pack_name}/file/{file_path:path}")
async def get_pack_file(pack_name: str, file_path: str, request: Request, current_user: dict = Depends(get_current_user)):
"""Get a file from a pack"""
async def get_pack_file(pack_name: str, file_path: str, request: Request, current_user: dict = Depends(get_current_user), preset: Optional[str] = None):
"""Get a file from a pack. If preset is specified, try preset dir first, fall back to base."""
if not has_permission(current_user["role"], Permissions.DOWNLOAD_PACK):
raise HTTPException(403, "Requires active pass")
full_path = PACKS_DIR / pack_name / file_path
if is_pack_disabled(pack_name):
raise HTTPException(403, "Pack is disabled by administrator")
client_ip = request.client.host if request.client else None
# If preset specified, try preset path first
if preset:
preset_path = PACKS_DIR / pack_name / "presets" / preset / file_path
preset_resolved = preset_path.resolve()
preset_root = (PACKS_DIR / pack_name).resolve()
try:
if str(preset_resolved).startswith(str(preset_root)) and preset_resolved.is_file():
full_path = preset_resolved
else:
full_path = None
except (ValueError, OSError):
full_path = None
else:
full_path = None
# Fall back to base path
if full_path is None:
full_path = PACKS_DIR / pack_name / file_path
# Security: prevent path traversal
try:
full_path = full_path.resolve()
@@ -2245,7 +2282,9 @@ async def proxy_download(request: Request):
"resources.download.minecraft.net",
"maven.minecraftforge.net",
"files.minecraftforge.net",
"maven.neoforged.net"
"maven.neoforged.net",
"api.zernmc.ru",
"api.zernmc.online"
]
# Проверяем, что URL ведет на разрешенный домен