diff --git a/cps/MyLoginManager.py b/cps/MyLoginManager.py index 419b2e90..44907045 100644 --- a/cps/MyLoginManager.py +++ b/cps/MyLoginManager.py @@ -19,14 +19,11 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import ast -import hashlib from .cw_login import LoginManager from flask import session - class MyLoginManager(LoginManager): def _session_protection_failed(self): sess = session._get_current_object() diff --git a/cps/cw_login/login_manager.py b/cps/cw_login/login_manager.py index bf0efbc7..21dc803d 100644 --- a/cps/cw_login/login_manager.py +++ b/cps/cw_login/login_manager.py @@ -397,7 +397,7 @@ class LoginManager: def _load_user_from_remember_cookie(self, cookie): signer_kwargs = dict( - key_derivation="hmac", digest_method=staticmethod(hashlib.sha1) + key_derivation="hmac", digest_method=hashlib.sha1 ) try: remember_dict = URLSafeSerializer( @@ -482,7 +482,7 @@ class LoginManager: # prepare data max_age = int(current_app.permanent_session_lifetime.total_seconds()) signer_kwargs = dict( - key_derivation="hmac", digest_method=staticmethod(hashlib.sha1) + key_derivation="hmac", digest_method=hashlib.sha1 ) # save data = URLSafeSerializer( diff --git a/cps/editbooks.py b/cps/editbooks.py index 84299c63..5f58cf81 100644 --- a/cps/editbooks.py +++ b/cps/editbooks.py @@ -134,8 +134,9 @@ def edit_book(book_id): # handle upload other formats from local disk meta = upload_single_file(request, book, book_id) # only merge metadata if file was uploaded and no error occurred (meta equals not false or none) + upload_format = False if meta: - merge_metadata(to_save, meta) + upload_format = merge_metadata(to_save, meta) # handle upload covers from local disk cover_upload_success = upload_cover(request, book) if cover_upload_success: @@ -179,7 +180,7 @@ def edit_book(book_id): modify_date |= edit_book_publisher(to_save['publisher'], book) # handle book languages try: - modify_date |= edit_book_languages(to_save['languages'], book) + modify_date |= edit_book_languages(to_save['languages'], book, upload_format) except ValueError as e: flash(str(e), category="error") edit_error = True @@ -575,6 +576,10 @@ def merge_metadata(to_save, meta): to_save['author_name'] = '' if to_save.get('book_title', "") == _('Unknown'): to_save['book_title'] = '' + if not to_save["languages"] and meta.languages: + upload_language = True + else: + upload_language = False for s_field, m_field in [ ('tags', 'tags'), ('author_name', 'author'), ('series', 'series'), ('series_index', 'series_id'), ('languages', 'languages'), @@ -582,7 +587,7 @@ def merge_metadata(to_save, meta): to_save[s_field] = to_save[s_field] or getattr(meta, m_field, '') to_save["description"] = to_save["description"] or Markup( getattr(meta, 'description', '')).unescape() - + return upload_language def identifier_list(to_save, book): """Generate a list of Identifiers from form information""" diff --git a/cps/embed_helper.py b/cps/embed_helper.py index 71de216d..54db47ef 100644 --- a/cps/embed_helper.py +++ b/cps/embed_helper.py @@ -28,7 +28,7 @@ log = logger.create() def do_calibre_export(book_id, book_format): try: - quotes = [3, 5, 7, 9] + quotes = [4, 6] tmp_dir = get_temp_dir() calibredb_binarypath = get_calibre_binarypath("calibredb") temp_file_name = str(uuid4()) diff --git a/cps/helper.py b/cps/helper.py index 08fa1387..004e1b0e 100644 --- a/cps/helper.py +++ b/cps/helper.py @@ -413,36 +413,6 @@ def rename_all_files_on_change(one_book, new_path, old_path, all_new_name, gdriv file_format.name = all_new_name -'''def rename_all_authors(first_author, renamed_author, calibre_path="", localbook=None, gdrive=False): - # Create new_author_dir from parameter or from database - # Create new title_dir from database and add id - if first_author: - new_authordir = get_valid_filename(first_author, chars=96) - for r in renamed_author: - new_author = calibre_db.session.query(db.Authors).filter(db.Authors.name == r).first() - old_author_dir = get_valid_filename(r, chars=96) - new_author_rename_dir = get_valid_filename(new_author.name, chars=96) - if gdrive: - g_file = gd.getFileFromEbooksFolder(None, old_author_dir) - if g_file: - gd.moveGdriveFolderRemote(g_file, new_author_rename_dir) - gd.updateDatabaseOnEdit(g_file['id'], new_author_rename_dir) - else: - if os.path.isdir(os.path.join(calibre_path, old_author_dir)): - old_author_path = os.path.join(calibre_path, old_author_dir) - new_author_path = os.path.join(calibre_path, new_author_rename_dir) - try: - shutil.move(os.path.normcase(old_author_path), os.path.normcase(new_author_path)) - except OSError as ex: - log.error("Rename author from: %s to %s: %s", old_author_path, new_author_path, ex) - log.debug(ex, exc_info=True) - return _("Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s", - src=old_author_path, dest=new_author_path, error=str(ex)) - else: - new_authordir = get_valid_filename(localbook.authors[0].name, chars=96) - return new_authordir''' - - def rename_author_path(first_author, old_author_dir, renamed_author, calibre_path="", gdrive=False): # Create new_author_dir from parameter or from database # Create new title_dir from database and add id @@ -459,12 +429,15 @@ def rename_author_path(first_author, old_author_dir, renamed_author, calibre_pat old_author_path = os.path.join(calibre_path, old_author_dir) new_author_path = os.path.join(calibre_path, new_author_rename_dir) try: - shutil.move(old_author_path, new_author_path) - except OSError as ex: - log.error("Rename author from: %s to %s: %s", old_author_path, new_author_path, ex) - log.debug(ex, exc_info=True) - return _("Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s", - src=old_author_path, dest=new_author_path, error=str(ex)) + os.rename(old_author_path, new_author_path) + except OSError: + try: + shutil.move(old_author_path, new_author_path) + except OSError as ex: + log.error("Rename author from: %s to %s: %s", old_author_path, new_author_path, ex) + log.error_or_exception(ex) + raise Exception(_("Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s", + src=old_author_path, dest=new_author_path, error=str(ex))) return new_authordir # Moves files in file storage during author/title rename, or from temp dir to file storage diff --git a/cps/main.py b/cps/main.py index 6afb18af..1b3b40b4 100644 --- a/cps/main.py +++ b/cps/main.py @@ -20,7 +20,6 @@ import sys from . import create_app, limiter from .jinjia import jinjia -from .remotelogin import remotelogin from flask import request @@ -42,6 +41,7 @@ def main(): from .shelf import shelf from .tasks_status import tasks from .error_handler import init_errorhandler + from .remotelogin import remotelogin try: from .kobo import kobo, get_kobo_activated from .kobo_auth import kobo_auth diff --git a/cps/static/js/reading/epub.js b/cps/static/js/reading/epub.js index 5047b1d3..a552da05 100644 --- a/cps/static/js/reading/epub.js +++ b/cps/static/js/reading/epub.js @@ -79,6 +79,6 @@ var reader; } // Default settings load - const theme = localStorage.getItem("calibre.reader.theme") ?? Object.keys(themes)[0]; + const theme = localStorage.getItem("calibre.reader.theme") ?? "lightTheme"; selectTheme(theme); })(); diff --git a/cps/tasks/convert.py b/cps/tasks/convert.py index e6af356f..3bef81a9 100644 --- a/cps/tasks/convert.py +++ b/cps/tasks/convert.py @@ -255,7 +255,7 @@ class TaskConvert(CalibreTask): try: # path_tmp_opf = self._embed_metadata() if config.config_embed_metadata: - quotes = [3, 5] + quotes = [5] tmp_dir = get_temp_dir() calibredb_binarypath = os.path.join(config.config_binariesdir, SUPPORTED_CALIBRE_BINARIES["calibredb"]) my_env = os.environ.copy() diff --git a/cps/tasks/database.py b/cps/tasks/database.py index e5aa26da..c9c30d43 100644 --- a/cps/tasks/database.py +++ b/cps/tasks/database.py @@ -16,11 +16,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from urllib.request import urlopen - from flask_babel import lazy_gettext as N_ -from cps import config, logger +from cps import config, logger, db, ub from cps.services.worker import CalibreTask @@ -28,18 +26,12 @@ class TaskReconnectDatabase(CalibreTask): def __init__(self, task_message=N_('Reconnecting Calibre database')): super(TaskReconnectDatabase, self).__init__(task_message) self.log = logger.create() - self.listen_address = config.get_config_ipaddress() - self.listen_port = config.config_port + self.calibre_db = db.CalibreDB(expire_on_commit=False, init=True) def run(self, worker_thread): - address = self.listen_address if self.listen_address else 'localhost' - port = self.listen_port if self.listen_port else 8083 - - try: - urlopen('http://' + address + ':' + str(port) + '/reconnect') - self._handleSuccess() - except Exception as ex: - self._handleError('Unable to reconnect Calibre database: ' + str(ex)) + self.calibre_db.reconnect_db(config, ub.app_DB_path) + self.calibre_db.session.close() + self._handleSuccess() @property def name(self): diff --git a/cps/tasks/thumbnail.py b/cps/tasks/thumbnail.py index 2921ffc9..d2179dd9 100644 --- a/cps/tasks/thumbnail.py +++ b/cps/tasks/thumbnail.py @@ -70,7 +70,6 @@ class TaskGenerateCoverThumbnails(CalibreTask): self.log = logger.create() self.book_id = book_id self.app_db_session = ub.get_new_session_instance() - # self.calibre_db = db.CalibreDB(expire_on_commit=False, init=True) self.cache = fs.FileSystem() self.resolutions = [ constants.COVER_THUMBNAIL_SMALL, diff --git a/cps/web.py b/cps/web.py index 7da22e3a..2519ebd5 100644 --- a/cps/web.py +++ b/cps/web.py @@ -89,21 +89,21 @@ except ImportError: def add_security_headers(resp): default_src = ([host.strip() for host in config.config_trustedhosts.split(',') if host] + ["'self'", "'unsafe-inline'", "'unsafe-eval'"]) - csp = "default-src " + ' '.join(default_src) + "; " - csp += "font-src 'self' data:" + csp = "default-src " + ' '.join(default_src) + if request.endpoint == "web.read_book" and config.config_use_google_drive: + csp +=" blob: " + csp += "; font-src 'self' data:" if request.endpoint == "web.read_book": - csp += " blob:" + csp += " blob: " csp += "; img-src 'self'" if request.path.startswith("/author/") and config.config_use_goodreads: csp += " images.gr-assets.com i.gr-assets.com s.gr-assets.com" csp += " data:" if request.endpoint == "edit-book.show_edit_book" or config.config_use_google_drive: - csp += " *;" - elif request.endpoint == "web.read_book": - csp += " blob:; style-src-elem 'self' blob: 'unsafe-inline';" - else: - csp += ";" - csp += " object-src 'none';" + csp += " *" + if request.endpoint == "web.read_book": + csp += " blob: ; style-src-elem 'self' blob: 'unsafe-inline'" + csp += "; object-src 'none';" resp.headers['Content-Security-Policy'] = csp resp.headers['X-Content-Type-Options'] = 'nosniff' resp.headers['X-Frame-Options'] = 'SAMEORIGIN' diff --git a/requirements.txt b/requirements.txt index fd6a808c..460a7357 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,6 @@ -Werkzeug<3.0.0 APScheduler>=3.6.3,<3.11.0 Babel>=1.3,<3.0 Flask-Babel>=0.11.1,<4.1.0 -# Flask-Login>=0.3.2,<0.6.4 Flask-Principal>=0.3.2,<0.5.1 Flask>=1.0.2,<3.1.0 iso-639>=0.4.5,<0.5.0 @@ -17,8 +15,8 @@ lxml>=4.9.1,<5.3.0 flask-wtf>=0.14.2,<1.3.0 chardet>=3.0.0,<4.1.0 advocate>=1.0.0,<1.1.0 -Flask-Limiter>=2.3.0,<3.6.0 +Flask-Limiter>=2.3.0,<3.9.0 regex>=2022.3.2,<2024.6.25 bleach>=6.0.0,<6.2.0 python-magic>=0.4.27,<0.5.0 -flask-httpAuth>=4.4.0 +flask-httpAuth>=4.4.0,<5.0.0