feat: harden isolated Tornado test workflow
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
using System.Text.Json;
|
||||
using MBN_STOCK_WEBVIEW.Core.Playout;
|
||||
|
||||
namespace MBN_STOCK_WEBVIEW.Core.Tests;
|
||||
|
||||
public sealed class PlayoutBridgeProtocolTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("https://app.mbn.local/index.html", true)]
|
||||
[InlineData("HTTPS://APP.MBN.LOCAL/path", true)]
|
||||
[InlineData("http://app.mbn.local/index.html", false)]
|
||||
[InlineData("https://app.mbn.local:444/index.html", false)]
|
||||
[InlineData("https://app.mbn.local@evil.example/index.html", false)]
|
||||
[InlineData("https://evil.example/index.html", false)]
|
||||
[InlineData("about:blank", false)]
|
||||
[InlineData("not-a-uri", false)]
|
||||
public void IsTrustedSource_RequiresTheExactHttpsDefaultPortOrigin(
|
||||
string source,
|
||||
bool expected)
|
||||
{
|
||||
Assert.Equal(
|
||||
expected,
|
||||
PlayoutBridgeProtocol.IsTrustedSource(source, "app.mbn.local"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("prepare", true)]
|
||||
[InlineData("next", true)]
|
||||
[InlineData("take-in", false)]
|
||||
[InlineData("take-out", false)]
|
||||
public void ParseCommand_AcceptsOnlyTheCommandSpecificCueShape(
|
||||
string command,
|
||||
bool hasCue)
|
||||
{
|
||||
var cue = hasCue ? ",\"cue\":{\"code\":\"5001\"}" : string.Empty;
|
||||
using var document = JsonDocument.Parse(
|
||||
$"{{\"requestId\":\"REQ_1\",\"command\":\"{command}\"{cue}}}");
|
||||
|
||||
var result = PlayoutBridgeProtocol.ParseCommand(document.RootElement);
|
||||
|
||||
Assert.True(result.IsValid);
|
||||
Assert.Equal("REQ_1", result.Request.RequestId);
|
||||
Assert.Equal(command, result.Request.Command);
|
||||
if (hasCue)
|
||||
{
|
||||
Assert.Equal("5001", result.Request.Cue?.SceneName);
|
||||
Assert.Equal("5001.t2s", result.Request.Cue?.SceneFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Null(result.Request.Cue);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("{\"requestId\":\"REQ\",\"command\":\"prepare\",\"cue\":{\"code\":\"../5001\"}}")]
|
||||
[InlineData("{\"requestId\":\"REQ\",\"command\":\"prepare\",\"cue\":{\"code\":\"5001\",\"title\":\"ignored\"}}")]
|
||||
[InlineData("{\"requestId\":\"REQ\",\"command\":\"take-in\",\"cue\":{\"code\":\"5001\"}}")]
|
||||
[InlineData("{\"requestId\":\"REQ\",\"command\":\"next\"}")]
|
||||
[InlineData("{\"requestId\":\"REQ\",\"command\":\"unknown\"}")]
|
||||
[InlineData("{\"requestId\":\"REQ\",\"requestId\":\"REQ2\",\"command\":\"take-out\"}")]
|
||||
[InlineData("{\"requestId\":\"REQ\",\"command\":\"take-out\",\"liveAuthorization\":true}")]
|
||||
public void ParseCommand_RejectsUnknownDuplicateOrUnsafeInput(string json)
|
||||
{
|
||||
using var document = JsonDocument.Parse(json);
|
||||
|
||||
var result = PlayoutBridgeProtocol.ParseCommand(document.RootElement);
|
||||
|
||||
Assert.False(result.IsValid);
|
||||
Assert.NotEmpty(result.Error);
|
||||
Assert.Null(result.Request.Cue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseCommand_DoesNotReflectAnUnsafeRequestIdentifier()
|
||||
{
|
||||
const string unsafeRequestId = "../../private-value";
|
||||
using var document = JsonDocument.Parse(
|
||||
$"{{\"requestId\":\"{unsafeRequestId}\",\"command\":\"take-out\"}}");
|
||||
|
||||
var result = PlayoutBridgeProtocol.ParseCommand(document.RootElement);
|
||||
|
||||
Assert.False(result.IsValid);
|
||||
Assert.Equal(string.Empty, result.Request.RequestId);
|
||||
Assert.DoesNotContain(unsafeRequestId, result.Error, StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user