greasemonkey: enable running in isolated js worlds
QtWebEngine (via chromium) has the ability to run injected scripts in isolated "worlds". What is isolated is just the javascript environment, so variables and functions defined by the page and the script won't clobber each other, or be able to interact (including variables saved to the global `window` object). The DOM is still accessible from "isolated" scripts. This is NOT a security measure. You cannot put untrusted scripts in one of these isolated worlds and expect it to not be able to do whatever page js can do, it is just for namespacing convenience. See https://stackoverflow.com/questions/9515704/insert-code-into-the-page-context-using-a-content-script for some examples of how to inject scripts into the page scope using DOM elements. Now you can specify the world ID in a `@qute-js-world` directive like: ``` // ==UserScript== // @name Do thing // @match *://some.site/* // @qute-js-world 1234 // ==/UserScript== document.body.innerHTML = "<strong>overwritten</strong>" ``` The QtWebEngine docs say worldid is a `quint32` so you can put whatever number (positive, whole, real) you want there. I have chosen to allow the `qutebrowser.utils.usertypes` enum as aliases for IDs that are predefined in `qutebrowser.browser.webengine.webenginetab._JS_WORLD_MAP`. So you can pass `main`, `application`, `user` or `jseval` in there too. `main` (0) is the default one and is the only one in which JS disabled when `content.javascript.enabled` is set to `false`. All others are still enabled. I'm not sure whether using any of those already-named worlds makes sense, apart from `main`. We could stop people from using them I suppose. Another option is to allow people to pass in `*` as a value to have scripts put into their own little worlds, probably backed by a counter in the GreaseMonkeyManager class. Chrome docs: https://developer.chrome.com/extensions/content_scripts#execution-environment Webengine docs: https://doc.qt.io/qt-5/qwebenginescript.html#details
This commit is contained in:
parent
1bc3d444b6
commit
54ca9b34e5
@ -58,6 +58,7 @@ class GreasemonkeyScript:
|
||||
self.run_at = None
|
||||
self.script_meta = None
|
||||
self.runs_on_sub_frames = True
|
||||
self.jsworld = "main"
|
||||
for name, value in properties:
|
||||
if name == 'name':
|
||||
self.name = value
|
||||
@ -77,6 +78,8 @@ class GreasemonkeyScript:
|
||||
self.runs_on_sub_frames = False
|
||||
elif name == 'require':
|
||||
self.requires.append(value)
|
||||
elif name == 'qute-js-world':
|
||||
self.jsworld = value
|
||||
|
||||
HEADER_REGEX = r'// ==UserScript==|\n+// ==/UserScript==\n'
|
||||
PROPS_REGEX = r'// @(?P<prop>[^\s]+)\s*(?P<val>.*)'
|
||||
|
@ -900,7 +900,18 @@ class _WebEngineScripts(QObject):
|
||||
# @run-at (and @include/@exclude/@match) is parsed by
|
||||
# QWebEngineScript.
|
||||
new_script = QWebEngineScript()
|
||||
new_script.setWorldId(QWebEngineScript.MainWorld)
|
||||
try:
|
||||
world = int(script.jsworld)
|
||||
except ValueError:
|
||||
try:
|
||||
world = _JS_WORLD_MAP[usertypes.JsWorld[
|
||||
script.jsworld.lower()]]
|
||||
except KeyError:
|
||||
log.greasemonkey.error(
|
||||
"script {} has invalid value for '@qute-js-world'"
|
||||
": {}".format(script.name, script.jsworld))
|
||||
continue
|
||||
new_script.setWorldId(world)
|
||||
new_script.setSourceCode(script.code())
|
||||
new_script.setName("GM-{}".format(script.name))
|
||||
new_script.setRunsOnSubFrames(script.runs_on_sub_frames)
|
||||
|
Loading…
Reference in New Issue
Block a user