Compare commits

..

11 Commits
7.1.0 ... 7.1.2

Author SHA1 Message Date
2dust
7cf9b9f57e up 7.1.2 2024-11-17 14:15:37 +08:00
2dust
736d995d4c up PackageReference 2024-11-17 14:11:51 +08:00
2dust
e335b2c0d6 Fix with AppendQuotes 2024-11-17 14:11:17 +08:00
2dust
96ae5517f6 Improve core msg 2024-11-17 09:58:57 +08:00
Slnanx
fb4b8d923a 可以通过判断系统语言来显示对应语言 (#6083) 2024-11-17 09:42:40 +08:00
2dust
2ade705e51 Bug fix 2024-11-16 20:15:05 +08:00
NagisaEfi
e0086b4b79 Update ResUI.zh-Hant.resx (#6080) 2024-11-16 10:34:55 +08:00
2dust
8f6d443104 Hide to tray when closing the window
https://github.com/2dust/v2rayN/issues/6076
2024-11-15 19:50:37 +08:00
2dust
5dbce16895 up 7.1.1 2024-11-15 13:36:44 +08:00
2dust
1016dcb3d1 Improve PAC 2024-11-15 11:59:22 +08:00
2dust
ba5ad12e13 Linux password encryption storage 2024-11-15 09:42:49 +08:00
27 changed files with 361 additions and 108 deletions

View File

@@ -0,0 +1,131 @@
using System.Collections.Generic;
using System.Globalization;
namespace AmazTool
{
public class LocalizationHelper
{
/// <summary>
/// 获取系统当前语言的本地化字符串
/// </summary>
/// <param name="key">要翻译的关键字</param>
/// <returns>对应语言的本地化字符串,如果没有找到则返回关键字</returns>
public static string GetLocalizedValue(string key)
{
// 定义支持的语言
HashSet<string> supportedLanguages = ["zh", "en"];
// 获取当前系统语言的 ISO 两字母代码
string currentLanguage = CultureInfo.CurrentCulture.TwoLetterISOLanguageName;
// 如果当前语言不在支持的语言列表中,默认使用英文
if (!supportedLanguages.Contains(currentLanguage))
{
currentLanguage = "en";
}
// 尝试获取对应语言的翻译
if (languageResources.TryGetValue(key, out var translations))
{
if (translations.TryGetValue(currentLanguage, out var translation))
{
return translation;
}
}
// 如果未找到翻译,返回关键字本身
return key;
}
/// <summary>
/// 存储不同语言的本地化资源
/// </summary>
public static Dictionary<string, Dictionary<string, string>> languageResources = new()
{
{
"Guidelines", new Dictionary<string, string>
{
{ "en", "Please run it from the main application." },
{ "zh", "请从主应用运行!" }
}
},
{
"Upgrade_File_Not_Found", new Dictionary<string, string>
{
{ "en", "Upgrade failed, file not found." },
{ "zh", "升级失败,文件不存在!" }
}
},
{
"In_Progress", new Dictionary<string, string>
{
{ "en", "In progress, please wait..." },
{ "zh", "正在进行中,请等待..." }
}
},
{
"Try_Terminate_Process", new Dictionary<string, string>
{
{ "en", "Try to terminate the v2rayN process." },
{ "zh", "尝试结束 v2rayN 进程..." }
}
},
{
"Failed_Terminate_Process", new Dictionary<string, string>
{
{ "en", "Failed to terminate the v2rayN.Close it manually,or the upgrade may fail." },
{ "zh", "请手动关闭正在运行的v2rayN否则可能升级失败。" }
}
},
{
"Start_Unzipping", new Dictionary<string, string>
{
{ "en", "Start extracting the update package." },
{ "zh", "开始解压缩更新包..." }
}
},
{
"Success_Unzipping", new Dictionary<string, string>
{
{ "en", "Successfully extracted the update package!" },
{ "zh", "解压缩更新包成功!" }
}
},
{
"Failed_Unzipping", new Dictionary<string, string>
{
{ "en", "Failed to extract the update package!" },
{ "zh", "解压缩更新包失败!" }
}
},
{
"Failed_Upgrade", new Dictionary<string, string>
{
{ "en", "Upgrade failed!" },
{ "zh", "升级失败!" }
}
},
{
"Success_Upgrade", new Dictionary<string, string>
{
{ "en", "Upgrade success!" },
{ "zh", "升级成功!" }
}
},
{
"Information", new Dictionary<string, string>
{
{ "en", "Information" },
{ "zh", "提示" }
}
},
{
"Restart_v2rayN", new Dictionary<string, string>
{
{ "en", "Start v2rayN, please wait..." },
{ "zh", "正在重启,请等待..." }
}
}
};
}
}

View File

@@ -1,4 +1,7 @@
namespace AmazTool
using System;
using System.Threading;
namespace AmazTool
{
internal static class Program
{
@@ -10,7 +13,7 @@
{
if (args.Length == 0)
{
Console.WriteLine("Please run it from the main application.(请从主应用运行)");
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Guidelines"));
Thread.Sleep(5000);
return;
}

View File

@@ -1,6 +1,9 @@
using System.Diagnostics;
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Text;
using System.Threading;
namespace AmazTool
{
@@ -9,17 +12,16 @@ namespace AmazTool
public static void Upgrade(string fileName)
{
Console.WriteLine(fileName);
Console.WriteLine("In progress, please wait...(正在进行中,请等待)");
Thread.Sleep(9000);
if (!File.Exists(fileName))
{
Console.WriteLine("Upgrade Failed, File Not Exist(升级失败,文件不存在).");
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Upgrade_File_Not_Found"));
return;
}
Console.WriteLine("Try to end the process(尝试结束进程).");
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Try_Terminate_Process"));
try
{
var existing = Process.GetProcessesByName(V2rayN);
@@ -32,11 +34,10 @@ namespace AmazTool
catch (Exception ex)
{
// Access may be denied without admin right. The user may not be an administrator.
Console.WriteLine("Failed to close v2rayN(关闭v2rayN失败).\n" +
"Close it manually, or the upgrade may fail.(请手动关闭正在运行的v2rayN否则可能升级失败。\n\n" + ex.StackTrace);
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Failed_Terminate_Process") + ex.StackTrace);
}
Console.WriteLine("Start extracting files(开始解压文件).");
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Start_Unzipping"));
StringBuilder sb = new();
try
{
@@ -79,16 +80,16 @@ namespace AmazTool
}
catch (Exception ex)
{
Console.WriteLine("Upgrade Failed(升级失败)." + ex.StackTrace);
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Failed_Upgrade") + ex.StackTrace);
//return;
}
if (sb.Length > 0)
{
Console.WriteLine("Upgrade Failed(升级失败)." + sb.ToString());
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Failed_Upgrade") + sb.ToString());
//return;
}
Console.WriteLine("Start v2rayN, please wait...(正在重启,请等待)");
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Restart_v2rayN"));
Thread.Sleep(9000);
Process process = new()
{

View File

@@ -11,11 +11,11 @@ public class PacHandler
private static int _httpPort;
private static int _pacPort;
private static TcpListener? _tcpListener;
private static string _pacText;
private static byte[] _writeContent;
private static bool _isRunning;
private static bool _needRestart = true;
public static void Start(string configPath, int httpPort, int pacPort)
public static async Task Start(string configPath, int httpPort, int pacPort)
{
_needRestart = (configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning);
@@ -23,7 +23,7 @@ public class PacHandler
_httpPort = httpPort;
_pacPort = pacPort;
InitText();
await InitText();
if (_needRestart)
{
@@ -32,15 +32,24 @@ public class PacHandler
}
}
private static void InitText()
private static async Task InitText()
{
var path = Path.Combine(_configPath, "pac.txt");
if (!File.Exists(path))
{
File.AppendAllText(path, Resources.ResourceManager.GetString("pac"));
await File.AppendAllTextAsync(path, Resources.ResourceManager.GetString("pac"));
}
_pacText = File.ReadAllText(path).Replace("__PROXY__", $"PROXY 127.0.0.1:{_httpPort};DIRECT;");
var pacText = (await File.ReadAllTextAsync(path)).Replace("__PROXY__", $"PROXY 127.0.0.1:{_httpPort};DIRECT;");
var sb = new StringBuilder();
sb.AppendLine("HTTP/1.0 200 OK");
sb.AppendLine("Content-type:application/x-ns-proxy-autoconfig");
sb.AppendLine("Connection:close");
sb.AppendLine("Content-Length:" + Encoding.UTF8.GetByteCount(pacText));
sb.AppendLine();
sb.Append(pacText);
_writeContent = Encoding.UTF8.GetBytes(sb.ToString());
}
private static void RunListener()
@@ -60,21 +69,8 @@ public class PacHandler
continue;
}
var client = _tcpListener.AcceptTcpClient();
await Task.Run(() =>
{
var stream = client.GetStream();
var sb = new StringBuilder();
sb.AppendLine("HTTP/1.0 200 OK");
sb.AppendLine("Content-type:application/x-ns-proxy-autoconfig");
sb.AppendLine("Connection:close");
sb.AppendLine("Content-Length:" + Encoding.UTF8.GetByteCount(_pacText));
sb.AppendLine();
sb.Append(_pacText);
var content = Encoding.UTF8.GetBytes(sb.ToString());
stream.Write(content, 0, content.Length);
stream.Flush();
});
var client = await _tcpListener.AcceptTcpClientAsync();
await Task.Run(() => { WriteContent(client); });
}
catch
{
@@ -84,6 +80,13 @@ public class PacHandler
}, TaskCreationOptions.LongRunning);
}
private static void WriteContent(TcpClient client)
{
var stream = client.GetStream();
stream.Write(_writeContent, 0, _writeContent.Length);
stream.Flush();
}
public static void Stop()
{
if (_tcpListener == null) return;

View File

@@ -0,0 +1,75 @@
using System.Security.Cryptography;
using System.Text;
namespace ServiceLib.Common
{
public class DesUtils
{
/// <summary>
/// Encrypt
/// </summary>
/// <param name="text"></param>
/// /// <param name="key"></param>
/// <returns></returns>
public static string Encrypt(string? text, string? key = null)
{
if (text.IsNullOrEmpty())
{
return string.Empty;
}
GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv);
var dsp = DES.Create();
using var memStream = new MemoryStream();
using var cryStream = new CryptoStream(memStream, dsp.CreateEncryptor(rgbKey, rgbIv), CryptoStreamMode.Write);
using var sWriter = new StreamWriter(cryStream);
sWriter.Write(text);
sWriter.Flush();
cryStream.FlushFinalBlock();
memStream.Flush();
return Convert.ToBase64String(memStream.GetBuffer(), 0, (int)memStream.Length);
}
/// <summary>
/// Decrypt
/// </summary>
/// <param name="encryptText"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string Decrypt(string? encryptText, string? key = null)
{
if (encryptText.IsNullOrEmpty())
{
return string.Empty;
}
GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv);
var dsp = DES.Create();
var buffer = Convert.FromBase64String(encryptText);
using var memStream = new MemoryStream();
using var cryStream = new CryptoStream(memStream, dsp.CreateDecryptor(rgbKey, rgbIv), CryptoStreamMode.Write);
cryStream.Write(buffer, 0, buffer.Length);
cryStream.FlushFinalBlock();
return Encoding.UTF8.GetString(memStream.ToArray());
}
private static void GetKeyIv(string key, out byte[] rgbKey, out byte[] rgbIv)
{
if (key.IsNullOrEmpty())
{
throw new ArgumentNullException("The key cannot be null");
}
if (key.Length <= 8)
{
throw new ArgumentNullException("The key length cannot be less than 8 characters.");
}
rgbKey = Encoding.ASCII.GetBytes(key.Substring(0, 8));
rgbIv = Encoding.ASCII.GetBytes(key.Insert(0, "w").Substring(0, 8));
}
private static string GetDefaultKey()
{
return Utils.GetMd5(Utils.GetHomePath() + "DesUtils");
}
}
}

View File

@@ -959,7 +959,6 @@ namespace ServiceLib.Handler
&& o.Address == n.Address
&& o.Port == n.Port
&& o.Id == n.Id
&& o.AlterId == n.AlterId
&& o.Security == n.Security
&& o.Network == n.Network
&& o.HeaderType == n.HeaderType
@@ -968,6 +967,10 @@ namespace ServiceLib.Handler
&& (o.ConfigType == EConfigType.Trojan || o.StreamSecurity == n.StreamSecurity)
&& o.Flow == n.Flow
&& o.Sni == n.Sni
&& o.Alpn == n.Alpn
&& o.Fingerprint == n.Fingerprint
&& o.PublicKey == n.PublicKey
&& o.ShortId == n.ShortId
&& (!remarks || o.Remarks == n.Remarks);
}

View File

@@ -59,14 +59,16 @@ namespace ServiceLib.Handler
var fileName = Utils.GetConfigPath(Global.CoreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
ShowMsg(true, result.Msg);
if (result.Success != true)
{
ShowMsg(true, result.Msg);
return;
}
else
{
ShowMsg(true, $"{node.GetSummary()}");
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
await CoreStop();
await Task.Delay(100);
await CoreStart(node);
@@ -100,6 +102,8 @@ namespace ServiceLib.Handler
ShowMsg(false, result.Msg);
if (result.Success)
{
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
ShowMsg(false, configPath);
pid = await CoreStartSpeedtest(configPath, coreType);
}
return pid;
@@ -167,9 +171,6 @@ namespace ServiceLib.Handler
private async Task CoreStart(ProfileItem node)
{
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
_config.RunningCoreType = coreType;
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
@@ -229,9 +230,6 @@ namespace ServiceLib.Handler
private async Task<int> CoreStartSpeedtest(string configPath, ECoreType coreType)
{
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
ShowMsg(false, configPath);
try
{
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
@@ -261,7 +259,7 @@ namespace ServiceLib.Handler
return _config.TunModeItem.EnableTun
&& eCoreType == ECoreType.sing_box
&& Utils.IsLinux()
&& _config.TunModeItem.LinuxSudoPassword.IsNotEmpty()
&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
;
}
@@ -299,9 +297,11 @@ namespace ServiceLib.Handler
if (isNeedSudo)
{
proc.StartInfo.FileName = $"/bin/sudo";
proc.StartInfo.Arguments = $"-S {fileName} {string.Format(coreInfo.Arguments, configPath)}";
proc.StartInfo.Arguments = $"-S {fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetConfigPath(configPath).AppendQuotes())}";
proc.StartInfo.WorkingDirectory = null;
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
proc.StartInfo.RedirectStandardInput = true;
Logging.SaveLog(proc.StartInfo.Arguments);
}
var startUpErrorMessage = new StringBuilder();
@@ -328,10 +328,11 @@ namespace ServiceLib.Handler
if (isNeedSudo)
{
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(_config.TunModeItem.LinuxSudoPassword);
await proc.StandardInput.WriteLineAsync(pwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(_config.TunModeItem.LinuxSudoPassword);
await proc.StandardInput.WriteLineAsync(pwd);
}
if (displayLog)

View File

@@ -165,7 +165,7 @@
private string PortableMode()
{
return $" -d \"{Utils.GetBinPath("")}\"";
return $" -d {Utils.GetBinPath("").AppendQuotes()}";
}
}
}

View File

@@ -33,15 +33,10 @@ namespace ServiceLib.Handler.SysProxy
await ProxySettingLinux.SetProxy(Global.Loopback, port);
break;
case ESysProxyType.ForcedChange:
{
if (Utils.IsOSX())
{
await ProxySettingOSX.SetProxy(Global.Loopback, port);
}
case ESysProxyType.ForcedChange when Utils.IsOSX():
await ProxySettingOSX.SetProxy(Global.Loopback, port);
break;
break;
}
case ESysProxyType.ForcedClear when Utils.IsWindows():
ProxySettingWindows.UnsetProxy();
break;
@@ -50,23 +45,13 @@ namespace ServiceLib.Handler.SysProxy
await ProxySettingLinux.UnsetProxy();
break;
case ESysProxyType.ForcedClear:
{
if (Utils.IsOSX())
{
await ProxySettingOSX.UnsetProxy();
}
case ESysProxyType.ForcedClear when Utils.IsOSX():
await ProxySettingOSX.UnsetProxy();
break;
break;
}
case ESysProxyType.Pac when Utils.IsWindows():
{
var portPac = AppHandler.Instance.GetLocalPort(EInboundProtocol.pac);
PacHandler.Start(Utils.GetConfigPath(), port, portPac);
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
ProxySettingWindows.SetProxy(strProxy, "", 4);
break;
}
await SetWindowsProxyPac(port);
break;
}
if (type != ESysProxyType.Pac && Utils.IsWindows())
@@ -102,5 +87,13 @@ namespace ServiceLib.Handler.SysProxy
.Replace("{socks_port}", portSocks.ToString());
}
}
private static async Task SetWindowsProxyPac(int port)
{
var portPac = AppHandler.Instance.GetLocalPort(EInboundProtocol.pac);
await PacHandler.Start(Utils.GetConfigPath(), port, portPac);
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
ProxySettingWindows.SetProxy(strProxy, "", 4);
}
}
}

View File

@@ -80,7 +80,7 @@
public bool IgnoreGeoUpdateCore { get; set; } = true;
public int AutoUpdateInterval { get; set; }
public bool EnableSecurityProtocolTls13 { get; set; }
public int TrayMenuServersLimit { get; set; } = 20;
@@ -116,6 +116,7 @@
public bool EnableDragDropSort { get; set; }
public bool DoubleClick2Activate { get; set; }
public bool AutoHideStartup { get; set; }
public bool Hide2TrayWhenClose { get; set; }
public List<ColumnItem> MainColumnItem { get; set; }
public bool ShowInTaskbar { get; set; }
}
@@ -161,7 +162,7 @@
public int Mtu { get; set; }
public bool EnableExInbound { get; set; }
public bool EnableIPv6Address { get; set; }
public string? LinuxSudoPassword { get; set; }
public string? LinuxSudoPwd { get; set; }
}
[Serializable]

