Esempio n. 1
0
async def create_client() -> AsyncClient:
    homeserver = ARGS.server
    user_id = ARGS.user
    password = ARGS.userpass
    if not ARGS.batch:
        homeserver = input(
            f"Enter URL of your homeserver: [{homeserver}] ") or homeserver
        user_id = input(f"Enter your full user ID: [{user_id}] ") or user_id
        password = getpass.getpass()
    client = AsyncClient(
        homeserver=homeserver,
        user=user_id,
        config=AsyncClientConfig(store=store.SqliteMemoryStore),
    )
    await client.login(password, DEVICE_NAME)
    client.load_store()
    room_keys_path = ARGS.keys
    room_keys_password = ARGS.keyspass
    if not ARGS.batch:
        room_keys_path = input(
            f"Enter full path to room E2E keys: [{room_keys_path}] "
        ) or room_keys_path
        room_keys_password = getpass.getpass("Room keys password: "******"Importing keys. This may take a while...")
    await client.import_keys(room_keys_path, room_keys_password)
    return client
Esempio n. 2
0
async def create_client() -> AsyncClient:
    homeserver = "https://matrix-client.matrix.org"
    homeserver = input(
        f"Enter URL of your homeserver: [{homeserver}] ") or homeserver
    user_id = input(f"Enter your full user ID (e.g. @user:matrix.org): ")
    password = getpass.getpass()
    client = AsyncClient(
        homeserver=homeserver,
        user=user_id,
        config=AsyncClientConfig(store=store.SqliteMemoryStore),
    )
    await client.login(password, DEVICE_NAME)
    client.load_store()
    room_keys_path = input("Enter full path to room E2E keys: ")
    room_keys_password = getpass.getpass("Room keys password: "******"Importing keys. This may take a while...")
    await client.import_keys(room_keys_path, room_keys_password)
    return client
Esempio n. 3
0
async def main():
    """The first function that is run when starting the bot"""

    # Read user-configured options from a config file.
    # A different config file path can be specified as the first command line argument
    if len(sys.argv) > 1:
        config_path = sys.argv[1]
    else:
        config_path = "config.yaml"

    # Read the parsed config file and create a Config object
    config = Config(config_path)

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

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

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

    if config.user_token:
        client.access_token = config.user_token
        client.user_id = config.user_id

    # Set up event callbacks
    callbacks = Callbacks(client, store, config)
    client.add_event_callback(callbacks.message, (RoomMessageText, ))
    client.add_event_callback(callbacks.invite, (InviteMemberEvent, ))
    client.add_event_callback(callbacks.decryption_failure, (MegolmEvent, ))
    client.add_event_callback(callbacks.unknown, (UnknownEvent, ))
    workflows = Workflow.fetch_workflows(config)
    aiocron.crontab(config.crontab,
                    func=report_last_nightlies,
                    args=(config, client, workflows))

    # Keep trying to reconnect on failure (with some time in-between)
    while True:
        try:
            if config.user_token:
                # Use token to log in
                client.load_store()

                # Sync encryption keys with the server
                if client.should_upload_keys:
                    await client.keys_upload()
            else:
                # 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) == LoginError:
                        logger.error("Failed to login: %s",
                                     login_response.message)
                        return False
                except 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!

            logger.info(f"Logged in as {config.user_id}")
            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()
