Compare commits

..

1 Commits

Author SHA1 Message Date
rustdesk
af096f800d swtich_code for hbbs to bypass ACL 2026-07-17 19:05:52 +08:00
5 changed files with 62 additions and 6 deletions

View File

@@ -426,8 +426,8 @@ impl Client {
NatType::from_i32(my_nat_type).unwrap_or(NatType::UNKNOWN_NAT) NatType::from_i32(my_nat_type).unwrap_or(NatType::UNKNOWN_NAT)
}; };
if !key.is_empty() && !token.is_empty() { let switch_code = interface.get_switch_code();
// mainly for the security of token if !key.is_empty() && (!token.is_empty() || !switch_code.is_empty()) {
secure_tcp(&mut socket, &key) secure_tcp(&mut socket, &key)
.await .await
.map_err(|e| anyhow!("Failed to secure tcp: {}", e))?; .map_err(|e| anyhow!("Failed to secure tcp: {}", e))?;
@@ -469,6 +469,7 @@ impl Client {
udp_port: udp_nat_port as _, udp_port: udp_nat_port as _,
force_relay: interface.is_force_relay(), force_relay: interface.is_force_relay(),
socket_addr_v6: ipv6.1.unwrap_or_default(), socket_addr_v6: ipv6.1.unwrap_or_default(),
switch_code,
..Default::default() ..Default::default()
}); });
for i in 1..=3 { for i in 1..=3 {
@@ -716,6 +717,7 @@ impl Client {
let mut direct = !conn.is_err(); let mut direct = !conn.is_err();
if interface.is_force_relay() || conn.is_err() { if interface.is_force_relay() || conn.is_err() {
if !relay_server.is_empty() { if !relay_server.is_empty() {
let switch_code = interface.get_switch_code();
conn = Self::request_relay( conn = Self::request_relay(
peer_id, peer_id,
relay_server.to_owned(), relay_server.to_owned(),
@@ -724,6 +726,7 @@ impl Client {
key, key,
token, token,
conn_type, conn_type,
&switch_code,
) )
.await; .await;
if let Err(e) = conn { if let Err(e) = conn {
@@ -844,6 +847,7 @@ impl Client {
key: &str, key: &str,
token: &str, token: &str,
conn_type: ConnType, conn_type: ConnType,
switch_code: &str,
) -> ResultType<Stream> { ) -> ResultType<Stream> {
let mut succeed = false; let mut succeed = false;
let mut uuid = "".to_owned(); let mut uuid = "".to_owned();
@@ -855,8 +859,7 @@ impl Client {
.await .await
.with_context(|| "Failed to connect to rendezvous server")?; .with_context(|| "Failed to connect to rendezvous server")?;
if !key.is_empty() && !token.is_empty() { if !key.is_empty() && (!token.is_empty() || !switch_code.is_empty()) {
// mainly for the security of token
secure_tcp(&mut socket, key).await?; secure_tcp(&mut socket, key).await?;
} }
@@ -877,6 +880,7 @@ impl Client {
uuid: uuid.clone(), uuid: uuid.clone(),
relay_server: relay_server.clone(), relay_server: relay_server.clone(),
secure, secure,
switch_code: switch_code.to_owned(),
..Default::default() ..Default::default()
}); });
socket.send(&msg_out).await?; socket.send(&msg_out).await?;
@@ -3736,6 +3740,16 @@ pub trait Interface: Send + Clone + 'static + Sized {
self.get_lch().read().unwrap().force_relay self.get_lch().read().unwrap().force_relay
} }
fn get_switch_code(&self) -> String {
match self.get_lch().read().unwrap().switch_uuid.clone() {
Some(u) if !u.is_empty() => {
use hbb_common::sodiumoxide::crypto::hash::sha256;
crate::encode64(sha256::hash(u.as_bytes()).0)
}
_ => String::new(),
}
}
fn swap_modifier_mouse(&self, _msg: &mut hbb_common::protos::message::MouseEvent) {} fn swap_modifier_mouse(&self, _msg: &mut hbb_common::protos::message::MouseEvent) {}
fn update_direct(&self, direct: Option<bool>) { fn update_direct(&self, direct: Option<bool>) {

View File

@@ -308,3 +308,44 @@ fn handle_config_options(config_options: HashMap<String, String>) {
pub fn is_pro() -> bool { pub fn is_pro() -> bool {
PRO.lock().unwrap().clone() PRO.lock().unwrap().clone()
} }
#[cfg(feature = "flutter")]
#[cfg(not(any(target_os = "android", target_os = "ios")))]
pub fn register_switch_grant(switch_uuid: String) {
tokio::spawn(async move {
let api_server = crate::ui_interface::get_api_server();
if api_server.is_empty() {
return;
}
use hbb_common::sodiumoxide::crypto::{hash::sha256, sign};
let switch_code = crate::encode64(sha256::hash(switch_uuid.as_bytes()).0);
let id = Config::get_id();
let kp = Config::get_key_pair();
let Some(sk) = sign::SecretKey::from_slice(&kp.0) else {
log::warn!("Failed to register switch grant: no device key");
return;
};
let signed = sign::sign(&switch_grant_signed_msg(&id, &switch_code), &sk);
let body = json!({
"id": id,
"switch_code": switch_code,
"signature": crate::encode64(signed),
})
.to_string();
let url = format!("{}/api/switch-grant", api_server);
if let Err(e) = crate::post_request(url, body, "").await {
log::warn!("Failed to register switch grant: {}", e);
}
});
}
#[cfg(feature = "flutter")]
#[cfg(not(any(target_os = "android", target_os = "ios")))]
fn switch_grant_signed_msg(id: &str, switch_code: &str) -> Vec<u8> {
let mut msg = Vec::with_capacity(13 + id.len() + 1 + switch_code.len());
msg.extend_from_slice(b"switch-grant\0");
msg.extend_from_slice(id.as_bytes());
msg.push(0);
msg.extend_from_slice(switch_code.as_bytes());
msg
}

View File

@@ -968,6 +968,7 @@ async fn handle(data: Data, stream: &mut Connection) {
Data::SwitchSidesRequest(id) => { Data::SwitchSidesRequest(id) => {
let uuid = uuid::Uuid::new_v4(); let uuid = uuid::Uuid::new_v4();
crate::server::insert_switch_sides_uuid(id, uuid.clone()); crate::server::insert_switch_sides_uuid(id, uuid.clone());
crate::hbbs_http::sync::register_switch_grant(uuid.to_string());
allow_err!( allow_err!(
stream stream
.send(&Data::SwitchSidesRequest(uuid.to_string())) .send(&Data::SwitchSidesRequest(uuid.to_string()))

View File

@@ -332,7 +332,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Relay Connection", "中继连接"), ("Relay Connection", "中继连接"),
("Secure Connection", "安全连接"), ("Secure Connection", "安全连接"),
("Insecure Connection", "非安全连接"), ("Insecure Connection", "非安全连接"),
("Continue", "继续"), ("Continue", ""),
("Scale original", "原始尺寸"), ("Scale original", "原始尺寸"),
("Scale adaptive", "适应窗口"), ("Scale adaptive", "适应窗口"),
("General", "常规"), ("General", "常规"),