fix(config): accept spaces and trailing commas in list option values

MEDIA_PROXY_RESOURCE_TYPES and TRUSTED_REVERSE_PROXY_NETWORKS were
validated by splitting the raw value without trimming, while the parser
trims items and skips empty ones. Values such as "image, video" or
"192.168.0.0/16, 10.0.0.0/8", and lists with a trailing comma, failed
startup even though the parser accepts them.

Validate the parsed list instead, and reject values that contain no
items at all so that a comma-only value cannot silently clear the
default media proxy resource types.
This commit is contained in:
Fred
2026-07-21 21:11:20 -07:00
committed by fguillot
parent 0e26f12426
commit 1d10e7a089
2 changed files with 48 additions and 2 deletions
+11 -2
View File
@@ -4,6 +4,7 @@
package config // import "miniflux.app/v2/internal/config" package config // import "miniflux.app/v2/internal/config"
import ( import (
"errors"
"maps" "maps"
"net" "net"
"net/url" "net/url"
@@ -383,7 +384,11 @@ func NewConfigOptions() *configOptions {
rawValue: "image", rawValue: "image",
valueType: stringListType, valueType: stringListType,
validator: func(rawValue string) error { validator: func(rawValue string) error {
return validateListChoices(strings.Split(rawValue, ","), []string{"image", "video", "audio"}) resourceTypes := parseStringListValue(rawValue, nil)
if len(resourceTypes) == 0 {
return errors.New("at least one resource type is required")
}
return validateListChoices(resourceTypes, []string{"image", "video", "audio"})
}, },
}, },
"METRICS_ALLOWED_NETWORKS": { "METRICS_ALLOWED_NETWORKS": {
@@ -569,7 +574,11 @@ func NewConfigOptions() *configOptions {
rawValue: "", rawValue: "",
valueType: stringListType, valueType: stringListType,
validator: func(rawValue string) error { validator: func(rawValue string) error {
for ip := range strings.SplitSeq(rawValue, ",") { networks := parseStringListValue(rawValue, nil)
if len(networks) == 0 {
return errors.New("at least one CIDR notation network is required")
}
for _, ip := range networks {
if _, _, err := net.ParseCIDR(ip); err != nil { if _, _, err := net.ParseCIDR(ip); err != nil {
return err return err
} }
+37
View File
@@ -1508,9 +1508,26 @@ func TestMediaProxyResourceTypesOptionParsing(t *testing.T) {
t.Fatalf("Expected MEDIA_PROXY_RESOURCE_TYPES to contain image and video") t.Fatalf("Expected MEDIA_PROXY_RESOURCE_TYPES to contain image and video")
} }
if err := configParser.parseLines([]string{"MEDIA_PROXY_RESOURCE_TYPES=image, video"}); err != nil {
t.Fatalf("Unexpected error for value with spaces: %v", err)
}
resourceTypes = configParser.options.MediaProxyResourceTypes()
if len(resourceTypes) != 2 || resourceTypes[0] != "image" || resourceTypes[1] != "video" {
t.Fatalf("Expected MEDIA_PROXY_RESOURCE_TYPES to contain image and video")
}
if err := configParser.parseLines([]string{"MEDIA_PROXY_RESOURCE_TYPES=image,video,"}); err != nil {
t.Fatalf("Unexpected error for value with trailing comma: %v", err)
}
if err := configParser.parseLines([]string{"MEDIA_PROXY_RESOURCE_TYPES=image,invalid,video"}); err == nil { if err := configParser.parseLines([]string{"MEDIA_PROXY_RESOURCE_TYPES=image,invalid,video"}); err == nil {
t.Fatal("Expected error due to invalid resource type") t.Fatal("Expected error due to invalid resource type")
} }
if err := configParser.parseLines([]string{"MEDIA_PROXY_RESOURCE_TYPES=,"}); err == nil {
t.Fatal("Expected error for value without any resource type")
}
} }
func TestMetricsAllowedNetworksOptionParsing(t *testing.T) { func TestMetricsAllowedNetworksOptionParsing(t *testing.T) {
@@ -1652,10 +1669,30 @@ func TestTrustedReverseProxyNetworksOptionParsing(t *testing.T) {
t.Errorf("Expected 192.168.1.0/24 in allowed networks") t.Errorf("Expected 192.168.1.0/24 in allowed networks")
} }
// Test value with spaces and trailing comma
if err := configParser.parseLines([]string{"TRUSTED_REVERSE_PROXY_NETWORKS=192.168.0.0/16, 10.0.0.0/8,"}); err != nil {
t.Fatalf("Unexpected error for value with spaces: %v", err)
}
allowedNetworks = configParser.options.TrustedReverseProxyNetworks()
if len(allowedNetworks) != 2 {
t.Fatalf("Expected 2 allowed networks, got %d", len(allowedNetworks))
}
if !slices.Contains(allowedNetworks, "192.168.0.0/16") {
t.Errorf("Expected 192.168.0.0/16 in allowed networks")
}
if !slices.Contains(allowedNetworks, "10.0.0.0/8") {
t.Errorf("Expected 10.0.0.0/8 in allowed networks")
}
// Test invalid value // Test invalid value
if err := configParser.parseLines([]string{"TRUSTED_REVERSE_PROXY_NETWORKS=127.0.0.1"}); err == nil { if err := configParser.parseLines([]string{"TRUSTED_REVERSE_PROXY_NETWORKS=127.0.0.1"}); err == nil {
t.Fatal("Expected error when parsing invalid CIDR notation IP 127.0.0.1, got nil") t.Fatal("Expected error when parsing invalid CIDR notation IP 127.0.0.1, got nil")
} }
if err := configParser.parseLines([]string{"TRUSTED_REVERSE_PROXY_NETWORKS=,"}); err == nil {
t.Fatal("Expected error for value without any network")
}
} }
func TestYouTubeEmbedDomainOptionParsing(t *testing.T) { func TestYouTubeEmbedDomainOptionParsing(t *testing.T) {