Exemplo n.º 1
0
async def matrix_transaction(request):
    """
    Handle a transaction sent by the homeserver.
    :param request: The request containing the transaction.
    :return: The response to send.
    """
    body = await request.json()
    events = body['events']
    for event in events:
        if 'age' in event and event['age'] > 600000:
            print('discarded event of age', event['age'])
            continue
        try:
            print('{}: <{}> {}'.format(event['room_id'], event['user_id'],
                                       event['type']))
        except KeyError:
            pass

        if event['type'] == 'm.room.aliases':
            aliases = event['content']['aliases']

            links = db.session.query(db.ChatLink)\
                      .filter_by(matrix_room=event['room_id']).all()
            for link in links:
                db.session.delete(link)

            for alias in aliases:
                print(alias)
                if alias.split('_')[0] != '#telegram' \
                        or alias.split(':')[-1] != MATRIX_HOST_BARE:
                    continue

                tg_id = alias.split('_')[1].split(':')[0]
                link = db.ChatLink(event['room_id'], tg_id, True)
                db.session.add(link)
                db.session.commit()

            continue

        link = db.session.query(db.ChatLink)\
                 .filter_by(matrix_room=event['room_id']).first()
        if not link:
            print('{} isn\'t linked!'.format(event['room_id']))
            continue
        group = TG_BOT.group(link.tg_room)

        try:
            if event['type'] == 'm.room.message':
                user_id = event['user_id']
                if matrix_is_telegram(user_id):
                    continue


                sender = db.session.query(db.MatrixUser)\
                           .filter_by(matrix_id=user_id).first()

                if not sender:
                    response = await matrix_get(
                        'client', 'profile/{}/displayname'.format(user_id),
                        None)
                    try:
                        displayname = response['displayname']
                    except KeyError:
                        displayname = get_username(user_id)
                    sender = db.MatrixUser(user_id, displayname)
                    db.session.add(sender)
                else:
                    displayname = sender.name or get_username(user_id)
                content = event['content']

                if 'msgtype' not in content:
                    continue

                if content['msgtype'] == 'm.text':
                    msg, mode = format_matrix_msg('<{}> {}', displayname,
                                                  content)
                    await group.send_text(msg, parse_mode=mode)
                elif content['msgtype'] == 'm.notice':
                    msg, mode = format_matrix_msg('[{}] {}', displayname,
                                                  content)
                    await group.send_text(msg, parse_mode=mode)
                elif content['msgtype'] == 'm.emote':
                    msg, mode = format_matrix_msg('* {} {}', displayname,
                                                  content)
                    await group.send_text(msg, parse_mode=mode)
                elif content['msgtype'] == 'm.image':
                    try:
                        url = urlparse(content['url'])

                        # Append the correct extension if it's missing or wrong
                        ext = mime_extensions[content['info']['mimetype']]
                        if not content['body'].endswith(ext):
                            content['body'] += '.' + ext

                        # Download the file
                        await download_matrix_file(url, content['body'])
                        with open('/tmp/{}'.format(content['body']),
                                  'rb') as img_file:
                            # Create the URL and shorten it
                            url_str = MATRIX_HOST_EXT + \
                                      '_matrix/media/r0/download/{}{}' \
                                      .format(url.netloc, quote(url.path))
                            url_str = await shorten_url(url_str)

                            caption = '<{}> {} ({})'.format(
                                displayname, content['body'], url_str)
                            await group.send_photo(img_file, caption=caption)
                    except:
                        pass
                else:
                    print('Unsupported message type {}'.format(
                        content['msgtype']))
                    print(json.dumps(content, indent=4))
            elif event['type'] == 'm.room.member':
                if matrix_is_telegram(event['state_key']):
                    continue

                user_id = event['state_key']
                content = event['content']

                sender = db.session.query(db.MatrixUser)\
                           .filter_by(matrix_id=user_id).first()
                if sender:
                    displayname = sender.name
                else:
                    displayname = get_username(user_id)

                if content['membership'] == 'join':
                    oldname = sender.name if sender else get_username(user_id)
                    try:
                        displayname = content['displayname'] or get_username(
                            user_id)
                    except KeyError:
                        displayname = get_username(user_id)

                    if not sender:
                        sender = db.MatrixUser(user_id, displayname)
                    else:
                        sender.name = displayname
                    db.session.add(sender)

                    msg = None
                    if 'unsigned' in event and 'prev_content' in event[
                            'unsigned']:
                        prev = event['unsigned']['prev_content']
                        if prev['membership'] == 'join':
                            if 'displayname' in prev and prev['displayname']:
                                oldname = prev['displayname']

                            msg = '> {} changed their display name to {}'\
                                  .format(oldname, displayname)
                    else:
                        msg = '> {} has joined the room'.format(displayname)

                    if msg:
                        await group.send_text(msg)
                elif content['membership'] == 'leave':
                    msg = '< {} has left the room'.format(displayname)
                    await group.send_text(msg)
                elif content['membership'] == 'ban':
                    msg = '<! {} was banned from the room'.format(displayname)
                    await group.send_text(msg)

        except RuntimeError as e:
            print('Got a runtime error:', e)
            print('Group:', group)

    db.session.commit()
    return create_response(200, {})
