From cbcb10a272ef8c46360da301e1bbbd4979d6f106 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Tue, 15 Sep 2020 16:28:09 +0300 Subject: [PATCH] Feeds: load quickaddfeed and search dialogs via XHR w/ CSRF protection --- classes/feeds.php | 2 +- js/CommonDialogs.js | 184 ++++++++++++++++++++++---------------------- js/Feeds.js | 65 ++++++++-------- 3 files changed, 129 insertions(+), 122 deletions(-) diff --git a/classes/feeds.php b/classes/feeds.php index 71890f6ab..b3c73a58d 100755 --- a/classes/feeds.php +++ b/classes/feeds.php @@ -8,7 +8,7 @@ class Feeds extends Handler_Protected { private $params; function csrf_ignore($method) { - $csrf_ignored = array("index", "quickaddfeed", "search"); + $csrf_ignored = array("index"); return array_search($method, $csrf_ignored) !== false; } diff --git a/js/CommonDialogs.js b/js/CommonDialogs.js index d3ad35161..ab72b3b9c 100644 --- a/js/CommonDialogs.js +++ b/js/CommonDialogs.js @@ -75,116 +75,120 @@ const CommonDialogs = { return false; }, quickAddFeed: function() { - const query = "backend.php?op=feeds&method=quickAddFeed"; // overlapping widgets if (dijit.byId("batchSubDlg")) dijit.byId("batchSubDlg").destroyRecursive(); if (dijit.byId("feedAddDlg")) dijit.byId("feedAddDlg").destroyRecursive(); - const dialog = new dijit.Dialog({ - id: "feedAddDlg", - title: __("Subscribe to Feed"), - style: "width: 600px", - show_error: function (msg) { - const elem = $("fadd_error_message"); + xhrPost("backend.php", + {op: "feeds", method: "quickAddFeed"}, + (transport) => { - elem.innerHTML = msg; + const dialog = new dijit.Dialog({ + id: "feedAddDlg", + title: __("Subscribe to Feed"), + style: "width: 600px", + content: transport.responseText, + show_error: function (msg) { + const elem = $("fadd_error_message"); - if (!Element.visible(elem)) - new Effect.Appear(elem); + elem.innerHTML = msg; - }, - execute: function () { - if (this.validate()) { - console.log(dojo.objectToQuery(this.attr('value'))); + if (!Element.visible(elem)) + new Effect.Appear(elem); - const feed_url = this.attr('value').feed; + }, + execute: function () { + if (this.validate()) { + console.log(dojo.objectToQuery(this.attr('value'))); - Element.show("feed_add_spinner"); - Element.hide("fadd_error_message"); + const feed_url = this.attr('value').feed; - xhrPost("backend.php", this.attr('value'), (transport) => { - try { + Element.show("feed_add_spinner"); + Element.hide("fadd_error_message"); - let reply; + xhrPost("backend.php", this.attr('value'), (transport) => { + try { - try { - reply = JSON.parse(transport.responseText); - } catch (e) { - Element.hide("feed_add_spinner"); - alert(__("Failed to parse output. This can indicate server timeout and/or network issues. Backend output was logged to browser console.")); - console.log('quickAddFeed, backend returned:' + transport.responseText); - return; - } + let reply; - const rc = reply['result']; - - Notify.close(); - Element.hide("feed_add_spinner"); - - console.log(rc); - - switch (parseInt(rc['code'])) { - case 1: - dialog.hide(); - Notify.info(__("Subscribed to %s").replace("%s", feed_url)); - - if (App.isPrefs()) - dijit.byId("feedTree").reload(); - else - Feeds.reload(); - - break; - case 2: - dialog.show_error(__("Specified URL seems to be invalid.")); - break; - case 3: - dialog.show_error(__("Specified URL doesn't seem to contain any feeds.")); - break; - case 4: - { - const feeds = rc['feeds']; - - Element.show("fadd_multiple_notify"); - - const select = dijit.byId("feedDlg_feedContainerSelect"); - - while (select.getOptions().length > 0) - select.removeOption(0); - - select.addOption({value: '', label: __("Expand to select feed")}); - - for (const feedUrl in feeds) { - if (feeds.hasOwnProperty(feedUrl)) { - select.addOption({value: feedUrl, label: feeds[feedUrl]}); - } + try { + reply = JSON.parse(transport.responseText); + } catch (e) { + Element.hide("feed_add_spinner"); + alert(__("Failed to parse output. This can indicate server timeout and/or network issues. Backend output was logged to browser console.")); + console.log('quickAddFeed, backend returned:' + transport.responseText); + return; } - Effect.Appear('feedDlg_feedsContainer', {duration: 0.5}); + const rc = reply['result']; + + Notify.close(); + Element.hide("feed_add_spinner"); + + console.log(rc); + + switch (parseInt(rc['code'])) { + case 1: + dialog.hide(); + Notify.info(__("Subscribed to %s").replace("%s", feed_url)); + + if (App.isPrefs()) + dijit.byId("feedTree").reload(); + else + Feeds.reload(); + + break; + case 2: + dialog.show_error(__("Specified URL seems to be invalid.")); + break; + case 3: + dialog.show_error(__("Specified URL doesn't seem to contain any feeds.")); + break; + case 4: + { + const feeds = rc['feeds']; + + Element.show("fadd_multiple_notify"); + + const select = dijit.byId("feedDlg_feedContainerSelect"); + + while (select.getOptions().length > 0) + select.removeOption(0); + + select.addOption({value: '', label: __("Expand to select feed")}); + + for (const feedUrl in feeds) { + if (feeds.hasOwnProperty(feedUrl)) { + select.addOption({value: feedUrl, label: feeds[feedUrl]}); + } + } + + Effect.Appear('feedDlg_feedsContainer', {duration: 0.5}); + } + break; + case 5: + dialog.show_error(__("Couldn't download the specified URL: %s").replace("%s", rc['message'])); + break; + case 6: + dialog.show_error(__("XML validation failed: %s").replace("%s", rc['message'])); + break; + case 0: + dialog.show_error(__("You are already subscribed to this feed.")); + break; + } + + } catch (e) { + console.error(transport.responseText); + App.Error.report(e); } - break; - case 5: - dialog.show_error(__("Couldn't download the specified URL: %s").replace("%s", rc['message'])); - break; - case 6: - dialog.show_error(__("XML validation failed: %s").replace("%s", rc['message'])); - break; - case 0: - dialog.show_error(__("You are already subscribed to this feed.")); - break; + }); } - - } catch (e) { - console.error(transport.responseText); - App.Error.report(e); - } + }, }); - } - }, - href: query - }); - dialog.show(); + dialog.show(); + }); }, showFeedsWithErrors: function() { const query = {op: "pref-feeds", method: "feedsWithErrors"}; diff --git a/js/Feeds.js b/js/Feeds.js index a12021566..49b5e0c2d 100644 --- a/js/Feeds.js +++ b/js/Feeds.js @@ -552,47 +552,50 @@ const Feeds = { return tree.model.store.getValue(nuf, 'bare_id'); }, search: function() { - const query = "backend.php?op=feeds&method=search¶m=" + - encodeURIComponent(Feeds.getActive() + ":" + Feeds.activeIsCat()); - if (dijit.byId("searchDlg")) dijit.byId("searchDlg").destroyRecursive(); - const dialog = new dijit.Dialog({ - id: "searchDlg", - title: __("Search"), - style: "width: 600px", - execute: function () { - if (this.validate()) { - Feeds._search_query = this.attr('value'); + xhrPost("backend.php", + {op: "feeds", method: "search", + param: Feeds.getActive() + ":" + Feeds.activeIsCat()}, + (transport) => { + const dialog = new dijit.Dialog({ + id: "searchDlg", + content: transport.responseText, + title: __("Search"), + style: "width: 600px", + execute: function () { + if (this.validate()) { + Feeds._search_query = this.attr('value'); - // disallow empty queries - if (!Feeds._search_query.query) - Feeds._search_query = false; + // disallow empty queries + if (!Feeds._search_query.query) + Feeds._search_query = false; - this.hide(); - Feeds.reloadCurrent(); - } - }, - href: query - }); + this.hide(); + Feeds.reloadCurrent(); + } + }, + }); - const tmph = dojo.connect(dialog, 'onLoad', function () { - dojo.disconnect(tmph); + const tmph = dojo.connect(dialog, 'onLoad', function () { + dojo.disconnect(tmph); - if (Feeds._search_query) { - if (Feeds._search_query.query) - dijit.byId('search_query') - .attr('value', Feeds._search_query.query); + if (Feeds._search_query) { + if (Feeds._search_query.query) + dijit.byId('search_query') + .attr('value', Feeds._search_query.query); - if (Feeds._search_query.search_language) - dijit.byId('search_language') - .attr('value', Feeds._search_query.search_language); - } + if (Feeds._search_query.search_language) + dijit.byId('search_language') + .attr('value', Feeds._search_query.search_language); + } - }); + }); + + dialog.show(); + }); - dialog.show(); }, updateRandom: function() { console.log("in update_random_feed");