mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2025-11-13 12:51:01 -05:00
Merge branch 'develop' into sh-cas-auth-via-homeserver
This commit is contained in:
commit
f5e25c5f35
39 changed files with 1266 additions and 290 deletions
|
|
@ -37,7 +37,7 @@ class ProfileDisplaynameRestServlet(ClientV1RestServlet):
|
|||
|
||||
@defer.inlineCallbacks
|
||||
def on_PUT(self, request, user_id):
|
||||
auth_user, _, _ = yield self.auth.get_user_by_req(request)
|
||||
auth_user, _, _ = yield self.auth.get_user_by_req(request, allow_guest=True)
|
||||
user = UserID.from_string(user_id)
|
||||
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
from twisted.internet import defer
|
||||
|
||||
from base import ClientV1RestServlet, client_path_pattern
|
||||
from synapse.api.errors import SynapseError, Codes
|
||||
from synapse.api.errors import SynapseError, Codes, AuthError
|
||||
from synapse.streams.config import PaginationConfig
|
||||
from synapse.api.constants import EventTypes, Membership
|
||||
from synapse.types import UserID, RoomID, RoomAlias
|
||||
|
|
@ -175,7 +175,7 @@ class RoomSendEventRestServlet(ClientV1RestServlet):
|
|||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request, room_id, event_type, txn_id=None):
|
||||
user, token_id, _ = yield self.auth.get_user_by_req(request)
|
||||
user, token_id, _ = yield self.auth.get_user_by_req(request, allow_guest=True)
|
||||
content = _parse_json(request)
|
||||
|
||||
msg_handler = self.handlers.message_handler
|
||||
|
|
@ -220,7 +220,10 @@ class JoinRoomAliasServlet(ClientV1RestServlet):
|
|||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request, room_identifier, txn_id=None):
|
||||
user, token_id, _ = yield self.auth.get_user_by_req(request)
|
||||
user, token_id, is_guest = yield self.auth.get_user_by_req(
|
||||
request,
|
||||
allow_guest=True
|
||||
)
|
||||
|
||||
# the identifier could be a room alias or a room id. Try one then the
|
||||
# other if it fails to parse, without swallowing other valid
|
||||
|
|
@ -242,16 +245,20 @@ class JoinRoomAliasServlet(ClientV1RestServlet):
|
|||
defer.returnValue((200, ret_dict))
|
||||
else: # room id
|
||||
msg_handler = self.handlers.message_handler
|
||||
content = {"membership": Membership.JOIN}
|
||||
if is_guest:
|
||||
content["kind"] = "guest"
|
||||
yield msg_handler.create_and_send_event(
|
||||
{
|
||||
"type": EventTypes.Member,
|
||||
"content": {"membership": Membership.JOIN},
|
||||
"content": content,
|
||||
"room_id": identifier.to_string(),
|
||||
"sender": user.to_string(),
|
||||
"state_key": user.to_string(),
|
||||
},
|
||||
token_id=token_id,
|
||||
txn_id=txn_id,
|
||||
is_guest=is_guest,
|
||||
)
|
||||
|
||||
defer.returnValue((200, {"room_id": identifier.to_string()}))
|
||||
|
|
@ -319,7 +326,7 @@ class RoomMemberListRestServlet(ClientV1RestServlet):
|
|||
}))
|
||||
|
||||
|
||||
# TODO: Needs unit testing
|
||||
# TODO: Needs better unit testing
|
||||
class RoomMessageListRestServlet(ClientV1RestServlet):
|
||||
PATTERN = client_path_pattern("/rooms/(?P<room_id>[^/]*)/messages$")
|
||||
|
||||
|
|
@ -365,12 +372,13 @@ class RoomInitialSyncRestServlet(ClientV1RestServlet):
|
|||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, room_id):
|
||||
user, _, _ = yield self.auth.get_user_by_req(request)
|
||||
user, _, is_guest = yield self.auth.get_user_by_req(request, allow_guest=True)
|
||||
pagination_config = PaginationConfig.from_request(request)
|
||||
content = yield self.handlers.message_handler.room_initial_sync(
|
||||
room_id=room_id,
|
||||
user_id=user.to_string(),
|
||||
pagin_config=pagination_config,
|
||||
is_guest=is_guest,
|
||||
)
|
||||
defer.returnValue((200, content))
|
||||
|
||||
|
|
@ -410,12 +418,12 @@ class RoomEventContext(ClientV1RestServlet):
|
|||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, room_id, event_id):
|
||||
user, _ = yield self.auth.get_user_by_req(request)
|
||||
user, _, is_guest = yield self.auth.get_user_by_req(request, allow_guest=True)
|
||||
|
||||
limit = int(request.args.get("limit", [10])[0])
|
||||
|
||||
results = yield self.handlers.room_context_handler.get_event_context(
|
||||
user, room_id, event_id, limit,
|
||||
user, room_id, event_id, limit, is_guest
|
||||
)
|
||||
|
||||
time_now = self.clock.time_msec()
|
||||
|
|
@ -445,7 +453,13 @@ class RoomMembershipRestServlet(ClientV1RestServlet):
|
|||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request, room_id, membership_action, txn_id=None):
|
||||
user, token_id, _ = yield self.auth.get_user_by_req(request)
|
||||
user, token_id, is_guest = yield self.auth.get_user_by_req(
|
||||
request,
|
||||
allow_guest=True
|
||||
)
|
||||
|
||||
if is_guest and membership_action not in {Membership.JOIN, Membership.LEAVE}:
|
||||
raise AuthError(403, "Guest access not allowed")
|
||||
|
||||
content = _parse_json(request)
|
||||
|
||||
|
|
@ -459,7 +473,6 @@ class RoomMembershipRestServlet(ClientV1RestServlet):
|
|||
content["medium"],
|
||||
content["address"],
|
||||
content["id_server"],
|
||||
content["display_name"],
|
||||
token_id,
|
||||
txn_id
|
||||
)
|
||||
|
|
@ -479,22 +492,27 @@ class RoomMembershipRestServlet(ClientV1RestServlet):
|
|||
|
||||
msg_handler = self.handlers.message_handler
|
||||
|
||||
content = {"membership": unicode(membership_action)}
|
||||
if is_guest:
|
||||
content["kind"] = "guest"
|
||||
|
||||
yield msg_handler.create_and_send_event(
|
||||
{
|
||||
"type": EventTypes.Member,
|
||||
"content": {"membership": unicode(membership_action)},
|
||||
"content": content,
|
||||
"room_id": room_id,
|
||||
"sender": user.to_string(),
|
||||
"state_key": state_key,
|
||||
},
|
||||
token_id=token_id,
|
||||
txn_id=txn_id,
|
||||
is_guest=is_guest,
|
||||
)
|
||||
|
||||
defer.returnValue((200, {}))
|
||||
|
||||
def _has_3pid_invite_keys(self, content):
|
||||
for key in {"id_server", "medium", "address", "display_name"}:
|
||||
for key in {"id_server", "medium", "address"}:
|
||||
if key not in content:
|
||||
return False
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ from synapse.http.servlet import (
|
|||
)
|
||||
from synapse.handlers.sync import SyncConfig
|
||||
from synapse.types import StreamToken
|
||||
from synapse.events import FrozenEvent
|
||||
from synapse.events.utils import (
|
||||
serialize_event, format_event_for_client_v2_without_event_id,
|
||||
)
|
||||
|
|
@ -165,6 +166,20 @@ class SyncRestServlet(RestServlet):
|
|||
return {"events": filter.filter_presence(formatted)}
|
||||
|
||||
def encode_joined(self, rooms, filter, time_now, token_id):
|
||||
"""
|
||||
Encode the joined rooms in a sync result
|
||||
|
||||
:param list[synapse.handlers.sync.JoinedSyncResult] rooms: list of sync
|
||||
results for rooms this user is joined to
|
||||
:param FilterCollection filter: filters to apply to the results
|
||||
:param int time_now: current time - used as a baseline for age
|
||||
calculations
|
||||
:param int token_id: ID of the user's auth token - used for namespacing
|
||||
of transaction IDs
|
||||
|
||||
:return: the joined rooms list, in our response format
|
||||
:rtype: dict[str, dict[str, object]]
|
||||
"""
|
||||
joined = {}
|
||||
for room in rooms:
|
||||
joined[room.room_id] = self.encode_room(
|
||||
|
|
@ -174,6 +189,20 @@ class SyncRestServlet(RestServlet):
|
|||
return joined
|
||||
|
||||
def encode_invited(self, rooms, filter, time_now, token_id):
|
||||
"""
|
||||
Encode the invited rooms in a sync result
|
||||
|
||||
:param list[synapse.handlers.sync.InvitedSyncResult] rooms: list of
|
||||
sync results for rooms this user is joined to
|
||||
:param FilterCollection filter: filters to apply to the results
|
||||
:param int time_now: current time - used as a baseline for age
|
||||
calculations
|
||||
:param int token_id: ID of the user's auth token - used for namespacing
|
||||
of transaction IDs
|
||||
|
||||
:return: the invited rooms list, in our response format
|
||||
:rtype: dict[str, dict[str, object]]
|
||||
"""
|
||||
invited = {}
|
||||
for room in rooms:
|
||||
invite = serialize_event(
|
||||
|
|
@ -189,6 +218,20 @@ class SyncRestServlet(RestServlet):
|
|||
return invited
|
||||
|
||||
def encode_archived(self, rooms, filter, time_now, token_id):
|
||||
"""
|
||||
Encode the archived rooms in a sync result
|
||||
|
||||
:param list[synapse.handlers.sync.ArchivedSyncResult] rooms: list of
|
||||
sync results for rooms this user is joined to
|
||||
:param FilterCollection filter: filters to apply to the results
|
||||
:param int time_now: current time - used as a baseline for age
|
||||
calculations
|
||||
:param int token_id: ID of the user's auth token - used for namespacing
|
||||
of transaction IDs
|
||||
|
||||
:return: the invited rooms list, in our response format
|
||||
:rtype: dict[str, dict[str, object]]
|
||||
"""
|
||||
joined = {}
|
||||
for room in rooms:
|
||||
joined[room.room_id] = self.encode_room(
|
||||
|
|
@ -199,8 +242,28 @@ class SyncRestServlet(RestServlet):
|
|||
|
||||
@staticmethod
|
||||
def encode_room(room, filter, time_now, token_id, joined=True):
|
||||
"""
|
||||
:param JoinedSyncResult|ArchivedSyncResult room: sync result for a
|
||||
single room
|
||||
:param FilterCollection filter: filters to apply to the results
|
||||
:param int time_now: current time - used as a baseline for age
|
||||
calculations
|
||||
:param int token_id: ID of the user's auth token - used for namespacing
|
||||
of transaction IDs
|
||||
:param joined: True if the user is joined to this room - will mean
|
||||
we handle ephemeral events
|
||||
|
||||
:return: the room, encoded in our response format
|
||||
:rtype: dict[str, object]
|
||||
"""
|
||||
event_map = {}
|
||||
state_events = filter.filter_room_state(room.state)
|
||||
state_dict = room.state
|
||||
timeline_events = filter.filter_room_timeline(room.timeline.events)
|
||||
|
||||
state_dict = SyncRestServlet._rollback_state_for_timeline(
|
||||
state_dict, timeline_events)
|
||||
|
||||
state_events = filter.filter_room_state(state_dict.values())
|
||||
state_event_ids = []
|
||||
for event in state_events:
|
||||
# TODO(mjark): Respect formatting requirements in the filter.
|
||||
|
|
@ -210,7 +273,6 @@ class SyncRestServlet(RestServlet):
|
|||
)
|
||||
state_event_ids.append(event.event_id)
|
||||
|
||||
timeline_events = filter.filter_room_timeline(room.timeline.events)
|
||||
timeline_event_ids = []
|
||||
for event in timeline_events:
|
||||
# TODO(mjark): Respect formatting requirements in the filter.
|
||||
|
|
@ -241,6 +303,63 @@ class SyncRestServlet(RestServlet):
|
|||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def _rollback_state_for_timeline(state, timeline):
|
||||
"""
|
||||
Wind the state dictionary backwards, so that it represents the
|
||||
state at the start of the timeline, rather than at the end.
|
||||
|
||||
:param dict[(str, str), synapse.events.EventBase] state: the
|
||||
state dictionary. Will be updated to the state before the timeline.
|
||||
:param list[synapse.events.EventBase] timeline: the event timeline
|
||||
:return: updated state dictionary
|
||||
"""
|
||||
logger.debug("Processing state dict %r; timeline %r", state,
|
||||
[e.get_dict() for e in timeline])
|
||||
|
||||
result = state.copy()
|
||||
|
||||
for timeline_event in reversed(timeline):
|
||||
if not timeline_event.is_state():
|
||||
continue
|
||||
|
||||
event_key = (timeline_event.type, timeline_event.state_key)
|
||||
|
||||
logger.debug("Considering %s for removal", event_key)
|
||||
|
||||
state_event = result.get(event_key)
|
||||
if (state_event is None or
|
||||
state_event.event_id != timeline_event.event_id):
|
||||
# the event in the timeline isn't present in the state
|
||||
# dictionary.
|
||||
#
|
||||
# the most likely cause for this is that there was a fork in
|
||||
# the event graph, and the state is no longer valid. Really,
|
||||
# the event shouldn't be in the timeline. We're going to ignore
|
||||
# it for now, however.
|
||||
logger.warn("Found state event %r in timeline which doesn't "
|
||||
"match state dictionary", timeline_event)
|
||||
continue
|
||||
|
||||
prev_event_id = timeline_event.unsigned.get("replaces_state", None)
|
||||
logger.debug("Replacing %s with %s in state dict",
|
||||
timeline_event.event_id, prev_event_id)
|
||||
|
||||
if prev_event_id is None:
|
||||
del result[event_key]
|
||||
else:
|
||||
result[event_key] = FrozenEvent({
|
||||
"type": timeline_event.type,
|
||||
"state_key": timeline_event.state_key,
|
||||
"content": timeline_event.unsigned['prev_content'],
|
||||
"sender": timeline_event.unsigned['prev_sender'],
|
||||
"event_id": prev_event_id,
|
||||
"room_id": timeline_event.room_id,
|
||||
})
|
||||
logger.debug("New value: %r", result.get(event_key))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
SyncRestServlet(hs).register(http_server)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue