Compare commits

...

2 Commits

Author SHA1 Message Date
rustdesk
c19a0ceba2 more "cargo build --locked" 2026-05-26 11:45:15 +08:00
fufesou
1f26e452fc refact(password): encrypt (#15073)
* refact(password): encrypt

Signed-off-by: fufesou <linlong1266@gmail.com>

* refact(password): simplify preset password

Signed-off-by: fufesou <linlong1266@gmail.com>

* update hbb_common

Signed-off-by: fufesou <linlong1266@gmail.com>

* refact(password): clear password, do not clear salt

* refact(password): update hbb_common

Signed-off-by: fufesou <linlong1266@gmail.com>

* refact(password): merge import

Signed-off-by: fufesou <linlong1266@gmail.com>

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-05-26 11:11:25 +08:00
18 changed files with 61 additions and 71 deletions

View File

@@ -363,7 +363,7 @@ jobs:
python3 res/inline-sciter.py
# Patch sciter x86
sed -i 's/branch = "dyn"/branch = "dyn_x86"/g' ./Cargo.toml
cargo build --features inline,vram,hwcodec --release --bins
cargo build --locked --features inline,vram,hwcodec --release --bins
mkdir -p ./Release
mv ./target/release/rustdesk.exe ./Release/rustdesk.exe
curl -LJ -o ./Release/sciter.dll https://github.com/c-smile/sciter-sdk/raw/master/bin.win/x32/sciter.dll
@@ -519,7 +519,7 @@ jobs:
- name: Build rustdesk lib
run: |
rustup target add ${{ matrix.job.target }}
cargo build --features flutter,hwcodec --release --target aarch64-apple-ios --lib
cargo build --locked --features flutter,hwcodec --release --target aarch64-apple-ios --lib
- name: Upload liblibrustdesk.a Artifacts
uses: actions/upload-artifact@master
@@ -1491,7 +1491,7 @@ jobs:
export JOBS=""
fi
echo $JOBS
cargo build --lib $JOBS --features hwcodec,flutter,unix-file-copy-paste --release
cargo build --locked --lib $JOBS --features hwcodec,flutter,unix-file-copy-paste --release
rm -rf target/release/deps target/release/build
rm -rf ~/.cargo
@@ -1821,7 +1821,7 @@ jobs:
# build rustdesk
python3 ./res/inline-sciter.py
export CARGO_INCREMENTAL=0
cargo build --features inline${{ matrix.job.extra_features }} --release --bins --jobs 1
cargo build --locked --features inline${{ matrix.job.extra_features }} --release --bins --jobs 1
# make debian package
mkdir -p ./Release
mv ./target/release/rustdesk ./Release/rustdesk

View File

@@ -172,7 +172,7 @@ def generate_build_script_for_docker():
# flutter_rust_bridge
dart pub global activate ffigen --version 5.0.1
pushd /tmp && git clone https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge --depth=1 && popd
pushd /tmp/flutter_rust_bridge/frb_codegen && cargo install --path . && popd
pushd /tmp/flutter_rust_bridge/frb_codegen && cargo install --path . --locked && popd
pushd flutter && flutter pub get && popd
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart
# install vcpkg
@@ -317,7 +317,7 @@ def ffi_bindgen_function_refactor():
def build_flutter_deb(version, features):
if not skip_cargo:
system2(f'cargo build --features {features} --lib --release')
system2(f'cargo build --locked --features {features} --lib --release')
ffi_bindgen_function_refactor()
os.chdir('flutter')
system2('flutter build linux --release')
@@ -405,7 +405,7 @@ def build_flutter_dmg(version, features):
if not skip_cargo:
# set minimum osx build target, now is 10.14, which is the same as the flutter xcode project
system2(
f'MACOSX_DEPLOYMENT_TARGET=10.14 cargo build --features {features} --release')
f'MACOSX_DEPLOYMENT_TARGET=10.14 cargo build --locked --features {features} --release')
# copy dylib
system2(
"cp target/release/liblibrustdesk.dylib target/release/librustdesk.dylib")
@@ -422,7 +422,7 @@ def build_flutter_dmg(version, features):
def build_flutter_arch_manjaro(version, features):
if not skip_cargo:
system2(f'cargo build --features {features} --lib --release')
system2(f'cargo build --locked --features {features} --lib --release')
ffi_bindgen_function_refactor()
os.chdir('flutter')
system2('flutter build linux --release')
@@ -433,7 +433,7 @@ def build_flutter_arch_manjaro(version, features):
def build_flutter_windows(version, features, skip_portable_pack):
if not skip_cargo:
system2(f'cargo build --features {features} --lib --release')
system2(f'cargo build --locked --features {features} --lib --release')
if not os.path.exists("target/release/librustdesk.dll"):
print("cargo build failed, please check rust source code.")
exit(-1)
@@ -489,13 +489,13 @@ def main():
if windows:
# build virtual display dynamic library
os.chdir('libs/virtual_display/dylib')
system2('cargo build --release')
system2('cargo build --locked --release')
os.chdir('../../..')
if flutter:
build_flutter_windows(version, features, args.skip_portable_pack)
return
system2('cargo build --release --features ' + features)
system2('cargo build --locked --release --features ' + features)
# system2('upx.exe target/release/rustdesk.exe')
system2('mv target/release/rustdesk.exe target/release/RustDesk.exe')
pa = os.environ.get('P')
@@ -519,7 +519,7 @@ def main():
if flutter:
build_flutter_arch_manjaro(version, features)
else:
system2('cargo build --release --features ' + features)
system2('cargo build --locked --release --features ' + features)
system2('git checkout src/ui/common.tis')
system2('strip target/release/rustdesk')
system2('ln -s res/pacman_install && ln -s res/PKGBUILD')
@@ -528,7 +528,7 @@ def main():
version, version))
# pacman -U ./rustdesk.pkg.tar.zst
elif os.path.isfile('/usr/bin/yum'):
system2('cargo build --release --features ' + features)
system2('cargo build --locked --release --features ' + features)
system2('strip target/release/rustdesk')
system2(
"sed -i 's/Version: .*/Version: %s/g' res/rpm.spec" % version)
@@ -538,7 +538,7 @@ def main():
version, version))
# yum localinstall rustdesk.rpm
elif os.path.isfile('/usr/bin/zypper'):
system2('cargo build --release --features ' + features)
system2('cargo build --locked --release --features ' + features)
system2('strip target/release/rustdesk')
system2(
"sed -i 's/Version: .*/Version: %s/g' res/rpm-suse.spec" % version)
@@ -557,7 +557,7 @@ def main():
# 'mv target/release/bundle/deb/rustdesk*.deb ./flutter/rustdesk.deb')
build_flutter_deb(version, features)
else:
system2('cargo bundle --release --features ' + features)
system2('cargo --locked bundle --release --features ' + features)
if osx:
system2(
'strip target/release/bundle/osx/RustDesk.app/Contents/MacOS/rustdesk')

