fix(file): 修复商品详情截图与提现打款凭证等私有图片 403 权限问题
- 放宽公开商品截图 key 提取规则,支持任意合规 object key 转换为免鉴权公开端点 - 补充后台截图上传 listing_screenshot 与 operating-expense 场景识别 - dependencies 授权器支持已审核上架商品截图兜底放行、提现人打款凭证鉴权及变体后缀匹配 - /api/files 路由组支持用户与管理员双重鉴权 (AuthUserOrAdmin) - 前端收款账号凭证与提现详情凭证统一升级为 AuthImage 组件并支持大图预览
This commit is contained in:
@@ -118,8 +118,12 @@ func fileURLForScene(scene string, key string) string {
|
||||
func normalizeScene(scene string) string {
|
||||
scene = strings.TrimSpace(strings.ToLower(scene))
|
||||
switch scene {
|
||||
case "listing", "handoff", "dispute", "realname", "avatar", "home-banner", "chat", "payment-cert", "announcement", "qrcode", "mohong", "crash", "aw-recycle", "cooperation-feedback", "manual-disbursement":
|
||||
case "listing", "handoff", "dispute", "realname", "avatar", "home-banner", "chat", "payment-cert", "announcement", "qrcode", "mohong", "crash", "aw-recycle", "cooperation-feedback", "manual-disbursement", "operating-expense":
|
||||
return scene
|
||||
case "listing_screenshot", "listing-screenshot":
|
||||
return "listing"
|
||||
case "operating_expense":
|
||||
return "operating-expense"
|
||||
default:
|
||||
return "misc"
|
||||
}
|
||||
|
||||
@@ -76,3 +76,19 @@ func TestCooperationFeedbackSceneUsesPublicFileURL(t *testing.T) {
|
||||
t.Fatalf("cooperation-feedback file url = %q, want public file endpoint", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeSceneListingScreenshotAndOperatingExpense(t *testing.T) {
|
||||
if got := normalizeScene("listing_screenshot"); got != "listing" {
|
||||
t.Fatalf("normalize listing_screenshot scene = %q, want listing", got)
|
||||
}
|
||||
if got := normalizeScene("listing-screenshot"); got != "listing" {
|
||||
t.Fatalf("normalize listing-screenshot scene = %q, want listing", got)
|
||||
}
|
||||
if got := normalizeScene("operating-expense"); got != "operating-expense" {
|
||||
t.Fatalf("normalize operating-expense scene = %q, want operating-expense", got)
|
||||
}
|
||||
if got := normalizeScene("operating_expense"); got != "operating-expense" {
|
||||
t.Fatalf("normalize operating_expense scene = %q, want operating-expense", got)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -452,11 +452,11 @@ func extractListingObjectKey(fileURL string) string {
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
key := parsed.Query().Get("key")
|
||||
if key == "" {
|
||||
if !strings.HasSuffix(parsed.Path, "/files/object") {
|
||||
return ""
|
||||
}
|
||||
if !strings.HasPrefix(key, "listing/") || strings.Contains(key, "..") {
|
||||
key := strings.TrimSpace(parsed.Query().Get("key"))
|
||||
if key == "" || strings.Contains(key, "..") || strings.HasPrefix(key, "/") || strings.HasPrefix(key, "\\") {
|
||||
return ""
|
||||
}
|
||||
return key
|
||||
|
||||
@@ -769,6 +769,44 @@ func TestApplyPublicScreenshotGroups(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublicScreenshotURLsWithMiscAndListingKeys(t *testing.T) {
|
||||
rawURLs := []string{
|
||||
"/api/files/object?key=misc%2F2026%2F09%2F16%2F984a80162e94e3b89090d1f8.webp",
|
||||
"/api/files/object?key=listing%2Fnormal.webp",
|
||||
"https://example.com/external.jpg",
|
||||
}
|
||||
publicURLs := publicScreenshotURLs(29969, rawURLs, "published", "approved")
|
||||
if len(publicURLs) != 3 {
|
||||
t.Fatalf("expected 3 public URLs, got %d", len(publicURLs))
|
||||
}
|
||||
if publicURLs[0] != "/api/listings/29969/screenshots/0" {
|
||||
t.Fatalf("expected /api/listings/29969/screenshots/0, got %q", publicURLs[0])
|
||||
}
|
||||
if publicURLs[1] != "/api/listings/29969/screenshots/1" {
|
||||
t.Fatalf("expected /api/listings/29969/screenshots/1, got %q", publicURLs[1])
|
||||
}
|
||||
if publicURLs[2] != "https://example.com/external.jpg" {
|
||||
t.Fatalf("external URL should remain unchanged, got %q", publicURLs[2])
|
||||
}
|
||||
|
||||
coverURL := publicCoverURL(29969, rawURLs, "published", "approved")
|
||||
if coverURL != "/api/listings/29969/cover" {
|
||||
t.Fatalf("expected /api/listings/29969/cover, got %q", coverURL)
|
||||
}
|
||||
|
||||
summary := map[string]any{
|
||||
"screenshot_groups": map[string]any{
|
||||
"coin": []string{"/api/files/object?key=misc%2F2026%2F09%2F16%2F984a80162e94e3b89090d1f8.webp"},
|
||||
},
|
||||
}
|
||||
applyPublicScreenshotGroups(29969, summary, rawURLs, publicURLs)
|
||||
groups := summary["screenshot_groups"].(map[string]any)
|
||||
coinList := groups["coin"].([]string)
|
||||
if len(coinList) != 1 || coinList[0] != "/api/listings/29969/screenshots/0" {
|
||||
t.Fatalf("expected mapped /api/listings/29969/screenshots/0, got %#v", coinList)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateScreenshots(t *testing.T) {
|
||||
db := database.NewTestDB()
|
||||
if err := database.MigrateListingLifecycleTestSchema(db); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user