add options: disable-change-permanent-password, disable-change-id, disable-unlock-pin (#13929)

Signed-off-by: 21pages <sunboeasy@gmail.com>
This commit is contained in:
21pages
2026-01-07 13:51:02 +08:00
committed by GitHub
parent a05b619563
commit 9dd4fa8646
8 changed files with 59 additions and 20 deletions

3
.gitmodules vendored
View File

@@ -1,3 +1,4 @@
[submodule "libs/hbb_common"] [submodule "libs/hbb_common"]
path = libs/hbb_common path = libs/hbb_common
url = https://github.com/rustdesk/hbb_common url = https://github.com/21pages/hbb_common
branch = disable-change-permanent-password

View File

@@ -3805,6 +3805,16 @@ setResizable(bool resizable) {
isOptionFixed(String key) => bind.mainIsOptionFixed(key: key); isOptionFixed(String key) => bind.mainIsOptionFixed(key: key);
bool isChangePermanentPasswordDisabled() =>
bind.mainGetBuildinOption(key: kOptionDisableChangePermanentPassword) ==
'Y';
bool isChangeIdDisabled() =>
bind.mainGetBuildinOption(key: kOptionDisableChangeId) == 'Y';
bool isUnlockPinDisabled() =>
bind.mainGetBuildinOption(key: kOptionDisableUnlockPin) == 'Y';
bool? _isCustomClient; bool? _isCustomClient;
bool get isCustomClient { bool get isCustomClient {
_isCustomClient ??= bind.isCustomClient(); _isCustomClient ??= bind.isCustomClient();

View File

@@ -180,6 +180,10 @@ const String kOptionHideSecuritySetting = "hide-security-settings";
const String kOptionHideNetworkSetting = "hide-network-settings"; const String kOptionHideNetworkSetting = "hide-network-settings";
const String kOptionRemovePresetPasswordWarning = const String kOptionRemovePresetPasswordWarning =
"remove-preset-password-warning"; "remove-preset-password-warning";
const String kOptionDisableChangePermanentPassword =
"disable-change-permanent-password";
const String kOptionDisableChangeId = "disable-change-id";
const String kOptionDisableUnlockPin = "disable-unlock-pin";
const kHideUsernameOnCard = "hide-username-on-card"; const kHideUsernameOnCard = "hide-username-on-card";
const String kOptionHideHelpCards = "hide-help-cards"; const String kOptionHideHelpCards = "hide-help-cards";

View File

@@ -825,7 +825,8 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
permissions(context), permissions(context),
password(context), password(context),
_Card(title: '2FA', children: [tfa()]), _Card(title: '2FA', children: [tfa()]),
_Card(title: 'ID', children: [changeId()]), if (!isChangeIdDisabled())
_Card(title: 'ID', children: [changeId()]),
more(context), more(context),
]), ]),
), ),
@@ -1091,6 +1092,10 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
.indexOf(kUsePermanentPassword)] && .indexOf(kUsePermanentPassword)] &&
(await bind.mainGetPermanentPassword()) (await bind.mainGetPermanentPassword())
.isEmpty) { .isEmpty) {
if (isChangePermanentPasswordDisabled()) {
await callback();
return;
}
setPasswordDialog(notEmptyCallback: callback); setPasswordDialog(notEmptyCallback: callback);
} else { } else {
await callback(); await callback();
@@ -1195,7 +1200,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
enabled: tmpEnabled && !locked), enabled: tmpEnabled && !locked),
if (usePassword) numericOneTimePassword, if (usePassword) numericOneTimePassword,
if (usePassword) radios[1], if (usePassword) radios[1],
if (usePassword) if (usePassword && !isChangePermanentPasswordDisabled())
_SubButton('Set permanent password', setPasswordDialog, _SubButton('Set permanent password', setPasswordDialog,
permEnabled && !locked), permEnabled && !locked),
// if (usePassword) // if (usePassword)
@@ -1218,7 +1223,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
_OptionCheckBox(context, 'allow-only-conn-window-open-tip', _OptionCheckBox(context, 'allow-only-conn-window-open-tip',
'allow-only-conn-window-open', 'allow-only-conn-window-open',
reverse: false, enabled: enabled), reverse: false, enabled: enabled),
if (bind.mainIsInstalled()) unlockPin() if (bind.mainIsInstalled() && !isUnlockPinDisabled()) unlockPin()
]); ]);
} }
@@ -2654,7 +2659,7 @@ Widget _lock(
]).marginSymmetric(vertical: 2)), ]).marginSymmetric(vertical: 2)),
onPressed: () async { onPressed: () async {
final unlockPin = bind.mainGetUnlockPin(); final unlockPin = bind.mainGetUnlockPin();
if (unlockPin.isEmpty) { if (unlockPin.isEmpty || isUnlockPinDisabled()) {
bool checked = await callMainCheckSuperUserPermission(); bool checked = await callMainCheckSuperUserPermission();
if (checked) { if (checked) {
onUnlock(); onUnlock();

View File

@@ -61,12 +61,13 @@ class _DropDownAction extends StatelessWidget {
final isAllowNumericOneTimePassword = final isAllowNumericOneTimePassword =
gFFI.serverModel.allowNumericOneTimePassword; gFFI.serverModel.allowNumericOneTimePassword;
return [ return [
PopupMenuItem( if (!isChangeIdDisabled())
enabled: gFFI.serverModel.connectStatus > 0, PopupMenuItem(
value: "changeID", enabled: gFFI.serverModel.connectStatus > 0,
child: Text(translate("Change ID")), value: "changeID",
), child: Text(translate("Change ID")),
const PopupMenuDivider(), ),
if (!isChangeIdDisabled()) const PopupMenuDivider(),
PopupMenuItem( PopupMenuItem(
value: 'AcceptSessionsViaPassword', value: 'AcceptSessionsViaPassword',
child: listTile( child: listTile(
@@ -87,7 +88,8 @@ class _DropDownAction extends StatelessWidget {
), ),
if (showPasswordOption) const PopupMenuDivider(), if (showPasswordOption) const PopupMenuDivider(),
if (showPasswordOption && if (showPasswordOption &&
verificationMethod != kUseTemporaryPassword) verificationMethod != kUseTemporaryPassword &&
!isChangePermanentPasswordDisabled())
PopupMenuItem( PopupMenuItem(
value: "setPermanentPassword", value: "setPermanentPassword",
child: Text(translate("Set permanent password")), child: Text(translate("Set permanent password")),
@@ -149,6 +151,10 @@ class _DropDownAction extends StatelessWidget {
if (value == kUsePermanentPassword && if (value == kUsePermanentPassword &&
(await bind.mainGetPermanentPassword()).isEmpty) { (await bind.mainGetPermanentPassword()).isEmpty) {
if (isChangePermanentPasswordDisabled()) {
callback();
return;
}
setPasswordDialog(notEmptyCallback: callback); setPasswordDialog(notEmptyCallback: callback);
} else { } else {
callback(); callback();
@@ -648,9 +654,8 @@ class ConnectionManager extends StatelessWidget {
return Column( return Column(
children: serverModel.clients children: serverModel.clients
.map((client) => PaddingCard( .map((client) => PaddingCard(
title: translate(client.isFileTransfer title: translate(
? "Transfer file" client.isFileTransfer ? "Transfer file" : "Share screen"),
: "Share screen"),
titleIcon: client.isFileTransfer titleIcon: client.isFileTransfer
? Icon(Icons.folder_outlined) ? Icon(Icons.folder_outlined)
: Icon(Icons.mobile_screen_share), : Icon(Icons.mobile_screen_share),

View File

@@ -406,6 +406,10 @@ pub fn core_main() -> Option<Vec<String>> {
println!("Settings are disabled!"); println!("Settings are disabled!");
return None; return None;
} }
if config::Config::is_disable_change_permanent_password() {
println!("Changing permanent password is disabled!");
return None;
}
if args.len() == 2 { if args.len() == 2 {
if crate::platform::is_installed() && is_root() { if crate::platform::is_installed() && is_root() {
if let Err(err) = crate::ipc::set_permanent_password(args[1].to_owned()) { if let Err(err) = crate::ipc::set_permanent_password(args[1].to_owned()) {
@@ -419,6 +423,10 @@ pub fn core_main() -> Option<Vec<String>> {
} }
return None; return None;
} else if args[0] == "--set-unlock-pin" { } else if args[0] == "--set-unlock-pin" {
if config::Config::is_disable_unlock_pin() {
println!("Unlock PIN is disabled!");
return None;
}
#[cfg(feature = "flutter")] #[cfg(feature = "flutter")]
if args.len() == 2 { if args.len() == 2 {
if crate::platform::is_installed() && is_root() { if crate::platform::is_installed() && is_root() {
@@ -440,6 +448,10 @@ pub fn core_main() -> Option<Vec<String>> {
println!("Settings are disabled!"); println!("Settings are disabled!");
return None; return None;
} }
if config::Config::is_disable_change_id() {
println!("Changing ID is disabled!");
return None;
}
if args.len() == 2 { if args.len() == 2 {
if crate::platform::is_installed() && is_root() { if crate::platform::is_installed() && is_root() {
let old_id = crate::ipc::get_id(); let old_id = crate::ipc::get_id();

View File

@@ -16,6 +16,8 @@ const disable_ab = handler.is_disable_ab();
const hide_server_settings = handler.get_builtin_option("hide-server-settings") == "Y"; const hide_server_settings = handler.get_builtin_option("hide-server-settings") == "Y";
const hide_proxy_settings = handler.get_builtin_option("hide-proxy-settings") == "Y"; const hide_proxy_settings = handler.get_builtin_option("hide-proxy-settings") == "Y";
const hide_websocket_settings = handler.get_builtin_option("hide-websocket-settings") == "Y"; const hide_websocket_settings = handler.get_builtin_option("hide-websocket-settings") == "Y";
const disable_change_permanent_password = handler.get_builtin_option("disable-change-permanent-password") == "Y";
const disable_change_id = handler.get_builtin_option("disable-change-id") == "Y";
// html min-width, min-height not working on mac, below works for all // html min-width, min-height not working on mac, below works for all
if (incoming_only) { if (incoming_only) {
@@ -508,11 +510,11 @@ class MyIdMenu: Reactor.Component {
{!disable_settings && is_win && handler.is_installed() ? <ShareRdp /> : ""} {!disable_settings && is_win && handler.is_installed() ? <ShareRdp /> : ""}
{!disable_settings && <DirectServer />} {!disable_settings && <DirectServer />}
{!disable_settings && false && handler.using_public_server() && <li #allow-always-relay><span>{svg_checkmark}</span>{translate('Always connect via relay')}</li>} {!disable_settings && false && handler.using_public_server() && <li #allow-always-relay><span>{svg_checkmark}</span>{translate('Always connect via relay')}</li>}
{handler.is_ok_change_id() ? <div .separator /> : ""} {!disable_change_id && handler.is_ok_change_id() ? <div .separator /> : ""}
{!disable_account && (username ? {!disable_account && (username ?
<li #logout>{translate('Logout')} ({username})</li> : <li #logout>{translate('Logout')} ({username})</li> :
<li #login>{translate('Login')}</li>)} <li #login>{translate('Login')}</li>)}
{!disable_settings && handler.is_ok_change_id() && key_confirmed && connect_status > 0 ? <li #change-id>{translate('Change ID')}</li> : ""} {!disable_change_id && !disable_settings && handler.is_ok_change_id() && key_confirmed && connect_status > 0 ? <li #change-id>{translate('Change ID')}</li> : ""}
<div .separator /> <div .separator />
<li #allow-darktheme><span>{svg_checkmark}</span>{translate('Dark Theme')}</li> <li #allow-darktheme><span>{svg_checkmark}</span>{translate('Dark Theme')}</li>
<Languages /> <Languages />
@@ -1050,7 +1052,7 @@ class PasswordArea: Reactor.Component {
{ !show_password ? '' : <li #use-permanent-password><span>{svg_checkmark}</span>{translate('Use permanent password')}</li> } { !show_password ? '' : <li #use-permanent-password><span>{svg_checkmark}</span>{translate('Use permanent password')}</li> }
{ !show_password ? '' : <li #use-both-passwords><span>{svg_checkmark}</span>{translate('Use both passwords')}</li> } { !show_password ? '' : <li #use-both-passwords><span>{svg_checkmark}</span>{translate('Use both passwords')}</li> }
{ !show_password ? '' : <div .separator /> } { !show_password ? '' : <div .separator /> }
{ !show_password ? '' : <li #set-password disabled={ method == 'use-temporary-password' ? "true" : "false" }>{translate('Set permanent password')}</li> } { !show_password || disable_change_permanent_password ? '' : <li #set-password disabled={ method == 'use-temporary-password' ? "true" : "false" }>{translate('Set permanent password')}</li> }
{ !show_password ? '' : <TemporaryPasswordLengthMenu /> } { !show_password ? '' : <TemporaryPasswordLengthMenu /> }
<div .separator /> <div .separator />
<li #tfa><span>{svg_checkmark}</span>{translate('enable-2fa-title')}</li> <li #tfa><span>{svg_checkmark}</span>{translate('enable-2fa-title')}</li>