diff --git a/synapse/events/spamcheck.py b/synapse/events/spamcheck.py
index 7984874e21..1048b4c825 100644
--- a/synapse/events/spamcheck.py
+++ b/synapse/events/spamcheck.py
@@ -30,7 +30,7 @@ from typing import (
from synapse.api.errors import Codes
from synapse.rest.media.v1._base import FileInfo
from synapse.rest.media.v1.media_storage import ReadableFileWrapper
-from synapse.spam_checker_api import Allow, Decision, RegistrationBehaviour
+from synapse.spam_checker_api import RegistrationBehaviour
from synapse.types import RoomAlias, UserProfile
from synapse.util.async_helpers import delay_cancellation, maybe_awaitable
from synapse.util.metrics import Measure
@@ -46,12 +46,9 @@ CHECK_EVENT_FOR_SPAM_CALLBACK = Callable[
["synapse.events.EventBase"],
Awaitable[
Union[
- Allow,
- Codes,
+ str,
# Deprecated
bool,
- # Deprecated
- str,
]
],
]
@@ -178,6 +175,8 @@ def load_legacy_spam_checkers(hs: "synapse.server.HomeServer") -> None:
class SpamChecker:
+ NOT_SPAM = "NOT_SPAM"
+
def __init__(self, hs: "synapse.server.HomeServer") -> None:
self.hs = hs
self.clock = hs.get_clock()
@@ -268,9 +267,7 @@ class SpamChecker:
if check_media_file_for_spam is not None:
self._check_media_file_for_spam_callbacks.append(check_media_file_for_spam)
- async def check_event_for_spam(
- self, event: "synapse.events.EventBase"
- ) -> Union[Decision, str]:
+ async def check_event_for_spam(self, event: "synapse.events.EventBase") -> str:
"""Checks if a given event is considered "spammy" by this server.
If the server considers an event spammy, then it will be rejected if
@@ -281,22 +278,20 @@ class SpamChecker:
event: the event to be checked
Returns:
- - on `ALLOW`, the event is considered good (non-spammy) and should
- be let through. Other spamcheck filters may still reject it.
- - on `Code`, the event is considered spammy and is rejected with a specific
+ - `NOT_SPAM` if the event is considered good (non-spammy) and should be let
+ through. Other spamcheck filters may still reject it.
+ - A `Code` if the event is considered spammy and is rejected with a specific
error message/code.
- - on `str`, the event is considered spammy and the string is used as error
- message. This usage is generally discouraged as it doesn't support
- internationalization.
+ - A string that isn't `NOT_SPAM` if the event is considered spammy and the
+ string should be used as the client-facing error message. This usage is
+ generally discouraged as it doesn't support internationalization.
"""
for callback in self._check_event_for_spam_callbacks:
with Measure(
self.clock, "{}.{}".format(callback.__module__, callback.__qualname__)
):
- res: Union[Decision, str, bool] = await delay_cancellation(
- callback(event)
- )
- if res is False or res is Allow.ALLOW:
+ res = await delay_cancellation(callback(event))
+ if res is False or res == self.NOT_SPAM:
# This spam-checker accepts the event.
# Other spam-checkers may reject it, though.
continue
@@ -304,13 +299,23 @@ class SpamChecker:
# This spam-checker rejects the event with deprecated
# return value `True`
return Codes.FORBIDDEN
+ elif not isinstance(res, str):
+ # mypy complains that we can't reach this code because of the
+ # return type in CHECK_EVENT_FOR_SPAM_CALLBACK, but we don't know
+ # for sure that the module actually returns it.
+ logger.warning( # type: ignore[unreachable]
+ "Module returned invalid value, rejecting message as spam"
+ )
+ res = "This message has been rejected as probable spam"
else:
- # This spam-checker rejects the event either with a `str`
- # or with a `Codes`. In either case, we stop here.
- return res
+ # The module rejected the event either with a `Codes`
+ # or some other `str`. In either case, we stop here.
+ pass
+
+ return res
# No spam-checker has rejected the event, let it pass.
- return Allow.ALLOW
+ return self.NOT_SPAM
async def should_drop_federated_event(
self, event: "synapse.events.EventBase"
|