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); } }