Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add bypass_for_users config #6

Merged
merged 2 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ modules:
# Identity server to use when checking the homeserver an email address belongs to
# using the /info endpoint. Required.
id_server: "vector.im"
# Disable access rules for this list of users
bypass_for_users: []
```

## Development and Testing
Expand Down
30 changes: 30 additions & 0 deletions room_access_rules/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class AccessRules:
@attr.s(frozen=True, auto_attribs=True)
class RoomAccessRulesConfig:
id_server: str
bypass_for_users: List[str] = []
domains_forbidden_when_restricted: List[str] = []
fix_admins_for_dm_power_levels: bool = False
add_live_location_power_levels: bool = False
Expand Down Expand Up @@ -306,6 +307,12 @@ async def on_create_room(
access_rule = None
join_rule = None

if (
is_requester_admin
or requester.user.to_string() in self.config.bypass_for_users
):
return True

# If there's a rules event in the initial state, check if it complies with the
# spec for im.vector.room.access_rules and deny the request if not.
for event in config.get("initial_state", []):
Expand Down Expand Up @@ -486,6 +493,14 @@ async def check_threepid_can_be_invited(

return True

async def _user_can_bypass_rules(self, user_id: str) -> bool:
if (
user_id in self.config.bypass_for_users
or await self.module_api.is_user_admin(user_id)
):
return True
return False

async def check_event_allowed(
self,
event: EventBase,
Expand All @@ -504,6 +519,9 @@ async def check_event_allowed(
allowed, False if it should be rejected. The second entry is always
None because this module doesn't replace event contents.
"""
if await self._user_can_bypass_rules(event.sender):
return True, None

# We check the rules when altering the state of the room, so only go further if
# the event is a state event.
if event.is_state():
Expand Down Expand Up @@ -643,6 +661,18 @@ async def _on_membership_or_invite(
Returns:
A boolean indicating whether the event is allowed.
"""

# Let's ignore rules if the user is accepting an invite coming from
# an user in the bypass list or an admin
if event.type == EventTypes.Member and event.membership == Membership.JOIN:
previous_membership = state_events.get((EventTypes.Member, event.state_key))
if (
previous_membership
and previous_membership.membership == Membership.INVITE
):
if await self._user_can_bypass_rules(previous_membership.sender):
return True

if rule == AccessRules.RESTRICTED:
ret = self._on_membership_or_invite_restricted(event)
elif rule == AccessRules.UNRESTRICTED:
Expand Down
3 changes: 2 additions & 1 deletion tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Any, Dict, Optional
from unittest.mock import Mock
from unittest.mock import AsyncMock, Mock

import attr
from synapse.module_api import ModuleApi, UserID
Expand Down Expand Up @@ -87,6 +87,7 @@ def create_module(
module_api.http_client = MockHttpClient()
module_api.public_room_list_manager = MockPublicRoomListManager()
module_api._hs = MockHomeserver()
module_api.is_user_admin = AsyncMock(return_value=False)

if config_override is None:
config_override = {}
Expand Down
Loading