Get rid of security.Options. Use security.Checker directly with options.Options

This commit is contained in:
DarthSim authored and Sergei Aleksandrovich committed 2025-11-14 14:09:43 +06:00
1 parent ef237b0585
commit 3f2b019721
17 files changed
+134 -141

No files matched your search

-1
View File
@@ -88,7 +88,6 @@ func (h *Handler) Execute(
r.req = req
r.rw = rw
r.config = h.config
r.secops = h.Security().NewOptions(r.opts)
return r.execute(ctx)
}
-2
View File
@@ -13,7 +13,6 @@ import (
"github.com/imgproxy/imgproxy/v3/monitoring"
"github.com/imgproxy/imgproxy/v3/options"
"github.com/imgproxy/imgproxy/v3/options/keys"
"github.com/imgproxy/imgproxy/v3/security"
"github.com/imgproxy/imgproxy/v3/server"
"github.com/imgproxy/imgproxy/v3/vips"
)
@@ -27,7 +26,6 @@ type request struct {
rw server.ResponseWriter
config *Config
opts *options.Options
secops security.Options
imageURL string
path string
monitoringMeta monitoring.Meta
+2 -2
View File
@@ -70,7 +70,7 @@ func (r *request) makeDownloadOptions(
return imagedata.DownloadOptions{
Header: h,
MaxSrcFileSize: r.secops.MaxSrcFileSize,
MaxSrcFileSize: r.Security().MaxSrcFileSize(r.opts),
CookieJar: jar,
}, nil
}
@@ -160,7 +160,7 @@ func (r *request) getFallbackImage(ctx context.Context) (imagedata.ImageData, ht
// processImage calls actual image processing
func (r *request) processImage(ctx context.Context, originData imagedata.ImageData) (*processing.Result, error) {
defer r.Monitoring().StartProcessingSegment(ctx, r.monitoringMeta.Filter(monitoring.MetaOptions))()
return r.Processor().ProcessImage(ctx, originData, r.opts, r.secops)
return r.Processor().ProcessImage(ctx, originData, r.opts)
}
// writeDebugHeaders writes debug headers (X-Origin-*, X-Result-*) to the response
+9 -9
View File
@@ -47,7 +47,7 @@ type Imgproxy struct {
imageDataFactory *imagedata.Factory
clientFeaturesDetector *clientfeatures.Detector
handlers ImgproxyHandlers
security *security.Checker
securityChecker *security.Checker
optionsParser *optionsparser.Parser
processor *processing.Processor
cookies *cookies.Cookies
@@ -62,6 +62,11 @@ func New(ctx context.Context, config *Config) (*Imgproxy, error) {
return nil, err
}
securityChecker, err := security.New(&config.Security)
if err != nil {
return nil, err
}
fetcher, err := fetcher.New(&config.Fetcher)
if err != nil {
return nil, err
@@ -86,12 +91,7 @@ func New(ctx context.Context, config *Config) (*Imgproxy, error) {
return nil, err
}
security, err := security.New(&config.Security)
if err != nil {
return nil, err
}
processor, err := processing.New(&config.Processing, watermarkImage)
processor, err := processing.New(&config.Processing, securityChecker, watermarkImage)
if err != nil {
return nil, err
}
@@ -124,7 +124,7 @@ func New(ctx context.Context, config *Config) (*Imgproxy, error) {
imageDataFactory: idf,
clientFeaturesDetector: clientFeaturesDetector,
config: config,
security: security,
securityChecker: securityChecker,
optionsParser: optionsParser,
processor: processor,
cookies: cookies,
@@ -262,7 +262,7 @@ func (i *Imgproxy) ClientFeaturesDetector() *clientfeatures.Detector {
}
func (i *Imgproxy) Security() *security.Checker {
return i.security
return i.securityChecker
}
func (i *Imgproxy) OptionsParser() *optionsparser.Parser {
+1 -1
View File
@@ -44,7 +44,7 @@ func (s *MatrixTestSuite) SetupTest() {
s.testImagesPath = s.TestData.Path("test-images")
s.matcher = testutil.NewImageHashMatcher(s.TestData)
s.Config().Security.DefaultOptions.MaxAnimationFrames = 999
s.Config().Security.MaxAnimationFrames = 999
s.Config().Server.DevelopmentErrorsMode = true
s.Config().Fetcher.Transport.Local.Root = s.testImagesPath
}
+2 -10
View File
@@ -9,7 +9,6 @@ import (
"time"
"github.com/imgproxy/imgproxy/v3/config/configurators"
"github.com/imgproxy/imgproxy/v3/fetcher"
"github.com/imgproxy/imgproxy/v3/httpheaders"
"github.com/imgproxy/imgproxy/v3/imagedata"
"github.com/imgproxy/imgproxy/v3/imagetype"
@@ -205,14 +204,7 @@ func (s *ProcessingHandlerTestSuite) TestSkipProcessingSVG() {
s.Require().Equal(http.StatusOK, res.StatusCode)
c := fetcher.NewDefaultConfig()
f, err := fetcher.New(&c)
s.Require().NoError(err)
idf := imagedata.NewFactory(f)
data, err := idf.NewFromBytes(s.TestData.Read("test1.svg"))
s.Require().NoError(err)
data := imagedata.NewFromBytesWithFormat(imagetype.SVG, s.TestData.Read("test1.svg"))
cfg := svg.NewDefaultConfig()
svg := svg.New(&cfg)
@@ -508,7 +500,7 @@ func (s *ProcessingHandlerTestSuite) TestAlwaysRasterizeSvgWithFormat() {
}
func (s *ProcessingHandlerTestSuite) TestMaxSrcFileSizeGlobal() {
s.Config().Security.DefaultOptions.MaxSrcFileSize = 1
s.Config().Security.MaxSrcFileSize = 1
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
rw.WriteHeader(200)
+19 -2
View File
@@ -6,6 +6,7 @@ import (
"github.com/imgproxy/imgproxy/v3/imagetype"
"github.com/imgproxy/imgproxy/v3/options"
"github.com/imgproxy/imgproxy/v3/options/keys"
"github.com/imgproxy/imgproxy/v3/security"
"github.com/imgproxy/imgproxy/v3/vips/color"
)
@@ -16,12 +17,16 @@ type ProcessingOptions struct {
// Config that contains default values for some options.
config *Config
// Security checker to obtain security-related limits.
securityChecker *security.Checker
}
func (p *Processor) NewProcessingOptions(o *options.Options) ProcessingOptions {
return ProcessingOptions{
Options: o,
config: p.config,
Options: o,
config: p.config,
securityChecker: p.securityChecker,
}
}
@@ -287,3 +292,15 @@ func (po ProcessingOptions) KeepCopyright() bool {
func (po ProcessingOptions) StripColorProfile() bool {
return po.Main().GetBool(keys.StripColorProfile, po.config.StripColorProfile)
}
func (po ProcessingOptions) MaxSrcResolution() int {
return po.securityChecker.MaxSrcResolution(po.Main())
}
func (po ProcessingOptions) MaxAnimationFrames() int {
return po.securityChecker.MaxAnimationFrames(po.Main())
}
func (po ProcessingOptions) MaxResultDimension() int {
return po.securityChecker.MaxResultDimension(po.Main())
}
+1 -8
View File
@@ -4,7 +4,6 @@ import (
"context"
"github.com/imgproxy/imgproxy/v3/imagedata"
"github.com/imgproxy/imgproxy/v3/security"
"github.com/imgproxy/imgproxy/v3/server"
"github.com/imgproxy/imgproxy/v3/vips"
)
@@ -19,9 +18,6 @@ type Context struct {
// Processing options this pipeline runs with
PO ProcessingOptions
// Security options this pipeline runs with
SecOps security.Options
// Original image data
ImgData imagedata.ImageData
@@ -80,10 +76,9 @@ func (p Pipeline) Run(
ctx context.Context,
img *vips.Image,
po ProcessingOptions,
secops security.Options,
imgdata imagedata.ImageData,
) error {
pctx := p.newContext(ctx, img, po, secops, imgdata)
pctx := p.newContext(ctx, img, po, imgdata)
pctx.CalcParams()
for _, step := range p {
@@ -105,14 +100,12 @@ func (p Pipeline) newContext(
ctx context.Context,
img *vips.Image,
po ProcessingOptions,
secops security.Options,
imgdata imagedata.ImageData,
) Context {
pctx := Context{
Ctx: ctx,
Img: img,
PO: po,
SecOps: secops,
ImgData: imgdata,
WScale: 1.0,
+1 -1
View File
@@ -221,7 +221,7 @@ func (c *Context) calcSizes(widthToScale, heightToScale int, po ProcessingOption
}
func (c *Context) limitScale(widthToScale, heightToScale int, po ProcessingOptions) {
maxresultDim := c.SecOps.MaxResultDimension
maxresultDim := c.PO.MaxResultDimension()
if maxresultDim <= 0 {
return
+14 -21
View File
@@ -10,7 +10,6 @@ import (
"github.com/imgproxy/imgproxy/v3/imagedata"
"github.com/imgproxy/imgproxy/v3/imagetype"
"github.com/imgproxy/imgproxy/v3/options"
"github.com/imgproxy/imgproxy/v3/security"
"github.com/imgproxy/imgproxy/v3/server"
"github.com/imgproxy/imgproxy/v3/vips"
)
@@ -63,7 +62,6 @@ func (p *Processor) ProcessImage(
ctx context.Context,
imgdata imagedata.ImageData,
o *options.Options,
secops security.Options,
) (*Result, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
@@ -84,14 +82,13 @@ func (p *Processor) ProcessImage(
// Let's check if we should skip standard processing
if p.shouldSkipStandardProcessing(imgdata.Format(), po) {
return p.skipStandardProcessing(img, imgdata, po, secops)
return p.skipStandardProcessing(img, imgdata, po)
}
// Check if we expect image to be processed as animated.
// If MaxAnimationFrames is 1, we never process as animated since we can only
// process a single frame.
animated := secops.MaxAnimationFrames > 1 &&
img.IsAnimated()
animated := po.MaxAnimationFrames() > 1 && img.IsAnimated()
// Determine output format and check if it's supported.
// The determined format is stored in po[KeyFormat].
@@ -108,24 +105,24 @@ func (p *Processor) ProcessImage(
// and remove animation-related data if not animated.
// Don't reload if we initially loaded a thumbnail.
if !thumbnailLoaded {
if err = p.reloadImageForProcessing(img, imgdata, po, secops, animated); err != nil {
if err = p.reloadImageForProcessing(img, imgdata, po, animated); err != nil {
return nil, err
}
}
// Check image dimensions and number of frames for security reasons
originWidth, originHeight, err := p.checkImageSize(img, imgdata.Format(), secops)
originWidth, originHeight, err := p.checkImageSize(img, imgdata.Format(), po)
if err != nil {
return nil, err
}
// Transform the image (resize, crop, etc)
if err = p.transformImage(ctx, img, po, secops, imgdata, animated); err != nil {
if err = p.transformImage(ctx, img, po, imgdata, animated); err != nil {
return nil, err
}
// Finalize the image (colorspace conversion, metadata stripping, etc)
if err = p.finalizePipeline().Run(ctx, img, po, secops, imgdata); err != nil {
if err = p.finalizePipeline().Run(ctx, img, po, imgdata); err != nil {
return nil, err
}
@@ -170,13 +167,12 @@ func (p *Processor) reloadImageForProcessing(
img *vips.Image,
imgdata imagedata.ImageData,
po ProcessingOptions,
secops security.Options,
asAnimated bool,
) error {
// If we are going to process the image as animated, we need to load all frames
// up to MaxAnimationFrames
if asAnimated {
frames := min(img.Pages(), secops.MaxAnimationFrames)
frames := min(img.Pages(), po.MaxAnimationFrames())
return img.Load(imgdata, 1.0, 0, frames)
}
@@ -189,7 +185,7 @@ func (p *Processor) reloadImageForProcessing(
func (p *Processor) checkImageSize(
img *vips.Image,
imgtype imagetype.Type,
secops security.Options,
po ProcessingOptions,
) (int, int, error) {
width, height, frames := p.getImageSize(img)
@@ -198,7 +194,7 @@ func (p *Processor) checkImageSize(
return width, height, nil
}
err := secops.CheckDimensions(width, height, frames)
err := p.securityChecker.CheckDimensions(po.Options, width, height, frames)
return width, height, err
}
@@ -258,11 +254,10 @@ func (p *Processor) skipStandardProcessing(
img *vips.Image,
imgdata imagedata.ImageData,
po ProcessingOptions,
secops security.Options,
) (*Result, error) {
// Even if we skip standard processing, we still need to check image dimensions
// to not send an image bomb to the client
originWidth, originHeight, err := p.checkImageSize(img, imgdata.Format(), secops)
originWidth, originHeight, err := p.checkImageSize(img, imgdata.Format(), po)
if err != nil {
return nil, err
}
@@ -368,22 +363,20 @@ func (p *Processor) transformImage(
ctx context.Context,
img *vips.Image,
po ProcessingOptions,
secops security.Options,
imgdata imagedata.ImageData,
asAnimated bool,
) error {
if asAnimated {
return p.transformAnimated(ctx, img, po, secops)
return p.transformAnimated(ctx, img, po)
}
return p.mainPipeline().Run(ctx, img, po, secops, imgdata)
return p.mainPipeline().Run(ctx, img, po, imgdata)
}
func (p *Processor) transformAnimated(
ctx context.Context,
img *vips.Image,
po ProcessingOptions,
secops security.Options,
) error {
if po.TrimEnabled() {
slog.Warn("Trim is not supported for animated images")
@@ -440,7 +433,7 @@ func (p *Processor) transformAnimated(
// Transform the frame using the main pipeline.
// We don't provide imgdata here to prevent scale-on-load.
// Watermarking is disabled for individual frames (see above)
if err = p.mainPipeline().Run(ctx, frame, po, secops, nil); err != nil {
if err = p.mainPipeline().Run(ctx, frame, po, nil); err != nil {
return err
}
@@ -475,7 +468,7 @@ func (p *Processor) transformAnimated(
// Set watermark opacity back
po.SetWatermarkOpacity(watermarkOpacity)
if err = p.applyWatermark(ctx, img, po, secops, dprScale, framesCount); err != nil {
if err = p.applyWatermark(ctx, img, po, dprScale, framesCount); err != nil {
return err
}
}
+7 -9
View File
@@ -48,10 +48,10 @@ func (s *ProcessingTestSuite) SetupSuite() {
s.securityConfig, _ = testutil.NewLazySuiteObj(s, func() (*security.Config, error) {
c := security.NewDefaultConfig()
c.DefaultOptions.MaxSrcResolution = 10 * 1024 * 1024
c.DefaultOptions.MaxSrcFileSize = 10 * 1024 * 1024
c.DefaultOptions.MaxAnimationFrames = 100
c.DefaultOptions.MaxAnimationFrameResolution = 10 * 1024 * 1024
c.MaxSrcResolution = 10 * 1024 * 1024
c.MaxSrcFileSize = 10 * 1024 * 1024
c.MaxAnimationFrames = 100
c.MaxAnimationFrameResolution = 10 * 1024 * 1024
return &c, nil
})
@@ -66,7 +66,7 @@ func (s *ProcessingTestSuite) SetupSuite() {
})
s.processor, _ = testutil.NewLazySuiteObj(s, func() (*Processor, error) {
return New(s.config(), nil)
return New(s.config(), s.security(), nil)
})
}
@@ -96,9 +96,7 @@ func (s *ProcessingTestSuite) processImageAndCheck(
o *options.Options,
expectedWidth, expectedHeight int,
) {
secops := s.security().NewOptions(o)
result, err := s.processor().ProcessImage(s.T().Context(), imgdata, o, secops)
result, err := s.processor().ProcessImage(s.T().Context(), imgdata, o)
s.Require().NoError(err)
s.Require().NotNil(result)
@@ -955,7 +953,7 @@ func (s *ProcessingTestSuite) TestImageResolutionTooLarge() {
o.Set(keys.MaxSrcResolution, 1)
imgdata := s.openFile("test2.jpg")
_, err := s.processor().ProcessImage(s.T().Context(), imgdata, o, s.security().NewOptions(o))
_, err := s.processor().ProcessImage(s.T().Context(), imgdata, o)
s.Require().Error(err)
s.Require().Equal(422, ierrors.Wrap(err, 0).StatusCode())
+8 -1
View File
@@ -3,23 +3,30 @@ package processing
import (
"github.com/imgproxy/imgproxy/v3/auximageprovider"
"github.com/imgproxy/imgproxy/v3/processing/svg"
"github.com/imgproxy/imgproxy/v3/security"
)
// Processor is responsible for processing images according to the given configuration.
type Processor struct {
config *Config
securityChecker *security.Checker
watermarkProvider auximageprovider.Provider
svg *svg.Processor
}
// New creates a new Processor instance with the given configuration and watermark provider
func New(config *Config, watermark auximageprovider.Provider) (*Processor, error) {
func New(
config *Config,
securityChecker *security.Checker,
watermark auximageprovider.Provider,
) (*Processor, error) {
if err := config.Validate(); err != nil {
return nil, err
}
return &Processor{
config: config,
securityChecker: securityChecker,
watermarkProvider: watermark,
svg: svg.New(&config.Svg),
}, nil
+4 -2
View File
@@ -11,8 +11,10 @@ func (p *Processor) vectorGuardScale(c *Context) error {
return nil
}
if resolution := c.Img.Width() * c.Img.Height(); resolution > c.SecOps.MaxSrcResolution {
shrink := math.Sqrt(float64(resolution) / float64(c.SecOps.MaxSrcResolution))
maxSrcRes := c.PO.MaxSrcResolution()
if resolution := c.Img.Width() * c.Img.Height(); resolution > maxSrcRes {
shrink := math.Sqrt(float64(resolution) / float64(maxSrcRes))
c.VectorBaseShrink = shrink
if err := c.Img.Load(c.ImgData, shrink, 0, 1); err != nil {
+3 -6
View File
@@ -8,7 +8,6 @@ import (
"github.com/imgproxy/imgproxy/v3/imath"
"github.com/imgproxy/imgproxy/v3/options"
"github.com/imgproxy/imgproxy/v3/options/keys"
"github.com/imgproxy/imgproxy/v3/security"
"github.com/imgproxy/imgproxy/v3/vips"
)
@@ -34,7 +33,6 @@ func (p *Processor) prepareWatermark(
wm *vips.Image,
wmData imagedata.ImageData,
po ProcessingOptions,
secops security.Options,
imgWidth, imgHeight int,
offsetScale float64,
framesCount int,
@@ -80,7 +78,7 @@ func (p *Processor) prepareWatermark(
wmPo.Set(keys.PaddingBottom, padY-padY/2)
}
if err := p.watermarkPipeline().Run(ctx, wm, wmPo, secops, wmData); err != nil {
if err := p.watermarkPipeline().Run(ctx, wm, wmPo, wmData); err != nil {
return err
}
@@ -104,7 +102,6 @@ func (p *Processor) applyWatermark(
ctx context.Context,
img *vips.Image,
po ProcessingOptions,
secops security.Options,
offsetScale float64,
framesCount int,
) error {
@@ -129,7 +126,7 @@ func (p *Processor) applyWatermark(
frameHeight := height / framesCount
if err := p.prepareWatermark(
ctx, wm, wmData, po, secops, width, frameHeight, offsetScale, framesCount,
ctx, wm, wmData, po, width, frameHeight, offsetScale, framesCount,
); err != nil {
return err
}
@@ -216,5 +213,5 @@ func (p *Processor) watermark(c *Context) error {
return nil
}
return p.applyWatermark(c.Ctx, c.Img, c.PO, c.SecOps, c.DprScale, 1)
return p.applyWatermark(c.Ctx, c.Img, c.PO, c.DprScale, 1)
}
+43 -23
View File
@@ -21,30 +21,50 @@ func New(config *Config) (*Checker, error) {
}, nil
}
// NewOptions creates a new [security.Options] instance
// filling it from [options.Options].
// If opts is nil, it returns default [security.Options].
func (s *Checker) NewOptions(opts *options.Options) (secops Options) {
secops = s.config.DefaultOptions
if opts == nil {
return
// MaxSrcResolution returns the maximum allowed source image resolution
func (s *Checker) MaxSrcResolution(o *options.Options) int {
return o.GetInt(keys.MaxSrcResolution, s.config.MaxSrcResolution)
}
// MaxSrcFileSize returns the maximum allowed source file size
func (s *Checker) MaxSrcFileSize(o *options.Options) int {
return o.GetInt(keys.MaxSrcFileSize, s.config.MaxSrcFileSize)
}
// MaxAnimationFrames returns the maximum allowed animation frames
func (s *Checker) MaxAnimationFrames(o *options.Options) int {
return o.GetInt(keys.MaxAnimationFrames, s.config.MaxAnimationFrames)
}
// MaxAnimationFrameResolution returns the maximum allowed animation frame resolution
func (s *Checker) MaxAnimationFrameResolution(o *options.Options) int {
return o.GetInt(
keys.MaxAnimationFrameResolution,
s.config.MaxAnimationFrameResolution,
)
}
// MaxResultDimension returns the maximum allowed result image dimension
func (s *Checker) MaxResultDimension(o *options.Options) int {
return o.GetInt(keys.MaxResultDimension, s.config.MaxResultDimension)
}
// CheckDimensions checks if the given dimensions are within the allowed limits
func (s *Checker) CheckDimensions(o *options.Options, width, height, frames int) error {
frames = max(frames, 1)
maxFrameRes := s.MaxAnimationFrameResolution(o)
if frames > 1 && maxFrameRes > 0 {
if width*height > maxFrameRes {
return newImageResolutionError("Source image frame resolution is too big")
}
return nil
}
secops.MaxSrcResolution = opts.GetInt(
keys.MaxSrcResolution, secops.MaxSrcResolution,
)
secops.MaxSrcFileSize = opts.GetInt(
keys.MaxSrcFileSize, secops.MaxSrcFileSize,
)
secops.MaxAnimationFrames = opts.GetInt(
keys.MaxAnimationFrames, secops.MaxAnimationFrames,
)
secops.MaxAnimationFrameResolution = opts.GetInt(
keys.MaxAnimationFrameResolution, secops.MaxAnimationFrameResolution,
)
secops.MaxResultDimension = opts.GetInt(
keys.MaxResultDimension, secops.MaxResultDimension,
)
if width*height*frames > s.MaxSrcResolution(o) {
return newImageResolutionError("Source image resolution is too big")
}
return
return nil
}
+20 -16
View File
@@ -32,21 +32,25 @@ type Config struct {
Salts [][]byte // List of the HMAC salts
SignatureSize int // Size of the HMAC signature in bytes
TrustedSignatures []string // List of trusted signature sources
DefaultOptions Options // Default security options
MaxSrcResolution int // Maximum allowed source image resolution
MaxSrcFileSize int // Maximum allowed source image file size in bytes
MaxAnimationFrames int // Maximum allowed animation frames
MaxAnimationFrameResolution int // Maximum allowed resolution per animation frame
MaxResultDimension int // Maximum allowed result image dimension (width or height)
}
// NewDefaultConfig returns a new Config instance with default values.
func NewDefaultConfig() Config {
return Config{
DefaultOptions: Options{
MaxSrcResolution: 50_000_000,
MaxSrcFileSize: 0,
MaxAnimationFrames: 1,
MaxAnimationFrameResolution: 0,
MaxResultDimension: 0,
},
AllowSecurityOptions: false,
SignatureSize: 32,
MaxSrcResolution: 50_000_000,
MaxSrcFileSize: 0,
MaxAnimationFrames: 1,
MaxAnimationFrameResolution: 0,
MaxResultDimension: 0,
}
}
@@ -60,11 +64,11 @@ func LoadConfigFromEnv(c *Config) (*Config, error) {
env.Int(&c.SignatureSize, IMGPROXY_SIGNATURE_SIZE),
env.StringSlice(&c.TrustedSignatures, IMGPROXY_TRUSTED_SIGNATURES),
env.MegaInt(&c.DefaultOptions.MaxSrcResolution, IMGPROXY_MAX_SRC_RESOLUTION),
env.Int(&c.DefaultOptions.MaxSrcFileSize, IMGPROXY_MAX_SRC_FILE_SIZE),
env.Int(&c.DefaultOptions.MaxAnimationFrames, IMGPROXY_MAX_ANIMATION_FRAMES),
env.MegaInt(&c.DefaultOptions.MaxAnimationFrameResolution, IMGPROXY_MAX_ANIMATION_FRAME_RESOLUTION),
env.Int(&c.DefaultOptions.MaxResultDimension, IMGPROXY_MAX_RESULT_DIMENSION),
env.MegaInt(&c.MaxSrcResolution, IMGPROXY_MAX_SRC_RESOLUTION),
env.Int(&c.MaxSrcFileSize, IMGPROXY_MAX_SRC_FILE_SIZE),
env.Int(&c.MaxAnimationFrames, IMGPROXY_MAX_ANIMATION_FRAMES),
env.MegaInt(&c.MaxAnimationFrameResolution, IMGPROXY_MAX_ANIMATION_FRAME_RESOLUTION),
env.Int(&c.MaxResultDimension, IMGPROXY_MAX_RESULT_DIMENSION),
env.HexSlice(&c.Keys, IMGPROXY_KEYS),
env.HexSlice(&c.Salts, IMGPROXY_SALTS),
@@ -75,15 +79,15 @@ func LoadConfigFromEnv(c *Config) (*Config, error) {
// Validate validates the configuration
func (c *Config) Validate() error {
if c.DefaultOptions.MaxSrcResolution <= 0 {
if c.MaxSrcResolution <= 0 {
return IMGPROXY_MAX_SRC_RESOLUTION.ErrorZeroOrNegative()
}
if c.DefaultOptions.MaxSrcFileSize < 0 {
if c.MaxSrcFileSize < 0 {
return IMGPROXY_MAX_SRC_FILE_SIZE.ErrorNegative()
}
if c.DefaultOptions.MaxAnimationFrames <= 0 {
if c.MaxAnimationFrames <= 0 {
return IMGPROXY_MAX_ANIMATION_FRAMES.ErrorZeroOrNegative()
}
-27
View File
@@ -1,27 +0,0 @@
package security
// Security options (part of processing options)
type Options struct {
MaxSrcResolution int
MaxSrcFileSize int
MaxAnimationFrames int
MaxAnimationFrameResolution int
MaxResultDimension int
}
// CheckDimensions checks if the given dimensions are within the allowed limits
func (o *Options) CheckDimensions(width, height, frames int) error {
frames = max(frames, 1)
if frames > 1 && o.MaxAnimationFrameResolution > 0 {
if width*height > o.MaxAnimationFrameResolution {
return newImageResolutionError("Source image frame resolution is too big")
}
} else {
if width*height*frames > o.MaxSrcResolution {
return newImageResolutionError("Source image resolution is too big")
}
}
return nil
}