Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Rejections #43

Merged
merged 18 commits into from
Jan 30, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
c92d64a
Make it the responsibility of the replication layer to check signatur…
erikjohnston Jan 26, 2015
0ef5bfd
Start implementing auth conflict res
erikjohnston Jan 28, 2015
c183cec
Add post_json(...) method to federation client
erikjohnston Jan 29, 2015
5a3a15f
Make post_json(...) actually send data.
erikjohnston Jan 29, 2015
7801594
Initial implementation of auth conflict resolution
erikjohnston Jan 29, 2015
c1c7b39
Fix bug where we changes in outlier in metadata dict propogated to ot…
erikjohnston Jan 30, 2015
c1d8608
Fix regression where we no longer correctly handled the case of gaps …
erikjohnston Jan 30, 2015
8239997
Fix bug in timeout handling in keyclient
erikjohnston Jan 30, 2015
0c2d245
Update the current state of an event if we update auth events.
erikjohnston Jan 30, 2015
2ebf795
Merge branch 'develop' of github.com:matrix-org/synapse into rejections
erikjohnston Jan 30, 2015
2c9e136
Fix bad merge fo python_dependencies.py
erikjohnston Jan 30, 2015
0adf3e5
Revert accidental bumping of angluar_sdk dep
erikjohnston Jan 30, 2015
a70a801
Fix bug where we superfluously asked for current state. Change API of…
erikjohnston Jan 30, 2015
c515d37
Merge branch 'replication_split' of github.com:matrix-org/synapse int…
erikjohnston Jan 30, 2015
1bd540e
Merge branch 'develop' of github.com:matrix-org/synapse into rejections
erikjohnston Jan 30, 2015
7a1e881
Remove debug logging
erikjohnston Jan 30, 2015
b724a80
Only auth_events with event if event in event.auth_events
erikjohnston Jan 30, 2015
776ac82
Briefly doc structure of query_auth API.
erikjohnston Jan 30, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 23 additions & 17 deletions synapse/api/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ def check_joined_room(self, room_id, user_id):
def check_host_in_room(self, room_id, host):
curr_state = yield self.state.get_current_state(room_id)

logger.debug("Got curr_state %s", curr_state)

for event in curr_state:
if event.type == EventTypes.Member:
try:
Expand Down Expand Up @@ -358,9 +360,23 @@ def is_server_admin(self, user):
def add_auth_events(self, builder, context):
yield run_on_reactor()

if builder.type == EventTypes.Create:
builder.auth_events = []
return
auth_ids = self.compute_auth_events(builder, context)

auth_events_entries = yield self.store.add_event_hashes(
auth_ids
)

builder.auth_events = auth_events_entries

context.auth_events = {
k: v
for k, v in context.current_state.items()
if v.event_id in auth_ids
}

def compute_auth_events(self, event, context):
if event.type == EventTypes.Create:
return []

auth_ids = []

Expand All @@ -373,7 +389,7 @@ def add_auth_events(self, builder, context):
key = (EventTypes.JoinRules, "", )
join_rule_event = context.current_state.get(key)

key = (EventTypes.Member, builder.user_id, )
key = (EventTypes.Member, event.user_id, )
member_event = context.current_state.get(key)

key = (EventTypes.Create, "", )
Expand All @@ -387,8 +403,8 @@ def add_auth_events(self, builder, context):
else:
is_public = False

if builder.type == EventTypes.Member:
e_type = builder.content["membership"]
if event.type == EventTypes.Member:
e_type = event.content["membership"]
if e_type in [Membership.JOIN, Membership.INVITE]:
if join_rule_event:
auth_ids.append(join_rule_event.event_id)
Expand All @@ -403,17 +419,7 @@ def add_auth_events(self, builder, context):
if member_event.content["membership"] == Membership.JOIN:
auth_ids.append(member_event.event_id)

auth_events_entries = yield self.store.add_event_hashes(
auth_ids
)

builder.auth_events = auth_events_entries

context.auth_events = {
k: v
for k, v in context.current_state.items()
if v.event_id in auth_ids
}
return auth_ids

@log_function
def _can_send_event(self, event, auth_events):
Expand Down
6 changes: 6 additions & 0 deletions synapse/api/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,9 @@ class EventTypes(object):
Message = "m.room.message"
Topic = "m.room.topic"
Name = "m.room.name"


