fix(api): 素材同步 - 增加 ID 长度边界校验
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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{}{
|
||||
|
||||
Reference in New Issue
Block a user