mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 09:20:22 +08:00
- 删除全部 Python 源码 (src/) 及 Alembic 迁移脚本,归档至 _deprecated_py_src/ - 重构 Rust gateway ai_pipeline: 拆分 planner/finalize 模块,新增 contracts/adaptation 层 - 重组 handlers 模块为 admin/public/proxy/internal/shared 子模块结构 - 新增 executor 模块,引入 Rust 原生数据库迁移 (aether-data/migrations) - 简化 CI/Docker 构建流程,移除 base image 二级构建,统一为单一 app image - 移除 Python 相关基础设施文件 (entrypoint.sh, gunicorn_conf.py, Dockerfile.base)
118 lines
3.4 KiB
Python
118 lines
3.4 KiB
Python
"""
|
||
SSL 工具函数
|
||
提供统一的 SSL 上下文创建功能
|
||
"""
|
||
|
||
import ssl
|
||
|
||
from loguru import logger
|
||
|
||
|
||
def _create_default_ssl_context() -> ssl.SSLContext:
|
||
try:
|
||
import certifi
|
||
|
||
return ssl.create_default_context(cafile=certifi.where())
|
||
except ImportError:
|
||
return ssl.create_default_context()
|
||
|
||
|
||
try:
|
||
_SSL_CONTEXT = _create_default_ssl_context()
|
||
except Exception:
|
||
_SSL_CONTEXT = ssl.create_default_context()
|
||
|
||
_PROXY_SSL_CONTEXT: ssl.SSLContext | None = None
|
||
_PROFILE_SSL_CONTEXTS: dict[str, ssl.SSLContext] = {}
|
||
|
||
|
||
def get_ssl_context() -> ssl.SSLContext:
|
||
"""
|
||
获取 SSL 上下文
|
||
|
||
优先使用 certifi 证书包,如果未安装则使用系统默认证书。
|
||
返回模块级缓存的 SSL 上下文实例。
|
||
|
||
Returns:
|
||
ssl.SSLContext: SSL 上下文
|
||
"""
|
||
return _SSL_CONTEXT
|
||
|
||
|
||
def get_proxy_ssl_context(expected_fingerprint: str | None = None) -> ssl.SSLContext:
|
||
"""
|
||
获取用于代理连接的 SSL 上下文(连接 aether-proxy TLS 端口)
|
||
|
||
当前使用 CERT_NONE(不验证证书),因为 aether-proxy 使用自签名证书。
|
||
expected_fingerprint 参数预留供未来实现指纹校验。
|
||
|
||
Args:
|
||
expected_fingerprint: 预期的证书 SHA-256 指纹(hex,预留参数)
|
||
|
||
Returns:
|
||
ssl.SSLContext: 代理专用 SSL 上下文
|
||
"""
|
||
global _PROXY_SSL_CONTEXT
|
||
|
||
if expected_fingerprint:
|
||
logger.warning("TLS 证书指纹校验尚未实现, fingerprint={} 被忽略", expected_fingerprint)
|
||
|
||
if _PROXY_SSL_CONTEXT is None:
|
||
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
||
ctx.check_hostname = False
|
||
ctx.verify_mode = ssl.CERT_NONE
|
||
_PROXY_SSL_CONTEXT = ctx
|
||
# TODO: 实现基于 expected_fingerprint 的证书指纹校验
|
||
return _PROXY_SSL_CONTEXT
|
||
|
||
|
||
def _build_claude_code_ssl_context() -> ssl.SSLContext:
|
||
"""构建 Claude Code best-effort TLS 配置。
|
||
|
||
说明:Python/OpenSSL 无法完整模拟 Node.js ClientHello。
|
||
这里仅做可控项的尽力对齐(ALPN/TLS 版本/常见 cipher 偏好)。
|
||
"""
|
||
ctx = _create_default_ssl_context()
|
||
ctx.minimum_version = ssl.TLSVersion.TLSv1_2
|
||
try:
|
||
ctx.maximum_version = ssl.TLSVersion.TLSv1_3
|
||
except Exception:
|
||
pass
|
||
try:
|
||
ctx.set_alpn_protocols(["h2", "http/1.1"])
|
||
except Exception:
|
||
pass
|
||
try:
|
||
ctx.set_ciphers(
|
||
"ECDHE-ECDSA-AES128-GCM-SHA256:"
|
||
"ECDHE-RSA-AES128-GCM-SHA256:"
|
||
"ECDHE-ECDSA-AES256-GCM-SHA384:"
|
||
"ECDHE-RSA-AES256-GCM-SHA384:"
|
||
"ECDHE-ECDSA-CHACHA20-POLY1305:"
|
||
"ECDHE-RSA-CHACHA20-POLY1305"
|
||
)
|
||
except Exception:
|
||
pass
|
||
return ctx
|
||
|
||
|
||
def get_ssl_context_for_profile(tls_profile: str | None = None) -> ssl.SSLContext:
|
||
"""按 profile 返回 SSL 上下文。"""
|
||
profile = str(tls_profile or "").strip().lower()
|
||
if not profile:
|
||
return get_ssl_context()
|
||
|
||
if profile in _PROFILE_SSL_CONTEXTS:
|
||
logger.debug("复用 TLS profile SSL context: {}", profile)
|
||
return _PROFILE_SSL_CONTEXTS[profile]
|
||
|
||
if profile == "claude_code_nodejs":
|
||
logger.info("启用 TLS profile: {}(best-effort)", profile)
|
||
ctx = _build_claude_code_ssl_context()
|
||
else:
|
||
logger.warning("未知 TLS profile: {},回退默认 SSL context", profile)
|
||
ctx = get_ssl_context()
|
||
|
||
_PROFILE_SSL_CONTEXTS[profile] = ctx
|
||
return ctx
|