class RejectedReason(object):
AUTH_ERROR = "auth_error"
REPLACED = "replaced"
NOT_ANCESTOR = "not_ancestor"
7 changes: 4 additions & 3 deletions synapse/crypto/keyclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,11 @@ class SynapseKeyClientProtocol(HTTPClient):

def __init__(self):
self.remote_key = defer.Deferred()
self.host = None

def connectionMade(self):
logger.debug("Connected to %s", self.transport.getHost())
self.host = self.transport.getHost()
logger.debug("Connected to %s", self.host)
self.sendCommand(b"GET", b"/_matrix/key/v1/")
self.endHeaders()
self.timer = reactor.callLater(
Expand Down Expand Up @@ -92,8 +94,7 @@ def handleResponse(self, response_body_bytes):
self.timer.cancel()

def on_timeout(self):
logger.debug("Timeout waiting for response from %s",
self.transport.getHost())
logger.debug("Timeout waiting for response from %s", self.host)
self.remote_key.errback(IOError("Timeout waiting for response"))
self.transport.abortConnection()

Expand Down
2 changes: 1 addition & 1 deletion synapse/events/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

class _EventInternalMetadata(object):
def __init__(self, internal_metadata_dict):
self.__dict__ = internal_metadata_dict
self.__dict__ = dict(internal_metadata_dict)

def get_dict(self):
return dict(self.__dict__)
Expand Down
5 changes: 3 additions & 2 deletions synapse/events/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@


class EventBuilder(EventBase):
def __init__(self, key_values={}):
def __init__(self, key_values={}, internal_metadata_dict={}):
signatures = copy.deepcopy(key_values.pop("signatures", {}))
unsigned = copy.deepcopy(key_values.pop("unsigned", {}))

super(EventBuilder, self).__init__(
key_values,
signatures=signatures,
unsigned=unsigned
unsigned=unsigned,
internal_metadata_dict=internal_metadata_dict,
)

def build(self):
Expand Down
11 changes: 8 additions & 3 deletions synapse/events/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ def prune_event(event):
"membership",
]

event_dict = event.get_dict()

new_content = {}

def add_fields(*fields):
for field in fields:
if field in event.content:
new_content[field] = event.content[field]
new_content[field] = event_dict["content"][field]

if event_type == EventTypes.Member:
add_fields("membership")
Expand All @@ -75,7 +77,7 @@ def add_fields(*fields):

allowed_fields = {
k: v
for k, v in event.get_dict().items()
for k, v in event_dict.items()
if k in allowed_keys
}

Expand All @@ -86,7 +88,10 @@ def add_fields(*fields):
if "age_ts" in event.unsigned:
allowed_fields["unsigned"]["age_ts"] = event.unsigned["age_ts"]

return type(event)(allowed_fields)
return type(event)(
allowed_fields,
internal_metadata_dict=event.internal_metadata.get_dict()
)


def serialize_event(e, time_now_ms, client_event=True):
Expand Down
142 changes: 129 additions & 13 deletions synapse/federation/federation_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@

from synapse.util.logutils import log_function
from synapse.events import FrozenEvent
from synapse.events.utils import prune_event

from syutil.jsonutil import encode_canonical_json

from synapse.crypto.event_signing import check_event_content_hash

from synapse.api.errors import SynapseError

import logging

Expand Down Expand Up @@ -126,6 +133,11 @@ def backfill(self, dest, context, limit, extremities):
for p in transaction_data["pdus"]
]

for i, pdu in enumerate(pdus):
pdus[i] = yield self._check_sigs_and_hash(pdu)

# FIXME: We should handle signature failures more gracefully.

defer.returnValue(pdus)

@defer.inlineCallbacks
Expand Down Expand Up @@ -159,25 +171,29 @@ def get_pdu(self, destinations, event_id, outlier=False):
transaction_data = yield self.transport_layer.get_event(
destination, event_id
)

logger.debug("transaction_data %r", transaction_data)

pdu_list = [
self.event_from_pdu_json(p, outlier=outlier)
for p in transaction_data["pdus"]
]

if pdu_list:
pdu = pdu_list[0]

# Check signatures are correct.
pdu = yield self._check_sigs_and_hash(pdu)

break

except Exception as e:
logger.info(
"Failed to get PDU %s from %s because %s",
event_id, destination, e,
)
continue

