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

Commit

Permalink
Converge with mainline
Browse files Browse the repository at this point in the history
Bring other callbacks to party with mainline, and fixup code calling to
the various callbacks.
  • Loading branch information
babolivier committed Oct 26, 2021
1 parent dfcb52c commit c9c1bed
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 129 deletions.
107 changes: 23 additions & 84 deletions synapse/events/spamcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,14 @@
Awaitable[bool],
]

def load_legacy_spam_checkers(hs: "synapse.server.HomeServer"):

def load_legacy_spam_checkers(hs: "synapse.server.HomeServer") -> None:
"""Wrapper that loads spam checkers configured using the old configuration, and
registers the spam checker hooks they implement.
"""
spam_checkers: List[Any] = []
api = hs.get_module_api()
for module, config in hs.config.spam_checkers:
for module, config in hs.config.spamchecker.spam_checkers:
# Older spam checkers don't accept the `api` argument, so we
# try and detect support.
spam_args = inspect.getfullargspec(module)
Expand All @@ -102,7 +103,6 @@ def load_legacy_spam_checkers(hs: "synapse.server.HomeServer"):
"check_username_for_spam",
"check_registration_for_spam",
"check_media_file_for_spam",
"user_may_join_room",
}

for spam_checker in spam_checkers:
Expand All @@ -129,9 +129,9 @@ def wrapper(
request_info: Collection[Tuple[str, str]],
auth_provider_id: Optional[str],
) -> Union[Awaitable[RegistrationBehaviour], RegistrationBehaviour]:
# We've already made sure f is not None above, but mypy doesn't
# do well across function boundaries so we need to tell it f is
# definitely not None.
# Assertion required because mypy can't prove we won't
# change `f` back to `None`. See
# https://mypy.readthedocs.io/en/latest/common_issues.html#narrowing-and-inner-functions
assert f is not None

