#!/bin/bash # Print some basic info about fediverse instances. # Version: 2022-05-25_1 if [[ -z "${1}" ]]; then echo "usage: ${0} DOMAIN" >&2 exit 1 fi if ! command -v curl > /dev/null; then echo "You need to install curl (https://curl.haxx.se/)" >&2 exit 2 fi if ! command -v jq > /dev/null; then echo "You need to install jq (https://stedolan.github.com/jq/)" >&2 exit 2 fi mycurl="curl -sk" function striphtml() { local extract="${*}" echo "${extract}" | sed 's/\\u003c//g' | sed -E 's/<[^>]+>//g' | sed 's/\\r\\n/ /g' | sed -E 's/(^"|"$)//g' } function parse_nodeinfo() { local instance="${1}" local nodeinfo="${2}" # shellcheck disable=SC2155 local json=$(${mycurl} "${nodeinfo}") # shellcheck disable=SC2155 local implementation=$(jq -r ".software.name" <<<"${json}") # shellcheck disable=SC2155 local version=$(jq -r ".software.version" <<<"${json}") echo "${implementation} ${version} detected." # shellcheck disable=SC2155 local description=$(jq -r ".metadata.nodeDescription" <<<"${json}") if [[ "${description}" == "null" ]]; then description=$(jq -r ".metadata.shortDescription" <<<"${json}") fi if [[ "${description}" == "null" ]]; then description=$(jq -r ".metadata.nodeName" <<<"${json}") fi [[ "${description}" != "null" ]] && echo "Description: ${description}" # shellcheck disable=SC2155 local admins=$(jq -r ".metadata.staffAccounts" <<<"${json}") if [[ "${admins}" == "null" ]]; then admins=$(jq -r ".metadata.adminAccount" <<<"${json}") fi [[ "${admins}" != "null" ]] && echo "Admins: ${admins}" echo -n "Number of users: " jq -r ".usage.users.total" <<<"${json}" # shellcheck disable=SC2155 local active=$(jq -r ".usage.users.activeMonth" <<<"${json}") [[ "${active}" != "null" ]] && echo "Active users (month): ${active}" echo -n "Open registrations: " jq -r ".openRegistrations" <<<"${json}" if [[ "${implementation}" == "activityrelay" ]]; then # shellcheck disable=SC2155 local peers=$(jq -r ".metadata.peers" <<<"${json}") [[ "${peers}" != "null" ]] && echo "Peers: ${peers}" fi # shellcheck disable=SC2155 local restrictions=$(jq -r ".metadata.federation.mrf_simple" <<<"${json}") if [[ "${restrictions}" == "null" ]]; then restrictions=$(jq -r ".federation" <<<"${json}") fi [[ "${restrictions}" != "null" ]] && echo "Federation restrictions: ${restrictions}" if [[ "${implementation}" == "pleroma" ]]; then echo "Further info, maybe: https://${instance}/about" elif [[ "${implementation}" == "funkwhale" ]]; then echo -n "Artists / tracks: " jq -rj ".metadata.library.artists.total" <<<"${json}" echo -n " / " jq -r ".metadata.library.tracks.total" <<<"${json}" elif [[ "${implementation}" == "mastodon" ]] || [[ "${implementation}" =~ don$ ]] || [[ "${implementation}" =~ ^masto ]] || [[ "${implementation}" == "bookwyrm" ]]; then echo -e "\nUsing Mastodon API additionally." parse_mastodon ${instance} "https://${instance}/api/v1/instance" elif [[ "${implementation}" == "pixelfed" ]]; then echo "Further info, maybe: https://${instance}/site/terms" elif [[ "${implementation}" == "peertube" ]]; then echo "Further info, maybe: https://${instance}/about/instance" elif [[ "${implementation}" == "friendica" ]]; then echo "Further info, maybe: https://${instance}/friendica" fi } function parse_mastodon() { local instance="${1}" local mastoinfo="${2}" # shellcheck disable=SC2155 local json=$(${mycurl} "${mastoinfo}") local implementation="" if grep -Eq '"is_(pro|verified)"' <<<"${json}"; then implementation="Gab" elif grep -Pq '"version":"\d+\.\d+\.\d+\.\d+\."' <<<"${json}"; then implementation="Florence" elif grep -Pq '"version":"\d+\.\d+\.\d+(rc\d+)?"' <<<"${json}"; then implementation="Mastodon" elif grep -Pq '"version":"\d+\.\d+\.\d+[\._\-\+]?[\w\_\+\-]+"' <<<"${json}" then implementation="Mastodon fork" fi if [[ -n "${implementation}" ]]; then # shellcheck disable=SC2155 local version=$(jq -r ".version" <<<"${json}") echo "${implementation} ${version} detected." fi echo -n "Description: " # shellcheck disable=SC2046 striphtml $(jq ".description" <<<"${json}") # shellcheck disable=SC2155 local admin=$(jq -r ".contact_account.acct" <<<"${json}") [[ "${admin}" != "null" ]] && echo "Admin: https://${instance}/users/${admin}" # shellcheck disable=SC2155 local email=$(jq -r ".email" <<<"${json}") [[ -n "${email}" ]] && echo "E-Mail: ${email}" echo -n "Number of users: " jq -r ".stats.user_count" <<<"${json}" echo -n "Open registrations: " jq -r ".registrations" <<<"${json}" if [[ "${implementation}" == "Mastodon" || "${implementation}" == "Mastodon fork" || "${implementation}" == "Florence" ]]; then echo "Further info, maybe: https://${instance}/about/more" elif [[ "${implementation}" == "Gab" ]]; then echo "Further info, maybe: https://${instance}/about" fi } function parse_misskey() { local instance="${1}" local misskeyinfo="${2}" # shellcheck disable=SC2155 local json=$(${mycurl} -X POST "${misskeyinfo}") # shellcheck disable=SC2155 local version=$(jq -r ".version" <<<"${json}") [[ "${version}" != "null" ]] && echo "Misskey ${version} detected." local description=$(jq -r ".description" <<<"${json}") [[ "${description}" != "null" ]] && echo "Description: ${description}" # shellcheck disable=SC2155 local email=$(jq -r ".maintainerEmail" <<<"${json}") [[ "${email}" != "null" ]] && echo "E-Mail: ${email}" # shellcheck disable=SC2155 local users=$(${mycurl} -X POST "https://${instance}/api/stats" | jq -r ".originalUsersCount") [[ ${users} != "null" ]] && echo "Number of users: ${users}" echo -n "Open registrations: " jq -r ".features.registration" <<<"${json}" # shellcheck disable=SC2155 local tos=$(jq -r ".ToSUrl" <<<"${json}") [[ "${tos}" != "null" ]] && echo "ToS: ${tos}" } function main() { local instance="${1}" # shellcheck disable=SC2155 local nodeinfo=$(${mycurl} -L "https://${instance}/.well-known/nodeinfo" | jq -r '.links[].href' 2> /dev/null | sort | tail -n 1) local mastoinfo="https://${instance}/api/v1/instance" local misskeyinfo="https://${instance}/api/meta" if ${mycurl} -ILf -X POST "${misskeyinfo}" | grep -iq 'HTTP.*200'; then echo "Misskey API found." parse_misskey "${instance}" "${misskeyinfo}" elif ${mycurl} -ILf "${nodeinfo}" | grep -iq 'Content-Type: application/json' \ || ${mycurl} -s "${nodeinfo}" | jq -e '.software' > /dev/null; then # ↑ Bookwyrm doesn't answer to HEAD requests ↑. echo "Nodeinfo found." parse_nodeinfo "${instance}" "${nodeinfo}" elif ${mycurl} -ILf "${mastoinfo}" | grep -iq 'Content-Type: application/json'; then echo "Mastodon API found." parse_mastodon "${instance}" "${mastoinfo}" else echo "Could not detect type of server." ${mycurl} -I "https://${instance}/" fi if ${mycurl} -ILf "${instance}" | grep -q 'Server: cloudflare'; then echo "Uses CloudFlare." fi echo "See also: https://fedi.ninja/${instance}" } main "${1}"