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:
10
warzone/Cargo.lock
generated
10
warzone/Cargo.lock
generated
@@ -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",
|
||||
|
||||
@@ -9,7 +9,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.0.27"
|
||||
version = "0.0.28"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.75"
|
||||
|
||||
@@ -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)"
|
||||
|
||||
@@ -236,6 +236,8 @@ struct RegisterBotRequest {
|
||||
e2e: Option<bool>, // true = E2E bot, false/None = plaintext bot
|
||||
#[serde(default)]
|
||||
owner: Option<String>, // fingerprint of the bot creator
|
||||
#[serde(default)]
|
||||
botfather_token: Option<String>,
|
||||
}
|
||||
|
||||
/// Register a bot and receive a token.
|
||||
@@ -249,12 +251,25 @@ async fn register_bot(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<RegisterBotRequest>,
|
||||
) -> AppResult<Json<serde_json::Value>> {
|
||||
// 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()
|
||||
|
||||
@@ -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 ──
|
||||
|
||||
@@ -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/
|
||||
|
||||
2
warzone/deploy/warzone-server.env.kh3rad3ree
Normal file
2
warzone/deploy/warzone-server.env.kh3rad3ree
Normal file
@@ -0,0 +1,2 @@
|
||||
# kh3rad3ree: federation + bots enabled
|
||||
EXTRA_ARGS=--enable-bots
|
||||
2
warzone/deploy/warzone-server.env.mequ
Normal file
2
warzone/deploy/warzone-server.env.mequ
Normal file
@@ -0,0 +1,2 @@
|
||||
# mequ: federation only, no bots
|
||||
EXTRA_ARGS=
|
||||
@@ -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
|
||||
|
||||
@@ -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": "<bf_token>"}
|
||||
|
||||
2. Extract the token from the response.
|
||||
|
||||
3. Poll for updates:
|
||||
POST /v1/bot/<token>/getUpdates
|
||||
{"timeout": 5}
|
||||
{"timeout": 50}
|
||||
|
||||
4. Send a reply:
|
||||
POST /v1/bot/<token>/sendMessage
|
||||
{"chat_id": "<sender_fingerprint>", "text": "Hello!"}
|
||||
{"chat_id": "<sender_fingerprint_or_numeric_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": "<botfather_token>",
|
||||
"owner": "<creator_fingerprint>"
|
||||
}
|
||||
```
|
||||
|
||||
| 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": "<creator_fingerprint>"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -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 (<b>, <i>, <code>, <a>). |
|
||||
|
||||
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 (<b>, <i>, <code>, <a>) |
|
||||
| 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.
|
||||
|
||||
@@ -5,15 +5,42 @@
|
||||
Server: `http://HOST:7700`
|
||||
All bot endpoints: `/v1/bot/<TOKEN>/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":"<bf_token>"}
|
||||
→ {"ok":true,"result":{"token":"TOKEN","alias":"@mybot_bot","owner":"<creator_fp>"}}
|
||||
```
|
||||
|
||||
Bot names must end with Bot/bot/_bot. Token format: `<fp_prefix>:<random_hex>`.
|
||||
|
||||
### 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 (<b>, <i>, <code>, <a>) |
|
||||
|
||||
## 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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 `/`.
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user