github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/teams/member_test.go (about)

     1  package teams
     2  
     3  import (
     4  	"crypto/rand"
     5  	"encoding/hex"
     6  	"fmt"
     7  	"sort"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/keybase/client/go/engine"
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  	"golang.org/x/net/context"
    15  
    16  	"github.com/davecgh/go-spew/spew"
    17  	"github.com/keybase/client/go/emails"
    18  	"github.com/keybase/client/go/externals"
    19  	"github.com/keybase/client/go/kbtest"
    20  	"github.com/keybase/client/go/libkb"
    21  	"github.com/keybase/client/go/protocol/keybase1"
    22  	"github.com/keybase/clockwork"
    23  )
    24  
    25  func memberSetupWithID(t *testing.T) (libkb.TestContext, *kbtest.FakeUser, string, keybase1.TeamID) {
    26  	tc := SetupTest(t, "team", 1)
    27  
    28  	u, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
    29  	if err != nil {
    30  		t.Fatal(err)
    31  	}
    32  
    33  	name, ID := createTeam2(tc)
    34  
    35  	t.Logf("User name is: %s", u.Username)
    36  	t.Logf("Team name is: %s", name)
    37  	return tc, u, name.String(), ID
    38  }
    39  
    40  func memberSetup(t *testing.T) (libkb.TestContext, *kbtest.FakeUser, string) {
    41  	tc, u, name, _ := memberSetupWithID(t)
    42  	return tc, u, name
    43  }
    44  
    45  func memberSetupMultiple(t *testing.T) (tc libkb.TestContext, owner, otherA, otherB *kbtest.FakeUser, name string) {
    46  	tc, owner, otherA, otherB, teamName, _ := memberSetupMultipleWithTeamID(t)
    47  	return tc, owner, otherA, otherB, teamName.String()
    48  }
    49  
    50  func memberSetupMultipleWithTeamID(t *testing.T) (tc libkb.TestContext, owner, otherA, otherB *kbtest.FakeUser, name keybase1.TeamName, teamID keybase1.TeamID) {
    51  	tc = SetupTest(t, "team", 1)
    52  
    53  	for i, ptr := range []**kbtest.FakeUser{&otherA, &otherB, &owner} {
    54  		if i > 0 {
    55  			kbtest.Logout(tc)
    56  		}
    57  		user, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
    58  		require.NoError(t, err)
    59  		*ptr = user
    60  	}
    61  
    62  	name, teamID = createTeam2(tc)
    63  	t.Logf("Created team %q", name)
    64  
    65  	return tc, owner, otherA, otherB, name, teamID
    66  }
    67  
    68  // creates a root team and a subteam.  owner is the owner of root, otherA is an admin, otherB is just a user.
    69  // no members in subteam.
    70  func memberSetupSubteam(t *testing.T) (tc libkb.TestContext, owner, otherA, otherB *kbtest.FakeUser, root, sub string) {
    71  	tc, owner, otherA, otherB, root = memberSetupMultiple(t)
    72  
    73  	t.Logf("mss owner: %v", owner.Username)
    74  	t.Logf("mss otherA: %v", otherA.Username)
    75  	t.Logf("mss otherB: %v", otherB.Username)
    76  
    77  	// add otherA and otherB as admins to rootName
    78  	_, err := AddMember(context.TODO(), tc.G, root, otherA.Username, keybase1.TeamRole_ADMIN, nil)
    79  	require.NoError(t, err)
    80  
    81  	assertRole(tc, root, owner.Username, keybase1.TeamRole_OWNER)
    82  	assertRole(tc, root, otherA.Username, keybase1.TeamRole_ADMIN)
    83  	assertRole(tc, root, otherB.Username, keybase1.TeamRole_NONE)
    84  
    85  	// create a subteam
    86  	rootTeamName, err := keybase1.TeamNameFromString(root)
    87  	require.NoError(t, err)
    88  
    89  	subPart := "sub"
    90  	_, err = CreateSubteam(context.TODO(), tc.G, subPart, rootTeamName, keybase1.TeamRole_NONE /* addSelfAs */)
    91  	require.NoError(t, err)
    92  
    93  	sub = root + "." + subPart
    94  
    95  	// make sure owner, otherA, otherB are not members
    96  	assertRole(tc, sub, owner.Username, keybase1.TeamRole_NONE)
    97  	assertRole(tc, sub, otherA.Username, keybase1.TeamRole_NONE)
    98  	assertRole(tc, sub, otherB.Username, keybase1.TeamRole_NONE)
    99  
   100  	return tc, owner, otherA, otherB, root, sub
   101  }
   102  
   103  func TestMemberOwner(t *testing.T) {
   104  	tc, u, name := memberSetup(t)
   105  	defer tc.Cleanup()
   106  
   107  	assertRole(tc, name, u.Username, keybase1.TeamRole_OWNER)
   108  	assertRole(tc, name, "t_alice", keybase1.TeamRole_NONE)
   109  }
   110  
   111  type setRoleTest struct {
   112  	name        string //nolint
   113  	setRoleFunc func(ctx context.Context, g *libkb.GlobalContext, teamname, username string) error
   114  	afterRole   keybase1.TeamRole
   115  }
   116  
   117  func setRestrictedBotRole(ctx context.Context, g *libkb.GlobalContext, teamname, username string) error {
   118  	return SetRoleRestrictedBot(ctx, g, teamname, username, keybase1.TeamBotSettings{})
   119  }
   120  
   121  var setRoleTests = []setRoleTest{
   122  	{name: "owner", setRoleFunc: SetRoleOwner, afterRole: keybase1.TeamRole_OWNER},
   123  	{name: "admin", setRoleFunc: SetRoleAdmin, afterRole: keybase1.TeamRole_ADMIN},
   124  	{name: "writer", setRoleFunc: SetRoleWriter, afterRole: keybase1.TeamRole_WRITER},
   125  	{name: "reader", setRoleFunc: SetRoleReader, afterRole: keybase1.TeamRole_READER},
   126  	{name: "bot", setRoleFunc: SetRoleBot, afterRole: keybase1.TeamRole_BOT},
   127  	{name: "restricted_bot", setRoleFunc: setRestrictedBotRole, afterRole: keybase1.TeamRole_RESTRICTEDBOT},
   128  }
   129  
   130  func TestMemberSetRole(t *testing.T) {
   131  	for _, test := range setRoleTests {
   132  		testMemberSetRole(t, test)
   133  	}
   134  }
   135  
   136  func testMemberSetRole(t *testing.T, test setRoleTest) {
   137  	tc, owner, other, _, name := memberSetupMultiple(t)
   138  	defer tc.Cleanup()
   139  
   140  	if err := test.setRoleFunc(context.TODO(), tc.G, name, other.Username); err != nil {
   141  		t.Fatal(err)
   142  	}
   143  
   144  	assertRole(tc, name, owner.Username, keybase1.TeamRole_OWNER)
   145  	assertRole(tc, name, other.Username, test.afterRole)
   146  }
   147  
   148  func TestMemberAddOK(t *testing.T) {
   149  	tc, _, other, _, name := memberSetupMultiple(t)
   150  	defer tc.Cleanup()
   151  
   152  	assertRole(tc, name, other.Username, keybase1.TeamRole_NONE)
   153  
   154  	res, err := AddMember(context.TODO(), tc.G, name, other.Username, keybase1.TeamRole_READER, nil)
   155  	if err != nil {
   156  		t.Fatal(err)
   157  	}
   158  	if res.User.Username != other.Username {
   159  		t.Errorf("AddMember result username %q does not match arg username %q", res.User.Username, other.Username)
   160  	}
   161  
   162  	assertRole(tc, name, other.Username, keybase1.TeamRole_READER)
   163  
   164  	// second AddMember should return err
   165  	if _, err := AddMember(context.TODO(), tc.G, name, other.Username, keybase1.TeamRole_WRITER, nil); err == nil {
   166  		t.Errorf("second AddMember succeeded, should have failed since user already a member")
   167  	}
   168  
   169  	assertRole(tc, name, other.Username, keybase1.TeamRole_READER)
   170  }
   171  
   172  func TestMembersEdit(t *testing.T) {
   173  	tc, _, otherA, otherB, name, teamID := memberSetupMultipleWithTeamID(t)
   174  	defer tc.Cleanup()
   175  
   176  	assertRole(tc, name.String(), otherA.Username, keybase1.TeamRole_NONE)
   177  
   178  	_, err := AddMember(context.TODO(), tc.G, name.String(), otherA.Username, keybase1.TeamRole_READER, nil)
   179  	if err != nil {
   180  		t.Fatal(err)
   181  	}
   182  
   183  	assertRole(tc, name.String(), otherA.Username, keybase1.TeamRole_READER)
   184  
   185  	assertRole(tc, name.String(), otherB.Username, keybase1.TeamRole_NONE)
   186  
   187  	_, err = AddMember(context.TODO(), tc.G, name.String(), otherB.Username, keybase1.TeamRole_READER, nil)
   188  	if err != nil {
   189  		t.Fatal(err)
   190  	}
   191  
   192  	assertRole(tc, name.String(), otherB.Username, keybase1.TeamRole_READER)
   193  
   194  	rolePairA := keybase1.UserRolePair{
   195  		Assertion:   otherA.Username,
   196  		Role:        keybase1.TeamRole_READER,
   197  		BotSettings: nil,
   198  	}
   199  
   200  	rolePairB := keybase1.UserRolePair{
   201  		Assertion:   otherB.Username,
   202  		Role:        keybase1.TeamRole_ADMIN,
   203  		BotSettings: nil,
   204  	}
   205  
   206  	userRolePairs := []keybase1.UserRolePair{rolePairA, rolePairB}
   207  
   208  	res, err := EditMembers(context.TODO(), tc.G, teamID, userRolePairs)
   209  	require.NoError(t, err)
   210  	require.Empty(t, res.Failures)
   211  }
   212  
   213  func TestMemberAddBot(t *testing.T) {
   214  	tc, _, otherA, otherB, name := memberSetupMultiple(t)
   215  	defer tc.Cleanup()
   216  
   217  	team, err := GetForTestByStringName(context.TODO(), tc.G, name)
   218  	require.NoError(t, err)
   219  	err = team.Rotate(context.TODO(), keybase1.RotationType_HIDDEN)
   220  	require.NoError(t, err)
   221  
   222  	assertRole(tc, name, otherA.Username, keybase1.TeamRole_NONE)
   223  	assertRole(tc, name, otherB.Username, keybase1.TeamRole_NONE)
   224  
   225  	res, err := AddMember(context.TODO(), tc.G, name, otherA.Username, keybase1.TeamRole_BOT, nil)
   226  	require.NoError(t, err)
   227  	require.Equal(t, otherA.Username, res.User.Username)
   228  	assertRole(tc, name, otherA.Username, keybase1.TeamRole_BOT)
   229  
   230  	// When changing to a restricted bot, botSettings are required.
   231  	err = EditMember(context.TODO(), tc.G, name, otherA.Username, keybase1.TeamRole_RESTRICTEDBOT, nil)
   232  	require.Error(t, err)
   233  
   234  	err = EditMember(context.TODO(), tc.G, name, otherA.Username, keybase1.TeamRole_RESTRICTEDBOT, &keybase1.TeamBotSettings{Cmds: true})
   235  	require.NoError(t, err)
   236  	assertRole(tc, name, otherA.Username, keybase1.TeamRole_RESTRICTEDBOT)
   237  
   238  	// botSettings is required.
   239  	res, err = AddMember(context.TODO(), tc.G, name, otherB.Username, keybase1.TeamRole_RESTRICTEDBOT, nil)
   240  	require.Error(t, err)
   241  
   242  	res, err = AddMember(context.TODO(), tc.G, name, otherB.Username, keybase1.TeamRole_RESTRICTEDBOT,
   243  		&keybase1.TeamBotSettings{Mentions: true})
   244  	require.NoError(t, err)
   245  	require.Equal(t, otherB.Username, res.User.Username)
   246  	assertRole(tc, name, otherB.Username, keybase1.TeamRole_RESTRICTEDBOT)
   247  
   248  	// make sure the bot settings links are present
   249  	team, err = Load(context.TODO(), tc.G, keybase1.LoadTeamArg{
   250  		Name:        name,
   251  		ForceRepoll: true,
   252  	})
   253  	require.NoError(t, err)
   254  	teamBotSettings, err := team.TeamBotSettings()
   255  	require.NoError(t, err)
   256  	require.Len(t, teamBotSettings, 2)
   257  	require.Equal(t, keybase1.TeamBotSettings{Cmds: true}, teamBotSettings[otherA.GetUserVersion()])
   258  	require.Equal(t, keybase1.TeamBotSettings{Mentions: true}, teamBotSettings[otherB.GetUserVersion()])
   259  
   260  	// second AddMember should return err
   261  	_, err = AddMember(context.TODO(), tc.G, name, otherA.Username, keybase1.TeamRole_WRITER, nil)
   262  	require.Error(t, err)
   263  	assertRole(tc, name, otherA.Username, keybase1.TeamRole_RESTRICTEDBOT)
   264  
   265  	_, err = AddMember(context.TODO(), tc.G, name, otherB.Username, keybase1.TeamRole_WRITER, nil)
   266  	require.Error(t, err)
   267  	assertRole(tc, name, otherB.Username, keybase1.TeamRole_RESTRICTEDBOT)
   268  }
   269  
   270  func TestMemberAddInvalidRole(t *testing.T) {
   271  	tc, _, other, _, name := memberSetupMultiple(t)
   272  	defer tc.Cleanup()
   273  
   274  	if _, err := AddMember(context.TODO(), tc.G, name, other.Username, keybase1.TeamRole(8888), nil); err == nil {
   275  		t.Errorf("AddMember worked with invalid role")
   276  	}
   277  
   278  	assertRole(tc, name, other.Username, keybase1.TeamRole_NONE)
   279  }
   280  
   281  // getFindNextMerkleRootAfterRemoval calls out to teams.FindNextMerkleRootAfterRemoval, which is
   282  // a thin wrapper around libkb.FindNextMerkleRootAfterTeamRemoval.
   283  func getFindNextMerkleRootAfterRemoval(t *testing.T, tc libkb.TestContext, user *kbtest.FakeUser, id keybase1.TeamID, anyRoleAllowed bool) (res keybase1.NextMerkleRootRes, err error) {
   284  	m := libkb.NewMetaContextForTest(tc)
   285  	upak, _, err := tc.G.GetUPAKLoader().LoadV2(libkb.NewLoadUserArgWithMetaContext(m).WithUID(user.GetUID()))
   286  	require.NoError(t, err)
   287  	require.NotNil(t, upak)
   288  	var signingKey keybase1.KID
   289  	for kid, obj := range upak.Current.DeviceKeys {
   290  		if obj.Base.IsSibkey {
   291  			signingKey = kid
   292  			break
   293  		}
   294  	}
   295  	require.False(t, signingKey.IsNil())
   296  	return FindNextMerkleRootAfterRemoval(m, keybase1.FindNextMerkleRootAfterTeamRemovalBySigningKeyArg{
   297  		Uid:            user.GetUID(),
   298  		SigningKey:     signingKey,
   299  		IsPublic:       false,
   300  		Team:           id,
   301  		AnyRoleAllowed: anyRoleAllowed,
   302  	})
   303  }
   304  
   305  // Check that `libkb.FindNextMerkleRootAfterTeamRemoval` works. To do so,
   306  // find the logpoint on the team where the user was removed, and pass it in.
   307  // Check for success simply by asserting that the Merkle Root seqno bumps
   308  // forward after the removal went into the team sigchain.
   309  func pollForNextMerkleRootAfterRemovalViaLibkb(t *testing.T, tc libkb.TestContext, user *kbtest.FakeUser, teamName string) (tid keybase1.TeamID, seqno keybase1.Seqno) {
   310  
   311  	m := libkb.NewMetaContextForTest(tc)
   312  	team, err := GetForTestByStringName(context.TODO(), tc.G, teamName)
   313  	require.NoError(t, err)
   314  	logPoint := team.chain().GetUserLogPoint(user.GetUserVersion())
   315  	require.NotNil(t, logPoint)
   316  
   317  	var delay time.Duration
   318  
   319  	// Unfortunately we need to poll here, since we don't know when merkled will mint a new root.
   320  	// Locally it is fast, but it might be slowish on CI.
   321  	for i := 0; i < 50; i++ {
   322  		res, err := libkb.FindNextMerkleRootAfterTeamRemoval(m, keybase1.FindNextMerkleRootAfterTeamRemovalArg{
   323  			Uid:               user.GetUID(),
   324  			Team:              team.ID,
   325  			IsPublic:          team.IsPublic(),
   326  			TeamSigchainSeqno: logPoint.SigMeta.SigChainLocation.Seqno,
   327  			Prev:              logPoint.SigMeta.PrevMerkleRootSigned,
   328  		})
   329  
   330  		// Success case!
   331  		if err == nil {
   332  			require.NotNil(t, res.Res)
   333  			require.True(t, res.Res.Seqno > logPoint.SigMeta.PrevMerkleRootSigned.Seqno)
   334  			return team.ID, res.Res.Seqno
   335  		}
   336  
   337  		if merr, ok := err.(libkb.MerkleClientError); ok && merr.IsNotFound() {
   338  			t.Logf("Failed to find a root, trying again to wait for merkled")
   339  		} else {
   340  			require.NoError(t, err)
   341  			return tid, seqno
   342  		}
   343  
   344  		if delay < time.Second {
   345  			delay += 10 * time.Millisecond
   346  		}
   347  		t.Logf("sleeping %v", delay)
   348  		time.Sleep(delay)
   349  	}
   350  	t.Fatalf("failed to find a suitable merkle root with team removal")
   351  	return tid, seqno
   352  }
   353  
   354  func TestMemberRemoveReader(t *testing.T) {
   355  	tc, owner, other, _, name := memberSetupMultiple(t)
   356  	defer tc.Cleanup()
   357  
   358  	anyRoleAllowed := true
   359  	if err := SetRoleReader(context.TODO(), tc.G, name, other.Username); err != nil {
   360  		t.Fatal(err)
   361  	}
   362  	assertRole(tc, name, owner.Username, keybase1.TeamRole_OWNER)
   363  	assertRole(tc, name, other.Username, keybase1.TeamRole_READER)
   364  
   365  	if err := RemoveMember(context.TODO(), tc.G, name, other.Username); err != nil {
   366  		t.Fatal(err)
   367  	}
   368  	assertRole(tc, name, owner.Username, keybase1.TeamRole_OWNER)
   369  	assertRole(tc, name, other.Username, keybase1.TeamRole_NONE)
   370  
   371  	teamID, expectedSeqno := pollForNextMerkleRootAfterRemovalViaLibkb(t, tc, other, name)
   372  	res, err := getFindNextMerkleRootAfterRemoval(t, tc, other, teamID, anyRoleAllowed)
   373  
   374  	require.NoError(t, err)
   375  	require.NotNil(t, res.Res)
   376  	require.Equal(t, res.Res.Seqno, expectedSeqno)
   377  }
   378  
   379  // Set up log points for a user in a team with roles of
   380  // Writer->Reader->Writer->Reader and verify that the first merkle root
   381  // after the last demotion from writer points to the last sequence number.
   382  func TestMemberRemoveWriter(t *testing.T) {
   383  	tc, owner, other, _, name := memberSetupMultiple(t)
   384  	defer tc.Cleanup()
   385  
   386  	anyRoleAllowed := false
   387  	if err := SetRoleWriter(context.TODO(), tc.G, name, other.Username); err != nil {
   388  		t.Fatal(err)
   389  	}
   390  	assertRole(tc, name, owner.Username, keybase1.TeamRole_OWNER)
   391  	assertRole(tc, name, other.Username, keybase1.TeamRole_WRITER)
   392  
   393  	if err := SetRoleReader(context.TODO(), tc.G, name, other.Username); err != nil {
   394  		t.Fatal(err)
   395  	}
   396  	assertRole(tc, name, other.Username, keybase1.TeamRole_READER)
   397  
   398  	if err := SetRoleWriter(context.TODO(), tc.G, name, other.Username); err != nil {
   399  		t.Fatal(err)
   400  	}
   401  	assertRole(tc, name, other.Username, keybase1.TeamRole_WRITER)
   402  
   403  	if err := SetRoleReader(context.TODO(), tc.G, name, other.Username); err != nil {
   404  		t.Fatal(err)
   405  	}
   406  	assertRole(tc, name, owner.Username, keybase1.TeamRole_OWNER)
   407  	assertRole(tc, name, other.Username, keybase1.TeamRole_READER)
   408  
   409  	teamID, expectedSeqno := pollForNextMerkleRootAfterRemovalViaLibkb(t, tc, other, name)
   410  	res, err := getFindNextMerkleRootAfterRemoval(t, tc, other, teamID, anyRoleAllowed)
   411  
   412  	require.NoError(t, err)
   413  	require.NotNil(t, res.Res)
   414  	require.Equal(t, res.Res.Seqno, expectedSeqno)
   415  }
   416  
   417  func TestMemberRemoveWithoutDemotion(t *testing.T) {
   418  	tc, owner, other, _, name := memberSetupMultiple(t)
   419  	defer tc.Cleanup()
   420  
   421  	anyRoleAllowed := true
   422  	if err := SetRoleWriter(context.TODO(), tc.G, name, other.Username); err != nil {
   423  		t.Fatal(err)
   424  	}
   425  	assertRole(tc, name, owner.Username, keybase1.TeamRole_OWNER)
   426  	assertRole(tc, name, other.Username, keybase1.TeamRole_WRITER)
   427  
   428  	team, err := GetForTestByStringName(context.TODO(), tc.G, name)
   429  	require.NoError(t, err)
   430  	res, err := getFindNextMerkleRootAfterRemoval(t, tc, other, team.ID, anyRoleAllowed)
   431  
   432  	require.Nil(t, res.Res)
   433  	require.Error(t, err)
   434  	require.IsType(t, libkb.NotFoundError{}, err)
   435  }
   436  
   437  func TestMembersRemove(t *testing.T) {
   438  	tc, _, otherA, otherB, name, teamID := memberSetupMultipleWithTeamID(t)
   439  	defer tc.Cleanup()
   440  
   441  	assertRole(tc, name.String(), otherA.Username, keybase1.TeamRole_NONE)
   442  
   443  	_, err := AddMember(context.TODO(), tc.G, name.String(), otherA.Username, keybase1.TeamRole_READER, nil)
   444  	if err != nil {
   445  		t.Fatal(err)
   446  	}
   447  
   448  	assertRole(tc, name.String(), otherA.Username, keybase1.TeamRole_READER)
   449  
   450  	assertRole(tc, name.String(), otherB.Username, keybase1.TeamRole_NONE)
   451  
   452  	_, err = AddMember(context.TODO(), tc.G, name.String(), otherB.Username, keybase1.TeamRole_READER, nil)
   453  	if err != nil {
   454  		t.Fatal(err)
   455  	}
   456  
   457  	assertRole(tc, name.String(), otherB.Username, keybase1.TeamRole_READER)
   458  
   459  	rolePairA := keybase1.NewTeamMemberToRemoveWithAssertion(keybase1.AssertionTeamMemberToRemove{
   460  		Assertion:         otherA.Username,
   461  		RemoveFromSubtree: false,
   462  	})
   463  	rolePairB := keybase1.NewTeamMemberToRemoveWithAssertion(keybase1.AssertionTeamMemberToRemove{
   464  		Assertion:         otherB.Username,
   465  		RemoveFromSubtree: false,
   466  	})
   467  
   468  	users := []keybase1.TeamMemberToRemove{rolePairA, rolePairB}
   469  
   470  	res, err := RemoveMembers(context.TODO(), tc.G, teamID, users, false)
   471  
   472  	assertRole(tc, name.String(), otherA.Username, keybase1.TeamRole_NONE)
   473  	assertRole(tc, name.String(), otherB.Username, keybase1.TeamRole_NONE)
   474  
   475  	require.NoError(t, err)
   476  	require.Empty(t, res.Failures)
   477  }
   478  
   479  // make sure that adding a member creates new recipient boxes
   480  func TestMemberAddHasBoxes(t *testing.T) {
   481  	tc, owner, other, _, name := memberSetupMultiple(t)
   482  	defer tc.Cleanup()
   483  
   484  	assertRole(tc, name, owner.Username, keybase1.TeamRole_OWNER)
   485  	assertRole(tc, name, other.Username, keybase1.TeamRole_NONE)
   486  
   487  	// this change request should generate boxes since other.Username
   488  	// is not a member
   489  	req := keybase1.TeamChangeReq{Readers: []keybase1.UserVersion{other.GetUserVersion()}}
   490  	tm, err := GetForTestByStringName(context.TODO(), tc.G, name)
   491  	if err != nil {
   492  		t.Fatal(err)
   493  	}
   494  
   495  	_, boxes, _, _, _, _, err := tm.changeMembershipSection(context.TODO(), req, false /* skipKeyRotation */)
   496  	if err != nil {
   497  		t.Fatal(err)
   498  	}
   499  	if boxes == nil || len(boxes.Boxes) == 0 {
   500  		t.Errorf("add member failed to make new boxes")
   501  	}
   502  }
   503  
   504  // make sure that changing a role does not send new boxes for the
   505  // member to the server
   506  func TestMemberChangeRoleNoBoxes(t *testing.T) {
   507  	tc, owner, other, _, name := memberSetupMultiple(t)
   508  	defer tc.Cleanup()
   509  
   510  	assertRole(tc, name, owner.Username, keybase1.TeamRole_OWNER)
   511  	assertRole(tc, name, other.Username, keybase1.TeamRole_NONE)
   512  
   513  	// add other.Username as a writer
   514  	if err := SetRoleWriter(context.TODO(), tc.G, name, other.Username); err != nil {
   515  		t.Fatal(err)
   516  	}
   517  
   518  	assertRole(tc, name, owner.Username, keybase1.TeamRole_OWNER)
   519  	assertRole(tc, name, other.Username, keybase1.TeamRole_WRITER)
   520  
   521  	// this change request shouldn't generate any new boxes
   522  	req := keybase1.TeamChangeReq{Readers: []keybase1.UserVersion{other.GetUserVersion()}}
   523  	tm, err := GetForTestByStringName(context.TODO(), tc.G, name)
   524  	if err != nil {
   525  		t.Fatal(err)
   526  	}
   527  
   528  	_, boxes, _, _, _, _, err := tm.changeMembershipSection(context.TODO(), req, false /* skipKeyRotation */)
   529  	if err != nil {
   530  		t.Fatal(err)
   531  	}
   532  	if boxes != nil && len(boxes.Boxes) > 0 {
   533  		t.Errorf("change role made new boxes: %+v", boxes)
   534  	}
   535  }
   536  
   537  func TestMemberRemoveRotatesKeys(t *testing.T) {
   538  	tc, owner, other, _, name := memberSetupMultiple(t)
   539  	defer tc.Cleanup()
   540  
   541  	before, err := GetForTestByStringName(context.TODO(), tc.G, name)
   542  	if err != nil {
   543  		t.Fatal(err)
   544  	}
   545  	if before.Generation() != 1 {
   546  		t.Fatalf("initial team generation: %d, expected 1", before.Generation())
   547  	}
   548  
   549  	if err := SetRoleWriter(context.TODO(), tc.G, name, other.Username); err != nil {
   550  		t.Fatal(err)
   551  	}
   552  	if err := RemoveMember(context.TODO(), tc.G, name, other.Username); err != nil {
   553  		t.Fatal(err)
   554  	}
   555  
   556  	assertRole(tc, name, owner.Username, keybase1.TeamRole_OWNER)
   557  	assertRole(tc, name, other.Username, keybase1.TeamRole_NONE)
   558  
   559  	after, err := GetForTestByStringName(context.TODO(), tc.G, name)
   560  	if err != nil {
   561  		t.Fatal(err)
   562  	}
   563  	if after.Generation() != 2 {
   564  		t.Errorf("after member remove: team generation: %d, expected 2", after.Generation())
   565  	}
   566  
   567  	secretAfter := after.Data.PerTeamKeySeedsUnverified[after.Generation()].Seed.ToBytes()
   568  	secretBefore := before.Data.PerTeamKeySeedsUnverified[before.Generation()].Seed.ToBytes()
   569  	if libkb.SecureByteArrayEq(secretAfter, secretBefore) {
   570  		t.Error("Team secret did not change when member removed")
   571  	}
   572  }
   573  
   574  func TestMemberAddNotAUser(t *testing.T) {
   575  	tc, _, name := memberSetup(t)
   576  	defer tc.Cleanup()
   577  
   578  	tc.G.SetProofServices(externals.NewProofServices(tc.G))
   579  
   580  	_, err := AddMember(context.TODO(), tc.G, name, "not_a_kb_user", keybase1.TeamRole_READER, nil)
   581  	if err == nil {
   582  		t.Fatal("Added a non-keybase username to a team")
   583  	}
   584  	if _, ok := err.(libkb.NotFoundError); !ok {
   585  		t.Errorf("error: %s (%T), expected libkb.NotFoundError", err, err)
   586  	}
   587  }
   588  
   589  func TestMemberAddSocial(t *testing.T) {
   590  	tc, _, name := memberSetup(t)
   591  	defer tc.Cleanup()
   592  
   593  	tc.G.SetProofServices(externals.NewProofServices(tc.G))
   594  
   595  	_, err := AddMember(context.TODO(), tc.G, name, "not_on_kb_yet@twitter", keybase1.TeamRole_OWNER, nil)
   596  	require.Error(t, err, "should not be able to invite a social user as an owner")
   597  
   598  	res, err := AddMember(context.TODO(), tc.G, name, "not_on_kb_yet@twitter", keybase1.TeamRole_READER, nil)
   599  	require.NoError(t, err)
   600  	require.True(t, res.Invited)
   601  
   602  	assertInvite(tc, name, "not_on_kb_yet", "twitter", keybase1.TeamRole_READER)
   603  
   604  	// second AddMember should return err
   605  	_, err = AddMember(context.TODO(), tc.G, name, "not_on_kb_yet@twitter", keybase1.TeamRole_WRITER, nil)
   606  	require.Error(t, err, "second AddMember should fail since user already invited")
   607  
   608  	// existing invite should be untouched
   609  	assertInvite(tc, name, "not_on_kb_yet", "twitter", keybase1.TeamRole_READER)
   610  }
   611  
   612  // add user without puk to a team, should create invite link
   613  func TestMemberAddNoPUK(t *testing.T) {
   614  	tc, _, name := memberSetup(t)
   615  	defer tc.Cleanup()
   616  
   617  	inviteNoPUK := func(username string, uid keybase1.UID, role keybase1.TeamRole) {
   618  
   619  		res, err := AddMember(context.TODO(), tc.G, name, username, role, nil)
   620  		if err != nil {
   621  			t.Fatal(err)
   622  		}
   623  		if !res.Invited {
   624  			t.Fatal("res.Invited should be set")
   625  		}
   626  		if res.User.Username != username {
   627  			t.Errorf("AddMember result username %q does not match arg username %q", res.User.Username, username)
   628  		}
   629  
   630  		fqUID := string(uid) + "%1"
   631  		assertInvite(tc, name, fqUID, "keybase", role)
   632  
   633  		// second AddMember should return err
   634  		if _, err := AddMember(context.TODO(), tc.G, name, username, keybase1.TeamRole_WRITER, nil); err == nil {
   635  			t.Errorf("second AddMember succeeded, should have failed since user already invited")
   636  		}
   637  
   638  		// existing invite should be untouched
   639  		assertInvite(tc, name, fqUID, "keybase", role)
   640  	}
   641  
   642  	inviteNoPUK("t_alice", keybase1.UID("295a7eea607af32040647123732bc819"), keybase1.TeamRole_READER)
   643  
   644  	// Disabled until we back out CORE-6170
   645  	// inviteNoPUK("t_bob", keybase1.UID("afb5eda3154bc13c1df0189ce93ba119"), keybase1.TeamRole_OWNER)
   646  }
   647  
   648  // add user without keys to a team, should create invite link
   649  func TestMemberAddNoKeys(t *testing.T) {
   650  	tc, _, name := memberSetup(t)
   651  	defer tc.Cleanup()
   652  
   653  	username := "t_ellen"
   654  	res, err := AddMember(context.TODO(), tc.G, name, username, keybase1.TeamRole_READER, nil)
   655  	if err != nil {
   656  		t.Fatal(err)
   657  	}
   658  	if !res.Invited {
   659  		t.Fatal("res.Invited should be set")
   660  	}
   661  	if res.User.Username != username {
   662  		t.Errorf("AddMember result username %q does not match arg username %q", res.User.Username, username)
   663  	}
   664  
   665  	assertInvite(tc, name, "561247eb1cc3b0f5dc9d9bf299da5e19%0", "keybase", keybase1.TeamRole_READER)
   666  
   667  	// second AddMember should return err
   668  	if _, err := AddMember(context.TODO(), tc.G, name, username, keybase1.TeamRole_WRITER, nil); err == nil {
   669  		t.Errorf("second AddMember succeeded, should have failed since user already invited")
   670  	}
   671  
   672  	// existing invite should be untouched
   673  	assertInvite(tc, name, "561247eb1cc3b0f5dc9d9bf299da5e19%0", "keybase", keybase1.TeamRole_READER)
   674  
   675  	// this is a keybase user, so they should show up in the member list
   676  	// even though they are technically only "invited"
   677  	details, err := Details(context.TODO(), tc.G, name)
   678  	if err != nil {
   679  		t.Fatal(err)
   680  	}
   681  	found := false
   682  	for _, m := range details.Members.Readers {
   683  		if m.Username == username {
   684  			found = true
   685  			break
   686  		}
   687  		t.Logf("not a match: %s != %s", m.Username, username)
   688  	}
   689  	if !found {
   690  		t.Fatal("keybase invited user not in membership list")
   691  	}
   692  }
   693  
   694  func TestMemberDetailsResetAndDeletedUser(t *testing.T) {
   695  	tc, owner, otherA, otherB, name := memberSetupMultiple(t)
   696  	defer tc.Cleanup()
   697  
   698  	tc.G.UIDMapper.SetTestingNoCachingMode(true)
   699  	_, err := AddMember(context.TODO(), tc.G, name, otherA.Username, keybase1.TeamRole_ADMIN, nil)
   700  	require.NoError(t, err)
   701  
   702  	_, err = AddMember(context.TODO(), tc.G, name, otherB.Username, keybase1.TeamRole_ADMIN, nil)
   703  	require.NoError(t, err)
   704  
   705  	details, err := Details(context.TODO(), tc.G, name)
   706  	require.NoError(t, err)
   707  
   708  	require.Len(t, details.Members.Admins, 2)
   709  	for _, admin := range details.Members.Admins {
   710  		require.Equal(t, admin.Status, keybase1.TeamMemberStatus_ACTIVE)
   711  	}
   712  
   713  	// Logout owner
   714  	kbtest.Logout(tc)
   715  
   716  	err = otherA.Login(tc.G)
   717  	require.NoError(t, err)
   718  	kbtest.ResetAccount(tc, otherA)
   719  
   720  	err = otherB.Login(tc.G)
   721  	require.NoError(t, err)
   722  	kbtest.DeleteAccount(tc, otherB)
   723  
   724  	err = owner.Login(tc.G)
   725  	require.NoError(t, err)
   726  
   727  	details, err = Details(context.TODO(), tc.G, name)
   728  	require.NoError(t, err)
   729  
   730  	require.Len(t, details.Members.Admins, 1)
   731  	require.Equal(t, otherA.Username, details.Members.Admins[0].Username)
   732  	require.Equal(t, keybase1.TeamMemberStatus_RESET, details.Members.Admins[0].Status)
   733  }
   734  
   735  func TestMemberAddEmail(t *testing.T) {
   736  	tc, _, name, teamID := memberSetupWithID(t)
   737  	defer tc.Cleanup()
   738  
   739  	address := "noone@keybase.io"
   740  
   741  	if err := InviteEmailPhoneMember(context.TODO(), tc.G, teamID, address, "email", keybase1.TeamRole_OWNER); err == nil {
   742  		t.Fatal("should not be able to invite an owner over email")
   743  	}
   744  
   745  	if err := InviteEmailPhoneMember(context.TODO(), tc.G, teamID, address, "email", keybase1.TeamRole_READER); err != nil {
   746  		t.Fatal(err)
   747  	}
   748  
   749  	assertInvite(tc, name, address, "email", keybase1.TeamRole_READER)
   750  
   751  	// second InviteEmailPhoneMember should return err
   752  	if err := InviteEmailPhoneMember(context.TODO(), tc.G, teamID, address, "email", keybase1.TeamRole_WRITER); err == nil {
   753  		t.Errorf("second InviteEmailMember succeeded, should have failed since user already invited")
   754  	}
   755  
   756  	// existing invite should be untouched
   757  	assertInvite(tc, name, address, "email", keybase1.TeamRole_READER)
   758  
   759  	details, err := Details(context.TODO(), tc.G, name)
   760  	if err != nil {
   761  		t.Fatal(err)
   762  	}
   763  	found := false
   764  	for _, invite := range details.AnnotatedActiveInvites {
   765  		if invite.TeamName == name && string(invite.InviteMetadata.Invite.Name) == address {
   766  			found = true
   767  		}
   768  	}
   769  	if !found {
   770  		t.Fatal("List team does not list invite.")
   771  	}
   772  }
   773  
   774  func TestMemberAddEmailBulk(t *testing.T) {
   775  	tc, _, name := memberSetup(t)
   776  	defer tc.Cleanup()
   777  
   778  	existingUserEmail := kbtest.GenerateRandomEmailAddress()
   779  	blob := string(existingUserEmail) + ", h@j.k,u1@keybase.io, u2@keybase.io\nu3@keybase.io,u4@keybase.io, u5@keybase.io,u6@keybase.io, u7@keybase.io\n\n\nFull Name <fullname@keybase.io>, Someone Else <someone@keybase.io>,u8@keybase.io\n\nXXXXXXXXXXXX"
   780  
   781  	// Create a user with a searchable email to test addEmailsBulk resolves
   782  	// existing users correctly.
   783  	tc2 := SetupTest(t, "team", 1)
   784  	u2, err := kbtest.CreateAndSignupFakeUser("team", tc2.G)
   785  	require.NoError(t, err)
   786  	err = emails.AddEmail(tc2.MetaContext(), existingUserEmail, keybase1.IdentityVisibility_PUBLIC)
   787  	require.NoError(t, err)
   788  	err = kbtest.VerifyEmailAuto(tc2.MetaContext(), existingUserEmail)
   789  	require.NoError(t, err)
   790  
   791  	res, err := AddEmailsBulk(context.TODO(), tc.G, name, blob, keybase1.TeamRole_WRITER)
   792  	if err != nil {
   793  		t.Fatal(err)
   794  	}
   795  	emails := []string{"u1@keybase.io", "u2@keybase.io", "u3@keybase.io", "u4@keybase.io", "u5@keybase.io", "u6@keybase.io", "u7@keybase.io", "fullname@keybase.io", "someone@keybase.io", "u8@keybase.io"}
   796  
   797  	require.Len(t, res.Malformed, 2)
   798  	for _, e := range emails {
   799  		assertInvite(tc, name, e, "email", keybase1.TeamRole_WRITER)
   800  	}
   801  
   802  	assertRole(tc, name, u2.Username, keybase1.TeamRole_WRITER)
   803  }
   804  
   805  func TestMemberListInviteUsername(t *testing.T) {
   806  	tc, user, name := memberSetup(t)
   807  	defer tc.Cleanup()
   808  
   809  	username := "t_ellen"
   810  	res, err := AddMember(context.TODO(), tc.G, name, username, keybase1.TeamRole_READER, nil)
   811  	require.NoError(t, err)
   812  	require.True(t, res.Invited)
   813  	require.Equal(t, username, res.User.Username)
   814  
   815  	// List can return stale results for invites, so do a force load of the team to refresh the cache.
   816  	// In the real world, hopefully gregor would cause this.
   817  	_, err = Load(context.TODO(), tc.G, keybase1.LoadTeamArg{
   818  		Name:        name,
   819  		ForceRepoll: true,
   820  	})
   821  	require.NoError(t, err)
   822  
   823  	annotatedTeamList, err := ListAll(context.TODO(), tc.G, keybase1.TeamListTeammatesArg{})
   824  	require.NoError(t, err)
   825  	require.Equal(t, 1, len(annotatedTeamList.Teams), "ListAll doesn't include keybase invites")
   826  
   827  	require.Equal(t, user.Username, annotatedTeamList.Teams[0].Username)
   828  	require.Equal(t, name, annotatedTeamList.Teams[0].FqName)
   829  }
   830  
   831  func TestMemberAddAsImplicitAdmin(t *testing.T) {
   832  	tc, owner, otherA, otherB, _, subteamName := memberSetupSubteam(t)
   833  	defer tc.Cleanup()
   834  
   835  	// owner created a subteam, otherA is implicit admin, otherB is nobody
   836  	// (all of that tested in memberSetupSubteam)
   837  
   838  	switchTo := func(to *kbtest.FakeUser) {
   839  		err := tc.Logout()
   840  		require.NoError(t, err)
   841  		err = to.Login(tc.G)
   842  		require.NoError(t, err)
   843  	}
   844  
   845  	switchTo(otherA)
   846  
   847  	// otherA has the power to add otherB to the subteam
   848  	res, err := AddMember(context.TODO(), tc.G, subteamName, otherB.Username, keybase1.TeamRole_WRITER, nil)
   849  	require.NoError(t, err)
   850  	require.Equal(t, otherB.Username, res.User.Username, "AddMember result username does not match arg")
   851  	// otherB should now be a writer
   852  	assertRole(tc, subteamName, otherB.Username, keybase1.TeamRole_WRITER)
   853  
   854  	// owner, otherA should still be non-members
   855  	assertRole(tc, subteamName, owner.Username, keybase1.TeamRole_NONE)
   856  	assertRole(tc, subteamName, otherA.Username, keybase1.TeamRole_NONE)
   857  
   858  	switchTo(otherB)
   859  	// Test ImplicitAdmins
   860  	subteamName2, err := keybase1.TeamNameFromString(subteamName)
   861  	require.NoError(t, err)
   862  	subteamID, err := ResolveNameToID(context.TODO(), tc.G, subteamName2)
   863  	require.NoError(t, err)
   864  
   865  	ias, err := tc.G.GetTeamLoader().ImplicitAdmins(context.TODO(), subteamID)
   866  	// ias, err := ImplicitAdmins(context.TODO(), tc.G, subteamID)
   867  	require.NoError(t, err)
   868  	t.Logf("res: %v", spew.Sdump(ias))
   869  	require.Len(t, ias, 2, "number of implicit admins")
   870  	sort.Slice(ias, func(i, _ int) bool {
   871  		return ias[i].Eq(owner.GetUserVersion())
   872  	})
   873  	require.Equal(t, owner.GetUserVersion(), ias[0])
   874  	require.Equal(t, otherA.GetUserVersion(), ias[1])
   875  }
   876  
   877  func TestLeave(t *testing.T) {
   878  	tc, owner, otherA, otherB, name := memberSetupMultiple(t)
   879  	defer tc.Cleanup()
   880  
   881  	botua, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
   882  	require.NoError(t, err)
   883  	err = tc.Logout()
   884  	require.NoError(t, err)
   885  	err = owner.Login(tc.G)
   886  	require.NoError(t, err)
   887  
   888  	restrictedBotua, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
   889  	require.NoError(t, err)
   890  	err = tc.Logout()
   891  	require.NoError(t, err)
   892  	err = owner.Login(tc.G)
   893  	require.NoError(t, err)
   894  
   895  	err = SetRoleAdmin(context.TODO(), tc.G, name, otherA.Username)
   896  	require.NoError(t, err)
   897  	err = SetRoleWriter(context.TODO(), tc.G, name, otherB.Username)
   898  	require.NoError(t, err)
   899  	err = SetRoleBot(context.TODO(), tc.G, name, botua.Username)
   900  	require.NoError(t, err)
   901  	err = SetRoleRestrictedBot(context.TODO(), tc.G, name, restrictedBotua.Username, keybase1.TeamBotSettings{})
   902  	require.NoError(t, err)
   903  
   904  	err = tc.Logout()
   905  	require.NoError(t, err)
   906  
   907  	err = otherA.Login(tc.G)
   908  	require.NoError(t, err)
   909  	err = Leave(context.TODO(), tc.G, name, false)
   910  	require.NoError(t, err)
   911  	err = tc.Logout()
   912  	require.NoError(t, err)
   913  
   914  	err = otherB.Login(tc.G)
   915  	require.NoError(t, err)
   916  	err = Leave(context.TODO(), tc.G, name, false)
   917  	require.NoError(t, err)
   918  	err = tc.Logout()
   919  	require.NoError(t, err)
   920  
   921  	err = botua.Login(tc.G)
   922  	require.NoError(t, err)
   923  	err = Leave(context.TODO(), tc.G, name, false)
   924  	require.NoError(t, err)
   925  	err = tc.Logout()
   926  	require.NoError(t, err)
   927  
   928  	err = restrictedBotua.Login(tc.G)
   929  	require.NoError(t, err)
   930  	err = Leave(context.TODO(), tc.G, name, false)
   931  	require.NoError(t, err)
   932  	err = tc.Logout()
   933  	require.NoError(t, err)
   934  
   935  	err = owner.Login(tc.G)
   936  	require.NoError(t, err)
   937  	team, err := GetForTestByStringName(context.TODO(), tc.G, name)
   938  	require.NoError(t, err)
   939  
   940  	require.False(t, team.IsMember(context.TODO(), otherA.GetUserVersion()))
   941  	require.False(t, team.IsMember(context.TODO(), otherB.GetUserVersion()))
   942  	require.False(t, team.IsMember(context.TODO(), botua.GetUserVersion()))
   943  	require.False(t, team.IsMember(context.TODO(), restrictedBotua.GetUserVersion()))
   944  }
   945  
   946  func TestImplicitAdminBecomesExplicit(t *testing.T) {
   947  	fus, tcs, cleanup := setupNTests(t, 2)
   948  	defer cleanup()
   949  
   950  	t.Logf("u0 creates a team (seqno:1)")
   951  	teamName, _ := createTeam2(*tcs[0])
   952  
   953  	t.Logf("U0 adds U1 to the team (2)")
   954  	_, err := AddMember(context.TODO(), tcs[0].G, teamName.String(), fus[1].Username, keybase1.TeamRole_ADMIN, nil)
   955  	require.NoError(t, err)
   956  
   957  	t.Logf("U0 makes a subteam")
   958  	subteamNameParsed, subteamID := createSubteam(tcs[0], teamName, "subteam")
   959  	subteamName := subteamNameParsed.String()
   960  
   961  	t.Logf("U0 adds themself as an admin to the subteam")
   962  	_, err = AddMember(context.TODO(), tcs[0].G, subteamName, fus[0].Username, keybase1.TeamRole_ADMIN, nil)
   963  	require.NoError(t, err)
   964  
   965  	t.Logf("U0 rotates the subteam 3 times")
   966  	subteam, err := GetForTestByID(context.TODO(), tcs[0].G, subteamID)
   967  	require.NoError(t, err)
   968  	for i := 0; i < 3; i++ {
   969  		err = subteam.Rotate(context.TODO(), keybase1.RotationType_HIDDEN)
   970  		require.NoError(t, err)
   971  		subteam, err = GetForTestByID(context.TODO(), tcs[0].G, subteamID)
   972  		require.NoError(t, err)
   973  	}
   974  
   975  	t.Logf("U1 fails to read the SALTPACK RKM at gen=4")
   976  	subteamPartial, err := GetForTestByID(context.TODO(), tcs[1].G, subteamID)
   977  	require.NoError(t, err)
   978  	mctx := libkb.NewMetaContextForTest(*tcs[1])
   979  	_, err = ApplicationKeyAtGeneration(mctx, subteamPartial, keybase1.TeamApplication_SALTPACK, keybase1.PerTeamKeyGeneration(4))
   980  	require.Error(t, err)
   981  	require.IsType(t, err, libkb.KeyMaskNotFoundError{})
   982  
   983  	t.Logf("U0 adds U1 as a writer to the subteam")
   984  	_, err = AddMember(context.TODO(), tcs[0].G, subteamName, fus[1].Username, keybase1.TeamRole_WRITER, nil)
   985  	require.NoError(t, err)
   986  
   987  	t.Logf("U1 succeeds in reading the SALTPACK RKM at gen=4")
   988  	subteamFull, err := GetForTestByID(context.TODO(), tcs[1].G, subteamID)
   989  	require.NoError(t, err)
   990  	_, err = ApplicationKeyAtGeneration(mctx, subteamFull, keybase1.TeamApplication_SALTPACK, keybase1.PerTeamKeyGeneration(4))
   991  	require.NoError(t, err)
   992  }
   993  
   994  func TestLeaveSubteamWithImplicitAdminship(t *testing.T) {
   995  	tc, owner, otherA, otherB, name := memberSetupMultiple(t)
   996  	defer tc.Cleanup()
   997  
   998  	if err := SetRoleAdmin(context.TODO(), tc.G, name, otherA.Username); err != nil {
   999  		t.Fatal(err)
  1000  	}
  1001  	if err := SetRoleAdmin(context.TODO(), tc.G, name, otherB.Username); err != nil {
  1002  		t.Fatal(err)
  1003  	}
  1004  	teamNameParsed, err := keybase1.TeamNameFromString(name)
  1005  	if err != nil {
  1006  		t.Fatal(err)
  1007  	}
  1008  
  1009  	subteamNameParsed, _ := createSubteam(&tc, teamNameParsed, "subteam")
  1010  	subteamName := subteamNameParsed.String()
  1011  
  1012  	if err := SetRoleAdmin(context.TODO(), tc.G, subteamName, otherA.Username); err != nil {
  1013  		t.Fatal(err)
  1014  	}
  1015  	if err := SetRoleAdmin(context.TODO(), tc.G, subteamName, otherB.Username); err != nil {
  1016  		t.Fatal(err)
  1017  	}
  1018  
  1019  	err = tc.Logout()
  1020  	require.NoError(t, err)
  1021  
  1022  	if err := otherA.Login(tc.G); err != nil {
  1023  		t.Fatal(err)
  1024  	}
  1025  	if err := Leave(context.TODO(), tc.G, subteamName, false); err != nil {
  1026  		t.Fatal(err)
  1027  	}
  1028  	err = tc.Logout()
  1029  	require.NoError(t, err)
  1030  
  1031  	if err := otherB.Login(tc.G); err != nil {
  1032  		t.Fatal(err)
  1033  	}
  1034  	if err := Leave(context.TODO(), tc.G, subteamName, false); err != nil {
  1035  		t.Fatal(err)
  1036  	}
  1037  	err = tc.Logout()
  1038  	require.NoError(t, err)
  1039  
  1040  	if err := owner.Login(tc.G); err != nil {
  1041  		t.Fatal(err)
  1042  	}
  1043  	team, err := GetForTestByStringName(context.TODO(), tc.G, subteamName)
  1044  	if err != nil {
  1045  		t.Fatal(err)
  1046  	}
  1047  	if team.IsMember(context.TODO(), otherA.GetUserVersion()) {
  1048  		t.Fatal("Admin user is still member after leave.")
  1049  	}
  1050  	if team.IsMember(context.TODO(), otherB.GetUserVersion()) {
  1051  		t.Fatal("Writer user is still member after leave.")
  1052  	}
  1053  
  1054  	// Try to leave the team again.
  1055  	// They are now an implicit admin and not an explicit member.
  1056  	// So this should fail, but with a reasonable error.
  1057  	t.Logf("try to leave again")
  1058  	err = tc.Logout()
  1059  	require.NoError(t, err)
  1060  	err = otherA.Login(tc.G)
  1061  	require.NoError(t, err)
  1062  	err = Leave(context.TODO(), tc.G, subteamName, false)
  1063  	require.Error(t, err)
  1064  	require.IsType(t, &ImplicitAdminCannotLeaveError{}, err, "wrong error type")
  1065  }
  1066  
  1067  // See CORE-6473
  1068  func TestOnlyOwnerLeaveThenUpgradeFriend(t *testing.T) {
  1069  
  1070  	tc, _, otherA, _, name := memberSetupMultiple(t)
  1071  	defer tc.Cleanup()
  1072  
  1073  	if err := SetRoleWriter(context.TODO(), tc.G, name, otherA.Username); err != nil {
  1074  		t.Fatal(err)
  1075  	}
  1076  	if err := Leave(context.TODO(), tc.G, name, false); err == nil {
  1077  		t.Fatal("expected an error when only owner is leaving")
  1078  	}
  1079  	if err := SetRoleOwner(context.TODO(), tc.G, name, otherA.Username); err != nil {
  1080  		t.Fatal(err)
  1081  	}
  1082  	if err := Leave(context.TODO(), tc.G, name, false); err != nil {
  1083  		t.Fatal(err)
  1084  	}
  1085  }
  1086  
  1087  func testLeaveAsRole(t *testing.T, role keybase1.TeamRole) {
  1088  	fus, tcs, cleanup := setupNTests(t, 2)
  1089  	defer cleanup()
  1090  
  1091  	t.Logf("U0 creates fennel_network")
  1092  	teamName, teamID := createTeam2(*tcs[0])
  1093  
  1094  	t.Logf("U0 adds U1 to the root")
  1095  	var botSettings *keybase1.TeamBotSettings
  1096  	if role.IsRestrictedBot() {
  1097  		botSettings = &keybase1.TeamBotSettings{}
  1098  	}
  1099  	_, err := AddMember(context.Background(), tcs[0].G, teamName.String(), fus[1].Username, role, botSettings)
  1100  	require.NoError(t, err)
  1101  
  1102  	t.Logf("U1 leaves the team")
  1103  	err = Leave(context.Background(), tcs[1].G, teamName.String(), false)
  1104  	require.NoError(t, err)
  1105  
  1106  	t.Logf("U0 loads the team")
  1107  	require.NoError(t, err, "loading the team")
  1108  	_, err = Load(context.Background(), tcs[0].G, keybase1.LoadTeamArg{
  1109  		ID:          teamID,
  1110  		ForceRepoll: true,
  1111  	})
  1112  	require.NoError(t, err)
  1113  
  1114  	t.Logf("U0 loads the team from scratch")
  1115  	_, err = Load(context.Background(), tcs[0].G, keybase1.LoadTeamArg{
  1116  		ID:              teamID,
  1117  		ForceFullReload: true,
  1118  		ForceRepoll:     true,
  1119  	})
  1120  	require.NoError(t, err, "loading the team FROM SCRATCH")
  1121  }
  1122  
  1123  func TestLeaveAsReader(t *testing.T) {
  1124  	testLeaveAsRole(t, keybase1.TeamRole_READER)
  1125  }
  1126  
  1127  func TestLeaveAsBot(t *testing.T) {
  1128  	testLeaveAsRole(t, keybase1.TeamRole_BOT)
  1129  }
  1130  
  1131  func TestLeaveAsRestrictedBot(t *testing.T) {
  1132  	testLeaveAsRole(t, keybase1.TeamRole_RESTRICTEDBOT)
  1133  }
  1134  
  1135  func TestMemberAddResolveCache(t *testing.T) {
  1136  	tc, _, other, _, name := memberSetupMultiple(t)
  1137  	defer tc.Cleanup()
  1138  
  1139  	assertRole(tc, name, other.Username, keybase1.TeamRole_NONE)
  1140  
  1141  	// load user so it is fully cached
  1142  	_, err := libkb.LoadUser(libkb.NewLoadUserByNameArg(tc.G, other.Username))
  1143  	if err != nil {
  1144  		t.Fatal(err)
  1145  	}
  1146  
  1147  	// clear the memory cache so it will come from disk
  1148  	tc.G.Resolver.EnableCaching(libkb.NewMetaContextForTest(tc))
  1149  
  1150  	// add the member
  1151  	res, err := AddMember(context.TODO(), tc.G, name, other.Username, keybase1.TeamRole_READER, nil)
  1152  	if err != nil {
  1153  		t.Fatal(err)
  1154  	}
  1155  	if res.User.Username != other.Username {
  1156  		t.Errorf("AddMember result username %q does not match arg username %q", res.User.Username, other.Username)
  1157  	}
  1158  
  1159  	assertRole(tc, name, other.Username, keybase1.TeamRole_READER)
  1160  }
  1161  
  1162  func assertRole(tc libkb.TestContext, name, username string, expected keybase1.TeamRole) {
  1163  	role, err := MemberRole(context.TODO(), tc.G, name, username)
  1164  	if err != nil {
  1165  		if err == errInviteRequired && expected == keybase1.TeamRole_NONE {
  1166  			return
  1167  		}
  1168  		require.Fail(tc.T, err.Error())
  1169  	}
  1170  	if role != expected {
  1171  		require.Fail(tc.T, fmt.Sprintf("role: %s, expected %s", role, expected))
  1172  	}
  1173  }
  1174  
  1175  func assertRole2(tc libkb.TestContext, teamID keybase1.TeamID, username string, expected keybase1.TeamRole) {
  1176  	team, err := Load(context.TODO(), tc.G, keybase1.LoadTeamArg{
  1177  		ID:          teamID,
  1178  		Public:      teamID.IsPublic(),
  1179  		ForceRepoll: true,
  1180  	})
  1181  	require.NoError(tc.T, err)
  1182  
  1183  	uv, err := loadUserVersionByUsername(context.TODO(), tc.G, username, true)
  1184  	require.NoError(tc.T, err)
  1185  
  1186  	role, err := team.MemberRole(context.TODO(), uv)
  1187  	require.NoError(tc.T, err)
  1188  
  1189  	if role != expected {
  1190  		tc.T.Fatalf("role: %s, expected %s", role, expected)
  1191  	}
  1192  }
  1193  
  1194  func assertInvite(tc libkb.TestContext, name, username, typ string, role keybase1.TeamRole) {
  1195  	tc.T.Logf("looking for invite for %s/%s w/ role %s in team %s", username, typ, role, name)
  1196  	iname := keybase1.TeamInviteName(username)
  1197  	itype, err := TeamInviteTypeFromString(tc.MetaContext(), typ)
  1198  	require.NoError(tc.T, err)
  1199  	invite, err := memberInvite(context.TODO(), tc.G, name, iname, itype)
  1200  	require.NoError(tc.T, err)
  1201  	require.NotNil(tc.T, invite)
  1202  	require.Equal(tc.T, role, invite.Role)
  1203  }
  1204  
  1205  func assertNoInvite(tc libkb.TestContext, name, username, typ string) {
  1206  	iname := keybase1.TeamInviteName(username)
  1207  	itype, err := TeamInviteTypeFromString(tc.MetaContext(), typ)
  1208  	if err != nil {
  1209  		tc.T.Fatal(err)
  1210  	}
  1211  	invite, err := memberInvite(context.TODO(), tc.G, name, iname, itype)
  1212  	if err == nil {
  1213  		tc.T.Fatal("expected not found err, got nil")
  1214  	}
  1215  	if _, ok := err.(libkb.NotFoundError); !ok {
  1216  		tc.T.Fatalf("expected libkb.NotFoundError, got %T", err)
  1217  	}
  1218  	if invite != nil {
  1219  		tc.T.Fatal("invite found")
  1220  	}
  1221  
  1222  }
  1223  func TestImplicitAdminsKeyedForSubteam(t *testing.T) {
  1224  	fus, tcs, cleanup := setupNTests(t, 3)
  1225  	defer cleanup()
  1226  
  1227  	t.Logf("U0 creates a root team")
  1228  	parentName, _ := createTeam2(*tcs[0])
  1229  
  1230  	t.Logf("U0 creates a subteam")
  1231  	subteamID, err := CreateSubteam(context.TODO(), tcs[0].G, "sub", parentName, keybase1.TeamRole_NONE /* addSelfAs */)
  1232  	require.NoError(t, err)
  1233  
  1234  	t.Logf("U1 and U2 can't load the subteam")
  1235  	_, err = tcs[1].G.GetTeamLoader().ImplicitAdmins(context.TODO(), *subteamID)
  1236  	require.Error(t, err, "U1 should not be able to load subteam without implicit admin status")
  1237  	_, err = tcs[2].G.GetTeamLoader().ImplicitAdmins(context.TODO(), *subteamID)
  1238  	require.Error(t, err, "U2 isn't in the subteam at all yet, shouldn't be able to load")
  1239  
  1240  	t.Logf("U0 adds U1 as an admin in the root team")
  1241  	_, err = AddMember(context.TODO(), tcs[0].G, parentName.String(), fus[1].Username, keybase1.TeamRole_ADMIN, nil)
  1242  	require.NoError(t, err)
  1243  
  1244  	t.Logf("now U1 can load the subteam, but not U2")
  1245  	_, err = tcs[1].G.GetTeamLoader().ImplicitAdmins(context.TODO(), *subteamID)
  1246  	require.NoError(t, err, "U1 should able to load subteam with implicit admin status")
  1247  	_, err = tcs[2].G.GetTeamLoader().ImplicitAdmins(context.TODO(), *subteamID)
  1248  	require.Error(t, err, "U2 still isn't in the subteam at yet, shouldn't be able to load")
  1249  
  1250  	t.Logf("U1 can add U2 to the subteam")
  1251  	_, err = AddMember(context.TODO(), tcs[1].G, parentName.String(), fus[2].Username, keybase1.TeamRole_ADMIN, nil)
  1252  	require.NoError(t, err)
  1253  
  1254  	t.Logf("now U2 can load the subteam")
  1255  	_, err = tcs[1].G.GetTeamLoader().ImplicitAdmins(context.TODO(), *subteamID)
  1256  	require.NoError(t, err, "now U2 is a member of the subteam and should be able to read it")
  1257  }
  1258  
  1259  func TestImplicitAdminsKeyedForSubteamAfterUpgrade(t *testing.T) {
  1260  	fus, tcs, cleanup := setupNTests(t, 2)
  1261  	defer cleanup()
  1262  
  1263  	parentName, _ := createTeam2(*tcs[0])
  1264  	t.Logf("U0 created a root team %q", parentName)
  1265  
  1266  	subteamID, err := CreateSubteam(context.TODO(), tcs[0].G, "sub", parentName, keybase1.TeamRole_NONE /* addSelfAs */)
  1267  	require.NoError(t, err)
  1268  	t.Logf("U0 created a subteam %q", subteamID)
  1269  
  1270  	_, err = AddMember(context.TODO(), tcs[0].G, parentName.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
  1271  	require.NoError(t, err)
  1272  
  1273  	// U1 can't read the subteam (yet).
  1274  	_, err = tcs[1].G.GetTeamLoader().ImplicitAdmins(context.TODO(), *subteamID)
  1275  	require.Error(t, err)
  1276  
  1277  	// Set U1 to be an admin of root team.
  1278  	err = SetRoleAdmin(context.TODO(), tcs[0].G, parentName.String(), fus[1].Username)
  1279  	require.NoError(t, err)
  1280  
  1281  	// U1 should be able to read subteam now.
  1282  	_, err = tcs[1].G.GetTeamLoader().ImplicitAdmins(context.TODO(), *subteamID)
  1283  	require.NoError(t, err)
  1284  }
  1285  
  1286  // add user without keys to a team, should create invite link.
  1287  // remove that user from the team should cancel the invite.
  1288  func TestMemberCancelInviteNoKeys(t *testing.T) {
  1289  	tc, _, name := memberSetup(t)
  1290  	defer tc.Cleanup()
  1291  
  1292  	username := "t_ellen"
  1293  	_, err := AddMember(context.TODO(), tc.G, name, username, keybase1.TeamRole_READER, nil)
  1294  	if err != nil {
  1295  		t.Fatal(err)
  1296  	}
  1297  
  1298  	assertInvite(tc, name, "561247eb1cc3b0f5dc9d9bf299da5e19%0", "keybase", keybase1.TeamRole_READER)
  1299  	assertRole(tc, name, username, keybase1.TeamRole_NONE)
  1300  
  1301  	if err := RemoveMember(context.TODO(), tc.G, name, username); err != nil {
  1302  		t.Fatal(err)
  1303  	}
  1304  
  1305  	assertNoInvite(tc, name, "561247eb1cc3b0f5dc9d9bf299da5e19%0", "keybase")
  1306  	assertRole(tc, name, username, keybase1.TeamRole_NONE)
  1307  }
  1308  
  1309  func TestMemberCancelInviteSocial(t *testing.T) {
  1310  	tc, _, name := memberSetup(t)
  1311  	defer tc.Cleanup()
  1312  
  1313  	tc.G.SetProofServices(externals.NewProofServices(tc.G))
  1314  
  1315  	username := "not_on_kb_yet@twitter"
  1316  	_, err := AddMember(context.TODO(), tc.G, name, username, keybase1.TeamRole_READER, nil)
  1317  	if err != nil {
  1318  		t.Fatal(err)
  1319  	}
  1320  	assertInvite(tc, name, "not_on_kb_yet", "twitter", keybase1.TeamRole_READER)
  1321  
  1322  	if err := RemoveMember(context.TODO(), tc.G, name, username); err != nil {
  1323  		t.Fatal(err)
  1324  	}
  1325  
  1326  	assertNoInvite(tc, name, "not_on_kb_yet", "twitter")
  1327  }
  1328  
  1329  func TestMemberCancelInviteEmail(t *testing.T) {
  1330  	tc, _, name, teamID := memberSetupWithID(t)
  1331  	defer tc.Cleanup()
  1332  
  1333  	tc.G.SetProofServices(externals.NewProofServices(tc.G))
  1334  
  1335  	address := "noone@keybase.io"
  1336  
  1337  	if err := InviteEmailPhoneMember(context.TODO(), tc.G, teamID, address, "email", keybase1.TeamRole_READER); err != nil {
  1338  		t.Fatal(err)
  1339  	}
  1340  	assertInvite(tc, name, address, "email", keybase1.TeamRole_READER)
  1341  
  1342  	require.NoError(t, CancelEmailInvite(context.TODO(), tc.G, teamID, address))
  1343  
  1344  	assertNoInvite(tc, name, address, "email")
  1345  
  1346  	// check error type for an email address with no invite
  1347  	err := CancelEmailInvite(context.TODO(), tc.G, teamID, "nope@keybase.io")
  1348  	if err == nil {
  1349  		t.Fatal("expected error canceling email invite for unknown email address")
  1350  	}
  1351  	require.IsType(t, err, &MemberNotFoundInChainError{})
  1352  
  1353  	// check error type for unknown team
  1354  	err = CancelEmailInvite(context.TODO(), tc.G, "notateam", address)
  1355  	if err == nil {
  1356  		t.Fatal("expected error canceling email invite for unknown team")
  1357  	}
  1358  	require.EqualError(t, err, "team load arg has invalid ID: \"notateam\"")
  1359  }
  1360  
  1361  // Test two users racing to post chain links to the same team.
  1362  // In this case, adding different users to the team.
  1363  // The expected behavior is that they both succeed.
  1364  // A rotation is also thrown in some time.
  1365  func TestMemberAddRace(t *testing.T) {
  1366  	fus, tcs, cleanup := setupNTests(t, 4)
  1367  	defer cleanup()
  1368  
  1369  	t.Logf("U0 creates A")
  1370  	rootName, rootID := createTeam2(*tcs[0])
  1371  
  1372  	t.Logf("U0 adds U1")
  1373  	_, err := AddMember(context.TODO(), tcs[0].G, rootName.String(), fus[1].Username, keybase1.TeamRole_ADMIN, nil)
  1374  	require.NoError(t, err, "add member")
  1375  
  1376  	// add or remove a user from the team
  1377  	mod := func(userIndexOperator, userIndexTarget int, add bool) <-chan error {
  1378  		errCh := make(chan error)
  1379  		go func() {
  1380  			ctx := context.Background()
  1381  			ctx = libkb.WithLogTag(ctx, "TEST")
  1382  			var err error
  1383  			desc := "removes"
  1384  			if add {
  1385  				desc = "adds"
  1386  			}
  1387  			t.Logf("U%v %v U%v", userIndexOperator, desc, userIndexTarget)
  1388  			if add {
  1389  				_, err = AddMember(ctx,
  1390  					tcs[userIndexOperator].G, rootName.String(), fus[userIndexTarget].Username, keybase1.TeamRole_READER, nil)
  1391  			} else {
  1392  				err = RemoveMember(ctx,
  1393  					tcs[userIndexOperator].G, rootName.String(), fus[userIndexTarget].Username)
  1394  			}
  1395  			errCh <- err
  1396  		}()
  1397  		return errCh
  1398  	}
  1399  
  1400  	rotate := func(userIndexOperator int) <-chan error {
  1401  		errCh := make(chan error)
  1402  		go func() {
  1403  			params := keybase1.TeamCLKRMsg{
  1404  				TeamID:              rootID,
  1405  				Generation:          keybase1.PerTeamKeyGeneration(100),
  1406  				ResetUsersUntrusted: nil,
  1407  			}
  1408  			err := HandleRotateRequest(context.TODO(), tcs[userIndexOperator].G, params)
  1409  			errCh <- err
  1410  		}()
  1411  		return errCh
  1412  	}
  1413  
  1414  	assertNoErr := func(errCh <-chan error, msgAndArgs ...interface{}) {
  1415  		select {
  1416  		case err := <-errCh:
  1417  			require.NoError(t, err, msgAndArgs...)
  1418  		case <-time.After(20 * time.Second):
  1419  			require.FailNow(t, "timeout waiting for return channel")
  1420  		}
  1421  	}
  1422  
  1423  	for i := 0; i < 5; i++ {
  1424  		t.Logf("round %v", i)
  1425  		doRotate := i%2 == 1
  1426  
  1427  		t.Logf("parallel start")
  1428  
  1429  		var errCh3 <-chan error
  1430  		if doRotate {
  1431  			errCh3 = rotate(0)
  1432  		}
  1433  		errCh1 := mod(0, 2, true)
  1434  		errCh2 := mod(1, 3, true)
  1435  		assertNoErr(errCh1, "round %v", i)
  1436  		assertNoErr(errCh2, "round %v", i)
  1437  		if doRotate {
  1438  			assertNoErr(errCh3, "round %v", i)
  1439  		}
  1440  
  1441  		t.Logf("parallel end")
  1442  
  1443  		assertNoErr(mod(0, 2, false))
  1444  		assertNoErr(mod(1, 3, false))
  1445  	}
  1446  }
  1447  
  1448  // Test two users racing to post chain links to the same team.
  1449  // In this case, adding the same user to the team.
  1450  // The expected behavior is that one will win and one will fail with a nice error.
  1451  func TestMemberAddRaceConflict(t *testing.T) {
  1452  	fus, tcs, cleanup := setupNTests(t, 4)
  1453  	defer cleanup()
  1454  
  1455  	t.Logf("U0 creates A")
  1456  	rootName, _ := createTeam2(*tcs[0])
  1457  
  1458  	t.Logf("U0 adds U1")
  1459  	_, err := AddMember(context.TODO(), tcs[0].G, rootName.String(), fus[1].Username, keybase1.TeamRole_ADMIN, nil)
  1460  	require.NoError(t, err, "add member")
  1461  
  1462  	// add or remove a user from the team
  1463  	mod := func(userIndexOperator, userIndexTarget int, add bool) <-chan error {
  1464  		errCh := make(chan error)
  1465  		go func() {
  1466  			ctx := context.Background()
  1467  			ctx = libkb.WithLogTag(ctx, "TEST")
  1468  			var err error
  1469  			desc := "removes"
  1470  			if add {
  1471  				desc = "adds"
  1472  			}
  1473  			t.Logf("U%v %v U%v", userIndexOperator, desc, userIndexTarget)
  1474  			if add {
  1475  				_, err = AddMember(ctx,
  1476  					tcs[userIndexOperator].G, rootName.String(), fus[userIndexTarget].Username, keybase1.TeamRole_READER, nil)
  1477  			} else {
  1478  				err = RemoveMember(ctx,
  1479  					tcs[userIndexOperator].G, rootName.String(), fus[userIndexTarget].Username)
  1480  			}
  1481  			errCh <- err
  1482  		}()
  1483  		return errCh
  1484  	}
  1485  
  1486  	assertNoErr := func(errCh <-chan error, msgAndArgs ...interface{}) {
  1487  		select {
  1488  		case err := <-errCh:
  1489  			require.NoError(t, err, msgAndArgs...)
  1490  		case <-time.After(20 * time.Second):
  1491  			require.FailNow(t, "timeout waiting for return channel")
  1492  		}
  1493  	}
  1494  
  1495  	// Exactly one error comes from the list of channels
  1496  	assertOneErr := func(errChs []<-chan error, msgAndArgs ...interface{}) (retErr error) {
  1497  		for i, errCh := range errChs {
  1498  			select {
  1499  			case err := <-errCh:
  1500  				if retErr == nil {
  1501  					retErr = err
  1502  				} else {
  1503  					require.NoError(t, err, msgAndArgs...)
  1504  				}
  1505  			case <-time.After(20 * time.Second):
  1506  				require.FailNow(t, "timeout waiting for return channel: %v", i)
  1507  			}
  1508  		}
  1509  		return retErr
  1510  	}
  1511  
  1512  	for i := 0; i < 5; i++ {
  1513  		t.Logf("round %v", i)
  1514  
  1515  		t.Logf("parallel start")
  1516  
  1517  		errCh1 := mod(0, 2, true)
  1518  		errCh2 := mod(1, 2, true)
  1519  		err := assertOneErr([](<-chan error){errCh1, errCh2})
  1520  		require.Errorf(t, err, "round %v", i)
  1521  		require.IsType(t, libkb.ExistsError{}, err, "user should already be in team (round %v)", i)
  1522  
  1523  		t.Logf("parallel end")
  1524  
  1525  		assertNoErr(mod(0, 2, false))
  1526  	}
  1527  }
  1528  
  1529  // Add user without puk to a team, then change their role.
  1530  func TestMemberInviteChangeRole(t *testing.T) {
  1531  	tc, _, name := memberSetup(t)
  1532  	defer tc.Cleanup()
  1533  
  1534  	username := "t_alice"
  1535  	uid := keybase1.UID("295a7eea607af32040647123732bc819")
  1536  	role := keybase1.TeamRole_READER
  1537  
  1538  	res, err := AddMember(context.TODO(), tc.G, name, username, role, nil)
  1539  	if err != nil {
  1540  		t.Fatal(err)
  1541  	}
  1542  	if !res.Invited {
  1543  		t.Fatal("res.Invited should be set")
  1544  	}
  1545  
  1546  	fqUID := string(uid) + "%1"
  1547  	assertInvite(tc, name, fqUID, "keybase", role)
  1548  
  1549  	if err := EditMember(context.TODO(), tc.G, name, username, keybase1.TeamRole_ADMIN, nil); err != nil {
  1550  		t.Fatal(err)
  1551  	}
  1552  	assertInvite(tc, name, fqUID, "keybase", keybase1.TeamRole_ADMIN)
  1553  }
  1554  
  1555  // Add user without puk to a team, then change the invite role to owner,
  1556  // which should now work.
  1557  func TestMemberInviteChangeRoleOwner(t *testing.T) {
  1558  	tc, _, name := memberSetup(t)
  1559  	defer tc.Cleanup()
  1560  
  1561  	username := "t_alice"
  1562  	uid := keybase1.UID("295a7eea607af32040647123732bc819")
  1563  	role := keybase1.TeamRole_READER
  1564  
  1565  	res, err := AddMember(context.TODO(), tc.G, name, username, role, nil)
  1566  	if err != nil {
  1567  		t.Fatal(err)
  1568  	}
  1569  	if !res.Invited {
  1570  		t.Fatal("res.Invited should be set")
  1571  	}
  1572  
  1573  	fqUID := string(uid) + "%1"
  1574  	assertInvite(tc, name, fqUID, "keybase", role)
  1575  
  1576  	if err := EditMember(context.TODO(), tc.G, name, username, keybase1.TeamRole_OWNER, nil); err != nil {
  1577  		t.Fatal(err)
  1578  	}
  1579  	assertInvite(tc, name, fqUID, "keybase", keybase1.TeamRole_OWNER)
  1580  }
  1581  
  1582  func TestFollowResetAdd(t *testing.T) {
  1583  	tc := SetupTest(t, "team", 1)
  1584  	defer tc.Cleanup()
  1585  
  1586  	alice, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
  1587  	require.NoError(t, err)
  1588  	teamName, teamID := createTeam2(tc)
  1589  	team := teamName.String()
  1590  	t.Logf("Created team %q", team)
  1591  	err = tc.Logout()
  1592  	require.NoError(t, err)
  1593  
  1594  	bob, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
  1595  	require.NoError(t, err)
  1596  	err = tc.Logout()
  1597  	require.NoError(t, err)
  1598  
  1599  	charlie, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
  1600  	require.NoError(t, err)
  1601  	err = tc.Logout()
  1602  	require.NoError(t, err)
  1603  
  1604  	// alice tracks bob and charlie
  1605  	err = alice.Login(tc.G)
  1606  	require.NoError(t, err)
  1607  	_, err = kbtest.RunTrack(tc, alice, bob.Username)
  1608  	require.NoError(t, err)
  1609  	_, err = kbtest.RunTrack(tc, alice, charlie.Username)
  1610  	require.NoError(t, err)
  1611  
  1612  	// alice lets charlie into the team
  1613  	_, err = AddMember(context.TODO(), tc.G, team, charlie.Username, keybase1.TeamRole_ADMIN, nil)
  1614  	require.NoError(t, err)
  1615  
  1616  	// bob and charlie reset
  1617  	err = tc.Logout()
  1618  	require.NoError(t, err)
  1619  	err = bob.Login(tc.G)
  1620  	require.NoError(t, err)
  1621  	kbtest.ResetAccount(tc, bob)
  1622  	err = tc.Logout()
  1623  	require.NoError(t, err)
  1624  
  1625  	err = charlie.Login(tc.G)
  1626  	require.NoError(t, err)
  1627  	kbtest.ResetAccount(tc, charlie)
  1628  	err = tc.Logout()
  1629  	require.NoError(t, err)
  1630  
  1631  	// alice fails to invite bob into the team since her tracking statement of him is broken
  1632  	err = alice.Login(tc.G)
  1633  	require.NoError(t, err)
  1634  	_, err = AddMember(context.TODO(), tc.G, team, bob.Username, keybase1.TeamRole_ADMIN, nil)
  1635  	require.Error(t, err)
  1636  	require.True(t, libkb.IsIdentifyProofError(err))
  1637  
  1638  	// AddMembers also fails
  1639  	added, notAdded, err := AddMembers(context.TODO(), tc.G, teamID, []keybase1.UserRolePair{{Assertion: bob.Username, Role: keybase1.TeamRole_ADMIN}}, nil /* emailInviteMsg */)
  1640  	require.Error(t, err)
  1641  	amerr, ok := err.(AddMembersError)
  1642  	require.True(t, ok)
  1643  	require.True(t, libkb.IsIdentifyProofError(amerr.Err))
  1644  	require.Nil(t, added)
  1645  	require.Nil(t, notAdded)
  1646  
  1647  	// alice succeeds in removing charlie from the team, since her broken tracking statement
  1648  	// is ignored for a team removal.
  1649  	err = RemoveMember(context.TODO(), tc.G, team, charlie.Username)
  1650  	require.NoError(t, err)
  1651  }
  1652  
  1653  func TestAddMemberWithRestrictiveContactSettings(t *testing.T) {
  1654  	tc := SetupTest(t, "team", 1)
  1655  	defer tc.Cleanup()
  1656  
  1657  	alice, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
  1658  	require.NoError(t, err)
  1659  	teamName, _ := createTeam2(tc)
  1660  	team := teamName.String()
  1661  	t.Logf("Created team %q", team)
  1662  	err = tc.Logout()
  1663  	require.NoError(t, err)
  1664  
  1665  	bob, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
  1666  	require.NoError(t, err)
  1667  	err = tc.Logout()
  1668  	require.NoError(t, err)
  1669  
  1670  	charlie, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
  1671  	require.NoError(t, err)
  1672  
  1673  	// charlie sets contact settings
  1674  	kbtest.SetContactSettings(tc, charlie, keybase1.ContactSettings{
  1675  		Enabled:              true,
  1676  		AllowFolloweeDegrees: 1,
  1677  	})
  1678  
  1679  	// alice can add bob
  1680  	err = tc.Logout()
  1681  	require.NoError(t, err)
  1682  	err = alice.Login(tc.G)
  1683  	require.NoError(t, err)
  1684  	_, err = AddMember(context.TODO(), tc.G, team, bob.Username, keybase1.TeamRole_WRITER, nil)
  1685  	require.NoError(t, err)
  1686  
  1687  	// alice can't add charlie
  1688  	_, err = AddMember(context.TODO(), tc.G, team, charlie.Username, keybase1.TeamRole_WRITER, nil)
  1689  	require.Error(t, err)
  1690  	usernames := err.(libkb.TeamContactSettingsBlockError).BlockedUsernames()
  1691  	require.Equal(t, usernames[0].String(), charlie.Username)
  1692  
  1693  	// charlie tracks alice
  1694  	err = tc.Logout()
  1695  	require.NoError(t, err)
  1696  	err = charlie.Login(tc.G)
  1697  	require.NoError(t, err)
  1698  
  1699  	_, err = kbtest.RunTrack(tc, charlie, alice.Username)
  1700  	require.NoError(t, err)
  1701  
  1702  	// alice can add charlie
  1703  	err = tc.Logout()
  1704  	require.NoError(t, err)
  1705  	err = alice.Login(tc.G)
  1706  	require.NoError(t, err)
  1707  
  1708  	_, err = AddMember(context.TODO(), tc.G, team, charlie.Username, keybase1.TeamRole_WRITER, nil)
  1709  	require.NoError(t, err)
  1710  }
  1711  
  1712  func TestAddMembersWithRestrictiveContactSettings(t *testing.T) {
  1713  	tc := SetupTest(t, "team", 1)
  1714  	defer tc.Cleanup()
  1715  
  1716  	alice, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
  1717  	require.NoError(t, err)
  1718  	teamName, teamID := createTeam2(tc)
  1719  	team := teamName.String()
  1720  	t.Logf("Created team %q", team)
  1721  	err = tc.Logout()
  1722  	require.NoError(t, err)
  1723  
  1724  	bob, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
  1725  	require.NoError(t, err)
  1726  	err = tc.Logout()
  1727  	require.NoError(t, err)
  1728  
  1729  	charlie, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
  1730  	require.NoError(t, err)
  1731  
  1732  	// charlie sets contact settings
  1733  	kbtest.SetContactSettings(tc, charlie, keybase1.ContactSettings{
  1734  		Enabled:              true,
  1735  		AllowFolloweeDegrees: 1,
  1736  	})
  1737  
  1738  	// alice can add bob but not charlie
  1739  	err = tc.Logout()
  1740  	require.NoError(t, err)
  1741  	err = alice.Login(tc.G)
  1742  	require.NoError(t, err)
  1743  	users := []keybase1.UserRolePair{
  1744  		{Assertion: bob.Username, Role: keybase1.TeamRole_WRITER},
  1745  		{Assertion: charlie.Username, Role: keybase1.TeamRole_WRITER},
  1746  	}
  1747  	added, notAdded, err := AddMembers(context.TODO(), tc.G, teamID, users, nil /* emailInviteMsg */)
  1748  	require.NoError(t, err)
  1749  	require.Equal(t, 1, len(added))
  1750  	require.Equal(t, libkb.NewNormalizedUsername(bob.Username), added[0].Username)
  1751  	require.Equal(t, 1, len(notAdded))
  1752  	require.Equal(t, libkb.NewNormalizedUsername(charlie.Username).String(), notAdded[0].Username)
  1753  }
  1754  
  1755  func TestAddMembersWithRestrictiveContactSettingsFailIfNoneAdded(t *testing.T) {
  1756  	tc := SetupTest(t, "team", 1)
  1757  	defer tc.Cleanup()
  1758  
  1759  	alice, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
  1760  	require.NoError(t, err)
  1761  	teamName, teamID := createTeam2(tc)
  1762  	team := teamName.String()
  1763  	t.Logf("Created team %q", team)
  1764  	err = tc.Logout()
  1765  	require.NoError(t, err)
  1766  
  1767  	bob, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
  1768  	require.NoError(t, err)
  1769  	kbtest.SetContactSettings(tc, bob, keybase1.ContactSettings{
  1770  		Enabled:              true,
  1771  		AllowFolloweeDegrees: 1,
  1772  	})
  1773  	err = tc.Logout()
  1774  	require.NoError(t, err)
  1775  
  1776  	charlie, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
  1777  	require.NoError(t, err)
  1778  	kbtest.SetContactSettings(tc, charlie, keybase1.ContactSettings{
  1779  		Enabled:              true,
  1780  		AllowFolloweeDegrees: 1,
  1781  	})
  1782  	err = tc.Logout()
  1783  	require.NoError(t, err)
  1784  
  1785  	expectedFailedUsernames := map[libkb.NormalizedUsername]bool{
  1786  		libkb.NewNormalizedUsername(bob.Username):     true,
  1787  		libkb.NewNormalizedUsername(charlie.Username): true,
  1788  	}
  1789  
  1790  	// alice can't add bob or charlie
  1791  	err = alice.Login(tc.G)
  1792  	require.NoError(t, err)
  1793  	users := []keybase1.UserRolePair{
  1794  		{Assertion: bob.Username, Role: keybase1.TeamRole_WRITER},
  1795  		{Assertion: charlie.Username, Role: keybase1.TeamRole_WRITER},
  1796  	}
  1797  	added, notAdded, err := AddMembers(context.TODO(), tc.G, teamID, users, nil /* emailInviteMsg */)
  1798  	require.Error(t, err)
  1799  	require.IsType(t, err, libkb.TeamContactSettingsBlockError{})
  1800  	usernames := err.(libkb.TeamContactSettingsBlockError).BlockedUsernames()
  1801  	require.Equal(t, 2, len(usernames))
  1802  	for _, username := range usernames {
  1803  		_, ok := expectedFailedUsernames[username]
  1804  		require.True(t, ok)
  1805  	}
  1806  	require.IsType(t, err, libkb.TeamContactSettingsBlockError{})
  1807  	require.Nil(t, added)
  1808  	require.Nil(t, notAdded)
  1809  }
  1810  
  1811  func TestGetUntrustedTeamInfo(t *testing.T) {
  1812  	fus, tcs, cleanup := setupNTests(t, 7)
  1813  	defer cleanup()
  1814  
  1815  	// prepare a mock team
  1816  	owner := 0
  1817  	publicAdmin := 1
  1818  	privateAdmin := 2
  1819  	publicReader := 3
  1820  	privateReader := 4
  1821  	restrictedBot := 5
  1822  	nonMember := 6
  1823  
  1824  	fullNames := make(map[int]string)
  1825  	fullNames[publicAdmin] = "TheMostAmazing Admin"
  1826  	fullNames[publicReader] = "TheEvenBetter Reader"
  1827  
  1828  	setFullName := func(target int) {
  1829  		eng := engine.NewProfileEdit(tcs[target].G, keybase1.ProfileEditArg{Location: "", FullName: fullNames[target], Bio: ""})
  1830  		err := eng.Run(tcs[target].MetaContext())
  1831  		require.NoError(t, err)
  1832  	}
  1833  	setFullName(publicAdmin)
  1834  	setFullName(publicReader)
  1835  
  1836  	teamName, teamID := createTeam2(*tcs[owner])
  1837  	team := teamName.String()
  1838  	added, notAdded, err := AddMembers(context.TODO(), tcs[owner].G, teamID, []keybase1.UserRolePair{
  1839  		{Assertion: fus[publicAdmin].Username, Role: keybase1.TeamRole_ADMIN},
  1840  		{Assertion: fus[privateAdmin].Username, Role: keybase1.TeamRole_ADMIN},
  1841  		{Assertion: fus[publicReader].Username, Role: keybase1.TeamRole_READER},
  1842  		{Assertion: fus[privateReader].Username, Role: keybase1.TeamRole_READER},
  1843  		{Assertion: fus[restrictedBot].Username, Role: keybase1.TeamRole_RESTRICTEDBOT, BotSettings: &keybase1.TeamBotSettings{Cmds: false, Mentions: true}},
  1844  	}, nil)
  1845  	require.NoError(t, err)
  1846  	require.Len(t, notAdded, 0)
  1847  	require.Len(t, added, 5)
  1848  	t.Logf("Created team %q", team)
  1849  
  1850  	// showcase the team, make it open and set some public members
  1851  	isShowcased := true
  1852  	description := "best team ever"
  1853  
  1854  	err = ChangeTeamSettingsByID(context.TODO(), tcs[owner].G, teamID, keybase1.TeamSettings{Open: true, JoinAs: keybase1.TeamRole_WRITER})
  1855  	require.NoError(t, err)
  1856  
  1857  	err = SetTeamShowcase(context.TODO(), tcs[owner].G, teamID, &isShowcased, &description, nil)
  1858  	require.NoError(t, err)
  1859  
  1860  	err = SetTeamMemberShowcase(context.TODO(), tcs[publicAdmin].G, teamID, true)
  1861  	require.NoError(t, err)
  1862  
  1863  	err = SetTeamMemberShowcase(context.TODO(), tcs[publicReader].G, teamID, true)
  1864  	require.NoError(t, err)
  1865  
  1866  	// load the team as a non member
  1867  	ret, err := GetUntrustedTeamInfo(tcs[nonMember].MetaContext(), teamName)
  1868  	require.NoError(t, err)
  1869  	// check the information matches what we expect
  1870  	require.Equal(t, teamName, ret.Name)
  1871  	require.Equal(t, description, ret.Description)
  1872  	require.Equal(t, false, ret.InTeam)
  1873  	require.Equal(t, true, ret.Open)
  1874  	require.Equal(t, 5, ret.NumMembers)
  1875  	require.Len(t, ret.PublicAdmins, 1)
  1876  	require.Equal(t, fus[publicAdmin].Username, ret.PublicAdmins[0])
  1877  	require.Len(t, ret.PublicMembers, 2)
  1878  
  1879  	checkPublicMember := func(target int, role keybase1.TeamRole) {
  1880  		found := false
  1881  		for _, pm := range ret.PublicMembers {
  1882  			if pm.Uid != fus[target].GetUID() {
  1883  				continue
  1884  			}
  1885  			found = true
  1886  			require.Equal(t, fus[target].User.GetUID(), pm.Uid)
  1887  			require.Equal(t, fus[target].Username, pm.Username)
  1888  			require.Equal(t, keybase1.FullName(fullNames[target]), pm.FullName)
  1889  			require.Equal(t, role, pm.Role)
  1890  		}
  1891  		assert.True(t, found, "target %v not found: %v", target, fus[target].Username)
  1892  	}
  1893  	checkPublicMember(publicAdmin, keybase1.TeamRole_ADMIN)
  1894  	checkPublicMember(publicReader, keybase1.TeamRole_READER)
  1895  }
  1896  
  1897  func TestMembersDetailsHasCorrectJoinTimes(t *testing.T) {
  1898  	fus, tcs, cleanup := setupNTests(t, 3)
  1899  	defer cleanup()
  1900  
  1901  	const (
  1902  		alice   = 0
  1903  		bob     = 1
  1904  		charlie = 2
  1905  	)
  1906  
  1907  	var team string
  1908  
  1909  	// setup some auxiliary functions
  1910  	type expectedMemberDetails struct {
  1911  		Username       string
  1912  		Role           keybase1.TeamRole
  1913  		JoinLowerBound keybase1.Time
  1914  		JoinUpperBound keybase1.Time
  1915  	}
  1916  
  1917  	findUserDetails := func(res []keybase1.TeamMemberDetails, username string, role keybase1.TeamRole) keybase1.TeamMemberDetails {
  1918  		for _, detail := range res {
  1919  			if detail.Username == username {
  1920  				return detail
  1921  			}
  1922  		}
  1923  		t.Fatalf("User %v with role %v not found", username, role)
  1924  		return keybase1.TeamMemberDetails{}
  1925  	}
  1926  
  1927  	checkDetails := func(tc *libkb.TestContext, details []expectedMemberDetails, expNumMembers int) {
  1928  		loadedTeam, err := Load(context.TODO(), tc.G, keybase1.LoadTeamArg{
  1929  			Name:        team,
  1930  			ForceRepoll: true,
  1931  		})
  1932  		require.NoError(t, err)
  1933  		res, err := MembersDetails(context.TODO(), tc.G, loadedTeam)
  1934  		require.NoError(t, err)
  1935  
  1936  		numMembers := len(res)
  1937  		require.Equal(t, expNumMembers, numMembers)
  1938  
  1939  		for _, expUserDetails := range details {
  1940  			userDetails := findUserDetails(res, expUserDetails.Username, expUserDetails.Role)
  1941  			assert.True(t, userDetails.JoinTime.After(expUserDetails.JoinLowerBound), "user %v joined at time %v but lower bound was %v", expUserDetails.Username, userDetails.JoinTime, expUserDetails.JoinLowerBound)
  1942  			assert.True(t, userDetails.JoinTime.Before(expUserDetails.JoinUpperBound), "user %v joined at time %v but upper bound was %v", expUserDetails.Username, userDetails.JoinTime, expUserDetails.JoinUpperBound)
  1943  		}
  1944  	}
  1945  
  1946  	fakeClock := clockwork.NewFakeClockAt(time.Now())
  1947  	tcs[alice].G.SetClock(fakeClock)
  1948  
  1949  	// start the test
  1950  	startTime := keybase1.ToTime(fakeClock.Now())
  1951  	// do small advances not to trigger the server into rejecting our updates (there is a 1 hour tolerance).
  1952  	fakeClock.Advance(1 * time.Minute)
  1953  
  1954  	// alice makes a team
  1955  	teamName, _ := createTeam2(*tcs[alice])
  1956  	team = teamName.String()
  1957  	t.Logf("Created team %q", team)
  1958  
  1959  	fakeClock.Advance(1 * time.Minute)
  1960  	teamCreateTime := keybase1.ToTime(fakeClock.Now())
  1961  	fakeClock.Advance(1 * time.Minute)
  1962  
  1963  	checkDetails(tcs[alice], []expectedMemberDetails{
  1964  		{Username: fus[alice].Username, Role: keybase1.TeamRole_OWNER, JoinLowerBound: startTime, JoinUpperBound: teamCreateTime},
  1965  	}, 1)
  1966  
  1967  	_, err := AddMember(context.TODO(), tcs[alice].G, team, fus[bob].Username, keybase1.TeamRole_READER, nil)
  1968  	require.NoError(t, err)
  1969  
  1970  	fakeClock.Advance(1 * time.Minute)
  1971  	firstAddBoBTime := keybase1.ToTime(fakeClock.Now())
  1972  	fakeClock.Advance(1 * time.Minute)
  1973  
  1974  	checkDetails(tcs[alice], []expectedMemberDetails{
  1975  		{Username: fus[alice].Username, Role: keybase1.TeamRole_OWNER, JoinLowerBound: startTime, JoinUpperBound: teamCreateTime},
  1976  		{Username: fus[bob].Username, Role: keybase1.TeamRole_READER, JoinLowerBound: teamCreateTime, JoinUpperBound: firstAddBoBTime},
  1977  	}, 2)
  1978  
  1979  	checkDetails(tcs[bob], []expectedMemberDetails{
  1980  		{Username: fus[alice].Username, Role: keybase1.TeamRole_OWNER, JoinLowerBound: startTime, JoinUpperBound: teamCreateTime},
  1981  		{Username: fus[bob].Username, Role: keybase1.TeamRole_READER, JoinLowerBound: teamCreateTime, JoinUpperBound: firstAddBoBTime},
  1982  	}, 2)
  1983  
  1984  	err = RemoveMember(context.TODO(), tcs[alice].G, team, fus[bob].Username)
  1985  	require.NoError(t, err)
  1986  
  1987  	fakeClock.Advance(1 * time.Minute)
  1988  	removeBoBTime := keybase1.ToTime(fakeClock.Now())
  1989  	fakeClock.Advance(1 * time.Minute)
  1990  
  1991  	checkDetails(tcs[alice], []expectedMemberDetails{
  1992  		{Username: fus[alice].Username, Role: keybase1.TeamRole_OWNER, JoinLowerBound: startTime, JoinUpperBound: teamCreateTime},
  1993  	}, 1)
  1994  
  1995  	_, err = AddMember(context.TODO(), tcs[alice].G, team, fus[charlie].Username, keybase1.TeamRole_READER, nil)
  1996  	require.NoError(t, err)
  1997  
  1998  	fakeClock.Advance(1 * time.Minute)
  1999  	addCharlieTime := keybase1.ToTime(fakeClock.Now())
  2000  	fakeClock.Advance(1 * time.Minute)
  2001  
  2002  	checkDetails(tcs[alice], []expectedMemberDetails{
  2003  		{Username: fus[alice].Username, Role: keybase1.TeamRole_OWNER, JoinLowerBound: startTime, JoinUpperBound: teamCreateTime},
  2004  		{Username: fus[charlie].Username, Role: keybase1.TeamRole_READER, JoinLowerBound: removeBoBTime, JoinUpperBound: addCharlieTime},
  2005  	}, 2)
  2006  
  2007  	_, err = AddMember(context.TODO(), tcs[alice].G, team, fus[bob].Username, keybase1.TeamRole_READER, nil)
  2008  	require.NoError(t, err)
  2009  
  2010  	fakeClock.Advance(1 * time.Minute)
  2011  	secondAddBoBTime := keybase1.ToTime(fakeClock.Now())
  2012  	fakeClock.Advance(1 * time.Minute)
  2013  
  2014  	checkDetails(tcs[alice], []expectedMemberDetails{
  2015  		{Username: fus[alice].Username, Role: keybase1.TeamRole_OWNER, JoinLowerBound: startTime, JoinUpperBound: teamCreateTime},
  2016  		{Username: fus[charlie].Username, Role: keybase1.TeamRole_READER, JoinLowerBound: removeBoBTime, JoinUpperBound: addCharlieTime},
  2017  		// ensure the bob's join time is from the second time he joined the team, not the first!
  2018  		{Username: fus[bob].Username, Role: keybase1.TeamRole_READER, JoinLowerBound: addCharlieTime, JoinUpperBound: secondAddBoBTime},
  2019  	}, 3)
  2020  
  2021  	err = EditMember(context.TODO(), tcs[alice].G, team, fus[charlie].Username, keybase1.TeamRole_ADMIN, nil)
  2022  	require.NoError(t, err)
  2023  
  2024  	checkDetails(tcs[alice], []expectedMemberDetails{
  2025  		{Username: fus[alice].Username, Role: keybase1.TeamRole_OWNER, JoinLowerBound: startTime, JoinUpperBound: teamCreateTime},
  2026  		// ensure the charlie's join time is not affected by his role change
  2027  		{Username: fus[charlie].Username, Role: keybase1.TeamRole_ADMIN, JoinLowerBound: removeBoBTime, JoinUpperBound: addCharlieTime},
  2028  		{Username: fus[bob].Username, Role: keybase1.TeamRole_READER, JoinLowerBound: addCharlieTime, JoinUpperBound: secondAddBoBTime},
  2029  	}, 3)
  2030  
  2031  }
  2032  
  2033  func TestTeamPlayerNoRoleChange(t *testing.T) {
  2034  	// Try to change_membership on user that is already in the team but do not
  2035  	// upgrade role.
  2036  
  2037  	tc, team, me := setupTestForPrechecks(t, false /* implicitTeam */)
  2038  	defer tc.Cleanup()
  2039  
  2040  	testUV := keybase1.UserVersion{Uid: libkb.UsernameToUID("t_alice_t"), EldestSeqno: 1}
  2041  
  2042  	teamSectionCM := makeTestSCTeamSection(team)
  2043  	teamSectionCM.Members = &SCTeamMembers{
  2044  		Writers: &[]SCTeamMember{SCTeamMember(testUV)},
  2045  	}
  2046  	state, err := appendSigToState(t, team, nil /* state */, libkb.LinkTypeChangeMembership,
  2047  		teamSectionCM, me, nil /* merkleRoot */)
  2048  	require.NoError(t, err)
  2049  
  2050  	userLog := state.inner.UserLog[testUV]
  2051  	require.Len(t, userLog, 1)
  2052  	require.Equal(t, keybase1.TeamRole_WRITER, userLog[0].Role)
  2053  	require.EqualValues(t, 2, userLog[0].SigMeta.SigChainLocation.Seqno)
  2054  
  2055  	// Append the same link again: "change" Writer testUV to Writer.
  2056  	state, err = appendSigToState(t, team, state, libkb.LinkTypeChangeMembership,
  2057  		teamSectionCM, me, nil /* merkleRoot */)
  2058  	require.NoError(t, err)
  2059  
  2060  	// That adds a new UserLog point with proper SigChainLocation, and the same
  2061  	// role (writer).
  2062  	userLog = state.inner.UserLog[testUV]
  2063  	require.Len(t, userLog, 2)
  2064  	for i, lp := range userLog {
  2065  		require.Equal(t, keybase1.TeamRole_WRITER, lp.Role)
  2066  		require.EqualValues(t, 2+i, lp.SigMeta.SigChainLocation.Seqno)
  2067  	}
  2068  }
  2069  
  2070  var rmMaker = func(assertion string) keybase1.TeamMemberToRemove {
  2071  	return keybase1.NewTeamMemberToRemoveWithAssertion(keybase1.AssertionTeamMemberToRemove{
  2072  		Assertion:         assertion,
  2073  		RemoveFromSubtree: false,
  2074  	})
  2075  }
  2076  var rmRecursiveMaker = func(assertion string) keybase1.TeamMemberToRemove {
  2077  	return keybase1.NewTeamMemberToRemoveWithAssertion(keybase1.AssertionTeamMemberToRemove{
  2078  		Assertion:         assertion,
  2079  		RemoveFromSubtree: true,
  2080  	})
  2081  }
  2082  
  2083  func TestRemoveMembersHappy(t *testing.T) {
  2084  	tc, _, alice, bob, name, teamID := memberSetupMultipleWithTeamID(t)
  2085  	defer tc.Cleanup()
  2086  
  2087  	if err := SetRoleReader(context.TODO(), tc.G, name.String(), alice.Username); err != nil {
  2088  		t.Fatal(err)
  2089  	}
  2090  
  2091  	res, err := RemoveMembers(context.TODO(), tc.G, teamID, []keybase1.TeamMemberToRemove{rmMaker(alice.Username)}, false)
  2092  	require.NoError(t, err)
  2093  	require.Len(t, res.Failures, 0)
  2094  	assertRole(tc, name.String(), alice.Username, keybase1.TeamRole_NONE)
  2095  
  2096  	if err := SetRoleReader(context.TODO(), tc.G, name.String(), alice.Username); err != nil {
  2097  		t.Fatal(err)
  2098  	}
  2099  	if err := SetRoleReader(context.TODO(), tc.G, name.String(), bob.Username); err != nil {
  2100  		t.Fatal(err)
  2101  	}
  2102  	twitterUser := "not_on_kb_yet@twitter"
  2103  	tAlice := "t_alice"
  2104  	_, err = AddMember(context.TODO(), tc.G, name.String(), twitterUser, keybase1.TeamRole_WRITER, nil)
  2105  	require.NoError(t, err, "add a social")
  2106  	_, err = AddMember(context.TODO(), tc.G, name.String(), tAlice, keybase1.TeamRole_WRITER, nil)
  2107  	require.NoError(t, err, "add a pukless")
  2108  	assertRole(tc, name.String(), alice.Username, keybase1.TeamRole_READER)
  2109  	assertRole(tc, name.String(), bob.Username, keybase1.TeamRole_READER)
  2110  	assertInvite(tc, name.String(), "not_on_kb_yet", "twitter", keybase1.TeamRole_WRITER)
  2111  	tAliceFQUID := "295a7eea607af32040647123732bc819%1"
  2112  	assertInvite(tc, name.String(), tAliceFQUID, "keybase", keybase1.TeamRole_WRITER)
  2113  	res, err = RemoveMembers(context.TODO(), tc.G, teamID, []keybase1.TeamMemberToRemove{
  2114  		rmMaker(alice.Username), rmRecursiveMaker(bob.Username),
  2115  		rmRecursiveMaker(twitterUser), rmMaker(tAlice),
  2116  	}, false)
  2117  	require.NoError(t, err)
  2118  	require.Len(t, res.Failures, 0)
  2119  	assertRole(tc, name.String(), alice.Username, keybase1.TeamRole_NONE)
  2120  	assertRole(tc, name.String(), bob.Username, keybase1.TeamRole_NONE)
  2121  	assertRole(tc, name.String(), twitterUser, keybase1.TeamRole_NONE)
  2122  	assertRole(tc, name.String(), tAlice, keybase1.TeamRole_NONE)
  2123  }
  2124  
  2125  func TestRemoveMembersErrorsBasic(t *testing.T) {
  2126  	tc, _, _, _, _, teamID := memberSetupMultipleWithTeamID(t)
  2127  	defer tc.Cleanup()
  2128  
  2129  	twitterUser := "not_on_kb_yet@twitter"
  2130  	tAlice := "t_alice"
  2131  	res, err := RemoveMembers(context.TODO(), tc.G, teamID, []keybase1.TeamMemberToRemove{
  2132  		rmMaker(tAlice),
  2133  		rmMaker(twitterUser),
  2134  	}, false)
  2135  	require.Error(t, err)
  2136  	require.Len(t, res.Failures, 2)
  2137  	require.NotNil(t, res.Failures[0].ErrorAtTarget)
  2138  	require.Contains(t, *res.Failures[0].ErrorAtTarget, "could not find team member in team")
  2139  	require.Nil(t, res.Failures[0].ErrorAtSubtree)
  2140  	require.NotNil(t, res.Failures[1].ErrorAtTarget)
  2141  	require.Contains(t, *res.Failures[1].ErrorAtTarget, "could not find team member in team")
  2142  	require.Nil(t, res.Failures[1].ErrorAtSubtree)
  2143  }
  2144  
  2145  func TestRemoveMembersJustAfterUpgrade(t *testing.T) {
  2146  	ownerTC := SetupTest(t, "team", 1)
  2147  	defer ownerTC.Cleanup()
  2148  	aliceTC := SetupTest(t, "team", 1)
  2149  	defer aliceTC.Cleanup()
  2150  
  2151  	_, err := kbtest.CreateAndSignupFakeUser("team", ownerTC.G)
  2152  	require.NoError(t, err)
  2153  
  2154  	alice, err := kbtest.CreateAndSignupFakeUser("team", aliceTC.G)
  2155  	require.NoError(t, err)
  2156  
  2157  	name, teamID := createTeam2(ownerTC)
  2158  	t.Logf("Created team %q", name)
  2159  
  2160  	t.Logf("Test that a just-upgraded admin can remove invited members (previously stubbed links)")
  2161  	if err := SetRoleReader(context.TODO(), ownerTC.G, name.String(), alice.Username); err != nil {
  2162  		t.Fatal(err)
  2163  	}
  2164  	redditUser := "new@reddit"
  2165  	_, err = AddMember(context.TODO(), ownerTC.G, name.String(), redditUser, keybase1.TeamRole_WRITER, nil)
  2166  	require.NoError(t, err)
  2167  
  2168  	_, err = Load(context.TODO(), aliceTC.G, keybase1.LoadTeamArg{
  2169  		Name:        name.String(),
  2170  		ForceRepoll: true,
  2171  	})
  2172  	require.NoError(t, err)
  2173  
  2174  	t.Logf("set as admin")
  2175  	if err := SetRoleAdmin(context.TODO(), ownerTC.G, name.String(), alice.Username); err != nil {
  2176  		t.Fatal(err)
  2177  	}
  2178  
  2179  	t.Logf("try to remove members")
  2180  	_, err = RemoveMembers(context.TODO(), aliceTC.G, teamID, []keybase1.TeamMemberToRemove{
  2181  		rmMaker(redditUser),
  2182  	}, false)
  2183  	require.NoError(t, err)
  2184  }
  2185  
  2186  func TestRemoveMembersHappyTree(t *testing.T) {
  2187  	tc := SetupTest(t, "team", 1)
  2188  	defer tc.Cleanup()
  2189  
  2190  	admin, err := kbtest.CreateAndSignupFakeUser("trm", tc.G)
  2191  	require.NoError(t, err)
  2192  	alice, err := kbtest.CreateAndSignupFakeUser("trm", tc.G)
  2193  	require.NoError(t, err)
  2194  	bob, err := kbtest.CreateAndSignupFakeUser("trm", tc.G)
  2195  	require.NoError(t, err)
  2196  	twitterUser := "not_on_kb_yet@twitter"
  2197  	redditUser := "hello@reddit"
  2198  	tAlice := "t_alice"
  2199  
  2200  	parentTeamName, err := keybase1.TeamNameFromString(admin.Username + "T")
  2201  	require.NoError(t, err)
  2202  	_, err = CreateRootTeam(context.TODO(), tc.G, parentTeamName.String(), keybase1.TeamSettings{})
  2203  	require.NoError(t, err)
  2204  	subteamBasename := "bbb"
  2205  	_, err = CreateSubteam(context.TODO(), tc.G, subteamBasename, parentTeamName, keybase1.TeamRole_NONE /* addSelfAs */)
  2206  	require.NoError(t, err)
  2207  	subteamName, err := parentTeamName.Append(subteamBasename)
  2208  	require.NoError(t, err)
  2209  	subsubteamBasename := "ccc"
  2210  	_, err = CreateSubteam(context.TODO(), tc.G, subsubteamBasename, subteamName, keybase1.TeamRole_NONE /* addSelfAs */)
  2211  	require.NoError(t, err)
  2212  	subsubteamName, err := subteamName.Append(subsubteamBasename)
  2213  	require.NoError(t, err)
  2214  	subsubsubteamBasename := "ddd"
  2215  	_, err = CreateSubteam(context.TODO(), tc.G, subsubsubteamBasename, subsubteamName, keybase1.TeamRole_NONE /* addSelfAs */)
  2216  	require.NoError(t, err)
  2217  	subsubsubteamName, err := subsubteamName.Append(subsubsubteamBasename)
  2218  	require.NoError(t, err)
  2219  
  2220  	_, err = AddMember(context.TODO(), tc.G, parentTeamName.String(), alice.Username, keybase1.TeamRole_ADMIN, nil)
  2221  	require.NoError(t, err)
  2222  	_, err = AddMember(context.TODO(), tc.G, subteamName.String(), alice.Username, keybase1.TeamRole_ADMIN, nil)
  2223  	require.NoError(t, err)
  2224  	_, err = AddMember(context.TODO(), tc.G, subteamName.String(), twitterUser, keybase1.TeamRole_WRITER, nil)
  2225  	require.NoError(t, err)
  2226  	_, err = AddMember(context.TODO(), tc.G, subteamName.String(), redditUser, keybase1.TeamRole_WRITER, nil)
  2227  	require.NoError(t, err)
  2228  	_, err = AddMember(context.TODO(), tc.G, subteamName.String(), tAlice, keybase1.TeamRole_WRITER, nil)
  2229  	require.NoError(t, err)
  2230  	_, err = AddMember(context.TODO(), tc.G, subsubteamName.String(), alice.Username, keybase1.TeamRole_ADMIN, nil)
  2231  	require.NoError(t, err)
  2232  	_, err = AddMember(context.TODO(), tc.G, subsubteamName.String(), bob.Username, keybase1.TeamRole_WRITER, nil)
  2233  	require.NoError(t, err)
  2234  	_, err = AddMember(context.TODO(), tc.G, subsubteamName.String(), tAlice, keybase1.TeamRole_WRITER, nil)
  2235  	require.NoError(t, err)
  2236  	_, err = AddMember(context.TODO(), tc.G, subsubsubteamName.String(), twitterUser, keybase1.TeamRole_WRITER, nil)
  2237  	require.NoError(t, err)
  2238  
  2239  	reddittype, err := TeamInviteTypeFromString(tc.MetaContext(), "reddit")
  2240  	require.NoError(t, err)
  2241  	redditInvite, err := memberInvite(context.TODO(), tc.G, subteamName.String(), "hello", reddittype)
  2242  	require.NoError(t, err)
  2243  	redditInviteID := redditInvite.Id
  2244  
  2245  	subteam, err := GetForTestByStringName(context.TODO(), tc.G, subteamName.String())
  2246  	require.NoError(t, err)
  2247  	res, err := RemoveMembers(context.TODO(), tc.G, subteam.ID, []keybase1.TeamMemberToRemove{
  2248  		rmRecursiveMaker(alice.Username),
  2249  		rmRecursiveMaker(twitterUser),
  2250  		keybase1.NewTeamMemberToRemoveWithInviteid(keybase1.InviteTeamMemberToRemove{
  2251  			InviteID: redditInviteID,
  2252  		}),
  2253  		rmMaker(tAlice),
  2254  		rmRecursiveMaker("notinteam"),
  2255  	}, false)
  2256  	require.Error(t, err, "got error for the one not-in-team user")
  2257  	require.Len(t, res.Failures, 1)
  2258  	require.Equal(t, rmRecursiveMaker("notinteam"), res.Failures[0].TeamMember)
  2259  	require.NotNil(t, res.Failures[0].ErrorAtTarget)
  2260  	require.NotNil(t, res.Failures[0].ErrorAtSubtree)
  2261  
  2262  	tAliceFQUID := "295a7eea607af32040647123732bc819%1"
  2263  	assertRole(tc, subteamName.String(), alice.Username, keybase1.TeamRole_NONE)
  2264  	assertNoInvite(tc, subteamName.String(), "not_on_kb_yet", "twitter")
  2265  	assertNoInvite(tc, subteamName.String(), "hello", "reddit")
  2266  	assertNoInvite(tc, subteamName.String(), tAliceFQUID, "keybase")
  2267  	assertRole(tc, subsubteamName.String(), alice.Username, keybase1.TeamRole_NONE)
  2268  	assertInvite(tc, subsubteamName.String(), tAliceFQUID, "keybase", keybase1.TeamRole_WRITER)
  2269  	assertNoInvite(tc, subsubteamName.String(), "not_on_kb_yet", "twitter")
  2270  	assertNoInvite(tc, subsubsubteamName.String(), "not_on_kb_yet", "twitter")
  2271  
  2272  	t.Logf("test removing self")
  2273  	_, err = AddMember(context.TODO(), tc.G, subteamName.String(), admin.Username, keybase1.TeamRole_WRITER, nil)
  2274  	require.NoError(t, err)
  2275  	_, err = AddMember(context.TODO(), tc.G, subsubsubteamName.String(), admin.Username, keybase1.TeamRole_WRITER, nil)
  2276  	require.NoError(t, err)
  2277  	res, err = RemoveMembers(context.TODO(), tc.G, subteam.ID, []keybase1.TeamMemberToRemove{
  2278  		rmRecursiveMaker(admin.Username),
  2279  	}, false)
  2280  	require.NoError(t, err)
  2281  	require.Len(t, res.Failures, 0)
  2282  	assertRole(tc, subteamName.String(), admin.Username, keybase1.TeamRole_NONE)
  2283  	assertRole(tc, subsubsubteamName.String(), admin.Username, keybase1.TeamRole_NONE)
  2284  }
  2285  
  2286  func TestFindAssertionsInTeamForInvites(t *testing.T) {
  2287  	tc, owner, _, teamID := memberSetupWithID(t)
  2288  	defer tc.Cleanup()
  2289  
  2290  	phone := kbtest.GenerateTestPhoneNumber()
  2291  
  2292  	err := InviteEmailPhoneMember(context.TODO(), tc.G, teamID, phone, "phone", keybase1.TeamRole_READER)
  2293  	require.NoError(t, err)
  2294  
  2295  	{
  2296  		assertions := []string{
  2297  			phone + "@phone",
  2298  		}
  2299  		ret, err := FindAssertionsInTeamNoResolve(tc.MetaContext(), teamID, assertions)
  2300  		require.NoError(t, err)
  2301  		require.Len(t, ret, 1)
  2302  		require.Equal(t, phone+"@phone", ret[0])
  2303  	}
  2304  
  2305  	{
  2306  		phone2 := kbtest.GenerateTestPhoneNumber()
  2307  		assertions := []string{
  2308  			phone2 + "@phone",
  2309  			phone + "@phone",
  2310  		}
  2311  		ret, err := FindAssertionsInTeamNoResolve(tc.MetaContext(), teamID, assertions)
  2312  		require.NoError(t, err)
  2313  		require.Len(t, ret, 1)
  2314  		require.Equal(t, phone+"@phone", ret[0])
  2315  	}
  2316  
  2317  	email := kbtest.GenerateRandomEmailAddress()
  2318  	err = InviteEmailPhoneMember(context.TODO(), tc.G, teamID, email.String(), "email", keybase1.TeamRole_WRITER)
  2319  	require.NoError(t, err)
  2320  
  2321  	{
  2322  		assertions := []string{
  2323  			fmt.Sprintf("[%s]@email", email),
  2324  		}
  2325  		ret, err := FindAssertionsInTeamNoResolve(tc.MetaContext(), teamID, assertions)
  2326  		require.NoError(t, err)
  2327  		require.Len(t, ret, 1)
  2328  		require.Equal(t, assertions[0], ret[0])
  2329  	}
  2330  
  2331  	{
  2332  		assertions := []string{
  2333  			fmt.Sprintf("[%s]@email", email),
  2334  			owner.Username,
  2335  		}
  2336  		ret, err := FindAssertionsInTeamNoResolve(tc.MetaContext(), teamID, assertions)
  2337  		require.NoError(t, err)
  2338  		require.Len(t, ret, 2)
  2339  		require.Equal(t, assertions[0], ret[0])
  2340  		require.Equal(t, owner.Username, ret[1])
  2341  	}
  2342  
  2343  	email2 := kbtest.GenerateRandomEmailAddress()
  2344  	err = InviteEmailPhoneMember(context.TODO(), tc.G, teamID, email2.String(), "email", keybase1.TeamRole_WRITER)
  2345  	require.NoError(t, err)
  2346  
  2347  	{
  2348  		var assertions []string
  2349  		assertions = append(assertions, fmt.Sprintf("[%s]@email", email2))
  2350  		for i := 0; i < 5; i++ {
  2351  			assertions = append(assertions, fmt.Sprintf("[%s]@email", kbtest.GenerateRandomEmailAddress()))
  2352  		}
  2353  		assertions = append(assertions, fmt.Sprintf("[%s]@email", email))
  2354  		ret, err := FindAssertionsInTeamNoResolve(tc.MetaContext(), teamID, assertions)
  2355  		require.NoError(t, err)
  2356  		require.Len(t, ret, 2)
  2357  		require.Equal(t, assertions[0], ret[0])
  2358  		require.Equal(t, assertions[6], ret[1])
  2359  	}
  2360  }
  2361  
  2362  func TestFindAssertionsInTeamForUsers(t *testing.T) {
  2363  	tc, owner, otherA, otherB, _, teamID := memberSetupMultipleWithTeamID(t)
  2364  	defer tc.Cleanup()
  2365  
  2366  	_, err := AddMemberByID(context.Background(), tc.G, teamID, otherA.Username, keybase1.TeamRole_WRITER,
  2367  		nil /* botSettings */, nil /* emailInviteMsg */)
  2368  	require.NoError(t, err)
  2369  
  2370  	{
  2371  		assertions := []string{
  2372  			otherA.Username,
  2373  		}
  2374  		ret, err := FindAssertionsInTeamNoResolve(tc.MetaContext(), teamID, assertions)
  2375  		require.NoError(t, err)
  2376  		require.Len(t, ret, 1)
  2377  		require.Equal(t, otherA.Username, ret[0])
  2378  	}
  2379  
  2380  	{
  2381  		assertions := []string{
  2382  			otherB.Username,
  2383  		}
  2384  		ret, err := FindAssertionsInTeamNoResolve(tc.MetaContext(), teamID, assertions)
  2385  		require.NoError(t, err)
  2386  		require.Len(t, ret, 0)
  2387  	}
  2388  
  2389  	{
  2390  		assertions := []string{
  2391  			otherB.Username,
  2392  			otherA.Username,
  2393  		}
  2394  		ret, err := FindAssertionsInTeamNoResolve(tc.MetaContext(), teamID, assertions)
  2395  		require.NoError(t, err)
  2396  		require.Len(t, ret, 1)
  2397  		require.Equal(t, otherA.Username, ret[0])
  2398  	}
  2399  
  2400  	{
  2401  		assertions := []string{
  2402  			otherB.Username,
  2403  			otherA.Username,
  2404  			owner.Username,
  2405  		}
  2406  		ret, err := FindAssertionsInTeamNoResolve(tc.MetaContext(), teamID, assertions)
  2407  		require.NoError(t, err)
  2408  		require.Len(t, ret, 2)
  2409  		require.Equal(t, otherA.Username, ret[0])
  2410  		require.Equal(t, owner.Username, ret[1])
  2411  	}
  2412  
  2413  	_, err = AddMemberByID(context.Background(), tc.G, teamID, otherB.Username, keybase1.TeamRole_WRITER,
  2414  		nil /* botSettings */, nil /* emailInviteMsg */)
  2415  	require.NoError(t, err)
  2416  
  2417  	{
  2418  		assertions := []string{
  2419  			otherA.Username,
  2420  			otherB.Username,
  2421  		}
  2422  		ret, err := FindAssertionsInTeamNoResolve(tc.MetaContext(), teamID, assertions)
  2423  		require.NoError(t, err)
  2424  		require.Len(t, ret, 2)
  2425  		require.Equal(t, otherA.Username, ret[0])
  2426  		require.Equal(t, otherB.Username, ret[1])
  2427  	}
  2428  
  2429  	{
  2430  		// Try invalid username
  2431  		buf := make([]byte, 5)
  2432  		_, err := rand.Read(buf)
  2433  		require.NoError(t, err)
  2434  		username := hex.EncodeToString(buf)
  2435  
  2436  		assertions := []string{
  2437  			otherA.Username,
  2438  			otherB.Username,
  2439  			username,
  2440  		}
  2441  		ret, err := FindAssertionsInTeamNoResolve(tc.MetaContext(), teamID, assertions)
  2442  		require.NoError(t, err)
  2443  		require.Len(t, ret, 2)
  2444  		require.Equal(t, otherA.Username, ret[0])
  2445  		require.Equal(t, otherB.Username, ret[1])
  2446  	}
  2447  
  2448  	{
  2449  		// Deduplicate, do not check same assertion more than once.
  2450  		assertions := []string{
  2451  			owner.Username,
  2452  			owner.Username,
  2453  			owner.Username,
  2454  		}
  2455  		ret, err := FindAssertionsInTeamNoResolve(tc.MetaContext(), teamID, assertions)
  2456  		require.NoError(t, err)
  2457  		require.Len(t, ret, 1)
  2458  		require.Equal(t, owner.Username, ret[0])
  2459  	}
  2460  }
  2461  
  2462  func TestFindAssertionsInTeamCompound(t *testing.T) {
  2463  	tc, owner, _, teamID := memberSetupWithID(t)
  2464  	defer tc.Cleanup()
  2465  
  2466  	kbtest.Logout(tc)
  2467  	user, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
  2468  	require.NoError(t, err)
  2469  
  2470  	kbtest.LogoutAndLoginAs(tc, owner)
  2471  
  2472  	assertionStr := fmt.Sprintf("%s@rooter+%s", user.Username, user.Username)
  2473  
  2474  	ret, err := FindAssertionsInTeamNoResolve(tc.MetaContext(), teamID, []string{assertionStr})
  2475  	require.NoError(t, err)
  2476  	require.Len(t, ret, 0)
  2477  
  2478  	_, err = AddMemberByID(context.Background(), tc.G, teamID, user.Username, keybase1.TeamRole_WRITER,
  2479  		nil /* botSettings */, nil /* emailInviteMsg */)
  2480  	require.NoError(t, err)
  2481  
  2482  	// Should find them even if user doesn't prove rooter - this function does
  2483  	// not do any resolutions, just looks at usernames and current member set.
  2484  	ret, err = FindAssertionsInTeamNoResolve(tc.MetaContext(), teamID, []string{assertionStr})
  2485  	require.NoError(t, err)
  2486  	require.Len(t, ret, 1)
  2487  	require.Equal(t, assertionStr, ret[0])
  2488  
  2489  	badAssertion := fmt.Sprintf("%s@rooter+%s+%s", user.Username, user.Username, owner.Username)
  2490  	_, err = FindAssertionsInTeamNoResolve(tc.MetaContext(), teamID, []string{badAssertion})
  2491  	require.Error(t, err)
  2492  	require.Contains(t, err.Error(), "has more than one Keybase username")
  2493  
  2494  	badAssertion = fmt.Sprintf("%s@rooter+%s@rooter", user.Username, owner.Username)
  2495  	_, err = FindAssertionsInTeamNoResolve(tc.MetaContext(), teamID, []string{badAssertion})
  2496  	require.Error(t, err)
  2497  	require.Contains(t, err.Error(), "does not have Keybase username")
  2498  }
  2499  
  2500  func TestTeamPlayerIdempotentChangesAssertRole(t *testing.T) {
  2501  	// Test change_memberships that do not change role  and if they work
  2502  	// correctly with AssertWasRoleOrAboveAt function.
  2503  
  2504  	tc, team, me := setupTestForPrechecks(t, false /* implicitTeam */)
  2505  	defer tc.Cleanup()
  2506  
  2507  	uvAlice := keybase1.UserVersion{Uid: libkb.UsernameToUID("t_alice"), EldestSeqno: 1}
  2508  	uvBob := keybase1.UserVersion{Uid: libkb.UsernameToUID("t_bob"), EldestSeqno: 1}
  2509  
  2510  	// Initial setup:
  2511  	// Add Alice as a writer and Bob as an admin, in separate links.
  2512  
  2513  	memberLists := []*SCTeamMembers{
  2514  		{Writers: &[]SCTeamMember{SCTeamMember(uvAlice)}},
  2515  		{Admins: &[]SCTeamMember{SCTeamMember(uvBob)}},
  2516  	}
  2517  
  2518  	var err error
  2519  	var state *TeamSigChainState
  2520  	for _, v := range memberLists {
  2521  		teamSectionCM := makeTestSCTeamSection(team)
  2522  		teamSectionCM.Members = v
  2523  		state, err = appendSigToState(t, team, state, libkb.LinkTypeChangeMembership,
  2524  			teamSectionCM, me, nil /* merkleRoot */)
  2525  		require.NoError(t, err)
  2526  	}
  2527  
  2528  	require.EqualValues(t, 3, state.GetLatestSeqno())
  2529  
  2530  	makeScl := func(seqno int) keybase1.SigChainLocation {
  2531  		return keybase1.SigChainLocation{
  2532  			Seqno:   keybase1.Seqno(seqno),
  2533  			SeqType: keybase1.SeqType_SEMIPRIVATE,
  2534  		}
  2535  	}
  2536  
  2537  	err = state.AssertWasRoleOrAboveAt(uvAlice, keybase1.TeamRole_WRITER, makeScl(1))
  2538  	require.Error(t, err)
  2539  	require.IsType(t, PermissionError{}, err)
  2540  
  2541  	for i := 1; i <= 2; i++ {
  2542  		// Bob was only added at seqno 3, so at seqnos 1 and 2 they weren't an
  2543  		// admin yet.
  2544  		err = state.AssertWasRoleOrAboveAt(uvBob, keybase1.TeamRole_ADMIN, makeScl(i))
  2545  		require.Error(t, err)
  2546  		require.IsType(t, AdminPermissionError{}, err)
  2547  	}
  2548  
  2549  	err = state.AssertWasRoleOrAboveAt(uvAlice, keybase1.TeamRole_WRITER, makeScl(2))
  2550  	require.NoError(t, err)
  2551  
  2552  	err = state.AssertWasRoleOrAboveAt(uvBob, keybase1.TeamRole_ADMIN, makeScl(3))
  2553  	require.NoError(t, err)
  2554  
  2555  	// Using memberLists, do bunch of idempotent role changes
  2556  	for i := 0; i < 2; i++ {
  2557  		for _, v := range memberLists {
  2558  			teamSectionCM := makeTestSCTeamSection(team)
  2559  			teamSectionCM.Members = v
  2560  			state, err = appendSigToState(t, team, state, libkb.LinkTypeChangeMembership,
  2561  				teamSectionCM, me, nil /* merkleRoot */)
  2562  			require.NoError(t, err)
  2563  		}
  2564  	}
  2565  
  2566  	require.EqualValues(t, 7, state.GetLatestSeqno())
  2567  
  2568  	// Alice is still a writer at every of the new seqnos.
  2569  	for i := 2; i <= 7; i++ {
  2570  		err = state.AssertWasRoleOrAboveAt(uvAlice, keybase1.TeamRole_WRITER, makeScl(i))
  2571  		require.NoError(t, err)
  2572  	}
  2573  
  2574  	// Bob is still an admin at every of the new seqnos.
  2575  	for i := 3; i <= 7; i++ {
  2576  		err = state.AssertWasRoleOrAboveAt(uvBob, keybase1.TeamRole_ADMIN, makeScl(i))
  2577  		require.NoError(t, err)
  2578  	}
  2579  }