github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/systests/teams_test.go (about) 1 package systests 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 "time" 8 9 "golang.org/x/net/context" 10 11 "github.com/davecgh/go-spew/spew" 12 "github.com/keybase/client/go/client" 13 "github.com/keybase/client/go/engine" 14 "github.com/keybase/client/go/kbtest" 15 "github.com/keybase/client/go/libkb" 16 "github.com/keybase/client/go/protocol/keybase1" 17 "github.com/keybase/client/go/protocol/stellar1" 18 "github.com/keybase/client/go/service" 19 "github.com/keybase/client/go/teams" 20 "github.com/keybase/go-framed-msgpack-rpc/rpc" 21 "github.com/stretchr/testify/require" 22 23 insecureTriplesec "github.com/keybase/go-triplesec-insecure" 24 ) 25 26 func TestTeamCreate(t *testing.T) { 27 tt := newTeamTester(t) 28 defer tt.cleanup() 29 30 tt.addUser("onr") 31 tt.addUser("wtr") 32 33 team := tt.users[0].createTeam() 34 tt.users[0].addTeamMember(team, tt.users[1].username, keybase1.TeamRole_WRITER) 35 } 36 37 func TestTeamBustCache(t *testing.T) { 38 tt := newTeamTester(t) 39 defer tt.cleanup() 40 41 tt.addUser("onr") 42 tt.addUser("adm") 43 tt.addUser("wtr") 44 45 team := tt.users[0].createTeam() 46 tt.users[0].addTeamMember(team, tt.users[1].username, keybase1.TeamRole_ADMIN) 47 48 before, err := GetTeamForTestByStringName(context.TODO(), tt.users[0].tc.G, team) 49 require.NoError(t, err) 50 beforeSeqno := before.CurrentSeqno() 51 tt.users[1].addTeamMember(team, tt.users[2].username, keybase1.TeamRole_WRITER) 52 53 // Poll for an update, we should get it as soon as gregor tells us to bust our cache. 54 pollForTrue(t, tt.users[0].tc.G, func(i int) bool { 55 after, err := teams.Load(context.TODO(), tt.users[0].tc.G, keybase1.LoadTeamArg{ 56 Name: team, 57 StaleOK: true, 58 }) 59 require.NoError(t, err) 60 if after.CurrentSeqno() > beforeSeqno { 61 t.Logf("Found new seqno %d at poll loop iter %d", after.CurrentSeqno(), i) 62 return true 63 } 64 return false 65 }) 66 } 67 68 func TestHiddenRotateGregor(t *testing.T) { 69 tt := newTeamTester(t) 70 defer tt.cleanup() 71 72 tt.addUser("onr") 73 tt.addUser("adm") 74 75 id, name := tt.users[0].createTeam2() 76 tt.users[0].addTeamMember(name.String(), tt.users[1].username, keybase1.TeamRole_ADMIN) 77 78 assertGen := func(g keybase1.PerTeamKeyGeneration) bool { 79 team, err := teams.Load(context.TODO(), tt.users[1].tc.G, keybase1.LoadTeamArg{ 80 Name: name.String(), 81 StaleOK: true, 82 }) 83 require.NoError(t, err) 84 key, err := team.ApplicationKey(context.TODO(), keybase1.TeamApplication_CHAT) 85 require.NoError(t, err) 86 return (key.KeyGeneration == g) 87 } 88 assertGenFTL := func(g keybase1.PerTeamKeyGeneration) bool { 89 mctx := libkb.NewMetaContextForTest(*tt.users[1].tc) 90 team, err := mctx.G().GetFastTeamLoader().Load(mctx, keybase1.FastTeamLoadArg{ 91 ID: id, 92 NeedLatestKey: true, 93 Applications: []keybase1.TeamApplication{keybase1.TeamApplication_CHAT}, 94 }) 95 require.NoError(t, err) 96 require.Equal(t, 1, len(team.ApplicationKeys)) 97 return (team.ApplicationKeys[0].KeyGeneration == g) 98 } 99 // Prime user 1's cache 100 ok := assertGen(keybase1.PerTeamKeyGeneration(1)) 101 require.True(t, ok) 102 ok = assertGenFTL(keybase1.PerTeamKeyGeneration(1)) 103 require.True(t, ok) 104 105 err := teams.RotateKey(context.TODO(), tt.users[0].tc.G, keybase1.TeamRotateKeyArg{TeamID: id, Rt: keybase1.RotationType_HIDDEN}) 106 require.NoError(t, err) 107 108 // Poll for an update, user 1 should get it as soon as gregor tells us to bust our cache. 109 pollForTrue(t, tt.users[1].tc.G, func(i int) bool { 110 return assertGen(keybase1.PerTeamKeyGeneration(2)) 111 }) 112 113 err = teams.RotateKey(context.TODO(), tt.users[0].tc.G, keybase1.TeamRotateKeyArg{TeamID: id, Rt: keybase1.RotationType_HIDDEN}) 114 require.NoError(t, err) 115 116 // Poll for an update to FTL, user 1 should get it as soon as gregor tells us to bust our cache. 117 pollForTrue(t, tt.users[1].tc.G, func(i int) bool { 118 return assertGenFTL(keybase1.PerTeamKeyGeneration(3)) 119 }) 120 } 121 122 func TestTeamRotateOnRevoke(t *testing.T) { 123 tt := newTeamTester(t) 124 defer tt.cleanup() 125 126 tt.addUser("onr") 127 tt.addUserWithPaper("wtr") 128 129 teamID, teamName := tt.users[0].createTeam2() 130 tt.users[0].addTeamMember(teamName.String(), tt.users[1].username, keybase1.TeamRole_WRITER) 131 132 // get the before state of the team 133 before, err := GetTeamForTestByStringName(context.TODO(), tt.users[0].tc.G, teamName.String()) 134 if err != nil { 135 t.Fatal(err) 136 } 137 if before.Generation() != 1 { 138 t.Errorf("generation before rotate: %d, expected 1", before.Generation()) 139 } 140 secretBefore := before.Data.PerTeamKeySeedsUnverified[before.Generation()].Seed.ToBytes() 141 142 // User1 should get a gregor that the team he was just added to changed. 143 tt.users[1].waitForTeamChangedGregor(teamID, keybase1.Seqno(2)) 144 // User0 should get a (redundant) gregor notification that 145 // he just changed the team. 146 tt.users[0].waitForTeamChangedGregor(teamID, keybase1.Seqno(2)) 147 148 tt.users[1].revokePaperKey() 149 tt.users[0].waitForAnyRotateByID(teamID, keybase1.Seqno(2) /* toSeqno */, keybase1.Seqno(1) /* toHiddenSeqno */) 150 151 // check that key was rotated for team 152 after, err := GetTeamForTestByStringName(context.TODO(), tt.users[0].tc.G, teamName.String()) 153 if err != nil { 154 t.Fatal(err) 155 } 156 if after.Generation() != 2 { 157 t.Errorf("generation after rotate: %d, expected 2", after.Generation()) 158 } 159 secretAfter := after.Data.PerTeamKeySeedsUnverified[after.Generation()].Seed.ToBytes() 160 if libkb.SecureByteArrayEq(secretAfter, secretBefore) { 161 t.Fatal("team secret did not change when rotated") 162 } 163 } 164 165 type teamTester struct { 166 t *testing.T 167 users []*userPlusDevice 168 } 169 170 func newTeamTester(t *testing.T) *teamTester { 171 return &teamTester{t: t} 172 } 173 174 func (tt *teamTester) addUser(pre string) *userPlusDevice { 175 return tt.addUserHelper(pre, true, false) 176 } 177 178 func (tt *teamTester) addUserWithPaper(pre string) *userPlusDevice { 179 return tt.addUserHelper(pre, true, true) 180 } 181 182 func (tt *teamTester) addPuklessUser(pre string) *userPlusDevice { 183 return tt.addUserHelper(pre, false, false) 184 } 185 186 func (tt *teamTester) logUserNames() { 187 for _, u := range tt.users { 188 var pukless string 189 if u.device.tctx.Tp.DisableUpgradePerUserKey { 190 pukless = "pukless " 191 } 192 tt.t.Logf("Signed up %s%q (%s)", pukless, u.username, u.uid) 193 } 194 } 195 196 func installInsecureTriplesec(g *libkb.GlobalContext) { 197 g.NewTriplesec = func(passphrase []byte, salt []byte) (libkb.Triplesec, error) { 198 warner := func() { g.Log.Warning("Installing insecure Triplesec with weak stretch parameters") } 199 isProduction := func() bool { 200 return g.Env.GetRunMode() == libkb.ProductionRunMode 201 } 202 return insecureTriplesec.NewCipher(passphrase, salt, libkb.ClientTriplesecVersion, warner, isProduction) 203 } 204 } 205 206 func (tt *teamTester) addUserHelper(pre string, puk bool, paper bool) *userPlusDevice { 207 tctx := setupTest(tt.t, pre) 208 if !puk { 209 tctx.Tp.DisableUpgradePerUserKey = true 210 } 211 212 var u userPlusDevice 213 u.device = &deviceWrapper{tctx: tctx} 214 u.device.start(0) 215 216 userInfo := randomUser(pre) 217 require.True(tt.t, libkb.CheckUsername.F(userInfo.username), "username check failed (%v): %v", libkb.CheckUsername.Hint, userInfo.username) 218 tc := u.device.tctx 219 g := tc.G 220 installInsecureTriplesec(g) 221 222 signupUI := signupUI{ 223 info: userInfo, 224 Contextified: libkb.NewContextified(g), 225 } 226 g.SetUI(&signupUI) 227 signup := client.NewCmdSignupRunner(g) 228 signup.SetTestWithPaper(paper) 229 require.NoError(tt.t, signup.Run()) 230 tt.t.Logf("signed up %s", userInfo.username) 231 232 u.tc = tc 233 u.userInfo = userInfo 234 u.username = userInfo.username 235 u.passphrase = userInfo.passphrase 236 u.uid = libkb.UsernameToUID(u.username) 237 238 cli, xp, err := client.GetRPCClientWithContext(g) 239 require.NoError(tt.t, err) 240 241 u.deviceClient = keybase1.DeviceClient{Cli: cli} 242 u.device.userClient = keybase1.UserClient{Cli: cli} 243 u.device.accountClient = keybase1.AccountClient{Cli: cli} 244 245 // register for notifications 246 u.notifications = newTeamNotifyHandler() 247 srv := rpc.NewServer(xp, nil) 248 err = srv.Register(keybase1.NotifyTeamProtocol(u.notifications)) 249 require.NoError(tt.t, err) 250 err = srv.Register(keybase1.NotifyBadgesProtocol(u.notifications)) 251 require.NoError(tt.t, err) 252 err = srv.Register(keybase1.NotifyEphemeralProtocol(u.notifications)) 253 require.NoError(tt.t, err) 254 err = srv.Register(keybase1.NotifyTeambotProtocol(u.notifications)) 255 require.NoError(tt.t, err) 256 ncli := keybase1.NotifyCtlClient{Cli: cli} 257 err = ncli.SetNotifications(context.TODO(), keybase1.NotificationChannels{ 258 Team: true, 259 Badges: true, 260 Ephemeral: true, 261 Teambot: true, 262 }) 263 require.NoError(tt.t, err) 264 265 // register fake teams UI for tests 266 err = srv.Register(keybase1.TeamsUiProtocol(&teamsUI{})) 267 require.NoError(tt.t, err) 268 269 u.teamsClient = keybase1.TeamsClient{Cli: cli} 270 u.userClient = keybase1.UserClient{Cli: cli} 271 u.stellarClient = newStellarRetryClient(cli) 272 273 err = g.ConfigureConfig() 274 require.NoError(tt.t, err) 275 276 devices, backups := u.device.loadEncryptionKIDs() 277 require.Len(tt.t, devices, 1, "devices") 278 u.device.deviceKey.KID = devices[0] 279 require.True(tt.t, u.device.deviceKey.KID.Exists()) 280 if paper { 281 require.Len(tt.t, backups, 1, "backup keys") 282 u.backupKey = &backups[0] 283 u.backupKey.secret = signupUI.info.displayedPaperKey 284 } else { 285 require.Len(tt.t, backups, 0, "backup keys") 286 } 287 288 tt.users = append(tt.users, &u) 289 return &u 290 } 291 292 func (tt *teamTester) cleanup() { 293 for _, u := range tt.users { 294 u.device.tctx.Cleanup() 295 if u.device.service != nil { 296 u.tc.T.Logf("in teamTester cleanup, stopping test user's service") 297 u.device.service.Stop(0) 298 err := u.device.stop() 299 require.NoError(u.tc.T, err) 300 u.tc.T.Logf("in teamTester cleanup, stopped test user's service") 301 } 302 } 303 } 304 305 type userPlusDevice struct { 306 uid keybase1.UID 307 username string 308 passphrase string 309 userInfo *signupInfo 310 backupKey *backupKey 311 device *deviceWrapper 312 tc *libkb.TestContext 313 deviceClient keybase1.DeviceClient 314 teamsClient keybase1.TeamsClient 315 userClient keybase1.UserClient 316 stellarClient stellar1.LocalInterface 317 notifications *teamNotifyHandler 318 suppressTeamChatAnnounce bool 319 } 320 321 func (u *userPlusDevice) createTeam() string { 322 create := client.NewCmdTeamCreateRunner(u.tc.G) 323 nameStr, err := libkb.RandString("tt", 5) 324 if err != nil { 325 u.tc.T.Fatal(err) 326 } 327 name, err := keybase1.TeamNameFromString(strings.ToLower(nameStr)) 328 if err != nil { 329 u.tc.T.Fatal(err) 330 } 331 create.TeamName = name 332 tracer := u.tc.G.CTimeTracer(context.Background(), "tracer-create-team", true) 333 defer tracer.Finish() 334 if err := create.Run(); err != nil { 335 u.tc.T.Fatal(err) 336 } 337 return create.TeamName.String() 338 } 339 340 func (u *userPlusDevice) createTeam2() (teamID keybase1.TeamID, teamName keybase1.TeamName) { 341 name := u.createTeam() 342 team, err := teams.Load(context.Background(), u.tc.G, keybase1.LoadTeamArg{ 343 Name: name, 344 }) 345 require.NoError(u.tc.T, err) 346 return team.ID, team.Name() 347 } 348 349 func (u *userPlusDevice) teamSetSettings(id keybase1.TeamID, settings keybase1.TeamSettings) { 350 err := u.teamsClient.TeamSetSettings(context.Background(), keybase1.TeamSetSettingsArg{ 351 TeamID: id, 352 Settings: settings, 353 }) 354 require.NoError(u.tc.T, err) 355 if u.notifications != nil { 356 changeByID := false 357 for { 358 select { 359 case arg := <-u.notifications.changeCh: 360 changeByID = arg.Changes.Misc 361 case <-time.After(500 * time.Millisecond * libkb.CITimeMultiplier(u.tc.G)): 362 u.tc.T.Fatal("no notification on teamSetSettings") 363 } 364 if changeByID { 365 return 366 } 367 } 368 } 369 } 370 371 func (u *userPlusDevice) teamGetDetails(teamName string) keybase1.TeamDetails { 372 res, err := u.teamsClient.TeamGet(context.Background(), keybase1.TeamGetArg{ 373 Name: teamName, 374 }) 375 require.NoError(u.tc.T, err) 376 return res 377 } 378 379 func (u *userPlusDevice) addRestrictedBotTeamMember(team, username string, botSettings keybase1.TeamBotSettings) { 380 add := client.NewCmdTeamAddMemberRunner(u.tc.G) 381 add.Team = team 382 add.Username = username 383 add.Role = keybase1.TeamRole_RESTRICTEDBOT 384 add.BotSettings = &botSettings 385 add.SkipChatNotification = u.suppressTeamChatAnnounce 386 err := add.Run() 387 require.NoError(u.tc.T, err) 388 } 389 390 func (u *userPlusDevice) addTeamMember(team, username string, role keybase1.TeamRole) { 391 if role.IsRestrictedBot() { 392 require.Fail(u.tc.T, "use addRestrictedBotTeamMember instead") 393 } 394 add := client.NewCmdTeamAddMemberRunner(u.tc.G) 395 add.Team = team 396 add.Username = username 397 add.Role = role 398 add.SkipChatNotification = u.suppressTeamChatAnnounce 399 err := add.Run() 400 require.NoError(u.tc.T, err) 401 } 402 403 func (u *userPlusDevice) removeTeamMember(team, username string) { 404 rm := client.NewCmdTeamRemoveMemberRunner(u.tc.G) 405 rm.Team = team 406 rm.Assertion = username 407 rm.Force = true 408 err := rm.Run() 409 require.NoError(u.tc.T, err) 410 } 411 412 func (u *userPlusDevice) leave(team string) { 413 leave := client.NewCmdTeamLeaveRunner(u.tc.G) 414 leave.Team = team 415 err := leave.Run() 416 require.NoError(u.tc.T, err) 417 } 418 419 func (u *userPlusDevice) changeTeamMember(team, username string, role keybase1.TeamRole) { 420 change := client.NewCmdTeamEditMemberRunner(u.tc.G) 421 change.Team = team 422 change.Username = username 423 change.Role = role 424 err := change.Run() 425 require.NoError(u.tc.T, err) 426 } 427 428 func (u *userPlusDevice) addTeamMemberEmail(team, email string, role keybase1.TeamRole) { 429 add := client.NewCmdTeamAddMemberRunner(u.tc.G) 430 add.Team = team 431 add.Email = email 432 add.Role = role 433 err := add.Run() 434 require.NoError(u.tc.T, err) 435 } 436 437 func (u *userPlusDevice) reAddUserAfterReset(team keybase1.TeamID, w *userPlusDevice) { 438 err := u.teamsClient.TeamReAddMemberAfterReset(context.Background(), 439 keybase1.TeamReAddMemberAfterResetArg{ 440 Id: team, 441 Username: w.username, 442 }) 443 require.NoError(u.tc.T, err) 444 } 445 446 func (u *userPlusDevice) loadTeam(teamname string, admin bool) *teams.Team { 447 team, err := teams.Load(context.Background(), u.tc.G, keybase1.LoadTeamArg{ 448 Name: teamname, 449 NeedAdmin: admin, 450 ForceRepoll: true, 451 }) 452 require.NoError(u.tc.T, err) 453 return team 454 } 455 456 func (u *userPlusDevice) loadTeamByID(teamID keybase1.TeamID, admin bool) *teams.Team { 457 team, err := teams.Load(context.Background(), u.tc.G, keybase1.LoadTeamArg{ 458 ID: teamID, 459 Public: teamID.IsPublic(), 460 NeedAdmin: admin, 461 ForceRepoll: true, 462 }) 463 require.NoError(u.tc.T, err) 464 return team 465 } 466 467 func (u *userPlusDevice) readInviteEmails(email string) []string { 468 mctx := u.MetaContext() 469 arg := libkb.NewAPIArg("test/team/get_tokens") 470 arg.Args = libkb.NewHTTPArgs() 471 arg.Args.Add("email", libkb.S{Val: email}) 472 res, err := u.tc.G.API.Get(mctx, arg) 473 if err != nil { 474 u.tc.T.Fatal(err) 475 } 476 tokens := res.Body.AtKey("tokens") 477 n, err := tokens.Len() 478 if err != nil { 479 u.tc.T.Fatal(err) 480 } 481 if n == 0 { 482 require.Fail(u.tc.T, fmt.Sprintf("no invite tokens for %s", email)) 483 } 484 485 exp := make([]string, n) 486 for i := 0; i < n; i++ { 487 token, err := tokens.AtIndex(i).GetString() 488 if err != nil { 489 u.tc.T.Fatal(err) 490 } 491 exp[i] = token 492 } 493 494 return exp 495 } 496 497 func (u *userPlusDevice) acceptEmailInvite(token string) { 498 c := client.NewCmdTeamAcceptInviteRunner(u.tc.G) 499 c.Token = token 500 if err := c.Run(); err != nil { 501 u.tc.T.Fatal(err) 502 } 503 } 504 505 func (u *userPlusDevice) acceptInviteOrRequestAccess(tokenOrName string) keybase1.TeamAcceptOrRequestResult { 506 tui := &teamsUI{} 507 ret, err := teams.TeamAcceptInviteOrRequestAccess(context.TODO(), u.tc.G, tui, tokenOrName) 508 require.NoError(u.tc.T, err) 509 return ret 510 } 511 512 func (u *userPlusDevice) teamList(userAssertion string, all, includeImplicitTeams bool) keybase1.AnnotatedTeamList { 513 cli := u.teamsClient 514 res, err := cli.TeamListUnverified(context.TODO(), keybase1.TeamListUnverifiedArg{ 515 UserAssertion: userAssertion, 516 IncludeImplicitTeams: includeImplicitTeams, 517 }) 518 require.NoError(u.tc.T, err) 519 return res 520 } 521 522 func (u *userPlusDevice) revokePaperKey() { 523 id := u.paperKeyID() 524 525 runner := client.NewCmdDeviceRemoveRunner(u.tc.G) 526 runner.SetIDOrName(id.String()) 527 if err := runner.Run(); err != nil { 528 u.tc.T.Fatal(err) 529 } 530 } 531 532 func (u *userPlusDevice) devices() []keybase1.Device { 533 d, err := u.deviceClient.DeviceList(context.TODO(), 0) 534 if err != nil { 535 u.tc.T.Fatal(err) 536 } 537 return d 538 } 539 540 func (u *userPlusDevice) userVersion() keybase1.UserVersion { 541 uv, err := u.device.userClient.MeUserVersion(context.TODO(), keybase1.MeUserVersionArg{ForcePoll: true}) 542 require.NoError(u.tc.T, err) 543 return uv 544 } 545 546 func (u *userPlusDevice) paperKeyID() keybase1.DeviceID { 547 for _, d := range u.devices() { 548 if d.Type == keybase1.DeviceTypeV2_PAPER { 549 return d.DeviceID 550 } 551 } 552 u.tc.T.Fatal("no paper key found") 553 return keybase1.DeviceID("") 554 } 555 556 func (u *userPlusDevice) waitForTeamChangedGregor(teamID keybase1.TeamID, toSeqno keybase1.Seqno) { 557 // process 10 team rotations or 10s worth of time 558 for i := 0; i < 10; i++ { 559 select { 560 case arg := <-u.notifications.changeCh: 561 u.tc.T.Logf("membership change received: %+v", arg) 562 if arg.TeamID.Eq(teamID) && arg.Changes.MembershipChanged && !arg.Changes.KeyRotated && !arg.Changes.Renamed && arg.LatestSeqno == toSeqno { 563 u.tc.T.Logf("change matched!") 564 return 565 } 566 u.tc.T.Logf("ignoring change message (expected teamID = %q, seqno = %d)", teamID.String(), toSeqno) 567 case <-time.After(1 * time.Second * libkb.CITimeMultiplier(u.tc.G)): 568 } 569 } 570 require.Fail(u.tc.T, fmt.Sprintf("timed out waiting for team rotate %s", teamID)) 571 } 572 573 func (u *userPlusDevice) waitForMetadataUpdateGregor(reason string) { 574 // process 10 team rotations or 10s worth of time 575 for i := 0; i < 10; i++ { 576 select { 577 case <-u.notifications.metadataUpdateCh: 578 u.tc.T.Logf("metadata update received for reason %q", reason) 579 return 580 case <-time.After(1 * time.Second * libkb.CITimeMultiplier(u.tc.G)): 581 } 582 } 583 require.Fail(u.tc.T, fmt.Sprintf("timed out waiting for metadata update for reason %q", reason)) 584 } 585 586 func (u *userPlusDevice) waitForBadgeStateWithReset(numReset int) keybase1.BadgeState { 587 // Process any number of badge state updates, but bail out after 588 // 10 seconds. 589 timeout := time.After(10 * time.Second * libkb.CITimeMultiplier(u.tc.G)) 590 i := 0 591 for { 592 select { 593 case arg := <-u.notifications.badgeCh: 594 u.tc.T.Logf("badge state received %d: %+v", i, arg.TeamsWithResetUsers) 595 i++ 596 if len(arg.TeamsWithResetUsers) == numReset { 597 u.tc.T.Logf("badge state length match") 598 return arg 599 } 600 case <-timeout: 601 u.tc.T.Fatal("timed out waiting for badge state") 602 return keybase1.BadgeState{} 603 } 604 } 605 } 606 607 func (u *userPlusDevice) drainGregor() { 608 for i := 0; i < 1000; i++ { 609 select { 610 case <-u.notifications.changeCh: 611 u.tc.T.Logf("dropped notification") 612 // drop 613 case <-time.After(500 * time.Millisecond * libkb.CITimeMultiplier(u.tc.G)): 614 u.tc.T.Logf("no notification received, drain complete") 615 return 616 } 617 } 618 } 619 620 func (u *userPlusDevice) waitForRotateByID(teamID keybase1.TeamID, toSeqno keybase1.Seqno) { 621 u.waitForAnyRotateByID(teamID, toSeqno, keybase1.Seqno(0)) 622 } 623 624 func (u *userPlusDevice) waitForAnyRotateByID(teamID keybase1.TeamID, toSeqno keybase1.Seqno, toHiddenSeqno keybase1.Seqno) { 625 u.tc.T.Logf("waiting for team rotate %s", teamID) 626 627 // jump start the clkr queue processing loop 628 u.kickTeamRekeyd() 629 630 // process 20 team rotate notifications or 10s worth of time 631 timeout := time.After(10 * time.Second * libkb.CITimeMultiplier(u.tc.G)) 632 for i := 0; i < 20; i++ { 633 select { 634 case arg := <-u.notifications.changeCh: 635 u.tc.T.Logf("rotate received: %s", spew.Sdump(arg)) 636 if arg.TeamID.Eq(teamID) && arg.Changes.KeyRotated && arg.LatestSeqno == toSeqno && (toHiddenSeqno == keybase1.Seqno(0) || toHiddenSeqno == arg.LatestHiddenSeqno) { 637 u.tc.T.Logf("rotate matched!") 638 return 639 } 640 u.tc.T.Logf("ignoring rotate message") 641 case <-timeout: 642 require.Fail(u.tc.T, fmt.Sprintf("timed out waiting for team rotate %s", teamID)) 643 return 644 } 645 } 646 } 647 648 func (u *userPlusDevice) waitForTeamChangedAndRotated(teamID keybase1.TeamID, toSeqno keybase1.Seqno) { 649 // process 20 team rotate notifications or 10s worth of time 650 timeout := time.After(10 * time.Second * libkb.CITimeMultiplier(u.tc.G)) 651 for i := 0; i < 20; i++ { 652 select { 653 case arg := <-u.notifications.changeCh: 654 u.tc.T.Logf("membership change received: %+v", arg) 655 if arg.TeamID.Eq(teamID) && arg.Changes.MembershipChanged && arg.Changes.KeyRotated && !arg.Changes.Renamed && arg.LatestSeqno == toSeqno { 656 u.tc.T.Logf("change matched!") 657 return 658 } 659 u.tc.T.Logf("ignoring change message (expected team = %v, seqno = %d)", teamID, toSeqno) 660 case <-timeout: 661 require.Fail(u.tc.T, fmt.Sprintf("timed out waiting for team rotate %s", teamID)) 662 return 663 } 664 } 665 } 666 667 func (u *userPlusDevice) waitForTeamChangeRenamed(teamID keybase1.TeamID) { 668 // Process any number of badge state updates, but bail out after 10 669 // seconds. 670 timeout := time.After(10 * time.Second * libkb.CITimeMultiplier(u.tc.G)) 671 i := 0 672 for { 673 select { 674 case arg := <-u.notifications.changeCh: 675 u.tc.T.Logf("membership change received: %+v", arg) 676 if arg.TeamID.Eq(teamID) && !arg.Changes.MembershipChanged && !arg.Changes.KeyRotated && arg.Changes.Renamed { 677 u.tc.T.Logf("change matched!") 678 return 679 } 680 u.tc.T.Logf("ignoring change message attempt %d (expected team = %v, renamed = true)", i, teamID) 681 case <-timeout: 682 require.Fail(u.tc.T, fmt.Sprintf("timed out waiting for team changes %s", teamID)) 683 } 684 i++ 685 } 686 } 687 688 func (u *userPlusDevice) waitForNewlyAddedToTeamByID(teamID keybase1.TeamID) { 689 u.tc.T.Logf("waiting for newly added to team %s", teamID) 690 691 // Process any number of badge state updates, but bail out after 10 692 // seconds. 693 timeout := time.After(10 * time.Second * libkb.CITimeMultiplier(u.tc.G)) 694 i := 0 695 for { 696 select { 697 case tid := <-u.notifications.newlyAddedToTeam: 698 u.tc.T.Logf("newlyAddedToTeam recieved: %+v", tid) 699 if tid.Eq(teamID) { 700 u.tc.T.Logf("newlyAddedToTeam matched!") 701 return 702 } 703 u.tc.T.Logf("ignoring newly added message attempt %d (expected team = %v)", i, teamID) 704 case <-timeout: 705 require.Fail(u.tc.T, fmt.Sprintf("timed out waiting newly added message %s", teamID)) 706 } 707 } 708 } 709 710 func (u *userPlusDevice) pollForTeamSeqnoLink(team string, toSeqno keybase1.Seqno) { 711 for i := 0; i < 20; i++ { 712 after, err := teams.Load(context.TODO(), u.tc.G, keybase1.LoadTeamArg{ 713 Name: team, 714 ForceRepoll: true, 715 }) 716 if err != nil { 717 require.Fail(u.tc.T, fmt.Sprintf("error while loading team %q: %v", team, err)) 718 } 719 720 if after.CurrentSeqno() >= toSeqno { 721 u.tc.T.Logf("Found new seqno %d at poll loop iter %d", after.CurrentSeqno(), i) 722 return 723 } 724 725 time.Sleep(500 * time.Millisecond * libkb.CITimeMultiplier(u.tc.G)) 726 } 727 728 require.Fail(u.tc.T, fmt.Sprintf("timed out waiting for team rotate %s", team)) 729 } 730 731 func (u *userPlusDevice) pollForTeamSeqnoLinkWithLoadArgs(args keybase1.LoadTeamArg, toSeqno keybase1.Seqno) { 732 args.ForceRepoll = true 733 for i := 0; i < 20; i++ { 734 details, err := teams.Load(context.Background(), u.tc.G, args) 735 if err != nil { 736 require.Fail(u.tc.T, fmt.Sprintf("error while loading team %v: %v", args, err)) 737 } 738 739 if details.CurrentSeqno() >= toSeqno { 740 u.tc.T.Logf("Found new seqno %d at poll loop iter %d", details.CurrentSeqno(), i) 741 return 742 } 743 744 time.Sleep(500 * time.Millisecond * libkb.CITimeMultiplier(u.tc.G)) 745 } 746 747 require.Fail(u.tc.T, fmt.Sprintf("timed out waiting for team %v seqno link %d", args, toSeqno)) 748 } 749 750 func (u *userPlusDevice) proveRooter() { 751 cmd := client.NewCmdProveRooterRunner(u.tc.G, u.username) 752 if err := cmd.Run(); err != nil { 753 u.tc.T.Fatal(err) 754 } 755 } 756 757 func (u *userPlusDevice) proveGubbleSocial() { 758 proveGubbleUniverse(u.tc, "gubble.social", "gubble_social", u.username, u.newSecretUI()) 759 } 760 761 func (u *userPlusDevice) revokeServiceProof(serviceType string) { 762 tctx := u.tc 763 arg := libkb.NewLoadUserArg(tctx.G).WithUID(u.uid).WithForcePoll(true) 764 user, err := libkb.LoadUser(arg) 765 require.NoError(tctx.T, err) 766 require.NotNil(tctx.T, user) 767 768 st := tctx.G.GetProofServices().GetServiceType(context.TODO(), "rooter") 769 ret := user.IDTable().GetActiveProofsFor(st) 770 require.Len(tctx.T, ret, 1) 771 sigID := ret[0].GetSigID() 772 773 revokeClient := keybase1.RevokeClient{Cli: u.teamsClient.Cli} 774 err = revokeClient.RevokeSigs(context.TODO(), keybase1.RevokeSigsArg{ 775 SigIDQueries: []string{sigID.String()}, 776 }) 777 require.NoError(tctx.T, err) 778 } 779 780 func (u *userPlusDevice) track(username string) { 781 trackCmd := client.NewCmdTrackRunner(u.tc.G) 782 trackCmd.SetUser(username) 783 trackCmd.SetOptions(keybase1.TrackOptions{BypassConfirm: true}) 784 err := trackCmd.Run() 785 require.NoError(u.tc.T, err) 786 } 787 788 func (u *userPlusDevice) block(username string, chat bool, follow bool) { 789 arg := keybase1.SetUserBlocksArg{ 790 Blocks: []keybase1.UserBlockArg{ 791 { 792 Username: username, 793 SetChatBlock: &chat, 794 SetFollowBlock: &follow, 795 }, 796 }, 797 } 798 err := u.device.userClient.SetUserBlocks(context.TODO(), arg) 799 require.NoError(u.tc.T, err) 800 } 801 802 func (u *userPlusDevice) untrack(username string) { 803 untrackCmd := client.NewCmdUntrackRunner(u.tc.G) 804 untrackCmd.SetUser(username) 805 err := untrackCmd.Run() 806 require.NoError(u.tc.T, err) 807 } 808 809 func (u *userPlusDevice) kickTeamRekeyd() { 810 kickTeamRekeyd(u.tc.G, u.tc.T) 811 } 812 813 func (u *userPlusDevice) kickAutoresetd() { 814 kickAutoresetd(u.tc.G, u.tc.T) 815 } 816 817 func (u *userPlusDevice) lookupImplicitTeam(create bool, displayName string, public bool) (keybase1.TeamID, error) { 818 res, err := u.lookupImplicitTeam2(create, displayName, public) 819 return res.TeamID, err 820 } 821 822 func (u *userPlusDevice) lookupImplicitTeam2(create bool, displayName string, public bool) (keybase1.LookupImplicitTeamRes, error) { 823 cli := u.teamsClient 824 var err error 825 var res keybase1.LookupImplicitTeamRes 826 if create { 827 res, err = cli.LookupOrCreateImplicitTeam(context.TODO(), keybase1.LookupOrCreateImplicitTeamArg{Name: displayName, Public: public}) 828 } else { 829 res, err = cli.LookupImplicitTeam(context.TODO(), keybase1.LookupImplicitTeamArg{Name: displayName, Public: public}) 830 } 831 return res, err 832 } 833 834 func (u *userPlusDevice) delayMerkleTeam(teamID keybase1.TeamID) { 835 mctx := u.MetaContext() 836 _, err := u.tc.G.API.Post(mctx, libkb.APIArg{ 837 Endpoint: "test/merkled/delay_team", 838 Args: libkb.HTTPArgs{ 839 "tid": libkb.S{Val: teamID.String()}, 840 }, 841 SessionType: libkb.APISessionTypeREQUIRED, 842 }) 843 require.NoError(u.tc.T, err) 844 } 845 846 func (u *userPlusDevice) newSecretUI() *libkb.TestSecretUI { 847 return &libkb.TestSecretUI{Passphrase: u.passphrase} 848 } 849 850 func (u *userPlusDevice) provisionNewDevice() (d *deviceWrapper, cleanup func()) { 851 tc := setupTest(u.tc.T, "sub") 852 t := tc.T 853 g := tc.G 854 855 device := &deviceWrapper{tctx: tc} 856 device.start(0) 857 858 require.NotNil(t, u.backupKey, "Add user with paper key to use provisionNewDevice") 859 860 // ui for provisioning 861 ui := &rekeyProvisionUI{username: u.username, backupKey: *u.backupKey} 862 { 863 _, xp, err := client.GetRPCClientWithContext(g) 864 require.NoError(t, err) 865 srv := rpc.NewServer(xp, nil) 866 protocols := []rpc.Protocol{ 867 keybase1.LoginUiProtocol(ui), 868 keybase1.SecretUiProtocol(ui), 869 keybase1.ProvisionUiProtocol(ui), 870 } 871 for _, prot := range protocols { 872 err = srv.Register(prot) 873 require.NoError(t, err) 874 } 875 } 876 877 cmd := client.NewCmdLoginRunner(g) 878 err := cmd.Run() 879 require.NoError(t, err, "login") 880 881 // Clear the paper key. 882 g.ActiveDevice.ClearCaches() 883 884 skey, err := g.ActiveDevice.SigningKey() 885 require.NoError(t, err) 886 device.deviceKey.KID = skey.GetKID() 887 require.True(t, device.deviceKey.KID.Exists()) 888 device.deviceKey.DeviceID = g.ActiveDevice.DeviceID() 889 require.True(t, device.deviceKey.DeviceID.Exists()) 890 891 cleanup = func() { 892 device.tctx.Cleanup() 893 if device.service != nil { 894 device.service.Stop(0) 895 err := device.stop() 896 require.NoError(tc.T, err) 897 } 898 } 899 900 return device, cleanup 901 } 902 903 func (u *userPlusDevice) reset() { 904 u.device.tctx.Tp.SkipLogoutIfRevokedCheck = true 905 uvBefore := u.userVersion() 906 err := u.device.accountClient.ResetAccount(context.TODO(), keybase1.ResetAccountArg{Passphrase: u.passphrase}) 907 require.NoError(u.tc.T, err) 908 uvAfter := u.userVersion() 909 require.NotEqual(u.tc.T, uvBefore.EldestSeqno, uvAfter.EldestSeqno, 910 "eldest seqno should change as result of reset") 911 u.tc.T.Logf("User reset; eldest seqno %d -> %d", uvBefore.EldestSeqno, uvAfter.EldestSeqno) 912 } 913 914 func (u *userPlusDevice) delete() { 915 g := u.tc.G 916 ui := genericUI{ 917 g: g, 918 SecretUI: signupInfoSecretUI{u.userInfo, u.tc.G.GetLog()}, 919 TerminalUI: smuTerminalUI{}, 920 } 921 g.SetUI(&ui) 922 cmd := client.NewCmdAccountDeleteRunner(g) 923 err := cmd.Run() 924 require.NoError(u.tc.T, err) 925 } 926 927 func (u *userPlusDevice) logout() { 928 err := u.tc.Logout() 929 require.NoError(u.tc.T, err) 930 } 931 932 func (u *userPlusDevice) login() { 933 uis := libkb.UIs{ 934 ProvisionUI: &kbtest.TestProvisionUI{}, 935 LogUI: u.tc.G.Log, 936 GPGUI: &kbtest.GPGTestUI{}, 937 SecretUI: u.newSecretUI(), 938 LoginUI: &libkb.TestLoginUI{Username: u.username}, 939 } 940 li := engine.NewLogin(u.tc.G, keybase1.DeviceTypeV2_DESKTOP, u.username, keybase1.ClientType_CLI) 941 mctx := libkb.NewMetaContextTODO(u.tc.G).WithUIs(uis) 942 err := engine.RunEngine2(mctx, li) 943 require.NoError(u.tc.T, err) 944 } 945 946 func (u *userPlusDevice) loginAfterReset() { 947 u.loginAfterResetHelper(true) 948 } 949 950 func (u *userPlusDevice) loginAfterResetPukless() { 951 u.loginAfterResetHelper(false) 952 } 953 954 func (u *userPlusDevice) loginAfterResetHelper(puk bool) { 955 t := u.device.tctx.T 956 u.device.tctx.Tp.DisableUpgradePerUserKey = !puk 957 g := u.device.tctx.G 958 959 // We have to reset a socket here, since we need to register 960 // the protocols in the genericUI below. If we reuse the previous 961 // socket, then the RPC protocols will not update, and we'll wind 962 // up reusing the old device name. 963 _, _, _, err := g.ResetSocket(true) 964 require.NoError(t, err) 965 966 devName := randomDevice() 967 g.Log.Debug("loginAfterResetHelper: new device name is %q", devName) 968 969 ui := genericUI{ 970 g: g, 971 SecretUI: signupInfoSecretUI{u.userInfo, u.tc.G.GetLog()}, 972 LoginUI: usernameLoginUI{u.username}, 973 ProvisionUI: nullProvisionUI{devName}, 974 } 975 g.SetUI(&ui) 976 loginCmd := client.NewCmdLoginRunner(g) 977 loginCmd.Username = u.username 978 err = loginCmd.Run() 979 require.NoError(t, err, "login after reset") 980 } 981 982 func TestTeamTesterMultipleResets(t *testing.T) { 983 tt := newTeamTester(t) 984 defer tt.cleanup() 985 986 ann := tt.addUser("ann") 987 t.Logf("Signed up ann (%s)", ann.username) 988 989 ann.reset() 990 ann.loginAfterReset() 991 992 t.Logf("Ann resets for first time, uv is %v", ann.userVersion()) 993 994 ann.reset() 995 ann.loginAfterReset() 996 t.Logf("Ann reset twice, uv is %v", ann.userVersion()) 997 } 998 999 func (u *userPlusDevice) perUserKeyUpgrade() { 1000 t := u.device.tctx.T 1001 u.device.tctx.Tp.DisableUpgradePerUserKey = false 1002 g := u.device.tctx.G 1003 arg := &engine.PerUserKeyUpgradeArgs{} 1004 eng := engine.NewPerUserKeyUpgrade(g, arg) 1005 uis := libkb.UIs{ 1006 LogUI: u.tc.G.Log, 1007 } 1008 m := libkb.NewMetaContextTODO(g).WithUIs(uis) 1009 err := engine.RunEngine2(m, eng) 1010 require.NoError(t, err, "Run engine.NewPerUserKeyUpgrade") 1011 } 1012 1013 func (u *userPlusDevice) disableTOFUSearch() { 1014 mctx := u.MetaContext() 1015 arg := libkb.NewAPIArg("test/disable_tofu_search_for_uid") 1016 arg.SessionType = libkb.APISessionTypeREQUIRED 1017 _, err := u.tc.G.API.Post(mctx, arg) 1018 require.NoError(u.tc.T, err) 1019 } 1020 1021 func (u *userPlusDevice) MetaContext() libkb.MetaContext { 1022 return libkb.NewMetaContextForTest(*u.tc) 1023 } 1024 1025 func kickAutoresetd(g *libkb.GlobalContext, t libkb.TestingTB) { 1026 mctx := libkb.NewMetaContextTODO(g) 1027 _, err := g.API.Post(mctx, libkb.APIArg{ 1028 Endpoint: "test/accelerate_autoresetd", 1029 SessionType: libkb.APISessionTypeREQUIRED, 1030 }) 1031 require.NoError(t, err) 1032 } 1033 1034 func kickTeamRekeyd(g *libkb.GlobalContext, t libkb.TestingTB) { 1035 const workTimeSec = 1 // team_rekeyd delay before retrying job if it wasn't finished. 1036 args := libkb.HTTPArgs{ 1037 "work_time_sec": libkb.I{Val: workTimeSec}, 1038 } 1039 apiArg := libkb.APIArg{ 1040 Endpoint: "test/accelerate_team_rekeyd", 1041 Args: args, 1042 SessionType: libkb.APISessionTypeREQUIRED, 1043 } 1044 1045 t.Logf("Calling accelerate_team_rekeyd, setting work_time_sec to %d", workTimeSec) 1046 1047 mctx := libkb.NewMetaContextTODO(g) 1048 _, err := g.API.Post(mctx, apiArg) 1049 require.NoError(t, err) 1050 } 1051 1052 func enableOpenSweepForTeam(g *libkb.GlobalContext, t libkb.TestingTB, teamID keybase1.TeamID) { 1053 args := libkb.HTTPArgs{ 1054 "team_id": libkb.S{Val: teamID.String()}, 1055 } 1056 apiArg := libkb.APIArg{ 1057 Endpoint: "test/team_enable_open_sweep", 1058 Args: args, 1059 SessionType: libkb.APISessionTypeREQUIRED, 1060 } 1061 1062 t.Logf("Calling team_enable_open_sweep for team ID: %s", teamID) 1063 1064 _, err := g.API.Post(libkb.NewMetaContextTODO(g), apiArg) 1065 require.NoError(t, err) 1066 } 1067 1068 func GetTeamForTestByStringName(ctx context.Context, g *libkb.GlobalContext, name string) (*teams.Team, error) { 1069 return teams.Load(ctx, g, keybase1.LoadTeamArg{ 1070 Name: name, 1071 ForceRepoll: true, 1072 }) 1073 } 1074 1075 func GetTeamForTestByID(ctx context.Context, g *libkb.GlobalContext, id keybase1.TeamID, public bool) (*teams.Team, error) { 1076 return teams.Load(ctx, g, keybase1.LoadTeamArg{ 1077 ID: id, 1078 Public: public, 1079 ForceRepoll: true, 1080 }) 1081 } 1082 1083 type teamNotifyHandler struct { 1084 changeCh chan keybase1.TeamChangedByIDArg 1085 abandonCh chan keybase1.TeamID 1086 badgeCh chan keybase1.BadgeState 1087 newTeamEKCh chan keybase1.NewTeamEkArg 1088 newTeambotEKCh chan keybase1.NewTeambotEkArg 1089 teambotEKNeededCh chan keybase1.TeambotEkNeededArg 1090 newTeambotKeyCh chan keybase1.NewTeambotKeyArg 1091 teambotKeyNeededCh chan keybase1.TeambotKeyNeededArg 1092 newlyAddedToTeam chan keybase1.TeamID 1093 teamRoleMapCh chan keybase1.UserTeamVersion 1094 metadataUpdateCh chan struct{} 1095 teamTreeMembershipsPartialCh chan keybase1.TeamTreeMembership 1096 teamTreeMembershipsDoneCh chan keybase1.TeamTreeMembershipsDoneResult 1097 } 1098 1099 func newTeamNotifyHandler() *teamNotifyHandler { 1100 return &teamNotifyHandler{ 1101 changeCh: make(chan keybase1.TeamChangedByIDArg, 10), 1102 abandonCh: make(chan keybase1.TeamID, 10), 1103 badgeCh: make(chan keybase1.BadgeState, 10), 1104 newTeamEKCh: make(chan keybase1.NewTeamEkArg, 10), 1105 newTeambotEKCh: make(chan keybase1.NewTeambotEkArg, 10), 1106 teambotEKNeededCh: make(chan keybase1.TeambotEkNeededArg, 10), 1107 newTeambotKeyCh: make(chan keybase1.NewTeambotKeyArg, 10), 1108 teambotKeyNeededCh: make(chan keybase1.TeambotKeyNeededArg, 10), 1109 newlyAddedToTeam: make(chan keybase1.TeamID, 10), 1110 teamRoleMapCh: make(chan keybase1.UserTeamVersion, 100), 1111 metadataUpdateCh: make(chan struct{}, 10), 1112 teamTreeMembershipsPartialCh: make(chan keybase1.TeamTreeMembership, 10), 1113 teamTreeMembershipsDoneCh: make(chan keybase1.TeamTreeMembershipsDoneResult, 10), 1114 } 1115 } 1116 1117 func (n *teamNotifyHandler) TeamChangedByID(ctx context.Context, arg keybase1.TeamChangedByIDArg) error { 1118 n.changeCh <- arg 1119 return nil 1120 } 1121 1122 func (n *teamNotifyHandler) TeamChangedByName(ctx context.Context, arg keybase1.TeamChangedByNameArg) error { 1123 return nil 1124 } 1125 1126 func (n *teamNotifyHandler) TeamDeleted(ctx context.Context, teamID keybase1.TeamID) error { 1127 return nil 1128 } 1129 1130 func (n *teamNotifyHandler) TeamExit(ctx context.Context, teamID keybase1.TeamID) error { 1131 return nil 1132 } 1133 1134 func (n *teamNotifyHandler) NewlyAddedToTeam(ctx context.Context, teamID keybase1.TeamID) error { 1135 n.newlyAddedToTeam <- teamID 1136 return nil 1137 } 1138 1139 func (n *teamNotifyHandler) TeamMetadataUpdate(ctx context.Context) error { 1140 n.metadataUpdateCh <- struct{}{} 1141 return nil 1142 } 1143 1144 func (n *teamNotifyHandler) TeamAbandoned(ctx context.Context, teamID keybase1.TeamID) error { 1145 n.abandonCh <- teamID 1146 return nil 1147 } 1148 1149 func (n *teamNotifyHandler) BadgeState(ctx context.Context, badgeState keybase1.BadgeState) error { 1150 n.badgeCh <- badgeState 1151 return nil 1152 } 1153 1154 func (n *teamNotifyHandler) NewTeamEk(ctx context.Context, arg keybase1.NewTeamEkArg) error { 1155 n.newTeamEKCh <- arg 1156 return nil 1157 } 1158 1159 func (n *teamNotifyHandler) NewTeambotEk(ctx context.Context, arg keybase1.NewTeambotEkArg) error { 1160 n.newTeambotEKCh <- arg 1161 return nil 1162 } 1163 1164 func (n *teamNotifyHandler) TeambotEkNeeded(ctx context.Context, arg keybase1.TeambotEkNeededArg) error { 1165 n.teambotEKNeededCh <- arg 1166 return nil 1167 } 1168 1169 func (n *teamNotifyHandler) NewTeambotKey(ctx context.Context, arg keybase1.NewTeambotKeyArg) error { 1170 n.newTeambotKeyCh <- arg 1171 return nil 1172 } 1173 1174 func (n *teamNotifyHandler) TeambotKeyNeeded(ctx context.Context, arg keybase1.TeambotKeyNeededArg) error { 1175 n.teambotKeyNeededCh <- arg 1176 return nil 1177 } 1178 1179 func (n *teamNotifyHandler) AvatarUpdated(ctx context.Context, arg keybase1.AvatarUpdatedArg) error { 1180 return nil 1181 } 1182 1183 func (n *teamNotifyHandler) TeamRoleMapChanged(ctx context.Context, version keybase1.UserTeamVersion) error { 1184 n.teamRoleMapCh <- version 1185 return nil 1186 } 1187 1188 func (n *teamNotifyHandler) TeamTreeMembershipsPartial(ctx context.Context, 1189 arg keybase1.TeamTreeMembership) error { 1190 1191 n.teamTreeMembershipsPartialCh <- arg 1192 return nil 1193 } 1194 1195 func (n *teamNotifyHandler) TeamTreeMembershipsDone(ctx context.Context, 1196 arg keybase1.TeamTreeMembershipsDoneResult) error { 1197 1198 n.teamTreeMembershipsDoneCh <- arg 1199 return nil 1200 } 1201 1202 func TestGetTeamRootID(t *testing.T) { 1203 tt := newTeamTester(t) 1204 defer tt.cleanup() 1205 1206 tt.addUser("onr") 1207 1208 t.Logf("create a team") 1209 parentName, err := keybase1.TeamNameFromString(tt.users[0].createTeam()) 1210 require.NoError(t, err) 1211 1212 parentID := parentName.ToPrivateTeamID() 1213 1214 t.Logf("create a subteam") 1215 subteamID, err := teams.CreateSubteam(context.TODO(), tt.users[0].tc.G, "mysubteam", parentName, keybase1.TeamRole_NONE /* addSelfAs */) 1216 require.NoError(t, err) 1217 1218 subteamName, err := parentName.Append("mysubteam") 1219 require.NoError(t, err) 1220 1221 t.Logf("create a sub-subteam") 1222 subteamID2, err := teams.CreateSubteam(context.TODO(), tt.users[0].tc.G, "teamofsubs", subteamName, keybase1.TeamRole_NONE /* addSelfAs */) 1223 require.NoError(t, err) 1224 1225 getAndCompare := func(id keybase1.TeamID) { 1226 retID, err := teams.GetRootID(context.TODO(), tt.users[0].tc.G, id) 1227 require.NoError(t, err) 1228 require.Equal(t, parentID, retID) 1229 } 1230 1231 getAndCompare(*subteamID) 1232 getAndCompare(*subteamID2) 1233 getAndCompare(parentID) 1234 } 1235 1236 // Test that we can still load a valid link a signed by a now-revoked device. 1237 func TestTeamSignedByRevokedDevice(t *testing.T) { 1238 tt := newTeamTester(t) 1239 defer tt.cleanup() 1240 1241 // the signer 1242 alice := tt.addUserWithPaper("alice") 1243 1244 // the loader 1245 bob := tt.addUser("bob") 1246 1247 teamID, teamName := alice.createTeam2() 1248 // Delay team sigs in the merkle queue to try to elicit a bad race. As a regression test for CORE-8233. 1249 alice.delayMerkleTeam(teamID) 1250 alice.addTeamMember(teamName.String(), bob.username, keybase1.TeamRole_ADMIN) 1251 1252 t.Logf("alice revokes the device used to sign team links") 1253 var revokedKID keybase1.KID 1254 { 1255 devices, _ := getActiveDevicesAndKeys(alice.tc, alice.username) 1256 var target *libkb.Device 1257 for _, device := range devices { 1258 if device.Type != keybase1.DeviceTypeV2_PAPER { 1259 target = device 1260 } 1261 } 1262 require.NotNil(t, target) 1263 revokedKID = target.Kid 1264 1265 revokeAttemptsMax := 3 1266 var err error 1267 for i := 0; i < revokeAttemptsMax; i++ { 1268 t.Logf("revoke attempt %v / %v", i+1, revokeAttemptsMax) 1269 revokeEngine := engine.NewRevokeDeviceEngine(alice.tc.G, engine.RevokeDeviceEngineArgs{ 1270 ID: target.ID, 1271 ForceSelf: true, 1272 ForceLast: false, 1273 }) 1274 uis := libkb.UIs{ 1275 LogUI: alice.tc.G.Log, 1276 SecretUI: alice.newSecretUI(), 1277 } 1278 m := libkb.NewMetaContextForTest(*alice.tc).WithUIs(uis) 1279 err = engine.RunEngine2(m, revokeEngine) 1280 if err == nil { 1281 break 1282 } 1283 t.Logf("revoke attempt %v failed: %v", i, err) 1284 if strings.Contains(err.Error(), "lazy merkle transaction in progress for key") { 1285 continue 1286 } 1287 } 1288 require.NoError(t, err) 1289 } 1290 1291 t.Logf("bob updates cache of alice's info") 1292 { 1293 arg := libkb.NewLoadUserArg(bob.tc.G).WithUID(alice.uid).WithPublicKeyOptional().WithForcePoll(true) 1294 _, _, err := bob.tc.G.GetUPAKLoader().LoadV2(arg) 1295 require.NoError(t, err) 1296 } 1297 1298 t.Logf("bob should see alice's key is revoked") 1299 { 1300 _, _, pubKey, err := bob.tc.G.GetUPAKLoader().LoadKeyV2(context.TODO(), alice.uid, revokedKID) 1301 require.NoError(t, err) 1302 t.Logf("%v", spew.Sdump(pubKey)) 1303 require.NotNil(t, pubKey.Base.Revocation, "key should be revoked: %v", revokedKID) 1304 } 1305 1306 t.Logf("bob loads the team") 1307 _, err := teams.Load(context.TODO(), bob.tc.G, keybase1.LoadTeamArg{ 1308 Name: teamName.String(), 1309 ForceRepoll: true, 1310 ForceFullReload: true, // don't use the cache 1311 }) 1312 require.NoError(t, err) 1313 } 1314 1315 // Another test of loading a team with a valid link signed by a now-revoked 1316 // device. The previous test didn't catch a bug. In this test at the time 1317 // when the device is revoked the team sigchain points to a link that was 1318 // signed by a never-revoked device and is subsequent to the link signed by the 1319 // revoked device. 1320 func TestTeamSignedByRevokedDevice2(t *testing.T) { 1321 tt := newTeamTester(t) 1322 defer tt.cleanup() 1323 1324 // the signer 1325 alice := tt.addUserWithPaper("alice") 1326 aliced2, cleanup := alice.provisionNewDevice() 1327 defer cleanup() 1328 1329 // the loader 1330 bob := tt.addUser("bob") 1331 1332 teamName := alice.createTeam() 1333 1334 t.Logf("sign a link with the to-be-revoked device (aliced2)") 1335 { 1336 eng := client.NewCmdTeamAddMemberRunner(aliced2.tctx.G) 1337 eng.Team = teamName 1338 eng.Username = bob.username 1339 eng.Role = keybase1.TeamRole_ADMIN 1340 err := eng.Run() 1341 require.NoError(t, err) 1342 } 1343 1344 alice.changeTeamMember(teamName, bob.username, keybase1.TeamRole_ADMIN) 1345 1346 t.Logf("alice revokes a device used to sign team links (alice2)") 1347 revokedKID := aliced2.KID() 1348 require.True(t, revokedKID.Exists()) 1349 { 1350 devices, _ := getActiveDevicesAndKeys(alice.tc, alice.username) 1351 var target *libkb.Device 1352 for _, device := range devices { 1353 t.Logf("scan device: ID:%v KID:%v", device.ID, device.Kid) 1354 if device.Kid.Equal(revokedKID) { 1355 target = device 1356 } 1357 } 1358 require.NotNil(t, target) 1359 1360 revokeEngine := engine.NewRevokeDeviceEngine(alice.tc.G, engine.RevokeDeviceEngineArgs{ 1361 ID: target.ID, 1362 ForceSelf: true, 1363 ForceLast: false, 1364 }) 1365 uis := libkb.UIs{ 1366 LogUI: alice.tc.G.Log, 1367 SecretUI: alice.newSecretUI(), 1368 } 1369 m := libkb.NewMetaContextForTest(*alice.tc).WithUIs(uis) 1370 err := engine.RunEngine2(m, revokeEngine) 1371 require.NoError(t, err) 1372 } 1373 1374 t.Logf("bob updates cache of alice's info") 1375 { 1376 arg := libkb.NewLoadUserArg(bob.tc.G).WithUID(alice.uid).WithPublicKeyOptional().WithForcePoll(true) 1377 _, _, err := bob.tc.G.GetUPAKLoader().LoadV2(arg) 1378 require.NoError(t, err) 1379 } 1380 1381 t.Logf("bob should see alice's key is revoked") 1382 { 1383 _, _, pubKey, err := bob.tc.G.GetUPAKLoader().LoadKeyV2(context.TODO(), alice.uid, revokedKID) 1384 require.NoError(t, err) 1385 t.Logf("%v", spew.Sdump(pubKey)) 1386 require.NotNil(t, pubKey.Base.Revocation, "key should be revoked: %v", revokedKID) 1387 } 1388 1389 t.Logf("bob loads the team") 1390 _, err := teams.Load(context.TODO(), bob.tc.G, keybase1.LoadTeamArg{ 1391 Name: teamName, 1392 ForceRepoll: true, 1393 ForceFullReload: true, // don't use the cache 1394 }) 1395 require.NoError(t, err) 1396 } 1397 1398 func TestImpTeamLookupWithTrackingFailure(t *testing.T) { 1399 tt := newTeamTester(t) 1400 defer tt.cleanup() 1401 1402 alice := tt.addUser("alice") 1403 g := tt.users[0].tc.G 1404 1405 tt.addUser("wong") 1406 wong := tt.users[1] 1407 1408 iTeamNameCreate := strings.Join([]string{alice.username, wong.username}, ",") 1409 1410 t.Logf("make an implicit team") 1411 team, err := alice.lookupImplicitTeam(true /*create*/, iTeamNameCreate, false /*isPublic*/) 1412 require.NoError(t, err) 1413 1414 iui := newSimpleIdentifyUI() 1415 attachIdentifyUI(t, g, iui) 1416 1417 t.Logf("prove rooter and track") 1418 g.ProofCache.DisableDisk() 1419 wong.proveRooter() 1420 iui.confirmRes = keybase1.ConfirmResult{IdentityConfirmed: true, RemoteConfirmed: true, AutoConfirmed: true} 1421 tt.users[0].track(wong.username) 1422 iui.confirmRes = keybase1.ConfirmResult{} 1423 1424 t.Logf("make rooter unreachable") 1425 g.XAPI = &flakeyRooterAPI{orig: g.XAPI, hardFail: true, G: g} 1426 err = g.ProofCache.Reset() 1427 require.NoError(t, err) 1428 1429 t.Logf("lookup the implicit team while full identify is failing") 1430 team2, err := alice.lookupImplicitTeam(true /*create*/, iTeamNameCreate, false /*isPublic*/) 1431 require.NoError(t, err) 1432 require.Equal(t, team, team2) 1433 } 1434 1435 // Leave a team and make sure the team list no longer includes it. 1436 func TestTeamLeaveThenList(t *testing.T) { 1437 tt := newTeamTester(t) 1438 defer tt.cleanup() 1439 1440 alice := tt.addUser("alice") 1441 bob := tt.addUser("bob") 1442 1443 teamID, teamName := alice.createTeam2() 1444 // add bob as owner because we can't leave as the only owner. 1445 alice.addTeamMember(teamName.String(), bob.username, keybase1.TeamRole_OWNER) 1446 1447 teams := alice.teamList("", false, false) 1448 require.Len(t, teams.Teams, 1) 1449 require.Equal(t, teamID, teams.Teams[0].TeamID) 1450 1451 alice.leave(teamName.String()) 1452 1453 teams = alice.teamList("", false, false) 1454 require.Len(t, teams.Teams, 0) 1455 } 1456 1457 func TestTeamCanUserPerform(t *testing.T) { 1458 tt := newTeamTester(t) 1459 defer tt.cleanup() 1460 1461 ann := tt.addUser("ann") 1462 bob := tt.addUser("bob") 1463 pam := tt.addUser("pam") 1464 edd := tt.addUser("edd") 1465 jon := tt.addUser("jon") 1466 1467 team := ann.createTeam() 1468 ann.addTeamMember(team, bob.username, keybase1.TeamRole_ADMIN) 1469 ann.addTeamMember(team, pam.username, keybase1.TeamRole_WRITER) 1470 ann.addTeamMember(team, edd.username, keybase1.TeamRole_READER) 1471 ann.addTeamMember(team, jon.username, keybase1.TeamRole_ADMIN) 1472 1473 parentName, err := keybase1.TeamNameFromString(team) 1474 require.NoError(t, err) 1475 1476 _, err = teams.CreateSubteam(context.TODO(), ann.tc.G, "mysubteam", parentName, keybase1.TeamRole_NONE /* addSelfAs */) 1477 require.NoError(t, err) 1478 subteam := team + ".mysubteam" 1479 ann.addTeamMember(subteam, jon.username, keybase1.TeamRole_READER) 1480 1481 callCanPerform := func(user *userPlusDevice, teamname string) keybase1.TeamOperation { 1482 ret, err := teams.CanUserPerform(context.TODO(), user.tc.G, teamname) 1483 t.Logf("teams.CanUserPerform(%s,%s)", user.username, teamname) 1484 require.NoError(t, err) 1485 return ret 1486 } 1487 annPerms := callCanPerform(ann, team) 1488 bobPerms := callCanPerform(bob, team) 1489 pamPerms := callCanPerform(pam, team) 1490 eddPerms := callCanPerform(edd, team) 1491 1492 // All ops except leave and join should be fine for owners and admins 1493 require.True(t, annPerms.ManageMembers) 1494 require.True(t, annPerms.ManageSubteams) 1495 require.True(t, annPerms.CreateChannel) 1496 require.True(t, annPerms.DeleteChannel) 1497 require.True(t, annPerms.RenameChannel) 1498 require.True(t, annPerms.EditChannelDescription) 1499 require.True(t, annPerms.EditTeamDescription) 1500 require.True(t, annPerms.SetTeamShowcase) 1501 require.True(t, annPerms.SetMemberShowcase) 1502 require.True(t, annPerms.SetRetentionPolicy) 1503 require.True(t, annPerms.SetMinWriterRole) 1504 require.True(t, annPerms.ChangeOpenTeam) 1505 require.False(t, annPerms.LeaveTeam) // sole owner can't leave 1506 require.False(t, annPerms.ListFirst) // only true for implicit admins 1507 require.False(t, annPerms.JoinTeam) 1508 require.True(t, annPerms.SetPublicityAny) 1509 require.True(t, annPerms.ChangeTarsDisabled) 1510 require.True(t, annPerms.DeleteChatHistory) 1511 require.True(t, annPerms.Chat) 1512 require.True(t, annPerms.DeleteTeam) 1513 1514 require.True(t, bobPerms.ManageMembers) 1515 require.True(t, bobPerms.ManageSubteams) 1516 require.True(t, bobPerms.CreateChannel) 1517 require.True(t, bobPerms.DeleteChannel) 1518 require.True(t, bobPerms.RenameChannel) 1519 require.True(t, bobPerms.EditChannelDescription) 1520 require.True(t, bobPerms.EditTeamDescription) 1521 require.True(t, bobPerms.SetTeamShowcase) 1522 require.True(t, bobPerms.SetMemberShowcase) 1523 require.True(t, bobPerms.SetRetentionPolicy) 1524 require.True(t, bobPerms.SetMinWriterRole) 1525 require.True(t, bobPerms.ChangeOpenTeam) 1526 require.True(t, bobPerms.LeaveTeam) 1527 require.False(t, bobPerms.ListFirst) 1528 require.False(t, bobPerms.JoinTeam) 1529 require.True(t, bobPerms.SetPublicityAny) 1530 require.True(t, bobPerms.ChangeTarsDisabled) 1531 require.True(t, bobPerms.DeleteChatHistory) 1532 require.True(t, bobPerms.Chat) 1533 require.False(t, bobPerms.DeleteTeam) 1534 1535 // Some ops are fine for writers 1536 require.False(t, pamPerms.ManageMembers) 1537 require.False(t, pamPerms.ManageSubteams) 1538 require.True(t, pamPerms.CreateChannel) 1539 require.False(t, pamPerms.DeleteChannel) 1540 require.True(t, pamPerms.RenameChannel) 1541 require.True(t, pamPerms.EditChannelDescription) 1542 require.False(t, pamPerms.EditTeamDescription) 1543 require.False(t, pamPerms.SetTeamShowcase) 1544 require.True(t, pamPerms.SetMemberShowcase) 1545 require.False(t, pamPerms.SetRetentionPolicy) 1546 require.False(t, pamPerms.SetMinWriterRole) 1547 require.False(t, pamPerms.ChangeOpenTeam) 1548 require.True(t, pamPerms.LeaveTeam) 1549 require.False(t, pamPerms.ListFirst) 1550 require.False(t, pamPerms.JoinTeam) 1551 require.False(t, pamPerms.SetPublicityAny) 1552 require.False(t, pamPerms.ChangeTarsDisabled) 1553 require.False(t, pamPerms.DeleteChatHistory) 1554 require.True(t, pamPerms.Chat) 1555 require.False(t, pamPerms.DeleteTeam) 1556 1557 // Only SetMemberShowcase (by default), LeaveTeam, and Chat is available for readers 1558 require.False(t, eddPerms.ManageMembers) 1559 require.False(t, eddPerms.ManageSubteams) 1560 require.False(t, eddPerms.CreateChannel) 1561 require.False(t, eddPerms.DeleteChannel) 1562 require.False(t, eddPerms.RenameChannel) 1563 require.False(t, eddPerms.EditChannelDescription) 1564 require.False(t, eddPerms.EditTeamDescription) 1565 require.False(t, eddPerms.SetTeamShowcase) 1566 require.True(t, eddPerms.SetMemberShowcase) 1567 require.False(t, eddPerms.SetRetentionPolicy) 1568 require.False(t, eddPerms.SetMinWriterRole) 1569 require.False(t, eddPerms.ChangeOpenTeam) 1570 require.True(t, eddPerms.LeaveTeam) 1571 require.False(t, eddPerms.ListFirst) 1572 require.False(t, eddPerms.JoinTeam) 1573 require.False(t, eddPerms.SetPublicityAny) 1574 require.False(t, eddPerms.ChangeTarsDisabled) 1575 require.False(t, eddPerms.DeleteChatHistory) 1576 require.True(t, eddPerms.Chat) 1577 require.False(t, eddPerms.DeleteTeam) 1578 1579 annPerms = callCanPerform(ann, subteam) 1580 bobPerms = callCanPerform(bob, subteam) 1581 jonPerms := callCanPerform(jon, subteam) 1582 1583 // Some ops are fine for implicit admins 1584 require.True(t, annPerms.ManageMembers) 1585 require.True(t, annPerms.ManageSubteams) 1586 require.False(t, annPerms.CreateChannel) 1587 require.False(t, annPerms.DeleteChannel) 1588 require.False(t, annPerms.RenameChannel) 1589 require.False(t, annPerms.EditChannelDescription) 1590 require.True(t, annPerms.EditTeamDescription) 1591 require.True(t, annPerms.SetTeamShowcase) 1592 require.False(t, annPerms.SetMemberShowcase) 1593 require.False(t, annPerms.SetRetentionPolicy) 1594 require.False(t, annPerms.SetMinWriterRole) 1595 require.True(t, annPerms.ChangeOpenTeam) // not a member of the subteam 1596 require.True(t, annPerms.ListFirst) 1597 require.True(t, annPerms.JoinTeam) 1598 require.True(t, annPerms.SetPublicityAny) 1599 require.True(t, annPerms.ChangeTarsDisabled) 1600 require.False(t, annPerms.DeleteChatHistory) 1601 require.False(t, annPerms.Chat) 1602 require.True(t, annPerms.DeleteTeam) 1603 1604 require.True(t, bobPerms.ManageMembers) 1605 require.True(t, bobPerms.ManageSubteams) 1606 require.False(t, bobPerms.CreateChannel) 1607 require.False(t, bobPerms.DeleteChannel) 1608 require.False(t, bobPerms.RenameChannel) 1609 require.False(t, bobPerms.EditChannelDescription) 1610 require.True(t, bobPerms.EditTeamDescription) 1611 require.True(t, bobPerms.SetTeamShowcase) 1612 require.False(t, bobPerms.SetMemberShowcase) 1613 require.False(t, bobPerms.SetRetentionPolicy) 1614 require.False(t, bobPerms.SetMinWriterRole) 1615 require.True(t, bobPerms.ChangeOpenTeam) 1616 require.False(t, bobPerms.LeaveTeam) // not a member of the subteam 1617 require.True(t, bobPerms.ListFirst) 1618 require.True(t, bobPerms.JoinTeam) 1619 require.True(t, bobPerms.SetPublicityAny) 1620 require.True(t, bobPerms.ChangeTarsDisabled) 1621 require.False(t, bobPerms.DeleteChatHistory) 1622 require.False(t, bobPerms.Chat) 1623 require.True(t, bobPerms.DeleteTeam) 1624 1625 // make sure JoinTeam is false since already a member 1626 require.True(t, jonPerms.ManageMembers) 1627 require.True(t, jonPerms.ManageSubteams) 1628 require.False(t, jonPerms.CreateChannel) 1629 require.False(t, jonPerms.DeleteChannel) 1630 require.False(t, jonPerms.RenameChannel) 1631 require.False(t, jonPerms.EditChannelDescription) 1632 require.True(t, jonPerms.EditTeamDescription) 1633 require.True(t, jonPerms.SetTeamShowcase) 1634 require.True(t, jonPerms.SetMemberShowcase) 1635 require.False(t, jonPerms.SetRetentionPolicy) 1636 require.False(t, jonPerms.SetMinWriterRole) 1637 require.True(t, jonPerms.ChangeOpenTeam) 1638 require.True(t, jonPerms.LeaveTeam) 1639 require.True(t, jonPerms.ListFirst) 1640 require.False(t, jonPerms.JoinTeam) 1641 require.True(t, jonPerms.SetPublicityAny) 1642 require.True(t, jonPerms.ChangeTarsDisabled) 1643 require.False(t, jonPerms.DeleteChatHistory) 1644 require.True(t, jonPerms.Chat) 1645 require.True(t, jonPerms.DeleteTeam) 1646 1647 // Invalid team for pam, no error 1648 _, err = teams.CanUserPerform(context.TODO(), pam.tc.G, subteam) 1649 require.NoError(t, err) 1650 1651 // Non-membership shouldn't be an error 1652 donny := tt.addUser("donny") 1653 donnyPerms, err := teams.CanUserPerform(context.TODO(), donny.tc.G, team) 1654 require.NoError(t, err, "non-member canUserPerform") 1655 1656 // Make sure a non-member can't do stuff 1657 require.False(t, donnyPerms.ManageMembers) 1658 require.False(t, donnyPerms.ManageSubteams) 1659 require.False(t, donnyPerms.CreateChannel) 1660 require.False(t, donnyPerms.DeleteChannel) 1661 require.False(t, donnyPerms.RenameChannel) 1662 require.False(t, donnyPerms.EditChannelDescription) 1663 require.False(t, donnyPerms.EditTeamDescription) 1664 require.False(t, donnyPerms.SetTeamShowcase) 1665 require.False(t, donnyPerms.SetMemberShowcase) 1666 require.False(t, donnyPerms.SetRetentionPolicy) 1667 require.False(t, donnyPerms.SetMinWriterRole) 1668 require.False(t, donnyPerms.ChangeOpenTeam) 1669 require.False(t, donnyPerms.ListFirst) 1670 // TBD: require.True(t, donnyPerms.JoinTeam) 1671 require.False(t, donnyPerms.SetPublicityAny) 1672 require.False(t, donnyPerms.DeleteChatHistory) 1673 require.False(t, donnyPerms.Chat) 1674 require.False(t, donnyPerms.DeleteTeam) 1675 } 1676 1677 func TestBatchAddMembersCLI(t *testing.T) { 1678 tt := newTeamTester(t) 1679 defer tt.cleanup() 1680 1681 alice := tt.addUser("alice") 1682 bob := tt.addUser("bob") 1683 ciara := tt.addUser("ciara") 1684 dodo := tt.addUser("dodo") 1685 botua := tt.addUser("botua") 1686 restrictedBotua := tt.addUser("rbot") 1687 john := tt.addPuklessUser("john") 1688 tt.logUserNames() 1689 teamID, _ := alice.createTeam2() 1690 1691 handler := service.NewAccountHandler(nil, ciara.tc.G) 1692 1693 // ciara doesn't allow alice to add them to team 1694 err := handler.UserSetContactSettings(context.Background(), keybase1.ContactSettings{ 1695 Enabled: true, 1696 AllowFolloweeDegrees: 0, 1697 }) 1698 require.NoError(t, err) 1699 1700 dodo.proveRooter() 1701 users := []keybase1.UserRolePair{ 1702 {Assertion: bob.username, Role: keybase1.TeamRole_ADMIN}, 1703 {Assertion: ciara.username, Role: keybase1.TeamRole_WRITER}, 1704 {Assertion: dodo.username + "+" + dodo.username + "@rooter", Role: keybase1.TeamRole_WRITER}, 1705 {Assertion: john.username + "@rooter", Role: keybase1.TeamRole_ADMIN}, 1706 {Assertion: john.username + "@keybase", Role: keybase1.TeamRole_READER}, 1707 {Assertion: "[rob@gmail.com]@email", Role: keybase1.TeamRole_READER}, 1708 {Assertion: botua.username, Role: keybase1.TeamRole_BOT}, 1709 {Assertion: restrictedBotua.username, Role: keybase1.TeamRole_RESTRICTEDBOT, BotSettings: &keybase1.TeamBotSettings{}}, 1710 } 1711 added, notAdded, err := teams.AddMembers(context.Background(), alice.tc.G, teamID, users, nil /* emailInviteMsg */) 1712 require.NoError(t, err) 1713 require.Len(t, added, 7) 1714 require.Len(t, notAdded, 1) 1715 require.Equal(t, keybase1.User{ 1716 Uid: ciara.uid, 1717 Username: ciara.username, 1718 }, notAdded[0]) 1719 1720 team := alice.loadTeamByID(teamID, true /* admin */) 1721 members, err := team.Members() 1722 require.NoError(t, err) 1723 require.Equal(t, []keybase1.UserVersion{{Uid: alice.uid, EldestSeqno: 1}}, members.Owners) 1724 require.Equal(t, []keybase1.UserVersion{{Uid: bob.uid, EldestSeqno: 1}}, members.Admins) 1725 require.Equal(t, []keybase1.UserVersion{{Uid: dodo.uid, EldestSeqno: 1}}, members.Writers) 1726 require.Len(t, members.Readers, 0) 1727 require.Equal(t, []keybase1.UserVersion{{Uid: botua.uid, EldestSeqno: 1}}, members.Bots) 1728 require.Equal(t, []keybase1.UserVersion{{Uid: restrictedBotua.uid, EldestSeqno: 1}}, members.RestrictedBots) 1729 invites := team.GetActiveAndObsoleteInvites() 1730 t.Logf("invites: %s", spew.Sdump(invites)) 1731 for _, invite := range invites { 1732 switch invite.Type.C__ { 1733 case keybase1.TeamInviteCategory_SBS: 1734 require.Equal(t, invite.Type.Sbs(), keybase1.TeamInviteSocialNetwork("rooter")) 1735 require.Equal(t, invite.Name, keybase1.TeamInviteName(john.username)) 1736 require.Equal(t, invite.Role, keybase1.TeamRole_ADMIN) 1737 case keybase1.TeamInviteCategory_EMAIL: 1738 require.Equal(t, invite.Name, keybase1.TeamInviteName("rob@gmail.com")) 1739 require.Equal(t, invite.Role, keybase1.TeamRole_READER) 1740 case keybase1.TeamInviteCategory_KEYBASE: 1741 require.Equal(t, invite.Name, keybase1.TeamInviteName(john.userVersion().PercentForm())) 1742 require.Equal(t, invite.Role, keybase1.TeamRole_READER) 1743 default: 1744 require.FailNowf(t, "unexpected invite type", "%v", spew.Sdump(invite)) 1745 } 1746 } 1747 1748 // It should fail to combine assertions with email addresses 1749 users = []keybase1.UserRolePair{ 1750 {Assertion: "[job@gmail.com]@email+job33", Role: keybase1.TeamRole_READER}, 1751 } 1752 _, _, err = teams.AddMembers(context.Background(), alice.tc.G, teamID, users, nil /* emailInviteMsg */) 1753 require.Error(t, err) 1754 require.IsType(t, err, teams.AddMembersError{}) 1755 require.IsType(t, err.(teams.AddMembersError).Err, teams.MixedServerTrustAssertionError{}) 1756 // It should also fail to combine invites with other assertions 1757 users = []keybase1.UserRolePair{ 1758 {Assertion: "xxffee22ee@twitter+jjjejiei3i@rooter", Role: keybase1.TeamRole_READER}, 1759 } 1760 _, _, err = teams.AddMembers(context.Background(), alice.tc.G, teamID, users, nil /* emailInviteMsg */) 1761 require.Error(t, err) 1762 require.IsType(t, err, teams.AddMembersError{}) 1763 require.IsType(t, err.(teams.AddMembersError).Err, teams.CompoundInviteError{}) 1764 } 1765 1766 func TestBatchAddMembers(t *testing.T) { 1767 tt := newTeamTester(t) 1768 defer tt.cleanup() 1769 1770 alice := tt.addUser("alice") 1771 bob := tt.addUser("bob") 1772 john := tt.addPuklessUser("john") 1773 rob := tt.addPuklessUser("rob") 1774 tt.logUserNames() 1775 1776 teamID, _ := alice.createTeam2() 1777 1778 assertions := []string{ 1779 bob.username, 1780 john.username, 1781 rob.username, 1782 bob.username + "@rooter", 1783 "foodle@twitter", 1784 } 1785 expectInvite := []bool{false, true, true, true, true} 1786 expectUsername := []bool{true, true, true, false, false} 1787 role := keybase1.TeamRole_OWNER 1788 1789 makeUserRolePairs := func(v []string, role keybase1.TeamRole) []keybase1.UserRolePair { 1790 var ret []keybase1.UserRolePair 1791 for _, s := range v { 1792 ret = append(ret, keybase1.UserRolePair{Assertion: s, Role: role}) 1793 } 1794 return ret 1795 } 1796 1797 added, notAdded, err := teams.AddMembers(context.Background(), alice.tc.G, teamID, makeUserRolePairs(assertions, role), nil /* emailInviteMsg */) 1798 require.Error(t, err, "can't invite assertions as owners") 1799 require.IsType(t, teams.AttemptedInviteSocialOwnerError{}, err) 1800 require.Nil(t, added) 1801 require.Nil(t, notAdded) 1802 team := alice.loadTeamByID(teamID, true /* admin */) 1803 members, err := team.Members() 1804 require.NoError(t, err) 1805 require.Len(t, members.Owners, 1) 1806 require.Len(t, members.Admins, 0) 1807 require.Len(t, members.Writers, 0) 1808 require.Len(t, members.Readers, 0) 1809 require.Len(t, members.RestrictedBots, 0) 1810 1811 role = keybase1.TeamRole_ADMIN 1812 added, notAdded, err = teams.AddMembers(context.Background(), alice.tc.G, teamID, makeUserRolePairs(assertions, role), nil /* emailInviteMsg */) 1813 require.NoError(t, err) 1814 require.Len(t, added, len(assertions)) 1815 require.Len(t, notAdded, 0) 1816 for i, r := range added { 1817 require.Equal(t, expectInvite[i], r.Invite, "invite %v", i) 1818 if expectUsername[i] { 1819 require.Equal(t, assertions[i], r.Username.String(), "expected username %v", i) 1820 } else { 1821 require.Equal(t, "", r.Username.String(), "expected no username %v", i) 1822 } 1823 } 1824 1825 team = alice.loadTeamByID(teamID, true /* admin */) 1826 members, err = team.Members() 1827 require.NoError(t, err) 1828 require.Len(t, members.Owners, 1) 1829 require.Equal(t, alice.userVersion(), members.Owners[0]) 1830 require.Len(t, members.Admins, 1) 1831 require.Equal(t, bob.userVersion(), members.Admins[0]) 1832 require.Len(t, members.Writers, 0) 1833 require.Len(t, members.Readers, 0) 1834 require.Len(t, members.RestrictedBots, 0) 1835 1836 invites := team.GetActiveAndObsoleteInvites() 1837 t.Logf("invites: %s", spew.Sdump(invites)) 1838 sbsCount := 0 1839 expectInvites := make(map[string]struct{}) 1840 expectInvites[john.userVersion().String()] = struct{}{} 1841 expectInvites[rob.userVersion().String()] = struct{}{} 1842 for x, invite := range invites { 1843 t.Logf("invites[%v]", x) 1844 require.Equal(t, invite.Role, role) 1845 switch invite.Type.C__ { 1846 case keybase1.TeamInviteCategory_SBS: 1847 switch invite.Type.Sbs() { 1848 case "twitter": 1849 require.Equal(t, "foodle", string(invite.Name)) 1850 case "rooter": 1851 require.Equal(t, bob.username, string(invite.Name)) 1852 default: 1853 require.FailNowf(t, "unexpected invite service", "%v", spew.Sdump(invite)) 1854 } 1855 sbsCount++ 1856 case keybase1.TeamInviteCategory_KEYBASE: 1857 require.Contains(t, expectInvites, string(invite.Name)) 1858 delete(expectInvites, string(invite.Name)) 1859 default: 1860 require.FailNowf(t, "unexpected invite type", "%v", spew.Sdump(invite)) 1861 } 1862 } 1863 require.Equal(t, 2, sbsCount, "sbs count") 1864 } 1865 1866 func TestAddCompoundAssertion(t *testing.T) { 1867 tt := newTeamTester(t) 1868 defer tt.cleanup() 1869 1870 alice := tt.addUser("alice") 1871 bob := tt.addUser("bob") 1872 1873 teamID, _ := alice.createTeam2() 1874 1875 bob.proveRooter() 1876 1877 assertion := fmt.Sprintf("%s@uid+%s@rooter", bob.uid, bob.username) 1878 1879 users := []keybase1.UserRolePair{ 1880 {Assertion: assertion, Role: keybase1.TeamRole_WRITER}, 1881 } 1882 added, notAdded, err := teams.AddMembers(context.Background(), alice.tc.G, teamID, users, nil /* emailInviteMsg */) 1883 require.NoError(t, err) 1884 require.Len(t, notAdded, 0) 1885 require.Len(t, added, 1) 1886 require.False(t, added[0].Invite) 1887 require.EqualValues(t, bob.username, added[0].Username) 1888 } 1889 1890 func TestTeamBustResolverCacheOnSubteamRename(t *testing.T) { 1891 tt := newTeamTester(t) 1892 defer tt.cleanup() 1893 1894 al := tt.addUser("al") 1895 bob := tt.addUser("bob") 1896 eve := tt.addUser("eve") 1897 1898 _, teamName := al.createTeam2() 1899 1900 // Verify subteams that have been renamed resolve correctly 1901 subteamBasename := "bb1" 1902 subteamID, err := teams.CreateSubteam(context.TODO(), al.tc.G, subteamBasename, teamName, keybase1.TeamRole_NONE /* addSelfAs */) 1903 require.NoError(t, err) 1904 subteamName, err := teamName.Append(subteamBasename) 1905 require.NoError(t, err) 1906 1907 al.addTeamMember(subteamName.String(), bob.username, keybase1.TeamRole_READER) 1908 al.addTeamMember(teamName.String(), eve.username, keybase1.TeamRole_ADMIN) 1909 1910 subteamRename, err := teamName.Append("bb2") 1911 require.NoError(t, err) 1912 1913 subteamNameActual, err := teams.ResolveIDToName(context.TODO(), al.tc.G, *subteamID) 1914 require.NoError(t, err) 1915 require.True(t, subteamName.Eq(subteamNameActual)) 1916 1917 err = teams.RenameSubteam(context.TODO(), al.tc.G, subteamName, subteamRename) 1918 require.NoError(t, err) 1919 1920 // While this may not be ideal, admin that posts the rename will 1921 // get two notifications. 1922 // - First notification comes from `RenameSubteam` func itself, 1923 // where `g.GetTeamLoader().NotifyTeamRename` is called. 1924 // - Second one is the regular gregor team.rename notification. 1925 t.Logf("Waiting for team notifications for %s", al.username) 1926 al.waitForTeamChangeRenamed(*subteamID) 1927 al.waitForTeamChangeRenamed(*subteamID) 1928 1929 // Members of subteam, and other admins from parent teams, will 1930 // get just one. 1931 for _, user := range []*userPlusDevice{bob, eve} { 1932 t.Logf("Waiting for team notifications for %s", user.username) 1933 user.waitForTeamChangeRenamed(*subteamID) 1934 } 1935 1936 for _, user := range tt.users { 1937 subteamRenameActual, err := teams.ResolveIDToName(context.TODO(), user.tc.G, *subteamID) 1938 require.NoError(t, err) 1939 require.True(t, subteamRename.Eq(subteamRenameActual)) 1940 1941 _, err = teams.ResolveNameToID(context.TODO(), user.tc.G, subteamName) 1942 require.Error(t, err) 1943 } 1944 } 1945 1946 func TestForceRepollState(t *testing.T) { 1947 tt := newTeamTester(t) 1948 defer tt.cleanup() 1949 1950 tt.addUser("onr") 1951 tt.addUser("wtr") 1952 1953 mctx := libkb.NewMetaContextForTest(*tt.users[0].tc) 1954 _, err := mctx.G().API.Post(mctx, libkb.APIArg{ 1955 Endpoint: "test/big_state_cutoff", 1956 SessionType: libkb.APISessionTypeREQUIRED, 1957 Args: libkb.HTTPArgs{ 1958 "cutoff": libkb.I{Val: 1}, 1959 }, 1960 }) 1961 require.NoError(t, err) 1962 1963 team := tt.users[0].createTeam() 1964 for i := 0; i < 3; i++ { 1965 tt.users[0].addTeamMember(team, tt.users[1].username, keybase1.TeamRole_WRITER) 1966 tt.users[0].removeTeamMember(team, tt.users[1].username) 1967 } 1968 found := false 1969 w := 10 * time.Millisecond 1970 for i := 0; i < 10; i++ { 1971 found = tt.users[0].tc.G.GetTeamLoader().(*teams.TeamLoader).InForceRepollMode(mctx) 1972 if found { 1973 break 1974 } 1975 w *= 2 1976 t.Logf("Waiting for %v, for gregor state update", w) 1977 time.Sleep(w) 1978 } 1979 require.True(t, found) 1980 } 1981 1982 func TestTeamMetadataUpdateNotifications(t *testing.T) { 1983 tt := newTeamTester(t) 1984 defer tt.cleanup() 1985 1986 tt.addUser("alf") 1987 tt.addUser("bra") 1988 tt.addUser("cha") 1989 1990 parentID, parentName := tt.users[0].createTeam2() 1991 _, err := teams.CreateSubteam(context.TODO(), tt.users[0].tc.G, "bb", parentName, keybase1.TeamRole_NONE /* addSelfAs */) 1992 require.NoError(t, err) 1993 subteamName, err := parentName.Append("bb") 1994 require.NoError(t, err) 1995 subteamID, err := teams.CreateSubteam(context.TODO(), tt.users[0].tc.G, "cc", subteamName, keybase1.TeamRole_NONE /* addSelfAs */) 1996 require.NoError(t, err) 1997 subsubteamName, err := subteamName.Append("cc") 1998 require.NoError(t, err) 1999 2000 t.Logf("Start testing metadata updates") 2001 2002 tt.users[0].addTeamMember(subsubteamName.String(), tt.users[2].username, keybase1.TeamRole_ADMIN) 2003 tt.users[2].waitForMetadataUpdateGregor("added to team") 2004 2005 tt.users[0].addTeamMember(parentName.String(), tt.users[1].username, keybase1.TeamRole_ADMIN) 2006 tt.users[1].waitForMetadataUpdateGregor("added to team") 2007 2008 subsubteamRename, err := subteamName.Append("cc2") 2009 require.NoError(t, err) 2010 err = teams.RenameSubteam(context.TODO(), tt.users[0].tc.G, subsubteamName, subsubteamRename) 2011 require.NoError(t, err) 2012 tt.users[1].waitForMetadataUpdateGregor("team user was an implicit admin of changed name") 2013 tt.users[2].waitForMetadataUpdateGregor("team user was an implicit admin of changed name") 2014 2015 subteamRename, err := parentName.Append("bb2") 2016 require.NoError(t, err) 2017 err = teams.RenameSubteam(context.TODO(), tt.users[0].tc.G, subteamName, subteamRename) 2018 require.NoError(t, err) 2019 // Suboptimality - but it's fine since renames are rare. 2020 tt.users[1].waitForMetadataUpdateGregor("team user was an implicit admin of changed name (subteam)") 2021 tt.users[1].waitForMetadataUpdateGregor("team user was an implicit admin of changed name (subsubteam)") 2022 tt.users[2].waitForMetadataUpdateGregor("parent team of subteam you're in changed name") 2023 2024 tt.users[0].changeTeamMember(parentName.String(), tt.users[1].username, keybase1.TeamRole_OWNER) 2025 tt.users[1].waitForMetadataUpdateGregor("now an owner") 2026 2027 tt.users[0].teamSetSettings(*subteamID, keybase1.TeamSettings{Open: true, JoinAs: keybase1.TeamRole_READER}) 2028 tt.users[1].waitForMetadataUpdateGregor("settings change of subteam") 2029 2030 _, err = subteamRename.Append("cc2") 2031 require.NoError(t, err) 2032 tt.users[0].teamSetSettings(*subteamID, keybase1.TeamSettings{Open: true, JoinAs: keybase1.TeamRole_WRITER}) 2033 tt.users[1].waitForMetadataUpdateGregor("settings change of subsubteam") 2034 tt.users[0].teamSetSettings(*subteamID, keybase1.TeamSettings{Open: true, JoinAs: keybase1.TeamRole_READER}) 2035 tt.users[1].waitForMetadataUpdateGregor("settings change of subsubteam") 2036 2037 val := true 2038 err = tt.users[0].teamsClient.SetTeamShowcase(context.Background(), keybase1.SetTeamShowcaseArg{ 2039 TeamID: *subteamID, 2040 IsShowcased: &val, 2041 }) 2042 require.NoError(tt.users[0].tc.T, err) 2043 tt.users[1].waitForMetadataUpdateGregor("change showcase") 2044 2045 desc := "desc" 2046 err = tt.users[0].teamsClient.SetTeamShowcase(context.Background(), keybase1.SetTeamShowcaseArg{ 2047 TeamID: *subteamID, 2048 IsShowcased: &val, 2049 Description: &desc, 2050 }) 2051 require.NoError(tt.users[0].tc.T, err) 2052 tt.users[1].waitForMetadataUpdateGregor("change showcase") 2053 2054 err = tt.users[0].teamsClient.SetTeamShowcase(context.Background(), keybase1.SetTeamShowcaseArg{ 2055 TeamID: *subteamID, 2056 IsShowcased: &val, 2057 Description: &desc, 2058 AnyMemberShowcase: &val, 2059 }) 2060 require.NoError(tt.users[0].tc.T, err) 2061 tt.users[1].waitForMetadataUpdateGregor("change showcase") 2062 2063 newTeamID, newteamName := tt.users[1].createTeam2() 2064 require.NoError(t, err) 2065 tt.users[1].waitForMetadataUpdateGregor("new team") 2066 tt.users[1].addTeamMember(newteamName.String(), tt.users[0].username, keybase1.TeamRole_OWNER) 2067 tt.users[1].waitForMetadataUpdateGregor("added someone to team") 2068 2069 tui := &teamsUI{} 2070 err = teams.Delete(context.Background(), tt.users[0].tc.G, tui, newTeamID) 2071 require.NoError(tt.users[0].tc.T, err) 2072 tt.users[1].waitForMetadataUpdateGregor("team deleted") 2073 2074 err = tt.users[1].teamsClient.SetTeamMemberShowcase(context.Background(), keybase1.SetTeamMemberShowcaseArg{ 2075 TeamID: parentID, 2076 IsShowcased: true, 2077 }) 2078 require.NoError(tt.users[1].tc.T, err) 2079 tt.users[1].waitForMetadataUpdateGregor("change member showcase") 2080 2081 tt.users[1].waitForMetadataUpdateGregor("change member count from TeamMemberCountCache") 2082 } 2083 2084 func TestTeamLoadParentAfterRotateRace(t *testing.T) { 2085 tt := newTeamTester(t) 2086 defer tt.cleanup() 2087 2088 tt.addUser("alf") 2089 tt.addUser("bra") 2090 2091 team := tt.users[0].createTeam() 2092 parentName, err := keybase1.TeamNameFromString(team) 2093 require.NoError(t, err) 2094 _, err = teams.CreateSubteam(context.TODO(), tt.users[0].tc.G, "bb", parentName, keybase1.TeamRole_NONE /* addSelfAs */) 2095 require.NoError(t, err) 2096 subteamName, err := parentName.Append("bb") 2097 require.NoError(t, err) 2098 _, err = teams.CreateSubteam(context.TODO(), tt.users[0].tc.G, "cc", subteamName, keybase1.TeamRole_NONE /* addSelfAs */) 2099 require.NoError(t, err) 2100 2101 tt.users[0].addTeamMember(parentName.String(), tt.users[1].username, keybase1.TeamRole_ADMIN) 2102 tt.users[0].addTeamMember(subteamName.String(), tt.users[1].username, keybase1.TeamRole_ADMIN) 2103 2104 parentid, err := teams.ResolveNameToID(context.TODO(), tt.users[0].tc.G, parentName) 2105 require.NoError(t, err) 2106 err = teams.RotateKey(context.TODO(), tt.users[0].tc.G, keybase1.TeamRotateKeyArg{TeamID: parentid, Rt: keybase1.RotationType_HIDDEN}) 2107 require.NoError(t, err) 2108 2109 _, err = teams.Load(context.Background(), tt.users[1].tc.G, keybase1.LoadTeamArg{Name: subteamName.String()}) 2110 require.NoError(t, err) 2111 2112 _, err = teams.Load(context.Background(), tt.users[1].tc.G, 2113 keybase1.LoadTeamArg{Name: parentName.String()}) 2114 require.NoError(t, err) 2115 } 2116 2117 func TestTeamHiddenGenerationRotateRace(t *testing.T) { 2118 tt := newTeamTester(t) 2119 defer tt.cleanup() 2120 2121 tt.addUser("alf") 2122 tt.addUser("bra") 2123 tt.addUser("cha") 2124 2125 alice := tt.users[0] 2126 bob := tt.users[1] 2127 charlie := tt.users[2] 2128 2129 team := alice.createTeam() 2130 parentName, err := keybase1.TeamNameFromString(team) 2131 require.NoError(t, err) 2132 _, err = teams.CreateSubteam(context.TODO(), alice.tc.G, "bb", 2133 parentName, keybase1.TeamRole_NONE /* addSelfAs */) 2134 require.NoError(t, err) 2135 subteamName, err := parentName.Append("bb") 2136 require.NoError(t, err) 2137 _, err = teams.CreateSubteam(context.TODO(), alice.tc.G, "cc", 2138 subteamName, keybase1.TeamRole_NONE /* addSelfAs */) 2139 require.NoError(t, err) 2140 subsubteamName, err := subteamName.Append("cc") 2141 require.NoError(t, err) 2142 2143 t.Logf("Start testing") 2144 2145 alice.addTeamMember(subsubteamName.String(), charlie.username, keybase1.TeamRole_ADMIN) 2146 charlie.waitForMetadataUpdateGregor("added to team") 2147 2148 alice.addTeamMember(parentName.String(), bob.username, keybase1.TeamRole_ADMIN) 2149 bob.waitForMetadataUpdateGregor("added to team") 2150 2151 alice.removeTeamMember(parentName.String(), bob.username) 2152 bob.waitForMetadataUpdateGregor("removed from team") 2153 2154 alice.addTeamMember(parentName.String(), bob.username, keybase1.TeamRole_ADMIN) 2155 bob.waitForMetadataUpdateGregor("added back") 2156 }