Skip to content

Commit a421dca

Browse files
committed
fix broken aim 6 signon flow
1 parent 324f76f commit a421dca

File tree

9 files changed

+263
-50
lines changed

9 files changed

+263
-50
lines changed

foodgroup/admin.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,7 @@ func (s AdminService) InfoChangeRequest(ctx context.Context, sess *state.Session
218218
FoodGroup: wire.OService,
219219
SubGroup: wire.OServiceUserInfoUpdate,
220220
},
221-
Body: wire.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
222-
TLVUserInfo: sess.TLVUserInfo(),
223-
},
221+
Body: newOServiceUserInfoUpdate(sess),
224222
})
225223
tlvList.Append(wire.NewTLVBE(wire.AdminTLVScreenNameFormatted, proposedName.String()))
226224
return getAdminChangeReply(tlvList), nil

foodgroup/admin_test.go

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ func TestAdminService_InfoChangeRequest_ScreenName(t *testing.T) {
472472
expectErr error
473473
}{
474474
{
475-
name: "user changes screen name format successfully",
475+
name: "user changes screen name format successfully aim < 6",
476476
userSession: newTestSession("chattingchuck"),
477477
mockParams: mockParams{
478478
accountManagerParams: accountManagerParams{
@@ -499,7 +499,77 @@ func TestAdminService_InfoChangeRequest_ScreenName(t *testing.T) {
499499
SubGroup: wire.OServiceUserInfoUpdate,
500500
},
501501
Body: wire.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
502-
TLVUserInfo: newTestSession("Chatting Chuck").TLVUserInfo(),
502+
UserInfo: []wire.TLVUserInfo{
503+
newTestSession("Chatting Chuck").TLVUserInfo(),
504+
},
505+
},
506+
},
507+
},
508+
},
509+
},
510+
},
511+
inputSNAC: wire.SNACMessage{
512+
Frame: wire.SNACFrame{
513+
FoodGroup: wire.Admin,
514+
SubGroup: wire.AdminInfoChangeRequest,
515+
RequestID: 1337,
516+
},
517+
Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
518+
TLVRestBlock: wire.TLVRestBlock{
519+
TLVList: wire.TLVList{
520+
wire.NewTLVBE(wire.AdminTLVScreenNameFormatted, "Chatting Chuck"),
521+
},
522+
},
523+
},
524+
},
525+
expectOutput: wire.SNACMessage{
526+
Frame: wire.SNACFrame{
527+
FoodGroup: wire.Admin,
528+
SubGroup: wire.AdminInfoChangeReply,
529+
RequestID: 1337,
530+
},
531+
Body: wire.SNAC_0x07_0x05_AdminChangeReply{
532+
Permissions: wire.AdminInfoPermissionsReadWrite,
533+
TLVBlock: wire.TLVBlock{
534+
TLVList: wire.TLVList{
535+
wire.NewTLVBE(wire.AdminTLVScreenNameFormatted, "Chatting Chuck"),
536+
},
537+
},
538+
},
539+
},
540+
},
541+
{
542+
name: "user changes screen name format successfully aim >= 6",
543+
userSession: newTestSession("chattingchuck", sessOptSetFoodGroupVersion(wire.OService, 4)),
544+
mockParams: mockParams{
545+
accountManagerParams: accountManagerParams{
546+
accountManagerUpdateDisplayScreenNameParams: accountManagerUpdateDisplayScreenNameParams{
547+
{
548+
displayScreenName: state.DisplayScreenName("Chatting Chuck"),
549+
},
550+
},
551+
},
552+
buddyBroadcasterParams: buddyBroadcasterParams{
553+
broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
554+
{
555+
screenName: state.NewIdentScreenName("Chatting Chuck"),
556+
},
557+
},
558+
},
559+
messageRelayerParams: messageRelayerParams{
560+
relayToScreenNameParams: relayToScreenNameParams{
561+
{
562+
screenName: state.NewIdentScreenName("Chatting Chuck"),
563+
message: wire.SNACMessage{
564+
Frame: wire.SNACFrame{
565+
FoodGroup: wire.OService,
566+
SubGroup: wire.OServiceUserInfoUpdate,
567+
},
568+
Body: wire.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
569+
UserInfo: []wire.TLVUserInfo{
570+
newTestSession("Chatting Chuck").TLVUserInfo(),
571+
newTestSession("Chatting Chuck").TLVUserInfo(),
572+
},
503573
},
504574
},
505575
},

foodgroup/helpers_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,8 +762,10 @@ func sessOptUIN(UIN uint32) func(session *state.Session) {
762762
}
763763
}
764764

765-
func sessOptFoodGroupVersions(versions [wire.MDir + 1]uint16) func(session *state.Session) {
765+
func sessOptSetFoodGroupVersion(foodGroup uint16, version uint16) func(session *state.Session) {
766766
return func(session *state.Session) {
767+
var versions [wire.MDir + 1]uint16
768+
versions[foodGroup] = version
767769
session.SetFoodGroupVersions(versions)
768770
}
769771
}

foodgroup/oservice.go

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,7 @@ func (s OServiceService) UserInfoQuery(_ context.Context, sess *state.Session, i
189189
SubGroup: wire.OServiceUserInfoUpdate,
190190
RequestID: inFrame.RequestID,
191191
},
192-
Body: wire.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
193-
TLVUserInfo: sess.TLVUserInfo(),
194-
},
192+
Body: newOServiceUserInfoUpdate(sess),
195193
}
196194
}
197195

