From 448da916e9f820e8d9333579a68f3b9c09cb19d9 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Thu, 12 Sep 2013 17:46:57 +0100 Subject: [PATCH] Readonly works - next comes updates --- openlp/plugins/remotes/lib/httprouter.py | 120 ++++++++++++++++------- openlp/plugins/remotes/lib/httpserver.py | 46 ++++----- 2 files changed, 108 insertions(+), 58 deletions(-) diff --git a/openlp/plugins/remotes/lib/httprouter.py b/openlp/plugins/remotes/lib/httprouter.py index 77927723c..4d9133e65 100644 --- a/openlp/plugins/remotes/lib/httprouter.py +++ b/openlp/plugins/remotes/lib/httprouter.py @@ -112,15 +112,14 @@ the remotes. {"results": {"items": [{...}, {...}]}} """ - +import base64 import json import logging import os import re import urllib.request -import urllib.parse import urllib.error -import urllib.parse +from urllib.parse import urlparse, parse_qs from mako.template import Template @@ -129,46 +128,77 @@ from PyQt4 import QtCore from openlp.core.lib import Registry, Settings, PluginStatus, StringContent, image_to_byte from openlp.core.utils import AppLocation, translate -from hashlib import sha1 - log = logging.getLogger(__name__) class HttpRouter(object): """ This code is called by the HttpServer upon a request and it processes it based on the routing table. + This code is stateless so need """ def initialise(self): """ - Initialise the router + Initialise the router stack and any other varables. """ + authcode = "%s:%s" % (Settings().value('remotes/user id'), Settings().value('remotes/password')) + try: + self.auth = base64.b64encode(authcode) + except TypeError: + self.auth = base64.b64encode(authcode.encode()).decode() self.routes = [ - ('^/$', self.serve_file), - ('^/(stage)$', self.serve_file), - ('^/(main)$', self.serve_file), - (r'^/files/(.*)$', self.serve_file), - (r'^/api/poll$', self.poll), - (r'^/stage/poll$', self.poll), - (r'^/main/poll$', self.main_poll), - (r'^/main/image$', self.main_image), - (r'^/api/controller/(live|preview)/(.*)$', self.controller), - (r'^/stage/controller/(live|preview)/(.*)$', self.controller), - (r'^/api/service/(.*)$', self.service), - (r'^/stage/service/(.*)$', self.service), - (r'^/api/display/(hide|show|blank|theme|desktop)$', self.display), - (r'^/api/alert$', self.alert), - (r'^/api/plugin/(search)$', self.plugin_info), - (r'^/api/(.*)/search$', self.search), - (r'^/api/(.*)/live$', self.go_live), - (r'^/api/(.*)/add$', self.add_to_service) + ('^/$', {'function': self.serve_file, 'secure': False}), + ('^/(stage)$', {'function': self.serve_file, 'secure': False}), + ('^/(main)$', {'function': self.serve_file, 'secure': False}), + (r'^/files/(.*)$', {'function': self.serve_file, 'secure': False}), + (r'^/api/poll$', {'function': self.poll, 'secure': False}), + (r'^/stage/poll$', {'function': self.poll, 'secure': False}), + (r'^/main/poll$', {'function': self.poll, 'secure': False}), + (r'^/main/image$', {'function': self.main_poll, 'secure': False}), + (r'^/api/controller/(live|preview)/(.*)$', {'function': self.controller, 'secure': False}), + (r'^/stage/controller/(live|preview)/(.*)$', {'function': self.controller, 'secure': False}), + (r'^/api/service/(.*)$', {'function':self.service, 'secure': False}), + (r'^/stage/service/(.*)$', {'function': self.service, 'secure': False}), + (r'^/api/display/(hide|show|blank|theme|desktop)$', {'function': self.display, 'secure': True}), + (r'^/api/alert$', {'function': self.alert, 'secure': True}), + (r'^/api/plugin/(search)$', {'function': self.plugin_info, 'secure': False}), + (r'^/api/(.*)/search$', {'function': self.search, 'secure': False}), + (r'^/api/(.*)/live$', {'function': self.go_live, 'secure': True}), + (r'^/api/(.*)/add$', {'function': self.add_to_service, 'secure': True}) ] self.translate() self.html_dir = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir), 'remotes', 'html') + def call_function(self, function, *args): + response = function['function'](*args) + if response: + self.wfile.write(response) + return + def process_http_request(self, url_path, *args): """ Common function to process HTTP requests + ``url_path`` + The requested URL. + + ``*args`` + Any passed data. + """ + url_path_split = urlparse(url_path) + for route, func in self.routes: + match = re.match(route, url_path_split.path) + if match: + print('Route "%s" matched "%s"', route, url_path) + args = [] + for param in match.groups(): + args.append(param) + return func, args + return None, None + + def _process_http_request(self, url_path, *args): + """ + Common function to process HTTP requests + ``url_path`` The requested URL. @@ -189,7 +219,29 @@ class HttpRouter(object): return response else: log.debug('Path not found %s', url_path) - return self._http_not_found() + return self.do_not_found() + + def do_http_success(self): + self.send_response(200) + self.send_header('Content-type', 'text/html') + self.end_headers() + + def do_http_error(self): + self.send_response(404) + self.send_header('Content-type', 'text/html') + self.end_headers() + + def do_authorisation(self): + self.send_response(401) + self.send_header('WWW-Authenticate', 'Basic realm=\"Test\"') + self.send_header('Content-type', 'text/html') + self.end_headers() + + def do_notfound(self): + self.send_response(404) + self.send_header('Content-type', 'text/html') + self.end_headers() + self.wfile.write(bytes('Sorry, an error occurred ', 'UTF-8')) def _get_service_items(self): """ @@ -259,25 +311,27 @@ class HttpRouter(object): file_name = 'main.html' path = os.path.normpath(os.path.join(self.html_dir, file_name)) if not path.startswith(self.html_dir): - return self._http_not_found() + return self.http_not_found() ext = os.path.splitext(file_name)[1] html = None if ext == '.html': - mimetype = 'text/html' + self.send_header('Content-type', 'text/html') variables = self.template_vars html = Template(filename=path, input_encoding='utf-8', output_encoding='utf-8').render(**variables) elif ext == '.css': - mimetype = 'text/css' + self.send_header('Content-type', 'text/css') elif ext == '.js': - mimetype = 'application/x-javascript' + self.send_header('Content-type', 'application/x-javascript') elif ext == '.jpg': - mimetype = 'image/jpeg' + self.send_header('Content-type', 'image/jpeg') elif ext == '.gif': - mimetype = 'image/gif' + self.send_header('Content-type', 'image/gif') + elif ext == '.ico': + self.send_header('Content-type', 'image/ico') elif ext == '.png': - mimetype = 'image/png' + self.send_header('Content-type', 'image/png') else: - mimetype = 'text/plain' + self.send_header('Content-type', 'text/plain') file_handle = None try: if html: diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index cee58b9ab..a819d8ac2 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -49,40 +49,26 @@ from openlp.plugins.remotes.lib import HttpRouter from socketserver import BaseServer, ThreadingMixIn from http.server import BaseHTTPRequestHandler, HTTPServer -from hashlib import sha1 - log = logging.getLogger(__name__) -def make_sha_hash(password): - """ - Create an encrypted password for the given password. - """ - log.debug("make_sha_hash") - return sha1(password.encode()).hexdigest() - - -def fetch_password(username): - """ - Fetch the password for a provided user. - """ - log.debug("Fetch Password") - if username != Settings().value('remotes/user id'): - return None - return make_sha_hash(Settings().value('remotes/password')) - - class CustomHandler(BaseHTTPRequestHandler, HttpRouter): """ - Main class to present webpages and authentication. + Stateless session handler to handle the HTTP request and process it. + This class handles just the overrides to the base methods and the logic to invoke the + methods within the HttpRouter class. + DO not try change the structure as this is as per the documentation. """ def do_POST(self): + """ + Present pages / data and invoke URL level user authentication. + """ self.do_GET() def do_GET(self): """ - Present frontpage with user authentication. + Present pages / data and invoke URL level user authentication. """ if self.path == '/favicon.ico': return @@ -141,7 +127,7 @@ class HttpThread(QtCore.QThread): class OpenLPServer(): def __init__(self): """ - Initialise the http server, and start the server. + Initialise the http server, and start the server of the correct type http / https """ log.debug('Initialise httpserver') self.settings_section = 'remotes' @@ -149,24 +135,34 @@ class OpenLPServer(): self.http_thread.start() def start_server(self): + """ + Start the correct server and save the handler + """ address = Settings().value(self.settings_section + '/ip address') if Settings().value(self.settings_section + '/https enabled'): port = Settings().value(self.settings_section + '/https port') self.httpd = HTTPSServer((address, port), CustomHandler) - print('started ssl httpd...') + log.debug('Started ssl httpd...') else: port = Settings().value(self.settings_section + '/port') self.httpd = ThreadingHTTPServer((address, port), CustomHandler) - print('started non ssl httpd...') + log.debug('Started non ssl httpd...') self.httpd.serve_forever() def stop_server(self): + """ + Stop the server + """ self.httpd.socket.close() self.httpd = None + log.debug('Stopped the server.') class HTTPSServer(HTTPServer): def __init__(self, address, handler): + """ + Initialise the secure handlers for the SSL server if required.s + """ BaseServer.__init__(self, address, handler) local_data = AppLocation.get_directory(AppLocation.DataDir) self.socket = ssl.SSLSocket(