Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c6d347d

Browse files
committedApr 25, 2025·
Refactor the Linux version to not store sudo password
1 parent ea42246 commit c6d347d

18 files changed

+161
-77
lines changed
 

‎v2rayN/ServiceLib/Enums/EViewAction.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public enum EViewAction
2020
BrowseServer,
2121
ImportRulesFromFile,
2222
InitSettingFont,
23+
PasswordInput,
2324
SubEditWindow,
2425
RoutingRuleSettingWindow,
2526
RoutingRuleDetailsWindow,

‎v2rayN/ServiceLib/Handler/AppHandler.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ public bool IsAdministrator
4040
}
4141
}
4242

43+
public string LinuxSudoPwd { get; set; }
44+
4345
#endregion Property
4446

4547
#region Init

‎v2rayN/ServiceLib/Handler/CoreHandler.cs

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -229,9 +229,7 @@ private bool IsNeedSudo(ECoreType eCoreType)
229229
{
230230
return _config.TunModeItem.EnableTun
231231
&& eCoreType == ECoreType.sing_box
232-
&& (Utils.IsNonWindows())
233-
//&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
234-
;
232+
&& Utils.IsNonWindows();
235233
}
236234

237235
#endregion Private
@@ -288,13 +286,11 @@ private bool IsNeedSudo(ECoreType eCoreType)
288286
}
289287
proc.Start();
290288

291-
if (isNeedSudo && _config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
289+
if (isNeedSudo && AppHandler.Instance.LinuxSudoPwd.IsNotEmpty())
292290
{
293-
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
291+
await proc.StandardInput.WriteLineAsync();
294292
await Task.Delay(10);
295-
await proc.StandardInput.WriteLineAsync(pwd);
296-
await Task.Delay(10);
297-
await proc.StandardInput.WriteLineAsync(pwd);
293+
await proc.StandardInput.WriteLineAsync(AppHandler.Instance.LinuxSudoPwd);
298294
}
299295
if (isNeedSudo)
300296
_linuxSudoPid = proc.Id;
@@ -333,7 +329,7 @@ private async Task RunProcessAsLinuxSudo(Process proc, string fileName, CoreInfo
333329
proc.StartInfo.FileName = shFilePath;
334330
proc.StartInfo.Arguments = "";
335331
proc.StartInfo.WorkingDirectory = "";
336-
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
332+
if (AppHandler.Instance.LinuxSudoPwd.IsNotEmpty())
337333
{
338334
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
339335
proc.StartInfo.RedirectStandardInput = true;
@@ -342,7 +338,7 @@ private async Task RunProcessAsLinuxSudo(Process proc, string fileName, CoreInfo
342338

343339
private async Task KillProcessAsLinuxSudo()
344340
{
345-
var cmdLine = $"kill {_linuxSudoPid}";
341+
var cmdLine = $"pkill -P {_linuxSudoPid} ; kill {_linuxSudoPid}";
346342
var shFilePath = await CreateLinuxShellFile(cmdLine, "kill_as_sudo.sh");
347343
Process proc = new()
348344
{
@@ -357,15 +353,13 @@ private async Task KillProcessAsLinuxSudo()
357353
};
358354
proc.Start();
359355

360-
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
356+
if (AppHandler.Instance.LinuxSudoPwd.IsNotEmpty())
361357
{
362358
try
363359
{
364-
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
365-
await Task.Delay(10);
366-
await proc.StandardInput.WriteLineAsync(pwd);
360+
await proc.StandardInput.WriteLineAsync();
367361
await Task.Delay(10);
368-
await proc.StandardInput.WriteLineAsync(pwd);
362+
await proc.StandardInput.WriteLineAsync(AppHandler.Instance.LinuxSudoPwd);
369363
}
370364
catch (Exception)
371365
{
@@ -375,7 +369,7 @@ private async Task KillProcessAsLinuxSudo()
375369

376370
var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10));
377371
await proc.WaitForExitAsync(timeout.Token);
378-
await Task.Delay(3000);
372+
await Task.Delay(1000);
379373
}
380374

381375
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
@@ -389,10 +383,6 @@ private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
389383
{
390384
sb.AppendLine($"{cmdLine}");
391385
}
392-
else if (_config.TunModeItem.LinuxSudoPwd.IsNullOrEmpty())
393-
{
394-
sb.AppendLine($"pkexec {cmdLine}");
395-
}
396386
else
397387
{
398388
sb.AppendLine($"sudo -S {cmdLine}");

‎v2rayN/ServiceLib/Models/ConfigItems.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ public class TunModeItem
147147
public int Mtu { get; set; }
148148
public bool EnableExInbound { get; set; }
149149
public bool EnableIPv6Address { get; set; }
150-
public string? LinuxSudoPwd { get; set; }
151150
}
152151

153152
[Serializable]

‎v2rayN/ServiceLib/Resx/ResUI.Designer.cs

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,7 +1339,7 @@
13391339
<value>رمز عبور sudo سیستم</value>
13401340
</data>
13411341
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
1342-
<value>رمز عبور رمزگذاری شده و فقط در فایل های محلی ذخیره می شود.</value>
1342+
<value>The password you entered cannot be verified, so make sure you enter it correctly. If the application does not work properly due to an incorrect input, please restart the application. The password will not be stored and you will need to enter it again after each restart.</value>
13431343
</data>
13441344
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
13451345
<value>لطفاً ابتدا رمز عبور sudo را در تنظیمات حالت Tun تنظیم کنید</value>
@@ -1416,4 +1416,4 @@
14161416
<data name="menuExportConfig" xml:space="preserve">
14171417
<value>صادر کردن سرور</value>
14181418
</data>
1419-
</root>
1419+
</root>

‎v2rayN/ServiceLib/Resx/ResUI.hu.resx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1339,7 +1339,7 @@
13391339
<value>Rendszer sudo jelszó</value>
13401340
</data>
13411341
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
1342-
<value>A jelszó titkosítva és csak a helyi fájlokban tárolva.</value>
1342+
<value>The password you entered cannot be verified, so make sure you enter it correctly. If the application does not work properly due to an incorrect input, please restart the application. The password will not be stored and you will need to enter it again after each restart.</value>
13431343
</data>
13441344
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
13451345
<value>Kérlek, először állítsd be a sudo jelszót a Tun módban</value>

‎v2rayN/ServiceLib/Resx/ResUI.resx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1339,7 +1339,7 @@
13391339
<value>System sudo password</value>
13401340
</data>
13411341
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
1342-
<value>The password is encrypted and stored only in local files</value>
1342+
<value>The password you entered cannot be verified, so make sure you enter it correctly. If the application does not work properly due to an incorrect input, please restart the application. The password will not be stored and you will need to enter it again after each restart.</value>
13431343
</data>
13441344
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
13451345
<value>Please set the sudo password in Tun mode settings first</value>

‎v2rayN/ServiceLib/Resx/ResUI.ru.resx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1339,7 +1339,7 @@
13391339
<value>System sudo password</value>
13401340
</data>
13411341
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
1342-
<value>Пароль зашифрован и хранится только в локальных файлах..</value>
1342+
<value>The password you entered cannot be verified, so make sure you enter it correctly. If the application does not work properly due to an incorrect input, please restart the application. The password will not be stored and you will need to enter it again after each restart.</value>
13431343
</data>
13441344
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
13451345
<value>Please set the sudo password in Tun mode settings first</value>

‎v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,13 +1071,13 @@
10711071
<data name="TbHeaderType8" xml:space="preserve">
10721072
<value>拥塞控制算法</value>
10731073
</data>
1074-
<data name="LvPrevProfile" xml:space="preserve">
1074+
<data name="LvPrevProfile" xml:space="preserve">
10751075
<value>前置代理配置文件别名</value>
10761076
</data>
1077-
<data name="LvNextProfile" xml:space="preserve">
1077+
<data name="LvNextProfile" xml:space="preserve">
10781078
<value>落地代理配置文件別名</value>
10791079
</data>
1080-
<data name="LvPrevProfileTip" xml:space="preserve">
1080+
<data name="LvPrevProfileTip" xml:space="preserve">
10811081
<value>请确保配置文件别名存在并唯一</value>
10821082
</data>
10831083
<data name="TbSettingsEnableExInbound" xml:space="preserve">
@@ -1336,7 +1336,7 @@
13361336
<value>系统的 sudo 密码</value>
13371337
</data>
13381338
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
1339-
<value>密码已加密且只存储在本地文件中,无密码则每次都要输入</value>
1339+
<value>输入的密码无法校验,所以请确保输入正确。如果因为输入错误导致无法正常运行时,请重启本应用。 密码不会存储,每次重启后都需要再次输入。</value>
13401340
</data>
13411341
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
13421342
<value>请先在 Tun 模式设置中设置 sudo 密码</value>
@@ -1413,4 +1413,4 @@
14131413
<data name="menuExportConfig" xml:space="preserve">
14141414
<value>导出配置文件</value>
14151415
</data>
1416-
</root>
1416+
</root>

‎v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,13 +1071,13 @@
10711071
<data name="TbHeaderType8" xml:space="preserve">
10721072
<value>擁塞控制算法</value>
10731073
</data>
1074-
<data name="LvPrevProfile" xml:space="preserve">
1074+
<data name="LvPrevProfile" xml:space="preserve">
10751075
<value>前置代理設定檔別名</value>
10761076
</data>
1077-
<data name="LvNextProfile" xml:space="preserve">
1077+
<data name="LvNextProfile" xml:space="preserve">
10781078
<value>落地代理設定檔別名</value>
10791079
</data>
1080-
<data name="LvPrevProfileTip" xml:space="preserve">
1080+
<data name="LvPrevProfileTip" xml:space="preserve">
10811081
<value>請確保設定檔別名存在並且唯一</value>
10821082
</data>
10831083
<data name="TbSettingsEnableExInbound" xml:space="preserve">
@@ -1336,7 +1336,7 @@
13361336
<value>系統的 sudo 密碼</value>
13371337
</data>
13381338
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
1339-
<value>密碼已加密且只儲存在本機檔案中,無密碼則每次都要輸入</value>
1339+
<value>輸入的密碼無法校驗,所以請確保輸入正確。如果因為輸入錯誤導致無法正常運作時,請重新啟動本應用。 密碼不會存儲,每次重啟後都需要再次輸入。</value>
13401340
</data>
13411341
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
13421342
<value>請先在 Tun 模式設定中設定 sudo 密碼</value>
@@ -1413,4 +1413,4 @@
14131413
<data name="menuExportConfig" xml:space="preserve">
14141414
<value>匯出設定檔</value>
14151415
</data>
1416-
</root>
1416+
</root>

‎v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ public class OptionSettingViewModel : MyReactiveObject
8888
[Reactive] public int TunMtu { get; set; }
8989
[Reactive] public bool TunEnableExInbound { get; set; }
9090
[Reactive] public bool TunEnableIPv6Address { get; set; }
91-
[Reactive] public string TunLinuxSudoPassword { get; set; }
9291

9392
#endregion Tun mode
9493

@@ -205,7 +204,6 @@ private async Task Init()
205204
TunMtu = _config.TunModeItem.Mtu;
206205
TunEnableExInbound = _config.TunModeItem.EnableExInbound;
207206
TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address;
208-
TunLinuxSudoPassword = _config.TunModeItem.LinuxSudoPwd;
209207

210208
#endregion Tun mode
211209

@@ -358,11 +356,7 @@ private async Task SaveSettingAsync()
358356
_config.TunModeItem.Mtu = TunMtu;
359357
_config.TunModeItem.EnableExInbound = TunEnableExInbound;
360358
_config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address;
361-
if (TunLinuxSudoPassword != _config.TunModeItem.LinuxSudoPwd)
362-
{
363-
_config.TunModeItem.LinuxSudoPwd = DesUtils.Encrypt(TunLinuxSudoPassword);
364-
}
365-
359+
366360
//coreType
367361
await SaveCoreType();
368362

‎v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -436,11 +436,13 @@ private async Task DoEnableTun(bool c)
436436
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
437437
return;
438438
}
439-
else if (Utils.IsOSX())
439+
else
440440
{
441-
_config.TunModeItem.EnableTun = false;
442-
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordIsEmpty);
443-
return;
441+
if (await _updateView?.Invoke(EViewAction.PasswordInput, null) == false)
442+
{
443+
_config.TunModeItem.EnableTun = false;
444+
return;
445+
}
444446
}
445447
}
446448
await ConfigHandler.SaveConfig(_config);
@@ -456,11 +458,11 @@ private bool AllowEnableTun()
456458
}
457459
else if (Utils.IsLinux())
458460
{
459-
return _config.TunModeItem.LinuxSudoPwd.IsNotEmpty();
461+
return AppHandler.Instance.LinuxSudoPwd.IsNotEmpty();
460462
}
461463
else if (Utils.IsOSX())
462464
{
463-
return _config.TunModeItem.LinuxSudoPwd.IsNotEmpty();
465+
return AppHandler.Instance.LinuxSudoPwd.IsNotEmpty();
464466
}
465467
return false;
466468
}

‎v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -784,28 +784,6 @@
784784
Margin="{StaticResource Margin4}"
785785
HorizontalAlignment="Left" />
786786

787-
<TextBlock
788-
x:Name="labLinuxSudoPassword"
789-
Grid.Row="7"
790-
Grid.Column="0"
791-
Margin="{StaticResource Margin4}"
792-
VerticalAlignment="Center"
793-
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPassword}" />
794-
<TextBox
795-
x:Name="txtLinuxSudoPassword"
796-
Grid.Row="7"
797-
Grid.Column="1"
798-
Width="200"
799-
Margin="{StaticResource Margin4}"
800-
HorizontalAlignment="Left" />
801-
<TextBlock
802-
x:Name="labLinuxSudoPasswordTip"
803-
Grid.Row="7"
804-
Grid.Column="2"
805-
Margin="{StaticResource Margin4}"
806-
VerticalAlignment="Center"
807-
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPasswordTip}"
808-
TextWrapping="Wrap" />
809787
</Grid>
810788
</TabItem>
811789

‎v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,6 @@ public OptionSettingWindow()
153153
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.SelectedValue).DisposeWith(disposables);
154154
this.Bind(ViewModel, vm => vm.TunEnableExInbound, v => v.togEnableExInbound.IsChecked).DisposeWith(disposables);
155155
this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables);
156-
this.Bind(ViewModel, vm => vm.TunLinuxSudoPassword, v => v.txtLinuxSudoPassword.Text).DisposeWith(disposables);
157156