@@ -220,9 +218,7 @@ func (s OServiceService) SetUserInfoFields(ctx context.Context, sess *state.Sess
220218
SubGroup: wire.OServiceUserInfoUpdate,
221219
RequestID: inFrame.RequestID,
222220
},
223-
Body: wire.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
224-
TLVUserInfo: sess.TLVUserInfo(),
225-
},
221+
Body: newOServiceUserInfoUpdate(sess),
226222
}, nil
227223
}
228224

@@ -847,3 +843,22 @@ func NewOServiceServiceForBART(
847843
timeNow: time.Now,
848844
}
849845
}
846+
847+
// newOServiceUserInfoUpdate constructs SNAC(0x01,0x0F) for user info updates.
848+
// For OService version 4 and above, it appends a duplicate TLVUserInfo block.
849+
// AIM 6+ expects at least two user info blocks to support multi-session:
850+
// the first represents overall state; subsequent ones represent client instances.
851+
func newOServiceUserInfoUpdate(sess *state.Session) wire.SNAC_0x01_0x0F_OServiceUserInfoUpdate {
852+
info := sess.TLVUserInfo()
853+
userInfo := []wire.TLVUserInfo{info}
854+
855+
if sess.FoodGroupVersions()[wire.OService] >= 4 {
856+
// ideally, the second block should contain only instance-specific TLVs,
857+
// but since the exact structure is unclear, we temporarily duplicate the first.
858+
userInfo = append(userInfo, info)
859+
}
860+
861+
return wire.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
862+
UserInfo: userInfo,
863+
}
864+
}

foodgroup/oservice_test.go

