Foxchat.NET/Foxchat.Core/Federation/RequestSigningService.Client.cs

65 lines
2.8 KiB
C#

using System.Net.Http.Headers;
using Foxchat.Core.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace Foxchat.Core.Federation;
public partial class RequestSigningService
{
public const string USER_AGENT_HEADER = "User-Agent";
public const string USER_AGENT = "Foxchat.NET";
public const string DATE_HEADER = "Date";
public const string SERVER_HEADER = "X-Foxchat-Server";
public const string SIGNATURE_HEADER = "X-Foxchat-Signature";
public const string USER_HEADER = "X-Foxchat-User";
private static readonly JsonSerializerSettings _jsonSerializerSettings = new()
{
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy()
}
};
public async Task<T> RequestAsync<T>(HttpMethod method, string domain, string requestPath, string? userId = null, object? body = null)
{
var request = BuildHttpRequest(method, domain, requestPath, userId, body);
var resp = await _httpClient.SendAsync(request);
if (!resp.IsSuccessStatusCode)
{
var error = await resp.Content.ReadAsStringAsync();
throw new ApiError.OutgoingFederationError($"Request to {domain}{requestPath} returned an error", DeserializeObject<Models.ApiError>(error));
}
var bodyString = await resp.Content.ReadAsStringAsync();
return DeserializeObject<T>(bodyString)
?? throw new ApiError.OutgoingFederationError($"Request to {domain}{requestPath} returned invalid response body");
}
private HttpRequestMessage BuildHttpRequest(HttpMethod method, string domain, string requestPath, string? userId = null, object? bodyData = null)
{
var body = bodyData != null ? SerializeObject(bodyData) : null;
var now = _clock.GetCurrentInstant();
var url = $"https://{domain}{requestPath}";
var signature = GenerateSignature(new SignatureData(now, domain, requestPath, body?.Length, userId));
var request = new HttpRequestMessage(method, url);
request.Headers.Clear();
request.Headers.Add(USER_AGENT_HEADER, USER_AGENT);
request.Headers.Add(DATE_HEADER, FormatTime(now));
request.Headers.Add(SERVER_HEADER, _config.Domain);
request.Headers.Add(SIGNATURE_HEADER, signature);
if (userId != null)
request.Headers.Add(USER_HEADER, userId);
if (body != null)
request.Content = new StringContent(body, new MediaTypeHeaderValue("application/json", "utf-8"));
return request;
}
public static string SerializeObject(object data) => JsonConvert.SerializeObject(data, _jsonSerializerSettings);
public static T? DeserializeObject<T>(string data) => JsonConvert.DeserializeObject<T>(data, _jsonSerializerSettings);
}