Telegram Bot:一组字符突破 HTML 转义

问题描述 投票:0回答:1

我有一个游戏电报机器人,它使用名字-姓氏对来根据用户的分数拼出聊天中的用户排行榜。截图示例如下:

因此,每个用户都有一个指向他们的链接。生成链接的实际代码:

EscapeType = typing.Literal['html']


def escape_string(s: str, escape: EscapeType | None = None) -> str:
    if escape == 'html':
        s = html_escape(s)
    elif escape is None:
        pass
    else:
        raise NotImplementedError(escape)
    return s


def getter(d):
    if isinstance(d, User):
        return lambda attr: getattr(d, attr, None)
    elif hasattr(d, '__getitem__') and hasattr(d, 'get'):
        return lambda attr: d.get(attr, None)
    else:
        return lambda attr: getattr(d, attr, None)


def personal_appeal(user: User | dict, escape: EscapeType | None = 'html') -> str:
    get = getter(user)

    if full_name := get("full_name"):
        appeal = full_name
    elif name := get("name"):
        appeal = name
    elif first_name := get("first_name"):
        if last_name := get("last_name"):
            appeal = f"{first_name} {last_name}"
        else:
            appeal = first_name
    elif username := get('username'):
        appeal = username
    else:
        raise ValueError(user)

    return escape_string(appeal, escape)


def user_mention(id: int | User, name: str | None = None, escape: EscapeType | None = 'html') -> str:
    if isinstance(id, User):
        user = id
        id = user.id
        name = personal_appeal(user)

    name = escape_string(name, escape=escape)

    if name is None:
        name = "N/A"

    if id is not None:
        return f'<a href="tg://user?id={id}">{name}</a>'
    else:
        return name

基本上,此代码从用户名 - 用户 ID 对生成链接。正如你所看到的,名称默认是 HTML 转义的。

但是,有一个用户通过他们不寻常的名字以某种方式破坏了此代码,这是他们使用的实际字符序列:

'$̴̢̛̙͈͚̎̓͆͑.̸̱̖͑͒ ̧̡͉̺̬͎̯.̸̧̢̠̺̮̬͙͛̓̀̐́.̵̦͑̉͌͌̎͘ ̞ ̷̡͈̤̓̀͋͗͊̈́̑̽͝'

针对该名字运行相同代码的结果的屏幕截图:

如您所见,电报似乎在标记中丢失了。该链接转义到其他不相关的字符,并且

<b>
标签也被破坏。

这是发送到电报服务器的实际字符串(除了我删除的 id):

🔝🏆 <u>Рейтинг игроков чата</u>:

🥇 1. <a href="tg://user?id=1">andy alexanderson</a> (<b>40</b>)
🥈 2. <a href="tg://user?id=2">$̴̢̛̙͈͚̎̓͆͑.̸̱̖͑͒ ̧̡͉̺̬͎̯.̸̧̢̠̺̮̬͙͛̓̀̐́.̵̦͑̉͌͌̎͘ ̞ ̷̡͈̤̓̀͋͗͊̈́̑̽͝</a> (<b>40</b>)
🤡 3. <a href="tg://user?id=3">: )</a> (<b>0</b>)

⏱️ <i>Рейтинг составлен 1 минуту назад</i>.
⏭️ <i>Следующее обновление через 28 минут</i>.

不过,这个标记中唯一奇怪的是昵称。

这是 Telegram 错误吗?

可以采取一些措施来缓解这种情况,以便我的用户无法逃避 HTML 标记吗? 我愿意牺牲他们名称表示的正确性(因为这些用户愿意混淆他们的名字),但是我需要以某种方式能够区分一些会破坏标记的东西

或者也许有一些我错过的 UTF-16 <-> UTF-8 编码内容?

使用的框架:

python-telegram-bot
。 Python版本:
3.10.12
.

python utf-8 escaping python-telegram-bot html-escape-characters
1个回答
0
投票

正如 @roganjosh 所指出的,这实际上是一个所谓的“zalgo”字符序列。为了删除 zalgo 字符,我首先从一个名为 lunicode.js 的旧 JS 库中找到了 这个解码函数 。我通过逆向找到它这个zalgo-文本编码器-解码器网站

原来是一个非常简单的函数,所以这里用python写的:

def remove_zalgo(txt: str) -> str:
    return ''.join([
        char
        for char in txt
        if ord(char) < 768 or ord(char) > 865
    ])

现在我的标记没有中断,并且我的用户名中没有 zalgo 字符。我想,这是一场胜利:)

© www.soinside.com 2019 - 2024. All rights reserved.