From 8a3bda97977c57ea01336647f0df70c20b59f880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?poljar=20=28Damir=20Jeli=C4=87=29?= Date: Wed, 9 May 2018 14:00:32 +0200 Subject: [PATCH] encryption: Stub functions for encrypted messages. --- main.py | 7 ++++--- matrix/api.py | 30 ++++++++++++++++++++++++++++++ matrix/commands.py | 3 +++ matrix/encryption.py | 34 +++++++++++++++++++++++++++++++++- matrix/events.py | 17 +++++++++++++++++ matrix/server.py | 20 ++++++++++++++++++++ 6 files changed, 107 insertions(+), 4 deletions(-) diff --git a/main.py b/main.py index 4e18f7b..5b9b02a 100644 --- a/main.py +++ b/main.py @@ -410,11 +410,12 @@ def room_input_cb(server_name, buffer, input_data): room_id = key_from_value(server.buffers, buffer) room = server.rooms[room_id] - if room.encrypted: - return W.WEECHAT_RC_OK - formatted_data = Formatted.from_input_line(input_data) + if room.encrypted: + server.send_room_message(room_id, formatted_data) + return W.WEECHAT_RC_OK + message = MatrixSendMessage( server.client, room_id=room_id, formatted_message=formatted_data) diff --git a/matrix/api.py b/matrix/api.py index dfb775a..00f1570 100644 --- a/matrix/api.py +++ b/matrix/api.py @@ -293,6 +293,20 @@ class MatrixClient: return HttpRequest(RequestType.POST, self.host, path, content) + def key_claim(self, key_dict): + query_parameters = {"access_token": self.access_token} + + path = ("{api}/keys/claim?" + "{query_parameters}").format( + api=MATRIX_API_PATH, + query_parameters=urlencode(query_parameters)) + + content = { + "one_time_keys": {key_dict} + } + + return HttpRequest(RequestType.POST, self.host, path, content) + def mxc_to_http(self, mxc): # type: (str) -> str url = urlparse(mxc) @@ -618,3 +632,19 @@ class MatrixKeyQueryMessage(MatrixMessage): server) return self._decode(server, object_hook) + + +class MatrixKeyClaimMessage(MatrixMessage): + + def __init__(self, client, key_dict): + data = { + "key_dict": key_dict, + } + + MatrixMessage.__init__(self, client.keys_query, data) + + def decode_body(self, server): + object_hook = partial(MatrixEvents.MatrixKeyClaimEvent.from_dict, + server) + + return self._decode(server, object_hook) diff --git a/matrix/commands.py b/matrix/commands.py index 958f180..0046526 100644 --- a/matrix/commands.py +++ b/matrix/commands.py @@ -134,6 +134,9 @@ def matrix_me_command_cb(data, buffer, args): room_id=room_id, formatted_message=formatted_data) + if server.rooms[room_id].encrypted: + return W.WEECHAT_RC_OK + server.send_or_queue(message) return W.WEECHAT_RC_OK diff --git a/matrix/encryption.py b/matrix/encryption.py index 92088b1..79ac911 100644 --- a/matrix/encryption.py +++ b/matrix/encryption.py @@ -20,6 +20,7 @@ from __future__ import unicode_literals import os import json import sqlite3 +import pprint # pylint: disable=redefined-builtin from builtins import str, bytes @@ -34,7 +35,11 @@ try: from olm.account import Account, OlmAccountError from olm.session import (Session, InboundSession, OlmSessionError, OlmPreKeyMessage) - from olm.group_session import InboundGroupSession, OlmGroupSessionError + from olm.group_session import ( + InboundGroupSession, + OutboundGroupSession, + OlmGroupSessionError + ) except ImportError: matrix.globals.ENCRYPTION = False @@ -229,6 +234,7 @@ class Olm(): self.sessions = sessions self.inbound_group_sessions = inbound_group_sessions + self.outbound_group_sessions = {} def _create_session(self, sender, sender_key, message): W.prnt("", "matrix: Creating session for {}".format(sender)) @@ -245,6 +251,32 @@ class Olm(): self.inbound_group_sessions[room_id][session_id] = session self._store_inbound_group_session(room_id, session) + def create_outbound_group_session(self, room_id): + session = OutboundGroupSession() + self.outbound_group_sessions[room_id] = session + self.create_group_session(room_id, session.id, session.session_key) + + @encrypt_enabled + def get_missing_sessions(self, users): + # type: (List[str]) -> Dict[str, Dict[str, str]] + missing = {} + + for user in users: + devices = [] + + for key in self.device_keys[user]: + # we don't need a session for our own device, skip it + if key.device_id == self.device_id: + continue + + if not self.sessions[user][key.device_id]: + devices.append(key.device_id) + + if devices: + missing[user] = {device: "ed25519" for device in devices} + + return missing + @encrypt_enabled def decrypt(self, sender, sender_key, message): plaintext = None diff --git a/matrix/events.py b/matrix/events.py index 2b96865..ee624d9 100644 --- a/matrix/events.py +++ b/matrix/events.py @@ -18,6 +18,7 @@ from __future__ import unicode_literals from builtins import str import json +import pprint from collections import deque, defaultdict from functools import partial @@ -337,10 +338,12 @@ class MatrixKeyQueryEvent(MatrixEvent): device_keys)) return cls(server, keys) except KeyError: + # TODO error message return MatrixErrorEvent.from_dict(server, "Error kicking user", False, parsed_dict) def execute(self): + # TODO move this logic into an Olm method olm = self.server.olm if olm.device_keys == self.keys: @@ -350,6 +353,20 @@ class MatrixKeyQueryEvent(MatrixEvent): # TODO invalidate megolm sessions for rooms that got new devices +class MatrixKeyClaimEvent(MatrixEvent): + + def __init__(self, server, keys): + self.keys = keys + MatrixEvent.__init__(self, server) + + @classmethod + def from_dict(cls, server, parsed_dict): + raise NotImplementedError + + def execute(self): + pass + + class MatrixBacklogEvent(MatrixEvent): def __init__(self, server, room_id, end_token, events): diff --git a/matrix/server.py b/matrix/server.py index 72f8599..d32e155 100644 --- a/matrix/server.py +++ b/matrix/server.py @@ -476,6 +476,26 @@ class MatrixServer: message = MatrixSyncMessage(self.client, self.next_batch, limit) self.send_queue.append(message) + def send_room_message(self, room_id, formatted_data): + # type: (str, Formatted) -> None + room = self.rooms[room_id] + + if not room.encrypted: + return + + missing = self.olm.get_missing_sessions(room.users.keys()) + + if missing: + W.prnt("", "{prefix}matrix: Olm session missing for room, can't" + " encrypt message.") + W.prnt("", pprint.pformat(missing)) + # message = MatrixKeyClaimMessage(self.client, missing) + # self.send_or_queue(message) + # TODO claim keys for the missing user/device combinations + return + + # self.send_queue.append(message) + @encrypt_enabled def upload_keys(self, device_keys=False, one_time_keys=False): keys = self.olm.account.identity_keys() if device_keys else None