online / endpoints 18 / categories 4 / rate 60/min/ip /

GET /.well-known/nodeinfo

GET /.well-known/nodeinfo

Fediverse server discovery document. Mastodon, Pleroma, Misskey, and other federated software fetch this to advertise their identity. Modes break the link's rel value, claim impossible versions, or point at other hosts.

mode bad-link (default; href points to a 404), wrong-rel (rel value is not the standard nodeinfo schema URL), version-mismatch (claims version 9.99 that does not exist), cross-host (link points to elsewhere.example).
build a request:

expect: 200 OK with Content-Type: application/json. The default points the links[].href at a /nodeinfo/2.0 path that 404s on this host. Other modes corrupt the rel schema URL, claim an invented version, or cross-host the link entirely. X-Chaos-Nodeinfo-Mode reflects the selection.

bash
curl -i 'https://bots.catastrophic.io/.well-known/nodeinfo?mode=bad-link'
import json, urllib.request
resp = urllib.request.urlopen("https://bots.catastrophic.io/.well-known/nodeinfo?mode=bad-link")
print(resp.status, resp.headers["X-Chaos-Nodeinfo-Mode"])
data = json.loads(resp.read())
for link in data.get("links", []):
    print(f"  rel={link.get('rel')}")
    print(f"  href={link.get('href')}")
const res = await fetch("https://bots.catastrophic.io/.well-known/nodeinfo?mode=bad-link");
console.log(res.status, res.headers.get("x-chaos-nodeinfo-mode"));
const data = await res.json();
for (const link of data.links || []) {
    console.log("  rel=" + link.rel);
    console.log("  href=" + link.href);
}
package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

func main() {
    resp, _ := http.Get("https://bots.catastrophic.io/.well-known/nodeinfo?mode=bad-link")
    defer resp.Body.Close()
    raw, _ := io.ReadAll(resp.Body)
    fmt.Println(resp.StatusCode, resp.Header.Get("X-Chaos-Nodeinfo-Mode"))
    var data struct {
        Links []struct {
            Rel  string `json:"rel"`
            Href string `json:"href"`
        } `json:"links"`
    }
    json.Unmarshal(raw, &data)
    for _, l := range data.Links {
        fmt.Printf("  rel=%s\n  href=%s\n", l.Rel, l.Href)
    }
}
fn main() -> Result<(), Box> {
    let resp = reqwest::blocking::get("https://bots.catastrophic.io/.well-known/nodeinfo?mode=bad-link")?;
    println!("{} {:?}", resp.status(), resp.headers().get("x-chaos-nodeinfo-mode"));
    let data: serde_json::Value = resp.json()?;
    if let Some(links) = data["links"].as_array() {
        for l in links {
            println!("  rel={} href={}", l["rel"], l["href"]);
        }
    }
    Ok(())
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URI;
import java.net.http.*;

public class BotsNodeinfo {
    public static void main(String[] args) throws Exception {
        var client = HttpClient.newHttpClient();
        var req = HttpRequest.newBuilder(URI.create("https://bots.catastrophic.io/.well-known/nodeinfo?mode=bad-link")).build();
        var resp = client.send(req, HttpResponse.BodyHandlers.ofString());
        System.out.println(resp.statusCode() + " " +
            resp.headers().firstValue("X-Chaos-Nodeinfo-Mode").orElse(""));
        var links = new ObjectMapper().readTree(resp.body()).path("links");
        links.forEach(l -> System.out.println(
            "  rel=" + l.path("rel").asText() + " href=" + l.path("href").asText()));
    }
}
using System.Text.Json;
using var client = new HttpClient();
var resp = await client.GetAsync("https://bots.catastrophic.io/.well-known/nodeinfo?mode=bad-link");
resp.Headers.TryGetValues("X-Chaos-Nodeinfo-Mode", out var mode);
Console.WriteLine($"{(int)resp.StatusCode} {mode?.FirstOrDefault()}");
var data = JsonDocument.Parse(await resp.Content.ReadAsStringAsync()).RootElement;
foreach (var link in data.GetProperty("links").EnumerateArray())
    Console.WriteLine($"  rel={link.GetProperty("rel")} href={link.GetProperty("href")}");
require "net/http"
require "json"
res = Net::HTTP.get_response(URI("https://bots.catastrophic.io/.well-known/nodeinfo?mode=bad-link"))
puts "#{res.code} #{res['X-Chaos-Nodeinfo-Mode']}"
JSON.parse(res.body)["links"].each do |l|
    puts "  rel=#{l['rel']} href=#{l['href']}"
end
$r = Invoke-WebRequest -Uri 'https://bots.catastrophic.io/.well-known/nodeinfo?mode=bad-link'
$r.Headers['X-Chaos-Nodeinfo-Mode']
($r.Content | ConvertFrom-Json).links | ForEach-Object {
    "  rel=$($_.rel) href=$($_.href)"
}