Only serve image files on ./image

This is an addition to the existing XSS fix in the previous commit.
This commit is contained in:
Jannis Mattheis 2022-12-29 12:46:41 +01:00
parent 022603ddf9
commit 33d86e41c2
2 changed files with 29 additions and 9 deletions

View File

@ -328,11 +328,7 @@ func (a *ApplicationAPI) UploadApplicationImage(ctx *gin.Context) {
} }
ext := filepath.Ext(file.Filename) ext := filepath.Ext(file.Filename)
if !ValidApplicationImageExt(ext) {
switch ext {
case ".gif", ".png", ".jpg", ".jpeg":
// ok
default:
ctx.AbortWithError(400, errors.New("invalid file extension")) ctx.AbortWithError(400, errors.New("invalid file extension"))
return return
} }
@ -391,3 +387,12 @@ func generateNonExistingImageName(imgDir string, gen func() string) string {
} }
} }
} }
func ValidApplicationImageExt(ext string) bool {
switch ext {
case ".gif", ".png", ".jpg", ".jpeg":
return true
default:
return false
}
}

View File

@ -2,6 +2,8 @@ package router
import ( import (
"fmt" "fmt"
"net/http"
"path/filepath"
"regexp" "regexp"
"time" "time"
@ -14,7 +16,7 @@ import (
"github.com/gotify/server/v2/config" "github.com/gotify/server/v2/config"
"github.com/gotify/server/v2/database" "github.com/gotify/server/v2/database"
"github.com/gotify/server/v2/docs" "github.com/gotify/server/v2/docs"
"github.com/gotify/server/v2/error" gerror "github.com/gotify/server/v2/error"
"github.com/gotify/server/v2/model" "github.com/gotify/server/v2/model"
"github.com/gotify/server/v2/plugin" "github.com/gotify/server/v2/plugin"
"github.com/gotify/server/v2/ui" "github.com/gotify/server/v2/ui"
@ -24,8 +26,8 @@ import (
func Create(db *database.GormDatabase, vInfo *model.VersionInfo, conf *config.Configuration) (*gin.Engine, func()) { func Create(db *database.GormDatabase, vInfo *model.VersionInfo, conf *config.Configuration) (*gin.Engine, func()) {
g := gin.New() g := gin.New()
g.Use(gin.LoggerWithFormatter(logFormatter), gin.Recovery(), error.Handler(), location.Default()) g.Use(gin.LoggerWithFormatter(logFormatter), gin.Recovery(), gerror.Handler(), location.Default())
g.NoRoute(error.NotFound()) g.NoRoute(gerror.NotFound())
streamHandler := stream.New(time.Duration(conf.Server.Stream.PingPeriodSeconds)*time.Second, 15*time.Second, conf.Server.Stream.AllowedOrigins) streamHandler := stream.New(time.Duration(conf.Server.Stream.PingPeriodSeconds)*time.Second, 15*time.Second, conf.Server.Stream.AllowedOrigins)
authentication := auth.Auth{DB: db} authentication := auth.Auth{DB: db}
@ -61,7 +63,8 @@ func Create(db *database.GormDatabase, vInfo *model.VersionInfo, conf *config.Co
g.GET("/health", healthHandler.Health) g.GET("/health", healthHandler.Health)
g.GET("/swagger", docs.Serve) g.GET("/swagger", docs.Serve)
g.Static("/image", conf.UploadedImagesDir) g.StaticFS("/image", &onlyImageFS{inner: gin.Dir(conf.UploadedImagesDir, false)})
g.GET("/docs", docs.UI) g.GET("/docs", docs.UI)
g.Use(func(ctx *gin.Context) { g.Use(func(ctx *gin.Context) {
@ -194,3 +197,15 @@ func logFormatter(param gin.LogFormatterParams) string {
param.ErrorMessage, param.ErrorMessage,
) )
} }
type onlyImageFS struct {
inner http.FileSystem
}
func (fs *onlyImageFS) Open(name string) (http.File, error) {
ext := filepath.Ext(name)
if !api.ValidApplicationImageExt(ext) {
return nil, fmt.Errorf("invalid file")
}
return fs.inner.Open(name)
}