mirror of
https://github.com/photoprism/photoprism.git
synced 2025-12-12 00:34:13 +01:00
API: Improve request parameter sanitation #1814
This commit is contained in:
8
go.sum
8
go.sum
@@ -84,13 +84,10 @@ github.com/esimov/pigo v1.4.5 h1:ySG0QqMh02VNALvHnx04L1ScRu66N6XA5vLLga8GiLg=
|
|||||||
github.com/esimov/pigo v1.4.5/go.mod h1:SGkOUpm4wlEmQQJKlaymAkThY8/8iP+XE0gFo7g8G6w=
|
github.com/esimov/pigo v1.4.5/go.mod h1:SGkOUpm4wlEmQQJKlaymAkThY8/8iP+XE0gFo7g8G6w=
|
||||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||||
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||||
github.com/gin-contrib/gzip v0.0.3 h1:etUaeesHhEORpZMp18zoOhepboiWnFtXrBZxszWUn4k=
|
|
||||||
github.com/gin-contrib/gzip v0.0.3/go.mod h1:YxxswVZIqOvcHEQpsSn+QF5guQtO1dCfy0shBPy4jFc=
|
|
||||||
github.com/gin-contrib/gzip v0.0.5 h1:mhnVU32YnnBh2LPH2iqRqsA/eR7SAqRaD388jL2s/j0=
|
github.com/gin-contrib/gzip v0.0.5 h1:mhnVU32YnnBh2LPH2iqRqsA/eR7SAqRaD388jL2s/j0=
|
||||||
github.com/gin-contrib/gzip v0.0.5/go.mod h1:OPIK6HR0Um2vNmBUTlayD7qle4yVVRZT0PyhdUigrKk=
|
github.com/gin-contrib/gzip v0.0.5/go.mod h1:OPIK6HR0Um2vNmBUTlayD7qle4yVVRZT0PyhdUigrKk=
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
|
||||||
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
||||||
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
|
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
|
||||||
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
|
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
|
||||||
@@ -114,7 +111,6 @@ github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa
|
|||||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||||
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
|
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
|
||||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
|
||||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||||
github.com/go-playground/validator/v10 v10.9.0 h1:NgTtmN58D0m8+UuxtYmGztBJB7VnPgjj221I1QHci2A=
|
github.com/go-playground/validator/v10 v10.9.0 h1:NgTtmN58D0m8+UuxtYmGztBJB7VnPgjj221I1QHci2A=
|
||||||
github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||||
@@ -164,8 +160,6 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
|
|||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/gosimple/slug v1.11.2 h1:MxFR0TmQ/qz0KvIrBbf4phu+G0RBgpwxOn6jPKFKFOw=
|
|
||||||
github.com/gosimple/slug v1.11.2/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ=
|
|
||||||
github.com/gosimple/slug v1.12.0 h1:xzuhj7G7cGtd34NXnW/yF0l+AGNfWqwgh/IXgFy7dnc=
|
github.com/gosimple/slug v1.12.0 h1:xzuhj7G7cGtd34NXnW/yF0l+AGNfWqwgh/IXgFy7dnc=
|
||||||
github.com/gosimple/slug v1.12.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ=
|
github.com/gosimple/slug v1.12.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ=
|
||||||
github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o=
|
github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o=
|
||||||
@@ -419,8 +413,6 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 h1:TyHqChC80pFkXWraUUf6RuB5IqFdQieMLwwCJokV2pc=
|
|
||||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827 h1:A0Qkn7Z/n8zC1xd9LTw17AiKlBRK64tw3ejWQiEqca0=
|
golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827 h1:A0Qkn7Z/n8zC1xd9LTw17AiKlBRK64tw3ejWQiEqca0=
|
||||||
golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ import (
|
|||||||
"github.com/photoprism/photoprism/internal/query"
|
"github.com/photoprism/photoprism/internal/query"
|
||||||
"github.com/photoprism/photoprism/internal/service"
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
"github.com/photoprism/photoprism/internal/workers"
|
"github.com/photoprism/photoprism/internal/workers"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/pkg/fs"
|
"github.com/photoprism/photoprism/pkg/fs"
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Namespaces for caching and logs.
|
// Namespaces for caching and logs.
|
||||||
@@ -47,7 +49,7 @@ func GetAccount(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := ParseUint(c.Param("id"))
|
id := sanitize.IdUint(c.Param("id"))
|
||||||
|
|
||||||
if m, err := query.AccountByID(id); err == nil {
|
if m, err := query.AccountByID(id); err == nil {
|
||||||
c.JSON(http.StatusOK, m)
|
c.JSON(http.StatusOK, m)
|
||||||
@@ -80,7 +82,7 @@ func GetAccountFolders(router *gin.RouterGroup) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
id := ParseUint(c.Param("id"))
|
id := sanitize.IdUint(c.Param("id"))
|
||||||
cache := service.FolderCache()
|
cache := service.FolderCache()
|
||||||
cacheKey := fmt.Sprintf("%s:%d", accountFolder, id)
|
cacheKey := fmt.Sprintf("%s:%d", accountFolder, id)
|
||||||
|
|
||||||
@@ -128,7 +130,7 @@ func ShareWithAccount(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := ParseUint(c.Param("id"))
|
id := sanitize.IdUint(c.Param("id"))
|
||||||
|
|
||||||
m, err := query.AccountByID(id)
|
m, err := query.AccountByID(id)
|
||||||
|
|
||||||
@@ -237,7 +239,7 @@ func UpdateAccount(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := ParseUint(c.Param("id"))
|
id := sanitize.IdUint(c.Param("id"))
|
||||||
|
|
||||||
m, err := query.AccountByID(id)
|
m, err := query.AccountByID(id)
|
||||||
|
|
||||||
@@ -306,7 +308,7 @@ func DeleteAccount(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := ParseUint(c.Param("id"))
|
id := sanitize.IdUint(c.Param("id"))
|
||||||
|
|
||||||
m, err := query.AccountByID(id)
|
m, err := query.AccountByID(id)
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/acl"
|
"github.com/photoprism/photoprism/internal/acl"
|
||||||
"github.com/photoprism/photoprism/internal/entity"
|
"github.com/photoprism/photoprism/internal/entity"
|
||||||
"github.com/photoprism/photoprism/internal/event"
|
"github.com/photoprism/photoprism/internal/event"
|
||||||
@@ -17,7 +18,9 @@ import (
|
|||||||
"github.com/photoprism/photoprism/internal/query"
|
"github.com/photoprism/photoprism/internal/query"
|
||||||
"github.com/photoprism/photoprism/internal/search"
|
"github.com/photoprism/photoprism/internal/search"
|
||||||
"github.com/photoprism/photoprism/internal/service"
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/pkg/fs"
|
"github.com/photoprism/photoprism/pkg/fs"
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
"github.com/photoprism/photoprism/pkg/txt"
|
"github.com/photoprism/photoprism/pkg/txt"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -51,7 +54,7 @@ func GetAlbum(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := c.Param("uid")
|
id := sanitize.IdString(c.Param("uid"))
|
||||||
a, err := query.AlbumByUID(id)
|
a, err := query.AlbumByUID(id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -114,7 +117,7 @@ func UpdateAlbum(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uid := c.Param("uid")
|
uid := sanitize.IdString(c.Param("uid"))
|
||||||
a, err := query.AlbumByUID(uid)
|
a, err := query.AlbumByUID(uid)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -166,7 +169,7 @@ func DeleteAlbum(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := c.Param("uid")
|
id := sanitize.IdString(c.Param("uid"))
|
||||||
|
|
||||||
a, err := query.AlbumByUID(id)
|
a, err := query.AlbumByUID(id)
|
||||||
|
|
||||||
@@ -217,7 +220,7 @@ func LikeAlbum(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := c.Param("uid")
|
id := sanitize.IdString(c.Param("uid"))
|
||||||
a, err := query.AlbumByUID(id)
|
a, err := query.AlbumByUID(id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -255,7 +258,7 @@ func DislikeAlbum(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := c.Param("uid")
|
id := sanitize.IdString(c.Param("uid"))
|
||||||
a, err := query.AlbumByUID(id)
|
a, err := query.AlbumByUID(id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -290,7 +293,7 @@ func CloneAlbums(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
a, err := query.AlbumByUID(c.Param("uid"))
|
a, err := query.AlbumByUID(sanitize.IdString(c.Param("uid")))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Abort(c, http.StatusNotFound, i18n.ErrAlbumNotFound)
|
Abort(c, http.StatusNotFound, i18n.ErrAlbumNotFound)
|
||||||
@@ -355,7 +358,7 @@ func AddPhotosToAlbum(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uid := c.Param("uid")
|
uid := sanitize.IdString(c.Param("uid"))
|
||||||
a, err := query.AlbumByUID(uid)
|
a, err := query.AlbumByUID(uid)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -415,7 +418,7 @@ func RemovePhotosFromAlbum(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
a, err := query.AlbumByUID(c.Param("uid"))
|
a, err := query.AlbumByUID(sanitize.IdString(c.Param("uid")))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Abort(c, http.StatusNotFound, i18n.ErrAlbumNotFound)
|
Abort(c, http.StatusNotFound, i18n.ErrAlbumNotFound)
|
||||||
@@ -453,7 +456,7 @@ func DownloadAlbum(router *gin.RouterGroup) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
a, err := query.AlbumByUID(c.Param("uid"))
|
a, err := query.AlbumByUID(sanitize.IdString(c.Param("uid")))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Abort(c, http.StatusNotFound, i18n.ErrAlbumNotFound)
|
Abort(c, http.StatusNotFound, i18n.ErrAlbumNotFound)
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/event"
|
"github.com/photoprism/photoprism/internal/event"
|
||||||
"github.com/photoprism/photoprism/internal/i18n"
|
"github.com/photoprism/photoprism/internal/i18n"
|
||||||
"github.com/photoprism/photoprism/internal/service"
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
@@ -64,7 +65,7 @@ func UpdateClientConfig() {
|
|||||||
func Abort(c *gin.Context, code int, id i18n.Message, params ...interface{}) {
|
func Abort(c *gin.Context, code int, id i18n.Message, params ...interface{}) {
|
||||||
resp := i18n.NewResponse(code, id, params...)
|
resp := i18n.NewResponse(code, id, params...)
|
||||||
|
|
||||||
log.Debugf("api: abort %s with code %d (%s)", c.FullPath(), code, resp.String())
|
log.Debugf("api: abort %s with code %d (%s)", txt.LogParam(c.FullPath()), code, resp.String())
|
||||||
|
|
||||||
c.AbortWithStatusJSON(code, resp)
|
c.AbortWithStatusJSON(code, resp)
|
||||||
}
|
}
|
||||||
@@ -74,7 +75,7 @@ func Error(c *gin.Context, code int, err error, id i18n.Message, params ...inter
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Details = err.Error()
|
resp.Details = err.Error()
|
||||||
log.Errorf("api: error %s with code %d in %s (%s)", txt.LogParam(err.Error()), code, c.FullPath(), resp.String())
|
log.Errorf("api: error %s with code %d in %s (%s)", txt.LogParam(err.Error()), code, txt.LogParam(c.FullPath()), resp.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
c.AbortWithStatusJSON(code, resp)
|
c.AbortWithStatusJSON(code, resp)
|
||||||
|
|||||||
@@ -3,17 +3,19 @@ package api
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/photoprism"
|
|
||||||
"github.com/photoprism/photoprism/internal/service"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/jinzhu/gorm"
|
"github.com/jinzhu/gorm"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/acl"
|
"github.com/photoprism/photoprism/internal/acl"
|
||||||
"github.com/photoprism/photoprism/internal/entity"
|
"github.com/photoprism/photoprism/internal/entity"
|
||||||
"github.com/photoprism/photoprism/internal/event"
|
"github.com/photoprism/photoprism/internal/event"
|
||||||
"github.com/photoprism/photoprism/internal/form"
|
"github.com/photoprism/photoprism/internal/form"
|
||||||
"github.com/photoprism/photoprism/internal/i18n"
|
"github.com/photoprism/photoprism/internal/i18n"
|
||||||
|
"github.com/photoprism/photoprism/internal/photoprism"
|
||||||
"github.com/photoprism/photoprism/internal/query"
|
"github.com/photoprism/photoprism/internal/query"
|
||||||
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/pkg/txt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BatchPhotosArchive moves multiple photos to the archive.
|
// BatchPhotosArchive moves multiple photos to the archive.
|
||||||
@@ -40,7 +42,7 @@ func BatchPhotosArchive(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("photos: archiving %s", f.String())
|
log.Infof("photos: archiving %s", txt.LogParam(f.String()))
|
||||||
|
|
||||||
if service.Config().BackupYaml() {
|
if service.Config().BackupYaml() {
|
||||||
photos, err := query.PhotoSelection(f)
|
photos, err := query.PhotoSelection(f)
|
||||||
@@ -103,7 +105,7 @@ func BatchPhotosRestore(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("photos: restoring %s", f.String())
|
log.Infof("photos: restoring %s", txt.LogParam(f.String()))
|
||||||
|
|
||||||
if service.Config().BackupYaml() {
|
if service.Config().BackupYaml() {
|
||||||
photos, err := query.PhotoSelection(f)
|
photos, err := query.PhotoSelection(f)
|
||||||
@@ -165,7 +167,7 @@ func BatchPhotosApprove(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("photos: approving %s", f.String())
|
log.Infof("photos: approving %s", txt.LogParam(f.String()))
|
||||||
|
|
||||||
photos, err := query.PhotoSelection(f)
|
photos, err := query.PhotoSelection(f)
|
||||||
|
|
||||||
@@ -217,7 +219,7 @@ func BatchAlbumsDelete(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("albums: deleting %s", f.String())
|
log.Infof("albums: deleting %s", txt.LogParam(f.String()))
|
||||||
|
|
||||||
entity.Db().Where("album_uid IN (?)", f.Albums).Delete(&entity.Album{})
|
entity.Db().Where("album_uid IN (?)", f.Albums).Delete(&entity.Album{})
|
||||||
entity.Db().Where("album_uid IN (?)", f.Albums).Delete(&entity.PhotoAlbum{})
|
entity.Db().Where("album_uid IN (?)", f.Albums).Delete(&entity.PhotoAlbum{})
|
||||||
@@ -254,7 +256,7 @@ func BatchPhotosPrivate(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("photos: updating private flag for %s", f.String())
|
log.Infof("photos: updating private flag for %s", txt.LogParam(f.String()))
|
||||||
|
|
||||||
if err := entity.Db().Model(entity.Photo{}).Where("photo_uid IN (?)", f.Photos).UpdateColumn("photo_private",
|
if err := entity.Db().Model(entity.Photo{}).Where("photo_uid IN (?)", f.Photos).UpdateColumn("photo_private",
|
||||||
gorm.Expr("CASE WHEN photo_private > 0 THEN 0 ELSE 1 END")).Error; err != nil {
|
gorm.Expr("CASE WHEN photo_private > 0 THEN 0 ELSE 1 END")).Error; err != nil {
|
||||||
@@ -307,7 +309,7 @@ func BatchLabelsDelete(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("labels: deleting %s", f.String())
|
log.Infof("labels: deleting %s", txt.LogParam(f.String()))
|
||||||
|
|
||||||
var labels entity.Labels
|
var labels entity.Labels
|
||||||
|
|
||||||
@@ -359,7 +361,7 @@ func BatchPhotosDelete(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("photos: deleting %s", f.String())
|
log.Infof("photos: deleting %s", txt.LogParam(f.String()))
|
||||||
|
|
||||||
photos, err := query.PhotoSelection(f)
|
photos, err := query.PhotoSelection(f)
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/photoprism/photoprism/internal/photoprism"
|
"github.com/photoprism/photoprism/internal/photoprism"
|
||||||
"github.com/photoprism/photoprism/internal/query"
|
"github.com/photoprism/photoprism/internal/query"
|
||||||
@@ -37,13 +39,13 @@ func AlbumCover(router *gin.RouterGroup) {
|
|||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
conf := service.Config()
|
conf := service.Config()
|
||||||
thumbName := thumb.Name(c.Param("size"))
|
thumbName := thumb.Name(sanitize.Token(c.Param("size")))
|
||||||
uid := c.Param("uid")
|
uid := sanitize.IdString(c.Param("uid"))
|
||||||
|
|
||||||
size, ok := thumb.Sizes[thumbName]
|
size, ok := thumb.Sizes[thumbName]
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Errorf("%s: invalid size %s", albumCover, thumbName)
|
log.Errorf("%s: invalid size %s", albumCover, txt.LogParam(thumbName.String()))
|
||||||
c.Data(http.StatusOK, "image/svg+xml", albumIconSvg)
|
c.Data(http.StatusOK, "image/svg+xml", albumIconSvg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -84,7 +86,7 @@ func AlbumCover(router *gin.RouterGroup) {
|
|||||||
fileName := photoprism.FileName(f.FileRoot, f.FileName)
|
fileName := photoprism.FileName(f.FileRoot, f.FileName)
|
||||||
|
|
||||||
if !fs.FileExists(fileName) {
|
if !fs.FileExists(fileName) {
|
||||||
log.Errorf("%s: found no original for %s", albumCover, fileName)
|
log.Errorf("%s: found no original for %s", albumCover, txt.LogParam(fileName))
|
||||||
c.Data(http.StatusOK, "image/svg+xml", albumIconSvg)
|
c.Data(http.StatusOK, "image/svg+xml", albumIconSvg)
|
||||||
|
|
||||||
// Set missing flag so that the file doesn't show up in search results anymore.
|
// Set missing flag so that the file doesn't show up in search results anymore.
|
||||||
@@ -149,13 +151,13 @@ func LabelCover(router *gin.RouterGroup) {
|
|||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
conf := service.Config()
|
conf := service.Config()
|
||||||
thumbName := thumb.Name(c.Param("size"))
|
thumbName := thumb.Name(sanitize.Token(c.Param("size")))
|
||||||
uid := c.Param("uid")
|
uid := sanitize.IdString(c.Param("uid"))
|
||||||
|
|
||||||
size, ok := thumb.Sizes[thumbName]
|
size, ok := thumb.Sizes[thumbName]
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Errorf("%s: invalid size %s", labelCover, thumbName)
|
log.Errorf("%s: invalid size %s", labelCover, txt.LogParam(thumbName.String()))
|
||||||
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,16 @@ package api
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/entity"
|
"github.com/photoprism/photoprism/internal/entity"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/service"
|
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/photoprism"
|
"github.com/photoprism/photoprism/internal/photoprism"
|
||||||
"github.com/photoprism/photoprism/internal/query"
|
"github.com/photoprism/photoprism/internal/query"
|
||||||
"github.com/photoprism/photoprism/pkg/fs"
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
"github.com/photoprism/photoprism/pkg/txt"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/photoprism/photoprism/pkg/fs"
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
|
"github.com/photoprism/photoprism/pkg/txt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: GET /api/v1/dl/file/:hash
|
// TODO: GET /api/v1/dl/file/:hash
|
||||||
@@ -44,7 +44,7 @@ func GetDownload(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fileHash := c.Param("hash")
|
fileHash := sanitize.Token(c.Param("hash"))
|
||||||
|
|
||||||
f, err := query.FileByHash(fileHash)
|
f, err := query.FileByHash(fileHash)
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package api
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/acl"
|
"github.com/photoprism/photoprism/internal/acl"
|
||||||
@@ -56,7 +58,7 @@ func UpdateFace(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
faceId := c.Param("id")
|
faceId := sanitize.Token(c.Param("id"))
|
||||||
m := entity.FindFace(faceId)
|
m := entity.FindFace(faceId)
|
||||||
|
|
||||||
if m == nil {
|
if m == nil {
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package api
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/photoprism/photoprism/internal/acl"
|
"github.com/photoprism/photoprism/internal/acl"
|
||||||
"github.com/photoprism/photoprism/internal/query"
|
"github.com/photoprism/photoprism/internal/query"
|
||||||
@@ -22,7 +24,7 @@ func GetFile(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := query.FileByHash(c.Param("hash"))
|
p, err := query.FileByHash(sanitize.Token(c.Param("hash")))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
AbortEntityNotFound(c)
|
AbortEntityNotFound(c)
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/photoprism/photoprism/internal/acl"
|
"github.com/photoprism/photoprism/internal/acl"
|
||||||
"github.com/photoprism/photoprism/internal/event"
|
"github.com/photoprism/photoprism/internal/event"
|
||||||
@@ -35,8 +37,8 @@ func DeleteFile(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
photoUID := c.Param("uid")
|
photoUID := sanitize.IdString(c.Param("uid"))
|
||||||
fileUID := c.Param("file_uid")
|
fileUID := sanitize.IdString(c.Param("file_uid"))
|
||||||
|
|
||||||
file, err := query.FileByUID(fileUID)
|
file, err := query.FileByUID(fileUID)
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/photoprism/photoprism/internal/photoprism"
|
"github.com/photoprism/photoprism/internal/photoprism"
|
||||||
"github.com/photoprism/photoprism/internal/query"
|
"github.com/photoprism/photoprism/internal/query"
|
||||||
@@ -36,7 +38,7 @@ func FolderCover(router *gin.RouterGroup) {
|
|||||||
start := time.Now()
|
start := time.Now()
|
||||||
conf := service.Config()
|
conf := service.Config()
|
||||||
uid := c.Param("uid")
|
uid := c.Param("uid")
|
||||||
thumbName := thumb.Name(c.Param("size"))
|
thumbName := thumb.Name(sanitize.Token(c.Param("size")))
|
||||||
download := c.Query("download") != ""
|
download := c.Query("download") != ""
|
||||||
|
|
||||||
size, ok := thumb.Sizes[thumbName]
|
size, ok := thumb.Sizes[thumbName]
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ func AddCoverCacheHeader(c *gin.Context) {
|
|||||||
AddCacheHeader(c, CoverCacheTTL)
|
AddCacheHeader(c, CoverCacheTTL)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddCacheHeader adds thumbnail cache control headers to the response.
|
// AddThumbCacheHeader adds thumbnail cache control headers to the response.
|
||||||
func AddThumbCacheHeader(c *gin.Context) {
|
func AddThumbCacheHeader(c *gin.Context) {
|
||||||
c.Header("Cache-Control", fmt.Sprintf("private, max-age=%s, no-transform, immutable", ThumbCacheTTL.String()))
|
c.Header("Cache-Control", fmt.Sprintf("private, max-age=%s, no-transform, immutable", ThumbCacheTTL.String()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ func StartImport(router *gin.RouterGroup) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(f.Albums) > 0 {
|
if len(f.Albums) > 0 {
|
||||||
log.Debugf("import: adding files to album %s", strings.Join(f.Albums, " and "))
|
log.Debugf("import: adding files to album %s", txt.LogParam(strings.Join(f.Albums, " and ")))
|
||||||
opt.Albums = f.Albums
|
opt.Albums = f.Albums
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package api
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/acl"
|
"github.com/photoprism/photoprism/internal/acl"
|
||||||
@@ -33,7 +35,7 @@ func UpdateLabel(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := c.Param("uid")
|
id := sanitize.IdString(c.Param("uid"))
|
||||||
m, err := query.LabelByUID(id)
|
m, err := query.LabelByUID(id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -67,7 +69,7 @@ func LikeLabel(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := c.Param("uid")
|
id := sanitize.IdString(c.Param("uid"))
|
||||||
label, err := query.LabelByUID(id)
|
label, err := query.LabelByUID(id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -107,7 +109,7 @@ func DislikeLabel(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := c.Param("uid")
|
id := sanitize.IdString(c.Param("uid"))
|
||||||
label, err := query.LabelByUID(id)
|
label, err := query.LabelByUID(id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -5,12 +5,15 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/acl"
|
"github.com/photoprism/photoprism/internal/acl"
|
||||||
"github.com/photoprism/photoprism/internal/entity"
|
"github.com/photoprism/photoprism/internal/entity"
|
||||||
"github.com/photoprism/photoprism/internal/event"
|
"github.com/photoprism/photoprism/internal/event"
|
||||||
"github.com/photoprism/photoprism/internal/form"
|
"github.com/photoprism/photoprism/internal/form"
|
||||||
"github.com/photoprism/photoprism/internal/i18n"
|
"github.com/photoprism/photoprism/internal/i18n"
|
||||||
"github.com/photoprism/photoprism/internal/query"
|
"github.com/photoprism/photoprism/internal/query"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
"github.com/photoprism/photoprism/pkg/txt"
|
"github.com/photoprism/photoprism/pkg/txt"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,7 +33,7 @@ func UpdateLink(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
link := entity.FindLink(c.Param("link"))
|
link := entity.FindLink(sanitize.Token(c.Param("link")))
|
||||||
|
|
||||||
link.SetSlug(f.ShareSlug)
|
link.SetSlug(f.ShareSlug)
|
||||||
link.MaxViews = f.MaxViews
|
link.MaxViews = f.MaxViews
|
||||||
@@ -70,7 +73,7 @@ func DeleteLink(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
link := entity.FindLink(c.Param("link"))
|
link := entity.FindLink(sanitize.Token(c.Param("link")))
|
||||||
|
|
||||||
if err := link.Delete(); err != nil {
|
if err := link.Delete(); err != nil {
|
||||||
c.AbortWithStatusJSON(http.StatusConflict, gin.H{"error": txt.UcFirst(err.Error())})
|
c.AbortWithStatusJSON(http.StatusConflict, gin.H{"error": txt.UcFirst(err.Error())})
|
||||||
@@ -102,7 +105,7 @@ func CreateLink(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
link := entity.NewLink(c.Param("uid"), f.CanComment, f.CanEdit)
|
link := entity.NewLink(sanitize.IdString(c.Param("uid")), f.CanComment, f.CanEdit)
|
||||||
|
|
||||||
link.SetSlug(f.ShareSlug)
|
link.SetSlug(f.ShareSlug)
|
||||||
link.MaxViews = f.MaxViews
|
link.MaxViews = f.MaxViews
|
||||||
@@ -132,7 +135,7 @@ func CreateLink(c *gin.Context) {
|
|||||||
// POST /api/v1/albums/:uid/links
|
// POST /api/v1/albums/:uid/links
|
||||||
func CreateAlbumLink(router *gin.RouterGroup) {
|
func CreateAlbumLink(router *gin.RouterGroup) {
|
||||||
router.POST("/albums/:uid/links", func(c *gin.Context) {
|
router.POST("/albums/:uid/links", func(c *gin.Context) {
|
||||||
if _, err := query.AlbumByUID(c.Param("uid")); err != nil {
|
if _, err := query.AlbumByUID(sanitize.IdString(c.Param("uid"))); err != nil {
|
||||||
Abort(c, http.StatusNotFound, i18n.ErrAlbumNotFound)
|
Abort(c, http.StatusNotFound, i18n.ErrAlbumNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -158,7 +161,7 @@ func DeleteAlbumLink(router *gin.RouterGroup) {
|
|||||||
// GET /api/v1/albums/:uid/links
|
// GET /api/v1/albums/:uid/links
|
||||||
func GetAlbumLinks(router *gin.RouterGroup) {
|
func GetAlbumLinks(router *gin.RouterGroup) {
|
||||||
router.GET("/albums/:uid/links", func(c *gin.Context) {
|
router.GET("/albums/:uid/links", func(c *gin.Context) {
|
||||||
m, err := query.AlbumByUID(c.Param("uid"))
|
m, err := query.AlbumByUID(sanitize.IdString(c.Param("uid")))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Abort(c, http.StatusNotFound, i18n.ErrAlbumNotFound)
|
Abort(c, http.StatusNotFound, i18n.ErrAlbumNotFound)
|
||||||
@@ -172,7 +175,7 @@ func GetAlbumLinks(router *gin.RouterGroup) {
|
|||||||
// POST /api/v1/photos/:uid/links
|
// POST /api/v1/photos/:uid/links
|
||||||
func CreatePhotoLink(router *gin.RouterGroup) {
|
func CreatePhotoLink(router *gin.RouterGroup) {
|
||||||
router.POST("/photos/:uid/links", func(c *gin.Context) {
|
router.POST("/photos/:uid/links", func(c *gin.Context) {
|
||||||
if _, err := query.PhotoByUID(c.Param("uid")); err != nil {
|
if _, err := query.PhotoByUID(sanitize.IdString(c.Param("uid"))); err != nil {
|
||||||
AbortEntityNotFound(c)
|
AbortEntityNotFound(c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -198,7 +201,7 @@ func DeletePhotoLink(router *gin.RouterGroup) {
|
|||||||
// GET /api/v1/photos/:uid/links
|
// GET /api/v1/photos/:uid/links
|
||||||
func GetPhotoLinks(router *gin.RouterGroup) {
|
func GetPhotoLinks(router *gin.RouterGroup) {
|
||||||
router.GET("/photos/:uid/links", func(c *gin.Context) {
|
router.GET("/photos/:uid/links", func(c *gin.Context) {
|
||||||
m, err := query.PhotoByUID(c.Param("uid"))
|
m, err := query.PhotoByUID(sanitize.IdString(c.Param("uid")))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Abort(c, http.StatusNotFound, i18n.ErrAlbumNotFound)
|
Abort(c, http.StatusNotFound, i18n.ErrAlbumNotFound)
|
||||||
@@ -212,7 +215,7 @@ func GetPhotoLinks(router *gin.RouterGroup) {
|
|||||||
// POST /api/v1/labels/:uid/links
|
// POST /api/v1/labels/:uid/links
|
||||||
func CreateLabelLink(router *gin.RouterGroup) {
|
func CreateLabelLink(router *gin.RouterGroup) {
|
||||||
router.POST("/labels/:uid/links", func(c *gin.Context) {
|
router.POST("/labels/:uid/links", func(c *gin.Context) {
|
||||||
if _, err := query.LabelByUID(c.Param("uid")); err != nil {
|
if _, err := query.LabelByUID(sanitize.IdString(c.Param("uid"))); err != nil {
|
||||||
Abort(c, http.StatusNotFound, i18n.ErrLabelNotFound)
|
Abort(c, http.StatusNotFound, i18n.ErrLabelNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -238,7 +241,7 @@ func DeleteLabelLink(router *gin.RouterGroup) {
|
|||||||
// GET /api/v1/labels/:uid/links
|
// GET /api/v1/labels/:uid/links
|
||||||
func GetLabelLinks(router *gin.RouterGroup) {
|
func GetLabelLinks(router *gin.RouterGroup) {
|
||||||
router.GET("/labels/:uid/links", func(c *gin.Context) {
|
router.GET("/labels/:uid/links", func(c *gin.Context) {
|
||||||
m, err := query.LabelByUID(c.Param("uid"))
|
m, err := query.LabelByUID(sanitize.IdString(c.Param("uid")))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Abort(c, http.StatusNotFound, i18n.ErrAlbumNotFound)
|
Abort(c, http.StatusNotFound, i18n.ErrAlbumNotFound)
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ import (
|
|||||||
"github.com/photoprism/photoprism/internal/photoprism"
|
"github.com/photoprism/photoprism/internal/photoprism"
|
||||||
"github.com/photoprism/photoprism/internal/query"
|
"github.com/photoprism/photoprism/internal/query"
|
||||||
"github.com/photoprism/photoprism/internal/service"
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/pkg/fs"
|
"github.com/photoprism/photoprism/pkg/fs"
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
"github.com/photoprism/photoprism/pkg/txt"
|
"github.com/photoprism/photoprism/pkg/txt"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -50,7 +52,7 @@ func GetPhoto(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := query.PhotoPreloadByUID(c.Param("uid"))
|
p, err := query.PhotoPreloadByUID(sanitize.IdString(c.Param("uid")))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
AbortEntityNotFound(c)
|
AbortEntityNotFound(c)
|
||||||
@@ -73,7 +75,7 @@ func UpdatePhoto(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uid := c.Param("uid")
|
uid := sanitize.IdString(c.Param("uid"))
|
||||||
m, err := query.PhotoByUID(uid)
|
m, err := query.PhotoByUID(uid)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -135,7 +137,7 @@ func GetPhotoDownload(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := query.FileByPhotoUID(c.Param("uid"))
|
f, err := query.FileByPhotoUID(sanitize.IdString(c.Param("uid")))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Data(http.StatusNotFound, "image/svg+xml", photoIconSvg)
|
c.Data(http.StatusNotFound, "image/svg+xml", photoIconSvg)
|
||||||
@@ -171,7 +173,7 @@ func GetPhotoYaml(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := query.PhotoPreloadByUID(c.Param("uid"))
|
p, err := query.PhotoPreloadByUID(sanitize.IdString(c.Param("uid")))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithStatus(http.StatusNotFound)
|
c.AbortWithStatus(http.StatusNotFound)
|
||||||
@@ -186,7 +188,7 @@ func GetPhotoYaml(router *gin.RouterGroup) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if c.Query("download") != "" {
|
if c.Query("download") != "" {
|
||||||
AddDownloadHeader(c, c.Param("uid")+fs.YamlExt)
|
AddDownloadHeader(c, sanitize.IdString(c.Param("uid"))+fs.YamlExt)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data(http.StatusOK, "text/x-yaml; charset=utf-8", data)
|
c.Data(http.StatusOK, "text/x-yaml; charset=utf-8", data)
|
||||||
@@ -206,7 +208,7 @@ func ApprovePhoto(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := c.Param("uid")
|
id := sanitize.IdString(c.Param("uid"))
|
||||||
m, err := query.PhotoByUID(id)
|
m, err := query.PhotoByUID(id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -241,7 +243,7 @@ func LikePhoto(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := c.Param("uid")
|
id := sanitize.IdString(c.Param("uid"))
|
||||||
m, err := query.PhotoByUID(id)
|
m, err := query.PhotoByUID(id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -276,7 +278,7 @@ func DislikePhoto(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := c.Param("uid")
|
id := sanitize.IdString(c.Param("uid"))
|
||||||
m, err := query.PhotoByUID(id)
|
m, err := query.PhotoByUID(id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -312,8 +314,8 @@ func PhotoPrimary(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uid := c.Param("uid")
|
uid := sanitize.IdString(c.Param("uid"))
|
||||||
fileUID := c.Param("file_uid")
|
fileUID := sanitize.IdString(c.Param("file_uid"))
|
||||||
err := query.SetPhotoPrimary(uid, fileUID)
|
err := query.SetPhotoPrimary(uid, fileUID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/photoprism/photoprism/internal/acl"
|
"github.com/photoprism/photoprism/internal/acl"
|
||||||
"github.com/photoprism/photoprism/internal/classify"
|
"github.com/photoprism/photoprism/internal/classify"
|
||||||
@@ -27,7 +29,7 @@ func AddPhotoLabel(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := query.PhotoByUID(c.Param("uid"))
|
m, err := query.PhotoByUID(sanitize.IdString(c.Param("uid")))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
AbortEntityNotFound(c)
|
AbortEntityNotFound(c)
|
||||||
@@ -68,7 +70,7 @@ func AddPhotoLabel(router *gin.RouterGroup) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := query.PhotoPreloadByUID(c.Param("uid"))
|
p, err := query.PhotoPreloadByUID(sanitize.IdString(c.Param("uid")))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
AbortEntityNotFound(c)
|
AbortEntityNotFound(c)
|
||||||
@@ -102,14 +104,14 @@ func RemovePhotoLabel(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := query.PhotoByUID(c.Param("uid"))
|
m, err := query.PhotoByUID(sanitize.IdString(c.Param("uid")))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
AbortEntityNotFound(c)
|
AbortEntityNotFound(c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
labelId, err := strconv.Atoi(c.Param("id"))
|
labelId, err := strconv.Atoi(sanitize.Token(c.Param("id")))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": txt.UcFirst(err.Error())})
|
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": txt.UcFirst(err.Error())})
|
||||||
@@ -130,7 +132,7 @@ func RemovePhotoLabel(router *gin.RouterGroup) {
|
|||||||
logError("label", entity.Db().Save(&label).Error)
|
logError("label", entity.Db().Save(&label).Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := query.PhotoPreloadByUID(c.Param("uid"))
|
p, err := query.PhotoPreloadByUID(sanitize.IdString(c.Param("uid")))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
AbortEntityNotFound(c)
|
AbortEntityNotFound(c)
|
||||||
@@ -144,7 +146,7 @@ func RemovePhotoLabel(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
PublishPhotoEvent(EntityUpdated, c.Param("uid"), c)
|
PublishPhotoEvent(EntityUpdated, sanitize.IdString(c.Param("uid")), c)
|
||||||
|
|
||||||
event.Success("label removed")
|
event.Success("label removed")
|
||||||
|
|
||||||
@@ -168,14 +170,14 @@ func UpdatePhotoLabel(router *gin.RouterGroup) {
|
|||||||
|
|
||||||
// TODO: Code clean-up, simplify
|
// TODO: Code clean-up, simplify
|
||||||
|
|
||||||
m, err := query.PhotoByUID(c.Param("uid"))
|
m, err := query.PhotoByUID(sanitize.IdString(c.Param("uid")))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
AbortEntityNotFound(c)
|
AbortEntityNotFound(c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
labelId, err := strconv.Atoi(c.Param("id"))
|
labelId, err := strconv.Atoi(sanitize.Token(c.Param("id")))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": txt.UcFirst(err.Error())})
|
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": txt.UcFirst(err.Error())})
|
||||||
@@ -199,7 +201,7 @@ func UpdatePhotoLabel(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := query.PhotoPreloadByUID(c.Param("uid"))
|
p, err := query.PhotoPreloadByUID(sanitize.IdString(c.Param("uid")))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
AbortEntityNotFound(c)
|
AbortEntityNotFound(c)
|
||||||
@@ -211,7 +213,7 @@ func UpdatePhotoLabel(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
PublishPhotoEvent(EntityUpdated, c.Param("uid"), c)
|
PublishPhotoEvent(EntityUpdated, sanitize.IdString(c.Param("uid")), c)
|
||||||
|
|
||||||
event.Success("label saved")
|
event.Success("label saved")
|
||||||
|
|
||||||
|
|||||||
@@ -5,15 +5,16 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/crop"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/internal/crop"
|
||||||
"github.com/photoprism/photoprism/internal/photoprism"
|
"github.com/photoprism/photoprism/internal/photoprism"
|
||||||
"github.com/photoprism/photoprism/internal/query"
|
"github.com/photoprism/photoprism/internal/query"
|
||||||
"github.com/photoprism/photoprism/internal/service"
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
"github.com/photoprism/photoprism/internal/thumb"
|
"github.com/photoprism/photoprism/internal/thumb"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/pkg/fs"
|
"github.com/photoprism/photoprism/pkg/fs"
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
"github.com/photoprism/photoprism/pkg/txt"
|
"github.com/photoprism/photoprism/pkg/txt"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -37,16 +38,16 @@ func GetThumb(router *gin.RouterGroup) {
|
|||||||
start := time.Now()
|
start := time.Now()
|
||||||
conf := service.Config()
|
conf := service.Config()
|
||||||
download := c.Query("download") != ""
|
download := c.Query("download") != ""
|
||||||
fileHash, cropArea := crop.ParseThumb(c.Param("thumb"))
|
fileHash, cropArea := crop.ParseThumb(sanitize.Token(c.Param("thumb")))
|
||||||
|
|
||||||
// Is cropped thumbnail?
|
// Is cropped thumbnail?
|
||||||
if cropArea != "" {
|
if cropArea != "" {
|
||||||
cropName := crop.Name(c.Param("size"))
|
cropName := crop.Name(sanitize.Token(c.Param("size")))
|
||||||
|
|
||||||
cropSize, ok := crop.Sizes[cropName]
|
cropSize, ok := crop.Sizes[cropName]
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Errorf("%s: invalid size %s", logPrefix, cropName)
|
log.Errorf("%s: invalid size %s", logPrefix, txt.LogParam(string(cropName)))
|
||||||
c.Data(http.StatusOK, "image/svg+xml", photoIconSvg)
|
c.Data(http.StatusOK, "image/svg+xml", photoIconSvg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -74,12 +75,12 @@ func GetThumb(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
thumbName := thumb.Name(c.Param("size"))
|
thumbName := thumb.Name(sanitize.Token(c.Param("size")))
|
||||||
|
|
||||||
size, ok := thumb.Sizes[thumbName]
|
size, ok := thumb.Sizes[thumbName]
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Errorf("%s: invalid size %s", logPrefix, thumbName)
|
log.Errorf("%s: invalid size %s", logPrefix, txt.LogParam(thumbName.String()))
|
||||||
c.Data(http.StatusOK, "image/svg+xml", photoIconSvg)
|
c.Data(http.StatusOK, "image/svg+xml", photoIconSvg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/photoprism/photoprism/internal/acl"
|
"github.com/photoprism/photoprism/internal/acl"
|
||||||
"github.com/photoprism/photoprism/internal/entity"
|
"github.com/photoprism/photoprism/internal/entity"
|
||||||
@@ -31,7 +33,7 @@ func PhotoUnstack(router *gin.RouterGroup) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
conf := service.Config()
|
conf := service.Config()
|
||||||
fileUID := c.Param("file_uid")
|
fileUID := sanitize.IdString(c.Param("file_uid"))
|
||||||
file, err := query.FileByUID(fileUID)
|
file, err := query.FileByUID(fileUID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package api
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gin-gonic/gin/binding"
|
"github.com/gin-gonic/gin/binding"
|
||||||
|
|
||||||
@@ -59,7 +61,7 @@ func SearchGeo(router *gin.RouterGroup) {
|
|||||||
var resp []byte
|
var resp []byte
|
||||||
|
|
||||||
// Render JSON response.
|
// Render JSON response.
|
||||||
switch c.Param("format") {
|
switch sanitize.Token(c.Param("format")) {
|
||||||
case "view":
|
case "view":
|
||||||
conf := service.Config()
|
conf := service.Config()
|
||||||
resp, err = photos.ViewerJSON(conf.ContentUri(), conf.ApiUri(), conf.PreviewToken(), conf.DownloadToken())
|
resp, err = photos.ViewerJSON(conf.ContentUri(), conf.ApiUri(), conf.PreviewToken(), conf.DownloadToken())
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package api
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/photoprism/photoprism/internal/acl"
|
"github.com/photoprism/photoprism/internal/acl"
|
||||||
"github.com/photoprism/photoprism/internal/entity"
|
"github.com/photoprism/photoprism/internal/entity"
|
||||||
@@ -89,7 +91,7 @@ func CreateSession(router *gin.RouterGroup) {
|
|||||||
// DELETE /api/v1/session/:id
|
// DELETE /api/v1/session/:id
|
||||||
func DeleteSession(router *gin.RouterGroup) {
|
func DeleteSession(router *gin.RouterGroup) {
|
||||||
router.DELETE("/session/:id", func(c *gin.Context) {
|
router.DELETE("/session/:id", func(c *gin.Context) {
|
||||||
id := c.Param("id")
|
id := sanitize.Token(c.Param("id"))
|
||||||
|
|
||||||
service.Session().Delete(id)
|
service.Session().Delete(id)
|
||||||
|
|
||||||
@@ -126,7 +128,7 @@ func Auth(id string, resource acl.Resource, action acl.Action) session.Data {
|
|||||||
|
|
||||||
// InvalidPreviewToken returns true if the token is invalid.
|
// InvalidPreviewToken returns true if the token is invalid.
|
||||||
func InvalidPreviewToken(c *gin.Context) bool {
|
func InvalidPreviewToken(c *gin.Context) bool {
|
||||||
token := c.Param("token")
|
token := sanitize.Token(c.Param("token"))
|
||||||
|
|
||||||
if token == "" {
|
if token == "" {
|
||||||
token = c.Query("t")
|
token = c.Query("t")
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
|
|
||||||
"github.com/disintegration/imaging"
|
"github.com/disintegration/imaging"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/photoprism/photoprism/internal/entity"
|
"github.com/photoprism/photoprism/internal/entity"
|
||||||
@@ -29,8 +31,8 @@ func SharePreview(router *gin.RouterGroup) {
|
|||||||
router.GET("/:token/:share/preview", func(c *gin.Context) {
|
router.GET("/:token/:share/preview", func(c *gin.Context) {
|
||||||
conf := service.Config()
|
conf := service.Config()
|
||||||
|
|
||||||
token := c.Param("token")
|
token := sanitize.Token(c.Param("token"))
|
||||||
share := c.Param("share")
|
share := sanitize.Token(c.Param("share"))
|
||||||
links := entity.FindLinks(token, share)
|
links := entity.FindLinks(token, share)
|
||||||
|
|
||||||
if len(links) != 1 {
|
if len(links) != 1 {
|
||||||
@@ -51,13 +53,13 @@ func SharePreview(router *gin.RouterGroup) {
|
|||||||
yesterday := time.Now().Add(-24 * time.Hour)
|
yesterday := time.Now().Add(-24 * time.Hour)
|
||||||
|
|
||||||
if info, err := os.Stat(previewFilename); err != nil {
|
if info, err := os.Stat(previewFilename); err != nil {
|
||||||
log.Debugf("share: creating new preview for %s", share)
|
log.Debugf("share: creating new preview for %s", txt.LogParam(share))
|
||||||
} else if info.ModTime().After(yesterday) {
|
} else if info.ModTime().After(yesterday) {
|
||||||
log.Debugf("share: using cached preview for %s", share)
|
log.Debugf("share: using cached preview for %s", txt.LogParam(share))
|
||||||
c.File(previewFilename)
|
c.File(previewFilename)
|
||||||
return
|
return
|
||||||
} else if err := os.Remove(previewFilename); err != nil {
|
} else if err := os.Remove(previewFilename); err != nil {
|
||||||
log.Errorf("share: could not remove old preview of %s", share)
|
log.Errorf("share: could not remove old preview of %s", txt.LogParam(share))
|
||||||
c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
|
c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package api
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/acl"
|
"github.com/photoprism/photoprism/internal/acl"
|
||||||
@@ -26,7 +28,7 @@ func GetSubject(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if subj := entity.FindSubject(c.Param("uid")); subj == nil {
|
if subj := entity.FindSubject(sanitize.IdString(c.Param("uid"))); subj == nil {
|
||||||
Abort(c, http.StatusNotFound, i18n.ErrSubjectNotFound)
|
Abort(c, http.StatusNotFound, i18n.ErrSubjectNotFound)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
@@ -54,7 +56,7 @@ func UpdateSubject(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uid := c.Param("uid")
|
uid := sanitize.IdString(c.Param("uid"))
|
||||||
m := entity.FindSubject(uid)
|
m := entity.FindSubject(uid)
|
||||||
|
|
||||||
if m == nil {
|
if m == nil {
|
||||||
@@ -107,7 +109,7 @@ func LikeSubject(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uid := c.Param("uid")
|
uid := sanitize.IdString(c.Param("uid"))
|
||||||
subj := entity.FindSubject(uid)
|
subj := entity.FindSubject(uid)
|
||||||
|
|
||||||
if subj == nil {
|
if subj == nil {
|
||||||
@@ -141,7 +143,7 @@ func DislikeSubject(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uid := c.Param("uid")
|
uid := sanitize.IdString(c.Param("uid"))
|
||||||
subj := entity.FindSubject(uid)
|
subj := entity.FindSubject(uid)
|
||||||
|
|
||||||
if subj == nil {
|
if subj == nil {
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ func Upload(router *gin.RouterGroup) {
|
|||||||
log.Debugf("upload: saving file %s", txt.LogParam(file.Filename))
|
log.Debugf("upload: saving file %s", txt.LogParam(file.Filename))
|
||||||
|
|
||||||
if err := c.SaveUploadedFile(file, filename); err != nil {
|
if err := c.SaveUploadedFile(file, filename); err != nil {
|
||||||
log.Errorf("upload: failed saving file %s", filepath.Base(file.Filename))
|
log.Errorf("upload: failed saving file %s", txt.LogParam(filepath.Base(file.Filename)))
|
||||||
AbortBadRequest(c)
|
AbortBadRequest(c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package api
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/photoprism/photoprism/internal/acl"
|
"github.com/photoprism/photoprism/internal/acl"
|
||||||
"github.com/photoprism/photoprism/internal/entity"
|
"github.com/photoprism/photoprism/internal/entity"
|
||||||
@@ -28,7 +30,7 @@ func ChangePassword(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uid := c.Param("uid")
|
uid := sanitize.IdString(c.Param("uid"))
|
||||||
m := entity.FindUserByUID(uid)
|
m := entity.FindUserByUID(uid)
|
||||||
|
|
||||||
if s.User.UserUID != m.UserUID {
|
if s.User.UserUID != m.UserUID {
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package api
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/service"
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -24,8 +26,8 @@ func GetVideo(router *gin.RouterGroup) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fileHash := c.Param("hash")
|
fileHash := sanitize.Token(c.Param("hash"))
|
||||||
typeName := c.Param("type")
|
typeName := sanitize.Token(c.Param("type"))
|
||||||
|
|
||||||
videoType, ok := video.Types[typeName]
|
videoType, ok := video.Types[typeName]
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/pkg/rnd"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/acl"
|
"github.com/photoprism/photoprism/internal/acl"
|
||||||
"github.com/photoprism/photoprism/internal/form"
|
"github.com/photoprism/photoprism/internal/form"
|
||||||
@@ -20,9 +20,8 @@ import (
|
|||||||
"github.com/photoprism/photoprism/internal/query"
|
"github.com/photoprism/photoprism/internal/query"
|
||||||
"github.com/photoprism/photoprism/internal/service"
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
"github.com/photoprism/photoprism/pkg/fs"
|
"github.com/photoprism/photoprism/pkg/fs"
|
||||||
|
"github.com/photoprism/photoprism/pkg/rnd"
|
||||||
"github.com/photoprism/photoprism/pkg/txt"
|
"github.com/photoprism/photoprism/pkg/txt"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// POST /api/v1/zip
|
// POST /api/v1/zip
|
||||||
@@ -146,7 +145,7 @@ func DownloadZip(router *gin.RouterGroup) {
|
|||||||
zipFileName := path.Join(zipPath, zipBaseName)
|
zipFileName := path.Join(zipPath, zipBaseName)
|
||||||
|
|
||||||
if !fs.FileExists(zipFileName) {
|
if !fs.FileExists(zipFileName) {
|
||||||
log.Errorf("could not find zip file: %s", zipFileName)
|
log.Errorf("could not find zip file: %s", txt.LogParam(zipFileName))
|
||||||
c.Data(404, "image/svg+xml", photoIconSvg)
|
c.Data(404, "image/svg+xml", photoIconSvg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
25
pkg/sanitize/hex.go
Normal file
25
pkg/sanitize/hex.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package sanitize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hex removes invalid character from a hex string and makes it lowercase.
|
||||||
|
func Hex(s string) string {
|
||||||
|
if s == "" {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
s = strings.ToLower(s)
|
||||||
|
|
||||||
|
// Remove all invalid characters.
|
||||||
|
s = strings.Map(func(r rune) rune {
|
||||||
|
if (r < '0' || r > '9') && (r < 'a' || r > 'f') {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}, s)
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
19
pkg/sanitize/hex_test.go
Normal file
19
pkg/sanitize/hex_test.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package sanitize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHex(t *testing.T) {
|
||||||
|
t.Run("UUID", func(t *testing.T) {
|
||||||
|
assert.Equal(t, "123e4567e89b12d3a456426614174000", Hex("123e4567-e89b-12d3-A456-426614174000 "))
|
||||||
|
})
|
||||||
|
t.Run("ThumbSize", func(t *testing.T) {
|
||||||
|
assert.Equal(t, "ef224", Hex("left_224"))
|
||||||
|
})
|
||||||
|
t.Run("SHA1", func(t *testing.T) {
|
||||||
|
assert.Equal(t, "5c50ae14f339364eb8224f23c2d3abc7e79016f3eaded", Hex("5c50ae14f339364eb8224f23c2d3abc7e79016f3 README.md"))
|
||||||
|
})
|
||||||
|
}
|
||||||
41
pkg/sanitize/id.go
Normal file
41
pkg/sanitize/id.go
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package sanitize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IdString removes invalid character from an id string.
|
||||||
|
func IdString(s string) string {
|
||||||
|
if s == "" || len(s) > 256 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
s = strings.ToLower(s)
|
||||||
|
|
||||||
|
// Remove all invalid characters.
|
||||||
|
s = strings.Map(func(r rune) rune {
|
||||||
|
if (r < '0' || r > '9') && (r < 'a' || r > 'z') && r != '-' && r != '_' && r != ':' {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}, s)
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// IdUint converts the string converted to an unsigned integer and 0 if the string is invalid.
|
||||||
|
func IdUint(s string) uint {
|
||||||
|
if s == "" || len(s) > 64 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := strconv.ParseUint(s, 10, 32)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return uint(result)
|
||||||
|
}
|
||||||
31
pkg/sanitize/id_test.go
Normal file
31
pkg/sanitize/id_test.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package sanitize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIdString(t *testing.T) {
|
||||||
|
t.Run("UUID", func(t *testing.T) {
|
||||||
|
assert.Equal(t, "123e4567-e89b-12d3-a456-426614174000", IdString("123e4567-e89b-12d3-A456-426614174000 "))
|
||||||
|
})
|
||||||
|
t.Run("ThumbSize", func(t *testing.T) {
|
||||||
|
assert.Equal(t, "left_224", IdString("left_224"))
|
||||||
|
})
|
||||||
|
t.Run("SHA1", func(t *testing.T) {
|
||||||
|
assert.Equal(t, "5c50ae14f339364eb8224f23c2d3abc7e79016f3readmemd", IdString("5c50ae14f339364eb8224f23c2d3abc7e79016f3 README.md"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIdUint(t *testing.T) {
|
||||||
|
t.Run("12334545", func(t *testing.T) {
|
||||||
|
assert.Equal(t, uint(12334545), IdUint("12334545"))
|
||||||
|
})
|
||||||
|
t.Run("ThumbSize", func(t *testing.T) {
|
||||||
|
assert.Equal(t, uint(0), IdUint("left_224"))
|
||||||
|
})
|
||||||
|
t.Run("SHA1", func(t *testing.T) {
|
||||||
|
assert.Equal(t, uint(0), IdUint("5c50ae14f339364eb8224f23c2d3abc7e79016f3 README.md"))
|
||||||
|
})
|
||||||
|
}
|
||||||
32
pkg/sanitize/sanitize.go
Normal file
32
pkg/sanitize/sanitize.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Package sanitize provides input value sanitation functions
|
||||||
|
|
||||||
|
Copyright (c) 2018 - 2021 Michael Mayer <hello@photoprism.app>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
PhotoPrism® is a registered trademark of Michael Mayer. You may use it as required
|
||||||
|
to describe our software, run your own server, for educational purposes, but not for
|
||||||
|
offering commercial goods, products, or services without prior written permission.
|
||||||
|
In other words, please ask.
|
||||||
|
|
||||||
|
Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
||||||
|
want to support our work, or just want to say hello.
|
||||||
|
|
||||||
|
Additional information can be found in our Developer Guide:
|
||||||
|
https://docs.photoprism.app/developer-guide/
|
||||||
|
|
||||||
|
*/
|
||||||
|
package sanitize
|
||||||
23
pkg/sanitize/token.go
Normal file
23
pkg/sanitize/token.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package sanitize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Token removes invalid character from a token string.
|
||||||
|
func Token(s string) string {
|
||||||
|
if s == "" {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove all invalid characters.
|
||||||
|
s = strings.Map(func(r rune) rune {
|
||||||
|
if (r < '0' || r > '9') && (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') && r != '-' && r != '_' && r != ':' {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}, s)
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
19
pkg/sanitize/token_test.go
Normal file
19
pkg/sanitize/token_test.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package sanitize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestToken(t *testing.T) {
|
||||||
|
t.Run("UUID", func(t *testing.T) {
|
||||||
|
assert.Equal(t, "123e4567-e89b-12d3-A456-426614174000", Token("123e4567-e89b-12d3-A456-426614174000 "))
|
||||||
|
})
|
||||||
|
t.Run("ThumbSize", func(t *testing.T) {
|
||||||
|
assert.Equal(t, "left_224", Token("left_224"))
|
||||||
|
})
|
||||||
|
t.Run("SHA1", func(t *testing.T) {
|
||||||
|
assert.Equal(t, "5c50ae14f339364eb8224f23c2d3abc7e79016f3READMEmd", Token("5c50ae14f339364eb8224f23c2d3abc7e79016f3 README.md"))
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user