Skip to main content

whitelist_bot/
whitelist_bot.rs

1//! A *private* bot: it auto-joins a community ONLY when invited by a trusted
2//! npub, ignoring invites from everyone else. This is what makes a bot safe to
3//! publish — it can't be spammed into random communities.
4//!
5//! Set the trusted inviters (comma-separated npubs) in `VECTOR_WHITELIST`.
6//!
7//! Run with:
8//! ```sh
9//! VECTOR_NSEC=nsec1...                       \
10//! VECTOR_WHITELIST=npub1aaa...,npub1bbb...    \
11//! cargo run -p vector-sdk --example whitelist_bot
12//! ```
13
14use vector_sdk::{BotEvent, VectorBot};
15
16#[tokio::main]
17async fn main() -> vector_sdk::Result<()> {
18    let nsec = std::env::var("VECTOR_NSEC").expect("set VECTOR_NSEC to your bot's nsec");
19    let whitelist: Vec<String> = std::env::var("VECTOR_WHITELIST")
20        .unwrap_or_default()
21        .split(',')
22        .map(|s| s.trim().to_string())
23        .filter(|s| !s.is_empty())
24        .collect();
25
26    // Only invites from these npubs are auto-accepted; all others stay parked.
27    let bot = VectorBot::builder().nsec(nsec).whitelist(whitelist).build().await?;
28
29    println!("Private bot online as {}", bot.npub());
30    for c in bot.communities().await {
31        println!("  already a member of community {}", c.id());
32    }
33
34    bot.on_event(|bot, event| async move {
35        match event {
36            // An invite arrived. A whitelisted inviter means it's already being joined;
37            // anyone else leaves it parked for you to review via bot.pending_invites().
38            BotEvent::Invite { community_id } => {
39                println!("invite to {community_id} (auto-join attempted per whitelist)");
40            }
41            // Best-effort hello once we land in a community we accepted.
42            BotEvent::MemberJoin { channel_id, npub } if npub == bot.npub() => {
43                let _ = bot.channel(channel_id).send("Hello! Reporting for duty 🫡").await;
44            }
45            BotEvent::Message(msg) if !msg.is_mine() => {
46                let _ = msg.reply("At your service. 🛡️").await;
47            }
48            _ => {}
49        }
50    })
51    .await?;
52
53    Ok(())
54}