From 57b68ef3e3e4c0094f0b4f6023c6c3a1de76c8c3 Mon Sep 17 00:00:00 2001 From: Kumi Date: Tue, 5 Dec 2023 10:09:14 +0100 Subject: [PATCH] Enhance Pantalaimon integration and config Integrated Pantalaimon support with updated configuration instructions and examples, facilitating secure communication when using the Matrix homeserver. The .gitignore is now extended to exclude a Pantalaimon configuration file, preventing sensitive information from accidental commits. Removed encryption callbacks and related functions as the application leverages Pantalaimon for E2EE, simplifying the codebase and shifting encryption responsibilities externally. Streamlined dependency management by removing the requirements.txt in favor of pyproject.toml, aligning with modern Python practices. This change overall improves security handling and eases future maintenance. --- .gitignore | 3 +- config.dist.ini | 3 + pantalaimon.example.conf | 5 ++ pantalaimon_first_login.py | 22 ++++++ pyproject.toml | 6 +- requirements.txt | 11 --- src/gptbot/callbacks/__init__.py | 4 - src/gptbot/callbacks/encrypted.py | 21 ------ src/gptbot/callbacks/keys.py | 14 ---- src/gptbot/callbacks/roomkey.py | 0 src/gptbot/classes/bot.py | 118 ++++-------------------------- 11 files changed, 50 insertions(+), 157 deletions(-) create mode 100644 pantalaimon.example.conf create mode 100644 pantalaimon_first_login.py delete mode 100644 requirements.txt delete mode 100644 src/gptbot/callbacks/encrypted.py delete mode 100644 src/gptbot/callbacks/keys.py delete mode 100644 src/gptbot/callbacks/roomkey.py diff --git a/.gitignore b/.gitignore index 1a46de2..84d3979 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ venv/ *.pyc __pycache__/ *.bak -dist/ \ No newline at end of file +dist/ +pantalaimon.conf \ No newline at end of file diff --git a/config.dist.ini b/config.dist.ini index 1eef4d7..2fb7886 100644 --- a/config.dist.ini +++ b/config.dist.ini @@ -129,6 +129,9 @@ APIKey = sk-yoursecretkey # The URL to your Matrix homeserver # +# If you are using Pantalaimon, this should be the URL of your Pantalaimon +# instance, not the Matrix homeserver itself. +# Homeserver = https://matrix.local # An Access Token for the user your bot runs as diff --git a/pantalaimon.example.conf b/pantalaimon.example.conf new file mode 100644 index 0000000..5cc48fd --- /dev/null +++ b/pantalaimon.example.conf @@ -0,0 +1,5 @@ +[Homeserver] +Homeserver = https://example.com +ListenAddress = localhost +ListenPort = 8010 +IgnoreVerification = True \ No newline at end of file diff --git a/pantalaimon_first_login.py b/pantalaimon_first_login.py new file mode 100644 index 0000000..7392337 --- /dev/null +++ b/pantalaimon_first_login.py @@ -0,0 +1,22 @@ +from nio import AsyncClient + +from configparser import ConfigParser + +async def main(): + config = ConfigParser() + config.read("config.ini") + + user_id = input("User ID: ") + password = input("Password: ") + + client = AsyncClient(config["Matrix"]["Homeserver"]) + client.user = user_id + await client.login(password) + + print("Access token: " + client.access_token) + + await client.close() + +if __name__ == "__main__": + import asyncio + asyncio.get_event_loop().run_until_complete(main()) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 0b69bfb..01121df 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,8 +50,12 @@ trackingmore = [ "trackingmore @ git+https://kumig.it/kumitterer/trackingmore-api-tool.git", ] +e2ee = [ + "pantalaimon", +] + all = [ - "matrix-gptbot[openai,wolframalpha,trackingmore]", + "matrix-gptbot[openai,wolframalpha,trackingmore,e2ee]", "geopy", "beautifulsoup4", ] diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index c19cce1..0000000 --- a/requirements.txt +++ /dev/null @@ -1,11 +0,0 @@ -openai>=1.2 -matrix-nio[e2e] -markdown2[all] -tiktoken -duckdb -python-magic -pillow -wolframalpha -pydub - -git+https://kumig.it/kumitterer/trackingmore-api-tool.git \ No newline at end of file diff --git a/src/gptbot/callbacks/__init__.py b/src/gptbot/callbacks/__init__.py index f57fa92..77ec2a1 100644 --- a/src/gptbot/callbacks/__init__.py +++ b/src/gptbot/callbacks/__init__.py @@ -16,15 +16,12 @@ from .invite import room_invite_callback from .join import join_callback from .message import message_callback from .roommember import roommember_callback -from .encrypted import encrypted_message_callback -from .keys import keys_query_callback from .test_response import test_response_callback RESPONSE_CALLBACKS = { #Response: test_response_callback, SyncResponse: sync_callback, JoinResponse: join_callback, - #KeysQueryResponse: keys_query_callback, } EVENT_CALLBACKS = { @@ -32,5 +29,4 @@ EVENT_CALLBACKS = { InviteEvent: room_invite_callback, RoomMessageText: message_callback, RoomMemberEvent: roommember_callback, - #MegolmEvent: encrypted_message_callback, } \ No newline at end of file diff --git a/src/gptbot/callbacks/encrypted.py b/src/gptbot/callbacks/encrypted.py deleted file mode 100644 index 54b69ce..0000000 --- a/src/gptbot/callbacks/encrypted.py +++ /dev/null @@ -1,21 +0,0 @@ -from nio import RoomMessage - -async def encrypted_message_callback(room, event, bot): - try: - # Request room key from server - room_key = await bot.matrix_client.request_room_key(room.room_id) - - # Attempt to decrypt the event - decrypted_event = await bot.matrix_client.decrypt_event(event) - - # Check if decryption was successful and the decrypted event has a new type - if isinstance(decrypted_event, RoomMessage): - # Send the decrypted event back to _event_callback for further processing - await bot._event_callback(room, decrypted_event) - else: - # Handle other decrypted event types or log a message - bot.logger.log(f"Decrypted event of type {type(decrypted_event)}", "info") - - except Exception as e: - bot.logger.log(f"Error decrypting event: {e}", "error") - await bot.send_message(room.room_id, "Sorry, I was unable to decrypt your message. Please try again, or use an unencrypted room.", True) diff --git a/src/gptbot/callbacks/keys.py b/src/gptbot/callbacks/keys.py deleted file mode 100644 index 7b032ce..0000000 --- a/src/gptbot/callbacks/keys.py +++ /dev/null @@ -1,14 +0,0 @@ -from nio.crypto.device import OlmDevice - -async def keys_query_callback(response, bot): - bot.matrix_client.receive_response(response) - try: - for user_id, device_dict in response.device_keys.items(): - for device_id, keys in device_dict.items(): - bot.logger.log(f"New keys for {device_id} from {user_id}: {keys}", "info") - device = OlmDevice(user_id, device_id, keys) - await bot.matrix_client.verify_device(device) - - except Exception as e: - bot.logger.log(f"Error handling KeysQueryResponse: {e}", "error") - raise diff --git a/src/gptbot/callbacks/roomkey.py b/src/gptbot/callbacks/roomkey.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/gptbot/classes/bot.py b/src/gptbot/classes/bot.py index 7bbc13b..a1bd219 100644 --- a/src/gptbot/classes/bot.py +++ b/src/gptbot/classes/bot.py @@ -15,7 +15,6 @@ from nio import ( MatrixRoom, Api, RoomMessagesError, - MegolmEvent, GroupEncryptionError, EncryptionError, RoomMessageText, @@ -33,12 +32,9 @@ from nio import ( RoomMessageAudio, DownloadError, DownloadResponse, - RoomKeyRequest, - RoomKeyRequestError, ToDeviceEvent, ToDeviceError, ) -from nio.crypto import Olm from nio.store import SqliteStore @@ -71,7 +67,7 @@ from .trackingmore import TrackingMore class GPTBot: # Default values database: Optional[sqlite3.Connection] = None - crypto_store_path: Optional[str | Path] = None + database_path: Optional[str | Path] = None matrix_client: Optional[AsyncClient] = None sync_token: Optional[str] = None logger: Optional[Logger] = Logger() @@ -207,15 +203,14 @@ class GPTBot: bot.config = config # Set the database connection - bot.database = ( - sqlite3.connect(config["Database"]["Path"]) + bot.database_path = ( + config["Database"]["Path"] if "Database" in config and "Path" in config["Database"] else None ) - - bot.crypto_store_path = ( - config["Database"]["CryptoStore"] - if "Database" in config and "CryptoStore" in config["Database"] + bot.database = ( + sqlite3.connect(bot.database_path) + if bot.database_path else None ) @@ -316,26 +311,6 @@ class GPTBot: if len(messages) >= n: break - if isinstance(event, ToDeviceEvent): - try: - event = await self.matrix_client.decrypt_to_device_event(event) - except ToDeviceError: - self.logger.log( - f"Could not decrypt message {event.event_id} in room {room_id}", - "error", - ) - continue - - if isinstance(event, MegolmEvent): - try: - event = await self.matrix_client.decrypt_event(event) - except (GroupEncryptionError, EncryptionError): - self.logger.log( - f"Could not decrypt message {event.event_id} in room {room_id}", - "error", - ) - continue - if isinstance(event, RoomMessageText): if event.body.startswith("!gptbot ignoreolder"): break @@ -753,36 +728,6 @@ class GPTBot: content = None - if self.matrix_client.olm and room.encrypted: - try: - if not room.members_synced: - responses = [] - responses.append( - await self.matrix_client.joined_members(room.room_id) - ) - - if self.matrix_client.olm.should_share_group_session(room.room_id): - try: - event = self.matrix_client.sharing_session[room.room_id] - await event.wait() - except KeyError: - await self.matrix_client.share_group_session( - room.room_id, - ignore_unverified_devices=True, - ) - - if msgtype != "m.reaction": - response = self.matrix_client.encrypt( - room.room_id, "m.room.message", msgcontent - ) - msgtype, content = response - - except Exception as e: - self.logger.log( - f"Error encrypting message: {e} - sending unencrypted", "warning" - ) - raise - if not content: msgtype = "m.room.message" content = msgcontent @@ -843,16 +788,8 @@ class GPTBot: if not self.matrix_client.device_id: self.matrix_client.device_id = await self._get_device_id() - # Set up database - - IN_MEMORY = False if not self.database: - self.logger.log( - "No database connection set up, using in-memory database. Data will be lost on bot shutdown.", - "warning", - ) - IN_MEMORY = True - self.database = sqlite3.connect(":memory:") + self.database = sqlite3.connect(Path(__file__).parent.parent / "database.db") self.logger.log("Running migrations...") @@ -872,34 +809,13 @@ class GPTBot: else: self.logger.log(f"Already at latest version {after}.") - if IN_MEMORY: - client_config = AsyncClientConfig( - store_sync_tokens=True, encryption_enabled=False - ) - else: - matrix_store = SqliteStore - client_config = AsyncClientConfig( - store_sync_tokens=True, encryption_enabled=True, store=matrix_store - ) - self.matrix_client.config = client_config - self.matrix_client.store = matrix_store( - self.matrix_client.user_id, - self.matrix_client.device_id, - '.', #store path - database_name=self.crypto_store_path or "", - ) + matrix_store = SqliteStore + client_config = AsyncClientConfig( + store_sync_tokens=True, encryption_enabled=False, store=matrix_store + ) + self.matrix_client.config = client_config - self.matrix_client.olm = Olm( - self.matrix_client.user_id, - self.matrix_client.device_id, - self.matrix_client.store, - ) - - self.matrix_client.encrypted_rooms = ( - self.matrix_client.store.load_encrypted_rooms() - ) - - # Run initial sync (now includes joining rooms) + # Run initial sync (includes joining rooms) sync = await self.matrix_client.sync(timeout=30000, full_state=True) if isinstance(sync, SyncResponse): await self.response_callback(sync) @@ -944,14 +860,6 @@ class GPTBot: self.logger.log("Syncing one last time...", "warning") await self.matrix_client.sync(timeout=30000, full_state=True) - async def request_keys(session_id, room_id): - request = RoomKeyRequest(session_id, room_id) - response = await client.send(request) - if isinstance(response, RoomKeyRequestError): - print(f"Failed to request keys for session {session_id}: {response.message}") - else: - print(f"Requested keys for session {session_id}") - async def create_space(self, name, visibility=RoomVisibility.private) -> str: """Create a space.