b9b928ddcf418ecadf2c48ac7a2507c592bb9562

Author
TheEdgeOfRage <git@theedgeofrage.com>
Committer
TheEdgeOfRage <git@theedgeofrage.com>
Date

Message

fix(web): copy absolute download URLs

Diff

This diff is truncated to protect this page.

 1diff --git a/pkg/web/pages/browser.go b/pkg/web/pages/browser.go
 2index 4049ca3d2d49bd8212a590493d09101877b17afd..04e597062160f8899466bf3c4271a8356ef65928 100644
 3--- a/pkg/web/pages/browser.go
 4+++ b/pkg/web/pages/browser.go
 5@@ -123,8 +123,9 @@ func treeBrowser(w http.ResponseWriter, r *http.Request) {
 6 		http.Error(w, "not found", http.StatusNotFound)
 7 		return
 8 	}
 9+	cfg := config.FromContext(r.Context())
10 	page := treePage{
11-		ServerName:  config.FromContext(r.Context()).Name,
12+		ServerName:  cfg.Name,
13 		Repository:  repo.Name(),
14 		Ref:         ref.Name().String(),
15 		Path:        treePath,
16@@ -141,7 +142,7 @@ func treeBrowser(w http.ResponseWriter, r *http.Request) {
17 			page.Entries, page.Truncated, err = treePageEntries(gitRepo, ref, repo.Name(), page.Ref, treePath)
18 			page.ParentURL = TreeURL(repo.Name(), page.Ref, path.Dir(treePath))
19 		} else {
20-			page.File, err = treeFilePage(entry, repo.Name(), page.Ref, treePath)
21+			page.File, err = treeFilePage(entry, cfg.HTTP.PublicURL, repo.Name(), page.Ref, treePath)
22 			page.ParentURL = TreeURL(repo.Name(), page.Ref, path.Dir(treePath))
23 		}
24 	}
25@@ -213,12 +214,12 @@ func treeEntryCommits(repo *git.Repository, ref *git.Reference, paths []string)
26 	return commits
27 }
28 
29-func treeFilePage(entry *git.TreeEntry, repository, refName, treePath string) (*treePageFile, error) {
30+func treeFilePage(entry *git.TreeEntry, publicURL, repository, refName, treePath string) (*treePageFile, error) {
31 	page := &treePageFile{
32 		Name:        entry.Name(),
33 		Path:        treePath,
34 		Size:        entry.Size(),
35-		DownloadURL: RawURL(repository, refName, treePath),
36+		DownloadURL: AbsoluteRawURL(publicURL, repository, refName, treePath),
37 	}
38 	content, err := LoadBlob(entry, TextLimit)
39 	if errors.Is(err, ErrContentTooLarge) {
40diff --git a/pkg/web/pages/urls.go b/pkg/web/pages/urls.go
41index 41778a6cd5b9b557f84e9b79153eaf18b87c35aa..a6b6aaddc3a96eb85906a1555c09738a4fd9bda7 100644
42--- a/pkg/web/pages/urls.go
43+++ b/pkg/web/pages/urls.go
44@@ -27,6 +27,18 @@ func RawURL(repository, ref, treePath string) string {
45 	return PageURL(repository, "raw", url.Values{"ref": {ref}, "path": {treePath}})
46 }
47 
48+func AbsoluteRawURL(publicURL, repository, ref, treePath string) string {
49+	base, err := url.Parse(publicURL)
50+	if err != nil || base.Scheme == "" || base.Host == "" {
51+		return RawURL(repository, ref, treePath)
52+	}
53+	raw, err := url.Parse(RawURL(repository, ref, treePath))
54+	if err != nil {
55+		return RawURL(repository, ref, treePath)
56+	}
57+	return base.ResolveReference(raw).String()
58+}
59+
60 func splitRepositoryName(name string) []string {
61 	// A repository name may be nested. URL.JoinPath escapes each component and
62 	// preserves only the deliberate repository separators.
63diff --git a/pkg/web/repository_browser_test.go b/pkg/web/repository_browser_test.go
64index 183347824d1b51fdb449b906349cc778a04afc3b..0f5cd07e1bf1b5b019d0e92504e3942b7ac2c6ee 100644
65--- a/pkg/web/repository_browser_test.go
66+++ b/pkg/web/repository_browser_test.go
67@@ -116,7 +116,7 @@ func TestRepositoryBrowserOverviewAndTreeRoutes(t *testing.T) {
68 		t.Errorf("nested tree ordering response = %d: %s", nested.Code, nested.Body.String())
69 	}
70 	source := request("/team/nested/@/tree?ref=refs%2Fheads%2Fmain&path=source.go")
71-	if source.Code != http.StatusOK || strings.Contains(source.Body.String(), "<script>alert") || !strings.Contains(source.Body.String(), "&lt;") {