Пора делать нормальных телеграм-ботов #2

Уверен, многие даже не задумываются над тем, как поведёт себя разрабатываемый бот в случае неправильного его использования. Самое время вскрыть своих ботов и исправить часто допускаемые недочёты, которые я здесь опишу. Снова их 5, снова никакого кода, снова только описание. Добро пожаловать под кат.

Предыдущие части:

1. Русские не просто так в аутсайдерах

Извините, если пересеклось с повесткой, но так уж получилось, что международная кодировка использует однобайтовую часть для латиницы, и двухбайтовую — для кириллицы и прочих (включая эмодзи). А значит при использовании «не латиницы», например, в кнопках (параметр callback_data) или в тексте сообщения (или в подписи к медиа) вам просто-напросто может не хватить места. Если отправить такой «длинный» запрос на сервер телеграма, он скажет об этом, но запрос дальше никуда не пойдёт. Ваша задача — проверить ответ от сервера, чтобы результат был положительным (например, для метода sendMessage положительным результатом будет отправленное сообщение, для answerCallbackQuery — True, а для editMessageText вообще по-разному, в зависимости от типа редактируемого сообщения). Если результат не положительный — нужно это как-то решать: сократить сообщение или ещё что-то.

Программист обязательно должен сделать так, чтобы его код сам себя контролировал. Ответ каждого вызываемого метода должен быть проверен, вдруг он не выполнился — тогда нужно что-то предпринять, чтобы код выполнился до конца, а не оборвался на середине из-за неверного ответа или неоднозначного поведения.

2. Пользователи имеют возможность удалять сообщения

Будет печально, если вы отправите сообщение, которое нужно будет потом обновить, но при этом сообщения в нужный момент не окажется в диалоге.

Не стоит забывать, что для программиста является заповедью считать пользователя идиотом.

Как бы вам ни хотелось писать поменьше проверок, этого не добиться, пока с другой стороны находится человек. Очевидно, что не выйдет обновить несуществующее сообщение, но есть проблема посерьёзнее: кнопки, крепящиеся под клавиатуру (ReplyKeyboard), существуют до тех пор (если их специально не удалять), пока существует сообщение, с которым эти кнопки пришли к пользователю. Поэтому если человек удаляет сообщение, эти кнопки быстрого набора также исчезают.

Пример кнопок, пришедших с сообщением от бота.

Пример кнопок, пришедших с сообщением от бота.

Я не пользуюсь этими кнопками, поэтому не могу привести примеры, когда это критично, но учитывайте то, что человек может их вот так вот потерять — просто удалив «то самое» сообщение.

3. Нужно больше проверок, чем вы думаете

Помимо базового «не допускайте SQL-инъекций» есть очень забавная ситуация:

Попросил бота отправить мне моё имя.

Попросил бота отправить мне моё имя.

Вот как выглядит моё имя в настройках:

Теги можно было вставить в разные части имени, но так тоже, думаю, понятно, о чём речь.

Теги можно было вставить в разные части имени, но так тоже, думаю, понятно, о чём речь.

Если разработчик использует html-разметку в сообщениях, то любые теги не будут являться текстом, если их специально не экранировать. Я не знаю, как это работает с markdown-разметкой, но имейте в виду, что при неправильной html-разметке (неполные теги, несуществующие и т. п.) телеграм не отправит сообщение в чат, а скажет, что у вас неверная разметка, а вы потом будете гадать, что же не так работает.

4. Нет, на этом проверки не заканчиваются

Бывает и такое:

Один из моих ботов. Два одинаковых сообщения.

Один из моих ботов. Два одинаковых сообщения.

Пользователь может дважды использовать кнопку (иногда даже очень опасную как для разработчика, так и для пользователя) в одинаковых сообщениях. Если вы не предусмотрели ещё кучу проверок на нажатие кнопки — результат может оказаться печальным. Иногда даже одной кнопки хватает, чтобы положить вам сервер или заставить его работать неправильно. Для этого есть несколько решений. Если несколько раз нажатая кнопка доставит проблемы, можно запретить нажимать повторно на кнопку до тех пор, пока не обработается текущее нажатие: например, выставить пользователю флаг блокировки, чтобы любые (или некоторые) запросы от пользователя игнорировались, пока предыдущий запрос обрабатывается. Помимо проверки на повторное использование опасных кнопок на сервере можно добавлять к кнопкам секрет (или, чтобы сэкономить место в запросе, сохранять идентификатор отправленного сообщения с нужными кнопками, они потом возвращаются к нам при нажатии), и при нажатии проверять, та ли (т. е. актуальная ли) кнопка используется. Если нет, то делать, например, вот так:

Пример отказа от обработки устаревшего сообщения.

Пример отказа от обработки устаревшего сообщения.

5. Телеграму тоже нельзя доверять

Так как при установке вебхука вы используете прямую ссылку на скрипт, это значит, что кто угодно может отправить любой запрос вашему боту, если ссылка будет скомпрометирована. Опасность отсутствия проверки данных, полученных от телеграма, прямо пропорциональна серьёзности разработки: чем «вкуснее» ваш бот (или ваша деятельность, соответственно) для хакеров, тем выше вероятность взлома, если вы не проверяете данные, полученные извне (даже если это сам телеграм). Если ожидается число — проверьте, что это действительно число; если ожидается текст с определённым количеством символов, пробелов и т.п. — проверьте и это.

Да, в простых ботах этого всего не требуется, но если вы будете следить за этими мелочами, контролировать сами себя, учитывать любой исход событий, тогда вам придётся меньше времени тратить на отлов ошибок. Создавайте ботов так, чтобы даже при намеренном неправильном использовании нельзя было сломать их поведение. Если не хотите продумывать это — просто запретите использовать бота неправильно.

© Habrahabr.ru