diff options
author | Richard van der Hoff <1389908+richvdh@users.noreply.github.com> | 2020-10-15 20:55:41 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-15 20:55:41 +0100 |
commit | 5649669c3ca770768c3e121aaf5189064c6a0acd (patch) | |
tree | ca387ad15fc170552017e8e18b49393a3266f7ea /synapse/handlers/message.py | |
parent | Solidify the HomeServer constructor. (#8515) (diff) | |
parent | changelog (diff) | |
download | synapse-5649669c3ca770768c3e121aaf5189064c6a0acd.tar.xz |
Merge pull request #8535 from matrix-org/rav/third_party_events_updates
Support modifying event content from ThirdPartyRules modules
Diffstat (limited to '')
-rw-r--r-- | synapse/handlers/message.py | 79 |
1 files changed, 71 insertions, 8 deletions
diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py index f18f882596..7f00805a91 100644 --- a/synapse/handlers/message.py +++ b/synapse/handlers/message.py @@ -811,6 +811,23 @@ class EventCreationHandler: if requester: context.app_service = requester.app_service + third_party_result = await self.third_party_event_rules.check_event_allowed( + event, context + ) + if not third_party_result: + logger.info( + "Event %s forbidden by third-party rules", event, + ) + raise SynapseError( + 403, "This event is not allowed in this context", Codes.FORBIDDEN + ) + elif isinstance(third_party_result, dict): + # the third-party rules want to replace the event. We'll need to build a new + # event. + event, context = await self._rebuild_event_after_third_party_rules( + third_party_result, event + ) + self.validator.validate_new(event, self.config) # If this event is an annotation then we check that that the sender @@ -897,14 +914,6 @@ class EventCreationHandler: else: room_version = await self.store.get_room_version_id(event.room_id) - event_allowed = await self.third_party_event_rules.check_event_allowed( - event, context - ) - if not event_allowed: - raise SynapseError( - 403, "This event is not allowed in this context", Codes.FORBIDDEN - ) - if event.internal_metadata.is_out_of_band_membership(): # the only sort of out-of-band-membership events we expect to see here # are invite rejections we have generated ourselves. @@ -1307,3 +1316,57 @@ class EventCreationHandler: room_id, ) del self._rooms_to_exclude_from_dummy_event_insertion[room_id] + + async def _rebuild_event_after_third_party_rules( + self, third_party_result: dict, original_event: EventBase + ) -> Tuple[EventBase, EventContext]: + # the third_party_event_rules want to replace the event. + # we do some basic checks, and then return the replacement event and context. + + # Construct a new EventBuilder and validate it, which helps with the + # rest of these checks. + try: + builder = self.event_builder_factory.for_room_version( + original_event.room_version, third_party_result + ) + self.validator.validate_builder(builder) + except SynapseError as e: + raise Exception( + "Third party rules module created an invalid event: " + e.msg, + ) + + immutable_fields = [ + # changing the room is going to break things: we've already checked that the + # room exists, and are holding a concurrency limiter token for that room. + # Also, we might need to use a different room version. + "room_id", + # changing the type or state key might work, but we'd need to check that the + # calling functions aren't making assumptions about them. + "type", + "state_key", + ] + + for k in immutable_fields: + if getattr(builder, k, None) != original_event.get(k): + raise Exception( + "Third party rules module created an invalid event: " + "cannot change field " + k + ) + + # check that the new sender belongs to this HS + if not self.hs.is_mine_id(builder.sender): + raise Exception( + "Third party rules module created an invalid event: " + "invalid sender " + builder.sender + ) + + # copy over the original internal metadata + for k, v in original_event.internal_metadata.get_dict().items(): + setattr(builder.internal_metadata, k, v) + + event = await builder.build(prev_event_ids=original_event.prev_event_ids()) + + # we rebuild the event context, to be on the safe side. If nothing else, + # delta_ids might need an update. + context = await self.state.compute_event_context(event) + return event, context |