diff --git a/internal/api/user.go b/internal/api/user.go index 112c19a2..1c5e2f02 100644 --- a/internal/api/user.go +++ b/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 diff --git a/internal/reader/filter/filter.go b/internal/reader/filter/filter.go index 09c77afd..c50225ea 100644 --- a/internal/reader/filter/filter.go +++ b/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 diff --git a/internal/reader/filter/filter_test.go b/internal/reader/filter/filter_test.go index 1540bab0..3e11c676 100644 --- a/internal/reader/filter/filter_test.go +++ b/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 { diff --git a/internal/ui/settings_update.go b/internal/ui/settings_update.go index e84f2b7f..682eada2 100644 --- a/internal/ui/settings_update.go +++ b/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"))