commit
fcc7bbaa44
|
@ -0,0 +1,9 @@
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace BirdsiteLive.Common.Regexes
|
||||||
|
{
|
||||||
|
public class HeaderRegexes
|
||||||
|
{
|
||||||
|
public static readonly Regex HeaderSignature = new Regex(@"^([a-zA-Z0-9]+)=""(.+)""$");
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,7 +40,7 @@ namespace BirdsiteLive.Domain
|
||||||
public async Task<Actor> GetUser(string objectId)
|
public async Task<Actor> GetUser(string objectId)
|
||||||
{
|
{
|
||||||
var httpClient = _httpClientFactory.CreateClient();
|
var httpClient = _httpClientFactory.CreateClient();
|
||||||
httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
|
httpClient.DefaultRequestHeaders.Add("Accept", "application/activity+json");
|
||||||
var result = await httpClient.GetAsync(objectId);
|
var result = await httpClient.GetAsync(objectId);
|
||||||
var content = await result.Content.ReadAsStringAsync();
|
var content = await result.Content.ReadAsStringAsync();
|
||||||
return JsonConvert.DeserializeObject<Actor>(content);
|
return JsonConvert.DeserializeObject<Actor>(content);
|
||||||
|
|
|
@ -7,6 +7,7 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BirdsiteLive.ActivityPub;
|
using BirdsiteLive.ActivityPub;
|
||||||
using BirdsiteLive.ActivityPub.Converters;
|
using BirdsiteLive.ActivityPub.Converters;
|
||||||
|
using BirdsiteLive.Common.Regexes;
|
||||||
using BirdsiteLive.Common.Settings;
|
using BirdsiteLive.Common.Settings;
|
||||||
using BirdsiteLive.Cryptography;
|
using BirdsiteLive.Cryptography;
|
||||||
using BirdsiteLive.Domain.BusinessUseCases;
|
using BirdsiteLive.Domain.BusinessUseCases;
|
||||||
|
@ -239,33 +240,24 @@ namespace BirdsiteLive.Domain
|
||||||
var signature_header = new Dictionary<string, string>();
|
var signature_header = new Dictionary<string, string>();
|
||||||
foreach (var signature in signatures)
|
foreach (var signature in signatures)
|
||||||
{
|
{
|
||||||
var splitSig = signature.Replace("\"", string.Empty).Split('=');
|
var m = HeaderRegexes.HeaderSignature.Match(signature);
|
||||||
signature_header.Add(splitSig[0], splitSig[1]);
|
signature_header.Add(m.Groups[1].ToString(), m.Groups[2].ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
signature_header["signature"] = signature_header["signature"] + "==";
|
|
||||||
|
|
||||||
var key_id = signature_header["keyId"];
|
var key_id = signature_header["keyId"];
|
||||||
var headers = signature_header["headers"];
|
var headers = signature_header["headers"];
|
||||||
var algorithm = signature_header["algorithm"];
|
var algorithm = signature_header["algorithm"];
|
||||||
var sig = Convert.FromBase64String(signature_header["signature"]);
|
var sig = Convert.FromBase64String(signature_header["signature"]);
|
||||||
|
|
||||||
|
// Retrieve User
|
||||||
var remoteUser = await _activityPubService.GetUser(actor);
|
var remoteUser = await _activityPubService.GetUser(actor);
|
||||||
|
|
||||||
|
// Prepare Key data
|
||||||
var toDecode = remoteUser.publicKey.publicKeyPem.Trim().Remove(0, remoteUser.publicKey.publicKeyPem.IndexOf('\n'));
|
var toDecode = remoteUser.publicKey.publicKeyPem.Trim().Remove(0, remoteUser.publicKey.publicKeyPem.IndexOf('\n'));
|
||||||
toDecode = toDecode.Remove(toDecode.LastIndexOf('\n')).Replace("\n", "");
|
toDecode = toDecode.Remove(toDecode.LastIndexOf('\n')).Replace("\n", "");
|
||||||
var signKey = ASN1.ToRSA(Convert.FromBase64String(toDecode));
|
var signKey = ASN1.ToRSA(Convert.FromBase64String(toDecode));
|
||||||
|
|
||||||
var toSign = new StringBuilder();
|
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(' '))
|
foreach (var headerKey in headers.Split(' '))
|
||||||
{
|
{
|
||||||
if (headerKey == "(request-target)") toSign.Append($"(request-target): {method.ToLower()} {path}{queryString}\n");
|
if (headerKey == "(request-target)") toSign.Append($"(request-target): {method.ToLower()} {path}{queryString}\n");
|
||||||
|
@ -273,21 +265,13 @@ namespace BirdsiteLive.Domain
|
||||||
}
|
}
|
||||||
toSign.Remove(toSign.Length - 1, 1);
|
toSign.Remove(toSign.Length - 1, 1);
|
||||||
|
|
||||||
//var signKey = ASN1.ToRSA(Convert.FromBase64String(toDecode));
|
// Import key
|
||||||
|
var key = new RSACryptoServiceProvider();
|
||||||
//new RSACryptoServiceProvider(keyId.publicKey.publicKeyPem);
|
var rsaKeyInfo = key.ExportParameters(false);
|
||||||
|
rsaKeyInfo.Modulus = Convert.FromBase64String(toDecode);
|
||||||
//Create a new instance of RSACryptoServiceProvider.
|
key.ImportParameters(rsaKeyInfo);
|
||||||
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);
|
|
||||||
|
|
||||||
|
// Trust and Verify
|
||||||
var result = signKey.VerifyData(Encoding.UTF8.GetBytes(toSign.ToString()), sig, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
var result = signKey.VerifyData(Encoding.UTF8.GetBytes(toSign.ToString()), sig, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||||
|
|
||||||
return new SignatureValidationResult()
|
return new SignatureValidationResult()
|
||||||
|
|
|
@ -39,7 +39,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BirdsiteLive.Domain.Tests",
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BirdsiteLive.Pipeline.Tests", "Tests\BirdsiteLive.Pipeline.Tests\BirdsiteLive.Pipeline.Tests.csproj", "{BF51CA81-5A7A-46F8-B4FB-861C6BE59298}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BirdsiteLive.Pipeline.Tests", "Tests\BirdsiteLive.Pipeline.Tests\BirdsiteLive.Pipeline.Tests.csproj", "{BF51CA81-5A7A-46F8-B4FB-861C6BE59298}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BirdsiteLive.DAL.Tests", "Tests\BirdsiteLive.DAL.Tests\BirdsiteLive.DAL.Tests.csproj", "{5A1E3EB5-6CBB-470D-8A0D-10F8C18353D5}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BirdsiteLive.DAL.Tests", "Tests\BirdsiteLive.DAL.Tests\BirdsiteLive.DAL.Tests.csproj", "{5A1E3EB5-6CBB-470D-8A0D-10F8C18353D5}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BirdsiteLive.Common.Tests", "Tests\BirdsiteLive.Common.Tests\BirdsiteLive.Common.Tests.csproj", "{C69F7582-6050-44DC-BAAB-7C8F0BDA525C}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
@ -107,6 +109,10 @@ Global
|
||||||
{5A1E3EB5-6CBB-470D-8A0D-10F8C18353D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{5A1E3EB5-6CBB-470D-8A0D-10F8C18353D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{5A1E3EB5-6CBB-470D-8A0D-10F8C18353D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{5A1E3EB5-6CBB-470D-8A0D-10F8C18353D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{5A1E3EB5-6CBB-470D-8A0D-10F8C18353D5}.Release|Any CPU.Build.0 = Release|Any CPU
|
{5A1E3EB5-6CBB-470D-8A0D-10F8C18353D5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C69F7582-6050-44DC-BAAB-7C8F0BDA525C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C69F7582-6050-44DC-BAAB-7C8F0BDA525C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C69F7582-6050-44DC-BAAB-7C8F0BDA525C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C69F7582-6050-44DC-BAAB-7C8F0BDA525C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -126,6 +132,7 @@ Global
|
||||||
{F544D745-89A8-4DEA-B61C-A7E6C53C1D63} = {A32D3458-09D0-4E0A-BA4B-8C411B816B94}
|
{F544D745-89A8-4DEA-B61C-A7E6C53C1D63} = {A32D3458-09D0-4E0A-BA4B-8C411B816B94}
|
||||||
{BF51CA81-5A7A-46F8-B4FB-861C6BE59298} = {A32D3458-09D0-4E0A-BA4B-8C411B816B94}
|
{BF51CA81-5A7A-46F8-B4FB-861C6BE59298} = {A32D3458-09D0-4E0A-BA4B-8C411B816B94}
|
||||||
{5A1E3EB5-6CBB-470D-8A0D-10F8C18353D5} = {A32D3458-09D0-4E0A-BA4B-8C411B816B94}
|
{5A1E3EB5-6CBB-470D-8A0D-10F8C18353D5} = {A32D3458-09D0-4E0A-BA4B-8C411B816B94}
|
||||||
|
{C69F7582-6050-44DC-BAAB-7C8F0BDA525C} = {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,7 +4,7 @@
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
<UserSecretsId>d21486de-a812-47eb-a419-05682bb68856</UserSecretsId>
|
<UserSecretsId>d21486de-a812-47eb-a419-05682bb68856</UserSecretsId>
|
||||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
<Version>0.13.1</Version>
|
<Version>0.14.0</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -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.7.1" />
|
||||||
|
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
|
||||||
|
<PackageReference Include="MSTest.TestFramework" Version="2.1.1" />
|
||||||
|
<PackageReference Include="coverlet.collector" Version="1.3.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\BirdsiteLive.Common\BirdsiteLive.Common.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,53 @@
|
||||||
|
using BirdsiteLive.Common.Regexes;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
|
||||||
|
namespace BirdsiteLive.Common.Tests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class HeaderRegexTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void KeyId_Test()
|
||||||
|
{
|
||||||
|
var input = @"keyId=""https://misskey.tdl/users/8hwf6zy2k1#main-key""";
|
||||||
|
|
||||||
|
Assert.IsTrue(HeaderRegexes.HeaderSignature.IsMatch(input));
|
||||||
|
var result = HeaderRegexes.HeaderSignature.Match(input);
|
||||||
|
Assert.AreEqual("keyId", result.Groups[1].ToString());
|
||||||
|
Assert.AreEqual("https://misskey.tdl/users/8hwf6zy2k1#main-key", result.Groups[2].ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Algorithm_Test()
|
||||||
|
{
|
||||||
|
var input = @"algorithm=""rsa-sha256""";
|
||||||
|
|
||||||
|
Assert.IsTrue(HeaderRegexes.HeaderSignature.IsMatch(input));
|
||||||
|
var result = HeaderRegexes.HeaderSignature.Match(input);
|
||||||
|
Assert.AreEqual("algorithm", result.Groups[1].ToString());
|
||||||
|
Assert.AreEqual("rsa-sha256", result.Groups[2].ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Target_Test()
|
||||||
|
{
|
||||||
|
var input = @"headers=""(request-target) date host digest""";
|
||||||
|
|
||||||
|
Assert.IsTrue(HeaderRegexes.HeaderSignature.IsMatch(input));
|
||||||
|
var result = HeaderRegexes.HeaderSignature.Match(input);
|
||||||
|
Assert.AreEqual("headers", result.Groups[1].ToString());
|
||||||
|
Assert.AreEqual("(request-target) date host digest", result.Groups[2].ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Signature_Test()
|
||||||
|
{
|
||||||
|
var input = @"signature=""ISxp4HYhkGc83SsCC3zNZMVKBota7HqgWVg6KwaQVTQcUqt+UsWXPxB0XPhaYkqLnH3hJ+KVMdoEn3rbzcw8XZpjVt48o9OAKd0rsEZYkLoERnnFFhEw0GmVDEhdoU7gyoeOreWGsIca6Pf7TC0vGTtqez31zmvoeXvxHgqRhWQvlZM/ovFR2xN+vhmF7rZdkd6UaKOzy21K8B/Q84J7PWdbJ8i0rKieVPDIuTCy5B0iQpgs1TMaz6xKZR/KVzAr207m9Gkku2gnJ4YZHFuoa2ct5M5AtIPMPCsWTU8yaimTkPdNNezSOKV5a7T55HSvFeopLNcQKsWNMioKGpZP5hCIRKNk0Ekx0yDReE6xF/qliT7eSAGVJ/6sLQjBpBFMPKBNOrYTxueBJGtISjCZlxaIyTtJ1ErNuCrKHGjImpNvvJzTJOtu+vWnjTcUJL7N1Mw7PEreCZrNUyNuAldDWSMAFuD4HVA3+KZjpWCfjAbyelzVy2gs96CyE56o9FqJEaM5XVQhsMTpa8OSHdr2QZtKYw7Wng0d8vmbKEX1pdTVeEIhi4M9js39ZdzB4mb8JXSBE/GA6PoE5s+oH3+GoufzJYINCpk0Ulwo9g7HKm9NATnwEZZPq4NKto5mSYZKYRtqjZaa8lIALNhdvzv2+8+ifPLHlOigAUVqoupd9Aq=""";
|
||||||
|
|
||||||
|
Assert.IsTrue(HeaderRegexes.HeaderSignature.IsMatch(input));
|
||||||
|
var result = HeaderRegexes.HeaderSignature.Match(input);
|
||||||
|
Assert.AreEqual("signature", result.Groups[1].ToString());
|
||||||
|
Assert.AreEqual("ISxp4HYhkGc83SsCC3zNZMVKBota7HqgWVg6KwaQVTQcUqt+UsWXPxB0XPhaYkqLnH3hJ+KVMdoEn3rbzcw8XZpjVt48o9OAKd0rsEZYkLoERnnFFhEw0GmVDEhdoU7gyoeOreWGsIca6Pf7TC0vGTtqez31zmvoeXvxHgqRhWQvlZM/ovFR2xN+vhmF7rZdkd6UaKOzy21K8B/Q84J7PWdbJ8i0rKieVPDIuTCy5B0iQpgs1TMaz6xKZR/KVzAr207m9Gkku2gnJ4YZHFuoa2ct5M5AtIPMPCsWTU8yaimTkPdNNezSOKV5a7T55HSvFeopLNcQKsWNMioKGpZP5hCIRKNk0Ekx0yDReE6xF/qliT7eSAGVJ/6sLQjBpBFMPKBNOrYTxueBJGtISjCZlxaIyTtJ1ErNuCrKHGjImpNvvJzTJOtu+vWnjTcUJL7N1Mw7PEreCZrNUyNuAldDWSMAFuD4HVA3+KZjpWCfjAbyelzVy2gs96CyE56o9FqJEaM5XVQhsMTpa8OSHdr2QZtKYw7Wng0d8vmbKEX1pdTVeEIhi4M9js39ZdzB4mb8JXSBE/GA6PoE5s+oH3+GoufzJYINCpk0Ulwo9g7HKm9NATnwEZZPq4NKto5mSYZKYRtqjZaa8lIALNhdvzv2+8+ifPLHlOigAUVqoupd9Aq=", result.Groups[2].ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue