diff --git a/synapse/events/spamcheck.py b/synapse/events/spamcheck.py
index 61bcbe2abe..7984874e21 100644
--- a/synapse/events/spamcheck.py
+++ b/synapse/events/spamcheck.py
@@ -27,9 +27,10 @@ from typing import (
Union,
)
+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 RegistrationBehaviour
+from synapse.spam_checker_api import Allow, Decision, RegistrationBehaviour
from synapse.types import RoomAlias, UserProfile
from synapse.util.async_helpers import delay_cancellation, maybe_awaitable
from synapse.util.metrics import Measure
@@ -40,9 +41,19 @@ if TYPE_CHECKING:
logger = logging.getLogger(__name__)
+
CHECK_EVENT_FOR_SPAM_CALLBACK = Callable[
["synapse.events.EventBase"],
- Awaitable[Union[bool, str]],
+ Awaitable[
+ Union[
+ Allow,
+ Codes,
+ # Deprecated
+ bool,
+ # Deprecated
+ str,
+ ]
+ ],
]
SHOULD_DROP_FEDERATED_EVENT_CALLBACK = Callable[
["synapse.events.EventBase"],
@@ -259,7 +270,7 @@ class SpamChecker:
async def check_event_for_spam(
self, event: "synapse.events.EventBase"
- ) -> Union[bool, str]:
+ ) -> Union[Decision, 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
@@ -270,18 +281,36 @@ class SpamChecker:
event: the event to be checked
Returns:
- True or a string if the event is spammy. If a string is returned it
- will be used as the error message returned to the user.
+ - 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
+ 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.
"""
for callback in self._check_event_for_spam_callbacks:
with Measure(
self.clock, "{}.{}".format(callback.__module__, callback.__qualname__)
):
- res: Union[bool, str] = await delay_cancellation(callback(event))
- if res:
- return res
-
- return False
+ res: Union[Decision, str, bool] = await delay_cancellation(
+ callback(event)
+ )
+ if res is False or res is Allow.ALLOW:
+ # This spam-checker accepts the event.
+ # Other spam-checkers may reject it, though.
+ continue
+ elif res is True:
+ # This spam-checker rejects the event with deprecated
+ # return value `True`
+ return Codes.FORBIDDEN
+ else:
+ # This spam-checker rejects the event either with a `str`
+ # or with a `Codes`. In either case, we stop here.
+ return res
+
+ # No spam-checker has rejected the event, let it pass.
+ return Allow.ALLOW
async def should_drop_federated_event(
self, event: "synapse.events.EventBase"
|