From f5fe4f53f92f44c2d4d2461c8e1a73c8781c95b3 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Sun, 28 Jun 2020 20:27:03 -0400 Subject: [PATCH 1/4] added follow debug + ap models + header signing --- .../ApDeserializer.cs | 25 +++++ .../BirdsiteLive.ActivityPub.csproj | 1 + .../Models/Activity.cs | 1 + .../Models/ActivityAccept.cs | 10 ++ .../Models/ActivityAcceptFollow.cs | 10 ++ src/BirdsiteLive.Domain/CryptoService.cs | 25 ++++- src/BirdsiteLive/BirdsiteLive.csproj | 2 +- .../Controllers/DebugController.cs | 94 +++++++++++++++++++ .../Controllers/InboxController.cs | 10 ++ src/BirdsiteLive/Views/Home/Index.cshtml | 9 +- .../ApDeserializerTests.cs | 16 ++++ 11 files changed, 200 insertions(+), 3 deletions(-) create mode 100644 src/BirdsiteLive.ActivityPub/Models/ActivityAccept.cs create mode 100644 src/BirdsiteLive.ActivityPub/Models/ActivityAcceptFollow.cs create mode 100644 src/BirdsiteLive/Controllers/DebugController.cs diff --git a/src/BirdsiteLive.ActivityPub/ApDeserializer.cs b/src/BirdsiteLive.ActivityPub/ApDeserializer.cs index ef978d9..1eaffa8 100644 --- a/src/BirdsiteLive.ActivityPub/ApDeserializer.cs +++ b/src/BirdsiteLive.ActivityPub/ApDeserializer.cs @@ -16,6 +16,31 @@ namespace BirdsiteLive.ActivityPub if(a.apObject.type == "Follow") return JsonConvert.DeserializeObject(json); break; + case "Accept": + var accept = JsonConvert.DeserializeObject(json); + //var acceptType = JsonConvert.DeserializeObject(accept.apObject); + switch ((accept.apObject as dynamic).type.ToString()) + { + case "Follow": + var acceptFollow = new ActivityAcceptFollow() + { + type = accept.type, + id = accept.id, + actor = accept.actor, + context = accept.context, + apObject = new ActivityFollow() + { + id = (accept.apObject as dynamic).id?.ToString(), + type = (accept.apObject as dynamic).type?.ToString(), + actor = (accept.apObject as dynamic).actor?.ToString(), + context = (accept.apObject as dynamic).context?.ToString(), + apObject = (accept.apObject as dynamic).@object?.ToString() + } + }; + return acceptFollow; + break; + } + break; } return null; diff --git a/src/BirdsiteLive.ActivityPub/BirdsiteLive.ActivityPub.csproj b/src/BirdsiteLive.ActivityPub/BirdsiteLive.ActivityPub.csproj index 01a891a..8dfebd7 100644 --- a/src/BirdsiteLive.ActivityPub/BirdsiteLive.ActivityPub.csproj +++ b/src/BirdsiteLive.ActivityPub/BirdsiteLive.ActivityPub.csproj @@ -5,6 +5,7 @@ + diff --git a/src/BirdsiteLive.ActivityPub/Models/Activity.cs b/src/BirdsiteLive.ActivityPub/Models/Activity.cs index 8a93505..0ad51f2 100644 --- a/src/BirdsiteLive.ActivityPub/Models/Activity.cs +++ b/src/BirdsiteLive.ActivityPub/Models/Activity.cs @@ -10,6 +10,7 @@ namespace BirdsiteLive.ActivityPub public string id { get; set; } public string type { get; set; } public string actor { get; set; } + //[JsonProperty("object")] //public string apObject { get; set; } } diff --git a/src/BirdsiteLive.ActivityPub/Models/ActivityAccept.cs b/src/BirdsiteLive.ActivityPub/Models/ActivityAccept.cs new file mode 100644 index 0000000..30b8746 --- /dev/null +++ b/src/BirdsiteLive.ActivityPub/Models/ActivityAccept.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace BirdsiteLive.ActivityPub +{ + public class ActivityAccept : Activity + { + [JsonProperty("object")] + public object apObject { get; set; } + } +} \ No newline at end of file diff --git a/src/BirdsiteLive.ActivityPub/Models/ActivityAcceptFollow.cs b/src/BirdsiteLive.ActivityPub/Models/ActivityAcceptFollow.cs new file mode 100644 index 0000000..f833a43 --- /dev/null +++ b/src/BirdsiteLive.ActivityPub/Models/ActivityAcceptFollow.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace BirdsiteLive.ActivityPub +{ + public class ActivityAcceptFollow : Activity + { + [JsonProperty("object")] + public ActivityFollow apObject { get; set; } + } +} \ No newline at end of file diff --git a/src/BirdsiteLive.Domain/CryptoService.cs b/src/BirdsiteLive.Domain/CryptoService.cs index 151344c..d259306 100644 --- a/src/BirdsiteLive.Domain/CryptoService.cs +++ b/src/BirdsiteLive.Domain/CryptoService.cs @@ -1,10 +1,13 @@ -using BirdsiteLive.Domain.Factories; +using System; +using System.Text; +using BirdsiteLive.Domain.Factories; namespace BirdsiteLive.Domain { public interface ICryptoService { string GetUserPem(string id); + string SignAndGetSignatureHeader(DateTime date, string actor, string host); } public class CryptoService : ICryptoService @@ -22,5 +25,25 @@ namespace BirdsiteLive.Domain { return _magicKeyFactory.GetMagicKey().AsPEM; } + + /// + /// + /// + /// + /// in the form of https://domain.io/actor + /// in the form of domain.io + /// + public string SignAndGetSignatureHeader(DateTime date, string actor, string targethost) + { + var httpDate = date.ToString("r"); + + var signedString = $"(request-target): post /inbox\nhost: {targethost}\ndate: {httpDate}"; + var signedStringBytes = Encoding.UTF8.GetBytes(signedString); + var signature = _magicKeyFactory.GetMagicKey().Sign(signedStringBytes); + var sig64 = Convert.ToBase64String(signature); + + var header = "keyId=\"" + actor + "\",headers=\"(request-target) host date\",signature=\"" + sig64 + "\""; + return header; + } } } \ No newline at end of file diff --git a/src/BirdsiteLive/BirdsiteLive.csproj b/src/BirdsiteLive/BirdsiteLive.csproj index d302ae7..332831e 100644 --- a/src/BirdsiteLive/BirdsiteLive.csproj +++ b/src/BirdsiteLive/BirdsiteLive.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/BirdsiteLive/Controllers/DebugController.cs b/src/BirdsiteLive/Controllers/DebugController.cs new file mode 100644 index 0000000..e8dadad --- /dev/null +++ b/src/BirdsiteLive/Controllers/DebugController.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using BirdsiteLive.ActivityPub; +using BirdsiteLive.Common.Settings; +using BirdsiteLive.Domain; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Newtonsoft.Json; + +namespace BirdsiteLive.Controllers +{ + public class DebugController : Controller + { + private readonly InstanceSettings _instanceSettings; + private readonly ICryptoService _cryptoService; + + #region Ctor + public DebugController(InstanceSettings instanceSettings, ICryptoService cryptoService) + { + _instanceSettings = instanceSettings; + _cryptoService = cryptoService; + } + #endregion + + public IActionResult Index() + { + return View(); + } + + [HttpPost] + public async Task Follow() + { + var actor = $"https://{_instanceSettings.Domain}/users/gra"; + var targethost = "mamot.fr"; + var followActivity = new ActivityFollow() + { + context = "https://www.w3.org/ns/activitystreams", + id = $"https://{_instanceSettings.Domain}/{Guid.NewGuid()}", + type = "Follow", + actor = actor, + apObject = $"https://{targethost}/users/testtest" + }; + + var json = JsonConvert.SerializeObject(followActivity); + + var date = DateTime.UtcNow.ToUniversalTime(); + var httpDate = date.ToString("r"); + var signature = _cryptoService.SignAndGetSignatureHeader(date, actor, targethost); + + var client = new HttpClient(); + var httpRequestMessage = new HttpRequestMessage + { + Method = HttpMethod.Post, + RequestUri = new Uri($"https://{targethost}/inbox"), + Headers = + { + {"Host", targethost}, + {"Date", httpDate}, + {"Signature", signature} + }, + Content = new StringContent(json, Encoding.UTF8, "application/ld+json") + }; + + try + { + var response = await client.SendAsync(httpRequestMessage); + var re = response.ReasonPhrase; + var t = await response.Content.ReadAsStringAsync(); + } + catch (Exception e) + { + throw; + } + + return View("Index"); + } + } + + public static class HtmlHelperExtensions + { + public static bool IsDebug() + { +#if DEBUG + return true; +#else + return false; +#endif + } + } +} \ No newline at end of file diff --git a/src/BirdsiteLive/Controllers/InboxController.cs b/src/BirdsiteLive/Controllers/InboxController.cs index 301bf6e..82de7b3 100644 --- a/src/BirdsiteLive/Controllers/InboxController.cs +++ b/src/BirdsiteLive/Controllers/InboxController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; @@ -14,6 +15,15 @@ namespace BirdsiteLive.Controllers [HttpPost] public async Task Inbox() { + var r = Request; + using (var reader = new StreamReader(Request.Body)) + { + var body = await reader.ReadToEndAsync(); + + + } + + throw new NotImplementedException(); } } diff --git a/src/BirdsiteLive/Views/Home/Index.cshtml b/src/BirdsiteLive/Views/Home/Index.cshtml index d2d19bd..6ae1367 100644 --- a/src/BirdsiteLive/Views/Home/Index.cshtml +++ b/src/BirdsiteLive/Views/Home/Index.cshtml @@ -1,8 +1,15 @@ -@{ +@using BirdsiteLive.Controllers; +@{ ViewData["Title"] = "Home Page"; }

