[backend/federation] Improve WebFinger host-meta handling
This commit is contained in:
parent
b69f92dbdc
commit
c86b2e192a
3 changed files with 20 additions and 19 deletions
|
@ -16,7 +16,7 @@ public class HostMetaXmlResponseLink()
|
||||||
{
|
{
|
||||||
[XmlAttribute("rel")] public string Rel = "lrdd";
|
[XmlAttribute("rel")] public string Rel = "lrdd";
|
||||||
[XmlAttribute("template")] public required string Template;
|
[XmlAttribute("template")] public required string Template;
|
||||||
[XmlAttribute("type")] public string Type = "application/xrd+xml";
|
[XmlAttribute("type")] public string Type = "application/jrd+json";
|
||||||
|
|
||||||
[SetsRequiredMembers]
|
[SetsRequiredMembers]
|
||||||
public HostMetaXmlResponseLink(string webDomain) : this() =>
|
public HostMetaXmlResponseLink(string webDomain) : this() =>
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace Iceshrimp.Backend.Controllers.Federation;
|
||||||
public class WellKnownController(IOptions<Config.InstanceSection> config, DatabaseContext db) : ControllerBase
|
public class WellKnownController(IOptions<Config.InstanceSection> config, DatabaseContext db) : ControllerBase
|
||||||
{
|
{
|
||||||
[HttpGet("webfinger")]
|
[HttpGet("webfinger")]
|
||||||
[Produces(MediaTypeNames.Application.Json)]
|
[Produces(MediaTypeNames.Application.Json, "application/jrd+json")]
|
||||||
[ProducesResults(HttpStatusCode.OK)]
|
[ProducesResults(HttpStatusCode.OK)]
|
||||||
[ProducesErrors(HttpStatusCode.NotFound)]
|
[ProducesErrors(HttpStatusCode.NotFound)]
|
||||||
public async Task<WebFingerResponse> WebFinger([FromQuery] string resource)
|
public async Task<WebFingerResponse> WebFinger([FromQuery] string resource)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
using System.Xml;
|
using System.Xml.Linq;
|
||||||
using Iceshrimp.Backend.Controllers.Federation.Schemas;
|
using Iceshrimp.Backend.Controllers.Federation.Schemas;
|
||||||
using Iceshrimp.Backend.Core.Configuration;
|
using Iceshrimp.Backend.Core.Configuration;
|
||||||
using Iceshrimp.Backend.Core.Middleware;
|
using Iceshrimp.Backend.Core.Middleware;
|
||||||
|
@ -28,6 +29,11 @@ public class WebFingerService(
|
||||||
IOptions<Config.InstanceSection> config
|
IOptions<Config.InstanceSection> config
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
private static readonly ImmutableArray<string> Accept =
|
||||||
|
[
|
||||||
|
"application/jrd+json", "application/json", "application/xrd+xml", "application/xml"
|
||||||
|
];
|
||||||
|
|
||||||
public async Task<WebFingerResponse?> ResolveAsync(string query)
|
public async Task<WebFingerResponse?> ResolveAsync(string query)
|
||||||
{
|
{
|
||||||
(query, var proto, var domain) = ParseQuery(query);
|
(query, var proto, var domain) = ParseQuery(query);
|
||||||
|
@ -39,7 +45,7 @@ public class WebFingerService(
|
||||||
using var cts = CancellationTokenSource.CreateLinkedTokenSource(appLifetime.ApplicationStopping);
|
using var cts = CancellationTokenSource.CreateLinkedTokenSource(appLifetime.ApplicationStopping);
|
||||||
cts.CancelAfter(TimeSpan.FromSeconds(10));
|
cts.CancelAfter(TimeSpan.FromSeconds(10));
|
||||||
|
|
||||||
var req = httpRqSvc.Get(webFingerUrl, ["application/jrd+json", "application/json"]);
|
var req = httpRqSvc.Get(webFingerUrl, Accept);
|
||||||
var res = await client.SendAsync(req, cts.Token);
|
var res = await client.SendAsync(req, cts.Token);
|
||||||
|
|
||||||
if (res.StatusCode == HttpStatusCode.Gone)
|
if (res.StatusCode == HttpStatusCode.Gone)
|
||||||
|
@ -96,6 +102,7 @@ public class WebFingerService(
|
||||||
return template.Replace("{uri}", encoded);
|
return template.Replace("{uri}", encoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Technically, we should be checking for rel=lrdd *and* type=application/jrd+json, but nearly all implementations break this, so we can't.
|
||||||
private async Task<string?> GetWebFingerTemplateFromHostMetaXmlAsync(string proto, string domain)
|
private async Task<string?> GetWebFingerTemplateFromHostMetaXmlAsync(string proto, string domain)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -105,19 +112,12 @@ public class WebFingerService(
|
||||||
HttpCompletionOption.ResponseHeadersRead);
|
HttpCompletionOption.ResponseHeadersRead);
|
||||||
await using var stream = await res.Content.ReadAsStreamAsync();
|
await using var stream = await res.Content.ReadAsStreamAsync();
|
||||||
|
|
||||||
var xml = new XmlDocument();
|
return XElement.Load(stream)
|
||||||
xml.Load(stream);
|
.Descendants(XName.Get("Link", "http://docs.oasis-open.org/ns/xri/xrd-1.0"))
|
||||||
|
//.Where(p => Accept.Contains(p.Attribute("type"))?.Value ?? ""))
|
||||||
var section = xml["XRD"]?.GetElementsByTagName("Link");
|
.FirstOrDefault(p => p.Attribute("rel")?.Value == "lrdd")
|
||||||
if (section == null) return null;
|
?.Attribute("template")
|
||||||
|
?.Value;
|
||||||
//TODO: implement https://stackoverflow.com/a/37322614/18402176 instead
|
|
||||||
|
|
||||||
for (var i = 0; i < section.Count; i++)
|
|
||||||
if (section[i]?.Attributes?["rel"]?.InnerText == "lrdd")
|
|
||||||
return section[i]?.Attributes?["template"]?.InnerText;
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -125,6 +125,7 @@ public class WebFingerService(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See above comment as for why jrd+json is commented out.
|
||||||
private async Task<string?> GetWebFingerTemplateFromHostMetaJsonAsync(string proto, string domain)
|
private async Task<string?> GetWebFingerTemplateFromHostMetaJsonAsync(string proto, string domain)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -137,7 +138,7 @@ public class WebFingerService(
|
||||||
var result = deserialized?.Links?.FirstOrDefault(p => p is
|
var result = deserialized?.Links?.FirstOrDefault(p => p is
|
||||||
{
|
{
|
||||||
Rel: "lrdd",
|
Rel: "lrdd",
|
||||||
Type: "application/jrd+json",
|
//Type: "application/jrd+json",
|
||||||
Template: not null
|
Template: not null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -159,7 +160,7 @@ public class WebFingerService(
|
||||||
var result = deserialized?.Links?.FirstOrDefault(p => p is
|
var result = deserialized?.Links?.FirstOrDefault(p => p is
|
||||||
{
|
{
|
||||||
Rel: "lrdd",
|
Rel: "lrdd",
|
||||||
Type: "application/jrd+json",
|
//Type: "application/jrd+json",
|
||||||
Template: not null
|
Template: not null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue