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

Commit

Permalink
Extend ModuleApi with the methods we'll need to reject spam based on …
Browse files Browse the repository at this point in the history
…IP - resolves #10832

Signed-off-by: David Teller <davidt@element.io>
  • Loading branch information
Yoric committed Sep 16, 2021
1 parent 3eba047 commit 229eefe
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 1 deletion.
1 change: 1 addition & 0 deletions changelog.d/10833.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Extend the ModuleApi to let plug-ins check whether an ID is local and to access IP + User Agent data.
49 changes: 48 additions & 1 deletion synapse/module_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
)

import jinja2
from typing_extensions import TypedDict

from twisted.internet import defer
from twisted.web.resource import IResource
Expand All @@ -46,7 +47,14 @@
from synapse.storage.database import DatabasePool, LoggingTransaction
from synapse.storage.databases.main.roommember import ProfileInfo
from synapse.storage.state import StateFilter
from synapse.types import JsonDict, Requester, UserID, UserInfo, create_requester
from synapse.types import (
DomainSpecificString,
JsonDict,
Requester,
UserID,
UserInfo,
create_requester,
)
from synapse.util import Clock
from synapse.util.caches.descriptors import cached

Expand Down Expand Up @@ -79,6 +87,13 @@
logger = logging.getLogger(__name__)


class UserIpAndAgent(TypedDict):
ip: str
user_agent: str
# The time at which this user agent/ip was last seen.
last_seen: int


class ModuleApi:
"""A proxy object that gets passed to various plugin modules so they
can register new users etc if necessary.
Expand Down Expand Up @@ -700,6 +715,38 @@ def read_templates(
(td for td in (self.custom_template_dir, custom_template_directory) if td),
)

def ts(self) -> int:
"""Return a timestamp for the current time, in milliseconds since the epoch"""
return self._hs.get_clock().time_msec()

def is_mine(self, domain_specific_string: DomainSpecificString) -> bool:
"""Checks whether an ID comes from this homeserver."""
return self._hs.is_mine(domain_specific_string)

def is_mine_id(self, string: str) -> bool:
"""Checks whether an ID comes from this homeserver."""
return string.split(":", 1)[1] == self._server_name

async def get_user_ip_and_agents(
self, user: UserID, since_ts: Optional[int] = None
) -> List[UserIpAndAgent]:
"""
Return the list of user IPs and agents for a user.
Only useful for local users.
"""
raw_data = await self._store.get_user_ip_and_agents(user)
# Sanitize some of the data. We don't want to return tokens.
return [
{
"ip": str(data["ip"]),
"user_agent": str(data["user_agent"]),
"last_seen": int(data["last_seen"]),
}
for data in raw_data
if since_ts is None or int(data["last_seen"]) >= since_ts
]


class PublicRoomListManager:
"""Contains methods for adding to, removing from and querying whether a room
Expand Down
13 changes: 13 additions & 0 deletions tests/module_api/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,19 @@ def test_get_userinfo_by_id__no_user_found(self):
found_user = self.get_success(self.module_api.get_userinfo_by_id("@alice:test"))
self.assertIsNone(found_user)

def test_get_user_ip_and_agents(self):
user_id = self.register_user("test_get_user_ip_and_agents_user", "1234")
info = self.get_success(self.module_api.get_user_ip_and_agents(user_id))
self.assertIdentical(info, [])

def test_get_user_ip_and_agents__no_user_found(self):
info = self.get_success(
self.module_api.get_user_ip_and_agents(
"@test_get_user_ip_and_agents_user_nonexistent"
)
)
self.assertIdentical(info, [])

def test_sending_events_into_room(self):
"""Tests that a module can send events into a room"""
# Mock out create_and_send_nonmember_event to check whether events are being sent
Expand Down

0 comments on commit 229eefe

Please sign in to comment.