Add unit tests for http signatures
This commit is contained in:
parent
5f088ba66f
commit
af054faa05
10 changed files with 227 additions and 55 deletions
|
@ -2,18 +2,21 @@ using System.Data;
|
||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
using Iceshrimp.Backend.Core.Database;
|
using Iceshrimp.Backend.Core.Database;
|
||||||
using Iceshrimp.Backend.Core.Federation.Cryptography;
|
using Iceshrimp.Backend.Core.Federation.Cryptography;
|
||||||
|
using Iceshrimp.Backend.Core.Middleware;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace Iceshrimp.Backend.Controllers;
|
namespace Iceshrimp.Backend.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Produces("application/json")]
|
|
||||||
[Route("/inbox")]
|
[Route("/inbox")]
|
||||||
|
[Produces("application/json")]
|
||||||
|
[EnableRequestBuffering(1024 * 1024)]
|
||||||
public class SignatureTestController(ILogger<SignatureTestController> logger, DatabaseContext db) : Controller {
|
public class SignatureTestController(ILogger<SignatureTestController> logger, DatabaseContext db) : Controller {
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Consumes(MediaTypeNames.Application.Json)]
|
[Consumes(MediaTypeNames.Application.Json)]
|
||||||
public async Task<IActionResult> Inbox() {
|
public async Task<IActionResult> Inbox([FromBody] JToken content) {
|
||||||
if (!Request.Headers.TryGetValue("signature", out var sigHeader))
|
if (!Request.Headers.TryGetValue("signature", out var sigHeader))
|
||||||
throw new ConstraintException("Signature string is missing the signature header");
|
throw new ConstraintException("Signature string is missing the signature header");
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ using Microsoft.Extensions.Primitives;
|
||||||
namespace Iceshrimp.Backend.Core.Federation.Cryptography;
|
namespace Iceshrimp.Backend.Core.Federation.Cryptography;
|
||||||
|
|
||||||
public static class HttpSignature {
|
public static class HttpSignature {
|
||||||
public static Task<bool> Verify(HttpRequest request, HttpSignatureHeader signature,
|
public static async Task<bool> Verify(HttpRequest request, HttpSignatureHeader signature,
|
||||||
IEnumerable<string> requiredHeaders, string key) {
|
IEnumerable<string> requiredHeaders, string key) {
|
||||||
if (!requiredHeaders.All(signature.Headers.Contains))
|
if (!requiredHeaders.All(signature.Headers.Contains))
|
||||||
throw new ConstraintException("Request is missing required headers");
|
throw new ConstraintException("Request is missing required headers");
|
||||||
|
@ -16,19 +16,22 @@ public static class HttpSignature {
|
||||||
request.Path,
|
request.Path,
|
||||||
request.Headers);
|
request.Headers);
|
||||||
|
|
||||||
return VerifySignature(key, signingString, signature, request.Headers, request.Body);
|
request.Body.Position = 0;
|
||||||
|
return await VerifySignature(key, signingString, signature, request.Headers, request.Body);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: make this share code with the the regular Verify function
|
public static async Task<bool> Verify(this HttpRequestMessage request, string key) {
|
||||||
public static Task<bool> Verify(this HttpRequestMessage request, string key) {
|
|
||||||
var signatureHeader = request.Headers.GetValues("Signature").First();
|
var signatureHeader = request.Headers.GetValues("Signature").First();
|
||||||
var signature = Parse(signatureHeader);
|
var signature = Parse(signatureHeader);
|
||||||
var signingString = GenerateSigningString(signature.Headers, request.Method.Method,
|
var signingString = GenerateSigningString(signature.Headers, request.Method.Method,
|
||||||
request.RequestUri!.AbsolutePath,
|
request.RequestUri!.AbsolutePath,
|
||||||
request.Headers.ToHeaderDictionary());
|
request.Headers.ToHeaderDictionary());
|
||||||
|
|
||||||
return VerifySignature(key, signingString, signature, request.Headers.ToHeaderDictionary(),
|
Stream? body = null;
|
||||||
request.Content?.ReadAsStream());
|
|
||||||
|
if (request.Content != null) body = await request.Content.ReadAsStreamAsync();
|
||||||
|
|
||||||
|
return await VerifySignature(key, signingString, signature, request.Headers.ToHeaderDictionary(), body);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<bool> VerifySignature(string key, string signingString, HttpSignatureHeader signature,
|
private static async Task<bool> VerifySignature(string key, string signingString, HttpSignatureHeader signature,
|
||||||
|
@ -36,13 +39,15 @@ public static class HttpSignature {
|
||||||
if (!headers.TryGetValue("date", out var date)) throw new Exception("Date header is missing");
|
if (!headers.TryGetValue("date", out var date)) throw new Exception("Date header is missing");
|
||||||
if (DateTime.Now - DateTime.Parse(date!) > TimeSpan.FromHours(12)) throw new Exception("Signature too old");
|
if (DateTime.Now - DateTime.Parse(date!) > TimeSpan.FromHours(12)) throw new Exception("Signature too old");
|
||||||
|
|
||||||
//TODO: does this break for requests without a body?
|
if (body is { Length: > 0 }) {
|
||||||
if (body != null) {
|
if (body.Position != 0)
|
||||||
|
body.Position = 0;
|
||||||
var digest = await SHA256.HashDataAsync(body);
|
var digest = await SHA256.HashDataAsync(body);
|
||||||
|
body.Position = 0;
|
||||||
|
|
||||||
//TODO: check for the SHA256= prefix instead of blindly removing the first 8 chars
|
//TODO: check for the SHA-256= prefix instead of blindly removing the first 8 chars
|
||||||
if (Convert.ToBase64String(digest) != headers["digest"].ToString().Remove(0, 8))
|
if (Convert.ToBase64String(digest) != headers["digest"].ToString().Remove(0, 8))
|
||||||
throw new ConstraintException("Request digest mismatch");
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var rsa = RSA.Create();
|
var rsa = RSA.Create();
|
||||||
|
@ -123,9 +128,9 @@ public static class HttpSignature {
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HttpSignatureHeader(string keyId, string algo, byte[] signature, IEnumerable<string> headers) {
|
public class HttpSignatureHeader(string keyId, string algo, byte[] signature, IEnumerable<string> headers) {
|
||||||
public readonly string KeyId = keyId;
|
|
||||||
public readonly string Algo = algo;
|
public readonly string Algo = algo;
|
||||||
public readonly byte[] Signature = signature;
|
|
||||||
public readonly IEnumerable<string> Headers = headers;
|
public readonly IEnumerable<string> Headers = headers;
|
||||||
|
public readonly string KeyId = keyId;
|
||||||
|
public readonly byte[] Signature = signature;
|
||||||
}
|
}
|
||||||
}
|
}
|
11
Iceshrimp.Backend/Core/Helpers/AppExtensions.cs
Normal file
11
Iceshrimp.Backend/Core/Helpers/AppExtensions.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using Iceshrimp.Backend.Core.Middleware;
|
||||||
|
|
||||||
|
namespace Iceshrimp.Backend.Core.Helpers;
|
||||||
|
|
||||||
|
public static class AppExtensions {
|
||||||
|
public static WebApplication UseCustomMiddleware(this WebApplication app) {
|
||||||
|
app.UseMiddleware<RequestBufferingMiddleware>();
|
||||||
|
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
||||||
|
namespace Iceshrimp.Backend.Core.Middleware;
|
||||||
|
|
||||||
|
public class RequestBufferingMiddleware(RequestDelegate next) {
|
||||||
|
public async Task InvokeAsync(HttpContext context) {
|
||||||
|
var endpoint = context.Features.Get<IEndpointFeature>()?.Endpoint;
|
||||||
|
var attribute = endpoint?.Metadata.GetMetadata<EnableRequestBufferingAttribute>();
|
||||||
|
|
||||||
|
if (attribute != null) context.Request.EnableBuffering(attribute.MaxLength);
|
||||||
|
|
||||||
|
await next(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EnableRequestBufferingAttribute(long maxLength) : Attribute {
|
||||||
|
internal long MaxLength = maxLength;
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ public class HttpRequestService(IOptions<Config.InstanceSection> options) {
|
||||||
IEnumerable<string>? accept = null) {
|
IEnumerable<string>? accept = null) {
|
||||||
var message = new HttpRequestMessage {
|
var message = new HttpRequestMessage {
|
||||||
RequestUri = new Uri(url),
|
RequestUri = new Uri(url),
|
||||||
Method = method,
|
Method = method
|
||||||
//Headers = { UserAgent = { ProductInfoHeaderValue.Parse(options.Value.UserAgent) } }
|
//Headers = { UserAgent = { ProductInfoHeaderValue.Parse(options.Value.UserAgent) } }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,10 +26,9 @@ public class HttpRequestService(IOptions<Config.InstanceSection> options) {
|
||||||
message.Content = new StringContent(body, MediaTypeHeaderValue.Parse(contentType));
|
message.Content = new StringContent(body, MediaTypeHeaderValue.Parse(contentType));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accept != null) {
|
if (accept != null)
|
||||||
foreach (var type in accept.Select(MediaTypeWithQualityHeaderValue.Parse))
|
foreach (var type in accept.Select(MediaTypeWithQualityHeaderValue.Parse))
|
||||||
message.Headers.Accept.Add(type);
|
message.Headers.Accept.Add(type);
|
||||||
}
|
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
@ -56,7 +55,7 @@ public class HttpRequestService(IOptions<Config.InstanceSection> options) {
|
||||||
// Generate and attach digest header
|
// Generate and attach digest header
|
||||||
var content = await message.Content.ReadAsStreamAsync();
|
var content = await message.Content.ReadAsStreamAsync();
|
||||||
var digest = await SHA256.HashDataAsync(content);
|
var digest = await SHA256.HashDataAsync(content);
|
||||||
message.Headers.Add("Digest", Convert.ToBase64String(digest));
|
message.Headers.Add("Digest", "SHA-256=" + Convert.ToBase64String(digest));
|
||||||
|
|
||||||
// Return the signed message
|
// Return the signed message
|
||||||
return message.Sign(["(request-target)", "date", "host", "digest"], keypair.PrivateKey,
|
return message.Sign(["(request-target)", "date", "host", "digest"], keypair.PrivateKey,
|
||||||
|
|
|
@ -4,7 +4,6 @@ using Iceshrimp.Backend.Core.Database;
|
||||||
using Iceshrimp.Backend.Core.Helpers;
|
using Iceshrimp.Backend.Core.Helpers;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Vite.AspNetCore.Extensions;
|
using Vite.AspNetCore.Extensions;
|
||||||
using StringExtensions = AngleSharp.Text.StringExtensions;
|
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
@ -59,6 +58,8 @@ app.UseSwagger();
|
||||||
app.UseSwaggerUI(options => { options.DocumentTitle = "Iceshrimp API documentation"; });
|
app.UseSwaggerUI(options => { options.DocumentTitle = "Iceshrimp API documentation"; });
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
app.UseCustomMiddleware();
|
||||||
|
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
app.MapFallbackToController("/api/{**slug}", "FallbackAction", "Fallback");
|
app.MapFallbackToController("/api/{**slug}", "FallbackAction", "Fallback");
|
||||||
app.MapRazorPages();
|
app.MapRazorPages();
|
||||||
|
|
106
Iceshrimp.Tests/Cryptography/HttpSignatureTests.cs
Normal file
106
Iceshrimp.Tests/Cryptography/HttpSignatureTests.cs
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
using System.Text;
|
||||||
|
using Iceshrimp.Backend.Core.Federation.ActivityStreams;
|
||||||
|
using Iceshrimp.Backend.Core.Federation.ActivityStreams.Types;
|
||||||
|
using Iceshrimp.Backend.Core.Federation.Cryptography;
|
||||||
|
using Iceshrimp.Backend.Core.Services;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace Iceshrimp.Tests.Cryptography;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class HttpSignatureTests {
|
||||||
|
private ASActor _actor = null!;
|
||||||
|
private JArray _expanded = null!;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize() {
|
||||||
|
_actor = MockObjects.ASActor;
|
||||||
|
_expanded = LdHelpers.Expand(_actor)!;
|
||||||
|
_expanded.Should().NotBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task SignedGetTest() {
|
||||||
|
var provider = MockObjects.ServiceProvider;
|
||||||
|
|
||||||
|
var httpRqSvc = provider.GetService<HttpRequestService>();
|
||||||
|
var request = httpRqSvc!.GetSigned("https://example.org/users/1234", ["application/ld+json"],
|
||||||
|
MockObjects.User, MockObjects.UserKeypair);
|
||||||
|
|
||||||
|
var verify = await request.Verify(MockObjects.UserKeypair.PublicKey);
|
||||||
|
verify.Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task InvalidSignatureDateTest() {
|
||||||
|
var provider = MockObjects.ServiceProvider;
|
||||||
|
|
||||||
|
var httpRqSvc = provider.GetService<HttpRequestService>();
|
||||||
|
var request = httpRqSvc!.GetSigned("https://example.org/users/1234", ["application/ld+json"],
|
||||||
|
MockObjects.User, MockObjects.UserKeypair);
|
||||||
|
|
||||||
|
request.Headers.Date = DateTimeOffset.Now - TimeSpan.FromHours(13);
|
||||||
|
|
||||||
|
await Assert.ThrowsExceptionAsync<Exception>(async () =>
|
||||||
|
await request.Verify(MockObjects.UserKeypair.PublicKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task InvalidSignatureTest() {
|
||||||
|
var provider = MockObjects.ServiceProvider;
|
||||||
|
|
||||||
|
var httpRqSvc = provider.GetService<HttpRequestService>();
|
||||||
|
var request = httpRqSvc!.GetSigned("https://example.org/users/1234", ["application/ld+json"],
|
||||||
|
MockObjects.User, MockObjects.UserKeypair);
|
||||||
|
|
||||||
|
var sig = request.Headers.GetValues("Signature").First();
|
||||||
|
sig = new StringBuilder(sig) { [sig.Length - 10] = (char)(sig[10] + 1) }.ToString();
|
||||||
|
|
||||||
|
request.Headers.Remove("Signature");
|
||||||
|
request.Headers.Add("Signature", sig);
|
||||||
|
|
||||||
|
var verify = await request.Verify(MockObjects.UserKeypair.PublicKey);
|
||||||
|
verify.Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ModifiedUriTest() {
|
||||||
|
var provider = MockObjects.ServiceProvider;
|
||||||
|
|
||||||
|
var httpRqSvc = provider.GetService<HttpRequestService>();
|
||||||
|
var request = httpRqSvc!.GetSigned("https://example.org/users/1234", ["application/ld+json"],
|
||||||
|
MockObjects.User, MockObjects.UserKeypair);
|
||||||
|
|
||||||
|
request.RequestUri = new Uri(request.RequestUri + "5");
|
||||||
|
|
||||||
|
var verify = await request.Verify(MockObjects.UserKeypair.PublicKey);
|
||||||
|
verify.Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task SignedPostTest() {
|
||||||
|
var provider = MockObjects.ServiceProvider;
|
||||||
|
|
||||||
|
var httpRqSvc = provider.GetService<HttpRequestService>();
|
||||||
|
var request = await httpRqSvc!.PostSigned("https://example.org/users/1234", "body", "text/plain",
|
||||||
|
MockObjects.User, MockObjects.UserKeypair);
|
||||||
|
|
||||||
|
var verify = await request.Verify(MockObjects.UserKeypair.PublicKey);
|
||||||
|
verify.Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ModifiedBodyTest() {
|
||||||
|
var provider = MockObjects.ServiceProvider;
|
||||||
|
|
||||||
|
var httpRqSvc = provider.GetService<HttpRequestService>();
|
||||||
|
var request = await httpRqSvc!.PostSigned("https://example.org/users/1234", "body", "text/plain",
|
||||||
|
MockObjects.User, MockObjects.UserKeypair);
|
||||||
|
|
||||||
|
request.Content = new StringContent("modified-body");
|
||||||
|
|
||||||
|
var verify = await request.Verify(MockObjects.UserKeypair.PublicKey);
|
||||||
|
verify.Should().BeFalse();
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,32 +2,19 @@ using System.Security.Cryptography;
|
||||||
using Iceshrimp.Backend.Core.Federation.ActivityStreams;
|
using Iceshrimp.Backend.Core.Federation.ActivityStreams;
|
||||||
using Iceshrimp.Backend.Core.Federation.ActivityStreams.Types;
|
using Iceshrimp.Backend.Core.Federation.ActivityStreams.Types;
|
||||||
using Iceshrimp.Backend.Core.Federation.Cryptography;
|
using Iceshrimp.Backend.Core.Federation.Cryptography;
|
||||||
using Iceshrimp.Backend.Core.Helpers;
|
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace Iceshrimp.Tests.Cryptography;
|
namespace Iceshrimp.Tests.Cryptography;
|
||||||
|
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class LdSignatureTests {
|
public class LdSignatureTests {
|
||||||
private ASActor _actor = null!;
|
private readonly ASActor _actor = MockObjects.ASActor;
|
||||||
private RSA _keypair = null!;
|
private readonly RSA _keypair = MockObjects.Keypair;
|
||||||
private JArray _expanded = null!;
|
private JArray _expanded = null!;
|
||||||
private JObject _signed = null!;
|
private JObject _signed = null!;
|
||||||
|
|
||||||
[TestInitialize]
|
[TestInitialize]
|
||||||
public async Task Initialize() {
|
public async Task Initialize() {
|
||||||
_keypair = RSA.Create();
|
|
||||||
_actor = new ASActor {
|
|
||||||
Id = $"https://example.org/users/{IdHelpers.GenerateSlowflakeId()}",
|
|
||||||
Type = ["https://www.w3.org/ns/activitystreams#Person"],
|
|
||||||
Url = new ASLink("https://example.org/@test"),
|
|
||||||
Username = "test",
|
|
||||||
DisplayName = "Test account",
|
|
||||||
IsCat = false,
|
|
||||||
IsDiscoverable = true,
|
|
||||||
IsLocked = true
|
|
||||||
};
|
|
||||||
|
|
||||||
_expanded = LdHelpers.Expand(_actor)!;
|
_expanded = LdHelpers.Expand(_actor)!;
|
||||||
_signed = await LdSignature.Sign(_expanded, _keypair.ExportRSAPrivateKeyPem(), _actor.Id + "#main-key");
|
_signed = await LdSignature.Sign(_expanded, _keypair.ExportRSAPrivateKeyPem(), _actor.Id + "#main-key");
|
||||||
|
|
||||||
|
@ -76,11 +63,15 @@ public class LdSignatureTests {
|
||||||
var data = (_signed.DeepClone() as JObject)!;
|
var data = (_signed.DeepClone() as JObject)!;
|
||||||
data.Should().NotBeNull();
|
data.Should().NotBeNull();
|
||||||
|
|
||||||
var signature = data["https://w3id.org/security#signature"]?[0]?["https://w3id.org/security#signatureValue"]?[0]?["@value"];
|
var signature =
|
||||||
|
data["https://w3id.org/security#signature"]?[0]?["https://w3id.org/security#signatureValue"]?[0]?["@value"];
|
||||||
signature.Should().NotBeNull();
|
signature.Should().NotBeNull();
|
||||||
|
|
||||||
data["https://w3id.org/security#signature"]![0]!["https://w3id.org/security#signatureValue"]![0]!["@value"] += "test";
|
data["https://w3id.org/security#signature"]![0]!["https://w3id.org/security#signatureValue"]![0]!["@value"] +=
|
||||||
await Assert.ThrowsExceptionAsync<FormatException>(async () => await LdSignature.Verify(data, _keypair.ExportRSAPublicKeyPem()));
|
"test";
|
||||||
|
await Assert.ThrowsExceptionAsync<FormatException>(async () =>
|
||||||
|
await LdSignature.Verify(data,
|
||||||
|
_keypair.ExportRSAPublicKeyPem()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -88,7 +79,8 @@ public class LdSignatureTests {
|
||||||
var data = (_signed.DeepClone() as JObject)!;
|
var data = (_signed.DeepClone() as JObject)!;
|
||||||
data.Should().NotBeNull();
|
data.Should().NotBeNull();
|
||||||
|
|
||||||
var creator = data["https://w3id.org/security#signature"]?[0]?["http://purl.org/dc/terms/creator"]?[0]?["@value"];
|
var creator =
|
||||||
|
data["https://w3id.org/security#signature"]?[0]?["http://purl.org/dc/terms/creator"]?[0]?["@value"];
|
||||||
creator.Should().NotBeNull();
|
creator.Should().NotBeNull();
|
||||||
|
|
||||||
data["https://w3id.org/security#signature"]![0]!["http://purl.org/dc/terms/creator"]![0]!["@value"] += "test";
|
data["https://w3id.org/security#signature"]![0]!["http://purl.org/dc/terms/creator"]![0]!["@value"] += "test";
|
||||||
|
|
47
Iceshrimp.Tests/MockObjects.cs
Normal file
47
Iceshrimp.Tests/MockObjects.cs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using Iceshrimp.Backend.Core.Database.Tables;
|
||||||
|
using Iceshrimp.Backend.Core.Federation.ActivityStreams.Types;
|
||||||
|
using Iceshrimp.Backend.Core.Helpers;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Iceshrimp.Tests;
|
||||||
|
|
||||||
|
public static class MockObjects {
|
||||||
|
public static readonly ASActor ASActor = new() {
|
||||||
|
Id = $"https://example.org/users/{IdHelpers.GenerateSlowflakeId()}",
|
||||||
|
Type = ["https://www.w3.org/ns/activitystreams#Person"],
|
||||||
|
Url = new ASLink("https://example.org/@test"),
|
||||||
|
Username = "test",
|
||||||
|
DisplayName = "Test account",
|
||||||
|
IsCat = false,
|
||||||
|
IsDiscoverable = true,
|
||||||
|
IsLocked = true
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly User User = new() {
|
||||||
|
Id = IdHelpers.GenerateSlowflakeId()
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly RSA Keypair = RSA.Create(4096);
|
||||||
|
|
||||||
|
public static readonly UserKeypair UserKeypair = new() {
|
||||||
|
UserId = User.Id,
|
||||||
|
PrivateKey = Keypair.ExportPkcs8PrivateKeyPem(),
|
||||||
|
PublicKey = Keypair.ExportSubjectPublicKeyInfoPem()
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly ServiceProvider DefaultServiceProvider = GetServiceProvider();
|
||||||
|
public static IServiceProvider ServiceProvider => DefaultServiceProvider.CreateScope().ServiceProvider;
|
||||||
|
|
||||||
|
private static ServiceProvider GetServiceProvider() {
|
||||||
|
var config = new ConfigurationManager();
|
||||||
|
config.AddIniFile("configuration.ini", false);
|
||||||
|
|
||||||
|
var collection = new ServiceCollection();
|
||||||
|
collection.AddServices();
|
||||||
|
collection.ConfigureServices(config);
|
||||||
|
|
||||||
|
return collection.BuildServiceProvider();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
using Iceshrimp.Backend.Core.Federation.ActivityStreams;
|
using Iceshrimp.Backend.Core.Federation.ActivityStreams;
|
||||||
using Iceshrimp.Backend.Core.Federation.ActivityStreams.Types;
|
using Iceshrimp.Backend.Core.Federation.ActivityStreams.Types;
|
||||||
using Iceshrimp.Backend.Core.Helpers;
|
|
||||||
|
|
||||||
namespace Iceshrimp.Tests.Serialization;
|
namespace Iceshrimp.Tests.Serialization;
|
||||||
|
|
||||||
|
@ -10,16 +9,7 @@ public class JsonLdTests {
|
||||||
|
|
||||||
[TestInitialize]
|
[TestInitialize]
|
||||||
public void Initialize() {
|
public void Initialize() {
|
||||||
_actor = new ASActor {
|
_actor = MockObjects.ASActor;
|
||||||
Id = $"https://example.org/users/{IdHelpers.GenerateSlowflakeId()}",
|
|
||||||
Type = ["https://www.w3.org/ns/activitystreams#Person"],
|
|
||||||
Url = new ASLink("https://example.org/@test"),
|
|
||||||
Username = "test",
|
|
||||||
DisplayName = "Test account",
|
|
||||||
IsCat = false,
|
|
||||||
IsDiscoverable = true,
|
|
||||||
IsLocked = true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
|
Loading…
Add table
Reference in a new issue