158157
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables);
159158
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.SelectedValue).DisposeWith(disposables);
@@ -170,10 +169,6 @@ public OptionSettingWindow()
170169
{
171170
txbSettingsExceptionTip2.IsVisible = false;
172171

173-
txtLinuxSudoPassword.IsVisible = false;
174-
labLinuxSudoPassword.IsVisible = false;
175-
labLinuxSudoPasswordTip.IsVisible = false;
176-
177172
labHide2TrayWhenClose.IsVisible = false;
178173
togHide2TrayWhenClose.IsVisible = false;
179174
}

‎v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
using Avalonia.Controls.ApplicationLifetimes;
55
using Avalonia.ReactiveUI;
66
using Avalonia.Threading;
7+
using DialogHostAvalonia;
78
using ReactiveUI;
89
using Splat;
910
using v2rayN.Desktop.Common;
11+
using static QRCoder.PayloadGenerator;
1012

1113
namespace v2rayN.Desktop.Views;
1214

@@ -81,6 +83,10 @@ private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
8183
return false;
8284
await AvaUtils.SetClipboardData(this, (string)obj);
8385
break;
86+
87+
case EViewAction.PasswordInput:
88+
return await PasswordInputAsync();
89+
break;
8490
}
8591
return await Task.FromResult(true);
8692
}
@@ -96,6 +102,20 @@ private void RefreshIcon()
96102
}
97103
}
98104

105+
private async Task<bool> PasswordInputAsync()
106+
{
107+
var dialog = new SudoPasswordInputView();
108+
var obj = await DialogHost.Show(dialog);
109+
if (obj == null)
110+
{
111+
togEnableTun.IsChecked = false;
112+
return false;
113+
}
114+
115+
AppHandler.Instance.LinuxSudoPwd = obj.ToString() ?? string.Empty;
116+
return true;
117+
}
118+
99119
private void TxtRunningServerDisplay_Tapped(object? sender, Avalonia.Input.TappedEventArgs e)
100120
{
101121
ViewModel?.TestServerAvailability();
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<UserControl
2+
x:Class="v2rayN.Desktop.Views.SudoPasswordInputView"
3+
xmlns="https://github.com/avaloniaui"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
7+
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
8+
d:DesignHeight="200"
9+
d:DesignWidth="400"
10+
mc:Ignorable="d">
11+
<DockPanel Margin="{StaticResource Margin8}">
12+
13+
<Border
14+
Margin="{StaticResource Margin4}"
15+
VerticalAlignment="Center"
16+
DockPanel.Dock="Bottom"
17+
Theme="{DynamicResource CardBorder}">
18+
19+
<StackPanel
20+
Margin="{StaticResource Margin4}"
21+
HorizontalAlignment="Center"
22+
Orientation="Horizontal">
23+
<Button
24+
x:Name="btnSave"
25+
Width="100"
26+
Content="{x:Static resx:ResUI.TbConfirm}"
27+
Cursor="Hand"
28+
IsDefault="True" />
29+
<Button
30+
x:Name="btnCancel"
31+
Width="100"
32+
Margin="{StaticResource MarginLr8}"
33+
Content="{x:Static resx:ResUI.TbCancel}"
34+
Cursor="Hand"
35+
IsCancel="True" />
36+
</StackPanel>
37+
</Border>
38+
39+
<Border
40+
Margin="{StaticResource Margin4}"
41+
VerticalAlignment="Center"
42+
Theme="{DynamicResource CardBorder}">
43+
44+
<Grid ColumnDefinitions="Auto,400" RowDefinitions="Auto,Auto,Auto">
45+
<TextBlock
46+
Grid.Row="1"
47+
Grid.Column="0"
48+
Margin="{StaticResource Margin4}"
49+
VerticalAlignment="Center"
50+
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPassword}" />
51+
52+
<TextBox
53+
x:Name="txtPassword"
54+
Grid.Row="1"
55+
Grid.Column="1"
56+
Margin="{StaticResource Margin4}"
57+
Classes="revealPasswordButton"
58+
Focusable="True" />
59+
60+
<TextBlock
61+
Grid.Row="2"
62+
Grid.Column="1"
63+
Margin="{StaticResource Margin4}"
64+
VerticalAlignment="Center"
65+
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPasswordTip}"
66+
TextWrapping="Wrap" />
67+
</Grid>
68+
</Border>
69+
</DockPanel>
70+
</UserControl>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using Avalonia.Controls;
2+
using Avalonia.Threading;
3+
using DialogHostAvalonia;
4+
5+
namespace v2rayN.Desktop.Views;
6+
7+
public partial class SudoPasswordInputView : UserControl
8+
{
9+
public SudoPasswordInputView()
10+
{
11+
InitializeComponent();
12+
13+
this.Loaded += (s, e) => txtPassword.Focus();
14+
15+
btnSave.Click += (_, _) =>
16+
{
17+
if (string.IsNullOrEmpty(txtPassword.Text))
18+
{
19+
txtPassword.Focus();
20+
return;
21+
}
22+
Dispatcher.UIThread.Post(() =>
23+
{
24+
DialogHost.Close(null, txtPassword.Text);
25+
});
26+
};
27+
28+
btnCancel.Click += (_, _) =>
29+
{
30+
DialogHost.Close(null);
31+
};
32+
}
33+
}

0 commit comments

Comments
 (0)
Please sign in to comment.