Respond to federated invite with non-empty context
Currently, we magically perform an extra database hit to find the inviter, and use this to guess where we should send the event. Instead, fill in a valid context, so that other callers relying on the context actually have one.
This commit is contained in:
parent
6605adf669
commit
a4e278bfe7
|
@ -147,7 +147,7 @@ class BaseHandler(object):
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def _create_new_client_event(self, builder):
|
def _create_new_client_event(self, builder):
|
||||||
latest_ret = yield self.store.get_latest_events_in_room(
|
latest_ret = yield self.store.get_latest_event_ids_and_hashes_in_room(
|
||||||
builder.room_id,
|
builder.room_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -156,7 +156,10 @@ class BaseHandler(object):
|
||||||
else:
|
else:
|
||||||
depth = 1
|
depth = 1
|
||||||
|
|
||||||
prev_events = [(e, h) for e, h, _ in latest_ret]
|
prev_events = [
|
||||||
|
(event_id, prev_hashes)
|
||||||
|
for event_id, prev_hashes, _ in latest_ret
|
||||||
|
]
|
||||||
|
|
||||||
builder.prev_events = prev_events
|
builder.prev_events = prev_events
|
||||||
builder.depth = depth
|
builder.depth = depth
|
||||||
|
@ -165,6 +168,31 @@ class BaseHandler(object):
|
||||||
|
|
||||||
context = yield state_handler.compute_event_context(builder)
|
context = yield state_handler.compute_event_context(builder)
|
||||||
|
|
||||||
|
# If we've received an invite over federation, there are no latest
|
||||||
|
# events in the room, because we don't know enough about the graph
|
||||||
|
# fragment we received to treat it like a graph, so the above returned
|
||||||
|
# no relevant events. It may have returned some events (if we have
|
||||||
|
# joined and left the room), but not useful ones, like the invite. So we
|
||||||
|
# forcibly set our context to the invite we received over federation.
|
||||||
|
if (
|
||||||
|
not self.is_host_in_room(context.current_state) and
|
||||||
|
builder.type == EventTypes.Member
|
||||||
|
):
|
||||||
|
prev_member_event = yield self.store.get_room_member(
|
||||||
|
builder.sender, builder.room_id
|
||||||
|
)
|
||||||
|
if prev_member_event:
|
||||||
|
builder.prev_events = (
|
||||||
|
prev_member_event.event_id,
|
||||||
|
prev_member_event.prev_events
|
||||||
|
)
|
||||||
|
|
||||||
|
context = yield state_handler.compute_event_context(
|
||||||
|
builder,
|
||||||
|
old_state=(prev_member_event,),
|
||||||
|
outlier=True
|
||||||
|
)
|
||||||
|
|
||||||
if builder.is_state():
|
if builder.is_state():
|
||||||
builder.prev_state = yield self.store.add_event_hashes(
|
builder.prev_state = yield self.store.add_event_hashes(
|
||||||
context.prev_state_events
|
context.prev_state_events
|
||||||
|
@ -187,6 +215,25 @@ class BaseHandler(object):
|
||||||
(event, context,)
|
(event, context,)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def is_host_in_room(self, current_state):
|
||||||
|
room_members = [
|
||||||
|
(state_key, event.membership)
|
||||||
|
for ((event_type, state_key), event) in current_state.items()
|
||||||
|
if event_type == EventTypes.Member
|
||||||
|
]
|
||||||
|
if len(room_members) == 0:
|
||||||
|
# has the room been created so we can join it?
|
||||||
|
create_event = current_state.get(("m.room.create", ""))
|
||||||
|
if create_event:
|
||||||
|
return True
|
||||||
|
for (state_key, membership) in room_members:
|
||||||
|
if (
|
||||||
|
UserID.from_string(state_key).domain == self.hs.hostname
|
||||||
|
and membership == Membership.JOIN
|
||||||
|
):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def handle_new_client_event(self, event, context, ratelimit=True, extra_users=[]):
|
def handle_new_client_event(self, event, context, ratelimit=True, extra_users=[]):
|
||||||
# We now need to go and hit out to wherever we need to hit out to.
|
# We now need to go and hit out to wherever we need to hit out to.
|
||||||
|
|
|
@ -510,10 +510,9 @@ class RoomMemberHandler(BaseHandler):
|
||||||
# so don't really fit into the general auth process.
|
# so don't really fit into the general auth process.
|
||||||
raise AuthError(403, "Guest access not allowed")
|
raise AuthError(403, "Guest access not allowed")
|
||||||
|
|
||||||
should_do_dance, room_hosts = yield self._should_do_dance(
|
should_do_dance, room_hosts = self._should_do_dance(
|
||||||
room_id,
|
|
||||||
context,
|
context,
|
||||||
(yield self.get_inviter(target_user.to_string(), room_id)),
|
(self.get_inviter(target_user.to_string(), context.current_state)),
|
||||||
room_hosts,
|
room_hosts,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -534,11 +533,11 @@ class RoomMemberHandler(BaseHandler):
|
||||||
)
|
)
|
||||||
handled = True
|
handled = True
|
||||||
if event.membership == Membership.LEAVE:
|
if event.membership == Membership.LEAVE:
|
||||||
is_host_in_room = yield self.is_host_in_room(room_id, context)
|
is_host_in_room = self.is_host_in_room(context.current_state)
|
||||||
if not is_host_in_room:
|
if not is_host_in_room:
|
||||||
# Rejecting an invite, rather than leaving a joined room
|
# Rejecting an invite, rather than leaving a joined room
|
||||||
handler = self.hs.get_handlers().federation_handler
|
handler = self.hs.get_handlers().federation_handler
|
||||||
inviter = yield self.get_inviter(target_user.to_string(), room_id)
|
inviter = self.get_inviter(target_user.to_string(), context.current_state)
|
||||||
if not inviter:
|
if not inviter:
|
||||||
# return the same error as join_room_alias does
|
# return the same error as join_room_alias does
|
||||||
raise SynapseError(404, "No known servers")
|
raise SynapseError(404, "No known servers")
|
||||||
|
@ -584,20 +583,18 @@ class RoomMemberHandler(BaseHandler):
|
||||||
and guest_access.content["guest_access"] == "can_join"
|
and guest_access.content["guest_access"] == "can_join"
|
||||||
)
|
)
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
def _should_do_dance(self, context, inviter, room_hosts=None):
|
||||||
def _should_do_dance(self, room_id, context, inviter, room_hosts=None):
|
|
||||||
# TODO: Shouldn't this be remote_room_host?
|
# TODO: Shouldn't this be remote_room_host?
|
||||||
room_hosts = room_hosts or []
|
room_hosts = room_hosts or []
|
||||||
|
|
||||||
# TODO(danielwh): This shouldn't need to yield for this check, we have a context.
|
is_host_in_room = self.is_host_in_room(context.current_state)
|
||||||
is_host_in_room = yield self.is_host_in_room(room_id, context)
|
|
||||||
if is_host_in_room:
|
if is_host_in_room:
|
||||||
defer.returnValue((False, room_hosts))
|
return False, room_hosts
|
||||||
|
|
||||||
if inviter and not self.hs.is_mine(inviter):
|
if inviter and not self.hs.is_mine(inviter):
|
||||||
room_hosts.append(inviter.domain)
|
room_hosts.append(inviter.domain)
|
||||||
|
|
||||||
defer.returnValue((True, room_hosts))
|
return True, room_hosts
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def lookup_room_alias(self, room_alias):
|
def lookup_room_alias(self, room_alias):
|
||||||
|
@ -624,36 +621,11 @@ class RoomMemberHandler(BaseHandler):
|
||||||
|
|
||||||
defer.returnValue((RoomID.from_string(room_id), hosts))
|
defer.returnValue((RoomID.from_string(room_id), hosts))
|
||||||
|
|
||||||
# TODO(danielwh): This should use the context, rather than looking up the store.
|
def get_inviter(self, user_id, current_state):
|
||||||
@defer.inlineCallbacks
|
prev_state = current_state.get((EventTypes.Member, user_id))
|
||||||
def get_inviter(self, user_id, room_id):
|
|
||||||
# TODO(markjh): get prev_state from snapshot
|
|
||||||
prev_state = yield self.store.get_room_member(
|
|
||||||
user_id, room_id
|
|
||||||
)
|
|
||||||
if prev_state and prev_state.membership == Membership.INVITE:
|
if prev_state and prev_state.membership == Membership.INVITE:
|
||||||
defer.returnValue(UserID.from_string(prev_state.user_id))
|
return UserID.from_string(prev_state.user_id)
|
||||||
|
return None
|
||||||
# TODO(danielwh): This looks insane. Please make it not insane.
|
|
||||||
@defer.inlineCallbacks
|
|
||||||
def is_host_in_room(self, room_id, context):
|
|
||||||
is_host_in_room = yield self.auth.check_host_in_room(
|
|
||||||
room_id,
|
|
||||||
self.hs.hostname
|
|
||||||
)
|
|
||||||
if not is_host_in_room:
|
|
||||||
# is *anyone* in the room?
|
|
||||||
room_member_keys = [
|
|
||||||
v for (k, v) in context.current_state.keys() if (
|
|
||||||
k == "m.room.member"
|
|
||||||
)
|
|
||||||
]
|
|
||||||
if len(room_member_keys) == 0:
|
|
||||||
# has the room been created so we can join it?
|
|
||||||
create_event = context.current_state.get(("m.room.create", ""))
|
|
||||||
if create_event:
|
|
||||||
is_host_in_room = True
|
|
||||||
defer.returnValue(is_host_in_room)
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def get_joined_rooms_for_user(self, user):
|
def get_joined_rooms_for_user(self, user):
|
||||||
|
|
|
@ -114,10 +114,10 @@ class EventFederationStore(SQLBaseStore):
|
||||||
retcol="event_id",
|
retcol="event_id",
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_latest_events_in_room(self, room_id):
|
def get_latest_event_ids_and_hashes_in_room(self, room_id):
|
||||||
return self.runInteraction(
|
return self.runInteraction(
|
||||||
"get_latest_events_in_room",
|
"get_latest_event_ids_and_hashes_in_room",
|
||||||
self._get_latest_events_in_room,
|
self._get_latest_event_ids_and_hashes_in_room,
|
||||||
room_id,
|
room_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ class EventFederationStore(SQLBaseStore):
|
||||||
desc="get_latest_event_ids_in_room",
|
desc="get_latest_event_ids_in_room",
|
||||||
)
|
)
|
||||||
|
|
||||||
def _get_latest_events_in_room(self, txn, room_id):
|
def _get_latest_event_ids_and_hashes_in_room(self, txn, room_id):
|
||||||
sql = (
|
sql = (
|
||||||
"SELECT e.event_id, e.depth FROM events as e "
|
"SELECT e.event_id, e.depth FROM events as e "
|
||||||
"INNER JOIN event_forward_extremities as f "
|
"INNER JOIN event_forward_extremities as f "
|
||||||
|
|
Loading…
Reference in New Issue