github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/stellar/stellarsvc/lookup_test.go (about) 1 package stellarsvc 2 3 import ( 4 "fmt" 5 "net/url" 6 "testing" 7 8 "github.com/keybase/client/go/protocol/stellar1" 9 "github.com/keybase/client/go/stellar" 10 "github.com/keybase/client/go/stellar/stellarcommon" 11 "github.com/stellar/go/address" 12 proto "github.com/stellar/go/protocols/federation" 13 stellarErrors "github.com/stellar/go/support/errors" 14 "github.com/stretchr/testify/require" 15 ) 16 17 type FederationTestClient struct { 18 lookupAddr func(addy string) (*proto.NameResponse, error) 19 validServers map[string]bool 20 testResponses map[string]*proto.NameResponse 21 } 22 23 func (c *FederationTestClient) LookupByAddress(addy string) (*proto.NameResponse, error) { 24 if c.lookupAddr != nil { 25 return c.lookupAddr(addy) 26 } 27 28 _, domain, err := address.Split(addy) 29 if err != nil { 30 return nil, stellarErrors.Wrap(err, "parse address failed") 31 } 32 33 if _, ok := c.validServers[domain]; !ok { 34 return nil, fmt.Errorf("lookup federation server failed") 35 } 36 37 resp, ok := c.testResponses[addy] 38 if !ok { 39 return nil, fmt.Errorf("get federation failed") 40 } 41 42 return resp, nil 43 } 44 45 func (c *FederationTestClient) LookupByAccountID(aid string) (*proto.IDResponse, error) { 46 return nil, fmt.Errorf("not implemented") 47 } 48 49 func (c *FederationTestClient) ForwardRequest(domain string, fields url.Values) (*proto.NameResponse, error) { 50 return nil, fmt.Errorf("not implemented") 51 } 52 53 func TestLookupRecipientFederation(t *testing.T) { 54 tcs, cleanup := setupNTests(t, 1) 55 defer cleanup() 56 57 acceptDisclaimer(tcs[0]) 58 fAccounts := tcs[0].Backend.ImportAccountsForUser(tcs[0]) 59 60 randomPub, _ := randomStellarKeypair() 61 randomPubMemo, _ := randomStellarKeypair() 62 63 testClient := &FederationTestClient{ 64 validServers: make(map[string]bool), 65 testResponses: make(map[string]*proto.NameResponse), 66 } 67 68 testClient.validServers["stellar.org"] = true 69 testClient.testResponses["j*stellar.org"] = &proto.NameResponse{ 70 AccountID: randomPub.String(), 71 } 72 testClient.testResponses["memo*stellar.org"] = &proto.NameResponse{ 73 AccountID: randomPubMemo.String(), 74 MemoType: "hash", 75 Memo: proto.Memo{Value: "ABCDEFGHIJK"}, 76 } 77 testClient.testResponses["memonotype*stellar.org"] = &proto.NameResponse{ 78 AccountID: randomPubMemo.String(), 79 Memo: proto.Memo{Value: "123456"}, 80 } 81 tcsAtStellar := fmt.Sprintf("%s*stellar.org", tcs[0].Fu.Username) 82 testClient.testResponses[tcsAtStellar] = &proto.NameResponse{ 83 AccountID: fAccounts[0].accountID.String(), 84 } 85 86 tcs[0].G.GetStellar().(*stellar.Stellar).SetFederationClientForTest(testClient) 87 mctx := tcs[0].MetaContext() 88 89 // Test if we are correctly rewriting stellar-org errors. Instead 90 // of "error (404)" we'd rather see "record not found". 91 _, err := stellar.LookupRecipient(mctx, stellarcommon.RecipientInput("m*example.com"), false) 92 require.Error(t, err) 93 require.Contains(t, err.Error(), "example.com") 94 require.Contains(t, err.Error(), "does not respond to federation requests") 95 96 _, err = stellar.LookupRecipient(mctx, stellarcommon.RecipientInput("test1*stellar.org"), false) 97 require.Error(t, err) 98 require.Contains(t, err.Error(), "stellar.org") 99 require.Contains(t, err.Error(), "test1") 100 require.Contains(t, err.Error(), "did not find record") 101 102 res, err := stellar.LookupRecipient(mctx, stellarcommon.RecipientInput("j*stellar.org"), false) 103 require.NoError(t, err) 104 require.Nil(t, res.User) 105 require.Nil(t, res.Assertion) 106 require.NotNil(t, res.AccountID) 107 require.Nil(t, res.PublicMemo) 108 require.Nil(t, res.PublicMemoType) 109 require.EqualValues(t, randomPub, *res.AccountID) 110 111 res, err = stellar.LookupRecipient(mctx, stellarcommon.RecipientInput("memo*stellar.org"), false) 112 require.NoError(t, err) 113 require.Nil(t, res.User) 114 require.Nil(t, res.Assertion) 115 require.NotNil(t, res.AccountID) 116 require.EqualValues(t, randomPubMemo, *res.AccountID) 117 require.NotNil(t, res.PublicMemo) 118 require.NotNil(t, res.PublicMemoType) 119 require.Equal(t, "ABCDEFGHIJK", *res.PublicMemo) 120 require.Equal(t, "hash", *res.PublicMemoType) 121 122 // if they don't return a memo_type, it's an error 123 res, err = stellar.LookupRecipient(mctx, stellarcommon.RecipientInput("memonotype*stellar.org"), false) 124 require.Error(t, err) 125 require.Nil(t, res.User) 126 require.Nil(t, res.Assertion) 127 require.Nil(t, res.AccountID) 128 129 // We ask external server about federation address, we get account id back 130 // That account ID is the primary of a keybase user. 131 // LookupRecipient doesn't tell us that, but LookupUserByAccountID does. 132 res, err = stellar.LookupRecipient(mctx, stellarcommon.RecipientInput(tcsAtStellar), false) 133 require.NoError(t, err) 134 require.NotNil(t, res.AccountID) 135 require.EqualValues(t, fAccounts[0].accountID, *res.AccountID) 136 require.Nil(t, res.User) 137 uv, username, err := stellar.LookupUserByAccountID(mctx, stellar1.AccountID(res.AccountID.String())) 138 require.NoError(t, err) 139 require.EqualValues(t, tcs[0].Fu.Username, username) 140 require.Equal(t, tcs[0].Fu.GetUserVersion(), uv) 141 } 142 143 func TestLookupRecipientKeybaseFederation(t *testing.T) { 144 tcs, cleanup := setupNTests(t, 1) 145 defer cleanup() 146 147 testClient := &FederationTestClient{ 148 lookupAddr: func(addy string) (*proto.NameResponse, error) { 149 const unexpected = "unexpected federation client call" 150 require.Fail(t, unexpected) 151 return nil, fmt.Errorf(unexpected) 152 }, 153 } 154 155 tcs[0].G.GetStellar().(*stellar.Stellar).SetFederationClientForTest(testClient) 156 mctx := tcs[0].MetaContext() 157 158 // *keybase.io lookups should go directly to Keybase username 159 // lookups, because that's what our federation server does anyway, 160 // with the exception of federation server being server trust. So 161 // we skip fed lookup entirely and go with Keybase identify. 162 fedAddr := fmt.Sprintf("%s*keybase.io", tcs[0].Fu.Username) 163 res, err := stellar.LookupRecipient(mctx, stellarcommon.RecipientInput(fedAddr), false) 164 require.NoError(t, err) 165 require.NotNil(t, res.User) 166 require.EqualValues(t, tcs[0].Fu.Username, res.User.Username) 167 require.Equal(t, tcs[0].Fu.GetUserVersion(), res.User.UV) 168 }