Files
Rendezvous/tests/FinalFactory.Rendezvous.Tests/Contracts/TraversalTokenCodecTests.cs
KyuubiYoru cc5793f935
quality-gate / quality (push) Failing after 1m50s
quality-gate / container (push) Has been skipped
feat(release): add reproducible signed artifacts (#19)
2026-07-16 17:48:21 +02:00

75 lines
3.3 KiB
C#

using System.Text.Json;
using FinalFactory.Rendezvous.Client;
using FinalFactory.Rendezvous.Contracts;
namespace FinalFactory.Rendezvous.Tests.Contracts;
public sealed class TraversalTokenCodecTests
{
[Fact]
public void IntroductionTokenBindsAttemptAndRedactsTheFixedTicket()
{
JoinAttemptId attemptId = new(Guid.Parse("00000000-0000-0000-0000-000000000301"));
string authenticator = Credential('T');
string encoded = NatIntroductionTokenCodec.Encode(attemptId, authenticator);
Assert.Equal(NatIntroductionTokenCodec.EncodedLength, encoded.Length);
Assert.True(encoded.Length <= ContractLimits.LiteNetLibNatTokenMaxCharacters);
Assert.True(NatIntroductionTokenCodec.TryDecode(encoded, out NatIntroductionToken? decoded));
Assert.NotNull(decoded);
Assert.Equal(attemptId, decoded.AttemptId);
Assert.Equal(encoded, decoded.ConnectionTicket);
Assert.DoesNotContain(encoded, decoded.ToString(), StringComparison.Ordinal);
}
[Fact]
public void ConnectionTicketMatchesTheVersionedV1Vector()
{
using JsonDocument vector = JsonDocument.Parse(ContractTestFiles.Read("connection-ticket.json"));
JsonElement root = vector.RootElement;
JoinAttemptId attemptId = new(Guid.Parse(root.GetProperty("attemptId").GetString()!));
string authenticator = root.GetProperty("derivedAuthenticator").GetString()!;
string ticket = NatIntroductionTokenCodec.Encode(attemptId, authenticator);
Assert.Equal(root.GetProperty("connectionTicket").GetString(), ticket);
Assert.Equal(root.GetProperty("digest").GetString(), NatIntroductionTokenCodec.ComputeDigest(ticket));
}
[Fact]
public void IntroductionTokenRejectsNonCanonicalOrAlteredFields()
{
string valid = NatIntroductionTokenCodec.Encode(
new JoinAttemptId(Guid.Parse("abcdef00-0000-0000-0000-000000000302")),
Credential('T'));
Assert.False(NatIntroductionTokenCodec.TryDecode(null, out _));
Assert.False(NatIntroductionTokenCodec.TryDecode(valid[..^1], out _));
Assert.False(NatIntroductionTokenCodec.TryDecode(valid[..^1] + "!", out _));
Assert.False(NatIntroductionTokenCodec.TryDecode(new string('A', 43), out _));
}
[Fact]
public void DirectConnectionRequestRoundTripsFixedBoundedPayloadAndRedactsTicket()
{
JoinAttemptId attemptId = new(Guid.Parse("00000000-0000-0000-0000-000000000303"));
string ticket = Credential('D');
byte[] encoded = DirectConnectionRequestCodec.Encode(attemptId, ticket);
Assert.Equal(DirectConnectionRequestCodec.EncodedLength, encoded.Length);
Assert.True(DirectConnectionRequestCodec.TryDecode(encoded, out DirectConnectionRequest? decoded));
Assert.NotNull(decoded);
Assert.Equal(attemptId, decoded.AttemptId);
Assert.Equal(ticket, decoded.ConnectionTicket);
Assert.DoesNotContain(ticket, decoded.ToString(), StringComparison.Ordinal);
encoded[0] ^= 0xff;
Assert.False(DirectConnectionRequestCodec.TryDecode(encoded, out _));
Assert.False(DirectConnectionRequestCodec.TryDecode(encoded.AsSpan(1), out _));
}
private static string Credential(char value) => new(value, ContractLimits.DerivedCredentialCharacters);
}