- deferred_bindings migration set under summercms.deferred with backend_user_id - lagoon.DeferredBind/Unbind/Bindings/Forget/Slaves scoped by DeferredKey - lagoon.PurgeDeferred with SKIP LOCKED batches and after-commit blob deletes - attach.Store with the ported image guard, extension and MIME limits - attach.Relation, attach.HasRelations, attach.BlobKeys, File.ThumbKey - lagoon README and attachments docs
48 lines
1.5 KiB
Go
48 lines
1.5 KiB
Go
package attach
|
|
|
|
import (
|
|
"bytes"
|
|
"image"
|
|
"net/http"
|
|
"slices"
|
|
)
|
|
|
|
// AllowedImageMIMEs are the content types IsAllowedImage accepts, as
|
|
// sniffed from the bytes: JPEG, PNG, GIF and WebP, the formats the
|
|
// thumbnailer decodes.
|
|
var AllowedImageMIMEs = []string{"image/jpeg", "image/png", "image/gif", "image/webp"}
|
|
|
|
// MaxImagePixels is the largest image (width times height) IsAllowedImage
|
|
// accepts, the same ceiling File.Thumb applies before decoding, so every
|
|
// accepted image can be thumbnailed.
|
|
const MaxImagePixels = maxThumbSourcePixels
|
|
|
|
// IsAllowedImage reports whether data is a JPEG, PNG, GIF or WebP image:
|
|
// the bytes must sniff as one of AllowedImageMIMEs (http.DetectContentType,
|
|
// independent of any file name or client header), the header must decode
|
|
// through image.DecodeConfig as that format with a positive width and
|
|
// height, and the image must not exceed MaxImagePixels. Decoding the header
|
|
// rejects a polyglot whose first bytes alone look right. It fails closed:
|
|
// empty or unreadable content is refused. data may be a prefix of the file
|
|
// as long as it holds the image header.
|
|
func IsAllowedImage(data []byte) bool {
|
|
if len(data) == 0 {
|
|
return false
|
|
}
|
|
if !slices.Contains(AllowedImageMIMEs, http.DetectContentType(data)) {
|
|
return false
|
|
}
|
|
cfg, format, err := image.DecodeConfig(bytes.NewReader(data))
|
|
if err != nil || cfg.Width <= 0 || cfg.Height <= 0 {
|
|
return false
|
|
}
|
|
if int64(cfg.Width)*int64(cfg.Height) > MaxImagePixels {
|
|
return false
|
|
}
|
|
switch format {
|
|
case "jpeg", "png", "gif", "webp":
|
|
return true
|
|
}
|
|
return false
|
|
}
|