OPDS Authentication, Cleanup, and Config Fixes

This commit is contained in:
DarkSir23 2017-10-31 12:57:26 -04:00 committed by evilhero
parent 9f739d8246
commit e1f4cabc0b
6 changed files with 127 additions and 32 deletions

View File

@ -240,6 +240,10 @@ def main():
'https_chain': mylar.CONFIG.HTTPS_CHAIN, 'https_chain': mylar.CONFIG.HTTPS_CHAIN,
'http_username': mylar.CONFIG.HTTP_USERNAME, 'http_username': mylar.CONFIG.HTTP_USERNAME,
'http_password': mylar.CONFIG.HTTP_PASSWORD, '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. # Try to start the server.

View File

@ -204,6 +204,34 @@
</div> </div>
</div> </div>
</fieldset> </fieldset>
<fieldset>
<legend>OPDS</legend>
<div class="row">
<div class="row_checkbox">
<input id="opds_enable" type="checkbox" name="opds_enable" value="1" ${config['opds_enable']} /><label>Enable OPDS</label>
</div>
<div id="opdsoptions">
<div class="row_checkbox">
<input id="opds_authentication" type="checkbox" name="opds_authentication" value="1" ${config['opds_authentication']} /><label>OPDS Requires Credentials</label>
<%
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."
%>
<a href="#" title="${opds_notes}"><img src="interfaces/default/images/info32.png" height="16" alt="" /></a>
<div id="opdscredentials">
<div class="row">
<label>OPDS Username</label>
<input type="text" name="opds_username" value="${config['opds_username']}" size="30">
</div>
<div class="row">
<label>OPDS Password</label>
<input type="password" name="opds_password" value="${config['opds_password']| h}" size="30">
</div>
</div>
</div>
</div>
</div>
</fieldset>
<fieldset> <fieldset>
<legend>Interval</legend> <legend>Interval</legend>
<div class="row"> <div class="row">
@ -1366,7 +1394,45 @@
$("#apioptions").slideUp(); $("#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")) if ($("#cbr2cbz").is(":checked"))
{ {

View File

@ -44,8 +44,8 @@ _CONFIG_DEFINITIONS = OrderedDict({
'CORRECT_METADATA': (bool, 'General', False), 'CORRECT_METADATA': (bool, 'General', False),
'MOVE_FILES': (bool, 'General', False), 'MOVE_FILES': (bool, 'General', False),
'RENAME_FILES': (bool, 'General', False), 'RENAME_FILES': (bool, 'General', False),
'FOLDER_FORMAT': (str, 'General', None), 'FOLDER_FORMAT': (str, 'General', '$Series ($Year)'),
'FILE_FORMAT': (str, 'General', None), 'FILE_FORMAT': (str, 'General', '$Series $Annual $Issue ($Year)'),
'REPLACE_SPACES': (bool, 'General', False), 'REPLACE_SPACES': (bool, 'General', False),
'REPLACE_CHAR': (str, 'General', None), 'REPLACE_CHAR': (str, 'General', None),
'ZERO_LEVEL': (bool, 'General', False), 'ZERO_LEVEL': (bool, 'General', False),
@ -104,7 +104,7 @@ _CONFIG_DEFINITIONS = OrderedDict({
'CV_VERIFY': (bool, 'CV', True), 'CV_VERIFY': (bool, 'CV', True),
'CV_ONLY': (bool, 'CV', True), 'CV_ONLY': (bool, 'CV', True),
'CV_ONETIMER': (bool, 'CV', True), 'CV_ONETIMER': (bool, 'CV', True),
'CVINFO': (bool, 'CV', True), 'CVINFO': (bool, 'CV', False),
'LOG_DIR' : (str, 'Logs', None), 'LOG_DIR' : (str, 'Logs', None),
'MAX_LOGSIZE' : (int, 'Logs', 10000000), 'MAX_LOGSIZE' : (int, 'Logs', 10000000),
@ -320,9 +320,9 @@ _CONFIG_DEFINITIONS = OrderedDict({
'QBITTORRENT_STARTONLOAD': (bool, 'qBittorrent', False), 'QBITTORRENT_STARTONLOAD': (bool, 'qBittorrent', False),
'OPDS_ENABLE': (bool, 'OPDS', False), 'OPDS_ENABLE': (bool, 'OPDS', False),
'OPDS_READONLYUSER': (bool, 'OPDS', False), 'OPDS_AUTHENTICATION': (bool, 'OPDS', False),
'OPDS_READONLYUSERNAME': (str, 'OPDS', None), 'OPDS_USERNAME': (str, 'OPDS', None),
'OPDS_READONLYPASSWORD': (str, 'OPDS', None), 'OPDS_PASSWORD': (str, 'OPDS', None),
}) })

View File

@ -20,7 +20,6 @@ import mylar
from mylar import db, mb, importer, search, PostProcessor, versioncheck, logger from mylar import db, mb, importer, search, PostProcessor, versioncheck, logger
import simplejson as simplejson import simplejson as simplejson
import cherrypy import cherrypy
from lxml import etree
import os import os
import urllib2 import urllib2
import cache import cache
@ -81,12 +80,9 @@ class OPDS(object):
return self.data return self.data
def _error_with_message(self, message): def _error_with_message(self, message):
feed = etree.Element("feed") error = '<feed><error>%s</error></feed>' % message
error = etree.SubElement(feed,'error')
error.text = message
cherrypy.response.headers['Content-Type'] = "text/xml" cherrypy.response.headers['Content-Type'] = "text/xml"
return etree.tostring(feed) return error
def _root(self, **kwargs): def _root(self, **kwargs):
myDB = db.DBConnection() myDB = db.DBConnection()
@ -96,23 +92,9 @@ class OPDS(object):
feed['updated'] = mylar.helpers.now() feed['updated'] = mylar.helpers.now()
links = [] links = []
entries=[] entries=[]
links.append({ links.append(getLink(href='/opds',type='application/atom+xml;profile=opds-catalog;kind=navigation', rel='start', title='Home'))
'href': '/opds', links.append(getLink(href='/opds',type='application/atom+xml;profile=opds-catalog;kind=navigation',rel='self'))
'type': 'application/atom+xml;profile=opds-catalog;kind=navigation', links.append(getLink(href='/opds?cmd=search', type='application/opensearchdescription+xml',rel='search',title='Search'))
'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',
})
publishers = myDB.select("SELECT ComicPublisher from comics GROUP BY ComicPublisher") publishers = myDB.select("SELECT ComicPublisher from comics GROUP BY ComicPublisher")
if len(publishers) > 0: if len(publishers) > 0:
count = len(publishers) count = len(publishers)
@ -142,7 +124,33 @@ class OPDS(object):
'kind': 'navigation' '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['links'] = links
feed['entries'] = entries feed['entries'] = entries
self.data = feed self.data = feed
return 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

View File

@ -4353,7 +4353,11 @@ class WebInterface(object):
"config_file": mylar.CONFIG_FILE, "config_file": mylar.CONFIG_FILE,
"branch_history": 'None', "branch_history": 'None',
# "branch_history" : br_hist, # "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) return serve_template(templatename="config.html", title="Settings", config=config, comicinfo=comicinfo)
config.exposed = True 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', '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', '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', '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: for checked_config in checked_configs:
if checked_config not in kwargs: if checked_config not in kwargs:

View File

@ -125,6 +125,18 @@ def initialize(options):
}) })
conf['/api'] = {'tools.auth_basic.on': False} 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 # Prevent time-outs
cherrypy.engine.timeout_monitor.unsubscribe() cherrypy.engine.timeout_monitor.unsubscribe()