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
This commit is contained in:
Kovid Goyal 2019-08-29 20:15:00 +05:30
parent 9cf6125f19
commit 85ccc7bdfc
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 21 additions and 11 deletions

View File

@ -1144,6 +1144,16 @@ def open_url(qurl):
QDesktopServices.openUrl(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(): def get_current_db():
''' '''
This method will try to return the current database in use by the user as This method will try to return the current database in use by the user as

View File

@ -25,7 +25,7 @@ from calibre.ebooks.metadata.search_internet import (
) )
from calibre.gui2 import ( from calibre.gui2 import (
NO_URL_FORMATTING, choose_save_file, config, default_author_link, gprefs, 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 ( from calibre.gui2.dnd import (
dnd_get_files, dnd_get_image, dnd_has_extension, dnd_has_image, image_extensions 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): def link_activated(self, link):
self._link_clicked = True self._link_clicked = True
if unicode_type(link.scheme()) in ('http', 'https'): 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)) link = unicode_type(link.toString(NO_URL_FORMATTING))
self.link_clicked.emit(link) 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]) url = url_for_book_search(data.where, title=self.last_data['title'], author=self.last_data['authors'][0])
else: else:
url = url_for_author_search(data.where, author=data.author) url = url_for_author_search(data.where, author=data.author)
open_url(url) safe_open_url(url)
def handle_click(self, link): def handle_click(self, link):
typ, val = link.partition(':')[0::2] typ, val = link.partition(':')[0::2]
@ -879,7 +879,7 @@ class BookDetails(QWidget): # {{{
self.search_requested.emit(from_hex_unicode(val)) self.search_requested.emit(from_hex_unicode(val))
else: else:
try: try:
open_url(QUrl(link, QUrl.TolerantMode)) safe_open_url(QUrl(link, QUrl.TolerantMode))
except: except:
import traceback import traceback
traceback.print_exc() traceback.print_exc()

View File

@ -17,7 +17,7 @@ from PyQt5.QtWebKit import QWebSettings, QWebElement
from calibre.gui2.viewer.flip import SlideFlip from calibre.gui2.viewer.flip import SlideFlip
from calibre.gui2.shortcuts import Shortcuts 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 import prints
from calibre.customize.ui import all_viewer_plugins from calibre.customize.ui import all_viewer_plugins
from calibre.gui2.viewer.keys import SHORTCUTS 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)) url = self.document.search_online_url.replace('{text}', QUrl().toPercentEncoding(text))
if not isinstance(url, bytes): if not isinstance(url, bytes):
url = url.encode('utf-8') url = url.encode('utf-8')
open_url(QUrl.fromEncoded(url)) safe_open_url(QUrl.fromEncoded(url))
def set_manager(self, manager): def set_manager(self, manager):
self.manager = manager self.manager = manager

View File

@ -23,7 +23,7 @@ from calibre.customize.ui import available_input_formats
from calibre.ebooks.oeb.iterator.book import EbookIterator from calibre.ebooks.oeb.iterator.book import EbookIterator
from calibre.gui2 import ( from calibre.gui2 import (
Application, add_to_recent_docs, choose_files, error_dialog, info_dialog, 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.toc import TOC
from calibre.gui2.viewer.ui import Main as MainWindow 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, 'Failed to use the custom dictionary for language: %s Falling back to default dictionary.') % lang,
det_msg=traceback.format_exc(), show=True) det_msg=traceback.format_exc(), show=True)
url = default_lookup_website(lang).format(word=word) url = default_lookup_website(lang).format(word=word)
open_url(url) safe_open_url(url)
def print_book(self): def print_book(self):
if self.iterator is None: if self.iterator is None:
@ -743,7 +743,7 @@ class EbookViewer(MainWindow):
# entry, since this one did not cause any scrolling at all. # entry, since this one did not cause any scrolling at all.
QTimer.singleShot(10, self.update_indexing_state) QTimer.singleShot(10, self.update_indexing_state)
else: else:
open_url(url) safe_open_url(url)
def load_started(self): def load_started(self):
self.open_progress_indicator(_('Loading flow...')) self.open_progress_indicator(_('Loading flow...'))

View File

@ -13,7 +13,7 @@ from PyQt5.Qt import (
QRegExpValidator, QRegExp, QPalette, QColor, QBrush, QPainter, QRegExpValidator, QRegExp, QPalette, QColor, QBrush, QPainter,
QDockWidget, QSize, QWebView, QLabel, QVBoxLayout) 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.main_window import MainWindow
from calibre.gui2.search_box import SearchBox2 from calibre.gui2.search_box import SearchBox2
from calibre.gui2.viewer.documentview import DocumentView from calibre.gui2.viewer.documentview import DocumentView
@ -83,7 +83,7 @@ class Metadata(QWebView): # {{{
def link_clicked(self, qurl): def link_clicked(self, qurl):
if qurl.scheme() in ('http', 'https'): if qurl.scheme() in ('http', 'https'):
return open_url(qurl) return safe_open_url(qurl)
def update_layout(self): def update_layout(self):
self.setGeometry(0, 0, self.parent().width(), self.parent().height()) self.setGeometry(0, 0, self.parent().width(), self.parent().height())