Skip to content

Commit

Permalink
Add --restricted
Browse files Browse the repository at this point in the history
Closes: #142
  • Loading branch information
iovxw committed Oct 27, 2020
1 parent 1013f78 commit 6cf7bfb
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 35 deletions.
7 changes: 4 additions & 3 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ USAGE:
rssbot [FLAGS] [OPTIONS] <token>
FLAGS:
-h, --help Prints help information
--insecure DANGER: Insecure mode, accept invalid TLS certificates
-V, --version Prints version information
-h, --help Prints help information
--insecure DANGER: Insecure mode, accept invalid TLS certificates
--restricted Make bot commands only accessible for group admins
-V, --version Prints version information
OPTIONS:
-d, --database <path> Path to database [default: ./rssbot.json]
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ USAGE:
rssbot [FLAGS] [OPTIONS] <token>
FLAGS:
-h, --help Prints help information
--insecure DANGER: Insecure mode, accept invalid TLS certificates
-V, --version Prints version information
-h, --help Prints help information
--insecure DANGER: Insecure mode, accept invalid TLS certificates
--restricted Make bot commands only accessible for group admins
-V, --version Prints version information
OPTIONS:
-d, --database <path> Path to database [default: ./rssbot.json]
Expand Down
5 changes: 3 additions & 2 deletions locales/en.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ verifying_channel = "Verifying channel"
unable_to_find_target_channel = "Unable to find the target channel: {desc}"
target_must_be_a_channel = "Target must be a channel"
unable_to_get_channel_info = "Unable to get channel information ({desc}), please grant this bot administrator rights"
admin_only_command = "This command can only be used by Channel administrators"
make_bot_admin = "Please grant this bot administrator rights"
channel_admin_only_command = "This command can only be used by channel administrators"
group_admin_only_command = "This command can only be used by group administrators"
make_bot_admin = "Please grant this bot administrator rights"
11 changes: 6 additions & 5 deletions locales/zh.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ subscription_failed = "订阅失败: {error}"
unsub_how_to_use = "使用方法: /unsub [Channel ID] <RSS URL>"
unsubscription_succeeded = "《<a href=\"{link}\">{title}</a>》 退订成功"
unsubscribed_from_rss = "未订阅过的 RSS"
verifying_channel = "正在验证 Channel"
unable_to_find_target_channel = "无法找到目标 Channel:{desc}"
target_must_be_a_channel = "目标需为 Channel"
verifying_channel = "正在验证频道"
unable_to_find_target_channel = "无法找到目标频道:{desc}"
target_must_be_a_channel = "目标需为频道"
unable_to_get_channel_info = "无法获取频道信息({desc}),请将本 Bot 设为管理员"
admin_only_command = "该命令只能由 Channel 管理员使用"
make_bot_admin = "请将本 Bot 设为管理员"
channel_admin_only_command = "该命令只能由 Channel 管理员使用"
group_admin_only_command = "该命令只能由群组管理员使用"
make_bot_admin = "请将本 Bot 设为管理员"
45 changes: 34 additions & 11 deletions src/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,50 @@ use crate::messages::{format_large_msg, Escape};

mod opml;

