using Microsoft.AspNetCore.Mvc; using MongoDB.Entities; using PrivaPub.Models.Federation; using PrivaPub.Models.User; using PrivaPub.Services.Federation; using PrivaPub.StaticServices; using System.Text.Json.Nodes; using PostEntity = PrivaPub.Models.Post.Post; namespace PrivaPub.Controllers.ServerToServer { [ApiController] public class WellKnownController : ControllerBase { readonly ILocalActorService _localActors; readonly DbEntities _dbEntities; public WellKnownController(ILocalActorService localActors, DbEntities dbEntities) { _localActors = localActors; _dbEntities = dbEntities; } [HttpGet, Route("/.well-known/webfinger")] public async Task WebFinger([FromQuery] string resource, CancellationToken token) { if (string.IsNullOrEmpty(resource)) return BadRequest(); LocalActor actor; if (resource.StartsWith("acct:", StringComparison.OrdinalIgnoreCase)) { var parts = resource[5..].TrimStart('@').Split('@'); var domain = new Uri(_localActors.BaseAddress).Authority; if (parts.Length != 2 || !parts[1].Equals(domain, StringComparison.OrdinalIgnoreCase)) return NotFound(); actor = await _localActors.FindByUserName(parts[0], token); } else actor = await _localActors.FindByUri(resource, token); if (actor == default) return NotFound(); var document = new JsonObject { ["subject"] = $"acct:{actor.Handle}", ["aliases"] = new JsonArray(actor.Uri), ["links"] = new JsonArray( new JsonObject { ["rel"] = "self", ["type"] = "application/activity+json", ["href"] = actor.Uri }, new JsonObject { ["rel"] = "http://webfinger.net/rel/profile-page", ["type"] = "text/html", ["href"] = actor.Uri }) }; return Content(document.ToJsonString(), "application/jrd+json; charset=utf-8"); } [HttpGet, Route("/.well-known/nodeinfo")] public IActionResult NodeInfoLinks() { var document = new JsonObject { ["links"] = new JsonArray(new JsonObject { ["rel"] = "http://nodeinfo.diaspora.software/ns/schema/2.0", ["href"] = $"{_localActors.BaseAddress}/nodeinfo/2.0" }) }; return Content(document.ToJsonString(), "application/json; charset=utf-8"); } [HttpGet, Route("/nodeinfo/2.0")] public async Task NodeInfo(CancellationToken token) { var users = await DB.Default.CountAsync(a => !a.DeletionAt.HasValue, token); var posts = await DB.Default.CountAsync(p => !p.IsFederatedCopy, token); var document = new JsonObject { ["version"] = "2.0", ["software"] = new JsonObject { ["name"] = "privapub", ["version"] = BuildInfo.Ref }, ["protocols"] = new JsonArray("activitypub"), ["services"] = new JsonObject { ["inbound"] = new JsonArray(), ["outbound"] = new JsonArray() }, ["openRegistrations"] = true, ["usage"] = new JsonObject { ["users"] = new JsonObject { ["total"] = users }, ["localPosts"] = posts }, ["metadata"] = new JsonObject() }; return Content(document.ToJsonString(), "application/json; profile=\"http://nodeinfo.diaspora.software/ns/schema/2.0#\"; charset=utf-8"); } } }