Start implementing the invite/join dance. Continue moving auth to use event.state_events

pull/12/head
Erik Johnston 2014-10-16 16:56:51 +01:00
parent e7bc1291a0
commit 1116f5330e
4 changed files with 133 additions and 22 deletions

View File

@ -21,7 +21,7 @@ from synapse.api.constants import Membership, JoinRules
from synapse.api.errors import AuthError, StoreError, Codes, SynapseError from synapse.api.errors import AuthError, StoreError, Codes, SynapseError
from synapse.api.events.room import ( from synapse.api.events.room import (
RoomMemberEvent, RoomPowerLevelsEvent, RoomRedactionEvent, RoomMemberEvent, RoomPowerLevelsEvent, RoomRedactionEvent,
RoomJoinRulesEvent, RoomOpsPowerLevelsEvent, RoomJoinRulesEvent, RoomOpsPowerLevelsEvent, InviteJoinEvent,
) )
from synapse.util.logutils import log_function from synapse.util.logutils import log_function
@ -56,6 +56,7 @@ class Auth(object):
defer.returnValue(allowed) defer.returnValue(allowed)
return return
if not event.type == InviteJoinEvent.TYPE:
self.check_event_sender_in_room(event) self.check_event_sender_in_room(event)
if is_state: if is_state:
@ -115,11 +116,6 @@ class Auth(object):
def is_membership_change_allowed(self, event): def is_membership_change_allowed(self, event):
target_user_id = event.state_key target_user_id = event.state_key
# does this room even exist
room = yield self.store.get_room(event.room_id)
if not room:
raise AuthError(403, "Room does not exist")
# get info about the caller # get info about the caller
key = (RoomMemberEvent.TYPE, event.user_id, ) key = (RoomMemberEvent.TYPE, event.user_id, )
caller = event.old_state_events.get(key) caller = event.old_state_events.get(key)
@ -170,7 +166,7 @@ class Auth(object):
# joined: It's a NOOP # joined: It's a NOOP
if event.user_id != target_user_id: if event.user_id != target_user_id:
raise AuthError(403, "Cannot force another user to join.") raise AuthError(403, "Cannot force another user to join.")
elif join_rule == JoinRules.PUBLIC or room.is_public: elif join_rule == JoinRules.PUBLIC:
pass pass
elif join_rule == JoinRules.INVITE: elif join_rule == JoinRules.INVITE:
if ( if (
@ -215,9 +211,9 @@ class Auth(object):
power_level_event = event.old_state_events.get(key) power_level_event = event.old_state_events.get(key)
level = None level = None
if power_level_event: if power_level_event:
level = power_level_event.content[user_id] level = power_level_event.content.get(user_id)
if not level: if not level:
level = power_level_event.content["default"] level = power_level_event.content.get("default", 0)
return level return level

View File

@ -393,9 +393,25 @@ class ReplicationLayer(object):
response = yield self.query_handlers[query_type](args) response = yield self.query_handlers[query_type](args)
defer.returnValue((200, response)) defer.returnValue((200, response))
else: else:
defer.returnValue((404, "No handler for Query type '%s'" defer.returnValue(
% (query_type) (404, "No handler for Query type '%s'" % (query_type, ))
)) )
def on_make_join_request(self, context, user_id):
return self.handler.on_make_join_request(context, user_id)
@defer.inlineCallbacks
def on_send_join_request(self, origin, content):
pdu = Pdu(**content)
state = yield self.handler.on_send_join_request(origin, pdu)
defer.returnValue((200, self._transaction_from_pdus(state).get_dict()))
def make_join(self, destination, context, user_id):
return self.transport_layer.make_join(
destination=destination,
context=context,
user_id=user_id,
)
@defer.inlineCallbacks @defer.inlineCallbacks
@log_function @log_function

View File

@ -197,6 +197,19 @@ class TransportLayer(object):
defer.returnValue(response) defer.returnValue(response)
@defer.inlineCallbacks
@log_function
def make_join(self, destination, context, user_id, retry_on_dns_fail=True):
path = PREFIX + "/make_join/%s/%s" % (context, user_id,)
response = yield self.client.get_json(
destination=destination,
path=path,
retry_on_dns_fail=retry_on_dns_fail,
)
defer.returnValue(response)
@defer.inlineCallbacks @defer.inlineCallbacks
def _authenticate_request(self, request): def _authenticate_request(self, request):
json_request = { json_request = {
@ -353,6 +366,12 @@ class TransportLayer(object):
) )
) )
self.server.register_path(
"GET",
re.compile("^" + PREFIX + "/make_join/([^/]*)/([^/]*)$"),
self._on_make_join_request
)
@defer.inlineCallbacks @defer.inlineCallbacks
@log_function @log_function
def _on_send_request(self, origin, content, query, transaction_id): def _on_send_request(self, origin, content, query, transaction_id):
@ -438,7 +457,20 @@ class TransportLayer(object):
versions = [v.split(",", 1) for v in v_list] versions = [v.split(",", 1) for v in v_list]
return self.request_handler.on_backfill_request( return self.request_handler.on_backfill_request(
context, versions, limit) context, versions, limit
)
@log_function
def _on_make_join_request(self, origin, content, query, context, user_id):
return self.request_handler.on_make_join_request(
context, user_id,
)
@log_function
def _on_send_join_request(self, origin, content, query):
return self.request_handler.on_send_join_request(
origin, content,
)
class TransportReceivedHandler(object): class TransportReceivedHandler(object):

