From 32c5343722759fc58dd93a8ad7ba795efbeb5985 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Sun, 28 Jun 2020 23:42:23 -0400 Subject: [PATCH] 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