creating notes functionnal

This commit is contained in:
Nicolas Constant 2020-06-28 23:42:23 -04:00
parent 3b08f75204
commit 32c5343722
No known key found for this signature in database
GPG key ID: 1E9F677FB01A5688
8 changed files with 126 additions and 35 deletions

View file

@ -0,0 +1,7 @@
namespace BirdsiteLive.ActivityPub
{
public class ActivityCreate
{
}
}

View file

@ -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; }
}
}

View file

@ -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<string,string> contentMap { get; set; }
public string[] attachment { get; set; }
public string[] tag { get; set; }
//public Dictionary<string, string> replies;
}
}

View file

@ -12,7 +12,7 @@ namespace BirdsiteLive.Domain
public interface IActivityPubService public interface IActivityPubService
{ {
Task<Actor> GetUser(string objectId); Task<Actor> GetUser(string objectId);
Task<HttpStatusCode> PostDataAsync<T>(T data, string targetHost, string actorUrl); Task<HttpStatusCode> PostDataAsync<T>(T data, string targetHost, string actorUrl, string inbox = null);
} }
public class ActivityPubService : IActivityPubService public class ActivityPubService : IActivityPubService
@ -37,19 +37,25 @@ namespace BirdsiteLive.Domain
} }
} }
public async Task<HttpStatusCode> PostDataAsync<T>(T data, string targetHost, string actorUrl) public async Task<HttpStatusCode> PostDataAsync<T>(T data, string targetHost, string actorUrl, string inbox = null)
{ {
var usedInbox = $"/inbox";
if (!string.IsNullOrWhiteSpace(inbox))
usedInbox = inbox;
var json = JsonConvert.SerializeObject(data); var json = JsonConvert.SerializeObject(data);
var date = DateTime.UtcNow.ToUniversalTime(); var date = DateTime.UtcNow.ToUniversalTime();
var httpDate = date.ToString("r"); 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 client = new HttpClient();
var httpRequestMessage = new HttpRequestMessage var httpRequestMessage = new HttpRequestMessage
{ {
Method = HttpMethod.Post, Method = HttpMethod.Post,
RequestUri = new Uri($"https://{targetHost}/inbox"), RequestUri = new Uri($"https://{targetHost}/{usedInbox}"),
Headers = Headers =
{ {
{"Host", targetHost}, {"Host", targetHost},

View file

@ -7,7 +7,7 @@ namespace BirdsiteLive.Domain
public interface ICryptoService public interface ICryptoService
{ {
string GetUserPem(string id); 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 public class CryptoService : ICryptoService
@ -33,11 +33,15 @@ namespace BirdsiteLive.Domain
/// <param name="actor">in the form of https://domain.io/actor</param> /// <param name="actor">in the form of https://domain.io/actor</param>
/// <param name="host">in the form of domain.io</param> /// <param name="host">in the form of domain.io</param>
/// <returns></returns> /// <returns></returns>
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 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 signedStringBytes = Encoding.UTF8.GetBytes(signedString);
var signature = _magicKeyFactory.GetMagicKey().Sign(signedStringBytes); var signature = _magicKeyFactory.GetMagicKey().Sign(signedStringBytes);
var sig64 = Convert.ToBase64String(signature); var sig64 = Convert.ToBase64String(signature);

View file

@ -17,12 +17,14 @@ namespace BirdsiteLive.Controllers
{ {
private readonly InstanceSettings _instanceSettings; private readonly InstanceSettings _instanceSettings;
private readonly ICryptoService _cryptoService; private readonly ICryptoService _cryptoService;
private readonly IActivityPubService _activityPubService;
#region Ctor #region Ctor
public DebugController(InstanceSettings instanceSettings, ICryptoService cryptoService) public DebugController(InstanceSettings instanceSettings, ICryptoService cryptoService, IActivityPubService activityPubService)
{ {
_instanceSettings = instanceSettings; _instanceSettings = instanceSettings;
_cryptoService = cryptoService; _cryptoService = cryptoService;
_activityPubService = activityPubService;
} }
#endregion #endregion
@ -35,7 +37,7 @@ namespace BirdsiteLive.Controllers
public async Task<IActionResult> Follow() public async Task<IActionResult> Follow()
{ {
var actor = $"https://{_instanceSettings.Domain}/users/gra"; var actor = $"https://{_instanceSettings.Domain}/users/gra";
var targethost = "mamot.fr"; var targethost = "mastodon.technology";
var followActivity = new ActivityFollow() var followActivity = new ActivityFollow()
{ {
context = "https://www.w3.org/ns/activitystreams", context = "https://www.w3.org/ns/activitystreams",
@ -45,36 +47,57 @@ namespace BirdsiteLive.Controllers
apObject = $"https://{targethost}/users/testtest" apObject = $"https://{targethost}/users/testtest"
}; };
var json = JsonConvert.SerializeObject(followActivity); await _activityPubService.PostDataAsync(followActivity, targethost, actor);
var date = DateTime.UtcNow.ToUniversalTime();
var httpDate = date.ToString("r");
var signature = _cryptoService.SignAndGetSignatureHeader(date, actor, targethost);
var client = new HttpClient(); return View("Index");
var httpRequestMessage = new HttpRequestMessage }
[HttpPost]
public async Task<IActionResult> 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, context = "https://www.w3.org/ns/activitystreams",
RequestUri = new Uri($"https://{targethost}/inbox"), id = $"{noteId}/activity",
Headers = type = "Create",
actor = actor,
published = nowString,
to = new []{ to },
//cc = new [] { apPublic },
apObject = new Note()
{ {
{"Host", targethost}, id = noteId,
{"Date", httpDate}, summary = null,
{"Signature", signature} inReplyTo = null,
}, published = nowString,
Content = new StringContent(json, Encoding.UTF8, "application/ld+json") url = noteUrl,
attributedTo = actor,
to = new[] { to },
//cc = new [] { apPublic },
sensitive = false,
content = "<p>Woooot</p>",
attachment = new string[0],
tag = new string[0]
}
}; };
try await _activityPubService.PostDataAsync(noteActivity, targetHost, actor, inbox);
{
var response = await client.SendAsync(httpRequestMessage);
var re = response.ReasonPhrase;
var t = await response.Content.ReadAsStringAsync();
}
catch (Exception e)
{
throw;
}
return View("Index"); return View("Index");
} }

View file

@ -63,8 +63,10 @@ namespace BirdsiteLive.Controllers
if (succeeded) return Accepted(); if (succeeded) return Accepted();
else return Unauthorized(); else return Unauthorized();
break; break;
case "Undo":
return Accepted();
default: default:
return Ok(); return Accepted();
} }
} }

View file

@ -47,5 +47,14 @@ namespace BirdsiteLive.ActivityPub.Tests
Assert.AreEqual("Follow", data.apObject.type); Assert.AreEqual("Follow", data.apObject.type);
Assert.AreEqual("https://mamot.fr/users/testtest", data.apObject.apObject); 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\":\"<p>test</p>\",\"contentMap\":{\"en\":\"<p>test</p>\"},\"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;
}
} }
} }