View File

@ -89,7 +89,7 @@ class FederationHandler(BaseHandler):
@defer.inlineCallbacks @defer.inlineCallbacks
def on_receive_pdu(self, pdu, backfilled): def on_receive_pdu(self, pdu, backfilled):
""" Called by the ReplicationLayer when we have a new pdu. We need to """ Called by the ReplicationLayer when we have a new pdu. We need to
do auth checks and put it throught the StateHandler. do auth checks and put it through the StateHandler.
""" """
event = self.pdu_codec.event_from_pdu(pdu) event = self.pdu_codec.event_from_pdu(pdu)
@ -97,7 +97,11 @@ class FederationHandler(BaseHandler):
yield self.state_handler.annotate_state_groups(event) yield self.state_handler.annotate_state_groups(event)
with (yield self.lock_manager.lock(pdu.context)): logger.debug("Event: %s", event)
if not backfilled:
yield self.auth.check(event, None, raises=True)
if event.is_state and not backfilled: if event.is_state and not backfilled:
is_new_state = yield self.state_handler.handle_new_state( is_new_state = yield self.state_handler.handle_new_state(
pdu pdu
@ -267,6 +271,69 @@ class FederationHandler(BaseHandler):
defer.returnValue(True) defer.returnValue(True)
@defer.inlineCallbacks
def on_make_join_request(self, context, user_id):
event = self.event_factory.create_event(
etype=RoomMemberEvent.TYPE,
content={"membership": Membership.JOIN},
room_id=context,
user_id=user_id,
state_key=user_id,
)
snapshot = yield self.store.snapshot_room(
event.room_id, event.user_id,
)
snapshot.fill_out_prev_events(event)
pdu = self.pdu_codec.pdu_from_event(event)
defer.returnValue(pdu)
@defer.inlineCallbacks
def on_send_join_request(self, origin, pdu):
event = self.pdu_codec.event_from_pdu(pdu)
yield self.state_handler.annotate_state_groups(event)
yield self.auth.check(event, None, raises=True)
is_new_state = yield self.state_handler.handle_new_state(
pdu
)
# FIXME (erikj): All this is duplicated above :(
yield self.store.persist_event(
event,
backfilled=False,
is_new_state=is_new_state
)
extra_users = []
if event.type == RoomMemberEvent.TYPE:
target_user_id = event.state_key
target_user = self.hs.parse_userid(target_user_id)
extra_users.append(target_user)
yield self.notifier.on_new_room_event(
event, extra_users=extra_users
)
if event.type == RoomMemberEvent.TYPE:
if event.membership == Membership.JOIN:
user = self.hs.parse_userid(event.state_key)
self.distributor.fire(
"user_joined_room", user=user, room_id=event.room_id
)
pdu.destinations = yield self.store.get_joined_hosts_for_room(
event.room_id
)
yield self.replication_layer.send_pdu(pdu)
defer.returnValue(event.state_events.values())
@log_function @log_function
def _on_user_joined(self, user, room_id): def _on_user_joined(self, user, room_id):
waiters = self.waiting_for_join_list.get((user.to_string(), room_id), []) waiters = self.waiting_for_join_list.get((user.to_string(), room_id), [])