fix(voice/tts): strip query from scheme-less URLs in redactURL
redactURL's fallback returned the raw string when url.Parse found no host. A scheme-less BaseURL (127.0.0.1:9880/v1?token=...) fails to parse, so the signed query reached the WARN log and the error chain verbatim. Strip at ? and # in that path, keeping the '@' full-redaction rule first. Test pins the scheme-less query/fragment cases and goes red if the fix is reverted.
This commit is contained in:
1 parent
a5b3d40a74
commit
28a6cd7e53
2 files changed
+58
-10
No files matched your search
@@ -306,16 +306,29 @@ type Audio struct {
|
||||
// redactURL 把 baseURL 收敛成**可打日志**的形态:只保留 scheme 与 host,
|
||||
// 丢掉 userinfo/query(若运维在地址里塞了凭据,别把它写进日志)。
|
||||
//
|
||||
// 解析失败或没有 host 时**不能**原样返回:`http://user:pass@` 这种不合法地址会
|
||||
// 把凭据整个写进日志。因此兜底判据是"含 `@` 就整体打码"(`@` 是 userinfo 的
|
||||
// 分隔符,出现在地址里只可能是凭据)。
|
||||
// 解析不出 host 时**不能**原样返回,两条兜底各挡一类泄漏:
|
||||
// - 含 `@`(userinfo 的分隔符,出现在地址里只可能是凭据)⇒ 整体打码。
|
||||
// `http://user:pass@` 这种不合法地址因此不会把凭据整个写进日志。
|
||||
// - 其余多半是**漏了 scheme** 的地址(`127.0.0.1:9880/v1?token=…`:`url.Parse`
|
||||
// 在首段的 `:` 上报错,host 为空)。漏 scheme 不是"原样返回"的理由 ——
|
||||
// 签名与 token 就在 query 里,因此按 `?`/`#` 切掉查询串与片段再返回。
|
||||
func redactURL(raw string) string {
|
||||
u, err := url.Parse(raw)
|
||||
if err != nil || u.Host == "" {
|
||||
if strings.Contains(raw, "@") {
|
||||
return "<redacted>"
|
||||
}
|
||||
return raw
|
||||
if err == nil && u.Host != "" {
|
||||
return u.Scheme + "://" + u.Host
|
||||
}
|
||||
return u.Scheme + "://" + u.Host
|
||||
if strings.Contains(raw, "@") {
|
||||
return "<redacted>"
|
||||
}
|
||||
return stripURLQuery(raw)
|
||||
}
|
||||
|
||||
// stripURLQuery 切掉 raw 里 `?` 或 `#` 起的部分。它是 redactURL 在「解析不出
|
||||
// host」那条路径上的兜底:那里拿不到 url.URL 的 RawQuery/Fragment,只能按
|
||||
// 分隔符切。没有分隔符时原样返回(不重新编码、不规范化,便于肉眼比对)。
|
||||
func stripURLQuery(raw string) string {
|
||||
if i := strings.IndexAny(raw, "?#"); i >= 0 {
|
||||
return raw[:i]
|
||||
}
|
||||
return raw
|
||||
}
|
||||
Reference in new issue
Block a user