def get_state_for_pdu(self, origin, room_id, event_id): yield run_on_reactor() in_room = yield self.auth.check_host_in_room(room_id, origin) if not in_room: raise AuthError(403, "Host not in room.") state_groups = yield self.store.get_state_groups([event_id]) if state_groups: _, state = state_groups.items().pop() results = {(e.type, e.state_key): e for e in state} event = yield self.store.get_event(event_id) if event and event.is_state(): # Get previous state if "replaces_state" in event.unsigned: prev_id = event.unsigned["replaces_state"] if prev_id != event.event_id: prev_event = yield self.store.get_event(prev_id) results[(event.type, event.state_key)] = prev_event else: del results[(event.type, event.state_key)] res = results.values() for event in res: event.signatures.update( compute_event_signature(event, self.hs.hostname, self.hs.config.signing_key[0])) defer.returnValue(res) else: defer.returnValue([])
def on_context_state_request(self, origin, room_id, event_id): if event_id: pdus = yield self.handler.get_state_for_pdu( origin, room_id, event_id, ) auth_chain = yield self.store.get_auth_chain( [pdu.event_id for pdu in pdus] ) for event in auth_chain: # We sign these again because there was a bug where we # incorrectly signed things the first time round if self.hs.is_mine_id(event.event_id): event.signatures.update( compute_event_signature( event, self.hs.hostname, self.hs.config.signing_key[0] ) ) else: raise NotImplementedError("Specify an event") defer.returnValue((200, { "pdus": [pdu.get_pdu_json() for pdu in pdus], "auth_chain": [pdu.get_pdu_json() for pdu in auth_chain], }))
def get_persisted_pdu(self, origin, event_id, do_auth=True): """ Get a PDU from the database with given origin and id. Returns: Deferred: Results in a `Pdu`. """ event = yield self.store.get_event( event_id, allow_none=True, ) if event: # FIXME: This is a temporary work around where we occasionally # return events slightly differently than when they were # originally signed event.signatures.update( compute_event_signature(event, self.hs.hostname, self.hs.config.signing_key[0])) if do_auth: in_room = yield self.auth.check_host_in_room( event.room_id, origin) if not in_room: raise AuthError(403, "Host not in room.") defer.returnValue(event) else: defer.returnValue(None)
def on_query_auth(self, origin, event_id, remote_auth_chain, rejects, missing): # Just go through and process each event in `remote_auth_chain`. We # don't want to fall into the trap of `missing` being wrong. for e in remote_auth_chain: try: yield self._handle_new_event(origin, e) except AuthError: pass # Now get the current auth_chain for the event. local_auth_chain = yield self.store.get_auth_chain([event_id]) # TODO: Check if we would now reject event_id. If so we need to tell # everyone. ret = yield self.construct_auth_difference( local_auth_chain, remote_auth_chain ) for event in ret["auth_chain"]: event.signatures.update( compute_event_signature( event, self.hs.hostname, self.hs.config.signing_key[0] ) ) logger.debug("on_query_auth returning: %s", ret) defer.returnValue(ret)
def on_invite_request(self, origin, pdu): """ We've got an invite event. Process and persist it. Sign it. Respond with the now signed event. """ event = pdu event.internal_metadata.outlier = True event.signatures.update( compute_event_signature(event, self.hs.hostname, self.hs.config.signing_key[0])) context = yield self.state_handler.compute_event_context(event) yield self.store.persist_event( event, context=context, backfilled=False, ) target_user = self.hs.parse_userid(event.state_key) yield self.notifier.on_new_room_event( event, extra_users=[target_user], ) defer.returnValue(event)
def get_persisted_pdu(self, origin, event_id, do_auth=True): """ Get a PDU from the database with given origin and id. Returns: Deferred: Results in a `Pdu`. """ event = yield self.store.get_event( event_id, allow_none=True, allow_rejected=True, ) if event: # FIXME: This is a temporary work around where we occasionally # return events slightly differently than when they were # originally signed event.signatures.update( compute_event_signature( event, self.hs.hostname, self.hs.config.signing_key[0] ) ) if do_auth: in_room = yield self.auth.check_host_in_room( event.room_id, origin ) if not in_room: raise AuthError(403, "Host not in room.") defer.returnValue(event) else: defer.returnValue(None)
def on_query_auth(self, origin, event_id, remote_auth_chain, rejects, missing): # Just go through and process each event in `remote_auth_chain`. We # don't want to fall into the trap of `missing` being wrong. for e in remote_auth_chain: try: yield self._handle_new_event(origin, e) except AuthError: pass # Now get the current auth_chain for the event. local_auth_chain = yield self.store.get_auth_chain([event_id]) # TODO: Check if we would now reject event_id. If so we need to tell # everyone. ret = yield self.construct_auth_difference( local_auth_chain, remote_auth_chain ) for event in ret["auth_chain"]: event.signatures.update( compute_event_signature( event, self.hs.hostname, self.hs.config.signing_key[0] ) ) logger.debug("on_query_auth returning: %s", ret) defer.returnValue(ret)
def on_invite_request(self, origin, pdu): """ We've got an invite event. Process and persist it. Sign it. Respond with the now signed event. """ event = pdu event.internal_metadata.outlier = True event.signatures.update( compute_event_signature( event, self.hs.hostname, self.hs.config.signing_key[0] ) ) context = yield self.state_handler.compute_event_context(event) yield self.store.persist_event( event, context=context, backfilled=False, ) target_user = UserID.from_string(event.state_key) yield self.notifier.on_new_room_event( event, extra_users=[target_user], ) defer.returnValue(event)
def on_invite_request(self, origin, pdu): """ We've got an invite event. Process and persist it. Sign it. Respond with the now signed event. """ event = pdu event.internal_metadata.outlier = True event.signatures.update( compute_event_signature(event, self.hs.hostname, self.hs.config.signing_key[0])) context = yield self.state_handler.compute_event_context(event) yield self.store.persist_event( event, context=context, backfilled=False, ) target_user = UserID.from_string(event.state_key) d = self.notifier.on_new_room_event( event, extra_users=[target_user], ) def log_failure(f): logger.warn("Failed to notify about %s: %s", event.event_id, f.value) d.addErrback(log_failure) defer.returnValue(event)
def on_event_auth(self, event_id): auth = yield self.store.get_auth_chain([event_id]) for event in auth: event.signatures.update( compute_event_signature(event, self.hs.hostname, self.hs.config.signing_key[0])) defer.returnValue([e for e in auth])
def on_event_auth(self, event_id): auth = yield self.store.get_auth_chain([event_id]) for event in auth: event.signatures.update( compute_event_signature( event, self.hs.hostname, self.hs.config.signing_key[0] ) ) defer.returnValue([e for e in auth])
def get_state_for_pdu(self, origin, room_id, event_id, do_auth=True): yield run_on_reactor() if do_auth: in_room = yield self.auth.check_host_in_room(room_id, origin) if not in_room: raise AuthError(403, "Host not in room.") state_groups = yield self.store.get_state_groups( [event_id] ) if state_groups: _, state = state_groups.items().pop() results = { (e.type, e.state_key): e for e in state } event = yield self.store.get_event(event_id) if event and event.is_state(): # Get previous state if "replaces_state" in event.unsigned: prev_id = event.unsigned["replaces_state"] if prev_id != event.event_id: prev_event = yield self.store.get_event(prev_id) results[(event.type, event.state_key)] = prev_event else: del results[(event.type, event.state_key)] res = results.values() for event in res: event.signatures.update( compute_event_signature( event, self.hs.hostname, self.hs.config.signing_key[0] ) ) defer.returnValue(res) else: defer.returnValue([])
def _on_context_state_request_compute(self, room_id, event_id): pdus = yield self.handler.get_state_for_pdu( room_id, event_id, ) auth_chain = yield self.store.get_auth_chain( [pdu.event_id for pdu in pdus]) for event in auth_chain: # We sign these again because there was a bug where we # incorrectly signed things the first time round if self.hs.is_mine_id(event.event_id): event.signatures.update( compute_event_signature(event, self.hs.hostname, self.hs.config.signing_key[0])) defer.returnValue({ "pdus": [pdu.get_pdu_json() for pdu in pdus], "auth_chain": [pdu.get_pdu_json() for pdu in auth_chain], })
def on_invite_request(self, origin, pdu): """ We've got an invite event. Process and persist it. Sign it. Respond with the now signed event. """ event = pdu event.internal_metadata.outlier = True event.signatures.update( compute_event_signature( event, self.hs.hostname, self.hs.config.signing_key[0] ) ) context = yield self.state_handler.compute_event_context(event) event_stream_id, max_stream_id = yield self.store.persist_event( event, context=context, backfilled=False, ) target_user = UserID.from_string(event.state_key) with PreserveLoggingContext(): d = self.notifier.on_new_room_event( event, event_stream_id, max_stream_id, extra_users=[target_user], ) def log_failure(f): logger.warn( "Failed to notify about %s: %s", event.event_id, f.value ) d.addErrback(log_failure) defer.returnValue(event)
def on_context_state_request(self, origin, room_id, event_id): if event_id: pdus = yield self.handler.get_state_for_pdu( origin, room_id, event_id, ) auth_chain = yield self.store.get_auth_chain( [pdu.event_id for pdu in pdus]) for event in auth_chain: event.signatures.update( compute_event_signature(event, self.hs.hostname, self.hs.config.signing_key[0])) else: raise NotImplementedError("Specify an event") defer.returnValue((200, { "pdus": [pdu.get_pdu_json() for pdu in pdus], "auth_chain": [pdu.get_pdu_json() for pdu in auth_chain], }))
def on_context_state_request(self, origin, room_id, event_id): if event_id: pdus = yield self.handler.get_state_for_pdu( origin, room_id, event_id, ) auth_chain = yield self.store.get_auth_chain( [pdu.event_id for pdu in pdus] ) for event in auth_chain: event.signatures.update( compute_event_signature( event, self.hs.hostname, self.hs.config.signing_key[0] ) ) else: raise NotImplementedError("Specify an event") defer.returnValue((200, { "pdus": [pdu.get_pdu_json() for pdu in pdus], "auth_chain": [pdu.get_pdu_json() for pdu in auth_chain], }))
def _on_context_state_request_compute(self, room_id, event_id): pdus = yield self.handler.get_state_for_pdu( room_id, event_id, ) auth_chain = yield self.store.get_auth_chain( [pdu.event_id for pdu in pdus] ) for event in auth_chain: # We sign these again because there was a bug where we # incorrectly signed things the first time round if self.hs.is_mine_id(event.event_id): event.signatures.update( compute_event_signature( event.get_pdu_json(), self.hs.hostname, self.hs.config.signing_key[0] ) ) defer.returnValue({ "pdus": [pdu.get_pdu_json() for pdu in pdus], "auth_chain": [pdu.get_pdu_json() for pdu in auth_chain], })
def reinsert_events(cursor, server_name, signing_key): print "Running delta: v10" cursor.executescript(delta_sql) cursor.execute("SELECT * FROM events ORDER BY rowid ASC") print "Getting events..." rows = store.cursor_to_dict(cursor) events = store._generate_event_json(cursor, rows) print "Got events from DB." algorithms = { "sha256": hashlib.sha256, } key_id = "%s:%s" % (signing_key.alg, signing_key.version) verify_key = signing_key.verify_key verify_key.alg = signing_key.alg verify_key.version = signing_key.version server_keys = {server_name: {key_id: verify_key}} i = 0 N = len(events) for event in events: if i % 100 == 0: print "Processed: %d/%d events" % ( i, N, ) i += 1 # for alg_name in event.hashes: # if check_event_content_hash(event, algorithms[alg_name]): # pass # else: # pass # print "FAIL content hash %s %s" % (alg_name, event.event_id, ) have_own_correctly_signed = False for host, sigs in event.signatures.items(): pruned = prune_event(event) for key_id in sigs: if host not in server_keys: server_keys[host] = {} # get_key(host) if key_id in server_keys[host]: try: verify_signed_json(pruned.get_pdu_json(), host, server_keys[host][key_id]) if host == server_name: have_own_correctly_signed = True except SignatureVerifyException: print "FAIL signature check %s %s" % (key_id, event.event_id) # TODO: Re sign with our own server key if not have_own_correctly_signed: sigs = compute_event_signature(event, server_name, signing_key) event.signatures.update(sigs) pruned = prune_event(event) for key_id in event.signatures[server_name]: verify_signed_json(pruned.get_pdu_json(), server_name, server_keys[server_name][key_id]) event_json = encode_canonical_json(event.get_dict()).decode("UTF-8") metadata_json = encode_canonical_json( event.internal_metadata.get_dict()).decode("UTF-8") store._simple_insert_txn( cursor, table="event_json", values={ "event_id": event.event_id, "room_id": event.room_id, "internal_metadata": metadata_json, "json": event_json, }, or_replace=True, )
def reinsert_events(cursor, server_name, signing_key): print "Running delta: v10" cursor.executescript(delta_sql) cursor.execute( "SELECT * FROM events ORDER BY rowid ASC" ) print "Getting events..." rows = store.cursor_to_dict(cursor) events = store._generate_event_json(cursor, rows) print "Got events from DB." algorithms = { "sha256": hashlib.sha256, } key_id = "%s:%s" % (signing_key.alg, signing_key.version) verify_key = signing_key.verify_key verify_key.alg = signing_key.alg verify_key.version = signing_key.version server_keys = { server_name: { key_id: verify_key } } i = 0 N = len(events) for event in events: if i % 100 == 0: print "Processed: %d/%d events" % (i,N,) i += 1 # for alg_name in event.hashes: # if check_event_content_hash(event, algorithms[alg_name]): # pass # else: # pass # print "FAIL content hash %s %s" % (alg_name, event.event_id, ) have_own_correctly_signed = False for host, sigs in event.signatures.items(): pruned = prune_event(event) for key_id in sigs: if host not in server_keys: server_keys[host] = {} # get_key(host) if key_id in server_keys[host]: try: verify_signed_json( pruned.get_pdu_json(), host, server_keys[host][key_id] ) if host == server_name: have_own_correctly_signed = True except SignatureVerifyException: print "FAIL signature check %s %s" % ( key_id, event.event_id ) # TODO: Re sign with our own server key if not have_own_correctly_signed: sigs = compute_event_signature(event, server_name, signing_key) event.signatures.update(sigs) pruned = prune_event(event) for key_id in event.signatures[server_name]: verify_signed_json( pruned.get_pdu_json(), server_name, server_keys[server_name][key_id] ) event_json = encode_canonical_json( event.get_dict() ).decode("UTF-8") metadata_json = encode_canonical_json( event.internal_metadata.get_dict() ).decode("UTF-8") store._simple_insert_txn( cursor, table="event_json", values={ "event_id": event.event_id, "room_id": event.room_id, "internal_metadata": metadata_json, "json": event_json, }, or_replace=True, )
async def _on_send_membership_event( self, origin: str, content: JsonDict, membership_type: str, room_id: str ) -> Tuple[EventBase, EventContext]: """Handle an on_send_{join,leave,knock} request Does some preliminary validation before passing the request on to the federation handler. Args: origin: The (authenticated) requesting server content: The body of the send_* request - a complete membership event membership_type: The expected membership type (join or leave, depending on the endpoint) room_id: The room_id from the request, to be validated against the room_id in the event Returns: The event and context of the event after inserting it into the room graph. Raises: SynapseError if there is a problem with the request, including things like the room_id not matching or the event not being authorized. """ assert_params_in_dict(content, ["room_id"]) if content["room_id"] != room_id: raise SynapseError( 400, "Room ID in body does not match that in request path", Codes.BAD_JSON, ) room_version = await self.store.get_room_version(room_id) if membership_type == Membership.KNOCK and not room_version.msc2403_knocking: raise SynapseError( 403, "This room version does not support knocking", errcode=Codes.FORBIDDEN, ) event = event_from_pdu_json(content, room_version) if event.type != EventTypes.Member or not event.is_state(): raise SynapseError(400, "Not an m.room.member event", Codes.BAD_JSON) if event.content.get("membership") != membership_type: raise SynapseError(400, "Not a %s event" % membership_type, Codes.BAD_JSON) origin_host, _ = parse_server_name(origin) await self.check_server_matches_acl(origin_host, event.room_id) logger.debug("_on_send_membership_event: pdu sigs: %s", event.signatures) # Sign the event since we're vouching on behalf of the remote server that # the event is valid to be sent into the room. Currently this is only done # if the user is being joined via restricted join rules. if ( room_version.msc3083_join_rules and event.membership == Membership.JOIN and "join_authorised_via_users_server" in event.content ): # We can only authorise our own users. authorising_server = get_domain_from_id( event.content["join_authorised_via_users_server"] ) if authorising_server != self.server_name: raise SynapseError( 400, f"Cannot authorise request from resident server: {authorising_server}", ) event.signatures.update( compute_event_signature( room_version, event.get_pdu_json(), self.hs.hostname, self.hs.signing_key, ) ) event = await self._check_sigs_and_hash(room_version, event) return await self._federation_event_handler.on_send_membership_event( origin, event )