From d3ddeb30671e7a5b33e5758bf6e33191662bc1e3 Mon Sep 17 00:00:00 2001 From: djmaze <7229+djmaze@users.noreply.github.com> Date: Tue, 10 Feb 2026 02:01:15 +0100 Subject: [PATCH] fix: activate E2E and accept room invites in Matrix channels --- nanobot/channels/matrix.py | 48 ++++++++++++++++++++++++-------------- nanobot/config/schema.py | 12 ++++++++++ pyproject.toml | 1 + 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/nanobot/channels/matrix.py b/nanobot/channels/matrix.py index 0ea4ae1..f3b8468 100644 --- a/nanobot/channels/matrix.py +++ b/nanobot/channels/matrix.py @@ -1,10 +1,11 @@ import asyncio from typing import Any -from nio import AsyncClient, MatrixRoom, RoomMessageText +from nio import AsyncClient, AsyncClientConfig, InviteEvent, MatrixRoom, RoomMessageText -from nanobot.channels.base import BaseChannel from nanobot.bus.events import OutboundMessage +from nanobot.channels.base import BaseChannel +from nanobot.config.loader import get_data_dir class MatrixChannel(BaseChannel): @@ -22,18 +23,28 @@ class MatrixChannel(BaseChannel): async def start(self) -> None: self._running = True - self.client = AsyncClient( - homeserver=self.config.homeserver, - user=self.config.user_id, - ) - - self.client.access_token = self.config.access_token + store_path = get_data_dir() / "matrix-store" + store_path.mkdir(parents=True, exist_ok=True) - self.client.add_event_callback( - self._on_message, - RoomMessageText + self.client = AsyncClient( + homeserver=self.config.homeserver, + user=self.config.user_id, + store_path=store_path, # Where tokens are saved + config=AsyncClientConfig( + store_sync_tokens=True, # Auto-persists next_batch tokens + encryption_enabled=True, + ), ) + self.client.user_id = self.config.user_id + self.client.access_token = self.config.access_token + self.client.device_id = self.config.device_id + + self.client.add_event_callback(self._on_message, RoomMessageText) + self.client.add_event_callback(self._on_room_invite, InviteEvent) + + self.client.load_store() + self._sync_task = asyncio.create_task(self._sync_loop()) async def stop(self) -> None: @@ -51,22 +62,23 @@ class MatrixChannel(BaseChannel): room_id=msg.chat_id, message_type="m.room.message", content={"msgtype": "m.text", "body": msg.content}, + ignore_unverified_devices=True, ) async def _sync_loop(self) -> None: while self._running: try: - await self.client.sync(timeout=30000) + await self.client.sync_forever(timeout=30000, full_state=True) except asyncio.CancelledError: break except Exception: await asyncio.sleep(2) - async def _on_message( - self, - room: MatrixRoom, - event: RoomMessageText - ) -> None: + async def _on_room_invite(self, room: MatrixRoom, event: RoomMessageText) -> None: + if event.sender in self.config.allow_from: + await self.client.join(room.room_id) + + async def _on_message(self, room: MatrixRoom, event: RoomMessageText) -> None: # Ignore self messages if event.sender == self.config.user_id: return @@ -76,4 +88,4 @@ class MatrixChannel(BaseChannel): chat_id=room.room_id, content=event.body, metadata={"room": room.display_name}, - ) \ No newline at end of file + ) diff --git a/nanobot/config/schema.py b/nanobot/config/schema.py index 6a1257e..8413f0a 100644 --- a/nanobot/config/schema.py +++ b/nanobot/config/schema.py @@ -60,6 +60,17 @@ class DiscordConfig(Base): intents: int = 37377 # GUILDS + GUILD_MESSAGES + DIRECT_MESSAGES + MESSAGE_CONTENT +class MatrixConfig(Base): + """Matrix (Element) channel configuration.""" + + enabled: bool = False + homeserver: str = "https://matrix.org" + access_token: str = "" + user_id: str = "" # @bot:matrix.org + device_id: str = "" + allow_from: list[str] = Field(default_factory=list) + + class EmailConfig(Base): """Email channel configuration (IMAP inbound + SMTP outbound).""" @@ -176,6 +187,7 @@ class ChannelsConfig(Base): email: EmailConfig = Field(default_factory=EmailConfig) slack: SlackConfig = Field(default_factory=SlackConfig) qq: QQConfig = Field(default_factory=QQConfig) + matrix: MatrixConfig = Field(default_factory=MatrixConfig) class AgentDefaults(Base): diff --git a/pyproject.toml b/pyproject.toml index 64a884d..18bbe70 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,6 +42,7 @@ dependencies = [ "prompt-toolkit>=3.0.50,<4.0.0", "mcp>=1.26.0,<2.0.0", "json-repair>=0.57.0,<1.0.0", + "matrix-nio[e2e]>=0.25.2", ] [project.optional-dependencies]