92 lines
1.7 KiB
Go
92 lines
1.7 KiB
Go
|
package upload
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"io"
|
||
|
"net/http"
|
||
|
"os"
|
||
|
|
||
|
"gitlab.com/gitlab-org/labkit/log"
|
||
|
"golang.org/x/image/tiff"
|
||
|
|
||
|
"gitlab.com/gitlab-org/gitlab/workhorse/internal/upload/exif"
|
||
|
)
|
||
|
|
||
|
func handleExifUpload(ctx context.Context, r io.Reader, filename string, imageType exif.FileType) (io.ReadCloser, error) {
|
||
|
tmpfile, err := os.CreateTemp("", "exifremove")
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
go func() {
|
||
|
<-ctx.Done()
|
||
|
tmpfile.Close()
|
||
|
}()
|
||
|
if err := os.Remove(tmpfile.Name()); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
_, err = io.Copy(tmpfile, r)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if _, err := tmpfile.Seek(0, io.SeekStart); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
isValidType := false
|
||
|
switch imageType {
|
||
|
case exif.TypeJPEG:
|
||
|
isValidType = isJPEG(tmpfile)
|
||
|
case exif.TypeTIFF:
|
||
|
isValidType = isTIFF(tmpfile)
|
||
|
}
|
||
|
|
||
|
if _, err := tmpfile.Seek(0, io.SeekStart); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if !isValidType {
|
||
|
log.WithContextFields(ctx, log.Fields{
|
||
|
"filename": filename,
|
||
|
"imageType": imageType,
|
||
|
}).Info("invalid content type, not running exiftool")
|
||
|
|
||
|
return tmpfile, nil
|
||
|
}
|
||
|
|
||
|
log.WithContextFields(ctx, log.Fields{
|
||
|
"filename": filename,
|
||
|
}).Info("running exiftool to remove any metadata")
|
||
|
|
||
|
cleaner, err := exif.NewCleaner(ctx, tmpfile)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return cleaner, nil
|
||
|
}
|
||
|
|
||
|
func isTIFF(r io.Reader) bool {
|
||
|
_, err := tiff.DecodeConfig(r)
|
||
|
if err == nil {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
if _, unsupported := err.(tiff.UnsupportedError); unsupported {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func isJPEG(r io.Reader) bool {
|
||
|
// Only the first 512 bytes are used to sniff the content type.
|
||
|
buf, err := io.ReadAll(io.LimitReader(r, 512))
|
||
|
if err != nil {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
return http.DetectContentType(buf) == "image/jpeg"
|
||
|
}
|