github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/teams/list_test.go (about) 1 package teams 2 3 import ( 4 "fmt" 5 "testing" 6 "time" 7 8 "github.com/keybase/client/go/protocol/keybase1" 9 "github.com/stretchr/testify/require" 10 ) 11 12 func newSocialInviteMD(typ keybase1.TeamInviteType, status keybase1.TeamInviteMetadataStatus) validityInput { 13 return validityInput{ 14 md: keybase1.TeamInviteMetadata{ 15 Invite: keybase1.TeamInvite{ 16 Type: typ, 17 }, 18 Status: status, 19 }, 20 } 21 } 22 23 // maxUses = nil -> infinite; otherwise finite 24 func newInvitelinkMD(etime *time.Time, maxUses *int, usedTimes []time.Time, cancelled *time.Time) validityInput { 25 userLog := make(map[keybase1.UserVersion][]keybase1.UserLogPoint) 26 var usedInvites []keybase1.TeamUsedInviteLogPoint 27 for idx, usedTime := range usedTimes { 28 uv := keybase1.UserVersion{ 29 Uid: keybase1.UID(fmt.Sprintf("fakeuid%d", idx)), 30 EldestSeqno: 3, 31 } 32 // Joined first via some other way 33 userLog[uv] = append(userLog[uv], keybase1.UserLogPoint{ 34 SigMeta: keybase1.SignatureMetadata{ 35 Time: keybase1.ToTime(usedTime), 36 }, 37 }) 38 // Then was added by invitelink 39 userLog[uv] = append(userLog[uv], keybase1.UserLogPoint{ 40 SigMeta: keybase1.SignatureMetadata{ 41 Time: keybase1.ToTime(usedTime), 42 }, 43 }) 44 usedInvites = append(usedInvites, keybase1.TeamUsedInviteLogPoint{ 45 Uv: uv, 46 LogPoint: 1, 47 }) 48 } 49 invite := keybase1.TeamInvite{ 50 Type: keybase1.NewTeamInviteTypeDefault(keybase1.TeamInviteCategory_INVITELINK), 51 } 52 if etime != nil { 53 tmp := keybase1.ToUnixTime(*etime) 54 invite.Etime = &tmp 55 } 56 var m keybase1.TeamInviteMaxUses 57 if maxUses == nil { 58 m = keybase1.TeamMaxUsesInfinite 59 } else { 60 m, _ = keybase1.NewTeamInviteFiniteUses(*maxUses) 61 } 62 invite.MaxUses = &m 63 status := keybase1.NewTeamInviteMetadataStatusWithActive() 64 if cancelled != nil { 65 status = keybase1.NewTeamInviteMetadataStatusWithCancelled(keybase1.TeamInviteMetadataCancel{ 66 TeamSigMeta: keybase1.TeamSignatureMetadata{ 67 SigMeta: keybase1.SignatureMetadata{ 68 Time: keybase1.ToTime(*cancelled), 69 }, 70 }, 71 }) 72 } 73 md := keybase1.TeamInviteMetadata{ 74 Invite: invite, 75 Status: status, 76 UsedInvites: usedInvites, 77 } 78 return validityInput{md, userLog} 79 } 80 81 type validityInput struct { 82 md keybase1.TeamInviteMetadata 83 userLog map[keybase1.UserVersion][]keybase1.UserLogPoint 84 } 85 86 // Tests go/protocol/keybase1/extras.go:TeamInviteMetadata.ComputeValidity. 87 // In this test we stub out fields of invites that are not needed/used by ComputeValidity, for 88 // brevity. 89 func TestComputeValidity(t *testing.T) { 90 now := time.Date(2020, time.January, 10, 14, 0, 0, 0, time.UTC) 91 hour := time.Hour 92 day := 24 * hour 93 week := 7 * day 94 month := 4 * week 95 year := 12 * month 96 97 intp := func(n int) *int { 98 return &n 99 } 100 timep := func(t time.Time) *time.Time { 101 return &t 102 } 103 104 var tests = []struct { 105 desc string 106 107 now time.Time 108 i validityInput 109 110 expectedIsValid bool 111 expectedValidityDescription string 112 }{ 113 { 114 "active twitter", 115 now, 116 newSocialInviteMD( 117 keybase1.NewTeamInviteTypeWithSbs(keybase1.TeamInviteSocialNetwork("twitter")), 118 keybase1.NewTeamInviteMetadataStatusWithActive(), 119 ), 120 true, 121 "Expires after 1 use", 122 }, 123 { 124 "cancelled twitter", 125 now, 126 newSocialInviteMD( 127 keybase1.NewTeamInviteTypeWithSbs(keybase1.TeamInviteSocialNetwork("twitter")), 128 keybase1.NewTeamInviteMetadataStatusWithCancelled(keybase1.TeamInviteMetadataCancel{ 129 TeamSigMeta: keybase1.TeamSignatureMetadata{ 130 SigMeta: keybase1.SignatureMetadata{ 131 Time: keybase1.ToTime(now.Add(-2 * week)), 132 }, 133 }, 134 }), 135 ), 136 false, 137 "Cancelled 2 weeks ago", 138 }, 139 { 140 "completed twitter", 141 now, 142 newSocialInviteMD( 143 keybase1.NewTeamInviteTypeWithSbs(keybase1.TeamInviteSocialNetwork("twitter")), 144 keybase1.NewTeamInviteMetadataStatusWithCompleted(keybase1.TeamInviteMetadataCompleted{ 145 TeamSigMeta: keybase1.TeamSignatureMetadata{ 146 SigMeta: keybase1.SignatureMetadata{ 147 Time: keybase1.ToTime(now.Add(-month)), 148 }, 149 }, 150 }), 151 ), 152 false, 153 "Completed 4 weeks ago", 154 }, 155 { 156 "immortal invitelink", 157 now, 158 newInvitelinkMD(nil, nil, []time.Time{now.Add(-month), now.Add(-week), now, now.Add(day)}, nil), 159 true, 160 "Does not expire", 161 }, 162 { 163 "cancelled immortal invitelink", 164 now, 165 newInvitelinkMD(nil, nil, []time.Time{now.Add(-month), now.Add(-week), now.Add(-3 * day), now.Add(-day)}, timep(now.Add(-hour))), 166 false, 167 "Cancelled 1 hour ago", 168 }, 169 { 170 "expiring invitelink", 171 now, 172 newInvitelinkMD(timep(now.Add(12*day)), nil, []time.Time{}, nil), 173 true, 174 "Expires in 1 week", 175 }, 176 { 177 "expiring limited invitelink", 178 now, 179 newInvitelinkMD(timep(now.Add(1*year+6*month)), intp(2), []time.Time{}, nil), 180 true, 181 "Expires in 1 year or after 2 uses", 182 }, 183 { 184 "limited invitelink", 185 now, 186 newInvitelinkMD(nil, intp(123), []time.Time{}, nil), 187 true, 188 "Expires after 123 uses", 189 }, 190 { 191 "expired invitelink, no uses", 192 now, 193 newInvitelinkMD(timep(now.Add(-16*day)), nil, []time.Time{}, nil), 194 false, 195 "Expired 2 weeks ago", 196 }, 197 { 198 "expired invitelink, some uses", 199 now, 200 newInvitelinkMD(timep(now.Add(-16*day)), nil, []time.Time{now.Add(-month), now.Add(-year)}, nil), 201 false, 202 "Expired 2 weeks ago", 203 }, 204 { 205 "expired invitelink, no uses, then cancelled", 206 now, 207 newInvitelinkMD(timep(now.Add(-16*day)), nil, []time.Time{}, timep(now.Add(-2*day))), 208 false, 209 "Cancelled 2 days ago", 210 }, 211 { 212 "usedup invitelink one use", 213 now, 214 newInvitelinkMD(nil, intp(1), []time.Time{now.Add(-month)}, nil), 215 false, 216 "Expired 4 weeks ago", 217 }, 218 { 219 "usedup invitelink multiuse", 220 now, 221 newInvitelinkMD(nil, intp(3), []time.Time{now.Add(-3 * month), now.Add(-2 * month), now.Add(-3 * day)}, nil), 222 false, 223 "Expired 3 days ago", 224 }, 225 { 226 "usedup invitelink multiuse then cancelled", 227 now, 228 newInvitelinkMD(nil, intp(3), []time.Time{now.Add(-3 * month), now.Add(-2 * month), now.Add(-3 * day)}, timep(now.Add(-2*hour))), 229 false, 230 "Cancelled 2 hours ago", 231 }, 232 { 233 "expiring partially used invitelink multiuse", 234 now, 235 newInvitelinkMD(timep(now.Add(3*day)), intp(3), []time.Time{now.Add(-3 * month), now.Add(-3 * day)}, nil), 236 true, 237 "Expires in 3 days or after 1 use", 238 }, 239 { 240 "partially used invitelink multiuse", 241 now, 242 newInvitelinkMD(nil, intp(3), []time.Time{now.Add(-3 * month), now.Add(-3 * day)}, nil), 243 true, 244 "Expires after 1 use", 245 }, 246 { 247 "expired and usedup invitelink, but the usedup happened first", 248 now, 249 newInvitelinkMD(timep(now.Add(-5*time.Minute)), intp(2), []time.Time{now.Add(-3 * month), now.Add(-1 * hour)}, nil), 250 false, 251 // i.e.; it was invalidated because it was used up, not because it later expired 252 "Expired 1 hour ago", 253 }, 254 } 255 for _, tt := range tests { 256 tt := tt 257 t.Run(tt.desc, func(t *testing.T) { 258 gotIsValid, gotValidityDescription := tt.i.md.ComputeValidity(tt.now, tt.i.userLog) 259 require.Equal(t, tt.expectedIsValid, gotIsValid) 260 require.Equal(t, tt.expectedValidityDescription, gotValidityDescription) 261 }) 262 } 263 }