Compare commits

..

9 Commits

Author SHA1 Message Date
21pages
5abf4e9724 Fix disabled installation bypass (#15598)
* Fix disabled installation bypass

Prevent install.exe and --install from opening the install flow when disable-installation is set.

Signed-off-by: 21pages <sunboeasy@gmail.com>

* Refine disabled installation handling for portable clients

Document why --install must be filtered from both Rust and Flutter runner arguments for portable wrappers such as no-install.exe. Remove redundant UI-
    layer installation checks because the install entry points are already gated upstream.

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-07-16 16:00:38 +08:00
jinqiang zhang
cf2b28faf9 fix linux llvm22 build (#15565)
bindgen-0.65 is incompatible with llvm 22, we should upgrade to a
newer bindgen version

error message:

```
error[E0609]: no field `g_w` on type `vpx_codec_enc_cfg`
  --> libs/scrap/src/common/vpxcodec.rs:66:19
   |
66 |                 c.g_w = config.width;
   |                   ^^^ unknown field
   |
   = note: available field is: `_address`
```
2026-07-15 13:27:15 +08:00
fufesou
bdb38c4730 fix: check valid id (#15535)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-07-14 15:35:52 +08:00
Maison da Silva
fa418cace6 Translate 'Continue' to 'Continuar' in ptbr.rs (#15567)
Translate 'Continue' to 'Continuar' in ptbr.rs
2026-07-13 18:56:41 +08:00
rustdesk
94a2a2bb4a fix https://github.com/rustdesk/rustdesk/issues/15566 2026-07-11 21:43:04 +08:00
Maison da Silva
865fe71c46 Update Portuguese translations for clarity (#15534) 2026-07-11 17:18:12 +08:00
rustdesk
137298e05a revert back 2026-07-10 15:21:48 +08:00
rustdesk
685a89a171 target Android 15 2026-07-10 15:12:06 +08:00
RustDesk
12b5cc7f72 Revert "fix: ci: macos: allow signed but not notarized dmg (#15530)" (#15551)
This reverts commit 29e1852a68.
2026-07-10 11:47:13 +08:00
10 changed files with 114 additions and 16 deletions

32
Cargo.lock generated
View File

@@ -771,6 +771,26 @@ dependencies = [
"syn 2.0.98",
]
[[package]]
name = "bindgen"
version = "0.72.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
dependencies = [
"bitflags 2.9.1",
"cexpr",
"clang-sys",
"itertools 0.12.1",
"log",
"prettyplease",
"proc-macro2 1.0.93",
"quote 1.0.36",
"regex",
"rustc-hash 2.1.1",
"shlex",
"syn 2.0.98",
]
[[package]]
name = "bit_field"
version = "0.10.2"
@@ -2329,7 +2349,7 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
dependencies = [
"libloading 0.7.4",
"libloading 0.8.4",
]
[[package]]
@@ -2694,7 +2714,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -4494,7 +4514,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d"
dependencies = [
"cfg-if 1.0.0",
"windows-targets 0.48.5",
"windows-targets 0.52.6",
]
[[package]]
@@ -7434,7 +7454,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys 0.11.0",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -7491,7 +7511,7 @@ dependencies = [
"security-framework 3.5.1",
"security-framework-sys",
"webpki-root-certs",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -7578,7 +7598,7 @@ name = "scrap"
version = "0.5.0"
dependencies = [
"android_logger",
"bindgen 0.65.1",
"bindgen 0.72.1",
"block",
"cfg-if 1.0.0",
"dbus",

View File

@@ -495,14 +495,14 @@ class _CmHeaderState extends State<_CmHeader>
if (client.type_() == ClientType.file)
FittedBox(
child: Text(
translate("File Transfer"),
translate("Transfer file"),
style: TextStyle(color: Colors.white70, fontSize: 12),
),
),
if (client.type_() == ClientType.camera)
FittedBox(
child: Text(
translate("View Camera"),
translate("View camera"),
style: TextStyle(color: Colors.white70, fontSize: 12),
),
),

View File

@@ -14,6 +14,7 @@
typedef char** (*FUNC_RUSTDESK_CORE_MAIN)(int*);
typedef void (*FUNC_RUSTDESK_FREE_ARGS)( char**, int);
typedef int (*FUNC_RUSTDESK_GET_APP_NAME)(wchar_t*, int);
typedef int (*FUNC_RUSTDESK_IS_DISABLE_INSTALLATION)();
/// Note: `--server`, `--service` are already handled in [core_main.rs].
const std::vector<std::string> parameters_white_list = {"--install", "--cm"};
@@ -62,6 +63,22 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
}
std::vector<std::string> rust_args(c_args, c_args + args_len);
free_c_args(c_args, args_len);
FUNC_RUSTDESK_IS_DISABLE_INSTALLATION rustdesk_is_disable_installation =
(FUNC_RUSTDESK_IS_DISABLE_INSTALLATION)GetProcAddress(hInstance, "rustdesk_is_disable_installation");
bool is_disable_installation =
rustdesk_is_disable_installation && rustdesk_is_disable_installation() != 0;
const auto installParam = std::string("--install");
// Flutter reads the original process command line, not only rust_args, so
// remove the `--install` injected by the portable wrapper here as well. This
// also lets `no-install.exe` continue as a portable app when installation is
// disabled. See: https://github.com/rustdesk/rustdesk-server-pro/issues/991#issuecomment-4978376890
if (is_disable_installation) {
command_line_arguments.erase(
std::remove(command_line_arguments.begin(),
command_line_arguments.end(),
installParam),
command_line_arguments.end());
}
std::wstring app_name = L"RustDesk";
FUNC_RUSTDESK_GET_APP_NAME get_rustdesk_app_name = (FUNC_RUSTDESK_GET_APP_NAME)GetProcAddress(hInstance, "get_rustdesk_app_name");
@@ -118,7 +135,6 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
is_cm_page = true;
}
bool is_install_page = false;
auto installParam = std::string("--install");
if (!command_line_arguments.empty() && command_line_arguments.front().compare(0, installParam.size(), installParam.c_str()) == 0) {
is_install_page = true;
}

View File

@@ -48,7 +48,7 @@ quest = "0.3"
[build-dependencies]
target_build_utils = "0.3"
bindgen = "0.65"
bindgen = "0.72.1"
pkg-config = { version = "0.3.27", optional = true }
[target.'cfg(target_os = "linux")'.dependencies]

View File

@@ -1024,7 +1024,7 @@ pub fn get_full_name() -> String {
}
pub fn is_setup(name: &str) -> bool {
name.to_lowercase().ends_with("install.exe")
!config::is_disable_installation() && name.to_lowercase().ends_with("install.exe")
}
pub fn get_custom_rendezvous_server(custom: String) -> String {
@@ -2623,6 +2623,20 @@ pub fn is_direct_ip_access(peer: &str) -> bool {
hbb_common::is_ip_str(peer) || hbb_common::is_domain_port_str(peer)
}
// Align the maximum length of the peer id to the maximum length of the peer id in the server.
const MAX_UNTRUSTED_PEER_ID_LEN: usize = 253;
const UNTRUSTED_PEER_ID_FORBIDDEN_CHARS: &[char] = &['"', '<', '>', '/', '\\', '|', '?', '*'];
// Shared validation for peer/connect ids that cross untrusted boundaries before
// they are stored or written into command/script contexts.
pub fn is_valid_untrusted_peer_id(id: &str) -> bool {
!id.is_empty()
&& id.len() <= MAX_UNTRUSTED_PEER_ID_LEN
&& !id.chars().any(|ch| {
ch.is_control() || ch.is_whitespace() || UNTRUSTED_PEER_ID_FORBIDDEN_CHARS.contains(&ch)
})
}
#[cfg(test)]
mod tests {
use super::*;
@@ -2653,6 +2667,29 @@ mod tests {
)
}
#[test]
fn untrusted_peer_id_validation() {
let cases = [
("123456789", true),
("m\u{00FC}nchen-pc", true),
("192.168.1.10:21118", true),
("9123456234@public", true),
(
r#"1" & oWS.Run("cmd.exe /k whoami /priv",1,False) & ""#,
false,
),
("", false),
("peer id", false),
("peer\nid", false),
("peer/id", false),
("peer?id", false),
];
for (id, expected) in cases {
assert_eq!(is_valid_untrusted_peer_id(id), expected, "{id:?}");
}
}
// ThrottledInterval tick at the same time as tokio interval, if no sleeps
#[allow(non_snake_case)]
#[tokio::test]

View File

@@ -127,6 +127,13 @@ pub fn core_main() -> Option<Vec<String>> {
if args.contains(&"--noinstall".to_string()) {
args.clear();
}
// The portable wrapper injects `--install` when its name ends with `install.exe`,
// including `no-install.exe`. Drop the argument instead of exiting so disabled
// clients can continue running as portable applications.
if config::is_disable_installation() {
args.retain(|arg| arg != "--install");
flutter_args.retain(|arg| arg != "--install");
}
if args.len() > 0 {
if args[0] == "--version" {
println!("{}", crate::VERSION);

View File

@@ -136,6 +136,12 @@ pub extern "C" fn rustdesk_core_main_args(args_len: *mut c_int) -> *mut *mut c_c
return std::ptr::null_mut() as _;
}
#[cfg(windows)]
#[no_mangle]
pub extern "C" fn rustdesk_is_disable_installation() -> c_int {
hbb_common::config::is_disable_installation() as c_int
}
// https://gist.github.com/iskakaushik/1c5b8aa75c77479c33c4320913eebef6
#[cfg(windows)]
fn rust_args_to_c_args(args: Vec<String>, outlen: *mut c_int) -> *mut *mut c_char {

View File

@@ -241,6 +241,14 @@ fn wait_response(
Some(rendezvous_message::Union::PeerDiscovery(p)) => {
last_recv_time = Instant::now();
if p.cmd == "pong" {
if !crate::common::is_valid_untrusted_peer_id(&p.id) {
log::warn!(
"Ignoring LAN discovery response from {} with invalid peer id",
addr
);
continue;
}
let local_mac = if try_get_ip_by_peer {
if let Some(self_addr) = get_ipaddr_by_peer(&addr) {
get_mac(&self_addr)

View File

@@ -112,7 +112,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Waiting", "Aguardando"),
("Finished", "Concluído"),
("Speed", "Velocidade"),
("Custom Image Quality", "Qualidade Visual Personalizada"),
("Custom Image Quality", "Qualidade de imagem personalizada"),
("Privacy mode", "Modo privado"),
("Block user input", "Bloquear entrada do usuário"),
("Unblock user input", "Desbloquear entrada do usuário"),
@@ -122,15 +122,15 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Stretch", "Aumentar"),
("Scrollbar", "Barra de rolagem"),
("ScrollAuto", "Rolagem automática"),
("Good image quality", "Boa qualidade de imagem"),
("Good image quality", "Melhor qualidade"),
("Balanced", "Balanceada"),
("Optimize reaction time", "Otimizar tempo de resposta"),
("Custom", "Personalizado"),
("Custom", "Personalizada"),
("Show remote cursor", "Mostrar cursor remoto"),
("Show quality monitor", "Exibir monitor de qualidade"),
("Disable clipboard", "Desabilitar área de transferência"),
("Lock after session end", "Bloquear após o fim da sessão"),
("Insert Ctrl + Alt + Del", "Enviar Ctrl + Alt + Del"),
("Insert Ctrl + Alt + Del", "Enviar Ctrl+Alt+Del"),
("Insert Lock", "Bloquear computador"),
("Refresh", "Atualizar"),
("ID does not exist", "ID não existe"),
@@ -332,7 +332,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Relay Connection", "Conexão via Relay"),
("Secure Connection", "Conexão Segura"),
("Insecure Connection", "Conexão Insegura"),
("Continue", ""),
("Continue", "Continuar"),
("Scale original", "Escala original"),
("Scale adaptive", "Escala adaptada"),
("General", "Geral"),

View File

@@ -2278,6 +2278,10 @@ fn get_shortcut_icon_location(install_dir: &str, exe: &str) -> String {
}
pub fn create_shortcut(id: &str) -> ResultType<()> {
if !crate::common::is_valid_untrusted_peer_id(id) {
bail!("Invalid peer id for shortcut");
}
let exe = std::env::current_exe()?.to_str().unwrap_or("").to_owned();
// https://github.com/rustdesk/rustdesk/issues/13735
// Replace ':' with '_' for filename since ':' is not allowed in Windows filenames