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

Move Spam Checker callbacks to a dedicated file #15453

Merged
merged 4 commits into from
Apr 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/15453.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Move various module API callback registration methods to a dedicated class.
2 changes: 1 addition & 1 deletion synapse/app/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@
from synapse.config.server import ListenerConfig, ManholeConfig, TCPListenerConfig
from synapse.crypto import context_factory
from synapse.events.presence_router import load_legacy_presence_router
from synapse.events.spamcheck import load_legacy_spam_checkers
from synapse.events.third_party_rules import load_legacy_third_party_event_rules
from synapse.handlers.auth import load_legacy_password_auth_providers
from synapse.http.site import SynapseSite
Expand All @@ -73,6 +72,7 @@
from synapse.metrics import install_gc_manager, register_threadpool
from synapse.metrics.background_process_metrics import wrap_as_background_process
from synapse.metrics.jemalloc import setup_jemalloc_stats
from synapse.module_api.callbacks.spamchecker_callbacks import load_legacy_spam_checkers
from synapse.types import ISynapseReactor
from synapse.util import SYNAPSE_VERSION
from synapse.util.caches.lrucache import setup_expire_lru_cache_entries
Expand Down
6 changes: 3 additions & 3 deletions synapse/federation/federation_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __init__(self, hs: "HomeServer"):

self.server_name = hs.hostname
self.keyring = hs.get_keyring()
self.spam_checker = hs.get_spam_checker()
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
self.store = hs.get_datastores().main
self._clock = hs.get_clock()
self._storage_controllers = hs.get_storage_controllers()
Expand Down Expand Up @@ -137,9 +137,9 @@ async def _check_sigs_and_hash(
)
return redacted_event

spam_check = await self.spam_checker.check_event_for_spam(pdu)
spam_check = await self._spam_checker_module_callbacks.check_event_for_spam(pdu)

