Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an option to allow communication with cooperate pages #322

Closed
derjanb opened this issue Sep 23, 2016 · 25 comments
Closed

Add an option to allow communication with cooperate pages #322

derjanb opened this issue Sep 23, 2016 · 25 comments
Milestone

Comments

@derjanb
Copy link
Member

derjanb commented Sep 23, 2016

This allows script hosters to detect Tampermonkey and to query by name whether a script is installed.

@derjanb derjanb added this to the 4.2 milestone Sep 23, 2016
@derjanb
Copy link
Member Author

derjanb commented Sep 23, 2016

A simple example how to get the Tampermonkey version and check whether Download YouTube Videos as MP4 is installed could look like this:

    var waitForExternalTm = function(cb) {
        var external, tm;
        if (!(external = window.external)) {
            return false;
        } else {
            if ((tm = external.Tampermonkey)) {
                cb(tm);
            } else {
                window.setTimeout(function() {
                    if ((tm = external.Tampermonkey)) {
                        cb(tm);
                    }
                }, 1000);
            }
        }
    };
    waitForExternalTm(function(tm) {
        tm.getVersion(function(i) {
           console.log('Hooray, found Tampermonkey version ' + i.version);
        });
        // https://greasyfork.org/en/scripts/1317-download-youtube-videos-as-mp4
        tm.isInstalled('Download YouTube Videos as MP4', 'http://googlesystem.blogspot.com', function(i) {
            if (i.installed) {
                console.log('Yes, ' + i.name + ' version ' + i.version + ' is installed and ' + (i.enabled ? 'enabled' : 'disabled') + '.');
            } else {
                console.log('No, ' + i.name + ' is not installed');
            }
        });
    });

And at the moment these functions are whitelisted to the following URLs:

        {
            '*://tampermonkey.net/*': [ 'getVersion' ],
            'https://greasyfork.org/*': [ '*' ],
            'https://openuserjs.org/*': [ '*' ],
            'https://userstyles.org/*': [ '*' ]
        }

Edit: updated example

@GreenLunar
Copy link

Why would you let servers to detect Tampermonkey?
I think it would be better to conduct any check on client-side.

@derjanb
Copy link
Member Author

derjanb commented Sep 28, 2016

Only the pages mentioned above are able to detect Tampermonkey. This feature enables them to know whether Tampermonkey is installed. If so then there is no need to show install instructions.
It would also be possible to detect whether a script is already installed and to check if the version is the current one.

Examples of such a behavior are:

  • the Chrome webstore changes the install button from "Add to Chrome" to "Added to Chrome" if an extension is already installed
  • userstyles.org changes "To use this style, first install Stylish" to "Install with Stylish"

If a user doesn't like it then this feature can be disabled and it's also disabled by default in incognito mode.

I think it would be better to conduct any check on client-side.

This would require me to monitor all the pages mentioned above and release a new Tampermonkey version or to update a pre-installed userscript once a change was detected. Also the page might look different dependent on the viewer's country, A/B tests, ...

@GreenLunar
Copy link

I now understand the problem of conducting this check on client-side.

I think this option should be disabled by default in any mode, but if it won't be disabled by default, inform users about this new option upon update.

@tophf
Copy link

tophf commented Sep 28, 2016

Maybe TM should show a confirmation page the first time a whitelisted site wants to get the info. With buttons to allow/disallow permanently/temporarily.

@JasonBarnabe
Copy link

What is Tampermonkey's behaviour if a user installs a script, the script gets renamed, then the user attempts to install again? Is the script updated or is another copy installed?

Are there other attributes that could be searched for? I'm concerned about the rename case as well as the case where a user has multiple scripts with the same name.

How does this work with localized script names?

What is your example script waiting to happen before it can do its thing?

@derjanb
Copy link
Member Author

derjanb commented Sep 29, 2016

@JasonBarnabe

What is Tampermonkey's behaviour if a user installs a script, the script gets renamed, then the user attempts to install again? Is the script updated or is another copy installed?

If the user manually renamed a script or the author renamed it and the user installs it again before an automatic update happened, then a new copy is installed. If the script was renamed at the server, then this API allows you to query both names and display a warning. Do you know how often scripts get renamed?

