diff --git a/internal/service/uploader/upload.go b/internal/service/uploader/upload.go index fb0b2af0..3619a6e1 100644 --- a/internal/service/uploader/upload.go +++ b/internal/service/uploader/upload.go @@ -244,7 +244,7 @@ func (us *uploaderService) uploadFile(ctx *gin.Context, file *multipart.FileHead } defer src.Close() - if !checker.IsSupportedImageFile(src, filepath.Ext(fileSubPath)) { + if !checker.IsSupportedImageFile(filePath) { return "", errors.BadRequest(reason.UploadFileUnsupportedFileFormat) } diff --git a/pkg/checker/file_type.go b/pkg/checker/file_type.go index 3599270a..6c61dca2 100644 --- a/pkg/checker/file_type.go +++ b/pkg/checker/file_type.go @@ -20,13 +20,18 @@ package checker import ( - "golang.org/x/image/webp" + "fmt" "image" _ "image/gif" // use init to support decode jpeg,jpg,png,gif _ "image/jpeg" _ "image/png" "io" + "os" + "path/filepath" "strings" + + "github.com/segmentfault/pacman/log" + "golang.org/x/image/webp" ) const ( @@ -35,47 +40,85 @@ const ( // IsSupportedImageFile currently answers support image type is // `image/jpeg, image/jpg, image/png, image/gif, image/webp` -func IsSupportedImageFile(file io.Reader, ext string) bool { - ext = strings.ToLower(strings.TrimPrefix(ext, ".")) - var err error +func IsSupportedImageFile(localFilePath string) bool { + ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(localFilePath), ".")) switch ext { case "jpg", "jpeg", "png", "gif": // only allow for `image/jpeg,image/jpg,image/png, image/gif` - if !checkImageSize(file) { + if !decodeAndCheckImageFile(localFilePath, standardImageConfigCheck) { + return false + } + if !decodeAndCheckImageFile(localFilePath, standardImageCheck) { return false } - _, _, err = image.Decode(file) case "ico": // TODO: There is currently no good Golang library to parse whether the image is in ico format. return true case "webp": - if !checkWebpSize(file) { + if !decodeAndCheckImageFile(localFilePath, webpImageConfigCheck) { + return false + } + if !decodeAndCheckImageFile(localFilePath, webpImageCheck) { return false } - _, err = webp.Decode(file) default: return false } - return err == nil + return true } -func checkImageSize(file io.Reader) bool { +func decodeAndCheckImageFile(localFilePath string, checker func(io.Reader) error) bool { + file, err := os.Open(localFilePath) + if err != nil { + log.Errorf("open file error: %v", err) + return false + } + defer file.Close() + + if err = checker(file); err != nil { + log.Errorf("check image format error: %v", err) + return false + } + return true +} + +func standardImageConfigCheck(file io.Reader) error { config, _, err := image.DecodeConfig(file) if err != nil { - return false + return fmt.Errorf("decode image config error: %v", err) } - if (config.Width * config.Height) > maxImageSize { - return false + if imageSizeTooLarge(config) { + return fmt.Errorf("image size too large") } - return true + return nil } -func checkWebpSize(file io.Reader) bool { +func standardImageCheck(file io.Reader) error { + _, _, err := image.Decode(file) + if err != nil { + return fmt.Errorf("decode image error: %v", err) + } + return nil +} + +func webpImageConfigCheck(file io.Reader) error { config, err := webp.DecodeConfig(file) if err != nil { - return false + return fmt.Errorf("decode webp image config error: %v", err) } - if (config.Width * config.Height) > maxImageSize { - return false + if imageSizeTooLarge(config) { + return fmt.Errorf("image size too large") } - return true + return nil +} + +func webpImageCheck(file io.Reader) error { + _, err := webp.Decode(file) + if err != nil { + return fmt.Errorf("decode webp image error: %v", err) + } + return nil +} + +func imageSizeTooLarge(config image.Config) bool { + return config.Width*config.Height > maxImageSize }