return f(
Expand All @@ -146,9 +146,10 @@ def wrapper(
"Bad signature for callback check_registration_for_spam",
)

def run(*args, **kwargs):
# mypy doesn't do well across function boundaries so we need to tell it
# wrapped_func is definitely not None.
def run(*args: Any, **kwargs: Any) -> Awaitable:
# Assertion required because mypy can't prove we won't change `f`
# back to `None`. See
# https://mypy.readthedocs.io/en/latest/common_issues.html#narrowing-and-inner-functions
assert wrapped_func is not None

return maybe_awaitable(wrapped_func(*args, **kwargs))
Expand All @@ -165,7 +166,7 @@ def run(*args, **kwargs):


class SpamChecker:
def __init__(self):
def __init__(self) -> None:
self._check_event_for_spam_callbacks: List[CHECK_EVENT_FOR_SPAM_CALLBACK] = []
self._user_may_join_room_callbacks: List[USER_MAY_JOIN_ROOM_CALLBACK] = []
self._user_may_invite_callbacks: List[USER_MAY_INVITE_CALLBACK] = []
Expand All @@ -189,7 +190,6 @@ def __init__(self):
self._check_media_file_for_spam_callbacks: List[
CHECK_MEDIA_FILE_FOR_SPAM_CALLBACK
] = []
self._user_may_join_room_callbacks: List[USER_MAY_JOIN_ROOM_CALLBACK] = []

def register_callbacks(
self,
Expand All @@ -210,7 +210,7 @@ def register_callbacks(
CHECK_REGISTRATION_FOR_SPAM_CALLBACK
] = None,
check_media_file_for_spam: Optional[CHECK_MEDIA_FILE_FOR_SPAM_CALLBACK] = None,
):
) -> None:
"""Register callbacks from module for each hook."""
if check_event_for_spam is not None:
self._check_event_for_spam_callbacks.append(check_event_for_spam)
Expand Down Expand Up @@ -253,9 +253,6 @@ def register_callbacks(
if check_media_file_for_spam is not None:
self._check_media_file_for_spam_callbacks.append(check_media_file_for_spam)

if user_may_join_room is not None:
self._user_may_join_room_callbacks.append(user_may_join_room)

async def check_event_for_spam(
self, event: "synapse.events.EventBase"
) -> Union[bool, str]:
Expand All @@ -279,7 +276,9 @@ async def check_event_for_spam(

return False

async def user_may_join_room(self, user_id: str, room_id: str, is_invited: bool):
async def user_may_join_room(
self, user_id: str, room_id: str, is_invited: bool
) -> bool:
"""Checks if a given users is allowed to join a room.
Not called when a user creates a room.
Expand All @@ -289,7 +288,7 @@ async def user_may_join_room(self, user_id: str, room_id: str, is_invited: bool)
is_invited: Whether the user is invited into the room
Returns:
bool: Whether the user may join the room
Whether the user may join the room
"""
for callback in self._user_may_join_room_callbacks:
if await callback(user_id, room_id, is_invited) is False:
Expand All @@ -298,48 +297,22 @@ async def user_may_join_room(self, user_id: str, room_id: str, is_invited: bool)
return True

async def user_may_invite(
self,
inviter_userid: str,
invitee_userid: Optional[str],
third_party_invite: Optional[Dict],
room_id: str,
new_room: bool,
published_room: bool,
self, inviter_userid: str, invitee_userid: str, room_id: str
) -> bool:
"""Checks if a given user may send an invite
If this method returns false, the invite will be rejected.
Args:
inviter_userid:
invitee_userid: The user ID of the invitee. Is None
if this is a third party invite and the 3PID is not bound to a
user ID.
third_party_invite: If a third party invite then is a
dict containing the medium and address of the invitee.
room_id:
new_room: Whether the user is being invited to the room as
part of a room creation, if so the invitee would have been
included in the call to `user_may_create_room`.
published_room: Whether the room the user is being invited
to has been published in the local homeserver's public room
directory.
inviter_userid: The user ID of the sender of the invitation
invitee_userid: The user ID targeted in the invitation
room_id: The room ID
Returns:
True if the user may send an invite, otherwise False
"""
for callback in self._user_may_invite_callbacks:
if (
await callback(
inviter_userid,
invitee_userid,
third_party_invite,
room_id,
new_room,
published_room,
)
is False
):
if await callback(inviter_userid, invitee_userid, room_id) is False:
return False

return True
Expand Down Expand Up @@ -369,34 +342,19 @@ async def user_may_send_3pid_invite(

return True

async def user_may_create_room(
self,
userid: str,
invite_list: List[str],
third_party_invite_list: List[Dict],
cloning: bool,
) -> bool:
async def user_may_create_room(self, userid: str) -> bool:
"""Checks if a given user may create a room
If this method returns false, the creation request will be rejected.
Args:
userid: The ID of the user attempting to create a room
invite_list: List of user IDs that would be invited to
the new room.
third_party_invite_list: List of third party invites
for the new room.
cloning: Whether the user is cloning an existing room, e.g.
upgrading a room.
Returns:
True if the user may create a room, otherwise False
"""
for callback in self._user_may_create_room_callbacks:
if (
await callback(userid, invite_list, third_party_invite_list, cloning)
is False
):
if await callback(userid) is False:
return False

return True
Expand Down Expand Up @@ -467,25 +425,6 @@ async def user_may_publish_room(self, userid: str, room_id: str) -> bool:

return True

async def user_may_join_room(self, userid: str, room_id: str, is_invited: bool):
"""Checks if a given users is allowed to join a room.
Not called when a user creates a room.
Args:
userid:
room_id:
is_invited: Whether the user is invited into the room
Returns:
bool: Whether the user may join the room
"""
for callback in self._user_may_join_room_callbacks:
if await callback(userid, room_id, is_invited) is False:
return False

return True

async def check_username_for_spam(self, user_profile: Dict[str, str]) -> bool:
"""Checks if a user ID or display name are considered "spammy" by this server.
Expand Down
9 changes: 1 addition & 8 deletions synapse/handlers/federation.py
Original file line number Diff line number Diff line change
Expand Up @@ -1893,15 +1893,8 @@ async def on_invite_request(
if self.hs.config.block_non_admin_invites:
raise SynapseError(403, "This server does not accept room invites")

is_published = await self.store.is_room_published(event.room_id)

if not await self.spam_checker.user_may_invite(
event.sender,
event.state_key,
None,
room_id=event.room_id,
new_room=False,
published_room=is_published,
event.sender, event.state_key, event.room_id
):
raise SynapseError(
403, "This user is not permitted to send invites to this server/user"
Expand Down
15 changes: 1 addition & 14 deletions synapse/handlers/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,19 +374,7 @@ async def clone_existing_room(
"""
user_id = requester.user.to_string()

if (
self._server_notices_mxid is not None
and requester.user.to_string() == self._server_notices_mxid
):
# allow the server notices mxid to create rooms
is_requester_admin = True

else:
is_requester_admin = await self.auth.is_server_admin(requester.user)

if not is_requester_admin and not await self.spam_checker.user_may_create_room(
user_id, invite_list=[], third_party_invite_list=[], cloning=True
):
if not await self.spam_checker.user_may_create_room(user_id):
raise SynapseError(403, "You are not permitted to create rooms")

creation_content: JsonDict = {
Expand Down Expand Up @@ -861,7 +849,6 @@ async def create_room(
id_server,
requester,
txn_id=None,
new_room=True,
id_access_token=id_access_token,
)

Expand Down
23 changes: 1 addition & 22 deletions synapse/handlers/room_member.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,15 +614,8 @@ async def update_membership_locked(
)
block_invite = True

is_published = await self.store.is_room_published(room_id)

if not await self.spam_checker.user_may_invite(
requester.user.to_string(),
target_id,
third_party_invite=None,
room_id=room_id,
new_room=new_room,
published_room=is_published,
requester.user.to_string(), target_id, room_id
):
logger.info("Blocking invite due to spam checker")
block_invite = True
Expand Down Expand Up @@ -1170,7 +1163,6 @@ async def do_3pid_invite(
id_server: str,
requester: Requester,
txn_id: Optional[str],
new_room: bool = False,
id_access_token: Optional[str] = None,
) -> int:
"""Invite a 3PID to a room.
Expand Down Expand Up @@ -1237,19 +1229,6 @@ async def do_3pid_invite(
id_server, medium, address, id_access_token
)

is_published = await self.store.is_room_published(room_id)

if not await self.spam_checker.user_may_invite(
requester.user.to_string(),
invitee,
third_party_invite={"medium": medium, "address": address},
room_id=room_id,
new_room=new_room,
published_room=is_published,
):
logger.info("Blocking invite due to spam checker")
raise SynapseError(403, "Invites have been disabled on this server")

if invitee:
# Note that update_membership with an action of "invite" can raise
# a ShadowBanError, but this was done above already.
Expand Down
1 change: 0 additions & 1 deletion synapse/rest/client/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,6 @@ async def on_POST(self, request, room_id, membership_action, txn_id=None):
content["id_server"],
requester,
txn_id,
new_room=False,
id_access_token=content.get("id_access_token"),
)
except ShadowBanError:
Expand Down

0 comments on commit c9c1bed

Please sign in to comment.