From ea42246d1b2cc8740b31676d9a9d6343d0536592 Mon Sep 17 00:00:00 2001
From: 2dust <31833384+2dust@users.noreply.github.com>
Date: Fri, 25 Apr 2025 14:38:33 +0800
Subject: [PATCH 1/8] Improved AmazTool
---
v2rayN/AmazTool/Program.cs | 84 +++++++++++++++++++++++++++++++++-----
1 file changed, 73 insertions(+), 11 deletions(-)
diff --git a/v2rayN/AmazTool/Program.cs b/v2rayN/AmazTool/Program.cs
index d71c25c2..4df39682 100644
--- a/v2rayN/AmazTool/Program.cs
+++ b/v2rayN/AmazTool/Program.cs
@@ -5,21 +5,83 @@ internal static class Program
[STAThread]
private static void Main(string[] args)
{
- if (args.Length == 0)
+ try
{
- Console.WriteLine(Resx.Resource.Guidelines);
- Thread.Sleep(5000);
- return;
- }
+ // If no arguments are provided, display usage guidelines and exit
+ if (args.Length == 0)
+ {
+ ShowHelp();
+ return;
+ }
- var argData = Uri.UnescapeDataString(string.Join(" ", args));
- if (argData.Equals("rebootas"))
+ // Log all arguments for debugging purposes
+ foreach (var arg in args)
+ {
+ Console.WriteLine(arg);
+ }
+
+ // Parse command based on first argument
+ switch (args[0].ToLowerInvariant())
+ {
+ case "rebootas":
+ // Handle application restart
+ HandleRebootAsync();
+ break;
+
+ case "help":
+ case "--help":
+ case "-h":
+ case "/?":
+ // Display help information
+ ShowHelp();
+ break;
+
+ default:
+ // Default behavior: handle as upgrade data
+ // Maintain backward compatibility with existing usage pattern
+ var argData = Uri.UnescapeDataString(string.Join(" ", args));
+ HandleUpgrade(argData);
+ break;
+ }
+ }
+ catch (Exception ex)
{
- Thread.Sleep(1000);
- Utils.StartV2RayN();
- return;
+ // Global exception handling
+ Console.WriteLine($"An error occurred: {ex.Message}");
+ Console.WriteLine("Press any key to exit...");
+ Console.ReadKey();
}
+ }
- UpgradeApp.Upgrade(argData);
+ ///
+ /// Display help information and usage guidelines
+ ///
+ private static void ShowHelp()
+ {
+ Console.WriteLine(Resx.Resource.Guidelines);
+ Console.WriteLine("Available commands:");
+ Console.WriteLine(" rebootas - Restart the application");
+ Console.WriteLine(" help - Display this help information");
+ Thread.Sleep(5000);
+ }
+
+ ///
+ /// Handle application restart
+ ///
+ private static void HandleRebootAsync()
+ {
+ Console.WriteLine("Restarting application...");
+ Thread.Sleep(1000);
+ Utils.StartV2RayN();
+ }
+
+ ///
+ /// Handle application upgrade with the provided data
+ ///
+ /// Data for the upgrade process
+ private static void HandleUpgrade(string upgradeData)
+ {
+ Console.WriteLine("Upgrading application...");
+ UpgradeApp.Upgrade(upgradeData);
}
}
From c6d347d49a62751f59acf9c8c54d332bc7f2204d Mon Sep 17 00:00:00 2001
From: 2dust <31833384+2dust@users.noreply.github.com>
Date: Fri, 25 Apr 2025 15:19:49 +0800
Subject: [PATCH 2/8] Refactor the Linux version to not store sudo password
---
v2rayN/ServiceLib/Enums/EViewAction.cs | 1 +
v2rayN/ServiceLib/Handler/AppHandler.cs | 2 +
v2rayN/ServiceLib/Handler/CoreHandler.cs | 30 +++-----
v2rayN/ServiceLib/Models/ConfigItems.cs | 1 -
v2rayN/ServiceLib/Resx/ResUI.Designer.cs | 2 +-
v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx | 4 +-
v2rayN/ServiceLib/Resx/ResUI.hu.resx | 2 +-
v2rayN/ServiceLib/Resx/ResUI.resx | 2 +-
v2rayN/ServiceLib/Resx/ResUI.ru.resx | 2 +-
v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx | 10 +--
v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx | 10 +--
.../ViewModels/OptionSettingViewModel.cs | 8 +--
.../ViewModels/StatusBarViewModel.cs | 14 ++--
.../Views/OptionSettingWindow.axaml | 22 ------
.../Views/OptionSettingWindow.axaml.cs | 5 --
.../Views/StatusBarView.axaml.cs | 20 ++++++
.../Views/SudoPasswordInputView.axaml | 70 +++++++++++++++++++
.../Views/SudoPasswordInputView.axaml.cs | 33 +++++++++
18 files changed, 161 insertions(+), 77 deletions(-)
create mode 100644 v2rayN/v2rayN.Desktop/Views/SudoPasswordInputView.axaml
create mode 100644 v2rayN/v2rayN.Desktop/Views/SudoPasswordInputView.axaml.cs
diff --git a/v2rayN/ServiceLib/Enums/EViewAction.cs b/v2rayN/ServiceLib/Enums/EViewAction.cs
index 75142925..a72e8765 100644
--- a/v2rayN/ServiceLib/Enums/EViewAction.cs
+++ b/v2rayN/ServiceLib/Enums/EViewAction.cs
@@ -20,6 +20,7 @@ public enum EViewAction
BrowseServer,
ImportRulesFromFile,
InitSettingFont,
+ PasswordInput,
SubEditWindow,
RoutingRuleSettingWindow,
RoutingRuleDetailsWindow,
diff --git a/v2rayN/ServiceLib/Handler/AppHandler.cs b/v2rayN/ServiceLib/Handler/AppHandler.cs
index 0b8054f1..3f9fdf74 100644
--- a/v2rayN/ServiceLib/Handler/AppHandler.cs
+++ b/v2rayN/ServiceLib/Handler/AppHandler.cs
@@ -40,6 +40,8 @@ public sealed class AppHandler
}
}
+ public string LinuxSudoPwd { get; set; }
+
#endregion Property
#region Init
diff --git a/v2rayN/ServiceLib/Handler/CoreHandler.cs b/v2rayN/ServiceLib/Handler/CoreHandler.cs
index 41ea866d..499d8999 100644
--- a/v2rayN/ServiceLib/Handler/CoreHandler.cs
+++ b/v2rayN/ServiceLib/Handler/CoreHandler.cs
@@ -229,9 +229,7 @@ public class CoreHandler
{
return _config.TunModeItem.EnableTun
&& eCoreType == ECoreType.sing_box
- && (Utils.IsNonWindows())
- //&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
- ;
+ && Utils.IsNonWindows();
}
#endregion Private
@@ -288,13 +286,11 @@ public class CoreHandler
}
proc.Start();
- if (isNeedSudo && _config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
+ if (isNeedSudo && AppHandler.Instance.LinuxSudoPwd.IsNotEmpty())
{
- var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
+ await proc.StandardInput.WriteLineAsync();
await Task.Delay(10);
- await proc.StandardInput.WriteLineAsync(pwd);
- await Task.Delay(10);
- await proc.StandardInput.WriteLineAsync(pwd);
+ await proc.StandardInput.WriteLineAsync(AppHandler.Instance.LinuxSudoPwd);
}
if (isNeedSudo)
_linuxSudoPid = proc.Id;
@@ -333,7 +329,7 @@ public class CoreHandler
proc.StartInfo.FileName = shFilePath;
proc.StartInfo.Arguments = "";
proc.StartInfo.WorkingDirectory = "";
- if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
+ if (AppHandler.Instance.LinuxSudoPwd.IsNotEmpty())
{
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
proc.StartInfo.RedirectStandardInput = true;
@@ -342,7 +338,7 @@ public class CoreHandler
private async Task KillProcessAsLinuxSudo()
{
- var cmdLine = $"kill {_linuxSudoPid}";
+ var cmdLine = $"pkill -P {_linuxSudoPid} ; kill {_linuxSudoPid}";
var shFilePath = await CreateLinuxShellFile(cmdLine, "kill_as_sudo.sh");
Process proc = new()
{
@@ -357,15 +353,13 @@ public class CoreHandler
};
proc.Start();
- if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
+ if (AppHandler.Instance.LinuxSudoPwd.IsNotEmpty())
{
try
{
- var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
+ await proc.StandardInput.WriteLineAsync();
await Task.Delay(10);
- await proc.StandardInput.WriteLineAsync(pwd);
- await Task.Delay(10);
- await proc.StandardInput.WriteLineAsync(pwd);
+ await proc.StandardInput.WriteLineAsync(AppHandler.Instance.LinuxSudoPwd);
}
catch (Exception)
{
@@ -375,7 +369,7 @@ public class CoreHandler
var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10));
await proc.WaitForExitAsync(timeout.Token);
- await Task.Delay(3000);
+ await Task.Delay(1000);
}
private async Task CreateLinuxShellFile(string cmdLine, string fileName)
@@ -389,10 +383,6 @@ public class CoreHandler
{
sb.AppendLine($"{cmdLine}");
}
- else if (_config.TunModeItem.LinuxSudoPwd.IsNullOrEmpty())
- {
- sb.AppendLine($"pkexec {cmdLine}");
- }
else
{
sb.AppendLine($"sudo -S {cmdLine}");
diff --git a/v2rayN/ServiceLib/Models/ConfigItems.cs b/v2rayN/ServiceLib/Models/ConfigItems.cs
index b3fa1b98..47c96a3f 100644
--- a/v2rayN/ServiceLib/Models/ConfigItems.cs
+++ b/v2rayN/ServiceLib/Models/ConfigItems.cs
@@ -147,7 +147,6 @@ public class TunModeItem
public int Mtu { get; set; }
public bool EnableExInbound { get; set; }
public bool EnableIPv6Address { get; set; }
- public string? LinuxSudoPwd { get; set; }
}
[Serializable]
diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
index 0b9cc936..ac507c45 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
+++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
@@ -3247,7 +3247,7 @@ namespace ServiceLib.Resx {
}
///
- /// 查找类似 The password is encrypted and stored only in local files 的本地化字符串。
+ /// 查找类似 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. 的本地化字符串。
///
public static string TbSettingsLinuxSudoPasswordTip {
get {
diff --git a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
index a937a262..adf4eb0e 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
@@ -1339,7 +1339,7 @@
رمز عبور sudo سیستم
- رمز عبور رمزگذاری شده و فقط در فایل های محلی ذخیره می شود.
+ 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.
لطفاً ابتدا رمز عبور sudo را در تنظیمات حالت Tun تنظیم کنید
@@ -1416,4 +1416,4 @@
صادر کردن سرور
-
+
\ No newline at end of file
diff --git a/v2rayN/ServiceLib/Resx/ResUI.hu.resx b/v2rayN/ServiceLib/Resx/ResUI.hu.resx
index 05a12c10..130c3579 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.hu.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.hu.resx
@@ -1339,7 +1339,7 @@
Rendszer sudo jelszó
- A jelszó titkosítva és csak a helyi fájlokban tárolva.
+ 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.
Kérlek, először állítsd be a sudo jelszót a Tun módban
diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx
index 1fb3d23b..7ec5d653 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.resx
@@ -1339,7 +1339,7 @@
System sudo password
- The password is encrypted and stored only in local files
+ 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.
Please set the sudo password in Tun mode settings first
diff --git a/v2rayN/ServiceLib/Resx/ResUI.ru.resx b/v2rayN/ServiceLib/Resx/ResUI.ru.resx
index 824ea29a..9103641b 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.ru.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.ru.resx
@@ -1339,7 +1339,7 @@
System sudo password
- Пароль зашифрован и хранится только в локальных файлах..
+ 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.
Please set the sudo password in Tun mode settings first
diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
index a5f07957..150a9353 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
@@ -1071,13 +1071,13 @@
拥塞控制算法
-
+
前置代理配置文件别名
-
+
落地代理配置文件別名
-
+
请确保配置文件别名存在并唯一
@@ -1336,7 +1336,7 @@
系统的 sudo 密码
- 密码已加密且只存储在本地文件中,无密码则每次都要输入
+ 输入的密码无法校验,所以请确保输入正确。如果因为输入错误导致无法正常运行时,请重启本应用。 密码不会存储,每次重启后都需要再次输入。
请先在 Tun 模式设置中设置 sudo 密码
@@ -1413,4 +1413,4 @@
导出配置文件
-
+
\ No newline at end of file
diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
index b8a5011a..e827d0ea 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
@@ -1071,13 +1071,13 @@
擁塞控制算法
-
+
前置代理設定檔別名
-
+
落地代理設定檔別名
-
+
請確保設定檔別名存在並且唯一
@@ -1336,7 +1336,7 @@
系統的 sudo 密碼
- 密碼已加密且只儲存在本機檔案中,無密碼則每次都要輸入
+ 輸入的密碼無法校驗,所以請確保輸入正確。如果因為輸入錯誤導致無法正常運作時,請重新啟動本應用。 密碼不會存儲,每次重啟後都需要再次輸入。
請先在 Tun 模式設定中設定 sudo 密碼
@@ -1413,4 +1413,4 @@
匯出設定檔
-
+
\ No newline at end of file
diff --git a/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs b/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs
index b99339d6..fd26eb32 100644
--- a/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs
+++ b/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs
@@ -88,7 +88,6 @@ public class OptionSettingViewModel : MyReactiveObject
[Reactive] public int TunMtu { get; set; }
[Reactive] public bool TunEnableExInbound { get; set; }
[Reactive] public bool TunEnableIPv6Address { get; set; }
- [Reactive] public string TunLinuxSudoPassword { get; set; }
#endregion Tun mode
@@ -205,7 +204,6 @@ public class OptionSettingViewModel : MyReactiveObject
TunMtu = _config.TunModeItem.Mtu;
TunEnableExInbound = _config.TunModeItem.EnableExInbound;
TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address;
- TunLinuxSudoPassword = _config.TunModeItem.LinuxSudoPwd;
#endregion Tun mode
@@ -358,11 +356,7 @@ public class OptionSettingViewModel : MyReactiveObject
_config.TunModeItem.Mtu = TunMtu;
_config.TunModeItem.EnableExInbound = TunEnableExInbound;
_config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address;
- if (TunLinuxSudoPassword != _config.TunModeItem.LinuxSudoPwd)
- {
- _config.TunModeItem.LinuxSudoPwd = DesUtils.Encrypt(TunLinuxSudoPassword);
- }
-
+
//coreType
await SaveCoreType();
diff --git a/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs b/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs
index 00cc391a..ec6ec39e 100644
--- a/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs
+++ b/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs
@@ -436,11 +436,13 @@ public class StatusBarViewModel : MyReactiveObject
Locator.Current.GetService()?.RebootAsAdmin();
return;
}
- else if (Utils.IsOSX())
+ else
{
- _config.TunModeItem.EnableTun = false;
- NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordIsEmpty);
- return;
+ if (await _updateView?.Invoke(EViewAction.PasswordInput, null) == false)
+ {
+ _config.TunModeItem.EnableTun = false;
+ return;
+ }
}
}
await ConfigHandler.SaveConfig(_config);
@@ -456,11 +458,11 @@ public class StatusBarViewModel : MyReactiveObject
}
else if (Utils.IsLinux())
{
- return _config.TunModeItem.LinuxSudoPwd.IsNotEmpty();
+ return AppHandler.Instance.LinuxSudoPwd.IsNotEmpty();
}
else if (Utils.IsOSX())
{
- return _config.TunModeItem.LinuxSudoPwd.IsNotEmpty();
+ return AppHandler.Instance.LinuxSudoPwd.IsNotEmpty();
}
return false;
}
diff --git a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml
index 8c9351d7..3ad9b178 100644
--- a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml
+++ b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml
@@ -784,28 +784,6 @@
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
-
-
-
diff --git a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml.cs
index 58aceaf1..4faa0c27 100644
--- a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml.cs
+++ b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml.cs
@@ -153,7 +153,6 @@ public partial class OptionSettingWindow : ReactiveWindow vm.TunMtu, v => v.cmbMtu.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunEnableExInbound, v => v.togEnableExInbound.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables);
- this.Bind(ViewModel, vm => vm.TunLinuxSudoPassword, v => v.txtLinuxSudoPassword.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.SelectedValue).DisposeWith(disposables);
@@ -170,10 +169,6 @@ public partial class OptionSettingWindow : ReactiveWindow
return false;
await AvaUtils.SetClipboardData(this, (string)obj);
break;
+
+ case EViewAction.PasswordInput:
+ return await PasswordInputAsync();
+ break;
}
return await Task.FromResult(true);
}
@@ -96,6 +102,20 @@ public partial class StatusBarView : ReactiveUserControl
}
}
+ private async Task PasswordInputAsync()
+ {
+ var dialog = new SudoPasswordInputView();
+ var obj = await DialogHost.Show(dialog);
+ if (obj == null)
+ {
+ togEnableTun.IsChecked = false;
+ return false;
+ }
+
+ AppHandler.Instance.LinuxSudoPwd = obj.ToString() ?? string.Empty;
+ return true;
+ }
+
private void TxtRunningServerDisplay_Tapped(object? sender, Avalonia.Input.TappedEventArgs e)
{
ViewModel?.TestServerAvailability();
diff --git a/v2rayN/v2rayN.Desktop/Views/SudoPasswordInputView.axaml b/v2rayN/v2rayN.Desktop/Views/SudoPasswordInputView.axaml
new file mode 100644
index 00000000..507cbb49
--- /dev/null
+++ b/v2rayN/v2rayN.Desktop/Views/SudoPasswordInputView.axaml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/v2rayN/v2rayN.Desktop/Views/SudoPasswordInputView.axaml.cs b/v2rayN/v2rayN.Desktop/Views/SudoPasswordInputView.axaml.cs
new file mode 100644
index 00000000..8276faf4
--- /dev/null
+++ b/v2rayN/v2rayN.Desktop/Views/SudoPasswordInputView.axaml.cs
@@ -0,0 +1,33 @@
+using Avalonia.Controls;
+using Avalonia.Threading;
+using DialogHostAvalonia;
+
+namespace v2rayN.Desktop.Views;
+
+public partial class SudoPasswordInputView : UserControl
+{
+ public SudoPasswordInputView()
+ {
+ InitializeComponent();
+
+ this.Loaded += (s, e) => txtPassword.Focus();
+
+ btnSave.Click += (_, _) =>
+ {
+ if (string.IsNullOrEmpty(txtPassword.Text))
+ {
+ txtPassword.Focus();
+ return;
+ }
+ Dispatcher.UIThread.Post(() =>
+ {
+ DialogHost.Close(null, txtPassword.Text);
+ });
+ };
+
+ btnCancel.Click += (_, _) =>
+ {
+ DialogHost.Close(null);
+ };
+ }
+}
From 0032a3d27af7d91010233bed494105120f0cff5b Mon Sep 17 00:00:00 2001
From: 2dust <31833384+2dust@users.noreply.github.com>
Date: Fri, 25 Apr 2025 16:36:28 +0800
Subject: [PATCH 3/8] Fix kill process for linux
---
v2rayN/ServiceLib/Handler/CoreHandler.cs | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/v2rayN/ServiceLib/Handler/CoreHandler.cs b/v2rayN/ServiceLib/Handler/CoreHandler.cs
index 499d8999..a2f24df8 100644
--- a/v2rayN/ServiceLib/Handler/CoreHandler.cs
+++ b/v2rayN/ServiceLib/Handler/CoreHandler.cs
@@ -155,6 +155,12 @@ public class CoreHandler
{
try
{
+ if (_linuxSudoPid > 0)
+ {
+ await KillProcessAsLinuxSudo();
+ _linuxSudoPid = -1;
+ }
+
if (_process != null)
{
await ProcUtils.ProcessKill(_process, true);
@@ -166,12 +172,6 @@ public class CoreHandler
await ProcUtils.ProcessKill(_processPre, true);
_processPre = null;
}
-
- if (_linuxSudoPid > 0)
- {
- await KillProcessAsLinuxSudo();
- }
- _linuxSudoPid = -1;
}
catch (Exception ex)
{
@@ -390,7 +390,7 @@ public class CoreHandler
await File.WriteAllTextAsync(shFilePath, sb.ToString());
await Utils.SetLinuxChmod(shFilePath);
- Logging.SaveLog(shFilePath);
+ //Logging.SaveLog(shFilePath);
return shFilePath;
}
From adf3b955d6a4546425fabbc99e1fce2955bd4840 Mon Sep 17 00:00:00 2001
From: 2dust <31833384+2dust@users.noreply.github.com>
Date: Sat, 26 Apr 2025 09:50:31 +0800
Subject: [PATCH 4/8] Refactor Linux to run Tun as sudo
---
v2rayN/ServiceLib/Handler/AppHandler.cs | 9 --
v2rayN/ServiceLib/Handler/CoreAdminHandler.cs | 144 ++++++++++++++++++
v2rayN/ServiceLib/Handler/CoreHandler.cs | 136 +++--------------
.../ViewModels/StatusBarViewModel.cs | 2 +-
.../v2rayN.Desktop/Views/MainWindow.axaml.cs | 2 +-
v2rayN/v2rayN/Views/MainWindow.xaml.cs | 2 +-
6 files changed, 171 insertions(+), 124 deletions(-)
create mode 100644 v2rayN/ServiceLib/Handler/CoreAdminHandler.cs
diff --git a/v2rayN/ServiceLib/Handler/AppHandler.cs b/v2rayN/ServiceLib/Handler/AppHandler.cs
index 3f9fdf74..906e2ba3 100644
--- a/v2rayN/ServiceLib/Handler/AppHandler.cs
+++ b/v2rayN/ServiceLib/Handler/AppHandler.cs
@@ -31,15 +31,6 @@ public sealed class AppHandler
}
}
- public bool IsAdministrator
- {
- get
- {
- _isAdministrator ??= Utils.IsAdministrator();
- return _isAdministrator.Value;
- }
- }
-
public string LinuxSudoPwd { get; set; }
#endregion Property
diff --git a/v2rayN/ServiceLib/Handler/CoreAdminHandler.cs b/v2rayN/ServiceLib/Handler/CoreAdminHandler.cs
new file mode 100644
index 00000000..85d90fc3
--- /dev/null
+++ b/v2rayN/ServiceLib/Handler/CoreAdminHandler.cs
@@ -0,0 +1,144 @@
+using System.Diagnostics;
+using System.Text;
+using CliWrap;
+
+namespace ServiceLib.Handler;
+
+public class CoreAdminHandler
+{
+ private static readonly Lazy _instance = new(() => new());
+ public static CoreAdminHandler Instance => _instance.Value;
+ private Config _config;
+ private Action? _updateFunc;
+ private const string _tag = "CoreAdminHandler";
+ private int _linuxSudoPid = -1;
+
+ public async Task Init(Config config, Action updateFunc)
+ {
+ if (_config != null)
+ {
+ return;
+ }
+ _config = config;
+ _updateFunc = updateFunc;
+ }
+
+ private void UpdateFunc(bool notify, string msg)
+ {
+ _updateFunc?.Invoke(notify, msg);
+ }
+
+ public async Task RunProcessAsLinuxSudo(string fileName, CoreInfo coreInfo, string configPath)
+ {
+ try
+ {
+ var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
+ var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh");
+
+ Process proc = new()
+ {
+ StartInfo = new()
+ {
+ FileName = shFilePath,
+ Arguments = "",
+ WorkingDirectory = Utils.GetBinConfigPath(),
+ UseShellExecute = false,
+ RedirectStandardInput = true,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ CreateNoWindow = true,
+ StandardInputEncoding = Encoding.UTF8,
+ StandardOutputEncoding = Encoding.UTF8,
+ StandardErrorEncoding = Encoding.UTF8,
+ }
+ };
+
+ proc.OutputDataReceived += (sender, e) =>
+ {
+ if (e.Data.IsNotEmpty())
+ {
+ UpdateFunc(false, e.Data + Environment.NewLine);
+ }
+ };
+ proc.ErrorDataReceived += (sender, e) =>
+ {
+ if (e.Data.IsNotEmpty())
+ {
+ UpdateFunc(false, e.Data + Environment.NewLine);
+ }
+ };
+
+ proc.Start();
+ proc.BeginOutputReadLine();
+ proc.BeginErrorReadLine();
+
+ await Task.Delay(10);
+ await proc.StandardInput.WriteLineAsync();
+ await Task.Delay(10);
+ await proc.StandardInput.WriteLineAsync(AppHandler.Instance.LinuxSudoPwd);
+
+ await Task.Delay(100);
+ if (proc is null or { HasExited: true })
+ {
+ throw new Exception(ResUI.FailedToRunCore);
+ }
+
+ _linuxSudoPid = proc.Id;
+
+ return proc;
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(_tag, ex);
+ UpdateFunc(false, ex.Message);
+ return null;
+ }
+ }
+
+ public async Task KillProcessAsLinuxSudo()
+ {
+ if (_linuxSudoPid < 0)
+ {
+ return;
+ }
+
+ try
+ {
+ var cmdLine = $"pkill -P {_linuxSudoPid} ; kill {_linuxSudoPid}";
+ var shFilePath = await CreateLinuxShellFile(cmdLine, "kill_as_sudo.sh");
+
+ var result = await Cli.Wrap(shFilePath)
+ .WithStandardInputPipe(PipeSource.FromString(AppHandler.Instance.LinuxSudoPwd))
+ .ExecuteAsync();
+
+ _linuxSudoPid = -1;
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(_tag, ex);
+ UpdateFunc(false, ex.Message);
+ }
+ }
+
+ private async Task CreateLinuxShellFile(string cmdLine, string fileName)
+ {
+ var shFilePath = Utils.GetBinConfigPath(fileName);
+ File.Delete(shFilePath);
+
+ var sb = new StringBuilder();
+ sb.AppendLine("#!/bin/sh");
+ if (Utils.IsAdministrator())
+ {
+ sb.AppendLine($"{cmdLine}");
+ }
+ else
+ {
+ sb.AppendLine($"sudo -S {cmdLine}");
+ }
+
+ await File.WriteAllTextAsync(shFilePath, sb.ToString());
+ await Utils.SetLinuxChmod(shFilePath);
+
+ return shFilePath;
+ }
+}
diff --git a/v2rayN/ServiceLib/Handler/CoreHandler.cs b/v2rayN/ServiceLib/Handler/CoreHandler.cs
index a2f24df8..97918693 100644
--- a/v2rayN/ServiceLib/Handler/CoreHandler.cs
+++ b/v2rayN/ServiceLib/Handler/CoreHandler.cs
@@ -13,7 +13,7 @@ public class CoreHandler
private Config _config;
private Process? _process;
private Process? _processPre;
- private int _linuxSudoPid = -1;
+ private bool _linuxSudo = false;
private Action? _updateFunc;
private const string _tag = "CoreHandler";
@@ -155,21 +155,21 @@ public class CoreHandler
{
try
{
- if (_linuxSudoPid > 0)
+ if (_linuxSudo)
{
- await KillProcessAsLinuxSudo();
- _linuxSudoPid = -1;
+ await CoreAdminHandler.Instance.KillProcessAsLinuxSudo();
+ _linuxSudo = false;
}
if (_process != null)
{
- await ProcUtils.ProcessKill(_process, true);
+ await ProcUtils.ProcessKill(_process, Utils.IsWindows());
_process = null;
}
if (_processPre != null)
{
- await ProcUtils.ProcessKill(_processPre, true);
+ await ProcUtils.ProcessKill(_processPre, Utils.IsWindows());
_processPre = null;
}
}
@@ -225,13 +225,6 @@ public class CoreHandler
_updateFunc?.Invoke(notify, msg);
}
- private bool IsNeedSudo(ECoreType eCoreType)
- {
- return _config.TunModeItem.EnableTun
- && eCoreType == ECoreType.sing_box
- && Utils.IsNonWindows();
- }
-
#endregion Private
#region Process
@@ -245,6 +238,16 @@ public class CoreHandler
return null;
}
+ if (mayNeedSudo
+ && _config.TunModeItem.EnableTun
+ && coreInfo.CoreType == ECoreType.sing_box
+ && Utils.IsNonWindows())
+ {
+ _linuxSudo = true;
+ await CoreAdminHandler.Instance.Init(_config, _updateFunc);
+ return await CoreAdminHandler.Instance.RunProcessAsLinuxSudo(fileName, coreInfo, configPath);
+ }
+
try
{
Process proc = new()
@@ -263,38 +266,25 @@ public class CoreHandler
}
};
- var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
- if (isNeedSudo)
- {
- await RunProcessAsLinuxSudo(proc, fileName, coreInfo, configPath);
- }
-
if (displayLog)
{
proc.OutputDataReceived += (sender, e) =>
{
- if (e.Data.IsNullOrEmpty())
- return;
- UpdateFunc(false, e.Data + Environment.NewLine);
+ if (e.Data.IsNotEmpty())
+ {
+ UpdateFunc(false, e.Data + Environment.NewLine);
+ }
};
proc.ErrorDataReceived += (sender, e) =>
{
- if (e.Data.IsNullOrEmpty())
- return;
- UpdateFunc(false, e.Data + Environment.NewLine);
+ if (e.Data.IsNotEmpty())
+ {
+ UpdateFunc(false, e.Data + Environment.NewLine);
+ }
};
}
proc.Start();
- if (isNeedSudo && AppHandler.Instance.LinuxSudoPwd.IsNotEmpty())
- {
- await proc.StandardInput.WriteLineAsync();
- await Task.Delay(10);
- await proc.StandardInput.WriteLineAsync(AppHandler.Instance.LinuxSudoPwd);
- }
- if (isNeedSudo)
- _linuxSudoPid = proc.Id;
-
if (displayLog)
{
proc.BeginOutputReadLine();
@@ -318,82 +308,4 @@ public class CoreHandler
}
#endregion Process
-
- #region Linux
-
- private async Task RunProcessAsLinuxSudo(Process proc, string fileName, CoreInfo coreInfo, string configPath)
- {
- var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
-
- var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh");
- proc.StartInfo.FileName = shFilePath;
- proc.StartInfo.Arguments = "";
- proc.StartInfo.WorkingDirectory = "";
- if (AppHandler.Instance.LinuxSudoPwd.IsNotEmpty())
- {
- proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
- proc.StartInfo.RedirectStandardInput = true;
- }
- }
-
- private async Task KillProcessAsLinuxSudo()
- {
- var cmdLine = $"pkill -P {_linuxSudoPid} ; kill {_linuxSudoPid}";
- var shFilePath = await CreateLinuxShellFile(cmdLine, "kill_as_sudo.sh");
- Process proc = new()
- {
- StartInfo = new()
- {
- FileName = shFilePath,
- UseShellExecute = false,
- CreateNoWindow = true,
- StandardInputEncoding = Encoding.UTF8,
- RedirectStandardInput = true
- }
- };
- proc.Start();
-
- if (AppHandler.Instance.LinuxSudoPwd.IsNotEmpty())
- {
- try
- {
- await proc.StandardInput.WriteLineAsync();
- await Task.Delay(10);
- await proc.StandardInput.WriteLineAsync(AppHandler.Instance.LinuxSudoPwd);
- }
- catch (Exception)
- {
- // ignored
- }
- }
-
- var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10));
- await proc.WaitForExitAsync(timeout.Token);
- await Task.Delay(1000);
- }
-
- private async Task CreateLinuxShellFile(string cmdLine, string fileName)
- {
- //Shell scripts
- var shFilePath = Utils.GetBinConfigPath(AppHandler.Instance.IsAdministrator ? "root_" + fileName : fileName);
- File.Delete(shFilePath);
- var sb = new StringBuilder();
- sb.AppendLine("#!/bin/sh");
- if (AppHandler.Instance.IsAdministrator)
- {
- sb.AppendLine($"{cmdLine}");
- }
- else
- {
- sb.AppendLine($"sudo -S {cmdLine}");
- }
-
- await File.WriteAllTextAsync(shFilePath, sb.ToString());
- await Utils.SetLinuxChmod(shFilePath);
- //Logging.SaveLog(shFilePath);
-
- return shFilePath;
- }
-
- #endregion Linux
}
diff --git a/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs b/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs
index ec6ec39e..2c48d0bf 100644
--- a/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs
+++ b/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs
@@ -454,7 +454,7 @@ public class StatusBarViewModel : MyReactiveObject
{
if (Utils.IsWindows())
{
- return AppHandler.Instance.IsAdministrator;
+ return Utils.IsAdministrator();
}
else if (Utils.IsLinux())
{
diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs
index 91328046..34852a50 100644
--- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs
+++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs
@@ -143,7 +143,7 @@ public partial class MainWindow : ReactiveWindow
}
else
{
- if (AppHandler.Instance.IsAdministrator)
+ if (Utils.IsAdministrator())
{
this.Title = $"{Utils.GetVersion()} - {ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp}";
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp);
diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml.cs b/v2rayN/v2rayN/Views/MainWindow.xaml.cs
index b837f65c..b3869cae 100644
--- a/v2rayN/v2rayN/Views/MainWindow.xaml.cs
+++ b/v2rayN/v2rayN/Views/MainWindow.xaml.cs
@@ -132,7 +132,7 @@ public partial class MainWindow
}
});
- this.Title = $"{Utils.GetVersion()} - {(AppHandler.Instance.IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
+ this.Title = $"{Utils.GetVersion()} - {(Utils.IsAdministrator() ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
if (!_config.GuiItem.EnableHWA)
{
From 1c04144573cd2e57df137cbf42f9b33d6626bc24 Mon Sep 17 00:00:00 2001
From: 2dust <31833384+2dust@users.noreply.github.com>
Date: Sat, 26 Apr 2025 09:53:19 +0800
Subject: [PATCH 5/8] Code clean
---
.../Views/StatusBarView.axaml.cs | 1 -
v2rayN/v2rayN/App.xaml | 2 +-
v2rayN/v2rayN/Views/MainWindow.xaml | 47 ++++++++++--------
v2rayN/v2rayN/Views/ProfilesView.xaml | 16 +++---
.../Views/RoutingRuleDetailsWindow.xaml | 6 +--
.../Views/RoutingRuleSettingWindow.xaml | 6 +--
v2rayN/v2rayN/Views/StatusBarView.xaml | 49 ++++++++++++-------
v2rayN/v2rayN/Views/SubEditWindow.xaml | 6 +--
v2rayN/v2rayN/Views/SubSettingWindow.xaml | 6 +--
v2rayN/v2rayN/Views/ThemeSettingView.xaml | 4 +-
10 files changed, 80 insertions(+), 63 deletions(-)
diff --git a/v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml.cs b/v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml.cs
index 3c44e2d4..b646b5d6 100644
--- a/v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml.cs
+++ b/v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml.cs
@@ -8,7 +8,6 @@ using DialogHostAvalonia;
using ReactiveUI;
using Splat;
using v2rayN.Desktop.Common;
-using static QRCoder.PayloadGenerator;
namespace v2rayN.Desktop.Views;
diff --git a/v2rayN/v2rayN/App.xaml b/v2rayN/v2rayN/App.xaml
index 2be80ccb..49a31268 100644
--- a/v2rayN/v2rayN/App.xaml
+++ b/v2rayN/v2rayN/App.xaml
@@ -1,9 +1,9 @@
diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml b/v2rayN/v2rayN/Views/MainWindow.xaml
index 6c233ef4..ea2cbe2d 100644
--- a/v2rayN/v2rayN/Views/MainWindow.xaml
+++ b/v2rayN/v2rayN/Views/MainWindow.xaml
@@ -1,14 +1,14 @@
- 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.
+ رمز عبوری که وارد کرده اید تایید نمی شود، بنابراین مطمئن شوید که آن را به درستی وارد کرده اید. اگر برنامه به دلیل ورودی نادرست به درستی کار نمی کند، لطفاً برنامه را مجدداً راه اندازی کنید. رمز عبور ذخیره نمی شود و پس از هر بار راه اندازی مجدد باید آن را دوباره وارد کنید.
لطفاً ابتدا رمز عبور sudo را در تنظیمات حالت Tun تنظیم کنید
@@ -1416,4 +1416,4 @@
صادر کردن سرور
-
\ No newline at end of file
+
From be3dbfb8e3c2635c981b8f66a58aa6c12d9a9d7e Mon Sep 17 00:00:00 2001
From: Reza Bakhshi Laktasaraei
<74649066+rezabakhshilaktasaraei@users.noreply.github.com>
Date: Sat, 26 Apr 2025 06:01:00 +0330
Subject: [PATCH 7/8] Fix Tab navigation in ToolBar by setting
KeyboardNavigation to Continue (#7185)
---
v2rayN/v2rayN/Views/MainWindow.xaml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml b/v2rayN/v2rayN/Views/MainWindow.xaml
index ea2cbe2d..925d1f84 100644
--- a/v2rayN/v2rayN/Views/MainWindow.xaml
+++ b/v2rayN/v2rayN/Views/MainWindow.xaml
@@ -40,7 +40,8 @@
HorizontalAlignment="Center"
VerticalAlignment="Center"
ClipToBounds="True"
- Style="{StaticResource MaterialDesignToolBar}">
+ Style="{StaticResource MaterialDesignToolBar}"
+ KeyboardNavigation.TabNavigation="Continue">