Compare commits

..

3 Commits
7.1.0 ... 7.1.1

Author SHA1 Message Date
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
15 changed files with 136 additions and 61 deletions

View File

@@ -11,11 +11,11 @@ public class PacHandler
private static int _httpPort; private static int _httpPort;
private static int _pacPort; private static int _pacPort;
private static TcpListener? _tcpListener; private static TcpListener? _tcpListener;
private static string _pacText; private static byte[] _writeContent;
private static bool _isRunning; private static bool _isRunning;
private static bool _needRestart = true; 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); _needRestart = (configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning);
@@ -23,7 +23,7 @@ public class PacHandler
_httpPort = httpPort; _httpPort = httpPort;
_pacPort = pacPort; _pacPort = pacPort;
InitText(); await InitText();
if (_needRestart) 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"); var path = Path.Combine(_configPath, "pac.txt");
if (!File.Exists(path)) 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() private static void RunListener()
@@ -60,21 +69,8 @@ public class PacHandler
continue; continue;
} }
var client = _tcpListener.AcceptTcpClient(); var client = await _tcpListener.AcceptTcpClientAsync();
await Task.Run(() => await Task.Run(() => { WriteContent(client); });
{
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();
});
} }
catch catch
{ {
@@ -84,6 +80,13 @@ public class PacHandler
}, TaskCreationOptions.LongRunning); }, TaskCreationOptions.LongRunning);
} }
private static void WriteContent(TcpClient client)
{
var stream = client.GetStream();
stream.Write(_writeContent, 0, _writeContent.Length);
stream.Flush();
}
public static void Stop() public static void Stop()
{ {
if (_tcpListener == null) return; 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

@@ -261,7 +261,7 @@ namespace ServiceLib.Handler
return _config.TunModeItem.EnableTun return _config.TunModeItem.EnableTun
&& eCoreType == ECoreType.sing_box && eCoreType == ECoreType.sing_box
&& Utils.IsLinux() && Utils.IsLinux()
&& _config.TunModeItem.LinuxSudoPassword.IsNotEmpty() && _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
; ;
} }
@@ -299,7 +299,8 @@ namespace ServiceLib.Handler
if (isNeedSudo) if (isNeedSudo)
{ {
proc.StartInfo.FileName = $"/bin/sudo"; proc.StartInfo.FileName = $"/bin/sudo";
proc.StartInfo.Arguments = $"-S {fileName} {string.Format(coreInfo.Arguments, configPath)}"; proc.StartInfo.Arguments = $"-S {fileName} {string.Format(coreInfo.Arguments, Utils.GetConfigPath(configPath))}";
proc.StartInfo.WorkingDirectory = null;
proc.StartInfo.StandardInputEncoding = Encoding.UTF8; proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
proc.StartInfo.RedirectStandardInput = true; proc.StartInfo.RedirectStandardInput = true;
} }
@@ -328,10 +329,11 @@ namespace ServiceLib.Handler
if (isNeedSudo) if (isNeedSudo)
{ {
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
await Task.Delay(10); await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(_config.TunModeItem.LinuxSudoPassword); await proc.StandardInput.WriteLineAsync(pwd);
await Task.Delay(10); await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(_config.TunModeItem.LinuxSudoPassword); await proc.StandardInput.WriteLineAsync(pwd);
} }
if (displayLog) if (displayLog)

View File

@@ -33,15 +33,10 @@ namespace ServiceLib.Handler.SysProxy
await ProxySettingLinux.SetProxy(Global.Loopback, port); await ProxySettingLinux.SetProxy(Global.Loopback, port);
break; break;
case ESysProxyType.ForcedChange: case ESysProxyType.ForcedChange when Utils.IsOSX():
{
if (Utils.IsOSX())
{
await ProxySettingOSX.SetProxy(Global.Loopback, port); await ProxySettingOSX.SetProxy(Global.Loopback, port);
}
break; break;
}
case ESysProxyType.ForcedClear when Utils.IsWindows(): case ESysProxyType.ForcedClear when Utils.IsWindows():
ProxySettingWindows.UnsetProxy(); ProxySettingWindows.UnsetProxy();
break; break;
@@ -50,24 +45,14 @@ namespace ServiceLib.Handler.SysProxy
await ProxySettingLinux.UnsetProxy(); await ProxySettingLinux.UnsetProxy();
break; break;
case ESysProxyType.ForcedClear: case ESysProxyType.ForcedClear when Utils.IsOSX():
{
if (Utils.IsOSX())
{
await ProxySettingOSX.UnsetProxy(); await ProxySettingOSX.UnsetProxy();
} break;
break;
}
case ESysProxyType.Pac when Utils.IsWindows(): case ESysProxyType.Pac when Utils.IsWindows():
{ await SetWindowsProxyPac(port);
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; break;
} }
}
if (type != ESysProxyType.Pac && Utils.IsWindows()) if (type != ESysProxyType.Pac && Utils.IsWindows())
{ {
@@ -102,5 +87,13 @@ namespace ServiceLib.Handler.SysProxy
.Replace("{socks_port}", portSocks.ToString()); .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

@@ -161,7 +161,7 @@
public int Mtu { get; set; } public int Mtu { get; set; }
public bool EnableExInbound { get; set; } public bool EnableExInbound { get; set; }
public bool EnableIPv6Address { get; set; } public bool EnableIPv6Address { get; set; }
public string? LinuxSudoPassword { get; set; } public string? LinuxSudoPwd { get; set; }
} }
[Serializable] [Serializable]

