added achitecture to handle Delete action

This commit is contained in:
Nicolas Constant 2021-12-09 02:02:30 -05:00
parent 5ef8af47eb
commit 93b43ee4a0
No known key found for this signature in database
GPG key ID: 1E9F677FB01A5688
7 changed files with 91 additions and 10 deletions

View file

@ -1,4 +1,5 @@
using System;
using BirdsiteLive.ActivityPub.Models;
using Newtonsoft.Json;
namespace BirdsiteLive.ActivityPub
@ -19,6 +20,8 @@ namespace BirdsiteLive.ActivityPub
if(a.apObject.type == "Follow")
return JsonConvert.DeserializeObject<ActivityUndoFollow>(json);
break;
case "Delete":
return JsonConvert.DeserializeObject<ActivityDelete>(json);
case "Accept":
var accept = JsonConvert.DeserializeObject<ActivityAccept>(json);
//var acceptType = JsonConvert.DeserializeObject<Activity>(accept.apObject);

View file

@ -0,0 +1,10 @@
using Newtonsoft.Json;
namespace BirdsiteLive.ActivityPub.Models
{
public class ActivityDelete : Activity
{
[JsonProperty("object")]
public object apObject { get; set; }
}
}

View file

@ -7,6 +7,7 @@ using System.Text;
using System.Threading.Tasks;
using BirdsiteLive.ActivityPub;
using BirdsiteLive.ActivityPub.Converters;
using BirdsiteLive.ActivityPub.Models;
using BirdsiteLive.Common.Regexes;
using BirdsiteLive.Common.Settings;
using BirdsiteLive.Cryptography;
@ -28,6 +29,7 @@ namespace BirdsiteLive.Domain
Task<bool> UndoFollowRequestedAsync(string signature, string method, string path, string queryString, Dictionary<string, string> requestHeaders, ActivityUndoFollow activity, string body);
Task<bool> SendRejectFollowAsync(ActivityFollow activity, string followerHost);
Task<bool> DeleteRequestedAsync(string signature, string method, string path, string queryString, Dictionary<string, string> requestHeaders, ActivityDelete activity, string body);
}
public class UserService : IUserService
@ -213,7 +215,7 @@ namespace BirdsiteLive.Domain
return result == HttpStatusCode.Accepted ||
result == HttpStatusCode.OK; //TODO: revamp this for better error handling
}
private string OnlyKeepRoute(string inbox, string host)
{
if (string.IsNullOrWhiteSpace(inbox))
@ -258,6 +260,19 @@ namespace BirdsiteLive.Domain
return result == HttpStatusCode.Accepted || result == HttpStatusCode.OK; //TODO: revamp this for better error handling
}
public async Task<bool> DeleteRequestedAsync(string signature, string method, string path, string queryString, Dictionary<string, string> requestHeaders,
ActivityDelete activity, string body)
{
// Validate
var sigValidation = await ValidateSignature(activity.actor, signature, method, path, queryString, requestHeaders, body);
if (!sigValidation.SignatureIsValidated) return false;
// Remove user and followings
throw new NotImplementedException();
return true;
}
private async Task<SignatureValidationResult> ValidateSignature(string actor, string rawSig, string method, string path, string queryString, Dictionary<string, string> requestHeaders, string body)
{
//Check Date Validity

View file

@ -3,6 +3,10 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using BirdsiteLive.ActivityPub;
using BirdsiteLive.ActivityPub.Models;
using BirdsiteLive.Domain;
using BirdsiteLive.Tools;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
@ -13,11 +17,13 @@ namespace BirdsiteLive.Controllers
public class InboxController : ControllerBase
{
private readonly ILogger<InboxController> _logger;
private readonly IUserService _userService;
#region Ctor
public InboxController(ILogger<InboxController> logger)
public InboxController(ILogger<InboxController> logger, IUserService userService)
{
_logger = logger;
_userService = userService;
}
#endregion
@ -33,6 +39,19 @@ namespace BirdsiteLive.Controllers
_logger.LogTrace("Inbox: {Body}", body);
//System.IO.File.WriteAllText($@"C:\apdebug\inbox\{Guid.NewGuid()}.json", body);
var activity = ApDeserializer.ProcessActivity(body);
var signature = r.Headers["Signature"].First();
switch (activity?.type)
{
case "Delete":
{
var succeeded = await _userService.DeleteRequestedAsync(signature, r.Method, r.Path,
r.QueryString.ToString(), HeaderHandler.RequestHeaders(r.Headers), activity as ActivityDelete, body);
if (succeeded) return Accepted();
else return Unauthorized();
}
}
}
return Accepted();

View file

@ -13,6 +13,7 @@ using BirdsiteLive.Common.Regexes;
using BirdsiteLive.Common.Settings;
using BirdsiteLive.Domain;
using BirdsiteLive.Models;
using BirdsiteLive.Tools;
using BirdsiteLive.Twitter;
using BirdsiteLive.Twitter.Models;
using Microsoft.AspNetCore.Http;
@ -142,7 +143,6 @@ namespace BirdsiteLive.Controllers
//System.IO.File.WriteAllText($@"C:\apdebug\{Guid.NewGuid()}.json", body);
var activity = ApDeserializer.ProcessActivity(body);
// Do something
var signature = r.Headers["Signature"].First();
switch (activity?.type)
@ -150,7 +150,7 @@ namespace BirdsiteLive.Controllers
case "Follow":
{
var succeeded = await _userService.FollowRequestedAsync(signature, r.Method, r.Path,
r.QueryString.ToString(), RequestHeaders(r.Headers), activity as ActivityFollow, body);
r.QueryString.ToString(), HeaderHandler.RequestHeaders(r.Headers), activity as ActivityFollow, body);
if (succeeded) return Accepted();
else return Unauthorized();
}
@ -158,11 +158,18 @@ namespace BirdsiteLive.Controllers
if (activity is ActivityUndoFollow)
{
var succeeded = await _userService.UndoFollowRequestedAsync(signature, r.Method, r.Path,
r.QueryString.ToString(), RequestHeaders(r.Headers), activity as ActivityUndoFollow, body);
r.QueryString.ToString(), HeaderHandler.RequestHeaders(r.Headers), activity as ActivityUndoFollow, body);
if (succeeded) return Accepted();
else return Unauthorized();
}
return Accepted();
case "Delete":
{
var succeeded = await _userService.DeleteRequestedAsync(signature, r.Method, r.Path,
r.QueryString.ToString(), HeaderHandler.RequestHeaders(r.Headers), activity as ActivityDelete, body);
if (succeeded) return Accepted();
else return Unauthorized();
}
default:
return Accepted();
}
@ -184,9 +191,6 @@ namespace BirdsiteLive.Controllers
return Content(jsonApUser, "application/activity+json; charset=utf-8");
}
private Dictionary<string, string> RequestHeaders(IHeaderDictionary header)
{
return header.ToDictionary<KeyValuePair<string, StringValues>, string, string>(h => h.Key.ToLowerInvariant(), h => h.Value);
}
}
}