Welcome

Learn about building Web apps with ASP.NET Core.

+ + + @if (HtmlHelperExtensions.IsDebug()) + { + Debug + }
diff --git a/src/Tests/BirdsiteLive.ActivityPub.Tests/ApDeserializerTests.cs b/src/Tests/BirdsiteLive.ActivityPub.Tests/ApDeserializerTests.cs index ab4441c..236e2dc 100644 --- a/src/Tests/BirdsiteLive.ActivityPub.Tests/ApDeserializerTests.cs +++ b/src/Tests/BirdsiteLive.ActivityPub.Tests/ApDeserializerTests.cs @@ -31,5 +31,21 @@ namespace BirdsiteLive.ActivityPub.Tests Assert.AreEqual("https://mastodon.technology/users/testtest", data.apObject.actor); Assert.AreEqual("https://4a120ca2680e.ngrok.io/users/manu", data.apObject.apObject); } + + [TestMethod] + public void AcceptDeserializationTest() + { + var json = "{\"@context\":\"https://www.w3.org/ns/activitystreams\",\"id\":\"https://mamot.fr/users/testtest#accepts/follows/333879\",\"type\":\"Accept\",\"actor\":\"https://mamot.fr/users/testtest\",\"object\":{\"id\":\"https://85da1577f778.ngrok.io/f89dfd87-f5ce-4603-83d9-405c0e229989\",\"type\":\"Follow\",\"actor\":\"https://85da1577f778.ngrok.io/users/gra\",\"object\":\"https://mamot.fr/users/testtest\"}}"; + + + var data = ApDeserializer.ProcessActivity(json) as ActivityAcceptFollow; + Assert.AreEqual("https://mamot.fr/users/testtest#accepts/follows/333879", data.id); + Assert.AreEqual("Accept", data.type); + Assert.AreEqual("https://mamot.fr/users/testtest", data.actor); + Assert.AreEqual("https://85da1577f778.ngrok.io/f89dfd87-f5ce-4603-83d9-405c0e229989", data.apObject.id); + Assert.AreEqual("https://85da1577f778.ngrok.io/users/gra", data.apObject.actor); + Assert.AreEqual("Follow", data.apObject.type); + Assert.AreEqual("https://mamot.fr/users/testtest", data.apObject.apObject); + } } } \ No newline at end of file From 3b08f75204efd2651dbc6f179c28c6680c78202d Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Sun, 28 Jun 2020 21:56:10 -0400 Subject: [PATCH 2/4] following working --- src/BirdsiteLive.Domain/ActivityPubService.cs | 42 ++++++++++++++++++- src/BirdsiteLive.Domain/UserService.cs | 24 +++++++++-- .../Controllers/UsersController.cs | 2 +- 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/src/BirdsiteLive.Domain/ActivityPubService.cs b/src/BirdsiteLive.Domain/ActivityPubService.cs index e80877c..93db1a4 100644 --- a/src/BirdsiteLive.Domain/ActivityPubService.cs +++ b/src/BirdsiteLive.Domain/ActivityPubService.cs @@ -1,17 +1,31 @@ -using System.Net.Http; +using System; +using System.Net; +using System.Net.Http; +using System.Text; using System.Threading.Tasks; using BirdsiteLive.ActivityPub; using Newtonsoft.Json; +using Org.BouncyCastle.Bcpg; namespace BirdsiteLive.Domain { public interface IActivityPubService { Task GetUser(string objectId); + Task PostDataAsync(T data, string targetHost, string actorUrl); } public class ActivityPubService : IActivityPubService { + private readonly ICryptoService _cryptoService; + + #region Ctor + public ActivityPubService(ICryptoService cryptoService) + { + _cryptoService = cryptoService; + } + #endregion + public async Task GetUser(string objectId) { using (var httpClient = new HttpClient()) @@ -22,5 +36,31 @@ namespace BirdsiteLive.Domain return JsonConvert.DeserializeObject(content); } } + + public async Task PostDataAsync(T data, string targetHost, string actorUrl) + { + var json = JsonConvert.SerializeObject(data); + + var date = DateTime.UtcNow.ToUniversalTime(); + var httpDate = date.ToString("r"); + var signature = _cryptoService.SignAndGetSignatureHeader(date, actorUrl, targetHost); + + var client = new HttpClient(); + var httpRequestMessage = new HttpRequestMessage + { + Method = HttpMethod.Post, + RequestUri = new Uri($"https://{targetHost}/inbox"), + Headers = + { + {"Host", targetHost}, + {"Date", httpDate}, + {"Signature", signature} + }, + Content = new StringContent(json, Encoding.UTF8, "application/ld+json") + }; + + var response = await client.SendAsync(httpRequestMessage); + return response.StatusCode; + } } } \ No newline at end of file diff --git a/src/BirdsiteLive.Domain/UserService.cs b/src/BirdsiteLive.Domain/UserService.cs index 174fbab..5c569f5 100644 --- a/src/BirdsiteLive.Domain/UserService.cs +++ b/src/BirdsiteLive.Domain/UserService.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Net; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; @@ -69,11 +71,25 @@ namespace BirdsiteLive.Domain if (!await ValidateSignature(activity.actor, signature, method, path, queryString, requestHeaders)) return false; // Save Follow in DB - - // Send Accept Activity - - throw new NotImplementedException(); + // Send Accept Activity + var targetHost = activity.actor.Replace("https://", string.Empty).Split('/').First(); + var acceptFollow = new ActivityAcceptFollow() + { + context = "https://www.w3.org/ns/activitystreams", + id = $"{activity.apObject}#accepts/follows/{Guid.NewGuid()}", + type = "Accept", + actor = activity.apObject, + apObject = new ActivityFollow() + { + id = activity.id, + type = activity.type, + actor = activity.actor, + apObject = activity.apObject + } + }; + var result = await _activityPubService.PostDataAsync(acceptFollow, targetHost, activity.apObject); + return result == HttpStatusCode.Accepted; } private async Task ValidateSignature(string actor, string rawSig, string method, string path, string queryString, Dictionary requestHeaders) diff --git a/src/BirdsiteLive/Controllers/UsersController.cs b/src/BirdsiteLive/Controllers/UsersController.cs index 91c8d69..02f4937 100644 --- a/src/BirdsiteLive/Controllers/UsersController.cs +++ b/src/BirdsiteLive/Controllers/UsersController.cs @@ -60,7 +60,7 @@ namespace BirdsiteLive.Controllers { 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(); + if (succeeded) return Accepted(); else return Unauthorized(); break; default: From 32c5343722759fc58dd93a8ad7ba795efbeb5985 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Sun, 28 Jun 2020 23:42:23 -0400 Subject: [PATCH 3/4] creating notes functionnal --- .../Models/ActivityCreate.cs | 7 ++ .../Models/ActivityCreateNote.cs | 15 ++++ src/BirdsiteLive.ActivityPub/Models/Note.cs | 25 ++++++ src/BirdsiteLive.Domain/ActivityPubService.cs | 14 +++- src/BirdsiteLive.Domain/CryptoService.cs | 10 ++- .../Controllers/DebugController.cs | 77 ++++++++++++------- .../Controllers/UsersController.cs | 4 +- .../ApDeserializerTests.cs | 9 +++ 8 files changed, 126 insertions(+), 35 deletions(-) create mode 100644 src/BirdsiteLive.ActivityPub/Models/ActivityCreate.cs create mode 100644 src/BirdsiteLive.ActivityPub/Models/ActivityCreateNote.cs create mode 100644 src/BirdsiteLive.ActivityPub/Models/Note.cs diff --git a/src/BirdsiteLive.ActivityPub/Models/ActivityCreate.cs b/src/BirdsiteLive.ActivityPub/Models/ActivityCreate.cs new file mode 100644 index 0000000..8532682 --- /dev/null +++ b/src/BirdsiteLive.ActivityPub/Models/ActivityCreate.cs @@ -0,0 +1,7 @@ +namespace BirdsiteLive.ActivityPub +{ + public class ActivityCreate + { + + } +} \ No newline at end of file diff --git a/src/BirdsiteLive.ActivityPub/Models/ActivityCreateNote.cs b/src/BirdsiteLive.ActivityPub/Models/ActivityCreateNote.cs new file mode 100644 index 0000000..d100b3a --- /dev/null +++ b/src/BirdsiteLive.ActivityPub/Models/ActivityCreateNote.cs @@ -0,0 +1,15 @@ +using System; +using Newtonsoft.Json; + +namespace BirdsiteLive.ActivityPub +{ + public class ActivityCreateNote : Activity + { + public string published { get; set; } + public string[] to { get; set; } + public string[] cc { get; set; } + + [JsonProperty("object")] + public Note apObject { get; set; } + } +} \ No newline at end of file diff --git a/src/BirdsiteLive.ActivityPub/Models/Note.cs b/src/BirdsiteLive.ActivityPub/Models/Note.cs new file mode 100644 index 0000000..0dc9c16 --- /dev/null +++ b/src/BirdsiteLive.ActivityPub/Models/Note.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; + +namespace BirdsiteLive.ActivityPub +{ + public class Note + { + public string id { get; set; } + public string type { get; } = "Note"; + public string summary { get; set; } + public string inReplyTo { get; set; } + public string published { get; set; } + public string url { get; set; } + public string attributedTo { get; set; } + public string[] to { get; set; } + public string[] cc { get; set; } + public bool sensitive { get; set; } + //public string conversation { get; set; } + public string content { get; set; } + //public Dictionary contentMap { get; set; } + public string[] attachment { get; set; } + public string[] tag { get; set; } + //public Dictionary replies; + } +} \ No newline at end of file diff --git a/src/BirdsiteLive.Domain/ActivityPubService.cs b/src/BirdsiteLive.Domain/ActivityPubService.cs index 93db1a4..d30daf8 100644 --- a/src/BirdsiteLive.Domain/ActivityPubService.cs +++ b/src/BirdsiteLive.Domain/ActivityPubService.cs @@ -12,7 +12,7 @@ namespace BirdsiteLive.Domain public interface IActivityPubService { Task GetUser(string objectId); - Task PostDataAsync(T data, string targetHost, string actorUrl); + Task PostDataAsync(T data, string targetHost, string actorUrl, string inbox = null); } public class ActivityPubService : IActivityPubService @@ -37,19 +37,25 @@ namespace BirdsiteLive.Domain } } - public async Task PostDataAsync(T data, string targetHost, string actorUrl) + public async Task PostDataAsync(T data, string targetHost, string actorUrl, string inbox = null) { + var usedInbox = $"/inbox"; + if (!string.IsNullOrWhiteSpace(inbox)) + usedInbox = inbox; + var json = JsonConvert.SerializeObject(data); var date = DateTime.UtcNow.ToUniversalTime(); var httpDate = date.ToString("r"); - var signature = _cryptoService.SignAndGetSignatureHeader(date, actorUrl, targetHost); + var signature = _cryptoService.SignAndGetSignatureHeader(date, actorUrl, targetHost, usedInbox); + + var client = new HttpClient(); var httpRequestMessage = new HttpRequestMessage { Method = HttpMethod.Post, - RequestUri = new Uri($"https://{targetHost}/inbox"), + RequestUri = new Uri($"https://{targetHost}/{usedInbox}"), Headers = { {"Host", targetHost}, diff --git a/src/BirdsiteLive.Domain/CryptoService.cs b/src/BirdsiteLive.Domain/CryptoService.cs index d259306..ed62a59 100644 --- a/src/BirdsiteLive.Domain/CryptoService.cs +++ b/src/BirdsiteLive.Domain/CryptoService.cs @@ -7,7 +7,7 @@ namespace BirdsiteLive.Domain public interface ICryptoService { string GetUserPem(string id); - string SignAndGetSignatureHeader(DateTime date, string actor, string host); + string SignAndGetSignatureHeader(DateTime date, string actor, string host, string inbox = null); } public class CryptoService : ICryptoService @@ -33,11 +33,15 @@ namespace BirdsiteLive.Domain /// in the form of https://domain.io/actor /// in the form of domain.io /// - public string SignAndGetSignatureHeader(DateTime date, string actor, string targethost) + public string SignAndGetSignatureHeader(DateTime date, string actor, string targethost, string inbox = null) { + var usedInbox = "/inbox"; + if (!string.IsNullOrWhiteSpace(inbox)) + usedInbox = inbox; + var httpDate = date.ToString("r"); - var signedString = $"(request-target): post /inbox\nhost: {targethost}\ndate: {httpDate}"; + var signedString = $"(request-target): post {usedInbox}\nhost: {targethost}\ndate: {httpDate}"; var signedStringBytes = Encoding.UTF8.GetBytes(signedString); var signature = _magicKeyFactory.GetMagicKey().Sign(signedStringBytes); var sig64 = Convert.ToBase64String(signature); diff --git a/src/BirdsiteLive/Controllers/DebugController.cs b/src/BirdsiteLive/Controllers/DebugController.cs index e8dadad..f187d32 100644 --- a/src/BirdsiteLive/Controllers/DebugController.cs +++ b/src/BirdsiteLive/Controllers/DebugController.cs @@ -17,12 +17,14 @@ namespace BirdsiteLive.Controllers { private readonly InstanceSettings _instanceSettings; private readonly ICryptoService _cryptoService; + private readonly IActivityPubService _activityPubService; #region Ctor - public DebugController(InstanceSettings instanceSettings, ICryptoService cryptoService) + public DebugController(InstanceSettings instanceSettings, ICryptoService cryptoService, IActivityPubService activityPubService) { _instanceSettings = instanceSettings; _cryptoService = cryptoService; + _activityPubService = activityPubService; } #endregion @@ -35,7 +37,7 @@ namespace BirdsiteLive.Controllers public async Task Follow() { var actor = $"https://{_instanceSettings.Domain}/users/gra"; - var targethost = "mamot.fr"; + var targethost = "mastodon.technology"; var followActivity = new ActivityFollow() { context = "https://www.w3.org/ns/activitystreams", @@ -45,36 +47,57 @@ namespace BirdsiteLive.Controllers apObject = $"https://{targethost}/users/testtest" }; - var json = JsonConvert.SerializeObject(followActivity); - - var date = DateTime.UtcNow.ToUniversalTime(); - var httpDate = date.ToString("r"); - var signature = _cryptoService.SignAndGetSignatureHeader(date, actor, targethost); + await _activityPubService.PostDataAsync(followActivity, targethost, actor); - var client = new HttpClient(); - var httpRequestMessage = new HttpRequestMessage + return View("Index"); + } + + [HttpPost] + public async Task PostNote() + { + var username = "gra"; + var actor = $"https://{_instanceSettings.Domain}/users/{username}"; + var targetHost = "mastodon.technology"; + var target = $"{targetHost}/users/testtest"; + var inbox = $"/users/testtest/inbox"; + + var noteGuid = Guid.NewGuid(); + var noteId = $"https://{_instanceSettings.Domain}/users/{username}/statuses/{noteGuid}"; + var noteUrl = $"https://{_instanceSettings.Domain}/@{username}/{noteGuid}"; + + var to = $"{actor}/followers"; + var apPublic = "https://www.w3.org/ns/activitystreams#Public"; + + var now = DateTime.UtcNow; + var nowString = now.ToString("s") + "Z"; + + var noteActivity = new ActivityCreateNote() { - Method = HttpMethod.Post, - RequestUri = new Uri($"https://{targethost}/inbox"), - Headers = + context = "https://www.w3.org/ns/activitystreams", + id = $"{noteId}/activity", + type = "Create", + actor = actor, + published = nowString, + to = new []{ to }, + //cc = new [] { apPublic }, + apObject = new Note() { - {"Host", targethost}, - {"Date", httpDate}, - {"Signature", signature} - }, - Content = new StringContent(json, Encoding.UTF8, "application/ld+json") + id = noteId, + summary = null, + inReplyTo = null, + published = nowString, + url = noteUrl, + attributedTo = actor, + to = new[] { to }, + //cc = new [] { apPublic }, + sensitive = false, + content = "

Woooot

", + attachment = new string[0], + tag = new string[0] + } }; - try - { - var response = await client.SendAsync(httpRequestMessage); - var re = response.ReasonPhrase; - var t = await response.Content.ReadAsStringAsync(); - } - catch (Exception e) - { - throw; - } + await _activityPubService.PostDataAsync(noteActivity, targetHost, actor, inbox); return View("Index"); } diff --git a/src/BirdsiteLive/Controllers/UsersController.cs b/src/BirdsiteLive/Controllers/UsersController.cs index 02f4937..05a6aac 100644 --- a/src/BirdsiteLive/Controllers/UsersController.cs +++ b/src/BirdsiteLive/Controllers/UsersController.cs @@ -63,8 +63,10 @@ namespace BirdsiteLive.Controllers if (succeeded) return Accepted(); else return Unauthorized(); break; + case "Undo": + return Accepted(); default: - return Ok(); + return Accepted(); } } diff --git a/src/Tests/BirdsiteLive.ActivityPub.Tests/ApDeserializerTests.cs b/src/Tests/BirdsiteLive.ActivityPub.Tests/ApDeserializerTests.cs index 236e2dc..ff6cd47 100644 --- a/src/Tests/BirdsiteLive.ActivityPub.Tests/ApDeserializerTests.cs +++ b/src/Tests/BirdsiteLive.ActivityPub.Tests/ApDeserializerTests.cs @@ -47,5 +47,14 @@ namespace BirdsiteLive.ActivityPub.Tests Assert.AreEqual("Follow", data.apObject.type); Assert.AreEqual("https://mamot.fr/users/testtest", data.apObject.apObject); } + + [TestMethod] + public void NoteDeserializationTest() + { + var json = + "{\"@context\":[\"https://www.w3.org/ns/activitystreams\",{\"ostatus\":\"http://ostatus.org#\",\"atomUri\":\"ostatus:atomUri\",\"inReplyToAtomUri\":\"ostatus:inReplyToAtomUri\",\"conversation\":\"ostatus:conversation\",\"sensitive\":\"as:sensitive\",\"toot\":\"http://joinmastodon.org/ns#\",\"votersCount\":\"toot:votersCount\"}],\"id\":\"https://mastodon.technology/users/testtest/statuses/104424839893177182/activity\",\"type\":\"Create\",\"actor\":\"https://mastodon.technology/users/testtest\",\"published\":\"2020-06-29T02:10:04Z\",\"to\":[\"https://mastodon.technology/users/testtest/followers\"],\"cc\":[],\"object\":{\"id\":\"https://mastodon.technology/users/testtest/statuses/104424839893177182\",\"type\":\"Note\",\"summary\":null,\"inReplyTo\":null,\"published\":\"2020-06-29T02:10:04Z\",\"url\":\"https://mastodon.technology/@testtest/104424839893177182\",\"attributedTo\":\"https://mastodon.technology/users/testtest\",\"to\":[\"https://mastodon.technology/users/testtest/followers\"],\"cc\":[],\"sensitive\":false,\"atomUri\":\"https://mastodon.technology/users/testtest/statuses/104424839893177182\",\"inReplyToAtomUri\":null,\"conversation\":\"tag:mastodon.technology,2020-06-29:objectId=34900058:objectType=Conversation\",\"content\":\"

test

\",\"contentMap\":{\"en\":\"

test

\"},\"attachment\":[],\"tag\":[],\"replies\":{\"id\":\"https://mastodon.technology/users/testtest/statuses/104424839893177182/replies\",\"type\":\"Collection\",\"first\":{\"type\":\"CollectionPage\",\"next\":\"https://mastodon.technology/users/testtest/statuses/104424839893177182/replies?only_other_accounts=true&page=true\",\"partOf\":\"https://mastodon.technology/users/testtest/statuses/104424839893177182/replies\",\"items\":[]}}}}"; + + var data = ApDeserializer.ProcessActivity(json) as ActivityAcceptFollow; + } } } \ No newline at end of file From 593c6c7be998d0b0de000be1443d64220e8b2836 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Sun, 28 Jun 2020 23:55:31 -0400 Subject: [PATCH 4/4] disabling tests --- .../ApDeserializerTests.cs | 14 ++--- .../RsaKeysTests.cs | 54 +++++++++---------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/Tests/BirdsiteLive.ActivityPub.Tests/ApDeserializerTests.cs b/src/Tests/BirdsiteLive.ActivityPub.Tests/ApDeserializerTests.cs index ff6cd47..3c85113 100644 --- a/src/Tests/BirdsiteLive.ActivityPub.Tests/ApDeserializerTests.cs +++ b/src/Tests/BirdsiteLive.ActivityPub.Tests/ApDeserializerTests.cs @@ -48,13 +48,13 @@ namespace BirdsiteLive.ActivityPub.Tests Assert.AreEqual("https://mamot.fr/users/testtest", data.apObject.apObject); } - [TestMethod] - public void NoteDeserializationTest() - { - var json = - "{\"@context\":[\"https://www.w3.org/ns/activitystreams\",{\"ostatus\":\"http://ostatus.org#\",\"atomUri\":\"ostatus:atomUri\",\"inReplyToAtomUri\":\"ostatus:inReplyToAtomUri\",\"conversation\":\"ostatus:conversation\",\"sensitive\":\"as:sensitive\",\"toot\":\"http://joinmastodon.org/ns#\",\"votersCount\":\"toot:votersCount\"}],\"id\":\"https://mastodon.technology/users/testtest/statuses/104424839893177182/activity\",\"type\":\"Create\",\"actor\":\"https://mastodon.technology/users/testtest\",\"published\":\"2020-06-29T02:10:04Z\",\"to\":[\"https://mastodon.technology/users/testtest/followers\"],\"cc\":[],\"object\":{\"id\":\"https://mastodon.technology/users/testtest/statuses/104424839893177182\",\"type\":\"Note\",\"summary\":null,\"inReplyTo\":null,\"published\":\"2020-06-29T02:10:04Z\",\"url\":\"https://mastodon.technology/@testtest/104424839893177182\",\"attributedTo\":\"https://mastodon.technology/users/testtest\",\"to\":[\"https://mastodon.technology/users/testtest/followers\"],\"cc\":[],\"sensitive\":false,\"atomUri\":\"https://mastodon.technology/users/testtest/statuses/104424839893177182\",\"inReplyToAtomUri\":null,\"conversation\":\"tag:mastodon.technology,2020-06-29:objectId=34900058:objectType=Conversation\",\"content\":\"

test

\",\"contentMap\":{\"en\":\"

test

\"},\"attachment\":[],\"tag\":[],\"replies\":{\"id\":\"https://mastodon.technology/users/testtest/statuses/104424839893177182/replies\",\"type\":\"Collection\",\"first\":{\"type\":\"CollectionPage\",\"next\":\"https://mastodon.technology/users/testtest/statuses/104424839893177182/replies?only_other_accounts=true&page=true\",\"partOf\":\"https://mastodon.technology/users/testtest/statuses/104424839893177182/replies\",\"items\":[]}}}}"; + //[TestMethod] + //public void NoteDeserializationTest() + //{ + // var json = + // "{\"@context\":[\"https://www.w3.org/ns/activitystreams\",{\"ostatus\":\"http://ostatus.org#\",\"atomUri\":\"ostatus:atomUri\",\"inReplyToAtomUri\":\"ostatus:inReplyToAtomUri\",\"conversation\":\"ostatus:conversation\",\"sensitive\":\"as:sensitive\",\"toot\":\"http://joinmastodon.org/ns#\",\"votersCount\":\"toot:votersCount\"}],\"id\":\"https://mastodon.technology/users/testtest/statuses/104424839893177182/activity\",\"type\":\"Create\",\"actor\":\"https://mastodon.technology/users/testtest\",\"published\":\"2020-06-29T02:10:04Z\",\"to\":[\"https://mastodon.technology/users/testtest/followers\"],\"cc\":[],\"object\":{\"id\":\"https://mastodon.technology/users/testtest/statuses/104424839893177182\",\"type\":\"Note\",\"summary\":null,\"inReplyTo\":null,\"published\":\"2020-06-29T02:10:04Z\",\"url\":\"https://mastodon.technology/@testtest/104424839893177182\",\"attributedTo\":\"https://mastodon.technology/users/testtest\",\"to\":[\"https://mastodon.technology/users/testtest/followers\"],\"cc\":[],\"sensitive\":false,\"atomUri\":\"https://mastodon.technology/users/testtest/statuses/104424839893177182\",\"inReplyToAtomUri\":null,\"conversation\":\"tag:mastodon.technology,2020-06-29:objectId=34900058:objectType=Conversation\",\"content\":\"

test

\",\"contentMap\":{\"en\":\"

test

\"},\"attachment\":[],\"tag\":[],\"replies\":{\"id\":\"https://mastodon.technology/users/testtest/statuses/104424839893177182/replies\",\"type\":\"Collection\",\"first\":{\"type\":\"CollectionPage\",\"next\":\"https://mastodon.technology/users/testtest/statuses/104424839893177182/replies?only_other_accounts=true&page=true\",\"partOf\":\"https://mastodon.technology/users/testtest/statuses/104424839893177182/replies\",\"items\":[]}}}}"; - var data = ApDeserializer.ProcessActivity(json) as ActivityAcceptFollow; - } + // var data = ApDeserializer.ProcessActivity(json) as ActivityAcceptFollow; + //} } } \ No newline at end of file diff --git a/src/Tests/BirdsiteLive.Cryptography.Tests/RsaKeysTests.cs b/src/Tests/BirdsiteLive.Cryptography.Tests/RsaKeysTests.cs index 50c77b9..2e4ae5e 100644 --- a/src/Tests/BirdsiteLive.Cryptography.Tests/RsaKeysTests.cs +++ b/src/Tests/BirdsiteLive.Cryptography.Tests/RsaKeysTests.cs @@ -1,34 +1,34 @@ -using System.Security.Cryptography; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using MyProject.Data.Encryption; +//using System.Security.Cryptography; +//using Microsoft.VisualStudio.TestTools.UnitTesting; +//using MyProject.Data.Encryption; -namespace BirdsiteLive.Cryptography.Tests -{ - [TestClass] - public class RsaKeysTests - { - [TestMethod] - public void TestMethod1() - { - var rsa = RSA.Create(); +//namespace BirdsiteLive.Cryptography.Tests +//{ +// [TestClass] +// public class RsaKeysTests +// { +// [TestMethod] +// public void TestMethod1() +// { +// var rsa = RSA.Create(); - var cspParams = new CspParameters(); - cspParams.ProviderType = 1; // PROV_RSA_FULL - cspParams.Flags = CspProviderFlags.CreateEphemeralKey; - var rsaProvider = new RSACryptoServiceProvider(2048, cspParams); +// var cspParams = new CspParameters(); +// cspParams.ProviderType = 1; // PROV_RSA_FULL +// cspParams.Flags = CspProviderFlags.CreateEphemeralKey; +// var rsaProvider = new RSACryptoServiceProvider(2048, cspParams); - var rsaPublicKey = RSAKeys.ExportPublicKey(rsaProvider); - var rsaPrivateKey = RSAKeys.ExportPrivateKey(rsaProvider); +// var rsaPublicKey = RSAKeys.ExportPublicKey(rsaProvider); +// var rsaPrivateKey = RSAKeys.ExportPrivateKey(rsaProvider); - //rsaProvider. +// //rsaProvider. - var pem = RSAKeys.ImportPublicKey(rsaPrivateKey); - } +// var pem = RSAKeys.ImportPublicKey(rsaPrivateKey); +// } - [TestMethod] - public void TestMethod2() - { +// [TestMethod] +// public void TestMethod2() +// { - } - } -} \ No newline at end of file +// } +// } +//} \ No newline at end of file