Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

link_test.gno

5.35 Kb · 140 lines
  1package wesh
  2
  3import (
  4	"encoding/hex"
  5	"testing"
  6
  7	"gno.land/p/nym-moultest123/x/daily/b58/v0"
  8	"gno.land/p/nt/uassert/v0"
  9)
 10
 11// bertyGoldenBlob is the base58 payload from berty's own links_test.go
 12// ("simple-contact"), produced by MarshalLink from
 13// PublicRendezvousSeed = 16 x 0x01 and AccountPk = 16 x 0x02.
 14//
 15// It is the ground truth for this package's wire format. The keys are 16 bytes
 16// because that test predates the length rule, so the vector is checked against
 17// the raw encoder rather than through Contact.Blob, which would (correctly)
 18// reject them.
 19const bertyGoldenBlob = "3geQXHmsW9rxRfQFJdu8CEuPtWkfTWgJH13NzAoGatcnh4brusu3"
 20
 21func TestBlobEncodingMatchesBertyGoldenVector(t *testing.T) {
 22	id := appendBytesField(nil, fieldBertyIDSeed, repeat(0x01, 16))
 23	id = appendBytesField(id, fieldBertyIDAccountPK, repeat(0x02, 16))
 24	blob := appendBytesField(nil, fieldBertyLinkBertyID, id)
 25
 26	uassert.Equal(t,
 27		"12240a1001010101010101010101010101010101121002020202020202020202020202020202",
 28		hex.EncodeToString(blob),
 29		"protobuf wire bytes")
 30	uassert.Equal(t, bertyGoldenBlob, b58.Encode(blob), "base58 payload berty produces")
 31}
 32
 33// TestWebLink pins the full link for a real 32-byte identity.
 34func TestWebLink(t *testing.T) {
 35	c := Contact{
 36		AccountPK: mustHex(t, testAccountPKHex),
 37		Seed:      mustHex(t, testSeedHex),
 38	}
 39	link, err := c.WebLink()
 40	uassert.NoError(t, err)
 41	uassert.Equal(t,
 42		"https://berty.tech/id#contact/oZBLFpzghxrATkepWvDPNX9pHYqi6BWgP45xGWhqxcwmqN2bnMMbU7UcwUuTaCcDyUvMjmWRMDWcP96bXAndcjNiAZ1Vz9X",
 43		link)
 44}
 45
 46// TestWebLinkDisplayNameEscaping matches berty's url.Values encoding: space
 47// becomes '+', and everything outside the unreserved set is percent-escaped.
 48func TestWebLinkDisplayNameEscaping(t *testing.T) {
 49	c := Contact{
 50		AccountPK:   mustHex(t, testAccountPKHex),
 51		Seed:        mustHex(t, testSeedHex),
 52		DisplayName: "Hello World!",
 53	}
 54	link, err := c.WebLink()
 55	uassert.NoError(t, err)
 56	uassert.True(t, endsWith(link, "/name=Hello+World%21"), "display name is query-escaped: "+link)
 57}
 58
 59func TestWebLinkRoundTrip(t *testing.T) {
 60	cases := []struct {
 61		name string
 62		in   Contact
 63	}{
 64		{"no display name", Contact{AccountPK: repeat(0x11, 32), Seed: repeat(0x22, 32)}},
 65		{"with a display name", Contact{AccountPK: repeat(0x11, 32), Seed: repeat(0x22, 32), DisplayName: "gno support"}},
 66		{"name needing escapes", Contact{AccountPK: repeat(0x11, 32), Seed: repeat(0x22, 32), DisplayName: "a/b c&d=e"}},
 67		{"leading zero bytes", Contact{AccountPK: repeat(0x00, 32), Seed: repeat(0x00, 32)}},
 68	}
 69	for _, tc := range cases {
 70		link, err := tc.in.WebLink()
 71		uassert.NoError(t, err, tc.name)
 72
 73		got, err := ParseWebLink(link)
 74		uassert.NoError(t, err, tc.name)
 75		uassert.Equal(t, hex.EncodeToString(tc.in.AccountPK), hex.EncodeToString(got.AccountPK), tc.name+": account key")
 76		uassert.Equal(t, hex.EncodeToString(tc.in.Seed), hex.EncodeToString(got.Seed), tc.name+": seed")
 77		uassert.Equal(t, tc.in.DisplayName, got.DisplayName, tc.name+": display name")
 78	}
 79}
 80
 81func TestParseWebLinkRejects(t *testing.T) {
 82	valid, err := Contact{AccountPK: repeat(0x11, 32), Seed: repeat(0x22, 32)}.WebLink()
 83	uassert.NoError(t, err)
 84
 85	cases := []struct {
 86		name string
 87		in   string
 88		want error
 89	}{
 90		{"not a berty link", "https://example.com/id#contact/abc", ErrNotAWebLink},
 91		{"no payload segment", WebLinkPrefix + "contact", ErrNotAWebLink},
 92		{"a group link, not a contact", WebLinkPrefix + "group/" + b58.Encode([]byte{1, 2, 3}), ErrNotAContactLink},
 93		{"payload is not base58", WebLinkPrefix + "contact/not-base58-0OIl", ErrBadLinkPayload},
 94		{"payload is not a BertyLink", WebLinkPrefix + "contact/" + b58.Encode([]byte{0xff, 0xff}), ErrBadLinkPayload},
 95		{"berty's own 16-byte golden vector is too short now", WebLinkPrefix + "contact/" + bertyGoldenBlob, ErrBadSeedLen},
 96		{"truncated payload", valid[:len(valid)-8], ErrBadLinkPayload},
 97	}
 98	for _, tc := range cases {
 99		_, err := ParseWebLink(tc.in)
100		uassert.ErrorIs(t, err, tc.want, tc.name)
101	}
102}
103
104// TestParseWebLinkIgnoresUnknownQueryKeys matches berty's UnmarshalLink, which
105// accepts a link carrying query keys it does not know.
106func TestParseWebLinkIgnoresUnknownQueryKeys(t *testing.T) {
107	link, err := Contact{AccountPK: repeat(0x11, 32), Seed: repeat(0x22, 32)}.WebLink()
108	uassert.NoError(t, err)
109
110	got, err := ParseWebLink(link + "/foo=bar&name=Alice")
111	uassert.NoError(t, err)
112	uassert.Equal(t, "Alice", got.DisplayName)
113}
114
115// TestLookupBytesFieldSkipsOtherWireTypes covers the decoder's skip paths: a
116// varint, a 64-bit and a 32-bit field ahead of the one being looked up.
117func TestLookupBytesFieldSkipsOtherWireTypes(t *testing.T) {
118	buf := []byte{0x08, 0x96, 0x01} // field 1, varint 150
119	buf = append(buf, 0x11)         // field 2, 64-bit
120	buf = append(buf, repeat(0xaa, 8)...)
121	buf = append(buf, 0x1d) // field 3, 32-bit
122	buf = append(buf, repeat(0xbb, 4)...)
123	buf = appendBytesField(buf, 4, []byte("found"))
124
125	got, ok := lookupBytesField(buf, 4)
126	uassert.True(t, ok, "the length-delimited field is reachable past the others")
127	uassert.Equal(t, "found", string(got))
128
129	_, ok = lookupBytesField(buf, 9)
130	uassert.False(t, ok, "an absent field is reported missing, not guessed")
131}
132
133func TestBlobRejectsAnInvalidContact(t *testing.T) {
134	_, err := Contact{AccountPK: repeat(1, 31), Seed: repeat(2, 32)}.Blob()
135	uassert.ErrorIs(t, err, ErrBadAccountPKLen)
136}
137
138func endsWith(s, suffix string) bool {
139	return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
140}