diff --git a/synapse/api/auth.py b/synapse/api/auth.py
index 1a25bf1086..487be7ce9c 100644
--- a/synapse/api/auth.py
+++ b/synapse/api/auth.py
@@ -187,6 +187,9 @@ class Auth(object):
join_rule = JoinRules.INVITE
user_level = self._get_user_power_level(event.user_id, auth_events)
+ target_level = self._get_user_power_level(
+ target_user_id, auth_events
+ )
# FIXME (erikj): What should we do here as the default?
ban_level = self._get_named_level(auth_events, "ban", 50)
@@ -258,12 +261,12 @@ class Auth(object):
elif target_user_id != event.user_id:
kick_level = self._get_named_level(auth_events, "kick", 50)
- if user_level < kick_level:
+ if user_level < kick_level or user_level <= target_level:
raise AuthError(
403, "You cannot kick user %s." % target_user_id
)
elif Membership.BAN == membership:
- if user_level < ban_level:
+ if user_level < ban_level or user_level <= target_level:
raise AuthError(403, "You don't have permission to ban")
else:
raise AuthError(500, "Unknown membership %s" % membership)
@@ -573,26 +576,26 @@ class Auth(object):
# Check other levels:
levels_to_check = [
- ("users_default", []),
- ("events_default", []),
- ("state_default", []),
- ("ban", []),
- ("redact", []),
- ("kick", []),
- ("invite", []),
+ ("users_default", None),
+ ("events_default", None),
+ ("state_default", None),
+ ("ban", None),
+ ("redact", None),
+ ("kick", None),
+ ("invite", None),
]
old_list = current_state.content.get("users")
for user in set(old_list.keys() + user_list.keys()):
levels_to_check.append(
- (user, ["users"])
+ (user, "users")
)
old_list = current_state.content.get("events")
new_list = event.content.get("events")
for ev_id in set(old_list.keys() + new_list.keys()):
levels_to_check.append(
- (ev_id, ["events"])
+ (ev_id, "events")
)
old_state = current_state.content
@@ -600,12 +603,10 @@ class Auth(object):
for level_to_check, dir in levels_to_check:
old_loc = old_state
- for d in dir:
- old_loc = old_loc.get(d, {})
-
new_loc = new_state
- for d in dir:
- new_loc = new_loc.get(d, {})
+ if dir:
+ old_loc = old_loc.get(dir, {})
+ new_loc = new_loc.get(dir, {})
if level_to_check in old_loc:
old_level = int(old_loc[level_to_check])
@@ -621,6 +622,14 @@ class Auth(object):
if new_level == old_level:
continue
+ if dir == "users" and level_to_check != event.user_id:
+ if old_level == user_level:
+ raise AuthError(
+ 403,
+ "You don't have permission to remove ops level equal "
+ "to your own"
+ )
+
if old_level > user_level or new_level > user_level:
raise AuthError(
403,
|