123 lines
4.3 KiB
C#
123 lines
4.3 KiB
C#
using System.Runtime.InteropServices;
|
|
|
|
namespace MBN_STOCK_WEBVIEW.Playout.Tests;
|
|
|
|
public sealed class TrustedPlayoutAssetPathTests
|
|
{
|
|
private static readonly IReadOnlySet<string> Allowed = new HashSet<string>(
|
|
[".vrv", ".png"],
|
|
StringComparer.OrdinalIgnoreCase);
|
|
|
|
[Fact]
|
|
public void ResolveRelativeFile_AcceptsOneInternalRegularFile()
|
|
{
|
|
using var root = TemporarySceneDirectory.Create("studio.vrv");
|
|
|
|
var resolved = TrustedPlayoutAssetPath.ResolveRelativeFile(
|
|
root.Path,
|
|
"studio.vrv",
|
|
Allowed);
|
|
|
|
Assert.Equal(Path.Combine(root.Path, "studio.vrv"), resolved, ignoreCase: true);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("..\\outside.vrv")]
|
|
[InlineData("C:\\outside.vrv")]
|
|
public void ResolveRelativeFile_RejectsRootEscape(string input)
|
|
{
|
|
using var root = TemporarySceneDirectory.Create("studio.vrv");
|
|
|
|
Assert.Throws<TrustedPlayoutAssetException>(() =>
|
|
TrustedPlayoutAssetPath.ResolveRelativeFile(root.Path, input, Allowed));
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolveRelativeFile_RejectsMissingFile()
|
|
{
|
|
using var root = TemporarySceneDirectory.Create();
|
|
|
|
Assert.Throws<TrustedPlayoutAssetException>(() =>
|
|
TrustedPlayoutAssetPath.ResolveRelativeFile(root.Path, "missing.vrv", Allowed));
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolveAbsoluteFile_RejectsPickerSelectionOutsideTheRoot()
|
|
{
|
|
using var root = TemporarySceneDirectory.Create();
|
|
using var outside = TemporarySceneDirectory.Create("outside.vrv");
|
|
|
|
Assert.Throws<TrustedPlayoutAssetException>(() =>
|
|
TrustedPlayoutAssetPath.ResolveAbsoluteFile(
|
|
root.Path,
|
|
Path.Combine(outside.Path, "outside.vrv"),
|
|
Allowed));
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolveRelativeFile_RejectsHardLinkedFile()
|
|
{
|
|
using var root = TemporarySceneDirectory.Create();
|
|
var parent = Directory.GetParent(root.Path)!.FullName;
|
|
var outside = Path.Combine(parent, "outside.vrv");
|
|
File.WriteAllText(outside, "outside trusted-looking bytes");
|
|
var link = Path.Combine(root.Path, "linked.vrv");
|
|
Assert.True(CreateHardLinkW(link, outside, IntPtr.Zero));
|
|
|
|
Assert.Throws<TrustedPlayoutAssetException>(() =>
|
|
TrustedPlayoutAssetPath.ResolveRelativeFile(root.Path, "linked.vrv", Allowed));
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolveRelativeFile_RejectsReparseDirectory()
|
|
{
|
|
using var root = TemporarySceneDirectory.Create();
|
|
var parent = Directory.GetParent(root.Path)!.FullName;
|
|
var outside = Path.Combine(parent, "outside");
|
|
Directory.CreateDirectory(outside);
|
|
File.WriteAllText(Path.Combine(outside, "studio.vrv"), "outside bytes");
|
|
var link = Path.Combine(root.Path, "linked");
|
|
try
|
|
{
|
|
Directory.CreateSymbolicLink(link, outside);
|
|
}
|
|
catch (Exception exception) when (
|
|
exception is UnauthorizedAccessException or IOException or PlatformNotSupportedException)
|
|
{
|
|
throw Xunit.Sdk.SkipException.ForSkip(
|
|
"The Windows test host does not permit creating a symbolic link.");
|
|
}
|
|
|
|
Assert.Throws<TrustedPlayoutAssetException>(() =>
|
|
TrustedPlayoutAssetPath.ResolveRelativeFile(
|
|
root.Path,
|
|
"linked\\studio.vrv",
|
|
Allowed));
|
|
}
|
|
|
|
[Fact]
|
|
public void EnsureOpenedRegularFile_BindsTheHandleToTheExpectedPath()
|
|
{
|
|
using var root = TemporarySceneDirectory.Create("expected.vrv", "other.vrv");
|
|
var expected = Path.Combine(root.Path, "expected.vrv");
|
|
var other = Path.Combine(root.Path, "other.vrv");
|
|
using var stream = new FileStream(
|
|
other,
|
|
FileMode.Open,
|
|
FileAccess.Read,
|
|
FileShare.Read);
|
|
|
|
Assert.Throws<TrustedPlayoutAssetException>(() =>
|
|
TrustedPlayoutAssetPath.EnsureOpenedRegularFile(
|
|
stream.SafeFileHandle,
|
|
expected));
|
|
}
|
|
|
|
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
private static extern bool CreateHardLinkW(
|
|
string fileName,
|
|
string existingFileName,
|
|
IntPtr securityAttributes);
|
|
}
|