From e1f4cabc0bae55eccda472aeced710e081701b6e Mon Sep 17 00:00:00 2001 From: DarkSir23 Date: Tue, 31 Oct 2017 12:57:26 -0400 Subject: [PATCH] OPDS Authentication, Cleanup, and Config Fixes --- Mylar.py | 4 ++ data/interfaces/default/config.html | 66 +++++++++++++++++++++++++++++ mylar/config.py | 12 +++--- mylar/opds.py | 56 +++++++++++++----------- mylar/webserve.py | 9 +++- mylar/webstart.py | 12 ++++++ 6 files changed, 127 insertions(+), 32 deletions(-) diff --git a/Mylar.py b/Mylar.py index b043ecc9..6e17c01a 100755 --- a/Mylar.py +++ b/Mylar.py @@ -240,6 +240,10 @@ def main(): 'https_chain': mylar.CONFIG.HTTPS_CHAIN, 'http_username': mylar.CONFIG.HTTP_USERNAME, 'http_password': mylar.CONFIG.HTTP_PASSWORD, + 'opds_enable': mylar.CONFIG.OPDS_ENABLE, + 'opds_authentication': mylar.CONFIG.OPDS_AUTHENTICATION, + 'opds_username': mylar.CONFIG.OPDS_USERNAME, + 'opds_password': mylar.CONFIG.OPDS_PASSWORD, } # Try to start the server. diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index b6985069..7fa855c6 100755 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -204,6 +204,34 @@ +
+ OPDS +
+
+ +
+
+
+ + <% + opds_notes = "Require authentication for OPDS. If checked\nyou will need to provide a username/password.\nThe service user name will work (if set). Additionally,\nyou can provide a user with only OPDS access below.\nNOTE: If this is not checked, OPDS will be available\nwithout a password." + %> + +
+
+ + +
+ +
+ + +
+
+
+
+
+
Interval
@@ -1366,7 +1394,45 @@ $("#apioptions").slideUp(); } }); + if ($("#opds_enable").is(":checked")) + { + $("#opdsoptions").show(); + } + else + { + $("#opdsoptions").hide(); + } + + $("#opds_enable").click(function(){ + if ($("#opds_enable").is(":checked")) + { + $("#opdsoptions").slideDown(); + } + else + { + $("#opdsoptions").slideUp(); + } + }); + if ($("#opds_authentication").is(":checked")) + { + $("#opdscredentials").show(); + } + else + { + $("#opdscredentials").hide(); + } + + $("#opds_authentication").click(function(){ + if ($("#opds_authentication").is(":checked")) + { + $("#opdscredentials").slideDown(); + } + else + { + $("#opdscredentials").slideUp(); + } + }); if ($("#cbr2cbz").is(":checked")) { diff --git a/mylar/config.py b/mylar/config.py index 0a13f1d8..1bd2b011 100644 --- a/mylar/config.py +++ b/mylar/config.py @@ -44,8 +44,8 @@ _CONFIG_DEFINITIONS = OrderedDict({ 'CORRECT_METADATA': (bool, 'General', False), 'MOVE_FILES': (bool, 'General', False), 'RENAME_FILES': (bool, 'General', False), - 'FOLDER_FORMAT': (str, 'General', None), - 'FILE_FORMAT': (str, 'General', None), + 'FOLDER_FORMAT': (str, 'General', '$Series ($Year)'), + 'FILE_FORMAT': (str, 'General', '$Series $Annual $Issue ($Year)'), 'REPLACE_SPACES': (bool, 'General', False), 'REPLACE_CHAR': (str, 'General', None), 'ZERO_LEVEL': (bool, 'General', False), @@ -104,7 +104,7 @@ _CONFIG_DEFINITIONS = OrderedDict({ 'CV_VERIFY': (bool, 'CV', True), 'CV_ONLY': (bool, 'CV', True), 'CV_ONETIMER': (bool, 'CV', True), - 'CVINFO': (bool, 'CV', True), + 'CVINFO': (bool, 'CV', False), 'LOG_DIR' : (str, 'Logs', None), 'MAX_LOGSIZE' : (int, 'Logs', 10000000), @@ -320,9 +320,9 @@ _CONFIG_DEFINITIONS = OrderedDict({ 'QBITTORRENT_STARTONLOAD': (bool, 'qBittorrent', False), 'OPDS_ENABLE': (bool, 'OPDS', False), - 'OPDS_READONLYUSER': (bool, 'OPDS', False), - 'OPDS_READONLYUSERNAME': (str, 'OPDS', None), - 'OPDS_READONLYPASSWORD': (str, 'OPDS', None), + 'OPDS_AUTHENTICATION': (bool, 'OPDS', False), + 'OPDS_USERNAME': (str, 'OPDS', None), + 'OPDS_PASSWORD': (str, 'OPDS', None), }) diff --git a/mylar/opds.py b/mylar/opds.py index 20b12dc9..818111ac 100644 --- a/mylar/opds.py +++ b/mylar/opds.py @@ -20,7 +20,6 @@ import mylar from mylar import db, mb, importer, search, PostProcessor, versioncheck, logger import simplejson as simplejson import cherrypy -from lxml import etree import os import urllib2 import cache @@ -81,12 +80,9 @@ class OPDS(object): return self.data def _error_with_message(self, message): - feed = etree.Element("feed") - - error = etree.SubElement(feed,'error') - error.text = message + error = '%s' % message cherrypy.response.headers['Content-Type'] = "text/xml" - return etree.tostring(feed) + return error def _root(self, **kwargs): myDB = db.DBConnection() @@ -96,23 +92,9 @@ class OPDS(object): feed['updated'] = mylar.helpers.now() links = [] entries=[] - links.append({ - 'href': '/opds', - 'type': 'application/atom+xml;profile=opds-catalog;kind=navigation', - 'rel': 'start', - 'title': 'Home' - }) - links.append({ - 'href': '/opds', - 'type': 'application/atom+xml;profile=opds-catalog;kind=navigation', - 'rel': 'self', - }) - links.append({ - 'href': '/opds?cmd=search', - 'type': 'application/opensearchdescription+xml', - 'rel': 'search', - 'title': 'Search', - }) + links.append(getLink(href='/opds',type='application/atom+xml;profile=opds-catalog;kind=navigation', rel='start', title='Home')) + links.append(getLink(href='/opds',type='application/atom+xml;profile=opds-catalog;kind=navigation',rel='self')) + links.append(getLink(href='/opds?cmd=search', type='application/opensearchdescription+xml',rel='search',title='Search')) publishers = myDB.select("SELECT ComicPublisher from comics GROUP BY ComicPublisher") if len(publishers) > 0: count = len(publishers) @@ -142,7 +124,33 @@ class OPDS(object): 'kind': 'navigation' } ) + storyArcs = mylar.helpers.listStoryArcs() + logger.debug(storyArcs) + if len(storyArcs) > 0: + entries.append( + { + 'title': 'Story Arcs (%s)' % len(storyArcs), + 'id': 'StoryArcs', + 'updated': mylar.helpers.now(), + 'content': 'List of Story Arcs', + 'href': '/opds?cmd=StoryArcs', + 'kind': 'navigation' + } + ) + feed['links'] = links feed['entries'] = entries self.data = feed - return \ No newline at end of file + return + +def getLink(href=None, type=None, rel=None, title=None): + link = {} + if href: + link['href'] = href + if type: + link['type'] = type + if rel: + link['rel'] = rel + if title: + link['title'] = title + return link diff --git a/mylar/webserve.py b/mylar/webserve.py index 18a58324..7446b778 100644 --- a/mylar/webserve.py +++ b/mylar/webserve.py @@ -4353,7 +4353,11 @@ class WebInterface(object): "config_file": mylar.CONFIG_FILE, "branch_history": 'None', # "branch_history" : br_hist, - "log_dir": mylar.CONFIG.LOG_DIR + "log_dir": mylar.CONFIG.LOG_DIR, + "opds_enable": helpers.checked(mylar.CONFIG.OPDS_ENABLE), + "opds_authentication": helpers.checked(mylar.CONFIG.OPDS_AUTHENTICATION), + "opds_username": mylar.CONFIG.OPDS_USERNAME, + "opds_password": mylar.CONFIG.OPDS_PASSWORD, } return serve_template(templatename="config.html", title="Settings", config=config, comicinfo=comicinfo) config.exposed = True @@ -4570,7 +4574,8 @@ class WebInterface(object): 'enable_meta', 'cbr2cbz_only', 'ct_tag_cr', 'ct_tag_cbl', 'ct_cbz_overwrite', 'rename_files', 'replace_spaces', 'zero_level', 'lowercase_filenames', 'autowant_upcoming', 'autowant_all', 'comic_cover_local', 'cvinfo', 'snatchedtorrent_notify', 'prowl_enabled', 'prowl_onsnatch', 'nma_enabled', 'nma_onsnatch', 'pushover_enabled', 'pushover_onsnatch', 'boxcar_enabled', - 'boxcar_onsnatch', 'pushbullet_enabled', 'pushbullet_onsnatch', 'telegram_enabled', 'telegram_onsnatch', 'slack_enabled', 'slack_onsnatch' ] + 'boxcar_onsnatch', 'pushbullet_enabled', 'pushbullet_onsnatch', 'telegram_enabled', 'telegram_onsnatch', 'slack_enabled', 'slack_onsnatch', + 'opds_enable', 'opds_authentication'] for checked_config in checked_configs: if checked_config not in kwargs: diff --git a/mylar/webstart.py b/mylar/webstart.py index 5494fa8f..d59341b1 100755 --- a/mylar/webstart.py +++ b/mylar/webstart.py @@ -125,6 +125,18 @@ def initialize(options): }) conf['/api'] = {'tools.auth_basic.on': False} + if options['opds_authentication']: + user_list = {} + if len(options['opds_username']) > 0: + user_list[options['opds_username']] = options['opds_password'] + if options['http_password'] is not None and options['http_username'] != options['opds_username']: + user_list[options['http_username']] = options['http_password'] + conf['/opds'] = {'tools.auth_basic.on': True, + 'tools.auth_basic.realm': 'Mylar OPDS', + 'tools.auth_basic.checkpassword': cherrypy.lib.auth_basic.checkpassword_dict(user_list)} + else: + conf['/opds'] = {'tools.auth_basic.on': False} + # Prevent time-outs cherrypy.engine.timeout_monitor.unsubscribe()