summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--synapse/api/auth.py40
-rw-r--r--synapse/api/events/__init__.py2
-rw-r--r--synapse/federation/units.py1
-rw-r--r--synapse/handlers/room.py12
-rw-r--r--synapse/storage/room.py3
-rw-r--r--synapse/storage/schema/im.sql2
6 files changed, 54 insertions, 6 deletions
diff --git a/synapse/api/auth.py b/synapse/api/auth.py
index 0e8973e823..abd7d73b0a 100644
--- a/synapse/api/auth.py
+++ b/synapse/api/auth.py
@@ -45,7 +45,10 @@ class Auth(object):
         """
         try:
             if hasattr(event, "room_id"):
+                is_state = hasattr(event, "state_key")
+
                 if event.type == RoomMemberEvent.TYPE:
+                    yield self._can_replace_state(event)
                     allowed = yield self.is_membership_change_allowed(event)
                     defer.returnValue(allowed)
                     return
@@ -56,10 +59,11 @@ class Auth(object):
                     room_id=snapshot.room_id,
                 )
 
-                if hasattr(event, "state_key"):
+                if is_state:
                     # TODO (erikj): This really only should be called for *new*
                     # state
                     yield self._can_add_state(event)
+                    yield self._can_replace_state(event)
                 else:
                     yield self._can_send_event(event)
 
@@ -175,7 +179,7 @@ class Auth(object):
             else:
                 ban_level = 5  # FIXME (erikj): What should we do here?
 
-            if ban_level < user_level:
+            if user_level < ban_level:
                 raise AuthError(403, "You don't have permission to ban")
         else:
             raise AuthError(500, "Unknown membership %s" % membership)
@@ -267,3 +271,35 @@ class Auth(object):
             )
 
         defer.returnValue(True)
+
+    @defer.inlineCallbacks
+    def _can_replace_state(self, event):
+        current_state = yield self.store.get_current_state(
+            event.room_id,
+            event.type,
+            event.state_key,
+        )
+
+        if current_state:
+            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
+
+        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
+
+            logger.debug("Checked power level for %s, %s", event.user_id, req)
+            if user_level < req:
+                raise AuthError(
+                    403,
+                    "You don't have permission to change that state"
+                )
diff --git a/synapse/api/events/__init__.py b/synapse/api/events/__init__.py
index bf8d288acc..9502f5df8f 100644
--- a/synapse/api/events/__init__.py
+++ b/synapse/api/events/__init__.py
@@ -42,6 +42,7 @@ class SynapseEvent(JsonEncodedObject):
         "user_id",  # sender/initiator
         "content",  # HTTP body, JSON
         "state_key",
+        "required_power_level",
     ]
 
     internal_keys = [
@@ -52,6 +53,7 @@ class SynapseEvent(JsonEncodedObject):
         "destinations",
         "origin",
         "outlier",
+        "power_level",
     ]
 
     required_keys = [
diff --git a/synapse/federation/units.py b/synapse/federation/units.py
index 2b2f11f36a..b468f70546 100644
--- a/synapse/federation/units.py
+++ b/synapse/federation/units.py
@@ -68,6 +68,7 @@ class Pdu(JsonEncodedObject):
         "power_level",
         "prev_state_id",
         "prev_state_origin",
+        "required_power_level",
     ]
 
     internal_keys = [
diff --git a/synapse/handlers/room.py b/synapse/handlers/room.py
index 9262afb474..f33bec9cc1 100644
--- a/synapse/handlers/room.py
+++ b/synapse/handlers/room.py
@@ -166,7 +166,7 @@ class RoomCreationHandler(BaseRoomHandler):
 
         power_levels_event = create(
             etype=RoomPowerLevelsEvent.TYPE,
-            **{creator.to_string(): 10}
+            **{creator.to_string(): 10, "default": 0}
         )
 
         join_rule = JoinRules.PUBLIC if is_public else JoinRules.INVITE
@@ -343,6 +343,16 @@ class RoomMemberHandler(BaseRoomHandler):
             if do_auth:
                 yield self.auth.check(event, snapshot, raises=True)
 
+            # If we're banning someone, set a req power level
+            if event.membership == Membership.BAN:
+                if not hasattr(event, "required_power_level") or event.required_power_level is None:
+                    # Add some default required_power_level
+                    user_level = yield self.store.get_power_level(
+                        event.room_id,
+                        event.user_id,
+                    )
+                    event.required_power_level = user_level
+
             if prev_state and prev_state.membership == event.membership:
                 # double same action, treat this event as a NOOP.
                 defer.returnValue({})
diff --git a/synapse/storage/room.py b/synapse/storage/room.py
index 3b2d1a8ecd..3ca07f4350 100644
--- a/synapse/storage/room.py
+++ b/synapse/storage/room.py
@@ -165,8 +165,7 @@ class RoomStore(SQLBaseStore):
         rows = txn.execute(sql, (room_id, user_id,)).fetchall()
 
         if len(rows) == 1:
-            defer.returnValue(rows[0][0])
-            return
+            return rows[0][0]
 
         sql = (
             "SELECT level FROM room_default_levels as r "
diff --git a/synapse/storage/schema/im.sql b/synapse/storage/schema/im.sql
index 1de0d59066..dbefbbda31 100644
--- a/synapse/storage/schema/im.sql
+++ b/synapse/storage/schema/im.sql
@@ -150,7 +150,7 @@ CREATE TABLE IF NOT EXISTS room_ops_levels(
     event_id TEXT NOT NULL,
     room_id TEXT NOT NULL,
     ban_level INTEGER,
-    kick_level INTEGER,
+    kick_level INTEGER
 );
 
 CREATE INDEX IF NOT EXISTS room_ops_levels_event_id ON room_ops_levels(event_id);