package libp2pwebtransport import ( "context" "fmt" "net" "testing" ma "github.com/multiformats/go-multiaddr" "github.com/multiformats/go-multibase" "github.com/multiformats/go-multihash" "github.com/stretchr/testify/require" ) func TestWebtransportMultiaddr(t *testing.T) { t.Run("valid", func(t *testing.T) { addr, err := toWebtransportMultiaddr(&net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1337}) require.NoError(t, err) require.Equal(t, "/ip4/127.0.0.1/udp/1337/quic-v1/webtransport", addr.String()) }) t.Run("invalid", func(t *testing.T) { _, err := toWebtransportMultiaddr(&net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1337}) require.EqualError(t, err, "not a UDP address") }) } func TestWebtransportMultiaddrFromString(t *testing.T) { t.Run("valid", func(t *testing.T) { addr, err := stringToWebtransportMultiaddr("1.2.3.4:60042") require.NoError(t, err) require.Equal(t, "/ip4/1.2.3.4/udp/60042/quic-v1/webtransport", addr.String()) }) t.Run("invalid", func(t *testing.T) { for _, addr := range [...]string{ "1.2.3.4", // missing port "1.2.3.4:123456", // invalid port ":1234", // missing IP "foobar", } { _, err := stringToWebtransportMultiaddr(addr) require.Error(t, err) } }) } func encodeCertHash(t *testing.T, b []byte, mh uint64, mb multibase.Encoding) string { t.Helper() h, err := multihash.Encode(b, mh) require.NoError(t, err) str, err := multibase.Encode(mb, h) require.NoError(t, err) return str } func TestExtractCertHashes(t *testing.T) { fooHash := encodeCertHash(t, []byte("foo"), multihash.SHA2_256, multibase.Base58BTC) barHash := encodeCertHash(t, []byte("bar"), multihash.BLAKE2B_MAX, multibase.Base32) // valid cases for _, tc := range [...]struct { addr string hashes []string }{ {addr: "/ip4/127.0.0.1/udp/1234/quic-v1/webtransport"}, {addr: fmt.Sprintf("/ip4/127.0.0.1/udp/1234/quic-v1/webtransport/certhash/%s", fooHash), hashes: []string{"foo"}}, {addr: fmt.Sprintf("/ip4/127.0.0.1/udp/1234/quic-v1/webtransport/certhash/%s/certhash/%s", fooHash, barHash), hashes: []string{"foo", "bar"}}, } { ch, err := extractCertHashes(ma.StringCast(tc.addr)) require.NoError(t, err) require.Len(t, ch, len(tc.hashes)) for i, h := range tc.hashes { require.Equal(t, h, string(ch[i].Digest)) } } } func TestWebtransportResolve(t *testing.T) { testCases := []string{ "/dns4/example.com/udp/1337/quic-v1/webtransport", "/dnsaddr/example.com/udp/1337/quic-v1/webtransport", "/ip4/127.0.0.1/udp/1337/quic-v1/sni/example.com/webtransport", } tpt := &transport{} ctx := context.Background() for _, tc := range testCases { t.Run(tc, func(t *testing.T) { outMa, err := tpt.Resolve(ctx, ma.StringCast(tc)) require.NoError(t, err) sni, err := outMa[0].ValueForProtocol(ma.P_SNI) require.NoError(t, err) require.Equal(t, "example.com", sni) }) } t.Run("No sni", func(t *testing.T) { outMa, err := tpt.Resolve(ctx, ma.StringCast("/ip4/127.0.0.1/udp/1337/quic-v1/webtransport")) require.NoError(t, err) _, err = outMa[0].ValueForProtocol(ma.P_SNI) require.Error(t, err) }) } func TestIsWebtransportMultiaddr(t *testing.T) { fooHash := encodeCertHash(t, []byte("foo"), multihash.SHA2_256, multibase.Base58BTC) barHash := encodeCertHash(t, []byte("bar"), multihash.SHA2_256, multibase.Base58BTC) testCases := []struct { addr string want bool certhashCount int }{ {addr: "/ip4/1.2.3.4/udp/60042/quic-v1/webtransport", want: true}, {addr: "/ip4/1.2.3.4/udp/60042/quic-v1/webtransport/certhash/" + fooHash, want: true, certhashCount: 1}, {addr: "/ip4/1.2.3.4/udp/60042/quic-v1/webtransport/certhash/" + fooHash + "/certhash/" + barHash, want: true, certhashCount: 2}, {addr: "/dns4/example.com/udp/60042/quic-v1/webtransport/certhash/" + fooHash, want: true, certhashCount: 1}, {addr: "/dns4/example.com/udp/60042/webrtc/certhash/" + fooHash, want: false}, } for _, tc := range testCases { t.Run(tc.addr, func(t *testing.T) { got, n := IsWebtransportMultiaddr(ma.StringCast(tc.addr)) require.Equal(t, tc.want, got) require.Equal(t, tc.certhashCount, n) }) } }