mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
telegram bot ui settings and code sending
This commit is contained in:
@@ -4,7 +4,7 @@ use hbb_common::{
|
||||
config::Config,
|
||||
get_time,
|
||||
password_security::{decrypt_vec_or_original, encrypt_vec_or_original},
|
||||
ResultType,
|
||||
tokio, ResultType,
|
||||
};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::sync::Mutex;
|
||||
@@ -133,46 +133,61 @@ impl TelegramBot {
|
||||
fn save(&self) -> ResultType<()> {
|
||||
let s = self.into_string()?;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
crate::ipc::set_option("telegram_bot", &s);
|
||||
crate::ipc::set_option("bot", &s);
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
Config::set_option("telegram_bot".to_owned(), s);
|
||||
Config::set_option("bot".to_owned(), s);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get() -> ResultType<TelegramBot> {
|
||||
let data = Config::get_option("telegram_bot");
|
||||
pub fn get() -> ResultType<Option<TelegramBot>> {
|
||||
let data = Config::get_option("bot");
|
||||
if data.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
let mut bot = serde_json::from_str::<TelegramBot>(&data)?;
|
||||
let (token, success, _) = decrypt_vec_or_original(&bot.token, "00");
|
||||
if success {
|
||||
bot.token_str = String::from_utf8(token)?;
|
||||
return Ok(bot);
|
||||
return Ok(Some(bot));
|
||||
}
|
||||
bail!("decrypt_vec_or_original telegram bot token failed")
|
||||
}
|
||||
}
|
||||
|
||||
// https://gist.github.com/dideler/85de4d64f66c1966788c1b2304b9caf1
|
||||
pub async fn send_2fa_code_to_telegram(code: &str) -> ResultType<()> {
|
||||
let bot = TelegramBot::get()?;
|
||||
pub async fn send_2fa_code_to_telegram(text: &str, bot: TelegramBot) -> ResultType<()> {
|
||||
let url = format!("https://api.telegram.org/bot{}/sendMessage", bot.token_str);
|
||||
let params = serde_json::json!({"chat_id": bot.chat_id, "text": code});
|
||||
let params = serde_json::json!({"chat_id": bot.chat_id, "text": text});
|
||||
crate::post_request(url, params.to_string(), "").await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
pub async fn get_chatid_telegram(bot_token: &str) -> ResultType<Option<String>> {
|
||||
// send a message to the bot first please, otherwise the chat_id will be empty
|
||||
let url = format!("https://api.telegram.org/bot{}/getUpdates", bot_token);
|
||||
let resp = crate::post_request(url, "".to_owned(), "")
|
||||
.await
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
let res = serde_json::from_str::<serde_json::Value>(&resp)
|
||||
.map(|x| {
|
||||
let chat_id = x["result"][0]["message"]["chat"]["id"].as_str();
|
||||
chat_id.map(|x| x.to_owned())
|
||||
})
|
||||
.map_err(|e| anyhow!(e));
|
||||
if let Ok(Some(chat_id)) = res.as_ref() {
|
||||
let value = serde_json::from_str::<serde_json::Value>(&resp).map_err(|e| anyhow!(e))?;
|
||||
|
||||
// Check for an error_code in the response
|
||||
if let Some(error_code) = value.get("error_code").and_then(|code| code.as_i64()) {
|
||||
// If there's an error_code, try to use the description for the error message
|
||||
let description = value["description"]
|
||||
.as_str()
|
||||
.unwrap_or("Unknown error occurred");
|
||||
return Err(anyhow!(
|
||||
"Telegram API error: {} (error_code: {})",
|
||||
description,
|
||||
error_code
|
||||
));
|
||||
}
|
||||
|
||||
let chat_id = value["result"][0]["message"]["chat"]["id"]
|
||||
.as_str()
|
||||
.map(|x| x.to_owned());
|
||||
|
||||
if let Some(chat_id) = chat_id.as_ref() {
|
||||
let bot = TelegramBot {
|
||||
token_str: bot_token.to_owned(),
|
||||
chat_id: chat_id.to_owned(),
|
||||
@@ -180,5 +195,6 @@ pub async fn get_chatid_telegram(bot_token: &str) -> ResultType<Option<String>>
|
||||
};
|
||||
bot.save()?;
|
||||
}
|
||||
res
|
||||
|
||||
Ok(chat_id)
|
||||
}
|
||||
|
||||
@@ -2178,6 +2178,14 @@ pub fn main_has_valid_2fa_sync() -> SyncReturn<bool> {
|
||||
SyncReturn(has_valid_2fa())
|
||||
}
|
||||
|
||||
pub fn main_verify_bot(token: String) -> String {
|
||||
verify_bot(token)
|
||||
}
|
||||
|
||||
pub fn main_has_valid_bot_sync() -> SyncReturn<bool> {
|
||||
SyncReturn(has_valid_bot())
|
||||
}
|
||||
|
||||
pub fn main_get_hard_option(key: String) -> SyncReturn<String> {
|
||||
SyncReturn(get_hard_option(key))
|
||||
}
|
||||
|
||||
@@ -230,5 +230,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("android_new_voice_call_tip", "A new voice call request was received. If you accept, the audio will switch to voice communication."),
|
||||
("texture_render_tip", "Use texture rendering to make the pictures smoother. You could try disabling this option if you encounter rendering issues."),
|
||||
("floating_window_tip", "It helps to keep RustDesk background service"),
|
||||
("enable-bot-tip", "If you enable this feature, you can receive the 2FA code from your bot. It can also function as a connection notification."),
|
||||
("enable-bot-desc", "1, Open a chat with @BotFather.\n2, Send the command \"/newbot\". You will receive a token after completing this step.\n3, Start a chat with your newly created bot. Send a message like \"hello\" to activate it.\n"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -627,5 +627,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Volume up", ""),
|
||||
("Volume down", ""),
|
||||
("Power", ""),
|
||||
("Telegram bot", ""),
|
||||
("enable-bot-tip", ""),
|
||||
("enable-bot-desc", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -401,7 +401,8 @@ impl Connection {
|
||||
#[cfg(target_os = "android")]
|
||||
start_channel(rx_to_cm, tx_from_cm);
|
||||
#[cfg(target_os = "android")]
|
||||
conn.send_permission(Permission::Keyboard, conn.keyboard).await;
|
||||
conn.send_permission(Permission::Keyboard, conn.keyboard)
|
||||
.await;
|
||||
#[cfg(not(target_os = "android"))]
|
||||
if !conn.keyboard {
|
||||
conn.send_permission(Permission::Keyboard, false).await;
|
||||
@@ -1079,6 +1080,33 @@ impl Connection {
|
||||
return;
|
||||
}
|
||||
if self.require_2fa.is_some() && !self.is_recent_session(true) && !self.from_switch {
|
||||
self.require_2fa.as_ref().map(|totp| {
|
||||
let bot = crate::auth_2fa::TelegramBot::get();
|
||||
let bot = match bot {
|
||||
Ok(Some(bot)) => bot,
|
||||
Err(err) => {
|
||||
log::error!("Failed to get telegram bot: {}", err);
|
||||
return;
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
let code = totp.generate_current();
|
||||
if let Ok(code) = code {
|
||||
let text = format!(
|
||||
"2FA code: {}\n\nA new connection has been established to your device with ID {}. The source IP address is {}.",
|
||||
code,
|
||||
Config::get_id(),
|
||||
self.ip,
|
||||
);
|
||||
tokio::spawn(async move {
|
||||
if let Err(err) =
|
||||
crate::auth_2fa::send_2fa_code_to_telegram(&text, bot).await
|
||||
{
|
||||
log::error!("Failed to send 2fa code to telegram bot: {}", err);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
self.send_login_error(crate::client::REQUIRE_2FA).await;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1392,6 +1392,20 @@ pub fn verify2fa(code: String) -> bool {
|
||||
res
|
||||
}
|
||||
|
||||
pub fn has_valid_bot() -> bool {
|
||||
crate::auth_2fa::TelegramBot::get().map_or(false, |bot| bot.is_some())
|
||||
}
|
||||
|
||||
pub fn verify_bot(token: String) -> String {
|
||||
match crate::auth_2fa::get_chatid_telegram(&token) {
|
||||
Err(err) => err.to_string(),
|
||||
Ok(None) => {
|
||||
"To activate the bot, simply send a message like \"hello\" to its chat.".to_owned()
|
||||
}
|
||||
_ => "".to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_hwcodec() {
|
||||
#[cfg(feature = "hwcodec")]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
||||
|
||||
Reference in New Issue
Block a user