mirror of
				https://github.com/imgproxy/imgproxy.git
				synced 2025-10-30 23:08:02 +02:00 
			
		
		
		
	Add IMGPROXY_ALLOWED_PROCESSING_OPTIONS config
This commit is contained in:
		| @@ -3,6 +3,7 @@ | ||||
| ## [Unreleased] | ||||
| ### 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_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_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. | ||||
|   | ||||
| @@ -48,6 +48,7 @@ var ( | ||||
| 	PngUnlimited                bool | ||||
| 	SvgUnlimited                bool | ||||
| 	MaxResultDimension          int | ||||
| 	AllowedProcessiongOptions   []string | ||||
| 	AllowSecurityOptions        bool | ||||
|  | ||||
| 	JpegProgressive       bool | ||||
| @@ -254,6 +255,7 @@ func Reset() { | ||||
| 	PngUnlimited = false | ||||
| 	SvgUnlimited = false | ||||
| 	MaxResultDimension = 0 | ||||
| 	AllowedProcessiongOptions = make([]string, 0) | ||||
| 	AllowSecurityOptions = false | ||||
|  | ||||
| 	JpegProgressive = false | ||||
| @@ -486,6 +488,7 @@ func Configure() error { | ||||
| 	configurators.Bool(&SvgUnlimited, "IMGPROXY_SVG_UNLIMITED") | ||||
|  | ||||
| 	configurators.Int(&MaxResultDimension, "IMGPROXY_MAX_RESULT_DIMENSION") | ||||
| 	configurators.StringSlice(&AllowedProcessiongOptions, "IMGPROXY_ALLOWED_PROCESSING_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 newOptionArgumentError(format string, args ...interface{}) error { | ||||
|   | ||||
| @@ -59,7 +59,7 @@ func parsePreset(presetStr string) error { | ||||
| func ValidatePresets() error { | ||||
| 	for name, opts := range presets { | ||||
| 		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) | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -691,7 +691,7 @@ func applyPresetOption(po *ProcessingOptions, args []string, usedPresets ...stri | ||||
|  | ||||
| 			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 | ||||
| 			} | ||||
| 		} else { | ||||
| @@ -1081,8 +1081,14 @@ func applyURLOption(po *ProcessingOptions, name string, args []string, usedPrese | ||||
| 	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 { | ||||
| 		if !allowAll && !slices.Contains(config.AllowedProcessiongOptions, opt.Name) { | ||||
| 			return newForbiddenOptionError("processing", opt.Name) | ||||
| 		} | ||||
|  | ||||
| 		if err := applyURLOption(po, opt.Name, opt.Args, usedPresets...); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| @@ -1154,7 +1160,7 @@ func parsePathOptions(parts []string, headers http.Header) (*ProcessingOptions, | ||||
|  | ||||
| 	options, urlParts := parseURLOptions(parts) | ||||
|  | ||||
| 	if err = applyURLOptions(po, options); err != nil { | ||||
| 	if err = applyURLOptions(po, options, false); err != nil { | ||||
| 		return nil, "", err | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import ( | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/suite" | ||||
| @@ -644,6 +645,40 @@ func (s *ProcessingOptionsTestSuite) TestParseBase64URLOnlyPresets() { | ||||
| 	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) { | ||||
| 	suite.Run(t, new(ProcessingOptionsTestSuite)) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user