mirror of
				https://github.com/NicolasConstant/BirdsiteLive
				synced 2025-06-05 21:49:16 +02:00 
			
		
		
		
	starting working on activity
This commit is contained in:
		
							
								
								
									
										30
									
								
								src/BirdsiteLive.ActivityPub/ApDeserializer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/BirdsiteLive.ActivityPub/ApDeserializer.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | using Newtonsoft.Json; | ||||||
|  |  | ||||||
|  | namespace BirdsiteLive.ActivityPub | ||||||
|  | { | ||||||
|  |     public class ApDeserializer | ||||||
|  |     { | ||||||
|  |         public static Activity ProcessActivity(string json) | ||||||
|  |         { | ||||||
|  |             var activity = JsonConvert.DeserializeObject<Activity>(json); | ||||||
|  |             switch (activity.type) | ||||||
|  |             { | ||||||
|  |                 case "Follow": | ||||||
|  |                     return JsonConvert.DeserializeObject<ActivityFollow>(json); | ||||||
|  |                 case "Undo": | ||||||
|  |                     var a = JsonConvert.DeserializeObject<ActivityUndo>(json); | ||||||
|  |                     if(a.apObject.type == "Follow") | ||||||
|  |                         return JsonConvert.DeserializeObject<ActivityUndoFollow>(json); | ||||||
|  |                     break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         private class Ac : Activity | ||||||
|  |         { | ||||||
|  |             [JsonProperty("object")] | ||||||
|  |             public Activity apObject { get; set; } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -5,6 +5,7 @@ | |||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|  |  | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|  |     <PackageReference Include="Newtonsoft.Json" Version="12.0.2" /> | ||||||
|     <PackageReference Include="System.Text.Json" Version="4.7.2" /> |     <PackageReference Include="System.Text.Json" Version="4.7.2" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								src/BirdsiteLive.ActivityPub/Models/Activity.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/BirdsiteLive.ActivityPub/Models/Activity.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | using System.Text.Json.Serialization; | ||||||
|  | using Newtonsoft.Json; | ||||||
|  |  | ||||||
|  | namespace BirdsiteLive.ActivityPub | ||||||
|  | { | ||||||
|  |     public class Activity | ||||||
|  |     { | ||||||
|  |         [JsonProperty("@context")] | ||||||
|  |         public string context { get; set; } | ||||||
|  |         public string id { get; set; } | ||||||
|  |         public string type { get; set; } | ||||||
|  |         public string actor { get; set; } | ||||||
|  |         //[JsonProperty("object")] | ||||||
|  |         //public string apObject { get; set; } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								src/BirdsiteLive.ActivityPub/Models/ActivityFollow.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/BirdsiteLive.ActivityPub/Models/ActivityFollow.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | using Newtonsoft.Json; | ||||||
|  |  | ||||||
|  | namespace BirdsiteLive.ActivityPub | ||||||
|  | { | ||||||
|  |     public class ActivityFollow : Activity | ||||||
|  |     { | ||||||
|  |         [JsonProperty("object")] | ||||||
|  |         public string apObject { get; set; } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								src/BirdsiteLive.ActivityPub/Models/ActivityUndo.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/BirdsiteLive.ActivityPub/Models/ActivityUndo.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | using Newtonsoft.Json; | ||||||
|  |  | ||||||
|  | namespace BirdsiteLive.ActivityPub | ||||||
|  | { | ||||||
|  |     public class ActivityUndo : Activity | ||||||
|  |     { | ||||||
|  |         [JsonProperty("object")] | ||||||
|  |         public Activity apObject { get; set; } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								src/BirdsiteLive.ActivityPub/Models/ActivityUndoFollow.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/BirdsiteLive.ActivityPub/Models/ActivityUndoFollow.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | using Newtonsoft.Json; | ||||||
|  |  | ||||||
|  | namespace BirdsiteLive.ActivityPub | ||||||
|  | { | ||||||
|  |     public class ActivityUndoFollow : Activity | ||||||
|  |     { | ||||||
|  |         [JsonProperty("object")] | ||||||
|  |         public ActivityFollow apObject { get; set; } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,12 +1,14 @@ | |||||||
| using System; | using System; | ||||||
| using System.Text.Json.Serialization; | using System.Text.Json.Serialization; | ||||||
|  | using Newtonsoft.Json; | ||||||
| 
 | 
 | ||||||
| namespace BirdsiteLive.ActivityPub | namespace BirdsiteLive.ActivityPub | ||||||
| { | { | ||||||
|     public class Actor |     public class Actor | ||||||
|     { |     { | ||||||
|         [JsonPropertyName("@context")] |         //[JsonPropertyName("@context")] | ||||||
|         public string[] context { get; set; } = new[] {"https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"}; |         [JsonProperty("@context")] | ||||||
|  |         public object[] context { get; set; } = new[] {"https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1" }; | ||||||
|         public string id { get; set; } |         public string id { get; set; } | ||||||
|         public string type { get; set; } |         public string type { get; set; } | ||||||
|         public string preferredUsername { get; set; } |         public string preferredUsername { get; set; } | ||||||
							
								
								
									
										26
									
								
								src/BirdsiteLive.Domain/ActivityPubService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/BirdsiteLive.Domain/ActivityPubService.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | using System.Net.Http; | ||||||
|  | using System.Threading.Tasks; | ||||||
|  | using BirdsiteLive.ActivityPub; | ||||||
|  | using Newtonsoft.Json; | ||||||
|  |  | ||||||
|  | namespace BirdsiteLive.Domain | ||||||
|  | { | ||||||
|  |     public interface IActivityPubService | ||||||
|  |     { | ||||||
|  |         Task<Actor> GetUser(string objectId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public class ActivityPubService : IActivityPubService | ||||||
|  |     { | ||||||
|  |         public async Task<Actor> GetUser(string objectId) | ||||||
|  |         { | ||||||
|  |             using (var httpClient = new HttpClient()) | ||||||
|  |             { | ||||||
|  |                 httpClient.DefaultRequestHeaders.Add("Accept", "application/json"); | ||||||
|  |                 var result = await httpClient.GetAsync(objectId); | ||||||
|  |                 var content = await result.Content.ReadAsStringAsync(); | ||||||
|  |                 return JsonConvert.DeserializeObject<Actor>(content); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,24 +1,33 @@ | |||||||
| using System; | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Security.Cryptography; | ||||||
|  | using System.Text; | ||||||
|  | using System.Threading.Tasks; | ||||||
| using BirdsiteLive.ActivityPub; | using BirdsiteLive.ActivityPub; | ||||||
| using BirdsiteLive.Common.Settings; | using BirdsiteLive.Common.Settings; | ||||||
|  | using BirdsiteLive.Cryptography; | ||||||
| using BirdsiteLive.Twitter.Models; | using BirdsiteLive.Twitter.Models; | ||||||
|  | using Tweetinvi.Core.Exceptions; | ||||||
|  |  | ||||||
| namespace BirdsiteLive.Domain | namespace BirdsiteLive.Domain | ||||||
| { | { | ||||||
|     public interface IUserService |     public interface IUserService | ||||||
|     { |     { | ||||||
|         Actor GetUser(TwitterUser twitterUser); |         Actor GetUser(TwitterUser twitterUser); | ||||||
|  |         Task<bool> FollowRequestedAsync(string signature, string method, string path, string queryString, Dictionary<string, string> requestHeaders, ActivityFollow activity); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public class UserService : IUserService |     public class UserService : IUserService | ||||||
|     { |     { | ||||||
|         private readonly ICryptoService _cryptoService; |         private readonly ICryptoService _cryptoService; | ||||||
|  |         private readonly IActivityPubService _activityPubService; | ||||||
|         private readonly string _host; |         private readonly string _host; | ||||||
|  |  | ||||||
|         #region Ctor |         #region Ctor | ||||||
|         public UserService(InstanceSettings instanceSettings, ICryptoService cryptoService) |         public UserService(InstanceSettings instanceSettings, ICryptoService cryptoService, IActivityPubService activityPubService) | ||||||
|         { |         { | ||||||
|             _cryptoService = cryptoService; |             _cryptoService = cryptoService; | ||||||
|  |             _activityPubService = activityPubService; | ||||||
|             _host = $"https://{instanceSettings.Domain.Replace("https://",string.Empty).Replace("http://", string.Empty).TrimEnd('/')}"; |             _host = $"https://{instanceSettings.Domain.Replace("https://",string.Empty).Replace("http://", string.Empty).TrimEnd('/')}"; | ||||||
|         } |         } | ||||||
|         #endregion |         #endregion | ||||||
| @@ -53,5 +62,78 @@ namespace BirdsiteLive.Domain | |||||||
|             }; |             }; | ||||||
|             return user; |             return user; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         public async Task<bool> FollowRequestedAsync(string signature, string method, string path, string queryString, Dictionary<string, string>  requestHeaders, ActivityFollow activity) | ||||||
|  |         { | ||||||
|  |             // Validate | ||||||
|  |             if (!await ValidateSignature(activity.actor, signature, method, path, queryString, requestHeaders)) return false; | ||||||
|  |  | ||||||
|  |             // Save Follow in DB | ||||||
|  |  | ||||||
|  |             // Send Accept Activity  | ||||||
|  |  | ||||||
|  |              | ||||||
|  |             throw new NotImplementedException(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         private async Task<bool> ValidateSignature(string actor, string rawSig, string method, string path, string queryString, Dictionary<string, string> requestHeaders) | ||||||
|  |         { | ||||||
|  |             var signatures = rawSig.Split(','); | ||||||
|  |             var signature_header = new Dictionary<string, string>(); | ||||||
|  |             foreach (var signature in signatures) | ||||||
|  |             { | ||||||
|  |                 var splitSig = signature.Replace("\"", string.Empty).Split('='); | ||||||
|  |                 signature_header.Add(splitSig[0], splitSig[1]); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             signature_header["signature"] = signature_header["signature"] + "=="; | ||||||
|  |  | ||||||
|  |             var key_id = signature_header["keyId"]; | ||||||
|  |             var headers = signature_header["headers"]; | ||||||
|  |             var algorithm = signature_header["algorithm"]; | ||||||
|  |             var sig = Convert.FromBase64String(signature_header["signature"]); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             var remoteUser = await _activityPubService.GetUser(actor); | ||||||
|  |  | ||||||
|  |             var toDecode = remoteUser.publicKey.publicKeyPem.Trim().Remove(0, remoteUser.publicKey.publicKeyPem.IndexOf('\n')); | ||||||
|  |             toDecode = toDecode.Remove(toDecode.LastIndexOf('\n')).Replace("\n", ""); | ||||||
|  |             var signKey = ASN1.ToRSA(Convert.FromBase64String(toDecode)); | ||||||
|  |  | ||||||
|  |             var toSign = new StringBuilder(); | ||||||
|  |             //var comparisonString = headers.Split(' ').Select(signed_header_name => | ||||||
|  |             //{ | ||||||
|  |             //    if (signed_header_name == "(request-target)") | ||||||
|  |             //        return "(request-target): post /inbox"; | ||||||
|  |             //    else | ||||||
|  |             //        return $"{signed_header_name}: {r.Headers[signed_header_name.ToUpperInvariant()]}"; | ||||||
|  |             //}); | ||||||
|  |  | ||||||
|  |             foreach (var headerKey in headers.Split(' ')) | ||||||
|  |             { | ||||||
|  |                 if (headerKey == "(request-target)") toSign.Append($"(request-target): {method.ToLower()} {path}{queryString}\n"); | ||||||
|  |                 else toSign.Append($"{headerKey}: {string.Join(", ", requestHeaders[headerKey])}\n"); | ||||||
|  |             } | ||||||
|  |             toSign.Remove(toSign.Length - 1, 1); | ||||||
|  |  | ||||||
|  |             //var signKey = ASN1.ToRSA(Convert.FromBase64String(toDecode)); | ||||||
|  |  | ||||||
|  |             //new RSACryptoServiceProvider(keyId.publicKey.publicKeyPem); | ||||||
|  |  | ||||||
|  |             //Create a new instance of RSACryptoServiceProvider. | ||||||
|  |             RSACryptoServiceProvider key = new RSACryptoServiceProvider(); | ||||||
|  |  | ||||||
|  |             //Get an instance of RSAParameters from ExportParameters function. | ||||||
|  |             RSAParameters RSAKeyInfo = key.ExportParameters(false); | ||||||
|  |  | ||||||
|  |             //Set RSAKeyInfo to the public key values. | ||||||
|  |             RSAKeyInfo.Modulus = Convert.FromBase64String(toDecode); | ||||||
|  |  | ||||||
|  |             key.ImportParameters(RSAKeyInfo); | ||||||
|  |  | ||||||
|  |             var result = signKey.VerifyData(Encoding.UTF8.GetBytes(toSign.ToString()), sig, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); | ||||||
|  |  | ||||||
|  |             return result; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -21,6 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BirdsiteLive.Domain", "Bird | |||||||
| EndProject | EndProject | ||||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BirdsiteLive.ActivityPub", "BirdsiteLive.ActivityPub\BirdsiteLive.ActivityPub.csproj", "{7463E1E2-9736-4A46-8507-010BDD8ECFBB}" | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BirdsiteLive.ActivityPub", "BirdsiteLive.ActivityPub\BirdsiteLive.ActivityPub.csproj", "{7463E1E2-9736-4A46-8507-010BDD8ECFBB}" | ||||||
| EndProject | EndProject | ||||||
|  | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BirdsiteLive.ActivityPub.Tests", "Tests\BirdsiteLive.ActivityPub.Tests\BirdsiteLive.ActivityPub.Tests.csproj", "{1D713961-9926-41FF-8D6A-8A4B8D548484}" | ||||||
|  | EndProject | ||||||
| Global | Global | ||||||
| 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||||
| 		Debug|Any CPU = Debug|Any CPU | 		Debug|Any CPU = Debug|Any CPU | ||||||
| @@ -55,6 +57,10 @@ Global | |||||||
| 		{7463E1E2-9736-4A46-8507-010BDD8ECFBB}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{7463E1E2-9736-4A46-8507-010BDD8ECFBB}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{7463E1E2-9736-4A46-8507-010BDD8ECFBB}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{7463E1E2-9736-4A46-8507-010BDD8ECFBB}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{7463E1E2-9736-4A46-8507-010BDD8ECFBB}.Release|Any CPU.Build.0 = Release|Any CPU | 		{7463E1E2-9736-4A46-8507-010BDD8ECFBB}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
|  | 		{1D713961-9926-41FF-8D6A-8A4B8D548484}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{1D713961-9926-41FF-8D6A-8A4B8D548484}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
|  | 		{1D713961-9926-41FF-8D6A-8A4B8D548484}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
|  | 		{1D713961-9926-41FF-8D6A-8A4B8D548484}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 	EndGlobalSection | 	EndGlobalSection | ||||||
| 	GlobalSection(SolutionProperties) = preSolution | 	GlobalSection(SolutionProperties) = preSolution | ||||||
| 		HideSolutionNode = FALSE | 		HideSolutionNode = FALSE | ||||||
| @@ -66,6 +72,7 @@ Global | |||||||
| 		{155D46A4-2D05-47F2-8FFC-0B7C412A7652} = {A32D3458-09D0-4E0A-BA4B-8C411B816B94} | 		{155D46A4-2D05-47F2-8FFC-0B7C412A7652} = {A32D3458-09D0-4E0A-BA4B-8C411B816B94} | ||||||
| 		{D48450EE-D8BD-4228-9864-043AC88F7EE0} = {4FEAD6BC-3C8E-451A-8CA1-FF1AF47D26CC} | 		{D48450EE-D8BD-4228-9864-043AC88F7EE0} = {4FEAD6BC-3C8E-451A-8CA1-FF1AF47D26CC} | ||||||
| 		{7463E1E2-9736-4A46-8507-010BDD8ECFBB} = {4FEAD6BC-3C8E-451A-8CA1-FF1AF47D26CC} | 		{7463E1E2-9736-4A46-8507-010BDD8ECFBB} = {4FEAD6BC-3C8E-451A-8CA1-FF1AF47D26CC} | ||||||
|  | 		{1D713961-9926-41FF-8D6A-8A4B8D548484} = {A32D3458-09D0-4E0A-BA4B-8C411B816B94} | ||||||
| 	EndGlobalSection | 	EndGlobalSection | ||||||
| 	GlobalSection(ExtensibilityGlobals) = postSolution | 	GlobalSection(ExtensibilityGlobals) = postSolution | ||||||
| 		SolutionGuid = {69E8DCAD-4C37-4010-858F-5F94E6FBABCE} | 		SolutionGuid = {69E8DCAD-4C37-4010-858F-5F94E6FBABCE} | ||||||
|   | |||||||
| @@ -4,9 +4,13 @@ using System.IO; | |||||||
| using System.Linq; | using System.Linq; | ||||||
| using System.Threading; | using System.Threading; | ||||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||||
|  | using BirdsiteLive.ActivityPub; | ||||||
| using BirdsiteLive.Domain; | using BirdsiteLive.Domain; | ||||||
| using BirdsiteLive.Twitter; | using BirdsiteLive.Twitter; | ||||||
|  | using Microsoft.AspNetCore.Http; | ||||||
| using Microsoft.AspNetCore.Mvc; | using Microsoft.AspNetCore.Mvc; | ||||||
|  | using Microsoft.Extensions.Primitives; | ||||||
|  | using Newtonsoft.Json; | ||||||
|  |  | ||||||
| namespace BirdsiteLive.Controllers | namespace BirdsiteLive.Controllers | ||||||
| { | { | ||||||
| @@ -34,7 +38,8 @@ namespace BirdsiteLive.Controllers | |||||||
|             if (r.Contains("application/activity+json")) |             if (r.Contains("application/activity+json")) | ||||||
|             { |             { | ||||||
|                 var apUser = _userService.GetUser(user); |                 var apUser = _userService.GetUser(user); | ||||||
|                 return Json(apUser); |                 var jsonApUser = JsonConvert.SerializeObject(apUser); | ||||||
|  |                 return Content(jsonApUser, "application/json"); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return View(user); |             return View(user); | ||||||
| @@ -48,11 +53,27 @@ namespace BirdsiteLive.Controllers | |||||||
|             using (var reader = new StreamReader(Request.Body)) |             using (var reader = new StreamReader(Request.Body)) | ||||||
|             { |             { | ||||||
|                 var body = await reader.ReadToEndAsync(); |                 var body = await reader.ReadToEndAsync(); | ||||||
|  |                 var activity = ApDeserializer.ProcessActivity(body); | ||||||
|                 // Do something |                 // Do something | ||||||
|  |  | ||||||
|  |                 switch (activity.type) | ||||||
|  |                 { | ||||||
|  |                     case "Follow":  | ||||||
|  |                         var succeeded = await _userService.FollowRequestedAsync(r.Headers["Signature"].First(), r.Method, r.Path, r.QueryString.ToString(), RequestHeaders(r.Headers), activity as ActivityFollow); | ||||||
|  |                         if (succeeded) return Ok(); | ||||||
|  |                         else return Unauthorized(); | ||||||
|  |                         break; | ||||||
|  |                     default: | ||||||
|  |                         return Ok(); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return Ok(); |             return Ok(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         private Dictionary<string, string> RequestHeaders(IHeaderDictionary header) | ||||||
|  |         { | ||||||
|  |             return header.ToDictionary<KeyValuePair<string, StringValues>, string, string>(h => h.Key, h => h.Value); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
							
								
								
									
										33
									
								
								src/Tests/BirdsiteLive.ActivityPub.Tests/ActivityTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/Tests/BirdsiteLive.ActivityPub.Tests/ActivityTests.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||||
|  | using Newtonsoft.Json; | ||||||
|  |  | ||||||
|  | namespace BirdsiteLive.ActivityPub.Tests | ||||||
|  | { | ||||||
|  |     //[TestClass] | ||||||
|  |     //public class ActivityTests | ||||||
|  |     //{ | ||||||
|  |     //    [TestMethod] | ||||||
|  |     //    public void FollowDeserializationTest() | ||||||
|  |     //    { | ||||||
|  |     //        var json = "{ \"@context\":\"https://www.w3.org/ns/activitystreams\",\"id\":\"https://mastodon.technology/c94567cf-1fda-42ba-82fc-a0f82f63ccbe\",\"type\":\"Follow\",\"actor\":\"https://mastodon.technology/users/testtest\",\"object\":\"https://4a120ca2680e.ngrok.io/users/manu\"}"; | ||||||
|  |  | ||||||
|  |     //        var data = JsonConvert.DeserializeObject<Activity>(json); | ||||||
|  |  | ||||||
|  |     //        Assert.AreEqual("https://mastodon.technology/c94567cf-1fda-42ba-82fc-a0f82f63ccbe", data.id); | ||||||
|  |     //        Assert.AreEqual("Follow", data.type); | ||||||
|  |     //        Assert.AreEqual("https://4a120ca2680e.ngrok.io/users/manu", data.apObject); | ||||||
|  |     //    } | ||||||
|  |  | ||||||
|  |     //    [TestMethod] | ||||||
|  |     //    public void UndoDeserializationTest() | ||||||
|  |     //    { | ||||||
|  |     //        var json = | ||||||
|  |     //            "{\"@context\":\"https://www.w3.org/ns/activitystreams\",\"id\":\"https://mastodon.technology/users/testtest#follows/225982/undo\",\"type\":\"Undo\",\"actor\":\"https://mastodon.technology/users/testtest\",\"object\":{\"id\":\"https://mastodon.technology/c94567cf-1fda-42ba-82fc-a0f82f63ccbe\",\"type\":\"Follow\",\"actor\":\"https://mastodon.technology/users/testtest\",\"object\":\"https://4a120ca2680e.ngrok.io/users/manu\"}}"; | ||||||
|  |  | ||||||
|  |     //        var data = JsonConvert.DeserializeObject<Activity>(json); | ||||||
|  |     //        Assert.AreEqual("https://mastodon.technology/users/testtest#follows/225982/undo", data.id); | ||||||
|  |     //        Assert.AreEqual("Undo", data.type); | ||||||
|  |     //        Assert.AreEqual("https://4a120ca2680e.ngrok.io/users/manu", data.apObject); | ||||||
|  |     //    } | ||||||
|  |     //} | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								src/Tests/BirdsiteLive.ActivityPub.Tests/ActorTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/Tests/BirdsiteLive.ActivityPub.Tests/ActorTests.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||||
|  | using Newtonsoft.Json; | ||||||
|  |  | ||||||
|  | namespace BirdsiteLive.ActivityPub.Tests | ||||||
|  | { | ||||||
|  |     [TestClass] | ||||||
|  |     public class ActorTests | ||||||
|  |     { | ||||||
|  |         [TestMethod] | ||||||
|  |         public void Deserialize() | ||||||
|  |         { | ||||||
|  |             var json = | ||||||
|  |                 "{\"@context\":[\"https://www.w3.org/ns/activitystreams\",\"https://w3id.org/security/v1\",{\"manuallyApprovesFollowers\":\"as:manuallyApprovesFollowers\",\"toot\":\"http://joinmastodon.org/ns#\",\"featured\":{\"@id\":\"toot:featured\",\"@type\":\"@id\"},\"alsoKnownAs\":{\"@id\":\"as:alsoKnownAs\",\"@type\":\"@id\"},\"movedTo\":{\"@id\":\"as:movedTo\",\"@type\":\"@id\"},\"schema\":\"http://schema.org#\",\"PropertyValue\":\"schema:PropertyValue\",\"value\":\"schema:value\",\"IdentityProof\":\"toot:IdentityProof\",\"discoverable\":\"toot:discoverable\"}],\"id\":\"https://mastodon.technology/users/testtest\",\"type\":\"Person\",\"following\":\"https://mastodon.technology/users/testtest/following\",\"followers\":\"https://mastodon.technology/users/testtest/followers\",\"inbox\":\"https://mastodon.technology/users/testtest/inbox\",\"outbox\":\"https://mastodon.technology/users/testtest/outbox\",\"featured\":\"https://mastodon.technology/users/testtest/collections/featured\",\"preferredUsername\":\"testtest\",\"name\":\"TESTEST\",\"summary\":\"\u003cp\u003etest \u003cbr /\u003edsqdq65d4sq56d456q4d8zd4q685d45qd4sqd2q1d5zq56d465qsd4q65sd21qsd23q1s5d64qsd8q465d4s5q1d6qsd35qs4dq6sd84q\u003c/p\u003e\",\"url\":\"https://mastodon.technology/@testtest\",\"manuallyApprovesFollowers\":false,\"discoverable\":false,\"publicKey\":{\"id\":\"https://mastodon.technology/users/testtest#main-key\",\"owner\":\"https://mastodon.technology/users/testtest\",\"publicKeyPem\":\"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm7BlbWI/UD/YJj288h/5\nFB0gXZj0BjYVaK28uzTvb4w6eMu4qpbE9NI0bFqrloXzL3z6PaOCL4Myz9uJYolE\nZ9uNVi2OeZmHigNEOT3hkJWzddtrhkg8MLXKPdOETjhVWV3n+na7QWDDIXP7Fuvi\n+osA5LOoqtD1rYs87xUcWQPLCtVHs928FXsCdLO11ofXiNrancSzY17nkuufjWO+\ndLtvz1kx4Mt2V4Fu+DHskQAzPKU2tzGBrtlVQrk+1R63psIuZYDB6e4i7L6/d1Xl\nIQGmBeJfyxiuNIlbfZIbJ3xPYBQaVAnRKtyGVEFMWwZCqMySwc2LBX+rxI20zJ0R\n7wIDAQAB\n-----END PUBLIC KEY-----\n\"},\"tag\":[],\"attachment\":[],\"endpoints\":{\"sharedInbox\":\"https://mastodon.technology/inbox\"}}"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             var actor = JsonConvert.DeserializeObject<Actor>(json); | ||||||
|  |  | ||||||
|  |              | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,35 @@ | |||||||
|  | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||||
|  | using Newtonsoft.Json; | ||||||
|  |  | ||||||
|  | namespace BirdsiteLive.ActivityPub.Tests | ||||||
|  | { | ||||||
|  |     [TestClass] | ||||||
|  |     public class ApDeserializerTests | ||||||
|  |     { | ||||||
|  |         [TestMethod] | ||||||
|  |         public void FollowDeserializationTest() | ||||||
|  |         { | ||||||
|  |             var json = "{ \"@context\":\"https://www.w3.org/ns/activitystreams\",\"id\":\"https://mastodon.technology/c94567cf-1fda-42ba-82fc-a0f82f63ccbe\",\"type\":\"Follow\",\"actor\":\"https://mastodon.technology/users/testtest\",\"object\":\"https://4a120ca2680e.ngrok.io/users/manu\"}"; | ||||||
|  |  | ||||||
|  |             var data = ApDeserializer.ProcessActivity(json) as ActivityFollow; | ||||||
|  |  | ||||||
|  |             Assert.AreEqual("https://mastodon.technology/c94567cf-1fda-42ba-82fc-a0f82f63ccbe", data.id); | ||||||
|  |             Assert.AreEqual("Follow", data.type); | ||||||
|  |             Assert.AreEqual("https://4a120ca2680e.ngrok.io/users/manu", data.apObject); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         [TestMethod] | ||||||
|  |         public void UndoDeserializationTest() | ||||||
|  |         { | ||||||
|  |             var json = | ||||||
|  |                 "{\"@context\":\"https://www.w3.org/ns/activitystreams\",\"id\":\"https://mastodon.technology/users/testtest#follows/225982/undo\",\"type\":\"Undo\",\"actor\":\"https://mastodon.technology/users/testtest\",\"object\":{\"id\":\"https://mastodon.technology/c94567cf-1fda-42ba-82fc-a0f82f63ccbe\",\"type\":\"Follow\",\"actor\":\"https://mastodon.technology/users/testtest\",\"object\":\"https://4a120ca2680e.ngrok.io/users/manu\"}}"; | ||||||
|  |  | ||||||
|  |             var data = ApDeserializer.ProcessActivity(json) as ActivityUndoFollow; | ||||||
|  |             Assert.AreEqual("https://mastodon.technology/users/testtest#follows/225982/undo", data.id); | ||||||
|  |             Assert.AreEqual("Undo", data.type); | ||||||
|  |             Assert.AreEqual("Follow", data.apObject.type); | ||||||
|  |             Assert.AreEqual("https://mastodon.technology/users/testtest", data.apObject.actor); | ||||||
|  |             Assert.AreEqual("https://4a120ca2680e.ngrok.io/users/manu", data.apObject.apObject); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,20 @@ | |||||||
|  | <Project Sdk="Microsoft.NET.Sdk"> | ||||||
|  |  | ||||||
|  |   <PropertyGroup> | ||||||
|  |     <TargetFramework>netcoreapp3.1</TargetFramework> | ||||||
|  |  | ||||||
|  |     <IsPackable>false</IsPackable> | ||||||
|  |   </PropertyGroup> | ||||||
|  |  | ||||||
|  |   <ItemGroup> | ||||||
|  |     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> | ||||||
|  |     <PackageReference Include="MSTest.TestAdapter" Version="2.1.0" /> | ||||||
|  |     <PackageReference Include="MSTest.TestFramework" Version="2.1.0" /> | ||||||
|  |     <PackageReference Include="coverlet.collector" Version="1.2.0" /> | ||||||
|  |   </ItemGroup> | ||||||
|  |  | ||||||
|  |   <ItemGroup> | ||||||
|  |     <ProjectReference Include="..\..\BirdsiteLive.ActivityPub\BirdsiteLive.ActivityPub.csproj" /> | ||||||
|  |   </ItemGroup> | ||||||
|  |  | ||||||
|  | </Project> | ||||||
		Reference in New Issue
	
	Block a user