From 910dcf2036da611bd7fb3a504bd56b79eb2b9b0f Mon Sep 17 00:00:00 2001 From: fufesou <13586388+fufesou@users.noreply.github.com> Date: Mon, 3 Nov 2025 23:21:01 +0800 Subject: [PATCH] refact: tls, native-tls fallback rustls-tls (#13263) Signed-off-by: fufesou --- .github/workflows/flutter-build.yml | 8 +- Cargo.lock | 228 ++++++-------- Cargo.toml | 12 +- flutter/lib/common/widgets/login.dart | 36 ++- flutter/lib/consts.dart | 5 +- .../desktop/pages/desktop_setting_page.dart | 97 ++++-- flutter/lib/mobile/pages/scan_page.dart | 2 +- flutter/lib/mobile/pages/settings_page.dart | 50 ++- flutter/lib/mobile/widgets/dialog.dart | 11 +- flutter/lib/utils/http_service.dart | 23 +- libs/hbb_common | 2 +- src/common.rs | 259 ++++++++++++++-- src/flutter_ffi.rs | 17 +- src/hbbs_http.rs | 8 +- src/hbbs_http/account.rs | 55 ++-- src/hbbs_http/downloader.rs | 4 +- src/hbbs_http/http_client.rs | 287 +++++++++++++++++- src/hbbs_http/record_upload.rs | 84 ++--- src/ipc.rs | 18 +- src/lang/ar.rs | 5 + src/lang/be.rs | 5 + src/lang/bg.rs | 5 + src/lang/ca.rs | 5 + src/lang/cn.rs | 7 +- src/lang/cs.rs | 5 + src/lang/da.rs | 5 + src/lang/de.rs | 5 + src/lang/el.rs | 5 + src/lang/en.rs | 3 + src/lang/eo.rs | 5 + src/lang/es.rs | 5 + src/lang/et.rs | 5 + src/lang/eu.rs | 5 + src/lang/fa.rs | 5 + src/lang/fi.rs | 18 +- src/lang/fr.rs | 5 + src/lang/ge.rs | 5 + src/lang/he.rs | 5 + src/lang/hr.rs | 5 + src/lang/hu.rs | 5 + src/lang/id.rs | 5 + src/lang/it.rs | 5 + src/lang/ja.rs | 5 + src/lang/ko.rs | 5 + src/lang/kz.rs | 5 + src/lang/lt.rs | 5 + src/lang/lv.rs | 5 + src/lang/nb.rs | 5 + src/lang/nl.rs | 5 + src/lang/pl.rs | 5 + src/lang/pt_PT.rs | 5 + src/lang/ptbr.rs | 5 + src/lang/ro.rs | 5 + src/lang/ru.rs | 5 + src/lang/sc.rs | 5 + src/lang/sk.rs | 5 + src/lang/sl.rs | 5 + src/lang/sq.rs | 5 + src/lang/sr.rs | 5 + src/lang/sv.rs | 5 + src/lang/ta.rs | 5 + src/lang/template.rs | 5 + src/lang/th.rs | 5 + src/lang/tr.rs | 5 + src/lang/tw.rs | 5 + src/lang/uk.rs | 5 + src/lang/vi.rs | 5 + src/ui.rs | 15 + src/ui/index.tis | 24 +- src/updater.rs | 4 +- 70 files changed, 1184 insertions(+), 318 deletions(-) diff --git a/.github/workflows/flutter-build.yml b/.github/workflows/flutter-build.yml index fdd7ea7cc..961029ed6 100644 --- a/.github/workflows/flutter-build.yml +++ b/.github/workflows/flutter-build.yml @@ -1443,7 +1443,8 @@ jobs: rpm \ unzip \ wget \ - xz-utils + xz-utils \ + libssl-dev # we have libopus compiled by us. apt-get remove -y libopus-dev || true # output devs @@ -1723,12 +1724,13 @@ jobs: unzip \ wget \ xz-utils \ - zip + zip \ + libssl-dev # arm-linux needs CMake and vcokg built from source as there # are no prebuilts available from Kitware and Microsoft if [ "${{ matrix.job.vcpkg-triplet }}" = "arm-linux" ]; then # install gcc/g++ 8 for vcpkg and OpenSSL headers for CMake - apt-get install -y gcc-8 g++-8 libssl-dev + apt-get install -y gcc-8 g++-8 # bootstrap CMake amd add it to PATH git clone --depth 1 https://github.com/kitware/cmake -b "v${{ env.SCITER_ARMV7_CMAKE_VERSION }}" /tmp/cmake pushd /tmp/cmake diff --git a/Cargo.lock b/Cargo.lock index e29de16a5..97cf52639 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -328,13 +328,13 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.11" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd066d0b4ef8ecb03a55319dc13aa6910616d0f44008a045bb1835af830abff5" +checksum = "5a89bce6054c720275ac2432fbba080a66a2106a44a1b804553930ca6909f4e0" dependencies = [ - "flate2", + "compression-codecs", + "compression-core", "futures-core", - "memchr", "pin-project-lite", "tokio", ] @@ -1269,6 +1269,23 @@ dependencies = [ "memchr", ] +[[package]] +name = "compression-codecs" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8a506ec4b81c460798f572caead636d57d3d7e940f998160f52bd254bf2d23" +dependencies = [ + "compression-core", + "flate2", + "memchr", +] + +[[package]] +name = "compression-core" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e47641d3deaf41fb1538ac1f54735925e275eaf3bf4d55c81b137fba797e5cbb" + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -3360,14 +3377,14 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-rustls", - "tokio-socks 0.5.2-3", + "tokio-socks", "tokio-tungstenite", "tokio-util", "toml 0.7.8", "tungstenite", "url", "uuid", - "webpki-roots 1.0.0", + "webpki-roots 1.0.4", "whoami", "winapi 0.3.9", "zstd 0.13.1", @@ -3521,18 +3538,20 @@ dependencies = [ [[package]] name = "hyper" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", + "futures-core", "http", "http-body", "httparse", "itoa 1.0.11", "pin-project-lite", + "pin-utils", "smallvec", "tokio", "want", @@ -3540,9 +3559,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.6" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a01595e11bdcec50946522c32dde3fc6914743000a68b93000965f2f02406d" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ "http", "hyper", @@ -3553,7 +3572,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.0", + "webpki-roots 1.0.4", ] [[package]] @@ -3574,17 +3593,21 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.12" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9f1e950e0d9d1d3c47184416723cf29c0d1f93bd8cccf37e4beb6b44f31710" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ + "base64 0.22.1", "bytes", "futures-channel", + "futures-core", "futures-util", "http", "http-body", "hyper", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2 0.5.10", "tokio", @@ -3753,9 +3776,19 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde 1.0.203", +] [[package]] name = "is-terminal" @@ -4302,12 +4335,6 @@ dependencies = [ "objc", ] -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -5218,6 +5245,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-src" +version = "300.5.3+3.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6bad8cd0233b63971e232cc9c5e83039375b8586d2312f31fda85db8f888c2" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.104" @@ -5226,6 +5262,7 @@ checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] @@ -5939,9 +5976,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ "bytes", "cfg_aliases 0.2.1", @@ -5959,9 +5996,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.12" +version = "0.11.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ "bytes", "getrandom 0.3.2", @@ -5980,9 +6017,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.12" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" dependencies = [ "cfg_aliases 0.2.1", "libc", @@ -6341,8 +6378,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.15" -source = "git+https://github.com/rustdesk-org/reqwest#9e859438203a71eb86ddc294fbebfde14cba7f7c" +version = "0.12.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" dependencies = [ "async-compression", "base64 0.22.1", @@ -6357,18 +6395,14 @@ dependencies = [ "hyper-rustls", "hyper-tls", "hyper-util", - "ipnet", "js-sys", "log", - "mime", "native-tls", - "once_cell", "percent-encoding", "pin-project-lite", "quinn", "rustls", "rustls-native-certs", - "rustls-pemfile", "rustls-pki-types", "serde 1.0.203", "serde_json 1.0.118", @@ -6377,16 +6411,15 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-rustls", - "tokio-socks 0.5.2", "tokio-util", "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.26.9", - "windows-registry", + "webpki-roots 1.0.4", ] [[package]] @@ -6587,6 +6620,7 @@ dependencies = [ "objc", "objc_id", "once_cell", + "openssl", "os-version", "pam", "parity-tokio-ipc", @@ -6725,15 +6759,6 @@ dependencies = [ "security-framework 3.5.1", ] -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "rustls-pki-types" version = "1.11.0" @@ -7935,18 +7960,6 @@ dependencies = [ "tokio-util", ] -[[package]] -name = "tokio-socks" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f" -dependencies = [ - "either", - "futures-util", - "thiserror 1.0.61", - "tokio", -] - [[package]] name = "tokio-tungstenite" version = "0.26.2" @@ -8082,6 +8095,24 @@ dependencies = [ "tower-service", ] +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags 2.9.1", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -8867,9 +8898,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" +checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" dependencies = [ "rustls-pki-types", ] @@ -9194,17 +9225,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-registry" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" -dependencies = [ - "windows-result 0.3.2", - "windows-strings 0.3.1", - "windows-targets 0.53.0", -] - [[package]] name = "windows-result" version = "0.1.2" @@ -9318,29 +9338,13 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", + "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - [[package]] name = "windows-version" version = "0.1.1" @@ -9377,12 +9381,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - [[package]] name = "windows_aarch64_msvc" version = "0.32.0" @@ -9413,12 +9411,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - [[package]] name = "windows_i686_gnu" version = "0.32.0" @@ -9449,24 +9441,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - [[package]] name = "windows_i686_msvc" version = "0.32.0" @@ -9497,12 +9477,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - [[package]] name = "windows_x86_64_gnu" version = "0.32.0" @@ -9533,12 +9507,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -9557,12 +9525,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - [[package]] name = "windows_x86_64_msvc" version = "0.32.0" @@ -9593,12 +9555,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - [[package]] name = "winit" version = "0.30.9" diff --git a/Cargo.toml b/Cargo.toml index 62af2c29c..d80ef28d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,6 +83,8 @@ shutdown_hooks = "0.1" totp-rs = { version = "5.4", default-features = false, features = ["gen_secret", "otpauth"] } stunclient = "0.4" kcp-sys= { git = "https://github.com/rustdesk-org/kcp-sys"} +reqwest = { version = "0.12", features = ["blocking", "socks", "json", "native-tls", "rustls-tls", "rustls-tls-native-roots", "gzip"], default-features=false } + [target.'cfg(not(target_os = "linux"))'.dependencies] # https://github.com/rustdesk/rustdesk/discussions/10197, not use cpal on linux cpal = { git = "https://github.com/rustdesk-org/cpal", branch = "osx-screencapturekit" } @@ -165,13 +167,6 @@ fontdb = "0.23" bytemuck = "1.23" ttf-parser = "0.25" -[target.'cfg(any(target_os = "macos", target_os = "windows"))'.dependencies] -# https://github.com/rustdesk/rustdesk-server-pro/issues/189, using native-tls for better tls support -reqwest = { git = "https://github.com/rustdesk-org/reqwest", features = ["blocking", "socks", "json", "native-tls", "gzip"], default-features=false } - -[target.'cfg(not(any(target_os = "macos", target_os = "windows")))'.dependencies] -reqwest = { git = "https://github.com/rustdesk-org/reqwest", features = ["blocking", "socks", "json", "rustls-tls", "rustls-tls-native-roots", "gzip"], default-features=false } - [target.'cfg(target_os = "linux")'.dependencies] psimple = { package = "libpulse-simple-binding", version = "2.27" } pulse = { package = "libpulse-binding", version = "2.27" } @@ -192,6 +187,9 @@ termios = "0.3" terminfo = "0.8" winit = "0.30" +[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies] +openssl = { version = "0.10", features = ["vendored"] } + [target.'cfg(target_os = "android")'.dependencies] android_logger = "0.13" jni = "0.21" diff --git a/flutter/lib/common/widgets/login.dart b/flutter/lib/common/widgets/login.dart index c1f18f0a8..5fafc87b9 100644 --- a/flutter/lib/common/widgets/login.dart +++ b/flutter/lib/common/widgets/login.dart @@ -400,6 +400,8 @@ Future loginDialog() async { String? passwordMsg; var isInProgress = false; final RxString curOP = ''.obs; + // Track hover state for the close icon + bool isCloseHovered = false; final loginOptions = [].obs; Future.delayed(Duration.zero, () async { @@ -557,21 +559,27 @@ Future loginDialog() async { Text( translate('Login'), ).marginOnly(top: MyTheme.dialogPadding), - InkWell( - child: Icon( - Icons.close, - size: 25, - // No need to handle the branch of null. - // Because we can ensure the color is not null when debug. - color: Theme.of(context) - .textTheme - .titleLarge - ?.color - ?.withOpacity(0.55), + MouseRegion( + onEnter: (_) => setState(() => isCloseHovered = true), + onExit: (_) => setState(() => isCloseHovered = false), + child: InkWell( + child: Icon( + Icons.close, + size: 25, + // No need to handle the branch of null. + // Because we can ensure the color is not null when debug. + color: isCloseHovered + ? Colors.white + : Theme.of(context) + .textTheme + .titleLarge + ?.color + ?.withOpacity(0.55), + ), + onTap: onDialogCancel, + hoverColor: Colors.red, + borderRadius: BorderRadius.circular(5), ), - onTap: onDialogCancel, - hoverColor: Colors.red, - borderRadius: BorderRadius.circular(5), ).marginOnly(top: 10, right: 15), ], ); diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index 35f7e90e9..64631c6c5 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -162,8 +162,11 @@ const String kOptionShowVirtualJoystick = "show-virtual-joystick"; // network options const String kOptionAllowWebSocket = "allow-websocket"; +const String kOptionAllowInsecureTLSFallback = "allow-insecure-tls-fallback"; +const String kOptionDisableUdp = "disable-udp"; +const String kOptionEnableFlutterHttpOnRust = "enable-flutter-http-on-rust"; -// buildin opitons +// builtin options const String kOptionHideServerSetting = "hide-server-settings"; const String kOptionHideProxySetting = "hide-proxy-settings"; const String kOptionHideWebSocketSetting = "hide-websocket-settings"; diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 6d1ef3a8b..d39bafe6e 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -1585,6 +1585,27 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin { ); } + Widget switchWidget(IconData icon, String title, String tooltipMessage, + String optionKey) => + listTile( + icon: icon, + title: title, + showTooltip: true, + tooltipMessage: tooltipMessage, + trailing: Switch( + value: mainGetBoolOptionSync(optionKey), + onChanged: locked || isOptionFixed(optionKey) + ? null + : (value) { + mainSetBoolOption(optionKey, value); + setState(() {}); + }, + ), + ); + + final outgoingOnly = bind.isOutgoingOnly(); + + final divider = const Divider(height: 1, indent: 16, endIndent: 16); return _Card( title: 'Network', children: [ @@ -1596,33 +1617,65 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin { listTile( icon: Icons.dns_outlined, title: 'ID/Relay Server', - onTap: () => showServerSettings(gFFI.dialogManager), + onTap: () => showServerSettings(gFFI.dialogManager, setState), ), - if (!hideServer && (!hideProxy || !hideWebSocket)) - Divider(height: 1, indent: 16, endIndent: 16), + if (!hideProxy && !hideServer) divider, if (!hideProxy) listTile( icon: Icons.network_ping_outlined, title: 'Socks5/Http(s) Proxy', onTap: changeSocks5Proxy, ), - if (!hideProxy && !hideWebSocket) - Divider(height: 1, indent: 16, endIndent: 16), + if (!hideWebSocket && (!hideServer || !hideProxy)) divider, if (!hideWebSocket) - listTile( - icon: Icons.web_asset_outlined, - title: 'Use WebSocket', - showTooltip: true, - tooltipMessage: 'websocket_tip', - trailing: Switch( - value: mainGetBoolOptionSync(kOptionAllowWebSocket), - onChanged: locked - ? null - : (value) { - mainSetBoolOption(kOptionAllowWebSocket, value); - setState(() {}); - }, - ), + switchWidget( + Icons.web_asset_outlined, + 'Use WebSocket', + '${translate('websocket_tip')}\n\n${translate('oss-not-support-tip')}', + kOptionAllowWebSocket), + if (!isWeb) + futureBuilder( + future: bind.mainIsUsingPublicServer(), + hasData: (isUsingPublicServer) { + if (isUsingPublicServer) { + return Offstage(); + } else { + return Column( + children: [ + if (!hideServer || !hideProxy || !hideWebSocket) + divider, + switchWidget( + Icons.no_encryption_outlined, + 'Allow insecure TLS fallback', + 'allow-insecure-tls-fallback-tip', + kOptionAllowInsecureTLSFallback), + if (!outgoingOnly) divider, + if (!outgoingOnly) + listTile( + icon: Icons.lan_outlined, + title: 'Disable UDP', + showTooltip: true, + tooltipMessage: + '${translate('disable-udp-tip')}\n\n${translate('oss-not-support-tip')}', + trailing: Switch( + value: bind.mainGetOptionSync( + key: kOptionDisableUdp) == + 'Y', + onChanged: + locked || isOptionFixed(kOptionDisableUdp) + ? null + : (value) async { + await bind.mainSetOption( + key: kOptionDisableUdp, + value: value ? 'Y' : 'N'); + setState(() {}); + }, + ), + ), + ], + ); + } + }, ), ], ), @@ -1742,9 +1795,9 @@ class _DisplayState extends State<_Display> { } Widget trackpadSpeed(BuildContext context) { - final initSpeed = (int.tryParse( - bind.mainGetUserDefaultOption(key: kKeyTrackpadSpeed)) ?? - kDefaultTrackpadSpeed); + final initSpeed = + (int.tryParse(bind.mainGetUserDefaultOption(key: kKeyTrackpadSpeed)) ?? + kDefaultTrackpadSpeed); final curSpeed = SimpleWrapper(initSpeed); void onDebouncer(int v) { bind.mainSetUserDefaultOption( diff --git a/flutter/lib/mobile/pages/scan_page.dart b/flutter/lib/mobile/pages/scan_page.dart index e92400dba..5bc033565 100644 --- a/flutter/lib/mobile/pages/scan_page.dart +++ b/flutter/lib/mobile/pages/scan_page.dart @@ -156,7 +156,7 @@ class _ScanPageState extends State { try { final sc = ServerConfig.decode(data.substring(7)); Timer(Duration(milliseconds: 60), () { - showServerSettingsWithValue(sc, gFFI.dialogManager); + showServerSettingsWithValue(sc, gFFI.dialogManager, null); }); } catch (e) { showToast('Invalid QR code'); diff --git a/flutter/lib/mobile/pages/settings_page.dart b/flutter/lib/mobile/pages/settings_page.dart index 5c9d28383..bb801c5db 100644 --- a/flutter/lib/mobile/pages/settings_page.dart +++ b/flutter/lib/mobile/pages/settings_page.dart @@ -94,7 +94,10 @@ class _SettingsState extends State with WidgetsBindingObserver { var _hideWebSocket = false; var _enableTrustedDevices = false; var _enableUdpPunch = false; + var _allowInsecureTlsFallback = false; + var _disableUdp = false; var _enableIpv6Punch = false; + var _isUsingPublicServer = false; _SettingsState() { _enableAbr = option2bool( @@ -109,6 +112,9 @@ class _SettingsState extends State with WidgetsBindingObserver { _enableHardwareCodec = option2bool(kOptionEnableHwcodec, bind.mainGetOptionSync(key: kOptionEnableHwcodec)); _allowWebSocket = mainGetBoolOptionSync(kOptionAllowWebSocket); + _allowInsecureTlsFallback = + mainGetBoolOptionSync(kOptionAllowInsecureTLSFallback); + _disableUdp = bind.mainGetOptionSync(key: kOptionDisableUdp) == 'Y'; _autoRecordIncomingSession = option2bool(kOptionAllowAutoRecordIncoming, bind.mainGetOptionSync(key: kOptionAllowAutoRecordIncoming)); _autoRecordOutgoingSession = option2bool(kOptionAllowAutoRecordOutgoing, @@ -200,6 +206,13 @@ class _SettingsState extends State with WidgetsBindingObserver { update = true; _buildDate = buildDate; } + + final isUsingPublicServer = await bind.mainIsUsingPublicServer(); + if (_isUsingPublicServer != isUsingPublicServer) { + update = true; + _isUsingPublicServer = isUsingPublicServer; + } + if (update) { setState(() {}); } @@ -667,7 +680,10 @@ class _SettingsState extends State with WidgetsBindingObserver { title: Text(translate('ID/Relay Server')), leading: Icon(Icons.cloud), onPressed: (context) { - showServerSettings(gFFI.dialogManager); + showServerSettings(gFFI.dialogManager, (callback) async { + _isUsingPublicServer = await bind.mainIsUsingPublicServer(); + setState(callback); + }); }), if (!isIOS && !_hideNetwork && !_hideProxy) SettingsTile( @@ -691,6 +707,38 @@ class _SettingsState extends State with WidgetsBindingObserver { }); }, ), + if (!_isUsingPublicServer) + SettingsTile.switchTile( + title: Text(translate('Allow insecure TLS fallback')), + initialValue: _allowInsecureTlsFallback, + onToggle: isOptionFixed(kOptionAllowInsecureTLSFallback) + ? null + : (v) async { + await mainSetBoolOption( + kOptionAllowInsecureTLSFallback, v); + final newValue = mainGetBoolOptionSync( + kOptionAllowInsecureTLSFallback); + setState(() { + _allowInsecureTlsFallback = newValue; + }); + }, + ), + if (isAndroid && !outgoingOnly && !_isUsingPublicServer) + SettingsTile.switchTile( + title: Text(translate('Disable UDP')), + initialValue: _disableUdp, + onToggle: isOptionFixed(kOptionDisableUdp) + ? null + : (v) async { + await bind.mainSetOption( + key: kOptionDisableUdp, value: v ? 'Y' : 'N'); + final newValue = + bind.mainGetOptionSync(key: kOptionDisableUdp) == 'Y'; + setState(() { + _disableUdp = newValue; + }); + }, + ), if (!incomingOnly) SettingsTile.switchTile( title: Text(translate('Enable UDP hole punching')), diff --git a/flutter/lib/mobile/widgets/dialog.dart b/flutter/lib/mobile/widgets/dialog.dart index ebedd79d4..f6900e5dd 100644 --- a/flutter/lib/mobile/widgets/dialog.dart +++ b/flutter/lib/mobile/widgets/dialog.dart @@ -147,18 +147,22 @@ void setTemporaryPasswordLengthDialog( }, backDismiss: true, clickMaskDismiss: true); } -void showServerSettings(OverlayDialogManager dialogManager) async { +void showServerSettings(OverlayDialogManager dialogManager, + void Function(VoidCallback) setState) async { Map options = {}; try { options = jsonDecode(await bind.mainGetOptions()); } catch (e) { print("Invalid server config: $e"); } - showServerSettingsWithValue(ServerConfig.fromOptions(options), dialogManager); + showServerSettingsWithValue( + ServerConfig.fromOptions(options), dialogManager, setState); } void showServerSettingsWithValue( - ServerConfig serverConfig, OverlayDialogManager dialogManager) async { + ServerConfig serverConfig, + OverlayDialogManager dialogManager, + void Function(VoidCallback)? upSetState) async { var isInProgress = false; final idCtrl = TextEditingController(text: serverConfig.idServer); final relayCtrl = TextEditingController(text: serverConfig.relayServer); @@ -288,6 +292,7 @@ void showServerSettingsWithValue( if (await submit()) { close(); showToast(translate('Successful')); + upSetState?.call(() {}); } else { showToast(translate('Failed')); } diff --git a/flutter/lib/utils/http_service.dart b/flutter/lib/utils/http_service.dart index 49855017b..1618e25ff 100644 --- a/flutter/lib/utils/http_service.dart +++ b/flutter/lib/utils/http_service.dart @@ -1,7 +1,9 @@ import 'dart:convert'; import 'package:flutter/foundation.dart'; +import 'package:flutter_hbb/consts.dart'; import 'package:http/http.dart' as http; import '../models/platform_model.dart'; +import 'package:flutter_hbb/common.dart'; export 'package:http/http.dart' show Response; enum HttpMethod { get, post, put, delete } @@ -15,11 +17,19 @@ class HttpService { }) async { headers ??= {'Content-Type': 'application/json'}; - // Determine if there is currently a proxy setting, and if so, use FFI to call the Rust HTTP method. - final isProxy = await bind.mainGetProxyStatus(); + // Use Rust HTTP implementation for non-web platforms for consistency. + var useFlutterHttp = (isWeb || kIsWeb); + if (!useFlutterHttp) { + final enableFlutterHttpOnRust = + mainGetLocalBoolOptionSync(kOptionEnableFlutterHttpOnRust); + // Use flutter http if: + // Not `enableFlutterHttpOnRust` and no proxy is set + useFlutterHttp = + !(enableFlutterHttpOnRust || await bind.mainGetProxyStatus()); + } - if (!isProxy) { - return await _pollFultterHttp(url, method, headers: headers, body: body); + if (useFlutterHttp) { + return await _pollFlutterHttp(url, method, headers: headers, body: body); } String headersJson = jsonEncode(headers); @@ -34,7 +44,7 @@ class HttpService { return _parseHttpResponse(resJson); } - Future _pollFultterHttp( + Future _pollFlutterHttp( Uri url, HttpMethod method, { Map? headers, @@ -87,7 +97,8 @@ class HttpService { int statusCode = parsedJson['status_code']; return http.Response(body, statusCode, headers: headers); } catch (e) { - throw Exception('Failed to parse response: $e'); + print('Failed to parse response\n$responseJson\nError:\n$e'); + throw Exception('Failed to parse response.\n$responseJson'); } } } diff --git a/libs/hbb_common b/libs/hbb_common index b55451eec..a4053b929 160000 --- a/libs/hbb_common +++ b/libs/hbb_common @@ -1 +1 @@ -Subproject commit b55451eeca27a2d65406dff71c925622c7b0f414 +Subproject commit a4053b929b14059b1bd116900de8a103d9d838ae diff --git a/src/common.rs b/src/common.rs index 90384efa2..4ac3b6cd9 100644 --- a/src/common.rs +++ b/src/common.rs @@ -13,6 +13,7 @@ use hbb_common::whoami; use hbb_common::{ allow_err, anyhow::{anyhow, Context}, + async_recursion::async_recursion, bail, base64, bytes::Bytes, config::{ @@ -27,6 +28,7 @@ use hbb_common::{ socket_client, sodiumoxide::crypto::{box_, secretbox, sign}, timeout, + tls::{get_cached_tls_accept_invalid_cert, get_cached_tls_type, upsert_tls_cache, TlsType}, tokio::{ self, net::UdpSocket, @@ -36,7 +38,7 @@ use hbb_common::{ }; use crate::{ - hbbs_http::create_http_client_async, + hbbs_http::{create_http_client_async, get_url_for_tls}, ui_interface::{get_option, set_option}, }; @@ -908,15 +910,35 @@ pub fn check_software_update() { } } +// No need to check `danger_accept_invalid_cert` for now. +// Because the url is always `https://api.rustdesk.com/version/latest`. #[tokio::main(flavor = "current_thread")] pub async fn do_check_software_update() -> hbb_common::ResultType<()> { let (request, url) = hbb_common::version_check_request(hbb_common::VER_TYPE_RUSTDESK_CLIENT.to_string()); - let latest_release_response = create_http_client_async() - .post(url) - .json(&request) - .send() - .await?; + let proxy_conf = Config::get_socks(); + let tls_url = get_url_for_tls(&url, &proxy_conf); + let tls_type = get_cached_tls_type(tls_url); + let is_tls_not_cached = tls_type.is_none(); + let tls_type = tls_type.unwrap_or(TlsType::Rustls); + let client = create_http_client_async(tls_type, false); + let latest_release_response = match client.post(&url).json(&request).send().await { + Ok(resp) => { + upsert_tls_cache(tls_url, tls_type, false); + resp + } + Err(err) => { + if is_tls_not_cached && err.is_request() { + let tls_type = TlsType::NativeTls; + let client = create_http_client_async(tls_type, false); + let resp = client.post(&url).json(&request).send().await?; + upsert_tls_cache(tls_url, tls_type, false); + resp + } else { + return Err(err.into()); + } + } + }; let bytes = latest_release_response.bytes().await?; let resp: hbb_common::VersionCheckResponse = serde_json::from_slice(&bytes)?; let response_url = resp.url; @@ -1067,7 +1089,38 @@ pub fn get_audit_server(api: String, custom: String, typ: String) -> String { } pub async fn post_request(url: String, body: String, header: &str) -> ResultType { - let mut req = create_http_client_async().post(url); + let proxy_conf = Config::get_socks(); + let tls_url = get_url_for_tls(&url, &proxy_conf); + let tls_type = get_cached_tls_type(tls_url); + let danger_accept_invalid_cert = get_cached_tls_accept_invalid_cert(tls_url); + let response = post_request_( + &url, + tls_url, + body.clone(), + header, + tls_type, + danger_accept_invalid_cert, + danger_accept_invalid_cert, + ) + .await?; + Ok(response.text().await?) +} + +#[async_recursion] +async fn post_request_( + url: &str, + tls_url: &str, + body: String, + header: &str, + tls_type: Option, + danger_accept_invalid_cert: Option, + original_danger_accept_invalid_cert: Option, +) -> ResultType { + let mut req = create_http_client_async( + tls_type.unwrap_or(TlsType::Rustls), + danger_accept_invalid_cert.unwrap_or(false), + ) + .post(url); if !header.is_empty() { let tmp: Vec<&str> = header.split(": ").collect(); if tmp.len() == 2 { @@ -1076,7 +1129,66 @@ pub async fn post_request(url: String, body: String, header: &str) -> ResultType } req = req.header("Content-Type", "application/json"); let to = std::time::Duration::from_secs(12); - Ok(req.body(body).timeout(to).send().await?.text().await?) + if tls_type.is_some() && danger_accept_invalid_cert.is_some() { + // This branch is used to reduce a `clone()` when both `tls_type` and + // `danger_accept_invalid_cert` are cached. + match req.body(body.clone()).timeout(to).send().await { + Ok(resp) => { + upsert_tls_cache( + tls_url, + tls_type.unwrap_or(TlsType::Rustls), + danger_accept_invalid_cert.unwrap_or(false), + ); + Ok(resp) + } + Err(e) => Err(anyhow!("{:?}", e)), + } + } else { + match req.body(body.clone()).timeout(to).send().await { + Ok(resp) => { + upsert_tls_cache( + tls_url, + tls_type.unwrap_or(TlsType::Rustls), + danger_accept_invalid_cert.unwrap_or(false), + ); + Ok(resp) + } + Err(e) => { + if (tls_type.is_none() || danger_accept_invalid_cert.is_none()) && e.is_request() { + if danger_accept_invalid_cert.is_none() { + log::warn!( + "HTTP request failed: {:?}, try again, danger accept invalid cert", + e + ); + post_request_( + url, + tls_url, + body, + header, + tls_type, + Some(true), + original_danger_accept_invalid_cert, + ) + .await + } else { + log::warn!("HTTP request failed: {:?}, try again with native-tls", e); + post_request_( + url, + tls_url, + body, + header, + Some(TlsType::NativeTls), + original_danger_accept_invalid_cert, + original_danger_accept_invalid_cert, + ) + .await + } + } else { + Err(anyhow!("{:?}", e)) + } + } + } + } } #[tokio::main(flavor = "current_thread")] @@ -1084,22 +1196,29 @@ pub async fn post_request_sync(url: String, body: String, header: &str) -> Resul post_request(url, body, header).await } -#[tokio::main(flavor = "current_thread")] -pub async fn http_request_sync( - url: String, - method: String, +#[async_recursion] +async fn get_http_response_async( + url: &str, + tls_url: &str, + method: &str, body: Option, - header: String, -) -> ResultType { - let http_client = create_http_client_async(); - let mut http_client = match method.as_str() { + header: &str, + tls_type: Option, + danger_accept_invalid_cert: Option, + original_danger_accept_invalid_cert: Option, +) -> ResultType { + let http_client = create_http_client_async( + tls_type.unwrap_or(TlsType::Rustls), + danger_accept_invalid_cert.unwrap_or(false), + ); + let mut http_client = match method { "get" => http_client.get(url), "post" => http_client.post(url), "put" => http_client.put(url), "delete" => http_client.delete(url), _ => return Err(anyhow!("The HTTP request method is not supported!")), }; - let v = serde_json::from_str(header.as_str())?; + let v = serde_json::from_str(header)?; if let Value::Object(obj) = v { for (key, value) in obj.iter() { @@ -1109,15 +1228,105 @@ pub async fn http_request_sync( return Err(anyhow!("HTTP header information parsing failed!")); } - if let Some(b) = body { - http_client = http_client.body(b); + if tls_type.is_some() && danger_accept_invalid_cert.is_some() { + if let Some(b) = body { + http_client = http_client.body(b); + } + match http_client + .timeout(std::time::Duration::from_secs(12)) + .send() + .await + { + Ok(resp) => { + upsert_tls_cache( + tls_url, + tls_type.unwrap_or(TlsType::Rustls), + danger_accept_invalid_cert.unwrap_or(false), + ); + Ok(resp) + } + Err(e) => Err(anyhow!("{:?}", e)), + } + } else { + if let Some(b) = body.clone() { + http_client = http_client.body(b); + } + + match http_client + .timeout(std::time::Duration::from_secs(12)) + .send() + .await + { + Ok(resp) => { + upsert_tls_cache( + tls_url, + tls_type.unwrap_or(TlsType::Rustls), + danger_accept_invalid_cert.unwrap_or(false), + ); + Ok(resp) + } + Err(e) => { + if (tls_type.is_none() || danger_accept_invalid_cert.is_none()) && e.is_request() { + if danger_accept_invalid_cert.is_none() { + log::warn!( + "HTTP request failed: {:?}, try again, danger accept invalid cert", + e + ); + get_http_response_async( + url, + tls_url, + method, + body, + header, + tls_type, + Some(true), + original_danger_accept_invalid_cert, + ) + .await + } else { + log::warn!("HTTP request failed: {:?}, try again with native-tls", e); + get_http_response_async( + url, + tls_url, + method, + body, + header, + Some(TlsType::NativeTls), + original_danger_accept_invalid_cert, + original_danger_accept_invalid_cert, + ) + .await + } + } else { + Err(anyhow!("{:?}", e)) + } + } + } } +} - let response = http_client - .timeout(std::time::Duration::from_secs(12)) - .send() - .await?; - +#[tokio::main(flavor = "current_thread")] +pub async fn http_request_sync( + url: String, + method: String, + body: Option, + header: String, +) -> ResultType { + let proxy_conf = Config::get_socks(); + let tls_url = get_url_for_tls(&url, &proxy_conf); + let tls_type = get_cached_tls_type(tls_url); + let danger_accept_invalid_cert = get_cached_tls_accept_invalid_cert(tls_url); + let response = get_http_response_async( + &url, + tls_url, + &method, + body.clone(), + &header, + tls_type, + danger_accept_invalid_cert, + danger_accept_invalid_cert, + ) + .await?; // Serialize response headers let mut response_headers = serde_json::map::Map::new(); for (key, value) in response.headers() { @@ -1772,7 +1981,7 @@ pub fn verify_login(_raw: &str, _id: &str) -> bool { #[inline] pub fn is_udp_disabled() -> bool { - get_builtin_option(keys::OPTION_DISABLE_UDP) == "Y" + Config::get_option(keys::OPTION_DISABLE_UDP) == "Y" } // this crate https://github.com/yoshd/stun-client supports nat type diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 7cf0130e4..dc025b8c8 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -951,10 +951,19 @@ pub fn main_set_option(key: String, value: String) { ); } - if key.eq("custom-rendezvous-server") + // If `is_allow_tls_fallback` and https proxy is used, we need to restart rendezvous mediator. + // No need to check if https proxy is used, because this option does not change frequently + // and restarting mediator is safe even https proxy is not used. + let is_allow_tls_fallback = key.eq(config::keys::OPTION_ALLOW_INSECURE_TLS_FALLBACK); + if is_allow_tls_fallback + || key.eq("custom-rendezvous-server") || key.eq(config::keys::OPTION_ALLOW_WEBSOCKET) + || key.eq(config::keys::OPTION_DISABLE_UDP) || key.eq("api-server") { + if is_allow_tls_fallback { + hbb_common::tls::reset_tls_cache(); + } set_option(key, value.clone()); #[cfg(target_os = "android")] crate::rendezvous_mediator::RendezvousMediator::restart(); @@ -2692,7 +2701,11 @@ pub fn session_get_common_sync( SyncReturn(session_get_common(session_id, key, param)) } -pub fn session_get_common(session_id: SessionID, key: String, #[allow(unused_variables)] param: String) -> Option { +pub fn session_get_common( + session_id: SessionID, + key: String, + #[allow(unused_variables)] param: String, +) -> Option { if let Some(s) = sessions::get_session_by_session_id(&session_id) { let v = if key == "is_screenshot_supported" { s.is_screenshot_supported().to_string() diff --git a/src/hbbs_http.rs b/src/hbbs_http.rs index e79534e2c..20316b6f5 100644 --- a/src/hbbs_http.rs +++ b/src/hbbs_http.rs @@ -4,12 +4,14 @@ use serde_json::{Map, Value}; #[cfg(feature = "flutter")] pub mod account; +pub mod downloader; mod http_client; pub mod record_upload; pub mod sync; -pub mod downloader; -pub use http_client::create_http_client; -pub use http_client::create_http_client_async; +pub use http_client::{ + create_http_client_async, create_http_client_async_with_url, create_http_client_with_url, + get_url_for_tls, +}; #[derive(Debug)] pub enum HbbHttpResponse { diff --git a/src/hbbs_http/account.rs b/src/hbbs_http/account.rs index 5cf223a49..6bdef6f06 100644 --- a/src/hbbs_http/account.rs +++ b/src/hbbs_http/account.rs @@ -1,5 +1,5 @@ use super::HbbHttpResponse; -use crate::hbbs_http::create_http_client; +use crate::hbbs_http::create_http_client_with_url; use hbb_common::{config::LocalConfig, log, ResultType}; use reqwest::blocking::Client; use serde_derive::{Deserialize, Serialize}; @@ -104,7 +104,7 @@ pub struct AuthBody { } pub struct OidcSession { - client: Client, + client: Option, state_msg: &'static str, failed_msg: String, code_url: Option, @@ -131,7 +131,7 @@ impl Default for UserStatus { impl OidcSession { fn new() -> Self { Self { - client: create_http_client(), + client: None, state_msg: REQUESTING_ACCOUNT_AUTH, failed_msg: "".to_owned(), code_url: None, @@ -142,24 +142,36 @@ impl OidcSession { } } + fn ensure_client(api_server: &str) { + let mut write_guard = OIDC_SESSION.write().unwrap(); + if write_guard.client.is_none() { + // This URL is used to detect the appropriate TLS implementation for the server. + let login_option_url = format!("{}/api/login-options", &api_server); + let client = create_http_client_with_url(&login_option_url); + write_guard.client = Some(client); + } + } + fn auth( api_server: &str, op: &str, id: &str, uuid: &str, ) -> ResultType> { - let resp = OIDC_SESSION - .read() - .unwrap() - .client - .post(format!("{}/api/oidc/auth", api_server)) - .json(&serde_json::json!({ - "op": op, - "id": id, - "uuid": uuid, - "deviceInfo": crate::ui_interface::get_login_device_info(), - })) - .send()?; + Self::ensure_client(api_server); + let resp = if let Some(client) = &OIDC_SESSION.read().unwrap().client { + client + .post(format!("{}/api/oidc/auth", api_server)) + .json(&serde_json::json!({ + "op": op, + "id": id, + "uuid": uuid, + "deviceInfo": crate::ui_interface::get_login_device_info(), + })) + .send()? + } else { + hbb_common::bail!("http client not initialized"); + }; let status = resp.status(); match resp.try_into() { Ok(v) => Ok(v), @@ -179,13 +191,12 @@ impl OidcSession { &format!("{}/api/oidc/auth-query", api_server), &[("code", code), ("id", id), ("uuid", uuid)], )?; - Ok(OIDC_SESSION - .read() - .unwrap() - .client - .get(url) - .send()? - .try_into()?) + Self::ensure_client(api_server); + if let Some(client) = &OIDC_SESSION.read().unwrap().client { + Ok(client.get(url).send()?.try_into()?) + } else { + hbb_common::bail!("http client not initialized") + } } fn reset(&mut self) { diff --git a/src/hbbs_http/downloader.rs b/src/hbbs_http/downloader.rs index 4821b0814..2afa2ba28 100644 --- a/src/hbbs_http/downloader.rs +++ b/src/hbbs_http/downloader.rs @@ -1,4 +1,4 @@ -use super::create_http_client_async; +use super::create_http_client_async_with_url; use hbb_common::{ bail, lazy_static::lazy_static, @@ -132,7 +132,7 @@ async fn do_download( auto_del_dur: Option, mut rx_cancel: UnboundedReceiver<()>, ) -> ResultType { - let client = create_http_client_async(); + let client = create_http_client_async_with_url(&url).await; let mut is_all_downloaded = false; tokio::select! { diff --git a/src/hbbs_http/http_client.rs b/src/hbbs_http/http_client.rs index c96877dcb..432e5fa38 100644 --- a/src/hbbs_http/http_client.rs +++ b/src/hbbs_http/http_client.rs @@ -1,23 +1,49 @@ -use hbb_common::config::Config; -use hbb_common::log::info; -use hbb_common::proxy::{Proxy, ProxyScheme}; -use reqwest::blocking::Client as SyncClient; -use reqwest::Client as AsyncClient; +use hbb_common::{ + async_recursion::async_recursion, + config::{Config, Socks5Server}, + log::{self, info}, + proxy::{Proxy, ProxyScheme}, + tls::{ + get_cached_tls_accept_invalid_cert, get_cached_tls_type, is_plain, upsert_tls_cache, + TlsType, + }, +}; +use reqwest::{blocking::Client as SyncClient, Client as AsyncClient}; macro_rules! configure_http_client { - ($builder:expr, $Client: ty) => {{ + ($builder:expr, $tls_type:expr, $danger_accept_invalid_cert:expr, $Client: ty) => {{ // https://github.com/rustdesk/rustdesk/issues/11569 // https://docs.rs/reqwest/latest/reqwest/struct.ClientBuilder.html#method.no_proxy let mut builder = $builder.no_proxy(); - #[cfg(any(target_os = "android", target_os = "ios"))] - match hbb_common::verifier::client_config() { - Ok(client_config) => { - builder = builder.use_preconfigured_tls(client_config); + + match $tls_type { + TlsType::Plain => {} + TlsType::NativeTls => { + builder = builder.use_native_tls(); + if $danger_accept_invalid_cert { + builder = builder.danger_accept_invalid_certs(true); + } } - Err(e) => { - hbb_common::log::error!("Failed to get client config: {}", e); + TlsType::Rustls => { + #[cfg(any(target_os = "android", target_os = "ios"))] + match hbb_common::verifier::client_config($danger_accept_invalid_cert) { + Ok(client_config) => { + builder = builder.use_preconfigured_tls(client_config); + } + Err(e) => { + hbb_common::log::error!("Failed to get client config: {}", e); + } + } + #[cfg(not(any(target_os = "android", target_os = "ios")))] + { + builder = builder.use_rustls_tls(); + if $danger_accept_invalid_cert { + builder = builder.danger_accept_invalid_certs(true); + } + } } } + let client = if let Some(conf) = Config::get_socks() { let proxy_result = Proxy::from_conf(&conf, None); @@ -70,12 +96,241 @@ macro_rules! configure_http_client { }}; } -pub fn create_http_client() -> SyncClient { +pub fn create_http_client(tls_type: TlsType, danger_accept_invalid_cert: bool) -> SyncClient { let builder = SyncClient::builder(); - configure_http_client!(builder, SyncClient) + configure_http_client!(builder, tls_type, danger_accept_invalid_cert, SyncClient) } -pub fn create_http_client_async() -> AsyncClient { +pub fn create_http_client_async( + tls_type: TlsType, + danger_accept_invalid_cert: bool, +) -> AsyncClient { let builder = AsyncClient::builder(); - configure_http_client!(builder, AsyncClient) + configure_http_client!(builder, tls_type, danger_accept_invalid_cert, AsyncClient) +} + +pub fn get_url_for_tls<'a>(url: &'a str, proxy_conf: &'a Option) -> &'a str { + if is_plain(url) { + if let Some(conf) = proxy_conf { + if conf.proxy.starts_with("https://") { + return &conf.proxy; + } + } + } + url +} + +pub fn create_http_client_with_url(url: &str) -> SyncClient { + let proxy_conf = Config::get_socks(); + let tls_url = get_url_for_tls(url, &proxy_conf); + let tls_type = get_cached_tls_type(tls_url); + let is_tls_type_cached = tls_type.is_some(); + let tls_type = tls_type.unwrap_or(TlsType::Rustls); + let tls_danger_accept_invalid_cert = get_cached_tls_accept_invalid_cert(tls_url); + create_http_client_with_url_( + url, + tls_url, + tls_type, + is_tls_type_cached, + tls_danger_accept_invalid_cert, + tls_danger_accept_invalid_cert, + ) +} + +fn create_http_client_with_url_( + url: &str, + tls_url: &str, + tls_type: TlsType, + is_tls_type_cached: bool, + danger_accept_invalid_cert: Option, + original_danger_accept_invalid_cert: Option, +) -> SyncClient { + let mut client = create_http_client(tls_type, danger_accept_invalid_cert.unwrap_or(false)); + if is_tls_type_cached && original_danger_accept_invalid_cert.is_some() { + return client; + } + if let Err(e) = client.head(url).send() { + if e.is_request() { + match (tls_type, is_tls_type_cached, danger_accept_invalid_cert) { + (TlsType::Rustls, _, None) => { + log::warn!( + "Failed to connect to server {} with rustls-tls: {:?}, trying accept invalid cert", + tls_url, + e + ); + client = create_http_client_with_url_( + url, + tls_url, + tls_type, + is_tls_type_cached, + Some(true), + original_danger_accept_invalid_cert, + ); + } + (TlsType::Rustls, false, Some(_)) => { + log::warn!( + "Failed to connect to server {} with rustls-tls: {:?}, trying native-tls", + tls_url, + e + ); + client = create_http_client_with_url_( + url, + tls_url, + TlsType::NativeTls, + is_tls_type_cached, + original_danger_accept_invalid_cert, + original_danger_accept_invalid_cert, + ); + } + (TlsType::NativeTls, _, None) => { + log::warn!( + "Failed to connect to server {} with native-tls: {:?}, trying accept invalid cert", + tls_url, + e + ); + client = create_http_client_with_url_( + url, + tls_url, + tls_type, + is_tls_type_cached, + Some(true), + original_danger_accept_invalid_cert, + ); + } + _ => { + log::error!( + "Failed to connect to server {} with {:?}, err: {:?}.", + tls_url, + tls_type, + e + ); + } + } + } else { + log::warn!( + "Failed to connect to server {} with {:?}, err: {}.", + tls_url, + tls_type, + e + ); + } + } else { + log::info!( + "Successfully connected to server {} with {:?}", + tls_url, + tls_type + ); + upsert_tls_cache( + tls_url, + tls_type, + danger_accept_invalid_cert.unwrap_or(false), + ); + } + client +} + +pub async fn create_http_client_async_with_url(url: &str) -> AsyncClient { + let proxy_conf = Config::get_socks(); + let tls_url = get_url_for_tls(url, &proxy_conf); + let tls_type = get_cached_tls_type(tls_url); + let is_tls_type_cached = tls_type.is_some(); + let tls_type = tls_type.unwrap_or(TlsType::Rustls); + let danger_accept_invalid_cert = get_cached_tls_accept_invalid_cert(tls_url); + create_http_client_async_with_url_( + url, + tls_url, + tls_type, + is_tls_type_cached, + danger_accept_invalid_cert, + danger_accept_invalid_cert, + ) + .await +} + +#[async_recursion] +async fn create_http_client_async_with_url_( + url: &str, + tls_url: &str, + tls_type: TlsType, + is_tls_type_cached: bool, + danger_accept_invalid_cert: Option, + original_danger_accept_invalid_cert: Option, +) -> AsyncClient { + let mut client = + create_http_client_async(tls_type, danger_accept_invalid_cert.unwrap_or(false)); + if is_tls_type_cached && original_danger_accept_invalid_cert.is_some() { + return client; + } + if let Err(e) = client.head(url).send().await { + match (tls_type, is_tls_type_cached, danger_accept_invalid_cert) { + (TlsType::Rustls, _, None) => { + log::warn!( + "Failed to connect to server {} with rustls-tls: {:?}, trying accept invalid cert", + tls_url, + e + ); + client = create_http_client_async_with_url_( + url, + tls_url, + tls_type, + is_tls_type_cached, + Some(true), + original_danger_accept_invalid_cert, + ) + .await; + } + (TlsType::Rustls, false, Some(_)) => { + log::warn!( + "Failed to connect to server {} with rustls-tls: {:?}, trying native-tls", + tls_url, + e + ); + client = create_http_client_async_with_url_( + url, + tls_url, + TlsType::NativeTls, + is_tls_type_cached, + original_danger_accept_invalid_cert, + original_danger_accept_invalid_cert, + ) + .await; + } + (TlsType::NativeTls, _, None) => { + log::warn!( + "Failed to connect to server {} with native-tls: {:?}, trying accept invalid cert", + tls_url, + e + ); + client = create_http_client_async_with_url_( + url, + tls_url, + tls_type, + is_tls_type_cached, + Some(true), + original_danger_accept_invalid_cert, + ) + .await; + } + _ => { + log::error!( + "Failed to connect to server {} with {:?}, err: {:?}.", + tls_url, + tls_type, + e + ); + } + } + } else { + log::info!( + "Successfully connected to server {} with {:?}", + tls_url, + tls_type + ); + upsert_tls_cache( + tls_url, + tls_type, + danger_accept_invalid_cert.unwrap_or(false), + ); + } + client } diff --git a/src/hbbs_http/record_upload.rs b/src/hbbs_http/record_upload.rs index a25aae42d..ac51d5c32 100644 --- a/src/hbbs_http/record_upload.rs +++ b/src/hbbs_http/record_upload.rs @@ -1,4 +1,4 @@ -use crate::hbbs_http::create_http_client; +use crate::hbbs_http::create_http_client_with_url; use bytes::Bytes; use hbb_common::{bail, config::Config, lazy_static, log, ResultType}; use reqwest::blocking::{Body, Client}; @@ -25,51 +25,57 @@ pub fn is_enable() -> bool { } pub fn run(rx: Receiver) { - let mut uploader = RecordUploader { - client: create_http_client(), - api_server: crate::get_api_server( + std::thread::spawn(move || { + let api_server = crate::get_api_server( Config::get_option("api-server"), Config::get_option("custom-rendezvous-server"), - ), - filepath: Default::default(), - filename: Default::default(), - upload_size: Default::default(), - running: Default::default(), - last_send: Instant::now(), - }; - std::thread::spawn(move || loop { - if let Err(e) = match rx.recv() { - Ok(state) => match state { - RecordState::NewFile(filepath) => uploader.handle_new_file(filepath), - RecordState::NewFrame => { - if uploader.running { - uploader.handle_frame(false) - } else { - Ok(()) + ); + // This URL is used for TLS connectivity testing and fallback detection. + let login_option_url = format!("{}/api/login-options", &api_server); + let client = create_http_client_with_url(&login_option_url); + let mut uploader = RecordUploader { + client, + api_server, + filepath: Default::default(), + filename: Default::default(), + upload_size: Default::default(), + running: Default::default(), + last_send: Instant::now(), + }; + loop { + if let Err(e) = match rx.recv() { + Ok(state) => match state { + RecordState::NewFile(filepath) => uploader.handle_new_file(filepath), + RecordState::NewFrame => { + if uploader.running { + uploader.handle_frame(false) + } else { + Ok(()) + } } - } - RecordState::WriteTail => { - if uploader.running { - uploader.handle_tail() - } else { - Ok(()) + RecordState::WriteTail => { + if uploader.running { + uploader.handle_tail() + } else { + Ok(()) + } } - } - RecordState::RemoveFile => { - if uploader.running { - uploader.handle_remove() - } else { - Ok(()) + RecordState::RemoveFile => { + if uploader.running { + uploader.handle_remove() + } else { + Ok(()) + } } + }, + Err(e) => { + log::trace!("upload thread stop: {}", e); + break; } - }, - Err(e) => { - log::trace!("upload thread stop: {}", e); - break; + } { + uploader.running = false; + log::error!("upload stop: {}", e); } - } { - uploader.running = false; - log::error!("upload stop: {}", e); } }); } diff --git a/src/ipc.rs b/src/ipc.rs index b50795516..2281686ac 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -363,6 +363,8 @@ pub struct CheckIfRestart { audio_input: String, voice_call_input: String, ws: String, + disable_udp: String, + allow_insecure_tls_fallback: String, api_server: String, } @@ -374,17 +376,31 @@ impl CheckIfRestart { audio_input: Config::get_option("audio-input"), voice_call_input: Config::get_option("voice-call-input"), ws: Config::get_option(OPTION_ALLOW_WEBSOCKET), + disable_udp: Config::get_option(config::keys::OPTION_DISABLE_UDP), + allow_insecure_tls_fallback: Config::get_option( + config::keys::OPTION_ALLOW_INSECURE_TLS_FALLBACK, + ), api_server: Config::get_option("api-server"), } } } impl Drop for CheckIfRestart { fn drop(&mut self) { - if self.stop_service != Config::get_option("stop-service") + // If https proxy is used, we need to restart rendezvous mediator. + // No need to check if https proxy is used, because this option does not change frequently + // and restarting mediator is safe even https proxy is not used. + let allow_insecure_tls_fallback_changed = self.allow_insecure_tls_fallback + != Config::get_option(config::keys::OPTION_ALLOW_INSECURE_TLS_FALLBACK); + if allow_insecure_tls_fallback_changed + || self.stop_service != Config::get_option("stop-service") || self.rendezvous_servers != Config::get_rendezvous_servers() || self.ws != Config::get_option(OPTION_ALLOW_WEBSOCKET) + || self.disable_udp != Config::get_option(config::keys::OPTION_DISABLE_UDP) || self.api_server != Config::get_option("api-server") { + if allow_insecure_tls_fallback_changed { + hbb_common::tls::reset_tls_cache(); + } RendezvousMediator::restart(); } if self.audio_input != Config::get_option("audio-input") { diff --git a/src/lang/ar.rs b/src/lang/ar.rs index 6f92da46a..381c91c6c 100644 --- a/src/lang/ar.rs +++ b/src/lang/ar.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/be.rs b/src/lang/be.rs index 06ed18b44..6ad8a6190 100644 --- a/src/lang/be.rs +++ b/src/lang/be.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/bg.rs b/src/lang/bg.rs index ab73ad990..a5c7aae13 100644 --- a/src/lang/bg.rs +++ b/src/lang/bg.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ca.rs b/src/lang/ca.rs index f9e0f2296..f4b968270 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", "Edita la nota"), ("Alias", "Alias"), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index f6a1b7c03..a1d10b692 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -721,6 +721,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show virtual joystick", "显示虚拟摇杆"), ("Edit note", "编辑备注"), ("Alias", "别名"), - ("ScrollEdge", ""), + ("ScrollEdge", "边缘滚动"), + ("Allow insecure TLS fallback", "允许回退到不安全的 TLS 连接"), + ("allow-insecure-tls-fallback-tip", "默认情况下,对于使用 TLS 的协议,RustDesk 会验证服务器证书。\n启用此选项后,在验证失败时,RustDesk 将转为跳过验证步骤并继续连接。"), + ("Disable UDP", "禁用 UDP"), + ("disable-udp-tip", "控制是否仅使用TCP。\n启用此选项后,RustDesk 将不再使用UDP 21116,而是使用TCP 21116。"), + ("oss-not-support-tip", "注意:RustDesk 开源服务器(oss server) 不包含此功能。"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 069bf13ff..ba73a24ea 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index a8b34b4fd..bb06048d8 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 915d0dcf1..a39d6f8ed 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", "Hinweis bearbeiten"), ("Alias", "Alias"), ("ScrollEdge", "Scrollen am Rand"), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/el.rs b/src/lang/el.rs index 61fe674b1..816fb57d6 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/en.rs b/src/lang/en.rs index dafa8f070..61199b861 100644 --- a/src/lang/en.rs +++ b/src/lang/en.rs @@ -258,5 +258,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("websocket_tip", "When using WebSocket, only relay connections are supported."), ("terminal-admin-login-tip", "Please input the administrator username and password of the controlled side."), ("elevation_username_tip", "Input username or domain\\username"), + ("allow-insecure-tls-fallback-tip", "By default, RustDesk verifies the server certificate for protocols using TLS.\nWith this option enabled, RustDesk will fall back to skipping the verification step and proceed in case of verification failure."), + ("disable-udp-tip", "Controls whether to use TCP only.\nWhen this option enabled, RustDesk will not use UDP 21116 any more, TCP 21116 will be used instead."), + ("oss-not-support-tip", "NOTE: RustDesk server oss doesn't include this feature."), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index a22fd331e..9f1f9562f 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index 857a95730..73c6f8d24 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", "Editar nota"), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/et.rs b/src/lang/et.rs index 18c63028c..a589883a1 100644 --- a/src/lang/et.rs +++ b/src/lang/et.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eu.rs b/src/lang/eu.rs index 84ceaebb6..e5cb42fac 100644 --- a/src/lang/eu.rs +++ b/src/lang/eu.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index 393773b25..0ee39e128 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fi.rs b/src/lang/fi.rs index 3cc83aa56..a47d1c31e 100644 --- a/src/lang/fi.rs +++ b/src/lang/fi.rs @@ -496,12 +496,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("resolution_custom_tip", "Käytä mukautettua resoluutiota"), ("Collapse toolbar", "Tiivistä työkalupalkki"), ("Accept and Elevate", "Hyväksy ja korota oikeudet"), - ("accept_and_elevate_btn_tooltip", "Hyväksy ja korota oikeudet järjestelmänvalvojaksi"), - ("clipboard_wait_response_timeout_tip", "Leikepöydän pyyntö aikakatkaistiin – ei vastausta etäpäästä."), - ("Incoming connection", "Saapuva yhteys"), - ("Outgoing connection", "Lähtevä yhteys"), - ("Exit", "Poistu"), - ("Open", "Avaa"), + ("accept_and_elevate_btn_tooltip", "Hyväksy ja korota oikeudet järjestelmänvalvojaksi"), + ("clipboard_wait_response_timeout_tip", "Leikepöydän pyyntö aikakatkaistiin – ei vastausta etäpäästä."), + ("Incoming connection", "Saapuva yhteys"), + ("Outgoing connection", "Lähtevä yhteys"), + ("Exit", "Poistu"), + ("Open", "Avaa"), ("logout_tip", "Haluatko varmasti kirjautua ulos?"), ("Service", "Palvelu"), ("Start", "Käynnistä"), @@ -721,5 +721,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show virtual joystick", "Näytä virtuaalinen ohjain"), ("Edit note", "Muokkaa muistiinpanoa"), ("Alias", "Alias"), + ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 4d03dd5c0..a3738eedd 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", "Modifier la note"), ("Alias", "Alias"), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ge.rs b/src/lang/ge.rs index 2b243ce7a..84c628918 100644 --- a/src/lang/ge.rs +++ b/src/lang/ge.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/he.rs b/src/lang/he.rs index c2092789b..878192b9b 100644 --- a/src/lang/he.rs +++ b/src/lang/he.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hr.rs b/src/lang/hr.rs index 4b02796a1..aeff94a8f 100644 --- a/src/lang/hr.rs +++ b/src/lang/hr.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index bb35f417b..044ec3297 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", "Jegyzet szerkesztése"), ("Alias", "Álnév"), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 2aada65ff..d41eb4a6d 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 0a161cdef..97465d571 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", "Modifica nota"), ("Alias", "Alias"), ("ScrollEdge", "Bordo scorrimento"), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 1962c2c29..4d4118c09 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", "メモを編集"), ("Alias", "エイリアス"), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index de0399fee..b274b413c 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", "노트 편집"), ("Alias", "별명"), ("ScrollEdge", "가장자리 스크롤"), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 6ee142fca..c222c2311 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lt.rs b/src/lang/lt.rs index 5a481119b..1c1e86929 100644 --- a/src/lang/lt.rs +++ b/src/lang/lt.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lv.rs b/src/lang/lv.rs index cea1cce4b..d06ffd3f0 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nb.rs b/src/lang/nb.rs index 00df82d59..b78b8d320 100644 --- a/src/lang/nb.rs +++ b/src/lang/nb.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nl.rs b/src/lang/nl.rs index 6ecdc113f..cdc949a9b 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", "Opmerking bewerken"), ("Alias", "Alias"), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 82f9ca8bd..ee7a5d016 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", "Edytuj notatkę"), ("Alias", "Alias"), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 5734d2029..7c6010b05 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 4b210090c..8c067882c 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ro.rs b/src/lang/ro.rs index c6dff88ea..e45c6078d 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index e4afe7020..1b4c1e90e 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", "Изменить заметку"), ("Alias", "Псевдоним"), ("ScrollEdge", "Прокрутка по краю"), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sc.rs b/src/lang/sc.rs index 174e15d7d..2bba419d8 100644 --- a/src/lang/sc.rs +++ b/src/lang/sc.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 0e354eb06..882188445 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sl.rs b/src/lang/sl.rs index dc5215fdf..23efdc9d1 100755 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sq.rs b/src/lang/sq.rs index 8ca030cf0..c9b0334da 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sr.rs b/src/lang/sr.rs index 92f616d81..d1faf2385 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sv.rs b/src/lang/sv.rs index 88a38b4fc..020783f98 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ta.rs b/src/lang/ta.rs index cb54af842..ae2000f1f 100644 --- a/src/lang/ta.rs +++ b/src/lang/ta.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index 4aef3bee9..9cf9b297a 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/th.rs b/src/lang/th.rs index 462b824f1..893f83b10 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 4208d77ea..5fdeff51f 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 284dcb2ba..f6fad4db6 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", "編輯備註"), ("Alias", "別名"), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/uk.rs b/src/lang/uk.rs index 9dcb34ef1..de3c552a6 100644 --- a/src/lang/uk.rs +++ b/src/lang/uk.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vi.rs b/src/lang/vi.rs index 0a8c0d5b5..1637bf3fe 100644 --- a/src/lang/vi.rs +++ b/src/lang/vi.rs @@ -722,5 +722,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Edit note", ""), ("Alias", ""), ("ScrollEdge", ""), + ("Allow insecure TLS fallback", ""), + ("allow-insecure-tls-fallback-tip", ""), + ("Disable UDP", ""), + ("disable-udp-tip", ""), + ("oss-not-support-tip", ""), ].iter().cloned().collect(); } diff --git a/src/ui.rs b/src/ui.rs index 6bf7c68da..a8e33f1ba 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -284,6 +284,18 @@ impl UI { crate::using_public_server() } + fn is_incoming_only(&self) -> bool { + hbb_common::config::is_incoming_only() + } + + pub fn is_outgoing_only(&self) -> bool { + hbb_common::config::is_outgoing_only() + } + + pub fn is_custom_client(&self) -> bool { + crate::common::is_custom_client() + } + fn get_options(&self) -> Value { let hashmap: HashMap = serde_json::from_str(&get_options()).unwrap_or_default(); @@ -671,6 +683,9 @@ impl sciter::EventHandler for UI { fn get_api_server(); fn is_xfce(); fn using_public_server(); + fn is_custom_client(); + fn is_outgoing_only(); + fn is_incoming_only(); fn get_id(); fn temporary_password(); fn update_temporary_password(); diff --git a/src/ui/index.tis b/src/ui/index.tis index bee8bba8c..a35438358 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -9,7 +9,9 @@ var app; var tmp = handler.get_connect_status(); var connect_status = tmp[0]; var service_stopped = handler.get_option("stop-service") == "Y"; +var disable_udp = handler.get_option("disable-udp") == "Y"; var using_public_server = handler.using_public_server(); +var outgoing_only = handler.is_outgoing_only(); var software_update_url = ""; var key_confirmed = tmp[1]; var system_error = ""; @@ -326,8 +328,10 @@ class MyIdMenu: Reactor.Component {
  • {translate('ID/Relay Server')}
  • {translate('IP Whitelisting')}
  • -
  • {translate('Socks5 Proxy')}
  • - { false &&
  • {svg_checkmark}{translate('Use WebSocket')}
  • } +
  • {translate('Socks5/Http(s) Proxy')}
  • +
  • {svg_checkmark}{translate('Use WebSocket')}
  • + {!using_public_server && !outgoing_only &&
  • {svg_checkmark}{translate('Disable UDP')}
  • } + {!using_public_server &&
  • {svg_checkmark}{translate('Allow insecure TLS fallback')}
  • }
  • {svg_checkmark}{translate("Enable service")}
  • {is_win && handler.is_installed() ? : ""} @@ -473,7 +477,7 @@ class MyIdMenu: Reactor.Component { var old_proxy = socks5[0] || ""; var old_username = socks5[1] || ""; var old_password = socks5[2] || ""; - msgbox("custom-server", "Socks5 Proxy",
    + msgbox("custom-server", "Socks5/Http(s) Proxy",
    {translate("Server")}:
    {translate("Username")}:
    {translate("Password")}:
    @@ -485,11 +489,18 @@ class MyIdMenu: Reactor.Component { var password = (res.password || "").trim(); if (proxy == old_proxy && username == old_username && password == old_password) return; if (proxy) { - var err = handler.test_if_valid_server(proxy, false); + var domain_port = proxy; + var protocol_index = domain_port.indexOf('://'); + if (protocol_index !== -1) { + domain_port = domain_port.substring(protocol_index + 3); + } + var err = handler.test_if_valid_server(domain_port, false); if (err) return translate("Server") + ": " + err; } handler.set_socks(proxy, username, password); }, 240); + } else if (me.id == "disable-udp") { + handler.set_option("disable-udp", handler.get_option("disable-udp") == "Y" ? "N" : "Y"); } else if (me.id == "stop-service") { handler.set_option("stop-service", service_stopped ? "" : "Y"); } else if (me.id == "change-id") { @@ -1196,6 +1207,11 @@ function checkConnectStatus() { updateAbPeer(); app.update(); } + tmp = handler.get_option("disable-udp") == "Y"; + if (tmp != disable_udp) { + disable_udp = tmp; + app.update(); + } check_if_overlay(); checkConnectStatus(); }); diff --git a/src/updater.rs b/src/updater.rs index 312edf91e..e1badd005 100644 --- a/src/updater.rs +++ b/src/updater.rs @@ -1,4 +1,4 @@ -use crate::{common::do_check_software_update, hbbs_http::create_http_client}; +use crate::{common::do_check_software_update, hbbs_http::create_http_client_with_url}; use hbb_common::{bail, config, log, ResultType}; use std::{ io::Write, @@ -146,7 +146,7 @@ fn check_update(manually: bool) -> ResultType<()> { format!("{}/rustdesk-{}-x86-sciter.exe", download_url, version) }; log::debug!("New version available: {}", &version); - let client = create_http_client(); + let client = create_http_client_with_url(&download_url); let Some(file_path) = get_download_file_from_url(&download_url) else { bail!("Failed to get the file path from the URL: {}", download_url); };