72 lines
1.8 KiB
Go
72 lines
1.8 KiB
Go
package user
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"bytes"
|
||
|
|
"fmt"
|
||
|
|
"image"
|
||
|
|
_ "image/jpeg"
|
||
|
|
_ "image/png"
|
||
|
|
"io"
|
||
|
|
"net/http"
|
||
|
|
"path/filepath"
|
||
|
|
"strings"
|
||
|
|
)
|
||
|
|
|
||
|
|
const (
|
||
|
|
MaxWidth = 512
|
||
|
|
MaxHeight = 512
|
||
|
|
MaxUploadSize = 5 * 1024 * 1024
|
||
|
|
)
|
||
|
|
|
||
|
|
func VerifyImageLimit(r io.Reader) error {
|
||
|
|
cfg, format, err := image.DecodeConfig(r)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("failed to decode image: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
switch format {
|
||
|
|
case "jpeg", "png":
|
||
|
|
// Allowed formats
|
||
|
|
default:
|
||
|
|
return fmt.Errorf("not supported format: %s", format)
|
||
|
|
}
|
||
|
|
|
||
|
|
if cfg.Width > MaxWidth || cfg.Height > MaxHeight {
|
||
|
|
return fmt.Errorf("image dimensions exceed limits: %dx%d (max %dx%d)", cfg.Width, cfg.Height, MaxWidth, MaxHeight)
|
||
|
|
}
|
||
|
|
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func ExtractUploadedImageBytes(r *http.Request, formKey string) ([]byte, string, error) {
|
||
|
|
// Read file with a size limit to prevent abuse. We read the raw multipart
|
||
|
|
// bytes, verify size and image format, then return them.
|
||
|
|
const maxRead = MaxUploadSize + 1024 // small extra for multipart framing
|
||
|
|
|
||
|
|
file, header, err := r.FormFile(formKey)
|
||
|
|
if err != nil {
|
||
|
|
return nil, "", fmt.Errorf("form error: %w", err)
|
||
|
|
}
|
||
|
|
defer file.Close()
|
||
|
|
|
||
|
|
ext := strings.ToLower(filepath.Ext(header.Filename))
|
||
|
|
if ext != ".jpg" && ext != ".jpeg" && ext != ".png" {
|
||
|
|
return nil, "", fmt.Errorf("invalid file type: only JPG or PNG are allowed")
|
||
|
|
}
|
||
|
|
|
||
|
|
// Read all bytes so we can verify image dimensions from a reusable reader.
|
||
|
|
lr := io.LimitReader(file, maxRead)
|
||
|
|
fileBytes, err := io.ReadAll(lr)
|
||
|
|
if err != nil {
|
||
|
|
return nil, "", err
|
||
|
|
}
|
||
|
|
if int64(len(fileBytes)) >= maxRead {
|
||
|
|
return nil, "", fmt.Errorf("file too large (max %d bytes)", MaxUploadSize)
|
||
|
|
}
|
||
|
|
|
||
|
|
if err := VerifyImageLimit(bytes.NewReader(fileBytes)); err != nil {
|
||
|
|
return nil, "", fmt.Errorf("invalid file: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return fileBytes, header.Filename, nil
|
||
|
|
}
|