github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/systests/team_seitan_invitelink_test.go (about) 1 package systests 2 3 import ( 4 "testing" 5 "time" 6 7 "github.com/keybase/client/go/libkb" 8 keybase1 "github.com/keybase/client/go/protocol/keybase1" 9 "github.com/keybase/client/go/teams" 10 "github.com/keybase/clockwork" 11 "github.com/stretchr/testify/require" 12 context "golang.org/x/net/context" 13 ) 14 15 func TestTeamInviteSeitanInvitelinkHappy(t *testing.T) { 16 testTeamInviteSeitanInvitelinkHappy(t, false /* implicitAdmin */) 17 testTeamInviteSeitanInvitelinkHappy(t, true /* implicitAdmin */) 18 } 19 20 func testTeamInviteSeitanInvitelinkHappy(t *testing.T, implicitAdmin bool) { 21 tt := newTeamTester(t) 22 defer tt.cleanup() 23 24 alice := tt.addUser("kvr") 25 bob := tt.addUser("eci") 26 27 teamIDParent, teamNameParent := alice.createTeam2() 28 teamID := teamIDParent 29 teamName := teamNameParent 30 t.Logf("Created team %v %v", teamIDParent, teamNameParent) 31 if implicitAdmin { 32 subteamID, err := teams.CreateSubteam(context.TODO(), tt.users[0].tc.G, "sub1", teamNameParent, keybase1.TeamRole_NONE /* addSelfAs */) 33 require.NoError(t, err) 34 teamID = *subteamID 35 subteamName, err := teamNameParent.Append("sub1") 36 require.NoError(t, err) 37 teamName = subteamName 38 t.Logf("Created subteam %v %v", teamID, teamName) 39 } 40 41 maxUses, err := keybase1.NewTeamInviteFiniteUses(3) 42 require.NoError(t, err) 43 etime := keybase1.ToUnixTime(time.Now().Add(24 * time.Hour)) 44 link, err := alice.teamsClient.TeamCreateSeitanInvitelink(context.TODO(), keybase1.TeamCreateSeitanInvitelinkArg{ 45 Teamname: teamName.String(), 46 Role: keybase1.TeamRole_WRITER, 47 MaxUses: maxUses, 48 Etime: &etime, 49 }) 50 require.NoError(t, err) 51 52 t.Logf("Created token %v", link) 53 54 details := alice.teamGetDetails(teamName.String()) 55 require.Len(t, details.AnnotatedActiveInvites, 1) 56 for _, aInvite := range details.AnnotatedActiveInvites { 57 invite := aInvite.InviteMetadata.Invite 58 require.Equal(t, keybase1.TeamRole_WRITER, invite.Role) 59 tic, err := invite.Type.C() 60 require.NoError(t, err) 61 require.Equal(t, keybase1.TeamInviteCategory_INVITELINK, tic) 62 } 63 64 bob.kickTeamRekeyd() 65 err = bob.teamsClient.TeamAcceptInvite(context.TODO(), keybase1.TeamAcceptInviteArg{ 66 Token: string(link.Ikey), 67 }) 68 require.NoError(t, err) 69 70 t.Logf("User used token, waiting for rekeyd") 71 72 alice.waitForTeamChangedGregor(teamID, keybase1.Seqno(3)) 73 74 t0, err := teams.GetTeamByNameForTest(context.TODO(), alice.tc.G, teamName.String(), false /* public */, true /* needAdmin */) 75 require.NoError(t, err) 76 77 role, err := t0.MemberRole(context.TODO(), teams.NewUserVersion(bob.uid, 1)) 78 require.NoError(t, err) 79 require.Equal(t, role, keybase1.TeamRole_WRITER) 80 } 81 82 func TestTeamInviteLinkAfterLeave(t *testing.T) { 83 tt := newTeamTester(t) 84 defer tt.cleanup() 85 86 alice := tt.addUser("ali") 87 bob := tt.addUser("bob") 88 89 teamID, teamName := alice.createTeam2() 90 maxUses, err := keybase1.NewTeamInviteFiniteUses(100) 91 require.NoError(t, err) 92 etime := keybase1.ToUnixTime(time.Now().AddDate(1, 0, 0)) 93 link, err := alice.teamsClient.TeamCreateSeitanInvitelink(context.TODO(), keybase1.TeamCreateSeitanInvitelinkArg{ 94 Teamname: teamName.String(), 95 Role: keybase1.TeamRole_WRITER, 96 MaxUses: maxUses, 97 Etime: &etime, 98 }) 99 require.NoError(t, err) 100 101 t.Logf("Created team invite link: %#v", link) 102 103 bob.kickTeamRekeyd() 104 err = bob.teamsClient.TeamAcceptInvite(context.TODO(), keybase1.TeamAcceptInviteArg{ 105 Token: string(link.Ikey), 106 }) 107 require.NoError(t, err) 108 109 alice.waitForTeamChangedGregor(teamID, keybase1.Seqno(3)) 110 111 // Bob leaves. 112 bob.leave(teamName.String()) 113 114 // Make sure Bob gets different akey when accepting again, and that Alice 115 // doesn't hit the "invite link was accepted before last change membership" 116 // when handling seitan. 117 clock := clockwork.NewFakeClockAt(time.Now()) 118 clock.Advance(1 * time.Second) 119 bob.tc.G.SetClock(clock) 120 alice.tc.G.SetClock(clock) 121 122 // Bob accepts the same invite again. 123 err = bob.teamsClient.TeamAcceptInvite(context.TODO(), keybase1.TeamAcceptInviteArg{ 124 Token: string(link.Ikey), 125 }) 126 require.NoError(t, err) 127 128 alice.waitForTeamChangedGregor(teamID, keybase1.Seqno(5)) 129 130 t.Logf("removing bob; expecting to ban since he was added by invitelink most recently") 131 alice.removeTeamMember(teamName.String(), bob.username) 132 t.Logf("bob tries to rejoin") 133 clock.Advance(1 * time.Second) 134 err = bob.teamsClient.TeamAcceptInvite(context.TODO(), keybase1.TeamAcceptInviteArg{ 135 Token: string(link.Ikey), 136 }) 137 require.Error(t, err, "server won't let bob back in") 138 appErr, ok := err.(libkb.AppStatusError) 139 require.True(t, ok, "got an app err") 140 require.Equal(t, appErr.Code, libkb.SCTeamBanned) 141 142 t.Logf("alice adds/removes manually to clear ban") 143 alice.addTeamMember(teamName.String(), bob.username, keybase1.TeamRole_WRITER) 144 alice.removeTeamMember(teamName.String(), bob.username) 145 146 clock.Advance(1 * time.Second) 147 err = bob.teamsClient.TeamAcceptInvite(context.TODO(), keybase1.TeamAcceptInviteArg{ 148 Token: string(link.Ikey), 149 }) 150 require.NoError(t, err, "bob can rejoin") 151 alice.waitForTeamChangedGregor(teamID, keybase1.Seqno(9)) 152 t0, err := teams.GetTeamByNameForTest(context.TODO(), alice.tc.G, 153 teamName.String(), false /* public */, true /* needAdmin */) 154 require.NoError(t, err) 155 role, err := t0.MemberRole(context.TODO(), teams.NewUserVersion(bob.uid, 1)) 156 require.NoError(t, err) 157 require.Equal(t, role, keybase1.TeamRole_WRITER) 158 } 159 160 func TestCreateSeitanInvitelinkWithDuration(t *testing.T) { 161 // Test for the GUI RPC. 162 163 tt := newTeamTester(t) 164 defer tt.cleanup() 165 166 alice := tt.addUser("ali") 167 _, teamName := alice.createTeam2() 168 169 now := alice.tc.G.Clock().Now() 170 171 maxUses := keybase1.TeamMaxUsesInfinite 172 expireAfter := "10 Y" 173 _, err := alice.teamsClient.TeamCreateSeitanInvitelinkWithDuration( 174 context.TODO(), 175 keybase1.TeamCreateSeitanInvitelinkWithDurationArg{ 176 Teamname: teamName.String(), 177 Role: keybase1.TeamRole_WRITER, 178 MaxUses: maxUses, 179 ExpireAfter: &expireAfter, 180 }) 181 require.NoError(t, err) 182 183 details := alice.teamGetDetails(teamName.String()) 184 require.Len(t, details.AnnotatedActiveInvites, 1) 185 for _, aInvite := range details.AnnotatedActiveInvites { 186 invite := aInvite.InviteMetadata.Invite 187 require.Equal(t, keybase1.TeamRole_WRITER, invite.Role) 188 require.NotNil(t, invite.MaxUses) 189 require.Equal(t, keybase1.TeamMaxUsesInfinite, *invite.MaxUses) 190 require.NotNil(t, invite.Etime) 191 require.Equal(t, now.Year()+10, invite.Etime.Time().Year()) 192 require.Equal(t, keybase1.TeamMaxUsesInfinite, *invite.MaxUses) 193 tic, err := invite.Type.C() 194 require.NoError(t, err) 195 require.Equal(t, keybase1.TeamInviteCategory_INVITELINK, tic) 196 } 197 }