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

Commit

Permalink
Merge branch 'develop' of github.com:matrix-org/synapse into default_…
Browse files Browse the repository at this point in the history
…notify
  • Loading branch information
erikjohnston committed Jan 19, 2016
2 parents d9db819 + 47e7963 commit 9a8949f
Show file tree
Hide file tree
Showing 29 changed files with 945 additions and 1,222 deletions.
8 changes: 8 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,14 @@ During setup of Synapse you need to call python2.7 directly again::

...substituting your host and domain name as appropriate.

FreeBSD
-------

Synapse can be installed via FreeBSD Ports or Packages:

- Ports: ``cd /usr/ports/net/py-matrix-synapse && make install clean``
- Packages: ``pkg install py27-matrix-synapse``

Windows Install
---------------
Synapse can be installed on Cygwin. It requires the following Cygwin packages:
Expand Down
56 changes: 30 additions & 26 deletions synapse/api/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,37 +510,14 @@ def get_user_by_req(self, request, allow_guest=False):
"""
# Can optionally look elsewhere in the request (e.g. headers)
try:
access_token = request.args["access_token"][0]

# Check for application service tokens with a user_id override
try:
app_service = yield self.store.get_app_service_by_token(
access_token
)
if not app_service:
raise KeyError

user_id = app_service.sender
if "user_id" in request.args:
user_id = request.args["user_id"][0]
if not app_service.is_interested_in_user(user_id):
raise AuthError(
403,
"Application service cannot masquerade as this user."
)

if not user_id:
raise KeyError

user_id = yield self._get_appservice_user_id(request.args)
if user_id:
request.authenticated_entity = user_id

defer.returnValue(
Requester(UserID.from_string(user_id), "", False)
)
return
except KeyError:
pass # normal users won't have the user_id query parameter set.

access_token = request.args["access_token"][0]
user_info = yield self._get_user_by_access_token(access_token)
user = user_info["user"]
token_id = user_info["token_id"]
Expand Down Expand Up @@ -573,6 +550,33 @@ def get_user_by_req(self, request, allow_guest=False):
errcode=Codes.MISSING_TOKEN
)

@defer.inlineCallbacks
def _get_appservice_user_id(self, request_args):
app_service = yield self.store.get_app_service_by_token(
request_args["access_token"][0]
)
if app_service is None:
defer.returnValue(None)

if "user_id" not in request_args:
defer.returnValue(app_service.sender)

user_id = request_args["user_id"][0]
if app_service.sender == user_id:
defer.returnValue(app_service.sender)

if not app_service.is_interested_in_user(user_id):
raise AuthError(
403,
"Application service cannot masquerade as this user."
)
if not (yield self.store.get_user_by_id(user_id)):
raise AuthError(
403,
"Application service has not registered this user"
)
defer.returnValue(user_id)

@defer.inlineCallbacks
def _get_user_by_access_token(self, token):
""" Get a registered user's ID.
Expand Down
2 changes: 2 additions & 0 deletions synapse/api/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Codes(object):
USER_IN_USE = "M_USER_IN_USE"
ROOM_IN_USE = "M_ROOM_IN_USE"
BAD_PAGINATION = "M_BAD_PAGINATION"
BAD_STATE = "M_BAD_STATE"
UNKNOWN = "M_UNKNOWN"
NOT_FOUND = "M_NOT_FOUND"
MISSING_TOKEN = "M_MISSING_TOKEN"
Expand All @@ -42,6 +43,7 @@ class Codes(object):
EXCLUSIVE = "M_EXCLUSIVE"
THREEPID_AUTH_FAILED = "M_THREEPID_AUTH_FAILED"
THREEPID_IN_USE = "THREEPID_IN_USE"
INVALID_USERNAME = "M_INVALID_USERNAME"


class CodeMessageException(RuntimeError):
Expand Down
9 changes: 9 additions & 0 deletions synapse/events/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ def get_pdu_json(self, time_now=None):
def __set__(self, instance, value):
raise AttributeError("Unrecognized attribute %s" % (instance,))

def __getitem__(self, field):
return self._event_dict[field]

def __contains__(self, field):
return field in self._event_dict

def items(self):
return self._event_dict.items()


class FrozenEvent(EventBase):
def __init__(self, event_dict, internal_metadata_dict={}, rejected_reason=None):
Expand Down
101 changes: 57 additions & 44 deletions synapse/handlers/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,54 @@ def __init__(self, hs):
self.event_builder_factory = hs.get_event_builder_factory()

@defer.inlineCallbacks
def _filter_events_for_client(self, user_id, events, is_guest=False):
# Assumes that user has at some point joined the room if not is_guest.
def _filter_events_for_clients(self, users, events):
""" Returns dict of user_id -> list of events that user is allowed to
see.
"""
event_id_to_state = yield self.store.get_state_for_events(
frozenset(e.event_id for e in events),
types=(
(EventTypes.RoomHistoryVisibility, ""),
(EventTypes.Member, None),
)
)

forgotten = yield defer.gatherResults([
self.store.who_forgot_in_room(
room_id,
)
for room_id in frozenset(e.room_id for e in events)
], consumeErrors=True)

# Set of membership event_ids that have been forgotten
event_id_forgotten = frozenset(
row["event_id"] for rows in forgotten for row in rows
)

def allowed(event, user_id, is_guest):
state = event_id_to_state[event.event_id]

visibility_event = state.get((EventTypes.RoomHistoryVisibility, ""), None)
if visibility_event:
visibility = visibility_event.content.get("history_visibility", "shared")
else:
visibility = "shared"

def allowed(event, membership, visibility):
if visibility == "world_readable":
return True

if is_guest:
return False

membership_event = state.get((EventTypes.Member, user_id), None)
if membership_event:
if membership_event.event_id in event_id_forgotten:
membership = None
else:
membership = membership_event.membership
else:
membership = None

if membership == Membership.JOIN:
return True

Expand All @@ -78,43 +116,20 @@ def allowed(event, membership, visibility):

return True

event_id_to_state = yield self.store.get_state_for_events(
frozenset(e.event_id for e in events),
types=(
(EventTypes.RoomHistoryVisibility, ""),
(EventTypes.Member, user_id),
)
)

events_to_return = []
for event in events:
state = event_id_to_state[event.event_id]
defer.returnValue({
user_id: [
event
for event in events
if allowed(event, user_id, is_guest)
]
for user_id, is_guest in users
})

membership_event = state.get((EventTypes.Member, user_id), None)
if membership_event:
was_forgotten_at_event = yield self.store.was_forgotten_at(
membership_event.state_key,
membership_event.room_id,
membership_event.event_id
)
if was_forgotten_at_event:
membership = None
else:
membership = membership_event.membership
else:
membership = None

visibility_event = state.get((EventTypes.RoomHistoryVisibility, ""), None)
if visibility_event:
visibility = visibility_event.content.get("history_visibility", "shared")
else:
visibility = "shared"

should_include = allowed(event, membership, visibility)
if should_include:
events_to_return.append(event)

defer.returnValue(events_to_return)
@defer.inlineCallbacks
def _filter_events_for_client(self, user_id, events, is_guest=False):
# Assumes that user has at some point joined the room if not is_guest.
res = yield self._filter_events_for_clients([(user_id, is_guest)], events)
defer.returnValue(res.get(user_id, []))

def ratelimit(self, user_id):
time_now = self.clock.time()
Expand Down Expand Up @@ -171,12 +186,10 @@ def _create_new_client_event(self, builder):
)

@defer.inlineCallbacks
def handle_new_client_event(self, event, context, extra_destinations=[],
extra_users=[], suppress_auth=False):
def handle_new_client_event(self, event, context, extra_users=[]):
# We now need to go and hit out to wherever we need to hit out to.

if not suppress_auth:
self.auth.check(event, auth_events=context.current_state)
self.auth.check(event, auth_events=context.current_state)

yield self.maybe_kick_guest_users(event, context.current_state.values())

Expand Down Expand Up @@ -258,7 +271,7 @@ def handle_new_client_event(self, event, context, extra_destinations=[],
event, self
)

