From 76cac77259c0877ccb1b95c4e57f7e4ed7a8c4b6 Mon Sep 17 00:00:00 2001 From: Siavash Sameni Date: Sun, 29 Mar 2026 09:52:12 +0400 Subject: [PATCH] v0.0.28: BotFather-only registration, per-instance bot toggle, docs update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- warzone/Cargo.lock | 10 +- warzone/Cargo.toml | 2 +- warzone/crates/warzone-protocol/Cargo.toml | 2 +- .../crates/warzone-server/src/routes/bot.rs | 19 ++- .../crates/warzone-server/src/routes/web.rs | 4 +- warzone/deploy/setup.sh | 7 ++ warzone/deploy/warzone-server.env.kh3rad3ree | 2 + warzone/deploy/warzone-server.env.mequ | 2 + warzone/deploy/warzone-server.service | 3 +- warzone/docs/BOT_API.md | 115 ++++++++++++------ warzone/docs/LLM_BOT_DEV.md | 63 ++++++++-- warzone/docs/LLM_HELP.md | 44 +++++-- warzone/docs/SERVER.md | 51 ++++++++ warzone/docs/USAGE.md | 38 +++++- 14 files changed, 288 insertions(+), 74 deletions(-) create mode 100644 warzone/deploy/warzone-server.env.kh3rad3ree create mode 100644 warzone/deploy/warzone-server.env.mequ diff --git a/warzone/Cargo.lock b/warzone/Cargo.lock index 637eef9..0e1ec62 100644 --- a/warzone/Cargo.lock +++ b/warzone/Cargo.lock @@ -2956,7 +2956,7 @@ dependencies = [ [[package]] name = "warzone-client" -version = "0.0.27" +version = "0.0.28" dependencies = [ "anyhow", "argon2", @@ -2989,7 +2989,7 @@ dependencies = [ [[package]] name = "warzone-mule" -version = "0.0.27" +version = "0.0.28" dependencies = [ "anyhow", "clap", @@ -2998,7 +2998,7 @@ dependencies = [ [[package]] name = "warzone-protocol" -version = "0.0.27" +version = "0.0.28" dependencies = [ "base64", "bincode", @@ -3023,7 +3023,7 @@ dependencies = [ [[package]] name = "warzone-server" -version = "0.0.27" +version = "0.0.28" dependencies = [ "anyhow", "axum", @@ -3053,7 +3053,7 @@ dependencies = [ [[package]] name = "warzone-wasm" -version = "0.0.27" +version = "0.0.28" dependencies = [ "base64", "bincode", diff --git a/warzone/Cargo.toml b/warzone/Cargo.toml index c30fc26..6c47e5c 100644 --- a/warzone/Cargo.toml +++ b/warzone/Cargo.toml @@ -9,7 +9,7 @@ members = [ ] [workspace.package] -version = "0.0.27" +version = "0.0.28" edition = "2021" license = "MIT" rust-version = "1.75" diff --git a/warzone/crates/warzone-protocol/Cargo.toml b/warzone/crates/warzone-protocol/Cargo.toml index 89dca0e..171de5d 100644 --- a/warzone/crates/warzone-protocol/Cargo.toml +++ b/warzone/crates/warzone-protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "warzone-protocol" -version = "0.0.27" +version = "0.0.28" edition = "2021" license = "MIT" description = "Core crypto & wire protocol for featherChat (Warzone messenger)" diff --git a/warzone/crates/warzone-server/src/routes/bot.rs b/warzone/crates/warzone-server/src/routes/bot.rs index 1e9f4ab..b0abdf8 100644 --- a/warzone/crates/warzone-server/src/routes/bot.rs +++ b/warzone/crates/warzone-server/src/routes/bot.rs @@ -236,6 +236,8 @@ struct RegisterBotRequest { e2e: Option, // true = E2E bot, false/None = plaintext bot #[serde(default)] owner: Option, // fingerprint of the bot creator + #[serde(default)] + botfather_token: Option, } /// Register a bot and receive a token. @@ -249,12 +251,25 @@ async fn register_bot( State(state): State, Json(req): Json, ) -> AppResult> { - // TODO: In production, only @botfather should be able to register bots. - // For v1, direct registration is allowed for development. if !state.bots_enabled { return Ok(Json(serde_json::json!({"ok": false, "description": "Bot API is disabled on this server. Use a server with --enable-bots"}))); } + // Only BotFather can register bots + // Require botfather_token field matching the stored BotFather token + if let Some(ref bf_token) = req.botfather_token { + let botfather_fp = "0000000000000000botfather00000000"; + let bf_key = format!("bot_fp:{}", botfather_fp); + let stored_token = state.db.tokens.get(bf_key.as_bytes()) + .ok().flatten() + .map(|v| String::from_utf8_lossy(&v).to_string()); + if stored_token.as_deref() != Some(bf_token.as_str()) { + return Ok(Json(serde_json::json!({"ok": false, "description": "invalid BotFather token"}))); + } + } else { + return Ok(Json(serde_json::json!({"ok": false, "description": "bot registration requires BotFather authorization. Message @botfather to create a bot."}))); + } + let fp = req .fingerprint .chars() diff --git a/warzone/crates/warzone-server/src/routes/web.rs b/warzone/crates/warzone-server/src/routes/web.rs index 89b25db..af8e3c0 100644 --- a/warzone/crates/warzone-server/src/routes/web.rs +++ b/warzone/crates/warzone-server/src/routes/web.rs @@ -50,7 +50,7 @@ async fn pwa_manifest() -> impl IntoResponse { async fn service_worker() -> impl IntoResponse { ([(header::CONTENT_TYPE, "application/javascript")], r##" -const CACHE = 'wz-v9'; +const CACHE = 'wz-v10'; const SHELL = ['/', '/wasm/warzone_wasm.js', '/wasm/warzone_wasm_bg.wasm', '/icon.svg', '/manifest.json']; self.addEventListener('install', e => { @@ -241,7 +241,7 @@ let pollTimer = null; let ws = null; // WebSocket connection let wasmReady = false; -const VERSION = '0.0.27'; +const VERSION = '0.0.28'; let DEBUG = true; // toggle with /debug command // ── Receipt tracking ── diff --git a/warzone/deploy/setup.sh b/warzone/deploy/setup.sh index de04223..18af261 100755 --- a/warzone/deploy/setup.sh +++ b/warzone/deploy/setup.sh @@ -32,6 +32,13 @@ chmod +x /home/warzone/warzone-server /home/warzone/warzone-client cp "federation-${HOSTNAME}.json" /home/warzone/federation.json chown warzone:warzone /home/warzone/warzone-server /home/warzone/warzone-client /home/warzone/federation.json +# Copy environment file +if [ -f "warzone-server.env.${HOSTNAME}" ]; then + cp "warzone-server.env.${HOSTNAME}" /home/warzone/server.env + chown warzone:warzone /home/warzone/server.env + echo " Environment: $(cat /home/warzone/server.env | grep -v '^#' | grep .)" +fi + # Install systemd service + journald log cap echo "[4/5] Installing systemd service..." cp warzone-server.service /etc/systemd/system/ diff --git a/warzone/deploy/warzone-server.env.kh3rad3ree b/warzone/deploy/warzone-server.env.kh3rad3ree new file mode 100644 index 0000000..5085630 --- /dev/null +++ b/warzone/deploy/warzone-server.env.kh3rad3ree @@ -0,0 +1,2 @@ +# kh3rad3ree: federation + bots enabled +EXTRA_ARGS=--enable-bots diff --git a/warzone/deploy/warzone-server.env.mequ b/warzone/deploy/warzone-server.env.mequ new file mode 100644 index 0000000..c9b6af5 --- /dev/null +++ b/warzone/deploy/warzone-server.env.mequ @@ -0,0 +1,2 @@ +# mequ: federation only, no bots +EXTRA_ARGS= diff --git a/warzone/deploy/warzone-server.service b/warzone/deploy/warzone-server.service index 534e5a0..4d65ca1 100644 --- a/warzone/deploy/warzone-server.service +++ b/warzone/deploy/warzone-server.service @@ -8,7 +8,8 @@ Type=simple User=warzone Group=warzone WorkingDirectory=/home/warzone -ExecStart=/home/warzone/warzone-server --bind 0.0.0.0:7700 --data-dir /home/warzone/data --federation /home/warzone/federation.json +EnvironmentFile=-/home/warzone/server.env +ExecStart=/home/warzone/warzone-server --bind 0.0.0.0:7700 --data-dir /home/warzone/data --federation /home/warzone/federation.json $EXTRA_ARGS Restart=always RestartSec=3 LimitNOFILE=65536 diff --git a/warzone/docs/BOT_API.md b/warzone/docs/BOT_API.md index ea5976e..c0e03ff 100644 --- a/warzone/docs/BOT_API.md +++ b/warzone/docs/BOT_API.md @@ -4,37 +4,45 @@ featherChat exposes a **Telegram Bot API-compatible** HTTP interface, allowing developers to build bots that interact with featherChat users using familiar -patterns. Bots register with the server, receive a token, and communicate via -long-polling (webhook support is planned). +patterns. Bots are created exclusively through **@botfather**, receive a token, +and communicate via long-polling or webhooks. -Key properties of v1: +The server must be started with `--enable-bots` to activate bot functionality. +Key properties: + +- **BotFather is required** -- only `@botfather` can register bots. It is + auto-created on first server start (token printed in server logs). - Bot aliases **must** end with `Bot`, `bot`, or `_bot` (auto-enforced on registration). - Bots receive encrypted user messages as **base64 blobs** (`raw_encrypted` - field). Plaintext bot-to-bot messages are delivered with a readable `text` - field. -- Bot-sent messages are **plaintext** (not E2E encrypted) in v1. -- `chat_id` values are hex fingerprints (not numeric Telegram-style IDs). + field) unless registered as E2E bots. Plaintext bot-to-bot messages are + delivered with a readable `text` field. +- Bot-sent messages are **plaintext** (not E2E encrypted) unless the bot is + registered in E2E mode. +- `chat_id` accepts both hex fingerprints and numeric IDs (Telegram + compatibility). Numeric IDs are also returned in `from.id`. +- Each bot has an `owner` field linking to the creating user's fingerprint. --- ## Quick Start ``` -1. Register your bot: +1. Message @botfather to create a bot (or use BotFather token from server logs). + BotFather registers the bot via: POST /v1/bot/register - {"name": "WeatherBot", "fingerprint": "aabbccdd..."} + {"name": "WeatherBot", "fingerprint": "aabbccdd...", "botfather_token": ""} 2. Extract the token from the response. 3. Poll for updates: POST /v1/bot//getUpdates - {"timeout": 5} + {"timeout": 50} 4. Send a reply: POST /v1/bot//sendMessage - {"chat_id": "", "text": "Hello!"} + {"chat_id": "", "text": "Hello!"} ``` --- @@ -48,21 +56,34 @@ POST /v1/bot/register ``` Creates a new bot, stores it in the server database, and auto-registers an -alias. +alias. **Only @botfather can call this endpoint** -- a valid `botfather_token` +is required. **Request:** ```json { "name": "MyBot", - "fingerprint": "aabbccdd1122334455667788aabbccdd" + "fingerprint": "aabbccdd1122334455667788aabbccdd", + "botfather_token": "", + "owner": "" } ``` -| Field | Type | Description | -|---------------|--------|----------------------------------------------| -| `name` | string | Display name. Alias suffix auto-added if needed. | -| `fingerprint` | string | Hex-encoded public key fingerprint for the bot. | +| Field | Type | Description | +|--------------------|--------|---------------------------------------------------| +| `name` | string | Display name. Alias suffix auto-added if needed. | +| `fingerprint` | string | Hex-encoded public key fingerprint for the bot. | +| `botfather_token` | string | BotFather authorization token (required). | +| `owner` | string | Fingerprint of the user who requested creation. | + +**E2E bot registration** (optional additional fields): + +| Field | Type | Description | +|---------------|--------|--------------------------------------------------| +| `e2e` | bool | Set to `true` to register as an E2E bot. | +| `bundle` | object | Full prekey bundle (identity_key, signed_prekey, signature, one_time_prekeys). | +| `eth_address` | string | Ethereum address for the bot. | **Response:** @@ -73,7 +94,8 @@ alias. "token": "aabbccdd11223344:9f8e7d6c5b4a39281706abcdef012345", "name": "MyBot", "fingerprint": "aabbccdd1122334455667788aabbccdd", - "alias": "@mybot_bot" + "alias": "@mybot_bot", + "owner": "" } } ``` @@ -139,14 +161,17 @@ Returns queued messages for the bot and deletes them from the queue. } ``` -| Field | Type | Description | -|-----------|------|-----------------------------------------------------| -| `timeout` | u64 | Optional. Long-poll wait in seconds. **Capped at 5.** | +| Field | Type | Description | +|-----------|------|------------------------------------------------------| +| `timeout` | u64 | Optional. Long-poll wait in seconds. **Capped at 50.** | If the queue is empty and `timeout > 0`, the server waits up to `timeout` -seconds (max 5) before returning an empty result, giving new messages a chance +seconds (max 50) before returning an empty result, giving new messages a chance to arrive. +> **Note:** If a webhook is configured via `setWebhook`, updates are delivered +> live to the webhook URL via POST instead of being queued for polling. + **Response:** ```json @@ -277,13 +302,15 @@ Sends a **plaintext** message to a user or another bot. } ``` -| Field | Type | Description | -|-----------|--------|--------------------------------------------------| -| `chat_id` | string | Recipient fingerprint (hex) or Ethereum address. | -| `text` | string | Plaintext message body. | +| Field | Type | Description | +|--------------|--------|-----------------------------------------------------------| +| `chat_id` | string/int | Recipient fingerprint (hex), Ethereum address, or numeric ID. | +| `text` | string | Message body. | +| `parse_mode` | string | Optional. `"HTML"` renders basic tags (, , , ). | -Non-hex characters in `chat_id` are stripped and the value is lowercased before -routing. +`chat_id` accepts hex fingerprint strings, Ethereum addresses, or numeric +integer IDs (Telegram compatibility). Non-hex characters in string chat_ids are +stripped and the value is lowercased before routing. **Response:** @@ -323,13 +350,15 @@ WebSocket connection (`true`) or queued for later retrieval (`false`). | Feature | Telegram | featherChat | |---------|----------|-------------| -| `chat_id` type | Numeric integer | Hex fingerprint string | -| `getUpdates` timeout | Up to 50s | Capped at **5s** | -| Message content | Always plaintext | Encrypted messages arrive as `raw_encrypted` base64; bot must decrypt if it has a session | -| Bot-sent messages | Plaintext | Plaintext (not E2E encrypted) in v1 | -| Inline keyboards / callback queries | Supported | Not yet (planned) | +| `chat_id` type | Numeric integer | Hex fingerprint string or numeric integer (both accepted) | +| `getUpdates` timeout | Up to 50s | Capped at **50s** | +| Message content | Always plaintext | Encrypted messages arrive as `raw_encrypted` base64; E2E bots can decrypt | +| Bot-sent messages | Plaintext | Plaintext by default; E2E mode available | +| `from.id` | Numeric integer | Numeric integer (`from.id_str` has hex fingerprint) | +| `parse_mode` | Renders HTML/Markdown | HTML rendered (, , , ) | +| Inline keyboards / callback queries | Supported | Stored + delivered, no popup | +| Webhooks (`setWebhook`) | Supported | Implemented -- updates delivered live to webhook URL | | Media groups | Supported | Not yet (planned) | -| Webhooks (`setWebhook`) | Supported | Not yet (planned) | | File download (`getFile`) | Supported | Not yet (planned) | --- @@ -344,7 +373,7 @@ TOKEN = "your_bot_token" API = f"http://localhost:7700/v1/bot/{TOKEN}" while True: - resp = requests.post(f"{API}/getUpdates", json={"timeout": 5}).json() + resp = requests.post(f"{API}/getUpdates", json={"timeout": 50}).json() for update in resp.get("result", []): msg = update.get("message", {}) text = msg.get("text") or "[encrypted]" @@ -392,10 +421,20 @@ like a password.** --- +## Bot Bridge (`tools/bot-bridge.py`) + +A compatibility layer for existing Telegram bot libraries. Translates between +featherChat Bot API and standard TG libraries (python-telegram-bot, aiogram, +Telegraf). Handles differences like fingerprint-based chat_id, numeric ID +translation, and webhook forwarding. + +```bash +python tools/bot-bridge.py --token YOUR_BOT_TOKEN --server http://localhost:7700 +``` + +--- + ## Future Plans -- **Webhook mode** (`setWebhook`) -- push updates to a URL instead of polling. -- **Inline keyboards and callback queries** -- interactive message buttons. -- **E2E encrypted bot sessions** -- bots participate in X3DH key exchange. - **File send/receive APIs** -- `sendDocument`, `getFile`. - **Group bot support** -- bots in group chats with sender-key encryption. diff --git a/warzone/docs/LLM_BOT_DEV.md b/warzone/docs/LLM_BOT_DEV.md index b2275d5..0e81e0e 100644 --- a/warzone/docs/LLM_BOT_DEV.md +++ b/warzone/docs/LLM_BOT_DEV.md @@ -5,15 +5,42 @@ Server: `http://HOST:7700` All bot endpoints: `/v1/bot//METHOD` -Register bot: +**Prerequisites:** The server must be started with `--enable-bots` to activate bot functionality. + +### BotFather Registration + +Bots can only be created through `@botfather`. On first server start, BotFather is auto-created and its token is printed in the server logs. + +To create a bot: +1. Message `@botfather` in the chat client (or use the BotFather token from server logs for programmatic access). +2. BotFather calls `/v1/bot/register` with your request, including a `botfather_token` field for authorization. + +Registration request (sent by BotFather internally): ``` POST /v1/bot/register -{"name":"MyBot","fingerprint":"any_32_hex_chars"} -→ {"ok":true,"result":{"token":"TOKEN","alias":"@mybot_bot"}} +{"name":"MyBot","fingerprint":"any_32_hex_chars","botfather_token":""} +→ {"ok":true,"result":{"token":"TOKEN","alias":"@mybot_bot","owner":""}} ``` Bot names must end with Bot/bot/_bot. Token format: `:`. +### E2E Bot Mode + +Bots can optionally participate in E2E encryption. Pass additional fields during registration: + +```json +{ + "name": "SecureBot", + "fingerprint": "...", + "botfather_token": "...", + "e2e": true, + "bundle": { "identity_key": "...", "signed_prekey": "...", "signature": "...", "one_time_prekeys": ["..."] }, + "eth_address": "0x..." +} +``` + +An E2E bot registers a full prekey bundle and can establish X3DH sessions with users, receiving decryptable messages instead of `raw_encrypted` blobs. + ## Endpoints ### getMe @@ -190,25 +217,41 @@ poll(); | Feature | Telegram | featherChat | |---------|----------|------------| -| chat_id | numeric | hex fingerprint string | -| getUpdates timeout | up to 50s | up to 30s | -| User messages | plaintext | E2E encrypted (text=null in v1) | -| Bot messages | plaintext | plaintext (no E2E) | +| chat_id | numeric | hex fingerprint string OR numeric (both accepted) | +| getUpdates timeout | up to 50s | up to 50s | +| User messages | plaintext | E2E encrypted (text=null unless E2E bot) | +| Bot messages | plaintext | plaintext (no E2E) unless E2E bot mode | | File upload | multipart form | JSON reference (v1) | | Inline keyboards | full support | stored + delivered, no popup | | Callback queries | full popup | acknowledged, no popup | -| Webhooks | full HTTPS | URL stored, delivery planned | +| Webhooks | full HTTPS | URL stored, updates delivered live (POST to webhook URL) | | Media groups | supported | not yet | -| parse_mode | renders HTML/MD | stored, not rendered (v1) | +| parse_mode | renders HTML/MD | HTML rendered (, , , ) | ## Key Patterns **Always use offset** — without it, the same messages are returned every poll. -**chat_id is the sender's fingerprint** — use `msg.chat.id` or `msg.from.id`. +**chat_id is the sender's fingerprint** — use `msg.chat.id` or `msg.from.id`. Note: `from.id` is now a numeric integer for TG compatibility; use `from.id_str` for the hex fingerprint. **Bot alias** — users message bots via `@mybot_bot` which resolves to the bot's fingerprint. **Error handling** — all responses have `{"ok": bool}`. Check `ok` before accessing `result`. **Rate limits** — 200 concurrent server requests, no per-bot limit (be reasonable). + +## Bot Bridge (`tools/bot-bridge.py`) + +The bot bridge provides a compatibility layer for existing Telegram bot libraries. It translates between featherChat's Bot API and standard TG libraries. + +**Supported libraries:** +- **python-telegram-bot** — set `base_url` to `http://your-server:7700/v1/bot/` +- **aiogram** — configure the bot session with the featherChat server URL +- **Telegraf (Node.js)** — set `telegram.apiRoot` to `http://your-server:7700/v1/bot` + +Usage: +```bash +python tools/bot-bridge.py --token YOUR_BOT_TOKEN --server http://localhost:7700 +``` + +The bridge handles differences like fingerprint-based chat_id, numeric ID translation, and webhook forwarding. diff --git a/warzone/docs/LLM_HELP.md b/warzone/docs/LLM_HELP.md index cbc415d..0b0e408 100644 --- a/warzone/docs/LLM_HELP.md +++ b/warzone/docs/LLM_HELP.md @@ -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":""} -→ 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":"","text":"Hello"}| +|/bot/:token/getMe|GET|--| +|/bot/:token/getUpdates|POST|{"timeout":50}| +|/bot/:token/sendMessage|POST|{"chat_id":"","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 (, , , ) 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) diff --git a/warzone/docs/SERVER.md b/warzone/docs/SERVER.md index 6d0d712..5371dcc 100644 --- a/warzone/docs/SERVER.md +++ b/warzone/docs/SERVER.md @@ -67,6 +67,7 @@ Rust 1.75 or later (`rust-version = "1.75"` in `Cargo.toml`). | `--bind` | `-b` | `0.0.0.0:7700` | Address and port to listen on | | `--data-dir` | `-d` | `./warzone-data` | Directory for the sled database | | `--federation` | `-f` | *(none)* | Path to federation JSON config file | +| `--enable-bots` | | *(off)* | Enable Bot API and auto-create BotFather on startup | ### Environment Variables @@ -75,6 +76,20 @@ Rust 1.75 or later (`rust-version = "1.75"` in `Cargo.toml`). | `RUST_LOG` | `warn` (production) | Log filter. Examples: `info`, `warzone_server=debug`, `trace` | | `WZP_RELAY_ADDR` | *(none)* | WZP voice relay address advertised to clients | +### Per-Instance Configuration (`server.env`) + +Each server instance can use a `server.env` file for per-instance settings. +Place it in the working directory or alongside the binary. This allows +different instances to have different configurations (e.g., bots enabled on +one server but not another). + +Example `server.env`: +``` +RUST_LOG=info +WZP_RELAY_ADDR=relay.example.com:3478 +ENABLE_BOTS=true +``` + ### systemd Service A production-ready unit file is provided at `deploy/warzone-server.service`: @@ -209,6 +224,42 @@ Returns JSON with connection state, peer info, and presence data. --- +## 4b. Bot System + +### Enabling Bots + +Start the server with `--enable-bots` to activate bot functionality. Without +this flag, all bot endpoints return 403. + +```bash +./warzone-server --bind 0.0.0.0:7700 --enable-bots +``` + +### BotFather Auto-Creation + +On first start with `--enable-bots`, the server auto-creates the `@botfather` +bot. The BotFather token is printed to the server logs. Users interact with +`@botfather` to register new bots. + +### Per-Instance Bot Toggle + +Bot support can be enabled independently per server instance: + +| Instance | Bots | Config | +|----------|------|--------| +| mequ | Disabled | No `--enable-bots` flag | +| kh3rad3ree | Enabled | `--enable-bots` flag set | + +### Bot Webhook Delivery + +When a bot has a webhook configured (via `setWebhook`), incoming messages are +delivered live to the webhook URL via HTTP POST instead of being queued for +`getUpdates` polling. This is integrated into the standard message routing +pipeline -- `deliver_or_queue` checks for webhook configuration before +queueing. + +--- + ## 5. API Reference All endpoints are prefixed with `/v1`. The web UI is served at `/`. diff --git a/warzone/docs/USAGE.md b/warzone/docs/USAGE.md index c872424..1555412 100644 --- a/warzone/docs/USAGE.md +++ b/warzone/docs/USAGE.md @@ -55,10 +55,11 @@ The `scripts/build-linux.sh` script builds Linux x86_64 binaries on a Hetzner Cl warzone-server --bind 0.0.0.0:7700 --data-dir ./warzone-data ``` -| Flag | Default | Description | -|--------------|------------------|--------------------| -| `--bind` | `0.0.0.0:7700` | Listen address | -| `--data-dir` | `./warzone-data` | sled database path | +| Flag | Default | Description | +|-----------------|------------------|--------------------------------------| +| `--bind` | `0.0.0.0:7700` | Listen address | +| `--data-dir` | `./warzone-data` | sled database path | +| `--enable-bots` | *(off)* | Enable Bot API and BotFather | Environment variables: @@ -336,6 +337,35 @@ The friend list is encrypted client-side and stored on the server as an opaque b --- +## Bots + +### Messaging Bots + +Clients auto-detect bot aliases (names ending in `Bot`, `bot`, or `_bot`) and send messages as plaintext -- no E2E session is established. Simply use `/peer @mybot_bot` and type your message. The client handles the rest. + +### Creating Bots with BotFather + +To create a bot, message `@botfather`: + +1. `/peer @botfather` +2. Send a message requesting a new bot (e.g., "create WeatherBot") +3. BotFather registers the bot and returns the API token +4. Use the token to run your bot against the server's Bot API + +BotFather is auto-created on servers that have `--enable-bots` enabled. It is the only way to create bots. + +### Bot Bridge for Telegram Compatibility + +The `tools/bot-bridge.py` script provides a compatibility layer that lets you use existing Telegram bot libraries (python-telegram-bot, aiogram, Telegraf) with featherChat. It translates between the two APIs, handling differences like fingerprint-based addressing and numeric ID translation. + +```bash +python tools/bot-bridge.py --token YOUR_BOT_TOKEN --server http://localhost:7700 +``` + +See `docs/BOT_API.md` and `docs/LLM_BOT_DEV.md` for full Bot API documentation. + +--- + ## Federation Federation connects two featherChat servers so that users on different servers can message each other transparently.