chore: refresh gramsrv public release

This commit is contained in:
A 2026-06-30 14:37:43 +08:00
parent 75cebe8dbf
commit 70b6820474
1274 changed files with 378751 additions and 59919 deletions

View file

@ -0,0 +1,75 @@
package domain
import (
"hash/fnv"
"net/url"
"strings"
)
// NormalizeWebPageURL 把用户消息里的链接规范化为去重用的稳定形态:仅接受 http/https、
// 拒绝带 userinfo 的 URL(SSRF/伪装防御)、小写 scheme 与 host、去掉默认端口与 fragment,
// 保留 path 与 query 原样。返回规范化 URL 与是否可预览(不可预览返回 false)。
func NormalizeWebPageURL(raw string) (string, bool) {
raw = strings.TrimSpace(raw)
if raw == "" {
return "", false
}
u, err := url.Parse(raw)
if err != nil {
return "", false
}
scheme := strings.ToLower(u.Scheme)
if scheme != "http" && scheme != "https" {
return "", false
}
if u.User != nil {
return "", false
}
host := strings.ToLower(u.Host)
if host == "" {
return "", false
}
// 去掉与 scheme 对应的默认端口,避免 example.com 与 example.com:80 哈希不同。
if h, port, ok := splitHostPort(host); ok {
if (scheme == "http" && port == "80") || (scheme == "https" && port == "443") {
host = h
}
}
out := scheme + "://" + host + u.EscapedPath()
if u.RawQuery != "" {
out += "?" + u.RawQuery
}
return out, true
}
// splitHostPort 拆分 host:port;无端口时 ok=false。不用 net.SplitHostPort 以免 IPv6
// 字面量裸 host(无端口)被当作错误。
func splitHostPort(host string) (string, string, bool) {
// IPv6 字面量形如 [::1]:443;只在末尾 ] 之后找端口。
idx := strings.LastIndexByte(host, ':')
if idx < 0 {
return host, "", false
}
if close := strings.LastIndexByte(host, ']'); close >= 0 && idx < close {
return host, "", false
}
return host[:idx], host[idx+1:], true
}
// IsPendingWebPageMedia 报告 media 是否为 ID==id 的 pending 链接预览占位(异步解析的
// 幂等守卫:仅这种状态才允许被解析结果就地替换)。
func IsPendingWebPageMedia(m *MessageMedia, id int64) bool {
return m != nil &&
m.Kind == MessageMediaKindWebPage &&
m.WebPage != nil &&
m.WebPage.State == MessageWebPageStatePending &&
m.WebPage.ID == id
}
// WebPageURLHash 计算规范化 URL 的稳定 63-bit 哈希,同时用作 web_pages 行的主键与
// webPage id(保证 pending 占位与 done 解析携带同一 id)。FNV-1a/64 取正。
func WebPageURLHash(normalized string) int64 {
h := fnv.New64a()
_, _ = h.Write([]byte(normalized))
return int64(h.Sum64() & 0x7fffffffffffffff)
}