|
33 | 33 | EventTypes, |
34 | 34 | EventUnsignedContentFields, |
35 | 35 | HistoryVisibility, |
| 36 | + JoinRules, |
36 | 37 | Membership, |
37 | 38 | ) |
38 | 39 | from synapse.events import EventBase |
@@ -111,7 +112,17 @@ async def filter_events_for_client( |
111 | 112 | # happen within the function. |
112 | 113 | events_before_filtering = events.copy() |
113 | 114 | # Default case is to *exclude* soft-failed events |
114 | | - events = [e for e in events if not e.internal_metadata.is_soft_failed()] |
| 115 | + events = [] |
| 116 | + found_call_invite = False |
| 117 | + for event in events_before_filtering: |
| 118 | + if event.internal_metadata.is_soft_failed(): |
| 119 | + continue |
| 120 | + |
| 121 | + if event.type == EventTypes.CallInvite and not event.is_state(): |
| 122 | + found_call_invite = True |
| 123 | + |
| 124 | + events.append(event) |
| 125 | + |
115 | 126 | client_config = await storage.main.get_admin_client_config_for_user(user_id) |
116 | 127 | if filter_send_to_client and await storage.main.is_server_admin(user_id): |
117 | 128 | if client_config.return_soft_failed_events: |
@@ -139,7 +150,11 @@ async def filter_events_for_client( |
139 | 150 | [event.event_id for event in events], |
140 | 151 | ) |
141 | 152 |
|
142 | | - types = (_HISTORY_VIS_KEY, (EventTypes.Member, user_id)) |
| 153 | + types = [_HISTORY_VIS_KEY, (EventTypes.Member, user_id)] |
| 154 | + if found_call_invite: |
| 155 | + # We need to fetch the room's join rules state to determine |
| 156 | + # whether to allow call invites in public rooms. |
| 157 | + types.append((EventTypes.JoinRules, "")) |
143 | 158 |
|
144 | 159 | # we exclude outliers at this point, and then handle them separately later |
145 | 160 | event_id_to_state = await storage.state.get_state_for_events( |
@@ -178,6 +193,25 @@ def allowed(event: EventBase) -> EventBase | None: |
178 | 193 | if filtered is None: |
179 | 194 | return None |
180 | 195 |
|
| 196 | + # Filter out call invites in public rooms, as this would potentially |
| 197 | + # ring a lot of users. |
| 198 | + if event.type == EventTypes.CallInvite and not event.is_state(): |
| 199 | + # `state_after_event` should only be None if the event is an outlier, |
| 200 | + # and earlier code should filter out outliers entirely. |
| 201 | + # |
| 202 | + # In addition, we only create outliers locally for out-of-band |
| 203 | + # invite rejections, invites received over federation, or state |
| 204 | + # events needed to authorise other events. None of this applies to |
| 205 | + # call invites. |
| 206 | + assert state_after_event is not None |
| 207 | + |
| 208 | + room_join_rules = state_after_event.get((EventTypes.JoinRules, "")) |
| 209 | + if ( |
| 210 | + room_join_rules is not None |
| 211 | + and room_join_rules.content.get("join_rule") == JoinRules.PUBLIC |
| 212 | + ): |
| 213 | + return None |
| 214 | + |
181 | 215 | # Annotate the event with the user's membership after the event. |
182 | 216 | # |
183 | 217 | # Normally we just look in `state_after_event`, but if the event is an outlier |
|
0 commit comments