View File

@@ -3176,7 +3176,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 The password will only be stored in the local file. 的本地化字符串。 /// 查找类似 The password is encrypted and stored only in local files. 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsLinuxSudoPasswordTip { public static string TbSettingsLinuxSudoPasswordTip {
get { get {

View File

@@ -1373,7 +1373,7 @@
<value>Linux system sudo password</value> <value>Linux system sudo password</value>
</data> </data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve"> <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>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve"> <data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value> <value>Please set the sudo password in Tun mode settings first</value>

View File

@@ -1373,7 +1373,7 @@
<value>Linux system sudo password</value> <value>Linux system sudo password</value>
</data> </data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve"> <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>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve"> <data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value> <value>Please set the sudo password in Tun mode settings first</value>

View File

@@ -1373,7 +1373,7 @@
<value>Linux system sudo password</value> <value>Linux system sudo password</value>
</data> </data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve"> <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>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve"> <data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value> <value>Please set the sudo password in Tun mode settings first</value>

View File

@@ -1370,7 +1370,7 @@
<value>Linux系统的sudo密码</value> <value>Linux系统的sudo密码</value>
</data> </data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve"> <data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>密码只存储在本地文件中,没有密码无法开启Tun</value> <value>密码已加密且只存储在本地文件中,密码无法开启Tun</value>
</data> </data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve"> <data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>请先在Tun模式设置中设置sudo密码</value> <value>请先在Tun模式设置中设置sudo密码</value>

View File

@@ -1370,7 +1370,7 @@
<value>Linux系統的sudo密碼</value> <value>Linux系統的sudo密碼</value>
</data> </data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve"> <data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>密碼只儲存在本機檔案中,沒有密碼無法開啟Tun</value> <value>密碼已加密且只儲存在本機檔案中,密碼無法開啟Tun</value>
</data> </data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve"> <data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>請先在Tun模式設定中設定sudo密碼</value> <value>請先在Tun模式設定中設定sudo密碼</value>

View File

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

View File

@@ -198,7 +198,7 @@ namespace ServiceLib.ViewModels
TunMtu = _config.TunModeItem.Mtu; TunMtu = _config.TunModeItem.Mtu;
TunEnableExInbound = _config.TunModeItem.EnableExInbound; TunEnableExInbound = _config.TunModeItem.EnableExInbound;
TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address; TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address;
TunLinuxSudoPassword = _config.TunModeItem.LinuxSudoPassword; TunLinuxSudoPassword = _config.TunModeItem.LinuxSudoPwd;
#endregion Tun mode #endregion Tun mode
@@ -342,7 +342,10 @@ namespace ServiceLib.ViewModels
_config.TunModeItem.Mtu = TunMtu; _config.TunModeItem.Mtu = TunMtu;
_config.TunModeItem.EnableExInbound = TunEnableExInbound; _config.TunModeItem.EnableExInbound = TunEnableExInbound;
_config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address; _config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address;
_config.TunModeItem.LinuxSudoPassword = TunLinuxSudoPassword; if (TunLinuxSudoPassword != _config.TunModeItem.LinuxSudoPwd)
{
_config.TunModeItem.LinuxSudoPwd = DesUtils.Encrypt(TunLinuxSudoPassword);
}
//coreType //coreType
await SaveCoreType(); await SaveCoreType();

View File

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

View File

@@ -808,8 +808,7 @@
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Classes="Margin8" Classes="Margin8" />
PasswordChar="*" />
<TextBlock <TextBlock
Grid.Row="7" Grid.Row="7"
Grid.Column="2" Grid.Column="2"