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 a HTTP header to make it possible to detect Mastodon #23939

Open
sindresorhus opened this issue Mar 3, 2023 · 17 comments
Open

Add a HTTP header to make it possible to detect Mastodon #23939

sindresorhus opened this issue Mar 3, 2023 · 17 comments
Labels
suggestion Feature suggestion

Comments

@sindresorhus
Copy link

Pitch

Include a HTTP header in every response that indicates that the URL points to a Mastodon instance.

Motivation

I need to be able to quickly detect whether a link points to a Mastodon instance. I'm aware I could try fetching https://[instance-url]/api/v1/instance and deduce it from its content, but that's a bit fragile and also slow.

If I instead could simply perform a HEAD request and check a header, it would be more reliable and faster.

My specific use-case:
I'm the author of a browser picker app called Velja. I want to add support for Mastodon. Meaning that when you click a Mastodon link outside of the browser, it will open with my app and my app will redirect it to a native app like Ivory. The problem is that I cannot know whether a link is a Mastodon link just by looking at the URL. I can have a list of popular Mastodon instances, but I can never cover them all, so I need a quick way to check whether a certain URL points to a Mastodon instance. It needs to be quick as it has to happen right after the user clicks a link and I don't want to keep them waiting.

I imagine there are other use-cases for this too. A link preview scraper could use this to quickly know whether to use a Mastodon scraper for the URL before starting to parse the content. A website that let users add social links could quickly check if the link is a Mastodon link and show the Mastodon icon.

@sindresorhus sindresorhus added the suggestion Feature suggestion label Mar 3, 2023
@Gargron
Copy link
Member

Gargron commented Mar 3, 2023

Mastodon returns the “Server” header with the value “Mastodon” but I think it often gets stripped out or overwritten by nginx.

@voxpelli
Copy link

voxpelli commented Mar 3, 2023

There is a rel-alternate link of type application/activity+json in the HTML response of a page like https://mastodon.social/@sindresorhus/109959846799782156

If that would added to a Link: HTTP Header then one could discover it without parsing the HTML response.

(Eventually it could even be added to a 103 Early Hints response or HEAD requests to make it even more lightweight to figure out)

As I noted in https://mastodon.social/@voxpelli/109959930023440575 it would be preferable if the solution is as independent as possible of Mastodon itself, so that other implementations of the same open protocols will also be supported.

@sindresorhus
Copy link
Author

sindresorhus commented Mar 3, 2023

I'm not seeing the Server header on https://mastodon.social at least.

@voxpelli
Copy link

voxpelli commented Mar 3, 2023

Yeah, the HTTP header is not there now, but the rel-alternate is in the HTML, see the parsed content eg here: https://pin13.net/mf2/?url=https%3A%2F%2Fmastodon.social%2F%40sindresorhus%2F109959846799782156

B409912E-FF10-4F5C-8C1A-207869C79D1D

@sindresorhus
Copy link
Author

Some possible headers:

  • is-mastodon: 1
  • mastodon: 1
  • mastodon: v4.1.0
  • mastodon-instance: 1

@sindresorhus
Copy link
Author

As I noted in https://mastodon.social/@voxpelli/109959930023440575 it would be preferable if the solution is as independent as possible of Mastodon itself, so that other implementations of the same open protocols will also be supported.

My use-case is to detect Mastodon specifically though, not any fediverse instance. So this feels like a separate issue.

@rbairwell
Copy link

Could the existing "Server" header be overridden to read "Mastodon/xx.yy" with allowing for optional "Glitch (Mastodon/xx.yy; compatible)" similar to browser user agents?

Might also be a case for .well-known/host-meta ( https://datatracker.ietf.org/doc/html/rfc6415 )

@sindresorhus
Copy link
Author

Could the existing "Server" header be overridden to read "Mastodon/xx.yy" with allowing for optional "Glitch (Mastodon/xx.yy; compatible)" similar to browser user agents?

This should be a separate issue.

@bertrandom
Copy link

I am developing a Chrome extension that could redirect to someone's personal Mastodon instance and came across this same issue. The usability issue of clicking on a Mastodon link and not being able to favorite or follow is quite frustrating, I think this would help.

@voxpelli
Copy link

voxpelli commented Mar 3, 2023

I was on my phone earlier, now home I could check more properly.

There is a Link: header in the response from HEAD https://mastodon.social/@sindresorhus/109959846799782156

Link: <https://mastodon.social/users/sindresorhus/statuses/109959846799782156>; rel="alternate"; type="application/activity+json"

Parse that using something like https://github.com/Frizlab/LinkHeaderParser and if the rel is alternate and type is application/activity+json then you know that there's an alternative representation that's an ActivityStreams JSON document and that is a clear sign that this is content that Ivory can consume.

(This is about the same way that RSS discovery works (but type is then eg. application/atom+xml)

Edit: This is where it is set in the code:

response.headers['Link'] = LinkHeader.new([[ActivityPub::TagManager.instance.uri_for(@status), [%w(rel alternate), %w(type application/activity+json)]]])

@voxpelli
Copy link

voxpelli commented Mar 3, 2023

So, steps would be:

  1. Do a HEAD to the URL
  2. Check if there's a rel-alternate of type application/activity+json link in the Link: header in the response
  3. If there is, open in Ivory by doing ivory://acct/openURL?url=<original URL>, eg: ivory://acct/openURL?url=https://tapbots.social/@ivory

@sindresorhus
Copy link
Author

@voxpelli This is useful and should definitely be documented somewhere.

However, it will not work for my specific use-case. My app redirects URLs and it needs to know exactly what it redirects so it can redirect to the correct thing. For example, a user may want to open links to a Mastodon instance and a PeerTube instance in different apps. Both are of type application/activity+json, so Velja would not be able to differentiate them with the above check.

So my initial request still stands.

@guest20
Copy link

guest20 commented Mar 13, 2023

@sinresorhus maybe you can you grab the list of domains from john mastodon's site: https://JoinMastodon.org

Not a perfect solution, but it might get you part of the way there, and let you do the check without having to make a request from the server at all.

@sindresorhus
Copy link
Author

@guest20 I'm already doing that. But that only works if I constantly keep the list up to date. I need a fallback for new and unknown servers, which is what this issue would solve.

@guest20
Copy link

guest20 commented Mar 14, 2023

@sindresorhus good thinking :)

My instances sends both Server: Mastodon (mentioned earlier, frontend proxies might replace it with their own name) there's also Set-Cookie: _mastodon_cookie..., which seems less likely to be tampered with since changing it on a running instance logs everyone out.

It looks like it was introduced in ff229aa it was requested ... some time ago #141

@voxpelli
Copy link

Fetch the application/activity+json data and introspect it to see if its the kind that should go one way or another.

The document eg. has a "type": "Note" when its a toot.

One could also maybe do something like jq '.["@context"][].toot?' on the response to get whether a toot: "http://joinmastodon.org/ns#" namespace exists, but that's not really a good way.

@sindresorhus
Copy link
Author

Fetch the application/activity+json data and introspect it to see if its the kind that should go one way or another.

That's too slow. I already said I need a HEAD request.

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

No branches or pull requests

6 participants