diff --git a/synapse/handlers/federation.py b/synapse/handlers/federation.py
index a3bb864bb2..9848534120 100644
--- a/synapse/handlers/federation.py
+++ b/synapse/handlers/federation.py
@@ -48,13 +48,14 @@ from synapse.crypto.event_signing import (
compute_event_signature,
)
from synapse.events.validator import EventValidator
+from synapse.metrics.background_process_metrics import run_as_background_process
from synapse.replication.http.federation import (
ReplicationCleanRoomRestServlet,
ReplicationFederationSendEventsRestServlet,
)
from synapse.replication.http.membership import ReplicationUserJoinedLeftRoomRestServlet
from synapse.state import StateResolutionStore, resolve_events_with_store
-from synapse.types import UserID, get_domain_from_id
+from synapse.types import UserID, get_domain_from_id, create_requester
from synapse.util import logcontext, unwrapFirstError
from synapse.util.async_helpers import Linearizer
from synapse.util.distributor import user_joined_room
@@ -105,6 +106,7 @@ class FederationHandler(BaseHandler):
self.hs = hs
+ self.clock = hs.get_clock()
self.store = hs.get_datastore() # type: synapse.storage.DataStore
self.federation_client = hs.get_federation_client()
self.state_handler = hs.get_state_handler()
@@ -1300,9 +1302,39 @@ class FederationHandler(BaseHandler):
context = yield self.state_handler.compute_event_context(event)
yield self.persist_events_and_notify([(event, context)])
+ sender = UserID.from_string(event.sender)
+ target = UserID.from_string(event.state_key)
+ if (sender.localpart == target.localpart):
+ run_as_background_process(
+ "_auto_accept_invite",
+ self._auto_accept_invite,
+ sender, target, event.room_id,
+ )
+
defer.returnValue(event)
@defer.inlineCallbacks
+ def _auto_accept_invite(self, sender, target, room_id):
+ joined = False
+ for attempt in range(0, 10):
+ try:
+ yield self.hs.get_room_member_handler().update_membership(
+ requester=create_requester(target.to_string()),
+ target=target,
+ room_id=room_id,
+ action="join",
+ )
+ joined = True
+ break
+ except Exception:
+ # We're going to retry, but we should log the error
+ logger.exception("Error auto-accepting invite on attempt %d" % attempt)
+ yield self.clock.sleep(1)
+ if not joined:
+ logger.error("Giving up on trying to auto-accept invite: too many attempts")
+
+
+ @defer.inlineCallbacks
def do_remotely_reject_invite(self, target_hosts, room_id, user_id):
origin, event = yield self._make_and_verify_event(
target_hosts,
diff --git a/synapse/handlers/room_member.py b/synapse/handlers/room_member.py
index 07fd3e82fc..147f8e1789 100644
--- a/synapse/handlers/room_member.py
+++ b/synapse/handlers/room_member.py
@@ -29,7 +29,8 @@ import synapse.server
import synapse.types
from synapse.api.constants import EventTypes, Membership
from synapse.api.errors import AuthError, Codes, SynapseError
-from synapse.types import RoomID, UserID
+from synapse.types import RoomID, UserID, RoomAlias
+from synapse.util import logcontext
from synapse.util.async_helpers import Linearizer
from synapse.util.distributor import user_joined_room, user_left_room
@@ -416,6 +417,10 @@ class RoomMemberHandler(object):
ret = yield self._remote_join(
requester, remote_room_hosts, room_id, target, content
)
+ logcontext.run_in_background(
+ self._send_merged_user_invites,
+ requester, room_id,
+ )
defer.returnValue(ret)
elif effective_membership_state == Membership.LEAVE:
@@ -450,9 +455,42 @@ class RoomMemberHandler(object):
prev_events_and_hashes=prev_events_and_hashes,
content=content,
)
+ if effective_membership_state == Membership.JOIN:
+ logcontext.run_in_background(
+ self._send_merged_user_invites,
+ requester, room_id,
+ )
defer.returnValue(res)
@defer.inlineCallbacks
+ def _send_merged_user_invites(self, requester, room_id):
+ profile_alias = "#_profile_" + requester.user.localpart + ":" + self.hs.hostname
+ profile_alias = RoomAlias.from_string(profile_alias)
+ profile_room_id, remote_room_hosts = yield self.lookup_room_alias(profile_alias)
+ if profile_room_id:
+ linked_accounts = yield self.state_handler.get_current_state(
+ room_id=profile_room_id.to_string(),
+ event_type="m.linked_accounts",
+ state_key="",
+ )
+ if not linked_accounts or not linked_accounts.content['all_children']:
+ return
+ for child_id in linked_accounts.content['all_children']:
+ child = UserID.from_string(child_id)
+ if self.hs.is_mine(child) or child_id == requester.user.to_string():
+ # TODO: Handle auto-invite for local users (not a priority)
+ continue
+ try:
+ yield self.update_membership(
+ requester=requester,
+ target=child,
+ room_id=room_id,
+ action="invite",
+ )
+ except Exception:
+ logger.exception("Failed to invite %s to %s" % (child_id, room_id))
+
+ @defer.inlineCallbacks
def send_membership_event(
self,
requester,
|