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

     1  package teams
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/hex"
     6  	"strings"
     7  	"testing"
     8  
     9  	"golang.org/x/net/context"
    10  
    11  	"github.com/davecgh/go-spew/spew"
    12  	"github.com/keybase/client/go/kbtest"
    13  	"github.com/keybase/client/go/libkb"
    14  	"github.com/keybase/client/go/protocol/keybase1"
    15  	"github.com/keybase/client/go/teams/storage"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  func TestLoaderBasic(t *testing.T) {
    20  	tc := SetupTest(t, "team", 1)
    21  	defer tc.Cleanup()
    22  
    23  	_, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
    24  	require.NoError(t, err)
    25  
    26  	t.Logf("create a team")
    27  	teamName, teamID := createTeam2(tc)
    28  
    29  	t.Logf("load the team")
    30  	team, _, err := tc.G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
    31  		ID: teamID,
    32  	})
    33  	require.NoError(t, err)
    34  	require.Equal(t, teamID, team.Chain.Id)
    35  	require.True(t, teamName.Eq(team.Name))
    36  
    37  	t.Logf("load the team again")
    38  	team, _, err = tc.G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
    39  		ID: teamID,
    40  	})
    41  	require.NoError(t, err)
    42  	require.Equal(t, teamID, team.Chain.Id)
    43  	require.True(t, teamName.Eq(team.Name))
    44  }
    45  
    46  // Test that the loader works after the cache turns stale
    47  // and it goes to the server and finds that there are no updates.
    48  // This does not actually verify that the loader tried to refresh.
    49  func TestLoaderStaleNoUpdates(t *testing.T) {
    50  	tc := SetupTest(t, "team", 1)
    51  	defer tc.Cleanup()
    52  
    53  	_, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
    54  	require.NoError(t, err)
    55  
    56  	public := false
    57  
    58  	t.Logf("create a team")
    59  	teamName, teamID := createTeam2(tc)
    60  
    61  	t.Logf("load the team")
    62  	team, _, err := tc.G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
    63  		ID:     teamID,
    64  		Public: public,
    65  	})
    66  	require.NoError(t, err)
    67  	require.Equal(t, teamID, team.Chain.Id)
    68  	require.True(t, teamName.Eq(team.Name))
    69  
    70  	t.Logf("make the cache look old")
    71  	st := getStorageFromG(tc.G)
    72  	mctx := libkb.NewMetaContextForTest(tc)
    73  	team, frozen, tombstoned := st.Get(mctx, teamID, public)
    74  	require.False(t, frozen)
    75  	require.False(t, tombstoned)
    76  	require.NotNil(t, team)
    77  	t.Logf("cache  pre-set cachedAt:%v", team.CachedAt.Time())
    78  	team.CachedAt = keybase1.ToTime(tc.G.Clock().Now().Add(freshnessLimit * -2))
    79  	st.Put(mctx, team)
    80  	t.Logf("cache post-set cachedAt:%v", team.CachedAt.Time())
    81  
    82  	t.Logf("load the team again")
    83  	team, _, err = tc.G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
    84  		ID:     teamID,
    85  		Public: public,
    86  	})
    87  	require.NoError(t, err)
    88  	require.Equal(t, teamID, team.Chain.Id)
    89  	require.True(t, teamName.Eq(team.Name))
    90  	require.Equal(t, public, team.Chain.Public)
    91  }
    92  
    93  // Test loading a root team by name.
    94  func TestLoaderByName(t *testing.T) {
    95  	tc := SetupTest(t, "team", 1)
    96  	defer tc.Cleanup()
    97  
    98  	_, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
    99  	require.NoError(t, err)
   100  
   101  	t.Logf("create a team")
   102  	teamName, teamID := createTeam2(tc)
   103  
   104  	t.Logf("load the team")
   105  	team, _, err := tc.G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   106  		Name: teamName.String(),
   107  	})
   108  	require.NoError(t, err)
   109  	require.Equal(t, teamID, team.Chain.Id)
   110  	require.True(t, teamName.Eq(team.Name))
   111  }
   112  
   113  // Test loading a team with NeedKeyGeneration set.
   114  // User A creates a team and rotate the key several times.
   115  // User B caches the team at generation 1, and then loads with NeedKeyGeneration later.
   116  //
   117  //	which should get the latest generation that exists.
   118  //
   119  // User C is a bot and never has access to keys.
   120  func TestLoaderKeyGen(t *testing.T) {
   121  	fus, tcs, cleanup := setupNTests(t, 4)
   122  	defer cleanup()
   123  
   124  	// Require that a team is at this key generation
   125  	requireGen := func(team *keybase1.TeamData, generation int) {
   126  		require.NotNil(t, team)
   127  		require.Len(t, team.PerTeamKeySeedsUnverified, generation)
   128  		require.Len(t, team.Chain.PerTeamKeys, generation)
   129  	}
   130  
   131  	t.Logf("create team")
   132  	teamName, teamID := createTeam2(*tcs[0])
   133  
   134  	t.Logf("add B to the team so they can load it")
   135  	_, err := AddMember(context.TODO(), tcs[0].G, teamName.String(), fus[1].Username, keybase1.TeamRole_READER, nil)
   136  	require.NoError(t, err)
   137  
   138  	t.Logf("B's first load at gen 1")
   139  	team, _, err := tcs[1].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   140  		ID: teamID,
   141  	})
   142  	require.NoError(t, err)
   143  	requireGen(team, 1)
   144  	require.Equal(t, keybase1.Seqno(2), team.Chain.LastSeqno, "chain seqno")
   145  	require.Len(t, team.ReaderKeyMasks[keybase1.TeamApplication_KBFS], 1, "number of kbfs rkms")
   146  
   147  	t.Logf("add C to the team so they can load it")
   148  	_, err = AddMember(context.TODO(), tcs[0].G, teamName.String(), fus[2].Username, keybase1.TeamRole_BOT, nil)
   149  	require.NoError(t, err)
   150  
   151  	t.Logf("C's first load at gen 1")
   152  	team, _, err = tcs[2].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   153  		ID: teamID,
   154  	})
   155  	require.NoError(t, err)
   156  	requireGen(team, 1)
   157  	require.Equal(t, keybase1.Seqno(3), team.Chain.LastSeqno, "chain seqno")
   158  	require.Len(t, team.ReaderKeyMasks[keybase1.TeamApplication_KBFS], 1, "number of kbfs rkms")
   159  
   160  	t.Logf("add D to the team so they can load it")
   161  	_, err = AddMember(context.TODO(), tcs[0].G, teamName.String(), fus[3].Username, keybase1.TeamRole_RESTRICTEDBOT, &keybase1.TeamBotSettings{})
   162  	require.NoError(t, err)
   163  
   164  	t.Logf("D's first load at gen 1, expect no secrets")
   165  	team, _, err = tcs[3].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   166  		ID: teamID,
   167  	})
   168  	require.NoError(t, err)
   169  	require.NotNil(t, team)
   170  	require.Zero(t, len(team.PerTeamKeySeedsUnverified))
   171  	require.Len(t, team.Chain.PerTeamKeys, 1)
   172  	require.Equal(t, keybase1.Seqno(5), team.Chain.LastSeqno, "chain seqno")
   173  	require.Zero(t, len(team.ReaderKeyMasks))
   174  
   175  	t.Logf("rotate the key a bunch of times")
   176  	// Rotate the key by removing and adding B from the team
   177  	for i := 0; i < 3; i++ {
   178  		err = RemoveMember(context.TODO(), tcs[0].G, teamName.String(), fus[1].Username)
   179  		require.NoError(t, err)
   180  
   181  		_, err = AddMember(context.TODO(), tcs[0].G, teamName.String(), fus[1].Username, keybase1.TeamRole_READER, nil)
   182  		require.NoError(t, err)
   183  	}
   184  
   185  	t.Logf("load as A to check the progression")
   186  	team, _, err = tcs[0].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   187  		ID:          teamID,
   188  		ForceRepoll: true,
   189  	})
   190  	require.NoError(t, err)
   191  	requireGen(team, 4)
   192  	require.Equal(t, keybase1.Seqno(11), team.Chain.LastSeqno)
   193  	require.Len(t, team.ReaderKeyMasks[keybase1.TeamApplication_KBFS], 4, "number of kbfs rkms")
   194  
   195  	t.Logf("B loads and hits its cache")
   196  	team, _, err = tcs[1].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   197  		ID: teamID,
   198  	})
   199  	require.NoError(t, err)
   200  	require.Equal(t, keybase1.Seqno(2), team.Chain.LastSeqno, "chain seqno")
   201  	requireGen(team, 1)
   202  	require.Len(t, team.ReaderKeyMasks[keybase1.TeamApplication_KBFS], 1, "number of kbfs rkms")
   203  
   204  	t.Logf("B loads with NeedKeyGeneration")
   205  	team, _, err = tcs[1].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   206  		ID: teamID,
   207  		Refreshers: keybase1.TeamRefreshers{
   208  			NeedKeyGeneration: 3,
   209  		},
   210  	})
   211  	require.NoError(t, err)
   212  	requireGen(team, 4)
   213  	require.Len(t, team.ReaderKeyMasks[keybase1.TeamApplication_KBFS], 4, "number of kbfs rkms")
   214  
   215  	t.Logf("D loads with NeedKeyGeneration and errors out")
   216  	_, _, err = tcs[3].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   217  		ID: teamID,
   218  		Refreshers: keybase1.TeamRefreshers{
   219  			NeedKeyGeneration: 3,
   220  		},
   221  	})
   222  	require.Error(t, err)
   223  	require.True(t, strings.Contains(err.Error(), "team key secret missing"))
   224  
   225  	t.Logf("D loads and never has keys")
   226  	team, _, err = tcs[3].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   227  		ID:          teamID,
   228  		ForceRepoll: true,
   229  	})
   230  	require.NoError(t, err)
   231  	require.NotNil(t, team)
   232  	require.Equal(t, keybase1.Seqno(11), team.Chain.LastSeqno, "chain seqno")
   233  	require.Zero(t, len(team.PerTeamKeySeedsUnverified))
   234  	require.Len(t, team.Chain.PerTeamKeys, 4)
   235  	require.Zero(t, len(team.ReaderKeyMasks))
   236  
   237  	t.Logf("D becomes a regular bot and gets access")
   238  	err = EditMember(context.TODO(), tcs[0].G, teamName.String(), fus[3].Username, keybase1.TeamRole_BOT, nil)
   239  	require.NoError(t, err)
   240  
   241  	team, _, err = tcs[3].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   242  		ID: teamID,
   243  		Refreshers: keybase1.TeamRefreshers{
   244  			NeedKeyGeneration: 3,
   245  		},
   246  	})
   247  	require.NoError(t, err)
   248  	requireGen(team, 4)
   249  	require.Len(t, team.ReaderKeyMasks[keybase1.TeamApplication_KBFS], 4, "number of kbfs rkms")
   250  
   251  	t.Logf("C becomes a restricted bot and has no access")
   252  	err = EditMember(context.TODO(), tcs[0].G, teamName.String(), fus[2].Username, keybase1.TeamRole_RESTRICTEDBOT, &keybase1.TeamBotSettings{})
   253  	require.NoError(t, err)
   254  
   255  	team, _, err = tcs[2].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   256  		ID:          teamID,
   257  		ForceRepoll: true,
   258  	})
   259  	require.NoError(t, err)
   260  	require.NotNil(t, team)
   261  	require.Zero(t, len(team.PerTeamKeySeedsUnverified))
   262  	require.Len(t, team.Chain.PerTeamKeys, 4)
   263  	require.Zero(t, len(team.ReaderKeyMasks))
   264  }
   265  
   266  func TestLoaderKBFSKeyGen(t *testing.T) {
   267  	fus, tcs, cleanup := setupNTests(t, 2)
   268  	defer cleanup()
   269  
   270  	// Require that a team is at this KBFS key generation
   271  	requireGen := func(team *keybase1.TeamData, generation int) {
   272  		require.NotNil(t, team)
   273  		keys, ok := team.TlfCryptKeys[keybase1.TeamApplication_CHAT]
   274  		require.True(t, ok)
   275  		require.True(t, keys[len(keys)-1].KeyGeneration >= generation)
   276  	}
   277  
   278  	displayName := fus[0].Username + "," + fus[1].Username
   279  	team, _, _, err := LookupOrCreateImplicitTeam(context.TODO(), tcs[0].G, displayName, false)
   280  	require.NoError(t, err)
   281  
   282  	tlfID := newImplicitTLFID(false)
   283  	cryptKeys := []keybase1.CryptKey{{
   284  		KeyGeneration: 1,
   285  	}, {
   286  		KeyGeneration: 2,
   287  	}}
   288  	require.NoError(t, team.AssociateWithTLFKeyset(context.TODO(), tlfID, cryptKeys,
   289  		keybase1.TeamApplication_CHAT))
   290  	team, err = Load(context.TODO(), tcs[0].G, keybase1.LoadTeamArg{
   291  		ID: team.ID,
   292  	})
   293  	require.NoError(t, err)
   294  
   295  	// See TODO below, CORE-9677. This test previously relied on buggy behavior, which now is fixed.
   296  	// require.Zero(t, len(team.KBFSCryptKeys(context.TODO(), keybase1.TeamApplication_CHAT)))
   297  
   298  	team, err = Load(context.TODO(), tcs[0].G, keybase1.LoadTeamArg{
   299  		ID: team.ID,
   300  		Refreshers: keybase1.TeamRefreshers{
   301  			NeedKBFSKeyGeneration: keybase1.TeamKBFSKeyRefresher{
   302  				Generation: 2,
   303  				AppType:    keybase1.TeamApplication_CHAT,
   304  			},
   305  		},
   306  	})
   307  	require.NoError(t, err)
   308  	requireGen(team.Data, 2)
   309  }
   310  
   311  func TestLoaderKBFSKeyGenOffset(t *testing.T) {
   312  	fus, tcs, cleanup := setupNTests(t, 2)
   313  	defer cleanup()
   314  
   315  	displayName := fus[0].Username + "," + fus[1].Username
   316  	team, _, _, err := LookupOrCreateImplicitTeam(context.TODO(), tcs[0].G, displayName, false)
   317  	require.NoError(t, err)
   318  
   319  	tlfID := newImplicitTLFID(false)
   320  	key1 := [32]byte{0, 1}
   321  	key2 := [32]byte{0, 2}
   322  	cryptKeys := []keybase1.CryptKey{{
   323  		KeyGeneration: 1,
   324  		Key:           key1,
   325  	}, {
   326  		KeyGeneration: 2,
   327  		Key:           key2,
   328  	}}
   329  	require.NoError(t, team.AssociateWithTLFKeyset(context.TODO(), tlfID, cryptKeys,
   330  		keybase1.TeamApplication_KBFS))
   331  	team, err = Load(context.TODO(), tcs[0].G, keybase1.LoadTeamArg{
   332  		ID: team.ID,
   333  	})
   334  	require.NoError(t, err)
   335  	keys, err := team.AllApplicationKeysWithKBFS(context.TODO(), keybase1.TeamApplication_KBFS)
   336  	require.NoError(t, err)
   337  
   338  	// TODO -- See CORE-9677 - fix this test to switch users to test the refresher, since if Alice does the update
   339  	// herself, her load is autorefreshed after bugfixes in CORE-9663.
   340  	require.Equal(t, 3, len(keys))
   341  	require.Equal(t, 1, keys[0].Generation())
   342  	key3 := keys[2].Key // See above TODO, this is also wonky
   343  
   344  	team, err = Load(context.TODO(), tcs[0].G, keybase1.LoadTeamArg{
   345  		ID: team.ID,
   346  		Refreshers: keybase1.TeamRefreshers{
   347  			NeedApplicationsAtGenerationsWithKBFS: map[keybase1.PerTeamKeyGeneration][]keybase1.TeamApplication{
   348  				3: {keybase1.TeamApplication_KBFS},
   349  			},
   350  		},
   351  	})
   352  
   353  	require.NoError(t, err)
   354  	keys, err = team.AllApplicationKeysWithKBFS(context.TODO(), keybase1.TeamApplication_KBFS)
   355  	require.NoError(t, err)
   356  	require.Equal(t, 3, len(keys))
   357  	key, err := team.ApplicationKeyAtGenerationWithKBFS(context.TODO(), keybase1.TeamApplication_KBFS, 1)
   358  	require.NoError(t, err)
   359  	require.Equal(t, 1, key.Generation())
   360  	require.True(t, bytes.Equal(key1[:], key.Key[:]))
   361  	key, err = team.ApplicationKeyAtGenerationWithKBFS(context.TODO(), keybase1.TeamApplication_KBFS, 3)
   362  	require.NoError(t, err)
   363  	require.Equal(t, 3, key.Generation())
   364  	require.True(t, bytes.Equal(key3[:], key.Key[:]))
   365  }
   366  
   367  // Test loading a team with WantMembers set.
   368  func TestLoaderWantMembers(t *testing.T) {
   369  	fus, tcs, cleanup := setupNTests(t, 4)
   370  	defer cleanup()
   371  
   372  	// Require that a team is at this seqno
   373  	requireSeqno := func(team *keybase1.TeamData, seqno int, dots ...interface{}) {
   374  		require.NotNil(t, team, dots...)
   375  		require.Equal(t, keybase1.Seqno(seqno), TeamSigChainState{inner: team.Chain}.GetLatestSeqno(), dots...)
   376  	}
   377  
   378  	t.Logf("U0 creates a team (seqno:1)")
   379  	teamName, teamID := createTeam2(*tcs[0])
   380  
   381  	t.Logf("U0 adds U1 to the team (2)")
   382  	_, err := AddMember(context.TODO(), tcs[0].G, teamName.String(), fus[1].Username, keybase1.TeamRole_ADMIN, nil)
   383  	require.NoError(t, err)
   384  
   385  	t.Logf("U1 loads and caches")
   386  	team, _, err := tcs[1].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   387  		ID: teamID,
   388  	})
   389  	require.NoError(t, err)
   390  	requireSeqno(team, 2)
   391  
   392  	t.Logf("U0 bumps the sigchain (add U3) (3)")
   393  	_, err = AddMember(context.TODO(), tcs[0].G, teamName.String(), fus[3].Username, keybase1.TeamRole_ADMIN, nil)
   394  	require.NoError(t, err)
   395  
   396  	t.Logf("U1 loads and hits the cache")
   397  	team, _, err = tcs[1].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   398  		ID: teamID,
   399  	})
   400  	require.NoError(t, err)
   401  	requireSeqno(team, 2)
   402  
   403  	t.Logf("U1 loads with WantMembers=U2 and that causes a repoll but no error")
   404  	loadAsU1WantU2 := func() *keybase1.TeamData {
   405  		team, _, err := tcs[1].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   406  			ID: teamID,
   407  			Refreshers: keybase1.TeamRefreshers{
   408  				WantMembers: []keybase1.UserVersion{fus[2].GetUserVersion()},
   409  			},
   410  		})
   411  		require.NoError(t, err)
   412  		return team
   413  	}
   414  	team = loadAsU1WantU2()
   415  	requireSeqno(team, 3, "seqno should advance because wantmembers pre-check fails")
   416  
   417  	t.Logf("U0 adds U2 (4)")
   418  	_, err = AddMember(context.TODO(), tcs[0].G, teamName.String(), fus[2].Username, keybase1.TeamRole_WRITER, nil)
   419  	require.NoError(t, err)
   420  
   421  	t.Logf("U1 loads with WantMembers=U2 and it works")
   422  	team = loadAsU1WantU2()
   423  	requireSeqno(team, 4, "seqno should advance to pick up the new link")
   424  	role, err := TeamSigChainState{inner: team.Chain}.GetUserRole(fus[2].GetUserVersion())
   425  	require.NoError(t, err)
   426  	require.Equal(t, keybase1.TeamRole_WRITER, role)
   427  
   428  	t.Logf("U0 bumps the sigchain (removemember) (5)")
   429  	err = RemoveMember(context.TODO(), tcs[0].G, teamName.String(), fus[3].Username)
   430  	require.NoError(t, err)
   431  
   432  	t.Logf("U1 loads with WantMembers=U2 and it hits the cache")
   433  	team = loadAsU1WantU2()
   434  	requireSeqno(team, 4, "seqno should not advance because this should be a cache hit")
   435  }
   436  
   437  // Test loading a team that has a subteam in it
   438  func TestLoaderParentEasy(t *testing.T) {
   439  	_, tcs, cleanup := setupNTests(t, 1)
   440  	defer cleanup()
   441  
   442  	t.Logf("create a team")
   443  	teamName, teamID := createTeam2(*tcs[0])
   444  
   445  	t.Logf("create a subteam")
   446  	subteamID, err := CreateSubteam(context.TODO(), tcs[0].G, "mysubteam", teamName, keybase1.TeamRole_NONE /* addSelfAs */)
   447  	require.NoError(t, err)
   448  
   449  	t.Logf("load the parent")
   450  	team, _, err := tcs[0].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   451  		ID:          teamID,
   452  		ForceRepoll: true,
   453  	})
   454  	require.NoError(t, err)
   455  	require.Equal(t, team.Chain.Id, teamID)
   456  	require.False(t, TeamSigChainState{inner: team.Chain}.HasAnyStubbedLinks(), "team has stubbed links")
   457  	subteamName, err := TeamSigChainState{inner: team.Chain}.GetSubteamName(*subteamID)
   458  	if err != nil {
   459  		t.Logf("seqno: %v", TeamSigChainState{inner: team.Chain}.GetLatestSeqno())
   460  		t.Logf("subteam log: %v", spew.Sdump(team.Chain.SubteamLog))
   461  		require.NoError(t, err)
   462  	}
   463  	expectedSubteamName, err := teamName.Append("mysubteam")
   464  	require.NoError(t, err)
   465  	require.Equal(t, expectedSubteamName, *subteamName)
   466  }
   467  
   468  // Test loading a subteam
   469  func TestLoaderSubteamEasy(t *testing.T) {
   470  	_, tcs, cleanup := setupNTests(t, 1)
   471  	defer cleanup()
   472  
   473  	t.Logf("create a team")
   474  	parentName, parentID := createTeam2(*tcs[0])
   475  
   476  	t.Logf("create a subteam")
   477  	subteamID, err := CreateSubteam(context.TODO(), tcs[0].G, "mysubteam", parentName, keybase1.TeamRole_NONE /* addSelfAs */)
   478  	require.NoError(t, err)
   479  
   480  	t.Logf("load the subteam")
   481  	team, _, err := tcs[0].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   482  		ID: *subteamID,
   483  	})
   484  	require.NoError(t, err)
   485  	require.Equal(t, team.Chain.Id, *subteamID)
   486  	expectedSubteamName, err := parentName.Append("mysubteam")
   487  	require.NoError(t, err)
   488  	require.Equal(t, expectedSubteamName, team.Name)
   489  	require.Equal(t, parentID, *team.Chain.ParentID)
   490  }
   491  
   492  // Test loading a team and filling in links.
   493  // User loads a team T1 with subteam links stubbed out,
   494  // then gets added to T1.T2 and T1,
   495  // then loads T1.T2, which causes T1 to have to fill in the subteam links.
   496  func TestLoaderFillStubbed(t *testing.T) {
   497  	fus, tcs, cleanup := setupNTests(t, 2)
   498  	defer cleanup()
   499  
   500  	t.Logf("create a team")
   501  	parentName, parentID := createTeam2(*tcs[0])
   502  
   503  	t.Logf("create a subteam")
   504  	subteamID, err := CreateSubteam(context.TODO(), tcs[0].G, "mysubteam", parentName, keybase1.TeamRole_NONE /* addSelfAs */)
   505  	require.NoError(t, err)
   506  
   507  	t.Logf("add U1 to the parent")
   508  	_, err = AddMember(context.TODO(), tcs[0].G, parentName.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
   509  	require.NoError(t, err)
   510  
   511  	t.Logf("U1 loads the parent")
   512  	_, _, err = tcs[1].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   513  		ID: parentID,
   514  	})
   515  	require.NoError(t, err)
   516  
   517  	t.Logf("add U1 to the subteam")
   518  	subteamName, err := parentName.Append("mysubteam")
   519  	require.NoError(t, err)
   520  	_, err = AddMember(context.TODO(), tcs[0].G, subteamName.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
   521  	require.NoError(t, err)
   522  
   523  	t.Logf("U1 loads the subteam")
   524  	_, _, err = tcs[1].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   525  		ID: *subteamID,
   526  	})
   527  	require.NoError(t, err)
   528  }
   529  
   530  // Test loading a team and when not a member of the parent.
   531  // User loads a team T1.T2 but has never been a member of T1.
   532  func TestLoaderNotInParent(t *testing.T) {
   533  	fus, tcs, cleanup := setupNTests(t, 2)
   534  	defer cleanup()
   535  
   536  	t.Logf("create a team")
   537  	parentName, _ := createTeam2(*tcs[0])
   538  
   539  	t.Logf("create a subteam")
   540  	subteamID, err := CreateSubteam(context.TODO(), tcs[0].G, "mysubteam", parentName, keybase1.TeamRole_NONE /* addSelfAs */)
   541  	require.NoError(t, err)
   542  
   543  	t.Logf("add U1 to the subteam")
   544  	subteamName, err := parentName.Append("mysubteam")
   545  	require.NoError(t, err)
   546  	_, err = AddMember(context.TODO(), tcs[0].G, subteamName.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
   547  	require.NoError(t, err)
   548  
   549  	t.Logf("U1 loads the subteam")
   550  	_, _, err = tcs[1].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   551  		ID: *subteamID,
   552  	})
   553  	require.NoError(t, err)
   554  }
   555  
   556  // Test loading a sub-sub-team: a.b.c.
   557  // When not a member of the ancestors: a, a.b.
   558  func TestLoaderMultilevel(t *testing.T) {
   559  	fus, tcs, cleanup := setupNTests(t, 2)
   560  	defer cleanup()
   561  
   562  	t.Logf("create a team")
   563  	parentName, _ := createTeam2(*tcs[0])
   564  
   565  	t.Logf("create a subteam")
   566  	_, err := CreateSubteam(context.TODO(), tcs[0].G, "abc", parentName, keybase1.TeamRole_NONE /* addSelfAs */)
   567  	require.NoError(t, err)
   568  
   569  	t.Logf("create a sub-subteam")
   570  	subTeamName, err := parentName.Append("abc")
   571  	require.NoError(t, err)
   572  	subsubteamID, err := CreateSubteam(context.TODO(), tcs[0].G, "def", subTeamName, keybase1.TeamRole_NONE /* addSelfAs */)
   573  	require.NoError(t, err)
   574  
   575  	expectedSubsubTeamName, err := subTeamName.Append("def")
   576  	require.NoError(t, err)
   577  
   578  	t.Logf("add the other user to the subsubteam")
   579  	_, err = AddMember(context.TODO(), tcs[0].G, expectedSubsubTeamName.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
   580  	require.NoError(t, err)
   581  
   582  	t.Logf("load the subteam")
   583  	team, _, err := tcs[1].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   584  		ID: *subsubteamID,
   585  	})
   586  	require.NoError(t, err)
   587  	require.Equal(t, *subsubteamID, team.Chain.Id)
   588  	require.Equal(t, expectedSubsubTeamName, team.Name)
   589  }
   590  
   591  // Test that loading with wantmembers which have eldestseqno=0 works.
   592  func TestLoaderInferWantMembers(t *testing.T) {
   593  	fus, tcs, cleanup := setupNTests(t, 3)
   594  	defer cleanup()
   595  
   596  	// Require that a team is at this seqno
   597  	requireSeqno := func(team *keybase1.TeamData, seqno int, dots ...interface{}) {
   598  		require.NotNil(t, team, dots...)
   599  		require.Equal(t, keybase1.Seqno(seqno), TeamSigChainState{inner: team.Chain}.GetLatestSeqno(), dots...)
   600  	}
   601  
   602  	t.Logf("U0 creates a team (seqno:1)")
   603  	teamName, teamID := createTeam2(*tcs[0])
   604  
   605  	t.Logf("U0 adds U1 to the team (2)")
   606  	_, err := AddMember(context.TODO(), tcs[0].G, teamName.String(), fus[1].Username, keybase1.TeamRole_ADMIN, nil)
   607  	require.NoError(t, err)
   608  
   609  	t.Logf("U1 loads and caches")
   610  	team, _, err := tcs[1].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   611  		ID: teamID,
   612  	})
   613  	require.NoError(t, err)
   614  	requireSeqno(team, 2)
   615  
   616  	t.Logf("U0 bumps the sigchain (add U2) (3)")
   617  	_, err = AddMember(context.TODO(), tcs[0].G, teamName.String(), fus[2].Username, keybase1.TeamRole_ADMIN, nil)
   618  	require.NoError(t, err)
   619  
   620  	t.Logf("U1 loads and hits the cache")
   621  	team, _, err = tcs[1].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   622  		ID: teamID,
   623  	})
   624  	require.NoError(t, err)
   625  	requireSeqno(team, 2)
   626  
   627  	t.Logf("U1 loads with WantMembers=U2 which infers the eldestseqno and repolls")
   628  	loadAsU1WantU2 := func() *keybase1.TeamData {
   629  		team, _, err := tcs[1].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   630  			ID: teamID,
   631  			Refreshers: keybase1.TeamRefreshers{
   632  				WantMembers: []keybase1.UserVersion{{
   633  					Uid:         fus[2].GetUID(),
   634  					EldestSeqno: 0,
   635  				}},
   636  			},
   637  		})
   638  		require.NoError(t, err)
   639  		return team
   640  	}
   641  	team = loadAsU1WantU2()
   642  	requireSeqno(team, 3, "seqno should advance because wantmembers pre-check fails")
   643  }
   644  
   645  func TestLoaderGetImplicitAdminsList(t *testing.T) {
   646  	fus, tcs, cleanup := setupNTests(t, 3)
   647  	defer cleanup()
   648  
   649  	t.Logf("U1 creates a root team")
   650  	parentName, _ := createTeam2(*tcs[1])
   651  
   652  	t.Logf("U1 adds U2 as an admin")
   653  	_, err := AddMember(context.TODO(), tcs[1].G, parentName.String(), fus[2].Username, keybase1.TeamRole_ADMIN, nil)
   654  	require.NoError(t, err)
   655  
   656  	t.Logf("U2 creates a subteam")
   657  	subteamID, err := CreateSubteam(context.TODO(), tcs[2].G, "sub", parentName, keybase1.TeamRole_NONE /* addSelfAs */)
   658  	require.NoError(t, err)
   659  	subteamName, err := parentName.Append("sub")
   660  	require.NoError(t, err)
   661  
   662  	t.Logf("U0 can't load the subteam")
   663  	_, err = tcs[0].G.GetTeamLoader().ImplicitAdmins(context.TODO(), *subteamID)
   664  	require.Error(t, err, "should not be able to load team when not a member")
   665  
   666  	t.Logf("U2 adds U0 to the subteam (as an admin)")
   667  	_, err = AddMember(context.TODO(), tcs[2].G, subteamName.String(), fus[0].Username, keybase1.TeamRole_ADMIN, nil)
   668  	require.NoError(t, err, "adding member to subteam")
   669  
   670  	assertImpAdmins := func(as *libkb.GlobalContext, teamID keybase1.TeamID, expectedSet []keybase1.UserVersion) {
   671  		impAdmins, err := as.GetTeamLoader().ImplicitAdmins(context.TODO(), teamID)
   672  		require.NoError(t, err)
   673  		require.ElementsMatch(t, impAdmins, expectedSet)
   674  	}
   675  
   676  	t.Logf("U0 sees the 2 implicit admins")
   677  	assertImpAdmins(tcs[0].G, *subteamID, []keybase1.UserVersion{fus[1].GetUserVersion(), fus[2].GetUserVersion()})
   678  
   679  	t.Logf("U1 adds U0 to the root team")
   680  	_, err = AddMember(context.TODO(), tcs[1].G, parentName.String(), fus[0].Username, keybase1.TeamRole_ADMIN, nil)
   681  	require.NoError(t, err)
   682  
   683  	t.Logf("U0 sees the 3 implicit admins")
   684  	assertImpAdmins(tcs[0].G, *subteamID, []keybase1.UserVersion{fus[0].GetUserVersion(), fus[1].GetUserVersion(), fus[2].GetUserVersion()})
   685  }
   686  
   687  // Subteams should be invisible to writers.
   688  // U0 creates a subteam
   689  // U0 adds U1 to the root team
   690  // U1 should not see any subteams
   691  func TestLoaderHiddenSubteam(t *testing.T) {
   692  	fus, tcs, cleanup := setupNTests(t, 2)
   693  	defer cleanup()
   694  
   695  	t.Logf("U0 creates A")
   696  	parentName, parentID := createTeam2(*tcs[0])
   697  
   698  	subteamName1 := createTeamName(t, parentName.String(), "bbb")
   699  
   700  	t.Logf("U0 creates A.B")
   701  	subteamID, err := CreateSubteam(context.TODO(), tcs[0].G, "bbb", parentName, keybase1.TeamRole_NONE /* addSelfAs */)
   702  	require.NoError(t, err)
   703  
   704  	t.Logf("U0 adds U1 to A as a WRITER")
   705  	_, err = AddMember(context.TODO(), tcs[0].G, parentName.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
   706  	require.NoError(t, err)
   707  
   708  	t.Logf("U0 loads A")
   709  	team, err := Load(context.TODO(), tcs[0].G, keybase1.LoadTeamArg{
   710  		ID:          parentID,
   711  		ForceRepoll: true,
   712  	})
   713  	require.NoError(t, err, "load team")
   714  	t.Logf(spew.Sdump(team.chain().inner.SubteamLog))
   715  	require.Len(t, team.chain().ListSubteams(), 1, "subteam list")
   716  	require.Equal(t, *subteamID, team.chain().ListSubteams()[0].Id, "subteam ID")
   717  	require.Equal(t, subteamName1.String(), team.chain().ListSubteams()[0].Name.String(), "subteam name")
   718  
   719  	t.Logf("U1 loads A")
   720  	team, err = Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{
   721  		ID:          parentID,
   722  		ForceRepoll: true,
   723  	})
   724  	require.NoError(t, err, "load team")
   725  	t.Logf(spew.Sdump(team.chain().inner.SubteamLog))
   726  	require.Len(t, team.chain().inner.SubteamLog, 0, "subteam log should be empty because all subteam links were stubbed for this user")
   727  }
   728  
   729  func TestLoaderSubteamHopWithNone(t *testing.T) {
   730  	testLoaderSubteamHop(t, keybase1.TeamRole_NONE)
   731  }
   732  
   733  // A member of A and A.B.C but not A.B should be able to load A.B.C
   734  // when they have already cached A with the new_subteam stubbed out.
   735  func TestLoaderSubteamHopWithWriter(t *testing.T) {
   736  	testLoaderSubteamHop(t, keybase1.TeamRole_WRITER)
   737  }
   738  
   739  func TestLoaderSubteamHopWithAdmin(t *testing.T) {
   740  	testLoaderSubteamHop(t, keybase1.TeamRole_ADMIN)
   741  }
   742  
   743  func testLoaderSubteamHop(t *testing.T, roleInRoot keybase1.TeamRole) {
   744  	t.Logf("testing with roleInRoot: %v", roleInRoot)
   745  	fus, tcs, cleanup := setupNTests(t, 2)
   746  	defer cleanup()
   747  
   748  	t.Logf("U0 creates A")
   749  	rootName, rootID := createTeam2(*tcs[0])
   750  
   751  	t.Logf("U0 creates A.B")
   752  	subteamName, subteamID := createSubteam(tcs[0], rootName, "bbb")
   753  
   754  	if roleInRoot != keybase1.TeamRole_NONE {
   755  		t.Logf("U0 adds U1 to A")
   756  		_, err := AddMember(context.TODO(), tcs[0].G, rootName.String(), fus[1].Username, roleInRoot, nil)
   757  		require.NoError(t, err, "add member")
   758  
   759  		t.Logf("U1 loads and caches A (with A.B's new_subteam link stubbed out)")
   760  		_, err = Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{
   761  			ID:          rootID,
   762  			ForceRepoll: true,
   763  		})
   764  		require.NoError(t, err, "load team")
   765  	}
   766  
   767  	t.Logf("U0 creates A.B.C")
   768  	subsubteamName, subsubteamID := createSubteam(tcs[0], subteamName, "ccc")
   769  
   770  	t.Logf("U0 adds U1 to A.B.C")
   771  	_, err := AddMember(context.TODO(), tcs[0].G, subsubteamName.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
   772  	require.NoError(t, err, "add member")
   773  
   774  	t.Logf("U1 loads A.B.C")
   775  	_, err = Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{
   776  		ID:          subsubteamID,
   777  		ForceRepoll: true,
   778  	})
   779  	require.NoError(t, err, "load team")
   780  
   781  	if roleInRoot == keybase1.TeamRole_NONE {
   782  		t.Logf("U1 cannot load A.B")
   783  		_, err = Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{
   784  			ID: subteamID,
   785  		})
   786  		require.Error(t, err, "shouldn't load team")
   787  	}
   788  }
   789  
   790  func TestLoaderCORE_6230(t *testing.T) {
   791  	fus, tcs, cleanup := setupNTests(t, 2)
   792  	defer cleanup()
   793  
   794  	t.Logf("U0 creates A")
   795  	rootName, rootID := createTeam2(*tcs[0])
   796  
   797  	t.Logf("U0 adds U1 to A")
   798  	_, err := AddMember(context.TODO(), tcs[0].G, rootName.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
   799  	require.NoError(t, err, "add member")
   800  
   801  	t.Logf("U1 loads and caches A")
   802  	_, err = Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{
   803  		ID:          rootID,
   804  		ForceRepoll: true,
   805  	})
   806  	require.NoError(t, err, "load team")
   807  
   808  	t.Logf("U0 creates A.B")
   809  	subteamName, subteamID := createSubteam(tcs[0], rootName, "bbb")
   810  
   811  	t.Logf("U0 adds U1 to A.B")
   812  	_, err = AddMember(context.TODO(), tcs[0].G, subteamName.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
   813  	require.NoError(t, err, "add member")
   814  
   815  	t.Logf("U1 loads A.B")
   816  	_, err = Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{
   817  		ID:          subteamID,
   818  		ForceRepoll: true,
   819  	})
   820  	// There was a bug where this would fail with:
   821  	//   proof error for proof 'became admin before team link': no linkID for seqno 3
   822  	require.NoError(t, err, "load team")
   823  }
   824  
   825  func TestLoaderCORE_6230_2(t *testing.T) {
   826  	fus, tcs, cleanup := setupNTests(t, 2)
   827  	defer cleanup()
   828  
   829  	t.Logf("U0 creates A")
   830  	rootName, rootID := createTeam2(*tcs[0])
   831  
   832  	t.Logf("U0 adds U1 to A")
   833  	_, err := AddMember(context.TODO(), tcs[0].G, rootName.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
   834  	require.NoError(t, err, "add member")
   835  
   836  	t.Logf("U1 loads and caches A")
   837  	_, err = Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{
   838  		ID:          rootID,
   839  		ForceRepoll: true,
   840  	})
   841  	require.NoError(t, err, "load team")
   842  
   843  	t.Logf("U0 creates A.B")
   844  	subteamName, subteamID := createSubteam(tcs[0], rootName, "bbb")
   845  
   846  	t.Logf("U0 adds U1 to A.B")
   847  	_, err = AddMember(context.TODO(), tcs[0].G, subteamName.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
   848  	require.NoError(t, err, "add member")
   849  
   850  	t.Logf("U1 loads A.B")
   851  	_, err = Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{
   852  		ID:          subteamID,
   853  		ForceRepoll: true,
   854  	})
   855  	_ = err // ignore the error if there is one, not testing that part.
   856  
   857  	t.Logf("U1 loads A.B (again, in case there was a bug above)")
   858  	_, err = Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{
   859  		ID:          subteamID,
   860  		ForceRepoll: true,
   861  	})
   862  	require.NoError(t, err, "load team")
   863  
   864  	t.Logf("U0 adds a link to A")
   865  	_, err = AddMember(context.TODO(), tcs[0].G, rootName.String(), "foobar@rooter", keybase1.TeamRole_READER, nil)
   866  	require.NoError(t, err)
   867  
   868  	t.Logf("U0 does an admin action to A.B")
   869  	_, err = AddMember(context.TODO(), tcs[0].G, subteamName.String(), fus[0].Username, keybase1.TeamRole_READER, nil)
   870  	require.NoError(t, err)
   871  
   872  	t.Logf("U1 loads A.B")
   873  	_, err = Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{
   874  		ID:          subteamID,
   875  		ForceRepoll: true,
   876  	})
   877  	require.NoError(t, err, "load team")
   878  }
   879  
   880  // Test that a link can be inflated even if the person who signed the (valid) link has since
   881  // lost permission to do so.
   882  func TestInflateAfterPermissionsChange(t *testing.T) {
   883  	fus, tcs, cleanup := setupNTests(t, 3)
   884  	defer cleanup()
   885  
   886  	// U1 is the user that signed a link and then lost permissions
   887  	// U2 is the user that inflates a link signed by U1
   888  
   889  	t.Logf("U0 creates fennel_network")
   890  	rootName, rootID := createTeam2(*tcs[0])
   891  
   892  	t.Logf("U0 adds U1 to the root")
   893  	_, err := AddMember(context.Background(), tcs[0].G, rootName.String(), fus[1].Username, keybase1.TeamRole_ADMIN, nil)
   894  	require.NoError(t, err)
   895  
   896  	t.Logf("U1 creates fennel_network.lair")
   897  	subteamLairID, err := CreateSubteam(context.Background(), tcs[1].G, "lair", rootName, keybase1.TeamRole_NONE /* addSelfAs */)
   898  	require.NoError(t, err)
   899  	subteamLairName, err := rootName.Append("lair")
   900  	require.NoError(t, err)
   901  
   902  	t.Logf("U1 creates fennel_network.chitchat")
   903  	subteamChitchatID, err := CreateSubteam(context.Background(), tcs[1].G, "chitchat", rootName, keybase1.TeamRole_NONE /* addSelfAs */)
   904  	require.NoError(t, err)
   905  	subteamChitchatName, err := rootName.Append("chitchat")
   906  	require.NoError(t, err)
   907  
   908  	t.Logf("U0 removes U1")
   909  	err = RemoveMember(context.Background(), tcs[0].G, rootName.String(), fus[1].Username)
   910  	require.NoError(t, err)
   911  
   912  	t.Logf("U0 adds U2 to chitchat")
   913  	_, err = AddMember(context.Background(), tcs[0].G, subteamChitchatName.String(), fus[2].Username, keybase1.TeamRole_WRITER, nil)
   914  	require.NoError(t, err)
   915  
   916  	t.Logf("U2 loads chitchat (thereby loading the root with the new_subteam:lair link stubbed out)")
   917  	_, err = Load(context.Background(), tcs[2].G, keybase1.LoadTeamArg{
   918  		ID:          *subteamChitchatID,
   919  		ForceRepoll: true,
   920  	})
   921  	require.NoError(t, err, "load team chitchat")
   922  
   923  	t.Logf("check that the link is stubbed in storage")
   924  	mctx := libkb.NewMetaContextForTest(*tcs[2])
   925  	rootData, frozen, tombstoned := tcs[2].G.GetTeamLoader().(*TeamLoader).storage.Get(mctx, rootID, rootID.IsPublic())
   926  	require.NotNil(t, rootData, "root team should be cached")
   927  	require.False(t, frozen)
   928  	require.False(t, tombstoned)
   929  	require.True(t, (TeamSigChainState{inner: rootData.Chain}).HasAnyStubbedLinks(), "root team should have a stubbed link")
   930  
   931  	t.Logf("U0 adds U2 to lair")
   932  	_, err = AddMember(context.Background(), tcs[0].G, subteamLairName.String(), fus[2].Username, keybase1.TeamRole_WRITER, nil)
   933  	require.NoError(t, err)
   934  
   935  	t.Logf("U2 loads lair (which requires inflating the new_subteam:lair link)")
   936  	_, err = Load(context.Background(), tcs[2].G, keybase1.LoadTeamArg{
   937  		ID:          *subteamLairID,
   938  		ForceRepoll: true,
   939  	})
   940  	require.NoError(t, err, "load team lair")
   941  }
   942  
   943  // Test loading a team where a rotate_key was signed by implicit-admin + explicit-reader
   944  func TestRotateSubteamByExplicitReader(t *testing.T) {
   945  	fus, tcs, cleanup := setupNTests(t, 2)
   946  	defer cleanup()
   947  
   948  	t.Logf("U0 creates fennel_network")
   949  	rootName, _ := createTeam2(*tcs[0])
   950  
   951  	t.Logf("U0 adds U1 to the root")
   952  	_, err := AddMember(context.Background(), tcs[0].G, rootName.String(), fus[1].Username, keybase1.TeamRole_ADMIN, nil)
   953  	require.NoError(t, err)
   954  
   955  	t.Logf("U0 creates fennel_network.sub1")
   956  	subteamID, err := CreateSubteam(context.Background(), tcs[0].G, "sub1", rootName, keybase1.TeamRole_NONE /* addSelfAs */)
   957  	require.NoError(t, err)
   958  	subteamName, err := rootName.Append("sub1")
   959  	require.NoError(t, err)
   960  
   961  	t.Logf("U0 adds both users to the subteam as readers")
   962  	for i := range tcs {
   963  		_, err := AddMember(context.Background(), tcs[0].G, subteamName.String(), fus[i].Username, keybase1.TeamRole_READER, nil)
   964  		require.NoError(t, err)
   965  	}
   966  
   967  	t.Logf("U0 rotates the subteam")
   968  	err = RotateKey(context.Background(), tcs[0].G, keybase1.TeamRotateKeyArg{TeamID: *subteamID, Rt: keybase1.RotationType_VISIBLE})
   969  	require.NoError(t, err)
   970  
   971  	t.Logf("Both users can still load the team")
   972  	for i := range tcs {
   973  		_, err = Load(context.Background(), tcs[i].G, keybase1.LoadTeamArg{
   974  			ID:          *subteamID,
   975  			ForceRepoll: true,
   976  		})
   977  		require.NoError(t, err, "load as %v", i)
   978  	}
   979  }
   980  
   981  // TestLoaderCORE_7201 tests a case that came up.
   982  // A user had trouble loading A.B because the cached object was stuck as secretless.
   983  // U1 is an   ADMIN in A
   984  // U1 is only IMP implicitly in A.B
   985  // U1 is a    WRITER in A.B.C
   986  func TestLoaderCORE_7201(t *testing.T) {
   987  	fus, tcs, cleanup := setupNTests(t, 2)
   988  	defer cleanup()
   989  
   990  	t.Logf("U0 creates A")
   991  	rootName, rootID := createTeam2(*tcs[0])
   992  
   993  	t.Logf("U0 adds U1 to A")
   994  	_, err := AddMember(context.TODO(), tcs[0].G, rootName.String(), fus[1].Username, keybase1.TeamRole_ADMIN, nil)
   995  	require.NoError(t, err, "add member")
   996  
   997  	t.Logf("U0 creates A.B")
   998  	subBName, subBID := createSubteam(tcs[0], rootName, "bbb")
   999  
  1000  	t.Logf("U0 creates A.B.C")
  1001  	subCName, subCID := createSubteam(tcs[0], subBName, "ccc")
  1002  
  1003  	t.Logf("U0 adds U1 to A.B.C")
  1004  	_, err = AddMember(context.TODO(), tcs[0].G, subCName.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
  1005  	require.NoError(t, err, "add member")
  1006  	t.Logf("setup complete")
  1007  
  1008  	t.Logf("U1 loads and caches A.B.C")
  1009  	// Causing A.B to get cached. Secretless?
  1010  	_, err = Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{
  1011  		ID:          subCID,
  1012  		ForceRepoll: true,
  1013  	})
  1014  	require.NoError(t, err)
  1015  
  1016  	t.Logf("U1 loads A")
  1017  	_, err = Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{
  1018  		ID:          rootID,
  1019  		ForceRepoll: true,
  1020  	})
  1021  	require.NoError(t, err)
  1022  
  1023  	t.Logf("U1 loads A.B")
  1024  	_, err = Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{
  1025  		ID:          subBID,
  1026  		ForceRepoll: true,
  1027  	})
  1028  	require.NoError(t, err)
  1029  }
  1030  
  1031  // TestLoaderCORE_8445 tests a case that came up.
  1032  // A user had trouble loading A.B because the cached object was stuck as without RKMs.
  1033  // U1 is an   ADMIN in A
  1034  // U1 is only IMP implicitly in A.B
  1035  // U1 is loads A.B caching the secret but not the RKMs
  1036  // U1 is a    WRITER A.B
  1037  func TestLoaderCORE_8445(t *testing.T) {
  1038  	fus, tcs, cleanup := setupNTests(t, 2)
  1039  	defer cleanup()
  1040  
  1041  	t.Logf("U0 creates A")
  1042  	rootName, _ := createTeam2(*tcs[0])
  1043  
  1044  	t.Logf("U0 adds U1 to A")
  1045  	_, err := AddMember(context.TODO(), tcs[0].G, rootName.String(), fus[1].Username, keybase1.TeamRole_ADMIN, nil)
  1046  	require.NoError(t, err, "add member")
  1047  
  1048  	t.Logf("U0 creates A.B")
  1049  	subBName, subBID := createSubteam(tcs[0], rootName, "bbb")
  1050  
  1051  	t.Logf("U1 loads and caches A.B")
  1052  	_, err = Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{
  1053  		ID:          subBID,
  1054  		ForceRepoll: true,
  1055  	})
  1056  	require.NoError(t, err)
  1057  
  1058  	t.Logf("U0 adds U1 to A.B")
  1059  	_, err = AddMember(context.TODO(), tcs[0].G, subBName.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
  1060  	require.NoError(t, err, "add member")
  1061  	t.Logf("setup complete")
  1062  
  1063  	t.Logf("U1 loads A.B without refreshing")
  1064  	subBStale, err := Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{
  1065  		ID: subBID,
  1066  	})
  1067  	// We're missing RKM data
  1068  	require.NoError(t, err)
  1069  	require.NotNil(t, subBStale.Data)
  1070  	require.False(t, subBStale.Data.Secretless)
  1071  	require.NotNil(t, subBStale.Data.PerTeamKeySeedsUnverified)
  1072  	_, ok := subBStale.Data.PerTeamKeySeedsUnverified[1]
  1073  	require.True(t, ok)
  1074  	require.NotNil(t, subBStale.Data.ReaderKeyMasks)
  1075  	require.Len(t, subBStale.Data.ReaderKeyMasks[keybase1.TeamApplication_CHAT], 0, "missing rkms")
  1076  
  1077  	t.Logf("U1 loads A.B with refreshing")
  1078  	subB, err := Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{
  1079  		ID: subBID,
  1080  		Refreshers: keybase1.TeamRefreshers{
  1081  			NeedApplicationsAtGenerations: map[keybase1.PerTeamKeyGeneration][]keybase1.TeamApplication{
  1082  				keybase1.PerTeamKeyGeneration(1): {keybase1.TeamApplication_CHAT},
  1083  			},
  1084  		},
  1085  	})
  1086  	require.NoError(t, err)
  1087  	require.NotNil(t, subB.Data)
  1088  	require.False(t, subB.Data.Secretless)
  1089  	require.NotNil(t, subB.Data.PerTeamKeySeedsUnverified)
  1090  	_, ok = subB.Data.PerTeamKeySeedsUnverified[1]
  1091  	require.True(t, ok)
  1092  	require.NotNil(t, subB.Data.ReaderKeyMasks)
  1093  	require.Len(t, subB.Data.ReaderKeyMasks[keybase1.TeamApplication_CHAT], 1, "number of chat rkms")
  1094  }
  1095  
  1096  // Earlier versions of the app didn't store the merkle head in the TeamChainState, but
  1097  // we need it to perform an audit. This code tests the path that refetches that data
  1098  // from the server.
  1099  func TestLoaderUpgradeMerkleHead(t *testing.T) {
  1100  	tc := SetupTest(t, "team", 1)
  1101  	defer tc.Cleanup()
  1102  	tc.G.Env.Test.TeamNoHeadMerkleStore = true
  1103  
  1104  	_, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
  1105  	require.NoError(t, err)
  1106  
  1107  	t.Logf("create a team")
  1108  	teamName, teamID := createTeam2(tc)
  1109  
  1110  	t.Logf("load the team")
  1111  	team, _, err := tc.G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
  1112  		ID: teamID,
  1113  	})
  1114  	require.NoError(t, err)
  1115  	require.Equal(t, teamID, team.Chain.Id)
  1116  	require.True(t, teamName.Eq(team.Name))
  1117  
  1118  	t.Logf("load the team again")
  1119  	team, _, err = tc.G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
  1120  		ID: teamID,
  1121  	})
  1122  	require.NoError(t, err)
  1123  	require.Equal(t, teamID, team.Chain.Id)
  1124  	require.True(t, teamName.Eq(team.Name))
  1125  }
  1126  
  1127  // Load a team where a writer wrote a kbfs link.
  1128  func TestLoaderKBFSWriter(t *testing.T) {
  1129  	fus, tcs, cleanup := setupNTests(t, 2)
  1130  	defer cleanup()
  1131  
  1132  	t.Logf("U0 creates A")
  1133  	rootName, rootID := createTeam2(*tcs[0])
  1134  
  1135  	t.Logf("U0 adds U1 as a writer")
  1136  	_, err := AddMember(context.Background(), tcs[0].G, rootName.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
  1137  	require.NoError(t, err)
  1138  
  1139  	t.Logf("U1 associates a tlf ID")
  1140  	err = CreateTLF(context.Background(), tcs[1].G, keybase1.CreateTLFArg{
  1141  		TeamID: rootID,
  1142  		TlfID:  randomTlfID(t),
  1143  	})
  1144  	require.NoError(t, err)
  1145  
  1146  	t.Logf("users can still load the team")
  1147  
  1148  	_, err = Load(context.TODO(), tcs[0].G, keybase1.LoadTeamArg{
  1149  		ID:          rootID,
  1150  		ForceRepoll: true,
  1151  	})
  1152  	require.NoError(t, err)
  1153  
  1154  	_, err = Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{
  1155  		ID:          rootID,
  1156  		ForceRepoll: true,
  1157  	})
  1158  	require.NoError(t, err)
  1159  }
  1160  
  1161  func TestLoaderCORE_10487(t *testing.T) {
  1162  	fus, tcs, cleanup := setupNTests(t, 2)
  1163  	defer cleanup()
  1164  
  1165  	t.Logf("U0 creates A")
  1166  	rootName, _ := createTeam2(*tcs[0])
  1167  
  1168  	t.Logf("U0 adds U1 to A")
  1169  	_, err := AddMember(context.Background(), tcs[0].G, rootName.String(), fus[1].Username, keybase1.TeamRole_OWNER, nil)
  1170  	require.NoError(t, err, "add member")
  1171  
  1172  	t.Logf("U0 creates A.B")
  1173  	subBName, subBID := createSubteam(tcs[0], rootName, "bbb")
  1174  
  1175  	t.Logf("U0 creates A.B.C")
  1176  	subsubCName, subsubCID := createSubteam(tcs[0], subBName, "ccc")
  1177  
  1178  	t.Logf("U1 loads A.B.C (to cache A.B)")
  1179  	_, err = Load(context.Background(), tcs[1].G, keybase1.LoadTeamArg{
  1180  		ID:          subsubCID,
  1181  		ForceRepoll: true,
  1182  	})
  1183  	require.NoError(t, err)
  1184  
  1185  	t.Logf("U1 loads A.B (to check cache)")
  1186  	team, err := Load(context.Background(), tcs[1].G, keybase1.LoadTeamArg{
  1187  		ID: subBID,
  1188  	})
  1189  	require.NoError(t, err)
  1190  	t.Logf("Expect missing KBFS RKMs (1)")
  1191  	require.NoError(t, err)
  1192  	require.NotNil(t, team.Data)
  1193  	require.False(t, team.Data.Secretless)
  1194  	require.NotNil(t, team.Data.PerTeamKeySeedsUnverified)
  1195  	_, ok := team.Data.PerTeamKeySeedsUnverified[1]
  1196  	require.True(t, ok)
  1197  	require.NotNil(t, team.Data.ReaderKeyMasks)
  1198  	require.Len(t, team.Data.ReaderKeyMasks[keybase1.TeamApplication_KBFS], 0, "missing rkms")
  1199  
  1200  	t.Logf("U1 self-promotes in A.B")
  1201  	_, err = AddMember(context.Background(), tcs[1].G, subBName.String(), fus[1].Username, keybase1.TeamRole_ADMIN, nil)
  1202  	require.NoError(t, err)
  1203  
  1204  	t.Logf("U1 self-promotes in A.B.C")
  1205  	_, err = AddMember(context.Background(), tcs[1].G, subsubCName.String(), fus[1].Username, keybase1.TeamRole_ADMIN, nil)
  1206  	require.NoError(t, err)
  1207  
  1208  	t.Logf("U1 loads A.B")
  1209  	team, err = Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{
  1210  		ID: subBID,
  1211  	})
  1212  	t.Logf("Expect missing KBFS RKMs (2)")
  1213  	require.NoError(t, err)
  1214  	require.NotNil(t, team.Data)
  1215  	require.False(t, team.Data.Secretless)
  1216  	require.NotNil(t, team.Data.PerTeamKeySeedsUnverified)
  1217  	_, ok = team.Data.PerTeamKeySeedsUnverified[1]
  1218  	require.True(t, ok)
  1219  	require.NotNil(t, team.Data.ReaderKeyMasks)
  1220  	if len(team.Data.ReaderKeyMasks[keybase1.TeamApplication_KBFS]) != 0 {
  1221  		t.Logf("RKMs received. This is acceptable client behavior, but not suitable to test this particular regression.")
  1222  		return
  1223  	}
  1224  
  1225  	t.Logf("U1 loads A.B like KBFS")
  1226  	_, err = LoadTeamPlusApplicationKeys(context.Background(), tcs[1].G, subBID,
  1227  		keybase1.TeamApplication_KBFS, keybase1.TeamRefreshers{
  1228  			NeedApplicationsAtGenerationsWithKBFS: map[keybase1.PerTeamKeyGeneration][]keybase1.TeamApplication{
  1229  				keybase1.PerTeamKeyGeneration(1): {
  1230  					keybase1.TeamApplication_KBFS,
  1231  				},
  1232  			}}, true)
  1233  	// When the bug was in place, this produced:
  1234  	// "You don't have access to KBFS for this team libkb.KeyMaskNotFoundError"
  1235  	require.NoError(t, err)
  1236  }
  1237  
  1238  func randomTlfID(t *testing.T) keybase1.TLFID {
  1239  	suffix := byte(0x29)
  1240  	idBytes, err := libkb.RandBytesWithSuffix(16, suffix)
  1241  	require.NoError(t, err)
  1242  	return keybase1.TLFID(hex.EncodeToString(idBytes))
  1243  }
  1244  
  1245  func getFastStorageFromG(g *libkb.GlobalContext) *storage.FTLStorage {
  1246  	tl := g.GetFastTeamLoader().(*FastTeamChainLoader)
  1247  	return tl.storage
  1248  }
  1249  
  1250  type freezeF = func(*libkb.TestContext, *kbtest.FakeUser, keybase1.TeamID, keybase1.TeamName, *libkb.TestContext) error
  1251  
  1252  func freezeTest(t *testing.T, freezeAction freezeF, unfreezeAction freezeF) {
  1253  	fus, tcs, cleanup := setupNTests(t, 2)
  1254  	defer cleanup()
  1255  
  1256  	rootName, rootID := createTeam2(*tcs[0])
  1257  
  1258  	_, err := AddMember(context.Background(), tcs[0].G, rootName.String(), fus[1].Username, keybase1.TeamRole_OWNER, nil)
  1259  	require.NoError(t, err)
  1260  
  1261  	// Explicitly load in FTL since AddMember doesn't do it
  1262  	mctx := libkb.NewMetaContextForTest(*tcs[0])
  1263  	_, err = tcs[0].G.GetFastTeamLoader().Load(mctx, keybase1.FastTeamLoadArg{
  1264  		ID:     rootID,
  1265  		Public: rootID.IsPublic(),
  1266  	})
  1267  	require.NoError(t, err)
  1268  
  1269  	err = freezeAction(tcs[0], fus[0], rootID, rootName, tcs[1])
  1270  	require.NoError(t, err)
  1271  
  1272  	st := getStorageFromG(tcs[0].G)
  1273  	td, frozen, tombstoned := st.Get(mctx, rootID, rootID.IsPublic())
  1274  	require.NotNil(t, td)
  1275  	require.True(t, frozen)
  1276  	require.False(t, tombstoned)
  1277  	require.Nil(t, td.ReaderKeyMasks)
  1278  	require.NotNil(t, td.Chain)
  1279  	require.NotNil(t, td.Chain.LastSeqno)
  1280  	require.NotNil(t, td.Chain.LastLinkID)
  1281  	require.Nil(t, td.Chain.UserLog)
  1282  	require.Nil(t, td.Chain.PerTeamKeys)
  1283  	fastS := getFastStorageFromG(tcs[0].G)
  1284  	ftd, frozen, tombstoned := fastS.Get(mctx, rootID, rootID.IsPublic())
  1285  	require.NotNil(t, ftd)
  1286  	require.True(t, frozen)
  1287  	require.False(t, tombstoned)
  1288  	require.NotNil(t, ftd.Chain)
  1289  	require.Nil(t, ftd.ReaderKeyMasks)
  1290  	require.Nil(t, ftd.Chain.PerTeamKeys)
  1291  	require.NotNil(t, ftd.Chain.ID)
  1292  	require.NotNil(t, ftd.Chain.Public)
  1293  	require.NotNil(t, ftd.Chain.Last)
  1294  	require.NotNil(t, ftd.Chain.Last.Seqno)
  1295  	require.NotNil(t, ftd.Chain.Last.LinkID)
  1296  
  1297  	err = unfreezeAction(tcs[0], fus[0], rootID, rootName, tcs[1])
  1298  	require.NoError(t, err)
  1299  
  1300  	// Load chains again, forcing repoll
  1301  	_, _, err = tcs[0].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
  1302  		ID:     rootID,
  1303  		Public: rootID.IsPublic(),
  1304  	})
  1305  	require.NoError(t, err)
  1306  	_, err = tcs[0].G.GetFastTeamLoader().Load(mctx, keybase1.FastTeamLoadArg{
  1307  		ID:     rootID,
  1308  		Public: rootID.IsPublic(),
  1309  	})
  1310  	require.NoError(t, err)
  1311  
  1312  	td, _, _ = st.Get(mctx, rootID, rootID.IsPublic())
  1313  	require.NotNil(t, td)
  1314  	require.NotNil(t, td.ReaderKeyMasks)
  1315  	require.NotNil(t, td.Chain.UserLog)
  1316  	require.NotNil(t, td.Chain.PerTeamKeys)
  1317  	ftd, frozen, tombstoned = fastS.Get(mctx, rootID, rootID.IsPublic())
  1318  	require.NotNil(t, ftd)
  1319  	require.False(t, frozen)
  1320  	require.False(t, tombstoned)
  1321  	require.NotNil(t, ftd.Chain)
  1322  	require.NotNil(t, ftd.ReaderKeyMasks)
  1323  	require.NotNil(t, ftd.Chain.PerTeamKeys)
  1324  	require.NotNil(t, ftd.Chain.ID)
  1325  	require.NotNil(t, ftd.Chain.Public)
  1326  	require.NotNil(t, ftd.Chain.Last)
  1327  	require.NotNil(t, ftd.Chain.Last.Seqno)
  1328  	require.NotNil(t, ftd.Chain.Last.LinkID)
  1329  }
  1330  
  1331  func TestFreezeBasic(t *testing.T) {
  1332  	freezeTest(t, func(tc *libkb.TestContext, fu *kbtest.FakeUser, teamID keybase1.TeamID, _ keybase1.TeamName, _ *libkb.TestContext) error {
  1333  		return FreezeTeam(libkb.NewMetaContextForTest(*tc), teamID)
  1334  	}, func(tc *libkb.TestContext, fu *kbtest.FakeUser, teamID keybase1.TeamID, _ keybase1.TeamName, _ *libkb.TestContext) error {
  1335  		return nil
  1336  	})
  1337  }
  1338  
  1339  func TestFreezeViaLeave(t *testing.T) {
  1340  	freezeTest(t, func(tc *libkb.TestContext, fu *kbtest.FakeUser, teamID keybase1.TeamID, teamName keybase1.TeamName, _ *libkb.TestContext) error {
  1341  		return Leave(context.TODO(), tc.G, teamName.String(), false)
  1342  	}, func(tc *libkb.TestContext, fu *kbtest.FakeUser, teamID keybase1.TeamID, teamName keybase1.TeamName, otherTc *libkb.TestContext) error {
  1343  		_, err := AddMember(context.TODO(), otherTc.G, teamName.String(), fu.Username, keybase1.TeamRole_READER, nil)
  1344  		return err
  1345  	})
  1346  }
  1347  
  1348  func TestTombstoneViaDelete(t *testing.T) {
  1349  	fus, tcs, cleanup := setupNTests(t, 2)
  1350  	defer cleanup()
  1351  
  1352  	rootName, rootID := createTeam2(*tcs[0])
  1353  	_, err := AddMember(context.Background(), tcs[0].G, rootName.String(), fus[1].Username, keybase1.TeamRole_OWNER, nil)
  1354  	require.NoError(t, err)
  1355  
  1356  	// Explicitly load in FTL since AddMember doesn't do it
  1357  	mctx := libkb.NewMetaContextForTest(*tcs[0])
  1358  	_, err = tcs[0].G.GetFastTeamLoader().Load(mctx, keybase1.FastTeamLoadArg{
  1359  		ID:     rootID,
  1360  		Public: rootID.IsPublic(),
  1361  	})
  1362  	require.NoError(t, err)
  1363  
  1364  	err = Delete(context.TODO(), tcs[0].G, &teamsUI{}, rootID)
  1365  	require.NoError(t, err)
  1366  
  1367  	st := getStorageFromG(tcs[0].G)
  1368  	td, frozen, tombstoned := st.Get(mctx, rootID, rootID.IsPublic())
  1369  	require.NotNil(t, td)
  1370  	require.False(t, frozen)
  1371  	require.True(t, tombstoned)
  1372  	require.Nil(t, td.ReaderKeyMasks)
  1373  	require.NotNil(t, td.Chain)
  1374  	require.NotNil(t, td.Chain.LastSeqno)
  1375  	require.NotNil(t, td.Chain.LastLinkID)
  1376  	require.Nil(t, td.Chain.UserLog)
  1377  	require.Nil(t, td.Chain.PerTeamKeys)
  1378  
  1379  	fastS := getFastStorageFromG(tcs[0].G)
  1380  	ftd, frozen, tombstoned := fastS.Get(mctx, rootID, rootID.IsPublic())
  1381  	require.NotNil(t, ftd)
  1382  	require.False(t, frozen)
  1383  	require.True(t, tombstoned)
  1384  	require.NotNil(t, ftd.Chain)
  1385  	require.Nil(t, ftd.ReaderKeyMasks)
  1386  	require.Nil(t, ftd.Chain.PerTeamKeys)
  1387  	require.NotNil(t, ftd.Chain.ID)
  1388  	require.NotNil(t, ftd.Chain.Public)
  1389  	require.NotNil(t, ftd.Chain.Last)
  1390  
  1391  	// Load chains again, should error due to tombstone
  1392  	_, _, err = tcs[0].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
  1393  		ID:     rootID,
  1394  		Public: rootID.IsPublic(),
  1395  	})
  1396  	require.NotNil(t, err)
  1397  	_, ok := err.(*TeamTombstonedError)
  1398  	require.True(t, ok)
  1399  	_, err = tcs[0].G.GetFastTeamLoader().Load(mctx, keybase1.FastTeamLoadArg{
  1400  		ID:     rootID,
  1401  		Public: rootID.IsPublic(),
  1402  	})
  1403  	require.NotNil(t, err)
  1404  	_, ok = err.(*TeamTombstonedError)
  1405  	require.True(t, ok)
  1406  }