Register QWebChannel on isolated ApplicationWorld

Mon, 12 Feb 2018 19:04:07 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Mon, 12 Feb 2018 19:04:07 +0100
changeset 6140
c20e2d414d0d
parent 6139
d24997c47244
child 6141
f4cecd941096

Register QWebChannel on isolated ApplicationWorld

This way scripts on pages don't have access to it. Exceptions are eric: and qthelp: schemes 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.

WebBrowser/Tools/Scripts.py file | annotate | diff | comparison | revisions
WebBrowser/WebBrowserPage.py file | annotate | diff | comparison | revisions
WebBrowser/WebBrowserWindow.py file | annotate | diff | comparison | revisions
diff -r d24997c47244 -r c20e2d414d0d WebBrowser/Tools/Scripts.py
--- a/WebBrowser/Tools/Scripts.py	Mon Feb 12 18:22:39 2018 +0100
+++ b/WebBrowser/Tools/Scripts.py	Mon Feb 12 19:04:07 2018 +0100
@@ -19,16 +19,22 @@
 from .WebBrowserTools import readAllFileContents
 
 
-def setupWebChannel():
+def setupWebChannel(worldId):
     """
     Function generating  a script to setup the web channel.
     
+    @param worlId world ID for which to setup the channel
+    @type int
     @return script to setup the web channel
     @rtype str
     """
     source = """
+// ==UserScript==
+{0}
+// ==/UserScript==
+
 (function() {{
-    {0}
+    {1}
     
     function registerExternal(e) {{
         window.external = e;
@@ -71,7 +77,13 @@
 
 }})()"""
     
-    return source.format(readAllFileContents(":/javascript/qwebchannel.js"))
+    from WebBrowser.WebBrowserPage import WebBrowserPage
+    if worldId == WebBrowserPage.SafeJsWorld:
+        match = "// @exclude eric:*"
+    else:
+        match = "// @include eric:*"
+    return source.format(
+        match, readAllFileContents(":/javascript/qwebchannel.js"))
 
 
 def setStyleSheet(css):
diff -r d24997c47244 -r c20e2d414d0d WebBrowser/WebBrowserPage.py
--- a/WebBrowser/WebBrowserPage.py	Mon Feb 12 18:22:39 2018 +0100
+++ b/WebBrowser/WebBrowserPage.py	Mon Feb 12 19:04:07 2018 +0100
@@ -43,10 +43,11 @@
         malicious web site as determined by safe browsing
     """
     if qVersionTuple() >= (5, 7, 0):
-        # SafeJsWorld = QWebEngineScript.ApplicationWorld
-        SafeJsWorld = QWebEngineScript.MainWorld
+        SafeJsWorld = QWebEngineScript.ApplicationWorld
+        # SafeJsWorld = QWebEngineScript.MainWorld
     else:
         SafeJsWorld = QWebEngineScript.MainWorld
+    UnsafeJsWorld = QWebEngineScript.MainWorld
     
     safeBrowsingAbort = pyqtSignal()
     safeBrowsingBad = pyqtSignal(str, str)
@@ -60,8 +61,6 @@
         super(WebBrowserPage, self).__init__(
             WebBrowserWindow.webProfile(), parent)
         
-        self.__setupWebChannel()
-        
         self.featurePermissionRequested.connect(
             self.__featurePermissionRequested)
         
@@ -81,6 +80,22 @@
         
         if qVersionTuple == (5, 10, 0):
             self.loadProgress.connect(self.__loadProgressSlot)
+        
+        # Workaround for changing webchannel world inside
+        # acceptNavigationRequest not working
+        self.__channelUrl = QUrl()
+        self.__channelWorldId = -1
+        self.__setupChannelTimer = QTimer(self)
+        self.__setupChannelTimer.setSingleShot(True)
+        self.__setupChannelTimer.setInterval(100)
+        self.__setupChannelTimer.timeout.connect(self.__setupChannelTimeout)
+    
+    @pyqtSlot()
+    def __setupChannelTimeout(self):
+        """
+        Private slot to initiate the setup of the web channel.
+        """
+        self.__setupWebChannelForUrl(self.__channelUrl)
     
     @pyqtSlot(int)
     def __loadProgressSlot(self, progress):
@@ -167,6 +182,9 @@
                 enable = True
             self.settings().setAttribute(
                 QWebEngineSettings.JavascriptEnabled, enable)
+            
+            self.__channelUrl = url
+            self.__setupChannelTimer.start()
         
         return result
     
@@ -347,18 +365,30 @@
         """
         return WebHitTestResult(self, pos)
     
-    def __setupWebChannel(self):
+    def __setupWebChannelForUrl(self, url):
         """
         Private method to setup a web channel to our external object.
+        
+        @param url URL for which to setup the web channel
+        @type QUrl
         """
-        oldChannel = self.webChannel()
-        newChannel = QWebChannel(self)
-        ExternalJsObject.setupWebChannel(newChannel, self)
-        self.setWebChannel(newChannel)
+        channel = self.webChannel()
+        if channel is None:
+            channel = QWebChannel(self)
+            ExternalJsObject.setupWebChannel(channel, self)
         
-        if oldChannel:
-            del oldChannel.registeredObjects["eric_object"]
-            del oldChannel
+        worldId = -1
+        if url.scheme() in ("eric", "qthelp"):
+            worldId = self.UnsafeJsWorld
+        else:
+            worldId = self.SafeJsWorld
+        if worldId != self.__channelWorldId:
+            self.__channelWorldId = worldId
+            try:
+                self.setWebChannel(channel, self.__channelWorldId)
+            except TypeError:
+                # pre Qt 5.7.0
+                self.setWebChannel(channel)
     
     def certificateError(self, error):
         """
diff -r d24997c47244 -r c20e2d414d0d WebBrowser/WebBrowserWindow.py
--- a/WebBrowser/WebBrowserWindow.py	Mon Feb 12 18:22:39 2018 +0100
+++ b/WebBrowser/WebBrowserWindow.py	Mon Feb 12 19:04:07 2018 +0100
@@ -4895,8 +4895,16 @@
             script.setInjectionPoint(QWebEngineScript.DocumentCreation)
             script.setWorldId(WebBrowserPage.SafeJsWorld)
             script.setRunsOnSubFrames(True)
-            script.setSourceCode(Scripts.setupWebChannel())
+            script.setSourceCode(Scripts.setupWebChannel(script.worldId()))
             cls._webProfile.scripts().insert(script)
+
+            script2 = QWebEngineScript()
+            script2.setName("_eric_webchannel2")
+            script2.setInjectionPoint(QWebEngineScript.DocumentCreation)
+            script2.setWorldId(WebBrowserPage.UnsafeJsWorld)
+            script2.setRunsOnSubFrames(True)
+            script2.setSourceCode(Scripts.setupWebChannel(script2.worldId()))
+            cls._webProfile.scripts().insert(script2)
         
         return cls._webProfile
     

eric ide

mercurial