mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2025-11-15 00:40:38 -05:00
Merge branch 'develop' into server2server_signing
Conflicts: synapse/storage/__init__.py tests/rest/test_presence.py
This commit is contained in:
commit
9605593d11
64 changed files with 2402 additions and 933 deletions
|
|
@ -19,7 +19,9 @@ from twisted.internet import defer
|
|||
|
||||
from synapse.api.constants import Membership, JoinRules
|
||||
from synapse.api.errors import AuthError, StoreError, Codes, SynapseError
|
||||
from synapse.api.events.room import RoomMemberEvent, RoomPowerLevelsEvent
|
||||
from synapse.api.events.room import (
|
||||
RoomMemberEvent, RoomPowerLevelsEvent, RoomRedactionEvent,
|
||||
)
|
||||
from synapse.util.logutils import log_function
|
||||
|
||||
import logging
|
||||
|
|
@ -70,6 +72,9 @@ class Auth(object):
|
|||
if event.type == RoomPowerLevelsEvent.TYPE:
|
||||
yield self._check_power_levels(event)
|
||||
|
||||
if event.type == RoomRedactionEvent.TYPE:
|
||||
yield self._check_redaction(event)
|
||||
|
||||
defer.returnValue(True)
|
||||
else:
|
||||
raise AuthError(500, "Unknown event: %s" % event)
|
||||
|
|
@ -170,7 +175,7 @@ class Auth(object):
|
|||
event.room_id,
|
||||
event.user_id,
|
||||
)
|
||||
_, kick_level = yield self.store.get_ops_levels(event.room_id)
|
||||
_, kick_level, _ = yield self.store.get_ops_levels(event.room_id)
|
||||
|
||||
if kick_level:
|
||||
kick_level = int(kick_level)
|
||||
|
|
@ -187,7 +192,7 @@ class Auth(object):
|
|||
event.user_id,
|
||||
)
|
||||
|
||||
ban_level, _ = yield self.store.get_ops_levels(event.room_id)
|
||||
ban_level, _, _ = yield self.store.get_ops_levels(event.room_id)
|
||||
|
||||
if ban_level:
|
||||
ban_level = int(ban_level)
|
||||
|
|
@ -201,6 +206,7 @@ class Auth(object):
|
|||
|
||||
defer.returnValue(True)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def get_user_by_req(self, request):
|
||||
""" Get a registered user's ID.
|
||||
|
||||
|
|
@ -213,7 +219,25 @@ class Auth(object):
|
|||
"""
|
||||
# Can optionally look elsewhere in the request (e.g. headers)
|
||||
try:
|
||||
return self.get_user_by_token(request.args["access_token"][0])
|
||||
access_token = request.args["access_token"][0]
|
||||
user_info = yield self.get_user_by_token(access_token)
|
||||
user = user_info["user"]
|
||||
|
||||
ip_addr = self.hs.get_ip_from_request(request)
|
||||
user_agent = request.requestHeaders.getRawHeaders(
|
||||
"User-Agent",
|
||||
default=[""]
|
||||
)[0]
|
||||
if user and access_token and ip_addr:
|
||||
self.store.insert_client_ip(
|
||||
user=user,
|
||||
access_token=access_token,
|
||||
device_id=user_info["device_id"],
|
||||
ip=ip_addr,
|
||||
user_agent=user_agent
|
||||
)
|
||||
|
||||
defer.returnValue(user)
|
||||
except KeyError:
|
||||
raise AuthError(403, "Missing access token.")
|
||||
|
||||
|
|
@ -222,21 +246,32 @@ class Auth(object):
|
|||
""" Get a registered user's ID.
|
||||
|
||||
Args:
|
||||
token (str)- The access token to get the user by.
|
||||
token (str): The access token to get the user by.
|
||||
Returns:
|
||||
UserID : User ID object of the user who has that access token.
|
||||
dict : dict that includes the user, device_id, and whether the
|
||||
user is a server admin.
|
||||
Raises:
|
||||
AuthError if no user by that token exists or the token is invalid.
|
||||
"""
|
||||
try:
|
||||
user_id = yield self.store.get_user_by_token(token=token)
|
||||
if not user_id:
|
||||
ret = yield self.store.get_user_by_token(token=token)
|
||||
if not ret:
|
||||
raise StoreError()
|
||||
defer.returnValue(self.hs.parse_userid(user_id))
|
||||
|
||||
user_info = {
|
||||
"admin": bool(ret.get("admin", False)),
|
||||
"device_id": ret.get("device_id"),
|
||||
"user": self.hs.parse_userid(ret.get("name")),
|
||||
}
|
||||
|
||||
defer.returnValue(user_info)
|
||||
except StoreError:
|
||||
raise AuthError(403, "Unrecognised access token.",
|
||||
errcode=Codes.UNKNOWN_TOKEN)
|
||||
|
||||
def is_server_admin(self, user):
|
||||
return self.store.is_server_admin(user)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
@log_function
|
||||
def _can_send_event(self, event):
|
||||
|
|
@ -321,6 +356,29 @@ class Auth(object):
|
|||
"You don't have permission to change that state"
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def _check_redaction(self, event):
|
||||
user_level = yield self.store.get_power_level(
|
||||
event.room_id,
|
||||
event.user_id,
|
||||
)
|
||||
|
||||
if user_level:
|
||||
user_level = int(user_level)
|
||||
else:
|
||||
user_level = 0
|
||||
|
||||
_, _, redact_level = yield self.store.get_ops_levels(event.room_id)
|
||||
|
||||
if not redact_level:
|
||||
redact_level = 50
|
||||
|
||||
if user_level < redact_level:
|
||||
raise AuthError(
|
||||
403,
|
||||
"You don't have permission to redact events"
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def _check_power_levels(self, event):
|
||||
for k, v in event.content.items():
|
||||
|
|
@ -372,11 +430,11 @@ class Auth(object):
|
|||
}
|
||||
|
||||
removed = set(old_people.keys()) - set(new_people.keys())
|
||||
added = set(old_people.keys()) - set(new_people.keys())
|
||||
added = set(new_people.keys()) - set(old_people.keys())
|
||||
same = set(old_people.keys()) & set(new_people.keys())
|
||||
|
||||
for r in removed:
|
||||
if int(old_list.content[r]) > user_level:
|
||||
if int(old_list[r]) > user_level:
|
||||
raise AuthError(
|
||||
403,
|
||||
"You don't have permission to remove user: %s" % (r, )
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ def serialize_event(hs, e):
|
|||
if not isinstance(e, SynapseEvent):
|
||||
return e
|
||||
|
||||
d = e.get_dict()
|
||||
# Should this strip out None's?
|
||||
d = {k: v for k, v in e.get_dict().items()}
|
||||
if "age_ts" in d:
|
||||
d["age"] = int(hs.get_clock().time_msec()) - d["age_ts"]
|
||||
del d["age_ts"]
|
||||
|
|
@ -58,17 +59,19 @@ class SynapseEvent(JsonEncodedObject):
|
|||
"required_power_level",
|
||||
"age_ts",
|
||||
"prev_content",
|
||||
"prev_state",
|
||||
"redacted_because",
|
||||
]
|
||||
|
||||
internal_keys = [
|
||||
"is_state",
|
||||
"prev_events",
|
||||
"prev_state",
|
||||
"depth",
|
||||
"destinations",
|
||||
"origin",
|
||||
"outlier",
|
||||
"power_level",
|
||||
"redacted",
|
||||
]
|
||||
|
||||
required_keys = [
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ from synapse.api.events.room import (
|
|||
RoomTopicEvent, MessageEvent, RoomMemberEvent, FeedbackEvent,
|
||||
InviteJoinEvent, RoomConfigEvent, RoomNameEvent, GenericEvent,
|
||||
RoomPowerLevelsEvent, RoomJoinRulesEvent, RoomOpsPowerLevelsEvent,
|
||||
RoomCreateEvent, RoomAddStateLevelEvent, RoomSendEventLevelEvent
|
||||
RoomCreateEvent, RoomAddStateLevelEvent, RoomSendEventLevelEvent,
|
||||
RoomRedactionEvent,
|
||||
)
|
||||
|
||||
from synapse.util.stringutils import random_string
|
||||
|
|
@ -39,6 +40,7 @@ class EventFactory(object):
|
|||
RoomAddStateLevelEvent,
|
||||
RoomSendEventLevelEvent,
|
||||
RoomOpsPowerLevelsEvent,
|
||||
RoomRedactionEvent,
|
||||
]
|
||||
|
||||
def __init__(self, hs):
|
||||
|
|
|
|||
|
|
@ -180,3 +180,12 @@ class RoomAliasesEvent(SynapseStateEvent):
|
|||
|
||||
def get_content_template(self):
|
||||
return {}
|
||||
|
||||
|
||||
class RoomRedactionEvent(SynapseEvent):
|
||||
TYPE = "m.room.redaction"
|
||||
|
||||
valid_keys = SynapseEvent.valid_keys + ["redacts"]
|
||||
|
||||
def get_content_template(self):
|
||||
return {}
|
||||
|
|
|
|||
64
synapse/api/events/utils.py
Normal file
64
synapse/api/events/utils.py
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2014 OpenMarket Ltd
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .room import (
|
||||
RoomMemberEvent, RoomJoinRulesEvent, RoomPowerLevelsEvent,
|
||||
RoomAddStateLevelEvent, RoomSendEventLevelEvent, RoomOpsPowerLevelsEvent,
|
||||
RoomAliasesEvent, RoomCreateEvent,
|
||||
)
|
||||
|
||||
def prune_event(event):
|
||||
""" Prunes the given event of all keys we don't know about or think could
|
||||
potentially be dodgy.
|
||||
|
||||
This is used when we "redact" an event. We want to remove all fields that
|
||||
the user has specified, but we do want to keep necessary information like
|
||||
type, state_key etc.
|
||||
"""
|
||||
|
||||
# Remove all extraneous fields.
|
||||
event.unrecognized_keys = {}
|
||||
|
||||
new_content = {}
|
||||
|
||||
def add_fields(*fields):
|
||||
for field in fields:
|
||||
if field in event.content:
|
||||
new_content[field] = event.content[field]
|
||||
|
||||
if event.type == RoomMemberEvent.TYPE:
|
||||
add_fields("membership")
|
||||
elif event.type == RoomCreateEvent.TYPE:
|
||||
add_fields("creator")
|
||||
elif event.type == RoomJoinRulesEvent.TYPE:
|
||||
add_fields("join_rule")
|
||||
elif event.type == RoomPowerLevelsEvent.TYPE:
|
||||
# TODO: Actually check these are valid user_ids etc.
|
||||
add_fields("default")
|
||||
for k, v in event.content.items():
|
||||
if k.startswith("@") and isinstance(v, (int, long)):
|
||||
new_content[k] = v
|
||||
elif event.type == RoomAddStateLevelEvent.TYPE:
|
||||
add_fields("level")
|
||||
elif event.type == RoomSendEventLevelEvent.TYPE:
|
||||
add_fields("level")
|
||||
elif event.type == RoomOpsPowerLevelsEvent.TYPE:
|
||||
add_fields("kick_level", "ban_level", "redact_level")
|
||||
elif event.type == RoomAliasesEvent.TYPE:
|
||||
add_fields("aliases")
|
||||
|
||||
event.content = new_content
|
||||
|
||||
return event
|
||||
Loading…
Add table
Add a link
Reference in a new issue