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  }