fix(aibox): never persist SOCKS5 proxy password to disk (F1/N1, +N11)
- config.set_proxy gains password_env (aligned with api_key_env convention): config file persists only the env var name; plaintext password lives in memory for the current session only - _save_config deep-copies and nulls proxy.socks5.password before json.dump, so every save path is sanitized (defense in depth) - get_proxy resolves password as in-memory plaintext first, then via password_env from os.environ; downstream consumers (llm_client, web tool curl args) unchanged - legacy migration on load: plaintext found on disk is kept in memory for the session, file is immediately rewritten sanitized - SetProxyTool exposes password_env and reports password source - registry debug logs mask password/api_key/token/secret/authorization kwargs (N11) Tests: new tests/test_config.py (3 cases: no plaintext on save, password_env resolution, legacy migration); full suite 267 passed. Audit report updated with Batch F progress.
This commit is contained in:
1 parent
a833cd0d5f
commit
eb88a77238
5 files changed
+179
-12
No files matched your search
@@ -34,7 +34,8 @@ class SetProxyTool(Tool):
|
||||
"host": {"type": "string", "description": "代理服务器地址,如 127.0.0.1"},
|
||||
"port": {"type": "integer", "description": "代理端口,如 1080"},
|
||||
"username": {"type": "string", "description": "用户名(可选)"},
|
||||
"password": {"type": "string", "description": "密码(可选)"},
|
||||
"password": {"type": "string", "description": "密码(可选,明文仅本次会话有效,不落盘)"},
|
||||
"password_env": {"type": "string", "description": "存有密码的环境变量名(可选,跨重启持久的推荐方式)"},
|
||||
"enabled": {"type": "boolean", "description": "是否启用代理,默认 true"},
|
||||
"save": {"type": "boolean", "description": "是否保存到配置文件(持久化),默认 true"}
|
||||
},
|
||||
@@ -42,14 +43,21 @@ class SetProxyTool(Tool):
|
||||
}
|
||||
|
||||
def execute(self, host: str, port: int, username: str = None, password: str = None,
|
||||
enabled: bool = True, save: bool = True, **kwargs) -> str:
|
||||
password_env: str = None, enabled: bool = True, save: bool = True, **kwargs) -> str:
|
||||
config = ConfigManager()
|
||||
config.set_proxy(host, port, username, password, enabled, save)
|
||||
config.set_proxy(host, port, username, password, password_env, enabled, save)
|
||||
proxy_info = config.get_proxy_info()
|
||||
if proxy_info.get("password_env"):
|
||||
pw_source = "环境变量 " + proxy_info["password_env"]
|
||||
elif proxy_info.get("password"):
|
||||
pw_source = "仅本次会话(不落盘)"
|
||||
else:
|
||||
pw_source = "无"
|
||||
data = {
|
||||
"代理状态": "启用" if proxy_info["enabled"] else "禁用",
|
||||
"服务器": f"{proxy_info['host']}:{proxy_info['port']}",
|
||||
"认证": "有" if proxy_info.get("username") else "无",
|
||||
"密码来源": pw_source,
|
||||
"持久化": "已保存" if save else "仅内存"
|
||||
}
|
||||
return self.format_result(True, "代理设置成功", data)
|
||||
|
||||
+12
-1
@@ -15,6 +15,17 @@ from common import Logger, i18n
|
||||
|
||||
from .base import Tool
|
||||
|
||||
# 工具参数名命中这些关键词时,debug 日志里打码(防密码/密钥进日志文件)
|
||||
_SENSITIVE_PARAM_KEYS = {"password", "api_key", "token", "secret", "authorization"}
|
||||
|
||||
|
||||
def _sanitize_kwargs(kwargs: Dict) -> Dict:
|
||||
"""复制一份参数并把敏感键的值替换为 ***(仅用于日志输出)"""
|
||||
return {
|
||||
k: ("***" if str(k).lower() in _SENSITIVE_PARAM_KEYS else v)
|
||||
for k, v in kwargs.items()
|
||||
}
|
||||
|
||||
|
||||
class ToolRegistry:
|
||||
"""工具注册器 - 支持技能热重载"""
|
||||
@@ -63,7 +74,7 @@ class ToolRegistry:
|
||||
if not tool:
|
||||
return f"❌ 错误:找不到工具 '{name}'"
|
||||
|
||||
self.logger.debug(f"工具调用: {name}({kwargs})")
|
||||
self.logger.debug(f"工具调用: {name}({_sanitize_kwargs(kwargs)})")
|
||||
start_time = time.time()
|
||||
|
||||
try:
|
||||
|
||||
Reference in new issue
Block a user