Files
backend/internal/service/message_segment_image.go
lafay 28a45caad3
All checks were successful
Build Backend / build (push) Successful in 13m35s
Build Backend / build-docker (push) Successful in 1m11s
feat(upload): integrate upload service for chat image validation and S3 uploads
- Added UploadService to handle image uploads and validation for chat messages.
- Updated ChatService and MessageService to utilize UploadService for validating image segments in messages.
- Enhanced wire generation to inject UploadService into relevant services.
- Introduced UploadImageBytes method in UploadService for uploading images directly from memory.
- Added TrustedPublicURLPrefix method in S3 Client for generating public URLs for uploaded images.
2026-03-25 03:57:40 +08:00

67 lines
1.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"fmt"
"net/url"
"strings"
"carrot_bbs/internal/model"
)
// ValidateChatMessageImageSegments 校验聊天消息中的图片段:禁止 data:/base64 内联,仅允许引用本站 S3 公开前缀下的 URL。
func (s *UploadService) ValidateChatMessageImageSegments(segments model.MessageSegments) error {
if s == nil || s.s3Client == nil {
return nil
}
prefix := strings.TrimSpace(s.s3Client.TrustedPublicURLPrefix())
if prefix == "" {
return nil
}
for _, seg := range segments {
if seg.Type != string(model.ContentTypeImage) && seg.Type != "image" {
continue
}
if seg.Data == nil {
return fmt.Errorf("图片消息数据无效")
}
urlStr, _ := seg.Data["url"].(string)
urlStr = strings.TrimSpace(urlStr)
if urlStr == "" {
return fmt.Errorf("图片消息缺少 url")
}
low := strings.ToLower(urlStr)
if strings.HasPrefix(low, "data:") || strings.HasPrefix(low, "base64:") || strings.HasPrefix(low, "base64://") {
return fmt.Errorf("禁止在消息中内联 base64 或 data URL请先通过上传接口获取图片地址")
}
if strings.ContainsAny(urlStr, "\n\r\x00") {
return fmt.Errorf("非法图片地址")
}
u, err := url.Parse(urlStr)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") {
return fmt.Errorf("图片地址必须为 http(s) 链接")
}
if u.Host == "" {
return fmt.Errorf("图片地址无效")
}
if !strings.HasPrefix(urlStr, prefix) {
return fmt.Errorf("图片必须使用本站上传接口生成的资源地址")
}
if thumb, ok := seg.Data["thumbnail_url"].(string); ok {
thumb = strings.TrimSpace(thumb)
if thumb != "" {
if strings.HasPrefix(strings.ToLower(thumb), "data:") {
return fmt.Errorf("禁止在图片消息中使用 data URL 缩略图")
}
if !strings.HasPrefix(thumb, prefix) {
return fmt.Errorf("缩略图地址不合法")
}
}
}
}
return nil
}