encryption: Initial key claiming support.

This commit is contained in:
poljar (Damir Jelić) 2018-05-16 11:21:59 +02:00
parent 47fae308e0
commit c8a7b4815d
4 changed files with 91 additions and 22 deletions

View file

@ -306,7 +306,7 @@ class MatrixClient:
return HttpRequest(RequestType.POST, self.host, path, content) return HttpRequest(RequestType.POST, self.host, path, content)
def key_claim(self, key_dict): def keys_claim(self, key_dict):
query_parameters = {"access_token": self.access_token} query_parameters = {"access_token": self.access_token}
path = ("{api}/keys/claim?" path = ("{api}/keys/claim?"
@ -315,7 +315,8 @@ class MatrixClient:
query_parameters=urlencode(query_parameters)) query_parameters=urlencode(query_parameters))
content = { content = {
"one_time_keys": {key_dict} "one_time_keys": key_dict,
"timeout": 10000
} }
return HttpRequest(RequestType.POST, self.host, path, content) return HttpRequest(RequestType.POST, self.host, path, content)
@ -661,16 +662,17 @@ class MatrixKeyQueryMessage(MatrixMessage):
class MatrixKeyClaimMessage(MatrixMessage): class MatrixKeyClaimMessage(MatrixMessage):
def __init__(self, client, key_dict): def __init__(self, client, room_id, key_dict):
self.room_id = room_id
data = { data = {
"key_dict": key_dict, "key_dict": key_dict,
} }
MatrixMessage.__init__(self, client.keys_query, data) MatrixMessage.__init__(self, client.keys_claim, data)
def decode_body(self, server): def decode_body(self, server):
object_hook = partial(MatrixEvents.MatrixKeyClaimEvent.from_dict, object_hook = partial(MatrixEvents.MatrixKeyClaimEvent.from_dict,
server) server, self.room_id)
return self._decode(server, object_hook) return self._decode(server, object_hook)

View file

@ -33,8 +33,8 @@ import matrix.globals
try: try:
from olm.account import Account, OlmAccountError from olm.account import Account, OlmAccountError
from olm.session import (Session, InboundSession, OlmSessionError, from olm.session import (Session, InboundSession, OutboundSession,
OlmPreKeyMessage) OlmSessionError, OlmPreKeyMessage)
from olm.group_session import ( from olm.group_session import (
InboundGroupSession, InboundGroupSession,
OutboundGroupSession, OutboundGroupSession,
@ -193,6 +193,14 @@ class OlmDeviceKey():
self.keys = key_dict self.keys = key_dict
class OneTimeKey():
def __init__(self, user_id, device_id, key):
# type: (str, str, str) -> None
self.user_id = user_id
self.device_id = device_id
self.key = key
class Olm(): class Olm():
@encrypt_enabled @encrypt_enabled
@ -245,6 +253,28 @@ class Olm():
return session return session
def create_session(self, user_id, device_id, one_time_key):
W.prnt("", "matrix: Creating session for {}".format(user_id))
id_key = None
for user, keys in self.device_keys.items():
if user != user_id:
continue
for key in keys:
if key.device_id == device_id:
id_key = key.keys["curve25519"]
break
if not id_key:
W.prnt("", "ERRR not found ID key")
W.prnt("", "Found id key {}".format(id_key))
session = OutboundSession(self.account, id_key, one_time_key)
self._update_acc_in_db()
self.sessions[user_id][device_id].append(session)
self._store_session(user_id, device_id, session)
W.prnt("", "matrix: Created session for {}".format(user_id))
def create_group_session(self, room_id, session_id, session_key): def create_group_session(self, room_id, session_id, session_key):
W.prnt("", "matrix: Creating group session for {}".format(room_id)) W.prnt("", "matrix: Creating group session for {}".format(room_id))
session = InboundGroupSession(session_key) session = InboundGroupSession(session_key)
@ -270,10 +300,12 @@ class Olm():
continue continue
if not self.sessions[user][key.device_id]: if not self.sessions[user][key.device_id]:
W.prnt("", "Missing session for device {}".format(key.device_id))
devices.append(key.device_id) devices.append(key.device_id)
if devices: if devices:
missing[user] = {device: "ed25519" for device in devices} missing[user] = {device: "signed_curve25519" for
device in devices}
return missing return missing
@ -376,11 +408,16 @@ class Olm():
} }
for user in users: for user in users:
if user not in self.device_keys:
continue
for key in self.device_keys[user]: for key in self.device_keys[user]:
if key.device_id == self.device_id: if key.device_id == self.device_id:
continue continue
if not self.sessions[user][key.device_id]:
continue
device_payload_dict = payload_dict.copy() device_payload_dict = payload_dict.copy()
# TODO sort the sessions # TODO sort the sessions
session = self.sessions[user][key.device_id][0] session = self.sessions[user][key.device_id][0]
@ -389,8 +426,6 @@ class Olm():
"ed25519": key.keys["ed25519"] "ed25519": key.keys["ed25519"]
} }
W.prnt("", pprint.pformat(device_payload_dict))
olm_message = session.encrypt( olm_message = session.encrypt(
Olm._to_json(device_payload_dict) Olm._to_json(device_payload_dict)
) )
@ -414,6 +449,7 @@ class Olm():
to_device_dict["messages"][user][key.device_id] = olm_dict to_device_dict["messages"][user][key.device_id] = olm_dict
# W.prnt("", pprint.pformat(to_device_dict))
return to_device_dict return to_device_dict
@classmethod @classmethod

View file

@ -31,7 +31,7 @@ from matrix.rooms import (matrix_create_room_buffer, RoomInfo, RoomMessageText,
RoomMessageEvent, RoomRedactedMessageEvent, RoomMessageEvent, RoomRedactedMessageEvent,
RoomMessageEmote) RoomMessageEmote)
from matrix.encryption import OlmDeviceKey from matrix.encryption import OlmDeviceKey, OneTimeKey
try: try:
from olm.session import OlmMessage, OlmPreKeyMessage from olm.session import OlmMessage, OlmPreKeyMessage
@ -355,16 +355,38 @@ class MatrixKeyQueryEvent(MatrixEvent):
class MatrixKeyClaimEvent(MatrixEvent): class MatrixKeyClaimEvent(MatrixEvent):
def __init__(self, server, keys): def __init__(self, server, room_id, keys):
self.keys = keys self.keys = keys
self.room_id = room_id
MatrixEvent.__init__(self, server) MatrixEvent.__init__(self, server)
@classmethod @classmethod
def from_dict(cls, server, parsed_dict): def from_dict(cls, server, room_id, parsed_dict):
raise NotImplementedError W.prnt("", pprint.pformat(parsed_dict))
keys = []
try:
for user_id, user_dict in parsed_dict["one_time_keys"].items():
for device_id, device_dict in user_dict.items():
for key_dict in device_dict.values():
# TODO check the signature of the key
key = OneTimeKey(user_id, device_id, key_dict["key"])
keys.append(key)
return cls(server, room_id, keys)
except KeyError:
return MatrixErrorEvent.from_dict(
server, ("Error claiming onetime keys."), False, parsed_dict)
def execute(self): def execute(self):
pass server = self.server
olm = server.olm
for key in self.keys:
olm.create_session(key.user_id, key.device_id, key.key)
while server.encryption_queue[self.room_id]:
formatted_message = server.encryption_queue[self.room_id].popleft()
server.send_room_message(self.room_id, formatted_message, True)
class MatrixToDeviceEvent(MatrixEvent): class MatrixToDeviceEvent(MatrixEvent):
@ -384,6 +406,7 @@ class MatrixToDeviceEvent(MatrixEvent):
"device message"), "device message"),
False, parsed_dict) False, parsed_dict)
class MatrixBacklogEvent(MatrixEvent): class MatrixBacklogEvent(MatrixEvent):
def __init__(self, server, room_id, end_token, events): def __init__(self, server, room_id, end_token, events):

View file

@ -24,7 +24,7 @@ import time
import datetime import datetime
import pprint import pprint
from collections import deque from collections import deque, defaultdict
from http_parser.pyparser import HttpParser from http_parser.pyparser import HttpParser
from matrix.plugin_options import Option, DebugType from matrix.plugin_options import Option, DebugType
@ -40,7 +40,8 @@ from matrix.api import (
MatrixKeyUploadMessage, MatrixKeyUploadMessage,
MatrixKeyQueryMessage, MatrixKeyQueryMessage,
MatrixToDeviceMessage, MatrixToDeviceMessage,
MatrixEncryptedMessage MatrixEncryptedMessage,
MatrixKeyClaimMessage
) )
from matrix.encryption import Olm, EncryptionError, encrypt_enabled from matrix.encryption import Olm, EncryptionError, encrypt_enabled
@ -63,7 +64,9 @@ class MatrixServer:
self.options = dict() # type: Dict[str, weechat.config] self.options = dict() # type: Dict[str, weechat.config]
self.device_name = "Weechat Matrix" # type: str self.device_name = "Weechat Matrix" # type: str
self.device_id = "" # type: str self.device_id = "" # type: str
self.olm = None # type: Olm self.olm = None # type: Olm
self.encryption_queue = defaultdict(deque)
self.user = "" # type: str self.user = "" # type: str
self.password = "" # type: str self.password = "" # type: str
@ -478,7 +481,12 @@ class MatrixServer:
message = MatrixSyncMessage(self.client, self.next_batch, limit) message = MatrixSyncMessage(self.client, self.next_batch, limit)
self.send_queue.append(message) self.send_queue.append(message)
def send_room_message(self, room_id, formatted_data): def send_room_message(
self,
room_id,
formatted_data,
already_claimed=False
):
# type: (str, Formatted) -> None # type: (str, Formatted) -> None
room = self.rooms[room_id] room = self.rooms[room_id]
@ -488,13 +496,13 @@ class MatrixServer:
# TODO don't send messages unless all the devices are verified # TODO don't send messages unless all the devices are verified
missing = self.olm.get_missing_sessions(room.users.keys()) missing = self.olm.get_missing_sessions(room.users.keys())
if missing: if missing and not already_claimed:
W.prnt("", "{prefix}matrix: Olm session missing for room, can't" W.prnt("", "{prefix}matrix: Olm session missing for room, can't"
" encrypt message.") " encrypt message.")
W.prnt("", pprint.pformat(missing)) W.prnt("", pprint.pformat(missing))
# message = MatrixKeyClaimMessage(self.client, missing) self.encryption_queue[room_id].append(formatted_data)
# self.send_or_queue(message) message = MatrixKeyClaimMessage(self.client, room_id, missing)
# TODO claim keys for the missing user/device combinations self.send_or_queue(message)
return return
body = {"msgtype": "m.text", "body": formatted_data.to_plain()} body = {"msgtype": "m.text", "body": formatted_data.to_plain()}