diff --git a/synapse/api/auth.py b/synapse/api/auth.py
index b4eda3df01..8f32191b57 100644
--- a/synapse/api/auth.py
+++ b/synapse/api/auth.py
@@ -18,8 +18,8 @@
from twisted.internet import defer
from synapse.api.constants import Membership, JoinRules
-from synapse.api.errors import AuthError, StoreError, Codes
-from synapse.api.events.room import RoomMemberEvent
+from synapse.api.errors import AuthError, StoreError, Codes, SynapseError
+from synapse.api.events.room import RoomMemberEvent, RoomPowerLevelsEvent
from synapse.util.logutils import log_function
import logging
@@ -67,6 +67,9 @@ class Auth(object):
else:
yield self._can_send_event(event)
+ if event.type == RoomPowerLevelsEvent.TYPE:
+ yield self._check_power_levels(event)
+
defer.returnValue(True)
else:
raise AuthError(500, "Unknown event: %s" % event)
@@ -172,7 +175,7 @@ class Auth(object):
if kick_level:
kick_level = int(kick_level)
else:
- kick_level = 5
+ kick_level = 50
if user_level < kick_level:
raise AuthError(
@@ -189,7 +192,7 @@ class Auth(object):
if ban_level:
ban_level = int(ban_level)
else:
- ban_level = 5 # FIXME (erikj): What should we do here?
+ ban_level = 50 # FIXME (erikj): What should we do here?
if user_level < ban_level:
raise AuthError(403, "You don't have permission to ban")
@@ -305,7 +308,9 @@ class Auth(object):
else:
user_level = 0
- logger.debug("Checking power level for %s, %s", event.user_id, user_level)
+ logger.debug(
+ "Checking power level for %s, %s", event.user_id, user_level
+ )
if current_state and hasattr(current_state, "required_power_level"):
req = current_state.required_power_level
@@ -315,3 +320,101 @@ class Auth(object):
403,
"You don't have permission to change that state"
)
+
+ @defer.inlineCallbacks
+ def _check_power_levels(self, event):
+ for k, v in event.content.items():
+ if k == "default":
+ continue
+
+ # FIXME (erikj): We don't want hsob_Ts in content.
+ if k == "hsob_ts":
+ continue
+
+ try:
+ self.hs.parse_userid(k)
+ except:
+ raise SynapseError(400, "Not a valid user_id: %s" % (k,))
+
+ try:
+ int(v)
+ except:
+ raise SynapseError(400, "Not a valid power level: %s" % (v,))
+
+ current_state = yield self.store.get_current_state(
+ event.room_id,
+ event.type,
+ event.state_key,
+ )
+
+ if not current_state:
+ return
+ else:
+ current_state = current_state[0]
+
+ 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
+
+ old_list = current_state.content
+
+ # FIXME (erikj)
+ old_people = {k: v for k, v in old_list.items() if k.startswith("@")}
+ new_people = {
+ k: v for k, v in event.content.items()
+ if k.startswith("@")
+ }
+
+ removed = set(old_people.keys()) - set(new_people.keys())
+ added = set(old_people.keys()) - set(new_people.keys())
+ same = set(old_people.keys()) & set(new_people.keys())
+
+ for r in removed:
+ if int(old_list.content[r]) > user_level:
+ raise AuthError(
+ 403,
+ "You don't have permission to remove user: %s" % (r, )
+ )
+
+ for n in added:
+ if int(event.content[n]) > user_level:
+ raise AuthError(
+ 403,
+ "You don't have permission to add ops level greater "
+ "than your own"
+ )
+
+ for s in same:
+ if int(event.content[s]) != int(old_list[s]):
+ if int(event.content[s]) > user_level:
+ raise AuthError(
+ 403,
+ "You don't have permission to add ops level greater "
+ "than your own"
+ )
+
+ if "default" in old_list:
+ old_default = int(old_list["default"])
+
+ if old_default > user_level:
+ raise AuthError(
+ 403,
+ "You don't have permission to add ops level greater than "
+ "your own"
+ )
+
+ if "default" in event.content:
+ new_default = int(event.content["default"])
+
+ if new_default > user_level:
+ raise AuthError(
+ 403,
+ "You don't have permission to add ops level greater "
+ "than your own"
+ )
diff --git a/synapse/api/errors.py b/synapse/api/errors.py
index 84afe4fa37..88175602c4 100644
--- a/synapse/api/errors.py
+++ b/synapse/api/errors.py
@@ -29,6 +29,8 @@ class Codes(object):
NOT_FOUND = "M_NOT_FOUND"
UNKNOWN_TOKEN = "M_UNKNOWN_TOKEN"
LIMIT_EXCEEDED = "M_LIMIT_EXCEEDED"
+ CAPTCHA_NEEDED = "M_CAPTCHA_NEEDED"
+ CAPTCHA_INVALID = "M_CAPTCHA_INVALID"
class CodeMessageException(Exception):
@@ -101,6 +103,19 @@ class StoreError(SynapseError):
pass
+class InvalidCaptchaError(SynapseError):
+ def __init__(self, code=400, msg="Invalid captcha.", error_url=None,
+ errcode=Codes.CAPTCHA_INVALID):
+ super(InvalidCaptchaError, self).__init__(code, msg, errcode)
+ self.error_url = error_url
+
+ def error_dict(self):
+ return cs_error(
+ self.msg,
+ self.errcode,
+ error_url=self.error_url,
+ )
+
class LimitExceededError(SynapseError):
"""A client has sent too many requests and is being throttled.
"""
diff --git a/synapse/api/events/__init__.py b/synapse/api/events/__init__.py
index f95468fc65..5f300de108 100644
--- a/synapse/api/events/__init__.py
+++ b/synapse/api/events/__init__.py
@@ -157,7 +157,12 @@ class SynapseEvent(JsonEncodedObject):
class SynapseStateEvent(SynapseEvent):
- def __init__(self, **kwargs):
+
+ valid_keys = SynapseEvent.valid_keys + [
+ "prev_content",
+ ]
+
+ def __init__(self, **kwargs):
if "state_key" not in kwargs:
kwargs["state_key"] = ""
super(SynapseStateEvent, self).__init__(**kwargs)
diff --git a/synapse/api/events/factory.py b/synapse/api/events/factory.py
index a3b293e024..5e38cdbc44 100644
--- a/synapse/api/events/factory.py
+++ b/synapse/api/events/factory.py
@@ -47,11 +47,14 @@ class EventFactory(object):
self._event_list[event_class.TYPE] = event_class
self.clock = hs.get_clock()
+ self.hs = hs
def create_event(self, etype=None, **kwargs):
kwargs["type"] = etype
if "event_id" not in kwargs:
- kwargs["event_id"] = random_string(10)
+ kwargs["event_id"] = "%s@%s" % (
+ random_string(10), self.hs.hostname
+ )
if "ts" not in kwargs:
kwargs["ts"] = int(self.clock.time_msec())
diff --git a/synapse/api/events/room.py b/synapse/api/events/room.py
index 33f0f0cb99..3a4dbc58ce 100644
--- a/synapse/api/events/room.py
+++ b/synapse/api/events/room.py
@@ -173,3 +173,10 @@ class RoomOpsPowerLevelsEvent(SynapseStateEvent):
def get_content_template(self):
return {}
+
+
+class RoomAliasesEvent(SynapseStateEvent):
+ TYPE = "m.room.aliases"
+
+ def get_content_template(self):
+ return {}
|