github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/systests/team_reset_test.go (about) 1 package systests 2 3 import ( 4 "testing" 5 "time" 6 7 "golang.org/x/net/context" 8 9 libkb "github.com/keybase/client/go/libkb" 10 keybase1 "github.com/keybase/client/go/protocol/keybase1" 11 teams "github.com/keybase/client/go/teams" 12 "github.com/stretchr/testify/require" 13 ) 14 15 func divDebug(ctx *smuContext, fmt string, arg ...interface{}) { 16 div := "------------" 17 ctx.log.Debug(div+" "+fmt+" "+div, arg...) 18 } 19 20 func pollForMembershipUpdate(team smuTeam, ann *smuUser, bob *smuUser, cam *smuUser) { 21 22 // Keep reloading this team until we get that Bob has been deactivated. 23 // It might happen after the team is rotated, since a cache bust via gregor has 24 // to happen 25 poller := func(d keybase1.TeamDetails) bool { 26 for _, member := range d.Members.Writers { 27 if member.Username == bob.username { 28 return member.Status.IsReset() 29 } 30 } 31 return false 32 } 33 34 details := ann.pollForMembershipUpdate(team, keybase1.PerTeamKeyGeneration(2), poller) 35 for _, member := range details.Members.Admins { 36 switch member.Username { 37 case ann.username: 38 require.True(ann.ctx.t, member.Status.IsActive()) 39 default: 40 require.Fail(ann.ctx.t, "unknown admin: %s", member.Username) 41 } 42 } 43 for _, member := range details.Members.Writers { 44 switch member.Username { 45 case bob.username: 46 require.True(ann.ctx.t, member.Status.IsReset()) 47 case cam.username: 48 require.True(ann.ctx.t, member.Status.IsActive()) 49 default: 50 require.Fail(ann.ctx.t, "unknown writer: %s (%+v)", member.Username, details) 51 } 52 } 53 ann.ctx.log.Debug("team details checked out: %+v", details) 54 } 55 56 // tests a user deleting her account. 57 func TestTeamDelete(t *testing.T) { 58 ctx := newSMUContext(t) 59 defer ctx.cleanup() 60 61 ann := ctx.installKeybaseForUser("ann", 10) 62 ann.signup() 63 divDebug(ctx, "Signed up ann (%s)", ann.username) 64 bob := ctx.installKeybaseForUser("bob", 10) 65 bob.signup() 66 divDebug(ctx, "Signed up bob (%s)", bob.username) 67 cam := ctx.installKeybaseForUser("cam", 10) 68 cam.signup() 69 divDebug(ctx, "Signed up cam (%s)", cam.username) 70 71 team := ann.createTeam([]*smuUser{bob, cam}) 72 divDebug(ctx, "team created (%s)", team.name) 73 74 ann.sendChat(team, "0") 75 divDebug(ctx, "Sent chat '0' (%s via %s)", team.name, ann.username) 76 77 ann.readChats(team, 1) 78 bob.readChats(team, 1) 79 divDebug(ctx, "Ann and bob can read") 80 81 // just one person needs to do this before ann deletes, so her 82 // deletion will immediately fall into accelerated rekeyd. 83 kickTeamRekeyd(bob.getPrimaryGlobalContext(), t) 84 85 ann.delete() 86 divDebug(ctx, "Ann deleted her account") 87 divDebug(ctx, "ann uid: %s", ann.uid()) 88 divDebug(ctx, "bob uid: %s", bob.uid()) 89 divDebug(ctx, "cam uid: %s", cam.uid()) 90 91 // bob and cam should see the key get rotated after ann deletes 92 bob.pollForMembershipUpdate(team, keybase1.PerTeamKeyGeneration(2), nil) 93 cam.pollForMembershipUpdate(team, keybase1.PerTeamKeyGeneration(2), nil) 94 95 // It's important for cam to clear her cache right before the attempt to send, 96 // since she might have received gregors that ann deleted her account, 97 // and therefore might be trying to refresh and load the team. 98 cam.primaryDevice().clearUPAKCache() 99 cam.sendChat(team, "1") 100 101 divDebug(ctx, "Cam sent a chat") 102 bob.readChats(team, 2) 103 104 // Disable UIDMapper cache to be able to see current state of 105 // Active/Inactive for members. 106 bob.setUIDMapperNoCachingMode(true) 107 cam.setUIDMapperNoCachingMode(true) 108 109 bob.assertMemberMissing(team, ann) 110 bob.assertMemberActive(team, cam) 111 112 cam.assertMemberMissing(team, ann) 113 cam.assertMemberActive(team, bob) 114 } 115 116 func TestTeamReset(t *testing.T) { 117 ctx := newSMUContext(t) 118 defer ctx.cleanup() 119 120 ann := ctx.installKeybaseForUser("ann", 10) 121 ann.signup() 122 divDebug(ctx, "Signed up ann (%s, %s)", ann.username, ann.uid()) 123 bob := ctx.installKeybaseForUser("bob", 10) 124 bob.signup() 125 divDebug(ctx, "Signed up bob (%s, %s)", bob.username, bob.uid()) 126 cam := ctx.installKeybaseForUser("cam", 10) 127 cam.signup() 128 divDebug(ctx, "Signed up cam (%s, %s)", cam.username, cam.uid()) 129 130 // Note that ann (the admin) has a UIDMapper that should get pubsub updates 131 // since she is an admin for the team in question. cam won't get those 132 // pubsub updates 133 ann.setUIDMapperNoCachingMode(true) 134 bob.setUIDMapperNoCachingMode(true) 135 cam.setUIDMapperNoCachingMode(true) 136 137 team := ann.createTeam([]*smuUser{bob, cam}) 138 divDebug(ctx, "team created (%s)", team.name) 139 140 // ensure bob is active according to other users 141 ann.assertMemberActive(team, bob) 142 cam.assertMemberActive(team, bob) 143 144 ann.sendChat(team, "0") 145 divDebug(ctx, "Sent chat '0' (%s via %s)", team.name, ann.username) 146 147 ann.readChats(team, 1) 148 bob.readChats(team, 1) 149 150 kickTeamRekeyd(bob.getPrimaryGlobalContext(), t) 151 bob.reset() 152 divDebug(ctx, "Reset bob (%s)", bob.username) 153 154 pollForMembershipUpdate(team, ann, bob, cam) 155 divDebug(ctx, "Polled for rekey") 156 157 // bob should be inactive according to other users 158 ann.assertMemberInactive(team, bob) 159 cam.assertMemberInactive(team, bob) 160 161 bob.loginAfterReset(10) 162 divDebug(ctx, "Bob logged in after reset") 163 164 // bob should be inactive according to other users 165 ann.assertMemberInactive(team, bob) 166 cam.assertMemberInactive(team, bob) 167 168 _, err := bob.teamGet(team) 169 require.Error(t, err) 170 ae, ok := err.(libkb.AppStatusError) 171 require.True(t, ok) 172 require.Equal(t, ae.Code, int(keybase1.StatusCode_SCTeamReadError)) 173 divDebug(ctx, "Bob failed to read the team") 174 175 // Make sure that ann can still send even though bob is ousted 176 ann.sendChat(team, "1") 177 divDebug(ctx, "Sent chat '1' (%s via %s)", team.name, ann.username) 178 ann.readChats(team, 2) 179 // Same goes for cam --- note that she never read before, so nothing 180 // is cached for her. 181 cam.readChats(team, 2) 182 183 _, err = bob.readChatsWithError(team) 184 require.Error(t, err) 185 ae, ok = err.(libkb.AppStatusError) 186 require.True(t, ok) 187 require.Equal(t, ae.Code, int(keybase1.StatusCode_SCTeamReadError)) 188 divDebug(ctx, "Bob failed to read the chat") 189 190 ann.addWriter(team, bob) 191 divDebug(ctx, "Added bob back as a writer") 192 _, err = bob.teamGet(team) 193 require.NoError(t, err) 194 divDebug(ctx, "Bob could read the team after added back") 195 bob.readChats(team, 2) 196 divDebug(ctx, "Bob reading chats after added back") 197 ann.sendChat(team, "2") 198 divDebug(ctx, "Ann sending chat '2'") 199 bob.readChats(team, 3) 200 divDebug(ctx, "Bob reading chat '2'") 201 } 202 203 // add bob (a user who has reset his account) to a team 204 // that he was never a member of 205 func TestTeamResetAdd(t *testing.T) { 206 ctx := newSMUContext(t) 207 defer ctx.cleanup() 208 209 ann := ctx.installKeybaseForUser("ann", 10) 210 ann.signup() 211 divDebug(ctx, "Signed up ann (%s)", ann.username) 212 bob := ctx.installKeybaseForUser("bob", 10) 213 bob.signup() 214 divDebug(ctx, "Signed up bob (%s)", bob.username) 215 cam := ctx.installKeybaseForUser("cam", 10) 216 cam.signup() 217 divDebug(ctx, "Signed up cam (%s)", cam.username) 218 219 team := ann.createTeam([]*smuUser{cam}) 220 divDebug(ctx, "team created (%s)", team.name) 221 222 ann.sendChat(team, "0") 223 divDebug(ctx, "Sent chat '2' (%s via %s)", team.name, ann.username) 224 225 ann.readChats(team, 1) 226 227 bob.reset() 228 divDebug(ctx, "Reset bob (%s)", bob.username) 229 230 bob.loginAfterReset(10) 231 divDebug(ctx, "Bob logged in after reset") 232 233 _, err := bob.teamGet(team) 234 require.Error(t, err) 235 divDebug(ctx, "Bob failed to read the team") 236 237 ann.addWriter(team, bob) 238 divDebug(ctx, "Added bob as a writer") 239 _, err = bob.teamGet(team) 240 require.NoError(t, err) 241 divDebug(ctx, "Bob could read the team after added") 242 bob.readChats(team, 1) 243 divDebug(ctx, "Bob reading chats after added") 244 ann.sendChat(team, "1") 245 divDebug(ctx, "Ann sending chat '2'") 246 bob.readChats(team, 2) 247 divDebug(ctx, "Bob reading chat '2'") 248 } 249 250 // Ann creates a team, and adds Bob as an admin. Then Alice resets, and Bob readmits 251 // Ann as an admin (since he can't make her an owner). It should work. 252 func TestTeamOwnerResetAdminReadmit(t *testing.T) { 253 ctx := newSMUContext(t) 254 defer ctx.cleanup() 255 256 ann := ctx.installKeybaseForUser("ann", 10) 257 ann.signup() 258 divDebug(ctx, "Signed up ann (%s)", ann.username) 259 bob := ctx.installKeybaseForUser("bob", 10) 260 bob.signup() 261 divDebug(ctx, "Signed up bob (%s)", bob.username) 262 263 team := ann.createTeam([]*smuUser{}) 264 divDebug(ctx, "team created (%s)", team.name) 265 ann.addAdmin(team, bob) 266 267 ann.reset() 268 divDebug(ctx, "Reset ann (%s)", ann.username) 269 270 ann.loginAfterReset(2) 271 divDebug(ctx, "Ann logged in after reset") 272 bob.addAdmin(team, ann) 273 _, err := ann.teamGet(team) 274 require.NoError(t, err) 275 divDebug(ctx, "Ann read the team") 276 } 277 278 // add bob (a user who has reset his account and has no PUK) to a team 279 // that he was never a member of 280 func TestTeamResetAddNoPUK(t *testing.T) { 281 ctx := newSMUContext(t) 282 defer ctx.cleanup() 283 284 ann := ctx.installKeybaseForUser("ann", 10) 285 ann.signup() 286 divDebug(ctx, "Signed up ann (%s)", ann.username) 287 bob := ctx.installKeybaseForUserNoPUK("bob", 10) 288 bob.signupNoPUK() 289 divDebug(ctx, "Signed up bob (%s)", bob.username) 290 cam := ctx.installKeybaseForUser("cam", 10) 291 cam.signup() 292 divDebug(ctx, "Signed up cam (%s)", cam.username) 293 294 team := ann.createTeam([]*smuUser{cam}) 295 divDebug(ctx, "team created (%s)", team.name) 296 297 ann.sendChat(team, "0") 298 divDebug(ctx, "Sent chat '2' (%s via %s)", team.name, ann.username) 299 300 ann.readChats(team, 1) 301 302 bob.reset() 303 divDebug(ctx, "Reset bob (%s)", bob.username) 304 305 bob.loginAfterResetNoPUK(1) 306 divDebug(ctx, "Bob logged in after reset") 307 308 _, err := bob.teamGet(team) 309 require.Error(t, err) 310 divDebug(ctx, "Bob failed to read the team") 311 312 // this is the main point of the test, to get this to work 313 // without an eldest seqno error. 314 ann.addWriter(team, bob) 315 divDebug(ctx, "Added bob as a writer") 316 } 317 318 // bob resets and added with no keys 319 func TestTeamResetNoKeys(t *testing.T) { 320 ctx := newSMUContext(t) 321 defer ctx.cleanup() 322 323 ann := ctx.installKeybaseForUser("ann", 10) 324 ann.signup() 325 divDebug(ctx, "Signed up ann (%s)", ann.username) 326 bob := ctx.installKeybaseForUser("bob", 10) 327 bob.signup() 328 divDebug(ctx, "Signed up bob (%s)", bob.username) 329 cam := ctx.installKeybaseForUser("cam", 10) 330 cam.signup() 331 divDebug(ctx, "Signed up cam (%s)", cam.username) 332 333 team := ann.createTeam([]*smuUser{cam}) 334 divDebug(ctx, "team created (%s)", team.name) 335 336 ann.sendChat(team, "0") 337 divDebug(ctx, "Sent chat '2' (%s via %s)", team.name, ann.username) 338 339 ann.readChats(team, 1) 340 341 bob.reset() 342 divDebug(ctx, "Reset bob (%s)", bob.username) 343 344 ann.addWriter(team, bob) 345 divDebug(ctx, "Added bob as a writer") 346 } 347 348 // bob resets several times and added with no keys 349 func TestTeamResetManyNoKeys(t *testing.T) { 350 ctx := newSMUContext(t) 351 defer ctx.cleanup() 352 353 ann := ctx.installKeybaseForUser("ann", 10) 354 ann.signup() 355 divDebug(ctx, "Signed up ann (%s)", ann.username) 356 bob := ctx.installKeybaseForUser("bob", 10) 357 bob.signup() 358 divDebug(ctx, "Signed up bob (%s)", bob.username) 359 cam := ctx.installKeybaseForUser("cam", 10) 360 cam.signup() 361 divDebug(ctx, "Signed up cam (%s)", cam.username) 362 363 team := ann.createTeam([]*smuUser{cam}) 364 divDebug(ctx, "team created (%s)", team.name) 365 366 ann.sendChat(team, "0") 367 divDebug(ctx, "Sent chat '2' (%s via %s)", team.name, ann.username) 368 369 ann.readChats(team, 1) 370 371 for i := 0; i < 5; i++ { 372 bob.reset() 373 divDebug(ctx, "Reset bob (%s)", bob.username) 374 375 bob.loginAfterReset(10) 376 divDebug(ctx, "Bob logged in after reset") 377 } 378 379 ann.addWriter(team, bob) 380 divDebug(ctx, "Added bob as a writer") 381 } 382 383 // bob resets and has no keys, added as an admin 384 func TestTeamResetNoKeysAdmin(t *testing.T) { 385 ctx := newSMUContext(t) 386 defer ctx.cleanup() 387 388 ann := ctx.installKeybaseForUser("ann", 10) 389 ann.signup() 390 divDebug(ctx, "Signed up ann (%s)", ann.username) 391 bob := ctx.installKeybaseForUser("bob", 10) 392 bob.signup() 393 divDebug(ctx, "Signed up bob (%s)", bob.username) 394 cam := ctx.installKeybaseForUser("cam", 10) 395 cam.signup() 396 divDebug(ctx, "Signed up cam (%s)", cam.username) 397 398 team := ann.createTeam([]*smuUser{cam}) 399 divDebug(ctx, "team created (%s)", team.name) 400 401 ann.sendChat(team, "0") 402 divDebug(ctx, "Sent chat '2' (%s via %s)", team.name, ann.username) 403 404 ann.readChats(team, 1) 405 406 bob.reset() 407 divDebug(ctx, "Reset bob (%s)", bob.username) 408 409 ann.addAdmin(team, bob) 410 divDebug(ctx, "Added bob as an admin") 411 } 412 413 // Remove a member who was in a team and reset. 414 func TestTeamRemoveAfterReset(t *testing.T) { 415 ctx := newSMUContext(t) 416 defer ctx.cleanup() 417 418 ann := ctx.installKeybaseForUser("ann", 10) 419 ann.signup() 420 divDebug(ctx, "Signed up ann (%s)", ann.username) 421 bob := ctx.installKeybaseForUser("bob", 10) 422 bob.signup() 423 divDebug(ctx, "Signed up bob (%s)", bob.username) 424 joe := ctx.installKeybaseForUser("joe", 10) 425 joe.signup() 426 divDebug(ctx, "Signed up joe (%s)", joe.username) 427 428 team := ann.createTeam([]*smuUser{bob, joe}) 429 divDebug(ctx, "team created (%s)", team.name) 430 431 kickTeamRekeyd(ann.getPrimaryGlobalContext(), t) 432 bob.reset() 433 divDebug(ctx, "Reset bob (%s)", bob.username) 434 435 bob.loginAfterReset(10) 436 divDebug(ctx, "Bob logged in after reset") 437 ann.pollForMembershipUpdate(team, keybase1.PerTeamKeyGeneration(2), nil) 438 439 joe.reset() 440 divDebug(ctx, "Reset joe (%s), not re-provisioning though!", joe.username) 441 442 ann.pollForMembershipUpdate(team, keybase1.PerTeamKeyGeneration(3), nil) 443 444 cli := ann.getTeamsClient() 445 err := cli.TeamRemoveMember(context.TODO(), keybase1.TeamRemoveMemberArg{ 446 TeamID: team.ID, 447 Member: keybase1.NewTeamMemberToRemoveWithAssertion(keybase1.AssertionTeamMemberToRemove{Assertion: bob.username}), 448 }) 449 require.NoError(t, err) 450 451 err = cli.TeamRemoveMember(context.TODO(), keybase1.TeamRemoveMemberArg{ 452 TeamID: team.ID, 453 Member: keybase1.NewTeamMemberToRemoveWithAssertion(keybase1.AssertionTeamMemberToRemove{Assertion: joe.username}), 454 }) 455 require.NoError(t, err) 456 457 G := ann.getPrimaryGlobalContext() 458 teams.NewTeamLoaderAndInstall(G) 459 role, err := teams.MemberRole(context.TODO(), G, team.name, bob.username) 460 require.NoError(t, err) 461 require.Equal(t, role, keybase1.TeamRole_NONE) 462 } 463 464 func TestTeamRemoveMemberAfterDelete(t *testing.T) { 465 ctx := newSMUContext(t) 466 defer ctx.cleanup() 467 468 ann := ctx.installKeybaseForUser("ann", 10) 469 ann.signup() 470 divDebug(ctx, "Signed up ann (%s)", ann.username) 471 bob := ctx.installKeybaseForUser("bob", 10) 472 bob.signup() 473 divDebug(ctx, "Signed up bob (%s)", bob.username) 474 475 team := ann.createTeam([]*smuUser{bob}) 476 divDebug(ctx, "team created (%s)", team.name) 477 478 bobUID := bob.uid() 479 480 bob.delete() 481 divDebug(ctx, "Bob deleted (%s)", bob.username) 482 483 ann.pollForMembershipUpdate(team, keybase1.PerTeamKeyGeneration(2), nil) 484 485 // Ensure ann sees bob as deleted, and not some cached remnant of 486 // the past. 487 ann.primaryDevice().clearUPAKCache() 488 G := ann.getPrimaryGlobalContext() 489 arg := libkb.NewLoadUserArg(G).WithNetContext(context.Background()). 490 WithUID(bobUID).WithPublicKeyOptional() 491 upak, _, err := G.GetUPAKLoader().LoadV2(arg) 492 require.NoError(t, err) 493 require.EqualValues(t, libkb.SCDeleted, upak.Current.Status) 494 495 cli := ann.getTeamsClient() 496 err = cli.TeamRemoveMember(context.Background(), keybase1.TeamRemoveMemberArg{ 497 TeamID: team.ID, 498 Member: keybase1.NewTeamMemberToRemoveWithAssertion(keybase1.AssertionTeamMemberToRemove{Assertion: bob.username}), 499 }) 500 require.NoError(t, err) 501 502 t.Logf("Calling TeamGet") 503 504 details, err := cli.TeamGet(context.Background(), keybase1.TeamGetArg{ 505 Name: team.name, 506 }) 507 require.NoError(t, err) 508 509 require.Equal(t, 1, len(details.Members.Owners)) 510 require.Equal(t, ann.username, details.Members.Owners[0].Username) 511 require.Equal(t, 0, len(details.Members.Admins)) 512 require.Equal(t, 0, len(details.Members.Writers)) 513 require.Equal(t, 0, len(details.Members.Readers)) 514 require.Equal(t, 0, len(details.Members.Bots)) 515 require.Equal(t, 0, len(details.Members.RestrictedBots)) 516 } 517 518 func TestTeamTryAddDeletedUser(t *testing.T) { 519 ctx := newSMUContext(t) 520 defer ctx.cleanup() 521 522 ann := ctx.installKeybaseForUser("ann", 10) 523 ann.signup() 524 divDebug(ctx, "Signed up ann (%s)", ann.username) 525 526 bob := ctx.installKeybaseForUser("bob", 10) 527 bob.signup() 528 divDebug(ctx, "Signed up bob (%s)", bob.username) 529 bob.delete() 530 divDebug(ctx, "Bob deleted (%s)", bob.username) 531 532 cli := ann.getTeamsClient() 533 team := ann.createTeam([]*smuUser{}) 534 divDebug(ctx, "team created (%s)", team.name) 535 536 _, err := cli.TeamAddMember(context.Background(), keybase1.TeamAddMemberArg{ 537 TeamID: team.ID, 538 Username: bob.username, 539 Role: keybase1.TeamRole_READER, 540 }) 541 require.Error(t, err) 542 } 543 544 // Add a member after reset in a normal (non-implicit) team 545 // Uses Add not Readd 546 func TestTeamAddAfterReset(t *testing.T) { 547 ctx := newSMUContext(t) 548 defer ctx.cleanup() 549 550 ann := ctx.installKeybaseForUser("ann", 10) 551 ann.signup() 552 divDebug(ctx, "Signed up ann (%s)", ann.username) 553 bob := ctx.installKeybaseForUser("bob", 10) 554 bob.signup() 555 divDebug(ctx, "Signed up bob (%s)", bob.username) 556 557 team := ann.createTeam([]*smuUser{bob}) 558 divDebug(ctx, "team created (%s)", team.name) 559 560 ann.sendChat(team, "0") 561 562 kickTeamRekeyd(ann.getPrimaryGlobalContext(), t) 563 bob.reset() 564 divDebug(ctx, "Reset bob (%s)", bob.username) 565 566 bob.loginAfterReset(10) 567 divDebug(ctx, "Bob logged in after reset") 568 569 ann.pollForMembershipUpdate(team, keybase1.PerTeamKeyGeneration(2), nil) 570 571 cli := ann.getTeamsClient() 572 _, err := cli.TeamAddMember(context.TODO(), keybase1.TeamAddMemberArg{ 573 TeamID: team.ID, 574 Username: bob.username, 575 // Note: any role would do! Does not have to be the same as before 576 // reset. This does not apply to imp-teams though, it requires the 577 // same role there. 578 Role: keybase1.TeamRole_READER, 579 }) 580 require.NoError(t, err) 581 582 G := ann.getPrimaryGlobalContext() 583 teams.NewTeamLoaderAndInstall(G) 584 role, err := teams.MemberRole(context.TODO(), G, team.name, bob.username) 585 require.NoError(t, err) 586 require.Equal(t, role, keybase1.TeamRole_READER) 587 588 bob.readChats(team, 1) 589 } 590 591 func TestTeamReAddAfterReset(t *testing.T) { 592 testTeamReAddAfterReset(t, true, false, false) 593 } 594 595 func TestTeamReAddAfterResetPukless(t *testing.T) { 596 testTeamReAddAfterReset(t, false, false, false) 597 } 598 599 func TestTeamReAddAfterResetAdminOwner(t *testing.T) { 600 testTeamReAddAfterReset(t, true, true, false) 601 } 602 603 func TestTeamReAddAfterResetAdminOwnerPukless(t *testing.T) { 604 testTeamReAddAfterReset(t, false, true, false) 605 } 606 607 func TestTeamResetReAddRemoveAdminOwner(t *testing.T) { 608 testTeamReAddAfterReset(t, true, true, true) 609 } 610 611 func TestTeamResetReAddRemoveAdminOwnerPukless(t *testing.T) { 612 testTeamReAddAfterReset(t, false, true, true) 613 } 614 615 // Add a member after reset in a normal (non-implicit) team 616 // pukful - re-add the user after they get a puk 617 // adminOwner - an admin is re-adding an owner. 618 func testTeamReAddAfterReset(t *testing.T, pukful, adminOwner, removeAfterReset bool) { 619 if removeAfterReset && !adminOwner { 620 require.FailNow(t, "nope") 621 } 622 ctx := newSMUContext(t) 623 defer ctx.cleanup() 624 625 ann := ctx.installKeybaseForUser("ann", 10) 626 ann.signup() 627 divDebug(ctx, "Signed up ann (%s)", ann.username) 628 bob := ctx.installKeybaseForUser("bob", 10) 629 bob.signup() 630 divDebug(ctx, "Signed up bob (%s)", bob.username) 631 632 var team smuTeam 633 if adminOwner { 634 // Create a team where ann is an admin and bob is an owner. 635 team = ann.createTeam2(nil, nil, nil, []*smuUser{bob}) 636 ann.editMember(&team, ann.username, keybase1.TeamRole_ADMIN) 637 } else { 638 team = ann.createTeam([]*smuUser{bob}) 639 } 640 divDebug(ctx, "team created (%s) (%v)", team.name, team.ID) 641 642 bobUVBeforeReset := bob.userVersion() 643 644 ann.sendChat(team, "0") 645 kickTeamRekeyd(ann.getPrimaryGlobalContext(), t) 646 bob.reset() 647 divDebug(ctx, "Reset bob (%s)", bob.username) 648 649 if pukful { 650 // Bob gets a puk BEFORE being re-added. 651 bob.loginAfterReset(10) 652 divDebug(ctx, "Bob logged in after reset") 653 } 654 655 ann.pollForMembershipUpdate(team, keybase1.PerTeamKeyGeneration(2), nil) 656 657 cli := ann.getTeamsClient() 658 err := cli.TeamReAddMemberAfterReset(context.TODO(), keybase1.TeamReAddMemberAfterResetArg{ 659 Id: team.ID, 660 Username: bob.username, 661 }) 662 require.NoError(t, err) 663 664 if removeAfterReset { 665 err := ann.getTeamsClient().TeamRemoveMember(context.TODO(), keybase1.TeamRemoveMemberArg{ 666 TeamID: team.ID, 667 Member: keybase1.NewTeamMemberToRemoveWithAssertion(keybase1.AssertionTeamMemberToRemove{Assertion: bob.username}), 668 }) 669 require.NoError(t, err) 670 return 671 } 672 673 if !pukful { 674 // Bob gets a puk AFTER being re-added. 675 bob.loginAfterReset(10) 676 divDebug(ctx, "Bob logged in after reset") 677 } 678 679 expectedRole := keybase1.TeamRole_WRITER 680 if adminOwner { 681 // The reset owner should be re-admitted as an owner since 682 // that's the highest power ann can grant. 683 expectedRole = keybase1.TeamRole_ADMIN 684 } 685 686 teams.NewTeamLoaderAndInstall(ann.getPrimaryGlobalContext()) 687 688 pollFn := func(_ int) bool { 689 G := ann.getPrimaryGlobalContext() 690 teamObj, err := teams.Load(context.TODO(), G, keybase1.LoadTeamArg{ 691 ID: team.ID, 692 NeedAdmin: true, 693 ForceRepoll: true, 694 }) 695 require.NoError(t, err) 696 697 role, err := teamObj.MemberRole(context.TODO(), bob.userVersion()) 698 require.NoError(t, err) 699 if role == keybase1.TeamRole_NONE { 700 return false 701 } 702 if role == expectedRole { 703 return true 704 } 705 require.FailNowf(t, "unexpected role", "got %v on the hunt for %v", role, expectedRole) 706 707 // Old UV should be gone. Note that the server would not have allowed 708 // adding new UV without removing the old one first, so if the old UV 709 // is not being removed correctly during SBS handling, this test would 710 // probably never get to the following assertions (unless that server 711 // logic has changed.) 712 role, err = teamObj.MemberRole(context.TODO(), bobUVBeforeReset) 713 require.NoError(t, err) 714 require.Equal(t, keybase1.TeamRole_NONE, role) 715 return false 716 } 717 718 if pukful { 719 // Bob should have been synchronously made a cyrptomember by re-add. 720 require.Equal(t, true, pollFn(0)) 721 } else { 722 // A background task should upgrade bob from an invite to a cryptomember. 723 pollTime := 10 * time.Second 724 pollFor(t, "bob to be upgraded from invite to cryptomember", 725 pollTime, ann.getPrimaryGlobalContext(), pollFn) 726 } 727 728 bob.readChats(team, 1) 729 } 730 731 func TestResetInOpenTeam(t *testing.T) { 732 ctx := newSMUContext(t) 733 defer ctx.cleanup() 734 735 ann := ctx.installKeybaseForUser("ann", 10) 736 ann.signup() 737 divDebug(ctx, "Signed up ann (%s)", ann.username) 738 bob := ctx.installKeybaseForUser("bob", 10) 739 bob.signup() 740 divDebug(ctx, "Signed up bob (%s)", bob.username) 741 742 team := ann.createTeam([]*smuUser{bob}) 743 divDebug(ctx, "team created (%s)", team.name) 744 ann.openTeam(team, keybase1.TeamRole_WRITER) 745 ann.assertMemberActive(team, bob) 746 747 enableOpenSweepForTeam(ann.getPrimaryGlobalContext(), t, team.ID) 748 749 kickTeamRekeyd(ann.getPrimaryGlobalContext(), t) 750 bob.reset() 751 divDebug(ctx, "Reset bob (%s)", bob.username) 752 753 // Wait for OPENSWEEP which will remove bob from the team posting link 4. 754 ann.pollForTeamSeqnoLink(team, keybase1.Seqno(4)) 755 756 teamObj := ann.loadTeam(team.name, false) 757 _, err := teamObj.UserVersionByUID(context.Background(), bob.uid()) 758 require.Error(t, err, "expecting reset user to be removed from the team") 759 require.Contains(t, err.Error(), "did not find user") 760 require.EqualValues(t, 4, teamObj.CurrentSeqno()) 761 // Generation shouldn't change during OPENSWEEPing. 762 require.Equal(t, keybase1.PerTeamKeyGeneration(1), teamObj.Generation()) 763 764 bob.loginAfterReset(10) 765 divDebug(ctx, "Bob logged in after reset") 766 767 bob.requestAccess(team) 768 divDebug(ctx, "Bob requested access to open team after reset") 769 770 ann.pollForTeamSeqnoLink(team, teamObj.NextSeqno()) 771 ann.assertMemberActive(team, bob) 772 773 teamObj = ann.loadTeam(team.name, false) 774 require.Equal(t, keybase1.PerTeamKeyGeneration(1), teamObj.Generation()) 775 } 776 777 func TestTeamListAfterReset(t *testing.T) { 778 ctx := newSMUContext(t) 779 defer ctx.cleanup() 780 781 ann := ctx.installKeybaseForUser("ann", 10) 782 ann.signup() 783 divDebug(ctx, "Signed up ann (%s, %s)", ann.username, ann.uid()) 784 bob := ctx.installKeybaseForUser("bob", 10) 785 bob.signup() 786 divDebug(ctx, "Signed up bob (%s, %s)", bob.username, bob.uid()) 787 cam := ctx.installKeybaseForUser("cam", 10) 788 cam.signup() 789 divDebug(ctx, "Signed up cam (%s, %s)", cam.username, cam.uid()) 790 791 team := ann.createTeam([]*smuUser{bob, cam}) 792 divDebug(ctx, "team created (%s)", team.name) 793 794 // ensure bob is active according to other users 795 ann.assertMemberActive(team, bob) 796 797 bob.reset() 798 divDebug(ctx, "Reset bob (%s)", bob.username) 799 800 bob.loginAfterReset(10) 801 divDebug(ctx, "Bob logged in after reset") 802 803 ann.addWriter(team, bob) 804 divDebug(ctx, "Added bob back as a writer") 805 806 list, err := cam.teamGet(team) 807 require.NoError(t, err) 808 found := false 809 for _, w := range list.Members.Writers { 810 if w.Username == bob.username { 811 require.False(t, found, "wasn't found twice") 812 require.True(t, w.Uv.EldestSeqno > 1, "reset eldest seqno") 813 require.True(t, w.Status.IsActive(), "is active") 814 found = true 815 } 816 } 817 require.True(t, found, "we found bob (before he found us)") 818 } 819 820 func TestTeamAfterDeleteUser(t *testing.T) { 821 ctx := newSMUContext(t) 822 defer ctx.cleanup() 823 824 ann := ctx.installKeybaseForUser("ann", 10) 825 ann.signup() 826 divDebug(ctx, "Signed up ann (%s, %s)", ann.username, ann.uid()) 827 bob := ctx.installKeybaseForUser("bob", 10) 828 bob.signup() 829 divDebug(ctx, "Signed up bob (%s, %s)", bob.username, bob.uid()) 830 831 team := ann.createTeam([]*smuUser{bob}) 832 divDebug(ctx, "team created (%s)", team.name) 833 834 ann.sendChat(team, "0") 835 divDebug(ctx, "Sent chat '0' (%s via %s)", team.name, ann.username) 836 837 kickTeamRekeyd(ann.getPrimaryGlobalContext(), t) 838 ann.delete() 839 840 bob.pollForMembershipUpdate(team, keybase1.PerTeamKeyGeneration(2), nil) 841 842 divDebug(ctx, "Deleted ann (%s)", ann.username) 843 844 _, err := bob.teamGet(team) 845 require.NoError(t, err) 846 847 bob.dbNuke() 848 849 _, err = bob.teamGet(team) 850 require.NoError(t, err) 851 852 bob.readChats(team, 1) 853 } 854 855 func testTeamResetBadgesAndDismiss(t *testing.T, readd bool) { 856 tt := newTeamTester(t) 857 defer tt.cleanup() 858 859 tt.addUser("own") 860 tt.addUser("roo") 861 862 teamID, teamName := tt.users[0].createTeam2() 863 tt.users[0].kickTeamRekeyd() 864 tt.users[0].addTeamMember(teamName.String(), tt.users[1].username, keybase1.TeamRole_WRITER) 865 tt.users[1].reset() 866 tt.users[0].waitForTeamChangedGregor(teamID, keybase1.Seqno(2)) 867 // wait for badge state to have 1 team w/ reset member 868 badgeState := tt.users[0].waitForBadgeStateWithReset(1) 869 870 // users[0] should be badged since users[1] reset 871 require.True(t, len(badgeState.TeamsWithResetUsers) > 0) 872 out := badgeState.TeamsWithResetUsers[0] 873 require.Equal(t, out.Teamname, teamName.String()) 874 require.Equal(t, out.Username, tt.users[1].username) 875 876 // users[1] logs in after reset 877 tt.users[1].loginAfterReset() 878 879 // Either re-adding or removing user from the team should clear 880 // the reset badge. 881 if readd { 882 // users[0] adds users[1] back to the team 883 tt.users[0].addTeamMember(teamName.String(), tt.users[1].username, keybase1.TeamRole_WRITER) 884 } else { 885 // users[0] removes users[1] from the team 886 tt.users[0].removeTeamMember(teamName.String(), tt.users[1].username) 887 } 888 889 // wait for badge state to have no teams w/ reset member 890 badgeState = tt.users[0].waitForBadgeStateWithReset(0) 891 892 // badge state should be cleared 893 require.Zero(t, len(badgeState.TeamsWithResetUsers)) 894 } 895 896 // TestTeamResetBadges checks that badges show up for admins 897 // when a member of the team resets, and that they are dismissed 898 // when the reset user is added. 899 func TestTeamResetBadgesOnAdd(t *testing.T) { 900 testTeamResetBadgesAndDismiss(t, true) 901 } 902 903 // TestTeamResetBadgesOnRemove checks that badges show up for admins 904 // when a member of the team resets, and that they are dismissed 905 // when the reset user is removed. 906 func TestTeamResetBadgesOnRemove(t *testing.T) { 907 testTeamResetBadgesAndDismiss(t, false) 908 } 909 910 // Test users leaving the team when their eldest seqno is not 1. 911 func TestTeamResetAfterReset(t *testing.T) { 912 tt := newTeamTester(t) 913 defer tt.cleanup() 914 915 alice := tt.addUser("alice") 916 bob := tt.addUser("bob") 917 918 bob.reset() 919 bob.loginAfterReset() 920 _, teamName := alice.createTeam2() 921 tn := teamName.String() 922 alice.addTeamMember(tn, bob.username, keybase1.TeamRole_OWNER) 923 bob.leave(tn) 924 bob.reset() 925 bob.loginAfterReset() 926 alice.addTeamMember(tn, bob.username, keybase1.TeamRole_WRITER) 927 bob.leave(tn) 928 bob.reset() 929 bob.loginAfterReset() 930 alice.addTeamMember(tn, bob.username, keybase1.TeamRole_OWNER) 931 bob.leave(tn) 932 alice.loadTeam(tn, false) 933 }