Greasemonkey: Don't navigate to the script, when popping install dialog

Created on 26 Jan 2018  ·  20Comments  ·  Source: greasemonkey/greasemonkey

If I remember correctly, even 3.x acted this way. We should still be able to, with WebExt APIs:

  1. If navigation to any .user.js is detected, abort navigation.
  2. Restart download of that URL in the background.
  3. If that download results in a non-matching MIME, re-start the navigation -- filtered so we won't abort it.
  4. Otherwise, pop install dialog and continue all downloads.

Most helpful comment

I would be really sad if the possibility to review sourcecode doesn't return. I always feel more comfortable by skimming code. And if there are @require includes which doesn't point to a well known library (officially hosted jQuery etc), I'm always skeptical and usually aborts install unless I really need that script (in which case I skim the content of @require too).

But even if I am an exception and most people doesn't look at or understand the code, I think there's a preventive effect for script writers to know source is shown when installing.

In case you still decide not to show sourcecode, then please add easy accessible view-source: links pointing to the sourcecode when installing a script (and preferable also any @require scripts included).

All 20 comments

I really think this should be rethought. Both VM and TM behave contrary to this. When navigating to a script you're presented with a page that includes both the script content/source and an installation button. While you are technically 'redirected' you are still, in essence, 'navigating' to the user script. Perhaps this should be brought up on the -users and -dev mailing list and see opinions others have?

I support community discussion.

Personally I'm of the opinion that ~nobody reviews the source, so it's a silly thing to show it to all users, including the majority who can't even understand it.

And: reviewing only the main source, when there's also a @require, accomplishes very little.

I would be really sad if the possibility to review sourcecode doesn't return. I always feel more comfortable by skimming code. And if there are @require includes which doesn't point to a well known library (officially hosted jQuery etc), I'm always skeptical and usually aborts install unless I really need that script (in which case I skim the content of @require too).

But even if I am an exception and most people doesn't look at or understand the code, I think there's a preventive effect for script writers to know source is shown when installing.

In case you still decide not to show sourcecode, then please add easy accessible view-source: links pointing to the sourcecode when installing a script (and preferable also any @require scripts included).

As mentioned I also value review-ability. For the minority of people who want it. I just want it to work like #2567 so that you can review _all_ of the source. You just click edit after install, and get all source and text resources visible. Enable or uninstall as you choose.

There's some performance implications on requiring multiple network requests. Specifically, between your 3. and 4. there's the "download to the point in which we have a valid metablock, so we can pop the install dialog".

Let's say the file isn't an actual user script and doesn't have a valid metablock. The installation dialog will never pop. The only course of action I see is to resume the navigation. Once navigation is resumed the file has to be redownloaded. An unnecessary request (#2830 addresses this by expanding what's currently being done in onHeadersReceived).

You've made this point before, and it should be considered. What happens if the connection is slow? For example purposes, let's say it takes 10 seconds to download the file. The user will have 10 seconds of no feedback as GM attempts the download looking for a script. It fails and hands it to the browser to continue the navigation. Again another 10 seconds downloading the file for display.

I'm not going to say there's no way around this. For example the data could be cached or somesuch, and then overwrite the output on actual navigation. But I feel like this leads to unnecessary code complexity just to shield users.

Alternatively you could bring up the install dialog anyway and just fail to install the non-script file (VM does this). I'd consider that bad UX.

If someone can come up with a clean way of doing this without the extra requests, great. Otherwise, I can't get behind this without _actual_ benefits. [1]

[1] You've mentioned "being able to review _all_ of the source code" due to #2567 as being a potential benefit. But I disagree. I feel like #2567 should be a feature _regardless_ of whether source code is available on install or not.


I don't know. On other topics I've been able to come around after some discussion. But this is one that I'm just not "seeing."

From my point of view I don't really care if the script is immediately visible, but I think that if I cancel the install or something that I should be able to see the raw file as I would have if greasemonkey wasn't installed. I don't really care if it is hidden by default or something but some way to dismiss the install dialog and get back to the script seems critical.

I don't think it makes sense to break viewing things called *.user.js. This is removing browser functionality.

I view a user script as more of an extension than a web page. You never browse to an extension, either. You download/install it, or you don't.

I don't think it makes sense to break viewing things called *.user.js. This is removing browser functionality.

It's also doing things just like previous versions of GM did -- including not touching navigations when disabled. If you so desperately need to see this in your browser, turn GM off first.

I view a user script as more of an extension than a web page. You never browse to an extension, either. You download/install it, or you don't.