Are there other attributes that could be searched for?

Yes, I thought about using the @updateURL or install URL for this. However, this also has some disadvantages:

  • script that were installed from another source (GitHub, OUJS) wouldn't be recognized anymore
  • if you want to change your routing, then you need to query all current and past URLs

I'm concerned about the rename case as well as the case where a user has multiple scripts with the same name.

Tampermonkey internally handles scripts using a UUID. However, on installation (from URLs) existing scripts with the same @name and @namespace are replaced. Therefore I don't think this is a big issue. I'll add a way to query by @name and @namespace.

How does this work with localized script names?

You always need to query for non-localized names (== the value of @name)

What is your example script waiting to happen before it can do its thing?

Since this feature is user-configurable the content script needs to contact the background page. Unfortunately this is asynchronous communication and therefore it can not be guaranteed to be finished earlier.

Edit: added @namespace

@derjanb
Copy link
Member Author

derjanb commented Oct 4, 2016

@JasonBarnabe @Martii I've added the possibility to query by name and namespace in order to identify the script more reliably and updated the example above.

So is this interesting for you in general?

@Martii
Copy link

Martii commented Oct 5, 2016

@derjanb

This can be used for example to not show installation hints or to modify download/install buttons to say something like "already installed".

I seriously doubt that OUJS is going to restrict clicking it more than once other than the brute force prevention. Sometimes there are unexpected failures in the pipeline and waiting a few is the only thing to do. One of my pet peeves in Chromium/Chrome is how google prevents you from reinstalling something when it's profile gets somewhat corrupted or failure to update. I still have to manually update TM in those browsers all the time... which means uninstall the current version then reinstall it from the store... you can see where I'm going with this.

in order to identify the script more reliably...

That is one of my concerns... if the UID (or whatever acronym is chosen here for script signature) is constant OUJS won't know when to signal "already installed"... perhaps if a user has hand edited a script, what then... if you catch my drift.

It isn't revolting or appealing right now as far as a I can tell but I may be missing some extra UI logic that you are aiming for. Proper identification is a plus for communication of this sort but as you already know another extension/add-on can wreak some havoc with that. As I noted over at the OUJS issue it won't be in our node stack but the "Content Scope" should be okay as long as another Userscript isn't messing with the results or identifiers/naming conventions (think the alert bypass in the global scope). Wouldn't object to a soft-notice I think but beyond that we'd have to be convinced to do something otherwise.

@JasonBarnabe
Copy link

Since this feature is user-configurable the content script needs to contact the background page. Unfortunately this is asynchronous communication and therefore it can not be guaranteed to be finished earlier.

Just to be clear, I was referencing the part where you're waiting for external.Tampermonkey to become available. I'm not sure if you're answering based on that. Can you not assume that external.Tampermonkey, if it is going to be available, will be available by DOMContentLoaded or load or something? I just don't want to be forever checking for it when it's not going to show up (e.g. Tampermonkey is not loaded). Though I suppose I could modify the script to just give up after a while...

@JasonBarnabe
Copy link

Is there a way to add to the whitelist (by console if necessary)? I'd like to test this out locally before deploying anything to greasyfork.org.

@derjanb
Copy link
Member Author

derjanb commented Oct 8, 2016

@JasonBarnabe

Can you not assume that external.Tampermonkey, if it is going to be available, will be available by DOMContentLoaded or load or something?

Unfortunately not. All methods to communicate with the background page (which contains the config) are asynchronous. However, I think after one second you can definitely give up waiting for Tampermonkey.

Is there a way to add to the whitelist (by console if necessary)? I'd like to test this out locally before deploying anything to greasyfork.org.

Unfortunately not, but I've build a version with localhost support. You have to drag and drop it to Chrome's extension page to install it.

Edit: updated test crx URL

@derjanb
Copy link
Member Author

derjanb commented Oct 8, 2016

@Martii

Wouldn't object to a soft-notice I think but beyond that we'd have to be convinced to do something otherwise.

A soft-notice is fine with me. I just wanted to give the script hosters a little bit more information about the user that is viewing the page.

