/
githubmirror
/
photoprism
Обзор
Документация
Войти
/
githubmirror
/
photoprism
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
develop
internal/api/download.go
107 строк
3 KB
Michael Mayer
API: Adopt download visibility helpers and simplify token parsing #5733 #5743
24 июл 2026, 21:38
24 июл 2026, 21:38
3e7cc29
Код
Авторство
О чём код?
package api import ( "net/http" "path/filepath" "github.com/gin-gonic/gin" "github.com/photoprism/photoprism/internal/api/download" "github.com/photoprism/photoprism/internal/config/customize" "github.com/photoprism/photoprism/internal/entity/query" "github.com/photoprism/photoprism/internal/entity/search" "github.com/photoprism/photoprism/internal/photoprism" "github.com/photoprism/photoprism/internal/photoprism/get" "github.com/photoprism/photoprism/pkg/clean" "github.com/photoprism/photoprism/pkg/fs" "github.com/photoprism/photoprism/pkg/rnd" ) // TODO: GET /api/v1/dl/file/:hash // TODO: GET /api/v1/dl/photo/:uid // TODO: GET /api/v1/dl/album/:uid // DownloadName returns the download file name type. func DownloadName(c *gin.Context) customize.DownloadName { switch c.Query("name") { case "file": return customize.DownloadNameFile case "share": return customize.DownloadNameShare case "original": return customize.DownloadNameOriginal default: return get.Config().Settings().Download.Name } } // GetDownload returns the raw file data. // // @Summary returns the raw file data // @Id GetDownload // @Tags Images, Files // @Produce application/octet-stream // @Failure 403,404 {file} image/svg+xml // @Success 200 {file} application/octet-stream // @Param file path string true "file hash or unique download id" // @Router /api/v1/dl/{file} [get] func GetDownload(router *gin.RouterGroup) { router.GET("/dl/:file", func(c *gin.Context) { id := clean.Token(c.Param("file")) // Check for temporary download if the file is identified by a UUID string. if rnd.IsUUID(id) { fileName, fileErr := download.Find(id) if fileErr != nil { AbortForbidden(c) return } else if !fs.FileExists(fileName) { AbortNotFound(c) return } c.FileAttachment(fileName, filepath.Base(fileName)) return } // If the file is identified by its hash, the request must be authorized: a valid "?t=" download // token, or a Portal JWT in the request header. sess, valid := AuthDownload(c) if !valid { c.Data(http.StatusForbidden, "image/svg+xml", brokenIconSvg) return } // Withhold files the session may not see, checked before the file is resolved so a not-visible // hash and an unknown hash return the identical 404 — a token holder cannot probe which files // exist by hash. FileDownloadable scopes an identified session and limits a coarse token to public. if visible, vErr := search.FileDownloadable(id, sess); vErr != nil || !visible { c.Data(http.StatusNotFound, "image/svg+xml", brokenIconSvg) return } f, err := query.FileByHash(id) // Every negative path returns the identical SVG 404 so an unknown hash is indistinguishable // from one hidden or missing (no existence disclosure to a valid token holder). if err != nil { c.Data(http.StatusNotFound, "image/svg+xml", brokenIconSvg) return } fileName := photoprism.FileName(f.FileRoot, f.FileName) if !fs.FileExists(fileName) { log.Errorf("download: file %s is missing", clean.Log(f.FileName)) c.Data(404, "image/svg+xml", brokenIconSvg) // Set missing flag so that the file doesn't show up in search results anymore. logErr("download", f.Update("FileMissing", true)) return } c.FileAttachment(fileName, f.DownloadName(DownloadName(c), 0)) }) }