102 lines
3.9 KiB
C#
102 lines
3.9 KiB
C#
using Microsoft.AspNetCore.Http;
|
|||
|
|
using Microsoft.Extensions.Caching.Memory;
|
||
|
|
|
||
|
|
using MongoDB.Entities;
|
||
|
|
|
||
|
|
using NetVips;
|
||
|
|
|
||
|
|
using PrivaPub.Domain.Media;
|
||
|
|
using PrivaPub.Domain.Statuses;
|
||
|
|
using PrivaPub.Federation.Rendering;
|
||
|
|
using PrivaPub.Models.Media;
|
||
|
|
using PrivaPub.Tests.Support;
|
||
|
|
|
||
|
|
namespace PrivaPub.Tests.Domain
|
||
|
|
{
|
||
|
|
[Trait("Category", "Integration")]
|
||
|
|
public sealed class MediaFlowTests : IAsyncLifetime
|
||
|
|
{
|
||
|
|
Harness _harness;
|
||
|
|
|
||
|
|
public async ValueTask InitializeAsync()
|
||
|
|
{
|
||
|
|
Assert.SkipUnless(MongoFixture.Enabled, MongoFixture.Skip);
|
||
|
|
_harness = await Harness.Start();
|
||
|
|
}
|
||
|
|
|
||
|
|
public async ValueTask DisposeAsync()
|
||
|
|
{
|
||
|
|
if (_harness != default)
|
||
|
|
await _harness.DisposeAsync();
|
||
|
|
}
|
||
|
|
|
||
|
|
static byte[] Png(int width, int height)
|
||
|
|
{
|
||
|
|
using var image = (Image.Black(width, height, bands: 3) + new double[] { 10, 120, 200 }).Cast(Enums.BandFormat.Uchar);
|
||
|
|
return image.WriteToBuffer(".png");
|
||
|
|
}
|
||
|
|
|
||
|
|
static IFormFile Upload(byte[] bytes, string contentType) =>
|
||
|
|
new FormFile(new MemoryStream(bytes), 0, bytes.Length, "file", "picture") { Headers = new HeaderDictionary(), ContentType = contentType };
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task An_upload_is_attached_once_and_federated_with_its_alt_text()
|
||
|
|
{
|
||
|
|
var token = TestContext.Current.CancellationToken;
|
||
|
|
var (_, alice) = await _harness.Persona("alice");
|
||
|
|
var (_, mallory) = await _harness.Persona("mallory");
|
||
|
|
|
||
|
|
var upload = await _harness.Media.Upload(alice, Upload(Png(300, 200), "image/png"), "a blue square", "0.25,-0.5", token);
|
||
|
|
Assert.True(upload.Ok);
|
||
|
|
Assert.True(File.Exists(Path.Combine(_harness.Media.Root, upload.Attachment.FilePath)));
|
||
|
|
|
||
|
|
var stolen = await _harness.Statuses.Publish(mallory, new StatusDraft { Text = "mine", MediaIds = new[] { upload.Attachment.ID } }, token);
|
||
|
|
Assert.False(stolen.Ok);
|
||
|
|
|
||
|
|
var posted = await _harness.Statuses.Publish(alice, new StatusDraft { Text = "look", MediaIds = new[] { upload.Attachment.ID } }, token);
|
||
|
|
Assert.True(posted.Ok);
|
||
|
|
Assert.Equal(posted.Post.ID, (await DB.Default.Find<MediaAttachment>().OneAsync(upload.Attachment.ID, token)).PostId);
|
||
|
|
|
||
|
|
var note = ActivityPubRenderer.Note(posted.Post, alice, default, default);
|
||
|
|
var attachment = note["attachment"]![0]!;
|
||
|
|
Assert.Equal("a blue square", attachment["name"]!.GetValue<string>());
|
||
|
|
Assert.Equal(300, attachment["width"]!.GetValue<int>());
|
||
|
|
Assert.Equal(-0.5f, attachment["focalPoint"]![1]!.GetValue<float>());
|
||
|
|
Assert.StartsWith("https://privapub.test/media/files/", attachment["url"]!.GetValue<string>());
|
||
|
|
|
||
|
|
var reused = await _harness.Statuses.Publish(alice, new StatusDraft { Text = "again", MediaIds = new[] { upload.Attachment.ID } }, token);
|
||
|
|
Assert.False(reused.Ok);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task Unsupported_files_are_refused()
|
||
|
|
{
|
||
|
|
var (_, alice) = await _harness.Persona("alice");
|
||
|
|
|
||
|
|
var outcome = await _harness.Media.Upload(alice, Upload(System.Text.Encoding.UTF8.GetBytes("<svg/>"), "image/svg+xml"), default, default, TestContext.Current.CancellationToken);
|
||
|
|
|
||
|
|
Assert.False(outcome.Ok);
|
||
|
|
Assert.Equal(422, outcome.Status);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task The_proxy_serves_signed_remote_media_and_nothing_else()
|
||
|
|
{
|
||
|
|
var token = TestContext.Current.CancellationToken;
|
||
|
|
var path = $"/files/{Guid.NewGuid():N}.png";
|
||
|
|
_harness.Peer.ServeFile(path, Png(10, 10), "image/png");
|
||
|
|
var proxy = new MediaProxy(_harness.Local, Peer.Http(), _harness.Media, new StaticOptions<MediaOptions>(new MediaOptions()));
|
||
|
|
|
||
|
|
var wrapped = proxy.Wrap(_harness.Peer.A + path);
|
||
|
|
var parts = new Uri(wrapped).AbsolutePath.Split('/');
|
||
|
|
var (file, contentType) = await proxy.Fetch(parts[3], parts[4], token);
|
||
|
|
var (tampered, _) = await proxy.Fetch(parts[3].Replace(parts[3][0], parts[3][0] == 'A' ? 'B' : 'A'), parts[4], token);
|
||
|
|
|
||
|
|
Assert.StartsWith("https://privapub.test/media/proxy/", wrapped);
|
||
|
|
Assert.Equal("image/png", contentType);
|
||
|
|
Assert.True(File.Exists(file));
|
||
|
|
Assert.StartsWith(_harness.Media.ProxyRoot, file);
|
||
|
|
Assert.Null(tampered);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|