`ListCategory` sorts its completion by default, we are already building
the categories in the right order so don't need that.
The test tests the case of where you have 11 tabs and if the model was
sorted the tabs with index 10 and 11 would be sorted before the one with
index 2.
The `random.sample` bit for the tab url and title is to also make sure
the model isn't being sorted on those columns, whithout haveng to write
and all ten lines.
We changed this a while ago in a2f62238f1
already, but Ctrl-V was kind of cumbersome as well, as it conflicted with
pasting.
Shift-Escape is closer to the default leave-mode binding (Escape), and also
unlikely to conflict as it's used for the task manager in Chrome.
- Update the docstring for repeat
- Remove the blank line after the docstring
- Update the docstring with scripts/dev/src2asciidoc.py
- Simplify the test
On Qt 5.7.1, window.print() caused a CommandError which wasn't handled as the
command was called from accept_navigation_request.
Instead, we now show the dialog in AbstractPrinting and use that directly.
Fixes#2603
The call to processEvents fixes an apparent race condition with some window
managers, e.g. i3. QT seems to be thinking, that the window is not marked as
urgent and toggles it twice, so synchronizing before issuing the alert makes QT
behave correctly.
This change should not change the behaviour on other systems only correct the
fault reported in #2603.
In ffc29ee043 (part of v1.0.0), a
qute://settings/set URL was added to change settings.
Contrary to what I apparently believed at the time, it *is* possible for
websites to access `qute://*` URLs (i.e., neither QtWebKit nor QtWebEngine
prohibit such requests, other than the usual cross-origin rules).
In other words, this means a website can e.g. have an `<img>` tag which loads a
`qute://settings/set` URL, which then sets `editor.command` to a bash script.
The result of that is arbitrary code execution.
Fixes#4060
See #2332
Add an additional argument to is_blocked for the current url, and enable
the host_blocking.enabled property to be set per domain.
This allows to bypass host blocking for specific domains
Moves the 5.8 check to `_WebEngineScripts.init()`.
Changes `_inject_userscripts` to allow for the two code paths. With
5.7.1 we need to specify the injection point and not clear all scripts
for each call, since we have to call it three times.
Change the 5.8+ hook to call a new method which passes all the scripts
into `_inject_userscripts` so that doesn't have to have a fallback
conditional inside it because thats an inversion of responsibility!
Pulling the remove scripts part into a seperate function and making it
the callers responsibilty to call that first would tidy it up a little
more but meh.
I was worried about just doing `_widget.page().urlChanged.connect()`
once at tab init, where before it was connected at page init, because I
was under the impression that the child page can be replaced at any
time, eg when navigating to a new origin. But under manual testing I
didn't see that at all. Maybe I was mistaken or maybe that only started
in a later Qt version.
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
When we click a QTBUG link (to open in a new tab) from Qt's codereview, we get
two RWHV objects which both are visible.
Experimenting with .setEnabled(False) it looks like it's (hopefully always...)
the last one which is the one to use.
Apparently the signal attributes already exist with PyQt 5.10 (*sigh*) but PyQt
doesn't know what to do with the arguments, causing this to happen:
TypeError: unable to convert a C++ 'QWebEngineRegisterProtocolHandlerRequest'
instance to a Python object
Doing so causes QtWebEngine to load its own view-source: page even if we supply
custom data.
Instead we pass the original page's URL (to not regress #2948).
This partially reverts #3521 and reintroduces TabData.viewing_source.
However, on QtWebEngine we can still ":view-source --pygments" and then
":view-source" (with or without "--pygments") again, because the bit gets
cleaned in _on_load_started.
See #3654.
Sometimes I want to see all the logs _except_ for the sql stuff and
"marked cookies as dirty". with this you should be able to pass
`--logfilter \!sql,save`.
This codepath may trigger a crash which was fixed by
0e75f3272d.
However, this commit does not make it more likely to happen, and this
patch was backported into arch (at least).
In the future, we may be able to use <enter> on qtwebkit with js,
without triggering this crash
It looks like chrome-error://chromewebdata/ triggers another invalid scheme
load which is why the endless loop happens. When we install a custom scheme
handler for chrome-error:// we can at least show an error page.
This issue was probably introduced in 545539f28d
- with JavaScript, we can't "click" on an external link.
There might be a better solution using
QWebEngineSettings::setUnknownUrlSchemePolicy(QWebEngineSettings::AllowAllUnknownUrlSchemes)
temporarily when using hints with PyQt 5.11.
Fixes#2833
This reverts commit 1956590df84a72c7f9a516e805d01529291fccf8.
Turns out the actual issue wasn't due to *invalid* links - it's with links
which have an unknown scheme.
There's still a change in behavior between Qt 5.10 and 5.11 though: Invalid
links are apparently not passed to acceptNavigationRequest (sometimes?) so we
don't show an error message. Instead, we just load about:blank. However,
Chromium does that too and we can't handle a real click easily, so let's just
ignore that one.
See #3661
This reverts commit 6cc920472ee4170b257a0b588687b175162e83df.
Since self._widget can go stale in the layout, we need to somehow solve this differently...
It reads nicer, and this is also speculative fix for #3896 as PyQt5 is
hopefully better at disconnecting partial-objects from dead objects than it is
with lambdas.
Turns out str.isdigit() also handles ² as a digit, but int('²') causes a
ValueError.
Here we use `string.digits` instead, which is '0123456789'.
Fixes#3743
Please let this be the last attempt... :D
Fixes#3939
Supersedes #3921
Reverts ae295a7f65
See #3661
This should not regress #3872. Might affect #3834 in some way.
Also change the block scoped `window` declaration to be const because it
seemed like a good idea. The real window seems to just silently ignore
attempts to overwrite it.
Since the JSCore used by WebKit 602.1 doesn't fully support Proxy and I
can't think of a way to provide isolation otherwise just revert to the
old behaviour in that case. I am checking for the specific WebKit
version because I'm pretty sure that version just happened to be
released when Proxy support was only partially done, any later release
will presumably have a newer JSCore where it works.
There I changed the indentation of a block in the jinja template which
will have inflated the diff.
I added mocking of `objects.backend` to the `webview` and
`webenginewebview` fixtures, I am pretty sure they are mutually
exclusive so don't expect any issues from that.
Because of the feature detection being at template compile time I had to
tweak the test setup to be done via a fixture instead of the setupClass
functionality that I was using before.
The implementation of Proxy in JSCore used by current QtWebkit (webkit
602.1) doesn't support the `set()` handler for whatever reason. So
instead of testing for a specific behaviour that we can't ensure on that
version let's just skip the tests and handle user complaints with
sympathy.
Apparently making a function like `function foo() {};` in block scope is
illegal. It should be named via assignment.
Switched to an IIFE anyway because it doesn't need a name.
Previously scripts were failing to find attributes that they assigned to
window and then tried to use from the global scope. Eg
window.newthing = function() {...};
newthing(...); // newthing is not defined error
This wasn't the case for things that already existed in the global scope
and were just being overwritten.
This change just overrides the `Proxy.has()` function which seems to fix
it. Probably the `while` implementation was failing to pick up new
attributes because of the lack.
I also tweaked some comments and variable names and const-ness to be a
little more production ready.
Since the global namespace of javascript in the browser is accessible
there where issues with scripts clobbering things that the page expected
to be attributes of window pages clobbering things that userscripts
saved to `window`. The latter was occuring with OneeChan. OneeChan was
setting `window.$` to a function that took a css selector and the 4chan
catalog script was setting `window.$` to some object. Since OneeChan was
set to run at document-start this broke OneeChan, switching it to
document-end broke scripts on 4chan.
I used OneeChan and 4chan-X on 4chan as the test case for this and
TamperMonkey as a guide for what is the correct way to handle scoping. I
didn't manage to pick apart just how TamperMonkey does what it does (I
think it might just be the environment that Chrome provides extensions
actually) but I got close to the same behaviour.
TamperMonkey provides a `window` object that appears to be what the
global window looked like before the webpage modified it. The global
scope though does have the pages modifications accessible. If the script
assigns something to an attribute `window` it can see that attribute in
the global scope. This implementation differs from that one in that, to
the scipt, `window` and the global scope always look the same, and that
is the same as the global scope looks in the environment provided by
TamperMonkey.
I am using the ES6 `Proxy` feature to allow the `window` object to look
like the actual (unsafe) one while allowing writing to it that doesn't
clobber the unsafe one. I am then using the ES4 `with` function to make
attributes of that window (proxy) object visible in the scope chain.
There may be other ways to do this without using `with` by using nested
functions and setting `this` creatively. There are notes around
alleging `with` to be various states of uncool[1].
I also ran into an issue where a userscript calling
`window.addEventListener(...)` would fail with `TypeError: Illegal
Execution` which is apparently due to `this` not being set correctly. I
looked at the functions which threw that error and those that didn't and
am using whether they have a `prototype` attribute or not to tell
whether I need to bind them with `window` as `this`. I am not sure how
correct that is but it worked for all the cases I ran into.
[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with
Previously, we would focus webviews even if they were in the
background to work around https://bugreports.qt.io/browse/QTBUG-68076.
This adjusts that to only occur when needed.
Closes#3875
The autoupdator, which uses `qutebrowser.misc.httpclient` has been failing recently because the URL that it hits to check version information is now serving a 301 moved permanently. By default QNetworkRequest doesn't follow redirects so it was getting back a (non-json, despite the request) body pointing to the new location, instead or version information. This changes fixes that by changing HTTPClient to use a QNetworkRequest subclass which follows redirects by default.
It lookes like HTTPClient is currently only used in autoupdate.py, version.py, and crashdialog.py so I don't expect any breakage.
5.6-5.8 Only had a boolean setting available which allows redirects, but not from the https scheme to http, 5.9 introduces a more nuanced setting. I have tested locally on 5.7.1 and 5.10.
The greasemonkey `@match` directive is used to match urls against
chromium url patterns (as opposed to `@include` which treats its
argument as a glob expression). I was using fnmatch for both here
because I am lazy and knew someone else was going to implement chromium
url patterns for me eventually. Now it is done and I should switch to
using them instead. The most common failing case that this will fix is
something matching on `*://*.domain.com/*` because it wouldn't match
the url with no subdomain.
This codepath is only used on webengine 5.7.1 and webkit backends.