mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-07 16:36:53 +08:00
Add nettest documentation comments
This commit is contained in:
@@ -53,6 +53,12 @@ _NETTEST_REDIRECT_STATUS_CODES = {301, 302, 303, 307, 308}
|
|||||||
|
|
||||||
|
|
||||||
def _match_nettest_prefix(url: str, prefix: str) -> bool:
|
def _match_nettest_prefix(url: str, prefix: str) -> bool:
|
||||||
|
"""
|
||||||
|
判断目标URL是否仍然落在允许的协议、主机、端口和路径前缀内。
|
||||||
|
|
||||||
|
nettest 会在服务端手动处理重定向,因此这里需要一个比简单 startswith
|
||||||
|
更严格的匹配,避免不同端口或同名路径被误判为白名单内跳转。
|
||||||
|
"""
|
||||||
parsed_url = urlparse(url)
|
parsed_url = urlparse(url)
|
||||||
parsed_prefix = urlparse(prefix)
|
parsed_prefix = urlparse(prefix)
|
||||||
if parsed_url.scheme.lower() != parsed_prefix.scheme.lower():
|
if parsed_url.scheme.lower() != parsed_prefix.scheme.lower():
|
||||||
@@ -67,6 +73,13 @@ def _match_nettest_prefix(url: str, prefix: str) -> bool:
|
|||||||
|
|
||||||
|
|
||||||
def _build_nettest_rules() -> list[dict[str, Any]]:
|
def _build_nettest_rules() -> list[dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
构建系统内置的网络测试目标。
|
||||||
|
|
||||||
|
这里集中维护“前端允许显示哪些测试项”和“后端允许访问哪些远端地址”。
|
||||||
|
前端只拿到展示所需的 id/name/icon;真正的 URL、代理策略、内容校验规则
|
||||||
|
和重定向白名单都保留在服务端,避免再出现用户可控 SSRF。
|
||||||
|
"""
|
||||||
github_proxy = UrlUtils.standardize_base_url(settings.GITHUB_PROXY or "")
|
github_proxy = UrlUtils.standardize_base_url(settings.GITHUB_PROXY or "")
|
||||||
pip_proxy = UrlUtils.standardize_base_url(
|
pip_proxy = UrlUtils.standardize_base_url(
|
||||||
settings.PIP_PROXY or "https://pypi.org/simple/"
|
settings.PIP_PROXY or "https://pypi.org/simple/"
|
||||||
@@ -238,6 +251,12 @@ def _build_nettest_rules() -> list[dict[str, Any]]:
|
|||||||
|
|
||||||
|
|
||||||
def _validate_nettest_url(url: str) -> Optional[str]:
|
def _validate_nettest_url(url: str) -> Optional[str]:
|
||||||
|
"""
|
||||||
|
对实际请求地址做基础安全校验。
|
||||||
|
|
||||||
|
即使请求来自服务端内置规则,这里仍保留一层兜底校验,防止配置项被拼出
|
||||||
|
非 HTTPS、带凭据或不在内置目标集合中的地址。
|
||||||
|
"""
|
||||||
parsed = urlparse(url)
|
parsed = urlparse(url)
|
||||||
if parsed.scheme.lower() != "https":
|
if parsed.scheme.lower() != "https":
|
||||||
return "测试地址仅支持 HTTPS"
|
return "测试地址仅支持 HTTPS"
|
||||||
@@ -251,6 +270,12 @@ def _validate_nettest_url(url: str) -> Optional[str]:
|
|||||||
|
|
||||||
|
|
||||||
def _get_nettest_rule(url: Optional[str] = None, target_id: Optional[str] = None) -> Optional[dict[str, Any]]:
|
def _get_nettest_rule(url: Optional[str] = None, target_id: Optional[str] = None) -> Optional[dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
根据 target_id 或历史兼容参数匹配网络测试规则。
|
||||||
|
|
||||||
|
现在的主路径是 target_id。保留 url 参数是为了兼容旧前端或未升级的调用方,
|
||||||
|
但匹配结果仍然只能落到服务端预定义规则上。
|
||||||
|
"""
|
||||||
for rule in _build_nettest_rules():
|
for rule in _build_nettest_rules():
|
||||||
if target_id and rule.get("id") == target_id:
|
if target_id and rule.get("id") == target_id:
|
||||||
return rule
|
return rule
|
||||||
@@ -260,6 +285,12 @@ def _get_nettest_rule(url: Optional[str] = None, target_id: Optional[str] = None
|
|||||||
|
|
||||||
|
|
||||||
def _is_allowed_nettest_redirect(url: str, rule: dict[str, Any]) -> bool:
|
def _is_allowed_nettest_redirect(url: str, rule: dict[str, Any]) -> bool:
|
||||||
|
"""
|
||||||
|
校验重定向目标是否仍属于当前测试项允许的跳转范围。
|
||||||
|
|
||||||
|
nettest 不再信任客户端跟随重定向,而是只允许在该测试项自己的白名单内跳转,
|
||||||
|
这样既能兼容正常 30x,又不会把安全边界重新放开。
|
||||||
|
"""
|
||||||
parsed = urlparse(url)
|
parsed = urlparse(url)
|
||||||
if parsed.scheme.lower() != "https" or not parsed.netloc:
|
if parsed.scheme.lower() != "https" or not parsed.netloc:
|
||||||
return False
|
return False
|
||||||
@@ -272,6 +303,12 @@ def _is_allowed_nettest_redirect(url: str, rule: dict[str, Any]) -> bool:
|
|||||||
|
|
||||||
|
|
||||||
async def _close_nettest_response(response: Any) -> None:
|
async def _close_nettest_response(response: Any) -> None:
|
||||||
|
"""
|
||||||
|
安静地关闭 httpx 响应对象。
|
||||||
|
|
||||||
|
nettest 在手动处理重定向时会提前结束部分响应读取,这里统一做资源回收,
|
||||||
|
避免连接泄漏干扰后续测试。
|
||||||
|
"""
|
||||||
if response is None or not hasattr(response, "aclose"):
|
if response is None or not hasattr(response, "aclose"):
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
@@ -775,7 +812,10 @@ def ruletest(
|
|||||||
@router.get("/nettest/targets", summary="获取网络测试目标", response_model=schemas.Response)
|
@router.get("/nettest/targets", summary="获取网络测试目标", response_model=schemas.Response)
|
||||||
async def nettest_targets(_: schemas.TokenPayload = Depends(verify_token)):
|
async def nettest_targets(_: schemas.TokenPayload = Depends(verify_token)):
|
||||||
"""
|
"""
|
||||||
获取网络测试目标
|
获取网络测试目标。
|
||||||
|
|
||||||
|
这里只返回前端渲染所需的最小信息,避免把可请求 URL、内容校验规则和
|
||||||
|
跳转白名单暴露给客户端。
|
||||||
"""
|
"""
|
||||||
return schemas.Response(
|
return schemas.Response(
|
||||||
success=True,
|
success=True,
|
||||||
@@ -799,7 +839,10 @@ async def nettest(
|
|||||||
_: schemas.TokenPayload = Depends(verify_token),
|
_: schemas.TokenPayload = Depends(verify_token),
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
测试网络连通性
|
测试内置目标的网络连通性。
|
||||||
|
|
||||||
|
`target_id` 是当前前端使用的正式入口。`url/proxy/include` 仅作兼容保留,
|
||||||
|
其中 `include` 不再参与客户端可控的内容匹配,具体校验由服务端规则决定。
|
||||||
"""
|
"""
|
||||||
target = _get_nettest_rule(url=url, target_id=target_id)
|
target = _get_nettest_rule(url=url, target_id=target_id)
|
||||||
if not target:
|
if not target:
|
||||||
|
|||||||
Reference in New Issue
Block a user