feat(seo): add robots.txt, sitemap, and noindex tags for downloads
All checks were successful
Build and Publish Docker Image / deploy (push) Successful in 2m2s

Register routes for robots.txt and sitemap.xml, and implement search engine indexing controls to protect user privacy.

Specifically:
- Set `X-Robots-Tag: noindex, nofollow, noarchive` headers on file downloads, thumbnails, and zip generation.
- Configure `Robots: web.RobotsNone` on download and preview pages to prevent indexing of temporary user uploads.
- Add canonical URLs, improved descriptions, and image alt tags to page metadata for better social sharing.
This commit is contained in:
2026-06-03 12:15:49 +03:00
parent f698ba516d
commit e17c5e92a7
16 changed files with 201 additions and 26 deletions

View File

@@ -136,10 +136,19 @@ func (a *App) DownloadPage(w http.ResponseWriter, r *http.Request) {
description = "This shared box is password protected."
}
pageURL := absoluteURL(r, fmt.Sprintf("/d/%s", box.ID))
ogImage := absoluteURL(r, fmt.Sprintf("/d/%s/og-image.jpg", box.ID))
// All user uploads are private/temporary — noindex by default.
robots := web.RobotsNone
a.renderPage(w, r, http.StatusOK, "download.html", web.PageData{
Title: title,
Description: description,
ImageURL: absoluteURL(r, fmt.Sprintf("/d/%s/og-image.jpg", box.ID)),
Title: title,
Description: description,
CanonicalURL: pageURL,
Robots: robots,
ImageURL: ogImage,
ImageAlt: fmt.Sprintf("%d shared file%s on Warp Box", len(box.Files), plural(len(box.Files))),
Data: downloadPageData{
Box: boxView{ID: box.ID},
Files: files,
@@ -179,19 +188,27 @@ func (a *App) DownloadFile(w http.ResponseWriter, r *http.Request) {
return
}
view := a.fileView(box, file)
fileSize := helpers.FormatBytes(file.Size)
title := file.Name
description := fmt.Sprintf("%s shared via Warpbox", helpers.FormatBytes(file.Size))
description := fmt.Sprintf("%s · %s file shared via Warp Box", fileSize, file.ContentType)
imageURL := absoluteURL(r, view.ThumbnailURL)
imageAlt := fmt.Sprintf("Preview of %s", file.Name)
if locked && box.Obfuscate {
title = "Protected Warpbox file"
description = "This shared file is password protected."
imageURL = absoluteURL(r, "/static/img/file-placeholder.webp")
imageAlt = "Password protected file on Warp Box"
}
pageURL := absoluteURL(r, fmt.Sprintf("/d/%s/f/%s", box.ID, file.ID))
a.renderPage(w, r, http.StatusOK, "preview.html", web.PageData{
Title: title,
Description: description,
ImageURL: imageURL,
Title: title,
Description: description,
CanonicalURL: pageURL,
Robots: web.RobotsNone,
ImageURL: imageURL,
ImageAlt: imageAlt,
Data: previewPageData{
Box: boxView{ID: box.ID},
File: view,
@@ -203,6 +220,7 @@ func (a *App) DownloadFile(w http.ResponseWriter, r *http.Request) {
}
func (a *App) DownloadFileContent(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Robots-Tag", "noindex, nofollow, noarchive")
box, file, ok := a.loadFileForRequest(w, r)
if !ok {
return
@@ -222,6 +240,7 @@ func (a *App) DownloadFileContent(w http.ResponseWriter, r *http.Request) {
}
func (a *App) Thumbnail(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Robots-Tag", "noindex, nofollow, noarchive")
box, file, ok := a.loadFileForRequest(w, r)
if !ok {
return
@@ -342,6 +361,7 @@ func readSeekCloser(source io.ReadCloser) io.ReadSeeker {
}
func (a *App) DownloadZip(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Robots-Tag", "noindex, nofollow, noarchive")
box, err := a.uploadService.GetBox(r.PathValue("boxID"))
if err != nil {
a.logger.Warn("zip request missing box", withRequestLogAttrs(r, "source", "download", "severity", "warn", "code", 4044, "box_id", r.PathValue("boxID"))...)