summaryrefslogtreecommitdiff
path: root/classes/pref
diff options
context:
space:
mode:
Diffstat (limited to 'classes/pref')
-rwxr-xr-xclasses/pref/feeds.php27
-rwxr-xr-xclasses/pref/filters.php55
-rw-r--r--classes/pref/prefs.php122
-rw-r--r--classes/pref/users.php23
4 files changed, 155 insertions, 72 deletions
diff --git a/classes/pref/feeds.php b/classes/pref/feeds.php
index 6d7295beb..4ff6ac9c2 100755
--- a/classes/pref/feeds.php
+++ b/classes/pref/feeds.php
@@ -449,7 +449,7 @@ class Pref_Feeds extends Handler_Protected {
if ($row = $sth->fetch()) {
@unlink(ICONS_DIR . "/$feed_id.ico");
- $sth = $this->pdo->prepare("UPDATE ttrss_feeds SET favicon_avg_color = NULL
+ $sth = $this->pdo->prepare("UPDATE ttrss_feeds SET favicon_avg_color = NULL, favicon_last_checked = '1970-01-01'
where id = ?");
$sth->execute([$feed_id]);
}
@@ -554,7 +554,7 @@ class Pref_Feeds extends Handler_Protected {
$last_error = $row["last_error"];
if ($last_error) {
- print "&nbsp;<i class=\"material-icons\"
+ print "&nbsp;<i class=\"material-icons\"
title=\"".htmlspecialchars($last_error)."\">error</i>";
}
@@ -676,7 +676,7 @@ class Pref_Feeds extends Handler_Protected {
$auth_checked = $auth_enabled ? 'checked' : '';
print "<label class='checkbox'>
<input type='checkbox' $auth_checked name='need_auth' dojoType='dijit.form.CheckBox' id='feedEditDlg_loginCheck'
- onclick='displayIfChecked(this, \"feedEditDlg_loginContainer\")'>
+ onclick='App.displayIfChecked(this, \"feedEditDlg_loginContainer\")'>
".__('This feed requires authentication.')."</label>";
print '</div><div dojoType="dijit.layout.ContentPane" title="'.__('Options').'">';
@@ -772,6 +772,7 @@ class Pref_Feeds extends Handler_Protected {
<input style='display: none' id='icon_file' size='10' name='icon_file' type='file'>
</label>
<input type='hidden' name='op' value='pref-feeds'>
+ <input type='hidden' name='csrf_token' value='".$_SESSION['csrf_token']."'>
<input type='hidden' name='feed_id' value='$feed_id'>
<input type='hidden' name='method' value='uploadicon'>
<button dojoType='dijit.form.Button' onclick=\"return CommonDialogs.uploadFeedIcon();\"
@@ -1172,7 +1173,7 @@ class Pref_Feeds extends Handler_Protected {
function index() {
print "<div dojoType='dijit.layout.AccordionContainer' region='center'>";
- print "<div style='padding : 0px' dojoType='dijit.layout.AccordionPane'
+ print "<div style='padding : 0px' dojoType='dijit.layout.AccordionPane'
title=\"<i class='material-icons'>rss_feed</i> ".__('Feeds')."\">";
$sth = $this->pdo->prepare("SELECT COUNT(id) AS num_errors
@@ -1307,7 +1308,7 @@ class Pref_Feeds extends Handler_Protected {
print "</div>"; # feeds pane
- print "<div dojoType='dijit.layout.AccordionPane'
+ print "<div dojoType='dijit.layout.AccordionPane'
title='<i class=\"material-icons\">import_export</i> ".__('OPML')."'>";
print "<h3>" . __("Using OPML you can export and import your feeds, filters, labels and Tiny Tiny RSS settings.") . "</h3>";
@@ -1325,6 +1326,7 @@ class Pref_Feeds extends Handler_Protected {
<input style='display : none' id='opml_file' name='opml_file' type='file'>&nbsp;
</label>
<input type='hidden' name='op' value='dlg'>
+ <input type='hidden' name='csrf_token' value='".$_SESSION['csrf_token']."'>
<input type='hidden' name='method' value='importOpml'>
<button dojoType='dijit.form.Button' class='alt-primary' onclick=\"return Helpers.OPML.import();\" type=\"submit\">" .
__('Import OPML') . "</button>";
@@ -1360,7 +1362,7 @@ class Pref_Feeds extends Handler_Protected {
print "</div>"; # pane
- print "<div dojoType=\"dijit.layout.AccordionPane\"
+ print "<div dojoType=\"dijit.layout.AccordionPane\"
title=\"<i class='material-icons'>share</i> ".__('Published & shared articles / Generated feeds')."\">";
print "<h3>" . __('Published articles can be subscribed by anyone who knows the following URL:') . "</h3>";
@@ -1637,6 +1639,8 @@ class Pref_Feeds extends Handler_Protected {
}
function batchSubscribe() {
+ print "<form onsubmit='return false'>";
+
print_hidden("op", "pref-feeds");
print_hidden("method", "batchaddfeeds");
@@ -1645,7 +1649,7 @@ class Pref_Feeds extends Handler_Protected {
print "<textarea
style='font-size : 12px; width : 98%; height: 200px;'
- dojoType='dijit.form.SimpleTextarea' name='feeds'></textarea>";
+ dojoType='fox.form.ValidationTextArea' required='1' name='feeds'></textarea>";
if (get_pref('ENABLE_FEED_CATS')) {
print "<fieldset>";
@@ -1670,14 +1674,17 @@ class Pref_Feeds extends Handler_Protected {
print "<fieldset class='narrow'>
<label class='checkbox'><input type='checkbox' name='need_auth' dojoType='dijit.form.CheckBox'
- onclick='displayIfChecked(this, \"feedDlg_loginContainer\")'> ".
+ onclick='App.displayIfChecked(this, \"feedDlg_loginContainer\")'> ".
__('Feeds require authentication.')."</label></div>";
print "</fieldset>";
print "<footer>
- <button dojoType='dijit.form.Button' type='submit' class='alt-primary'>".__('Subscribe')."</button>
+ <button dojoType='dijit.form.Button' onclick=\"return dijit.byId('batchSubDlg').execute()\" type='submit' class='alt-primary'>".
+ __('Subscribe')."</button>
<button dojoType='dijit.form.Button' onclick=\"return dijit.byId('batchSubDlg').hide()\">".__('Cancel')."</button>
</footer>";
+
+ print "</form>";
}
function batchAddFeeds() {
@@ -1696,7 +1703,7 @@ class Pref_Feeds extends Handler_Protected {
foreach ($feeds as $feed) {
$feed = trim($feed);
- if (Feeds::validate_feed_url($feed)) {
+ if (UrlHelper::validate($feed)) {
$this->pdo->beginTransaction();
diff --git a/classes/pref/filters.php b/classes/pref/filters.php
index a3a0ce77f..6121e4c14 100755
--- a/classes/pref/filters.php
+++ b/classes/pref/filters.php
@@ -3,7 +3,7 @@ class Pref_Filters extends Handler_Protected {
function csrf_ignore($method) {
$csrf_ignored = array("index", "getfiltertree", "edit", "newfilter", "newrule",
- "newaction", "savefilterorder");
+ "newaction", "savefilterorder", "testfilterdlg");
return array_search($method, $csrf_ignored) !== false;
}
@@ -159,22 +159,19 @@ class Pref_Filters extends Handler_Protected {
print json_encode($rv);
}
- function testFilter() {
+ function testFilterDlg() {
+ ?>
+ <div>
+ <img id='prefFilterLoadingIndicator' src='images/indicator_tiny.gif'>&nbsp;
+ <span id='prefFilterProgressMsg'>Looking for articles...</span>
+ </div>
- if (isset($_REQUEST["offset"])) return $this->testFilterDo();
-
- //print __("Articles matching this filter:");
-
- print "<div><img id='prefFilterLoadingIndicator' src='images/indicator_tiny.gif'>&nbsp;<span id='prefFilterProgressMsg'>Looking for articles...</span></div>";
-
- print "<ul class='panel panel-scrollable list list-unstyled' id='prefFilterTestResultList'>";
- print "</ul>";
-
- print "<footer class='text-center'>";
- print "<button dojoType='dijit.form.Button' onclick=\"dijit.byId('filterTestDlg').hide()\">".
- __('Close this window')."</button>";
- print "</footer>";
+ <ul class='panel panel-scrollable list list-unstyled' id='prefFilterTestResultList'></ul>
+ <footer class='text-center'>
+ <button dojoType='dijit.form.Button' onclick="dijit.byId('filterTestDlg').hide()"><?php echo __('Close this window') ?></button>
+ </footer>
+ <?php
}
private function getfilterrules_list($filter_id) {
@@ -241,6 +238,7 @@ class Pref_Filters extends Handler_Protected {
$root = array();
$root['id'] = 'root';
$root['name'] = __('Filters');
+ $root['enabled'] = true;
$root['items'] = array();
$filter_search = $_SESSION["prefs_filter_search"];
@@ -305,7 +303,7 @@ class Pref_Filters extends Handler_Protected {
$filter['param'] = $name[1];
$filter['checkbox'] = false;
$filter['last_triggered'] = $line["last_triggered"] ? make_local_datetime($line["last_triggered"], false) : null;
- $filter['enabled'] = $line["enabled"];
+ $filter['enabled'] = sql_bool_to_bool($line["enabled"]);
$filter['rules'] = $this->getfilterrules_list($line['id']);
if (!$filter_search || $match_ok) {
@@ -600,10 +598,6 @@ class Pref_Filters extends Handler_Protected {
}
function editSave() {
- if (clean($_REQUEST["savemode"] && $_REQUEST["savemode"]) == "test") {
- return $this->testFilter();
- }
-
$filter_id = clean($_REQUEST["id"]);
$enabled = checkbox_to_sql_bool(clean($_REQUEST["enabled"]));
$match_any_rule = checkbox_to_sql_bool(clean($_REQUEST["match_any_rule"]));
@@ -714,10 +708,6 @@ class Pref_Filters extends Handler_Protected {
}
function add() {
- if (clean($_REQUEST["savemode"] && $_REQUEST["savemode"]) == "test") {
- return $this->testFilter();
- }
-
$enabled = checkbox_to_sql_bool(clean($_REQUEST["enabled"]));
$match_any_rule = checkbox_to_sql_bool(clean($_REQUEST["match_any_rule"]));
$title = clean($_REQUEST["title"]);
@@ -975,19 +965,18 @@ class Pref_Filters extends Handler_Protected {
print "<section>";
- print "<input dojoType=\"dijit.form.ValidationTextBox\"
- required=\"true\" id=\"filterDlg_regExp\"
- onchange='Filters.filterDlgCheckRegExp(this)'
- onblur='Filters.filterDlgCheckRegExp(this)'
- onfocus='Filters.filterDlgCheckRegExp(this)'
- style=\"font-size : 16px; width : 500px\"
- name=\"reg_exp\" value=\"$reg_exp\"/>";
+ print "<textarea dojoType='fox.form.ValidationTextArea'
+ required='true' id='filterDlg_regExp'
+ ValidRegExp='true'
+ rows='4'
+ style='font-size : 14px; width : 490px; word-break: break-all'
+ name='reg_exp'>$reg_exp</textarea>";
print "<div dojoType='dijit.Tooltip' id='filterDlg_regExp_tip' connectId='filterDlg_regExp' position='below'></div>";
print "<fieldset>";
- print "<label class='checkbox'><input id=\"filterDlg_inverse\" dojoType=\"dijit.form.CheckBox\"
- name=\"inverse\" $inverse_checked/> ".
+ print "<label class='checkbox'><input id='filterDlg_inverse' dojoType='dijit.form.CheckBox'
+ name='inverse' $inverse_checked/> ".
__("Inverse regular expression matching")."</label>";
print "</fieldset>";
diff --git a/classes/pref/prefs.php b/classes/pref/prefs.php
index ac16b5971..f825454dd 100644
--- a/classes/pref/prefs.php
+++ b/classes/pref/prefs.php
@@ -8,7 +8,7 @@ class Pref_Prefs extends Handler_Protected {
private $profile_blacklist = [];
function csrf_ignore($method) {
- $csrf_ignored = array("index", "updateself", "customizecss", "editprefprofiles");
+ $csrf_ignored = array("index", "updateself", "customizecss", "editprefprofiles", "otpqrcode");
return array_search($method, $csrf_ignored) !== false;
}
@@ -125,8 +125,14 @@ class Pref_Prefs extends Handler_Protected {
$old_pw = clean($_POST["old_password"]);
$new_pw = clean($_POST["new_password"]);
+ $new_unclean_pw = $_POST["new_password"];
$con_pw = clean($_POST["confirm_password"]);
+ if ($new_unclean_pw != $new_pw) {
+ print "ERROR: ".format_error("New password contains disallowed characters.");
+ return;
+ }
+
if ($old_pw == $new_pw) {
print "ERROR: ".format_error("New password must be different from the old one.");
return;
@@ -213,11 +219,9 @@ class Pref_Prefs extends Handler_Protected {
if ($old_email != $email) {
$mailer = new Mailer();
- require_once "lib/MiniTemplator.class.php";
+ $tpl = new Templator();
- $tpl = new MiniTemplator;
-
- $tpl->readTemplateFromFile("templates/mail_change_template.txt");
+ $tpl->readTemplateFromFile("mail_change_template.txt");
$tpl->setVariable('LOGIN', $row["login"]);
$tpl->setVariable('NEWMAIL', $email);
@@ -253,7 +257,7 @@ class Pref_Prefs extends Handler_Protected {
AND owner_uid = :uid");
$sth->execute([":profile" => $_SESSION['profile'], ":uid" => $_SESSION['uid']]);
- initialize_user_prefs($_SESSION["uid"], $_SESSION["profile"]);
+ $this->initialize_user_prefs($_SESSION["uid"], $_SESSION["profile"]);
echo __("Your preferences are now set to default values.");
}
@@ -382,12 +386,12 @@ class Pref_Prefs extends Handler_Protected {
print "<fieldset>";
print "<label>" . __("New password:") . "</label>";
- print "<input dojoType='dijit.form.ValidationTextBox' type='password' required='1' name='new_password'>";
+ print "<input dojoType='dijit.form.ValidationTextBox' type='password' regexp='^[^<>]+' required='1' name='new_password'>";
print "</fieldset>";
print "<fieldset>";
print "<label>" . __("Confirm password:") . "</label>";
- print "<input dojoType='dijit.form.ValidationTextBox' type='password' required='1' name='confirm_password'>";
+ print "<input dojoType='dijit.form.ValidationTextBox' type='password' regexp='^[^<>]+' required='1' name='confirm_password'>";
print "</fieldset>";
print_hidden("op", "pref-prefs");
@@ -479,8 +483,8 @@ class Pref_Prefs extends Handler_Protected {
if (function_exists("imagecreatefromstring")) {
print "<h3>" . __("Scan the following code by the Authenticator application or copy the key manually") . "</h3>";
- $csrf_token = $_SESSION["csrf_token"];
- print "<img alt='otp qr-code' src='backend.php?op=pref-prefs&method=otpqrcode&csrf_token=$csrf_token'>";
+ $csrf_token_hash = sha1($_SESSION["csrf_token"]);
+ print "<img alt='otp qr-code' src='backend.php?op=pref-prefs&method=otpqrcode&csrf_token_hash=$csrf_token_hash'>";
} else {
print_error("PHP GD functions are required to generate QR codes.");
print "<h3>" . __("Use the following OTP key with a compatible Authenticator application") . "</h3>";
@@ -586,9 +590,9 @@ class Pref_Prefs extends Handler_Protected {
if ($profile) {
print_notice(__("Some preferences are only available in default profile."));
- initialize_user_prefs($_SESSION["uid"], $profile);
+ $this->initialize_user_prefs($_SESSION["uid"], $profile);
} else {
- initialize_user_prefs($_SESSION["uid"]);
+ $this->initialize_user_prefs($_SESSION["uid"]);
}
$prefs_available = [];
@@ -854,6 +858,10 @@ class Pref_Prefs extends Handler_Protected {
print_warning("Your PHP configuration has open_basedir restrictions enabled. Some plugins relying on CURL for functionality may not work correctly.");
}
+ if ($_SESSION["safe_mode"]) {
+ print_error("You have logged in using safe mode, no user plugins will be actually enabled until you login again.");
+ }
+
$feed_handler_whitelist = [ "Af_Comics" ];
$feed_handlers = array_merge(
@@ -862,7 +870,7 @@ class Pref_Prefs extends Handler_Protected {
PluginHost::getInstance()->get_hooks(PluginHost::HOOK_FETCH_FEED));
$feed_handlers = array_filter($feed_handlers, function($plugin) use ($feed_handler_whitelist) {
- return in_array(get_class($plugin), $feed_handler_whitelist) === FALSE; });
+ return in_array(get_class($plugin), $feed_handler_whitelist) === false; });
if (count($feed_handlers) > 0) {
print_error(
@@ -1006,21 +1014,28 @@ class Pref_Prefs extends Handler_Protected {
}
function otpqrcode() {
- require_once "lib/phpqrcode/phpqrcode.php";
+ $csrf_token_hash = clean($_REQUEST["csrf_token_hash"]);
- $sth = $this->pdo->prepare("SELECT login
- FROM ttrss_users
- WHERE id = ?");
- $sth->execute([$_SESSION['uid']]);
+ if (sha1($_SESSION["csrf_token"]) === $csrf_token_hash) {
+ require_once "lib/phpqrcode/phpqrcode.php";
- if ($row = $sth->fetch()) {
- $secret = $this->otpsecret();
- $login = $row['login'];
+ $sth = $this->pdo->prepare("SELECT login
+ FROM ttrss_users
+ WHERE id = ?");
+ $sth->execute([$_SESSION['uid']]);
- if ($secret) {
- QRcode::png("otpauth://totp/".urlencode($login).
- "?secret=$secret&issuer=".urlencode("Tiny Tiny RSS"));
+ if ($row = $sth->fetch()) {
+ $secret = $this->otpsecret();
+ $login = $row['login'];
+
+ if ($secret) {
+ QRcode::png("otpauth://totp/".urlencode($login).
+ "?secret=$secret&issuer=".urlencode("Tiny Tiny RSS"));
+ }
}
+ } else {
+ header("Content-Type: text/json");
+ print error_json(6);
}
}
@@ -1087,11 +1102,9 @@ class Pref_Prefs extends Handler_Protected {
if ($row = $sth->fetch()) {
$mailer = new Mailer();
- require_once "lib/MiniTemplator.class.php";
-
- $tpl = new MiniTemplator;
+ $tpl = new Templator();
- $tpl->readTemplateFromFile("templates/otp_disabled_template.txt");
+ $tpl->readTemplateFromFile("otp_disabled_template.txt");
$tpl->setVariable('LOGIN', $row["login"]);
$tpl->setVariable('TTRSS_HOST', SELF_URL_PATH);
@@ -1353,4 +1366,57 @@ class Pref_Prefs extends Handler_Protected {
$this->appPasswordList();
}
+
+ static function initialize_user_prefs($uid, $profile = false) {
+
+ if (get_schema_version() < 63) $profile_qpart = "";
+
+ $pdo = Db::pdo();
+ $in_nested_tr = false;
+
+ try {
+ $pdo->beginTransaction();
+ } catch (Exception $e) {
+ $in_nested_tr = true;
+ }
+
+ $sth = $pdo->query("SELECT pref_name,def_value FROM ttrss_prefs");
+
+ if (!is_numeric($profile) || !$profile || get_schema_version() < 63) $profile = null;
+
+ $u_sth = $pdo->prepare("SELECT pref_name
+ FROM ttrss_user_prefs WHERE owner_uid = :uid AND
+ (profile = :profile OR (:profile IS NULL AND profile IS NULL))");
+ $u_sth->execute([':uid' => $uid, ':profile' => $profile]);
+
+ $active_prefs = array();
+
+ while ($line = $u_sth->fetch()) {
+ array_push($active_prefs, $line["pref_name"]);
+ }
+
+ while ($line = $sth->fetch()) {
+ if (array_search($line["pref_name"], $active_prefs) === false) {
+// print "adding " . $line["pref_name"] . "<br>";
+
+ if (get_schema_version() < 63) {
+ $i_sth = $pdo->prepare("INSERT INTO ttrss_user_prefs
+ (owner_uid,pref_name,value) VALUES
+ (?, ?, ?)");
+ $i_sth->execute([$uid, $line["pref_name"], $line["def_value"]]);
+
+ } else {
+ $i_sth = $pdo->prepare("INSERT INTO ttrss_user_prefs
+ (owner_uid,pref_name,value, profile) VALUES
+ (?, ?, ?, ?)");
+ $i_sth->execute([$uid, $line["pref_name"], $line["def_value"], $profile]);
+ }
+
+ }
+ }
+
+ if (!$in_nested_tr) $pdo->commit();
+
+ }
+
}
diff --git a/classes/pref/users.php b/classes/pref/users.php
index 851d4fa9e..aeabc4502 100644
--- a/classes/pref/users.php
+++ b/classes/pref/users.php
@@ -259,7 +259,7 @@ class Pref_Users extends Handler_Protected {
print T_sprintf("Added user %s with password %s",
$login, $tmp_user_pwd);
- initialize_user($new_uid);
+ $this->initialize_user($new_uid);
} else {
@@ -443,4 +443,25 @@ class Pref_Users extends Handler_Protected {
return $default;
}
+ // this is called after user is created to initialize default feeds, labels
+ // or whatever else
+ // user preferences are checked on every login, not here
+ static function initialize_user($uid) {
+
+ $pdo = Db::pdo();
+
+ $sth = $pdo->prepare("insert into ttrss_feeds (owner_uid,title,feed_url)
+ values (?, 'Tiny Tiny RSS: Forum',
+ 'https://tt-rss.org/forum/rss.php')");
+ $sth->execute([$uid]);
+ }
+
+ static function logout_user() {
+ @session_destroy();
+ if (isset($_COOKIE[session_name()])) {
+ setcookie(session_name(), '', time()-42000, '/');
+ }
+ session_commit();
+ }
+
}