@JasonBarnabe
Copy link

I implemented this on greasyfork.org. Code is at https://github.com/JasonBarnabe/greasyfork/blob/master/app/assets/javascripts/versioncheck.js

@derjanb derjanb closed this as completed Dec 7, 2016
@feildmaster
Copy link

feildmaster commented Oct 29, 2018

I really like this, but I don't use congregated userscript sites. Do you think you could enable "isInstalled" for "https://*.github.io/*"?

It would be pretty nice if I could detect script versions on my landing pages for userscript.

@Kio-td
Copy link

Kio-td commented Oct 29, 2018

I have to agree with @feildmaster, but I would really prefer if the whitelist goes bye-bye. I want to prevent users from tampering with the anti-cheat I have installed, and the only way to check is if Tampermonkey tells me.

@maple3142
Copy link

However, if this feature doesn't have a whitelist, any site can prevent user from using userscript.
And it is totally unacceptable.

Maybe a better solution is enable user to control a whitelist to expose tampermonkey api.

@Kio-td I don't think it is a valid reason for doing this, because there is many ways to do so.
A proper way is check them in your server instead of checking them in client.

@feildmaster
Copy link

Can it be used to prevent userscripts? I thought it was simply a getter for data. I mean ,I guess you could code something to say "We don't like you using userscripts" but really?

@maple3142
Copy link

For example, a website can simply document.write('') if any userscript is detected.
It will force user to disable the script.

@feildmaster
Copy link

I see. Personally that'd put me off of using a website that is so adamant against user scripts. And for those cases I suspect it would be more convenient to have a blacklist for the API, rather than a whitelist.

I still would like github.io to be whitelisted though.

@Kio-td
Copy link

Kio-td commented Oct 30, 2018

I get your points, but still, I have very vulnerable parts of the code that I'd rather not leave exposed in the open, even if I take preventative measures on my server. The only thing I can see TM being used on my server is to disable Anticheat, or to change servers, and I'm not about to take that 50/50 risk, which is why I'd rather the whitelist be gone. After all, the point of the game is to be fast, and I'm not going to have anything on there that'll slow down the game, or anything else about it, like particles.

To go against your point, of course, I get that people like userscripts. But how do you check to make sure someone is not cheating, or using Automovers, or something else without this sort of feature? God, anyone can see how some games have become much shittier because of cheaters.

Let's take this example to the airport, yeah? In essence, you're asking me to watch for anyone trying to run past security, instead of using metal detectors. I get it, you want to keep your glasses, iPhones and knives on your body, but it just becomes a really really dangerous and -guessish- process that can end up in disappointed clients, and worst case - lost money because of it.

For these reasons, I see this as valid, mainly because I want as many preemptive measures to keep people from breaking the TOS.

@maple3142
Copy link

From my perspective, the only use of client side verification is better UX, so you should never trust the data sent by users by all means.
Besides, Tampermonkey is neither the only way to inject code in the website nor is the only way to cheat.
Violentmonkey, Greasemonkey and so on can do this job as well, and you can achieve it without userscript managers by devtool, proxy...
I thought this debate is somewhat like whether a website should be able to know if adblocker enabled or not.

@feildmaster
Copy link

Lets see, to address Kio with his anti-cheat now that I understand what he's doing... Clients are never to be trusted, even if you add a hell of a lot of anti-cheat methods on the client side. The best place for anti-cheat is on the server, to validate the data being sent.

Now for wanting to block userscripts simply because you don't want cheaters... I'm not sure I understand really. I make scripts for games. It's usually to add in features the game developers refuse to incorporate. Do some people think it's cheating? I'm sure they do. However I never consider any of the scripts I make to be cheating.

And if I understand the API any, you can't just get all of the scripts being run. You have to actually query them. You can't just say... "Tampermonkey is enabled, disable it to play the game." That just isn't... fair.

@derjanb
Copy link
Member Author

derjanb commented Nov 2, 2018

Do you think you could enable "isInstalled" for "https://.github.io/"?

Unfortunately this is not possible.

@feildmaster
Copy link

It's not? That's a shame. How come?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants