Compare commits

..

7 Commits

Author SHA1 Message Date
xuwenwei 41f39232c2 Rename Win resources: RustDesk -> SoonDesk
Sync the Windows-side branding with the macOS changes from 7edd248.

Changes:
- flutter/windows/runner/Runner.rc: FileDescription, ProductName
- flutter/windows/runner/main.cpp: app_name L"RustDesk" -> L"SoonDesk"
- flutter/windows/CMakeLists.txt: project name + BINARY_NAME

Note: librustdesk.dll name on the Rust side is unchanged — it's the
library crate name (libs/hbb_common/Cargo.toml defines it) and changing
it would require touching the dylib name in build scripts. The SoonDesk
.exe loads librustdesk.dll as before; only the user-visible strings
and the exe name change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 13:56:36 +08:00
xuwenwei 53ba2d753e Hide 'powered by RustDesk' link on login page
loadPowered() in flutter/lib/common.dart now always returns SizedBox.shrink()
for the SoonDesk fork. The link is misleading for a non-official build
and clutters the login page.

Upstream behavior (controlled by the 'hide-powered-by-me' builtin option)
is preserved in commented-out form for reference.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 13:48:03 +08:00
xuwenwei 7edd24854f Rename app from RustDesk to SoonDesk
Changes:
- libs/hbb_common/src/config.rs: APP_NAME = 'SoonDesk' (single source of truth)
- flutter/lib/desktop/widgets/tabbar_widget.dart: hard-coded tab title
- flutter/macos/Runner/Configs/AppInfo.xcconfig: PRODUCT_NAME, BUNDLE_ID
- flutter/macos/Runner.xcodeproj/project.pbxproj: hard-coded BUNDLE_ID override
- flutter/lib/web/bridge.dart: comment about why isCustomClient comparison unchanged

This single APP_NAME change drives:
- Window title (src/ui.rs:87 frame.set_title(&crate::get_app_name()))
- macOS app bundle display name (CFBundleName via $(PRODUCT_NAME))
- Linux .desktop file name
- Config / log directory paths (~/Library/Logs/SoonDesk/)
- Lang translation strings: src/lang.rs auto-replaces 'RustDesk' in all
  translations with APP_NAME when is_rustdesk() returns false (since
  APP_NAME is no longer 'RustDesk').

Protocol-level 'RustDesk' references are preserved (PunchHoleRequest
fields, etc.) so we still interop with upstream RustDesk servers and
clients.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 12:22:28 +08:00
xuwenwei f32373643e Default ON: enable-keyboard, enable-clipboard, enable-file-transfer
Per user feedback: these 3 features are core remote-support functionality
(typing, copying, sending files). 6d587a8 set them to N to save bandwidth
on the 5 Mbps self-hosted hbbs (114.55.133.123), but the user wants
them on by default. Users can still flip them off per-session.

Still OFF by default (kept from 6d587a8):
- enable-audio
- enable-tunnel
- enable-record-session
- enable-camera

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 00:16:50 +08:00
xuwenwei 6d587a840e Default-off 6 options (file-transfer, clipboard, keyboard, tunnel, record-session, camera) + force-on 2 NAT punch options
For 4 users on 5 Mbps server (114.55.133.123) where file transfers were saturating bandwidth:

Turn OFF by default (users can still flip on per-session):
- enable-file-transfer: THE KILLER (1 GB upload = 2 GB server bandwidth)
- enable-clipboard: 50 kbps + privacy
- enable-keyboard: only needed for typing-on-remote
- enable-tunnel: prevents using server as jump host
- enable-record-session: only when explicitly recording
- enable-camera: 500 kbps; rarely used for support
- enable-audio: (already in c94a72a)

Force ON (overrides RustDesk's conservative default for self-hosted servers):
- enable-udp-punch, enable-ipv6-punch: src/common.rs:1107 turns these off
  when rendezvous server is non-public. That's a safety measure meant for
  untrusted public servers, but our self-hosted server is fully trusted.
  Force-enabling boosts P2P success rate → less relay (21117) traffic →
  less server bandwidth.
2026-06-09 00:31:42 +08:00
xuwenwei 0532fafe9f BUILD.md: document the Rust source edit (custom.txt path is broken for unsigned forks) 2026-06-08 23:36:50 +08:00
xuwenwei d49ba37c1c Revert "Default 'enable-audio' to off via custom.txt (read by Rust load_custom_client)"
This reverts commit a5b0c523fc.
2026-06-08 23:36:09 +08:00
12 changed files with 117 additions and 66 deletions
+30 -20
View File
@@ -114,34 +114,44 @@ Dart 3.12 rejects `const Map<FontWeight, String>{...}`. Change `const` to `final
be wiped by `flutter pub cache clean`.** To make it permanent, copy the patched file into
`./local_google_fonts/` and use `dependency_overrides: google_fonts: { path: ... }`.
### 2.6. `flutter/macos/Runner/custom.txt` (default settings via Rust's `load_custom_client`)
### 2.6. `src/common.rs` — hardcode `enable-audio` default to off (NOT via custom.txt)
RustDesk's Rust core reads `Contents/Resources/custom.txt` on startup
(see `src/common.rs::load_custom_client` + `read_custom_client`). It accepts two
keys: `default-settings` (fills `DEFAULT_SETTINGS`; user config still wins) and
`override-settings` (fills `OVERWRITE_SETTINGS`; user can't override).
**The naive approach (custom.txt) is broken for unsigned forks.** `load_custom_client`
reads `Contents/Resources/custom.txt` and passes the content to `read_custom_client`,
but `read_custom_client` (line 2191) immediately calls `decode64()` and then
`sign::verify()` with a hardcoded ed25519 public key. Plain JSON fails the
base64 decode and the function returns early — your settings are silently dropped.
Only **official signed** custom-client builds can use the `custom.txt` path.
**Current contents:**
```json
**What we do instead: inject `enable-audio = N` directly into `DEFAULT_SETTINGS` at
the end of `load_custom_client`**, in [src/common.rs:2104-2114](src/common.rs#L2104):
```rust
// Custom fork: hardcode enable-audio = N as the default. User can still flip it on in Settings.
// Reason: RustDesk's official custom.txt path requires ed25519-signed base64 (see
// read_custom_client at line 2191 — decode64 + sign::verify with key
// "5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM="), which we can't produce without the
// official signing key. So we bypass custom.txt and inject directly into DEFAULT_SETTINGS.
// entry().or_insert() preserves the priority chain: OVERWRITE_SETTINGS → CONFIG2 → DEFAULT_SETTINGS.
{
"app-name": "RustDesk",
"default-settings": {
"enable-audio": "N"
}
let mut defaults = config::DEFAULT_SETTINGS.write().unwrap();
defaults.entry("enable-audio".to_string()).or_insert("N".to_string());
}
```
Effect: the "Enable audio" option in Settings is **off by default** for new
installs. Users can still flip it on. To add more defaults, follow the
`KEYS_SETTINGS` whitelist in `libs/hbb_common/src/config.rs:3130`.
`entry().or_insert()` (not `insert()`) is intentional — it lets users override
`enable-audio` by writing to their own `RustDesk2.toml`'s `[options]` table
(CONFIG2 wins in the priority chain).
**Two parts to make this work:**
**To add more default-off settings**, append more `defaults.entry(...).or_insert(...)`
lines. Any key from the `KEYS_SETTINGS` whitelist at
[libs/hbb_common/src/config.rs:3130](libs/hbb_common/src/config.rs#L3130) works.
Candidates: `enable-clipboard`, `enable-keyboard`, `enable-file-transfer`,
`enable-tunnel`, `enable-record-session`.
1. The file `flutter/macos/Runner/custom.txt` must exist (it does in git).
2. `flutter/macos/Runner.xcodeproj/project.pbxproj` must list `custom.txt` in
the `PBXResourcesBuildPhase`'s `files` list. We added it under UUIDs
`AABBCC000100000000000001` (BuildFile) and `AABBCC000200000000000002`
(FileReference). If you regenerate the Xcode project, re-add it.
**Verified end-to-end:** debug eprintln confirmed `DEFAULT_SETTINGS.get("enable-audio") == Some("N")`
at startup. UI's "Settings → Permissions" page now shows the audio checkbox unchecked.
User can still flip it on in Settings.
---
+26 -21
View File
@@ -3690,27 +3690,32 @@ Color? disabledTextColor(BuildContext context, bool enabled) {
}
Widget loadPowered(BuildContext context) {
if (bind.mainGetBuildinOption(key: "hide-powered-by-me") == 'Y') {
return SizedBox.shrink();
}
return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () {
launchUrl(Uri.parse('https://rustdesk.com'));
},
child: Opacity(
opacity: 0.5,
child: Text(
translate("powered_by_me"),
overflow: TextOverflow.clip,
style: Theme.of(context)
.textTheme
.bodySmall
?.copyWith(fontSize: 9, decoration: TextDecoration.underline),
)),
),
).marginOnly(top: 6);
// Custom fork (SoonDesk): never show the "powered by RustDesk" link.
// For non-official builds this is misleading (we're not "powered by"
// upstream RustDesk), and clutters the login page.
return SizedBox.shrink();
// (Upstream behavior kept below for reference.)
// if (bind.mainGetBuildinOption(key: "hide-powered-by-me") == 'Y') {
// return SizedBox.shrink();
// }
// return MouseRegion(
// cursor: SystemMouseCursors.click,
// child: GestureDetector(
// onTap: () {
// launchUrl(Uri.parse('https://rustdesk.com'));
// },
// child: Opacity(
// opacity: 0.5,
// child: Text(
// translate("powered_by_me"),
// overflow: TextOverflow.clip,
// style: Theme.of(context)
// .textTheme
// .bodySmall
// ?.copyWith(fontSize: 9, decoration: TextDecoration.underline),
// )),
// ),
// ).marginOnly(top: 6);
}
// max 300 x 60
@@ -641,7 +641,7 @@ class _DesktopTabState extends State<DesktopTab>
Offstage(
offstage: !showTitle,
child: const Text(
"RustDesk",
"SoonDesk",
style: TextStyle(fontSize: 13),
).marginOnly(left: 2))
]).marginOnly(
+6
View File
@@ -1611,6 +1611,12 @@ class RustdeskImpl {
// is_custom_client() checks if app name is not "RustDesk"
return mainGetAppNameSync(hint: hint) != "RustDesk";
}
// NOTE: We don't change the comparison string here. The upstream
// `is_custom_client` semantics are: "true when this build is NOT the
// official RustDesk build." For our SoonDesk fork, APP_NAME is
// "SoonDesk" (set in libs/hbb_common/src/config.rs), which still
// satisfies != "RustDesk" isCustomClient returns true. So this
// check is correct as-is for the SoonDesk fork.
bool isDisableSettings({dynamic hint}) {
// Checks HARD_SETTINGS["disable-settings"] == "Y"
@@ -26,7 +26,6 @@
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
7ED2B35F2BB007420099885C /* AppIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 7ED2B35E2BB007420099885C /* AppIcon.icns */; };
AABBCC000100000000000001 /* custom.txt in Resources */ = {isa = PBXBuildFile; fileRef = AABBCC000200000000000002 /* custom.txt */; };
84010BA8292CF66600152837 /* liblibrustdesk.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 84010BA7292CF66600152837 /* liblibrustdesk.dylib */; settings = {ATTRIBUTES = (Weak, ); }; };
84010BA9292CF68300152837 /* liblibrustdesk.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 84010BA7292CF66600152837 /* liblibrustdesk.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
C5E54335B73C89F72DB1B606 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26C84465887F29AE938039CB /* Pods_Runner.framework */; };
@@ -76,7 +75,6 @@
7436B85D94E8F7B5A9324869 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
7ED2B35E2BB007420099885C /* AppIcon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = AppIcon.icns; path = Runner/AppIcon.icns; sourceTree = "<group>"; };
AABBCC000200000000000002 /* custom.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = custom.txt; path = Runner/custom.txt; sourceTree = "<group>"; };
84010BA7292CF66600152837 /* liblibrustdesk.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = liblibrustdesk.dylib; path = ../../target/release/liblibrustdesk.dylib; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
C3BB669FF6190AE1B11BCAEA /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
@@ -135,7 +133,6 @@
7ED2B35E2BB007420099885C /* AppIcon.icns */,
33CC10F42044A3C60003C045 /* MainMenu.xib */,
33CC10F72044A3C60003C045 /* Info.plist */,
AABBCC000200000000000002 /* custom.txt */,
);
name = Resources;
path = ..;
@@ -268,7 +265,6 @@
files = (
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,
7ED2B35F2BB007420099885C /* AppIcon.icns in Resources */,
AABBCC000100000000000001 /* custom.txt in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -459,7 +455,7 @@
../../target/profile,
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = com.carriez.rustdesk;
PRODUCT_BUNDLE_IDENTIFIER = com.cardsoon.soondesk;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
@@ -604,7 +600,7 @@
../../target/debug,
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = com.carriez.rustdesk;
PRODUCT_BUNDLE_IDENTIFIER = com.cardsoon.soondesk;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
"SWIFT_OBJC_BRIDGING_HEADER[arch=*]" = Runner/bridge_generated.h;
@@ -641,7 +637,7 @@
__cgpreloginapp,
/dev/null,
);
PRODUCT_BUNDLE_IDENTIFIER = com.carriez.rustdesk;
PRODUCT_BUNDLE_IDENTIFIER = com.cardsoon.soondesk;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
"SWIFT_OBJC_BRIDGING_HEADER[arch=*]" = Runner/bridge_generated.h;
@@ -5,10 +5,10 @@
// 'flutter create' template.
// The application's name. By default this is also the title of the Flutter window.
PRODUCT_NAME = RustDesk
PRODUCT_NAME = SoonDesk
// The application's bundle identifier
PRODUCT_BUNDLE_IDENTIFIER = com.carriez.flutterHbb
PRODUCT_BUNDLE_IDENTIFIER = com.cardsoon.soondesk
// The copyright displayed in application information
PRODUCT_COPYRIGHT = Copyright © 2025 Purslane Ltd. All rights reserved.
PRODUCT_COPYRIGHT = Copyright © 2026 Cardsoon. All rights reserved.
-6
View File
@@ -1,6 +0,0 @@
{
"app-name": "RustDesk",
"default-settings": {
"enable-audio": "N"
}
}
+2 -2
View File
@@ -1,10 +1,10 @@
# Project-level configuration.
cmake_minimum_required(VERSION 3.14)
project(rustdesk LANGUAGES CXX)
project(soondesk LANGUAGES CXX)
# The name of the executable created for the application. Change this to change
# the on-disk name of your application.
set(BINARY_NAME "rustdesk")
set(BINARY_NAME "soondesk")
# Explicitly opt into modern CMake behaviors to avoid warnings with recent
# versions of CMake.
+2 -2
View File
@@ -90,12 +90,12 @@ BEGIN
BLOCK "040904e4"
BEGIN
VALUE "CompanyName", "Purslane Ltd" "\0"
VALUE "FileDescription", "RustDesk Remote Desktop" "\0"
VALUE "FileDescription", "SoonDesk Remote Desktop" "\0"
VALUE "FileVersion", VERSION_AS_STRING "\0"
VALUE "InternalName", "rustdesk" "\0"
VALUE "LegalCopyright", "Copyright © 2025 Purslane Ltd. All rights reserved." "\0"
VALUE "OriginalFilename", "rustdesk.exe" "\0"
VALUE "ProductName", "RustDesk" "\0"
VALUE "ProductName", "SoonDesk" "\0"
VALUE "ProductVersion", VERSION_AS_STRING "\0"
END
END
+1 -1
View File
@@ -63,7 +63,7 @@ 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);
std::wstring app_name = L"RustDesk";
std::wstring app_name = L"SoonDesk";
FUNC_RUSTDESK_GET_APP_NAME get_rustdesk_app_name = (FUNC_RUSTDESK_GET_APP_NAME)GetProcAddress(hInstance, "get_rustdesk_app_name");
if (get_rustdesk_app_name) {
wchar_t app_name_buffer[512] = {0};
+11 -1
View File
@@ -69,7 +69,17 @@ lazy_static::lazy_static! {
static ref ONLINE: Mutex<HashMap<String, i64>> = Default::default();
pub static ref PROD_RENDEZVOUS_SERVER: RwLock<String> = RwLock::new("".to_owned());
pub static ref EXE_RENDEZVOUS_SERVER: RwLock<String> = Default::default();
pub static ref APP_NAME: RwLock<String> = RwLock::new("RustDesk".to_owned());
// Custom fork: rename the app from "RustDesk" to "SoonDesk".
// This single constant drives:
// - Window title and menu bar text
// - macOS app bundle display name (set separately in Info.plist)
// - Linux .desktop file name
// - Config / log directory names
// - All Rust-side references to "RustDesk"
// is_rustdesk() at src/common.rs:1009 still compares against "RustDesk",
// so it will now return false for this fork. Update there too if that
// helper is used in any policy check.
pub static ref APP_NAME: RwLock<String> = RwLock::new("SoonDesk".to_owned());
static ref KEY_PAIR: Mutex<Option<KeyPair>> = Default::default();
static ref USER_DEFAULT_CONFIG: RwLock<(UserDefaultConfig, Instant)> = RwLock::new((UserDefaultConfig::load(), Instant::now()));
pub static ref NEW_STORED_PEER_CONFIG: Mutex<HashSet<String>> = Default::default();
+32 -2
View File
@@ -2102,15 +2102,45 @@ pub fn load_custom_client() {
read_custom_client(&data.trim());
}
// Custom fork: hardcode enable-audio = N as the default. User can still flip it on in Settings.
// Custom fork: hardcode bandwidth-heavy / sensitive defaults to off.
// Reason: RustDesk's official custom.txt path requires ed25519-signed base64 (see
// read_custom_client at line 2191 — decode64 + sign::verify with key
// "5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM="), which we can't produce without the
// official signing key. So we bypass custom.txt and inject directly into DEFAULT_SETTINGS.
// entry().or_insert() preserves the priority chain: OVERWRITE_SETTINGS → CONFIG2 → DEFAULT_SETTINGS.
// entry().or_insert() preserves the priority chain: OVERWRITE_SETTINGS → CONFIG2 → DEFAULT_SETTINGS,
// so users can still override any of these in their own RustDesk2.toml.
//
// Why each one is off (user has 4 users on 5 Mbps server, file transfers were saturating it):
// enable-audio — not needed for 4-user remote support; saves 64 kbps/session
// enable-tunnel — TCP tunneling = users abusing server as a jump host
// enable-record-session — only needed if explicitly recording
// enable-camera — 500 kbps; rarely used for support
//
// Note: enable-keyboard, enable-clipboard, enable-file-transfer were
// originally set to N here, but the user requested they default to ON
// (these are core remote-support features: typing, copying, sending
// files to/from the remote machine). The user can still flip them off
// per-session via the Settings UI.
{
let mut defaults = config::DEFAULT_SETTINGS.write().unwrap();
defaults.entry("enable-audio".to_string()).or_insert("N".to_string());
defaults.entry("enable-tunnel".to_string()).or_insert("N".to_string());
defaults.entry("enable-record-session".to_string()).or_insert("N".to_string());
defaults.entry("enable-camera".to_string()).or_insert("N".to_string());
}
// Force-enable UDP and IPv6 NAT punch for the self-hosted server scenario.
// Background: get_local_option() at src/common.rs:1107 turns off UDP/IPv6 punch
// when the rendezvous server is non-public (i.e. self-hosted). That conservativeness
// is meant to protect users from untrusted public servers, but for OUR self-hosted
// server (114.55.133.123, fully controlled by the user), it unnecessarily
// degrades P2P success rate → more relay traffic → more 21117 bandwidth.
// Force Y here so P2P success rate is high; relay (21117) only kicks in when
// P2P truly fails.
{
let mut locals = config::OVERWRITE_LOCAL_SETTINGS.write().unwrap();
locals.entry("enable-udp-punch".to_string()).or_insert("Y".to_string());
locals.entry("enable-ipv6-punch".to_string()).or_insert("Y".to_string());
}
}