Merge branch 'master' into master

This commit is contained in:
RustDesk 2023-01-28 15:22:59 +08:00 committed by GitHub
commit c8f38c9386
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 1135 additions and 1032 deletions

View File

@ -13,8 +13,7 @@ on:
env:
LLVM_VERSION: "15.0.6"
# Note: currently 3.0.5 does not support arm64 officially, we use latest stable version first.
FLUTTER_VERSION: "3.0.5"
FLUTTER_VERSION: "3.7.0"
# vcpkg version: 2022.05.10
# for multiarch gcc compatibility
VCPKG_COMMIT_ID: "14e7bb4ae24616ec54ff6b2f6ef4e8659434ea44"
@ -28,7 +27,7 @@ jobs:
fail-fast: true
matrix:
job:
- { target: i686-pc-windows-msvc , os: windows-2019 }
# - { target: i686-pc-windows-msvc , os: windows-2019 }
# - { target: x86_64-pc-windows-gnu , os: windows-2019 }
- { target: x86_64-pc-windows-msvc, os: windows-2019 }
steps:
@ -51,9 +50,9 @@ jobs:
run: |
flutter doctor -v
flutter precache --windows
Invoke-WebRequest -Uri https://github.com/Kingtous/engine/releases/download/v3.0.5-rustdesk.2/windows-x64-flutter-release.zip -OutFile windows-x64-flutter-release.zip
Invoke-WebRequest -Uri https://github.com/Kingtous/engine/releases/download/v3.7.0-rustdesk/windows-x64-release-flutter.zip -OutFile windows-x64-flutter-release.zip
Expand-Archive windows-x64-flutter-release.zip -DestinationPath engine
mv -Force engine/* C:/hostedtoolcache/windows/flutter/stable-3.0.5-x64/bin/cache/artifacts/engine/windows-x64-release/
mv -Force engine/* C:/hostedtoolcache/windows/flutter/stable-${{ env.FLUTTER_VERSION }}-x64/bin/cache/artifacts/engine/windows-x64-release/
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
@ -837,12 +836,12 @@ jobs:
# disable git safe.directory
git config --global --add safe.directory "*"
pushd /opt
# clone repo and reset to flutter 3.0.5
# clone repo and reset to flutter 3.7.0
git clone https://github.com/sony/flutter-elinux.git || true
pushd flutter-elinux
# reset to flutter 3.0.5
# reset to flutter 3.7.0
git fetch
git reset --hard b09a90eee643859ce4e676839227edd9fd3feba8
git reset --hard 51a1d685901f79fbac51665a967c3a1a789ecee5
popd
- uses: Kingtous/run-on-arch-action@amd64-support
@ -867,11 +866,17 @@ jobs:
git config --global --add safe.directory "*"
pushd /workspace
# we use flutter-elinux to build our rustdesk
sed -i "s/flutter build linux --release/flutter-elinux build linux/g" ./build.py
# Setup flutter-elinux
export PATH=/opt/flutter-elinux/bin:$PATH
sed -i "s/flutter build linux --release/flutter-elinux build linux/g" ./build.py
# Setup flutter-elinux. Run doctor to check if issues here.
flutter-elinux doctor -v
# edit to corresponding arch
# Patch arm64 engine for flutter 3.6.0+
flutter-elinux precache --linux
pushd /tmp
curl -O https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.7.0-stable.tar.xz
tar -xvf flutter_linux_3.7.0-stable.tar.xz flutter/bin/cache/artifacts/engine/linux-x64/shader_lib
cp -R flutter/bin/cache/artifacts/engine/linux-x64/shader_lib /opt/flutter-elinux/flutter/bin/cache/artifacts/engine/linux-arm64
popd
case ${{ matrix.job.arch }} in
aarch64)
sed -i "s/Architecture: amd64/Architecture: arm64/g" ./build.py

View File

@ -8,8 +8,7 @@ on:
env:
LLVM_VERSION: "15.0.6"
# Note: currently 3.0.5 does not support arm64 officially, we use latest stable version first.
FLUTTER_VERSION: "3.0.5"
FLUTTER_VERSION: "3.7.0"
TAG_NAME: "nightly"
# vcpkg version: 2022.05.10
# for multiarch gcc compatibility
@ -53,9 +52,9 @@ jobs:
run: |
flutter doctor -v
flutter precache --windows
Invoke-WebRequest -Uri https://github.com/Kingtous/engine/releases/download/v3.0.5-rustdesk.2/windows-x64-flutter-release.zip -OutFile windows-x64-flutter-release.zip
Invoke-WebRequest -Uri https://github.com/Kingtous/engine/releases/download/v3.7.0-rustdesk/windows-x64-release-flutter.zip -OutFile windows-x64-flutter-release.zip
Expand-Archive windows-x64-flutter-release.zip -DestinationPath engine
mv -Force engine/* C:/hostedtoolcache/windows/flutter/stable-3.0.5-x64/bin/cache/artifacts/engine/windows-x64-release/
mv -Force engine/* C:/hostedtoolcache/windows/flutter/stable-${{ env.FLUTTER_VERSION }}-x64/bin/cache/artifacts/engine/windows-x64-release/
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
@ -983,12 +982,12 @@ jobs:
# disable git safe.directory
git config --global --add safe.directory "*"
pushd /opt
# clone repo and reset to flutter 3.0.5
# clone repo and reset to flutter 3.7.0
git clone https://github.com/sony/flutter-elinux.git || true
pushd flutter-elinux
# reset to flutter 3.0.5
# reset to flutter 3.7.0
git fetch
git reset --hard b09a90eee643859ce4e676839227edd9fd3feba8
git reset --hard 51a1d685901f79fbac51665a967c3a1a789ecee5
popd
- uses: Kingtous/run-on-arch-action@amd64-support
@ -1013,10 +1012,17 @@ jobs:
git config --global --add safe.directory "*"
pushd /workspace
# we use flutter-elinux to build our rustdesk
sed -i "s/flutter build linux --release/flutter-elinux build linux/g" ./build.py
# Setup flutter-elinux
export PATH=/opt/flutter-elinux/bin:$PATH
sed -i "s/flutter build linux --release/flutter-elinux build linux/g" ./build.py
# Setup flutter-elinux. Run doctor to check if issues here.
flutter-elinux doctor -v
# Patch arm64 engine for flutter 3.6.0+
flutter-elinux precache --linux
pushd /tmp
curl -O https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.7.0-stable.tar.xz
tar -xvf flutter_linux_3.7.0-stable.tar.xz flutter/bin/cache/artifacts/engine/linux-x64/shader_lib
cp -R flutter/bin/cache/artifacts/engine/linux-x64/shader_lib /opt/flutter-elinux/flutter/bin/cache/artifacts/engine/linux-arm64
popd
# edit to corresponding arch
case ${{ matrix.job.arch }} in
aarch64)

2
Cargo.lock generated
View File

@ -4371,7 +4371,7 @@ dependencies = [
[[package]]
name = "rdev"
version = "0.5.0-2"
source = "git+https://github.com/fufesou/rdev#1be26c7e8ed0d43cebdd8331d467bb61130a2e6e"
source = "git+https://github.com/fufesou/rdev#238c9778da40056e2efda1e4264355bc89fb6358"
dependencies = [
"cocoa",
"core-foundation 0.9.3",

View File

@ -1092,21 +1092,21 @@ Widget getOnline(double rightPadding, bool online) {
}
class ActionMore extends StatelessWidget {
final RxBool _iconMoreHover = false.obs;
final RxBool _hover = false.obs;
@override
Widget build(BuildContext context) {
return MouseRegion(
onEnter: (_) => _iconMoreHover.value = true,
onExit: (_) => _iconMoreHover.value = false,
return InkWell(
onTap: () {},
onHover: (value) => _hover.value = value,
child: Obx(() => CircleAvatar(
radius: 14,
backgroundColor: _iconMoreHover.value
backgroundColor: _hover.value
? Theme.of(context).scaffoldBackgroundColor
: Theme.of(context).backgroundColor,
child: Icon(Icons.more_vert,
size: 18,
color: _iconMoreHover.value
color: _hover.value
? Theme.of(context).textTheme.titleLarge?.color
: Theme.of(context)
.textTheme

View File

@ -652,8 +652,7 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
dismissOnClicked: true,
));
}
if (false &&
pi.platform != kPeerPlatformAndroid &&
if (pi.platform != kPeerPlatformAndroid &&
version_cmp(peer_version, '1.2.0') >= 0) {
displayMenu.add(MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text(

View File

@ -1,4 +1,5 @@
import 'dart:convert';
import 'dart:io';
import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/foundation.dart';
@ -63,8 +64,10 @@ class RustDeskMultiWindowManager {
..setFrame(const Offset(0, 0) & const Size(1280, 720))
..center()
..setTitle(getWindowNameWithId(remoteId,
overrideType: WindowType.RemoteDesktop))
..show();
overrideType: WindowType.RemoteDesktop));
if (Platform.isMacOS) {
Future.microtask(() => remoteDesktopController.show());
}
registerActiveWindow(remoteDesktopController.windowId);
_remoteDesktopWindowId = remoteDesktopController.windowId;
} else {
@ -90,8 +93,10 @@ class RustDeskMultiWindowManager {
..setFrame(const Offset(0, 0) & const Size(1280, 720))
..center()
..setTitle(getWindowNameWithId(remoteId,
overrideType: WindowType.FileTransfer))
..show();
overrideType: WindowType.FileTransfer));
if (Platform.isMacOS) {
Future.microtask(() => fileTransferController.show());
}
registerActiveWindow(fileTransferController.windowId);
_fileTransferWindowId = fileTransferController.windowId;
} else {
@ -116,9 +121,11 @@ class RustDeskMultiWindowManager {
portForwardController
..setFrame(const Offset(0, 0) & const Size(1280, 720))
..center()
..setTitle(
getWindowNameWithId(remoteId, overrideType: WindowType.PortForward))
..show();
..setTitle(getWindowNameWithId(remoteId,
overrideType: WindowType.PortForward));
if (Platform.isMacOS) {
Future.microtask(() => portForwardController.show());
}
registerActiveWindow(portForwardController.windowId);
_portForwardWindowId = portForwardController.windowId;
} else {

View File

@ -7,7 +7,7 @@ import desktop_drop
import device_info_plus_macos
import flutter_custom_cursor
import package_info_plus_macos
import path_provider_macos
import path_provider_foundation
import screen_retriever
import sqflite
// import tray_manager

View File

@ -31,7 +31,7 @@ dependencies:
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.3
ffi: ^2.0.1
path_provider: ^2.0.2
path_provider: ^2.0.12
external_path: ^1.0.1
provider: ^6.0.3
tuple: ^2.0.0
@ -75,14 +75,14 @@ dependencies:
debounce_throttle: ^2.0.0
file_picker: ^5.1.0
flutter_svg: ^1.1.5
flutter_improved_scrolling: ^0.0.3
flutter_improved_scrolling:
# currently, we use flutter 3.0.5 for windows build, latest for other builds.
#
# for flutter 3.0.5, please use official version(just comment code below).
# if build rustdesk by flutter >=3.3, please use our custom pub below (uncomment code below).
# git:
# url: https://github.com/Kingtous/flutter_improved_scrolling
# ref: 62f09545149f320616467c306c8c5f71714a18e6
git:
url: https://github.com/Kingtous/flutter_improved_scrolling
ref: 62f09545149f320616467c306c8c5f71714a18e6
uni_links: ^0.5.1
uni_links_desktop: ^0.1.4
path: ^1.8.1

View File

@ -8,10 +8,7 @@ fn main() {
.out_dir(out_dir)
.inputs(&["protos/rendezvous.proto", "protos/message.proto"])
.include("protos")
.customize(
protobuf_codegen::Customize::default()
.tokio_bytes(true)
)
.customize(protobuf_codegen::Customize::default().tokio_bytes(true))
.run()
.expect("Codegen failed.");
}

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,12 @@ enum DecodeState {
Data(usize),
}
impl Default for BytesCodec {
fn default() -> Self {
Self::new()
}
}
impl BytesCodec {
pub fn new() -> Self {
Self {
@ -56,7 +62,7 @@ impl BytesCodec {
}
src.advance(head_len);
src.reserve(n);
return Ok(Some(n));
Ok(Some(n))
}
fn decode_data(&self, n: usize, src: &mut BytesMut) -> io::Result<Option<BytesMut>> {

View File

@ -32,12 +32,7 @@ pub fn decompress(data: &[u8]) -> Vec<u8> {
const MAX: usize = 1024 * 1024 * 64;
const MIN: usize = 1024 * 1024;
let mut n = 30 * data.len();
if n > MAX {
n = MAX;
}
if n < MIN {
n = MIN;
}
n = n.clamp(MIN, MAX);
match d.decompress(data, n) {
Ok(res) => out = res,
Err(err) => {

View File

@ -29,7 +29,7 @@ pub const READ_TIMEOUT: u64 = 30_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";
const PASSWORD_ENC_VERSION: &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=
@ -43,6 +43,7 @@ lazy_static::lazy_static! {
}
type Size = (i32, i32, i32, i32);
type KeyPair = (Vec<u8>, Vec<u8>);
lazy_static::lazy_static! {
static ref CONFIG: Arc<RwLock<Config>> = Arc::new(RwLock::new(Config::load()));
@ -54,7 +55,7 @@ lazy_static::lazy_static! {
_ => "",
}.to_owned()));
pub static ref APP_NAME: Arc<RwLock<String>> = Arc::new(RwLock::new("RustDesk".to_owned()));
static ref KEY_PAIR: Arc<Mutex<Option<(Vec<u8>, Vec<u8>)>>> = Default::default();
static ref KEY_PAIR: Arc<Mutex<Option<KeyPair>>> = Default::default();
static ref HW_CODEC_CONFIG: Arc<RwLock<HwCodecConfig>> = Arc::new(RwLock::new(HwCodecConfig::load()));
}
@ -75,18 +76,18 @@ lazy_static::lazy_static! {
]);
}
const CHARS: &'static [char] = &[
const CHARS: &[char] = &[
'2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
];
const RENDEZVOUS_SERVERS: &'static [&'static str] = &[
pub const RENDEZVOUS_SERVERS: &[&str] = &[
"rs-ny.rustdesk.com",
"rs-sg.rustdesk.com",
"rs-cn.rustdesk.com",
];
pub const RS_PUB_KEY: &'static str = match option_env!("RS_PUB_KEY") {
pub const RS_PUB_KEY: &str = match option_env!("RS_PUB_KEY") {
Some(key) if !key.is_empty() => key,
_ => "OeVuKk5nlHiXp+APNn0Y3pC1Iwpwn44JGqrQCsWqmBw=",
};
@ -131,7 +132,7 @@ pub struct Config {
#[serde(default)]
salt: String,
#[serde(default)]
key_pair: (Vec<u8>, Vec<u8>), // sk, pk
key_pair: KeyPair, // sk, pk
#[serde(default)]
key_confirmed: bool,
#[serde(default)]
@ -319,7 +320,7 @@ impl Config2 {
pub fn load_path<T: serde::Serialize + serde::de::DeserializeOwned + Default + std::fmt::Debug>(
file: PathBuf,
) -> T {
let cfg = match confy::load_path(&file) {
let cfg = match confy::load_path(file) {
Ok(config) => config,
Err(err) => {
log::error!("Failed to load config: {}", err);
@ -366,20 +367,16 @@ impl Config {
config.id = id;
id_valid = true;
store |= store2;
} else {
if crate::get_modified_time(&Self::file_(""))
.checked_sub(std::time::Duration::from_secs(30)) // allow modification during installation
.unwrap_or(crate::get_exe_time())
< crate::get_exe_time()
{
if !config.id.is_empty()
&& config.enc_id.is_empty()
&& !decrypt_str_or_original(&config.id, PASSWORD_ENC_VERSION).1
{
id_valid = true;
store = true;
}
}
} else if crate::get_modified_time(&Self::file_(""))
.checked_sub(std::time::Duration::from_secs(30)) // allow modification during installation
.unwrap_or_else(crate::get_exe_time)
< crate::get_exe_time()
&& !config.id.is_empty()
&& config.enc_id.is_empty()
&& !decrypt_str_or_original(&config.id, PASSWORD_ENC_VERSION).1
{
id_valid = true;
store = true;
}
if !id_valid {
for _ in 0..3 {
@ -444,18 +441,18 @@ impl Config {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
{
#[cfg(not(target_os = "macos"))]
let org = "";
let org = "".to_owned();
#[cfg(target_os = "macos")]
let org = ORG.read().unwrap().clone();
// /var/root for root
if let Some(project) =
directories_next::ProjectDirs::from("", &org, &*APP_NAME.read().unwrap())
directories_next::ProjectDirs::from("", &org, &APP_NAME.read().unwrap())
{
let mut path = patch(project.config_dir().to_path_buf());
path.push(p);
return path;
}
return "".into();
"".into()
}
}
@ -539,9 +536,9 @@ impl Config {
rendezvous_server = Self::get_rendezvous_servers()
.drain(..)
.next()
.unwrap_or("".to_owned());
.unwrap_or_default();
}
if !rendezvous_server.contains(":") {
if !rendezvous_server.contains(':') {
rendezvous_server = format!("{}:{}", rendezvous_server, RENDEZVOUS_PORT);
}
rendezvous_server
@ -559,8 +556,8 @@ impl Config {
let serial_obsolute = CONFIG2.read().unwrap().serial > SERIAL;
if serial_obsolute {
let ss: Vec<String> = Self::get_option("rendezvous-servers")
.split(",")
.filter(|x| x.contains("."))
.split(',')
.filter(|x| x.contains('.'))
.map(|x| x.to_owned())
.collect();
if !ss.is_empty() {
@ -580,7 +577,7 @@ impl Config {
let mut delay = i64::MAX;
for (tmp_host, tmp_delay) in ONLINE.lock().unwrap().iter() {
if tmp_delay > &0 && tmp_delay < &delay {
delay = tmp_delay.clone();
delay = *tmp_delay;
host = tmp_host.to_string();
}
}
@ -647,7 +644,7 @@ impl Config {
for x in &ma.bytes()[2..] {
id = (id << 8) | (*x as u32);
}
id = id & 0x1FFFFFFF;
id &= 0x1FFFFFFF;
Some(id.to_string())
} else {
None
@ -679,11 +676,7 @@ impl Config {
}
pub fn get_host_key_confirmed(host: &str) -> bool {
if let Some(true) = CONFIG.read().unwrap().keys_confirmed.get(host) {
true
} else {
false
}
matches!(CONFIG.read().unwrap().keys_confirmed.get(host), Some(true))
}
pub fn set_host_key_confirmed(host: &str, v: bool) {
@ -695,7 +688,7 @@ impl Config {
config.store();
}
pub fn get_key_pair() -> (Vec<u8>, Vec<u8>) {
pub fn get_key_pair() -> KeyPair {
// lock here to make sure no gen_keypair more than once
// no use of CONFIG directly here to ensure no recursive calling in Config::load because of password dec which calling this function
let mut lock = KEY_PAIR.lock().unwrap();
@ -714,7 +707,7 @@ impl Config {
});
}
*lock = Some(config.key_pair.clone());
return config.key_pair;
config.key_pair
}
pub fn get_id() -> String {
@ -849,7 +842,7 @@ impl Config {
let ext = path.extension();
if let Some(ext) = ext {
let ext = format!("{}.toml", ext.to_string_lossy());
path.with_extension(&ext)
path.with_extension(ext)
} else {
path.with_extension("toml")
}
@ -861,7 +854,7 @@ const PEERS: &str = "peers";
impl PeerConfig {
pub fn load(id: &str) -> PeerConfig {
let _lock = CONFIG.read().unwrap();
match confy::load_path(&Self::path(id)) {
match confy::load_path(Self::path(id)) {
Ok(config) => {
let mut config: PeerConfig = config;
let mut store = false;
@ -869,16 +862,16 @@ impl PeerConfig {
decrypt_vec_or_original(&config.password, PASSWORD_ENC_VERSION);
config.password = password;
store = store || store2;
config.options.get_mut("rdp_password").map(|v| {
if let Some(v) = config.options.get_mut("rdp_password") {
let (password, _, store2) = decrypt_str_or_original(v, PASSWORD_ENC_VERSION);
*v = password;
store = store || store2;
});
config.options.get_mut("os-password").map(|v| {
}
if let Some(v) = config.options.get_mut("os-password") {
let (password, _, store2) = decrypt_str_or_original(v, PASSWORD_ENC_VERSION);
*v = password;
store = store || store2;
});
}
if store {
config.store(id);
}
@ -895,34 +888,29 @@ impl PeerConfig {
let _lock = CONFIG.read().unwrap();
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 Some(v) = config.options.get_mut("rdp_password") {
*v = encrypt_str_or_original(v, PASSWORD_ENC_VERSION)
}
if let Some(v) = config.options.get_mut("os-password") {
*v = encrypt_str_or_original(v, PASSWORD_ENC_VERSION)
};
if let Err(err) = store_path(Self::path(id), config) {
log::error!("Failed to store config: {}", err);
}
}
pub fn remove(id: &str) {
fs::remove_file(&Self::path(id)).ok();
fs::remove_file(Self::path(id)).ok();
}
fn path(id: &str) -> PathBuf {
let id_encoded: String;
//If the id contains invalid chars, encode it
let forbidden_paths = Regex::new(r".*[<>:/\\|\?\*].*").unwrap();
if forbidden_paths.is_match(id) {
id_encoded =
"base64_".to_string() + base64::encode(id, base64::Variant::Original).as_str();
let id_encoded = if forbidden_paths.is_match(id) {
"base64_".to_string() + base64::encode(id, base64::Variant::Original).as_str()
} else {
id_encoded = id.to_string();
}
id.to_string()
};
let path: PathBuf = [PEERS, id_encoded.as_str()].iter().collect();
Config::with_extension(Config::path(path))
}
@ -940,26 +928,24 @@ impl PeerConfig {
&& p.extension().map(|p| p.to_str().unwrap_or("")) == Some("toml")
})
.map(|p| {
let t = crate::get_modified_time(&p);
let t = crate::get_modified_time(p);
let id = p
.file_stem()
.map(|p| p.to_str().unwrap_or(""))
.unwrap_or("")
.to_owned();
let id_decoded_string: String;
if id.starts_with("base64_") && id.len() != 7 {
let id_decoded_string = if id.starts_with("base64_") && id.len() != 7 {
let id_decoded = base64::decode(&id[7..], base64::Variant::Original)
.unwrap_or(Vec::new());
id_decoded_string =
String::from_utf8_lossy(&id_decoded).as_ref().to_owned();
.unwrap_or_default();
String::from_utf8_lossy(&id_decoded).as_ref().to_owned()
} else {
id_decoded_string = id;
}
id
};
let c = PeerConfig::load(&id_decoded_string);
if c.info.platform.is_empty() {
fs::remove_file(&p).ok();
fs::remove_file(p).ok();
}
(id_decoded_string, t, c)
})
@ -1149,7 +1135,7 @@ pub struct LanPeers {
impl LanPeers {
pub fn load() -> LanPeers {
let _lock = CONFIG.read().unwrap();
match confy::load_path(&Config::file_("_lan_peers")) {
match confy::load_path(Config::file_("_lan_peers")) {
Ok(peers) => peers,
Err(err) => {
log::error!("Failed to load lan peers: {}", err);
@ -1158,9 +1144,9 @@ impl LanPeers {
}
}
pub fn store(peers: &Vec<DiscoveryPeer>) {
pub fn store(peers: &[DiscoveryPeer]) {
let f = LanPeers {
peers: peers.clone(),
peers: peers.to_owned(),
};
if let Err(err) = store_path(Config::file_("_lan_peers"), f) {
log::error!("Failed to store lan peers: {}", err);

View File

@ -13,13 +13,13 @@ use crate::{
config::{Config, COMPRESS_LEVEL},
};
pub fn read_dir(path: &PathBuf, include_hidden: bool) -> ResultType<FileDirectory> {
pub fn read_dir(path: &Path, include_hidden: bool) -> ResultType<FileDirectory> {
let mut dir = FileDirectory {
path: get_string(&path),
path: get_string(path),
..Default::default()
};
#[cfg(windows)]
if "/" == &get_string(&path) {
if "/" == &get_string(path) {
let drives = unsafe { winapi::um::fileapi::GetLogicalDrives() };
for i in 0..32 {
if drives & (1 << i) != 0 {
@ -36,74 +36,70 @@ pub fn read_dir(path: &PathBuf, include_hidden: bool) -> ResultType<FileDirector
}
return Ok(dir);
}
for entry in path.read_dir()? {
if let Ok(entry) = entry {
let p = entry.path();
let name = p
.file_name()
.map(|p| p.to_str().unwrap_or(""))
.unwrap_or("")
.to_owned();
if name.is_empty() {
continue;
}
let mut is_hidden = false;
let meta;
if let Ok(tmp) = std::fs::symlink_metadata(&p) {
meta = tmp;
} else {
continue;
}
// docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
#[cfg(windows)]
if meta.file_attributes() & 0x2 != 0 {
is_hidden = true;
}
#[cfg(not(windows))]
if name.find('.').unwrap_or(usize::MAX) == 0 {
is_hidden = true;
}
if is_hidden && !include_hidden {
continue;
}
let (entry_type, size) = {
if p.is_dir() {
if meta.file_type().is_symlink() {
(FileType::DirLink.into(), 0)
} else {
(FileType::Dir.into(), 0)
}
} else {
if meta.file_type().is_symlink() {
(FileType::FileLink.into(), 0)
} else {
(FileType::File.into(), meta.len())
}
}
};
let modified_time = meta
.modified()
.map(|x| {
x.duration_since(std::time::SystemTime::UNIX_EPOCH)
.map(|x| x.as_secs())
.unwrap_or(0)
})
.unwrap_or(0) as u64;
dir.entries.push(FileEntry {
name: get_file_name(&p),
entry_type,
is_hidden,
size,
modified_time,
..Default::default()
});
for entry in path.read_dir()?.flatten() {
let p = entry.path();
let name = p
.file_name()
.map(|p| p.to_str().unwrap_or(""))
.unwrap_or("")
.to_owned();
if name.is_empty() {
continue;
}
let mut is_hidden = false;
let meta;
if let Ok(tmp) = std::fs::symlink_metadata(&p) {
meta = tmp;
} else {
continue;
}
// docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
#[cfg(windows)]
if meta.file_attributes() & 0x2 != 0 {
is_hidden = true;
}
#[cfg(not(windows))]
if name.find('.').unwrap_or(usize::MAX) == 0 {
is_hidden = true;
}
if is_hidden && !include_hidden {
continue;
}
let (entry_type, size) = {
if p.is_dir() {
if meta.file_type().is_symlink() {
(FileType::DirLink.into(), 0)
} else {
(FileType::Dir.into(), 0)
}
} else if meta.file_type().is_symlink() {
(FileType::FileLink.into(), 0)
} else {
(FileType::File.into(), meta.len())
}
};
let modified_time = meta
.modified()
.map(|x| {
x.duration_since(std::time::SystemTime::UNIX_EPOCH)
.map(|x| x.as_secs())
.unwrap_or(0)
})
.unwrap_or(0);
dir.entries.push(FileEntry {
name: get_file_name(&p),
entry_type,
is_hidden,
size,
modified_time,
..Default::default()
});
}
Ok(dir)
}
#[inline]
pub fn get_file_name(p: &PathBuf) -> String {
pub fn get_file_name(p: &Path) -> String {
p.file_name()
.map(|p| p.to_str().unwrap_or(""))
.unwrap_or("")
@ -111,7 +107,7 @@ pub fn get_file_name(p: &PathBuf) -> String {
}
#[inline]
pub fn get_string(path: &PathBuf) -> String {
pub fn get_string(path: &Path) -> String {
path.to_str().unwrap_or("").to_owned()
}
@ -127,14 +123,14 @@ pub fn get_home_as_string() -> String {
fn read_dir_recursive(
path: &PathBuf,
prefix: &PathBuf,
prefix: &Path,
include_hidden: bool,
) -> ResultType<Vec<FileEntry>> {
let mut files = Vec::new();
if path.is_dir() {
// to-do: symbol link handling, cp the link rather than the content
// to-do: file mode, for unix
let fd = read_dir(&path, include_hidden)?;
let fd = read_dir(path, include_hidden)?;
for entry in fd.entries.iter() {
match entry.entry_type.enum_value() {
Ok(FileType::File) => {
@ -158,7 +154,7 @@ fn read_dir_recursive(
}
Ok(files)
} else if path.is_file() {
let (size, modified_time) = if let Ok(meta) = std::fs::metadata(&path) {
let (size, modified_time) = if let Ok(meta) = std::fs::metadata(path) {
(
meta.len(),
meta.modified()
@ -167,7 +163,7 @@ fn read_dir_recursive(
.map(|x| x.as_secs())
.unwrap_or(0)
})
.unwrap_or(0) as u64,
.unwrap_or(0),
)
} else {
(0, 0)
@ -249,7 +245,7 @@ pub struct RemoveJobMeta {
#[inline]
fn get_ext(name: &str) -> &str {
if let Some(i) = name.rfind(".") {
if let Some(i) = name.rfind('.') {
return &name[i + 1..];
}
""
@ -270,6 +266,7 @@ fn is_compressed_file(name: &str) -> bool {
}
impl TransferJob {
#[allow(clippy::too_many_arguments)]
pub fn new_write(
id: i32,
remote: String,
@ -281,7 +278,7 @@ impl TransferJob {
enable_overwrite_detection: bool,
) -> Self {
log::info!("new write {}", path);
let total_size = files.iter().map(|x| x.size as u64).sum();
let total_size = files.iter().map(|x| x.size).sum();
Self {
id,
remote,
@ -307,7 +304,7 @@ impl TransferJob {
) -> ResultType<Self> {
log::info!("new read {}", path);
let files = get_recursive_files(&path, show_hidden)?;
let total_size = files.iter().map(|x| x.size as u64).sum();
let total_size = files.iter().map(|x| x.size).sum();
Ok(Self {
id,
remote,
@ -363,7 +360,7 @@ impl TransferJob {
let entry = &self.files[file_num];
let path = self.join(&entry.name);
let download_path = format!("{}.download", get_string(&path));
std::fs::rename(&download_path, &path).ok();
std::fs::rename(download_path, &path).ok();
filetime::set_file_mtime(
&path,
filetime::FileTime::from_unix_time(entry.modified_time as _, 0),
@ -378,7 +375,7 @@ impl TransferJob {
let entry = &self.files[file_num];
let path = self.join(&entry.name);
let download_path = format!("{}.download", get_string(&path));
std::fs::remove_file(&download_path).ok();
std::fs::remove_file(download_path).ok();
}
}
@ -433,7 +430,7 @@ impl TransferJob {
}
let name = &self.files[file_num].name;
if self.file.is_none() {
match File::open(self.join(&name)).await {
match File::open(self.join(name)).await {
Ok(file) => {
self.file = Some(file);
self.file_confirmed = false;
@ -447,20 +444,15 @@ impl TransferJob {
}
}
}
if self.enable_overwrite_detection {
if !self.file_confirmed() {
if !self.file_is_waiting() {
self.send_current_digest(stream).await?;
self.set_file_is_waiting(true);
}
return Ok(None);
if self.enable_overwrite_detection && !self.file_confirmed() {
if !self.file_is_waiting() {
self.send_current_digest(stream).await?;
self.set_file_is_waiting(true);
}
return Ok(None);
}
const BUF_SIZE: usize = 128 * 1024;
let mut buf: Vec<u8> = Vec::with_capacity(BUF_SIZE);
unsafe {
buf.set_len(BUF_SIZE);
}
let mut buf: Vec<u8> = vec![0; BUF_SIZE];
let mut compressed = false;
let mut offset: usize = 0;
loop {
@ -582,10 +574,7 @@ impl TransferJob {
#[inline]
pub fn job_completed(&self) -> bool {
// has no error, Condition 2
if !self.enable_overwrite_detection || (!self.file_confirmed && !self.file_is_waiting) {
return true;
}
return false;
!self.enable_overwrite_detection || (!self.file_confirmed && !self.file_is_waiting)
}
/// Get job error message, useful for getting status when job had finished
@ -660,7 +649,7 @@ pub fn new_dir(id: i32, path: String, files: Vec<FileEntry>) -> Message {
resp.set_dir(FileDirectory {
id,
path,
entries: files.into(),
entries: files,
..Default::default()
});
let mut msg_out = Message::new();
@ -692,7 +681,7 @@ pub fn new_receive(id: i32, path: String, file_num: i32, files: Vec<FileEntry>)
action.set_receive(FileTransferReceiveRequest {
id,
path,
files: files.into(),
files,
file_num,
..Default::default()
});
@ -736,8 +725,8 @@ pub fn remove_job(id: i32, jobs: &mut Vec<TransferJob>) {
}
#[inline]
pub fn get_job(id: i32, jobs: &mut Vec<TransferJob>) -> Option<&mut TransferJob> {
jobs.iter_mut().filter(|x| x.id() == id).next()
pub fn get_job(id: i32, jobs: &mut [TransferJob]) -> Option<&mut TransferJob> {
jobs.iter_mut().find(|x| x.id() == id)
}
pub async fn handle_read_jobs(
@ -789,7 +778,7 @@ pub fn remove_all_empty_dir(path: &PathBuf) -> ResultType<()> {
remove_all_empty_dir(&path.join(&entry.name)).ok();
}
Ok(FileType::DirLink) | Ok(FileType::FileLink) => {
std::fs::remove_file(&path.join(&entry.name)).ok();
std::fs::remove_file(path.join(&entry.name)).ok();
}
_ => {}
}
@ -813,7 +802,7 @@ pub fn create_dir(dir: &str) -> ResultType<()> {
#[inline]
pub fn transform_windows_path(entries: &mut Vec<FileEntry>) {
for entry in entries {
entry.name = entry.name.replace("\\", "/");
entry.name = entry.name.replace('\\', "/");
}
}

View File

@ -96,8 +96,24 @@ pub type ResultType<F, E = anyhow::Error> = anyhow::Result<F, E>;
pub struct AddrMangle();
#[inline]
pub fn try_into_v4(addr: SocketAddr) -> SocketAddr {
match addr {
SocketAddr::V6(v6) if !addr.ip().is_loopback() => {
if let Some(v4) = v6.ip().to_ipv4() {
SocketAddr::new(IpAddr::V4(v4), addr.port())
} else {
addr
}
}
_ => addr,
}
}
impl AddrMangle {
pub fn encode(addr: SocketAddr) -> Vec<u8> {
// not work with [:1]:<port>
let addr = try_into_v4(addr);
match addr {
SocketAddr::V4(addr_v4) => {
let tm = (SystemTime::now()
@ -129,22 +145,20 @@ impl AddrMangle {
}
pub fn decode(bytes: &[u8]) -> SocketAddr {
use std::convert::TryInto;
if bytes.len() > 16 {
if bytes.len() != 18 {
return Config::get_any_listen_addr(false);
}
#[allow(invalid_value)]
let mut tmp: [u8; 2] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
tmp.copy_from_slice(&bytes[16..]);
let tmp: [u8; 2] = bytes[16..].try_into().unwrap();
let port = u16::from_le_bytes(tmp);
#[allow(invalid_value)]
let mut tmp: [u8; 16] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
tmp.copy_from_slice(&bytes[..16]);
let tmp: [u8; 16] = bytes[..16].try_into().unwrap();
let ip = std::net::Ipv6Addr::from(tmp);
return SocketAddr::new(IpAddr::V6(ip), port);
}
let mut padded = [0u8; 16];
padded[..bytes.len()].copy_from_slice(&bytes);
padded[..bytes.len()].copy_from_slice(bytes);
let number = u128::from_le_bytes(padded);
let tm = (number >> 17) & (u32::max_value() as u128);
let ip = (((number >> 49) - tm) as u32).to_le_bytes();
@ -158,21 +172,9 @@ impl AddrMangle {
pub fn get_version_from_url(url: &str) -> String {
let n = url.chars().count();
let a = url
.chars()
.rev()
.enumerate()
.filter(|(_, x)| x == &'-')
.next()
.map(|(i, _)| i);
let a = url.chars().rev().position(|x| x == '-');
if let Some(a) = a {
let b = url
.chars()
.rev()
.enumerate()
.filter(|(_, x)| x == &'.')
.next()
.map(|(i, _)| i);
let b = url.chars().rev().position(|x| x == '.');
if let Some(b) = b {
if a > b {
if url
@ -195,22 +197,30 @@ pub fn get_version_from_url(url: &str) -> String {
}
pub fn gen_version() {
if Ok("release".to_owned()) != std::env::var("PROFILE") {
return;
}
println!("cargo:rerun-if-changed=Cargo.toml");
use std::io::prelude::*;
let mut file = File::create("./src/version.rs").unwrap();
for line in read_lines("Cargo.toml").unwrap() {
if let Ok(line) = line {
let ab: Vec<&str> = line.split("=").map(|x| x.trim()).collect();
if ab.len() == 2 && ab[0] == "version" {
file.write_all(format!("pub const VERSION: &str = {};\n", ab[1]).as_bytes())
.ok();
break;
}
for line in read_lines("Cargo.toml").unwrap().flatten() {
let ab: Vec<&str> = line.split('=').map(|x| x.trim()).collect();
if ab.len() == 2 && ab[0] == "version" {
file.write_all(format!("pub const VERSION: &str = {};\n", ab[1]).as_bytes())
.ok();
break;
}
}
// generate build date
let build_date = format!("{}", chrono::Local::now().format("%Y-%m-%d %H:%M"));
file.write_all(format!("pub const BUILD_DATE: &str = \"{}\";", build_date).as_bytes())
.ok();
file.write_all(
format!(
"#[allow(dead_code)]\npub const BUILD_DATE: &str = \"{}\";",
build_date
)
.as_bytes(),
)
.ok();
file.sync_all().ok();
}
@ -230,20 +240,20 @@ pub fn is_valid_custom_id(id: &str) -> bool {
pub fn get_version_number(v: &str) -> i64 {
let mut n = 0;
for x in v.split(".") {
for x in v.split('.') {
n = n * 1000 + x.parse::<i64>().unwrap_or(0);
}
n
}
pub fn get_modified_time(path: &std::path::Path) -> SystemTime {
std::fs::metadata(&path)
std::fs::metadata(path)
.map(|m| m.modified().unwrap_or(UNIX_EPOCH))
.unwrap_or(UNIX_EPOCH)
}
pub fn get_created_time(path: &std::path::Path) -> SystemTime {
std::fs::metadata(&path)
std::fs::metadata(path)
.map(|m| m.created().unwrap_or(UNIX_EPOCH))
.unwrap_or(UNIX_EPOCH)
}
@ -276,32 +286,6 @@ pub fn get_time() -> i64 {
.unwrap_or(0) as _
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mangle() {
let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 16, 32), 21116));
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
let addr = "[2001:db8::1]:8080".parse::<SocketAddr>().unwrap();
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
let addr = "[2001:db8:ff::1111]:80".parse::<SocketAddr>().unwrap();
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
}
#[test]
fn test_allow_err() {
allow_err!(Err("test err") as Result<(), &str>);
allow_err!(
Err("test err with msg") as Result<(), &str>,
"prompt {}",
"failed"
);
}
}
#[inline]
pub fn is_ipv4_str(id: &str) -> bool {
regex::Regex::new(r"^\d+\.\d+\.\d+\.\d+(:\d+)?$")
@ -334,9 +318,31 @@ pub fn is_domain_port_str(id: &str) -> bool {
}
#[cfg(test)]
mod test_lib {
mod test {
use super::*;
#[test]
fn test_mangle() {
let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 16, 32), 21116));
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
let addr = "[2001:db8::1]:8080".parse::<SocketAddr>().unwrap();
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
let addr = "[2001:db8:ff::1111]:80".parse::<SocketAddr>().unwrap();
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
}
#[test]
fn test_allow_err() {
allow_err!(Err("test err") as Result<(), &str>);
allow_err!(
Err("test err with msg") as Result<(), &str>,
"prompt {}",
"failed"
);
}
#[test]
fn test_ipv6() {
assert_eq!(is_ipv6_str("1:2:3"), true);
@ -373,4 +379,20 @@ mod test_lib {
assert_eq!(is_domain_port_str("test.com:0"), true);
assert_eq!(is_domain_port_str("test.com:98989"), true);
}
#[test]
fn test_mangle2() {
let addr = "[::ffff:127.0.0.1]:8080".parse().unwrap();
let addr_v4 = "127.0.0.1:8080".parse().unwrap();
assert_eq!(AddrMangle::decode(&AddrMangle::encode(addr)), addr_v4);
assert_eq!(
AddrMangle::decode(&AddrMangle::encode("[::127.0.0.1]:8080".parse().unwrap())),
addr_v4
);
assert_eq!(AddrMangle::decode(&AddrMangle::encode(addr_v4)), addr_v4);
let addr_v6 = "[ef::fe]:8080".parse().unwrap();
assert_eq!(AddrMangle::decode(&AddrMangle::encode(addr_v6)), addr_v6);
let addr_v6 = "[::1]:8080".parse().unwrap();
assert_eq!(AddrMangle::decode(&AddrMangle::encode(addr_v6)), addr_v6);
}
}

View File

@ -104,7 +104,7 @@ 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) = decrypt(&s[VERSION_LEN..].as_bytes()) {
if let Ok(v) = decrypt(s[VERSION_LEN..].as_bytes()) {
return (
String::from_utf8_lossy(&v).to_string(),
true,
@ -149,7 +149,7 @@ pub fn decrypt_vec_or_original(v: &[u8], current_version: &str) -> (Vec<u8>, boo
}
fn encrypt(v: &[u8]) -> Result<String, ()> {
if v.len() > 0 {
if !v.is_empty() {
symmetric_crypt(v, true).map(|v| base64::encode(v, base64::Variant::Original))
} else {
Err(())
@ -157,7 +157,7 @@ fn encrypt(v: &[u8]) -> Result<String, ()> {
}
fn decrypt(v: &[u8]) -> Result<Vec<u8>, ()> {
if v.len() > 0 {
if !v.is_empty() {
base64::decode(v, base64::Variant::Original).and_then(|v| symmetric_crypt(&v, false))
} else {
Err(())

View File

@ -32,7 +32,7 @@ pub fn get_display_server() -> String {
// loginctl has not given the expected output. try something else.
if let Ok(sid) = std::env::var("XDG_SESSION_ID") {
// could also execute "cat /proc/self/sessionid"
session = sid.to_owned();
session = sid;
}
if session.is_empty() {
session = run_cmds("cat /proc/self/sessionid".to_owned()).unwrap_or_default();
@ -63,7 +63,7 @@ fn get_display_server_of_session(session: &str) -> String {
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 xorg_results.trim_end() != "" {
// If it is, manually return "x11", otherwise return tty
return "x11".to_owned();
}
@ -88,7 +88,7 @@ pub fn get_values_of_seat0(indices: Vec<usize>) -> Vec<String> {
if let Ok(output) = run_loginctl(None) {
for line in String::from_utf8_lossy(&output.stdout).lines() {
if line.contains("seat0") {
if let Some(sid) = line.split_whitespace().nth(0) {
if let Some(sid) = line.split_whitespace().next() {
if is_active(sid) {
return indices
.into_iter()
@ -103,7 +103,7 @@ pub fn get_values_of_seat0(indices: Vec<usize>) -> Vec<String> {
// some case, there is no seat0 https://github.com/rustdesk/rustdesk/issues/73
if let Ok(output) = run_loginctl(None) {
for line in String::from_utf8_lossy(&output.stdout).lines() {
if let Some(sid) = line.split_whitespace().nth(0) {
if let Some(sid) = line.split_whitespace().next() {
let d = get_display_server_of_session(sid);
if is_active(sid) && d != "tty" {
return indices

View File

@ -71,7 +71,7 @@ pub trait IsResolvedSocketAddr {
impl IsResolvedSocketAddr for SocketAddr {
fn resolve(&self) -> Option<&SocketAddr> {
Some(&self)
Some(self)
}
}
@ -120,12 +120,12 @@ pub async fn connect_tcp_local<
if let Some(target) = target.resolve() {
if let Some(local) = local {
if local.is_ipv6() && target.is_ipv4() {
let target = query_nip_io(&target).await?;
return Ok(FramedStream::new(target, Some(local), ms_timeout).await?);
let target = query_nip_io(target).await?;
return FramedStream::new(target, Some(local), ms_timeout).await;
}
}
}
Ok(FramedStream::new(target, local, ms_timeout).await?)
FramedStream::new(target, local, ms_timeout).await
}
#[inline]
@ -140,15 +140,14 @@ pub fn is_ipv4(target: &TargetAddr<'_>) -> bool {
pub async fn query_nip_io(addr: &SocketAddr) -> ResultType<SocketAddr> {
tokio::net::lookup_host(format!("{}.nip.io:{}", addr.ip(), addr.port()))
.await?
.filter(|x| x.is_ipv6())
.next()
.find(|x| x.is_ipv6())
.context("Failed to get ipv6 from nip.io")
}
#[inline]
pub fn ipv4_to_ipv6(addr: String, ipv4: bool) -> String {
if !ipv4 && crate::is_ipv4_str(&addr) {
if let Some(ip) = addr.split(":").next() {
if let Some(ip) = addr.split(':').next() {
return addr.replace(ip, &format!("{}.nip.io", ip));
}
}

View File

@ -1,4 +1,5 @@
use crate::{bail, bytes_codec::BytesCodec, ResultType};
use anyhow::Context as AnyhowCtx;
use bytes::{BufMut, Bytes, BytesMut};
use futures::{SinkExt, StreamExt};
use protobuf::Message;
@ -209,7 +210,7 @@ impl FramedStream {
if let Some(Ok(bytes)) = res.as_mut() {
key.2 += 1;
let nonce = Self::get_nonce(key.2);
match secretbox::open(&bytes, &nonce, &key.0) {
match secretbox::open(bytes, &nonce, &key.0) {
Ok(res) => {
bytes.clear();
bytes.put_slice(&res);
@ -245,16 +246,17 @@ impl FramedStream {
const DEFAULT_BACKLOG: u32 = 128;
#[allow(clippy::never_loop)]
pub async fn new_listener<T: ToSocketAddrs>(addr: T, reuse: bool) -> ResultType<TcpListener> {
if !reuse {
Ok(TcpListener::bind(addr).await?)
} else {
for addr in lookup_host(&addr).await? {
let socket = new_socket(addr, true)?;
return Ok(socket.listen(DEFAULT_BACKLOG)?);
}
bail!("could not resolve to any address");
let addr = lookup_host(&addr)
.await?
.next()
.context("could not resolve to any address")?;
new_socket(addr, true)?
.listen(DEFAULT_BACKLOG)
.map_err(anyhow::Error::msg)
}
}

View File

@ -1,11 +1,11 @@
use crate::{bail, ResultType};
use anyhow::anyhow;
use crate::ResultType;
use anyhow::{anyhow, Context};
use bytes::{Bytes, BytesMut};
use futures::{SinkExt, StreamExt};
use protobuf::Message;
use socket2::{Domain, Socket, Type};
use std::net::SocketAddr;
use tokio::net::{ToSocketAddrs, UdpSocket};
use tokio::net::{lookup_host, ToSocketAddrs, UdpSocket};
use tokio_socks::{udp::Socks5UdpFramed, IntoTargetAddr, TargetAddr, ToProxyAddrs};
use tokio_util::{codec::BytesCodec, udp::UdpFramed};
@ -37,39 +37,31 @@ fn new_socket(addr: SocketAddr, reuse: bool, buf_size: usize) -> Result<Socket,
addr,
socket.recv_buffer_size()
);
if addr.is_ipv6() && addr.ip().is_unspecified() && addr.port() > 0 {
socket.set_only_v6(false).ok();
}
socket.bind(&addr.into())?;
Ok(socket)
}
impl FramedSocket {
pub async fn new<T: ToSocketAddrs>(addr: T) -> ResultType<Self> {
let socket = UdpSocket::bind(addr).await?;
Ok(Self::Direct(UdpFramed::new(socket, BytesCodec::new())))
Self::new_reuse(addr, false, 0).await
}
#[allow(clippy::never_loop)]
pub async fn new_reuse<T: std::net::ToSocketAddrs>(addr: T) -> ResultType<Self> {
for addr in addr.to_socket_addrs()? {
let socket = new_socket(addr, true, 0)?.into_udp_socket();
return Ok(Self::Direct(UdpFramed::new(
UdpSocket::from_std(socket)?,
BytesCodec::new(),
)));
}
bail!("could not resolve to any address");
}
pub async fn new_with_buf_size<T: std::net::ToSocketAddrs>(
pub async fn new_reuse<T: ToSocketAddrs>(
addr: T,
reuse: bool,
buf_size: usize,
) -> ResultType<Self> {
for addr in addr.to_socket_addrs()? {
return Ok(Self::Direct(UdpFramed::new(
UdpSocket::from_std(new_socket(addr, false, buf_size)?.into_udp_socket())?,
BytesCodec::new(),
)));
}
bail!("could not resolve to any address");
let addr = lookup_host(&addr)
.await?
.next()
.context("could not resolve to any address")?;
Ok(Self::Direct(UdpFramed::new(
UdpSocket::from_std(new_socket(addr, reuse, buf_size)?.into_udp_socket())?,
BytesCodec::new(),
)))
}
pub async fn new_proxy<'a, 't, P: ToProxyAddrs, T: ToSocketAddrs>(
@ -104,11 +96,12 @@ impl FramedSocket {
) -> ResultType<()> {
let addr = addr.into_target_addr()?.to_owned();
let send_data = Bytes::from(msg.write_to_bytes()?);
let _ = match self {
Self::Direct(f) => match addr {
TargetAddr::Ip(addr) => f.send((send_data, addr)).await?,
_ => {}
},
match self {
Self::Direct(f) => {
if let TargetAddr::Ip(addr) = addr {
f.send((send_data, addr)).await?
}
}
Self::ProxySocks(f) => f.send((send_data, addr)).await?,
};
Ok(())
@ -123,11 +116,12 @@ impl FramedSocket {
) -> ResultType<()> {
let addr = addr.into_target_addr()?.to_owned();
let _ = match self {
Self::Direct(f) => match addr {
TargetAddr::Ip(addr) => f.send((Bytes::from(msg), addr)).await?,
_ => {}
},
match self {
Self::Direct(f) => {
if let TargetAddr::Ip(addr) = addr {
f.send((Bytes::from(msg), addr)).await?
}
}
Self::ProxySocks(f) => f.send((Bytes::from(msg), addr)).await?,
};
Ok(())
@ -165,12 +159,12 @@ impl FramedSocket {
}
}
pub fn is_ipv4(&self) -> bool {
pub fn local_addr(&self) -> Option<SocketAddr> {
if let FramedSocket::Direct(x) = self {
if let Ok(v) = x.get_ref().local_addr() {
return v.is_ipv4();
return Some(v);
}
}
true
None
}
}

View File

@ -2083,6 +2083,7 @@ pub fn check_if_retry(msgtype: &str, title: &str, text: &str, retry_for_relay: b
&& !text.to_lowercase().contains("mismatch")
&& !text.to_lowercase().contains("manually")
&& !text.to_lowercase().contains("not allowed")
&& !text.to_lowercase().contains("as expected")
&& !text.to_lowercase().contains("reset by the peer")))
}

View File

@ -245,8 +245,14 @@ pub fn session_get_keyboard_mode(id: String) -> Option<String> {
}
pub fn session_set_keyboard_mode(id: String, value: String) {
let mut _mode_updated = false;
if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) {
session.save_keyboard_mode(value);
_mode_updated = true;
}
#[cfg(windows)]
if _mode_updated {
crate::keyboard::update_grab_get_key_name();
}
}
@ -1182,7 +1188,9 @@ pub fn main_update_me() -> SyncReturn<bool> {
}
pub fn set_cur_session_id(id: String) {
super::flutter::set_cur_session_id(id)
super::flutter::set_cur_session_id(id);
#[cfg(windows)]
crate::keyboard::update_grab_get_key_name();
}
pub fn install_show_run_without_install() -> SyncReturn<bool> {

View File

@ -64,6 +64,8 @@ pub mod client {
match state {
GrabState::Ready => {}
GrabState::Run => {
#[cfg(windows)]
update_grab_get_key_name();
#[cfg(any(target_os = "windows", target_os = "macos"))]
KEYBOARD_HOOKED.swap(true, Ordering::SeqCst);
@ -184,6 +186,15 @@ pub mod client {
}
}
#[cfg(windows)]
pub fn update_grab_get_key_name() {
match get_keyboard_mode_enum() {
KeyboardMode::Map => rdev::set_get_key_name(false),
KeyboardMode::Translate => rdev::set_get_key_name(true),
_ => {}
};
}
pub fn start_grab_loop() {
#[cfg(any(target_os = "windows", target_os = "macos"))]
std::thread::spawn(move || {

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", ""),
("Group", ""),
("Search", ""),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", "添加到地址簿"),
("Group", "小组"),
("Search", "搜索"),
("Closed manually by the web console", "被web控制台手动关闭"),
("Closed manually by web console", "被web控制台手动关闭"),
("Local keyboard type", "本地键盘类型"),
("Select local keyboard type", "请选择本地键盘类型"),
("software_render_tip", "如果你使用英伟达显卡, 并且远程窗口在会话建立后会立刻关闭, 那么安装nouveau驱动并且选择使用软件渲染可能会有帮助。重启软件后生效。"),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", "反转访问方向"),
("Please confirm if you want to share your desktop?", "请确认要让对方访问你的桌面?"),
("Closed as expected", "正常关闭"),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", ""),
("Group", ""),
("Search", ""),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", ""),
("Group", ""),
("Search", ""),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", "Zum Adressbuch hinzufügen"),
("Group", "Gruppe"),
("Search", "Suchen"),
("Closed manually by the web console", "Manuell über die Webkonsole beendet"),
("Closed manually by web console", "Manuell über die Webkonsole beendet"),
("Local keyboard type", "Lokaler Tastaturtyp"),
("Select local keyboard type", "Lokalen Tastaturtyp auswählen"),
("software_render_tip", "Wenn Sie eine Nvidia-Grafikkarte haben und sich das entfernte Fenster sofort nach dem Herstellen der Verbindung schließt, kann es helfen, den Nouveau-Treiber zu installieren und Software-Rendering zu verwenden. Ein Neustart der Software ist erforderlich."),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", "Stark"),
("Switch Sides", "Seiten wechseln"),
("Please confirm if you want to share your desktop?", "Bitte bestätigen Sie, ob Sie Ihren Desktop freigeben möchten."),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", ""),
("Group", ""),
("Search", ""),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", "Añadir a la libreta de direcciones"),
("Group", "Grupo"),
("Search", "Búsqueda"),
("Closed manually by the web console", "Cerrado manualmente por la consola web"),
("Closed manually by web console", "Cerrado manualmente por la consola web"),
("Local keyboard type", "Tipo de teclado local"),
("Select local keyboard type", "Seleccionar tipo de teclado local"),
("software_render_tip", "Si tienes una gráfica Nvidia y la ventana remota se cierra inmediatamente, instalar el driver nouveau y elegir renderizado por software podría ayudar. Se requiere reiniciar la aplicación."),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", "Fuerte"),
("Switch Sides", "Intercambiar lados"),
("Please confirm if you want to share your desktop?", "Por favor, confirma si quieres compartir tu escritorio"),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", "افزودن به دفترچه آدرس"),
("Group", "گروه"),
("Search", "جستجو"),
("Closed manually by the web console", "به صورت دستی توسط کنسول وب بسته شد"),
("Closed manually by web console", "به صورت دستی توسط کنسول وب بسته شد"),
("Local keyboard type", "نوع صفحه کلید محلی"),
("Select local keyboard type", "نوع صفحه کلید محلی را انتخاب کنید"),
("software_render_tip", "اگر کارت گرافیک Nvidia دارید و پنجره راه دور بلافاصله پس از اتصال بسته می شود، درایور nouveau را نصب نمایید و انتخاب گزینه استفاده از رندر نرم افزار می تواند کمک کننده باشد. راه اندازی مجدد نرم افزار مورد نیاز است."),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", "قوی"),
("Switch Sides", "طرفین را عوض کنید"),
("Please confirm if you want to share your desktop?", "لطفاً تأیید کنید که آیا می خواهید دسکتاپ خود را به اشتراک بگذارید؟"),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -77,10 +77,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Connected, waiting for image...", "Connecté, en attente de transmission d'image..."),
("Name", "Nom"),
("Type", "Type"),
("Modified", "Modifié"),
("Modified", "Modifié le"),
("Size", "Taille"),
("Show Hidden Files", "Afficher les fichiers cachés"),
("Receive", "Accepter"),
("Receive", "Recevoir"),
("Send", "Envoyer"),
("Refresh File", "Actualiser le fichier"),
("Local", "Local"),
@ -90,7 +90,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Confirm Delete", "Confirmer la suppression"),
("Delete", "Supprimer"),
("Properties", "Propriétés"),
("Multi Select", "Choix multiple"),
("Multi Select", "Sélection multiple"),
("Select All", "Tout sélectionner"),
("Unselect All", "Tout déselectionner"),
("Empty Directory", "Répertoire vide"),
@ -208,7 +208,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Run without install", "Exécuter sans installer"),
("Always connected via relay", "Forcer la connexion relais"),
("Always connect via relay", "Forcer la connexion relais"),
("whitelist_tip", "Seul l'IP dans la liste blanche peut accéder à mon appareil"),
("whitelist_tip", "Seule une IP de la liste blanche peut accéder à mon appareil"),
("Login", "Connexion"),
("Verify", "Vérifier"),
("Remember me", "Se souvenir de moi"),
@ -269,7 +269,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Chat", "Discuter"),
("Total", "Total"),
("items", "éléments"),
("Selected", "Choisi"),
("Selected", "Sélectionné"),
("Screen Capture", "Capture d'écran"),
("Input Control", "Contrôle de saisie"),
("Audio Capture", "Capture audio"),
@ -303,7 +303,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("In privacy mode", "en mode privé"),
("Out privacy mode", "hors mode de confidentialité"),
("Language", "Langue"),
("Keep RustDesk background service", "Gardez le service RustDesk service arrière plan"),
("Keep RustDesk background service", "Gardez le service RustDesk en arrière plan"),
("Ignore Battery Optimizations", "Ignorer les optimisations batterie"),
("android_open_battery_optimizations_tip", "Conseil android d'optimisation de batterie"),
("Connection not allowed", "Connexion non autorisée"),
@ -356,14 +356,14 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Clear", "Effacer"),
("Audio Input Device", "Périphérique source audio"),
("Deny remote access", "Interdir l'accès distant"),
("Use IP Whitelisting", "Utiliser liste blanche d'IP"),
("Use IP Whitelisting", "Utiliser une liste blanche d'IP"),
("Network", "Réseau"),
("Enable RDP", "Activer RDP"),
("Pin menubar", "Épingler la barre de menus"),
("Unpin menubar", "Détacher la barre de menu"),
("Recording", "Enregistrement"),
("Directory", "Répertoire"),
("Automatically record incoming sessions", "Enregistrement automatique des session entrantes"),
("Automatically record incoming sessions", "Enregistrement automatique des sessions entrantes"),
("Change", "Modifier"),
("Start session recording", "Commencer l'enregistrement"),
("Stop session recording", "Stopper l'enregistrement"),
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", "Ajouter au carnet d'adresses"),
("Group", "Groupe"),
("Search", "Rechercher"),
("Closed manually by the web console", "Fermé manuellement par la console Web"),
("Closed manually by web console", "Fermé manuellement par la console Web"),
("Local keyboard type", "Disposition du clavier local"),
("Select local keyboard type", "Selectionner la disposition du clavier local"),
("software_render_tip", "Si vous avez une carte graphique NVIDIA et que la fenêtre distante se ferme immédiatement après la connexion, l'installation du pilote Nouveau et le choix d'utiliser le rendu du logiciel peuvent aider. Un redémarrage du logiciel est requis."),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", "Fort"),
("Switch Sides", "Inverser la prise de contrôle"),
("Please confirm if you want to share your desktop?", "Veuillez confirmer le partager de votre bureau ?"),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", "Προσθήκη στο Βιβλίο Διευθύνσεων"),
("Group", "Ομάδα"),
("Search", "Αναζήτηση"),
("Closed manually by the web console", "Κλειστό χειροκίνητα από την κονσόλα web"),
("Closed manually by web console", "Κλειστό χειροκίνητα από την κονσόλα web"),
("Local keyboard type", "Τύπος τοπικού πληκτρολογίου"),
("Select local keyboard type", "Επιλογή τύπου τοπικού πληκτρολογίου"),
("software_render_tip", "Εάν έχετε κάρτα γραφικών Nvidia και το παράθυρο σύνδεσης κλείνει αμέσως μετά τη σύνδεση, η εγκατάσταση του προγράμματος οδήγησης nouveau και η επιλογή χρήσης της επιτάχυνσης γραφικών μέσω λογισμικού μπορεί να βοηθήσει. Απαιτείται επανεκκίνηση."),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", "Δυνατό"),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", ""),
("Group", ""),
("Search", ""),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", ""),
("Group", ""),
("Search", "Pencarian"),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", "Aggiungi alla rubrica"),
("Group", "Gruppo"),
("Search", "Cerca"),
("Closed manually by the web console", "Chiudi manualmente dalla console Web"),
("Closed manually by web console", "Chiudi manualmente dalla console Web"),
("Local keyboard type", "Tipo di tastiera locale"),
("Select local keyboard type", "Seleziona il tipo di tastiera locale"),
("software_render_tip", "Se si dispone di una scheda grafica Nvidia e la finestra remota si chiude immediatamente dopo la connessione, l'installazione del driver nouveau e la scelta di utilizzare il rendering software possono aiutare. È necessario un riavvio del software."),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", "Forte"),
("Switch Sides", "Cambia lato"),
("Please confirm if you want to share your desktop?", "Vuoi condividere il tuo desktop?"),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", ""),
("Group", ""),
("Search", ""),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", ""),
("Group", ""),
("Search", ""),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", ""),
("Group", ""),
("Search", ""),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", "Dodaj do Książki Adresowej"),
("Group", "Grypy"),
("Search", "Szukaj"),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", ""),
("Group", ""),
("Search", ""),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", ""),
("Group", ""),
("Search", ""),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -39,6 +39,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Change ID", "Schimbă ID"),
("Website", "Site web"),
("About", "Despre"),
("Slogan_tip", ""),
("Privacy Statement", ""),
("Mute", "Fără sunet"),
("Audio Input", "Intrare audio"),
("Enhancements", "Îmbunătățiri"),
@ -116,7 +118,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Good image quality", "Calitate bună a imaginii"),
("Balanced", "Calitate normală a imaginii"),
("Optimize reaction time", "Optimizează timpul de reacție"),
("Custom", "Personalizare"),
("Custom", "Personalizat"),
("Show remote cursor", "Afișează cursor la distanță"),
("Show quality monitor", "Afișează indicator de calitate"),
("Disable clipboard", "Dezactivează clipboard"),
@ -208,6 +210,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Always connect via relay", "Se conectează mereu prin retransmisie"),
("whitelist_tip", "Doar adresele IP autorizate pot accesa acest dispozitiv"),
("Login", "Conectare"),
("Verify", ""),
("Remember me", ""),
("Trust this device", ""),
("Verification code", ""),
("verification_tip", ""),
("Logout", "Deconectare"),
("Tags", "Etichetare"),
("Search ID", "Caută după ID"),
@ -332,7 +339,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Scale adaptive", "Scală adaptivă"),
("General", "General"),
("Security", "Securitate"),
("Account", "Cont"),
("Theme", "Temă"),
("Dark Theme", "Temă întunecată"),
("Dark", "Întunecat"),
@ -345,7 +351,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Server", "Server"),
("Direct IP Access", "Acces direct IP"),
("Proxy", "Proxy"),
("Port", "Port"),
("Apply", "Aplică"),
("Disconnect all devices?", "Vrei să deconectezi toate dispozitivele?"),
("Clear", "Golește"),
@ -374,7 +379,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Other", "Altele"),
("Confirm before closing multiple tabs", "Confirmă înainte de a închide mai multe file"),
("Keyboard Settings", "Configurare tastatură"),
("Custom", "Personalizat"),
("Full Access", "Acces total"),
("Screen Share", "Partajare ecran"),
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland necesită Ubuntu 21.04 sau o versiune superioară."),
@ -397,5 +401,38 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Request access to your device", "Solicită acces la dispozitivul tău"),
("Hide connection management window", "Ascunde fereastra de gestionare a conexiunilor"),
("hide_cm_tip", "Permite ascunderea ferestrei de gestionare doar dacă accepți începerea sesiunilor folosind parola permanentă"),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
("Skipped", ""),
("Add to Address Book", ""),
("Group", ""),
("Search", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
("Always use software rendering", ""),
("config_input", ""),
("request_elevation_tip", ""),
("Wait", ""),
("Elevation Error", ""),
("Ask the remote user for authentication", ""),
("Choose this if the remote account is administrator", ""),
("Transmit the username and password of administrator", ""),
("still_click_uac_tip", ""),
("Request Elevation", ""),
("wait_accept_uac_tip", ""),
("Elevate successfully", ""),
("uppercase", ""),
("lowercase", ""),
("digit", ""),
("special character", ""),
("length>=8", ""),
("Weak", ""),
("Medium", ""),
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", "Добавить в адресную книгу"),
("Group", "Группа"),
("Search", "Поиск"),
("Closed manually by the web console", "Закрыто вручную через веб-консоль"),
("Closed manually by web console", "Закрыто вручную через веб-консоль"),
("Local keyboard type", "Тип локальной клавиатуры"),
("Select local keyboard type", "Выберите тип локальной клавиатуры"),
("software_render_tip", "Если у вас видеокарта Nvidia и удалённое окно закрывается сразу после подключения, может помочь установка драйвера Nouveau и выбор использования программной визуализации. Потребуется перезапуск."),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", "Стойкий"),
("Switch Sides", "Переключить стороны"),
("Please confirm if you want to share your desktop?", "Подтвердите, что хотите поделиться своим рабочим столом?"),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", ""),
("Group", ""),
("Search", ""),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", "Dodaj v adresar"),
("Group", "Skupina"),
("Search", "Iskanje"),
("Closed manually by the web console", "Ročno zaprto iz spletne konzole"),
("Closed manually by web console", "Ročno zaprto iz spletne konzole"),
("Local keyboard type", "Lokalna vrsta tipkovnice"),
("Select local keyboard type", "Izberite lokalno vrsto tipkovnice"),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", ""),
("Group", ""),
("Search", ""),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", "Dodaj u adresar"),
("Group", "Grupa"),
("Search", "Pretraga"),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", ""),
("Group", ""),
("Search", ""),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", ""),
("Group", ""),
("Search", ""),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", "เพิ่มไปยังสมุดรายชื่อ"),
("Group", "กลุ่ม"),
("Search", "ค้นหา"),
("Closed manually by the web console", "ถูกปิดโดยเว็บคอนโซล"),
("Closed manually by web console", "ถูกปิดโดยเว็บคอนโซล"),
("Local keyboard type", "ประเภทคีย์บอร์ด"),
("Select local keyboard type", "เลือกประเภทคีย์บอร์ด"),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", ""),
("Group", ""),
("Search", ""),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", "添加到地址簿"),
("Group", "小組"),
("Search", "搜索"),
("Closed manually by the web console", "被web控制台手動關閉"),
("Closed manually by web console", "被web控制台手動關閉"),
("Local keyboard type", "本地鍵盤類型"),
("Select local keyboard type", "請選擇本地鍵盤類型"),
("software_render_tip", "如果你使用英偉達顯卡, 並且遠程窗口在會話建立後會立刻關閉, 那麼安裝nouveau驅動並且選擇使用軟件渲染可能會有幫助。重啟軟件後生效。"),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", "正常關閉"),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", "Додати IP до Адресної книги"),
("Group", "Група"),
("Search", "Пошук"),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add to Address Book", ""),
("Group", ""),
("Search", ""),
("Closed manually by the web console", ""),
("Closed manually by web console", ""),
("Local keyboard type", ""),
("Select local keyboard type", ""),
("software_render_tip", ""),
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Closed as expected", ""),
].iter().cloned().collect();
}

View File

@ -839,6 +839,11 @@ pub fn check_update_broker_process() -> ResultType<()> {
let cur_dir = exe_file.parent().unwrap();
let cur_exe = cur_dir.join(process_exe);
if !std::path::Path::new(&cur_exe).exists() {
std::fs::copy(origin_process_exe, cur_exe)?;
return Ok(());
}
let ori_modified = fs::metadata(origin_process_exe)?.modified()?;
if let Ok(metadata) = fs::metadata(&cur_exe) {
if let Ok(cur_modified) = metadata.modified() {

View File

@ -101,7 +101,6 @@ pub struct Connection {
lr: LoginRequest,
last_recv_time: Arc<Mutex<Instant>>,
chat_unanswered: bool,
close_manually: bool,
#[allow(unused)]
elevation_requested: bool,
from_switch: bool,
@ -200,7 +199,6 @@ impl Connection {
lr: Default::default(),
last_recv_time: Arc::new(Mutex::new(Instant::now())),
chat_unanswered: false,
close_manually: false,
elevation_requested: false,
from_switch: false,
};
@ -271,7 +269,9 @@ impl Connection {
}
}
ipc::Data::Close => {
conn.on_close_manually("connection manager", "peer").await;
conn.chat_unanswered = false; // seen
conn.send_close_reason_no_retry("").await;
conn.on_close("connection manager", true).await;
break;
}
ipc::Data::ChatMessage{text} => {
@ -411,7 +411,8 @@ impl Connection {
}
Ok(conns) = hbbs_rx.recv() => {
if conns.contains(&id) {
conn.on_close_manually("web console", "web console").await;
conn.send_close_reason_no_retry("Closed manually by web console").await;
conn.on_close("web console", true).await;
break;
}
}
@ -441,7 +442,8 @@ impl Connection {
Some(message::Union::Misc(m)) => {
match &m.union {
Some(misc::Union::StopService(_)) => {
conn.on_close_manually("stop service", "peer").await;
conn.send_close_reason_no_retry("").await;
conn.on_close("stop service", true).await;
break;
}
_ => {},
@ -540,6 +542,9 @@ impl Connection {
"action": "close",
}));
ALIVE_CONNS.lock().unwrap().retain(|&c| c != id);
if let Some(s) = conn.server.upgrade() {
s.write().unwrap().remove_connection(&conn.inner);
}
log::info!("#{} connection loop exited", id);
}
@ -1274,7 +1279,7 @@ impl Connection {
.retain(|_, v| v.0.elapsed() < SWITCH_SIDES_TIMEOUT);
let uuid_old = SWITCH_SIDES_UUID.lock().unwrap().remove(&lr.my_id);
if let Ok(uuid) = uuid::Uuid::from_slice(_s.uuid.to_vec().as_ref()) {
if let Some((instant, uuid_old)) = uuid_old {
if let Some((_instant, uuid_old)) = uuid_old {
if uuid == uuid_old {
self.from_switch = true;
self.try_start_cm(lr.my_id.clone(), lr.my_name.clone(), true);
@ -1583,6 +1588,8 @@ impl Connection {
uuid.to_string().as_ref(),
])
.ok();
self.send_close_reason_no_retry("Closed as expected");
self.on_close("switch sides", false);
return false;
}
}
@ -1756,16 +1763,13 @@ impl Connection {
}
async fn on_close(&mut self, reason: &str, lock: bool) {
if let Some(s) = self.server.upgrade() {
s.write().unwrap().remove_connection(&self.inner);
}
log::info!("#{} Connection closed: {}", self.inner.id(), reason);
if lock && self.lock_after_session_end && self.keyboard {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
lock_screen().await;
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
let data = if self.chat_unanswered && !self.close_manually {
let data = if self.chat_unanswered {
ipc::Data::Disconnected
} else {
ipc::Data::Close
@ -1776,15 +1780,17 @@ impl Connection {
self.port_forward_socket.take();
}
async fn on_close_manually(&mut self, close_from: &str, close_by: &str) {
self.close_manually = true;
// The `reason` should be consistent with `check_if_retry` if not empty
async fn send_close_reason_no_retry(&mut self, reason: &str) {
let mut misc = Misc::new();
misc.set_close_reason(format!("Closed manually by the {}", close_by));
if reason.is_empty() {
misc.set_close_reason("Closed manually by the peer".to_string());
} else {
misc.set_close_reason(reason.to_string());
}
let mut msg_out = Message::new();
msg_out.set_misc(misc);
self.send(msg_out).await;
self.on_close(&format!("Close requested from {}", close_from), false)
.await;
SESSIONS.lock().unwrap().remove(&self.lr.my_id);
}

View File

@ -449,14 +449,11 @@ pub async fn start_ipc<T: InvokeUiCM>(cm: ConnectionManager<T>) {
#[cfg(windows)]
std::thread::spawn(move || {
log::info!("try create privacy mode window");
#[cfg(windows)]
{
if let Err(e) = crate::platform::windows::check_update_broker_process() {
log::warn!(
"Failed to check update broker process. Privacy mode may not work properly. {}",
e
);
}
if let Err(e) = crate::platform::windows::check_update_broker_process() {
log::warn!(
"Failed to check update broker process. Privacy mode may not work properly. {}",
e
);
}
allow_err!(crate::ui::win_privacy::start());
});