1
0

Update for v2.

This commit is contained in:
Patrick Cloke
2023-04-05 14:11:44 -04:00
parent 24647487a0
commit cf26b9f897
9 changed files with 78 additions and 84 deletions

View File

@@ -125,6 +125,8 @@ class EventTypes:
Reaction: Final = "m.reaction"
Hub: Final = "m.room.hub"
class ToDeviceEventTypes:
RoomKeyRequest: Final = "m.room_key_request"

View File

@@ -468,8 +468,13 @@ class RoomVersions:
msc3989_redaction_rules=True, # Used by MSC3820
linearized_matrix=False,
)
# Based on room version 11:
#
# - Enable MSC2176, MSC2175, MSC3989, MSC2174, MSC1767, MSC3821.
# - Disable 'restricted' and 'knock_restricted' join rules.
# - Mark as linearized.
LINEARIZED = RoomVersion(
"org.matrix.i-d.ralston-mimi-linearized-matrix.00",
"org.matrix.i-d.ralston-mimi-linearized-matrix.02",
RoomDisposition.UNSTABLE,
EventFormatVersions.LINEARIZED,
StateResolutionVersions.V2,
@@ -479,13 +484,13 @@ class RoomVersions:
limit_notifications_power_levels=True,
msc2175_implicit_room_creator=True,
msc2176_redaction_rules=True,
msc3083_join_rules=True,
msc3375_redaction_rules=True,
msc3083_join_rules=False,
msc3375_redaction_rules=False,
msc2403_knocking=True,
msc3389_relation_redactions=False,
msc3787_knock_restricted_join_rule=True,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=True,
msc3821_redaction_rules=False,
msc3821_redaction_rules=True,
msc3931_push_features=(),
msc3989_redaction_rules=True,
linearized_matrix=True,

View File

@@ -55,7 +55,7 @@ from synapse.types import (
if typing.TYPE_CHECKING:
# conditional imports to avoid import cycle
from synapse.events import EventBase, FrozenLinearizedEvent
from synapse.events import EventBase
from synapse.events.builder import EventBuilder
logger = logging.getLogger(__name__)
@@ -126,20 +126,13 @@ def validate_event_for_room_version(event: "EventBase") -> None:
raise AuthError(403, "Event not signed by sending server")
if event.format_version == EventFormatVersions.LINEARIZED:
assert isinstance(event, FrozenLinearizedEvent)
# TODO Are these handling DAG-native events properly? Is the null-checks
# a bypass?
# CHeck that the authorizing domain signed it.
owner_server = event.owner_server
if owner_server and not event.signatures.get(owner_server):
raise AuthError(403, "Event not signed by owner server")
# If this is a delegated PDU, check the original domain signed it.
delegated_server = event.delegated_server
if delegated_server and not event.signatures.get(delegated_server):
raise AuthError(403, "Event not signed by delegated server")
# Check that the hub server signed it.
hub_server = event.hub_server
if hub_server and not event.signatures.get(hub_server):
raise AuthError(403, "Event not signed by hub server")
is_invite_via_allow_rule = (
event.room_version.msc3083_join_rules
@@ -293,6 +286,13 @@ def check_state_dependent_auth_rules(
auth_dict = {(e.type, e.state_key): e for e in auth_events}
# If the event was sent from a hub server it must be the current hub server.
if event.room_version.linearized_matrix:
if event.hub_server:
current_hub_server = get_hub_server(auth_dict)
if current_hub_server != event.hub_server:
raise AuthError(403, "Event sent from incorrect hub server.")
# additional check for m.federate
creating_domain = get_domain_from_id(event.room_id)
originating_domain = get_domain_from_id(event.sender)
@@ -347,6 +347,12 @@ def check_state_dependent_auth_rules(
logger.debug("Allowing! %s", event)
return
# Hub events must be signed by the current hub.
if event.type == EventTypes.Hub:
current_hub_server = get_hub_server(auth_dict)
if not event.signatures.get(current_hub_server):
raise AuthError(403, "Unsigned hub event")
_can_send_event(event, auth_dict)
if event.type == EventTypes.PowerLevels:
@@ -1081,6 +1087,16 @@ def _verify_third_party_invite(
return False
def get_hub_server(auth_events: StateMap["EventBase"]) -> str:
# The current hub is the sender of the current hub event...
hub_event = auth_events.get((EventTypes.Hub, ""), None)
if not hub_event:
# ...or the room creator if there is no hub event.
hub_event = auth_events[(EventTypes.Create, "")]
return get_domain_from_id(hub_event.sender)
def get_public_keys(invite_event: "EventBase") -> List[Dict[str, Any]]:
public_keys = []
if "public_key" in invite_event.content:
@@ -1134,4 +1150,9 @@ def auth_types_for_event(
)
auth_types.add(key)
# Events sent from a hub server must reference the hub state-event, if one
# exists.
if event.hub_server:
auth_types.add((EventTypes.Hub, ""))
return auth_types

View File

@@ -335,12 +335,7 @@ class EventBase(metaclass=abc.ABCMeta):
type: DictProperty[str] = DictProperty("type")
user_id: DictProperty[str] = DictProperty("sender")
# Should only matter for Linearized Matrix.
owner_server: DictProperty[Optional[str]] = DefaultDictProperty(
"owner_server", None
)
delegated_server: DictProperty[Optional[str]] = DefaultDictProperty(
"delegated_server", None
)
hub_server: DictProperty[Optional[str]] = DefaultDictProperty("hub_server", None)
@property
def event_id(self) -> str:
@@ -615,31 +610,17 @@ class FrozenLinearizedEvent(FrozenEventV3):
"""The domain which added this event to the DAG.
It could be the authorized server or the sender."""
if self.delegated_server is not None:
return self.delegated_server
if self.hub_server is not None:
return self.hub_server
return super().pdu_domain
def get_linearized_pdu_json(self, /, delegated: bool) -> JsonDict:
# if delegated and self.delegated_server is None:
# # TODO Better error.
# raise ValueError("Invalid")
# TODO Is this form correct? Are there other fields?
result = {
"room_id": self.room_id,
"type": self.type,
# Should state key be left out if it isn't a state event?
"state_key": self.state_key,
"sender": self.sender,
"origin_server_ts": self.origin_server_ts,
# If we want the delegated version use the owner_server
# if it exists.
"owner_server": self.delegated_server,
"content": self.content,
"hashes": self.hashes,
}
if delegated and self.delegated_server:
result["delegated_server"] = self.delegated_server
return result
def get_linearized_pdu_json(self) -> JsonDict:
# Get the full PDU and then remove fields from it.
pdu = self.get_pdu_json()
pdu.pop("hashes")
pdu.pop("auth_events")
pdu.pop("prev_events")
return pdu
def _event_type_from_format_version(

View File

@@ -87,6 +87,9 @@ class EventBuilder:
_redacts: Optional[str] = None
_origin_server_ts: Optional[int] = None
# TODO(LM) If Synapse is acting as a hub-server this should be itself.
hub_server: Optional[str] = None
internal_metadata: _EventInternalMetadata = attr.Factory(
lambda: _EventInternalMetadata({})
)

View File

@@ -65,9 +65,6 @@ def prune_event(event: EventBase) -> EventBase:
type, state_key etc.
"""
# TODO Check users of prune_event and prune_event_dict to ensure they shouldn't
# be doing something with linearized matrix.
pruned_event_dict = prune_event_dict(event.room_version, event.get_dict())
from . import make_event_from_dict
@@ -115,6 +112,9 @@ def prune_event_dict(room_version: RoomVersion, event_dict: JsonDict) -> JsonDic
# Room versions from before MSC2176 had additional allowed keys.
if not room_version.msc2176_redaction_rules:
allowed_keys.extend(["prev_state", "membership"])
# The hub server should not be redacted for linear matrix.
if room_version.linearized_matrix:
allowed_keys.append("hub_server")
# Room versions before MSC3989 kept the origin field.
if not room_version.msc3989_redaction_rules:

View File

@@ -21,7 +21,7 @@ from synapse.api.room_versions import EventFormatVersions, RoomVersion
from synapse.crypto.event_signing import check_event_content_hash
from synapse.crypto.keyring import Keyring
from synapse.events import EventBase, FrozenLinearizedEvent, make_event_from_dict
from synapse.events.utils import prune_event, validate_canonicaljson
from synapse.events.utils import prune_event, prune_event_dict, validate_canonicaljson
from synapse.http.servlet import assert_params_in_dict
from synapse.logging.opentracing import log_kv, trace
from synapse.types import JsonDict, get_domain_from_id
@@ -174,7 +174,7 @@ async def _check_sigs_on_pdu(
# we want to check that the event is signed by:
#
# (a) the sender's (or the delagated sender's) server
# (a) the sender's server or the hub
#
# - except in the case of invites created from a 3pid invite, which are exempt
# from this check, because the sender has to match that of the original 3pid
@@ -250,50 +250,26 @@ async def _check_sigs_on_pdu(
pdu.event_id,
) from None
# If this is a linearized PDU we may need to check signatures of the owner
# If this is a linearized PDU we may need to check signatures of the hub
# and sender.
if room_version.event_format == EventFormatVersions.LINEARIZED:
assert isinstance(pdu, FrozenLinearizedEvent)
# Check that the fields are not invalid.
if pdu.delegated_server and not pdu.owner_server:
raise InvalidEventSignatureError(
"PDU missing owner_server", pdu.event_id
) from None
# If the event was sent from a linear server, check the authorized server.
# If the event was sent via a hub server, check the signature of the
# sender against the Linear PDU. (But only if the sender isn't the hub.)
#
# Note that the signature of the delegated server, if one exists, is
# checked against the full PDU above.
if pdu.owner_server:
# Construct the Linear PDU and check the signature against the sender.
#
# If the owner & sender are the same, then only a Delegated Linear PDU
# is created (the Linear PDU is not signed by itself).
if pdu.owner_server != sender_domain:
try:
await keyring.verify_json_for_server(
sender_domain,
pdu.get_linearized_pdu_json(delegated=False),
origin_server_ts_for_signing,
)
except Exception as e:
raise InvalidEventSignatureError(
f"unable to verify signature for sender {sender_domain}: {e}",
pdu.event_id,
) from None
# Construct the Delegated Linear PDU and check the signature
# against owner_server.
# Note that the signature of the hub server, if one exists, is checked
# against the full PDU above.
if pdu.hub_server and pdu.hub_server != sender_domain:
try:
await keyring.verify_json_for_server(
pdu.owner_server,
pdu.get_linearized_pdu_json(delegated=True),
sender_domain,
prune_event_dict(pdu.room_version, pdu.get_linearized_pdu_json()),
origin_server_ts_for_signing,
)
except Exception as e:
raise InvalidEventSignatureError(
f"unable to verify signature for owner_server {pdu.owner_server}: {e}",
f"unable to verify signature for sender {sender_domain}: {e}",
pdu.event_id,
) from None

View File

@@ -290,6 +290,11 @@ class FederationServer(FederationBase):
# accurate as possible.
request_time = self._clock.time_msec()
# TODO(LM): If we are the hub server and the destination is a participant
# server then pdus are Linear PDUs.
#
# TODO(LM): If we are the hub's DAG server we need to linearize and give
# it the results.
transaction = Transaction(
transaction_id=transaction_id,
destination=destination,

View File

@@ -85,6 +85,7 @@ class FakeEvent:
self.state_key = state_key
self.content = content
self.room_id = ROOM_ID
self.hub_server = None
def to_event(self, auth_events: List[str], prev_events: List[str]) -> EventBase:
"""Given the auth_events and prev_events, convert to a Frozen Event