瀏覽代碼

don't reveal invisible user via buddy arrival notif

Mike 6 月之前
父節點
當前提交
0b56038d19
共有 4 個文件被更改,包括 255 次插入0 次删除
  1. 7 0
      foodgroup/buddy.go
  2. 153 0
      foodgroup/buddy_test.go
  3. 5 0
      wire/snacs.go
  4. 90 0
      wire/snacs_test.go

+ 7 - 0
foodgroup/buddy.go

@@ -164,6 +164,10 @@ type buddyNotifier struct {
 // only used to indicate the user coming online. It can also notify changes to
 // buddy icons, warning levels, invisibility status, etc.
 func (s buddyNotifier) BroadcastBuddyArrived(ctx context.Context, screenName state.IdentScreenName, userInfo wire.TLVUserInfo) error {
+	if userInfo.IsInvisible() {
+		return nil
+	}
+
 	users, err := s.relationshipFetcher.AllRelationships(ctx, screenName, nil)
 	if err != nil {
 		return err
@@ -319,6 +323,9 @@ func (s buddyNotifier) unicastBuddyDeparted(ctx context.Context, from *state.Ses
 // only used to indicate the user coming online. It can also notify changes to
 // buddy icons, warning levels, invisibility status, etc.
 func (s buddyNotifier) unicastBuddyArrived(ctx context.Context, userInfo wire.TLVUserInfo, to state.IdentScreenName) {
+	if userInfo.IsInvisible() {
+		return
+	}
 	s.messageRelayer.RelayToScreenName(ctx, to, wire.SNACMessage{
 		Frame: wire.SNACFrame{
 			FoodGroup: wire.Buddy,

+ 153 - 0
foodgroup/buddy_test.go

@@ -506,6 +506,26 @@ func TestBuddyNotifier_BroadcastBuddyArrived(t *testing.T) {
 				},
 			},
 		},
+		{
+			name:       "user invisible, don't send notification",
+			screenName: state.NewIdentScreenName("me"),
+			userInfo: wire.TLVUserInfo{
+				ScreenName: "me",
+				TLVBlock: wire.TLVBlock{
+					TLVList: wire.TLVList{
+						wire.NewTLVBE(wire.OServiceUserInfoStatus, wire.OServiceUserStatusInvisible),
+					},
+				},
+			},
+			mockParams: mockParams{
+				relationshipFetcherParams: relationshipFetcherParams{
+					allRelationshipsParams: allRelationshipsParams{}, // don't look up relationships
+				},
+				messageRelayerParams: messageRelayerParams{
+					relayToScreenNamesParams: relayToScreenNamesParams{}, // don't send notification
+				},
+			},
+		},
 	}
 
 	for _, tc := range cases {
@@ -803,6 +823,139 @@ func Test_buddyNotifier_BroadcastVisibility(t *testing.T) {
 			},
 			doSendDepartures: true,
 		},
+		{
+			name:     "user invisible, don't send notification to buddies",
+			instance: newTestInstance("me", sessOptInvisible),
+			mockParams: mockParams{
+				relationshipFetcherParams: relationshipFetcherParams{
+					allRelationshipsParams: allRelationshipsParams{
+						{
+							screenName: state.NewIdentScreenName("me"),
+							filter:     nil,
+							result: []state.Relationship{
+								{
+									User:          state.NewIdentScreenName("friend1-blocks-you"),
+									BlocksYou:     true,
+									YouBlock:      false,
+									IsOnYourList:  true,
+									IsOnTheirList: true,
+								},
+								{
+									User:          state.NewIdentScreenName("friend2-visible-on-their-list"),
+									BlocksYou:     false,
+									YouBlock:      false,
+									IsOnYourList:  false,
+									IsOnTheirList: true,
+								},
+								{
+									User:          state.NewIdentScreenName("friend3-visible-on-your-list"),
+									BlocksYou:     false,
+									YouBlock:      false,
+									IsOnYourList:  true,
+									IsOnTheirList: false,
+								},
+								{
+									User:          state.NewIdentScreenName("friend4-visible-on-both-lists"),
+									BlocksYou:     false,
+									YouBlock:      false,
+									IsOnYourList:  true,
+									IsOnTheirList: true,
+								},
+								{
+									User:          state.NewIdentScreenName("friend5-blocked-on-their-list"),
+									BlocksYou:     false,
+									YouBlock:      true,
+									IsOnYourList:  false,
+									IsOnTheirList: true,
+								},
+								{
+									User:          state.NewIdentScreenName("friend6-blocked-on-your-list"),
+									BlocksYou:     false,
+									YouBlock:      true,
+									IsOnYourList:  true,
+									IsOnTheirList: false,
+								},
+								{
+									User:          state.NewIdentScreenName("friend7-blocked-on-both-lists"),
+									BlocksYou:     false,
+									YouBlock:      true,
+									IsOnYourList:  true,
+									IsOnTheirList: true,
+								},
+								{
+									User:          state.NewIdentScreenName("friend7-visible-offline"),
+									BlocksYou:     false,
+									YouBlock:      false,
+									IsOnYourList:  true,
+									IsOnTheirList: true,
+								},
+							},
+						},
+					},
+				},
+				messageRelayerParams: messageRelayerParams{
+					relayToScreenNameParams: relayToScreenNameParams{
+						{
+							screenName: state.NewIdentScreenName("me"),
+							message:    newBuddyArrivedNotif("friend3-visible-on-your-list"),
+						},
+						{
+							screenName: state.NewIdentScreenName("me"),
+							message:    newBuddyArrivedNotif("friend4-visible-on-both-lists"),
+						},
+						{
+							screenName: state.NewIdentScreenName("friend5-blocked-on-their-list"),
+							message:    newBuddyDepartedNotif("me"),
+						},
+						{
+							screenName: state.NewIdentScreenName("me"),
+							message:    newBuddyDepartedNotif("friend6-blocked-on-your-list"),
+						},
+						{
+							screenName: state.NewIdentScreenName("me"),
+							message:    newBuddyDepartedNotif("friend7-blocked-on-both-lists"),
+						},
+						{
+							screenName: state.NewIdentScreenName("friend7-blocked-on-both-lists"),
+							message:    newBuddyDepartedNotif("me"),
+						},
+					},
+				},
+				sessionRetrieverParams: sessionRetrieverParams{
+					retrieveSessionParams: retrieveSessionParams{
+						{
+							screenName: state.NewIdentScreenName("friend2-visible-on-their-list"),
+							result:     newTestInstance("friend2-visible-on-their-list").Session(),
+						},
+						{
+							screenName: state.NewIdentScreenName("friend3-visible-on-your-list"),
+							result:     newTestInstance("friend3-visible-on-your-list").Session(),
+						},
+						{
+							screenName: state.NewIdentScreenName("friend4-visible-on-both-lists"),
+							result:     newTestInstance("friend4-visible-on-both-lists").Session(),
+						},
+						{
+							screenName: state.NewIdentScreenName("friend5-blocked-on-their-list"),
+							result:     newTestInstance("friend5-blocked-on-their-list").Session(),
+						},
+						{
+							screenName: state.NewIdentScreenName("friend6-blocked-on-your-list"),
+							result:     newTestInstance("friend6-blocked-on-your-list").Session(),
+						},
+						{
+							screenName: state.NewIdentScreenName("friend7-blocked-on-both-lists"),
+							result:     newTestInstance("friend7-blocked-on-both-lists").Session(),
+						},
+						{
+							screenName: state.NewIdentScreenName("friend7-visible-offline"),
+							result:     nil,
+						},
+					},
+				},
+			},
+			doSendDepartures: true,
+		},
 		{
 			name:     "don't send departure notifications",
 			instance: newTestInstance("me"),

+ 5 - 0
wire/snacs.go

@@ -2508,6 +2508,11 @@ func (t TLVUserInfo) IsAway() bool {
 	return flags&OServiceUserFlagUnavailable == OServiceUserFlagUnavailable
 }
 
+func (t TLVUserInfo) IsInvisible() bool {
+	mask, _ := t.Uint32BE(OServiceUserInfoStatus)
+	return mask&OServiceUserStatusInvisible == OServiceUserStatusInvisible
+}
+
 type FeedbagItem struct {
 	Name    string `oscar:"len_prefix=uint16"`
 	GroupID uint16

+ 90 - 0
wire/snacs_test.go

@@ -147,3 +147,93 @@ func TestUnmarshalChatMessageText(t *testing.T) {
 		})
 	}
 }
+
+func TestTLVUserInfo_IsAway(t *testing.T) {
+	tests := []struct {
+		name     string
+		userInfo TLVUserInfo
+		want     bool
+	}{
+		{
+			name: "flag is set",
+			userInfo: TLVUserInfo{
+				TLVBlock: TLVBlock{
+					TLVList: TLVList{
+						NewTLVBE(OServiceUserInfoUserFlags, OServiceUserFlagUnavailable),
+					},
+				},
+			},
+			want: true,
+		},
+		{
+			name: "flag is not set",
+			userInfo: TLVUserInfo{
+				TLVBlock: TLVBlock{
+					TLVList: TLVList{
+						NewTLVBE(OServiceUserInfoUserFlags, OServiceUserFlagOSCARFree),
+					},
+				},
+			},
+			want: false,
+		},
+		{
+			name: "TLV is missing",
+			userInfo: TLVUserInfo{
+				TLVBlock: TLVBlock{
+					TLVList: TLVList{},
+				},
+			},
+			want: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			assert.Equal(t, tt.want, tt.userInfo.IsAway())
+		})
+	}
+}
+
+func TestTLVUserInfo_IsInvisible(t *testing.T) {
+	tests := []struct {
+		name     string
+		userInfo TLVUserInfo
+		want     bool
+	}{
+		{
+			name: "status mask has invisible bit set",
+			userInfo: TLVUserInfo{
+				TLVBlock: TLVBlock{
+					TLVList: TLVList{
+						NewTLVBE(OServiceUserInfoStatus, OServiceUserStatusInvisible),
+					},
+				},
+			},
+			want: true,
+		},
+		{
+			name: "status mask does not have invisible bit set",
+			userInfo: TLVUserInfo{
+				TLVBlock: TLVBlock{
+					TLVList: TLVList{
+						NewTLVBE(OServiceUserInfoStatus, OServiceUserStatusAvailable),
+					},
+				},
+			},
+			want: false,
+		},
+		{
+			name: "TLV is missing",
+			userInfo: TLVUserInfo{
+				TLVBlock: TLVBlock{
+					TLVList: TLVList{},
+				},
+			},
+			want: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			assert.Equal(t, tt.want, tt.userInfo.IsInvisible())
+		})
+	}
+}