From c5201d600bb2c05a941ce9228cec030b2c60d7a2 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 1 Nov 2026 13:39:15 +0800 Subject: [PATCH] Allow trusted devices for direct IP connections (#16778) * Allow trusted devices for direct IP connections Signed-off-by: fufesou * test: preserve existing V2 trusted-device credentials Signed-off-by: fufesou --------- Signed-off-by: fufesou --- src/server/connection/trusted_devices.rs | 2 +- src/trusted_devices/client.rs | 26 ++++++++++++++++++++---- src/trusted_devices/tests.rs | 1 + src/trusted_devices/tests/credentials.rs | 23 +++++++++++++++++++++ 4 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 src/trusted_devices/tests/credentials.rs diff --git a/src/server/connection/trusted_devices.rs b/src/server/connection/trusted_devices.rs index d058a20ff..2f70374d3 100644 --- a/src/server/connection/trusted_devices.rs +++ b/src/server/connection/trusted_devices.rs @@ -9,7 +9,7 @@ use base::message_proto::LoginResponse; impl Connection { pub(super) async fn begin_trusted_device(&mut self) -> bool { if self.conn_audit_primary_auth != ConnAuditPrimaryAuth::PermanentPassword - || !self.stream.is_secured() + || (!self.stream.is_secured() && !crate::common::is_direct_ip_access(&self.lr.username)) || self.require_2fa.is_none() || self.from_switch || !hbb_common::config::Config::get_bool_option( diff --git a/src/trusted_devices/client.rs b/src/trusted_devices/client.rs index 3a52e175a..96a3ae92c 100644 --- a/src/trusted_devices/client.rs +++ b/src/trusted_devices/client.rs @@ -52,6 +52,12 @@ impl Session { secured: bool, key: Option<&[u8]>, ) -> ResultType { + if crate::common::is_direct_ip_access(login.get_id()) { + return Ok(Self { + credentials: Some(Credentials::direct_ip(login.get_id())), + ..Default::default() + }); + } let Some(key) = key.filter(|_| secured) else { return Ok(Self::default()); }; @@ -137,7 +143,7 @@ impl Session { #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] struct Issuer { namespace: String, - public_key: [u8; TOKEN_BYTES], + public_key: Option<[u8; TOKEN_BYTES]>, } #[derive(Serialize, Deserialize)] @@ -153,14 +159,26 @@ pub(super) struct Credentials { } impl Credentials { + fn direct_ip(peer_id: &str) -> Self { + Self { + peer_id: peer_id.to_owned(), + issuer: Issuer { + namespace: format!("direct-ip:{peer_id}"), + public_key: None, + }, + } + } + pub fn new(peer_id: String, namespace: String, public_key: &[u8]) -> ResultType { Ok(Self { peer_id, issuer: Issuer { namespace, - public_key: public_key - .try_into() - .map_err(|_| anyhow!("Invalid trusted host public key"))?, + public_key: Some( + public_key + .try_into() + .map_err(|_| anyhow!("Invalid trusted host public key"))?, + ), }, }) } diff --git a/src/trusted_devices/tests.rs b/src/trusted_devices/tests.rs index 6f1715c8f..109b3adbe 100644 --- a/src/trusted_devices/tests.rs +++ b/src/trusted_devices/tests.rs @@ -11,6 +11,7 @@ use hbb_common::{ use std::fs; mod configuration; +mod credentials; mod recovery; const PASSWORD: &str = "permanent-test-password"; diff --git a/src/trusted_devices/tests/credentials.rs b/src/trusted_devices/tests/credentials.rs new file mode 100644 index 000000000..312fc990a --- /dev/null +++ b/src/trusted_devices/tests/credentials.rs @@ -0,0 +1,23 @@ +use super::*; +use hbb_common::password_security::symmetric_crypt; + +#[test] +fn id_credentials_saved_before_direct_ip_support_remain_readable() { + const NAMESPACE: &str = "[\"rs.example.com\"]"; + const PUBLIC_KEY: [u8; TOKEN_BYTES] = [1; TOKEN_BYTES]; + + initialize_config(); + let peer_id = uuid::Uuid::new_v4().to_string(); + let token = random_token().unwrap(); + let saved = serde_json::json!({ + "issuer": { + "namespace": NAMESPACE, + "public_key": PUBLIC_KEY, + }, + "ciphertext": symmetric_crypt(&token, true).unwrap(), + }); + PeerConfig::set_trusted_device_v2(&peer_id, saved.to_string(), Default::default()).unwrap(); + + let credentials = Credentials::new(peer_id, NAMESPACE.into(), &PUBLIC_KEY).unwrap(); + assert_eq!(credentials.load().unwrap(), Some(token.to_vec())); +}