logger.debug("transaction_data %r", transaction_data)

pdu_list = [
self.event_from_pdu_json(p, outlier=outlier)
for p in transaction_data["pdus"]
]

if pdu_list:
pdu = pdu_list[0]
# TODO: We need to check signatures here
break

defer.returnValue(pdu)

@defer.inlineCallbacks
Expand Down Expand Up @@ -208,6 +224,16 @@ def get_state_for_room(self, destination, room_id, event_id):
for p in result.get("auth_chain", [])
]

for i, pdu in enumerate(pdus):
pdus[i] = yield self._check_sigs_and_hash(pdu)

# FIXME: We should handle signature failures more gracefully.

for i, pdu in enumerate(auth_chain):
auth_chain[i] = yield self._check_sigs_and_hash(pdu)

# FIXME: We should handle signature failures more gracefully.

defer.returnValue((pdus, auth_chain))

@defer.inlineCallbacks
Expand All @@ -222,6 +248,11 @@ def get_event_auth(self, destination, room_id, event_id):
for p in res["auth_chain"]
]

for i, pdu in enumerate(auth_chain):
auth_chain[i] = yield self._check_sigs_and_hash(pdu)

# FIXME: We should handle signature failures more gracefully.

auth_chain.sort(key=lambda e: e.depth)

defer.returnValue(auth_chain)
Expand Down Expand Up @@ -260,6 +291,16 @@ def send_join(self, destination, pdu):
for p in content.get("auth_chain", [])
]

for i, pdu in enumerate(state):
state[i] = yield self._check_sigs_and_hash(pdu)

# FIXME: We should handle signature failures more gracefully.

for i, pdu in enumerate(auth_chain):
auth_chain[i] = yield self._check_sigs_and_hash(pdu)

# FIXME: We should handle signature failures more gracefully.

auth_chain.sort(key=lambda e: e.depth)

defer.returnValue({
Expand All @@ -281,7 +322,48 @@ def send_invite(self, destination, room_id, event_id, pdu):

logger.debug("Got response to send_invite: %s", pdu_dict)

defer.returnValue(self.event_from_pdu_json(pdu_dict))
pdu = self.event_from_pdu_json(pdu_dict)

# Check signatures are correct.
pdu = yield self._check_sigs_and_hash(pdu)

# FIXME: We should handle signature failures more gracefully.

defer.returnValue(pdu)

@defer.inlineCallbacks
def query_auth(self, destination, room_id, event_id, local_auth):
"""
Params:
destination (str)
event_it (str)
local_auth (list)
"""
time_now = self._clock.time_msec()

send_content = {
"auth_chain": [e.get_pdu_json(time_now) for e in local_auth],
}

code, content = yield self.transport_layer.send_query_auth(
destination=destination,
room_id=room_id,
event_id=event_id,
content=send_content,
)

auth_chain = [
(yield self._check_sigs_and_hash(self.event_from_pdu_json(e)))
for e in content["auth_chain"]
]

ret = {
"auth_chain": auth_chain,
"rejects": content.get("rejects", []),
"missing": content.get("missing", []),
}

defer.returnValue(ret)

def event_from_pdu_json(self, pdu_json, outlier=False):
event = FrozenEvent(
Expand All @@ -291,3 +373,37 @@ def event_from_pdu_json(self, pdu_json, outlier=False):
event.internal_metadata.outlier = outlier

return event

@defer.inlineCallbacks
def _check_sigs_and_hash(self, pdu):
"""Throws a SynapseError if the PDU does not have the correct
signatures.

Returns:
FrozenEvent: Either the given event or it redacted if it failed the
content hash check.
"""
# Check signatures are correct.
redacted_event = prune_event(pdu)
redacted_pdu_json = redacted_event.get_pdu_json()

try:
yield self.keyring.verify_json_for_server(
pdu.origin, redacted_pdu_json
)
except SynapseError:
logger.warn(
"Signature check failed for %s redacted to %s",
encode_canonical_json(pdu.get_pdu_json()),
encode_canonical_json(redacted_pdu_json),
)
raise

if not check_event_content_hash(pdu):
logger.warn(
"Event content has been tampered, redacting %s, %s",
pdu.event_id, encode_canonical_json(pdu.get_dict())
)
defer.returnValue(redacted_event)

defer.returnValue(pdu)
Loading