Exemplo n.º 2
0
async def matrix_transaction(request):
    """
    Handle a transaction sent by the homeserver.
    :param request: The request containing the transaction.
    :return: The response to send.
    """
    body = await request.json()
    events = body['events']
    for event in events:
        if 'age' in event and event['age'] > 600000:
            print('discarded event of age', event['age'])
            continue
        try:
            print('{}: <{}> {}'.format(event['room_id'], event['user_id'],
                                       event['type']))
        except KeyError:
            pass

        if event['type'] == 'm.room.aliases' and event[
                'state_key'] == MATRIX_HOST_BARE:
            aliases = event['content']['aliases']

            links = db.session.query(db.ChatLink)\
                      .filter_by(matrix_room=event['room_id']).all()
            for link in links:
                db.session.delete(link)

            for alias in aliases:
                print(alias)
                if alias.split('_')[0] != '#telegram' \
                        or alias.split(':')[-1] != MATRIX_HOST_BARE:
                    continue

                tg_id = alias.split('_')[1].split(':')[0]
                link = db.ChatLink(event['room_id'], tg_id, True)
                db.session.add(link)
                db.session.commit()

            continue

        link = db.session.query(db.ChatLink)\
                 .filter_by(matrix_room=event['room_id']).first()
        if not link:
            print('{} isn\'t linked!'.format(event['room_id']))
            continue
        group = TG_BOT.group(link.tg_room)

        try:
            response = None

            if event['type'] == 'm.room.message':
                user_id = event['user_id']
                if matrix_is_telegram(user_id):
                    continue

                sender = db.session.query(db.MatrixUser)\
                           .filter_by(matrix_id=user_id).first()

                if not sender:
                    response = await matrix_get(
                        'client', 'profile/{}/displayname'.format(user_id),
                        None)
                    try:
                        displayname = response['displayname']
                    except KeyError:
                        displayname = get_username(user_id)
                    sender = db.MatrixUser(user_id, displayname)
                    db.session.add(sender)
                else:
                    displayname = sender.name or get_username(user_id)
                content = event['content']

                if 'msgtype' not in content:
                    continue

                if content['msgtype'] == 'm.text':
                    msg, mode = format_matrix_msg('{}', content)
                    response = await group.send_text("<b>{}:</b> {}".format(
                        displayname, msg),
                                                     parse_mode='HTML')
                elif content['msgtype'] == 'm.notice':
                    msg, mode = format_matrix_msg('{}', content)
                    response = await group.send_text("[{}] {}".format(
                        displayname, msg),
                                                     parse_mode=mode)
                elif content['msgtype'] == 'm.emote':
                    msg, mode = format_matrix_msg('{}', content)
                    response = await group.send_text("* {} {}".format(
                        displayname, msg),
                                                     parse_mode=mode)
                elif content['msgtype'] in [
                        'm.image', 'm.audio', 'm.video', 'm.file'
                ]:
                    try:
                        url = urlparse(content['url'])

                        # Append the correct extension if it's missing or wrong
                        try:
                            exts = MT.types_map_inv[1][content['info']
                                                       ['mimetype']]
                            if not content['body'].endswith(tuple(exts)):
                                content['body'] += '.' + exts[0]
                        except KeyError:
                            pass

                        # Download the file
                        await download_matrix_file(url, content['body'])
                        with open('/tmp/{}'.format(content['body']),
                                  'rb') as file:
                            # Create the URL and shorten it
                            url_str = MATRIX_HOST_EXT + \
                                      '_matrix/media/r0/download/{}{}' \
                                      .format(url.netloc, quote(url.path))
                            url_str = await shorten_url(url_str)

                            if content['msgtype'] == 'm.image':
                                if content['info']['mimetype'] == 'image/gif':
                                    # Send gif as a video, so telegram can display it animated
                                    caption = '{} sent a gif'.format(
                                        displayname)
                                    await group.send_chat_action('upload_video'
                                                                 )
                                    response = await group.send_video(
                                        file, caption=caption)
                                else:
                                    caption = '{} sent an image'.format(
                                        displayname)
                                    await group.send_chat_action('upload_photo'
                                                                 )
                                    response = await group.send_photo(
                                        file, caption=caption)
                            elif content['msgtype'] == 'm.video':
                                caption = '{} sent a video'.format(displayname)
                                await group.send_chat_action('upload_video')
                                response = await group.send_video(
                                    file, caption=caption)
                            elif content['msgtype'] == 'm.audio':
                                caption = '{} sent an audio file'.format(
                                    displayname)
                                await group.send_chat_action('upload_audio')
                                response = await group.send_audio(
                                    file, caption=caption)
                            elif content['msgtype'] == 'm.file':
                                caption = '{} sent a file'.format(displayname)
                                await group.send_chat_action('upload_document')
                                response = await group.send_document(
                                    file, caption=caption)
                    except:
                        pass
                else:
                    print('Unsupported message type {}'.format(
                        content['msgtype']))
                    print(json.dumps(content, indent=4))

            elif event['type'] == 'm.sticker':
                user_id = event['user_id']
                if matrix_is_telegram(user_id):
                    continue

                sender = db.session.query(db.MatrixUser) \
                    .filter_by(matrix_id=user_id).first()

                if not sender:
                    response = await matrix_get(
                        'client', 'profile/{}/displayname'.format(user_id),
                        None)
                    try:
                        displayname = response['displayname']
                    except KeyError:
                        displayname = get_username(user_id)
                    sender = db.MatrixUser(user_id, displayname)
                    db.session.add(sender)
                else:
                    displayname = sender.name or get_username(user_id)
                content = event['content']

                try:
                    url = urlparse(content['url'])
                    await download_matrix_file(url, content['body'])

                    png_image = Image.open('/tmp/{}'.format(content['body']))
                    png_image.save('/tmp/{}.webp'.format(content['body']),
                                   'WEBP')
                    with open('/tmp/{}.webp'.format(content['body']),
                              'rb') as file:
                        response = await group.send_document(file)

                except:
                    pass

            elif event['type'] == 'm.room.member':
                if HIDE_MEMBERSHIP_CHANGES:  # Hide everything, could be improved to be
                    # more specific
                    continue
                if matrix_is_telegram(event['state_key']):
                    continue

                user_id = event['state_key']
                content = event['content']

                sender = db.session.query(db.MatrixUser)\
                           .filter_by(matrix_id=user_id).first()
                if sender:
                    displayname = sender.name
                else:
                    displayname = get_username(user_id)

                if content['membership'] == 'join':
                    oldname = sender.name if sender else get_username(user_id)
                    try:
                        displayname = content['displayname'] or get_username(
                            user_id)
                    except KeyError:
                        displayname = get_username(user_id)

                    if not sender:
                        sender = db.MatrixUser(user_id, displayname)
                    else:
                        sender.name = displayname
                    db.session.add(sender)

                    msg = None
                    if 'unsigned' in event and 'prev_content' in event[
                            'unsigned']:
                        prev = event['unsigned']['prev_content']
                        if prev['membership'] == 'join':
                            if 'displayname' in prev and prev['displayname']:
                                oldname = prev['displayname']

                            msg = '> {} changed their display name to {}'\
                                  .format(oldname, displayname)
                    else:
                        msg = '> {} has joined the room'.format(displayname)

                    if msg:
                        response = await group.send_text(msg)
                elif content['membership'] == 'leave':
                    msg = '< {} has left the room'.format(displayname)
                    response = await group.send_text(msg)
                elif content['membership'] == 'ban':
                    msg = '<! {} was banned from the room'.format(displayname)
                    response = await group.send_text(msg)

            if response:
                message = db.Message(response['result']['chat']['id'],
                                     response['result']['message_id'],
                                     event['room_id'], event['event_id'],
                                     displayname)
                db.session.add(message)

        except RuntimeError as e:
            print('Got a runtime error:', e)
            print('Group:', group)

    db.session.commit()
    return create_response(200, {})