View File

@@ -3103,6 +3103,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Hide to tray when closing the window 的本地化字符串。
/// </summary>
public static string TbSettingsHide2TrayWhenClose {
get {
return ResourceManager.GetString("TbSettingsHide2TrayWhenClose", resourceCulture);
}
}
/// <summary>
/// 查找类似 HTTP Port 的本地化字符串。
/// </summary>
@@ -3176,7 +3185,7 @@ namespace ServiceLib.Resx {
}
/// <summary>
/// 查找类似 The password will only be stored in the local file. 的本地化字符串。
/// 查找类似 The password is encrypted and stored only in local files. 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPasswordTip {
get {

View File

@@ -1373,7 +1373,7 @@
<value>Linux system sudo password</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password will only be stored in the local file.</value>
<value>The password is encrypted and stored only in local files.</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value>
@@ -1387,4 +1387,7 @@
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra raw JSON, format: { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Hide to tray when closing the window</value>
</data>
</root>

View File

@@ -1373,7 +1373,7 @@
<value>Linux system sudo password</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password will only be stored in the local file.</value>
<value>The password is encrypted and stored only in local files.</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value>
@@ -1387,4 +1387,7 @@
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra raw JSON, format: { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Hide to tray when closing the window</value>
</data>
</root>

View File

@@ -1373,7 +1373,7 @@
<value>Linux system sudo password</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password will only be stored in the local file.</value>
<value>The password is encrypted and stored only in local files.</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value>
@@ -1387,4 +1387,7 @@
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra raw JSON, format: { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Hide to tray when closing the window</value>
</data>
</root>

View File

@@ -1370,7 +1370,7 @@
<value>Linux系统的sudo密码</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>密码只存储在本地文件中,没有密码无法开启Tun</value>
<value>密码已加密且只存储在本地文件中,密码无法开启Tun</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>请先在Tun模式设置中设置sudo密码</value>
@@ -1384,4 +1384,7 @@
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra 原始 JSON格式 { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>关闭窗口时隐藏至托盘</value>
</data>
</root>

View File

@@ -127,7 +127,7 @@
<value>設定格式不正確</value>
</data>
<data name="CustomServerTips" xml:space="preserve">
<value>注意,自訂設定完全依賴您自己的設定,不能使用所有設定功能。如需使用系統代理請手動修改聽埠。</value>
<value>注意,自訂設定完全依賴您自己的設定,不能使用所有設定功能。如需使用系統代理請手動修改聽埠。</value>
</data>
<data name="Downloading" xml:space="preserve">
<value>下載開始...</value>
@@ -157,7 +157,7 @@
<value>請填寫正確格式伺服器埠</value>
</data>
<data name="FillLocalListeningPort" xml:space="preserve">
<value>請填寫本機聽埠</value>
<value>請填寫本機聽埠</value>
</data>
<data name="FillPassword" xml:space="preserve">
<value>請填寫密碼</value>
@@ -722,7 +722,7 @@
<value>例外. 對於下列字元開頭的位址不使用代理設定檔:使用分號(;)分隔</value>
</data>
<data name="TbSettingsHttpPort" xml:space="preserve">
<value>本機HTTP聽埠</value>
<value>本機HTTP聽埠</value>
</data>
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
<value>更新Core時忽略Geo檔案</value>
@@ -755,7 +755,7 @@
<value>開啟流量探測</value>
</data>
<data name="TbSettingsSocksPort" xml:space="preserve">
<value>本機SOCKS聽埠</value>
<value>本機SOCKS聽埠</value>
</data>
<data name="TbSettingsStartBoot" xml:space="preserve">
<value>開機啟動(可能會不成功)</value>
@@ -998,7 +998,7 @@
<value>複製字型TTF/TTC檔案到目錄guiFonts重啟設定</value>
</data>
<data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>http端口= +1Pac端口= +4*ray API端口= +5mihomo API端口= +6</value>
<value>http連接埠= +1Pac連接埠= +4*ray API連接埠= +5mihomo API連接埠= +6</value>
</data>
<data name="TbSettingsStartBootTip" xml:space="preserve">
<value>以管理員權限設定此項,在啟動後獲得管理員權限</value>
@@ -1094,7 +1094,7 @@
<value>請確保別名存在並且唯一</value>
</data>
<data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>啟用額外監聽端口</value>
<value>啟用額外偵聽連接埠</value>
</data>
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>啟用IPv6</value>
@@ -1154,7 +1154,7 @@
<value>您目前運行的是獨立包,請手動下載 SelfContained.7z檔案解壓縮覆蓋!</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>自訂設定的Socks端口</value>
<value>自訂設定的Socks連接埠</value>
</data>
<data name="menuBackupAndRestore" xml:space="preserve">
<value>備份和還原</value>
@@ -1370,7 +1370,7 @@
<value>Linux系統的sudo密碼</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>密碼只儲存在本機檔案中,沒有密碼無法開啟Tun</value>
<value>密碼已加密且只儲存在本機檔案中,密碼無法開啟Tun</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>請先在Tun模式設定中設定sudo密碼</value>
@@ -1384,4 +1384,7 @@
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra 原始 JSON格式 { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>關閉視窗時隱藏至托盤</value>
</data>
</root>

View File

@@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>7.1.0</Version>
<Version>7.1.2</Version>
</PropertyGroup>
<ItemGroup>

View File

@@ -1024,18 +1024,17 @@ namespace ServiceLib.Services.CoreConfig
//request Host
string request = Utils.GetEmbedText(Global.V2raySampleHttpRequestFileName);
string[] arrHost = host.Split(',');
string host2 = string.Join("\",\"", arrHost);
request = request.Replace("$requestHost$", $"\"{host2}\"");
//request = request.Replace("$requestHost$", string.Format("\"{0}\"", config.requestHost()));
request = request.Replace("$requestUserAgent$", $"\"{useragent}\"");
string host2 = string.Join(",".AppendQuotes(), arrHost);
request = request.Replace("$requestHost$", $"{host2.AppendQuotes()}");
request = request.Replace("$requestUserAgent$", $"{useragent.AppendQuotes()}");
//Path
string pathHttp = @"/";
if (Utils.IsNotEmpty(node.Path))
{
string[] arrPath = node.Path.Split(',');
pathHttp = string.Join("\",\"", arrPath);
pathHttp = string.Join(",".AppendQuotes(), arrPath);
}
request = request.Replace("$requestPath$", $"\"{pathHttp}\"");
request = request.Replace("$requestPath$", $"{pathHttp.AppendQuotes()}");
tcpSettings.header.request = JsonUtils.Deserialize<object>(request);
streamSettings.tcpSettings = tcpSettings;

View File

@@ -267,7 +267,7 @@ namespace ServiceLib.ViewModels
var filesList = (new DirectoryInfo(toPath)).GetFiles().Select(u => u.FullName).ToList();
foreach (var file in filesList)
{
await Utils.SetLinuxChmod(Path.Combine(toPath, item.CoreType));
await Utils.SetLinuxChmod(Path.Combine(toPath, item.CoreType.ToLower()));
}
}

View File

@@ -53,6 +53,7 @@ namespace ServiceLib.ViewModels
[Reactive] public bool EnableUpdateSubOnlyRemarksExist { get; set; }
[Reactive] public bool EnableSecurityProtocolTls13 { get; set; }
[Reactive] public bool AutoHideStartup { get; set; }
[Reactive] public bool Hide2TrayWhenClose { get; set; }
[Reactive] public bool EnableDragDropSort { get; set; }
[Reactive] public bool DoubleClick2Activate { get; set; }
[Reactive] public int AutoUpdateInterval { get; set; }
@@ -166,6 +167,7 @@ namespace ServiceLib.ViewModels
EnableUpdateSubOnlyRemarksExist = _config.UiItem.EnableUpdateSubOnlyRemarksExist;
EnableSecurityProtocolTls13 = _config.GuiItem.EnableSecurityProtocolTls13;
AutoHideStartup = _config.UiItem.AutoHideStartup;
Hide2TrayWhenClose = _config.UiItem.Hide2TrayWhenClose;
EnableDragDropSort = _config.UiItem.EnableDragDropSort;
DoubleClick2Activate = _config.UiItem.DoubleClick2Activate;
AutoUpdateInterval = _config.GuiItem.AutoUpdateInterval;
@@ -198,7 +200,7 @@ namespace ServiceLib.ViewModels
TunMtu = _config.TunModeItem.Mtu;
TunEnableExInbound = _config.TunModeItem.EnableExInbound;
TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address;
TunLinuxSudoPassword = _config.TunModeItem.LinuxSudoPassword;
TunLinuxSudoPassword = _config.TunModeItem.LinuxSudoPwd;
#endregion Tun mode
@@ -316,6 +318,7 @@ namespace ServiceLib.ViewModels
_config.UiItem.EnableUpdateSubOnlyRemarksExist = EnableUpdateSubOnlyRemarksExist;
_config.GuiItem.EnableSecurityProtocolTls13 = EnableSecurityProtocolTls13;
_config.UiItem.AutoHideStartup = AutoHideStartup;
_config.UiItem.Hide2TrayWhenClose = Hide2TrayWhenClose;
_config.GuiItem.AutoUpdateInterval = AutoUpdateInterval;
_config.UiItem.EnableDragDropSort = EnableDragDropSort;
_config.UiItem.DoubleClick2Activate = DoubleClick2Activate;
@@ -342,7 +345,10 @@ namespace ServiceLib.ViewModels
_config.TunModeItem.Mtu = TunMtu;
_config.TunModeItem.EnableExInbound = TunEnableExInbound;
_config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address;
_config.TunModeItem.LinuxSudoPassword = TunLinuxSudoPassword;
if (TunLinuxSudoPassword != _config.TunModeItem.LinuxSudoPwd)
{
_config.TunModeItem.LinuxSudoPwd = DesUtils.Encrypt(TunLinuxSudoPassword);
}
//coreType
await SaveCoreType();

View File

@@ -440,7 +440,7 @@ namespace ServiceLib.ViewModels
}
else if (Utils.IsLinux())
{
return _config.TunModeItem.LinuxSudoPassword.IsNotEmpty();
return _config.TunModeItem.LinuxSudoPwd.IsNotEmpty();
}
return false;
}

View File

@@ -50,7 +50,7 @@
<Border
Width="500"
Height="80"
Margin="0"
Margin="-2"
VerticalAlignment="Center"
Theme="{StaticResource CardBorder}">
<Grid>

View File

@@ -382,7 +382,7 @@ namespace v2rayN.Desktop.Views
#endregion Event
#region UI
public void ShowHideWindow(bool? blShow)
{
var bl = blShow ?? !_config.UiItem.ShowInTaskbar;
@@ -398,7 +398,7 @@ namespace v2rayN.Desktop.Views
}
else
{
if (Utils.IsWindows())
if (_config.UiItem.Hide2TrayWhenClose)
{
this.Hide();
}

View File

@@ -489,6 +489,18 @@
HorizontalAlignment="Left"
Classes="Margin8" />
<TextBlock
Grid.Row="9"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbSettingsHide2TrayWhenClose}" />
<ToggleSwitch
x:Name="togHide2TrayWhenClose"
Grid.Row="9"
Grid.Column="1"
HorizontalAlignment="Left"
Classes="Margin8" />
<TextBlock
@@ -808,8 +820,7 @@
Grid.Column="1"
Width="200"
HorizontalAlignment="Left"
Classes="Margin8"
PasswordChar="*" />
Classes="Margin8" />
<TextBlock
Grid.Row="7"
Grid.Column="2"

View File

@@ -131,6 +131,7 @@ namespace v2rayN.Desktop.Views
this.Bind(ViewModel, vm => vm.EnableUpdateSubOnlyRemarksExist, v => v.togEnableUpdateSubOnlyRemarksExist.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableSecurityProtocolTls13, v => v.togEnableSecurityProtocolTls13.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoHideStartup, v => v.togAutoHideStartup.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Hide2TrayWhenClose, v => v.togHide2TrayWhenClose.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DoubleClick2Activate, v => v.togDoubleClick2Activate.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoUpdateInterval, v => v.txtautoUpdateInterval.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CurrentFontFamily, v => v.cmbcurrentFontFamily.SelectedValue).DisposeWith(disposables);

View File

@@ -61,6 +61,7 @@
Width="54"
Height="30"
Margin="20,0"
Padding="2"
Classes="Tertiary"
Theme="{DynamicResource BorderlessSplitButton}"
ToolTip.Tip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">

View File

@@ -20,16 +20,16 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.2.0" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.2.0" />
<PackageReference Include="Avalonia.Desktop" Version="11.2.0" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.0" />
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.0" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.2.0" />
<PackageReference Include="Avalonia" Version="11.2.1" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.2.1" />
<PackageReference Include="Avalonia.Desktop" Version="11.2.1" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.1" />
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.1" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.2.1" />
<PackageReference Include="DialogHost.Avalonia" Version="0.8.1" />
<PackageReference Include="MessageBox.Avalonia" Version="3.2.0" />
<PackageReference Include="Semi.Avalonia" Version="11.2.0" />
<PackageReference Include="Semi.Avalonia.DataGrid" Version="11.2.0" />
<PackageReference Include="Semi.Avalonia" Version="11.2.1" />
<PackageReference Include="Semi.Avalonia.DataGrid" Version="11.2.1" />
<PackageReference Include="ReactiveUI" Version="20.1.63" />
<PackageReference Include="ReactiveUI.Fody" Version="19.5.41" />
</ItemGroup>