From 85ccc7bdfc220ed0e934825e977355f5e98dee2d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 29 Aug 2019 20:15:00 +0530 Subject: [PATCH] Dont pass on requests to open executables to the OS from ebooks/metadata This is because some OSes (windows) actually launch these executables without asking the user --- src/calibre/gui2/__init__.py | 10 ++++++++++ src/calibre/gui2/book_details.py | 8 ++++---- src/calibre/gui2/viewer/documentview.py | 4 ++-- src/calibre/gui2/viewer/main.py | 6 +++--- src/calibre/gui2/viewer/ui.py | 4 ++-- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 7812dfe1c0..a56acfc9aa 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -1144,6 +1144,16 @@ def open_url(qurl): QDesktopServices.openUrl(qurl) +def safe_open_url(qurl): + if qurl.scheme() in ('', 'file'): + path = qurl.toLocalFile() + ext = os.path.splitext(path)[-1].lower()[1:] + if ext in ('exe', 'com', 'cmd', 'bat', 'sh', 'psh', 'ps1', 'vbs', 'js', 'wsf', 'vba', 'py', 'rb', 'pl'): + prints('Refusing to open file:', path) + return + open_url(qurl) + + def get_current_db(): ''' This method will try to return the current database in use by the user as diff --git a/src/calibre/gui2/book_details.py b/src/calibre/gui2/book_details.py index 357ea55c65..d8cfb3bd51 100644 --- a/src/calibre/gui2/book_details.py +++ b/src/calibre/gui2/book_details.py @@ -25,7 +25,7 @@ from calibre.ebooks.metadata.search_internet import ( ) from calibre.gui2 import ( NO_URL_FORMATTING, choose_save_file, config, default_author_link, gprefs, - open_url, pixmap_to_data, rating_font + safe_open_url, pixmap_to_data, rating_font ) from calibre.gui2.dnd import ( dnd_get_files, dnd_get_image, dnd_has_extension, dnd_has_image, image_extensions @@ -627,7 +627,7 @@ class BookInfo(QWebView): def link_activated(self, link): self._link_clicked = True if unicode_type(link.scheme()) in ('http', 'https'): - return open_url(link) + return safe_open_url(link) link = unicode_type(link.toString(NO_URL_FORMATTING)) self.link_clicked.emit(link) @@ -864,7 +864,7 @@ class BookDetails(QWidget): # {{{ url = url_for_book_search(data.where, title=self.last_data['title'], author=self.last_data['authors'][0]) else: url = url_for_author_search(data.where, author=data.author) - open_url(url) + safe_open_url(url) def handle_click(self, link): typ, val = link.partition(':')[0::2] @@ -879,7 +879,7 @@ class BookDetails(QWidget): # {{{ self.search_requested.emit(from_hex_unicode(val)) else: try: - open_url(QUrl(link, QUrl.TolerantMode)) + safe_open_url(QUrl(link, QUrl.TolerantMode)) except: import traceback traceback.print_exc() diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py index b8c210ef7f..7632e62548 100644 --- a/src/calibre/gui2/viewer/documentview.py +++ b/src/calibre/gui2/viewer/documentview.py @@ -17,7 +17,7 @@ from PyQt5.QtWebKit import QWebSettings, QWebElement from calibre.gui2.viewer.flip import SlideFlip from calibre.gui2.shortcuts import Shortcuts -from calibre.gui2 import open_url, secure_web_page, error_dialog +from calibre.gui2 import safe_open_url, secure_web_page, error_dialog from calibre import prints from calibre.customize.ui import all_viewer_plugins from calibre.gui2.viewer.keys import SHORTCUTS @@ -806,7 +806,7 @@ class DocumentView(QWebView): # {{{ url = self.document.search_online_url.replace('{text}', QUrl().toPercentEncoding(text)) if not isinstance(url, bytes): url = url.encode('utf-8') - open_url(QUrl.fromEncoded(url)) + safe_open_url(QUrl.fromEncoded(url)) def set_manager(self, manager): self.manager = manager diff --git a/src/calibre/gui2/viewer/main.py b/src/calibre/gui2/viewer/main.py index f28e2d3d74..1867ba807e 100644 --- a/src/calibre/gui2/viewer/main.py +++ b/src/calibre/gui2/viewer/main.py @@ -23,7 +23,7 @@ from calibre.customize.ui import available_input_formats from calibre.ebooks.oeb.iterator.book import EbookIterator from calibre.gui2 import ( Application, add_to_recent_docs, choose_files, error_dialog, info_dialog, - open_url, setup_gui_option_parser + safe_open_url, setup_gui_option_parser ) from calibre.gui2.viewer.toc import TOC from calibre.gui2.viewer.ui import Main as MainWindow @@ -433,7 +433,7 @@ class EbookViewer(MainWindow): 'Failed to use the custom dictionary for language: %s Falling back to default dictionary.') % lang, det_msg=traceback.format_exc(), show=True) url = default_lookup_website(lang).format(word=word) - open_url(url) + safe_open_url(url) def print_book(self): if self.iterator is None: @@ -743,7 +743,7 @@ class EbookViewer(MainWindow): # entry, since this one did not cause any scrolling at all. QTimer.singleShot(10, self.update_indexing_state) else: - open_url(url) + safe_open_url(url) def load_started(self): self.open_progress_indicator(_('Loading flow...')) diff --git a/src/calibre/gui2/viewer/ui.py b/src/calibre/gui2/viewer/ui.py index cf9c432509..e4d718f880 100644 --- a/src/calibre/gui2/viewer/ui.py +++ b/src/calibre/gui2/viewer/ui.py @@ -13,7 +13,7 @@ from PyQt5.Qt import ( QRegExpValidator, QRegExp, QPalette, QColor, QBrush, QPainter, QDockWidget, QSize, QWebView, QLabel, QVBoxLayout) -from calibre.gui2 import rating_font, error_dialog, open_url +from calibre.gui2 import rating_font, error_dialog, safe_open_url from calibre.gui2.main_window import MainWindow from calibre.gui2.search_box import SearchBox2 from calibre.gui2.viewer.documentview import DocumentView @@ -83,7 +83,7 @@ class Metadata(QWebView): # {{{ def link_clicked(self, qurl): if qurl.scheme() in ('http', 'https'): - return open_url(qurl) + return safe_open_url(qurl) def update_layout(self): self.setGeometry(0, 0, self.parent().width(), self.parent().height())