diff --git a/CHANGELOG.md b/CHANGELOG.md index 7403103..c0dda50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,28 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 0.9.3 2021-05-14 +## 0.10.2 2021-07-14 + +### Fixed + +- [[#103]] Prevent E2EE downgrade on failed syncs + +[#103]: https://github.com/matrix-org/pantalaimon/pull/103 + + +## 0.10.1 2021-07-06 + +### Fixed + +- [[#100]] Don't require the rooms dicts in the sync response +- [[#99]] Thumbnails not generating for media uploaded in unencrypted rooms + whole LRU cache when it shouldn't + +[#100]: https://github.com/matrix-org/pantalaimon/pull/100 +[#99]: https://github.com/matrix-org/pantalaimon/pull/99 + + +## 0.10.0 2021-05-14 ### Added diff --git a/pantalaimon/client.py b/pantalaimon/client.py index dad2936..02070b2 100644 --- a/pantalaimon/client.py +++ b/pantalaimon/client.py @@ -411,6 +411,10 @@ class PanClient(AsyncClient): except (asyncio.CancelledError, KeyboardInterrupt): return + @property + def has_been_synced(self) -> bool: + self.last_sync_token is not None + async def sync_tasks(self, response): if self.index: await self.index.commit_events() @@ -937,7 +941,7 @@ class PanClient(AsyncClient): self.handle_to_device_from_sync_body(body) - for room_id, room_dict in body["rooms"]["join"].items(): + for room_id, room_dict in body.get("rooms", {}).get("join", {}).items(): try: if not self.rooms[room_id].encrypted: logger.info( @@ -952,7 +956,7 @@ class PanClient(AsyncClient): # pan sync stream did. Let's assume that the room is encrypted. pass - for event in room_dict["timeline"]["events"]: + for event in room_dict.get("timeline", {}).get("events", []): if "type" not in event: continue diff --git a/pantalaimon/daemon.py b/pantalaimon/daemon.py index f61c384..23b40ab 100755 --- a/pantalaimon/daemon.py +++ b/pantalaimon/daemon.py @@ -838,9 +838,7 @@ class ProxyDaemon: body=await response.read(), ) - def _get_upload_and_media_info(self, content_key, content): - content_uri = content[content_key] - + def _get_upload_and_media_info(self, content_uri: str): try: upload_info = self.upload_info[content_uri] except KeyError: @@ -850,7 +848,6 @@ class ProxyDaemon: self.upload_info[content_uri] = upload_info - content_uri = content[content_key] mxc = urlparse(content_uri) mxc_server = mxc.netloc.strip("/") mxc_path = mxc.path.strip("/") @@ -863,8 +860,8 @@ class ProxyDaemon: return upload_info, media_info - async def _map_decrypted_uri(self, content_key, content, request, client): - upload_info, media_info = self._get_upload_and_media_info(content_key, content) + async def _decrypt_uri(self, content_uri, client): + upload_info, media_info = self._get_upload_and_media_info(content_uri) if not upload_info or not media_info: raise NotDecryptedAvailableError @@ -880,7 +877,7 @@ class ProxyDaemon: decrypted_upload, _ = await client.upload( data_provider=BufferedReader(BytesIO(decrypted_file)), - content_type=response.content_type, + content_type=upload_info.mimetype, filename=upload_info.filename, encrypt=False, filesize=len(decrypted_file), @@ -889,9 +886,7 @@ class ProxyDaemon: if not isinstance(decrypted_upload, UploadResponse): raise NotDecryptedAvailableError - content[content_key] = decrypted_upload.content_uri - - return content + return decrypted_upload.content_uri async def send_message(self, request): access_token = self.get_access_token(request) @@ -905,12 +900,36 @@ class ProxyDaemon: room_id = request.match_info["room_id"] - # The room is not in the joined rooms list, just forward it. try: room = client.rooms[room_id] encrypt = room.encrypted except KeyError: - return await self.forward_to_web(request, token=client.access_token) + # The room is not in the joined rooms list, either the pan client + # didn't manage to sync the state or we're not joined, in either + # case send an error response. + if client.has_been_synced: + return web.json_response( + { + "errcode": "M_FORBIDDEN", + "error": "You do not have permission to send the event." + }, + headers=CORS_HEADERS, + status=403, + ) + else: + logger.error( + "The internal Pantalaimon client did not manage " + "to sync with the server." + ) + return web.json_response( + { + "errcode": "M_UNKNOWN", + "error": "The pantalaimon client did not manage to sync with " + "the server", + }, + headers=CORS_HEADERS, + status=500, + ) # Don't encrypt reactions for now - they are weird and clients # need to support them like this. @@ -933,9 +952,11 @@ class ProxyDaemon: or msgtype == "m.room.avatar" ): try: - content = await self._map_decrypted_uri( - "url", content, request, client - ) + content["url"] = await self._decrypt_uri(content["url"], client) + if "info" in content and "thumbnail_url" in content["info"]: + content["info"]["thumbnail_url"] = await self._decrypt_uri( + content["info"]["thumbnail_url"], client + ) return await self.forward_to_web( request, data=json.dumps(content), token=client.access_token ) @@ -956,7 +977,7 @@ class ProxyDaemon: or msgtype == "m.room.avatar" ): upload_info, media_info = self._get_upload_and_media_info( - "url", content + content["url"] ) if not upload_info or not media_info: response = await client.room_send( @@ -976,7 +997,7 @@ class ProxyDaemon: thumb_upload_info, thumb_media_info, ) = self._get_upload_and_media_info( - "thumbnail_url", content["info"] + content["info"]["thumbnail_url"] ) if thumb_upload_info and thumb_media_info: thumb_media_info.to_thumbnail( @@ -1275,8 +1296,8 @@ class ProxyDaemon: return self._not_json try: - content = await self._map_decrypted_uri( - "avatar_url", content, request, client + content["avatar_url"] = await self._decrypt_uri( + content["avatar_url"], client ) return await self.forward_to_web( request, data=json.dumps(content), token=client.access_token diff --git a/pantalaimon/main.py b/pantalaimon/main.py index 271a706..fe5e167 100644 --- a/pantalaimon/main.py +++ b/pantalaimon/main.py @@ -262,7 +262,7 @@ async def daemon(context, log_level, debug_encryption, config, data_path): "connect to pantalaimon." ) ) -@click.version_option(version="0.10.0", prog_name="pantalaimon") +@click.version_option(version="0.10.2", prog_name="pantalaimon") @click.option( "--log-level", type=click.Choice(["error", "warning", "info", "debug"]), diff --git a/pantalaimon/panctl.py b/pantalaimon/panctl.py index 26344a1..fdb9921 100644 --- a/pantalaimon/panctl.py +++ b/pantalaimon/panctl.py @@ -690,7 +690,7 @@ class PanCtl: "the pantalaimon daemon." ) ) -@click.version_option(version="0.10.0", prog_name="panctl") +@click.version_option(version="0.10.2", prog_name="panctl") def main(): loop = asyncio.get_event_loop() glib_loop = GLib.MainLoop() diff --git a/setup.py b/setup.py index a604a44..b13317a 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ with open("README.md", encoding="utf-8") as f: setup( name="pantalaimon", - version="0.10.0", + version="0.10.2", url="https://github.com/matrix-org/pantalaimon", author="The Matrix.org Team", author_email="poljar@termina.org.uk", @@ -29,7 +29,7 @@ setup( "cachetools >= 3.0.0", "prompt_toolkit > 2, < 4", "typing;python_version<'3.5'", - "matrix-nio[e2e] >= 0.14, < 0.19" + "matrix-nio[e2e] >= 0.18, < 0.19" ], extras_require={ "ui": [