diff --git a/src/BirdsiteLive.Domain/ActivityPubService.cs b/src/BirdsiteLive.Domain/ActivityPubService.cs index 21ee7fd..bbabf07 100644 --- a/src/BirdsiteLive.Domain/ActivityPubService.cs +++ b/src/BirdsiteLive.Domain/ActivityPubService.cs @@ -90,7 +90,7 @@ namespace BirdsiteLive.Domain var date = DateTime.UtcNow.ToUniversalTime(); var httpDate = date.ToString("r"); - var digest = ComputeSha256Hash(json); + var digest = _cryptoService.ComputeSha256Hash(json); var signature = _cryptoService.SignAndGetSignatureHeader(date, actorUrl, targetHost, digest, usedInbox); @@ -113,15 +113,6 @@ namespace BirdsiteLive.Domain return response.StatusCode; } - static string ComputeSha256Hash(string rawData) - { - // Create a SHA256 - using (SHA256 sha256Hash = SHA256.Create()) - { - // ComputeHash - returns byte array - byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData)); - return Convert.ToBase64String(bytes); - } - } + } } \ No newline at end of file diff --git a/src/BirdsiteLive.Domain/CryptoService.cs b/src/BirdsiteLive.Domain/CryptoService.cs index 837922e..01e7d63 100644 --- a/src/BirdsiteLive.Domain/CryptoService.cs +++ b/src/BirdsiteLive.Domain/CryptoService.cs @@ -1,4 +1,5 @@ using System; +using System.Security.Cryptography; using System.Text; using BirdsiteLive.Domain.Factories; @@ -8,6 +9,7 @@ namespace BirdsiteLive.Domain { string GetUserPem(string id); string SignAndGetSignatureHeader(DateTime date, string actor, string host, string digest, string inbox); + string ComputeSha256Hash(string data); } public class CryptoService : ICryptoService @@ -49,5 +51,16 @@ namespace BirdsiteLive.Domain var header = "keyId=\"" + actor + "\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest\",signature=\"" + sig64 + "\""; return header; } + + public string ComputeSha256Hash(string data) + { + // Create a SHA256 + using (SHA256 sha256Hash = SHA256.Create()) + { + // ComputeHash - returns byte array + byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(data)); + return Convert.ToBase64String(bytes); + } + } } } \ No newline at end of file diff --git a/src/BirdsiteLive.Domain/UserService.cs b/src/BirdsiteLive.Domain/UserService.cs index 1e6e8dc..221ff4f 100644 --- a/src/BirdsiteLive.Domain/UserService.cs +++ b/src/BirdsiteLive.Domain/UserService.cs @@ -18,8 +18,8 @@ namespace BirdsiteLive.Domain public interface IUserService { Actor GetUser(TwitterUser twitterUser); - Task FollowRequestedAsync(string signature, string method, string path, string queryString, Dictionary requestHeaders, ActivityFollow activity); - Task UndoFollowRequestedAsync(string signature, string method, string path, string queryString, Dictionary requestHeaders, ActivityUndoFollow activity); + Task FollowRequestedAsync(string signature, string method, string path, string queryString, Dictionary requestHeaders, ActivityFollow activity, string body); + Task UndoFollowRequestedAsync(string signature, string method, string path, string queryString, Dictionary requestHeaders, ActivityUndoFollow activity, string body); } public class UserService : IUserService @@ -79,10 +79,10 @@ namespace BirdsiteLive.Domain return user; } - public async Task FollowRequestedAsync(string signature, string method, string path, string queryString, Dictionary requestHeaders, ActivityFollow activity) + public async Task FollowRequestedAsync(string signature, string method, string path, string queryString, Dictionary requestHeaders, ActivityFollow activity, string body) { // Validate - var sigValidation = await ValidateSignature(activity.actor, signature, method, path, queryString, requestHeaders); + var sigValidation = await ValidateSignature(activity.actor, signature, method, path, queryString, requestHeaders, body); if (!sigValidation.SignatureIsValidated) return false; // Save Follow in DB @@ -130,10 +130,10 @@ namespace BirdsiteLive.Domain } public async Task UndoFollowRequestedAsync(string signature, string method, string path, string queryString, - Dictionary requestHeaders, ActivityUndoFollow activity) + Dictionary requestHeaders, ActivityUndoFollow activity, string body) { // Validate - var sigValidation = await ValidateSignature(activity.actor, signature, method, path, queryString, requestHeaders); + var sigValidation = await ValidateSignature(activity.actor, signature, method, path, queryString, requestHeaders, body); if (!sigValidation.SignatureIsValidated) return false; // Save Follow in DB @@ -162,8 +162,22 @@ namespace BirdsiteLive.Domain return result == HttpStatusCode.Accepted; } - private async Task ValidateSignature(string actor, string rawSig, string method, string path, string queryString, Dictionary requestHeaders) + private async Task ValidateSignature(string actor, string rawSig, string method, string path, string queryString, Dictionary requestHeaders, string body) { + //Check Date Validity + var date = requestHeaders["date"]; + var d = DateTime.Parse(date).ToUniversalTime(); + var now = DateTime.UtcNow; + var delta = Math.Abs((d - now).TotalSeconds); + if (delta > 30) return new SignatureValidationResult { SignatureIsValidated = false }; + + //Check Digest + var digest = requestHeaders["digest"]; + var digestHash = digest.Split(new [] {"SHA-256="},StringSplitOptions.RemoveEmptyEntries).LastOrDefault(); + var calculatedDigestHash = _cryptoService.ComputeSha256Hash(body); + if (digestHash != calculatedDigestHash) return new SignatureValidationResult { SignatureIsValidated = false }; + + //Check Signature var signatures = rawSig.Split(','); var signature_header = new Dictionary(); foreach (var signature in signatures) diff --git a/src/BirdsiteLive/BirdsiteLive.csproj b/src/BirdsiteLive/BirdsiteLive.csproj index 2195422..8b92b7c 100644 --- a/src/BirdsiteLive/BirdsiteLive.csproj +++ b/src/BirdsiteLive/BirdsiteLive.csproj @@ -4,6 +4,7 @@ netcoreapp3.1 d21486de-a812-47eb-a419-05682bb68856 Linux + 0.1.0 diff --git a/src/BirdsiteLive/Controllers/UsersController.cs b/src/BirdsiteLive/Controllers/UsersController.cs index 0f6d7e3..dd1b081 100644 --- a/src/BirdsiteLive/Controllers/UsersController.cs +++ b/src/BirdsiteLive/Controllers/UsersController.cs @@ -111,7 +111,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); + r.QueryString.ToString(), RequestHeaders(r.Headers), activity as ActivityFollow, body); if (succeeded) return Accepted(); else return Unauthorized(); } @@ -119,7 +119,7 @@ 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); + r.QueryString.ToString(), RequestHeaders(r.Headers), activity as ActivityUndoFollow, body); if (succeeded) return Accepted(); else return Unauthorized(); } diff --git a/src/BirdsiteLive/Controllers/WellKnownController.cs b/src/BirdsiteLive/Controllers/WellKnownController.cs index 30a6f22..9ac3bb3 100644 --- a/src/BirdsiteLive/Controllers/WellKnownController.cs +++ b/src/BirdsiteLive/Controllers/WellKnownController.cs @@ -50,6 +50,8 @@ namespace BirdsiteLive.Controllers [Route("/nodeinfo/{id}.json")] public IActionResult NodeInfo(string id) { + var version = System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString(3); + if (id == "2.0") { var nodeInfo = new NodeInfoV20 @@ -66,7 +68,7 @@ namespace BirdsiteLive.Controllers software = new Software() { name = "birdsitelive", - version = "0.1.0" + version = version }, protocols = new[] { @@ -101,7 +103,7 @@ namespace BirdsiteLive.Controllers software = new SoftwareV21() { name = "birdsitelive", - version = "0.1.0", + version = version, repository = "https://github.com/NicolasConstant/BirdsiteLive" }, protocols = new[] diff --git a/src/BirdsiteLive/Views/Shared/_Layout.cshtml b/src/BirdsiteLive/Views/Shared/_Layout.cshtml index 633fd0d..5275267 100644 --- a/src/BirdsiteLive/Views/Shared/_Layout.cshtml +++ b/src/BirdsiteLive/Views/Shared/_Layout.cshtml @@ -36,11 +36,14 @@ - +
+
+ + Github @*Privacy*@ + + BirdsiteLIVE @System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString(3) +
+