diff --git a/locale/translations.go b/locale/translations.go index 815e0bbe..e8a82b12 100644 --- a/locale/translations.go +++ b/locale/translations.go @@ -249,6 +249,8 @@ var translations = map[string]string{ "error.site_url_not_empty": "Die Site-URL darf nicht leer sein.", "error.feed_title_not_empty": "Der Feed-Titel darf nicht leer sein.", "error.feed_category_not_found": "Diese Kategorie existiert nicht oder gehört nicht zu diesem Benutzer.", + "error.feed_invalid_blocklist_rule": "Die Sperrlistenregel ist ungültig.", + "error.feed_invalid_keeplist_rule": "Die Keep List-Regel ist ungültig.", "error.user_mandatory_fields": "Der Benutzername ist obligatorisch.", "error.api_key_already_exists": "Dieser API-Schlüssel ist bereits vorhanden.", "error.unable_to_create_api_key": "Dieser API-Schlüssel kann nicht erstellt werden.", @@ -615,6 +617,8 @@ var translations = map[string]string{ "error.site_url_not_empty": "The site URL cannot be empty.", "error.feed_title_not_empty": "The feed title cannot be empty.", "error.feed_category_not_found": "This category does not exist or does not belong to this user.", + "error.feed_invalid_blocklist_rule": "The block list rule is invalid.", + "error.feed_invalid_keeplist_rule": "The keep list rule is invalid.", "error.user_mandatory_fields": "The username is mandatory.", "error.api_key_already_exists": "This API Key already exists.", "error.unable_to_create_api_key": "Unable to create this API Key.", @@ -953,6 +957,8 @@ var translations = map[string]string{ "error.site_url_not_empty": "La URL del sitio no puede estar vacía.", "error.feed_title_not_empty": "El título del feed no puede estar vacío.", "error.feed_category_not_found": "Esta categoría no existe o no pertenece a este usuario.", + "error.feed_invalid_blocklist_rule": "La regla de la lista de bloqueo no es válida.", + "error.feed_invalid_keeplist_rule": "La regla de mantener la lista no es válida.", "error.user_mandatory_fields": "El nombre de usuario es obligatorio.", "error.api_key_already_exists": "Esta clave API ya existe.", "error.unable_to_create_api_key": "No se puede crear esta clave API.", @@ -1295,6 +1301,8 @@ var translations = map[string]string{ "error.site_url_not_empty": "L'URL du site ne peut pas être vide.", "error.feed_title_not_empty": "Le titre du flux ne peut pas être vide.", "error.feed_category_not_found": "Cette catégorie n'existe pas ou n'appartient pas à cet utilisateur.", + "error.feed_invalid_blocklist_rule": "La règle de blocage n'est pas valide.", + "error.feed_invalid_keeplist_rule": "La règle d'autorisation n'est pas valide.", "error.user_mandatory_fields": "Le nom d'utilisateur est obligatoire.", "error.api_key_already_exists": "Cette clé d'API existe déjà.", "error.unable_to_create_api_key": "Impossible de créer cette clé d'API.", @@ -1314,7 +1322,7 @@ var translations = map[string]string{ "form.feed.label.rewrite_rules": "Règles de réécriture", "form.feed.label.blocklist_rules": "Règles de blocage", "form.feed.label.keeplist_rules": "Règles d'autorisation", - "form.feed.label.ignore_http_cache": "Ignore cache HTTP", + "form.feed.label.ignore_http_cache": "Ignorer le cache HTTP", "form.feed.label.fetch_via_proxy": "Récupérer via proxy", "form.feed.label.disabled": "Ne pas actualiser ce flux", "form.category.label.title": "Titre", @@ -1657,6 +1665,8 @@ var translations = map[string]string{ "error.site_url_not_empty": "L'URL del sito non può essere vuoto.", "error.feed_title_not_empty": "Il titolo del feed non può essere vuoto.", "error.feed_category_not_found": "Questa categoria non esiste o non appartiene a questo utente.", + "error.feed_invalid_blocklist_rule": "La regola dell'elenco di blocco non è valida.", + "error.feed_invalid_keeplist_rule": "La regola dell'elenco di conservazione non è valida.", "error.user_mandatory_fields": "Il nome utente è obbligatorio.", "error.api_key_already_exists": "Questa chiave API esiste già.", "error.unable_to_create_api_key": "Impossibile creare questa chiave API.", @@ -1999,6 +2009,8 @@ var translations = map[string]string{ "error.site_url_not_empty": "サイトのURLを空にすることはできません。", "error.feed_title_not_empty": "フィードのタイトルを空にすることはできません。", "error.feed_category_not_found": "このカテゴリは存在しないか、このユーザーに属していません。", + "error.feed_invalid_blocklist_rule": "ブロックリストルールが無効です。", + "error.feed_invalid_keeplist_rule": "リストの保持ルールが無効です。", "error.user_mandatory_fields": "ユーザー名が必要です。", "error.api_key_already_exists": "このAPIキーは既に存在します。", "error.unable_to_create_api_key": "このAPIキーを作成できません。", @@ -2341,6 +2353,8 @@ var translations = map[string]string{ "error.site_url_not_empty": "De site-URL mag niet leeg zijn.", "error.feed_title_not_empty": "De feedtitel mag niet leeg zijn.", "error.feed_category_not_found": "Deze categorie bestaat niet of behoort niet tot deze gebruiker.", + "error.feed_invalid_blocklist_rule": "De regel voor de blokkeerlijst is ongeldig.", + "error.feed_invalid_keeplist_rule": "De regel voor het bewaren van een lijst is ongeldig.", "error.user_mandatory_fields": "Gebruikersnaam is verplicht", "error.api_key_already_exists": "This API Key already exists.", "error.unable_to_create_api_key": "Kan deze API-sleutel niet maken.", @@ -2703,6 +2717,8 @@ var translations = map[string]string{ "error.site_url_not_empty": "Adres URL witryny nie może być pusty.", "error.feed_title_not_empty": "Tytuł kanału nie może być pusty.", "error.feed_category_not_found": "Ta kategoria nie istnieje lub nie należy do tego użytkownika.", + "error.feed_invalid_blocklist_rule": "Reguła listy zablokowanych jest nieprawidłowa.", + "error.feed_invalid_keeplist_rule": "Reguła listy zachowania jest nieprawidłowa.", "error.user_mandatory_fields": "Nazwa użytkownika jest obowiązkowa.", "error.api_key_already_exists": "Deze API-sleutel bestaat al.", "error.unable_to_create_api_key": "Nie można utworzyć tego klucza API.", @@ -3069,6 +3085,8 @@ var translations = map[string]string{ "error.site_url_not_empty": "O URL do site não pode estar vazio.", "error.feed_title_not_empty": "O título do feed não pode estar vazio.", "error.feed_category_not_found": "Esta categoria não existe ou não pertence a este usuário.", + "error.feed_invalid_blocklist_rule": "A regra da lista de bloqueio é inválida.", + "error.feed_invalid_keeplist_rule": "A regra de manutenção da lista é inválida.", "error.user_mandatory_fields": "O nome de usuário é obrigatório.", "error.api_key_already_exists": "Essa chave de API já existe.", "error.unable_to_create_api_key": "Não foi possível criar uma chave de API.", @@ -3413,6 +3431,8 @@ var translations = map[string]string{ "error.site_url_not_empty": "URL сайта не может быть пустым.", "error.feed_title_not_empty": "Заголовок фида не может быть пустым.", "error.feed_category_not_found": "Эта категория не существует или не принадлежит этому пользователю.", + "error.feed_invalid_blocklist_rule": "Правило черного списка недействительно.", + "error.feed_invalid_keeplist_rule": "Правило списка хранения недействительно.", "error.user_mandatory_fields": "Имя пользователя обязательно.", "error.api_key_already_exists": "Этот ключ API уже существует.", "error.unable_to_create_api_key": "Невозможно создать этот ключ API.", @@ -3759,6 +3779,8 @@ var translations = map[string]string{ "error.site_url_not_empty": "网站网址不能为空。", "error.feed_title_not_empty": "供稿标题不能为空。", "error.feed_category_not_found": "此类别不存在或不属于该用户。", + "error.feed_invalid_blocklist_rule": "阻止列表规则无效。", + "error.feed_invalid_keeplist_rule": "保留列表规则无效。", "error.user_mandatory_fields": "必须填写用户名", "error.api_key_already_exists": "此API密钥已存在。", "error.unable_to_create_api_key": "无法创建此API密钥。", @@ -3871,15 +3893,15 @@ var translations = map[string]string{ } var translationsChecksums = map[string]string{ - "de_DE": "96616242d64bfca6bcc27762260aac38a3014ae854dfe4d85711491f7e0e52a2", - "en_US": "0718463b2edc0157dba7b26c033bcfa36181e57addd613a19ce60e6c6b34cb19", - "es_ES": "fc767762d1eb5cd44d89aab99a58a0c28b910ba06457d7ffe1b21092d473bb8e", - "fr_FR": "3abdb817b699ffb2c9f3c2316879c65b96510ff3e6a875860fcccdd063b29e63", - "it_IT": "2d2aa46e81f48494c08b78963d88d6522395856bd25f4b1504403da1f8d531e8", - "ja_JP": "7c1098e38962f4d285b957f7db428b28d562d1fe3b16117c0ac0340870cd43b0", - "nl_NL": "43093afdfa7d692d83455f5e4f3d36d4e725c704796961b749a84ba27ddbbd0b", - "pl_PL": "eb0baf99b46f5440a32084453091272f57c5f676b595640016f168fb65e439b7", - "pt_BR": "9ed1a472f60e65c4f8309417a3af17572299cd23c25ae6e1d368996578963b25", - "ru_RU": "de2cda1638754b7c3376749fa7d62d75d3594543465c1f78f801fe6c08d4eb2f", - "zh_CN": "07f1fb9efeb93f2d45b71c7028b50fe5bca378c307d1e2dadd0821fabd074918", + "de_DE": "204b8359228926129612defadb82b425ca6d76a60606572a5e66b4313753b6b8", + "en_US": "836c34115c6e190e9b77e894ab998193bdc5dae204636084994a09b6274ff41f", + "es_ES": "b190315004d23bfeda4123e6f77613bdcb78335b0b6a2876dd0e1bc76c428eaa", + "fr_FR": "7be464741f4301dd3a6ace3fd66f471884dbbd1f9a2866a805502227382b94a7", + "it_IT": "e2027bf6c5ee384d0bf776c4fb04fd99b5c4e18c694db4d7ff09529b9fe96d17", + "ja_JP": "33ac3c96003b95222dc1318f6dc1e929c8b75e2415700e7b544abfbe57b6eb0a", + "nl_NL": "dbf1343301ed35161f8deebd25726bc39d6a1bfdeb198ac555b1a0c72e16d96d", + "pl_PL": "8c646402462d62235245229f3a9f0297cdf6ac2f53df1e25508075e43a1ccf4e", + "pt_BR": "2d613ce5fd8b00da9df5c9cf1f675839cdfc3e4c5646b0cc949f0bf18aca59d0", + "ru_RU": "e6c4d0467051235d28c0329404e9ec8a7d353563b789f69e6cada2099d816f5d", + "zh_CN": "51ec39c564c11373b1574ed35d798dab61036d8cbeb6c807116e5dbf7443f31c", } diff --git a/locale/translations/de_DE.json b/locale/translations/de_DE.json index 3badbc5c..accdfac1 100644 --- a/locale/translations/de_DE.json +++ b/locale/translations/de_DE.json @@ -244,6 +244,8 @@ "error.site_url_not_empty": "Die Site-URL darf nicht leer sein.", "error.feed_title_not_empty": "Der Feed-Titel darf nicht leer sein.", "error.feed_category_not_found": "Diese Kategorie existiert nicht oder gehört nicht zu diesem Benutzer.", + "error.feed_invalid_blocklist_rule": "Die Sperrlistenregel ist ungültig.", + "error.feed_invalid_keeplist_rule": "Die Keep List-Regel ist ungültig.", "error.user_mandatory_fields": "Der Benutzername ist obligatorisch.", "error.api_key_already_exists": "Dieser API-Schlüssel ist bereits vorhanden.", "error.unable_to_create_api_key": "Dieser API-Schlüssel kann nicht erstellt werden.", diff --git a/locale/translations/en_US.json b/locale/translations/en_US.json index 4fddc568..489ce27b 100644 --- a/locale/translations/en_US.json +++ b/locale/translations/en_US.json @@ -248,6 +248,8 @@ "error.site_url_not_empty": "The site URL cannot be empty.", "error.feed_title_not_empty": "The feed title cannot be empty.", "error.feed_category_not_found": "This category does not exist or does not belong to this user.", + "error.feed_invalid_blocklist_rule": "The block list rule is invalid.", + "error.feed_invalid_keeplist_rule": "The keep list rule is invalid.", "error.user_mandatory_fields": "The username is mandatory.", "error.api_key_already_exists": "This API Key already exists.", "error.unable_to_create_api_key": "Unable to create this API Key.", diff --git a/locale/translations/es_ES.json b/locale/translations/es_ES.json index cd2cbc0d..81c9cbaa 100644 --- a/locale/translations/es_ES.json +++ b/locale/translations/es_ES.json @@ -244,6 +244,8 @@ "error.site_url_not_empty": "La URL del sitio no puede estar vacía.", "error.feed_title_not_empty": "El título del feed no puede estar vacío.", "error.feed_category_not_found": "Esta categoría no existe o no pertenece a este usuario.", + "error.feed_invalid_blocklist_rule": "La regla de la lista de bloqueo no es válida.", + "error.feed_invalid_keeplist_rule": "La regla de mantener la lista no es válida.", "error.user_mandatory_fields": "El nombre de usuario es obligatorio.", "error.api_key_already_exists": "Esta clave API ya existe.", "error.unable_to_create_api_key": "No se puede crear esta clave API.", diff --git a/locale/translations/fr_FR.json b/locale/translations/fr_FR.json index 5c03805f..33117e6f 100644 --- a/locale/translations/fr_FR.json +++ b/locale/translations/fr_FR.json @@ -244,6 +244,8 @@ "error.site_url_not_empty": "L'URL du site ne peut pas être vide.", "error.feed_title_not_empty": "Le titre du flux ne peut pas être vide.", "error.feed_category_not_found": "Cette catégorie n'existe pas ou n'appartient pas à cet utilisateur.", + "error.feed_invalid_blocklist_rule": "La règle de blocage n'est pas valide.", + "error.feed_invalid_keeplist_rule": "La règle d'autorisation n'est pas valide.", "error.user_mandatory_fields": "Le nom d'utilisateur est obligatoire.", "error.api_key_already_exists": "Cette clé d'API existe déjà.", "error.unable_to_create_api_key": "Impossible de créer cette clé d'API.", @@ -263,7 +265,7 @@ "form.feed.label.rewrite_rules": "Règles de réécriture", "form.feed.label.blocklist_rules": "Règles de blocage", "form.feed.label.keeplist_rules": "Règles d'autorisation", - "form.feed.label.ignore_http_cache": "Ignore cache HTTP", + "form.feed.label.ignore_http_cache": "Ignorer le cache HTTP", "form.feed.label.fetch_via_proxy": "Récupérer via proxy", "form.feed.label.disabled": "Ne pas actualiser ce flux", "form.category.label.title": "Titre", diff --git a/locale/translations/it_IT.json b/locale/translations/it_IT.json index 91df1ae1..561322e9 100644 --- a/locale/translations/it_IT.json +++ b/locale/translations/it_IT.json @@ -244,6 +244,8 @@ "error.site_url_not_empty": "L'URL del sito non può essere vuoto.", "error.feed_title_not_empty": "Il titolo del feed non può essere vuoto.", "error.feed_category_not_found": "Questa categoria non esiste o non appartiene a questo utente.", + "error.feed_invalid_blocklist_rule": "La regola dell'elenco di blocco non è valida.", + "error.feed_invalid_keeplist_rule": "La regola dell'elenco di conservazione non è valida.", "error.user_mandatory_fields": "Il nome utente è obbligatorio.", "error.api_key_already_exists": "Questa chiave API esiste già.", "error.unable_to_create_api_key": "Impossibile creare questa chiave API.", diff --git a/locale/translations/ja_JP.json b/locale/translations/ja_JP.json index 88512725..54d72214 100644 --- a/locale/translations/ja_JP.json +++ b/locale/translations/ja_JP.json @@ -244,6 +244,8 @@ "error.site_url_not_empty": "サイトのURLを空にすることはできません。", "error.feed_title_not_empty": "フィードのタイトルを空にすることはできません。", "error.feed_category_not_found": "このカテゴリは存在しないか、このユーザーに属していません。", + "error.feed_invalid_blocklist_rule": "ブロックリストルールが無効です。", + "error.feed_invalid_keeplist_rule": "リストの保持ルールが無効です。", "error.user_mandatory_fields": "ユーザー名が必要です。", "error.api_key_already_exists": "このAPIキーは既に存在します。", "error.unable_to_create_api_key": "このAPIキーを作成できません。", diff --git a/locale/translations/nl_NL.json b/locale/translations/nl_NL.json index 72cef0a0..800d04d8 100644 --- a/locale/translations/nl_NL.json +++ b/locale/translations/nl_NL.json @@ -244,6 +244,8 @@ "error.site_url_not_empty": "De site-URL mag niet leeg zijn.", "error.feed_title_not_empty": "De feedtitel mag niet leeg zijn.", "error.feed_category_not_found": "Deze categorie bestaat niet of behoort niet tot deze gebruiker.", + "error.feed_invalid_blocklist_rule": "De regel voor de blokkeerlijst is ongeldig.", + "error.feed_invalid_keeplist_rule": "De regel voor het bewaren van een lijst is ongeldig.", "error.user_mandatory_fields": "Gebruikersnaam is verplicht", "error.api_key_already_exists": "This API Key already exists.", "error.unable_to_create_api_key": "Kan deze API-sleutel niet maken.", diff --git a/locale/translations/pl_PL.json b/locale/translations/pl_PL.json index 3c90a1e3..2249e18b 100644 --- a/locale/translations/pl_PL.json +++ b/locale/translations/pl_PL.json @@ -246,6 +246,8 @@ "error.site_url_not_empty": "Adres URL witryny nie może być pusty.", "error.feed_title_not_empty": "Tytuł kanału nie może być pusty.", "error.feed_category_not_found": "Ta kategoria nie istnieje lub nie należy do tego użytkownika.", + "error.feed_invalid_blocklist_rule": "Reguła listy zablokowanych jest nieprawidłowa.", + "error.feed_invalid_keeplist_rule": "Reguła listy zachowania jest nieprawidłowa.", "error.user_mandatory_fields": "Nazwa użytkownika jest obowiązkowa.", "error.api_key_already_exists": "Deze API-sleutel bestaat al.", "error.unable_to_create_api_key": "Nie można utworzyć tego klucza API.", diff --git a/locale/translations/pt_BR.json b/locale/translations/pt_BR.json index 9c44a309..26cc1166 100644 --- a/locale/translations/pt_BR.json +++ b/locale/translations/pt_BR.json @@ -244,6 +244,8 @@ "error.site_url_not_empty": "O URL do site não pode estar vazio.", "error.feed_title_not_empty": "O título do feed não pode estar vazio.", "error.feed_category_not_found": "Esta categoria não existe ou não pertence a este usuário.", + "error.feed_invalid_blocklist_rule": "A regra da lista de bloqueio é inválida.", + "error.feed_invalid_keeplist_rule": "A regra de manutenção da lista é inválida.", "error.user_mandatory_fields": "O nome de usuário é obrigatório.", "error.api_key_already_exists": "Essa chave de API já existe.", "error.unable_to_create_api_key": "Não foi possível criar uma chave de API.", diff --git a/locale/translations/ru_RU.json b/locale/translations/ru_RU.json index a75e995d..c030f306 100644 --- a/locale/translations/ru_RU.json +++ b/locale/translations/ru_RU.json @@ -246,6 +246,8 @@ "error.site_url_not_empty": "URL сайта не может быть пустым.", "error.feed_title_not_empty": "Заголовок фида не может быть пустым.", "error.feed_category_not_found": "Эта категория не существует или не принадлежит этому пользователю.", + "error.feed_invalid_blocklist_rule": "Правило черного списка недействительно.", + "error.feed_invalid_keeplist_rule": "Правило списка хранения недействительно.", "error.user_mandatory_fields": "Имя пользователя обязательно.", "error.api_key_already_exists": "Этот ключ API уже существует.", "error.unable_to_create_api_key": "Невозможно создать этот ключ API.", diff --git a/locale/translations/zh_CN.json b/locale/translations/zh_CN.json index 39cacd41..5cb4c32f 100644 --- a/locale/translations/zh_CN.json +++ b/locale/translations/zh_CN.json @@ -242,6 +242,8 @@ "error.site_url_not_empty": "网站网址不能为空。", "error.feed_title_not_empty": "供稿标题不能为空。", "error.feed_category_not_found": "此类别不存在或不属于该用户。", + "error.feed_invalid_blocklist_rule": "阻止列表规则无效。", + "error.feed_invalid_keeplist_rule": "保留列表规则无效。", "error.user_mandatory_fields": "必须填写用户名", "error.api_key_already_exists": "此API密钥已存在。", "error.unable_to_create_api_key": "无法创建此API密钥。", diff --git a/tests/feed_test.go b/tests/feed_test.go index f1fdad1d..5400d221 100644 --- a/tests/feed_test.go +++ b/tests/feed_test.go @@ -202,6 +202,55 @@ func TestCreateFeedWithScraperRule(t *testing.T) { } } +func TestCreateFeedWithKeeplistRule(t *testing.T) { + client := createClient(t) + + categories, err := client.Categories() + if err != nil { + t.Fatal(err) + } + + feedID, err := client.CreateFeed(&miniflux.FeedCreationRequest{ + FeedURL: testFeedURL, + CategoryID: categories[0].ID, + KeeplistRules: "(?i)miniflux", + }) + if err != nil { + t.Fatal(err) + } + + if feedID == 0 { + t.Fatalf(`Invalid feed ID, got %q`, feedID) + } + + feed, err := client.Feed(feedID) + if err != nil { + t.Fatal(err) + } + + if feed.KeeplistRules != "(?i)miniflux" { + t.Error(`The feed should have the custom keep list rule saved`) + } +} + +func TestCreateFeedWithInvalidBlocklistRule(t *testing.T) { + client := createClient(t) + + categories, err := client.Categories() + if err != nil { + t.Fatal(err) + } + + _, err = client.CreateFeed(&miniflux.FeedCreationRequest{ + FeedURL: testFeedURL, + CategoryID: categories[0].ID, + BlocklistRules: "[", + }) + if err == nil { + t.Fatal(`Feed with invalid block list rule should not be created`) + } +} + func TestUpdateFeedURL(t *testing.T) { client := createClient(t) feed, _ := createFeed(t, client) diff --git a/ui/feed_update.go b/ui/feed_update.go index fb5aeee9..e54e58f9 100644 --- a/ui/feed_update.go +++ b/ui/feed_update.go @@ -58,10 +58,12 @@ func (h *handler) updateFeed(w http.ResponseWriter, r *http.Request) { view.Set("defaultUserAgent", config.Opts.HTTPClientUserAgent()) feedModificationRequest := &model.FeedModificationRequest{ - FeedURL: model.OptionalString(feedForm.FeedURL), - SiteURL: model.OptionalString(feedForm.SiteURL), - Title: model.OptionalString(feedForm.Title), - CategoryID: model.OptionalInt64(feedForm.CategoryID), + FeedURL: model.OptionalString(feedForm.FeedURL), + SiteURL: model.OptionalString(feedForm.SiteURL), + Title: model.OptionalString(feedForm.Title), + CategoryID: model.OptionalInt64(feedForm.CategoryID), + BlocklistRules: model.OptionalString(feedForm.BlocklistRules), + KeeplistRules: model.OptionalString(feedForm.KeeplistRules), } if validationErr := validator.ValidateFeedModification(h.store, loggedUser.ID, feedModificationRequest); validationErr != nil { diff --git a/ui/form/subscription.go b/ui/form/subscription.go index 40f6dbb0..73967c24 100644 --- a/ui/form/subscription.go +++ b/ui/form/subscription.go @@ -9,6 +9,7 @@ import ( "strconv" "miniflux.app/errors" + "miniflux.app/validator" ) // SubscriptionForm represents the subscription form. @@ -32,6 +33,18 @@ func (s *SubscriptionForm) Validate() error { return errors.NewLocalizedError("error.feed_mandatory_fields") } + if !validator.IsValidURL(s.URL) { + return errors.NewLocalizedError("error.invalid_feed_url") + } + + if !validator.IsValidRegex(s.BlocklistRules) { + return errors.NewLocalizedError("error.feed_invalid_blocklist_rule") + } + + if !validator.IsValidRegex(s.KeeplistRules) { + return errors.NewLocalizedError("error.feed_invalid_keeplist_rule") + } + return nil } diff --git a/validator/feed.go b/validator/feed.go index 3c14d424..614b688e 100644 --- a/validator/feed.go +++ b/validator/feed.go @@ -15,7 +15,7 @@ func ValidateFeedCreation(store *storage.Storage, userID int64, request *model.F return NewValidationError("error.feed_mandatory_fields") } - if !isValidURL(request.FeedURL) { + if !IsValidURL(request.FeedURL) { return NewValidationError("error.invalid_feed_url") } @@ -27,6 +27,14 @@ func ValidateFeedCreation(store *storage.Storage, userID int64, request *model.F return NewValidationError("error.feed_category_not_found") } + if !IsValidRegex(request.BlocklistRules) { + return NewValidationError("error.feed_invalid_blocklist_rule") + } + + if !IsValidRegex(request.KeeplistRules) { + return NewValidationError("error.feed_invalid_keeplist_rule") + } + return nil } @@ -37,7 +45,7 @@ func ValidateFeedModification(store *storage.Storage, userID int64, request *mod return NewValidationError("error.feed_url_not_empty") } - if !isValidURL(*request.FeedURL) { + if !IsValidURL(*request.FeedURL) { return NewValidationError("error.invalid_feed_url") } } @@ -47,7 +55,7 @@ func ValidateFeedModification(store *storage.Storage, userID int64, request *mod return NewValidationError("error.site_url_not_empty") } - if !isValidURL(*request.SiteURL) { + if !IsValidURL(*request.SiteURL) { return NewValidationError("error.invalid_site_url") } } @@ -64,5 +72,17 @@ func ValidateFeedModification(store *storage.Storage, userID int64, request *mod } } + if request.BlocklistRules != nil { + if !IsValidRegex(*request.BlocklistRules) { + return NewValidationError("error.feed_invalid_blocklist_rule") + } + } + + if request.KeeplistRules != nil { + if !IsValidRegex(*request.KeeplistRules) { + return NewValidationError("error.feed_invalid_keeplist_rule") + } + } + return nil } diff --git a/validator/subscription.go b/validator/subscription.go index 6d1cc9c9..a907f4fe 100644 --- a/validator/subscription.go +++ b/validator/subscription.go @@ -8,7 +8,7 @@ import "miniflux.app/model" // ValidateSubscriptionDiscovery validates subscription discovery requests. func ValidateSubscriptionDiscovery(request *model.SubscriptionDiscoveryRequest) *ValidationError { - if !isValidURL(request.URL) { + if !IsValidURL(request.URL) { return NewValidationError("error.invalid_site_url") } diff --git a/validator/validator.go b/validator/validator.go index 0a711324..5ebaef88 100644 --- a/validator/validator.go +++ b/validator/validator.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "net/url" + "regexp" "miniflux.app/locale" ) @@ -53,7 +54,14 @@ func ValidateDirection(direction string) error { return fmt.Errorf(`Invalid direction, valid direction values are: "asc" or "desc"`) } -func isValidURL(absoluteURL string) bool { +// IsValidRegex verifies if the regex can be compiled. +func IsValidRegex(expr string) bool { + _, err := regexp.Compile(expr) + return err == nil +} + +// IsValidURL verifies if the provided value is a valid absolute URL. +func IsValidURL(absoluteURL string) bool { _, err := url.ParseRequestURI(absoluteURL) return err == nil } diff --git a/validator/validator_test.go b/validator/validator_test.go index 5e3cf76b..6f26f660 100644 --- a/validator/validator_test.go +++ b/validator/validator_test.go @@ -14,7 +14,7 @@ func TestIsValidURL(t *testing.T) { } for link, expected := range scenarios { - result := isValidURL(link) + result := IsValidURL(link) if result != expected { t.Errorf(`Unexpected result, got %v instead of %v`, result, expected) } @@ -46,3 +46,17 @@ func TestValidateDirection(t *testing.T) { t.Error(`An invalid direction should generate a error`) } } + +func TestIsValidRegex(t *testing.T) { + scenarios := map[string]bool{ + "(?i)miniflux": true, + "[": false, + } + + for expr, expected := range scenarios { + result := IsValidRegex(expr) + if result != expected { + t.Errorf(`Unexpected result, got %v instead of %v`, result, expected) + } + } +}