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