From db835755e01b13dcb8d33a91f57ae8f20b931c57 Mon Sep 17 00:00:00 2001 From: Rory& Date: Sun, 9 Mar 2025 17:24:34 +0100 Subject: Well known resolver work, synapse admin work --- LibMatrix/Services/HomeserverResolverService.cs | 6 +- LibMatrix/Services/ServiceInstaller.cs | 7 +- .../WellKnownResolverConfiguration.cs | 49 ++++++++++++ .../WellKnownResolver/WellKnownResolverService.cs | 91 ++++++++++++++++++++++ .../WellKnownResolvers/BaseWellKnownResolver.cs | 52 +++++++++++++ .../WellKnownResolvers/ClientWellKnownResolver.cs | 42 ++++++++++ .../WellKnownResolvers/ServerWellKnownResolver.cs | 38 +++++++++ .../WellKnownResolvers/SupportWellKnownResolver.cs | 44 +++++++++++ LibMatrix/Services/WellKnownResolverService.cs | 88 --------------------- .../WellKnownResolvers/ClientWellKnownResolver.cs | 53 ------------- .../WellKnownResolvers/SupportWellKnownResolver.cs | 54 ------------- 11 files changed, 326 insertions(+), 198 deletions(-) create mode 100644 LibMatrix/Services/WellKnownResolver/WellKnownResolverConfiguration.cs create mode 100644 LibMatrix/Services/WellKnownResolver/WellKnownResolverService.cs create mode 100644 LibMatrix/Services/WellKnownResolver/WellKnownResolvers/BaseWellKnownResolver.cs create mode 100644 LibMatrix/Services/WellKnownResolver/WellKnownResolvers/ClientWellKnownResolver.cs create mode 100644 LibMatrix/Services/WellKnownResolver/WellKnownResolvers/ServerWellKnownResolver.cs create mode 100644 LibMatrix/Services/WellKnownResolver/WellKnownResolvers/SupportWellKnownResolver.cs delete mode 100644 LibMatrix/Services/WellKnownResolverService.cs delete mode 100644 LibMatrix/Services/WellKnownResolvers/ClientWellKnownResolver.cs delete mode 100644 LibMatrix/Services/WellKnownResolvers/SupportWellKnownResolver.cs (limited to 'LibMatrix/Services') diff --git a/LibMatrix/Services/HomeserverResolverService.cs b/LibMatrix/Services/HomeserverResolverService.cs index fa75f1e..01b11cc 100644 --- a/LibMatrix/Services/HomeserverResolverService.cs +++ b/LibMatrix/Services/HomeserverResolverService.cs @@ -49,6 +49,7 @@ public class HomeserverResolverService { ArgumentNullException.ThrowIfNull(homeserver); _logger.LogTrace("Resolving client well-known: {homeserver}", homeserver); ClientWellKnown? clientWellKnown = null; + homeserver = homeserver.TrimEnd('/'); // check if homeserver has a client well-known if (homeserver.StartsWith("https://")) { clientWellKnown = await _httpClient.TryGetFromJsonAsync($"{homeserver}/.well-known/matrix/client"); @@ -80,6 +81,7 @@ public class HomeserverResolverService { ArgumentNullException.ThrowIfNull(homeserver); _logger.LogTrace($"Resolving server well-known: {homeserver}"); ServerWellKnown? serverWellKnown = null; + homeserver = homeserver.TrimEnd('/'); // check if homeserver has a server well-known if (homeserver.StartsWith("https://")) { serverWellKnown = await _httpClient.TryGetFromJsonAsync($"{homeserver}/.well-known/matrix/server"); @@ -95,7 +97,7 @@ public class HomeserverResolverService { _logger.LogInformation("Server well-known for {hs}: {json}", homeserver, serverWellKnown?.ToJson() ?? "null"); if (!string.IsNullOrWhiteSpace(serverWellKnown?.Homeserver)) { - var resolved = serverWellKnown.Homeserver; + var resolved = serverWellKnown.Homeserver.TrimEnd('/'); if (resolved.StartsWith("https://") || resolved.StartsWith("http://")) return resolved; if (await _httpClient.CheckSuccessStatus($"https://{resolved}/_matrix/federation/v1/version")) @@ -106,7 +108,7 @@ public class HomeserverResolverService { } // fallback: most servers host C2S and S2S on the same domain - var clientUrl = await _tryResolveClientEndpoint(homeserver); + var clientUrl = (await _tryResolveClientEndpoint(homeserver)).TrimEnd('/'); if (clientUrl is not null && await _httpClient.CheckSuccessStatus($"{clientUrl}/_matrix/federation/v1/version")) return clientUrl; diff --git a/LibMatrix/Services/ServiceInstaller.cs b/LibMatrix/Services/ServiceInstaller.cs index ecc3f09..5ffd43a 100644 --- a/LibMatrix/Services/ServiceInstaller.cs +++ b/LibMatrix/Services/ServiceInstaller.cs @@ -1,4 +1,5 @@ -using LibMatrix.Services.WellKnownResolvers; +using LibMatrix.Services.WellKnownResolver; +using LibMatrix.Services.WellKnownResolver.WellKnownResolvers; using Microsoft.Extensions.DependencyInjection; namespace LibMatrix.Services; @@ -10,6 +11,10 @@ public static class ServiceInstaller { //Add services services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + if (!services.Any(x => x.ServiceType == typeof(WellKnownResolverConfiguration))) + services.AddSingleton(); services.AddSingleton(); // Legacy services.AddSingleton(); diff --git a/LibMatrix/Services/WellKnownResolver/WellKnownResolverConfiguration.cs b/LibMatrix/Services/WellKnownResolver/WellKnownResolverConfiguration.cs new file mode 100644 index 0000000..26a4c43 --- /dev/null +++ b/LibMatrix/Services/WellKnownResolver/WellKnownResolverConfiguration.cs @@ -0,0 +1,49 @@ +using System.Text.Json.Serialization; + +namespace LibMatrix.Services.WellKnownResolver; + +public class WellKnownResolverConfiguration { + /// + /// Allow transparent downgrades to plaintext HTTP if HTTPS fails + /// Enabling this is unsafe! + /// + [JsonPropertyName("allow_http")] + public bool AllowHttp { get; set; } = false; + + /// + /// Use DNS resolution if available, for resolving SRV records + /// + [JsonPropertyName("allow_dns")] + public bool AllowDns { get; set; } = true; + + /// + /// Use system resolver(s) if empty + /// + [JsonPropertyName("dns_servers")] + public List DnsServers { get; set; } = new(); + + /// + /// Same as AllowDns, but for DNS over HTTPS - useful in browser contexts + /// + [JsonPropertyName("allow_doh")] + public bool AllowDoh { get; set; } = true; + + /// + /// Use DNS over HTTPS - useful in browser contexts + /// Disabled if empty + /// + [JsonPropertyName("doh_servers")] + public List DohServers { get; set; } = new(); + + /// + /// Whether to allow fallback subdomain lookups + /// + [JsonPropertyName("allow_fallback_subdomains")] + public bool AllowFallbackSubdomains { get; set; } = true; + + /// + /// Fallback subdomains to try if the homeserver is not found + /// + [JsonPropertyName("fallback_subdomains")] + public List FallbackSubdomains { get; set; } = ["matrix", "chat", "im"]; +} \ No newline at end of file diff --git a/LibMatrix/Services/WellKnownResolver/WellKnownResolverService.cs b/LibMatrix/Services/WellKnownResolver/WellKnownResolverService.cs new file mode 100644 index 0000000..4c78347 --- /dev/null +++ b/LibMatrix/Services/WellKnownResolver/WellKnownResolverService.cs @@ -0,0 +1,91 @@ +using System.Diagnostics; +using System.Text.Json.Serialization; +using LibMatrix.Extensions; +using LibMatrix.Services.WellKnownResolver.WellKnownResolvers; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + +namespace LibMatrix.Services.WellKnownResolver; + +public class WellKnownResolverService { + private readonly MatrixHttpClient _httpClient = new(); + + private readonly ILogger _logger; + private readonly ClientWellKnownResolver _clientWellKnownResolver; + private readonly SupportWellKnownResolver _supportWellKnownResolver; + private readonly ServerWellKnownResolver _serverWellKnownResolver; + private readonly WellKnownResolverConfiguration _configuration; + + public WellKnownResolverService(ILogger logger, ClientWellKnownResolver clientWellKnownResolver, SupportWellKnownResolver supportWellKnownResolver, + WellKnownResolverConfiguration configuration, ServerWellKnownResolver serverWellKnownResolver) { + _logger = logger; + _clientWellKnownResolver = clientWellKnownResolver; + _supportWellKnownResolver = supportWellKnownResolver; + _configuration = configuration; + _serverWellKnownResolver = serverWellKnownResolver; + if (logger is NullLogger) { + var stackFrame = new StackTrace(true).GetFrame(1); + Console.WriteLine( + $"WARN | Null logger provided to WellKnownResolverService!\n{stackFrame?.GetMethod()?.DeclaringType?.ToString() ?? "null"} at {stackFrame?.GetFileName() ?? "null"}:{stackFrame?.GetFileLineNumber().ToString() ?? "null"}"); + } + } + + public async Task TryResolveWellKnownRecords(string homeserver, bool includeClient = true, bool includeServer = true, bool includeSupport = true, + WellKnownResolverConfiguration? config = null) { + WellKnownRecords records = new(); + _logger.LogDebug($"Resolving well-knowns for {homeserver}"); + if (includeClient && await _clientWellKnownResolver.TryResolveWellKnown(homeserver, config ?? _configuration) is { } clientResult) { + records.ClientWellKnown = clientResult; + } + + if (includeServer && await _serverWellKnownResolver.TryResolveWellKnown(homeserver, config ?? _configuration) is { } serverResult) { + records.ServerWellKnown = serverResult; + } + + if (includeSupport && await _supportWellKnownResolver.TryResolveWellKnown(homeserver, config ?? _configuration) is { } supportResult) { + records.SupportWellKnown = supportResult; + } + + return records; + } + + public class WellKnownRecords { + public WellKnownResolutionResult? ClientWellKnown { get; set; } + public WellKnownResolutionResult? ServerWellKnown { get; set; } + public WellKnownResolutionResult? SupportWellKnown { get; set; } + } + + public class WellKnownResolutionResult { + public WellKnownSource Source { get; set; } + public string? SourceUri { get; set; } + public T? Content { get; set; } + public List Warnings { get; set; } = []; + } + + [JsonConverter(typeof(JsonStringEnumConverter))] + public enum WellKnownSource { + None, + Https, + Dns, + Http, + ManualCheck, + Search + } + + public struct WellKnownResolutionWarning { + public WellKnownResolutionWarningType Type { get; set; } + public string Message { get; set; } + [JsonIgnore] + public Exception? Exception { get; set; } + public string? ExceptionMessage => Exception?.Message; + + [JsonConverter(typeof(JsonStringEnumConverter))] + public enum WellKnownResolutionWarningType { + None, + Exception, + InvalidResponse, + Timeout, + SlowResponse + } + } +} \ No newline at end of file diff --git a/LibMatrix/Services/WellKnownResolver/WellKnownResolvers/BaseWellKnownResolver.cs b/LibMatrix/Services/WellKnownResolver/WellKnownResolvers/BaseWellKnownResolver.cs new file mode 100644 index 0000000..cbe5b0a --- /dev/null +++ b/LibMatrix/Services/WellKnownResolver/WellKnownResolvers/BaseWellKnownResolver.cs @@ -0,0 +1,52 @@ +using System.Diagnostics; +using System.Net.Http.Json; +using ArcaneLibs.Collections; +using LibMatrix.Extensions; + +namespace LibMatrix.Services.WellKnownResolver.WellKnownResolvers; + +public class BaseWellKnownResolver where T : class, new() { + internal static readonly SemaphoreCache> WellKnownCache = new() { + StoreNulls = false + }; + + internal static readonly MatrixHttpClient HttpClient = new(); + + internal async Task> TryGetWellKnownFromUrl(string url, + WellKnownResolverService.WellKnownSource source) { + var sw = Stopwatch.StartNew(); + try { + var request = await HttpClient.GetAsync(url); + sw.Stop(); + var result = new WellKnownResolverService.WellKnownResolutionResult { + Content = await request.Content.ReadFromJsonAsync(), + Source = source, + SourceUri = url, + Warnings = [] + }; + + if (sw.ElapsedMilliseconds > 1000) { + // logger.LogWarning($"Support well-known resolution took {sw.ElapsedMilliseconds}ms: {url}"); + result.Warnings.Add(new() { + Type = WellKnownResolverService.WellKnownResolutionWarning.WellKnownResolutionWarningType.SlowResponse, + Message = $"Well-known resolution took {sw.ElapsedMilliseconds}ms" + }); + } + + return result; + } + catch (Exception e) { + return new WellKnownResolverService.WellKnownResolutionResult { + Source = source, + SourceUri = url, + Warnings = [ + new() { + Exception = e, + Type = WellKnownResolverService.WellKnownResolutionWarning.WellKnownResolutionWarningType.Exception, + Message = e.Message + } + ] + }; + } + } +} \ No newline at end of file diff --git a/LibMatrix/Services/WellKnownResolver/WellKnownResolvers/ClientWellKnownResolver.cs b/LibMatrix/Services/WellKnownResolver/WellKnownResolvers/ClientWellKnownResolver.cs new file mode 100644 index 0000000..f8de38d --- /dev/null +++ b/LibMatrix/Services/WellKnownResolver/WellKnownResolvers/ClientWellKnownResolver.cs @@ -0,0 +1,42 @@ +using System.Text.Json.Serialization; +using ArcaneLibs.Collections; +using LibMatrix.Extensions; +using Microsoft.Extensions.Logging; +using WellKnownType = LibMatrix.Services.WellKnownResolver.WellKnownResolvers.ClientWellKnown; +using ResultType = + LibMatrix.Services.WellKnownResolver.WellKnownResolverService.WellKnownResolutionResult; + +namespace LibMatrix.Services.WellKnownResolver.WellKnownResolvers; + +public class ClientWellKnownResolver(ILogger logger, WellKnownResolverConfiguration configuration) + : BaseWellKnownResolver { + private static readonly SemaphoreCache> ClientWellKnownCache = new() { + StoreNulls = false + }; + + private static readonly MatrixHttpClient HttpClient = new(); + + public Task> TryResolveWellKnown(string homeserver, WellKnownResolverConfiguration? config = null) { + config ??= configuration; + return ClientWellKnownCache.TryGetOrAdd(homeserver, async () => { + logger.LogTrace($"Resolving client well-known: {homeserver}"); + + WellKnownResolverService.WellKnownResolutionResult result = + await TryGetWellKnownFromUrl($"https://{homeserver}/.well-known/matrix/client", WellKnownResolverService.WellKnownSource.Https); + if (result.Content != null) return result; + + + return result; + }); + } +} + +public class ClientWellKnown { + [JsonPropertyName("m.homeserver")] + public WellKnownHomeserver Homeserver { get; set; } + + public class WellKnownHomeserver { + [JsonPropertyName("base_url")] + public required string BaseUrl { get; set; } + } +} \ No newline at end of file diff --git a/LibMatrix/Services/WellKnownResolver/WellKnownResolvers/ServerWellKnownResolver.cs b/LibMatrix/Services/WellKnownResolver/WellKnownResolvers/ServerWellKnownResolver.cs new file mode 100644 index 0000000..a99185c --- /dev/null +++ b/LibMatrix/Services/WellKnownResolver/WellKnownResolvers/ServerWellKnownResolver.cs @@ -0,0 +1,38 @@ +using System.Text.Json.Serialization; +using ArcaneLibs.Collections; +using LibMatrix.Extensions; +using Microsoft.Extensions.Logging; +using WellKnownType = LibMatrix.Services.WellKnownResolver.WellKnownResolvers.ServerWellKnown; +using ResultType = + LibMatrix.Services.WellKnownResolver.WellKnownResolverService.WellKnownResolutionResult; + +namespace LibMatrix.Services.WellKnownResolver.WellKnownResolvers; + +public class ServerWellKnownResolver(ILogger logger, WellKnownResolverConfiguration configuration) + : BaseWellKnownResolver { + private static readonly SemaphoreCache> ClientWellKnownCache = new() { + StoreNulls = false + }; + + private static readonly MatrixHttpClient HttpClient = new(); + + public Task> TryResolveWellKnown(string homeserver, WellKnownResolverConfiguration? config = null) { + config ??= configuration; + return ClientWellKnownCache.TryGetOrAdd(homeserver, async () => { + logger.LogTrace($"Resolving client well-known: {homeserver}"); + + WellKnownResolverService.WellKnownResolutionResult result = + await TryGetWellKnownFromUrl($"https://{homeserver}/.well-known/matrix/server", WellKnownResolverService.WellKnownSource.Https); + if (result.Content != null) return result; + + + return result; + }); + } +} + + +public class ServerWellKnown { + [JsonPropertyName("m.server")] + public string Homeserver { get; set; } +} \ No newline at end of file diff --git a/LibMatrix/Services/WellKnownResolver/WellKnownResolvers/SupportWellKnownResolver.cs b/LibMatrix/Services/WellKnownResolver/WellKnownResolvers/SupportWellKnownResolver.cs new file mode 100644 index 0000000..99313db --- /dev/null +++ b/LibMatrix/Services/WellKnownResolver/WellKnownResolvers/SupportWellKnownResolver.cs @@ -0,0 +1,44 @@ +using System.Diagnostics; +using System.Net.Http.Json; +using System.Text.Json.Serialization; +using Microsoft.Extensions.Logging; +using WellKnownType = LibMatrix.Services.WellKnownResolver.WellKnownResolvers.SupportWellKnown; +using ResultType = LibMatrix.Services.WellKnownResolver.WellKnownResolverService.WellKnownResolutionResult< + LibMatrix.Services.WellKnownResolver.WellKnownResolvers.SupportWellKnown? +>; + +namespace LibMatrix.Services.WellKnownResolver.WellKnownResolvers; + +public class SupportWellKnownResolver(ILogger logger, WellKnownResolverConfiguration configuration) : BaseWellKnownResolver { + public Task TryResolveWellKnown(string homeserver, WellKnownResolverConfiguration? config = null) { + config ??= configuration; + return WellKnownCache.TryGetOrAdd(homeserver, async () => { + logger.LogTrace($"Resolving support well-known: {homeserver}"); + + ResultType result = await TryGetWellKnownFromUrl($"https://{homeserver}/.well-known/matrix/support", WellKnownResolverService.WellKnownSource.Https); + if (result.Content != null) + return result; + + return null; + }); + } +} + +public class SupportWellKnown { + [JsonPropertyName("contacts")] + public List? Contacts { get; set; } + + [JsonPropertyName("support_page")] + public Uri? SupportPage { get; set; } + + public class WellKnownContact { + [JsonPropertyName("email_address")] + public string? EmailAddress { get; set; } + + [JsonPropertyName("matrix_id")] + public string? MatrixId { get; set; } + + [JsonPropertyName("role")] + public required string Role { get; set; } + } +} \ No newline at end of file diff --git a/LibMatrix/Services/WellKnownResolverService.cs b/LibMatrix/Services/WellKnownResolverService.cs deleted file mode 100644 index ab2660f..0000000 --- a/LibMatrix/Services/WellKnownResolverService.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System.Diagnostics; -using System.Text.Json.Serialization; -using ArcaneLibs.Collections; -using ArcaneLibs.Extensions; -using LibMatrix.Extensions; -using LibMatrix.Services.WellKnownResolvers; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; - -namespace LibMatrix.Services; - -public class WellKnownResolverService { - private readonly MatrixHttpClient _httpClient = new(); - - private readonly ILogger _logger; - - public WellKnownResolverService(ILogger logger) { - _logger = logger; - if (logger is NullLogger) { - var stackFrame = new StackTrace(true).GetFrame(1); - Console.WriteLine( - $"WARN | Null logger provided to WellKnownResolverService!\n{stackFrame?.GetMethod()?.DeclaringType?.ToString() ?? "null"} at {stackFrame?.GetFileName() ?? "null"}:{stackFrame?.GetFileLineNumber().ToString() ?? "null"}"); - } - } - - public async Task TryResolveWellKnownRecords(string homeserver) { - WellKnownRecords records = new(); - _logger.LogDebug($"Resolving well-knowns for {homeserver}"); - - return records; - } - - - - public class ServerWellKnown { - [JsonPropertyName("m.server")] - public required string Homeserver { get; set; } - } - - public class WellKnownRecords { - public ClientWellKnownResolver.ClientWellKnown? ClientWellKnown { get; set; } - public ServerWellKnown? ServerWellKnown { get; set; } - public SupportWellKnownResolver.SupportWellKnown? SupportWellKnown { get; set; } - - /// - /// Reports the source of the client well-known data. - /// - public WellKnownSource? ClientWellKnownSource { get; set; } - - /// - /// Reports the source of the server well-known data. - /// - public WellKnownSource? ServerWellKnownSource { get; set; } - - /// - /// Reports the source of the support well-known data. - /// - public WellKnownSource? SupportWellKnownSource { get; set; } - } - - public struct WellKnownResolutionResult { - public WellKnownResolverService.WellKnownSource Source { get; set; } - public T WellKnown { get; set; } - public List Warnings { get; set; } - } - - public enum WellKnownSource { - None, - Https, - Dns, - Http, - ManualCheck, - Search - } - - public struct WellKnownResolutionWarning { - public WellKnownResolutionWarningType Type { get; set; } - public string Message { get; set; } - public Exception? Exception { get; set; } - - public enum WellKnownResolutionWarningType { - None, - Exception, - InvalidResponse, - Timeout - } - } -} \ No newline at end of file diff --git a/LibMatrix/Services/WellKnownResolvers/ClientWellKnownResolver.cs b/LibMatrix/Services/WellKnownResolvers/ClientWellKnownResolver.cs deleted file mode 100644 index d4d0166..0000000 --- a/LibMatrix/Services/WellKnownResolvers/ClientWellKnownResolver.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Text.Json.Serialization; -using ArcaneLibs.Collections; -using LibMatrix.Extensions; -using Microsoft.Extensions.Logging; - -namespace LibMatrix.Services.WellKnownResolvers; - -public class ClientWellKnownResolver(ILogger logger) { - private static readonly SemaphoreCache ClientWellKnownCache = new() { - StoreNulls = false - }; - private static readonly MatrixHttpClient HttpClient = new(); - - public Task TryResolveClientWellKnown(string homeserver) { - return ClientWellKnownCache.TryGetOrAdd(homeserver, async () => { - logger.LogTrace($"Resolving client well-known: {homeserver}"); - if ((await TryGetClientWellKnownFromHttps(homeserver)) is { } clientWellKnown) - return new() { - Source = WellKnownResolverService.WellKnownSource.Https, - WellKnown = clientWellKnown - }; - - return default!; - }); - } - - private async Task TryGetClientWellKnownFromHttps(string homeserver) { - try { - return await HttpClient.TryGetFromJsonAsync($"https://{homeserver}/.well-known/matrix/client"); - } - catch { - return null; - } - } - - - - public class ClientWellKnown { - [JsonPropertyName("m.homeserver")] - public required WellKnownHomeserver Homeserver { get; set; } - - public class WellKnownHomeserver { - [JsonPropertyName("base_url")] - public required string BaseUrl { get; set; } - } - } - - public struct WellKnownResolutionResult { - public WellKnownResolverService.WellKnownSource Source { get; set; } - public ClientWellKnown WellKnown { get; set; } - public List Warnings { get; set; } - } -} \ No newline at end of file diff --git a/LibMatrix/Services/WellKnownResolvers/SupportWellKnownResolver.cs b/LibMatrix/Services/WellKnownResolvers/SupportWellKnownResolver.cs deleted file mode 100644 index 1d7567a..0000000 --- a/LibMatrix/Services/WellKnownResolvers/SupportWellKnownResolver.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Text.Json.Serialization; -using ArcaneLibs.Collections; -using LibMatrix.Extensions; -using Microsoft.Extensions.Logging; - -namespace LibMatrix.Services.WellKnownResolvers; - -public class SupportWellKnownResolver(ILogger logger) { - private static readonly SemaphoreCache> ClientWellKnownCache = new() { - StoreNulls = false - }; - - private static readonly MatrixHttpClient HttpClient = new(); - - public Task> TryResolveClientWellKnown(string homeserver) { - return ClientWellKnownCache.TryGetOrAdd(homeserver, async () => { - logger.LogTrace($"Resolving client well-known: {homeserver}"); - if ((await TryGetClientWellKnownFromHttps(homeserver)) is { } clientWellKnown) - return new() { - Source = WellKnownResolverService.WellKnownSource.Https, - WellKnown = clientWellKnown - }; - return default!; - }); - } - - private async Task TryGetClientWellKnownFromHttps(string homeserver) { - try { - return await HttpClient.TryGetFromJsonAsync($"https://{homeserver}/.well-known/matrix/support"); - } - catch { - return null; - } - } - - public struct SupportWellKnown { - [JsonPropertyName("contacts")] - public List? Contacts { get; set; } - - [JsonPropertyName("support_page")] - public Uri? SupportPage { get; set; } - - public class WellKnownContact { - [JsonPropertyName("email_address")] - public string? EmailAddress { get; set; } - - [JsonPropertyName("matrix_id")] - public string? MatrixId { get; set; } - - [JsonPropertyName("role")] - public required string Role { get; set; } - } - } -} \ No newline at end of file -- cgit 1.5.1