I disagree with this reasoning. An extension is an archived package of files. A user script is not. You could make the argument about @requires and @resources but I think that's tenuous. Not all of them use those and plenty of them are just plain text. When you navigate to a raw text page you're generally (assuming the attachment / download header isn't set.. Which I find annoying too) not required to download it before viewing it.

It's also doing things just like previous versions of GM did

Sure, but I don't think this is a great argument for or against any particular feature. The previous version can give a baseline but moving forward I think everything should be reexamined under new contexts. This includes code complexity, benefits it does or does not instill, merits, etc.

You never browse to an extension, either. You download/install it, or you don't.

Being a text file does make a difference. For example github has a "view raw" option which is now broken.

including not touching navigations when disabled.

This is good to know. I guess I might have guessed this but it really isn't obvious. I'm just flustered because I was trying to view a file and it won't render. Maybe we could provide a hint to the user that this can be done when they encounter it, rather then displaying a blank page.

I value making design decisions that provide the most value to the most users, so I value input.

This however will be a rare case where I'm putting my foot down. Don't bother debating approaches. I want the behavior of: there's a link to a valid user script, I click that link, I see (only) the install dialog, and I never navigate to a text file, never in fact see the source. I'm going to do what it takes to make Greasemonkey act that way. Period.


Before WebExt, we got this by using http-on-modify-request, to suspend any user-script-looking request as soon as possible. We'd trigger the install dialog, and start a RemoteScript operation to download all parts, all in new requests. Iff this detected a non-user-script (i.e. HTML) thing at a user-script-looking URL, it would cancel the request it owns, and ... something would restart the navigation (I think by resuming the channel exactly, but I can't find that).

With a slow script, nothing happens at first -- once the ==UserScript== part is loaded, the install dialog appears, then its progress bar fills as the rest is downloaded -- the rest of the script, the resource, requires, etc.

It does manage to download the script with only one connection to the server.


Under WebExt, all the APIs are different of course, but the blocking/filtering onHeadersReceived event already in place at HEAD _seems_ to be the best thing to use. I've still got to do research.

I want the behavior of: there's a link to a valid user script, I click that link, I see (only) the install dialog, and I never navigate to a text file, never in fact see the source. I'm going to do what it takes to make Greasemonkey act that way.

But this is a change to the old behavior. GM 3.x I had the option to click on view source instead of install and then nothing was installed, but I got a tab which displayed the source of the script. From there I had the possibility to install or to just close the tab and do nothing. This would be the behavior I would like at least to see again. For me it is not necessary to always display the source, but an option to inspect it before I install anything as it was before, would be great.

The reason for this request is that I saw the harm malicious scripts can cause and thus I always inspect the source before I install anything. This is the reason why I also see silent auto-updating as an issue as it might bring new malicious code to the user.

With webRequest you can return a fake URL to abort the load and cause the browser to stay where it is. But doing so immediately aborts the connection, you can't also use the filter to observe/parse/change the content, so you'll need to start a new connection. I think this is fine in this case, because we've got all the data we need (request method, response headers) in scope and so we can make a confident decision about whether this really is a user script or not, and it's also very early in the request cycle.

I had the option to .. inspect it before I install anything ...

2567

What if it looks like a user script, but it's not? For example, if you take your slow load example and just remove the initial // ==UserScript==. Open it in 3.x, the install dialog never opens (correct) and then the text content is written to the tab / page. With WebEx if you create a new connection in the background I don't see how you can write the contents to the page. As far as I'm aware the only direct way to write some content to a page in the background is through the stream filter.

I can think of some ways to 'work around' that. Again no good solutions. Pass the data to a content script that'll just echo the contents (should be doable, I think). Redirect to a extension page, but that'll break history. Or cause FF to restart the request with some flag set to ignore script checking. But then that's a third request..

Maybe I'm missing something..

Open it in 3.x, the install dialog never opens (correct) and then the text content is written to the tab / page.

Eh, I'd like to correct this point. I was incorrect, I had a typo in user when I tested initially.

@Sxderp let me repeat that I highly value the contributions you've made to date and hope you'll continue.

But for a bit more clarity as to my decision outlined above: I've cleaned up my work in progress; first I moved some unrelated work to separate commits. What was left is a file rename and then this big commit, which is only + 425 -491 .

The Downloader class encapsulates all the logic about (downloading and) installing a script, regardless of source. You just need to set up the inputs -- just the URL for an install, but also the main script source and maybe require/resource contents if already known (for edit case), it downloads anything else missing (i.e. edit in a new require/resource) and passes always one same format to user-script-regstry which persists it in only one way. The entire downloader.js is under 250 lines. There are as a result fewer messages passed between background/content and no new ports.

There are times that it makes a lot of sense to break a big complex piece of code into more smaller and simpler pieces. But IMO this is not it. The data that's flowing around is the same, whether we're installing a "new" script, or updating one, or editing one in place. Only minor things change (do we already know the UUID of the already installed script? do we already know or need to download this or that?).

Does this also resolve the recursive structure of parsedDetails (there's an issue somewhere, don't have time to look for it)?

I don't know. I doubt it?

Does this also resolve the recursive structure of parsedDetails (there's an issue somewhere, don't have time to look for it)?

You mean #2806 ?

Was this page helpful?
0 / 5 - 0 ratings