Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 9a16801

Browse files
committed
Uniformize spam-checker API, part 3: Expand check_event_for_spam with the ability to return additional fields.
1 parent 92b87d5 commit 9a16801

File tree

3 files changed

+44
-23
lines changed

3 files changed

+44
-23
lines changed

synapse/api/errors.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,13 @@ class SynapseError(CodeMessageException):
139139
errcode: Matrix error code e.g 'M_FORBIDDEN'
140140
"""
141141

142-
def __init__(self, code: int, msg: str, errcode: str = Codes.UNKNOWN):
142+
def __init__(
143+
self,
144+
code: int,
145+
msg: str,
146+
errcode: str = Codes.UNKNOWN,
147+
additional_fields: Optional[Dict] = None,
148+
):
143149
"""Constructs a synapse error.
144150
145151
Args:
@@ -149,9 +155,13 @@ def __init__(self, code: int, msg: str, errcode: str = Codes.UNKNOWN):
149155
"""
150156
super().__init__(code, msg)
151157
self.errcode = errcode
158+
if additional_fields is None:
159+
self._additional_fields: Dict = {}
160+
else:
161+
self._additional_fields = dict(additional_fields)
152162

153163
def error_dict(self) -> "JsonDict":
154-
return cs_error(self.msg, self.errcode)
164+
return cs_error(self.msg, self.errcode, **self._additional_fields)
155165

156166

157167
class InvalidAPICallError(SynapseError):
@@ -176,14 +186,7 @@ def __init__(
176186
errcode: str = Codes.UNKNOWN,
177187
additional_fields: Optional[Dict] = None,
178188
):
179-
super().__init__(code, msg, errcode)
180-
if additional_fields is None:
181-
self._additional_fields: Dict = {}
182-
else:
183-
self._additional_fields = dict(additional_fields)
184-
185-
def error_dict(self) -> "JsonDict":
186-
return cs_error(self.msg, self.errcode, **self._additional_fields)
189+
super().__init__(code, msg, errcode, additional_fields)
187190

188191

189192
class ConsentNotGivenError(SynapseError):

synapse/events/spamcheck.py

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
Awaitable,
2222
Callable,
2323
Collection,
24+
Dict,
2425
List,
2526
Optional,
2627
Tuple,
@@ -42,15 +43,23 @@
4243
logger = logging.getLogger(__name__)
4344

4445

45-
# A boolean returned value, kept for backwards compatibility but deprecated.
46-
DEPRECATED_BOOL = bool
47-
48-
# A string returned value, kept for backwards compatibility but deprecated.
49-
DEPRECATED_STR = str
50-
5146
CHECK_EVENT_FOR_SPAM_CALLBACK = Callable[
5247
["synapse.events.EventBase"],
53-
Awaitable[Union[Allow, Codes, DEPRECATED_BOOL, DEPRECATED_STR]],
48+
Awaitable[
49+
Union[
50+
Allow,
51+
Codes,
52+
# Highly experimental, not officially part of the spamchecker API, may
53+
# disappear without warning depending on the results of ongoing
54+
# experiments.
55+
# Use this to return additional information as part of an error.
56+
Tuple[Codes, Dict],
57+
# Deprecated
58+
bool,
59+
# Deprecated
60+
str,
61+
]
62+
],
5463
]
5564
USER_MAY_JOIN_ROOM_CALLBACK = Callable[[str, str, bool], Awaitable[bool]]
5665
USER_MAY_INVITE_CALLBACK = Callable[[str, str, str], Awaitable[bool]]
@@ -252,7 +261,7 @@ def register_callbacks(
252261

253262
async def check_event_for_spam(
254263
self, event: "synapse.events.EventBase"
255-
) -> Union[Decision, str]:
264+
) -> Union[Decision, Tuple[Codes, Dict], str]:
256265
"""Checks if a given event is considered "spammy" by this server.
257266
258267
If the server considers an event spammy, then it will be rejected if
@@ -275,9 +284,9 @@ async def check_event_for_spam(
275284
with Measure(
276285
self.clock, "{}.{}".format(callback.__module__, callback.__qualname__)
277286
):
278-
res: Union[Decision, str, bool] = await delay_cancellation(
279-
callback(event)
280-
)
287+
res: Union[
288+
Decision, Tuple[Codes, Dict], str, bool
289+
] = await delay_cancellation(callback(event))
281290
if res is False or res is Allow.ALLOW:
282291
# This spam-checker accepts the event.
283292
# Other spam-checkers may reject it, though.
@@ -287,8 +296,9 @@ async def check_event_for_spam(
287296
# return value `True`
288297
return Codes.FORBIDDEN
289298
else:
290-
# This spam-checker rejects the event either with a `str`
291-
# or with a `Codes`. In either case, we stop here.
299+
# This spam-checker rejects the event either with a `str`,
300+
# with a `Codes` or with a `Tuple[Codes, Dict]`. In either
301+
# case, we stop here.
292302
return res
293303

294304
# No spam-checker has rejected the event, let it pass.

synapse/handlers/message.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,14 @@ async def create_and_send_nonmember_event(
888888

889889
spam_check = await self.spam_checker.check_event_for_spam(event)
890890
if spam_check is not synapse.spam_checker_api.Allow.ALLOW:
891+
if isinstance(spam_check, tuple):
892+
[code, dict] = spam_check
893+
raise SynapseError(
894+
403,
895+
"This message had been rejected as probable spam",
896+
code,
897+
dict,
898+
)
891899
raise SynapseError(
892900
403, "This message had been rejected as probable spam", spam_check
893901
)

0 commit comments

Comments
 (0)