From 614e68194b9865f334b8e843272fbbf67ebf4da7 Mon Sep 17 00:00:00 2001 From: Alec Murphy Date: Fri, 21 Feb 2025 17:44:54 -0500 Subject: [PATCH] Slon/Modules/NodeInfo: Implement .well-known/nodeinfo and nodeinfo/2.0 --- Slon/Endpoints/Get/NodeInfo.HC | 4 ++++ Slon/Endpoints/Get/WellKnown.HC | 5 +++++ Slon/Http/Server.HC | 1 + Slon/MakeSlon.HC | 1 + Slon/Modules/NodeInfo.HC | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 44 insertions(+) create mode 100644 Slon/Endpoints/Get/NodeInfo.HC create mode 100644 Slon/Modules/NodeInfo.HC diff --git a/Slon/Endpoints/Get/NodeInfo.HC b/Slon/Endpoints/Get/NodeInfo.HC new file mode 100644 index 0000000..3492114 --- /dev/null +++ b/Slon/Endpoints/Get/NodeInfo.HC @@ -0,0 +1,4 @@ +if (!StrICmp("/nodeinfo/2.0", @slon_http_request_path(session))) { + @slon_nodeinfo_20(session); + return; +} diff --git a/Slon/Endpoints/Get/WellKnown.HC b/Slon/Endpoints/Get/WellKnown.HC index 0f14f2c..22a654c 100644 --- a/Slon/Endpoints/Get/WellKnown.HC +++ b/Slon/Endpoints/Get/WellKnown.HC @@ -3,6 +3,11 @@ if (!StrICmp("/.well-known/host-meta", @slon_http_request_path(session))) { return; } +if (!StrICmp("/.well-known/nodeinfo", @slon_http_request_path(session))) { + @slon_nodeinfo(session); + return; +} + if (!StrICmp("/.well-known/oauth-authorization-server", @slon_http_request_path(session))) { @slon_oauth_well_known(session); return; diff --git a/Slon/Http/Server.HC b/Slon/Http/Server.HC index a36ab85..6e454df 100644 --- a/Slon/Http/Server.HC +++ b/Slon/Http/Server.HC @@ -500,6 +500,7 @@ U0 @slon_http_handle_get_request(SlonHttpSession* session) #include "Endpoints/Get/FollowedTags"; #include "Endpoints/Get/Instance"; #include "Endpoints/Get/Notifications"; + #include "Endpoints/Get/NodeInfo"; #include "Endpoints/Get/OAuth"; #include "Endpoints/Get/Search"; #include "Endpoints/Get/Suggestions"; diff --git a/Slon/MakeSlon.HC b/Slon/MakeSlon.HC index a1aa3f1..d51535c 100644 --- a/Slon/MakeSlon.HC +++ b/Slon/MakeSlon.HC @@ -29,6 +29,7 @@ WinMax(Fs); #include "Modules/ActivityPub"; #include "Modules/Meta"; +#include "Modules/NodeInfo"; #include "Modules/OAuth"; #include "Modules/Web"; #include "Modules/Webfinger"; diff --git a/Slon/Modules/NodeInfo.HC b/Slon/Modules/NodeInfo.HC new file mode 100644 index 0000000..524c04e --- /dev/null +++ b/Slon/Modules/NodeInfo.HC @@ -0,0 +1,33 @@ +U0 @slon_nodeinfo(SlonHttpSession* session) +{ + SLON_SCRATCH_BUFFER_AND_REQUEST_JSON + no_warn request_json; + + StrPrint(scratch_buffer, "{\"links\":[{\"rel\":\"http://nodeinfo.diaspora.software/ns/schema/2.0\",\"href\":\"https://%s/nodeinfo/2.0\"}]}", db->o("instance")->@("uri")); + @slon_http_set_content_type(session, "application/json; charset=utf-8"); + session->send(scratch_buffer); +} + +U0 @slon_nodeinfo_20(SlonHttpSession* session) +{ + JsonObject* nodeinfo = Json.CreateObject(); + nodeinfo->set("version", "2.0", JSON_STRING); + nodeinfo->set("software", Json.CreateObject(), JSON_OBJECT); + nodeinfo->o("software")->set("name", "slon", JSON_STRING); + nodeinfo->o("software")->set("version", db->o("instance")->@("version"), JSON_STRING); + nodeinfo->set("protocols", Json.Parse("[\"activitypub\"]"), JSON_ARRAY); + nodeinfo->set("services", Json.Parse("{\"outbound\":[],\"inbound\":[]}"), JSON_OBJECT); + nodeinfo->set("usage", Json.CreateObject(), JSON_OBJECT); + nodeinfo->o("usage")->set("users", Json.CreateObject(), JSON_OBJECT); + nodeinfo->o("usage")->o("users")->set("total", db->o("instance")->o("stats")->@("user_count"), JSON_NUMBER); + // FIXME: return activeMonth, activeHalfyear + nodeinfo->o("usage")->o("users")->set("activeMonth", 0, JSON_NUMBER); + nodeinfo->o("usage")->o("users")->set("activeHalfyear", 0, JSON_NUMBER); + nodeinfo->set("localPosts", db->o("instance")->o("stats")->@("status_count"), JSON_NUMBER); + nodeinfo->set("openRegistrations", db->o("instance")->@("registrations"), JSON_BOOLEAN); + nodeinfo->set("metadata", Json.CreateObject(), JSON_OBJECT); + nodeinfo->o("metadata")->set("nodeName", db->o("instance")->@("title"), JSON_STRING); + nodeinfo->o("metadata")->set("nodeDescription", db->o("instance")->@("description"), JSON_STRING); + session->send(nodeinfo); + Json.Delete(nodeinfo); +}