github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/systests/sbs_test.go (about)

     1  package systests
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/keybase/client/go/teams"
     7  
     8  	"github.com/keybase/client/go/emails"
     9  
    10  	"github.com/keybase/client/go/externals"
    11  	"github.com/keybase/client/go/kbtest"
    12  	"github.com/keybase/client/go/libkb"
    13  	"github.com/keybase/client/go/phonenumbers"
    14  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    15  	"github.com/stretchr/testify/require"
    16  	context "golang.org/x/net/context"
    17  )
    18  
    19  func assertionFromKV(t *testing.T, key, value string) libkb.AssertionURL {
    20  	actx := externals.MakeStaticAssertionContext(context.TODO())
    21  	ret, err := libkb.ParseAssertionURLKeyValue(actx, key, value, true /* strict */)
    22  	require.NoError(t, err)
    23  	return ret
    24  }
    25  
    26  // Same SBS test can run against different SBS types, where each one has
    27  // different way of proving (verifying), revoking etc. Encapsulate all that
    28  // under a type that implements `userSBSProvider` and pass it to the "generic"
    29  // SBS test function.
    30  type userSBSProvider interface {
    31  	SetUser(user *userPlusDevice)
    32  	GetAssertionKV() (key string, value string)
    33  	Verify()
    34  	Revoke()
    35  }
    36  
    37  // Phone numbers
    38  type userSBSPhoneNumber struct {
    39  	u           *userPlusDevice
    40  	phoneNumber string // without `+`
    41  }
    42  
    43  func (p *userSBSPhoneNumber) SetUser(user *userPlusDevice) {
    44  	p.u = user
    45  	p.phoneNumber = kbtest.GenerateTestPhoneNumber()
    46  }
    47  
    48  func (p *userSBSPhoneNumber) GetAssertionKV() (key string, value string) {
    49  	return "phone", p.phoneNumber
    50  }
    51  
    52  func (p *userSBSPhoneNumber) Verify() {
    53  	mctx := p.u.MetaContext()
    54  	tctx := p.u.tc
    55  	phoneNumber := keybase1.PhoneNumber("+" + p.phoneNumber)
    56  	require.NoError(tctx.T, phonenumbers.AddPhoneNumber(mctx, phoneNumber, keybase1.IdentityVisibility_PUBLIC))
    57  	code, err := kbtest.GetPhoneVerificationCode(libkb.NewMetaContextTODO(tctx.G), phoneNumber)
    58  	require.NoError(tctx.T, err)
    59  	require.NoError(tctx.T, phonenumbers.VerifyPhoneNumber(mctx, phoneNumber, code))
    60  }
    61  
    62  func (p *userSBSPhoneNumber) Revoke() {
    63  	err := phonenumbers.DeletePhoneNumber(p.u.MetaContext(), keybase1.PhoneNumber("+"+p.phoneNumber))
    64  	require.NoError(p.u.tc.T, err)
    65  }
    66  
    67  // ------------------
    68  
    69  // Emails
    70  type userSBSEmail struct {
    71  	u *userPlusDevice
    72  }
    73  
    74  func (p *userSBSEmail) SetUser(user *userPlusDevice) {
    75  	p.u = user
    76  }
    77  
    78  func (p *userSBSEmail) GetAssertionKV() (key string, value string) {
    79  	return "email", p.u.userInfo.email
    80  }
    81  
    82  func (p *userSBSEmail) Verify() {
    83  	emailAddress := keybase1.EmailAddress(p.u.userInfo.email)
    84  	err := emails.SetVisibilityEmail(p.u.MetaContext(), emailAddress, keybase1.IdentityVisibility_PUBLIC)
    85  	require.NoError(p.u.tc.T, err)
    86  	err = kbtest.VerifyEmailAuto(p.u.MetaContext(), emailAddress)
    87  	require.NoError(p.u.tc.T, err)
    88  }
    89  
    90  func (p *userSBSEmail) Revoke() {
    91  	err := emails.DeleteEmail(p.u.MetaContext(), keybase1.EmailAddress(p.u.userInfo.email))
    92  	require.NoError(p.u.tc.T, err)
    93  }
    94  
    95  // ------------------
    96  
    97  // Rooter
    98  type userSBSRooter struct {
    99  	u *userPlusDevice
   100  }
   101  
   102  func (p *userSBSRooter) SetUser(user *userPlusDevice) {
   103  	p.u = user
   104  }
   105  
   106  func (p *userSBSRooter) GetAssertionKV() (key string, value string) {
   107  	return "rooter", p.u.username
   108  }
   109  
   110  func (p *userSBSRooter) Verify() {
   111  	p.u.proveRooter()
   112  }
   113  
   114  func (p *userSBSRooter) Revoke() {
   115  	p.u.revokeServiceProof("rooter")
   116  }
   117  
   118  // ------------------
   119  
   120  func testTeamInviteSBS(t *testing.T, sbs userSBSProvider) {
   121  	tt := newTeamTester(t)
   122  	defer tt.cleanup()
   123  
   124  	ann := tt.addUser("ann")
   125  	bob := tt.addUser("bob")
   126  	sbs.SetUser(bob)
   127  
   128  	// User 0 creates a team.
   129  	teamID, teamName := ann.createTeam2()
   130  
   131  	key, value := sbs.GetAssertionKV()
   132  	assertionURL := assertionFromKV(t, key, value)
   133  	assertion := assertionURL.String()
   134  
   135  	ann.addTeamMember(teamName.String(), assertion, keybase1.TeamRole_WRITER)
   136  
   137  	ann.kickTeamRekeyd()
   138  	sbs.Verify()
   139  
   140  	ann.waitForTeamChangedGregor(teamID, keybase1.Seqno(3))
   141  	bob.waitForTeamChangedGregor(teamID, keybase1.Seqno(3))
   142  
   143  	// The team should have user 1 in it now as a writer.
   144  	t0 := ann.loadTeam(teamName.String(), true /* admin */)
   145  	writers, err := t0.UsersWithRole(keybase1.TeamRole_WRITER)
   146  	require.NoError(t, err)
   147  	require.Len(t, writers, 1)
   148  	require.Equal(t, bob.uid, writers[0].Uid)
   149  
   150  	// The invite should not be in the active invite map.
   151  	require.Equal(t, 0, t0.NumActiveInvites())
   152  	exists, err := t0.HasActiveInvite(tt.users[0].tc.MetaContext(), keybase1.TeamInviteName(value), key)
   153  	require.NoError(t, err)
   154  	require.False(t, exists, "after accepting invite, active invite shouldn't exist")
   155  }
   156  
   157  func TestTeamInviteSBSPhone(t *testing.T) {
   158  	testTeamInviteSBS(t, &userSBSPhoneNumber{})
   159  }
   160  
   161  func TestTeamInviteSBSEmail(t *testing.T) {
   162  	testTeamInviteSBS(t, &userSBSEmail{})
   163  }
   164  
   165  func TestTeamInviteSBSRooter(t *testing.T) {
   166  	testTeamInviteSBS(t, &userSBSRooter{})
   167  }
   168  
   169  // ------------------
   170  
   171  func testTeamInviteExistingUserSBS(t *testing.T, sbs userSBSProvider) {
   172  	tt := newTeamTester(t)
   173  	defer tt.cleanup()
   174  
   175  	ann := tt.addUser("ann")
   176  	bob := tt.addUser("bob")
   177  	sbs.SetUser(bob)
   178  
   179  	key, value := sbs.GetAssertionKV()
   180  	assertionURL := assertionFromKV(t, key, value)
   181  	assertion := assertionURL.String()
   182  
   183  	sbs.Verify()
   184  
   185  	// User 0 creates a team.
   186  	_, teamName := ann.createTeam2()
   187  
   188  	// Add bob by SBS assertion. Should just add bob and not an invite. Adding
   189  	// resolvable SBS assertion via invite would also bounce off the server
   190  	// with `TEAM_INVITE_USER_EXISTS` error.
   191  	ann.addTeamMember(teamName.String(), assertion, keybase1.TeamRole_WRITER)
   192  
   193  	// The team should have user 1 in it now as a writer.
   194  	t0 := ann.loadTeam(teamName.String(), true /* admin */)
   195  	writers, err := t0.UsersWithRole(keybase1.TeamRole_WRITER)
   196  	require.NoError(t, err)
   197  	require.Len(t, writers, 1)
   198  	require.Equal(t, bob.uid, writers[0].Uid)
   199  
   200  	// There should be no invite for the SBS.
   201  	require.Equal(t, 0, t0.NumActiveInvites())
   202  	exists, err := t0.HasActiveInvite(tt.users[0].tc.MetaContext(), keybase1.TeamInviteName(value), key)
   203  	require.NoError(t, err)
   204  	require.False(t, exists, "after adding resolvable assertion, no invite should have been created")
   205  }
   206  
   207  func TestTeamInviteExistingUserSBSPhone(t *testing.T) {
   208  	testTeamInviteExistingUserSBS(t, &userSBSPhoneNumber{})
   209  }
   210  
   211  func TestTeamInviteExistingUserSBSEmail(t *testing.T) {
   212  	testTeamInviteExistingUserSBS(t, &userSBSEmail{})
   213  }
   214  
   215  func TestTeamInviteExistingUserSBSRooter(t *testing.T) {
   216  	testTeamInviteExistingUserSBS(t, &userSBSRooter{})
   217  }
   218  
   219  // ------------------
   220  
   221  func TestTeamInviteSBSError(t *testing.T) {
   222  	// Make sure we can't add invites for assertions if we can't attempt to
   223  	// resolve them.
   224  
   225  	tt := newTeamTester(t)
   226  	defer tt.cleanup()
   227  
   228  	ann := tt.addUser("ann")
   229  	bob := tt.addUser("bob")
   230  
   231  	ann.disableTOFUSearch()
   232  
   233  	teamID, teamName := ann.createTeam2()
   234  
   235  	sbsProviders := []userSBSProvider{
   236  		&userSBSEmail{},
   237  		&userSBSPhoneNumber{},
   238  	}
   239  
   240  	for _, sbs := range sbsProviders {
   241  		sbs.SetUser(bob)
   242  		sbs.Verify()
   243  
   244  		key, value := sbs.GetAssertionKV()
   245  		assertionURL := assertionFromKV(t, key, value)
   246  		assertion := assertionURL.String()
   247  
   248  		_, err := teams.AddMemberByID(context.TODO(), ann.tc.G, teamID, assertion, keybase1.TeamRole_WRITER, nil, nil /* emailInviteMsg */)
   249  		require.Error(t, err)
   250  		require.Contains(t, err.Error(), "error 602") // user cannot search for assertions
   251  	}
   252  
   253  	t0 := ann.loadTeam(teamName.String(), true /* admin */)
   254  	require.Equal(t, 0, t0.NumActiveInvites())
   255  }