Lines changed: 140 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ func TestSetUserInfoFields(t *testing.T) {
366366
mockParams mockParams
367367
}{
368368
{
369-
name: "set user status to visible",
369+
name: "set user status to visible aim < 6",
370370
userSession: newTestSession("me"),
371371
inputSNAC: wire.SNACMessage{
372372
Frame: wire.SNACFrame{
@@ -387,7 +387,9 @@ func TestSetUserInfoFields(t *testing.T) {
387387
RequestID: 1234,
388388
},
389389
Body: wire.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
390-
TLVUserInfo: newTestSession("me").TLVUserInfo(),
390+
UserInfo: []wire.TLVUserInfo{
391+
newTestSession("me").TLVUserInfo(),
392+
},
391393
},
392394
},
393395
mockParams: mockParams{
@@ -401,7 +403,7 @@ func TestSetUserInfoFields(t *testing.T) {
401403
},
402404
},
403405
{
404-
name: "set user status to invisible",
406+
name: "set user status to invisible aim < 6",
405407
userSession: newTestSession("me"),
406408
inputSNAC: wire.SNACMessage{
407409
Frame: wire.SNACFrame{
@@ -422,7 +424,85 @@ func TestSetUserInfoFields(t *testing.T) {
422424
RequestID: 1234,
423425
},
424426
Body: wire.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
425-
TLVUserInfo: newTestSession("me", sessOptInvisible).TLVUserInfo(),
427+
UserInfo: []wire.TLVUserInfo{
428+
newTestSession("me", sessOptInvisible).TLVUserInfo(),
429+
},
430+
},
431+
},
432+
mockParams: mockParams{
433+
buddyBroadcasterParams: buddyBroadcasterParams{
434+
broadcastBuddyDepartedParams: broadcastBuddyDepartedParams{
435+
{
436+
screenName: state.NewIdentScreenName("me"),
437+
},
438+
},
439+
},
440+
},
441+
},
442+
{
443+
name: "set user status to visible aim >= 6",
444+
userSession: newTestSession("me", sessOptSetFoodGroupVersion(wire.OService, 4)),
445+
inputSNAC: wire.SNACMessage{
446+
Frame: wire.SNACFrame{
447+
RequestID: 1234,
448+
},
449+
Body: wire.SNAC_0x01_0x1E_OServiceSetUserInfoFields{
450+
TLVRestBlock: wire.TLVRestBlock{
451+
TLVList: wire.TLVList{
452+
wire.NewTLVBE(wire.OServiceUserInfoStatus, uint32(0x0000)),
453+
},
454+
},
455+
},
456+
},
457+
expectOutput: wire.SNACMessage{
458+
Frame: wire.SNACFrame{
459+
FoodGroup: wire.OService,
460+
SubGroup: wire.OServiceUserInfoUpdate,
461+
RequestID: 1234,
462+
},
463+
Body: wire.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
464+
UserInfo: []wire.TLVUserInfo{
465+
newTestSession("me").TLVUserInfo(),
466+
newTestSession("me").TLVUserInfo(),
467+
},
468+
},
469+
},
470+
mockParams: mockParams{
471+
buddyBroadcasterParams: buddyBroadcasterParams{
472+
broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
473+
{
474+
screenName: state.NewIdentScreenName("me"),
475+
},
476+
},
477+
},
478+
},
479+
},
480+
{
481+
name: "set user status to invisible aim >= 6",
482+
userSession: newTestSession("me", sessOptSetFoodGroupVersion(wire.OService, 4)),
483+
inputSNAC: wire.SNACMessage{
484+
Frame: wire.SNACFrame{
485+
RequestID: 1234,
486+
},
487+
Body: wire.SNAC_0x01_0x1E_OServiceSetUserInfoFields{
488+
TLVRestBlock: wire.TLVRestBlock{
489+
TLVList: wire.TLVList{
490+
wire.NewTLVBE(wire.OServiceUserInfoStatus, uint32(0x0100)),
491+
},
492+
},
493+
},
494+
},
495+
expectOutput: wire.SNACMessage{
496+
Frame: wire.SNACFrame{
497+
FoodGroup: wire.OService,
498+
SubGroup: wire.OServiceUserInfoUpdate,
499+
RequestID: 1234,
500+
},
501+
Body: wire.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
502+
UserInfo: []wire.TLVUserInfo{
503+
newTestSession("me", sessOptInvisible).TLVUserInfo(),
504+
newTestSession("me", sessOptInvisible).TLVUserInfo(),
505+
},
426506
},
427507
},
428508
mockParams: mockParams{
@@ -754,11 +834,8 @@ func TestOServiceService_RateParamsQuery(t *testing.T) {
754834
timeNow func() time.Time
755835
}{
756836
{
757-
name: "get rate limits for AIM > 1.x clients",
758-
userSession: newTestSession("me", sessOptFoodGroupVersions([wire.MDir + 1]uint16{
759-
0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // set OService version
760-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
761-
})),
837+
name: "get rate limits for AIM > 1.x clients",
838+
userSession: newTestSession("me", sessOptSetFoodGroupVersion(wire.OService, 3)),
762839
inputSNAC: wire.SNACMessage{
763840
Frame: wire.SNACFrame{RequestID: 1234},
764841
},
@@ -1081,26 +1158,64 @@ func TestOServiceService_ClientVersions(t *testing.T) {
10811158
}
10821159

10831160
func TestOServiceService_UserInfoQuery(t *testing.T) {
1084-
svc := OServiceService{
1085-
cfg: config.Config{},
1086-
logger: slog.Default(),
1087-
}
1088-
sess := newTestSession("me")
1089-
1090-
want := wire.SNACMessage{
1091-
Frame: wire.SNACFrame{
1092-
FoodGroup: wire.OService,
1093-
SubGroup: wire.OServiceUserInfoUpdate,
1094-
RequestID: 1234,
1161+
tests := []struct {
1162+
name string
1163+
sess *state.Session
1164+
given wire.SNACMessage
1165+
want wire.SNACMessage
1166+
wantErr error
1167+
}{
1168+
{
1169+
name: "happy path windows aim < 6",
1170+
sess: newTestSession("me"),
1171+
given: wire.SNACMessage{
1172+
Frame: wire.SNACFrame{RequestID: 1234},
1173+
},
1174+
want: wire.SNACMessage{
1175+
Frame: wire.SNACFrame{
1176+
FoodGroup: wire.OService,
1177+
SubGroup: wire.OServiceUserInfoUpdate,
1178+
RequestID: 1234,
1179+
},
1180+
Body: wire.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
1181+
UserInfo: []wire.TLVUserInfo{
1182+
newTestSession("me").TLVUserInfo(),
1183+
},
1184+
},
1185+
},
10951186
},
1096-
Body: wire.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
1097-
TLVUserInfo: sess.TLVUserInfo(),
1187+
{
1188+
name: "happy path windows aim >= 6",
1189+
sess: newTestSession("me", sessOptSetFoodGroupVersion(wire.OService, 4)),
1190+
given: wire.SNACMessage{
1191+
Frame: wire.SNACFrame{RequestID: 1234},
1192+
},
1193+
want: wire.SNACMessage{
1194+
Frame: wire.SNACFrame{
1195+
FoodGroup: wire.OService,
1196+
SubGroup: wire.OServiceUserInfoUpdate,
1197+
RequestID: 1234,
1198+
},
1199+
Body: wire.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
1200+
UserInfo: []wire.TLVUserInfo{
1201+
newTestSession("me").TLVUserInfo(),
1202+
newTestSession("me").TLVUserInfo(),
1203+
},
1204+
},
1205+
},
10981206
},
10991207
}
11001208

1101-
have := svc.UserInfoQuery(nil, sess, wire.SNACFrame{RequestID: 1234})
1102-
1103-
assert.Equal(t, want, have)
1209+
for _, tt := range tests {
1210+
t.Run(tt.name, func(t *testing.T) {
1211+
svc := OServiceService{
1212+
cfg: config.Config{},
1213+
logger: slog.Default(),
1214+
}
1215+
have := svc.UserInfoQuery(context.Background(), tt.sess, tt.given.Frame)
1216+
assert.Equal(t, tt.want, have)
1217+
})
1218+
}
11041219
}
11051220

11061221
func TestOServiceService_IdleNotification(t *testing.T) {

server/oscar/handler/oservice_test.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,9 @@ func TestOServiceHandler_SetUserInfoFields(t *testing.T) {
306306
SubGroup: wire.OServiceUserInfoUpdate,
307307
},
308308
Body: wire.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
309-
TLVUserInfo: wire.TLVUserInfo{
310-
ScreenName: "screen-name",
309+
UserInfo: []wire.TLVUserInfo{
310+
{ScreenName: "screen-name"},
311+
{ScreenName: "screen-name"},
311312
},
312313
},
313314
}
@@ -349,8 +350,9 @@ func TestOServiceHandler_UserInfoQuery(t *testing.T) {
349350
SubGroup: wire.OServiceUserInfoUpdate,
350351
},
351352
Body: wire.SNAC_0x01_0x0F_OServiceUserInfoUpdate{
352-
TLVUserInfo: wire.TLVUserInfo{
353-
ScreenName: "screen-name",
353+
UserInfo: []wire.TLVUserInfo{
354+
{ScreenName: "screen-name"},
355+
{ScreenName: "screen-name"},
354356
},
355357
},
356358
}

state/session.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,8 @@ func (s *Session) userInfo() wire.TLVList {
374374
tlvs.Append(wire.NewTLVBE(wire.OServiceUserInfoOscarCaps, s.caps))
375375
}
376376

377+
tlvs.Append(wire.NewTLVBE(wire.OServiceUserInfoMySubscriptions, uint32(0)))
378+
377379
return tlvs
378380
}
379381

0 commit comments

Comments
 (0)