v0.0.28: BotFather-only registration, per-instance bot toggle, docs update

Security:
- Bot registration restricted to BotFather (requires botfather_token)
- Direct POST /v1/bot/register without BotFather auth → rejected

Deploy:
- systemd service reads /home/warzone/server.env for EXTRA_ARGS
- deploy/warzone-server.env.mequ: no bots (default)
- deploy/warzone-server.env.kh3rad3ree: --enable-bots
- setup.sh copies per-hostname env file

Docs updated:
- LLM_HELP.md: BotFather flow, plaintext bot messaging, E2E option, bridge
- LLM_BOT_DEV.md: botfather_token requirement, E2E mode, bridge section
- BOT_API.md: full BotFather flow, ownership, numeric IDs, webhook delivery
- SERVER.md: --enable-bots flag, per-instance config, bot system section
- USAGE.md: bot messaging, BotFather, bridge tool

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Siavash Sameni
2026-03-29 09:52:12 +04:00
parent 8603087afb
commit 76cac77259
14 changed files with 288 additions and 74 deletions

View File

@@ -131,21 +131,47 @@ no prekeys available | recipient's one-time prekeys exhausted | they need to re-
## Bot API (Telegram-compatible)
Register: POST /v1/bot/register {"name":"MyBot","fingerprint":"<fp>"}
→ returns token + auto-creates @mybot_bot alias
### BotFather
`@botfather` is the only way to create bots. It is auto-created on first server start (token printed in server logs). Users message `@botfather` to register new bots. The server must be started with `--enable-bots` to activate bot functionality.
### Registration
Bots are created via BotFather, which calls POST /v1/bot/register with a `botfather_token` field. Each bot has an `owner` field linking it to the user who requested creation.
Bot aliases must end with Bot, bot, or _bot. Non-bots cannot use these.
### Plaintext Bot Messaging
Clients auto-detect bot aliases (names ending in Bot/bot/_bot) and send messages unencrypted (plaintext JSON). No E2E session is established for standard bot interactions.
### E2E Bot Option
Bots can optionally participate in E2E encryption by registering with a seed and prekey bundle. Pass `e2e: true` + `bundle` + `eth_address` in the registration request. Users messaging an E2E bot establish a normal X3DH session.
### Bot Bridge
`tools/bot-bridge.py` provides Telegram library compatibility. It translates between featherChat Bot API and standard TG bot libraries (python-telegram-bot, aiogram, Telegraf).
### Endpoints
|Endpoint|Method|Body|
|---|---|---|
|/bot/:token/getMe|GET||
|/bot/:token/getUpdates|POST|{"timeout":5}|
|/bot/:token/sendMessage|POST|{"chat_id":"<fp>","text":"Hello"}|
|/bot/:token/getMe|GET|--|
|/bot/:token/getUpdates|POST|{"timeout":50}|
|/bot/:token/sendMessage|POST|{"chat_id":"<fp_or_numeric>","text":"Hello","parse_mode":"HTML"}|
|/bot/:token/setWebhook|POST|{"url":"https://..."}|
|/bot/:token/deleteWebhook|POST|--|
|/bot/:token/getWebhookInfo|GET|--|
- Token format: fp_prefix:random_hex
- getUpdates: long-poll (max 5s), returns then deletes queued msgs
- sendMessage: plaintext JSON, NOT E2E encrypted
- getUpdates: long-poll (max 50s), returns then deletes queued msgs
- sendMessage: plaintext JSON, NOT E2E encrypted (unless E2E bot)
- Bot msgs delivered via same routing (WS push or DB queue)
- Webhooks: updates are delivered live to the registered URL (POST with JSON body)
- chat_id: accepts hex fingerprint or numeric ID (TG compatibility)
- parse_mode: `HTML` renders basic HTML tags (<b>, <i>, <code>, <a>) in clients
- from.id is numeric (integer), from.id_str contains the hex fingerprint
Update types in getUpdates:
- Encrypted msg: text=null, raw_encrypted=base64
@@ -153,15 +179,13 @@ Update types in getUpdates:
- Call signal: text="/call_Offer", call_signal={type,payload}
- File: document={file_name,file_size}
v1 limits: sendMessage is plaintext (no E2E), timeout max 5s, no webhooks yet.
Echo bot (Python):
```python
import requests, time
TOKEN = "your_token"
API = f"http://srv:7700/v1/bot/{TOKEN}"
while True:
for u in requests.post(f"{API}/getUpdates",json={"timeout":5}).json().get("result",[]):
for u in requests.post(f"{API}/getUpdates",json={"timeout":50}).json().get("result",[]):
m = u["message"]
if m.get("text"): requests.post(f"{API}/sendMessage",json={"chat_id":m["chat"]["id"],"text":"Echo: "+m["text"]})
time.sleep(1)