From b37f02846b935cf14e00e60fb6e540880af0bcb6 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Wed, 14 Aug 2024 01:49:49 +0200 Subject: [PATCH] [backend/federation] Add support for returning xrd+xml WebFinger responses for local users --- .../Federation/WellKnownController.cs | 8 ++++++- .../Core/Extensions/MvcBuilderExtensions.cs | 2 ++ .../Core/Federation/WebFinger/Types.cs | 21 ++++++++++--------- .../Federation/WebFinger/WebFingerService.cs | 12 +++-------- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/Iceshrimp.Backend/Controllers/Federation/WellKnownController.cs b/Iceshrimp.Backend/Controllers/Federation/WellKnownController.cs index 7495aa11..4e8940b6 100644 --- a/Iceshrimp.Backend/Controllers/Federation/WellKnownController.cs +++ b/Iceshrimp.Backend/Controllers/Federation/WellKnownController.cs @@ -24,7 +24,7 @@ namespace Iceshrimp.Backend.Controllers.Federation; public class WellKnownController(IOptions config, DatabaseContext db) : ControllerBase { [HttpGet("webfinger")] - [Produces(MediaTypeNames.Application.Json, "application/jrd+json")] + [Produces("application/jrd+json", "application/json", "application/xrd+xml", "application/xml")] [ProducesResults(HttpStatusCode.OK)] [ProducesErrors(HttpStatusCode.NotFound)] public async Task WebFinger([FromQuery] string resource) @@ -66,6 +66,12 @@ public class WellKnownController(IOptions config, Databa Href = user.GetPublicUri(config.Value) }, new WebFingerLink + { + Rel = "self", + Type = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"", + Href = user.GetPublicUri(config.Value) + }, + new WebFingerLink { Rel = "http://webfinger.net/rel/profile-page", Type = "text/html", diff --git a/Iceshrimp.Backend/Core/Extensions/MvcBuilderExtensions.cs b/Iceshrimp.Backend/Core/Extensions/MvcBuilderExtensions.cs index e75810a1..323f010f 100644 --- a/Iceshrimp.Backend/Core/Extensions/MvcBuilderExtensions.cs +++ b/Iceshrimp.Backend/Core/Extensions/MvcBuilderExtensions.cs @@ -1,6 +1,7 @@ using System.Buffers; using System.Net; using System.Text.Encodings.Web; +using System.Xml; using Iceshrimp.Backend.Controllers.Shared.Attributes; using Iceshrimp.Backend.Core.Middleware; using Microsoft.AspNetCore.Mvc; @@ -35,6 +36,7 @@ public static class MvcBuilderExtensions opts.InputFormatters.Insert(0, new JsonInputMultiFormatter()); opts.OutputFormatters.Insert(0, new JsonOutputMultiFormatter()); + opts.OutputFormatters.Add(new XmlSerializerOutputFormatter()); }); return builder; diff --git a/Iceshrimp.Backend/Core/Federation/WebFinger/Types.cs b/Iceshrimp.Backend/Core/Federation/WebFinger/Types.cs index 3a1df4d0..09a097b7 100644 --- a/Iceshrimp.Backend/Core/Federation/WebFinger/Types.cs +++ b/Iceshrimp.Backend/Core/Federation/WebFinger/Types.cs @@ -30,24 +30,25 @@ public sealed class WebFingerLink [SuppressMessage("ReSharper", "CollectionNeverUpdated.Global")] [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] +[XmlRoot("XRD", Namespace = "http://docs.oasis-open.org/ns/xri/xrd-1.0", IsNullable = false)] public sealed class WebFingerResponse { - [J("links")] [JR] public List Links { get; set; } = null!; - [J("subject")] [JR] public string Subject { get; set; } = null!; + [XmlElement("Link")] + [J("links")] + [JR] + public required List Links { get; set; } = null!; + [XmlElement("Subject")] + [J("subject")] + [JR] + public required string Subject { get; set; } = null!; + + [XmlElement("Alias")] [J("aliases")] [JI(Condition = JsonIgnoreCondition.WhenWritingNull)] public List? Aliases { get; set; } } -[XmlRoot("XRD", Namespace = "http://docs.oasis-open.org/ns/xri/xrd-1.0", IsNullable = false)] -public sealed class WebFingerXmlResponse -{ - [XmlElement("Subject")] public required string Subject { get; set; } = null!; - [XmlElement("Alias")] public List? Aliases { get; set; } - [XmlElement("Link")] public required List Links { get; set; } -} - public sealed class NodeInfoIndexResponse { [J("links")] [JR] public List Links { get; set; } = null!; diff --git a/Iceshrimp.Backend/Core/Federation/WebFinger/WebFingerService.cs b/Iceshrimp.Backend/Core/Federation/WebFinger/WebFingerService.cs index 3a182a10..8aef7aa7 100644 --- a/Iceshrimp.Backend/Core/Federation/WebFinger/WebFingerService.cs +++ b/Iceshrimp.Backend/Core/Federation/WebFinger/WebFingerService.cs @@ -59,16 +59,10 @@ public class WebFingerService( if (res.Content.Headers.ContentType?.MediaType is "application/jrd+json" or "application/json") return await res.Content.ReadFromJsonAsync(cts.Token); - var deserializer = new XmlSerializer(typeof(WebFingerXmlResponse)); - if (deserializer.Deserialize(await res.Content.ReadAsStreamAsync(cts.Token)) is not WebFingerXmlResponse xml) - throw new Exception("Failed to deserialize xml payload"); + var deserializer = new XmlSerializer(typeof(WebFingerResponse)); - return new WebFingerResponse - { - Subject = xml.Subject, - Links = xml.Links, - Aliases = xml.Aliases - }; + return deserializer.Deserialize(await res.Content.ReadAsStreamAsync(cts.Token)) as WebFingerResponse ?? + throw new Exception("Failed to deserialize xml payload"); } public static (string query, string proto, string domain) ParseQuery(string query)