if spam_check != self.spam_checker.NOT_SPAM:
if spam_check != self._spam_checker_module_callbacks.NOT_SPAM:
logger.warning("Event contains spam, soft-failing %s", pdu.event_id)
log_kv(
{
Expand Down
8 changes: 5 additions & 3 deletions synapse/federation/federation_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def __init__(self, hs: "HomeServer"):
super().__init__(hs)

self.handler = hs.get_federation_handler()
self._spam_checker = hs.get_spam_checker()
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
self._federation_event_handler = hs.get_federation_event_handler()
self.state = hs.get_state_handler()
self._event_auth_handler = hs.get_event_auth_handler()
Expand Down Expand Up @@ -1129,7 +1129,7 @@ async def _handle_received_pdu(self, origin: str, pdu: EventBase) -> None:
logger.warning("event id %s: %s", pdu.event_id, e)
raise FederationError("ERROR", 403, str(e), affected=pdu.event_id)

if await self._spam_checker.should_drop_federated_event(pdu):
if await self._spam_checker_module_callbacks.should_drop_federated_event(pdu):
logger.warning(
"Unstaged federated event contains spam, dropping %s", pdu.event_id
)
Expand Down Expand Up @@ -1174,7 +1174,9 @@ async def _get_next_nonspam_staged_event_for_room(

origin, event = next

if await self._spam_checker.should_drop_federated_event(event):
if await self._spam_checker_module_callbacks.should_drop_federated_event(
event
):
logger.warning(
"Staged federated event contains spam, dropping %s",
event.event_id,
Expand Down
14 changes: 9 additions & 5 deletions synapse/handlers/directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def __init__(self, hs: "HomeServer"):
"directory", self.on_directory_query
)

self.spam_checker = hs.get_spam_checker()
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker

async def _create_association(
self,
Expand Down Expand Up @@ -145,10 +145,12 @@ async def create_association(
403, "You must be in the room to create an alias for it"
)

spam_check = await self.spam_checker.user_may_create_room_alias(
user_id, room_alias
spam_check = (
await self._spam_checker_module_callbacks.user_may_create_room_alias(
user_id, room_alias
)
)
if spam_check != self.spam_checker.NOT_SPAM:
if spam_check != self._spam_checker_module_callbacks.NOT_SPAM:
raise AuthError(
403,
"This user is not permitted to create this alias",
Expand Down Expand Up @@ -444,7 +446,9 @@ async def edit_published_room_list(
"""
user_id = requester.user.to_string()

spam_check = await self.spam_checker.user_may_publish_room(user_id, room_id)
spam_check = await self._spam_checker_module_callbacks.user_may_publish_room(
user_id, room_id
)
if spam_check != NOT_SPAM:
raise AuthError(
403,
Expand Down
4 changes: 2 additions & 2 deletions synapse/handlers/federation.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def __init__(self, hs: "HomeServer"):
self.server_name = hs.hostname
self.keyring = hs.get_keyring()
self.is_mine_id = hs.is_mine_id
self.spam_checker = hs.get_spam_checker()
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
self.event_creation_handler = hs.get_event_creation_handler()
self.event_builder_factory = hs.get_event_builder_factory()
self._event_auth_handler = hs.get_event_auth_handler()
Expand Down Expand Up @@ -1042,7 +1042,7 @@ async def on_invite_request(
if self.hs.config.server.block_non_admin_invites:
raise SynapseError(403, "This server does not accept room invites")

spam_check = await self.spam_checker.user_may_invite(
spam_check = await self._spam_checker_module_callbacks.user_may_invite(
event.sender, event.state_key, event.room_id
)
if spam_check != NOT_SPAM:
Expand Down
10 changes: 7 additions & 3 deletions synapse/handlers/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ def __init__(self, hs: "HomeServer"):

self._bulk_push_rule_evaluator = hs.get_bulk_push_rule_evaluator()

self.spam_checker = hs.get_spam_checker()
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
self.third_party_event_rules: "ThirdPartyEventRules" = (
self.hs.get_third_party_event_rules()
)
Expand Down Expand Up @@ -1035,8 +1035,12 @@ async def create_and_send_nonmember_event(
event.sender,
)

spam_check_result = await self.spam_checker.check_event_for_spam(event)
if spam_check_result != self.spam_checker.NOT_SPAM:
spam_check_result = (
await self._spam_checker_module_callbacks.check_event_for_spam(
event
)
)
if spam_check_result != self._spam_checker_module_callbacks.NOT_SPAM:
if isinstance(spam_check_result, tuple):
try:
[code, dict] = spam_check_result
Expand Down
4 changes: 2 additions & 2 deletions synapse/handlers/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def __init__(self, hs: "HomeServer"):
self._server_notices_mxid = hs.config.servernotices.server_notices_mxid
self._server_name = hs.hostname

self.spam_checker = hs.get_spam_checker()
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker

if hs.config.worker.worker_app:
self._register_client = ReplicationRegisterServlet.make_client(hs)
Expand Down Expand Up @@ -259,7 +259,7 @@ async def register_user(

await self.check_registration_ratelimit(address)

result = await self.spam_checker.check_registration_for_spam(
result = await self._spam_checker_module_callbacks.check_registration_for_spam(
threepid,
localpart,
user_agent_ips or [],
Expand Down
10 changes: 7 additions & 3 deletions synapse/handlers/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def __init__(self, hs: "HomeServer"):
self.auth_blocking = hs.get_auth_blocking()
self.clock = hs.get_clock()
self.hs = hs
self.spam_checker = hs.get_spam_checker()
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
self.event_creation_handler = hs.get_event_creation_handler()
self.room_member_handler = hs.get_room_member_handler()
self._event_auth_handler = hs.get_event_auth_handler()
Expand Down Expand Up @@ -449,7 +449,9 @@ async def clone_existing_room(
"""
user_id = requester.user.to_string()

spam_check = await self.spam_checker.user_may_create_room(user_id)
spam_check = await self._spam_checker_module_callbacks.user_may_create_room(
user_id
)
if spam_check != NOT_SPAM:
raise SynapseError(
403,
Expand Down Expand Up @@ -761,7 +763,9 @@ async def create_room(
)

if not is_requester_admin:
spam_check = await self.spam_checker.user_may_create_room(user_id)
spam_check = await self._spam_checker_module_callbacks.user_may_create_room(
user_id
)
if spam_check != NOT_SPAM:
raise SynapseError(
403,
Expand Down
22 changes: 13 additions & 9 deletions synapse/handlers/room_member.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def __init__(self, hs: "HomeServer"):
self.member_as_limiter = Linearizer(max_count=10, name="member_as_limiter")

self.clock = hs.get_clock()
self.spam_checker = hs.get_spam_checker()
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
self.third_party_event_rules = hs.get_third_party_event_rules()
self._server_notices_mxid = self.config.servernotices.server_notices_mxid
self._enable_lookup = hs.config.registration.enable_3pid_lookup
Expand Down Expand Up @@ -806,7 +806,7 @@ async def update_membership_locked(
)
block_invite_result = (Codes.FORBIDDEN, {})

spam_check = await self.spam_checker.user_may_invite(
spam_check = await self._spam_checker_module_callbacks.user_may_invite(
requester.user.to_string(), target_id, room_id
)
if spam_check != NOT_SPAM:
Expand Down Expand Up @@ -940,8 +940,10 @@ async def update_membership_locked(
# a room then they're allowed to join it.
and not new_room
):
spam_check = await self.spam_checker.user_may_join_room(
target.to_string(), room_id, is_invited=inviter is not None
spam_check = (
await self._spam_checker_module_callbacks.user_may_join_room(
target.to_string(), room_id, is_invited=inviter is not None
)
)
if spam_check != NOT_SPAM:
raise SynapseError(
Expand Down Expand Up @@ -1550,11 +1552,13 @@ async def do_3pid_invite(
)
else:
# Check if the spamchecker(s) allow this invite to go through.
spam_check = await self.spam_checker.user_may_send_3pid_invite(
inviter_userid=requester.user.to_string(),
medium=medium,
address=address,
room_id=room_id,
spam_check = (
await self._spam_checker_module_callbacks.user_may_send_3pid_invite(
inviter_userid=requester.user.to_string(),
medium=medium,
address=address,
room_id=room_id,
)
)
if spam_check != NOT_SPAM:
raise SynapseError(
Expand Down
6 changes: 4 additions & 2 deletions synapse/handlers/user_directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def __init__(self, hs: "HomeServer"):
self.is_mine_id = hs.is_mine_id
self.update_user_directory = hs.config.worker.should_update_user_directory
self.search_all_users = hs.config.userdirectory.user_directory_search_all_users
self.spam_checker = hs.get_spam_checker()
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
self._hs = hs

# The current position in the current_state_delta stream
Expand Down Expand Up @@ -149,7 +149,9 @@ async def search_users(
# Remove any spammy users from the results.
non_spammy_users = []
for user in results["results"]:
if not await self.spam_checker.check_username_for_spam(user):
if not await self._spam_checker_module_callbacks.check_username_for_spam(
user
):
non_spammy_users.append(user)
results["results"] = non_spammy_users

Expand Down
7 changes: 3 additions & 4 deletions synapse/media/media_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
from twisted.internet.interfaces import IConsumer
from twisted.protocols.basic import FileSender

import synapse
from synapse.api.errors import NotFoundError
from synapse.logging.context import defer_to_thread, make_deferred_yieldable
from synapse.util import Clock
Expand Down Expand Up @@ -74,7 +73,7 @@ def __init__(
self.local_media_directory = local_media_directory
self.filepaths = filepaths
self.storage_providers = storage_providers
self.spam_checker = hs.get_spam_checker()
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
self.clock = hs.get_clock()

async def store_file(self, source: IO, file_info: FileInfo) -> str:
Expand Down Expand Up @@ -145,10 +144,10 @@ async def finish() -> None:
f.flush()
f.close()

spam_check = await self.spam_checker.check_media_file_for_spam(
spam_check = await self._spam_checker_module_callbacks.check_media_file_for_spam(
ReadableFileWrapper(self.clock, fname), file_info
)
if spam_check != synapse.module_api.NOT_SPAM:
if spam_check != self._spam_checker_module_callbacks.NOT_SPAM:
logger.info("Blocking media due to spam checker")
# Note that we'll delete the stored media, due to the
# try/except below. The media also won't be stored in
Expand Down
33 changes: 16 additions & 17 deletions synapse/module_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,6 @@
GET_USERS_FOR_STATES_CALLBACK,
PresenceRouter,
)
from synapse.events.spamcheck import (
CHECK_EVENT_FOR_SPAM_CALLBACK,
CHECK_MEDIA_FILE_FOR_SPAM_CALLBACK,
CHECK_REGISTRATION_FOR_SPAM_CALLBACK,
CHECK_USERNAME_FOR_SPAM_CALLBACK,
SHOULD_DROP_FEDERATED_EVENT_CALLBACK,
USER_MAY_CREATE_ROOM_ALIAS_CALLBACK,
USER_MAY_CREATE_ROOM_CALLBACK,
USER_MAY_INVITE_CALLBACK,
USER_MAY_JOIN_ROOM_CALLBACK,
USER_MAY_PUBLISH_ROOM_CALLBACK,
USER_MAY_SEND_3PID_INVITE_CALLBACK,
SpamChecker,
)
from synapse.events.third_party_rules import (
CHECK_CAN_DEACTIVATE_USER_CALLBACK,
CHECK_CAN_SHUTDOWN_ROOM_CALLBACK,
Expand Down Expand Up @@ -105,6 +91,20 @@
ON_LEGACY_SEND_MAIL_CALLBACK,
ON_USER_REGISTRATION_CALLBACK,
)
from synapse.module_api.callbacks.spamchecker_callbacks import (
CHECK_EVENT_FOR_SPAM_CALLBACK,
CHECK_MEDIA_FILE_FOR_SPAM_CALLBACK,
CHECK_REGISTRATION_FOR_SPAM_CALLBACK,
CHECK_USERNAME_FOR_SPAM_CALLBACK,
SHOULD_DROP_FEDERATED_EVENT_CALLBACK,
USER_MAY_CREATE_ROOM_ALIAS_CALLBACK,
USER_MAY_CREATE_ROOM_CALLBACK,
USER_MAY_INVITE_CALLBACK,
USER_MAY_JOIN_ROOM_CALLBACK,
USER_MAY_PUBLISH_ROOM_CALLBACK,
USER_MAY_SEND_3PID_INVITE_CALLBACK,
SpamCheckerModuleApiCallbacks,
)
from synapse.rest.client.login import LoginResponse
from synapse.storage import DataStore
from synapse.storage.background_updates import (
Expand Down Expand Up @@ -147,7 +147,7 @@
"""

PRESENCE_ALL_USERS = PresenceRouter.ALL_USERS
NOT_SPAM = SpamChecker.NOT_SPAM
NOT_SPAM = SpamCheckerModuleApiCallbacks.NOT_SPAM

__all__ = [
"errors",
Expand Down Expand Up @@ -271,7 +271,6 @@ def __init__(self, hs: "HomeServer", auth_handler: AuthHandler) -> None:
self._public_room_list_manager = PublicRoomListManager(hs)
self._account_data_manager = AccountDataManager(hs)

self._spam_checker = hs.get_spam_checker()
self._third_party_event_rules = hs.get_third_party_event_rules()
self._password_auth_provider = hs.get_password_auth_provider()
self._presence_router = hs.get_presence_router()
Expand Down Expand Up @@ -305,7 +304,7 @@ def register_spam_checker_callbacks(

Added in Synapse v1.37.0.
"""
return self._spam_checker.register_callbacks(
return self._callbacks.spam_checker.register_callbacks(
check_event_for_spam=check_event_for_spam,
should_drop_federated_event=should_drop_federated_event,
user_may_join_room=user_may_join_room,
Expand Down
11 changes: 10 additions & 1 deletion synapse/module_api/callbacks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,20 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import TYPE_CHECKING

if TYPE_CHECKING:
from synapse.server import HomeServer

from synapse.module_api.callbacks.account_validity_callbacks import (
AccountValidityModuleApiCallbacks,
)
from synapse.module_api.callbacks.spamchecker_callbacks import (
SpamCheckerModuleApiCallbacks,
)


class ModuleApiCallbacks:
def __init__(self) -> None:
def __init__(self, hs: "HomeServer") -> None:
self.account_validity = AccountValidityModuleApiCallbacks()
self.spam_checker = SpamCheckerModuleApiCallbacks(hs)
Original file line number Diff line number Diff line change
Expand Up @@ -286,11 +286,10 @@ def run(*args: Any, **kwargs: Any) -> Awaitable:
api.register_spam_checker_callbacks(**hooks)


class SpamChecker:
class SpamCheckerModuleApiCallbacks:
NOT_SPAM: Literal["NOT_SPAM"] = "NOT_SPAM"

def __init__(self, hs: "synapse.server.HomeServer") -> None:
self.hs = hs
self.clock = hs.get_clock()

self._check_event_for_spam_callbacks: List[CHECK_EVENT_FOR_SPAM_CALLBACK] = []
Expand Down
Loading