def add_hashes_and_signatures( room_version: RoomVersion, event_dict: JsonDict, signature_name: str, signing_key: SigningKey, ) -> None: """Add content hash and sign the event Args: room_version: the version of the room this event is in event_dict: The event to add hashes to and sign signature_name: The name of the entity signing the event (typically the server's hostname). signing_key: The key to sign with """ name, digest = compute_content_hash(event_dict, hash_algorithm=hashlib.sha256) event_dict.setdefault("hashes", {})[name] = encode_base64(digest) event_dict["signatures"] = compute_event_signature( room_version, event_dict, signature_name=signature_name, signing_key=signing_key)
def create_local_event_from_event_dict( clock: Clock, hostname: str, signing_key: SigningKey, room_version: RoomVersion, event_dict: JsonDict, internal_metadata_dict: Optional[JsonDict] = None, ) -> EventBase: """Takes a fully formed event dict, ensuring that fields like `origin` and `origin_server_ts` have correct values for a locally produced event, then signs and hashes it. """ format_version = room_version.event_format if format_version not in KNOWN_EVENT_FORMAT_VERSIONS: raise Exception("No event format defined for version %r" % (format_version, )) if internal_metadata_dict is None: internal_metadata_dict = {} time_now = int(clock.time_msec()) if format_version == EventFormatVersions.V1: event_dict["event_id"] = _create_event_id(clock, hostname) event_dict["origin"] = hostname event_dict.setdefault("origin_server_ts", time_now) event_dict.setdefault("unsigned", {}) age = event_dict["unsigned"].pop("age", 0) event_dict["unsigned"].setdefault("age_ts", time_now - age) event_dict.setdefault("signatures", {}) add_hashes_and_signatures(room_version, event_dict, hostname, signing_key) return make_event_from_dict(event_dict, room_version, internal_metadata_dict=internal_metadata_dict)
def _inject_bundled_aggregations( self, event: EventBase, time_now: int, config: SerializeEventConfig, bundled_aggregations: Dict[str, "BundledAggregations"], serialized_event: JsonDict, apply_edits: bool, ) -> None: """Potentially injects bundled aggregations into the unsigned portion of the serialized event. Args: event: The event being serialized. time_now: The current time in milliseconds config: Event serialization config bundled_aggregations: Bundled aggregations to be injected. A map from event_id to aggregation data. Must contain at least an entry for `event`. While serializing the bundled aggregations this map may be searched again for additional events in a recursive manner. serialized_event: The serialized event which may be modified. apply_edits: Whether the content of the event should be modified to reflect any replacement in `aggregations.replace`. """ # We have already checked that aggregations exist for this event. event_aggregations = bundled_aggregations[event.event_id] # The JSON dictionary to be added under the unsigned property of the event # being serialized. serialized_aggregations = {} if event_aggregations.annotations: serialized_aggregations[ RelationTypes.ANNOTATION] = event_aggregations.annotations if event_aggregations.references: serialized_aggregations[ RelationTypes.REFERENCE] = event_aggregations.references if event_aggregations.replace: # If there is an edit, optionally apply it to the event. edit = event_aggregations.replace if apply_edits: self._apply_edit(event, serialized_event, edit) # Include information about it in the relations dict. serialized_aggregations[RelationTypes.REPLACE] = { "event_id": edit.event_id, "origin_server_ts": edit.origin_server_ts, "sender": edit.sender, } # Include any threaded replies to this event. if event_aggregations.thread: thread = event_aggregations.thread serialized_latest_event = self.serialize_event( thread.latest_event, time_now, config=config, bundle_aggregations=bundled_aggregations, ) thread_summary = { "latest_event": serialized_latest_event, "count": thread.count, "current_user_participated": thread.current_user_participated, } serialized_aggregations[RelationTypes.THREAD] = thread_summary # Include the bundled aggregations in the event. if serialized_aggregations: # There is likely already an "unsigned" field, but a filter might # have stripped it off (via the event_fields option). The server is # allowed to return additional fields, so add it back. serialized_event.setdefault("unsigned", {}).setdefault( "m.relations", {}).update(serialized_aggregations)