pub async fn check_command(owner: Option<i64>, cmd: Arc<Command<Text>>) -> bool {
pub async fn check_command(opt: &crate::Opt, cmd: Arc<Command<Text>>) -> bool {
use tbot::contexts::fields::Message;
use tbot::types::chat::Kind::*;
let target = &mut MsgTarget::new(cmd.chat.id, cmd.message_id);
let from = cmd
.from()
.map(|user| user.id.0)
.unwrap_or_else(|| cmd.chat.id.0);
if matches!(owner, Some(owner) if owner != from) {

// Single user mode
if matches!(opt.single_user, Some(owner) if owner != from) {
eprintln!(
"Unauthenticated request from user/channel: {}, command: {}, args: {}",
from, cmd.command, cmd.text.value
);
return false;
}
if cmd.chat().kind.is_channel() {
let msg = tr!("commands_in_private_channel");
let _ignore_result = update_response(&cmd.bot, target, parameters::Text::plain(&msg)).await;
return false;

match cmd.chat.kind {
Channel { .. } => {
let msg = tr!("commands_in_private_channel");
let _ignore_result =
update_response(&cmd.bot, target, parameters::Text::plain(&msg)).await;
return false;
}
// Restrict mode: bot commands are only accessible to admins.
Group { .. } | Supergroup { .. } if opt.restricted => {
let user_id = cmd.from.as_ref().unwrap().id;
let admins = match cmd.bot.get_chat_administrators(cmd.chat.id).call().await {
Ok(r) => r,
_ => return false,
};
let user_is_admin = admins.iter().any(|member| member.user.id == user_id);
if !user_is_admin {
let _ignore_result = update_response(
&cmd.bot,
target,
parameters::Text::plain(tr!("group_admin_only_command")),
)
.await;
}
return user_is_admin;
}
_ => (),
}

true
Expand Down Expand Up @@ -350,15 +376,12 @@ async fn check_channel_permission(
}
other => other?,
};
let user_is_admin = admins
.iter()
.find(|member| member.user.id == user_id)
.is_some();
let user_is_admin = admins.iter().any(|member| member.user.id == user_id);
if !user_is_admin {
update_response(
bot,
target,
parameters::Text::plain(tr!("admin_only_command")),
parameters::Text::plain(tr!("channel_admin_only_command")),
)
.await?;
return Ok(None);
Expand Down
32 changes: 21 additions & 11 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ static BOT_ID: OnceCell<tbot::types::user::Id> = OnceCell::new();
about = "A simple Telegram RSS bot.",
after_help = "NOTE: You can get <user id> using bots like @userinfobot @getidsbot"
)]
struct Opt {
pub struct Opt {
/// Telegram bot token
token: String,
/// Path to database
Expand Down Expand Up @@ -74,6 +74,9 @@ struct Opt {
/// Single user mode, only specified user can use this bot
#[structopt(long, value_name = "user id")]
single_user: Option<i64>,
/// Make bot commands only accessible for group admins.
#[structopt(long)]
restricted: bool,
/// DANGER: Insecure mode, accept invalid TLS certificates
#[structopt(long)]
insecure: bool,
Expand Down Expand Up @@ -109,11 +112,11 @@ async fn main() -> anyhow::Result<()> {
enable_fail_fast();

let opt = Opt::from_args();
let db = Arc::new(Mutex::new(Database::open(opt.database)?));
let db = Arc::new(Mutex::new(Database::open(opt.database.clone())?));
let bot = if let Some(proxy) = init_proxy() {
tbot::Bot::with_proxy(opt.token, proxy)
tbot::Bot::with_proxy(opt.token.clone(), proxy)
} else {
tbot::Bot::new(opt.token)
tbot::Bot::new(opt.token.clone())
};
let me = bot
.get_me()
Expand All @@ -130,16 +133,23 @@ async fn main() -> anyhow::Result<()> {
gardener::start_pruning(bot.clone(), db.clone());
fetcher::start(bot.clone(), db.clone(), opt.min_interval, opt.max_interval);

let owner = opt.single_user;
let check_command = move |cmd| async move { handlers::check_command(owner, cmd).await };
let opt = Arc::new(opt);
let check_command = move |cmd| {
let opt = opt.clone();
async move { handlers::check_command(&opt, cmd).await }
};

let mut event_loop = bot.event_loop();
event_loop.username(me.user.username.unwrap());
event_loop.start_if(check_command, handle!(db, handlers::start));
event_loop.command_if("rss", check_command, handle!(db, handlers::rss));
event_loop.command_if("sub", check_command, handle!(db, handlers::sub));
event_loop.command_if("unsub", check_command, handle!(db, handlers::unsub));
event_loop.command_if("export", check_command, handle!(db, handlers::export));
event_loop.start_if(check_command.clone(), handle!(db, handlers::start));
event_loop.command_if("rss", check_command.clone(), handle!(db, handlers::rss));
event_loop.command_if("sub", check_command.clone(), handle!(db, handlers::sub));
event_loop.command_if("unsub", check_command.clone(), handle!(db, handlers::unsub));
event_loop.command_if(
"export",
check_command.clone(),
handle!(db, handlers::export),
);

event_loop.polling().start().await.unwrap();
Ok(())
Expand Down

0 comments on commit 6cf7bfb

Please sign in to comment.