mirror of
https://github.com/imgproxy/imgproxy.git
synced 2025-09-16 09:36:18 +02:00
Add IMGPROXY_ALLOWED_PROCESSING_OPTIONS config
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
- Add [IMGPROXY_MAX_RESULT_DIMENSION](https://docs.imgproxy.net/latest/configuration/options#IMGPROXY_MAX_RESULT_DIMENSION) config and [max_result_dimension](https://docs.imgproxy.net/latest/usage/processing#max-result-dimension) processing option.
|
- Add [IMGPROXY_MAX_RESULT_DIMENSION](https://docs.imgproxy.net/latest/configuration/options#IMGPROXY_MAX_RESULT_DIMENSION) config and [max_result_dimension](https://docs.imgproxy.net/latest/usage/processing#max-result-dimension) processing option.
|
||||||
|
- Add [IMGPROXY_ALLOWED_PROCESSING_OPTIONS](https://docs.imgproxy.net/latest/configuration/options#IMGPROXY_ALLOWED_PROCESSING_OPTIONS) config.
|
||||||
- Add `imgproxy.source_image_origin` attribute to New Relic, DataDog, and OpenTelemetry traces.
|
- Add `imgproxy.source_image_origin` attribute to New Relic, DataDog, and OpenTelemetry traces.
|
||||||
- Add `imgproxy.source_image_url` and `imgproxy.source_image_origin` attributes to `downloading_image` spans in New Relic, DataDog, and OpenTelemetry traces.
|
- Add `imgproxy.source_image_url` and `imgproxy.source_image_origin` attributes to `downloading_image` spans in New Relic, DataDog, and OpenTelemetry traces.
|
||||||
- Add `imgproxy.processing_options` attribute to `processing_image` spans in New Relic, DataDog, and OpenTelemetry traces.
|
- Add `imgproxy.processing_options` attribute to `processing_image` spans in New Relic, DataDog, and OpenTelemetry traces.
|
||||||
|
@@ -48,6 +48,7 @@ var (
|
|||||||
PngUnlimited bool
|
PngUnlimited bool
|
||||||
SvgUnlimited bool
|
SvgUnlimited bool
|
||||||
MaxResultDimension int
|
MaxResultDimension int
|
||||||
|
AllowedProcessiongOptions []string
|
||||||
AllowSecurityOptions bool
|
AllowSecurityOptions bool
|
||||||
|
|
||||||
JpegProgressive bool
|
JpegProgressive bool
|
||||||
@@ -254,6 +255,7 @@ func Reset() {
|
|||||||
PngUnlimited = false
|
PngUnlimited = false
|
||||||
SvgUnlimited = false
|
SvgUnlimited = false
|
||||||
MaxResultDimension = 0
|
MaxResultDimension = 0
|
||||||
|
AllowedProcessiongOptions = make([]string, 0)
|
||||||
AllowSecurityOptions = false
|
AllowSecurityOptions = false
|
||||||
|
|
||||||
JpegProgressive = false
|
JpegProgressive = false
|
||||||
@@ -486,6 +488,7 @@ func Configure() error {
|
|||||||
configurators.Bool(&SvgUnlimited, "IMGPROXY_SVG_UNLIMITED")
|
configurators.Bool(&SvgUnlimited, "IMGPROXY_SVG_UNLIMITED")
|
||||||
|
|
||||||
configurators.Int(&MaxResultDimension, "IMGPROXY_MAX_RESULT_DIMENSION")
|
configurators.Int(&MaxResultDimension, "IMGPROXY_MAX_RESULT_DIMENSION")
|
||||||
|
configurators.StringSlice(&AllowedProcessiongOptions, "IMGPROXY_ALLOWED_PROCESSING_OPTIONS")
|
||||||
|
|
||||||
configurators.Bool(&AllowSecurityOptions, "IMGPROXY_ALLOW_SECURITY_OPTIONS")
|
configurators.Bool(&AllowSecurityOptions, "IMGPROXY_ALLOW_SECURITY_OPTIONS")
|
||||||
|
|
||||||
|
@@ -35,6 +35,16 @@ func newUnknownOptionError(kind, opt string) error {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newForbiddenOptionError(kind, opt string) error {
|
||||||
|
return ierrors.Wrap(
|
||||||
|
UnknownOptionError(fmt.Sprintf("Forbidden %s option %s", kind, opt)),
|
||||||
|
1,
|
||||||
|
ierrors.WithStatusCode(http.StatusNotFound),
|
||||||
|
ierrors.WithPublicMessage("Invalid URL"),
|
||||||
|
ierrors.WithShouldReport(false),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func (e UnknownOptionError) Error() string { return string(e) }
|
func (e UnknownOptionError) Error() string { return string(e) }
|
||||||
|
|
||||||
func newOptionArgumentError(format string, args ...interface{}) error {
|
func newOptionArgumentError(format string, args ...interface{}) error {
|
||||||
|
@@ -59,7 +59,7 @@ func parsePreset(presetStr string) error {
|
|||||||
func ValidatePresets() error {
|
func ValidatePresets() error {
|
||||||
for name, opts := range presets {
|
for name, opts := range presets {
|
||||||
po := NewProcessingOptions()
|
po := NewProcessingOptions()
|
||||||
if err := applyURLOptions(po, opts, name); err != nil {
|
if err := applyURLOptions(po, opts, true, name); err != nil {
|
||||||
return fmt.Errorf("Error in preset `%s`: %s", name, err)
|
return fmt.Errorf("Error in preset `%s`: %s", name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -691,7 +691,7 @@ func applyPresetOption(po *ProcessingOptions, args []string, usedPresets ...stri
|
|||||||
|
|
||||||
po.UsedPresets = append(po.UsedPresets, preset)
|
po.UsedPresets = append(po.UsedPresets, preset)
|
||||||
|
|
||||||
if err := applyURLOptions(po, p, append(usedPresets, preset)...); err != nil {
|
if err := applyURLOptions(po, p, true, append(usedPresets, preset)...); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1081,8 +1081,14 @@ func applyURLOption(po *ProcessingOptions, name string, args []string, usedPrese
|
|||||||
return newUnknownOptionError("processing", name)
|
return newUnknownOptionError("processing", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyURLOptions(po *ProcessingOptions, options urlOptions, usedPresets ...string) error {
|
func applyURLOptions(po *ProcessingOptions, options urlOptions, allowAll bool, usedPresets ...string) error {
|
||||||
|
allowAll = allowAll || len(config.AllowedProcessiongOptions) == 0
|
||||||
|
|
||||||
for _, opt := range options {
|
for _, opt := range options {
|
||||||
|
if !allowAll && !slices.Contains(config.AllowedProcessiongOptions, opt.Name) {
|
||||||
|
return newForbiddenOptionError("processing", opt.Name)
|
||||||
|
}
|
||||||
|
|
||||||
if err := applyURLOption(po, opt.Name, opt.Args, usedPresets...); err != nil {
|
if err := applyURLOption(po, opt.Name, opt.Args, usedPresets...); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -1154,7 +1160,7 @@ func parsePathOptions(parts []string, headers http.Header) (*ProcessingOptions,
|
|||||||
|
|
||||||
options, urlParts := parseURLOptions(parts)
|
options, urlParts := parseURLOptions(parts)
|
||||||
|
|
||||||
if err = applyURLOptions(po, options); err != nil {
|
if err = applyURLOptions(po, options, false); err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,6 +6,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
@@ -644,6 +645,40 @@ func (s *ProcessingOptionsTestSuite) TestParseBase64URLOnlyPresets() {
|
|||||||
s.Require().Equal(originURL, imageURL)
|
s.Require().Equal(originURL, imageURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ProcessingOptionsTestSuite) TestParseAllowedOptions() {
|
||||||
|
config.AllowedProcessiongOptions = []string{"w", "h", "pr"}
|
||||||
|
|
||||||
|
presets["test1"] = urlOptions{
|
||||||
|
urlOption{Name: "blur", Args: []string{"0.2"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
originURL := "http://images.dev/lorem/ipsum.jpg?param=value"
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
options string
|
||||||
|
expectedError string
|
||||||
|
}{
|
||||||
|
{options: "w:100/h:200", expectedError: ""},
|
||||||
|
{options: "w:100/h:200/blur:10", expectedError: "Forbidden processing option blur"},
|
||||||
|
{options: "w:100/h:200/pr:test1", expectedError: ""},
|
||||||
|
{options: "w:100/h:200/pr:test1/blur:10", expectedError: "Forbidden processing option blur"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
s.Run(strings.ReplaceAll(tc.options, "/", "_"), func() {
|
||||||
|
path := fmt.Sprintf("/%s/%s.png", tc.options, base64.RawURLEncoding.EncodeToString([]byte(originURL)))
|
||||||
|
_, _, err := ParsePath(path, make(http.Header))
|
||||||
|
|
||||||
|
if len(tc.expectedError) > 0 {
|
||||||
|
s.Require().Error(err)
|
||||||
|
s.Require().Equal(tc.expectedError, err.Error())
|
||||||
|
} else {
|
||||||
|
s.Require().NoError(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestProcessingOptions(t *testing.T) {
|
func TestProcessingOptions(t *testing.T) {
|
||||||
suite.Run(t, new(ProcessingOptionsTestSuite))
|
suite.Run(t, new(ProcessingOptionsTestSuite))
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user