diff --git a/pkg/channels/feishu/common.go b/pkg/channels/feishu/common.go index 1bce0e74e..3ca6d0b46 100644 --- a/pkg/channels/feishu/common.go +++ b/pkg/channels/feishu/common.go @@ -87,6 +87,7 @@ func stripMentionPlaceholders(content string, mentions []*larkim.MentionEvent) s // extractCardImageKeys recursively extracts all image keys from a Feishu interactive card. // Image keys are used to download images from Feishu API. +// Only Feishu-hosted keys are returned (img_xxx, icon_xxx); external URLs are filtered out. func extractCardImageKeys(rawContent string) []string { if rawContent == "" { return nil @@ -102,7 +103,21 @@ func extractCardImageKeys(rawContent string) []string { return keys } +// isFeishuImageKey returns true if the string is a Feishu-hosted image key +// (not an external URL). Feishu keys typically start with img_, icon_, or file_. +func isFeishuImageKey(s string) bool { + if s == "" { + return false + } + // Filter out external URLs + if strings.HasPrefix(s, "http://") || strings.HasPrefix(s, "https://") { + return false + } + return true +} + // extractImageKeysRecursive traverses card structure to find all image keys. +// Only Feishu-hosted keys are collected; external URLs are skipped. func extractImageKeysRecursive(v any, keys *[]string) { switch val := v.(type) { case map[string]any: @@ -110,12 +125,12 @@ func extractImageKeysRecursive(v any, keys *[]string) { if tag, ok := val["tag"].(string); ok { switch tag { case "img": - // Try img_key first (most common) + // Try img_key first (most common, always Feishu-hosted) if imgKey, ok := val["img_key"].(string); ok && imgKey != "" { *keys = append(*keys, imgKey) } - // Also try src (alternative format) - if src, ok := val["src"].(string); ok && src != "" { + // Also try src, but only if it's a Feishu-hosted key (not external URL) + if src, ok := val["src"].(string); ok && src != "" && isFeishuImageKey(src) { *keys = append(*keys, src) } case "icon": diff --git a/pkg/channels/feishu/common_test.go b/pkg/channels/feishu/common_test.go index c8b77f655..52b47669e 100644 --- a/pkg/channels/feishu/common_test.go +++ b/pkg/channels/feishu/common_test.go @@ -347,6 +347,16 @@ func TestExtractCardImageKeys(t *testing.T) { content: `{"header":{"title":{"content":"Title"}},"elements":[{"tag":"div","text":{"content":"Description"}},{"tag":"img","img_key":"img_main"}]}`, want: []string{"img_main"}, }, + { + name: "external URL in src is filtered out", + content: `{"elements":[{"tag":"img","src":"https://example.com/image.png"}]}`, + want: nil, + }, + { + name: "mixed Feishu keys and external URLs", + content: `{"elements":[{"tag":"img","img_key":"img_feishu"},{"tag":"img","src":"https://cdn.example.com/external.jpg"},{"tag":"img","src":"img_another"}]}`, + want: []string{"img_feishu", "img_another"}, + }, } for _, tt := range tests {