Browse Source

Add IMGPROXY_ALLOWED_SOURCES config (#169)

* Add config option to exclusively allow local file system images

* Add allowed sources list, and move source check processing_options.

* Implement custom source parser and remove redundant code.
rhyst 5 years ago
parent
commit
70b3252373
3 changed files with 36 additions and 2 deletions
  1. 13 0
      config.go
  2. 1 0
      docs/configuration.md
  3. 22 2
      processing_options.go

+ 13 - 0
config.go

@@ -128,6 +128,17 @@ func presetFileConfig(p presets, filepath string) {
 	}
 }
 
+func sourceEnvConfig(allowedsources *[]string, name string) {
+	sources := []string{}
+	if env := os.Getenv(name); len(env) > 0 {
+		for _, source := range strings.Split(env, ",") {
+			logWarning("source: %s", source)
+			sources = append(sources, fmt.Sprintf("%s://", source))
+		}
+	}
+	*allowedsources = sources
+}
+
 type config struct {
 	Bind             string
 	ReadTimeout      int
@@ -172,6 +183,7 @@ type config struct {
 	IgnoreSslVerification bool
 	DevelopmentErrorsMode bool
 
+	AllowedSources      []string
 	LocalFileSystemRoot string
 	S3Enabled           bool
 	S3Region            string
@@ -306,6 +318,7 @@ func configure() {
 	boolEnvConfig(&conf.DevelopmentErrorsMode, "IMGPROXY_DEVELOPMENT_ERRORS_MODE")
 
 	strEnvConfig(&conf.LocalFileSystemRoot, "IMGPROXY_LOCAL_FILESYSTEM_ROOT")
+	sourceEnvConfig(&conf.AllowedSources, "IMGPROXY_ALLOWED_SOURCES")
 
 	boolEnvConfig(&conf.S3Enabled, "IMGPROXY_USE_S3")
 	strEnvConfig(&conf.S3Region, "IMGPROXY_S3_REGION")

+ 1 - 0
docs/configuration.md

@@ -166,6 +166,7 @@ imgproxy can be switched into "presets-only mode". In this mode, imgproxy accept
 imgproxy can serve your local images, but this feature is disabled by default. To enable it, specify your local filesystem root:
 
 * `IMGPROXY_LOCAL_FILESYSTEM_ROOT`: the root of the local filesystem. Keep empty to disable serving of local files.
+* `IMGPROXY_ONLY_LOCAL_FILESYSTEM`: when true only allows images to be served from the local filesytem. Default: false;
 
 Check out the [Serving local files](serving_local_files.md) guide to learn more.
 

+ 22 - 2
processing_options.go

@@ -140,8 +140,9 @@ const (
 	urlTokenPlain           = "plain"
 	maxClientHintDPR        = 8
 
-	msgForbidden  = "Forbidden"
-	msgInvalidURL = "Invalid URL"
+	msgForbidden     = "Forbidden"
+	msgInvalidURL    = "Invalid URL"
+	msgInvalidSource = "Invalid Source"
 )
 
 func (gt gravityType) String() string {
@@ -791,6 +792,21 @@ func applyProcessingOptions(po *processingOptions, options urlOptions) error {
 	return nil
 }
 
+func isAllowedSource(imageURL string) bool {
+	logWarning("URL: %s", imageURL)
+	if len(conf.AllowedSources) == 0 {
+		logWarning("No sources set")
+		return true
+	}
+	for _, val := range conf.AllowedSources {
+		logWarning("Allowed Source: %s", string(val))
+		if strings.HasPrefix(imageURL, string(val)) {
+			return true
+		}
+	}
+	return false
+}
+
 func parseURLOptions(opts []string) (urlOptions, []string) {
 	parsed := make(urlOptions, 0, len(opts))
 	urlStart := len(opts) + 1
@@ -984,6 +1000,10 @@ func parsePath(ctx context.Context, r *http.Request) (context.Context, error) {
 		return ctx, newError(404, err.Error(), msgInvalidURL)
 	}
 
+	if !isAllowedSource(imageURL) {
+		return ctx, newError(404, fmt.Sprintf("Invalid source"), msgInvalidSource)
+	}
+
 	ctx = context.WithValue(ctx, imageURLCtxKey, imageURL)
 	ctx = context.WithValue(ctx, processingOptionsCtxKey, po)