View file

@ -0,0 +1,15 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
namespace BirdsiteLive.Tools
{
public class HeaderHandler
{
public static Dictionary<string, string> RequestHeaders(IHeaderDictionary header)
{
return header.ToDictionary<KeyValuePair<string, StringValues>, string, string>(h => h.Key.ToLowerInvariant(), h => h.Value);
}
}
}

View file

@ -1,4 +1,5 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using BirdsiteLive.ActivityPub.Models;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
namespace BirdsiteLive.ActivityPub.Tests
@ -48,6 +49,20 @@ namespace BirdsiteLive.ActivityPub.Tests
Assert.AreEqual("https://mamot.fr/users/testtest", data.apObject.apObject);
}
[TestMethod]
public void DeleteDeserializationTest()
{
var json =
"{\"@context\": \"https://www.w3.org/ns/activitystreams\", \"id\": \"https://mastodon.technology/users/deleteduser#delete\", \"type\": \"Delete\", \"actor\": \"https://mastodon.technology/users/deleteduser\", \"to\": [\"https://www.w3.org/ns/activitystreams#Public\"],\"object\": \"https://mastodon.technology/users/deleteduser\",\"signature\": {\"type\": \"RsaSignature2017\",\"creator\": \"https://mastodon.technology/users/deleteduser#main-key\",\"created\": \"2020-11-19T22:43:01Z\",\"signatureValue\": \"peksQao4v5N+sMZgHXZ6xZnGaZrd0s+LqZimu63cnp7O5NBJM6gY9AAu/vKUgrh4C50r66f9OQdHg5yChQhc4ViE+yLR/3/e59YQimelmXJPpcC99Nt0YLU/iTRLsBehY3cDdC6+ogJKgpkToQvB6tG2KrPdrkreYh4Il4eXLKMfiQhgdKluOvenLnl2erPWfE02hIu/jpuljyxSuvJunMdU4yQVSZHTtk/I8q3jjzIzhgyb7ICWU5Hkx0H/47Q24ztsvOgiTWNgO+v6l9vA7qIhztENiRPhzGP5RCCzUKRAe6bcSu1Wfa3NKWqB9BeJ7s+2y2bD7ubPbiEE1MQV7Q==\"}}";
var data = ApDeserializer.ProcessActivity(json) as ActivityDelete;
Assert.AreEqual("https://mastodon.technology/users/deleteduser#delete", data.id);
Assert.AreEqual("Delete", data.type);
Assert.AreEqual("https://mastodon.technology/users/deleteduser", data.actor);
Assert.AreEqual("https://mastodon.technology/users/deleteduser", data.apObject);
}
//[TestMethod]
//public void NoteDeserializationTest()
//{