84 lines
2.2 KiB
Go
84 lines
2.2 KiB
Go
package media
|
||
|
||
import "fmt"
|
||
|
||
// Kind classifies media for policy checks.
|
||
type Kind string
|
||
|
||
const (
|
||
KindImage Kind = "image"
|
||
KindVideo Kind = "video"
|
||
KindAvatar Kind = "avatar"
|
||
)
|
||
|
||
// Violation describes an oversize resource (dimensions and/or bytes).
|
||
type Violation struct {
|
||
Kind Kind
|
||
Reason string
|
||
Width int
|
||
Height int
|
||
MaxEdge int
|
||
Size int64
|
||
MaxSize int64
|
||
Duration int // ms; video only
|
||
}
|
||
|
||
func (v *Violation) Error() string {
|
||
if v == nil {
|
||
return ""
|
||
}
|
||
return fmt.Sprintf("media %s oversize: %s", v.Kind, v.Reason)
|
||
}
|
||
|
||
// Policy controls user-path detection (bots always compress via infrastructure/media).
|
||
type Policy struct {
|
||
Enabled bool // master switch for user checks
|
||
UserReject bool // when true, publish/upload returns ErrMediaOversized; else log-only
|
||
Limits Limits
|
||
}
|
||
|
||
// CheckImageMeta validates declared image width/height/size against Limits.
|
||
// Zero width/height skips dimension check (client omitted); size 0 skips byte check.
|
||
func (p Policy) CheckImageMeta(w, h int, size int64) *Violation {
|
||
return p.check(KindImage, w, h, size, 0)
|
||
}
|
||
|
||
// CheckVideoMeta validates declared video metadata.
|
||
func (p Policy) CheckVideoMeta(w, h int, size int64, durationMS int) *Violation {
|
||
return p.check(KindVideo, w, h, size, durationMS)
|
||
}
|
||
|
||
// CheckAvatarMeta validates avatar dimensions/size (≤200×200 by default).
|
||
func (p Policy) CheckAvatarMeta(w, h int, size int64) *Violation {
|
||
return p.check(KindAvatar, w, h, size, 0)
|
||
}
|
||
|
||
func (p Policy) check(kind Kind, w, h int, size int64, durationMS int) *Violation {
|
||
if !p.Enabled {
|
||
return nil
|
||
}
|
||
lim := p.Limits.Normalize()
|
||
maxEdge, maxSize := lim.ImageMaxEdge, lim.ImageMaxBytes
|
||
switch kind {
|
||
case KindVideo:
|
||
maxEdge, maxSize = lim.VideoMaxEdge, lim.VideoMaxBytes
|
||
case KindAvatar:
|
||
maxEdge, maxSize = lim.AvatarMaxEdge, lim.AvatarMaxBytes
|
||
}
|
||
if w > 0 && h > 0 && NeedsResize(w, h, maxEdge) {
|
||
return &Violation{
|
||
Kind: kind, Reason: "edge_exceeded",
|
||
Width: w, Height: h, MaxEdge: maxEdge,
|
||
Size: size, MaxSize: maxSize, Duration: durationMS,
|
||
}
|
||
}
|
||
if size > 0 && maxSize > 0 && size > maxSize {
|
||
return &Violation{
|
||
Kind: kind, Reason: "size_exceeded",
|
||
Width: w, Height: h, MaxEdge: maxEdge,
|
||
Size: size, MaxSize: maxSize, Duration: durationMS,
|
||
}
|
||
}
|
||
return nil
|
||
}
|