using RadicadeServer.Utils; using Xunit; namespace RadicadeServer.Tests; // An imported room save names its holotar and image blobs by their original // rec.net names, and the 2023 client fetches exactly those (GET /data/.htr). // The admin upload route used to rename every file to a fresh GUID, so all of // them answered 404 and the rooms loaded with those objects missing. The route // can now be told the name to store under - and must refuse anything that is not // a bare file name, since it writes into the CDN directory. public class AdminUploadNameTests { [Fact] public void NoNameRequested_LeavesTheNameToTheServer() { Assert.True(AdminUtils.TryResolveUploadName(null, out var name, out var error)); Assert.Null(name); Assert.Null(error); Assert.True(AdminUtils.TryResolveUploadName(" ", out name, out error)); Assert.Null(name); Assert.Null(error); } [Theory] [InlineData("315cb6bf6af14c0b83bfe2fdc8ef0c79.htr")] [InlineData("f4ab6f0d2409427fa7b1b33587f4db67.room")] [InlineData("DefaultProfileImage.jpg")] [InlineData("room_image-2.png")] public void ABlobNameIsKeptExactly(string requested) { Assert.True(AdminUtils.TryResolveUploadName(requested, out var name, out var error)); Assert.Equal(requested, name); Assert.Null(error); } [Fact] public void SurroundingWhitespaceIsNotPartOfTheName() { Assert.True(AdminUtils.TryResolveUploadName(" abc.htr ", out var name, out _)); Assert.Equal("abc.htr", name); } // Every one of these would place the write somewhere other than the CDN // directory, or produce a name the client could never have requested. [Theory] [InlineData("../outside.htr")] [InlineData("..\\outside.htr")] [InlineData("sub/dir/blob.htr")] [InlineData("sub\\dir\\blob.htr")] [InlineData("/absolute/blob.htr")] [InlineData("C:\\Windows\\blob.htr")] [InlineData("blob..htr")] [InlineData("blob name.htr")] [InlineData("blob%2e%2e.htr")] [InlineData("blob;rm -rf.htr")] public void APathOrAnOddNameIsRefusedRatherThanRenamed(string requested) { Assert.False(AdminUtils.TryResolveUploadName(requested, out var name, out var error)); Assert.Null(name); Assert.NotNull(error); } [Fact] public void AnOverlongNameIsRefused() { Assert.False(AdminUtils.TryResolveUploadName(new string('a', 129) + ".htr", out _, out var error)); Assert.NotNull(error); } }