v0.0.27: TG-compatible bots — plaintext send, numeric IDs, webhooks, BotFather
Bot compatibility: - Clients send plaintext bot_message to bot aliases (no E2E encryption) - Numeric chat_id: fp_to_numeric_id() deterministic hash, accept string/number - Webhook delivery: POST updates to bot's webhook URL (async, fire-and-forget) - getUpdates timeout raised to 50s (was 30, TG uses 50) - parse_mode HTML rendered in web client - E2E bot registration: optional seed + bundle for encrypted bot sessions BotFather + instance control: - --enable-bots CLI flag (default: disabled) - BotFather auto-created on first start (@botfather alias) - Bot ownership: owner fingerprint stored in bot_info - All bot endpoints return 403 when disabled Bot Bridge: - tools/bot-bridge.py: TG-compatible proxy for unmodified TG bots - Translates chat_id int↔string, proxies getUpdates/sendMessage - README with python-telegram-bot and Telegraf examples Test fixes: - Updated tests for ETH address display in header/messages Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,10 @@ struct Cli {
|
||||
/// Federation config file (JSON). Enables server-to-server message relay.
|
||||
#[arg(short, long)]
|
||||
federation: Option<String>,
|
||||
|
||||
/// Enable bot API (disabled by default)
|
||||
#[arg(long, default_value = "false")]
|
||||
enable_bots: bool,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
@@ -49,6 +53,36 @@ async fn main() -> anyhow::Result<()> {
|
||||
state.federation = Some(handle);
|
||||
}
|
||||
|
||||
// Enable bot API if requested
|
||||
state.bots_enabled = cli.enable_bots;
|
||||
if cli.enable_bots {
|
||||
tracing::info!("Bot API enabled");
|
||||
|
||||
// Auto-create BotFather if it doesn't exist
|
||||
let botfather_fp = "0000000000000000botfather00000000";
|
||||
let botfather_key = format!("bot_fp:{}", botfather_fp);
|
||||
if state.db.tokens.get(botfather_key.as_bytes()).ok().flatten().is_none() {
|
||||
let token = format!("botfather:{}", hex::encode(rand::random::<[u8; 16]>()));
|
||||
let bot_info = serde_json::json!({
|
||||
"name": "BotFather",
|
||||
"fingerprint": botfather_fp,
|
||||
"token": token,
|
||||
"owner": "system",
|
||||
"e2e": false,
|
||||
"created_at": chrono::Utc::now().timestamp(),
|
||||
});
|
||||
let key = format!("bot:{}", token);
|
||||
let _ = state.db.tokens.insert(key.as_bytes(), serde_json::to_vec(&bot_info).unwrap_or_default());
|
||||
let _ = state.db.tokens.insert(botfather_key.as_bytes(), token.as_bytes());
|
||||
// Register alias
|
||||
let _ = state.db.aliases.insert(b"a:botfather", botfather_fp.as_bytes());
|
||||
let _ = state.db.aliases.insert(format!("fp:{}", botfather_fp).as_bytes(), b"botfather");
|
||||
tracing::info!("BotFather created: @botfather (token: {}...)", &token[..20]);
|
||||
} else {
|
||||
tracing::info!("BotFather already exists");
|
||||
}
|
||||
}
|
||||
|
||||
// Spawn federation outgoing WS connection if enabled
|
||||
if let Some(ref fed) = state.federation {
|
||||
let handle = fed.clone();
|
||||
|
||||
Reference in New Issue
Block a user