From 8bd4ad02fd797e53f3ca7bafba0f076b039f8f76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20P=C3=B5ldaru?= Date: Tue, 13 Mar 2012 02:58:30 +0200 Subject: [PATCH 01/12] Fixes traceback when sending # or ; from web remote search or alert field. Fixes: https://launchpad.net/bugs/908226 --- openlp/plugins/remotes/html/openlp.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/openlp/plugins/remotes/html/openlp.js b/openlp/plugins/remotes/html/openlp.js index 56c0c5859..8377912f8 100644 --- a/openlp/plugins/remotes/html/openlp.js +++ b/openlp/plugins/remotes/html/openlp.js @@ -208,9 +208,8 @@ window.OpenLP = { }, showAlert: function (event) { event.preventDefault(); - var text = "{\"request\": {\"text\": \"" + - $("#alert-text").val().replace(/\\/g, "\\\\").replace(/"/g, "\\\"") + - "\"}}"; + var alert = OpenLP.escapeString($("#alert-text").val()) + var text = "{\"request\": {\"text\": \"" + alert + "\"}}"; $.getJSON( "/api/alert", {"data": text}, @@ -221,9 +220,8 @@ window.OpenLP = { }, search: function (event) { event.preventDefault(); - var text = "{\"request\": {\"text\": \"" + - $("#search-text").val().replace(/\\/g, "\\\\").replace(/"/g, "\\\"") + - "\"}}"; + var query = OpenLP.escapeString($("#search-text").val()) + var text = "{\"request\": {\"text\": \"" + query + "\"}}"; $.getJSON( "/api/" + $("#search-plugin").val() + "/search", {"data": text}, @@ -280,6 +278,10 @@ window.OpenLP = { ); $("#options").dialog("close"); $.mobile.changePage("#service-manager"); + }, + escapeString: function (string) { + string = string.replace(/\\/g, "\\\\").replace(/"/g, "\\\"") + return string.replace(/#/g, "\\u0023").replace(/;/g, "\\u003B") } } // Service Manager From f7752255b0443b37357acd34b3fdc1487ca610db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20P=C3=B5ldaru?= Date: Tue, 13 Mar 2012 11:05:07 +0200 Subject: [PATCH 02/12] Encode characters using URL encoding not JSON unicode markup. --- openlp/plugins/remotes/html/openlp.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openlp/plugins/remotes/html/openlp.js b/openlp/plugins/remotes/html/openlp.js index 8377912f8..5c467d123 100644 --- a/openlp/plugins/remotes/html/openlp.js +++ b/openlp/plugins/remotes/html/openlp.js @@ -281,7 +281,8 @@ window.OpenLP = { }, escapeString: function (string) { string = string.replace(/\\/g, "\\\\").replace(/"/g, "\\\"") - return string.replace(/#/g, "\\u0023").replace(/;/g, "\\u003B") + string = string.replace(/#/g, "%23").replace(/;/g, "%3B") + return string } } // Service Manager From c599a1785d39db0f71d0fe284497925e39ee61df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20P=C3=B5ldaru?= Date: Tue, 13 Mar 2012 11:11:36 +0200 Subject: [PATCH 03/12] Make escaping function a one-liner. --- openlp/plugins/remotes/html/openlp.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openlp/plugins/remotes/html/openlp.js b/openlp/plugins/remotes/html/openlp.js index 5c467d123..4d3c4cde8 100644 --- a/openlp/plugins/remotes/html/openlp.js +++ b/openlp/plugins/remotes/html/openlp.js @@ -280,9 +280,8 @@ window.OpenLP = { $.mobile.changePage("#service-manager"); }, escapeString: function (string) { - string = string.replace(/\\/g, "\\\\").replace(/"/g, "\\\"") - string = string.replace(/#/g, "%23").replace(/;/g, "%3B") - return string + return string.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace( + /#/g, "%23").replace(/;/g, "%3B") } } // Service Manager From f8a559c633895a2dbc6a444b054fbe59bd9519c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20P=C3=B5ldaru?= Date: Tue, 13 Mar 2012 12:08:24 +0200 Subject: [PATCH 04/12] + is restricted as well. --- openlp/plugins/remotes/html/openlp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/remotes/html/openlp.js b/openlp/plugins/remotes/html/openlp.js index 4d3c4cde8..33941c1b9 100644 --- a/openlp/plugins/remotes/html/openlp.js +++ b/openlp/plugins/remotes/html/openlp.js @@ -281,7 +281,7 @@ window.OpenLP = { }, escapeString: function (string) { return string.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace( - /#/g, "%23").replace(/;/g, "%3B") + /#/g, "%23").replace(/;/g, "%3B").replace(/\+/g, "%2B") } } // Service Manager From 081f9b04c2f49284ca69d7b66a5de62fc399669c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20P=C3=B5ldaru?= Date: Sat, 17 Mar 2012 08:18:59 +0200 Subject: [PATCH 05/12] Fix 404 not found errors. --- openlp/plugins/remotes/lib/httpserver.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index 8daa1c7b0..67ab34a18 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -537,6 +537,7 @@ class HttpConnection(object): plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type) if plugin.status == PluginStatus.Active and plugin.mediaItem: plugin.mediaItem.goLive(id, remote=True) + return HttpResponse(code=u'200 OK') def add_to_service(self, type): """ @@ -547,6 +548,7 @@ class HttpConnection(object): if plugin.status == PluginStatus.Active and plugin.mediaItem: item_id = plugin.mediaItem.createItemFromId(id) plugin.mediaItem.addToService(item_id, remote=True) + return HttpResponse(code=u'200 OK') def send_response(self, response): http = u'HTTP/1.1 %s\r\n' % response.code From 76221b4f528243efad372d7ba4b3af7fb4e12d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20P=C3=B5ldaru?= Date: Sat, 17 Mar 2012 08:19:52 +0200 Subject: [PATCH 06/12] Fix JS event not found error when being called from poll response. --- openlp/plugins/remotes/html/openlp.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openlp/plugins/remotes/html/openlp.js b/openlp/plugins/remotes/html/openlp.js index 33941c1b9..93197b160 100644 --- a/openlp/plugins/remotes/html/openlp.js +++ b/openlp/plugins/remotes/html/openlp.js @@ -72,7 +72,9 @@ window.OpenLP = { ); }, loadController: function (event) { - event.preventDefault(); + if (event) { + event.preventDefault(); + } $.getJSON( "/api/controller/live/text", function (data, status) { From 103d38d016b609313b51852ad5653e2220ba6f71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20P=C3=B5ldaru?= Date: Sat, 17 Mar 2012 08:24:42 +0200 Subject: [PATCH 07/12] Fix double loading of songs when using remote's search and setting the song live after. --- openlp/plugins/remotes/html/openlp.js | 1 + openlp/plugins/remotes/lib/httpserver.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/openlp/plugins/remotes/html/openlp.js b/openlp/plugins/remotes/html/openlp.js index 93197b160..686b61e29 100644 --- a/openlp/plugins/remotes/html/openlp.js +++ b/openlp/plugins/remotes/html/openlp.js @@ -93,6 +93,7 @@ window.OpenLP = { li.children("a").click(OpenLP.setSlide); ul.append(li); } + OpenLP.currentItem = data.results.item; ul.listview("refresh"); } ); diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index 67ab34a18..45aa78418 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -463,6 +463,8 @@ class HttpConnection(object): item[u'selected'] = (self.parent.current_slide == index) data.append(item) json_data = {u'results': {u'slides': data}} + if current_item: + json_data[u'results'][u'item'] = self.parent.current_item._uuid else: if self.url_params and self.url_params.get(u'data'): data = json.loads(self.url_params[u'data'][0]) From 00390ed688338a4882d9f4e8681dc3296f2199db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20P=C3=B5ldaru?= Date: Sat, 17 Mar 2012 08:55:12 +0200 Subject: [PATCH 08/12] Alphabetic import order, remove old catcher from python 2.5. --- openlp/plugins/remotes/lib/httpserver.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index 45aa78418..6309666a7 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -111,15 +111,11 @@ the remotes. {"results": {"items": [{...}, {...}]}} """ +import json import logging import os -import urlparse import re - -try: - import json -except ImportError: - import simplejson as json +import urlparse from PyQt4 import QtCore, QtNetwork from mako.template import Template From 4ed5c3358428acb03bd6ddce6f92027275fef779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20P=C3=B5ldaru?= Date: Sat, 17 Mar 2012 09:55:59 +0200 Subject: [PATCH 09/12] Better fix for the encoding and related issue, less doube-encoding. Now we unquote the characters after JSON has decoded it's bits. --- openlp/plugins/remotes/html/openlp.js | 3 +-- openlp/plugins/remotes/lib/httpserver.py | 16 +++++++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/openlp/plugins/remotes/html/openlp.js b/openlp/plugins/remotes/html/openlp.js index 686b61e29..d081a6b3e 100644 --- a/openlp/plugins/remotes/html/openlp.js +++ b/openlp/plugins/remotes/html/openlp.js @@ -283,8 +283,7 @@ window.OpenLP = { $.mobile.changePage("#service-manager"); }, escapeString: function (string) { - return string.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace( - /#/g, "%23").replace(/;/g, "%3B").replace(/\+/g, "%2B") + return string.replace(/\\/g, "\\\\").replace(/"/g, "\\\"") } } // Service Manager diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index 6309666a7..94f30096b 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -115,6 +115,7 @@ import json import logging import os import re +import urllib import urlparse from PyQt4 import QtCore, QtNetwork @@ -310,11 +311,14 @@ class HttpConnection(object): """ log.debug(u'ready to read socket') if self.socket.canReadLine(): - data = self.socket.readLine() - data = QtCore.QByteArray.fromPercentEncoding(data) - data = unicode(data, 'utf8') - log.debug(u'received: ' + data) - words = data.split(u' ') + data = str(self.socket.readLine()) + try: + log.debug(u'received: ' + data) + except UnicodeDecodeError: + # Malicious request containing non-ASCII characters. + self.close() + return + words = data.split(' ') response = None if words[0] == u'GET': url = urlparse.urlparse(words[1]) @@ -423,6 +427,7 @@ class HttpConnection(object): Send an alert. """ text = json.loads(self.url_params[u'data'][0])[u'request'][u'text'] + text = urllib.unquote(text) Receiver.send_message(u'alerts_text', [text]) return HttpResponse(json.dumps({u'results': {u'success': True}}), {u'Content-Type': u'application/json'}) @@ -517,6 +522,7 @@ class HttpConnection(object): The plugin name to search in. """ text = json.loads(self.url_params[u'data'][0])[u'request'][u'text'] + text = urllib.unquote(text) plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type) if plugin.status == PluginStatus.Active and \ plugin.mediaItem and plugin.mediaItem.hasSearch: From 5cd7162cec95e8c66c773fe453a3fae12dfd3d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20P=C3=B5ldaru?= Date: Sat, 17 Mar 2012 10:11:42 +0200 Subject: [PATCH 10/12] Let's catch also all errors when response from remote is not correct JSON or it does not contain required item. --- openlp/plugins/remotes/lib/httpserver.py | 30 +++++++++++++++++++----- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index 94f30096b..0ccd2a869 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -426,7 +426,10 @@ class HttpConnection(object): """ Send an alert. """ - text = json.loads(self.url_params[u'data'][0])[u'request'][u'text'] + try: + text = json.loads(self.url_params[u'data'][0])[u'request'][u'text'] + except ValueError: + return HttpResponse(code=u'400 Bad Request') text = urllib.unquote(text) Receiver.send_message(u'alerts_text', [text]) return HttpResponse(json.dumps({u'results': {u'success': True}}), @@ -468,7 +471,10 @@ class HttpConnection(object): json_data[u'results'][u'item'] = self.parent.current_item._uuid else: if self.url_params and self.url_params.get(u'data'): - data = json.loads(self.url_params[u'data'][0]) + try: + data = json.loads(self.url_params[u'data'][0]) + except ValueError: + return HttpResponse(code=u'400 Bad Request') log.info(data) # This slot expects an int within a list. id = data[u'request'][u'id'] @@ -488,7 +494,10 @@ class HttpConnection(object): else: event += u'_item' if self.url_params and self.url_params.get(u'data'): - data = json.loads(self.url_params[u'data'][0]) + try: + data = json.loads(self.url_params[u'data'][0]) + except ValueError: + return HttpResponse(code=u'400 Bad Request') Receiver.send_message(event, data[u'request'][u'id']) else: Receiver.send_message(event) @@ -521,7 +530,10 @@ class HttpConnection(object): ``type`` The plugin name to search in. """ - text = json.loads(self.url_params[u'data'][0])[u'request'][u'text'] + try: + text = json.loads(self.url_params[u'data'][0])[u'request'][u'text'] + except ValueError: + return HttpResponse(code=u'400 Bad Request') text = urllib.unquote(text) plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type) if plugin.status == PluginStatus.Active and \ @@ -537,7 +549,10 @@ class HttpConnection(object): """ Go live on an item of type ``type``. """ - id = json.loads(self.url_params[u'data'][0])[u'request'][u'id'] + try: + id = json.loads(self.url_params[u'data'][0])[u'request'][u'id'] + except ValueError: + return HttpResponse(code=u'400 Bad Request') plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type) if plugin.status == PluginStatus.Active and plugin.mediaItem: plugin.mediaItem.goLive(id, remote=True) @@ -547,7 +562,10 @@ class HttpConnection(object): """ Add item of type ``type`` to the end of the service. """ - id = json.loads(self.url_params[u'data'][0])[u'request'][u'id'] + try: + id = json.loads(self.url_params[u'data'][0])[u'request'][u'id'] + except ValueError: + return HttpResponse(code=u'400 Bad Request') plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type) if plugin.status == PluginStatus.Active and plugin.mediaItem: item_id = plugin.mediaItem.createItemFromId(id) From 5710e2aefd5cc557ac74a55c3bf36d37db053b40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20P=C3=B5ldaru?= Date: Sun, 18 Mar 2012 01:44:16 +0200 Subject: [PATCH 11/12] Drop received alerts if alerts plugin is disabled. Prevent tracebacks when url does not contain data= element. --- openlp/plugins/remotes/lib/httpserver.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index 0ccd2a869..a1b22a45e 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -426,9 +426,16 @@ class HttpConnection(object): """ Send an alert. """ + for plugin in self.parent.plugin.pluginManager.plugins: + if plugin.name == u'alerts' and \ + plugin.status != PluginStatus.Active: + # Forget about the request, alerts is turned off. + return HttpResponse(json.dumps( + {u'results': {u'success': False}}), + {u'Content-Type': u'application/json'}) try: text = json.loads(self.url_params[u'data'][0])[u'request'][u'text'] - except ValueError: + except KeyError, ValueError: return HttpResponse(code=u'400 Bad Request') text = urllib.unquote(text) Receiver.send_message(u'alerts_text', [text]) @@ -473,7 +480,7 @@ class HttpConnection(object): if self.url_params and self.url_params.get(u'data'): try: data = json.loads(self.url_params[u'data'][0]) - except ValueError: + except KeyError, ValueError: return HttpResponse(code=u'400 Bad Request') log.info(data) # This slot expects an int within a list. @@ -496,7 +503,7 @@ class HttpConnection(object): if self.url_params and self.url_params.get(u'data'): try: data = json.loads(self.url_params[u'data'][0]) - except ValueError: + except KeyError, ValueError: return HttpResponse(code=u'400 Bad Request') Receiver.send_message(event, data[u'request'][u'id']) else: @@ -532,7 +539,7 @@ class HttpConnection(object): """ try: text = json.loads(self.url_params[u'data'][0])[u'request'][u'text'] - except ValueError: + except KeyError, ValueError: return HttpResponse(code=u'400 Bad Request') text = urllib.unquote(text) plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type) @@ -551,7 +558,7 @@ class HttpConnection(object): """ try: id = json.loads(self.url_params[u'data'][0])[u'request'][u'id'] - except ValueError: + except KeyError, ValueError: return HttpResponse(code=u'400 Bad Request') plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type) if plugin.status == PluginStatus.Active and plugin.mediaItem: @@ -564,7 +571,7 @@ class HttpConnection(object): """ try: id = json.loads(self.url_params[u'data'][0])[u'request'][u'id'] - except ValueError: + except KeyError, ValueError: return HttpResponse(code=u'400 Bad Request') plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type) if plugin.status == PluginStatus.Active and plugin.mediaItem: From 06ff33ac9653a73277d728de2880717c22c04273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20P=C3=B5ldaru?= Date: Sun, 18 Mar 2012 02:15:31 +0200 Subject: [PATCH 12/12] Style fix. Thanks to trb for nice example on he's branch. --- openlp/plugins/remotes/lib/httpserver.py | 27 ++++++++++++------------ 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index a1b22a45e..383c7fa03 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -426,20 +426,19 @@ class HttpConnection(object): """ Send an alert. """ - for plugin in self.parent.plugin.pluginManager.plugins: - if plugin.name == u'alerts' and \ - plugin.status != PluginStatus.Active: - # Forget about the request, alerts is turned off. - return HttpResponse(json.dumps( - {u'results': {u'success': False}}), - {u'Content-Type': u'application/json'}) - try: - text = json.loads(self.url_params[u'data'][0])[u'request'][u'text'] - except KeyError, ValueError: - return HttpResponse(code=u'400 Bad Request') - text = urllib.unquote(text) - Receiver.send_message(u'alerts_text', [text]) - return HttpResponse(json.dumps({u'results': {u'success': True}}), + plugin = self.parent.plugin.pluginManager.get_plugin_by_name("alerts") + if plugin.status == PluginStatus.Active: + try: + text = json.loads( + self.url_params[u'data'][0])[u'request'][u'text'] + except KeyError, ValueError: + return HttpResponse(code=u'400 Bad Request') + text = urllib.unquote(text) + Receiver.send_message(u'alerts_text', [text]) + success = True + else: + success = False + return HttpResponse(json.dumps({u'results': {u'success': success}}), {u'Content-Type': u'application/json'}) def controller(self, type, action):