Боты в Скрепе: BotFather, E2E-диалоги и запуск gateway
Этот туториал поможет создать бота через @botfather, безопасно сохранить его реквизиты, запустить skrepa-bot-gateway и ответить на первое сообщение. Исходники Скрепы, Rust toolchain и protobuf-файлы для этого сценария не требуются.
Справочник методов, схем, ошибок и примеров запросов находится в интерактивной документации Bot API.
Что понадобится
- учётная запись Скрепы и веб-клиент, чтобы поговорить с BotFather;
curlиjqдля команд из туториала;- Mac с Apple Silicon либо Docker с поддержкой Linux amd64;
- отдельный каталог для конфигурации и постоянного состояния бота.
Все команды ниже можно выполнить в пустом каталоге.
Как устроен gateway
skrepa-bot-gateway — локальный адаптер между кодом вашего бота и защищённым транспортом Скрепы. Приложение бота работает с привычным Telegram-compatible HTTP API. Gateway подключается к серверу по gRPC, регистрируется как отдельное устройство бота и берёт на себя E2E-криптографию.
flowchart LR
U["Пользователь<br/>в клиенте Скрепы"] <-->|"E2E-DM"| S["Транспорт Скрепы"]
S <-->|"gRPC:<br/>device inbox и ciphertext"| G["skrepa-bot-gateway"]
G <-->|"Telegram-compatible HTTP:<br/>getUpdates и sendMessage"| B["Код вашего бота"]
G --- D[("state_dir:<br/>identity, device, prekeys,<br/>Double Ratchet, durable queue")]
Путь входящего сообщения выглядит так:
- gateway получает зашифрованное сообщение из device inbox;
- расшифровывает его в сессии Double Ratchet;
- сохраняет update в локальную durable queue;
- код бота забирает update методом
getUpdates.
Для исходящего сообщения код вызывает sendMessage. Gateway находит активные устройства адресата, создаёт отдельный ciphertext для каждого устройства и повторяет отправку до подтверждения сервера. Код бота при этом работает только с открытым текстом на локальной HTTP-границе.
Конфигурация gateway связывает четыре части:
bot_platform_endpoint— адрес сервера Скрепы;- bot token — учётные данные для подключения;
- identity recovery secret — ключ восстановления постоянной identity бота;
state_dir— локальное состояние конкретного runtime: device identity, prekeys, ratchet-сессии, неподтверждённые updates и исходящие сообщения.
Каталог state_dir должен переживать перезапуски. Размещайте его на постоянном диске, выдавайте доступ только процессу gateway и не подключайте один каталог одновременно к нескольким экземплярам. Bot token можно заменить через BotFather; identity recovery secret при ротации token остаётся прежним.
Gateway слушает два локальных адреса. Порт 8081 предоставляет обычный Bot API (getMe, getUpdates, sendMessage). Порт 8082 предназначен для дополнительных возможностей платформы. Для первого echo-бота достаточно порта 8081, однако healthcheck удобно выполнять на обоих.
Команды BotFather
| Команда | Результат |
|---|---|
/start или /help | справка |
/newbot | пошаговое создание бота |
/mybots | список собственных ботов и их статусы |
/token @username | отзыв прежнего credential и выпуск нового token |
/disable @username | отключение бота и отзыв всех активных credentials |
/cancel | сброс незавершённого сценария |
Туториал: создаём echo_bot
1. Откройте диалог
В клиенте Скрепы найдите @botfather и откройте личный диалог. Поиск не зависит от регистра; начальный символ @ можно опустить. В профиле должна отображаться отметка бота.
Если @botfather отсутствует в результатах или долго не отвечает, обновите клиент и повторите попытку. Сохраняющаяся ошибка означает проблему сервиса, о которой следует сообщить оператору стенда.
2. Запустите мастер
Отправьте:
/newbot
BotFather последовательно запросит:
usernameдлиной 3–32 ASCII-символа; разрешены латинские буквы, цифры и_;- отображаемое имя длиной до 128 Unicode-символов;
- набор возможностей.
Для учебного бота диалог выглядит так:
Вы: /newbot
BotFather: Пришлите username нового бота…
Вы: echo_bot
BotFather: Теперь пришлите отображаемое имя бота.
Вы: Эхо
BotFather: Выберите возможности: default либо список dm,groups,channels через запятую.
Вы: default
BotFather: Готово: @echo_bot. … skrepa_bot_<bot-id-hex>_<secret-hex>
BotFather: Ключ восстановления identity: <64 hex символа>
Для текущего echo-сценария выберите default: этого достаточно для приватных сообщений. Значения groups и channels резервируют соответствующие возможности бота, хотя опубликованный gateway пока реализует только приватные текстовые диалоги.
3. Сохраните token и recovery secret
BotFather показывает два разных секрета:
- bot token авторизует gateway и входит в локальный URL Bot API;
- identity recovery secret позволяет новому runtime восстановить постоянную identity того же бота.
Bot token показывается при создании и каждой ротации. Identity recovery secret выдаётся при создании и остаётся постоянным после ротации token. Сохраните оба значения в secret manager или файле с правами 0600. Не помещайте их в Git, shell history, issue tracker и логи.
При утрате или подозрении на компрометацию отправьте:
/token @echo_bot
Прежний token становится недействительным сразу после ответа.
4. Получите bot_id
Token имеет форму:
skrepa_bot_<64 hex символа bot_id>_<64 hex символа секрета>
Извлеките идентификатор локально:
set +x
read -rsp 'Bot token: ' SKREPA_BOT_TOKEN; printf '\n'
read -rsp 'Identity recovery secret: ' SKREPA_BOT_IDENTITY_RECOVERY_SECRET; printf '\n'
export SKREPA_BOT_TOKEN
export SKREPA_BOT_IDENTITY_RECOVERY_SECRET
export SKREPA_BOT_ID_HEX="$(printf '%s' "$SKREPA_BOT_TOKEN" | cut -d_ -f3)"
test "${#SKREPA_BOT_ID_HEX}" -eq 64
5. Скачайте gateway
Готовые дистрибутивы публикуются вместе с серверным релизом. На Mac с Apple Silicon скачайте нативный бинарный файл:
mkdir -p var/echo-bot/bin
cd var/echo-bot/bin
curl --fail-with-body -LO \
https://skrepa.fomkin.org/download/bot-gateway/skrepa-bot-gateway-darwin-arm64.tar.gz
curl --fail-with-body -LO \
https://skrepa.fomkin.org/download/bot-gateway/skrepa-bot-gateway-darwin-arm64.tar.gz.sha256
shasum -a 256 -c skrepa-bot-gateway-darwin-arm64.tar.gz.sha256
tar -xzf skrepa-bot-gateway-darwin-arm64.tar.gz
chmod 700 skrepa-bot-gateway
cd -
Для Linux amd64 и для остальных систем с Docker доступен образ в архиве:
mkdir -p var/echo-bot/image
cd var/echo-bot/image
curl --fail-with-body -LO \
https://skrepa.fomkin.org/download/bot-gateway/skrepa-bot-gateway-linux-amd64.docker.tar.gz
curl --fail-with-body -LO \
https://skrepa.fomkin.org/download/bot-gateway/skrepa-bot-gateway-linux-amd64.docker.tar.gz.sha256
shasum -a 256 -c skrepa-bot-gateway-linux-amd64.docker.tar.gz.sha256
gzip -dc skrepa-bot-gateway-linux-amd64.docker.tar.gz | docker load
cd -
Checksum-файл содержит имя соседнего архива. Поэтому команды проверки следует запускать из каталога, куда скачаны оба файла. На Linux shasum -a 256 -c можно заменить на sha256sum -c.
6. Создайте конфигурацию gateway
umask 077
mkdir -p var/echo-bot
jq -n \
--arg endpoint "https://skrepa.fomkin.org" \
--arg state_dir "${PWD}/var/echo-bot/state" \
--arg bot_id_hex "${SKREPA_BOT_ID_HEX}" \
--arg token "${SKREPA_BOT_TOKEN}" \
--arg identity_recovery_secret "${SKREPA_BOT_IDENTITY_RECOVERY_SECRET}" \
'{
compatibility_profile_id: "telegram-v1-bot-api-9.6-minus-miniapps-business",
bot_platform_endpoint: $endpoint,
telegram_listen_addr: "127.0.0.1:8081",
extensions_listen_addr: "127.0.0.1:8082",
state_dir: $state_dir,
bots: [{
bot_id_hex: $bot_id_hex,
token: $token,
identity_recovery_secret_hex: $identity_recovery_secret,
telegram_user_id: 7100001,
username: "echo_bot",
first_name: "Эхо"
}]
}' > var/echo-bot/gateway.json
chmod 600 var/echo-bot/gateway.json
telegram_user_id — положительный стабильный int64 для Telegram-compatible JSON. Текущая платформа его не назначает. identity_recovery_secret_hex — отдельный 256-битный recovery secret, который BotFather показывает вместе с первым token. Храните его в secret manager и сохраняйте прежним при ротации bot token. state_dir содержит стабильный bot_runtime_id и должен переживать перезапуски.
7. Запустите gateway
На Mac с Apple Silicon:
./var/echo-bot/bin/skrepa-bot-gateway serve var/echo-bot/gateway.json
Для Docker подготовьте конфигурацию с контейнерными адресами и каталогом state:
jq \
'.telegram_listen_addr = "0.0.0.0:8081"
| .extensions_listen_addr = "0.0.0.0:8082"
| .state_dir = "/state"' \
var/echo-bot/gateway.json > var/echo-bot/gateway.docker.json
chmod 600 var/echo-bot/gateway.docker.json
mkdir -p var/echo-bot/state
docker run --rm --name skrepa-echo-bot \
--user "$(id -u):$(id -g)" \
-p 127.0.0.1:8081:8081 \
-p 127.0.0.1:8082:8082 \
-v "${PWD}/var/echo-bot/gateway.docker.json:/config/gateway.json:ro" \
-v "${PWD}/var/echo-bot/state:/state" \
skrepa-bot-gateway:0.1.0 serve /config/gateway.json
Команда работает в foreground и пишет только служебные сведения о runtime. Для постоянного запуска перенесите те же параметры в systemd, Compose или вашу систему оркестрации. Секретный URL Bot API стоит исключить из access logs.
В другом терминале проверьте listeners и server-backed getMe:
curl --fail-with-body -sS http://127.0.0.1:8081/healthz | jq .
curl --fail-with-body -sS http://127.0.0.1:8082/healthz | jq .
curl --fail-with-body -sS \
"http://127.0.0.1:8081/bot${SKREPA_BOT_TOKEN}/getMe" | jq .
Ожидаемый профиль:
{
"ok": true,
"result": {
"id": 7100001,
"is_bot": true,
"first_name": "Эхо",
"username": "echo_bot"
}
}
После /token или /disable старый URL начинает возвращать HTTP 401. Gateway пока не перечитывает credential на лету: обновите gateway.json, перезапустите процесс и повторите getMe.
Gateway сам создаёт стабильное bot device, регистрирует подписанные prekey и запускает delivery loop. Входящие E2E-DM появляются в getUpdates:
curl --fail-with-body -sS \
"http://127.0.0.1:8081/bot${SKREPA_BOT_TOKEN}/getUpdates?limit=100" | jq .
update_id подтверждается обычной Telegram-семантикой: следующий запрос передаёт offset, равный последнему обработанному update_id + 1. До этого момента update остаётся в локальной durable queue и переживает перезапуск gateway.
Ответ в приватный E2E-диалог отправляется через sendMessage. Возьмите chat.id из update:
curl --fail-with-body -sS \
-H 'content-type: application/json' \
-d '{"chat_id": 217020518514230019, "text": "Привет из бота"}' \
"http://127.0.0.1:8081/bot${SKREPA_BOT_TOKEN}/sendMessage" | jq .
Gateway сверяет активные устройства адресата, шифрует отдельный ciphertext для каждого и сохраняет исходящее сообщение в local outbox до подтверждения платформы.
Что сохранять между перезапусками
В state_dir находятся криптографические сессии и локальные очереди конкретного экземпляра gateway. Это рабочие данные, сопоставимые с небольшой базой данных:
- сохраняйте каталог на постоянном диске;
- выдавайте файлам права
0600, а каталогу —0700; - делайте резервную копию только при остановленном gateway;
- используйте отдельный
state_dirдля каждого одновременно работающего экземпляра; - не подменяйте state одного бота каталогом другого.
Потеря state_dir заставит gateway зарегистрировать новое устройство и построить криптографические сессии заново. Updates, которые уже были приняты с сервера и оставались только в локальной очереди, восстановить будет нельзя. Identity recovery secret сохраняет identity бота, однако локальные очереди он не заменяет.
Безопасность эксплуатации
- Храните bot token и identity recovery secret в secret manager или конфигурации с правами
0600. - Оставляйте HTTP listeners на loopback-интерфейсе. При доступе из другой сети ставьте перед ними аутентифицированный reverse proxy.
- Исключите пути
/bot<TOKEN>/...из access logs: token находится прямо в URL. - Защитите и резервируйте
state_dir; он содержит private keys и незавершённые сообщения. - После
/tokenатомарно обновите конфигурацию и перезапустите gateway. Старый token уже не действует. - Запускайте gateway от отдельного системного пользователя без лишних прав.
Диагностика
| Симптом | Что проверить |
|---|---|
@botfather отсутствует в поиске | проверьте написание, авторизацию клиента и соединение; затем сообщите оператору стенда |
| BotFather не отвечает | обновите клиент, повторите команду новым сообщением и проверьте соединение |
| gateway завершается при старте | проверьте JSON-конфигурацию, доступность bot_platform_endpoint и права на state_dir |
gateway getMe возвращает 401 | token устарел, отозван, содержит лишние символы или бот отключён |
| регистрация устройства отклонена | проверьте соответствие bot token, recovery secret и каталога state одному боту |
getUpdates пуст после сообщения | убедитесь, что пользователь написал этому боту, gateway продолжает работать и переданный offset корректен |
sendMessage сообщает unknown private chat | сначала должен прийти update из этого диалога; используйте его chat.id |
Текущие ограничения
- Telegram-compatible gateway поддерживает
getMe,getUpdatesи текстовыйsendMessageв приватных диалогах. Webhook, media и групповые сообщения пока отсутствуют. - Параметр
timeoutуgetUpdatesпока не включает long polling: пустая очередь возвращается сразу. - Состояние в
state_dirзащищено правами файловой системы хоста; отдельного ключа шифрования каталога сейчас нет. - Gateway читает token при старте. После ротации требуется изменить конфигурацию и перезапустить процесс.
- Параметры
groupsиchannelsможно выбрать при создании бота, но соответствующие методы gateway ещё не опубликованы.
Что дальше
Замените ручные вызовы getUpdates циклом вашего приложения, сохраняйте последний подтверждённый update_id и обрабатывайте повторную доставку идемпотентно. Полный контракт запросов и ответов смотрите в Bot API Reference.