cloutier--bird.makeup/src/BirdsiteLive.Domain/ActivityPubService.cs

113 lines
4.3 KiB
C#
Raw Normal View History

2020-06-28 21:56:10 -04:00
using System;
2020-08-01 13:19:41 -04:00
using System.Linq;
2020-06-28 21:56:10 -04:00
using System.Net;
using System.Net.Http;
2020-11-20 20:21:44 -05:00
using System.Security.Cryptography;
2020-06-28 21:56:10 -04:00
using System.Text;
2020-06-06 01:29:13 -04:00
using System.Threading.Tasks;
using BirdsiteLive.ActivityPub;
2021-01-09 22:26:17 -05:00
using BirdsiteLive.ActivityPub.Converters;
2020-07-31 22:13:52 -04:00
using BirdsiteLive.ActivityPub.Models;
using BirdsiteLive.Common.Settings;
2021-03-08 19:27:08 -05:00
using Microsoft.Extensions.Logging;
2020-06-06 01:29:13 -04:00
using Newtonsoft.Json;
namespace BirdsiteLive.Domain
{
public interface IActivityPubService
{
Task<Actor> GetUser(string objectId);
2020-06-28 23:42:23 -04:00
Task<HttpStatusCode> PostDataAsync<T>(T data, string targetHost, string actorUrl, string inbox = null);
2023-02-10 11:54:33 -05:00
Task PostNewActivity(ActivityCreateNote note, string username, string noteId, string targetHost,
string targetInbox);
2020-06-06 01:29:13 -04:00
}
public class ActivityPubService : IActivityPubService
{
private readonly InstanceSettings _instanceSettings;
2021-01-16 00:51:52 -05:00
private readonly IHttpClientFactory _httpClientFactory;
2020-06-28 21:56:10 -04:00
private readonly ICryptoService _cryptoService;
2021-03-08 19:27:08 -05:00
private readonly ILogger<ActivityPubService> _logger;
2020-06-28 21:56:10 -04:00
#region Ctor
2021-03-08 19:27:08 -05:00
public ActivityPubService(ICryptoService cryptoService, InstanceSettings instanceSettings, IHttpClientFactory httpClientFactory, ILogger<ActivityPubService> logger)
2020-06-28 21:56:10 -04:00
{
_cryptoService = cryptoService;
_instanceSettings = instanceSettings;
2021-01-16 00:51:52 -05:00
_httpClientFactory = httpClientFactory;
2021-03-08 19:27:08 -05:00
_logger = logger;
2020-06-28 21:56:10 -04:00
}
#endregion
2020-06-06 01:29:13 -04:00
public async Task<Actor> GetUser(string objectId)
{
2021-01-16 00:51:52 -05:00
var httpClient = _httpClientFactory.CreateClient();
2021-02-06 00:11:11 -05:00
httpClient.DefaultRequestHeaders.Add("Accept", "application/activity+json");
2021-01-16 00:51:52 -05:00
var result = await httpClient.GetAsync(objectId);
2022-02-09 01:15:48 -05:00
if (result.StatusCode == HttpStatusCode.Gone)
2022-02-09 01:54:35 -05:00
throw new FollowerIsGoneException();
2022-02-09 01:15:48 -05:00
result.EnsureSuccessStatusCode();
2021-01-16 00:51:52 -05:00
var content = await result.Content.ReadAsStringAsync();
2021-04-13 01:25:36 -04:00
var actor = JsonConvert.DeserializeObject<Actor>(content);
if (string.IsNullOrWhiteSpace(actor.url)) actor.url = objectId;
return actor;
2020-06-06 01:29:13 -04:00
}
2020-06-28 21:56:10 -04:00
2023-02-10 11:54:33 -05:00
public async Task PostNewActivity(ActivityCreateNote noteActivity, string username, string noteId, string targetHost, string targetInbox)
{
2021-03-08 19:27:08 -05:00
try
{
var actor = UrlFactory.GetActorUrl(_instanceSettings.Domain, username);
2021-03-08 19:27:08 -05:00
await PostDataAsync(noteActivity, targetHost, actor, targetInbox);
}
catch (Exception e)
{
_logger.LogError(e, "Error sending {Username} post ({NoteId}) to {Host}{Inbox}", username, noteId, targetHost, targetInbox);
throw;
}
}
2020-06-28 23:42:23 -04:00
public async Task<HttpStatusCode> PostDataAsync<T>(T data, string targetHost, string actorUrl, string inbox = null)
2020-06-28 21:56:10 -04:00
{
2020-06-28 23:42:23 -04:00
var usedInbox = $"/inbox";
if (!string.IsNullOrWhiteSpace(inbox))
usedInbox = inbox;
2022-05-09 20:31:18 -04:00
var json = JsonConvert.SerializeObject(data, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
2020-06-28 21:56:10 -04:00
var date = DateTime.UtcNow.ToUniversalTime();
var httpDate = date.ToString("r");
2020-06-28 23:42:23 -04:00
2020-12-28 00:43:02 -05:00
var digest = _cryptoService.ComputeSha256Hash(json);
2020-11-20 20:21:44 -05:00
var signature = _cryptoService.SignAndGetSignatureHeader(date, actorUrl, targetHost, digest, usedInbox);
2020-06-28 21:56:10 -04:00
2021-01-16 00:51:52 -05:00
var client = _httpClientFactory.CreateClient();
2023-01-27 13:55:19 -05:00
client.Timeout = TimeSpan.FromSeconds(2);
2020-06-28 21:56:10 -04:00
var httpRequestMessage = new HttpRequestMessage
{
Method = HttpMethod.Post,
2020-11-20 19:00:31 -05:00
RequestUri = new Uri($"https://{targetHost}{usedInbox}"),
2020-06-28 21:56:10 -04:00
Headers =
{
{"Host", targetHost},
{"Date", httpDate},
2020-11-20 20:21:44 -05:00
{"Signature", signature},
{"Digest", $"SHA-256={digest}"}
2020-06-28 21:56:10 -04:00
},
Content = new StringContent(json, Encoding.UTF8, "application/ld+json")
};
var response = await client.SendAsync(httpRequestMessage);
2021-01-16 00:34:09 -05:00
response.EnsureSuccessStatusCode();
2022-05-08 13:45:11 -04:00
_logger.LogInformation("Sent tweet to " + targetHost);
2022-05-08 13:51:35 -04:00
2020-06-28 21:56:10 -04:00
return response.StatusCode;
}
2020-06-06 01:29:13 -04:00
}
}