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 }