[backend/federation] Fall back to JRD during host-meta step of the WebFinger process (ISH-162)

This commit is contained in:
Laura Hausmann 2024-03-12 05:34:45 +01:00
parent 91137b7fd9
commit 0833cf49d2
No known key found for this signature in database
GPG key ID: D044E84C5BE01605
2 changed files with 72 additions and 8 deletions

View file

@ -2,14 +2,26 @@ using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
namespace Iceshrimp.Backend.Controllers.Federation.Schemas;
public class HostMetaJsonResponse(string webDomain)
public class HostMetaJsonResponse()
{
[J("links")] public List<HostMetaJsonResponseLink> Links => [new HostMetaJsonResponseLink(webDomain)];
public HostMetaJsonResponse(string webDomain) : this()
{
Links = [new HostMetaJsonResponseLink(webDomain)];
}
[J("links")] public List<HostMetaJsonResponseLink>? Links { get; set; }
}
public class HostMetaJsonResponseLink(string webDomain)
public class HostMetaJsonResponseLink()
{
[J("rel")] public string Rel => "lrdd";
[J("type")] public string Type => "application/jrd+json";
[J("template")] public string Template => $"https://{webDomain}/.well-known/webfinger?resource={{uri}}";
public HostMetaJsonResponseLink(string webDomain) : this()
{
Rel = "lrdd";
Type = "application/jrd+json";
Template = $"https://{webDomain}/.well-known/webfinger?resource={{uri}}";
}
[J("rel")] public string? Rel { get; set; }
[J("type")] public string? Type { get; set; }
[J("template")] public string? Template { get; set; }
}

View file

@ -1,6 +1,7 @@
using System.Net;
using System.Text.Encodings.Web;
using System.Xml;
using Iceshrimp.Backend.Controllers.Federation.Schemas;
using Iceshrimp.Backend.Core.Middleware;
using Iceshrimp.Backend.Core.Services;
@ -75,17 +76,20 @@ public class WebFingerService(HttpClient client, HttpRequestService httpRqSvc, I
private async Task<string> GetWebFingerUrlAsync(string query, string proto, string domain)
{
var template = await GetWebFingerTemplateFromHostMetaAsync($"{proto}://{domain}/.well-known/host-meta") ??
var template = await GetWebFingerTemplateFromHostMetaXmlAsync(proto, domain) ??
await GetWebFingerTemplateFromHostMetaJsonAsync(proto, domain) ??
$"{proto}://{domain}/.well-known/webfinger?resource={{uri}}";
var finalQuery = query.StartsWith('@') ? $"acct:{query[1..]}" : query;
var encoded = UrlEncoder.Default.Encode(finalQuery);
return template.Replace("{uri}", encoded);
}
private async Task<string?> GetWebFingerTemplateFromHostMetaAsync(string hostMetaUrl)
private async Task<string?> GetWebFingerTemplateFromHostMetaXmlAsync(string proto, string domain)
{
try
{
var hostMetaUrl = $"{proto}://{domain}/.well-known/host-meta";
using var res = await client.SendAsync(httpRqSvc.Get(hostMetaUrl, ["application/xrd+xml"]),
HttpCompletionOption.ResponseHeadersRead);
using var stream = await res.Content.ReadAsStreamAsync();
@ -109,4 +113,52 @@ public class WebFingerService(HttpClient client, HttpRequestService httpRqSvc, I
return null;
}
}
private async Task<string?> GetWebFingerTemplateFromHostMetaJsonAsync(string proto, string domain)
{
try
{
var hostMetaUrl = $"{proto}://{domain}/.well-known/host-meta.json";
using var res = await client.SendAsync(httpRqSvc.Get(hostMetaUrl, ["application/jrd+json"]),
HttpCompletionOption.ResponseHeadersRead);
var deserialized = await res.Content.ReadFromJsonAsync<HostMetaJsonResponse>();
var result = deserialized?.Links?.FirstOrDefault(p => p is
{
Rel: "lrdd",
Type: "application/jrd+json",
Template: not null
});
if (result?.Template != null)
return result.Template;
}
catch
{
// ignored
}
try
{
var hostMetaUrl = $"{proto}://{domain}/.well-known/host-meta";
using var res = await client.SendAsync(httpRqSvc.Get(hostMetaUrl, ["application/jrd+json"]),
HttpCompletionOption.ResponseHeadersRead);
var deserialized = await res.Content.ReadFromJsonAsync<HostMetaJsonResponse>();
var result = deserialized?.Links?.FirstOrDefault(p => p is
{
Rel: "lrdd",
Type: "application/jrd+json",
Template: not null
});
return result?.Template;
}
catch
{
// ignored
}
return null;
}
}