support policy rooms
This commit is contained in:
parent
c0d5dfcb5b
commit
b7174bd16c
2 changed files with 89 additions and 21 deletions
14
README.md
14
README.md
|
@ -4,9 +4,9 @@ This is a Synapse module that checks incoming invites based on allowlist and blo
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **allowlist and blocklist**: Allows invites from homeservers in the allowlist, blocks invites from homeservers in the blocklist.
|
- **Allowlist and Blocklist**: Allows invites from homeservers in the allowlist, blocks invites from homeservers in the blocklist.
|
||||||
- **Dynamic Fetching**: The allowlist and blocklist are fetched dynamically from a provided URL, and cached.
|
- **Dynamic Fetching**: The allowlist and blocklist are fetched dynamically from a provided URL, and cached.
|
||||||
- **Fallback on Failure**: If the JSON file cannot be fetched (e.g., network error), the module automatically allows all invites to prevent disruptions.
|
- **Support for MSC2313 Policy Rooms**: This module now supports fetching blocklists from MSC2313 policy rooms to block invites
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
|
@ -18,15 +18,19 @@ modules:
|
||||||
config:
|
config:
|
||||||
# URL to fetch the JSON file containing the allowlist and blocklist
|
# URL to fetch the JSON file containing the allowlist and blocklist
|
||||||
blocklist_allowlist_url: "https://example.com/invite-checker-lists.json"
|
blocklist_allowlist_url: "https://example.com/invite-checker-lists.json"
|
||||||
|
# Optionally specify policy rooms for dynamic blocklist fetching via MSC2313
|
||||||
|
policy_rooms:
|
||||||
|
- "!policy-room-1:matrix.org"
|
||||||
|
- "!policy-room-2:matrix.org"
|
||||||
# Whether to use the allowlist to allow certain homeservers (default: true)
|
# Whether to use the allowlist to allow certain homeservers (default: true)
|
||||||
use_allowlist: true
|
use_allowlist: true
|
||||||
# Whether to use the blocklist to block certain homeservers (default: true)
|
# Whether to use the blocklist to block certain homeservers (default: true)
|
||||||
use_blocklist: true
|
use_blocklist: true
|
||||||
blocklist_rooms:
|
blocklist_rooms:
|
||||||
- "#test:matrix.org"
|
- "#test:matrix.org"
|
||||||
- "!dkgsemSiSMrGfxEwCb:ubuntu.com
|
- "!dkgsemSiSMrGfxEwCb:ubuntu.com"
|
||||||
|
|
||||||
Example for the contents of the URL with the json data:
|
Example for the contents of the URL with the JSON data:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
@ -46,4 +50,4 @@ Example for the contents of the URL with the json data:
|
||||||
"!abc123:matrix.org" // Direct room ID
|
"!abc123:matrix.org" // Direct room ID
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
|
@ -14,6 +14,7 @@ class InviteCheckerConfig:
|
||||||
self.use_blocklist = config.get("use_blocklist", True)
|
self.use_blocklist = config.get("use_blocklist", True)
|
||||||
self.blocklist_allowlist_url = config.get("blocklist_allowlist_url", None)
|
self.blocklist_allowlist_url = config.get("blocklist_allowlist_url", None)
|
||||||
self.blocklist_rooms = config.get("blocklist_rooms", []) # Blocklist for room names
|
self.blocklist_rooms = config.get("blocklist_rooms", []) # Blocklist for room names
|
||||||
|
self.policy_room_ids = config.get("policy_room_ids", []) # List of policy room IDs
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_config(config):
|
def parse_config(config):
|
||||||
|
@ -60,9 +61,54 @@ class InviteChecker:
|
||||||
logger.error(f"Error while fetching JSON: {str(e)}")
|
logger.error(f"Error while fetching JSON: {str(e)}")
|
||||||
returnValue(None)
|
returnValue(None)
|
||||||
|
|
||||||
|
@inlineCallbacks
|
||||||
|
def fetch_policy_room_banlist(self):
|
||||||
|
"""Fetches the ban lists from multiple policy rooms using Synapse API."""
|
||||||
|
if not self.config.policy_room_ids:
|
||||||
|
return set() # No policy rooms configured, return an empty set
|
||||||
|
|
||||||
|
logger.info(f"Fetching ban lists from policy rooms: {self.config.policy_room_ids}")
|
||||||
|
banned_entities = set()
|
||||||
|
banned_entities_by_room = set()
|
||||||
|
for room_id in self.config.policy_room_ids:
|
||||||
|
logger.info(f"Fetching ban list from policy room: {room_id}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Fetch all state events from the policy room
|
||||||
|
state_events = yield self.api.get_room_state(room_id)
|
||||||
|
|
||||||
|
if isinstance(state_events, dict):
|
||||||
|
logger.info(f"Received state events in dict format from room {room_id} with {len(state_events)} entries.")
|
||||||
|
|
||||||
|
# Loop over the dictionary of state events
|
||||||
|
for key, event in state_events.items():
|
||||||
|
event_type = event.get("type", "")
|
||||||
|
content = event.get("content", {})
|
||||||
|
|
||||||
|
# Check for ban events of type 'm.policy.rule.user' and 'm.policy.rule.server'
|
||||||
|
if event_type in ["m.policy.rule.user", "m.policy.rule.server"]:
|
||||||
|
entity = content.get('entity', '')
|
||||||
|
if entity:
|
||||||
|
banned_entities_by_room.add(entity)
|
||||||
|
#else:
|
||||||
|
# logger.warning(f"Missing 'entity' in event: {event}")
|
||||||
|
|
||||||
|
logger.info(f"Fetched {len(banned_entities_by_room)} banned entities from policy room {room_id}.")
|
||||||
|
banned_entities = banned_entities_by_room.union(banned_entities)
|
||||||
|
banned_entities_by_room = set()
|
||||||
|
|
||||||
|
else:
|
||||||
|
logger.error(f"Unexpected response format from room {room_id}: {type(state_events)}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to fetch policy room ban list from room {room_id}. Error: {str(e)}")
|
||||||
|
|
||||||
|
logger.info(f"Total banned entities from all policy rooms: {len(banned_entities)}")
|
||||||
|
return banned_entities
|
||||||
|
|
||||||
@inlineCallbacks
|
@inlineCallbacks
|
||||||
def update_blocklist_allowlist(self):
|
def update_blocklist_allowlist(self):
|
||||||
"""Fetch and update the blocklist, allowlist, and blocklisted room IDs from the URLs."""
|
"""Fetch and update the blocklist, allowlist, and blocklisted room IDs."""
|
||||||
logger.info("Updating blocklist, allowlist, and room blocklist")
|
logger.info("Updating blocklist, allowlist, and room blocklist")
|
||||||
|
|
||||||
json_data = yield self.fetch_json(self.config.blocklist_allowlist_url)
|
json_data = yield self.fetch_json(self.config.blocklist_allowlist_url)
|
||||||
|
@ -73,25 +119,43 @@ class InviteChecker:
|
||||||
self.use_blocklist = json_data.get('use_blocklist', True)
|
self.use_blocklist = json_data.get('use_blocklist', True)
|
||||||
self.blocklist = set(json_data.get('blocklist', []))
|
self.blocklist = set(json_data.get('blocklist', []))
|
||||||
self.allowlist = set(json_data.get('allowlist', []))
|
self.allowlist = set(json_data.get('allowlist', []))
|
||||||
self.blocklist_room_ids_json = set(json_data.get('blocklist_rooms', []))
|
|
||||||
self.blocklist_room_ids = set()
|
# Fetch and merge the policy room ban lists from multiple rooms
|
||||||
for room_entry in self.blocklist_room_ids_json:
|
policy_banlist = yield self.fetch_policy_room_banlist()
|
||||||
|
self.blocklist.update(policy_banlist)
|
||||||
|
|
||||||
|
self.blocklist_room_ids = set()
|
||||||
|
for room_entry in json_data.get('blocklist_rooms', []):
|
||||||
if room_entry.startswith('!'):
|
if room_entry.startswith('!'):
|
||||||
# If it's a room ID, add it directly to the blocklist
|
|
||||||
logger.info(f"Blocklisting room ID directly: {room_entry}")
|
logger.info(f"Blocklisting room ID directly: {room_entry}")
|
||||||
self.blocklist_room_ids.add(room_entry)
|
self.blocklist_room_ids.add(room_entry)
|
||||||
else:
|
else:
|
||||||
try:
|
room_id = yield self.resolve_room_id(room_entry)
|
||||||
# If it's a room alias, resolve it to a room ID
|
if room_id:
|
||||||
room_id = yield self.resolve_room_id(room_entry)
|
logger.info(f"Blocklisting room: {room_entry} -> {room_id}")
|
||||||
if room_id:
|
self.blocklist_room_ids.add(room_id)
|
||||||
logger.info(f"Blocklisting room: {room_entry} -> {room_id}")
|
else:
|
||||||
self.blocklist_room_ids.add(room_id)
|
logger.error(f"Failed to blocklist room: {room_entry}")
|
||||||
else:
|
|
||||||
logger.error(f"Failed to blocklist room: {room_entry}")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Failed to blocklist room: {room_entry}. Error: {str(e)}")
|
|
||||||
|
|
||||||
|
logger.info(f"Updated blocklist with {len(self.blocklist)} entries and {len(self.blocklist_room_ids)} room IDs.")
|
||||||
|
else:
|
||||||
|
logger.error("Failed to update allowlist/blocklist due to missing JSON data.")
|
||||||
|
self.allow_all_invites_on_error = True
|
||||||
|
|
||||||
|
@inlineCallbacks
|
||||||
|
def resolve_room_id(self, room_alias):
|
||||||
|
"""Resolve a room alias to a room_id and cache the result."""
|
||||||
|
if room_alias in self.room_id_cache:
|
||||||
|
returnValue(self.room_id_cache[room_alias])
|
||||||
|
|
||||||
|
logger.info(f"Resolving room alias to room_id: {room_alias}")
|
||||||
|
try:
|
||||||
|
room_id = yield self.api.resolve_room_alias(room_alias)
|
||||||
|
self.room_id_cache[room_alias] = room_id
|
||||||
|
returnValue(room_id)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to resolve room alias {room_alias}: {e}")
|
||||||
|
returnValue(None)
|
||||||
|
|
||||||
@inlineCallbacks
|
@inlineCallbacks
|
||||||
def get_blocklist_allowlist(self):
|
def get_blocklist_allowlist(self):
|
||||||
|
@ -117,7 +181,7 @@ class InviteChecker:
|
||||||
blocklist, allowlist, blocklist_room_ids = yield self.get_blocklist_allowlist()
|
blocklist, allowlist, blocklist_room_ids = yield self.get_blocklist_allowlist()
|
||||||
inviter_domain = UserID.from_string(inviter).domain
|
inviter_domain = UserID.from_string(inviter).domain
|
||||||
|
|
||||||
logger.info(f"Blocklist: {blocklist}, Allowlist: {allowlist}, Blocklist Room IDs: {blocklist_room_ids}")
|
logger.debug(f"Blocklist: {blocklist}, Allowlist: {allowlist}, Blocklist Room IDs: {blocklist_room_ids}")
|
||||||
|
|
||||||
if room_id in blocklist_room_ids:
|
if room_id in blocklist_room_ids:
|
||||||
logger.info(f"Invite blocked: room {room_id} is blocklisted")
|
logger.info(f"Invite blocked: room {room_id} is blocklisted")
|
||||||
|
|
Loading…
Reference in a new issue