From 4bf85ee3cb6168016e64cd8642fc31ae3ee2cfba Mon Sep 17 00:00:00 2001 From: David Rosca Date: Wed, 10 Jan 2018 12:36:41 +0100 Subject: [PATCH] WebPage: Register QWebChannel on isolated ApplicationWorld This way scripts on pages don't have access to it. Exception is qupzilla: scheme as internal pages requires the bridge. GreaseMonkey userscripts now runs on ApplicationWorld too. This fixes userscript that depend on script world being isolated from main page world. Tested with 4ChanX + OneeChan. --- src/lib/app/mainapplication.cpp | 12 ++++++++++-- src/lib/autofill/autofill.cpp | 5 +++-- src/lib/navigation/websearchbar.cpp | 2 +- src/lib/tools/scripts.cpp | 18 ++++++++++++++---- src/lib/tools/scripts.h | 4 ++-- src/lib/webengine/webpage.cpp | 24 +++++++++++++++++++----- src/lib/webengine/webpage.h | 4 +++- src/lib/webtab/searchtoolbar.cpp | 4 ++-- src/plugins/GreaseMonkey/gm_script.cpp | 6 +++--- 9 files changed, 57 insertions(+), 22 deletions(-) diff --git a/src/lib/app/mainapplication.cpp b/src/lib/app/mainapplication.cpp index a61031160..5f726b8f2 100644 --- a/src/lib/app/mainapplication.cpp +++ b/src/lib/app/mainapplication.cpp @@ -273,11 +273,19 @@ MainApplication::MainApplication(int &argc, char** argv) QWebEngineScript script; script.setName(QSL("_falkon_webchannel")); script.setInjectionPoint(QWebEngineScript::DocumentCreation); - script.setWorldId(QWebEngineScript::MainWorld); + script.setWorldId(WebPage::SafeJsWorld); script.setRunsOnSubFrames(true); - script.setSourceCode(Scripts::setupWebChannel()); + script.setSourceCode(Scripts::setupWebChannel(script.worldId())); m_webProfile->scripts()->insert(script); + QWebEngineScript script2; + script2.setName(QSL("_qupzilla_webchannel2")); + script2.setInjectionPoint(QWebEngineScript::DocumentCreation); + script2.setWorldId(WebPage::UnsafeJsWorld); + script2.setRunsOnSubFrames(true); + script2.setSourceCode(Scripts::setupWebChannel(script2.worldId())); + m_webProfile->scripts()->insert(script2); + if (!isPrivate()) { m_sessionManager = new SessionManager(this); m_autoSaver = new AutoSaver(this); diff --git a/src/lib/autofill/autofill.cpp b/src/lib/autofill/autofill.cpp index 51a733afa..32e8eb5df 100644 --- a/src/lib/autofill/autofill.cpp +++ b/src/lib/autofill/autofill.cpp @@ -1,6 +1,6 @@ /* ============================================================ * Falkon - Qt web browser -* Copyright (C) 2010-2017 David Rosca +* Copyright (C) 2010-2018 David Rosca * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,6 +27,7 @@ #include "passwordmanager.h" #include "qztools.h" #include "scripts.h" +#include "webpage.h" #include #include @@ -45,7 +46,7 @@ AutoFill::AutoFill(QObject* parent) QWebEngineScript script; script.setName(QSL("_falkon_autofill")); script.setInjectionPoint(QWebEngineScript::DocumentReady); - script.setWorldId(QWebEngineScript::MainWorld); + script.setWorldId(WebPage::SafeJsWorld); script.setRunsOnSubFrames(true); script.setSourceCode(Scripts::setupFormObserver()); mApp->webProfile()->scripts()->insert(script); diff --git a/src/lib/navigation/websearchbar.cpp b/src/lib/navigation/websearchbar.cpp index 55b9c1aa4..ccb588018 100644 --- a/src/lib/navigation/websearchbar.cpp +++ b/src/lib/navigation/websearchbar.cpp @@ -1,6 +1,6 @@ /* ============================================================ * Falkon - Qt web browser -* Copyright (C) 2010-2017 David Rosca +* Copyright (C) 2010-2018 David Rosca * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/lib/tools/scripts.cpp b/src/lib/tools/scripts.cpp index e260b1c8a..fab318e38 100644 --- a/src/lib/tools/scripts.cpp +++ b/src/lib/tools/scripts.cpp @@ -18,13 +18,17 @@ #include "scripts.h" #include "qztools.h" +#include "webpage.h" #include -QString Scripts::setupWebChannel() +QString Scripts::setupWebChannel(quint32 worldId) { - QString source = QL1S("(function() {" - "%1" + QString source = QL1S("// ==UserScript==\n" + "// %1\n" + "// ==/UserScript==\n\n" + "(function() {" + "%2" "" "function registerExternal(e) {" " window.external = e;" @@ -66,7 +70,13 @@ QString Scripts::setupWebChannel() "" "})()"); - return source.arg(QzTools::readAllFileContents(QSL(":/qtwebchannel/qwebchannel.js"))); + QString match; + if (worldId == WebPage::SafeJsWorld) { + match = QSL("@exclude qupzilla:*"); + } else { + match = QSL("@include qupzilla:*"); + } + return source.arg(match, QzTools::readAllFileContents(QSL(":/qtwebchannel/qwebchannel.js"))); } QString Scripts::setupFormObserver() diff --git a/src/lib/tools/scripts.h b/src/lib/tools/scripts.h index 04f6e46d3..4cf799c30 100644 --- a/src/lib/tools/scripts.h +++ b/src/lib/tools/scripts.h @@ -1,6 +1,6 @@ /* ============================================================ * Falkon - Qt web browser -* Copyright (C) 2015-2016 David Rosca +* Copyright (C) 2015-2018 David Rosca * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ class QWebEngineView; class FALKON_EXPORT Scripts { public: - static QString setupWebChannel(); + static QString setupWebChannel(quint32 worldId); static QString setupFormObserver(); static QString setCss(const QString &css); diff --git a/src/lib/webengine/webpage.cpp b/src/lib/webengine/webpage.cpp index 544b13b9a..fa252e43f 100644 --- a/src/lib/webengine/webpage.cpp +++ b/src/lib/webengine/webpage.cpp @@ -71,9 +71,7 @@ WebPage::WebPage(QObject* parent) , m_blockAlerts(false) , m_secureStatus(false) { - QWebChannel *channel = new QWebChannel(this); - ExternalJsObject::setupWebChannel(channel, this); - setWebChannel(channel); + setupWebChannelForUrl(QUrl()); connect(this, &QWebEnginePage::loadProgress, this, &WebPage::progress); connect(this, &QWebEnginePage::loadFinished, this, &WebPage::finished); @@ -167,13 +165,13 @@ WebHitTestResult WebPage::hitTestContent(const QPoint &pos) const void WebPage::scroll(int x, int y) { - runJavaScript(QSL("window.scrollTo(window.scrollX + %1, window.scrollY + %2)").arg(x).arg(y), WebPage::SafeJsWorld); + runJavaScript(QSL("window.scrollTo(window.scrollX + %1, window.scrollY + %2)").arg(x).arg(y), SafeJsWorld); } void WebPage::setScrollPosition(const QPointF &pos) { const QPointF v = mapToViewport(pos.toPoint()); - runJavaScript(QSL("window.scrollTo(%1, %2)").arg(v.x()).arg(v.y()), WebPage::SafeJsWorld); + runJavaScript(QSL("window.scrollTo(%1, %2)").arg(v.x()).arg(v.y()), SafeJsWorld); } bool WebPage::isRunningLoop() @@ -362,6 +360,20 @@ void WebPage::renderProcessTerminated(QWebEnginePage::RenderProcessTerminationSt }); } +void WebPage::setupWebChannelForUrl(const QUrl &url) +{ + QWebChannel *channel = webChannel(); + if (!channel) { + channel = new QWebChannel(this); + ExternalJsObject::setupWebChannel(channel, this); + } + if (url.scheme() == QL1S("qupzilla")) { + setWebChannel(channel, UnsafeJsWorld); + } else { + setWebChannel(channel, SafeJsWorld); + } +} + bool WebPage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame) { if (!mApp->plugins()->acceptNavigationRequest(this, url, type, isMainFrame)) @@ -373,6 +385,8 @@ bool WebPage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::Navigatio const bool isWeb = url.scheme() == QL1S("http") || url.scheme() == QL1S("https"); const bool globalJsEnabled = mApp->webSettings()->testAttribute(QWebEngineSettings::JavascriptEnabled); settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, isWeb ? globalJsEnabled : true); + + setupWebChannelForUrl(url); } return result; diff --git a/src/lib/webengine/webpage.h b/src/lib/webengine/webpage.h index 3ba97368a..007c5f0f5 100644 --- a/src/lib/webengine/webpage.h +++ b/src/lib/webengine/webpage.h @@ -39,6 +39,7 @@ class FALKON_EXPORT WebPage : public QWebEnginePage public: enum JsWorld { + UnsafeJsWorld = QWebEngineScript::MainWorld, SafeJsWorld = QWebEngineScript::ApplicationWorld }; @@ -48,7 +49,7 @@ public: WebView *view() const; bool execPrintPage(QPrinter *printer, int timeout = 1000); - QVariant execJavaScript(const QString &scriptSource, quint32 worldId = QWebEngineScript::MainWorld, int timeout = 500); + QVariant execJavaScript(const QString &scriptSource, quint32 worldId = UnsafeJsWorld, int timeout = 500); QPointF mapToViewport(const QPointF &pos) const; WebHitTestResult hitTestContent(const QPoint &pos) const; @@ -84,6 +85,7 @@ private slots: void renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, int exitCode); private: + void setupWebChannelForUrl(const QUrl &url); bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) Q_DECL_OVERRIDE; bool certificateError(const QWebEngineCertificateError &error) Q_DECL_OVERRIDE; QStringList chooseFiles(FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes) Q_DECL_OVERRIDE; diff --git a/src/lib/webtab/searchtoolbar.cpp b/src/lib/webtab/searchtoolbar.cpp index 3e333d0a7..54d41bf29 100644 --- a/src/lib/webtab/searchtoolbar.cpp +++ b/src/lib/webtab/searchtoolbar.cpp @@ -1,6 +1,6 @@ /* ============================================================ * Falkon - Qt web browser -* Copyright (C) 2010-2017 David Rosca +* Copyright (C) 2010-2018 David Rosca * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -133,7 +133,7 @@ void SearchToolBar::searchText(const QString &text) ui->lineEdit->style()->polish(ui->lineEdit); // Clear selection - m_view->page()->runJavaScript(QSL("window.getSelection().empty();")); + m_view->page()->runJavaScript(QSL("window.getSelection().empty();"), WebPage::SafeJsWorld); }); } diff --git a/src/plugins/GreaseMonkey/gm_script.cpp b/src/plugins/GreaseMonkey/gm_script.cpp index 82ad0cd10..801a2d2b9 100644 --- a/src/plugins/GreaseMonkey/gm_script.cpp +++ b/src/plugins/GreaseMonkey/gm_script.cpp @@ -1,6 +1,6 @@ /* ============================================================ * GreaseMonkey plugin for Falkon -* Copyright (C) 2012-2017 David Rosca +* Copyright (C) 2012-2018 David Rosca * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,9 +19,9 @@ #include "gm_manager.h" #include "gm_downloader.h" -#include "qzregexp.h" #include "delayedfilewatcher.h" #include "mainapplication.h" +#include "webpage.h" #include #include @@ -131,7 +131,7 @@ QWebEngineScript GM_Script::webScript() const QWebEngineScript script; script.setSourceCode(QSL("%1\n%2").arg(m_manager->bootstrapScript(), m_script)); script.setName(fullName()); - script.setWorldId(QWebEngineScript::MainWorld); + script.setWorldId(WebPage::SafeJsWorld); script.setRunsOnSubFrames(!m_noframes); return script; }