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.