mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
Merge branch 'master' of https://github.com/rustdesk/rustdesk
This commit is contained in:
@@ -7,9 +7,9 @@ edition = "2018"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
protobuf = "3.0.0-alpha.2"
|
||||
tokio = { version = "1.15", features = ["full"] }
|
||||
tokio-util = { version = "0.6", features = ["full"] }
|
||||
protobuf = { version = "3.1", features = ["with-bytes"] }
|
||||
tokio = { version = "1.20", features = ["full"] }
|
||||
tokio-util = { version = "0.7", features = ["full"] }
|
||||
futures = "0.3"
|
||||
bytes = "1.1"
|
||||
log = "0.4"
|
||||
@@ -23,6 +23,7 @@ directories-next = "2.0"
|
||||
rand = "0.8"
|
||||
serde_derive = "1.0"
|
||||
serde = "1.0"
|
||||
serde_with = "1.14.0"
|
||||
lazy_static = "1.4"
|
||||
confy = { git = "https://github.com/open-trade/confy" }
|
||||
dirs-next = "2.0"
|
||||
@@ -33,12 +34,13 @@ tokio-socks = { git = "https://github.com/open-trade/tokio-socks" }
|
||||
|
||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||
mac_address = "1.1"
|
||||
machine-uid = "0.2"
|
||||
|
||||
[features]
|
||||
quic = []
|
||||
|
||||
[build-dependencies]
|
||||
protobuf-codegen-pure = "3.0.0-alpha.2"
|
||||
protobuf-codegen = { version = "3.1" }
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winapi = { version = "0.3", features = ["winuser"] }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
fn main() {
|
||||
std::fs::create_dir_all("src/protos").unwrap();
|
||||
protobuf_codegen_pure::Codegen::new()
|
||||
protobuf_codegen::Codegen::new()
|
||||
.pure()
|
||||
.out_dir("src/protos")
|
||||
.inputs(&["protos/rendezvous.proto", "protos/message.proto"])
|
||||
.include("protos")
|
||||
|
||||
@@ -63,6 +63,7 @@ message LoginRequest {
|
||||
PortForward port_forward = 8;
|
||||
}
|
||||
bool video_ack_required = 9;
|
||||
uint64 session_id = 10;
|
||||
}
|
||||
|
||||
message ChatMessage { string text = 1; }
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
use crate::log;
|
||||
use crate::{
|
||||
log,
|
||||
password_security::config::{
|
||||
decrypt_str_or_original, decrypt_vec_or_original, encrypt_str_or_original,
|
||||
encrypt_vec_or_original,
|
||||
},
|
||||
};
|
||||
use anyhow::Result;
|
||||
use directories_next::ProjectDirs;
|
||||
use rand::Rng;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
@@ -17,6 +24,7 @@ pub const CONNECT_TIMEOUT: u64 = 18_000;
|
||||
pub const REG_INTERVAL: i64 = 12_000;
|
||||
pub const COMPRESS_LEVEL: i32 = 3;
|
||||
const SERIAL: i32 = 3;
|
||||
const PASSWORD_ENC_VERSION: &'static str = "00";
|
||||
// 128x128
|
||||
#[cfg(target_os = "macos")] // 128x128 on 160x160 canvas, then shrink to 128, mac looks better with padding
|
||||
pub const ICON: &str = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAyVBMVEUAAAAAcf8Acf8Acf8Acv8Acf8Acf8Acf8Acf8AcP8Acf8Ab/8AcP8Acf////8AaP/z+f/o8v/k7v/5/v/T5f8AYP/u9v/X6f+hx/+Kuv95pP8Aef/B1/+TwP9xoP8BdP/g6P+Irv9ZmP8Bgf/E3f98q/9sn/+01f+Es/9nm/9Jif8hhv8off/M4P+syP+avP86iP/c7f+xy/9yqf9Om/9hk/9Rjv+60P99tv9fpf88lv8yjf8Tgf8deP+kvP8BiP8NeP8hkP80gP8oj2VLAAAADXRSTlMA7o7qLvnaxZ1FOxYPjH9HWgAABHJJREFUeNrtm+tW4jAQgBfwuu7MtIUWsOUiCCioIIgLiqvr+z/UHq/LJKVkmwTcc/r9E2nzlU4mSTP9lpGRkZGR8VX5cZjfL+yCEXYL+/nDH//U/Pd8DgyTy39Xbv7oIAcWyB0cqbW/sweW2NtRaj8H1sgpGOwUIAH7Bkd7YJW9dXFwAJY5WNP/cmCZQnJvzIN18on5LwfWySXlxEPYAIcad8D6PdiHDbCfIFCADVBIENiFDbCbIACKPPXrZ+cP8E6/0znvP4EymgIEravIRcTxu8HxNSJ60a8W0AYECKrlAN+YwAthCd9wm1Ug6wKzIn5SgRduXfwkqDasCjx0XFzi9PV6zwNcIuhcWBOg+ikySq8C9UD4dEKWBCoOcspvAuLHTo9sCDQiFPHotRM48j8G5gVur1FdAN2uaYEuiz7xFsgEJ2RUoMUakXuBTHHoGxQYOBhHjeUBAefEnMAowFhaLBOKuOemBBbxLRQrH2PBCgMvNCPQGMeevTb9zLrPxz2Mo+QbEaijzPUcOOHMQZkKGRAIPem39+bypREMPTkQW/oCfk866zAkiIFG4yIKRE/aAnfiSd0WrORY6pFdXQEqi9mvAQm0RIOSnoCcZ8vJoz3diCnjRk+g8VP4/fuQDJ2Lxr6WwG0gXs9aTpDzW0vgDBlVUpixR8gYk44AD8FrUKHr8JQJGgIDnoDqoALxmWPQSi9AVVzm8gKUuEPGr/QCvptwJkbSYT/TC4S8C96DGjTj86aHtAI0x2WaBIq0eSYYpRa4EsdWVVwWu9O0Aj6f6dyBMnwEraeOgSYu0wZlauzA47QCbT7DgAQSE+hZWoEBF/BBmWOewNMK3BsSqKUW4MGcWqCSVmDkbvkXGKQOwg6PAUO9oL3xXhA20yaiCjuwYygRVQlUOTWTCf2SuNJTxeFjgaHByGuAIvd8ItdPLTDhS7IuqEE1YSKVOgbayLhSFQhMzYh8hwfBs1r7c505YVIQYEdNoKwxK06MJiyrpUFHiF0NAfCQUVHoiRclIXJIR6C2fqG37pBHvcWpgwzvAtYwkR5UGV2e42UISdBJETl3mg8ouo54Rcnti1/vaT+iuUQBt500Cgo4U10BeHSkk57FB0JjWkKRMWgLUA0lLodtImAQdaMiiri3+gIAPZQoutHNsgKF1aaDMhMyIdBf8Th+Bh8MTjGWCpl5Wv43tDmnF+IUVMrcZgRoiAxhtrloYizNkZaAnF5leglbNhj0wYCAbCDvGb0mP4nib7O7ZlcYQ2m1gPtIZgVgGNNMeaVAaWR+57TrqgtUnm3sHQ+kYeE6fufUubG1ez50FXbPnWgBlgSABmN3TTcsRl2yWkHRrwbiunvk/W2+Mg1hPZplPDeXRbZzStFH15s1QIVd3UImP5z/bHpeeQLvRJ7XLFUffQIlCvqlXETQbgN9/rlYABGosv+Vi9m2Xs639YLGrZd0br+odetlvdsvbN56abfd4vbCzv9Q3v/ygoOV21A4OPpfXvH4Ai+5ZGRkZGRkbJA/t/I0QMzoMiEAAAAASUVORK5CYII=
|
||||
@@ -114,7 +122,7 @@ pub struct Config2 {
|
||||
pub options: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
|
||||
pub struct PeerConfig {
|
||||
#[serde(default)]
|
||||
pub password: Vec<u8>,
|
||||
@@ -168,7 +176,7 @@ pub struct PeerInfoSerde {
|
||||
pub platform: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
|
||||
pub struct TransferSerde {
|
||||
#[serde(default)]
|
||||
pub write_jobs: Vec<String>,
|
||||
@@ -207,7 +215,16 @@ fn patch(path: PathBuf) -> PathBuf {
|
||||
|
||||
impl Config2 {
|
||||
fn load() -> Config2 {
|
||||
Config::load_::<Config2>("2")
|
||||
let mut config = Config::load_::<Config2>("2");
|
||||
if let Some(mut socks) = config.socks {
|
||||
let (password, store) = decrypt_str_or_original(&socks.password, PASSWORD_ENC_VERSION);
|
||||
socks.password = password;
|
||||
config.socks = Some(socks);
|
||||
if store {
|
||||
config.store();
|
||||
}
|
||||
}
|
||||
config
|
||||
}
|
||||
|
||||
pub fn file() -> PathBuf {
|
||||
@@ -215,7 +232,12 @@ impl Config2 {
|
||||
}
|
||||
|
||||
fn store(&self) {
|
||||
Config::store_(self, "2");
|
||||
let mut config = self.clone();
|
||||
if let Some(mut socks) = config.socks {
|
||||
socks.password = encrypt_str_or_original(&socks.password, PASSWORD_ENC_VERSION);
|
||||
config.socks = Some(socks);
|
||||
}
|
||||
Config::store_(&config, "2");
|
||||
}
|
||||
|
||||
pub fn get() -> Config2 {
|
||||
@@ -267,11 +289,19 @@ impl Config {
|
||||
}
|
||||
|
||||
fn load() -> Config {
|
||||
Config::load_::<Config>("")
|
||||
let mut config = Config::load_::<Config>("");
|
||||
let (password, store) = decrypt_str_or_original(&config.password, PASSWORD_ENC_VERSION);
|
||||
config.password = password;
|
||||
if store {
|
||||
config.store();
|
||||
}
|
||||
config
|
||||
}
|
||||
|
||||
fn store(&self) {
|
||||
Config::store_(self, "");
|
||||
let mut config = self.clone();
|
||||
config.password = encrypt_str_or_original(&config.password, PASSWORD_ENC_VERSION);
|
||||
Config::store_(&config, "");
|
||||
}
|
||||
|
||||
pub fn file() -> PathBuf {
|
||||
@@ -627,7 +657,7 @@ impl Config {
|
||||
log::info!("id updated from {} to {}", id, new_id);
|
||||
}
|
||||
|
||||
pub fn set_password(password: &str) {
|
||||
pub fn set_security_password(password: &str) {
|
||||
let mut config = CONFIG.write().unwrap();
|
||||
if password == config.password {
|
||||
return;
|
||||
@@ -636,13 +666,8 @@ impl Config {
|
||||
config.store();
|
||||
}
|
||||
|
||||
pub fn get_password() -> String {
|
||||
let mut password = CONFIG.read().unwrap().password.clone();
|
||||
if password.is_empty() {
|
||||
password = Config::get_auto_password();
|
||||
Config::set_password(&password);
|
||||
}
|
||||
password
|
||||
pub fn get_security_password() -> String {
|
||||
CONFIG.read().unwrap().password.clone()
|
||||
}
|
||||
|
||||
pub fn set_salt(salt: &str) {
|
||||
@@ -714,7 +739,28 @@ impl PeerConfig {
|
||||
pub fn load(id: &str) -> PeerConfig {
|
||||
let _ = CONFIG.read().unwrap(); // for lock
|
||||
match confy::load_path(&Self::path(id)) {
|
||||
Ok(config) => config,
|
||||
Ok(config) => {
|
||||
let mut config: PeerConfig = config;
|
||||
let mut store = false;
|
||||
let (password, store2) =
|
||||
decrypt_vec_or_original(&config.password, PASSWORD_ENC_VERSION);
|
||||
config.password = password;
|
||||
store = store || store2;
|
||||
config.options.get_mut("rdp_password").map(|v| {
|
||||
let (password, store2) = decrypt_str_or_original(v, PASSWORD_ENC_VERSION);
|
||||
*v = password;
|
||||
store = store || store2;
|
||||
});
|
||||
config.options.get_mut("os-password").map(|v| {
|
||||
let (password, store2) = decrypt_str_or_original(v, PASSWORD_ENC_VERSION);
|
||||
*v = password;
|
||||
store = store || store2;
|
||||
});
|
||||
if store {
|
||||
config.store(id);
|
||||
}
|
||||
config
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("Failed to load config: {}", err);
|
||||
Default::default()
|
||||
@@ -724,7 +770,17 @@ impl PeerConfig {
|
||||
|
||||
pub fn store(&self, id: &str) {
|
||||
let _ = CONFIG.read().unwrap(); // for lock
|
||||
if let Err(err) = confy::store_path(Self::path(id), self) {
|
||||
let mut config = self.clone();
|
||||
config.password = encrypt_vec_or_original(&config.password, PASSWORD_ENC_VERSION);
|
||||
config
|
||||
.options
|
||||
.get_mut("rdp_password")
|
||||
.map(|v| *v = encrypt_str_or_original(v, PASSWORD_ENC_VERSION));
|
||||
config
|
||||
.options
|
||||
.get_mut("os-password")
|
||||
.map(|v| *v = encrypt_str_or_original(v, PASSWORD_ENC_VERSION));
|
||||
if let Err(err) = confy::store_path(Self::path(id), config) {
|
||||
log::error!("Failed to store config: {}", err);
|
||||
}
|
||||
}
|
||||
@@ -856,10 +912,26 @@ impl LocalConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
pub struct DiscoveryPeer {
|
||||
pub id: String,
|
||||
#[serde(with = "serde_with::rust::map_as_tuple_list")]
|
||||
pub ip_mac: HashMap<String, String>,
|
||||
pub username: String,
|
||||
pub hostname: String,
|
||||
pub platform: String,
|
||||
pub online: bool,
|
||||
}
|
||||
|
||||
impl DiscoveryPeer {
|
||||
pub fn is_same_peer(&self, other: &DiscoveryPeer) -> bool {
|
||||
self.id == other.id && self.username == other.username
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
pub struct LanPeers {
|
||||
#[serde(default)]
|
||||
pub peers: String,
|
||||
pub peers: Vec<DiscoveryPeer>,
|
||||
}
|
||||
|
||||
impl LanPeers {
|
||||
@@ -874,8 +946,10 @@ impl LanPeers {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn store(peers: String) {
|
||||
let f = LanPeers { peers };
|
||||
pub fn store(peers: &Vec<DiscoveryPeer>) {
|
||||
let f = LanPeers {
|
||||
peers: peers.clone(),
|
||||
};
|
||||
if let Err(err) = confy::store_path(Config::file_("_lan_peers"), f) {
|
||||
log::error!("Failed to store lan peers: {}", err);
|
||||
}
|
||||
|
||||
@@ -573,7 +573,7 @@ impl TransferJob {
|
||||
log::info!("file num truncated, ignoring");
|
||||
} else {
|
||||
match r.union {
|
||||
Some(file_transfer_send_confirm_request::Union::skip(s)) => {
|
||||
Some(file_transfer_send_confirm_request::Union::Skip(s)) => {
|
||||
if s {
|
||||
log::debug!("skip file id:{}, file_num:{}", r.id, r.file_num);
|
||||
self.skip_current_file();
|
||||
@@ -581,7 +581,7 @@ impl TransferJob {
|
||||
self.set_file_confirmed(true);
|
||||
}
|
||||
}
|
||||
Some(file_transfer_send_confirm_request::Union::offset_blk(_offset)) => {
|
||||
Some(file_transfer_send_confirm_request::Union::OffsetBlk(_offset)) => {
|
||||
self.set_file_confirmed(true);
|
||||
}
|
||||
_ => {}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
pub mod compress;
|
||||
#[path = "./protos/message.rs"]
|
||||
pub mod message_proto;
|
||||
#[path = "./protos/rendezvous.rs"]
|
||||
pub mod rendezvous_proto;
|
||||
pub mod protos;
|
||||
pub mod platform;
|
||||
pub use protos::message as message_proto;
|
||||
pub use protos::rendezvous as rendezvous_proto;
|
||||
pub use bytes;
|
||||
use config::Config;
|
||||
pub use futures;
|
||||
pub use protobuf;
|
||||
use std::{
|
||||
@@ -27,6 +28,7 @@ pub use anyhow::{self, bail};
|
||||
pub use futures_util;
|
||||
pub mod config;
|
||||
pub mod fs;
|
||||
pub use lazy_static;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
pub use mac_address;
|
||||
pub use rand;
|
||||
@@ -35,7 +37,7 @@ pub use sodiumoxide;
|
||||
pub use tokio_socks;
|
||||
pub use tokio_socks::IntoTargetAddr;
|
||||
pub use tokio_socks::TargetAddr;
|
||||
pub use lazy_static;
|
||||
pub mod password_security;
|
||||
|
||||
#[cfg(feature = "quic")]
|
||||
pub type Stream = quic::Connection;
|
||||
@@ -200,6 +202,14 @@ pub fn get_modified_time(path: &std::path::Path) -> SystemTime {
|
||||
.unwrap_or(UNIX_EPOCH)
|
||||
}
|
||||
|
||||
pub fn get_uuid() -> Vec<u8> {
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
if let Ok(id) = machine_uid::get() {
|
||||
return id.into();
|
||||
}
|
||||
Config::get_key_pair().1
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
330
libs/hbb_common/src/password_security.rs
Normal file
330
libs/hbb_common/src/password_security.rs
Normal file
@@ -0,0 +1,330 @@
|
||||
pub mod password {
|
||||
use crate::config::Config;
|
||||
use std::{
|
||||
fmt::Display,
|
||||
str::FromStr,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref RANDOM_PASSWORD:Arc<RwLock<String>> = Arc::new(RwLock::new(Config::get_auto_password()));
|
||||
}
|
||||
|
||||
const SECURITY_ENABLED: &'static str = "security-password-enabled";
|
||||
const RANDOM_ENABLED: &'static str = "random-password-enabled";
|
||||
const ONETIME_ENABLED: &'static str = "onetime-password-enabled";
|
||||
const ONETIME_ACTIVATED: &'static str = "onetime-password-activated";
|
||||
const UPDATE_METHOD: &'static str = "random-password-update-method";
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum UpdateMethod {
|
||||
KEEP,
|
||||
UPDATE,
|
||||
DISABLE,
|
||||
}
|
||||
|
||||
impl FromStr for UpdateMethod {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if s == "KEEP" {
|
||||
Ok(Self::KEEP)
|
||||
} else if s == "UPDATE" {
|
||||
Ok(Self::UPDATE)
|
||||
} else if s == "DISABLE" {
|
||||
Ok(Self::DISABLE)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for UpdateMethod {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
UpdateMethod::KEEP => write!(f, "KEEP"),
|
||||
UpdateMethod::UPDATE => write!(f, "UPDATE"),
|
||||
UpdateMethod::DISABLE => write!(f, "DISABLE"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_random_password(password: &str) {
|
||||
*RANDOM_PASSWORD.write().unwrap() = password.to_owned();
|
||||
}
|
||||
|
||||
pub fn random_password() -> String {
|
||||
let mut password = RANDOM_PASSWORD.read().unwrap().clone();
|
||||
if password.is_empty() {
|
||||
password = Config::get_auto_password();
|
||||
set_random_password(&password);
|
||||
}
|
||||
password
|
||||
}
|
||||
|
||||
pub fn random_password_valid() -> bool {
|
||||
if random_enabled() {
|
||||
onetime_password_activated() || !onetime_password_enabled()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn passwords() -> Vec<String> {
|
||||
let mut v = vec![];
|
||||
if random_password_valid() {
|
||||
v.push(random_password());
|
||||
}
|
||||
if security_enabled() {
|
||||
v.push(Config::get_security_password());
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
pub fn after_session(authorized: bool) {
|
||||
if authorized && random_enabled() {
|
||||
UpdateMethod::from_str(&update_method())
|
||||
.map(|method| match method {
|
||||
UpdateMethod::KEEP => {}
|
||||
UpdateMethod::UPDATE => set_random_password(&Config::get_auto_password()),
|
||||
UpdateMethod::DISABLE => set_random_enabled(false),
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_method() -> String {
|
||||
let mut method = Config::get_option(UPDATE_METHOD);
|
||||
if UpdateMethod::from_str(&method).is_err() {
|
||||
method = UpdateMethod::KEEP.to_string(); // default is keep
|
||||
set_update_method(&method);
|
||||
}
|
||||
method
|
||||
}
|
||||
|
||||
pub fn set_update_method(method: &str) {
|
||||
Config::set_option(UPDATE_METHOD.to_owned(), method.to_owned());
|
||||
}
|
||||
|
||||
pub fn random_enabled() -> bool {
|
||||
str2bool(RANDOM_ENABLED, true, || {
|
||||
set_onetime_password_activated(false);
|
||||
set_random_password(&Config::get_auto_password());
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_random_enabled(enabled: bool) {
|
||||
if enabled != random_enabled() {
|
||||
Config::set_option(RANDOM_ENABLED.to_owned(), bool2str(enabled));
|
||||
set_onetime_password_activated(false);
|
||||
if enabled {
|
||||
set_random_password(&Config::get_auto_password());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn security_enabled() -> bool {
|
||||
str2bool(SECURITY_ENABLED, true, || {})
|
||||
}
|
||||
|
||||
pub fn set_security_enabled(enabled: bool) {
|
||||
if enabled != security_enabled() {
|
||||
Config::set_option(SECURITY_ENABLED.to_owned(), bool2str(enabled));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn onetime_password_enabled() -> bool {
|
||||
str2bool(ONETIME_ENABLED, false, || {
|
||||
set_onetime_password_activated(false);
|
||||
set_random_password(&Config::get_auto_password());
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_onetime_password_enabled(enabled: bool) {
|
||||
if enabled != onetime_password_enabled() {
|
||||
Config::set_option(ONETIME_ENABLED.to_owned(), bool2str(enabled));
|
||||
set_onetime_password_activated(false);
|
||||
set_random_password(&Config::get_auto_password());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn onetime_password_activated() -> bool {
|
||||
str2bool(ONETIME_ACTIVATED, false, || {})
|
||||
}
|
||||
|
||||
pub fn set_onetime_password_activated(activated: bool) {
|
||||
if activated != onetime_password_activated() {
|
||||
Config::set_option(ONETIME_ACTIVATED.to_owned(), bool2str(activated));
|
||||
if activated {
|
||||
set_random_password(&Config::get_auto_password());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// notice: Function nesting
|
||||
fn str2bool(key: &str, default: bool, default_set: impl Fn()) -> bool {
|
||||
let option = Config::get_option(key);
|
||||
if option == "Y" {
|
||||
true
|
||||
} else if option == "N" {
|
||||
false
|
||||
} else {
|
||||
Config::set_option(key.to_owned(), bool2str(default));
|
||||
default_set();
|
||||
default
|
||||
}
|
||||
}
|
||||
|
||||
fn bool2str(option: bool) -> String {
|
||||
if option { "Y" } else { "N" }.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
pub mod config {
|
||||
use super::base64::decrypt as decrypt00;
|
||||
use super::base64::encrypt as encrypt00;
|
||||
|
||||
const VERSION_LEN: usize = 2;
|
||||
|
||||
pub fn encrypt_str_or_original(s: &str, version: &str) -> String {
|
||||
if version.len() == VERSION_LEN {
|
||||
if version == "00" {
|
||||
if let Ok(s) = encrypt00(s.as_bytes()) {
|
||||
return version.to_owned() + &s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s.to_owned()
|
||||
}
|
||||
|
||||
// bool: whether should store to re-encrypt when load
|
||||
pub fn decrypt_str_or_original(s: &str, current_version: &str) -> (String, bool) {
|
||||
if s.len() > VERSION_LEN {
|
||||
let version = &s[..VERSION_LEN];
|
||||
if version == "00" {
|
||||
if let Ok(v) = decrypt00(&s[VERSION_LEN..].as_bytes()) {
|
||||
return (
|
||||
String::from_utf8_lossy(&v).to_string(),
|
||||
version != current_version,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(s.to_owned(), !s.is_empty())
|
||||
}
|
||||
|
||||
pub fn encrypt_vec_or_original(v: &[u8], version: &str) -> Vec<u8> {
|
||||
if version.len() == VERSION_LEN {
|
||||
if version == "00" {
|
||||
if let Ok(s) = encrypt00(v) {
|
||||
let mut version = version.to_owned().into_bytes();
|
||||
version.append(&mut s.into_bytes());
|
||||
return version;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v.to_owned()
|
||||
}
|
||||
|
||||
// bool: whether should store to re-encrypt when load
|
||||
pub fn decrypt_vec_or_original(v: &[u8], current_version: &str) -> (Vec<u8>, bool) {
|
||||
if v.len() > VERSION_LEN {
|
||||
let version = String::from_utf8_lossy(&v[..VERSION_LEN]);
|
||||
if version == "00" {
|
||||
if let Ok(v) = decrypt00(&v[VERSION_LEN..]) {
|
||||
return (v, version != current_version);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(v.to_owned(), !v.is_empty())
|
||||
}
|
||||
|
||||
mod test {
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
use crate::password_security::config::*;
|
||||
|
||||
println!("test str");
|
||||
let data = "Hello World";
|
||||
let encrypted = encrypt_str_or_original(data, "00");
|
||||
let (decrypted, store) = decrypt_str_or_original(&encrypted, "00");
|
||||
println!("data: {}", data);
|
||||
println!("encrypted: {}", encrypted);
|
||||
println!("decrypted: {}", decrypted);
|
||||
assert_eq!(data, decrypted);
|
||||
assert_eq!("00", &encrypted[..2]);
|
||||
assert_eq!(store, false);
|
||||
let (_, store2) = decrypt_str_or_original(&encrypted, "01");
|
||||
assert_eq!(store2, true);
|
||||
|
||||
println!("test vec");
|
||||
let data: Vec<u8> = vec![1, 2, 3, 4];
|
||||
let encrypted = encrypt_vec_or_original(&data, "00");
|
||||
let (decrypted, store) = decrypt_vec_or_original(&encrypted, "00");
|
||||
println!("data: {:?}", data);
|
||||
println!("encrypted: {:?}", encrypted);
|
||||
println!("decrypted: {:?}", decrypted);
|
||||
assert_eq!(data, decrypted);
|
||||
assert_eq!("00".as_bytes(), &encrypted[..2]);
|
||||
assert_eq!(store, false);
|
||||
let (_, store2) = decrypt_vec_or_original(&encrypted, "01");
|
||||
assert_eq!(store2, true);
|
||||
|
||||
println!("test old");
|
||||
let data = "00Hello World";
|
||||
let (decrypted, store) = decrypt_str_or_original(&data, "00");
|
||||
assert_eq!(data, decrypted);
|
||||
assert_eq!(store, true);
|
||||
let data: Vec<u8> = vec!['0' as u8, '0' as u8, 1, 2, 3, 4];
|
||||
let (decrypted, store) = decrypt_vec_or_original(&data, "00");
|
||||
assert_eq!(data, decrypted);
|
||||
assert_eq!(store, true);
|
||||
let (_, store) = decrypt_str_or_original("", "00");
|
||||
assert_eq!(store, false);
|
||||
let (_, store) = decrypt_vec_or_original(&vec![], "00");
|
||||
assert_eq!(store, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod base64 {
|
||||
use super::symmetric_crypt;
|
||||
use sodiumoxide::base64;
|
||||
|
||||
pub fn encrypt(v: &[u8]) -> Result<String, ()> {
|
||||
if v.len() > 0 {
|
||||
symmetric_crypt(v, true).map(|v| base64::encode(v, base64::Variant::Original))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decrypt(v: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
if v.len() > 0 {
|
||||
base64::decode(v, base64::Variant::Original).and_then(|v| symmetric_crypt(&v, false))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn symmetric_crypt(data: &[u8], encrypt: bool) -> Result<Vec<u8>, ()> {
|
||||
use sodiumoxide::crypto::secretbox;
|
||||
use std::convert::TryInto;
|
||||
|
||||
let mut keybuf = crate::get_uuid();
|
||||
keybuf.resize(secretbox::KEYBYTES, 0);
|
||||
let key = secretbox::Key(keybuf.try_into().map_err(|_| ())?);
|
||||
let nonce = secretbox::Nonce([0; secretbox::NONCEBYTES]);
|
||||
|
||||
if encrypt {
|
||||
Ok(secretbox::seal(data, &nonce, &key))
|
||||
} else {
|
||||
secretbox::open(data, &nonce, &key)
|
||||
}
|
||||
}
|
||||
102
libs/hbb_common/src/platform/linux.rs
Normal file
102
libs/hbb_common/src/platform/linux.rs
Normal file
@@ -0,0 +1,102 @@
|
||||
use crate::ResultType;
|
||||
|
||||
pub fn get_display_server() -> String {
|
||||
let session = get_value_of_seat0(0);
|
||||
get_display_server_of_session(&session)
|
||||
}
|
||||
|
||||
fn get_display_server_of_session(session: &str) -> String {
|
||||
if let Ok(output) = std::process::Command::new("loginctl")
|
||||
.args(vec!["show-session", "-p", "Type", session])
|
||||
.output()
|
||||
// Check session type of the session
|
||||
{
|
||||
let display_server = String::from_utf8_lossy(&output.stdout)
|
||||
.replace("Type=", "")
|
||||
.trim_end()
|
||||
.into();
|
||||
if display_server == "tty" {
|
||||
// If the type is tty...
|
||||
if let Ok(output) = std::process::Command::new("loginctl")
|
||||
.args(vec!["show-session", "-p", "TTY", session])
|
||||
.output()
|
||||
// Get the tty number
|
||||
{
|
||||
let tty: String = String::from_utf8_lossy(&output.stdout)
|
||||
.replace("TTY=", "")
|
||||
.trim_end()
|
||||
.into();
|
||||
if let Ok(xorg_results) = run_cmds(format!("ps -e | grep \"{}.\\\\+Xorg\"", tty))
|
||||
// And check if Xorg is running on that tty
|
||||
{
|
||||
if xorg_results.trim_end().to_string() != "" {
|
||||
// If it is, manually return "x11", otherwise return tty
|
||||
"x11".to_owned()
|
||||
} else {
|
||||
display_server
|
||||
}
|
||||
} else {
|
||||
// If any of these commands fail just fall back to the display server
|
||||
display_server
|
||||
}
|
||||
} else {
|
||||
display_server
|
||||
}
|
||||
} else {
|
||||
// If the session is not a tty, then just return the type as usual
|
||||
display_server
|
||||
}
|
||||
} else {
|
||||
"".to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_value_of_seat0(i: usize) -> String {
|
||||
if let Ok(output) = std::process::Command::new("loginctl").output() {
|
||||
for line in String::from_utf8_lossy(&output.stdout).lines() {
|
||||
if line.contains("seat0") {
|
||||
if let Some(sid) = line.split_whitespace().nth(0) {
|
||||
if is_active(sid) {
|
||||
if let Some(uid) = line.split_whitespace().nth(i) {
|
||||
return uid.to_owned();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// some case, there is no seat0 https://github.com/rustdesk/rustdesk/issues/73
|
||||
if let Ok(output) = std::process::Command::new("loginctl").output() {
|
||||
for line in String::from_utf8_lossy(&output.stdout).lines() {
|
||||
if let Some(sid) = line.split_whitespace().nth(0) {
|
||||
let d = get_display_server_of_session(sid);
|
||||
if is_active(sid) && d != "tty" {
|
||||
if let Some(uid) = line.split_whitespace().nth(i) {
|
||||
return uid.to_owned();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "".to_owned();
|
||||
}
|
||||
|
||||
fn is_active(sid: &str) -> bool {
|
||||
if let Ok(output) = std::process::Command::new("loginctl")
|
||||
.args(vec!["show-session", "-p", "State", sid])
|
||||
.output()
|
||||
{
|
||||
String::from_utf8_lossy(&output.stdout).contains("active")
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_cmds(cmds: String) -> ResultType<String> {
|
||||
let output = std::process::Command::new("sh")
|
||||
.args(vec!["-c", &cmds])
|
||||
.output()?;
|
||||
Ok(String::from_utf8_lossy(&output.stdout).to_string())
|
||||
}
|
||||
2
libs/hbb_common/src/platform/mod.rs
Normal file
2
libs/hbb_common/src/platform/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod linux;
|
||||
@@ -27,6 +27,8 @@ fn new_socket(addr: SocketAddr, reuse: bool, buf_size: usize) -> Result<Socket,
|
||||
socket.set_reuse_port(true)?;
|
||||
socket.set_reuse_address(true)?;
|
||||
}
|
||||
// only nonblocking work with tokio, https://stackoverflow.com/questions/64649405/receiver-on-tokiompscchannel-only-receives-messages-when-buffer-is-full
|
||||
socket.set_nonblocking(true)?;
|
||||
if buf_size > 0 {
|
||||
socket.set_recv_buffer_size(buf_size).ok();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user