destinations = set(extra_destinations)
destinations = set()
for k, s in context.current_state.items():
try:
if k[0] == EventTypes.Member:
Expand Down
4 changes: 2 additions & 2 deletions synapse/handlers/federation.py
Original file line number Diff line number Diff line change
Expand Up @@ -1692,7 +1692,7 @@ def exchange_third_party_invite(self, invite):
self.auth.check(event, context.current_state)
yield self._validate_keyserver(event, auth_events=context.current_state)
member_handler = self.hs.get_handlers().room_member_handler
yield member_handler.change_membership(event, context)
yield member_handler.send_membership_event(event, context)
else:
destinations = set([x.split(":", 1)[-1] for x in (sender, room_id)])
yield self.replication_layer.forward_third_party_invite(
Expand Down Expand Up @@ -1721,7 +1721,7 @@ def on_exchange_third_party_invite_request(self, origin, room_id, event_dict):
# TODO: Make sure the signatures actually are correct.
event.signatures.update(returned_invite.signatures)
member_handler = self.hs.get_handlers().room_member_handler
yield member_handler.change_membership(event, context)
yield member_handler.send_membership_event(event, context)

@defer.inlineCallbacks
def add_display_name_to_third_party_invite(self, event_dict, event, context):
Expand Down
57 changes: 45 additions & 12 deletions synapse/handlers/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,30 +174,25 @@ def get_messages(self, user_id=None, room_id=None, pagin_config=None,
defer.returnValue(chunk)

@defer.inlineCallbacks
def create_and_send_event(self, event_dict, ratelimit=True,
token_id=None, txn_id=None, is_guest=False):
""" Given a dict from a client, create and handle a new event.
def create_event(self, event_dict, token_id=None, txn_id=None):
"""
Given a dict from a client, create a new event.
Creates an FrozenEvent object, filling out auth_events, prev_events,
etc.
Adds display names to Join membership events.
Persists and notifies local clients and federation.
Args:
event_dict (dict): An entire event
Returns:
Tuple of created event (FrozenEvent), Context
"""
builder = self.event_builder_factory.new(event_dict)

self.validator.validate_new(builder)

if ratelimit:
self.ratelimit(builder.user_id)
# TODO(paul): Why does 'event' not have a 'user' object?
user = UserID.from_string(builder.user_id)
assert self.hs.is_mine(user), "User must be our own: %s" % (user,)

if builder.type == EventTypes.Member:
membership = builder.content.get("membership", None)
if membership == Membership.JOIN:
Expand All @@ -216,6 +211,25 @@ def create_and_send_event(self, event_dict, ratelimit=True,
event, context = yield self._create_new_client_event(
builder=builder,
)
defer.returnValue((event, context))

@defer.inlineCallbacks
def send_event(self, event, context, ratelimit=True, is_guest=False):
"""
Persists and notifies local clients and federation of an event.
Args:
event (FrozenEvent) the event to send.
context (Context) the context of the event.
ratelimit (bool): Whether to rate limit this send.
is_guest (bool): Whether the sender is a guest.
"""
user = UserID.from_string(event.sender)

assert self.hs.is_mine(user), "User must be our own: %s" % (user,)

if ratelimit:
self.ratelimit(event.sender)

if event.is_state():
prev_state = context.current_state.get((event.type, event.state_key))
Expand All @@ -229,7 +243,7 @@ def create_and_send_event(self, event_dict, ratelimit=True,

if event.type == EventTypes.Member:
member_handler = self.hs.get_handlers().room_member_handler
yield member_handler.change_membership(event, context, is_guest=is_guest)
yield member_handler.send_membership_event(event, context, is_guest=is_guest)
else:
yield self.handle_new_client_event(
event=event,
Expand All @@ -241,6 +255,25 @@ def create_and_send_event(self, event_dict, ratelimit=True,
with PreserveLoggingContext():
presence.bump_presence_active_time(user)

@defer.inlineCallbacks
def create_and_send_event(self, event_dict, ratelimit=True,
token_id=None, txn_id=None, is_guest=False):
"""
Creates an event, then sends it.
See self.create_event and self.send_event.
"""
event, context = yield self.create_event(
event_dict,
token_id=token_id,
txn_id=txn_id
)
yield self.send_event(
event,
context,
ratelimit=ratelimit,
is_guest=is_guest
)
defer.returnValue(event)

@defer.inlineCallbacks
Expand Down
3 changes: 2 additions & 1 deletion synapse/handlers/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ def check_username(self, localpart, guest_access_token=None):
raise SynapseError(
400,
"User ID must only contain characters which do not"
" require URL encoding."
" require URL encoding.",
Codes.INVALID_USERNAME
)

user = UserID(localpart, self.hs.hostname)
Expand Down
Loading

0 comments on commit 9a8949f

Please sign in to comment.