daemon: Handle the room/messages endpoint.

This commit is contained in:
Damir Jelić 2019-04-12 14:19:37 +02:00
parent 1bbf38e240
commit f2907b1811
2 changed files with 97 additions and 39 deletions

View File

@ -1,6 +1,6 @@
import asyncio import asyncio
from pprint import pformat from pprint import pformat
from typing import Any, Dict from typing import Any, Dict, Optional
from nio import (AsyncClient, ClientConfig, EncryptionError, from nio import (AsyncClient, ClientConfig, EncryptionError,
GroupEncryptionError, KeysQueryResponse, MegolmEvent, GroupEncryptionError, KeysQueryResponse, MegolmEvent,
@ -110,6 +110,71 @@ class PanClient(AsyncClient):
content content
) )
def pan_decrypt_event(self, event_dict, room_id=None):
# type: (Dict[Any, Any], Optional[str]) -> ()
event = RoomEncryptedEvent.parse_event(event_dict)
if not event.room_id:
event.room_id = room_id
if not isinstance(event, MegolmEvent):
logger.warn("Encrypted event is not a megolm event:"
"\n{}".format(pformat(event_dict)))
return None
try:
decrypted_event = self.decrypt_event(event)
logger.info("Decrypted event: {}".format(decrypted_event))
event_dict["type"] = "m.room.message"
# TODO support other event types
# This should be best done in nio, modify events so they
# keep the dictionary from which they are built in a source
# attribute.
event_dict["content"] = {
"msgtype": "m.text",
"body": decrypted_event.body
}
if decrypted_event.formatted_body:
event_dict["content"]["formatted_body"] = (
decrypted_event.formatted_body)
event_dict["content"]["format"] = decrypted_event.format
event_dict["decrypted"] = True
event_dict["verified"] = decrypted_event.verified
except EncryptionError as error:
logger.warn(error)
return
def decrypt_messages_body(self, body):
# type: (Dict[Any, Any]) -> Dict[Any, Any]
"""Go through a messages response and decrypt megolm encrypted events.
Args:
body (Dict[Any, Any]): The dictionary of a Sync response.
Returns the json response with decrypted events.
"""
if "chunk" not in body:
return body
logger.info("Decrypting room messages")
for event in body["chunk"]:
if "type" not in event:
continue
if event["type"] != "m.room.encrypted":
logger.debug("Event is not encrypted: "
"\n{}".format(pformat(event)))
continue
self.pan_decrypt_event(event)
return body
def decrypt_sync_body(self, body): def decrypt_sync_body(self, body):
# type: (Dict[Any, Any]) -> Dict[Any, Any] # type: (Dict[Any, Any]) -> Dict[Any, Any]
"""Go through a json sync response and decrypt megolm encrypted events. """Go through a json sync response and decrypt megolm encrypted events.
@ -119,6 +184,7 @@ class PanClient(AsyncClient):
Returns the json response with decrypted events. Returns the json response with decrypted events.
""" """
logger.info("Decrypting sync")
for room_id, room_dict in body["rooms"]["join"].items(): for room_id, room_dict in body["rooms"]["join"].items():
try: try:
if not self.rooms[room_id].encrypted: if not self.rooms[room_id].encrypted:
@ -131,43 +197,6 @@ class PanClient(AsyncClient):
continue continue
for event in room_dict["timeline"]["events"]: for event in room_dict["timeline"]["events"]:
if event["type"] != "m.room.encrypted": self.pan_decrypt_event(event, room_id)
logger.info("Event is not encrypted: "
"\n{}".format(pformat(event)))
continue
parsed_event = RoomEncryptedEvent.parse_event(event)
parsed_event.room_id = room_id
if not isinstance(parsed_event, MegolmEvent):
logger.warn("Encrypted event is not a megolm event:"
"\n{}".format(pformat(event)))
continue
try:
decrypted_event = self.decrypt_event(parsed_event)
logger.info("Decrypted event: {}".format(decrypted_event))
event["type"] = "m.room.message"
# TODO support other event types
# This should be best done in nio, modify events so they
# keep the dictionary from which they are built in a source
# attribute.
event["content"] = {
"msgtype": "m.text",
"body": decrypted_event.body
}
if decrypted_event.formatted_body:
event["content"]["formatted_body"] = (
decrypted_event.formatted_body)
event["content"]["format"] = decrypted_event.format
event["decrypted"] = True
event["verified"] = decrypted_event.verified
except EncryptionError as error:
logger.warn(error)
continue
return body return body

View File

@ -319,6 +319,34 @@ class ProxyDaemon:
text=await response.text() text=await response.text()
) )
async def messages(self, request):
access_token = self.get_access_token(request)
if not access_token:
return self._missing_token
try:
client_info = self.client_info[access_token]
client = self.pan_clients[client_info.user_id]
except KeyError:
return self._unknown_token
response = await self.forward_request(request)
if response.status == 200:
json_response = await response.json()
json_response = client.decrypt_messages_body(json_response)
return web.Response(
status=response.status,
text=json.dumps(json_response)
)
else:
return web.Response(
status=response.status,
text=await response.text()
)
async def to_web_response(self, response): async def to_web_response(self, response):
return web.Response(status=response.status, text=await response.text()) return web.Response(status=response.status, text=await response.text())
@ -396,6 +424,7 @@ async def init(homeserver, http_proxy, ssl):
app.add_routes([ app.add_routes([
web.post("/_matrix/client/r0/login", proxy.login), web.post("/_matrix/client/r0/login", proxy.login),
web.get("/_matrix/client/r0/sync", proxy.sync), web.get("/_matrix/client/r0/sync", proxy.sync),
web.get("/_matrix/client/r0/rooms/{room_id}/messages", proxy.messages),
web.put( web.put(
r"/_matrix/client/r0/rooms/{room_id}/send/{event_type}/{txnid}", r"/_matrix/client/r0/rooms/{room_id}/send/{event_type}/{txnid}",
proxy.send_message proxy.send_message