easy access: move grant exchange from rendezvous to API server
Signed-off-by: 21pages <sunboeasy@gmail.com>
This commit is contained in:
parent
8117f01598
commit
04554d9129
7 changed files with 281 additions and 204 deletions
|
|
@ -61,7 +61,7 @@ Future<List<Map<String, dynamic>>> fetchEasyAccessManagers() async {
|
|||
}
|
||||
|
||||
final response = await http.post(
|
||||
Uri.parse('$url/api/devices/easy-access-managers'),
|
||||
Uri.parse('$url/api/easy_access/managers'),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: authBody,
|
||||
);
|
||||
|
|
|
|||
153
src/client.rs
153
src/client.rs
|
|
@ -207,7 +207,6 @@ impl Client {
|
|||
debug_assert!(peer == interface.get_id());
|
||||
interface.update_direct(None);
|
||||
interface.update_received(false);
|
||||
interface.clear_easy_access_challenge();
|
||||
match Self::_start(peer, key, token, conn_type, interface.clone()).await {
|
||||
Err(err) => {
|
||||
let err_str = err.to_string();
|
||||
|
|
@ -344,9 +343,7 @@ impl Client {
|
|||
contained,
|
||||
);
|
||||
if udp.0.is_none() {
|
||||
let conn = fut.await?;
|
||||
interface.get_lch().write().unwrap().controller_config = conn.3;
|
||||
return Ok((conn.0, conn.1, conn.2));
|
||||
return fut.await;
|
||||
}
|
||||
let mut connect_futures = Vec::new();
|
||||
connect_futures.push(fut.boxed());
|
||||
|
|
@ -355,7 +352,7 @@ impl Client {
|
|||
key.to_owned(),
|
||||
token.to_owned(),
|
||||
conn_type,
|
||||
interface.clone(),
|
||||
interface,
|
||||
(None, None),
|
||||
None,
|
||||
rendezvous_server,
|
||||
|
|
@ -364,10 +361,7 @@ impl Client {
|
|||
);
|
||||
connect_futures.push(fut.boxed());
|
||||
match select_ok(connect_futures).await {
|
||||
Ok(conn) => {
|
||||
interface.get_lch().write().unwrap().controller_config = conn.0 .3;
|
||||
Ok((conn.0 .0, conn.0 .1, conn.0 .2))
|
||||
}
|
||||
Ok(conn) => Ok((conn.0 .0, conn.0 .1, conn.0 .2)),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
|
@ -393,7 +387,6 @@ impl Client {
|
|||
),
|
||||
(i32, String),
|
||||
bool,
|
||||
Option<ControllerConfig>,
|
||||
)> {
|
||||
let mut start = Instant::now();
|
||||
let mut socket = connect_tcp(&*rendezvous_server, CONNECT_TIMEOUT).await;
|
||||
|
|
@ -464,7 +457,6 @@ impl Client {
|
|||
};
|
||||
let udp_nat_port = udp.1.map(|x| *x.lock().unwrap()).unwrap_or(0);
|
||||
let punch_type = if udp_nat_port > 0 { "UDP" } else { "TCP" };
|
||||
let mut controller_config = None;
|
||||
msg_out.set_punch_hole_request(PunchHoleRequest {
|
||||
id: peer.to_owned(),
|
||||
token: token.to_owned(),
|
||||
|
|
@ -518,7 +510,6 @@ impl Client {
|
|||
relay_server = ph.relay_server;
|
||||
peer_addr = AddrMangle::decode(&ph.socket_addr);
|
||||
feedback = ph.feedback;
|
||||
controller_config = ph.controller_config.into_option();
|
||||
let s = udp.0.take();
|
||||
if ph.is_udp && s.is_some() {
|
||||
if let Some(s) = s {
|
||||
|
|
@ -558,7 +549,6 @@ impl Client {
|
|||
}
|
||||
}
|
||||
signed_id_pk = rr.pk().into();
|
||||
controller_config = rr.controller_config.into_option();
|
||||
let fut = Self::create_relay(
|
||||
&peer,
|
||||
rr.uuid,
|
||||
|
|
@ -589,7 +579,6 @@ impl Client {
|
|||
(conn, typ == "IPv6", pk, kcp, typ),
|
||||
(feedback, rendezvous_server),
|
||||
false,
|
||||
controller_config,
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -633,12 +622,10 @@ impl Client {
|
|||
udp.0,
|
||||
ipv6.0,
|
||||
punch_type,
|
||||
&mut controller_config,
|
||||
)
|
||||
.await?,
|
||||
(feedback, rendezvous_server),
|
||||
true,
|
||||
controller_config,
|
||||
))
|
||||
}
|
||||
|
||||
|
|
@ -661,7 +648,6 @@ impl Client {
|
|||
udp_socket_nat: Option<Arc<UdpSocket>>,
|
||||
udp_socket_v6: Option<Arc<UdpSocket>>,
|
||||
punch_type: &str,
|
||||
controller_config: &mut Option<ControllerConfig>,
|
||||
) -> ResultType<(
|
||||
Stream,
|
||||
bool,
|
||||
|
|
@ -736,7 +722,6 @@ impl Client {
|
|||
key,
|
||||
token,
|
||||
conn_type,
|
||||
controller_config,
|
||||
)
|
||||
.await;
|
||||
if let Err(e) = conn {
|
||||
|
|
@ -857,7 +842,6 @@ impl Client {
|
|||
key: &str,
|
||||
token: &str,
|
||||
conn_type: ConnType,
|
||||
controller_config: &mut Option<ControllerConfig>,
|
||||
) -> ResultType<Stream> {
|
||||
let mut succeed = false;
|
||||
let mut uuid = "".to_owned();
|
||||
|
|
@ -902,7 +886,6 @@ impl Client {
|
|||
if !rs.refuse_reason.is_empty() {
|
||||
bail!(rs.refuse_reason);
|
||||
}
|
||||
*controller_config = rs.controller_config.into_option();
|
||||
succeed = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1778,7 +1761,7 @@ pub struct LoginConfigHandler {
|
|||
pub enable_trusted_devices: bool,
|
||||
pub record_state: bool,
|
||||
pub record_permission: bool,
|
||||
pub controller_config: Option<ControllerConfig>,
|
||||
easy_access_grant_id: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl Deref for LoginConfigHandler {
|
||||
|
|
@ -1893,6 +1876,7 @@ impl LoginConfigHandler {
|
|||
self.shared_password = shared_password;
|
||||
self.record_state = false;
|
||||
self.record_permission = true;
|
||||
self.easy_access_grant_id = None;
|
||||
|
||||
// `std::env::remove_var("IS_TERMINAL_ADMIN");` is called in `session_add_sync()` - `flutter_ffi.rs`.
|
||||
let is_terminal_admin = conn_type == ConnType::TERMINAL
|
||||
|
|
@ -2673,16 +2657,15 @@ impl LoginConfigHandler {
|
|||
};
|
||||
let mut avatar = get_builtin_option(keys::OPTION_AVATAR);
|
||||
if avatar.is_empty() {
|
||||
avatar = serde_json::from_str::<serde_json::Value>(&LocalConfig::get_option(
|
||||
"user_info",
|
||||
))
|
||||
.ok()
|
||||
.and_then(|x| {
|
||||
x.get("avatar")
|
||||
.and_then(|x| x.as_str())
|
||||
.map(|x| x.trim().to_owned())
|
||||
})
|
||||
.unwrap_or_default();
|
||||
avatar =
|
||||
serde_json::from_str::<serde_json::Value>(&LocalConfig::get_option("user_info"))
|
||||
.ok()
|
||||
.and_then(|x| {
|
||||
x.get("avatar")
|
||||
.and_then(|x| x.as_str())
|
||||
.map(|x| x.trim().to_owned())
|
||||
})
|
||||
.unwrap_or_default();
|
||||
}
|
||||
avatar = resolve_avatar_url(avatar);
|
||||
let mut display_name = get_builtin_option(keys::OPTION_DISPLAY_NAME);
|
||||
|
|
@ -2728,11 +2711,7 @@ impl LoginConfigHandler {
|
|||
} else {
|
||||
Bytes::new()
|
||||
};
|
||||
let easy_access_challenge: Bytes = self
|
||||
.controller_config
|
||||
.as_ref()
|
||||
.map(|config| config.easy_access_challenge.clone())
|
||||
.unwrap_or_default();
|
||||
let easy_access_grant_id = self.easy_access_grant_id.clone().unwrap_or_default().into();
|
||||
let mut lr = LoginRequest {
|
||||
username: pure_id,
|
||||
password: password.into(),
|
||||
|
|
@ -2750,7 +2729,7 @@ impl LoginConfigHandler {
|
|||
.into(),
|
||||
hwid,
|
||||
avatar,
|
||||
easy_access_challenge,
|
||||
easy_access_grant_id,
|
||||
..Default::default()
|
||||
};
|
||||
match self.conn_type {
|
||||
|
|
@ -2778,6 +2757,99 @@ impl LoginConfigHandler {
|
|||
msg_out
|
||||
}
|
||||
|
||||
async fn request_easy_access_grant(
|
||||
lc: Arc<RwLock<LoginConfigHandler>>,
|
||||
hash: &Hash,
|
||||
secure: bool,
|
||||
) {
|
||||
let (peer, challenge, other_server) = {
|
||||
let mut lc = lc.write().unwrap();
|
||||
lc.easy_access_grant_id = None;
|
||||
(
|
||||
lc.id.clone(),
|
||||
hash.easy_access_challenge.to_vec(),
|
||||
lc.other_server.is_some(),
|
||||
)
|
||||
};
|
||||
let grant_id =
|
||||
Self::fetch_easy_access_grant_id(&peer, challenge, other_server, secure).await;
|
||||
lc.write().unwrap().easy_access_grant_id = grant_id;
|
||||
}
|
||||
|
||||
async fn fetch_easy_access_grant_id(
|
||||
peer: &str,
|
||||
challenge: Vec<u8>,
|
||||
other_server: bool,
|
||||
secure: bool,
|
||||
) -> Option<Vec<u8>> {
|
||||
if other_server || !secure || challenge.is_empty() {
|
||||
return None;
|
||||
}
|
||||
if hbb_common::is_ip_str(peer) || hbb_common::is_domain_port_str(peer) {
|
||||
return None;
|
||||
}
|
||||
let access_token = LocalConfig::get_option("access_token");
|
||||
if access_token.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let api_server = crate::get_api_server(
|
||||
Config::get_option("api-server"),
|
||||
Config::get_option("custom-rendezvous-server"),
|
||||
);
|
||||
if api_server.is_empty() || crate::is_public(&api_server) {
|
||||
return None;
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct EasyAccessGrantRequest<'a> {
|
||||
id: &'a str,
|
||||
challenge: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct EasyAccessGrantResponse {
|
||||
#[serde(default)]
|
||||
grant_id: String,
|
||||
}
|
||||
|
||||
let challenge_base64 = crate::encode64(&challenge);
|
||||
let body = match serde_json::to_string(&EasyAccessGrantRequest {
|
||||
id: peer,
|
||||
challenge: &challenge_base64,
|
||||
}) {
|
||||
Ok(body) => body,
|
||||
Err(err) => {
|
||||
log::warn!("Easy access grant request serialize failed: {}", err);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let url = format!("{}/api/easy_access/grant", api_server);
|
||||
let header = format!("Authorization: Bearer {}", access_token);
|
||||
let response = match crate::post_request(url, body, &header).await {
|
||||
Ok(response) => response,
|
||||
Err(err) => {
|
||||
log::debug!("Easy access grant request failed: {}", err);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let response: EasyAccessGrantResponse = match serde_json::from_str(&response) {
|
||||
Ok(response) => response,
|
||||
Err(err) => {
|
||||
log::warn!("Easy access grant response parse failed: {}", err);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let grant_id = match crate::decode64(&response.grant_id) {
|
||||
Ok(grant_id) if !grant_id.is_empty() => grant_id,
|
||||
Ok(_) => return None,
|
||||
Err(err) => {
|
||||
log::warn!("Easy access grant id invalid: {}", err);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
Some(grant_id)
|
||||
}
|
||||
|
||||
pub fn update_supported_decodings(&self) -> Message {
|
||||
let decoding = scrap::codec::Decoder::supported_decodings(
|
||||
Some(&self.id),
|
||||
|
|
@ -3473,6 +3545,7 @@ pub async fn handle_hash(
|
|||
peer: &mut Stream,
|
||||
) {
|
||||
lc.write().unwrap().hash = hash.clone();
|
||||
LoginConfigHandler::request_easy_access_grant(lc.clone(), &hash, peer.is_secured()).await;
|
||||
// Take care of password application order
|
||||
|
||||
// switch_uuid
|
||||
|
|
@ -3739,12 +3812,6 @@ pub trait Interface: Send + Clone + 'static + Sized {
|
|||
self.get_lch().write().unwrap().received = received;
|
||||
}
|
||||
|
||||
fn clear_easy_access_challenge(&self) {
|
||||
if let Some(config) = self.get_lch().write().unwrap().controller_config.as_mut() {
|
||||
config.easy_access_challenge = Default::default();
|
||||
}
|
||||
}
|
||||
|
||||
fn on_establish_connection_error(&self, err: String) {
|
||||
let title = "Connection Error";
|
||||
let text = err.to_string();
|
||||
|
|
|
|||
|
|
@ -2603,7 +2603,7 @@ pub fn str2color(s: &str, alpha: u8) -> u32 {
|
|||
/// Returns: Some(true) = enabled, Some(false) = disabled, None = not set or invalid
|
||||
pub fn get_control_permission(
|
||||
permissions: u64,
|
||||
permission: hbb_common::rendezvous_proto::controlled_config::Permission,
|
||||
permission: hbb_common::rendezvous_proto::control_permissions::Permission,
|
||||
) -> Option<bool> {
|
||||
use hbb_common::protobuf::Enum;
|
||||
let index = permission.value();
|
||||
|
|
|
|||
|
|
@ -1084,7 +1084,7 @@ async fn handle(data: Data, stream: &mut Connection) {
|
|||
}
|
||||
},
|
||||
Data::ControlPermissionsRemoteModify(_) => {
|
||||
use hbb_common::rendezvous_proto::controlled_config::Permission;
|
||||
use hbb_common::rendezvous_proto::control_permissions::Permission;
|
||||
let state =
|
||||
crate::server::get_control_permission_state(Permission::remote_modify, true);
|
||||
allow_err!(
|
||||
|
|
@ -1095,7 +1095,7 @@ async fn handle(data: Data, stream: &mut Connection) {
|
|||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
Data::FileTransferEnabledState(_) => {
|
||||
use hbb_common::rendezvous_proto::controlled_config::Permission;
|
||||
use hbb_common::rendezvous_proto::control_permissions::Permission;
|
||||
let state = crate::server::get_control_permission_state(Permission::file, false);
|
||||
let enabled = state.unwrap_or_else(|| {
|
||||
crate::server::Connection::is_permission_enabled_locally(
|
||||
|
|
|
|||
|
|
@ -472,8 +472,7 @@ impl RendezvousMediator {
|
|||
rr.secure,
|
||||
false,
|
||||
Default::default(),
|
||||
rr.controlled_config.clone().into_option(),
|
||||
rr.request_id,
|
||||
rr.control_permissions.clone().into_option(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
|
@ -487,8 +486,7 @@ impl RendezvousMediator {
|
|||
secure: bool,
|
||||
initiate: bool,
|
||||
socket_addr_v6: bytes::Bytes,
|
||||
controlled_config: Option<ControlledConfig>,
|
||||
request_id: bytes::Bytes,
|
||||
control_permissions: Option<ControlPermissions>,
|
||||
) -> ResultType<()> {
|
||||
let peer_addr = AddrMangle::decode(&socket_addr);
|
||||
log::info!(
|
||||
|
|
@ -506,7 +504,6 @@ impl RendezvousMediator {
|
|||
socket_addr: socket_addr.into(),
|
||||
version: crate::VERSION.to_owned(),
|
||||
socket_addr_v6,
|
||||
request_id,
|
||||
..Default::default()
|
||||
};
|
||||
if initiate {
|
||||
|
|
@ -523,7 +520,7 @@ impl RendezvousMediator {
|
|||
peer_addr,
|
||||
secure,
|
||||
is_ipv4(&self.addr),
|
||||
controlled_config,
|
||||
control_permissions,
|
||||
)
|
||||
.await;
|
||||
Ok(())
|
||||
|
|
@ -546,7 +543,7 @@ impl RendezvousMediator {
|
|||
peer_addr_v6,
|
||||
addr,
|
||||
server.clone(),
|
||||
fla.controlled_config.clone().into_option(),
|
||||
fla.control_permissions.clone().into_option(),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
|
@ -574,8 +571,7 @@ impl RendezvousMediator {
|
|||
true,
|
||||
true,
|
||||
socket_addr_v6,
|
||||
fla.controlled_config.into_option(),
|
||||
fla.request_id,
|
||||
fla.control_permissions.into_option(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
|
@ -602,7 +598,6 @@ impl RendezvousMediator {
|
|||
relay_server,
|
||||
version: crate::VERSION.to_owned(),
|
||||
socket_addr_v6,
|
||||
request_id: fla.request_id,
|
||||
..Default::default()
|
||||
});
|
||||
let bytes = msg_out.write_to_bytes()?;
|
||||
|
|
@ -612,7 +607,7 @@ impl RendezvousMediator {
|
|||
socket,
|
||||
peer_addr,
|
||||
true,
|
||||
fla.controlled_config.into_option(),
|
||||
fla.control_permissions.into_option(),
|
||||
)
|
||||
.await;
|
||||
Ok(())
|
||||
|
|
@ -629,13 +624,13 @@ impl RendezvousMediator {
|
|||
let peer_addr_v6 = hbb_common::AddrMangle::decode(&ph.socket_addr_v6);
|
||||
let relay = use_ws() || Config::is_proxy() || ph.force_relay;
|
||||
let mut socket_addr_v6 = Default::default();
|
||||
let controlled_config = ph.controlled_config.into_option();
|
||||
let control_permissions = ph.control_permissions.into_option();
|
||||
if peer_addr_v6.port() > 0 && !relay {
|
||||
socket_addr_v6 = start_ipv6(
|
||||
peer_addr_v6,
|
||||
peer_addr,
|
||||
server.clone(),
|
||||
controlled_config.clone(),
|
||||
control_permissions.clone(),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
|
@ -656,8 +651,7 @@ impl RendezvousMediator {
|
|||
true,
|
||||
true,
|
||||
socket_addr_v6.clone(),
|
||||
controlled_config,
|
||||
ph.request_id,
|
||||
control_permissions,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
|
@ -670,12 +664,11 @@ impl RendezvousMediator {
|
|||
nat_type: nat_type.into(),
|
||||
version: crate::VERSION.to_owned(),
|
||||
socket_addr_v6,
|
||||
request_id: ph.request_id,
|
||||
..Default::default()
|
||||
};
|
||||
if ph.udp_port > 0 {
|
||||
peer_addr.set_port(ph.udp_port as u16);
|
||||
self.punch_udp_hole(peer_addr, server, msg_punch, controlled_config)
|
||||
self.punch_udp_hole(peer_addr, server, msg_punch, control_permissions)
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
|
|
@ -692,7 +685,8 @@ impl RendezvousMediator {
|
|||
msg_out.set_punch_hole_sent(msg_punch);
|
||||
let bytes = msg_out.write_to_bytes()?;
|
||||
socket.send_raw(bytes).await?;
|
||||
crate::accept_connection(server.clone(), socket, peer_addr, true, controlled_config).await;
|
||||
crate::accept_connection(server.clone(), socket, peer_addr, true, control_permissions)
|
||||
.await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -701,7 +695,7 @@ impl RendezvousMediator {
|
|||
peer_addr: SocketAddr,
|
||||
server: ServerPtr,
|
||||
msg_punch: PunchHoleSent,
|
||||
controlled_config: Option<ControlledConfig>,
|
||||
control_permissions: Option<ControlPermissions>,
|
||||
) -> ResultType<()> {
|
||||
let mut msg_out = Message::new();
|
||||
msg_out.set_punch_hole_sent(msg_punch);
|
||||
|
|
@ -721,7 +715,7 @@ impl RendezvousMediator {
|
|||
peer_addr,
|
||||
peer_addr,
|
||||
server,
|
||||
controlled_config,
|
||||
control_permissions,
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
|
|
@ -880,7 +874,7 @@ async fn direct_server(server: ServerPtr) {
|
|||
hbb_common::Stream::from(stream, local_addr),
|
||||
addr,
|
||||
false,
|
||||
None, // Direct connections don't have controlled_config
|
||||
None, // Direct connections don't have control_permissions
|
||||
)
|
||||
.await
|
||||
);
|
||||
|
|
@ -912,7 +906,7 @@ async fn start_ipv6(
|
|||
peer_addr_v6: SocketAddr,
|
||||
peer_addr_v4: SocketAddr,
|
||||
server: ServerPtr,
|
||||
controlled_config: Option<ControlledConfig>,
|
||||
control_permissions: Option<ControlPermissions>,
|
||||
) -> bytes::Bytes {
|
||||
crate::test_ipv6().await;
|
||||
if let Some((socket, local_addr_v6)) = crate::get_ipv6_socket().await {
|
||||
|
|
@ -924,7 +918,7 @@ async fn start_ipv6(
|
|||
peer_addr_v6,
|
||||
peer_addr_v4,
|
||||
server,
|
||||
controlled_config,
|
||||
control_permissions
|
||||
)
|
||||
.await
|
||||
);
|
||||
|
|
@ -939,7 +933,7 @@ async fn udp_nat_listen(
|
|||
peer_addr: SocketAddr,
|
||||
peer_addr_v4: SocketAddr,
|
||||
server: ServerPtr,
|
||||
controlled_config: Option<ControlledConfig>,
|
||||
control_permissions: Option<ControlPermissions>,
|
||||
) -> ResultType<()> {
|
||||
let tm = Instant::now();
|
||||
let socket_cloned = socket.clone();
|
||||
|
|
@ -957,7 +951,7 @@ async fn udp_nat_listen(
|
|||
stream.1,
|
||||
peer_addr_v4,
|
||||
true,
|
||||
controlled_config,
|
||||
control_permissions,
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ async fn accept_connection_(
|
|||
server: ServerPtr,
|
||||
socket: Stream,
|
||||
secure: bool,
|
||||
controlled_config: Option<ControlledConfig>,
|
||||
control_permissions: Option<ControlPermissions>,
|
||||
) -> ResultType<()> {
|
||||
let local_addr = socket.local_addr();
|
||||
drop(socket);
|
||||
|
|
@ -180,7 +180,7 @@ async fn accept_connection_(
|
|||
Stream::from(stream, stream_addr),
|
||||
addr,
|
||||
secure,
|
||||
controlled_config,
|
||||
control_permissions,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
|
@ -192,7 +192,7 @@ pub async fn create_tcp_connection(
|
|||
stream: Stream,
|
||||
addr: SocketAddr,
|
||||
secure: bool,
|
||||
controlled_config: Option<ControlledConfig>,
|
||||
control_permissions: Option<ControlPermissions>,
|
||||
) -> ResultType<()> {
|
||||
let mut stream = stream;
|
||||
let id = server.write().unwrap().get_new_id();
|
||||
|
|
@ -265,7 +265,7 @@ pub async fn create_tcp_connection(
|
|||
stream,
|
||||
id,
|
||||
Arc::downgrade(&server),
|
||||
controlled_config,
|
||||
control_permissions,
|
||||
)
|
||||
.await;
|
||||
Ok(())
|
||||
|
|
@ -276,9 +276,9 @@ pub async fn accept_connection(
|
|||
socket: Stream,
|
||||
peer_addr: SocketAddr,
|
||||
secure: bool,
|
||||
controlled_config: Option<ControlledConfig>,
|
||||
control_permissions: Option<ControlPermissions>,
|
||||
) {
|
||||
if let Err(err) = accept_connection_(server, socket, secure, controlled_config).await {
|
||||
if let Err(err) = accept_connection_(server, socket, secure, control_permissions).await {
|
||||
log::warn!("Failed to accept connection from {}: {}", peer_addr, err);
|
||||
}
|
||||
}
|
||||
|
|
@ -290,7 +290,7 @@ pub async fn create_relay_connection(
|
|||
peer_addr: SocketAddr,
|
||||
secure: bool,
|
||||
ipv4: bool,
|
||||
controlled_config: Option<ControlledConfig>,
|
||||
control_permissions: Option<ControlPermissions>,
|
||||
) {
|
||||
if let Err(err) = create_relay_connection_(
|
||||
server,
|
||||
|
|
@ -299,7 +299,7 @@ pub async fn create_relay_connection(
|
|||
peer_addr,
|
||||
secure,
|
||||
ipv4,
|
||||
controlled_config,
|
||||
control_permissions,
|
||||
)
|
||||
.await
|
||||
{
|
||||
|
|
@ -319,7 +319,7 @@ async fn create_relay_connection_(
|
|||
peer_addr: SocketAddr,
|
||||
secure: bool,
|
||||
ipv4: bool,
|
||||
controlled_config: Option<ControlledConfig>,
|
||||
control_permissions: Option<ControlPermissions>,
|
||||
) -> ResultType<()> {
|
||||
let mut stream = socket_client::connect_tcp(
|
||||
socket_client::ipv4_to_ipv6(crate::check_port(relay_server, RELAY_PORT), ipv4),
|
||||
|
|
@ -334,7 +334,7 @@ async fn create_relay_connection_(
|
|||
..Default::default()
|
||||
});
|
||||
stream.send(&msg_out).await?;
|
||||
create_tcp_connection(server, stream, peer_addr, secure, controlled_config).await?;
|
||||
create_tcp_connection(server, stream, peer_addr, secure, control_permissions).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,10 +35,10 @@ use hbb_common::{
|
|||
fs::{self, can_enable_overwrite_detection, JobType},
|
||||
futures::{SinkExt, StreamExt},
|
||||
get_time, get_version_number,
|
||||
message_proto::EasyAccessManagerApproval,
|
||||
message_proto::{option_message::BoolOption, permission_info::Permission},
|
||||
password_security::{self as password, ApproveMode},
|
||||
rand,
|
||||
rendezvous_proto::EasyAccessManagerApproval,
|
||||
sha2::{Digest, Sha256},
|
||||
sleep,
|
||||
sodiumoxide::crypto::{
|
||||
|
|
@ -82,7 +82,7 @@ lazy_static::lazy_static! {
|
|||
static ref SESSIONS: Arc::<Mutex<HashMap<SessionKey, Session>>> = Default::default();
|
||||
static ref ALIVE_CONNS: Arc::<Mutex<Vec<i32>>> = Default::default();
|
||||
pub static ref AUTHED_CONNS: Arc::<Mutex<Vec<AuthedConn>>> = Default::default();
|
||||
pub static ref CONTROLLED_CONFIG_ARRAY: Arc::<Mutex<Vec<(i32, ControlledConfig)>>> = Default::default();
|
||||
pub static ref CONTROL_PERMISSIONS_ARRAY: Arc::<Mutex<Vec<(i32, ControlPermissions)>>> = Default::default();
|
||||
static ref WAKELOCK_SENDER: Arc::<Mutex<std::sync::mpsc::Sender<(usize, usize)>>> = Arc::new(Mutex::new(start_wakelock_thread()));
|
||||
static ref WAKELOCK_KEEP_AWAKE_OPTION: Arc::<Mutex<Option<bool>>> = Default::default();
|
||||
}
|
||||
|
|
@ -287,7 +287,7 @@ pub struct Connection {
|
|||
recording: bool,
|
||||
block_input: bool,
|
||||
privacy_mode: bool,
|
||||
controlled_config: Option<ControlledConfig>,
|
||||
control_permissions: Option<ControlPermissions>,
|
||||
last_test_delay: Option<Instant>,
|
||||
network_delay: u32,
|
||||
lock_after_session_end: bool,
|
||||
|
|
@ -404,6 +404,7 @@ const MILLI1: Duration = Duration::from_millis(1);
|
|||
const SEND_TIMEOUT_VIDEO: u64 = 12_000;
|
||||
const SEND_TIMEOUT_OTHER: u64 = SEND_TIMEOUT_VIDEO * 10;
|
||||
const SESSION_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
const EASY_ACCESS_CHALLENGE_LEN: usize = 32;
|
||||
|
||||
impl Connection {
|
||||
pub async fn start(
|
||||
|
|
@ -411,19 +412,25 @@ impl Connection {
|
|||
stream: super::Stream,
|
||||
id: i32,
|
||||
server: super::ServerPtrWeak,
|
||||
controlled_config: Option<ControlledConfig>,
|
||||
control_permissions: Option<ControlPermissions>,
|
||||
) {
|
||||
// Android does not support control_permissions yet.
|
||||
// Android is not supported yet, so we always set control_permissions to None.
|
||||
#[cfg(target_os = "android")]
|
||||
let controlled_config = controlled_config.map(|mut c| {
|
||||
c.control_permissions = 0;
|
||||
c
|
||||
});
|
||||
let control_permissions = None;
|
||||
let _raii_id = raii::ConnectionID::new(id);
|
||||
let _raii_controlled_config_id = raii::ControlledConfigID::new(id, &controlled_config);
|
||||
let _raii_control_permissions_id =
|
||||
raii::ControlPermissionsID::new(id, &control_permissions);
|
||||
let easy_access_challenge = if hbb_common::config::is_allow_easy_access() {
|
||||
rand::random::<[u8; EASY_ACCESS_CHALLENGE_LEN]>()
|
||||
.to_vec()
|
||||
.into()
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let hash = Hash {
|
||||
salt: Config::get_salt(),
|
||||
challenge: Config::get_auto_password(6),
|
||||
easy_access_challenge,
|
||||
..Default::default()
|
||||
};
|
||||
let (tx_from_cm_holder, mut rx_from_cm) = mpsc::unbounded_channel::<ipc::Data>();
|
||||
|
|
@ -471,16 +478,16 @@ impl Connection {
|
|||
port_forward_address: "".to_owned(),
|
||||
tx_to_cm,
|
||||
authorized: false,
|
||||
keyboard: Self::permission(keys::OPTION_ENABLE_KEYBOARD, &controlled_config),
|
||||
clipboard: Self::permission(keys::OPTION_ENABLE_CLIPBOARD, &controlled_config),
|
||||
audio: Self::permission(keys::OPTION_ENABLE_AUDIO, &controlled_config),
|
||||
keyboard: Self::permission(keys::OPTION_ENABLE_KEYBOARD, &control_permissions),
|
||||
clipboard: Self::permission(keys::OPTION_ENABLE_CLIPBOARD, &control_permissions),
|
||||
audio: Self::permission(keys::OPTION_ENABLE_AUDIO, &control_permissions),
|
||||
// to-do: make sure is the option correct here
|
||||
file: Self::permission(keys::OPTION_ENABLE_FILE_TRANSFER, &controlled_config),
|
||||
restart: Self::permission(keys::OPTION_ENABLE_REMOTE_RESTART, &controlled_config),
|
||||
recording: Self::permission(keys::OPTION_ENABLE_RECORD_SESSION, &controlled_config),
|
||||
block_input: Self::permission(keys::OPTION_ENABLE_BLOCK_INPUT, &controlled_config),
|
||||
privacy_mode: Self::permission(keys::OPTION_ENABLE_PRIVACY_MODE, &controlled_config),
|
||||
controlled_config,
|
||||
file: Self::permission(keys::OPTION_ENABLE_FILE_TRANSFER, &control_permissions),
|
||||
restart: Self::permission(keys::OPTION_ENABLE_REMOTE_RESTART, &control_permissions),
|
||||
recording: Self::permission(keys::OPTION_ENABLE_RECORD_SESSION, &control_permissions),
|
||||
block_input: Self::permission(keys::OPTION_ENABLE_BLOCK_INPUT, &control_permissions),
|
||||
privacy_mode: Self::permission(keys::OPTION_ENABLE_PRIVACY_MODE, &control_permissions),
|
||||
control_permissions,
|
||||
last_test_delay: None,
|
||||
network_delay: 0,
|
||||
lock_after_session_end: false,
|
||||
|
|
@ -1004,7 +1011,7 @@ impl Connection {
|
|||
match data {
|
||||
#[cfg(all(target_os = "windows", feature = "flutter"))]
|
||||
ipc::Data::PrinterData(data) => {
|
||||
if Self::permission(keys::OPTION_ENABLE_REMOTE_PRINTER, &conn.controlled_config) {
|
||||
if Self::permission(keys::OPTION_ENABLE_REMOTE_PRINTER, &conn.control_permissions) {
|
||||
conn.send_printer_request(data).await;
|
||||
} else {
|
||||
conn.send_remote_printing_disallowed().await;
|
||||
|
|
@ -1547,9 +1554,6 @@ impl Connection {
|
|||
return false;
|
||||
}
|
||||
self.authorized = true;
|
||||
if let Some(c) = self.controlled_config.as_mut() {
|
||||
c.easy_access_grant = Default::default();
|
||||
}
|
||||
let (conn_type, auth_conn_type) = if self.file_transfer.is_some() {
|
||||
(1, AuthConnType::FileTransfer)
|
||||
} else if self.port_forward_socket.is_some() {
|
||||
|
|
@ -2260,10 +2264,10 @@ impl Connection {
|
|||
|
||||
fn permission(
|
||||
enable_prefix_option: &str,
|
||||
controlled_config: &Option<ControlledConfig>,
|
||||
control_permissions: &Option<ControlPermissions>,
|
||||
) -> bool {
|
||||
use hbb_common::rendezvous_proto::controlled_config::Permission;
|
||||
if let Some(controlled_config) = controlled_config {
|
||||
use hbb_common::rendezvous_proto::control_permissions::Permission;
|
||||
if let Some(control_permissions) = control_permissions {
|
||||
let permission = match enable_prefix_option {
|
||||
keys::OPTION_ENABLE_KEYBOARD => Some(Permission::keyboard),
|
||||
keys::OPTION_ENABLE_REMOTE_PRINTER => Some(Permission::remote_printer),
|
||||
|
|
@ -2281,7 +2285,7 @@ impl Connection {
|
|||
};
|
||||
if let Some(permission) = permission {
|
||||
if let Some(enabled) =
|
||||
crate::get_control_permission(controlled_config.control_permissions, permission)
|
||||
crate::get_control_permission(control_permissions.permissions, permission)
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
|
@ -2324,8 +2328,7 @@ impl Connection {
|
|||
device_nonce: &[u8],
|
||||
approved: bool,
|
||||
) -> Vec<u8> {
|
||||
const EASY_ACCESS_CONSUME_DECISION_DOMAIN: &[u8] =
|
||||
b"easy-access-consume-decision/v1";
|
||||
const EASY_ACCESS_CONSUME_DECISION_DOMAIN: &[u8] = b"easy-access-consume-decision/v1";
|
||||
|
||||
let mut bytes = Vec::new();
|
||||
bytes.extend_from_slice(EASY_ACCESS_CONSUME_DECISION_DOMAIN);
|
||||
|
|
@ -2356,6 +2359,7 @@ impl Connection {
|
|||
device_nonce: String,
|
||||
approved: bool,
|
||||
signature: String,
|
||||
grant: String,
|
||||
}
|
||||
|
||||
async fn consume_easy_access_grant(
|
||||
|
|
@ -2363,26 +2367,26 @@ impl Connection {
|
|||
target_uuid: &[u8],
|
||||
target_sk: &[u8],
|
||||
server_pk: &sign::PublicKey,
|
||||
) -> bool {
|
||||
) -> Option<EasyAccessGrant> {
|
||||
let api_server = crate::get_api_server(
|
||||
Config::get_option("api-server"),
|
||||
Config::get_option("custom-rendezvous-server"),
|
||||
);
|
||||
if api_server.is_empty() {
|
||||
log::warn!("Easy access consume skipped: api server missing");
|
||||
return false;
|
||||
if api_server.is_empty() || crate::is_public(&api_server) {
|
||||
log::warn!("Easy access consume skipped: api server missing or public");
|
||||
return None;
|
||||
}
|
||||
let Some(device_sign_sk) = sign::SecretKey::from_slice(target_sk) else {
|
||||
log::warn!("Easy access consume failed: target private key invalid");
|
||||
return false;
|
||||
return None;
|
||||
};
|
||||
let Ok(device_box_sk) = ed25519::to_curve25519_sk(&device_sign_sk) else {
|
||||
log::warn!("Easy access consume failed: target box private key invalid");
|
||||
return false;
|
||||
return None;
|
||||
};
|
||||
let Ok(server_box_pk) = ed25519::to_curve25519_pk(server_pk) else {
|
||||
log::warn!("Easy access consume failed: server box public key invalid");
|
||||
return false;
|
||||
return None;
|
||||
};
|
||||
let device_nonce: [u8; 32] = rand::random();
|
||||
let plaintext = match serde_json::to_vec(&EasyAccessGrantConsumeDeviceAuthPayload {
|
||||
|
|
@ -2393,7 +2397,7 @@ impl Connection {
|
|||
Ok(bytes) => bytes,
|
||||
Err(err) => {
|
||||
log::warn!("Easy access consume payload serialize failed: {}", err);
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let nonce = box_::gen_nonce();
|
||||
|
|
@ -2408,45 +2412,45 @@ impl Connection {
|
|||
Ok(body) => body,
|
||||
Err(err) => {
|
||||
log::warn!("Easy access consume request serialize failed: {}", err);
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let url = format!("{}/api/devices/consume-easy-access-grant", api_server);
|
||||
let url = format!("{}/api/easy_access/consume", api_server);
|
||||
let response = match crate::post_request(url, body, "").await {
|
||||
Ok(response) => response,
|
||||
Err(err) => {
|
||||
log::warn!("Easy access consume request failed: {}", err);
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let response: EasyAccessGrantConsumeResponse = match serde_json::from_str(&response) {
|
||||
Ok(response) => response,
|
||||
Err(err) => {
|
||||
log::warn!("Easy access consume response parse failed: {}", err);
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let response_grant_id = match crate::decode64(&response.grant_id) {
|
||||
Ok(grant_id) => grant_id,
|
||||
Err(err) => {
|
||||
log::warn!("Easy access consume response grant_id invalid: {}", err);
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let response_device_nonce = match crate::decode64(&response.device_nonce) {
|
||||
Ok(device_nonce) => device_nonce,
|
||||
Err(err) => {
|
||||
log::warn!("Easy access consume response device_nonce invalid: {}", err);
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
};
|
||||
if response_grant_id.as_slice() != grant_id {
|
||||
log::warn!("Easy access consume response grant_id mismatch");
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
if response_device_nonce.as_slice() != device_nonce.as_slice() {
|
||||
log::warn!("Easy access consume response device_nonce mismatch");
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
let signature = match crate::decode64(&response.signature)
|
||||
.ok()
|
||||
|
|
@ -2455,7 +2459,7 @@ impl Connection {
|
|||
Some(signature) => signature,
|
||||
None => {
|
||||
log::warn!("Easy access consume response signature invalid");
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
};
|
||||
if !sign::verify_detached(
|
||||
|
|
@ -2468,39 +2472,43 @@ impl Connection {
|
|||
server_pk,
|
||||
) {
|
||||
log::warn!("Easy access consume response signature verify failed");
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
if !response.approved {
|
||||
log::warn!("Easy access consume denied by server");
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
match crate::decode64(&response.grant) {
|
||||
Ok(grant) if !grant.is_empty() => match EasyAccessGrant::parse_from_bytes(&grant) {
|
||||
Ok(grant) => Some(grant),
|
||||
Err(err) => {
|
||||
log::warn!("Easy access grant parse failed: {}", err);
|
||||
None
|
||||
}
|
||||
},
|
||||
Ok(_) => None,
|
||||
Err(err) => {
|
||||
log::warn!("Easy access grant payload invalid: {}", err);
|
||||
None
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
if !hbb_common::config::is_allow_easy_access() {
|
||||
return false;
|
||||
}
|
||||
let Some(ticket) = self
|
||||
.controlled_config
|
||||
.as_ref()
|
||||
.and_then(|c| c.easy_access_grant.as_ref().cloned())
|
||||
else {
|
||||
if !self.stream.is_secured() {
|
||||
log::warn!("Easy access requires a secured peer connection");
|
||||
return false;
|
||||
}
|
||||
|
||||
let grant_id = self.lr.easy_access_grant_id.clone();
|
||||
if grant_id.is_empty() {
|
||||
return false;
|
||||
};
|
||||
if ticket.version != EASY_ACCESS_GRANT_VERSION {
|
||||
log::warn!("Easy access grant version invalid: {}", ticket.version);
|
||||
return false;
|
||||
}
|
||||
if ticket.server_approval_signature.is_empty() {
|
||||
log::warn!("Easy access server approval signature missing");
|
||||
return false;
|
||||
}
|
||||
if ticket.device_bound_proof.is_empty() {
|
||||
log::warn!("Easy access device-bound proof missing");
|
||||
return false;
|
||||
}
|
||||
let lr_challenge_bytes = self.lr.easy_access_challenge.clone();
|
||||
if lr_challenge_bytes.is_empty() {
|
||||
let target_challenge = self.hash.easy_access_challenge.clone();
|
||||
if target_challenge.is_empty() {
|
||||
log::warn!("Easy access target challenge missing");
|
||||
return false;
|
||||
}
|
||||
let target_uuid = hbb_common::get_uuid();
|
||||
|
|
@ -2525,6 +2533,24 @@ impl Connection {
|
|||
return false;
|
||||
}
|
||||
};
|
||||
let Some(ticket) =
|
||||
consume_easy_access_grant(&grant_id, target_uuid.as_slice(), &target_sk, &server_pk)
|
||||
.await
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
if ticket.version != EASY_ACCESS_GRANT_VERSION {
|
||||
log::warn!("Easy access grant version invalid: {}", ticket.version);
|
||||
return false;
|
||||
}
|
||||
if ticket.server_approval_signature.is_empty() {
|
||||
log::warn!("Easy access server approval signature missing");
|
||||
return false;
|
||||
}
|
||||
if ticket.device_bound_proof.is_empty() {
|
||||
log::warn!("Easy access device-bound proof missing");
|
||||
return false;
|
||||
}
|
||||
let manager_approval_bytes = match open_easy_access_device_bound_proof(
|
||||
&ticket.device_bound_proof,
|
||||
&ticket.server_approval_signature,
|
||||
|
|
@ -2565,15 +2591,19 @@ impl Connection {
|
|||
log::warn!("Easy access target binding missing");
|
||||
return false;
|
||||
};
|
||||
if manager_approval.manager_signing_pk.is_empty() {
|
||||
log::warn!("Easy access manager signing public key missing");
|
||||
if manager_approval.manager_pk.is_empty() {
|
||||
log::warn!("Easy access manager public key missing");
|
||||
return false;
|
||||
}
|
||||
if manager_approval.manager_approval_signature.is_empty() {
|
||||
log::warn!("Easy access manager approval signature missing");
|
||||
return false;
|
||||
}
|
||||
if target_binding.challenge.as_ref() != lr_challenge_bytes.as_ref() {
|
||||
if manager_approval.manager_id.is_empty() {
|
||||
log::warn!("Easy access manager id missing");
|
||||
return false;
|
||||
}
|
||||
if target_binding.challenge.as_ref() != target_challenge.as_ref() {
|
||||
log::warn!("Easy access challenge mismatch");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2589,14 +2619,13 @@ impl Connection {
|
|||
log::warn!("Easy access grant id missing");
|
||||
return false;
|
||||
}
|
||||
let manager_signing_pk =
|
||||
match sign::PublicKey::from_slice(&manager_approval.manager_signing_pk) {
|
||||
Some(pk) => pk,
|
||||
None => {
|
||||
log::warn!("Easy access manager signing public key invalid");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
let manager_pk = match sign::PublicKey::from_slice(&manager_approval.manager_pk) {
|
||||
Some(pk) => pk,
|
||||
None => {
|
||||
log::warn!("Easy access manager public key invalid");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
let manager_approval_signature =
|
||||
match sign::Signature::from_bytes(&manager_approval.manager_approval_signature) {
|
||||
Ok(sig) => sig,
|
||||
|
|
@ -2615,19 +2644,13 @@ impl Connection {
|
|||
if !sign::verify_detached(
|
||||
&manager_approval_signature,
|
||||
&target_binding_bytes,
|
||||
&manager_signing_pk,
|
||||
&manager_pk,
|
||||
) {
|
||||
log::warn!("Easy access manager approval signature verify failed");
|
||||
return false;
|
||||
}
|
||||
if !consume_easy_access_grant(
|
||||
target_binding.grant_id.as_ref(),
|
||||
target_uuid.as_slice(),
|
||||
&target_sk,
|
||||
&server_pk,
|
||||
)
|
||||
.await
|
||||
{
|
||||
if target_binding.grant_id.as_ref() != grant_id.as_ref() {
|
||||
log::warn!("Easy access grant id mismatch");
|
||||
return false;
|
||||
}
|
||||
log::info!("Easy access grant verified");
|
||||
|
|
@ -2729,8 +2752,10 @@ impl Connection {
|
|||
}
|
||||
match lr.union {
|
||||
Some(login_request::Union::FileTransfer(ft)) => {
|
||||
if !Self::permission(keys::OPTION_ENABLE_FILE_TRANSFER, &self.controlled_config)
|
||||
{
|
||||
if !Self::permission(
|
||||
keys::OPTION_ENABLE_FILE_TRANSFER,
|
||||
&self.control_permissions,
|
||||
) {
|
||||
self.send_login_error("No permission of file transfer")
|
||||
.await;
|
||||
sleep(1.).await;
|
||||
|
|
@ -2739,7 +2764,7 @@ impl Connection {
|
|||
self.file_transfer = Some((ft.dir, ft.show_hidden));
|
||||
}
|
||||
Some(login_request::Union::ViewCamera(_vc)) => {
|
||||
if !Self::permission(keys::OPTION_ENABLE_CAMERA, &self.controlled_config) {
|
||||
if !Self::permission(keys::OPTION_ENABLE_CAMERA, &self.control_permissions) {
|
||||
self.send_login_error("No permission of viewing camera")
|
||||
.await;
|
||||
sleep(1.).await;
|
||||
|
|
@ -2748,7 +2773,7 @@ impl Connection {
|
|||
self.view_camera = true;
|
||||
}
|
||||
Some(login_request::Union::Terminal(terminal)) => {
|
||||
if !Self::permission(keys::OPTION_ENABLE_TERMINAL, &self.controlled_config) {
|
||||
if !Self::permission(keys::OPTION_ENABLE_TERMINAL, &self.control_permissions) {
|
||||
self.send_login_error("No permission of terminal").await;
|
||||
sleep(1.).await;
|
||||
return false;
|
||||
|
|
@ -2769,7 +2794,7 @@ impl Connection {
|
|||
self.terminal_service_id = terminal.service_id;
|
||||
}
|
||||
Some(login_request::Union::PortForward(mut pf)) => {
|
||||
if !Self::permission(keys::OPTION_ENABLE_TUNNEL, &self.controlled_config) {
|
||||
if !Self::permission(keys::OPTION_ENABLE_TUNNEL, &self.control_permissions) {
|
||||
self.send_login_error("No permission of IP tunneling").await;
|
||||
sleep(1.).await;
|
||||
return false;
|
||||
|
|
@ -2873,22 +2898,13 @@ impl Connection {
|
|||
&& is_logon();
|
||||
|
||||
if self.verify_easy_access().await {
|
||||
// Consume the token so it cannot be reused
|
||||
if let Some(c) = self.controlled_config.as_mut() {
|
||||
c.easy_access_signature = Default::default();
|
||||
c.manager_id = Default::default();
|
||||
}
|
||||
// Easy access: token verified, skip password validation and click accept
|
||||
if err_msg.is_empty() {
|
||||
#[cfg(target_os = "linux")]
|
||||
self.linux_headless_handle.wait_desktop_cm_ready().await;
|
||||
if !self.send_logon_response_and_keep_alive().await {
|
||||
return false;
|
||||
}
|
||||
self.try_start_cm(lr.my_id.clone(), lr.my_name.clone(), self.authorized);
|
||||
} else {
|
||||
self.send_login_error(err_msg).await;
|
||||
#[cfg(target_os = "linux")]
|
||||
self.linux_headless_handle.wait_desktop_cm_ready().await;
|
||||
if !self.send_logon_response_and_keep_alive().await {
|
||||
return false;
|
||||
}
|
||||
self.try_start_cm(lr.my_id.clone(), lr.my_name.clone(), self.authorized);
|
||||
} else if (password::approve_mode() == ApproveMode::Click
|
||||
&& !allow_logon_screen_password)
|
||||
|| password::approve_mode() == ApproveMode::Both && !password::has_valid_password()
|
||||
|
|
@ -6197,17 +6213,17 @@ impl Retina {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get control permission state from CONNECTION_CONFIG_ARRAY.
|
||||
/// Get control permission state from CONTROL_PERMISSIONS_ARRAY.
|
||||
/// Returns: Some(false) if any disable, Some(true) if any enable (and no disable), None if not set.
|
||||
pub fn get_control_permission_state(
|
||||
permission: hbb_common::rendezvous_proto::controlled_config::Permission,
|
||||
permission: hbb_common::rendezvous_proto::control_permissions::Permission,
|
||||
disable_if_has_disabled: bool,
|
||||
) -> Option<bool> {
|
||||
let controlled_configs = CONTROLLED_CONFIG_ARRAY.lock().unwrap();
|
||||
let control_permissions = CONTROL_PERMISSIONS_ARRAY.lock().unwrap();
|
||||
let mut has_enable = false;
|
||||
let mut has_disable = false;
|
||||
for (_, cc) in controlled_configs.iter() {
|
||||
match crate::get_control_permission(cc.control_permissions, permission) {
|
||||
for (_, cp) in control_permissions.iter() {
|
||||
match crate::get_control_permission(cp.permissions, permission) {
|
||||
Some(false) => has_disable = true,
|
||||
Some(true) => has_enable = true,
|
||||
None => {}
|
||||
|
|
@ -6447,30 +6463,30 @@ mod raii {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct ControlledConfigID {
|
||||
pub struct ControlPermissionsID {
|
||||
id: i32,
|
||||
controlled_config: Option<ControlledConfig>,
|
||||
control_permissions: Option<ControlPermissions>,
|
||||
}
|
||||
|
||||
impl Drop for ControlledConfigID {
|
||||
impl Drop for ControlPermissionsID {
|
||||
fn drop(&mut self) {
|
||||
if self.controlled_config.is_some() {
|
||||
let mut lock = CONTROLLED_CONFIG_ARRAY.lock().unwrap();
|
||||
if self.control_permissions.is_some() {
|
||||
let mut lock = CONTROL_PERMISSIONS_ARRAY.lock().unwrap();
|
||||
lock.retain(|(conn_id, _)| *conn_id != self.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ControlledConfigID {
|
||||
pub fn new(id: i32, controlled_config: &Option<ControlledConfig>) -> Self {
|
||||
if let Some(s) = controlled_config {
|
||||
CONTROLLED_CONFIG_ARRAY
|
||||
impl ControlPermissionsID {
|
||||
pub fn new(id: i32, control_permissions: &Option<ControlPermissions>) -> Self {
|
||||
if let Some(s) = control_permissions {
|
||||
CONTROL_PERMISSIONS_ARRAY
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push((id, s.clone()));
|
||||
}
|
||||
Self {
|
||||
id,
|
||||
controlled_config: controlled_config.clone(),
|
||||
control_permissions: control_permissions.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue