25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 
 
 

301 satır
9.7 KiB

  1. # Copyright 2014-2016 OpenMarket Ltd
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import logging
  15. from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
  16. import attr
  17. from signedjson.types import SigningKey
  18. from synapse.api.constants import MAX_DEPTH
  19. from synapse.api.room_versions import (
  20. KNOWN_EVENT_FORMAT_VERSIONS,
  21. EventFormatVersions,
  22. RoomVersion,
  23. )
  24. from synapse.crypto.event_signing import add_hashes_and_signatures
  25. from synapse.event_auth import auth_types_for_event
  26. from synapse.events import EventBase, _EventInternalMetadata, make_event_from_dict
  27. from synapse.state import StateHandler
  28. from synapse.storage.databases.main import DataStore
  29. from synapse.types import EventID, JsonDict, StrCollection
  30. from synapse.types.state import StateFilter
  31. from synapse.util import Clock
  32. from synapse.util.stringutils import random_string
  33. if TYPE_CHECKING:
  34. from synapse.handlers.event_auth import EventAuthHandler
  35. from synapse.server import HomeServer
  36. logger = logging.getLogger(__name__)
  37. @attr.s(slots=True, cmp=False, frozen=True, auto_attribs=True)
  38. class EventBuilder:
  39. """A format independent event builder used to build up the event content
  40. before signing the event.
  41. (Note that while objects of this class are frozen, the
  42. content/unsigned/internal_metadata fields are still mutable)
  43. Attributes:
  44. room_version: Version of the target room
  45. room_id
  46. type
  47. sender
  48. content
  49. unsigned
  50. internal_metadata
  51. _state
  52. _auth
  53. _store
  54. _clock
  55. _hostname: The hostname of the server creating the event
  56. _signing_key: The signing key to use to sign the event as the server
  57. """
  58. _state: StateHandler
  59. _event_auth_handler: "EventAuthHandler"
  60. _store: DataStore
  61. _clock: Clock
  62. _hostname: str
  63. _signing_key: SigningKey
  64. room_version: RoomVersion
  65. room_id: str
  66. type: str
  67. sender: str
  68. content: JsonDict = attr.Factory(dict)
  69. unsigned: JsonDict = attr.Factory(dict)
  70. # These only exist on a subset of events, so they raise AttributeError if
  71. # someone tries to get them when they don't exist.
  72. _state_key: Optional[str] = None
  73. _redacts: Optional[str] = None
  74. _origin_server_ts: Optional[int] = None
  75. internal_metadata: _EventInternalMetadata = attr.Factory(
  76. lambda: _EventInternalMetadata({})
  77. )
  78. @property
  79. def state_key(self) -> str:
  80. if self._state_key is not None:
  81. return self._state_key
  82. raise AttributeError("state_key")
  83. def is_state(self) -> bool:
  84. return self._state_key is not None
  85. async def build(
  86. self,
  87. prev_event_ids: StrCollection,
  88. auth_event_ids: Optional[List[str]],
  89. depth: Optional[int] = None,
  90. ) -> EventBase:
  91. """Transform into a fully signed and hashed event
  92. Args:
  93. prev_event_ids: The event IDs to use as the prev events
  94. auth_event_ids: The event IDs to use as the auth events.
  95. Should normally be set to None, which will cause them to be calculated
  96. based on the room state at the prev_events.
  97. depth: Override the depth used to order the event in the DAG.
  98. Should normally be set to None, which will cause the depth to be calculated
  99. based on the prev_events.
  100. Returns:
  101. The signed and hashed event.
  102. """
  103. if auth_event_ids is None:
  104. state_ids = await self._state.compute_state_after_events(
  105. self.room_id,
  106. prev_event_ids,
  107. state_filter=StateFilter.from_types(
  108. auth_types_for_event(self.room_version, self)
  109. ),
  110. await_full_state=False,
  111. )
  112. auth_event_ids = self._event_auth_handler.compute_auth_events(
  113. self, state_ids
  114. )
  115. format_version = self.room_version.event_format
  116. # The types of auth/prev events changes between event versions.
  117. prev_events: Union[StrCollection, List[Tuple[str, Dict[str, str]]]]
  118. auth_events: Union[List[str], List[Tuple[str, Dict[str, str]]]]
  119. if format_version == EventFormatVersions.ROOM_V1_V2:
  120. auth_events = await self._store.add_event_hashes(auth_event_ids)
  121. prev_events = await self._store.add_event_hashes(prev_event_ids)
  122. else:
  123. auth_events = auth_event_ids
  124. prev_events = prev_event_ids
  125. # Otherwise, progress the depth as normal
  126. if depth is None:
  127. (
  128. _,
  129. most_recent_prev_event_depth,
  130. ) = await self._store.get_max_depth_of(prev_event_ids)
  131. depth = most_recent_prev_event_depth + 1
  132. # we cap depth of generated events, to ensure that they are not
  133. # rejected by other servers (and so that they can be persisted in
  134. # the db)
  135. depth = min(depth, MAX_DEPTH)
  136. event_dict: Dict[str, Any] = {
  137. "auth_events": auth_events,
  138. "prev_events": prev_events,
  139. "type": self.type,
  140. "room_id": self.room_id,
  141. "sender": self.sender,
  142. "content": self.content,
  143. "unsigned": self.unsigned,
  144. "depth": depth,
  145. }
  146. if self.is_state():
  147. event_dict["state_key"] = self._state_key
  148. # MSC2174 moves the redacts property to the content, it is invalid to
  149. # provide it as a top-level property.
  150. if self._redacts is not None and not self.room_version.updated_redaction_rules:
  151. event_dict["redacts"] = self._redacts
  152. if self._origin_server_ts is not None:
  153. event_dict["origin_server_ts"] = self._origin_server_ts
  154. return create_local_event_from_event_dict(
  155. clock=self._clock,
  156. hostname=self._hostname,
  157. signing_key=self._signing_key,
  158. room_version=self.room_version,
  159. event_dict=event_dict,
  160. internal_metadata_dict=self.internal_metadata.get_dict(),
  161. )
  162. class EventBuilderFactory:
  163. def __init__(self, hs: "HomeServer"):
  164. self.clock = hs.get_clock()
  165. self.hostname = hs.hostname
  166. self.signing_key = hs.signing_key
  167. self.store = hs.get_datastores().main
  168. self.state = hs.get_state_handler()
  169. self._event_auth_handler = hs.get_event_auth_handler()
  170. def for_room_version(
  171. self, room_version: RoomVersion, key_values: dict
  172. ) -> EventBuilder:
  173. """Generate an event builder appropriate for the given room version
  174. Args:
  175. room_version:
  176. Version of the room that we're creating an event builder for
  177. key_values: Fields used as the basis of the new event
  178. Returns:
  179. EventBuilder
  180. """
  181. return EventBuilder(
  182. store=self.store,
  183. state=self.state,
  184. event_auth_handler=self._event_auth_handler,
  185. clock=self.clock,
  186. hostname=self.hostname,
  187. signing_key=self.signing_key,
  188. room_version=room_version,
  189. type=key_values["type"],
  190. state_key=key_values.get("state_key"),
  191. room_id=key_values["room_id"],
  192. sender=key_values["sender"],
  193. content=key_values.get("content", {}),
  194. unsigned=key_values.get("unsigned", {}),
  195. redacts=key_values.get("redacts", None),
  196. origin_server_ts=key_values.get("origin_server_ts", None),
  197. )
  198. def create_local_event_from_event_dict(
  199. clock: Clock,
  200. hostname: str,
  201. signing_key: SigningKey,
  202. room_version: RoomVersion,
  203. event_dict: JsonDict,
  204. internal_metadata_dict: Optional[JsonDict] = None,
  205. ) -> EventBase:
  206. """Takes a fully formed event dict, ensuring that fields like `origin`
  207. and `origin_server_ts` have correct values for a locally produced event,
  208. then signs and hashes it.
  209. """
  210. format_version = room_version.event_format
  211. if format_version not in KNOWN_EVENT_FORMAT_VERSIONS:
  212. raise Exception("No event format defined for version %r" % (format_version,))
  213. if internal_metadata_dict is None:
  214. internal_metadata_dict = {}
  215. time_now = int(clock.time_msec())
  216. if format_version == EventFormatVersions.ROOM_V1_V2:
  217. event_dict["event_id"] = _create_event_id(clock, hostname)
  218. event_dict["origin"] = hostname
  219. event_dict.setdefault("origin_server_ts", time_now)
  220. event_dict.setdefault("unsigned", {})
  221. age = event_dict["unsigned"].pop("age", 0)
  222. event_dict["unsigned"].setdefault("age_ts", time_now - age)
  223. event_dict.setdefault("signatures", {})
  224. add_hashes_and_signatures(room_version, event_dict, hostname, signing_key)
  225. return make_event_from_dict(
  226. event_dict, room_version, internal_metadata_dict=internal_metadata_dict
  227. )
  228. # A counter used when generating new event IDs
  229. _event_id_counter = 0
  230. def _create_event_id(clock: Clock, hostname: str) -> str:
  231. """Create a new event ID
  232. Args:
  233. clock
  234. hostname: The server name for the event ID
  235. Returns:
  236. The new event ID
  237. """
  238. global _event_id_counter
  239. i = str(_event_id_counter)
  240. _event_id_counter += 1
  241. local_part = str(int(clock.time())) + i + random_string(5)
  242. e_id = EventID(local_part, hostname)
  243. return e_id.to_string()