From f4d3f97cb75b657af5e0b10f380d948cd60656b0 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 24 Apr 2017 22:24:04 +0200 Subject: [PATCH] Implement private browsing for QtWebEngine --- .../browser/webengine/webenginesettings.py | 46 ++++++++++++------- qutebrowser/browser/webengine/webenginetab.py | 18 ++++---- qutebrowser/browser/webengine/webview.py | 16 +++++-- qutebrowser/config/configdata.py | 3 +- 4 files changed, 51 insertions(+), 32 deletions(-) diff --git a/qutebrowser/browser/webengine/webenginesettings.py b/qutebrowser/browser/webengine/webenginesettings.py index e1f4a22c9..2eb31d005 100644 --- a/qutebrowser/browser/webengine/webenginesettings.py +++ b/qutebrowser/browser/webengine/webenginesettings.py @@ -38,6 +38,12 @@ from qutebrowser.utils import (objreg, utils, standarddir, javascript, log, qtutils) +# The default QWebEngineProfile +default_profile = None +# The QWebEngineProfile used for private (off-the-record) windows +private_profile = None + + class Attribute(websettings.Attribute): """A setting set via QWebEngineSettings::setAttribute.""" @@ -67,7 +73,7 @@ class StaticSetter(websettings.StaticSetter): GLOBAL_SETTINGS = QWebEngineSettings.globalSettings -class ProfileSetter(websettings.Base): +class DefaultProfileSetter(websettings.Base): """A setting set on the QWebEngineProfile.""" @@ -78,16 +84,16 @@ class ProfileSetter(websettings.Base): def get(self, settings=None): utils.unused(settings) - getter = getattr(QWebEngineProfile.defaultProfile(), self._getter) + getter = getattr(default_profile, self._getter) return getter() def _set(self, value, settings=None): utils.unused(settings) - setter = getattr(QWebEngineProfile.defaultProfile(), self._setter) + setter = getattr(default_profile, self._setter) setter(value) -class PersistentCookiePolicy(ProfileSetter): +class PersistentCookiePolicy(DefaultProfileSetter): """The cookies -> store setting is different from other settings.""" @@ -141,19 +147,27 @@ def _init_stylesheet(profile): profile.scripts().insert(script) -def _init_profile(profile): - """Initialize settings set on the QWebEngineProfile.""" - profile.setCachePath(os.path.join(standarddir.cache(), 'webengine')) - profile.setPersistentStoragePath( - os.path.join(standarddir.data(), 'webengine')) - - def update_settings(section, option): """Update global settings when qwebsettings changed.""" websettings.update_mappings(MAPPINGS, section, option) - profile = QWebEngineProfile.defaultProfile() if section == 'ui' and option in ['hide-scrollbar', 'user-stylesheet']: - _init_stylesheet(profile) + _init_stylesheet(default_profile) + _init_stylesheet(private_profile) + + +def _init_profiles(): + """Init the two used QWebEngineProfiles""" + global default_profile, private_profile + default_profile = QWebEngineProfile.defaultProfile() + default_profile.setCachePath( + os.path.join(standarddir.cache(), 'webengine')) + default_profile.setPersistentStoragePath( + os.path.join(standarddir.data(), 'webengine')) + _init_stylesheet(default_profile) + + private_profile = QWebEngineProfile() + assert private_profile.isOffTheRecord() + _init_stylesheet(private_profile) def init(args): @@ -173,9 +187,7 @@ def init(args): else: log.misc.debug("Imported PyOpenGL as workaround") - profile = QWebEngineProfile.defaultProfile() - _init_profile(profile) - _init_stylesheet(profile) + _init_profiles() # We need to do this here as a WORKAROUND for # https://bugreports.qt.io/browse/QTBUG-58650 if not qtutils.version_check('5.9'): @@ -282,7 +294,7 @@ MAPPINGS = { 'local-storage': Attribute(QWebEngineSettings.LocalStorageEnabled), 'cache-size': - ProfileSetter(getter='httpCacheMaximumSize', + DefaultProfileSetter(getter='httpCacheMaximumSize', setter='setHttpCacheMaximumSize') }, 'general': { diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 57bd49f6b..7c17fc5b8 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -34,7 +34,8 @@ from PyQt5.QtWebEngineWidgets import (QWebEnginePage, QWebEngineScript, from qutebrowser.browser import browsertab, mouse, shared from qutebrowser.browser.webengine import (webview, webengineelem, tabhistory, interceptor, webenginequtescheme, - webenginedownloads) + webenginedownloads, + webenginesettings) from qutebrowser.misc import miscwidgets from qutebrowser.utils import (usertypes, qtutils, log, javascript, utils, objreg, jinja, debug) @@ -50,21 +51,23 @@ def init(): # https://www.riverbankcomputing.com/pipermail/pyqt/2016-September/038075.html global _qute_scheme_handler app = QApplication.instance() - profile = QWebEngineProfile.defaultProfile() log.init.debug("Initializing qute://* handler...") _qute_scheme_handler = webenginequtescheme.QuteSchemeHandler(parent=app) - _qute_scheme_handler.install(profile) + _qute_scheme_handler.install(webenginesettings.default_profile) + _qute_scheme_handler.install(webenginesettings.private_profile) log.init.debug("Initializing request interceptor...") host_blocker = objreg.get('host-blocker') req_interceptor = interceptor.RequestInterceptor( host_blocker, parent=app) - req_interceptor.install(profile) + req_interceptor.install(webenginesettings.default_profile) + req_interceptor.install(webenginesettings.private_profile) log.init.debug("Initializing QtWebEngine downloads...") download_manager = webenginedownloads.DownloadManager(parent=app) - download_manager.install(profile) + download_manager.install(webenginesettings.default_profile) + download_manager.install(webenginesettings.private_profile) objreg.register('webengine-download-manager', download_manager) @@ -522,11 +525,10 @@ class WebEngineTab(browsertab.AbstractTab): """A QtWebEngine tab in the browser.""" def __init__(self, *, win_id, mode_manager, private, parent=None): - # FIXME - assert not private super().__init__(win_id=win_id, mode_manager=mode_manager, private=private, parent=parent) - widget = webview.WebEngineView(tabdata=self.data, win_id=win_id) + widget = webview.WebEngineView(tabdata=self.data, win_id=win_id, + private=private) self.history = WebEngineHistory(self) self.scroller = WebEngineScroller(self, parent=self) self.caret = WebEngineCaret(win_id=win_id, mode_manager=mode_manager, diff --git a/qutebrowser/browser/webengine/webview.py b/qutebrowser/browser/webengine/webview.py index ee6e099bf..0cb9bb612 100644 --- a/qutebrowser/browser/webengine/webview.py +++ b/qutebrowser/browser/webengine/webview.py @@ -28,7 +28,7 @@ from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage # pylint: enable=no-name-in-module,import-error,useless-suppression from qutebrowser.browser import shared -from qutebrowser.browser.webengine import certificateerror +from qutebrowser.browser.webengine import certificateerror, webenginesettings from qutebrowser.config import config from qutebrowser.utils import (log, debug, usertypes, jinja, urlutils, message, objreg) @@ -38,13 +38,19 @@ class WebEngineView(QWebEngineView): """Custom QWebEngineView subclass with qutebrowser-specific features.""" - def __init__(self, tabdata, win_id, parent=None): + def __init__(self, *, tabdata, win_id, private, parent=None): super().__init__(parent) self._win_id = win_id self._tabdata = tabdata theme_color = self.style().standardPalette().color(QPalette.Base) - page = WebEnginePage(theme_color=theme_color, parent=self) + if private: + profile = webenginesettings.private_profile + assert profile.isOffTheRecord() + else: + profile = webenginesettings.default_profile + page = WebEnginePage(theme_color=theme_color, profile=profile, + parent=self) self.setPage(page) def shutdown(self): @@ -124,8 +130,8 @@ class WebEnginePage(QWebEnginePage): certificate_error = pyqtSignal() shutting_down = pyqtSignal() - def __init__(self, theme_color, parent=None): - super().__init__(parent) + def __init__(self, *, theme_color, profile, parent=None): + super().__init__(profile, parent) self._is_shutting_down = False self.featurePermissionRequested.connect( self._on_feature_permission_requested) diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index 11f46094f..0ac20a1e6 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -185,8 +185,7 @@ def data(readonly=False): "Encoding to use for editor."), ('private-browsing', - SettingValue(typ.Bool(), 'false', - backends=[usertypes.Backend.QtWebKit]), + SettingValue(typ.Bool(), 'false'), "Do not record visited pages in the history or store web page " "icons."),