15
15
16
16
import logging
17
17
import typing
18
- from typing import Any , Dict , Iterable , List , Optional , Set , Tuple , Union
18
+ from typing import Any , Collection , Dict , Iterable , List , Optional , Set , Tuple , Union
19
19
20
20
from canonicaljson import encode_canonical_json
21
21
from signedjson .key import decode_verify_key_bytes
22
22
from signedjson .sign import SignatureVerifyException , verify_signed_json
23
+ from typing_extensions import Protocol
23
24
from unpaddedbase64 import decode_base64
24
25
25
26
from synapse .api .constants import (
35
36
EventFormatVersions ,
36
37
RoomVersion ,
37
38
)
38
- from synapse .types import StateMap , UserID , get_domain_from_id
39
+ from synapse .storage .databases .main .events_worker import EventRedactBehaviour
40
+ from synapse .types import MutableStateMap , StateMap , UserID , get_domain_from_id
39
41
40
42
if typing .TYPE_CHECKING :
41
43
# conditional imports to avoid import cycle
45
47
logger = logging .getLogger (__name__ )
46
48
47
49
50
+ class _EventSourceStore (Protocol ):
51
+ async def get_events (
52
+ self ,
53
+ event_ids : Collection [str ],
54
+ redact_behaviour : EventRedactBehaviour ,
55
+ get_prev_content : bool = False ,
56
+ allow_rejected : bool = False ,
57
+ ) -> Dict [str , "EventBase" ]:
58
+ ...
59
+
60
+
48
61
def validate_event_for_room_version (event : "EventBase" ) -> None :
49
62
"""Ensure that the event complies with the limits, and has the right signatures
50
63
@@ -112,54 +125,61 @@ def validate_event_for_room_version(event: "EventBase") -> None:
112
125
raise AuthError (403 , "Event not signed by authorising server" )
113
126
114
127
115
- def check_auth_rules_for_event (
128
+ async def check_state_independent_auth_rules (
129
+ store : _EventSourceStore ,
116
130
event : "EventBase" ,
117
- auth_events : Iterable ["EventBase" ],
118
131
) -> None :
119
- """Check that an event complies with the auth rules
120
-
121
- Checks whether an event passes the auth rules with a given set of state events
122
-
123
- Assumes that we have already checked that the event is the right shape (it has
124
- enough signatures, has a room ID, etc). In other words:
125
-
126
- - it's fine for use in state resolution, when we have already decided whether to
127
- accept the event or not, and are now trying to decide whether it should make it
128
- into the room state
132
+ """Check that an event complies with auth rules that are independent of room state
129
133
130
- - when we're doing the initial event auth, it is only suitable in combination with
131
- a bunch of other tests.
134
+ Runs through the first few auth rules, which are independent of room state. (Which
135
+ means that we only need to them once for each received event)
132
136
133
137
Args:
138
+ store: the datastore; used to fetch the auth events for validation
134
139
event: the event being checked.
135
- auth_events: the room state to check the events against.
136
140
137
141
Raises:
138
142
AuthError if the checks fail
139
143
"""
140
- # We need to ensure that the auth events are actually for the same room, to
141
- # stop people from using powers they've been granted in other rooms for
142
- # example.
143
- #
144
- # Arguably we don't need to do this when we're just doing state res, as presumably
145
- # the state res algorithm isn't silly enough to give us events from different rooms.
146
- # Still, it's easier to do it anyway.
144
+ # Check the auth events.
145
+ auth_events = await store .get_events (
146
+ event .auth_event_ids (),
147
+ redact_behaviour = EventRedactBehaviour .as_is ,
148
+ allow_rejected = True ,
149
+ )
147
150
room_id = event .room_id
148
- for auth_event in auth_events :
151
+ auth_dict : MutableStateMap [str ] = {}
152
+ for auth_event_id in event .auth_event_ids ():
153
+ auth_event = auth_events .get (auth_event_id )
154
+
155
+ # we should have all the auth events by now, so if we do not, that suggests
156
+ # a synapse programming error
157
+ if auth_event is None :
158
+ raise RuntimeError (
159
+ f"Event { event .event_id } has unknown auth event { auth_event_id } "
160
+ )
161
+
162
+ # We need to ensure that the auth events are actually for the same room, to
163
+ # stop people from using powers they've been granted in other rooms for
164
+ # example.
149
165
if auth_event .room_id != room_id :
150
166
raise AuthError (
151
167
403 ,
152
168
"During auth for event %s in room %s, found event %s in the state "
153
169
"which is in room %s"
154
- % (event .event_id , room_id , auth_event . event_id , auth_event .room_id ),
170
+ % (event .event_id , room_id , auth_event_id , auth_event .room_id ),
155
171
)
172
+
173
+ # We also need to check that the auth event itself is not rejected.
156
174
if auth_event .rejected_reason :
157
175
raise AuthError (
158
176
403 ,
159
177
"During auth for event %s: found rejected event %s in the state"
160
178
% (event .event_id , auth_event .event_id ),
161
179
)
162
180
181
+ auth_dict [(auth_event .type , auth_event .state_key )] = auth_event_id
182
+
163
183
# Implementation of https://matrix.org/docs/spec/rooms/v1#authorization-rules
164
184
#
165
185
# 1. If type is m.room.create:
@@ -181,16 +201,46 @@ def check_auth_rules_for_event(
181
201
"room appears to have unsupported version %s" % (room_version_prop ,),
182
202
)
183
203
184
- logger .debug ("Allowing! %s" , event )
185
204
return
186
205
187
- auth_dict = {(e .type , e .state_key ): e for e in auth_events }
188
-
189
206
# 3. If event does not have a m.room.create in its auth_events, reject.
190
207
creation_event = auth_dict .get ((EventTypes .Create , "" ), None )
191
208
if not creation_event :
192
209
raise AuthError (403 , "No create event in auth events" )
193
210
211
+
212
+ def check_state_dependent_auth_rules (
213
+ event : "EventBase" ,
214
+ auth_events : Iterable ["EventBase" ],
215
+ ) -> None :
216
+ """Check that an event complies with auth rules that depend on room state
217
+
218
+ Runs through the parts of the auth rules that check an event against bits of room
219
+ state.
220
+
221
+ Note:
222
+
223
+ - it's fine for use in state resolution, when we have already decided whether to
224
+ accept the event or not, and are now trying to decide whether it should make it
225
+ into the room state
226
+
227
+ - when we're doing the initial event auth, it is only suitable in combination with
228
+ a bunch of other tests (including, but not limited to, check_state_independent_auth_rules).
229
+
230
+ Args:
231
+ event: the event being checked.
232
+ auth_events: the room state to check the events against.
233
+
234
+ Raises:
235
+ AuthError if the checks fail
236
+ """
237
+ # there are no state-dependent auth rules for create events.
238
+ if event .type == EventTypes .Create :
239
+ logger .debug ("Allowing! %s" , event )
240
+ return
241
+
242
+ auth_dict = {(e .type , e .state_key ): e for e in auth_events }
243
+
194
244
# additional check for m.federate
195
245
creating_domain = get_domain_from_id (event .room_id )
196
246
originating_domain = get_domain_from_id (event .sender )
0 commit comments