From 56fbb82cb004fb6f8689ee7f50be05d6a927f9f1 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Tue, 21 Feb 2012 12:36:29 +0400 Subject: [PATCH] properly handle invalid regular expressions supplied when testing filters, add some additional regexp checks (closes #427) --- classes/pref_filters.php | 78 +++++++++++++++------------- include/functions.php | 107 +++++++++++++++++++++------------------ js/functions.js | 42 +++++++++++---- tt-rss.css | 4 ++ 4 files changed, 136 insertions(+), 95 deletions(-) diff --git a/classes/pref_filters.php b/classes/pref_filters.php index c66e9e810..9b8c295ff 100644 --- a/classes/pref_filters.php +++ b/classes/pref_filters.php @@ -33,55 +33,65 @@ class Pref_Filters extends Protected_Handler { else $feed = -4; - $feed_title = getFeedTitle($this->link, $feed); - - $qfh_ret = queryFeedHeadlines($this->link, $cat_filter ? $cat_id : $feed, - 30, "", $cat_filter, false, false, - false, "date_entered DESC", 0, $_SESSION["uid"], $filter); - - $result = $qfh_ret[0]; - - $articles = array(); - $found = 0; + $regexp_valid = preg_match('/' . $filter['reg_exp'] . '/', + $filter['reg_exp']) !== FALSE; print __("Articles matching this filter:"); print "
"; print ""; - while ($line = db_fetch_assoc($result)) { + if ($regexp_valid) { - $entry_timestamp = strtotime($line["updated"]); - $entry_tags = get_article_tags($this->link, $line["id"], $_SESSION["uid"]); + $feed_title = getFeedTitle($this->link, $feed); - $content_preview = truncate_string( - strip_tags($line["content_preview"]), 100, '...'); + $qfh_ret = queryFeedHeadlines($this->link, $cat_filter ? $cat_id : $feed, + 30, "", $cat_filter, false, false, + false, "date_entered DESC", 0, $_SESSION["uid"], $filter); - if ($line["feed_title"]) - $feed_title = $line["feed_title"]; + $result = $qfh_ret[0]; - print ""; + $articles = array(); + $found = 0; - print ""; - print ""; + $content_preview = truncate_string( + strip_tags($line["content_preview"]), 100, '...'); - $found++; - } + if ($line["feed_title"]) + $feed_title = $line["feed_title"]; + + print ""; + + print ""; + print ""; + + $found++; + } + + if ($found == 0) { + print ""; + } + } else { + print ""; - if ($found == 0) { - print ""; } print "
"; + while ($line = db_fetch_assoc($result)) { - print $line["title"]; - print " ("; - print "" . $feed_title . ""; - print "): "; - print "" . $content_preview . ""; - print " " . mb_substr($line["date_entered"], 0, 16); + $entry_timestamp = strtotime($line["updated"]); + $entry_tags = get_article_tags($this->link, $line["id"], $_SESSION["uid"]); - print "
"; + + print $line["title"]; + print " ("; + print "" . $feed_title . ""; + print "): "; + print "" . $content_preview . ""; + print " " . mb_substr($line["date_entered"], 0, 16); + + print "
" . + __("No articles matching this filter has been found.") . "
" . + __("Invalid regular expression.") . "
" . - __("No articles matching this filter has been found.") . "
"; diff --git a/include/functions.php b/include/functions.php index 25c188ee6..dc5cbc816 100644 --- a/include/functions.php +++ b/include/functions.php @@ -4973,63 +4973,70 @@ function filter_to_sql($filter) { $query = ""; - if (DB_TYPE == "pgsql") - $reg_qpart = "~"; - else - $reg_qpart = "REGEXP"; + $regexp_valid = preg_match('/' . $filter['reg_exp'] . '/', + $filter['reg_exp']) !== FALSE; - switch ($filter["type"]) { - case "title": - $query = "LOWER(ttrss_entries.title) $reg_qpart LOWER('". - $filter['reg_exp'] . "')"; - break; - case "content": - $query = "LOWER(ttrss_entries.content) $reg_qpart LOWER('". - $filter['reg_exp'] . "')"; - break; - case "both": - $query = "LOWER(ttrss_entries.title) $reg_qpart LOWER('". - $filter['reg_exp'] . "') OR LOWER(" . - "ttrss_entries.content) $reg_qpart LOWER('" . $filter['reg_exp'] . "')"; - break; - case "tag": - $query = "LOWER(ttrss_user_entries.tag_cache) $reg_qpart LOWER('". - $filter['reg_exp'] . "')"; - break; - case "link": - $query = "LOWER(ttrss_entries.link) $reg_qpart LOWER('". - $filter['reg_exp'] . "')"; - break; - case "date": + if ($regexp_valid) { - if ($filter["filter_param"] == "before") - $cmp_qpart = "<"; - else - $cmp_qpart = ">="; + if (DB_TYPE == "pgsql") + $reg_qpart = "~"; + else + $reg_qpart = "REGEXP"; - $timestamp = date("Y-m-d H:N:s", strtotime($filter["reg_exp"])); - $query = "ttrss_entries.date_entered $cmp_qpart '$timestamp'"; - break; - case "author": - $query = "LOWER(ttrss_entries.author) $reg_qpart LOWER('". - $filter['reg_exp'] . "')"; - break; - } + switch ($filter["type"]) { + case "title": + $query = "LOWER(ttrss_entries.title) $reg_qpart LOWER('". + $filter['reg_exp'] . "')"; + break; + case "content": + $query = "LOWER(ttrss_entries.content) $reg_qpart LOWER('". + $filter['reg_exp'] . "')"; + break; + case "both": + $query = "LOWER(ttrss_entries.title) $reg_qpart LOWER('". + $filter['reg_exp'] . "') OR LOWER(" . + "ttrss_entries.content) $reg_qpart LOWER('" . $filter['reg_exp'] . "')"; + break; + case "tag": + $query = "LOWER(ttrss_user_entries.tag_cache) $reg_qpart LOWER('". + $filter['reg_exp'] . "')"; + break; + case "link": + $query = "LOWER(ttrss_entries.link) $reg_qpart LOWER('". + $filter['reg_exp'] . "')"; + break; + case "date": - if ($filter["inverse"]) - $query = "NOT ($query)"; + if ($filter["filter_param"] == "before") + $cmp_qpart = "<"; + else + $cmp_qpart = ">="; - if ($query) { - if (DB_TYPE == "pgsql") { - $query = " ($query) AND ttrss_entries.date_entered > NOW() - INTERVAL '14 days'"; - } else { - $query = " ($query) AND ttrss_entries.date_entered > DATE_SUB(NOW(), INTERVAL 14 DAY)"; + $timestamp = date("Y-m-d H:N:s", strtotime($filter["reg_exp"])); + $query = "ttrss_entries.date_entered $cmp_qpart '$timestamp'"; + break; + case "author": + $query = "LOWER(ttrss_entries.author) $reg_qpart LOWER('". + $filter['reg_exp'] . "')"; + break; } - $query .= " AND "; + + if ($filter["inverse"]) + $query = "NOT ($query)"; + + if ($query) { + if (DB_TYPE == "pgsql") { + $query = " ($query) AND ttrss_entries.date_entered > NOW() - INTERVAL '14 days'"; + } else { + $query = " ($query) AND ttrss_entries.date_entered > DATE_SUB(NOW(), INTERVAL 14 DAY)"; + } + $query .= " AND "; + } + + return $query; + } else { + return false; } - - - return $query; } // Status codes: diff --git a/js/functions.js b/js/functions.js index bd0d5fb73..4a4602f9e 100644 --- a/js/functions.js +++ b/js/functions.js @@ -982,19 +982,39 @@ function quickAddFilter() { test: function() { if (this.validate()) { - if (dijit.byId("filterTestDlg")) - dijit.byId("filterTestDlg").destroyRecursive(); + var query = "?op=rpc&method=verifyRegexp®_exp=" + + param_escape(dialog.attr('value').reg_exp); - tdialog = new dijit.Dialog({ - id: "filterTestDlg", - title: __("Filter Test Results"), - style: "width: 600px", - href: "backend.php?savemode=test&" + - dojo.objectToQuery(dialog.attr('value')), - }); + notify_progress("Verifying regular expression..."); - tdialog.show(); + new Ajax.Request("backend.php", { + parameters: query, + onComplete: function(transport) { + var reply = JSON.parse(transport.responseText); + if (reply) { + notify(''); + + if (!reply['status']) { + alert("Invalid regular expression."); + return; + } else { + + if (dijit.byId("filterTestDlg")) + dijit.byId("filterTestDlg").destroyRecursive(); + + tdialog = new dijit.Dialog({ + id: "filterTestDlg", + title: __("Filter Test Results"), + style: "width: 600px", + href: "backend.php?savemode=test&" + + dojo.objectToQuery(dialog.attr('value')), + }); + + tdialog.show(); + } + } + }}); } }, execute: function() { @@ -1014,7 +1034,7 @@ function quickAddFilter() { notify(''); if (!reply['status']) { - alert("Match regular expression seems to be invalid."); + alert("Invalid regular expression."); return; } else { notify_progress("Saving data...", true); diff --git a/tt-rss.css b/tt-rss.css index 94aa75874..7a0ef8bbb 100644 --- a/tt-rss.css +++ b/tt-rss.css @@ -1407,3 +1407,7 @@ a.bookmarklet { padding : 1em; color : gray; } + +td.error { + color : red; +}