namespace DodoSSH.Client.Session.Tests;
///
/// Reading a dodossh://spelunk/connect link, which anything on the machine can hand the application.
///
///
/// A link is data to check, never an instruction. The refusals below are the part that matters: each is a
/// link that is nearly right, and "nearly right" is the shape a crafted one takes.
///
public sealed class SpelunkLinkTests
{
private const string Server = "0192f0c8-bbbb-7c3d-8e4f-5a6b7c8d9e0b";
private const string Link =
"dodossh://spelunk/connect?api=https%3A%2F%2Fapi.spelunk.example.com&server=" + Server
+ "&name=web%2001&host=203.0.113.10";
[Fact]
public void ALinkFromSpelunk_IsRead()
{
SpelunkLink.TryParse(Link, out var link).ShouldBeTrue();
link.ShouldBe(new SpelunkLink("https://api.spelunk.example.com", Guid.Parse(Server), "web 01", "203.0.113.10"));
link.Hostname.ShouldBe("203.0.113.10");
}
[Fact]
public void ALinkWithNoHost_NamesTheHostAfterTheServer()
{
// The name the host key is pinned under, so it has to be stable and this server's alone.
SpelunkLink.TryParse(Link.Replace("&host=203.0.113.10", string.Empty, StringComparison.Ordinal), out var link)
.ShouldBeTrue();
link.Host.ShouldBeNull();
link.Hostname.ShouldBe($"spelunk-{Server}");
}
[Fact]
public void ALink_WritesOutAsItReadsBack()
{
// What a second launch sends the running instance: the one spelling this build writes.
SpelunkLink.TryParse(Link, out var link).ShouldBeTrue();
SpelunkLink.TryParse(link.ToString(), out var again).ShouldBeTrue();
again.ShouldBe(link);
}
[Fact]
public void ANameFormEncoded_AndOneWithControlCharacters_AreCleanedForDisplay()
{
SpelunkLink.TryParse(Link.Replace("web%2001", "web+01%0A%1B%5B31m", StringComparison.Ordinal), out var link)
.ShouldBeTrue();
link.Name.ShouldNotContain('\n');
link.Name.ShouldNotContain('\u001b');
link.Name.ShouldStartWith("web 01");
}
[Fact]
public void AnUnknownParameter_IsIgnored()
{
// So a newer Spelunk can add one without every DodoSSH already installed refusing its links.
SpelunkLink.TryParse(Link + "&port=22", out _).ShouldBeTrue();
}
[Theory]
[InlineData("https://spelunk/connect?api=https%3A%2F%2Fapi.example.com&server=" + Server)]
[InlineData("dodossh://elsewhere/connect?api=https%3A%2F%2Fapi.example.com&server=" + Server)]
[InlineData("dodossh://spelunk/disconnect?api=https%3A%2F%2Fapi.example.com&server=" + Server)]
[InlineData("dodossh://user@spelunk/connect?api=https%3A%2F%2Fapi.example.com&server=" + Server)]
[InlineData("dodossh://spelunk:8080/connect?api=https%3A%2F%2Fapi.example.com&server=" + Server)]
[InlineData("dodossh://spelunk/connect?api=https%3A%2F%2Fapi.example.com&server=" + Server + "#x")]
[InlineData("dodossh://spelunk/connect?server=" + Server)]
[InlineData("dodossh://spelunk/connect?api=https%3A%2F%2Fapi.example.com")]
[InlineData("dodossh://spelunk/connect?api=https%3A%2F%2Fapi.example.com&server=not-a-guid")]
[InlineData("dodossh://spelunk/connect?api=https%3A%2F%2Fapi.example.com&server=00000000-0000-0000-0000-000000000000")]
[InlineData("dodossh://spelunk/connect?api=http%3A%2F%2Fapi.example.com&server=" + Server)]
[InlineData("dodossh://spelunk/connect?api=https%3A%2F%2Fu%3Ap%40api.example.com&server=" + Server)]
[InlineData("dodossh://spelunk/connect?api=https%3A%2F%2Fapi.example.com&api=https%3A%2F%2Fevil.example&server=" + Server)]
[InlineData("dodossh://spelunk/connect?api=https%3A%2F%2Fapi.example.com&server=" + Server + "&host=bad%20host")]
[InlineData("dodossh://spelunk/connect?api=https%3A%2F%2Fapi.example.com&server=" + Server + "&name=a b")]
[InlineData("")]
public void ALinkThatIsNotExactlyThis_IsRefused(string text)
{
SpelunkLink.TryParse(text, out var link).ShouldBeFalse();
link.ShouldBeNull();
}
[Fact]
public void AnOverlongLink_IsRefusedBeforeItIsParsed()
{
SpelunkLink.TryParse(Link + "&name=" + new string('a', SpelunkLink.MaxLength), out _).ShouldBeFalse();
}
[Fact]
public void ANameThatRunsOn_IsCut()
{
SpelunkLink.TryParse(Link.Replace("web%2001", new string('a', 500), StringComparison.Ordinal), out var link)
.ShouldBeTrue();
link.Name.Length.ShouldBe(SpelunkLink.MaxNameLength);
}
[Theory]
[InlineData("dodossh://spelunk/connect", true)]
[InlineData("DODOSSH://anything", true)]
[InlineData("--veloapp-install", false)]
[InlineData(null, false)]
public void TheLauncher_TellsALinkFromAnotherArgument(string? argument, bool looksLikeOne)
{
SpelunkLink.LooksLikeOne(argument).ShouldBe(looksLikeOne);
}
}