From e796cefe9f791956c231629714d4edeab15e1bf4 Mon Sep 17 00:00:00 2001 From: Linghong Date: Thu, 9 Jul 2026 13:02:29 +0000 Subject: [PATCH] =?UTF-8?q?=E8=84=B1=E6=95=8F=E9=98=BF=E9=87=8C=E4=BA=91?= =?UTF-8?q?=E6=8A=A0=E5=9B=BE=E7=BB=93=E6=9E=9C=E4=B8=8B=E8=BD=BD=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 避免临时 OSS 签名 URL 进入日志和审计 metadata 补充结果下载错误脱敏单测 --- server-rs/crates/platform-matting/src/lib.rs | 74 +++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/server-rs/crates/platform-matting/src/lib.rs b/server-rs/crates/platform-matting/src/lib.rs index 42f38ee7b..09cf22e9f 100644 --- a/server-rs/crates/platform-matting/src/lib.rs +++ b/server-rs/crates/platform-matting/src/lib.rs @@ -358,7 +358,9 @@ impl MattingClient { .get(url) .send() .await - .map_err(|error| MattingError::Upstream(format!("下载抠图结果失败:{error}")))?; + .map_err(|error| { + MattingError::Upstream(describe_result_download_transport_error(&error)) + })?; let status = response.status(); if !status.is_success() { return Err(MattingError::Upstream(format!( @@ -370,7 +372,9 @@ impl MattingClient { .bytes() .await .map(|bytes| bytes.to_vec()) - .map_err(|error| MattingError::Upstream(format!("读取抠图结果字节失败:{error}"))) + .map_err(|error| { + MattingError::Upstream(describe_result_download_body_error(&error)) + }) } /// 把本地图片字节上传到 VIAPI 官方临时桶,返回可直接作为 ImageURL 的公网地址。 @@ -581,6 +585,48 @@ fn hmac_sha1_base64(key: &[u8], content: &[u8]) -> Result Ok(base64::engine::general_purpose::STANDARD.encode(signer.finalize().into_bytes())) } +fn describe_result_download_transport_error(error: &reqwest::Error) -> String { + sanitize_result_download_error_message(format!( + "下载抠图结果失败(transport={}, timeout={}, connect={})", + classify_reqwest_error(error), + error.is_timeout(), + error.is_connect() + )) +} + +fn describe_result_download_body_error(error: &reqwest::Error) -> String { + sanitize_result_download_error_message(format!( + "读取抠图结果字节失败(transport={}, timeout={}, connect={})", + classify_reqwest_error(error), + error.is_timeout(), + error.is_connect() + )) +} + +fn classify_reqwest_error(error: &reqwest::Error) -> &'static str { + if error.is_timeout() { + "timeout" + } else if error.is_connect() { + "connect" + } else if error.is_body() || error.is_decode() { + "body" + } else if error.is_request() { + "request" + } else { + "unknown" + } +} + +fn sanitize_result_download_error_message(message: String) -> String { + if message.contains("OSSAccessKeyId=") + || message.contains("Signature=") + || message.contains("Expires=") + { + return "下载抠图结果失败(临时签名 URL 已脱敏)".to_string(); + } + message +} + fn insert_header( headers: &mut reqwest::header::HeaderMap, name: &'static str, @@ -710,4 +756,28 @@ mod tests { .expect("x-acs-date should exist"); assert!(!date.contains('.'), "x-acs-date 不能带小数秒:{date}"); } + + #[test] + fn result_download_error_message_redacts_signed_oss_url() { + let message = sanitize_result_download_error_message( + "下载抠图结果失败:error sending request for url (https://viapi-customer-temp.oss-cn-shanghai.aliyuncs.com/a.png?OSSAccessKeyId=ak&Expires=123&Signature=secret)".to_string(), + ); + + assert!(!message.contains("OSSAccessKeyId")); + assert!(!message.contains("Signature")); + assert!(!message.contains("Expires=123")); + assert_eq!(message, "下载抠图结果失败(临时签名 URL 已脱敏)"); + } + + #[test] + fn result_download_error_message_keeps_safe_text() { + let message = sanitize_result_download_error_message( + "下载抠图结果失败(transport=connect, timeout=false, connect=true)".to_string(), + ); + + assert_eq!( + message, + "下载抠图结果失败(transport=connect, timeout=false, connect=true)" + ); + } }