72 lines
3.1 KiB
C#
72 lines
3.1 KiB
C#
using System.Net.Http.Headers;
|
|
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 CONTENT_LENGTH_HEADER = "Content-Length";
|
|
public const string CONTENT_TYPE_HEADER = "Content-Type";
|
|
public const string CONTENT_TYPE = "application/json; charset=utf-8";
|
|
|
|
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);
|
|
_logger.Debug("Content length in header: '{ContentLength}'", request.Headers.Where(c => c.Key == "Content-Length"));
|
|
var resp = await _httpClient.SendAsync(request);
|
|
if (!resp.IsSuccessStatusCode)
|
|
{
|
|
var error = await resp.Content.ReadAsStringAsync();
|
|
_logger.Error("Received {Status}, body: {Error}", resp.StatusCode, error);
|
|
// TODO: replace this with specific exception type
|
|
throw new Exception("oh no a request error");
|
|
}
|
|
|
|
var bodyString = await resp.Content.ReadAsStringAsync();
|
|
// TODO: replace this with specific exception type
|
|
return DeserializeObject<T>(bodyString) ?? throw new Exception("oh no invalid json");
|
|
}
|
|
|
|
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);
|
|
}
|