async def main(args):
    cfgparser = configparser.ConfigParser()
    with open(args.config) as fh:
        cfgparser.read_file(fh)
    cfg = cfgparser['DEFAULT']
    room = cfg['room']

    payload = {
        'service': args.service,
        'host': args.host,
        'type': args.type.upper(),
        'state': args.state.upper(),
        'output': args.output,
        'msg': args.message,
    }

    device = {}
    device_state = os.path.join(cfg['state'], 'device.json')
    try:
        with open(device_state) as fh:
            device = json.load(fh)
    except FileNotFoundError:
        pass

    ensure_dir(cfg['state'])
    ensure_dir(os.path.join(cfg['state'], 'nio'))
    ensure_dir(os.path.join(cfg['state'], 'nio', cfg['user_id']))

    client = AsyncClient(cfg['homeserver'],
                         cfg['user_id'],
                         device_id=device.get('device_id'),
                         store_path=os.path.join(cfg['state'], 'nio',
                                                 cfg['user_id']),
                         config=ClientConfig(store_sync_tokens=True))

    if device:
        client.access_token = device['access_token']
        client.user_id = device['user_id']
        client.load_store()
    else:
        resp = await client.login_raw({
            'type': 'org.matrix.login.jwt',
            'token': cfg['token'],
        })
        if (isinstance(resp, LoginResponse)):
            write_state(device_state, resp)
        else:
            print(f"Failed to log in: {resp}", file=sys.stderr)
            sys.exit(1)

    await client.sync(timeout=args.timeout * 1000, full_state=True)

    in_rooms = client.rooms.keys()
    room_id = (await client.room_resolve_alias(room)).room_id
    if not room_id in in_rooms:
        await client.join(room_id)
    for unwanted in [r for r in in_rooms if r != room_id]:
        await client.room_leave(room)

    if client.should_upload_keys:
        await client.keys_upload()
    if client.should_query_keys:
        await client.keys_query()
    if client.should_claim_keys:
        await client.keys_claim(client.get_users_for_key_claiming())

    await client.sync(timeout=args.timeout * 1000, full_state=True)

    ps_l = []
    if payload['msg']:
        ps_l.append(payload['msg'])
    if payload['output']:
        ps_l.append(payload['output'])
    ps = '\n'.join(ps_l)

    await client.room_send(
        room_id,
        'm.room.message', {
            'msgtype':
            'm.text',
            'body':
            '{type}: {service} on {host} is {state}\n{msg}'.format(**payload),
            'format':
            'org.matrix.custom.html',
            'formatted_body':
            '<span style="background-color: #{color};"><span data-mx-bg-color="#{color}"><strong>{type}</strong>:</span></span> <span data-mx-bg-color="#ffffff">Service <strong>{service}</strong> on <strong>{host}</strong> is <strong>{state}</strong>:<br />{ps}</span>'
            .format(**payload,
                    bgcolor=state_colors_back.get(payload['state'].lower(),
                                                  '222288'),
                    ps=ps,
                    color=state_colors.get(payload['state'].lower(),
                                           '1111ff')),
        },
        ignore_unverified_devices=True)

    await client.sync(timeout=args.timeout * 1000, full_state=True)

    await client.close()
Esempio n. 5
0
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_path = sys.argv[1]
    else:
        config_path = "config.yaml"
    config = Config(config_path)

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

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

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

    if config.user_token:
        client.access_token = config.user_token
        client.user_id = config.user_id

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

    # Keep trying to reconnect on failure (with some time in-between)
    while True:
        try:
            if config.user_token:
                # Use token to log in
                client.load_store()

                # Sync encryption keys with the server
                if client.should_upload_keys:
                    await client.keys_upload()
            else:
                # 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) == LoginError:
                        logger.error("Failed to login: %s",
                                     login_response.message)
                        break
                except 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,
                    )
                    break

                # Login succeeded!

            # Join the management room or fail
            response = await with_ratelimit(client, "join",
                                            config.management_room)
            if type(response) == JoinError:
                logger.fatal("Could not join the management room, aborting.")
                break
            else:
                logger.info(f"Management room membership is good")

            # Resolve management room ID if not known
            if config.management_room.startswith('#'):
                # Resolve the room ID
                response = await with_ratelimit(client, "room_resolve_alias",
                                                config.management_room)
                if type(response) == RoomResolveAliasResponse:
                    config.management_room_id = response.room_id
                else:
                    logger.fatal(
                        "Could not resolve the management room ID from alias, aborting"
                    )
                    break

            logger.info(f"Logged in as {config.user_id}")
            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()