using Api.SeaHavenIndustries.Helper; using FluentAssertions; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Moq; using SeaHaven.Services.Helpers; using Xunit; namespace Api.SeaHavenIndustries.Tests; public class WorkOrderPrivateFileStorageTests { private static (WorkOrderPrivateFileStorage Storage, string Root) CreateStorage() { var root = Path.Combine(Path.GetTempPath(), "wo-files-" + Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); var env = new Mock(); env.Setup(e => e.ContentRootPath).Returns(root); return (new WorkOrderPrivateFileStorage(env.Object), root); } private static IFormFile FakeFile(string fileName, byte[]? bytes = null) { bytes ??= new byte[] { 1, 2, 3, 4 }; var stream = new MemoryStream(bytes); return new FormFile(stream, 0, bytes.Length, "file", fileName) { Headers = new HeaderDictionary(), ContentType = "application/octet-stream" }; } [Fact] public async Task SaveAsync_UsesServerControlledName_OutsideWwwroot() { var (storage, root) = CreateStorage(); try { var key = await storage.SaveAsync(42, FakeFile("../../evil.pdf")); key.Should().StartWith("workorder-files/42/"); key.Should().EndWith(".pdf"); key.Should().NotContain(".."); key.Should().NotContain("evil"); storage.TryResolvePhysicalPath(key, out var physical).Should().BeTrue(); physical.Should().StartWith(Path.Combine(root, "App_Data", "workorder-files")); File.Exists(physical).Should().BeTrue(); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } } [Fact] public async Task SaveAsync_RejectsDisallowedExtension() { var (storage, root) = CreateStorage(); try { var act = async () => await storage.SaveAsync(1, FakeFile("payload.exe")); await act.Should().ThrowAsync(); Directory.Exists(Path.Combine(root, "App_Data", "workorder-files", "1")).Should().BeFalse(); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } } [Fact] public void TryResolvePhysicalPath_RejectsPathEscape() { var (storage, root) = CreateStorage(); try { storage.TryResolvePhysicalPath("workorder-files/../secret.txt", out _).Should().BeFalse(); storage.TryResolvePhysicalPath("https://host/Assets/Documents/x.pdf", out _).Should().BeFalse(); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } } }