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.
This commit is contained in:
parent
4eb33a3c0a
commit
57b68ef3e3
11 changed files with 50 additions and 157 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -6,4 +6,5 @@ venv/
|
||||||
*.pyc
|
*.pyc
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.bak
|
*.bak
|
||||||
dist/
|
dist/
|
||||||
|
pantalaimon.conf
|
|
@ -129,6 +129,9 @@ APIKey = sk-yoursecretkey
|
||||||
|
|
||||||
# The URL to your Matrix homeserver
|
# 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
|
Homeserver = https://matrix.local
|
||||||
|
|
||||||
# An Access Token for the user your bot runs as
|
# An Access Token for the user your bot runs as
|
||||||
|
|
5
pantalaimon.example.conf
Normal file
5
pantalaimon.example.conf
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
[Homeserver]
|
||||||
|
Homeserver = https://example.com
|
||||||
|
ListenAddress = localhost
|
||||||
|
ListenPort = 8010
|
||||||
|
IgnoreVerification = True
|
22
pantalaimon_first_login.py
Normal file
22
pantalaimon_first_login.py
Normal file
|
@ -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())
|
|
@ -50,8 +50,12 @@ trackingmore = [
|
||||||
"trackingmore @ git+https://kumig.it/kumitterer/trackingmore-api-tool.git",
|
"trackingmore @ git+https://kumig.it/kumitterer/trackingmore-api-tool.git",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
e2ee = [
|
||||||
|
"pantalaimon",
|
||||||
|
]
|
||||||
|
|
||||||
all = [
|
all = [
|
||||||
"matrix-gptbot[openai,wolframalpha,trackingmore]",
|
"matrix-gptbot[openai,wolframalpha,trackingmore,e2ee]",
|
||||||
"geopy",
|
"geopy",
|
||||||
"beautifulsoup4",
|
"beautifulsoup4",
|
||||||
]
|
]
|
||||||
|
|
|
@ -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
|
|
|
@ -16,15 +16,12 @@ from .invite import room_invite_callback
|
||||||
from .join import join_callback
|
from .join import join_callback
|
||||||
from .message import message_callback
|
from .message import message_callback
|
||||||
from .roommember import roommember_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
|
from .test_response import test_response_callback
|
||||||
|
|
||||||
RESPONSE_CALLBACKS = {
|
RESPONSE_CALLBACKS = {
|
||||||
#Response: test_response_callback,
|
#Response: test_response_callback,
|
||||||
SyncResponse: sync_callback,
|
SyncResponse: sync_callback,
|
||||||
JoinResponse: join_callback,
|
JoinResponse: join_callback,
|
||||||
#KeysQueryResponse: keys_query_callback,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EVENT_CALLBACKS = {
|
EVENT_CALLBACKS = {
|
||||||
|
@ -32,5 +29,4 @@ EVENT_CALLBACKS = {
|
||||||
InviteEvent: room_invite_callback,
|
InviteEvent: room_invite_callback,
|
||||||
RoomMessageText: message_callback,
|
RoomMessageText: message_callback,
|
||||||
RoomMemberEvent: roommember_callback,
|
RoomMemberEvent: roommember_callback,
|
||||||
#MegolmEvent: encrypted_message_callback,
|
|
||||||
}
|
}
|
|
@ -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)
|
|
|
@ -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
|
|
|
@ -15,7 +15,6 @@ from nio import (
|
||||||
MatrixRoom,
|
MatrixRoom,
|
||||||
Api,
|
Api,
|
||||||
RoomMessagesError,
|
RoomMessagesError,
|
||||||
MegolmEvent,
|
|
||||||
GroupEncryptionError,
|
GroupEncryptionError,
|
||||||
EncryptionError,
|
EncryptionError,
|
||||||
RoomMessageText,
|
RoomMessageText,
|
||||||
|
@ -33,12 +32,9 @@ from nio import (
|
||||||
RoomMessageAudio,
|
RoomMessageAudio,
|
||||||
DownloadError,
|
DownloadError,
|
||||||
DownloadResponse,
|
DownloadResponse,
|
||||||
RoomKeyRequest,
|
|
||||||
RoomKeyRequestError,
|
|
||||||
ToDeviceEvent,
|
ToDeviceEvent,
|
||||||
ToDeviceError,
|
ToDeviceError,
|
||||||
)
|
)
|
||||||
from nio.crypto import Olm
|
|
||||||
from nio.store import SqliteStore
|
from nio.store import SqliteStore
|
||||||
|
|
||||||
|
|
||||||
|
@ -71,7 +67,7 @@ from .trackingmore import TrackingMore
|
||||||
class GPTBot:
|
class GPTBot:
|
||||||
# Default values
|
# Default values
|
||||||
database: Optional[sqlite3.Connection] = None
|
database: Optional[sqlite3.Connection] = None
|
||||||
crypto_store_path: Optional[str | Path] = None
|
database_path: Optional[str | Path] = None
|
||||||
matrix_client: Optional[AsyncClient] = None
|
matrix_client: Optional[AsyncClient] = None
|
||||||
sync_token: Optional[str] = None
|
sync_token: Optional[str] = None
|
||||||
logger: Optional[Logger] = Logger()
|
logger: Optional[Logger] = Logger()
|
||||||
|
@ -207,15 +203,14 @@ class GPTBot:
|
||||||
bot.config = config
|
bot.config = config
|
||||||
|
|
||||||
# Set the database connection
|
# Set the database connection
|
||||||
bot.database = (
|
bot.database_path = (
|
||||||
sqlite3.connect(config["Database"]["Path"])
|
config["Database"]["Path"]
|
||||||
if "Database" in config and "Path" in config["Database"]
|
if "Database" in config and "Path" in config["Database"]
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
|
bot.database = (
|
||||||
bot.crypto_store_path = (
|
sqlite3.connect(bot.database_path)
|
||||||
config["Database"]["CryptoStore"]
|
if bot.database_path
|
||||||
if "Database" in config and "CryptoStore" in config["Database"]
|
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -316,26 +311,6 @@ class GPTBot:
|
||||||
if len(messages) >= n:
|
if len(messages) >= n:
|
||||||
break
|
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 isinstance(event, RoomMessageText):
|
||||||
if event.body.startswith("!gptbot ignoreolder"):
|
if event.body.startswith("!gptbot ignoreolder"):
|
||||||
break
|
break
|
||||||
|
@ -753,36 +728,6 @@ class GPTBot:
|
||||||
|
|
||||||
content = None
|
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:
|
if not content:
|
||||||
msgtype = "m.room.message"
|
msgtype = "m.room.message"
|
||||||
content = msgcontent
|
content = msgcontent
|
||||||
|
@ -843,16 +788,8 @@ class GPTBot:
|
||||||
if not self.matrix_client.device_id:
|
if not self.matrix_client.device_id:
|
||||||
self.matrix_client.device_id = await self._get_device_id()
|
self.matrix_client.device_id = await self._get_device_id()
|
||||||
|
|
||||||
# Set up database
|
|
||||||
|
|
||||||
IN_MEMORY = False
|
|
||||||
if not self.database:
|
if not self.database:
|
||||||
self.logger.log(
|
self.database = sqlite3.connect(Path(__file__).parent.parent / "database.db")
|
||||||
"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.logger.log("Running migrations...")
|
self.logger.log("Running migrations...")
|
||||||
|
|
||||||
|
@ -872,34 +809,13 @@ class GPTBot:
|
||||||
else:
|
else:
|
||||||
self.logger.log(f"Already at latest version {after}.")
|
self.logger.log(f"Already at latest version {after}.")
|
||||||
|
|
||||||
if IN_MEMORY:
|
matrix_store = SqliteStore
|
||||||
client_config = AsyncClientConfig(
|
client_config = AsyncClientConfig(
|
||||||
store_sync_tokens=True, encryption_enabled=False
|
store_sync_tokens=True, encryption_enabled=False, store=matrix_store
|
||||||
)
|
)
|
||||||
else:
|
self.matrix_client.config = client_config
|
||||||
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 "",
|
|
||||||
)
|
|
||||||
|
|
||||||
self.matrix_client.olm = Olm(
|
# Run initial sync (includes joining rooms)
|
||||||
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)
|
|
||||||
sync = await self.matrix_client.sync(timeout=30000, full_state=True)
|
sync = await self.matrix_client.sync(timeout=30000, full_state=True)
|
||||||
if isinstance(sync, SyncResponse):
|
if isinstance(sync, SyncResponse):
|
||||||
await self.response_callback(sync)
|
await self.response_callback(sync)
|
||||||
|
@ -944,14 +860,6 @@ class GPTBot:
|
||||||
self.logger.log("Syncing one last time...", "warning")
|
self.logger.log("Syncing one last time...", "warning")
|
||||||
await self.matrix_client.sync(timeout=30000, full_state=True)
|
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:
|
async def create_space(self, name, visibility=RoomVisibility.private) -> str:
|
||||||
"""Create a space.
|
"""Create a space.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue