encryption: Initial key claiming support.
This commit is contained in:
parent
47fae308e0
commit
c8a7b4815d
4 changed files with 91 additions and 22 deletions
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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()}
|
||||||
|
|
Loading…
Add table
Reference in a new issue