Browse Source

fix(filter): remove `\r\n` in rule parsing

Frédéric Guillot 8 months ago
parent
commit
dc81725788

+ 0 - 14
internal/api/user.go

@@ -7,8 +7,6 @@ import (
 	json_parser "encoding/json"
 	"errors"
 	"net/http"
-	"regexp"
-	"strings"
 
 	"miniflux.app/v2/internal/http/request"
 	"miniflux.app/v2/internal/http/response/json"
@@ -84,18 +82,6 @@ func (h *handler) updateUser(w http.ResponseWriter, r *http.Request) {
 		}
 	}
 
-	cleanEnd := regexp.MustCompile(`(?m)\r\n\s*$`)
-	if userModificationRequest.BlockFilterEntryRules != nil {
-		*userModificationRequest.BlockFilterEntryRules = cleanEnd.ReplaceAllLiteralString(*userModificationRequest.BlockFilterEntryRules, "")
-		// Clean carriage returns for Windows environments
-		*userModificationRequest.BlockFilterEntryRules = strings.ReplaceAll(*userModificationRequest.BlockFilterEntryRules, "\r\n", "\n")
-	}
-	if userModificationRequest.KeepFilterEntryRules != nil {
-		*userModificationRequest.KeepFilterEntryRules = cleanEnd.ReplaceAllLiteralString(*userModificationRequest.KeepFilterEntryRules, "")
-		// Clean carriage returns for Windows environments
-		*userModificationRequest.KeepFilterEntryRules = strings.ReplaceAll(*userModificationRequest.KeepFilterEntryRules, "\r\n", "\n")
-	}
-
 	if validationErr := validator.ValidateUserModification(h.store, originalUser.ID, &userModificationRequest); validationErr != nil {
 		json.BadRequest(w, r, validationErr.Error())
 		return

+ 1 - 0
internal/reader/filter/filter.go

@@ -128,6 +128,7 @@ func matchesEntryRegexRules(rules string, entry *model.Entry, feed *model.Feed,
 }
 
 func matchesRule(rule string, entry *model.Entry) bool {
+	rule = strings.TrimSpace(strings.ReplaceAll(rule, "\r\n", ""))
 	parts := strings.SplitN(rule, "=", 2)
 	if len(parts) != 2 {
 		return false

+ 9 - 2
internal/reader/filter/filter_test.go

@@ -52,12 +52,15 @@ func TestBlockingEntries(t *testing.T) {
 		{&model.Feed{ID: 1, BlockFilterEntryRules: "EntryURL=(?i)example"}, &model.Entry{URL: "https://example.com", Title: "Some Other"}, &model.User{BlockFilterEntryRules: "EntryTitle=(?i)title"}, true},       // Feed rule matches
 		{&model.Feed{ID: 1, BlockFilterEntryRules: "EntryURL=(?i)example"}, &model.Entry{URL: "https://different.com", Title: "Some Other"}, &model.User{BlockFilterEntryRules: "EntryTitle=(?i)title"}, false},    // Neither rule matches
 		{&model.Feed{ID: 1, BlockFilterEntryRules: "EntryURL=(?i)example"}, &model.Entry{URL: "https://example.com", Title: "Some Title"}, &model.User{BlockFilterEntryRules: "EntryTitle=(?i)title"}, true},       // Both rules would match
+		// Test multiple rules with \r\n separators
+		{&model.Feed{ID: 1, BlockFilterEntryRules: "EntryURL=(?i)example\r\nEntryTitle=(?i)Test"}, &model.Entry{URL: "https://example.com", Title: "Some Example"}, &model.User{}, true},
+		{&model.Feed{ID: 1, BlockFilterEntryRules: "EntryURL=(?i)example\r\nEntryTitle=(?i)Test"}, &model.Entry{URL: "https://different.com", Title: "Some Test"}, &model.User{}, true},
 	}
 
-	for _, tc := range scenarios {
+	for index, tc := range scenarios {
 		result := IsBlockedEntry(tc.feed, tc.entry, tc.user)
 		if tc.expected != result {
-			t.Errorf(`Unexpected result, got %v for entry %q`, result, tc.entry.Title)
+			t.Errorf(`Unexpected result for scenario %d, got %v for entry %q`, index, result, tc.entry.Title)
 		}
 	}
 }
@@ -113,6 +116,10 @@ func TestAllowEntries(t *testing.T) {
 		{&model.Feed{ID: 1, KeepFilterEntryRules: "EntryURL=(?i)example"}, &model.Entry{URL: "https://example.com", Title: "Some Other"}, &model.User{KeepFilterEntryRules: "EntryTitle=(?i)title"}, true},    // Feed rule matches
 		{&model.Feed{ID: 1, KeepFilterEntryRules: "EntryURL=(?i)example"}, &model.Entry{URL: "https://different.com", Title: "Some Other"}, &model.User{KeepFilterEntryRules: "EntryTitle=(?i)title"}, false}, // Neither rule matches
 		{&model.Feed{ID: 1, KeepFilterEntryRules: "EntryURL=(?i)example"}, &model.Entry{URL: "https://example.com", Title: "Some Title"}, &model.User{KeepFilterEntryRules: "EntryTitle=(?i)title"}, true},    // Both rules would match
+		// Test multiple rules with \r\n separators
+		{&model.Feed{ID: 1, KeepFilterEntryRules: "EntryURL=(?i)example\r\nEntryTitle=(?i)Test"}, &model.Entry{URL: "https://example.com", Title: "Some Example"}, &model.User{}, true},
+		{&model.Feed{ID: 1, KeepFilterEntryRules: "EntryURL=(?i)example\r\nEntryTitle=(?i)Test"}, &model.Entry{URL: "https://different.com", Title: "Some Test"}, &model.User{}, true},
+		{&model.Feed{ID: 1, KeepFilterEntryRules: "EntryURL=(?i)example\r\nEntryTitle=(?i)Test"}, &model.Entry{URL: "https://different.com", Title: "Some Example"}, &model.User{}, false},
 	}
 
 	for _, tc := range scenarios {

+ 0 - 10
internal/ui/settings_update.go

@@ -5,8 +5,6 @@ package ui // import "miniflux.app/v2/internal/ui"
 
 import (
 	"net/http"
-	"regexp"
-	"strings"
 
 	"miniflux.app/v2/internal/http/request"
 	"miniflux.app/v2/internal/http/response/html"
@@ -61,14 +59,6 @@ func (h *handler) updateSettings(w http.ResponseWriter, r *http.Request) {
 	view.Set("countWebAuthnCerts", h.store.CountWebAuthnCredentialsByUserID(loggedUser.ID))
 	view.Set("webAuthnCerts", creds)
 
-	// Sanitize the end of the block & Keep rules
-	cleanEnd := regexp.MustCompile(`(?m)\r\n\s*$`)
-	settingsForm.BlockFilterEntryRules = cleanEnd.ReplaceAllLiteralString(settingsForm.BlockFilterEntryRules, "")
-	settingsForm.KeepFilterEntryRules = cleanEnd.ReplaceAllLiteralString(settingsForm.KeepFilterEntryRules, "")
-	// Clean carriage returns for Windows environments
-	settingsForm.BlockFilterEntryRules = strings.ReplaceAll(settingsForm.BlockFilterEntryRules, "\r\n", "\n")
-	settingsForm.KeepFilterEntryRules = strings.ReplaceAll(settingsForm.KeepFilterEntryRules, "\r\n", "\n")
-
 	if validationErr := settingsForm.Validate(); validationErr != nil {
 		view.Set("errorMessage", validationErr.Translate(loggedUser.Language))
 		html.OK(w, r, view.Render("settings"))