matrix-nio icon indicating copy to clipboard operation
matrix-nio copied to clipboard

Message sent after creating encrypted private chat is encrypted, but the keys are not sent with it

Open redsolver opened this issue 4 years ago • 0 comments

The following code invites the user to an encrypted private chat and sends a message, but the client (Element/Riot Desktop) can't decrypt it and shows the warning ** Unable to decrypt: The sender's device has not sent us the keys for this message. ** My code is based on https://github.com/anoadragon453/nio-template

#!/usr/bin/env python3

import logging
import asyncio
import sys
import traceback

from time import sleep
import nio
from aiohttp import (
    ServerDisconnectedError,
    ClientConnectionError
)
from callbacks import Callbacks
from config import Config
from storage import Storage

logger = logging.getLogger(__name__)


async def main():
    # Read config file

    # A different config file path can be specified as the first command line argument
    if len(sys.argv) > 1:
        config_filepath = sys.argv[1]
    else:
        config_filepath = "config.yaml"
    config = Config(config_filepath)

    # Configure the database
    store = Storage(config.database_filepath)

    # Configuration options for the AsyncClient
    client_config = nio.AsyncClientConfig(
        max_limit_exceeded=0,
        max_timeouts=0,
        store_sync_tokens=True,
        encryption_enabled=True,
    )

    # Initialize the matrix client
    client = nio.AsyncClient(
        config.homeserver_url,
        config.user_id,
        device_id=config.device_id,
        store_path=config.store_filepath,
        config=client_config,
    )

    # Set up event callbacks
    callbacks = Callbacks(client, store, config)
    client.add_event_callback(callbacks.message, (nio.RoomMessageText,))
    client.add_event_callback(callbacks.invite, (nio.InviteMemberEvent,))

    # My Code
    async def background():
        try:
            await asyncio.sleep(5)
            logger.info("creating private chat...")

            invite = "@example:matrix.org" # CHANGEME

            res = await client.get_profile(invite)

            logger.info(res.displayname)

            response = await client.room_create(
                invite=[invite],
                is_direct=True,
                visibility=nio.RoomVisibility.private,
                initial_state= [nio.EnableEncryptionBuilder().as_dict()],                          
            )
            
            logger.info(response.room_id)

            room_id = response.room_id        

            await client.room_send(
                room_id=room_id,
                content={
                    "msgtype": "m.text",
                    "body": "Hello, this message is encrypted!"
                },
                message_type="m.room.message",
                ignore_unverified_devices=True,
            )
        except:
            logger.info("Error")
            logger.info(sys.exc_info()[0])


    # Keep trying to reconnect on failure (with some time in-between)
    while True:
        try:
            # Try to login with the configured username/password
            try:
                login_response = await client.login(
                    password=config.user_password,
                    device_name=config.device_name,
                )

                # Check if login failed
                if type(login_response) == nio.LoginError:
                    logger.error(f"Failed to login: %s",
                                 login_response.message)
                    return False
            except nio.LocalProtocolError as e:
                # There's an edge case here where the user hasn't installed the correct C
                # dependencies. In that case, a LocalProtocolError is raised on login.
                logger.fatal(
                    "Failed to login. Have you installed the correct dependencies? "
                    "https://github.com/poljar/matrix-nio#installation "
                    "Error: %s", e
                )
                return False

            # Login succeeded!

            # Sync encryption keys with the server
            # Required for participating in encrypted rooms
            if client.should_upload_keys:
                await client.keys_upload()

            logger.info(f"Logged in as {config.user_id}")

            bg_task = asyncio.run_coroutine_threadsafe(
                background(), asyncio.get_event_loop())

            logger.info("sync_forever")

            await client.sync_forever(timeout=30000, full_state=True)


        except (ClientConnectionError, ServerDisconnectedError):
            logger.warning(
                "Unable to connect to homeserver, retrying in 15s...")

            # Sleep so we don't bombard the server with login requests
            sleep(15)
        finally:
            # Make sure to close the client connection on disconnect
            await client.close()

asyncio.get_event_loop().run_until_complete(main())

redsolver avatar Jul 21 '20 09:07 redsolver