fix(gateway): prevent double /v1/files/ prefix in media URLs

OnEvent handler mutated MediaResult.Path in-place on the shared
RunResult.Media slice, corrupting paths for downstream consumers
(announce queue, outbound channels). Clone the media slice before
signing URLs. Add defense-in-depth guard in mediaToMarkdown to
skip prefix when path already starts with v1/files/ or v1/media/.
This commit is contained in:
viettranx committed 2026-03-25 12:06:41 +07:00
1 parent 0609b0cba7
commit 5f1658cfad
2 files changed
+16 -5

No files matched your search

+7 -1
View File
@@ -126,7 +126,13 @@ func mediaToMarkdown(media []agent.MediaResult, cfg *config.Config) string {
}
// Store clean path only — no auth tokens in persisted session messages.
// Frontend adds auth (Bearer header or ?ft= signed token) at render time.
fileURL := "/v1/files/" + urlPath
// Guard: if path is already a /v1/ URL (e.g. from mutated media), don't double-prefix.
var fileURL string
if strings.HasPrefix(urlPath, "v1/files/") || strings.HasPrefix(urlPath, "v1/media/") {
fileURL = "/" + strings.SplitN(urlPath, "?", 2)[0] // strip any existing query params
} else {
fileURL = "/v1/files/" + urlPath
}
if strings.HasPrefix(mr.ContentType, "image/") {
parts = append(parts, fmt.Sprintf("![image](%s)", fileURL))
} else {
+9 -4
View File
@@ -179,13 +179,18 @@ func wireExtras(
}
// Convert media local paths → signed /v1/files/basename?ft=hash
if rawMedia, ok := m["media"].([]agent.MediaResult); ok {
for i := range rawMedia {
basename := filepath.Base(rawMedia[i].Path)
// Clone slice — the original is shared with RunResult.Media;
// mutating in-place corrupts paths for downstream consumers
// (announce queue, outbound channels) that expect local paths.
signed := make([]agent.MediaResult, len(rawMedia))
for i, mr := range rawMedia {
signed[i] = mr
basename := filepath.Base(mr.Path)
url := "/v1/files/" + basename
ft := httpapi.SignFileToken(url, secret, httpapi.FileTokenTTL)
rawMedia[i].Path = url + "?ft=" + ft
signed[i].Path = url + "?ft=" + ft
}
m["media"] = rawMedia
m["media"] = signed
}
}
msgBus.Broadcast(bus.Event{