View File

@@ -33,4 +33,4 @@ if [ -z $release ]; then
fi
set -f
#shellcheck disable=2086
VCPKG_ROOT=/vcpkg cargo build $argv
VCPKG_ROOT=/vcpkg cargo build --locked $argv

View File

@@ -460,6 +460,7 @@ build)
--target "${RUST_TARGET}" \
--bindgen \
build \
--locked \
--release \
--features "${RUSTDESK_FEATURES}"

View File

@@ -1,2 +1,2 @@
#!/usr/bin/env bash
cargo build --features flutter,hwcodec --release --target aarch64-apple-ios --lib
cargo build --locked --features flutter,hwcodec --release --target aarch64-apple-ios --lib

View File

@@ -1,2 +1,2 @@
#!/usr/bin/env bash
cargo build --features flutter --release --target x86_64-apple-ios --lib
cargo build --locked --features flutter --release --target x86_64-apple-ios --lib

View File

@@ -1,2 +1,2 @@
#!/usr/bin/env bash
cargo ndk --platform 21 --target armv7-linux-androideabi build --release --features flutter,hwcodec
cargo ndk --platform 21 --target armv7-linux-androideabi build --locked --release --features flutter,hwcodec

View File

@@ -1,2 +1,2 @@
#!/usr/bin/env bash
cargo ndk --platform 21 --target aarch64-linux-android build --release --features flutter,hwcodec
cargo ndk --platform 21 --target aarch64-linux-android build --locked --release --features flutter,hwcodec

View File

@@ -1,2 +1,2 @@
#!/usr/bin/env bash
cargo ndk --platform 21 --target x86_64-linux-android build --release --features flutter
cargo ndk --platform 21 --target x86_64-linux-android build --locked --release --features flutter

View File

@@ -7,4 +7,4 @@
export CFLAGS="-DBROKEN_CLANG_ATOMICS"
export CXXFLAGS="-DBROKEN_CLANG_ATOMICS"
cargo ndk --platform 21 --target i686-linux-android build --release --features flutter
cargo ndk --platform 21 --target i686-linux-android build --locked --release --features flutter

View File

@@ -1,9 +1,9 @@
#!/usr/bin/env bash
cargo install flutter_rust_bridge_codegen --version 1.80.1 --features uuid
cargo install flutter_rust_bridge_codegen --version 1.80.1 --features uuid --locked
flutter pub get
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ../src/flutter_ffi.rs --dart-output ./lib/generated_bridge.dart --c-output ./macos/Runner/bridge_generated.h
# call `flutter clean` if cargo build fails
# export LLVM_HOME=/Library/Developer/CommandLineTools/usr/
cargo build --features flutter
cargo build --locked --features flutter
flutter run $@

View File

@@ -67,9 +67,9 @@ def write_app_metadata(output_folder: str):
def build_portable(output_folder: str, target: str):
os.chdir(output_folder)
if target:
os.system("cargo build --release --target " + target)
os.system("cargo build --locked --release --target " + target)
else:
os.system("cargo build --release")
os.system("cargo build --locked --release")
# Linux: python3 generate.py -f ../rustdesk-portable-packer/test -o . -e ./test/main.py
# Windows: python3 .\generate.py -f ..\rustdesk\flutter\build\windows\runner\Debug\ -o . -e ..\rustdesk\flutter\build\windows\runner\Debug\rustdesk.exe

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
echo $MACOS_CODESIGN_IDENTITY
cargo install flutter_rust_bridge_codegen --version 1.80.1 --features uuid
cargo install flutter_rust_bridge_codegen --version 1.80.1 --features uuid --locked
cd flutter; flutter pub get; cd -
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart --c-output ./flutter/macos/Runner/bridge_generated.h
./build.py --flutter

View File

@@ -2471,23 +2471,13 @@ pub fn is_disable_installation() -> SyncReturn<bool> {
}
pub fn is_preset_password() -> bool {
let hard = config::HARD_SETTINGS
.read()
.unwrap()
.get("password")
.cloned()
.unwrap_or_default();
if hard.is_empty() {
return false;
}
// On desktop, service owns the authoritative config; query it via IPC and return only a boolean.
#[cfg(not(any(target_os = "android", target_os = "ios")))]
return crate::ipc::is_permanent_password_preset();
// On mobile, we have no service IPC; verify against local storage.
#[cfg(any(target_os = "android", target_os = "ios"))]
return config::Config::matches_permanent_password_plain(&hard);
return config::Config::is_using_preset_password();
}
// Don't call this function for desktop version.

View File

@@ -839,15 +839,7 @@ async fn handle(data: Data, stream: &mut Connection) {
"N".to_owned()
});
} else if name == "permanent-password-is-preset" {
let hard = config::HARD_SETTINGS
.read()
.unwrap()
.get("password")
.cloned()
.unwrap_or_default();
let is_preset =
!hard.is_empty() && Config::matches_permanent_password_plain(&hard);
value = Some(if is_preset {
value = Some(if Config::is_using_preset_password() {
"Y".to_owned()
} else {
"N".to_owned()
@@ -898,7 +890,7 @@ async fn handle(data: Data, stream: &mut Connection) {
log::warn!("Changing permanent password is disabled");
updated = false;
} else {
Config::set_permanent_password(&value);
updated = Config::set_permanent_password(&value);
}
// Explicitly ACK/NACK permanent-password writes. This allows UIs/FFI to
// distinguish "accepted by daemon" vs "IPC send succeeded" without
@@ -1550,11 +1542,6 @@ fn apply_permanent_password_storage_and_salt_payload(payload: Option<&str>) -> R
bail!("Invalid permanent-password-storage-and-salt payload");
};
if storage.is_empty() {
Config::set_permanent_password_storage_for_sync("", "")?;
return Ok(());
}
Config::set_permanent_password_storage_for_sync(storage, salt)?;
Ok(())
}

View File

@@ -30,8 +30,11 @@ use cidr_utils::cidr::IpCidr;
#[cfg(target_os = "android")]
use hbb_common::protobuf::EnumOrUnknown;
use hbb_common::{
config::decode_permanent_password_h1_from_storage,
config::{self, keys, Config, TrustedDevice},
config::{
self, decode_permanent_password_h1_from_storage, decode_preset_password_h1_from_storage,
keys, local_permanent_password_storage_is_usable_for_auth,
preset_permanent_password_storage_is_usable_for_auth, Config, TrustedDevice,
},
fs::{self, can_enable_overwrite_detection, JobType},
futures::{SinkExt, StreamExt},
get_time, get_version_number,
@@ -412,8 +415,9 @@ impl Connection {
let _raii_id = raii::ConnectionID::new(id);
let _raii_control_permissions_id =
raii::ControlPermissionsID::new(id, &control_permissions);
let salt = Config::get_effective_permanent_password_salt();
let hash = Hash {
salt: Config::get_salt(),
salt,
challenge: Config::get_auto_password(6),
..Default::default()
};
@@ -2109,6 +2113,16 @@ impl Connection {
self.validate_password_plain(storage)
}
fn validate_preset_password_storage(&self, storage: &str, salt: &str) -> bool {
if salt.is_empty() {
return self.validate_password_plain(storage);
}
let Some(h1) = decode_preset_password_h1_from_storage(storage) else {
return false;
};
self.verify_h1(&h1[..])
}
// This is coarse brute-force protection for the current temporary password value.
// We only care whether the active temporary password itself was presented correctly,
// not whether later authorization steps succeed. A successful temporary-password
@@ -2180,23 +2194,22 @@ impl Connection {
log::info!("Permanent password accepted via logon-screen fallback");
}
};
// Since hashed storage uses a prefix-based encoding, a hard plaintext that
// happens to look like hashed storage could be mis-detected. Validate local storage
// and hard/preset plaintext via separate paths to avoid that ambiguity.
let (local_storage, _) = Config::get_local_permanent_password_storage_and_salt();
// Strictly check storage usability before auth so malformed encrypted/hash storage
// cannot fall back to being accepted as legacy plaintext.
let (local_storage, local_salt) =
Config::get_local_permanent_password_storage_and_salt();
if !local_storage.is_empty() {
if self.validate_password_storage(&local_storage) {
if local_permanent_password_storage_is_usable_for_auth(&local_storage, &local_salt)
&& self.validate_password_storage(&local_storage)
{
print_fallback();
return true;
}
} else {
let hard = config::HARD_SETTINGS
.read()
.unwrap()
.get("password")
.cloned()
.unwrap_or_default();
if !hard.is_empty() && self.validate_password_plain(&hard) {
let (hard, salt) = Config::get_preset_password_storage_and_salt();
if preset_permanent_password_storage_is_usable_for_auth(&hard, &salt)
&& self.validate_preset_password_storage(&hard, &salt)
{
print_fallback();
return true;
}

View File

@@ -647,8 +647,7 @@ pub fn set_permanent_password_with_result(password: String) -> bool {
}
#[cfg(any(target_os = "android", target_os = "ios"))]
{
config::Config::set_permanent_password(&password);
return true;
return config::Config::set_permanent_password(&password);
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
{