def persist(self, sender=USER_ID, room_id=ROOM_ID, type={}, key=None, internal={}, state=None, reset_state=False, backfill=False, depth=None, prev_events=[], auth_events=[], prev_state=[], redacts=None, push_actions=[], **content): """ Returns: synapse.events.FrozenEvent: The event that was persisted. """ if depth is None: depth = self.event_id event_dict = { "sender": sender, "type": type, "content": content, "event_id": "$%d:blue" % (self.event_id, ), "room_id": room_id, "depth": depth, "origin_server_ts": self.event_id, "prev_events": prev_events, "auth_events": auth_events, } if key is not None: event_dict["state_key"] = key event_dict["prev_state"] = prev_state if redacts is not None: event_dict["redacts"] = redacts event = FrozenEvent(event_dict, internal_metadata_dict=internal) self.event_id += 1 context = EventContext(current_state=state) context.push_actions = push_actions ordering = None if backfill: yield self.master_store.persist_events([(event, context)], backfilled=True) else: ordering, _ = yield self.master_store.persist_event( event, context, current_state=reset_state) if ordering: event.internal_metadata.stream_ordering = ordering defer.returnValue(event)
def create_event(name=None, type=None, state_key=None, depth=2, event_id=None, prev_events=[], **kwargs): global _next_event_id if not event_id: _next_event_id += 1 event_id = str(_next_event_id) if not name: if state_key is not None: name = "<%s-%s, %s>" % (type, state_key, event_id,) else: name = "<%s, %s>" % (type, event_id,) d = { "event_id": event_id, "type": type, "sender": "@user_id:example.com", "room_id": "!room_id:example.com", "depth": depth, "prev_events": prev_events, } if state_key is not None: d["state_key"] = state_key d.update(kwargs) event = FrozenEvent(d) return event
def test_sign_message(self): event_dict = { "content": { "body": "Here is the message content" }, "event_id": "$0:domain", "origin": "domain", "origin_server_ts": 1000000, "type": "m.room.message", "room_id": "!r:domain", "sender": "@u:domain", "signatures": {}, "unsigned": { "age_ts": 1000000 }, } add_hashes_and_signatures(RoomVersions.V1, event_dict, HOSTNAME, self.signing_key) event = FrozenEvent(event_dict) self.assertTrue(hasattr(event, "hashes")) self.assertIn("sha256", event.hashes) self.assertEquals(event.hashes["sha256"], "onLKD1bGljeBWQhWZ1kaP9SorVmRQNdN5aM2JYU2n/g") self.assertTrue(hasattr(event, "signatures")) self.assertIn(HOSTNAME, event.signatures) self.assertIn(KEY_NAME, event.signatures["domain"]) self.assertEquals( event.signatures[HOSTNAME][KEY_NAME], "Wm+VzmOUOz08Ds+0NTWb1d4CZrVsJSikkeRxh6aCcUw" "u6pNC78FunoD7KNWzqFn241eYHYMGCA5McEiVPdhzBA", )
def test_sign_minimal(self): event_dict = { "event_id": "$0:domain", "origin": "domain", "origin_server_ts": 1000000, "signatures": {}, "type": "X", "unsigned": { "age_ts": 1000000 }, } add_hashes_and_signatures(RoomVersions.V1, event_dict, HOSTNAME, self.signing_key) event = FrozenEvent(event_dict) self.assertTrue(hasattr(event, "hashes")) self.assertIn("sha256", event.hashes) self.assertEquals(event.hashes["sha256"], "6tJjLpXtggfke8UxFhAKg82QVkJzvKOVOOSjUDK4ZSI") self.assertTrue(hasattr(event, "signatures")) self.assertIn(HOSTNAME, event.signatures) self.assertIn(KEY_NAME, event.signatures["domain"]) self.assertEquals( event.signatures[HOSTNAME][KEY_NAME], "2Wptgo4CwmLo/Y8B8qinxApKaCkBG2fjTWB7AbP5Uy+" "aIbygsSdLOFzvdDjww8zUVKCmI02eP9xtyJxc/cLiBA", )
def build_event(self, sender=USER_ID, room_id=ROOM_ID, type="m.room.message", key=None, internal={}, state=None, depth=None, prev_events=[], auth_events=[], prev_state=[], redacts=None, push_actions=[], **content): if depth is None: depth = self.event_id if not prev_events: latest_event_ids = self.get_success( self.master_store.get_latest_event_ids_in_room(room_id)) prev_events = [(ev_id, {}) for ev_id in latest_event_ids] event_dict = { "sender": sender, "type": type, "content": content, "event_id": "$%d:blue" % (self.event_id, ), "room_id": room_id, "depth": depth, "origin_server_ts": self.event_id, "prev_events": prev_events, "auth_events": auth_events, } if key is not None: event_dict["state_key"] = key event_dict["prev_state"] = prev_state if redacts is not None: event_dict["redacts"] = redacts event = FrozenEvent(event_dict, internal_metadata_dict=internal) self.event_id += 1 if state is not None: state_ids = {key: e.event_id for key, e in state.items()} context = EventContext.with_state(state_group=None, current_state_ids=state_ids, prev_state_ids=state_ids) else: state_handler = self.hs.get_state_handler() context = self.get_success( state_handler.compute_event_context(event)) self.master_store.add_push_actions_to_staging( event.event_id, {user_id: actions for user_id, actions in push_actions}) return event, context
def _handle_request(self, request): with Measure(self.clock, "repl_fed_send_events_parse"): content = parse_json_object_from_request(request) backfilled = content["backfilled"] event_payloads = content["events"] event_and_contexts = [] for event_payload in event_payloads: event_dict = event_payload["event"] internal_metadata = event_payload["internal_metadata"] rejected_reason = event_payload["rejected_reason"] event = FrozenEvent(event_dict, internal_metadata, rejected_reason) context = yield EventContext.deserialize( self.store, event_payload["context"], ) event_and_contexts.append((event, context)) logger.info( "Got %d events from federation", len(event_and_contexts), ) yield self.federation_handler.persist_events_and_notify( event_and_contexts, backfilled, ) defer.returnValue((200, {}))
def test_sign_message(self): event_dict = { 'content': { 'body': "Here is the message content" }, 'event_id': "$0:domain", 'origin': "domain", 'origin_server_ts': 1000000, 'type': "m.room.message", 'room_id': "!r:domain", 'sender': "@u:domain", 'signatures': {}, 'unsigned': { 'age_ts': 1000000 }, } add_hashes_and_signatures(event_dict, HOSTNAME, self.signing_key) event = FrozenEvent(event_dict) self.assertTrue(hasattr(event, 'hashes')) self.assertIn('sha256', event.hashes) self.assertEquals(event.hashes['sha256'], "onLKD1bGljeBWQhWZ1kaP9SorVmRQNdN5aM2JYU2n/g") self.assertTrue(hasattr(event, 'signatures')) self.assertIn(HOSTNAME, event.signatures) self.assertIn(KEY_NAME, event.signatures["domain"]) self.assertEquals( event.signatures[HOSTNAME][KEY_NAME], "Wm+VzmOUOz08Ds+0NTWb1d4CZrVsJSikkeRxh6aCcUw" "u6pNC78FunoD7KNWzqFn241eYHYMGCA5McEiVPdhzBA", )
def _get_evaluator( self, content: JsonDict, relations: Optional[Dict[str, Set[Tuple[str, str]]]] = None, relations_match_enabled: bool = False, ) -> PushRuleEvaluatorForEvent: event = FrozenEvent( { "event_id": "$event_id", "type": "m.room.history_visibility", "sender": "@user:test", "state_key": "", "room_id": "#room:test", "content": content, }, RoomVersions.V1, ) room_member_count = 0 sender_power_level = 0 power_levels: Dict[str, Union[int, Dict[str, int]]] = {} return PushRuleEvaluatorForEvent( event, room_member_count, sender_power_level, power_levels, relations or set(), relations_match_enabled, )
def test_sign_minimal(self): event_dict = { 'event_id': "$0:domain", 'origin': "domain", 'origin_server_ts': 1000000, 'signatures': {}, 'type': "X", 'unsigned': { 'age_ts': 1000000 }, } add_hashes_and_signatures(event_dict, HOSTNAME, self.signing_key) event = FrozenEvent(event_dict) self.assertTrue(hasattr(event, 'hashes')) self.assertIn('sha256', event.hashes) self.assertEquals(event.hashes['sha256'], "6tJjLpXtggfke8UxFhAKg82QVkJzvKOVOOSjUDK4ZSI") self.assertTrue(hasattr(event, 'signatures')) self.assertIn(HOSTNAME, event.signatures) self.assertIn(KEY_NAME, event.signatures["domain"]) self.assertEquals( event.signatures[HOSTNAME][KEY_NAME], "2Wptgo4CwmLo/Y8B8qinxApKaCkBG2fjTWB7AbP5Uy+" "aIbygsSdLOFzvdDjww8zUVKCmI02eP9xtyJxc/cLiBA", )
def event_from_pdu_json(pdu_json, outlier=False): """Construct a FrozenEvent from an event json received over federation Args: pdu_json (object): pdu as received over federation outlier (bool): True to mark this event as an outlier Returns: FrozenEvent Raises: SynapseError: if the pdu is missing required fields or is otherwise not a valid matrix event """ # we could probably enforce a bunch of other fields here (room_id, sender, # origin, etc etc) assert_params_in_dict(pdu_json, ('event_id', 'type', 'depth')) depth = pdu_json['depth'] if not isinstance(depth, six.integer_types): raise SynapseError(400, "Depth %r not an intger" % (depth, ), Codes.BAD_JSON) if depth < 0: raise SynapseError(400, "Depth too small", Codes.BAD_JSON) elif depth > MAX_DEPTH: raise SynapseError(400, "Depth too large", Codes.BAD_JSON) event = FrozenEvent( pdu_json ) event.internal_metadata.outlier = outlier return event
def test_cant_hide_direct_ancestors(self): """ If you send a message, you must be able to provide the direct prev_events that said event references. """ def post_json(destination, path, data, headers=None, timeout=0): # If it asks us for new missing events, give them NOTHING if path.startswith("/_matrix/federation/v1/get_missing_events/"): return {"events": []} self.http_client.post_json = post_json # Figure out what the most recent event is most_recent = self.successResultOf( maybeDeferred( self.homeserver.datastore.get_latest_event_ids_in_room, self.room_id))[0] # Now lie about an event lying_event = FrozenEvent({ "room_id": self.room_id, "sender": "@baduser:test.serv", "event_id": "one:test.serv", "depth": 1000, "origin_server_ts": 1, "type": "m.room.message", "origin": "test.serv", "content": "hewwo?", "auth_events": [], "prev_events": [("two:test.serv", {}), (most_recent, {})], }) d = self.handler.on_receive_pdu("test.serv", lying_event, sent_to_us_directly=True) # Step the reactor, so the database fetches come back self.reactor.advance(1) # on_receive_pdu should throw an error failure = self.failureResultOf(d) self.assertEqual( failure.value.args[0], ("ERROR 403: Your server isn't divulging details about prev_events " "referenced in this event."), ) # Make sure the invalid event isn't there extrem = maybeDeferred( self.homeserver.datastore.get_latest_event_ids_in_room, self.room_id) self.assertEqual(self.successResultOf(extrem)[0], "$join:test.serv")
def _handle_request(self, request, event_id): with Measure(self.clock, "repl_send_event_parse"): content = parse_json_object_from_request(request) event_dict = content["event"] internal_metadata = content["internal_metadata"] rejected_reason = content["rejected_reason"] event = FrozenEvent(event_dict, internal_metadata, rejected_reason) requester = Requester.deserialize(self.store, content["requester"]) context = yield EventContext.deserialize(self.store, content["context"]) ratelimit = content["ratelimit"] extra_users = [UserID.from_string(u) for u in content["extra_users"]] if requester.user: request.authenticated_entity = requester.user.to_string() logger.info( "Got event to send with ID: %s into room: %s", event.event_id, event.room_id, ) yield self.event_creation_handler.persist_and_notify_client_event( requester, event, context, ratelimit=ratelimit, extra_users=extra_users, ) defer.returnValue((200, {}))
def to_event(self, auth_events, prev_events): """Given the auth_events and prev_events, convert to a Frozen Event Args: auth_events (list[str]): list of event_ids prev_events (list[str]): list of event_ids Returns: FrozenEvent """ global ORIGIN_SERVER_TS ts = ORIGIN_SERVER_TS ORIGIN_SERVER_TS = ORIGIN_SERVER_TS + 1 event_dict = { "auth_events": [(a, {}) for a in auth_events], "prev_events": [(p, {}) for p in prev_events], "event_id": self.node_id, "sender": self.sender, "type": self.type, "content": self.content, "origin_server_ts": ts, "room_id": ROOM_ID, } if self.state_key is not None: event_dict["state_key"] = self.state_key return FrozenEvent(event_dict)
def _get_event_from_row_txn(self, txn, internal_metadata, js, redacted, check_redacted=True, get_prev_content=False): d = json.loads(js) internal_metadata = json.loads(internal_metadata) ev = FrozenEvent(d, internal_metadata_dict=internal_metadata) if check_redacted and redacted: ev = prune_event(ev) ev.unsigned["redacted_by"] = redacted # Get the redaction event. because = self._get_event_txn(txn, redacted, check_redacted=False) if because: ev.unsigned["redacted_because"] = because if get_prev_content and "replaces_state" in ev.unsigned: prev = self._get_event_txn( txn, ev.unsigned["replaces_state"], get_prev_content=False, ) if prev: ev.unsigned["prev_content"] = prev.get_dict()["content"] return ev
def _get_event_from_row(self, internal_metadata, js, redacted, check_redacted=True, get_prev_content=False, rejected_reason=None): d = json.loads(js) internal_metadata = json.loads(internal_metadata) if rejected_reason: rejected_reason = yield self._simple_select_one_onecol( table="rejections", keyvalues={"event_id": rejected_reason}, retcol="reason", desc="_get_event_from_row", ) ev = FrozenEvent( d, internal_metadata_dict=internal_metadata, rejected_reason=rejected_reason, ) if check_redacted and redacted: ev = prune_event(ev) redaction_id = yield self._simple_select_one_onecol( table="redactions", keyvalues={"redacts": ev.event_id}, retcol="event_id", desc="_get_event_from_row", ) ev.unsigned["redacted_by"] = redaction_id # Get the redaction event. because = yield self.get_event( redaction_id, check_redacted=False, allow_none=True, ) if because: ev.unsigned["redacted_because"] = because if get_prev_content and "replaces_state" in ev.unsigned: prev = yield self.get_event( ev.unsigned["replaces_state"], get_prev_content=False, allow_none=True, ) if prev: ev.unsigned["prev_content"] = prev.get_dict()["content"] self._get_event_cache.prefill(ev.event_id, check_redacted, get_prev_content, ev) defer.returnValue(ev)
def _get_event_from_row_txn(self, txn, internal_metadata, js, redacted, check_redacted=True, get_prev_content=False, rejected_reason=None): d = json.loads(js) internal_metadata = json.loads(internal_metadata) if rejected_reason: rejected_reason = self._simple_select_one_onecol_txn( txn, table="rejections", keyvalues={"event_id": rejected_reason}, retcol="reason", ) ev = FrozenEvent( d, internal_metadata_dict=internal_metadata, rejected_reason=rejected_reason, ) if check_redacted and redacted: ev = prune_event(ev) redaction_id = self._simple_select_one_onecol_txn( txn, table="redactions", keyvalues={"redacts": ev.event_id}, retcol="event_id", ) ev.unsigned["redacted_by"] = redaction_id # Get the redaction event. because = self._get_event_txn(txn, redaction_id, check_redacted=False) if because: ev.unsigned["redacted_because"] = because if get_prev_content and "replaces_state" in ev.unsigned: prev = self._get_event_txn( txn, ev.unsigned["replaces_state"], get_prev_content=False, ) if prev: ev.unsigned["prev_content"] = prev.content ev.unsigned["prev_sender"] = prev.sender self._get_event_cache.prefill( (ev.event_id, check_redacted, get_prev_content), ev) return ev
def _create_acl_event(content): return FrozenEvent({ "room_id": "!a:b", "event_id": "$a:b", "type": "m.room.server_acls", "sender": "@a:b", "content": content })
def _process_replication_row(self, row, backfilled): internal = json.loads(row[1]) event_json = json.loads(row[2]) event = FrozenEvent(event_json, internal_metadata_dict=internal) self.invalidate_caches_for_event( event, backfilled, )
def event_from_pdu_json(self, pdu_json, outlier=False): event = FrozenEvent( pdu_json ) event.internal_metadata.outlier = outlier return event
def _process_replication_row(self, row, backfilled, state_resets): position = row[0] internal = json.loads(row[1]) event_json = json.loads(row[2]) event = FrozenEvent(event_json, internal_metadata_dict=internal) self.invalidate_caches_for_event(event, backfilled, reset_state=position in state_resets)
def _power_levels_event(sender, content): return FrozenEvent({ "room_id": TEST_ROOM_ID, "event_id": _get_event_id(), "type": "m.room.power_levels", "sender": sender, "state_key": "", "content": content, })
def _get_event_from_row(self, internal_metadata, js, redacted, rejected_reason=None): with Measure(self._clock, "_get_event_from_row"): d = json.loads(js) internal_metadata = json.loads(internal_metadata) if rejected_reason: rejected_reason = yield self._simple_select_one_onecol( table="rejections", keyvalues={"event_id": rejected_reason}, retcol="reason", desc="_get_event_from_row_rejected_reason", ) original_ev = FrozenEvent( d, internal_metadata_dict=internal_metadata, rejected_reason=rejected_reason, ) redacted_event = None if redacted: redacted_event = prune_event(original_ev) redaction_id = yield self._simple_select_one_onecol( table="redactions", keyvalues={"redacts": redacted_event.event_id}, retcol="event_id", desc="_get_event_from_row_redactions", ) redacted_event.unsigned["redacted_by"] = redaction_id # Get the redaction event. because = yield self.get_event( redaction_id, check_redacted=False, allow_none=True, ) if because: # It's fine to do add the event directly, since get_pdu_json # will serialise this field correctly redacted_event.unsigned["redacted_because"] = because cache_entry = _EventCacheEntry( event=original_ev, redacted_event=redacted_event, ) self._get_event_cache.prefill((original_ev.event_id, ), cache_entry) defer.returnValue(cache_entry)
def make_pdu(prev_pdus=[], **kwargs): """Provide some default fields for making a PduTuple.""" pdu_fields = { "state_key": None, "prev_events": prev_pdus, } pdu_fields.update(kwargs) return FrozenEvent(pdu_fields)
def _create_event(user_id): return FrozenEvent( { "room_id": TEST_ROOM_ID, "event_id": _get_event_id(), "type": "m.room.create", "sender": user_id, "content": {"creator": user_id}, } )
def _join_event(user_id): return FrozenEvent( { "room_id": TEST_ROOM_ID, "event_id": _get_event_id(), "type": "m.room.member", "sender": user_id, "state_key": user_id, "content": {"membership": "join"}, } )
def _random_state_event(sender): return FrozenEvent( { "room_id": TEST_ROOM_ID, "event_id": _get_event_id(), "type": "test.state", "sender": sender, "state_key": "", "content": {"membership": "join"}, } )
def test_msg(self): pdu = FrozenEvent({ "type": EventTypes.Message, "room_id": "foo", "content": { "msgtype": u"fooo" }, "origin_server_ts": 0, "event_id": "$a:b", "user_id": "@a:b", "origin": "b", "auth_events": [], "hashes": { "sha256": "AcLrgtUIqqwaGoHhrEvYG1YLDIsVPYJdSRGhkp3jJp8" }, }) self.datastore.persist_event.return_value = defer.succeed(None) self.datastore.get_room.return_value = defer.succeed(True) self.auth.check_host_in_room.return_value = defer.succeed(True) def have_events(event_ids): return defer.succeed({}) self.datastore.have_events.side_effect = have_events def annotate(ev, old_state=None): context = Mock() context.current_state = {} context.auth_events = {} return defer.succeed(context) self.state_handler.compute_event_context.side_effect = annotate yield self.handlers.federation_handler.on_receive_pdu("fo", pdu, False) self.datastore.persist_event.assert_called_once_with( ANY, is_new_state=True, backfilled=False, current_state=None, context=ANY, ) self.state_handler.compute_event_context.assert_called_once_with( ANY, old_state=None, ) self.auth.check.assert_called_once_with(ANY, auth_events={}) self.notifier.on_new_room_event.assert_called_once_with(ANY, extra_users=[])
def _get_event_from_row_txn(self, txn, internal_metadata, js, redacted, check_redacted=True, get_prev_content=False, rejected_reason=None): start_time = time.time() * 1000 def update_counter(desc, last_time): curr_time = self._get_event_counters.update(desc, last_time) sql_getevents_timer.inc_by(curr_time - last_time, desc) return curr_time d = json.loads(js) start_time = update_counter("decode_json", start_time) internal_metadata = json.loads(internal_metadata) start_time = update_counter("decode_internal", start_time) ev = FrozenEvent( d, internal_metadata_dict=internal_metadata, rejected_reason=rejected_reason, ) start_time = update_counter("build_frozen_event", start_time) if check_redacted and redacted: ev = prune_event(ev) ev.unsigned["redacted_by"] = redacted # Get the redaction event. because = self._get_event_txn( txn, redacted, check_redacted=False ) if because: ev.unsigned["redacted_because"] = because start_time = update_counter("redact_event", start_time) if get_prev_content and "replaces_state" in ev.unsigned: prev = self._get_event_txn( txn, ev.unsigned["replaces_state"], get_prev_content=False, ) if prev: ev.unsigned["prev_content"] = prev.get_dict()["content"] start_time = update_counter("get_prev_content", start_time) return ev
def _get_event_txn(self, txn, event_id, check_redacted=True, get_prev_content=True): sql = ( "SELECT internal_metadata, json, r.event_id FROM event_json as e " "LEFT JOIN redactions as r ON e.event_id = r.redacts " "WHERE e.event_id = ? " "LIMIT 1 ") txn.execute(sql, (event_id, )) res = txn.fetchone() if not res: return None internal_metadata, js, redacted = res d = json.loads(js) internal_metadata = json.loads(internal_metadata) ev = FrozenEvent(d, internal_metadata_dict=internal_metadata) if check_redacted and redacted: ev = prune_event(ev) ev.unsigned["redacted_by"] = redacted # Get the redaction event. because = self._get_event_txn(txn, redacted, check_redacted=False) if because: ev.unsigned["redacted_because"] = because if get_prev_content and "replaces_state" in ev.unsigned: prev = self._get_event_txn( txn, ev.unsigned["replaces_state"], get_prev_content=False, ) if prev: ev.unsigned["prev_content"] = prev.get_dict()["content"] return ev
def _get_evaluator(self, content): event = FrozenEvent( { "event_id": "$event_id", "type": "m.room.history_visibility", "sender": "@user:test", "state_key": "", "room_id": "#room:test", "content": content, }, RoomVersions.V1, ) room_member_count = 0 sender_power_level = 0 power_levels = {} return PushRuleEvaluatorForEvent(event, room_member_count, sender_power_level, power_levels)