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 }