fix(api): 素材同步 - 增加 ID 长度边界校验

This commit is contained in:
ddCat
2026-08-15 17:00:30 +08:00
parent f5bb9ed4f9
commit fdb31832e5
2 changed files with 55 additions and 1 deletions

View File

@@ -5,6 +5,7 @@ import (
"errors"
"strings"
"time"
"unicode/utf8"
"infinite-canvas/backend/internal/model"
@@ -295,6 +296,13 @@ func assetFromJSON(userID string, raw json.RawMessage) (model.Asset, error) {
if id == "" {
id = newID()
}
if utf8.RuneCountInString(id) > model.AssetIDMaxLength {
return model.Asset{}, BadAuthRequest("素材 ID 不能超过 80 个字符")
}
primaryVersionID := strings.TrimSpace(payload.PrimaryVersionID)
if utf8.RuneCountInString(primaryVersionID) > 36 {
return model.Asset{}, BadAuthRequest("素材主版本 ID 不能超过 36 个字符")
}
category := model.AssetCategory(strings.TrimSpace(payload.Category))
if category == "" {
category = model.AssetCategoryOther
@@ -309,7 +317,7 @@ func assetFromJSON(userID string, raw json.RawMessage) (model.Asset, error) {
Kind: strings.TrimSpace(payload.Kind),
Category: category,
Status: status,
PrimaryVersionID: strings.TrimSpace(payload.PrimaryVersionID),
PrimaryVersionID: primaryVersionID,
Title: strings.TrimSpace(payload.Title),
PayloadJSON: string(raw),
CreatedAt: createdAt,

View File

@@ -2,9 +2,55 @@ package service
import (
"encoding/json"
"strings"
"testing"
"infinite-canvas/backend/internal/model"
)
func TestAssetFromJSONAcceptsDeterministicGenerationID(t *testing.T) {
id := "generation_" + strings.Repeat("a", 64)
raw, err := json.Marshal(map[string]any{"id": id, "kind": "image", "title": "生成图片"})
if err != nil {
t.Fatalf("marshal asset: %v", err)
}
asset, err := assetFromJSON("user-1", raw)
if err != nil {
t.Fatalf("assetFromJSON: %v", err)
}
if asset.ID != id {
t.Fatalf("asset ID = %q, want %q", asset.ID, id)
}
if len([]rune(asset.ID)) > model.AssetIDMaxLength {
t.Fatalf("generation asset ID length = %d, limit %d", len([]rune(asset.ID)), model.AssetIDMaxLength)
}
}
func TestAssetFromJSONRejectsIDOverLimit(t *testing.T) {
raw, err := json.Marshal(map[string]any{"id": strings.Repeat("a", model.AssetIDMaxLength+1), "kind": "image"})
if err != nil {
t.Fatalf("marshal asset: %v", err)
}
_, err = assetFromJSON("user-1", raw)
if err == nil || !strings.Contains(err.Error(), "素材 ID 不能超过 80 个字符") {
t.Fatalf("assetFromJSON error = %v", err)
}
}
func TestAssetFromJSONRejectsPrimaryVersionIDOverLimit(t *testing.T) {
raw, err := json.Marshal(map[string]any{"id": "asset-1", "primaryVersionId": strings.Repeat("v", 37)})
if err != nil {
t.Fatalf("marshal asset: %v", err)
}
_, err = assetFromJSON("user-1", raw)
if err == nil || !strings.Contains(err.Error(), "素材主版本 ID 不能超过 36 个字符") {
t.Fatalf("assetFromJSON error = %v", err)
}
}
func TestValidateSyncedPayloadAllowsDataURLMentionInErrorMessage(t *testing.T) {
raw, err := json.Marshal(map[string]interface{}{
"nodes": []interface{}{