feat: SSRF protection via NEXUS_ALLOWED_HOSTS, _env_int validation warnings
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
import asyncio
|
||||
import hashlib
|
||||
import os
|
||||
from urllib.parse import unquote
|
||||
from urllib.parse import unquote, urlparse
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -15,6 +15,15 @@ from ..constants import (
|
||||
from ..logging_setup import log
|
||||
|
||||
|
||||
def _validate_download_url(url: str) -> bool:
|
||||
parsed = urlparse(url)
|
||||
if parsed.scheme not in ("http", "https"):
|
||||
return False
|
||||
if parsed.hostname not in config.nexus_allowed_hosts:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def extract_pypi_info(asset_path: str) -> tuple[str, str] | None:
|
||||
"""Extract package name and version from a PyPI asset path.
|
||||
|
||||
@@ -101,6 +110,10 @@ def parse_package_path(path: str) -> tuple[str, str]:
|
||||
|
||||
async def download_asset(download_url: str, dest_dir: str) -> str | None:
|
||||
"""Download an asset from Nexus using async httpx."""
|
||||
if not _validate_download_url(download_url):
|
||||
log.warning("SSRF prevention: blocked download from %s", download_url)
|
||||
return None
|
||||
|
||||
dest_path = os.path.join(dest_dir, os.path.basename(download_url.split("?")[0]))
|
||||
|
||||
async with httpx.AsyncClient(
|
||||
|
||||
Reference in New Issue
Block a user