feat: v0.8.2 安全纵深补全 · 协议保真 · 断链修复 — 图片SSRF/根MEMORY.md保护根治 · Anthropic thinking回传+pause_turn续传 · 2523 用例全量回归 + E2E 扩充
CI / 类型检查 + Lint + 单元测试 (push) Failing after 9m45s
CI / 全量测试 (Electron ABI) (push) Failing after 6m28s
CI / 产物编译验证 (push) Successful in 11m18s

This commit is contained in:
2026-09-08 14:30:27 +08:00
parent 69776e447f
commit 4cd6e997b5
86 changed files with 4303 additions and 956 deletions
+27
View File
@@ -25,6 +25,7 @@ import type {
MetonaStreamEvent,
} from '../types';
import type { MetonaModelInfo } from '../types/metona-adapter';
import { fetchImageAsBase64 } from './shared/ssrf-image-fetch';
/**
* 内容审核错误 — Provider 的安全过滤策略触发的错误
@@ -88,6 +89,16 @@ export abstract class BaseAdapter implements IMetonaProviderAdapter {
this.externalAbortSignal = signal;
}
/**
* v0.8.2 P3-3: 读取外部中断信号(流式消费阶段的中断贯通)。
* 子类的 sendStream 把它传入流读取辅助 —— fetch 头阶段的 abort 由
* fetchWithTimeout 处理,流体消费阶段的 abort 由 readStreamChunkWithIdleTimeout
* 竞速处理(此前 reader.read() 对用户中断无感,挂起流无法被"中断"按钮终止)。
*/
protected getExternalAbortSignal(): AbortSignal | undefined {
return this.externalAbortSignal;
}
/**
* #24 修复: 封装 fetch + 超时控制,在 finally 中 clearTimeout,避免 timer 泄漏
*
@@ -155,6 +166,22 @@ export abstract class BaseAdapter implements IMetonaProviderAdapter {
}
}
/**
* v0.8.2 P0-1: SSRF 安全的图片下载通道(Anthropic / Ollama 图片 URL 共用)
*
* 此前子类直接 fetchWithTimeout 下载消息里的 http(s) 图片 URL —— 无 SSRF 校验、
* 无字节上限,且下载结果以 base64 进入模型上下文(**数据可回读**的外泄通道)。
* 现统一走 fetchImageAsBase64resolvePublicAddresses + DNS pinning 校验与连接
* 同源、逐跳重定向复检、10MB 字节上限、png/jpeg/gif/webp 类型白名单;
* 外部 abort 信号(用户中断)照常透传。失败时调用方按"跳过该图"降级。
*/
protected async fetchImageAsBase64(
url: string,
timeoutMs = 30_000,
): Promise<{ base64: string; mediaType: string }> {
return fetchImageAsBase64(url, { timeoutMs, signal: this.externalAbortSignal });
}
async healthCheck(): Promise<boolean> {
try {
await this.listModels();