summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2016-01-07 16:13:16 +0100
committerAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2016-01-15 10:44:48 +0000
commitbc315ce05298cf500f45f3a897b0f7c0408fd611 (patch)
tree7560fbe0e18f63dcc62a5e9d0f328b3cb2b67bec /src
parent4bf31a52de2f9c8d049d2fd7410b9cfb88d41168 (diff)
Add API to set WebChannel on isolated world
Make it possible to set a web-channel so that it can only be accessed by private scripts. Pulls in needed API extension in 3rdparty. Task-number: QTBUG-50318 Change-Id: I61bcce5c318dffe0a406ee8cddf31f58a021c22c Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
Diffstat (limited to 'src')
m---------src/3rdparty0
-rw-r--r--src/core/common/qt_messages.h5
-rw-r--r--src/core/renderer/web_channel_ipc_transport.cpp52
-rw-r--r--src/core/renderer/web_channel_ipc_transport.h5
-rw-r--r--src/core/web_channel_ipc_transport_host.cpp16
-rw-r--r--src/core/web_channel_ipc_transport_host.h6
-rw-r--r--src/core/web_contents_adapter.cpp17
-rw-r--r--src/core/web_contents_adapter.h2
-rw-r--r--src/core/web_contents_adapter_p.h1
-rw-r--r--src/webengine/api/qquickwebengineview.cpp28
-rw-r--r--src/webengine/api/qquickwebengineview_p.h4
-rw-r--r--src/webengine/api/qquickwebengineview_p_p.h1
-rw-r--r--src/webenginewidgets/api/qwebenginepage.cpp33
-rw-r--r--src/webenginewidgets/api/qwebenginepage.h1
14 files changed, 138 insertions, 33 deletions
diff --git a/src/3rdparty b/src/3rdparty
-Subproject e921076fcf1736db4aeb76877c6f608f42f4acc
+Subproject 1334c7619425f44b0473c1c808ed1005fdb3e2a
diff --git a/src/core/common/qt_messages.h b/src/core/common/qt_messages.h
index 02f8716d6..386f8fc76 100644
--- a/src/core/common/qt_messages.h
+++ b/src/core/common/qt_messages.h
@@ -34,8 +34,9 @@ IPC_MESSAGE_ROUTED1(RenderViewObserverQt_FetchDocumentInnerText,
IPC_MESSAGE_ROUTED1(RenderViewObserverQt_SetBackgroundColor,
uint32 /* color */)
-IPC_MESSAGE_ROUTED0(WebChannelIPCTransport_Install)
-IPC_MESSAGE_ROUTED1(WebChannelIPCTransport_Message, std::vector<char> /*binaryJSON*/)
+IPC_MESSAGE_ROUTED1(WebChannelIPCTransport_Install, uint /* worldId */)
+IPC_MESSAGE_ROUTED1(WebChannelIPCTransport_Uninstall, uint /* worldId */)
+IPC_MESSAGE_ROUTED2(WebChannelIPCTransport_Message, std::vector<char> /*binaryJSON*/, uint /* worldId */)
// User scripts messages
IPC_MESSAGE_ROUTED1(RenderViewObserverHelper_AddScript,
diff --git a/src/core/renderer/web_channel_ipc_transport.cpp b/src/core/renderer/web_channel_ipc_transport.cpp
index 12acd348e..43dc3cd81 100644
--- a/src/core/renderer/web_channel_ipc_transport.cpp
+++ b/src/core/renderer/web_channel_ipc_transport.cpp
@@ -57,7 +57,8 @@ namespace QtWebEngineCore {
class WebChannelTransport : public gin::Wrappable<WebChannelTransport> {
public:
static gin::WrapperInfo kWrapperInfo;
- static void Install(blink::WebFrame *frame);
+ static void Install(blink::WebFrame *frame, uint worldId);
+ static void Uninstall(blink::WebFrame *frame, uint worldId);
private:
content::RenderView *GetRenderView(v8::Isolate *isolate);
WebChannelTransport() { }
@@ -89,11 +90,15 @@ private:
gin::WrapperInfo WebChannelTransport::kWrapperInfo = { gin::kEmbedderNativeGin };
-void WebChannelTransport::Install(blink::WebFrame *frame)
+void WebChannelTransport::Install(blink::WebFrame *frame, uint worldId)
{
v8::Isolate *isolate = v8::Isolate::GetCurrent();
v8::HandleScope handleScope(isolate);
- v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
+ v8::Handle<v8::Context> context;
+ if (worldId == 0)
+ context = frame->mainWorldScriptContext();
+ else
+ context = frame->toWebLocalFrame()->isolatedWorldScriptContext(worldId, 0);
v8::Context::Scope contextScope(context);
gin::Handle<WebChannelTransport> transport = gin::CreateHandle(isolate, new WebChannelTransport);
@@ -106,6 +111,24 @@ void WebChannelTransport::Install(blink::WebFrame *frame)
qt->Set(gin::StringToV8(isolate, "webChannelTransport"), transport.ToV8());
}
+void WebChannelTransport::Uninstall(blink::WebFrame *frame, uint worldId)
+{
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope handleScope(isolate);
+ v8::Handle<v8::Context> context;
+ if (worldId == 0)
+ context = frame->mainWorldScriptContext();
+ else
+ context = frame->toWebLocalFrame()->isolatedWorldScriptContext(worldId, 0);
+ v8::Context::Scope contextScope(context);
+
+ v8::Handle<v8::Object> global(context->Global());
+ v8::Handle<v8::Object> qt = global->Get(gin::StringToV8(isolate, "qt"))->ToObject();
+ if (qt.IsEmpty())
+ return;
+ qt->Delete(gin::StringToV8(isolate, "webChannelTransport"));
+}
+
gin::ObjectTemplateBuilder WebChannelTransport::GetObjectTemplateBuilder(v8::Isolate *isolate)
{
return gin::Wrappable<WebChannelTransport>::GetObjectTemplateBuilder(isolate).SetMethod("send", &WebChannelTransport::NativeQtSendMessage);
@@ -130,15 +153,23 @@ WebChannelIPCTransport::WebChannelIPCTransport(content::RenderView *renderView)
{
}
-void WebChannelIPCTransport::installExtension()
+void WebChannelIPCTransport::installWebChannel(uint worldId)
+{
+ blink::WebView *webView = render_view()->GetWebView();
+ if (!webView)
+ return;
+ WebChannelTransport::Install(webView->mainFrame(), worldId);
+}
+
+void WebChannelIPCTransport::uninstallWebChannel(uint worldId)
{
blink::WebView *webView = render_view()->GetWebView();
if (!webView)
return;
- WebChannelTransport::Install(webView->mainFrame());
+ WebChannelTransport::Uninstall(webView->mainFrame(), worldId);
}
-void WebChannelIPCTransport::dispatchWebChannelMessage(const std::vector<char> &binaryJSON)
+void WebChannelIPCTransport::dispatchWebChannelMessage(const std::vector<char> &binaryJSON, uint worldId)
{
blink::WebView *webView = render_view()->GetWebView();
if (!webView)
@@ -151,7 +182,11 @@ void WebChannelIPCTransport::dispatchWebChannelMessage(const std::vector<char> &
v8::Isolate *isolate = v8::Isolate::GetCurrent();
v8::HandleScope handleScope(isolate);
blink::WebFrame *frame = webView->mainFrame();
- v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
+ v8::Handle<v8::Context> context;
+ if (worldId == 0)
+ context = frame->mainWorldScriptContext();
+ else
+ context = frame->toWebLocalFrame()->isolatedWorldScriptContext(worldId, 0);
v8::Context::Scope contextScope(context);
v8::Handle<v8::Object> global(context->Global());
@@ -183,7 +218,8 @@ bool WebChannelIPCTransport::OnMessageReceived(const IPC::Message &message)
{
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(WebChannelIPCTransport, message)
- IPC_MESSAGE_HANDLER(WebChannelIPCTransport_Install, installExtension)
+ IPC_MESSAGE_HANDLER(WebChannelIPCTransport_Install, installWebChannel)
+ IPC_MESSAGE_HANDLER(WebChannelIPCTransport_Uninstall, uninstallWebChannel)
IPC_MESSAGE_HANDLER(WebChannelIPCTransport_Message, dispatchWebChannelMessage)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
diff --git a/src/core/renderer/web_channel_ipc_transport.h b/src/core/renderer/web_channel_ipc_transport.h
index ba378f440..e5d65c358 100644
--- a/src/core/renderer/web_channel_ipc_transport.h
+++ b/src/core/renderer/web_channel_ipc_transport.h
@@ -52,8 +52,9 @@ public:
WebChannelIPCTransport(content::RenderView *);
private:
- void dispatchWebChannelMessage(const std::vector<char> &binaryJSON);
- void installExtension();
+ void dispatchWebChannelMessage(const std::vector<char> &binaryJSON, uint worldId);
+ void installWebChannel(uint worldId);
+ void uninstallWebChannel(uint worldId);
virtual bool OnMessageReceived(const IPC::Message &message) Q_DECL_OVERRIDE;
};
diff --git a/src/core/web_channel_ipc_transport_host.cpp b/src/core/web_channel_ipc_transport_host.cpp
index 800e78308..1e01c6e8e 100644
--- a/src/core/web_channel_ipc_transport_host.cpp
+++ b/src/core/web_channel_ipc_transport_host.cpp
@@ -46,23 +46,33 @@
namespace QtWebEngineCore {
-WebChannelIPCTransportHost::WebChannelIPCTransportHost(content::WebContents *contents, QObject *parent)
+WebChannelIPCTransportHost::WebChannelIPCTransportHost(content::WebContents *contents, uint worldId, QObject *parent)
: QWebChannelAbstractTransport(parent)
, content::WebContentsObserver(contents)
+ , m_worldId(worldId)
{
- Send(new WebChannelIPCTransport_Install(routing_id()));
+ Send(new WebChannelIPCTransport_Install(routing_id(), m_worldId));
}
WebChannelIPCTransportHost::~WebChannelIPCTransportHost()
{
}
+void WebChannelIPCTransportHost::setWorldId(uint worldId)
+{
+ if (worldId == m_worldId)
+ return;
+ Send(new WebChannelIPCTransport_Uninstall(routing_id(), m_worldId));
+ m_worldId = worldId;
+ Send(new WebChannelIPCTransport_Install(routing_id(), m_worldId));
+}
+
void WebChannelIPCTransportHost::sendMessage(const QJsonObject &message)
{
QJsonDocument doc(message);
int size = 0;
const char *rawData = doc.rawData(&size);
- Send(new WebChannelIPCTransport_Message(routing_id(), std::vector<char>(rawData, rawData + size)));
+ Send(new WebChannelIPCTransport_Message(routing_id(), std::vector<char>(rawData, rawData + size), m_worldId));
}
void WebChannelIPCTransportHost::onWebChannelMessage(const std::vector<char> &message)
diff --git a/src/core/web_channel_ipc_transport_host.h b/src/core/web_channel_ipc_transport_host.h
index 9c21116f1..c84a0ee55 100644
--- a/src/core/web_channel_ipc_transport_host.h
+++ b/src/core/web_channel_ipc_transport_host.h
@@ -52,15 +52,19 @@ class WebChannelIPCTransportHost : public QWebChannelAbstractTransport
, public content::WebContentsObserver
{
public:
- WebChannelIPCTransportHost(content::WebContents *, QObject *parent = 0);
+ WebChannelIPCTransportHost(content::WebContents *, uint worldId = 0, QObject *parent = 0);
virtual ~WebChannelIPCTransportHost();
// QWebChannelAbstractTransport
virtual void sendMessage(const QJsonObject &message) Q_DECL_OVERRIDE;
+ void setWorldId(uint worldId);
+ uint worldId() const { return m_worldId; }
+
private:
bool OnMessageReceived(const IPC::Message& message) Q_DECL_OVERRIDE;
void onWebChannelMessage(const std::vector<char> &message);
+ uint m_worldId;
};
} // namespace
diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp
index fc77bdb9d..657a2eed3 100644
--- a/src/core/web_contents_adapter.cpp
+++ b/src/core/web_contents_adapter.cpp
@@ -315,6 +315,7 @@ WebContentsAdapterPrivate::WebContentsAdapterPrivate()
// This has to be the first thing we create, and the last we destroy.
: engineContext(WebEngineContext::current())
, webChannel(0)
+ , webChannelWorld(0)
, adapterClient(0)
, nextRequestId(CallbackDirectory::ReservedCallbackIdsEnd)
, lastFindRequestId(0)
@@ -961,17 +962,23 @@ QWebChannel *WebContentsAdapter::webChannel() const
return d->webChannel;
}
-void WebContentsAdapter::setWebChannel(QWebChannel *channel)
+void WebContentsAdapter::setWebChannel(QWebChannel *channel, uint worldId)
{
Q_D(WebContentsAdapter);
- if (d->webChannel == channel)
+ if (d->webChannel == channel && d->webChannelWorld == worldId)
return;
+
if (!d->webChannelTransport.get())
- d->webChannelTransport.reset(new WebChannelIPCTransportHost(d->webContents.get()));
- else
- d->webChannel->disconnectFrom(d->webChannelTransport.get());
+ d->webChannelTransport.reset(new WebChannelIPCTransportHost(d->webContents.get(), worldId));
+ else {
+ if (d->webChannel != channel)
+ d->webChannel->disconnectFrom(d->webChannelTransport.get());
+ if (d->webChannelWorld != worldId)
+ d->webChannelTransport->setWorldId(worldId);
+ }
d->webChannel = channel;
+ d->webChannelWorld = worldId;
if (!channel) {
d->webChannelTransport.reset();
return;
diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h
index 90e035da1..ddb313c32 100644
--- a/src/core/web_contents_adapter.h
+++ b/src/core/web_contents_adapter.h
@@ -150,7 +150,7 @@ public:
BrowserContextQt* browserContext();
BrowserContextAdapter* browserContextAdapter();
QWebChannel *webChannel() const;
- void setWebChannel(QWebChannel *);
+ void setWebChannel(QWebChannel *, uint worldId);
QPointF lastScrollOffset() const;
QSizeF lastContentsSize() const;
diff --git a/src/core/web_contents_adapter_p.h b/src/core/web_contents_adapter_p.h
index 63f075bce..709cb8c2a 100644
--- a/src/core/web_contents_adapter_p.h
+++ b/src/core/web_contents_adapter_p.h
@@ -85,6 +85,7 @@ public:
scoped_ptr<RenderViewObserverHostQt> renderViewObserverHost;
scoped_ptr<WebChannelIPCTransportHost> webChannelTransport;
QWebChannel *webChannel;
+ unsigned int webChannelWorld;
WebContentsAdapterClient *adapterClient;
quint64 nextRequestId;
int lastFindRequestId;
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index 61a19faa5..2eef6a767 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -109,9 +109,10 @@ QQuickWebEngineViewPrivate::QQuickWebEngineViewPrivate()
, isLoading(false)
, m_activeFocusOnPress(true)
, devicePixelRatio(QGuiApplication::primaryScreen()->devicePixelRatio())
+ , m_webChannel(0)
+ , m_webChannelWorld(0)
, m_dpiScale(1.0)
, m_backgroundColor(Qt::white)
- , m_webChannel(0)
{
// The gold standard for mobile web content is 160 dpi, and the devicePixelRatio expected
// is the (possibly quantized) ratio of device dpi to 160 dpi.
@@ -733,7 +734,7 @@ void QQuickWebEngineViewPrivate::adoptWebContents(WebContentsAdapter *webContent
// associate the webChannel with the new adapter
if (m_webChannel)
- adapter->setWebChannel(m_webChannel);
+ adapter->setWebChannel(m_webChannel, m_webChannelWorld);
// set initial background color if non-default
if (m_backgroundColor != Qt::white)
@@ -782,7 +783,7 @@ void QQuickWebEngineViewPrivate::ensureContentsAdapter()
if (m_backgroundColor != Qt::white)
adapter->backgroundColorChanged();
if (m_webChannel)
- adapter->setWebChannel(m_webChannel);
+ adapter->setWebChannel(m_webChannel, m_webChannelWorld);
if (explicitUrl.isValid())
adapter->load(explicitUrl);
// push down the page's user scripts
@@ -1209,7 +1210,7 @@ QQmlWebChannel *QQuickWebEngineView::webChannel()
if (!d->m_webChannel) {
d->m_webChannel = new QQmlWebChannel(this);
if (d->adapter)
- d->adapter->setWebChannel(d->m_webChannel);
+ d->adapter->setWebChannel(d->m_webChannel, d->m_webChannelWorld);
}
return d->m_webChannel;
@@ -1222,10 +1223,27 @@ void QQuickWebEngineView::setWebChannel(QQmlWebChannel *webChannel)
return;
d->m_webChannel = webChannel;
if (d->adapter)
- d->adapter->setWebChannel(webChannel);
+ d->adapter->setWebChannel(webChannel, d->m_webChannelWorld);
Q_EMIT webChannelChanged();
}
+uint QQuickWebEngineView::webChannelWorld() const
+{
+ Q_D(const QQuickWebEngineView);
+ return d->m_webChannelWorld;
+}
+
+void QQuickWebEngineView::setWebChannelWorld(uint webChannelWorld)
+{
+ Q_D(QQuickWebEngineView);
+ if (d->m_webChannelWorld == webChannelWorld)
+ return;
+ d->m_webChannelWorld = webChannelWorld;
+ if (d->adapter)
+ d->adapter->setWebChannel(d->m_webChannel, d->m_webChannelWorld);
+ Q_EMIT webChannelWorldChanged(webChannelWorld);
+}
+
void QQuickWebEngineView::grantFeaturePermission(const QUrl &securityOrigin, QQuickWebEngineView::Feature feature, bool granted)
{
if (!d_ptr->adapter)
diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h
index 43cdcb73e..7fdbafb77 100644
--- a/src/webengine/api/qquickwebengineview_p.h
+++ b/src/webengine/api/qquickwebengineview_p.h
@@ -111,6 +111,7 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem {
Q_PROPERTY(QSizeF contentsSize READ contentsSize NOTIFY contentsSizeChanged FINAL REVISION 3)
Q_PROPERTY(QPointF scrollPosition READ scrollPosition NOTIFY scrollPositionChanged FINAL REVISION 3)
Q_PROPERTY(bool audioMuted READ isAudioMuted WRITE setAudioMuted NOTIFY audioMutedChanged REVISION 3)
+ Q_PROPERTY(uint webChannelWorld READ webChannelWorld WRITE setWebChannelWorld NOTIFY webChannelWorldChanged REVISION 3)
#ifdef ENABLE_QML_TESTSUPPORT_API
Q_PROPERTY(QQuickWebEngineTestSupport *testSupport READ testSupport WRITE setTestSupport FINAL)
@@ -274,6 +275,8 @@ public:
QQmlWebChannel *webChannel();
void setWebChannel(QQmlWebChannel *);
QQuickWebEngineHistory *navigationHistory() const;
+ uint webChannelWorld() const;
+ void setWebChannelWorld(uint);
#ifdef ENABLE_QML_TESTSUPPORT_API
QQuickWebEngineTestSupport *testSupport() const;
@@ -329,6 +332,7 @@ Q_SIGNALS:
Q_REVISION(3) void scrollPositionChanged(const QPointF& position);
Q_REVISION(3) void audioMutedChanged(bool muted);
Q_REVISION(3) void wasRecentlyAudibleChanged(bool wasRecentlyAudible);
+ Q_REVISION(3) void webChannelWorldChanged(uint);
protected:
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h
index dd20c8972..6d72628a2 100644
--- a/src/webengine/api/qquickwebengineview_p_p.h
+++ b/src/webengine/api/qquickwebengineview_p_p.h
@@ -214,6 +214,7 @@ public:
QMap<quint64, QJSValue> m_callbacks;
QList<QSharedPointer<CertificateErrorController> > m_certificateErrorControllers;
QQmlWebChannel *m_webChannel;
+ uint m_webChannelWorld;
private:
QScopedPointer<QtWebEngineCore::UIDelegatesManager> m_uIDelegatesManager;
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index d97cb5a09..23ab9a244 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -551,7 +551,7 @@ QWebEngineSettings *QWebEnginePage::settings() const
* that is exposed in the JavaScript context of this page as \c qt.webChannelTransport.
*
* \since 5.5
- * \sa QWebChannel
+ * \sa setWebChannel
*/
QWebChannel *QWebEnginePage::webChannel() const
{
@@ -560,20 +560,41 @@ QWebChannel *QWebEnginePage::webChannel() const
}
/*!
+ * \overload
+ *
+ * Sets the web channel instance to be used by this page to \a channel and installs
+ * it in the main JavaScript world.
+ *
+ * With this method the web channel can be accessed by web page content. If the content
+ * is not under your control and might be hostile, this could be a security issue and
+ * you should consider installing it in a private JavaScript world.
+ *
+ * \since 5.5
+ * \sa QWebEngineScript::MainWorld
+ */
+
+void QWebEnginePage::setWebChannel(QWebChannel *channel)
+{
+ setWebChannel(channel, QWebEngineScript::MainWorld);
+}
+
+/*!
* Sets the web channel instance to be used by this page to \a channel and connects it to
* web engine's transport using Chromium IPC messages. The transport is exposed in the JavaScript
- * context of this page as
+ * world \a worldId as
* \c qt.webChannelTransport, which should be used when using the \l{Qt WebChannel JavaScript API}.
*
* \note The page does not take ownership of the channel object.
+ * \note Only one web channel can be installed per page, setting one even in another JavaScript
+ * world uninstalls any already installed web channel.
*
- * \since 5.5
+ * \since 5.7
+ * \sa QWebEngineScript::ScriptWorldId
*/
-
-void QWebEnginePage::setWebChannel(QWebChannel *channel)
+void QWebEnginePage::setWebChannel(QWebChannel *channel, uint worldId)
{
Q_D(QWebEnginePage);
- d->adapter->setWebChannel(channel);
+ d->adapter->setWebChannel(channel, worldId);
}
/*!
diff --git a/src/webenginewidgets/api/qwebenginepage.h b/src/webenginewidgets/api/qwebenginepage.h
index 950ae374a..c25d3d452 100644
--- a/src/webenginewidgets/api/qwebenginepage.h
+++ b/src/webenginewidgets/api/qwebenginepage.h
@@ -248,6 +248,7 @@ public:
QWebChannel *webChannel() const;
void setWebChannel(QWebChannel *);
+ void setWebChannel(QWebChannel *, uint worldId);
QColor backgroundColor() const;
void setBackgroundColor(const QColor &color);