Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f29e1f8c45 | ||
|
|
5d2bc88bb9 | ||
|
|
298fdb1191 | ||
|
|
59b34688ea | ||
|
|
5ce0bb6e4a | ||
|
|
487b1ab182 | ||
|
|
5c144a8ba3 | ||
|
|
ad344356df | ||
|
|
a55c65374d | ||
|
|
28447a9d43 | ||
|
|
0c03550c62 | ||
|
|
6d9a84803f | ||
|
|
03b0e4e2bb | ||
|
|
a00e9a6f5e | ||
|
|
ba17f8fde9 | ||
|
|
01d35456bd | ||
|
|
672b8c48ac | ||
|
|
ac1a357740 | ||
|
|
504f8d09a6 | ||
|
|
89ce7c23c9 | ||
|
|
a5d99b1eb5 | ||
|
|
800d193acb | ||
|
|
7a1d12be76 | ||
|
|
1b9c95e801 | ||
|
|
9f44815470 | ||
|
|
ca38239bce | ||
|
|
d9c22de6b8 |
32
.github/workflows/build-osx.yml
vendored
Normal file
32
.github/workflows/build-osx.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: release macos
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "master" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "master" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
configuration: [Release]
|
||||||
|
|
||||||
|
runs-on: macos-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cd v2rayN &&
|
||||||
|
./build-osx.sh
|
||||||
|
|
||||||
|
- name: Upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: v2rayN-osx
|
||||||
|
path: |
|
||||||
|
./v2rayN/v2rayN-osx.zip
|
||||||
|
|
||||||
|
|
||||||
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cd v2rayN &&
|
run: cd v2rayN &&
|
||||||
.\build.ps1
|
./build.ps1
|
||||||
|
|
||||||
# - name: Package
|
# - name: Package
|
||||||
# shell: pwsh
|
# shell: pwsh
|
||||||
@@ -40,7 +40,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: v2rayN
|
name: v2rayN
|
||||||
path: |
|
path: |
|
||||||
.\v2rayN\v2rayN.zip
|
./v2rayN/v2rayN.zip
|
||||||
|
|
||||||
# - name: Release
|
# - name: Release
|
||||||
# uses: softprops/action-gh-release@v1
|
# uses: softprops/action-gh-release@v1
|
||||||
|
|||||||
101
v2rayN/ServiceLib/Common/AesUtils.cs
Normal file
101
v2rayN/ServiceLib/Common/AesUtils.cs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ServiceLib.Common
|
||||||
|
{
|
||||||
|
public class AesUtils
|
||||||
|
{
|
||||||
|
private const int KeySize = 256; // AES-256
|
||||||
|
private const int IvSize = 16; // AES block size
|
||||||
|
private const int Iterations = 10000;
|
||||||
|
private static readonly byte[] Salt = Encoding.ASCII.GetBytes("saltysalt".PadRight(16, ' ')); // google浏览器默认盐值
|
||||||
|
private static readonly string DefaultPassword = Utils.GetMd5(Utils.GetHomePath() + "AesUtils");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encrypt
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">Plain text</param>
|
||||||
|
/// <param name="password">Password for key derivation or direct key in ASCII bytes</param>
|
||||||
|
/// <returns>Base64 encoded cipher text with IV</returns>
|
||||||
|
public static string Encrypt(string text, string? password = null)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(text))
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
var plaintext = Encoding.UTF8.GetBytes(text);
|
||||||
|
var key = GetKey(password);
|
||||||
|
var iv = GenerateIv();
|
||||||
|
|
||||||
|
using var aes = Aes.Create();
|
||||||
|
aes.Key = key;
|
||||||
|
aes.IV = iv;
|
||||||
|
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
ms.Write(iv, 0, iv.Length);
|
||||||
|
|
||||||
|
using (var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
|
||||||
|
{
|
||||||
|
cs.Write(plaintext, 0, plaintext.Length);
|
||||||
|
cs.FlushFinalBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
var cipherTextWithIv = ms.ToArray();
|
||||||
|
return Convert.ToBase64String(cipherTextWithIv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decrypt
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cipherTextWithIv">Base64 encoded cipher text with IV</param>
|
||||||
|
/// <param name="password">Password for key derivation or direct key in ASCII bytes</param>
|
||||||
|
/// <returns>Plain text</returns>
|
||||||
|
public static string Decrypt(string cipherTextWithIv, string? password = null)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(cipherTextWithIv))
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
var cipherTextWithIvBytes = Convert.FromBase64String(cipherTextWithIv);
|
||||||
|
var key = GetKey(password);
|
||||||
|
|
||||||
|
var iv = new byte[IvSize];
|
||||||
|
Buffer.BlockCopy(cipherTextWithIvBytes, 0, iv, 0, IvSize);
|
||||||
|
|
||||||
|
var cipherText = new byte[cipherTextWithIvBytes.Length - IvSize];
|
||||||
|
Buffer.BlockCopy(cipherTextWithIvBytes, IvSize, cipherText, 0, cipherText.Length);
|
||||||
|
|
||||||
|
using var aes = Aes.Create();
|
||||||
|
aes.Key = key;
|
||||||
|
aes.IV = iv;
|
||||||
|
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
using (var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
|
||||||
|
{
|
||||||
|
cs.Write(cipherText, 0, cipherText.Length);
|
||||||
|
cs.FlushFinalBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
var plainText = ms.ToArray();
|
||||||
|
return Encoding.UTF8.GetString(plainText);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] GetKey(string? password)
|
||||||
|
{
|
||||||
|
if (password.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
password = DefaultPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var pbkdf2 = new Rfc2898DeriveBytes(password, Salt, Iterations, HashAlgorithmName.SHA256);
|
||||||
|
return pbkdf2.GetBytes(KeySize / 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] GenerateIv()
|
||||||
|
{
|
||||||
|
var randomNumber = new byte[IvSize];
|
||||||
|
|
||||||
|
using var rng = RandomNumberGenerator.Create();
|
||||||
|
rng.GetBytes(randomNumber);
|
||||||
|
return randomNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
|
public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
|
||||||
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
|
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
|
||||||
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs";
|
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs";
|
||||||
public const string IPAPIUrl = "https://ipapi.co/json";
|
public const string IPAPIUrl = "https://api.ip.sb/geoip";
|
||||||
|
|
||||||
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
|
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
|
||||||
public const string ConfigFileName = "guiNConfig.json";
|
public const string ConfigFileName = "guiNConfig.json";
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ namespace ServiceLib.Handler
|
|||||||
await SetTaskLinux();
|
await SetTaskLinux();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(Utils.IsOSX())
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1026,6 +1026,36 @@ namespace ServiceLib.Handler
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<ProfileItem?> GetPreSocksItem(Config config, ProfileItem node, ECoreType coreType)
|
||||||
|
{
|
||||||
|
ProfileItem? itemSocks = null;
|
||||||
|
var preCoreType = ECoreType.sing_box;
|
||||||
|
if (node.ConfigType != EConfigType.Custom && coreType != ECoreType.sing_box && config.TunModeItem.EnableTun)
|
||||||
|
{
|
||||||
|
itemSocks = new ProfileItem()
|
||||||
|
{
|
||||||
|
CoreType = preCoreType,
|
||||||
|
ConfigType = EConfigType.SOCKS,
|
||||||
|
Address = Global.Loopback,
|
||||||
|
Sni = node.Address, //Tun2SocksAddress
|
||||||
|
Port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if ((node.ConfigType == EConfigType.Custom && node.PreSocksPort > 0))
|
||||||
|
{
|
||||||
|
preCoreType = config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray;
|
||||||
|
itemSocks = new ProfileItem()
|
||||||
|
{
|
||||||
|
CoreType = preCoreType,
|
||||||
|
ConfigType = EConfigType.SOCKS,
|
||||||
|
Address = Global.Loopback,
|
||||||
|
Port = node.PreSocksPort.Value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemSocks;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion Server
|
#endregion Server
|
||||||
|
|
||||||
#region Batch add servers
|
#region Batch add servers
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ namespace ServiceLib.Handler
|
|||||||
private Config _config;
|
private Config _config;
|
||||||
private Process? _process;
|
private Process? _process;
|
||||||
private Process? _processPre;
|
private Process? _processPre;
|
||||||
|
private int _linuxSudoPid = -1;
|
||||||
private Action<bool, string>? _updateFunc;
|
private Action<bool, string>? _updateFunc;
|
||||||
|
|
||||||
public async Task Init(Config config, Action<bool, string> updateFunc)
|
public async Task Init(Config config, Action<bool, string> updateFunc)
|
||||||
@@ -23,7 +24,7 @@ namespace ServiceLib.Handler
|
|||||||
Environment.SetEnvironmentVariable("V2RAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
Environment.SetEnvironmentVariable("V2RAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||||
Environment.SetEnvironmentVariable("XRAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
Environment.SetEnvironmentVariable("XRAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||||
|
|
||||||
if (Utils.IsLinux())
|
if (Utils.IsLinux() || Utils.IsOSX())
|
||||||
{
|
{
|
||||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
|
||||||
foreach (var it in coreInfo)
|
foreach (var it in coreInfo)
|
||||||
@@ -64,49 +65,30 @@ namespace ServiceLib.Handler
|
|||||||
ShowMsg(true, result.Msg);
|
ShowMsg(true, result.Msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
ShowMsg(true, $"{node.GetSummary()}");
|
ShowMsg(true, $"{node.GetSummary()}");
|
||||||
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
|
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
|
||||||
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
||||||
await CoreStop();
|
await CoreStop();
|
||||||
await Task.Delay(100);
|
await Task.Delay(100);
|
||||||
await CoreStart(node);
|
await CoreStart(node);
|
||||||
|
await CoreStartPreService(node);
|
||||||
//In tun mode, do a delay check and restart the core
|
|
||||||
//if (_config.tunModeItem.enableTun)
|
|
||||||
//{
|
|
||||||
// Observable.Range(1, 1)
|
|
||||||
// .Delay(TimeSpan.FromSeconds(15))
|
|
||||||
// .Subscribe(x =>
|
|
||||||
// {
|
|
||||||
// {
|
|
||||||
// if (_process == null || _process.HasExited)
|
|
||||||
// {
|
|
||||||
// CoreStart(node);
|
|
||||||
// ShowMsg(false, "Tun mode restart the core once");
|
|
||||||
// Logging.SaveLog("Tun mode restart the core once");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
|
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
|
||||||
{
|
{
|
||||||
var pid = -1;
|
|
||||||
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard) ? ECoreType.sing_box : ECoreType.Xray;
|
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard) ? ECoreType.sing_box : ECoreType.Xray;
|
||||||
var configPath = Utils.GetConfigPath(Global.CoreSpeedtestConfigFileName);
|
var configPath = Utils.GetConfigPath(Global.CoreSpeedtestConfigFileName);
|
||||||
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
|
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
|
||||||
ShowMsg(false, result.Msg);
|
ShowMsg(false, result.Msg);
|
||||||
if (result.Success)
|
if (result.Success != true)
|
||||||
{
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
||||||
ShowMsg(false, configPath);
|
ShowMsg(false, configPath);
|
||||||
pid = await CoreStartSpeedtest(configPath, coreType);
|
return await CoreStartSpeedtest(configPath, coreType);
|
||||||
}
|
|
||||||
return pid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task CoreStop()
|
public async Task CoreStop()
|
||||||
@@ -126,6 +108,12 @@ namespace ServiceLib.Handler
|
|||||||
_processPre.Dispose();
|
_processPre.Dispose();
|
||||||
_processPre = null;
|
_processPre = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_linuxSudoPid > 0)
|
||||||
|
{
|
||||||
|
await KillProcessAsLinuxSudo();
|
||||||
|
}
|
||||||
|
_linuxSudoPid = -1;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -171,8 +159,7 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
private async Task CoreStart(ProfileItem node)
|
private async Task CoreStart(ProfileItem node)
|
||||||
{
|
{
|
||||||
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
|
var coreType = _config.RunningCoreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
|
||||||
_config.RunningCoreType = coreType;
|
|
||||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
||||||
|
|
||||||
var displayLog = node.ConfigType != EConfigType.Custom || node.DisplayLog;
|
var displayLog = node.ConfigType != EConfigType.Custom || node.DisplayLog;
|
||||||
@@ -182,47 +169,28 @@ namespace ServiceLib.Handler
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_process = proc;
|
_process = proc;
|
||||||
|
}
|
||||||
|
|
||||||
//start a pre service
|
private async Task CoreStartPreService(ProfileItem node)
|
||||||
|
{
|
||||||
if (_process != null && !_process.HasExited)
|
if (_process != null && !_process.HasExited)
|
||||||
{
|
{
|
||||||
ProfileItem? itemSocks = null;
|
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
|
||||||
var preCoreType = ECoreType.sing_box;
|
var itemSocks = await ConfigHandler.GetPreSocksItem(_config, node, coreType);
|
||||||
if (node.ConfigType != EConfigType.Custom && coreType != ECoreType.sing_box && _config.TunModeItem.EnableTun)
|
|
||||||
{
|
|
||||||
itemSocks = new ProfileItem()
|
|
||||||
{
|
|
||||||
CoreType = preCoreType,
|
|
||||||
ConfigType = EConfigType.SOCKS,
|
|
||||||
Address = Global.Loopback,
|
|
||||||
Sni = node.Address, //Tun2SocksAddress
|
|
||||||
Port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if ((node.ConfigType == EConfigType.Custom && node.PreSocksPort > 0))
|
|
||||||
{
|
|
||||||
preCoreType = _config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray;
|
|
||||||
itemSocks = new ProfileItem()
|
|
||||||
{
|
|
||||||
CoreType = preCoreType,
|
|
||||||
ConfigType = EConfigType.SOCKS,
|
|
||||||
Address = Global.Loopback,
|
|
||||||
Port = node.PreSocksPort.Value,
|
|
||||||
};
|
|
||||||
_config.RunningCoreType = preCoreType;
|
|
||||||
}
|
|
||||||
if (itemSocks != null)
|
if (itemSocks != null)
|
||||||
{
|
{
|
||||||
var fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName);
|
var preCoreType = _config.RunningCoreType = itemSocks.CoreType ?? ECoreType.sing_box;
|
||||||
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2);
|
var fileName = Utils.GetConfigPath(Global.CorePreConfigFileName);
|
||||||
|
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName);
|
||||||
if (result.Success)
|
if (result.Success)
|
||||||
{
|
{
|
||||||
var coreInfo2 = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
|
||||||
var proc2 = await RunProcess(coreInfo2, Global.CorePreConfigFileName, true, true);
|
var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true);
|
||||||
if (proc2 is not null)
|
if (proc is null)
|
||||||
{
|
{
|
||||||
_processPre = proc2;
|
return;
|
||||||
}
|
}
|
||||||
|
_processPre = proc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -258,7 +226,7 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
return _config.TunModeItem.EnableTun
|
return _config.TunModeItem.EnableTun
|
||||||
&& eCoreType == ECoreType.sing_box
|
&& eCoreType == ECoreType.sing_box
|
||||||
&& Utils.IsLinux()
|
&& (Utils.IsLinux() || Utils.IsOSX())
|
||||||
//&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
|
//&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
@@ -296,7 +264,7 @@ namespace ServiceLib.Handler
|
|||||||
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
|
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
|
||||||
if (isNeedSudo)
|
if (isNeedSudo)
|
||||||
{
|
{
|
||||||
await RunProcessAsLinuxRoot(proc, fileName, coreInfo, configPath);
|
await RunProcessAsLinuxSudo(proc, fileName, coreInfo, configPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
var startUpErrorMessage = new StringBuilder();
|
var startUpErrorMessage = new StringBuilder();
|
||||||
@@ -329,6 +297,7 @@ namespace ServiceLib.Handler
|
|||||||
await Task.Delay(10);
|
await Task.Delay(10);
|
||||||
await proc.StandardInput.WriteLineAsync(pwd);
|
await proc.StandardInput.WriteLineAsync(pwd);
|
||||||
}
|
}
|
||||||
|
if (isNeedSudo) _linuxSudoPid = proc.Id;
|
||||||
|
|
||||||
if (displayLog)
|
if (displayLog)
|
||||||
{
|
{
|
||||||
@@ -357,65 +326,107 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RunProcessAsLinuxRoot(Process proc, string fileName, CoreInfo coreInfo, string configPath)
|
|
||||||
{
|
|
||||||
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetConfigPath(configPath).AppendQuotes())}";
|
|
||||||
|
|
||||||
//Prefer shell scripts
|
|
||||||
var shFilePath = Utils.GetBinPath("run_as_root.sh");
|
|
||||||
File.Delete(shFilePath);
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.AppendLine("#!/bin/sh");
|
|
||||||
sb.AppendLine(cmdLine);
|
|
||||||
await File.WriteAllTextAsync(shFilePath, sb.ToString());
|
|
||||||
await Utils.SetLinuxChmod(shFilePath);
|
|
||||||
|
|
||||||
//Replace command
|
|
||||||
var args = File.Exists(shFilePath) ? shFilePath : cmdLine;
|
|
||||||
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
|
|
||||||
{
|
|
||||||
proc.StartInfo.FileName = $"/bin/sudo";
|
|
||||||
proc.StartInfo.Arguments = $"-S {args}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
proc.StartInfo.FileName = $"/bin/pkexec";
|
|
||||||
proc.StartInfo.Arguments = $"{args}";
|
|
||||||
}
|
|
||||||
proc.StartInfo.WorkingDirectory = null;
|
|
||||||
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
|
|
||||||
proc.StartInfo.RedirectStandardInput = true;
|
|
||||||
Logging.SaveLog(proc.StartInfo.Arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task KillProcess(Process? proc)
|
private async Task KillProcess(Process? proc)
|
||||||
{
|
{
|
||||||
if (proc is null)
|
if (proc is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(1));
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await proc.WaitForExitAsync(timeout.Token);
|
proc?.Kill();
|
||||||
}
|
|
||||||
catch (OperationCanceledException)
|
|
||||||
{
|
|
||||||
proc.Kill();
|
|
||||||
}
|
|
||||||
if (!proc.HasExited)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await proc.WaitForExitAsync(timeout.Token);
|
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
proc.Kill();
|
// ignored
|
||||||
|
}
|
||||||
|
await Task.Delay(100);
|
||||||
|
if (proc?.HasExited == false)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
proc?.Kill();
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Process
|
#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.GetConfigPath(configPath).AppendQuotes())}";
|
||||||
|
|
||||||
|
var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh");
|
||||||
|
proc.StartInfo.FileName = shFilePath;
|
||||||
|
proc.StartInfo.Arguments = "";
|
||||||
|
proc.StartInfo.WorkingDirectory = "";
|
||||||
|
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
|
||||||
|
{
|
||||||
|
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
|
||||||
|
proc.StartInfo.RedirectStandardInput = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task KillProcessAsLinuxSudo()
|
||||||
|
{
|
||||||
|
var cmdLine = $"kill -9 {_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 (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
|
||||||
|
{
|
||||||
|
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
|
||||||
|
await Task.Delay(10);
|
||||||
|
await proc.StandardInput.WriteLineAsync(pwd);
|
||||||
|
await Task.Delay(10);
|
||||||
|
await proc.StandardInput.WriteLineAsync(pwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10));
|
||||||
|
await proc.WaitForExitAsync(timeout.Token);
|
||||||
|
await Task.Delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
|
||||||
|
{
|
||||||
|
//Shell scripts
|
||||||
|
var shFilePath = Utils.GetBinPath(fileName);
|
||||||
|
File.Delete(shFilePath);
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.AppendLine("#!/bin/sh");
|
||||||
|
if (_config.TunModeItem.LinuxSudoPwd.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
sb.AppendLine($"pkexec {cmdLine}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.AppendLine($"sudo -S {cmdLine}");
|
||||||
|
}
|
||||||
|
|
||||||
|
await File.WriteAllTextAsync(shFilePath, sb.ToString());
|
||||||
|
await Utils.SetLinuxChmod(shFilePath);
|
||||||
|
Logging.SaveLog(shFilePath);
|
||||||
|
|
||||||
|
return shFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Linux
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,6 +42,8 @@
|
|||||||
DownloadUrlWinArm64 = Global.NUrl + "/download/{0}/v2rayN-windows-arm64.zip",
|
DownloadUrlWinArm64 = Global.NUrl + "/download/{0}/v2rayN-windows-arm64.zip",
|
||||||
DownloadUrlLinux64 = Global.NUrl + "/download/{0}/v2rayN-linux-64.zip",
|
DownloadUrlLinux64 = Global.NUrl + "/download/{0}/v2rayN-linux-64.zip",
|
||||||
DownloadUrlLinuxArm64 = Global.NUrl + "/download/{0}/v2rayN-linux-arm64.zip",
|
DownloadUrlLinuxArm64 = Global.NUrl + "/download/{0}/v2rayN-linux-arm64.zip",
|
||||||
|
DownloadUrlOSX64 = Global.NUrl + "/download/{0}/v2rayN-macos-64.zip",
|
||||||
|
DownloadUrlOSXArm64 = Global.NUrl + "/download/{0}/v2rayN-macos-arm64.zip",
|
||||||
});
|
});
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
_coreInfo.Add(new CoreInfo
|
||||||
@@ -79,6 +81,8 @@
|
|||||||
DownloadUrlWinArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-arm64-v8a.zip",
|
DownloadUrlWinArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-arm64-v8a.zip",
|
||||||
DownloadUrlLinux64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-64.zip",
|
DownloadUrlLinux64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-64.zip",
|
||||||
DownloadUrlLinuxArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-arm64-v8a.zip",
|
DownloadUrlLinuxArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-arm64-v8a.zip",
|
||||||
|
DownloadUrlOSX64 = Global.XrayCoreUrl + "/download/{0}/Xray-macos-64.zip",
|
||||||
|
DownloadUrlOSXArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-macos-arm64-v8a.zip",
|
||||||
Match = "Xray",
|
Match = "Xray",
|
||||||
VersionArg = "-version",
|
VersionArg = "-version",
|
||||||
RedirectInfo = true,
|
RedirectInfo = true,
|
||||||
@@ -95,6 +99,8 @@
|
|||||||
DownloadUrlWinArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-windows-arm64-{0}.zip",
|
DownloadUrlWinArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-windows-arm64-{0}.zip",
|
||||||
DownloadUrlLinux64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-amd64-compatible-{0}.gz",
|
DownloadUrlLinux64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-amd64-compatible-{0}.gz",
|
||||||
DownloadUrlLinuxArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-arm64-{0}.gz",
|
DownloadUrlLinuxArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-arm64-{0}.gz",
|
||||||
|
DownloadUrlOSX64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-darwin-amd64-compatible-{0}.gz",
|
||||||
|
DownloadUrlOSXArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-darwin-arm64-{0}.gz",
|
||||||
Match = "Mihomo",
|
Match = "Mihomo",
|
||||||
VersionArg = "-v",
|
VersionArg = "-v",
|
||||||
RedirectInfo = true,
|
RedirectInfo = true,
|
||||||
@@ -140,6 +146,8 @@
|
|||||||
DownloadUrlWinArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-arm64.zip",
|
DownloadUrlWinArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-arm64.zip",
|
||||||
DownloadUrlLinux64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-amd64.tar.gz",
|
DownloadUrlLinux64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-amd64.tar.gz",
|
||||||
DownloadUrlLinuxArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-arm64.tar.gz",
|
DownloadUrlLinuxArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-arm64.tar.gz",
|
||||||
|
DownloadUrlOSX64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-darwin-amd64.tar.gz",
|
||||||
|
DownloadUrlOSXArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-darwin-arm64.tar.gz",
|
||||||
Match = "sing-box",
|
Match = "sing-box",
|
||||||
VersionArg = "version",
|
VersionArg = "version",
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
public string? DownloadUrlWinArm64 { get; set; }
|
public string? DownloadUrlWinArm64 { get; set; }
|
||||||
public string? DownloadUrlLinux64 { get; set; }
|
public string? DownloadUrlLinux64 { get; set; }
|
||||||
public string? DownloadUrlLinuxArm64 { get; set; }
|
public string? DownloadUrlLinuxArm64 { get; set; }
|
||||||
|
public string? DownloadUrlOSX64 { get; set; }
|
||||||
|
public string? DownloadUrlOSXArm64 { get; set; }
|
||||||
public string? Match { get; set; }
|
public string? Match { get; set; }
|
||||||
public string? VersionArg { get; set; }
|
public string? VersionArg { get; set; }
|
||||||
public bool RedirectInfo { get; set; }
|
public bool RedirectInfo { get; set; }
|
||||||
|
|||||||
@@ -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.2.1</Version>
|
<Version>7.2.2</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -548,6 +548,7 @@ namespace ServiceLib.Services.CoreConfig
|
|||||||
}
|
}
|
||||||
|
|
||||||
var tunInbound = JsonUtils.Deserialize<Inbound4Sbox>(Utils.GetEmbedText(Global.TunSingboxInboundFileName)) ?? new Inbound4Sbox { };
|
var tunInbound = JsonUtils.Deserialize<Inbound4Sbox>(Utils.GetEmbedText(Global.TunSingboxInboundFileName)) ?? new Inbound4Sbox { };
|
||||||
|
tunInbound.interface_name = Utils.IsOSX()? $"utun{new Random().Next(99)}": "singbox_tun";
|
||||||
tunInbound.mtu = _config.TunModeItem.Mtu;
|
tunInbound.mtu = _config.TunModeItem.Mtu;
|
||||||
tunInbound.strict_route = _config.TunModeItem.StrictRoute;
|
tunInbound.strict_route = _config.TunModeItem.StrictRoute;
|
||||||
tunInbound.stack = _config.TunModeItem.Stack;
|
tunInbound.stack = _config.TunModeItem.Stack;
|
||||||
|
|||||||
@@ -249,9 +249,9 @@ namespace ServiceLib.Services
|
|||||||
var ip = Global.None;
|
var ip = Global.None;
|
||||||
if (time > 0)
|
if (time > 0)
|
||||||
{
|
{
|
||||||
var result = await downloadHandle.TryDownloadString(Global.IPAPIUrl, true, "ipapi");
|
var result = await downloadHandle.TryDownloadString(Global.IPAPIUrl, true, Global.IPAPIUrl);
|
||||||
var ipInfo = JsonUtils.Deserialize<IPAPIInfo>(result);
|
var ipInfo = JsonUtils.Deserialize<IPAPIInfo>(result);
|
||||||
ip = $"({ipInfo?.country}) {ipInfo?.ip}";
|
ip = $"({ipInfo?.country_code}) {ipInfo?.ip}";
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFunc?.Invoke(false, string.Format(ResUI.TestMeOutput, time, ip));
|
updateFunc?.Invoke(false, string.Format(ResUI.TestMeOutput, time, ip));
|
||||||
@@ -450,6 +450,15 @@ namespace ServiceLib.Services
|
|||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
else if (Utils.IsOSX())
|
||||||
|
{
|
||||||
|
return RuntimeInformation.ProcessArchitecture switch
|
||||||
|
{
|
||||||
|
Architecture.Arm64 => coreInfo?.DownloadUrlOSXArm64,
|
||||||
|
Architecture.X64 => coreInfo?.DownloadUrlOSX64,
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ namespace ServiceLib.ViewModels
|
|||||||
FileManager.ZipExtractToFile(fileName, toPath, _config.GuiItem.IgnoreGeoUpdateCore ? "geo" : "");
|
FileManager.ZipExtractToFile(fileName, toPath, _config.GuiItem.IgnoreGeoUpdateCore ? "geo" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Utils.IsLinux())
|
if (Utils.IsLinux() || Utils.IsOSX())
|
||||||
{
|
{
|
||||||
var filesList = (new DirectoryInfo(toPath)).GetFiles().Select(u => u.FullName).ToList();
|
var filesList = (new DirectoryInfo(toPath)).GetFiles().Select(u => u.FullName).ToList();
|
||||||
foreach (var file in filesList)
|
foreach (var file in filesList)
|
||||||
|
|||||||
@@ -437,6 +437,10 @@ namespace ServiceLib.ViewModels
|
|||||||
{
|
{
|
||||||
return _config.TunModeItem.LinuxSudoPwd.IsNotEmpty();
|
return _config.TunModeItem.LinuxSudoPwd.IsNotEmpty();
|
||||||
}
|
}
|
||||||
|
else if (Utils.IsOSX())
|
||||||
|
{
|
||||||
|
return _config.TunModeItem.LinuxSudoPwd.IsNotEmpty();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
17
v2rayN/build-osx.sh
Executable file
17
v2rayN/build-osx.sh
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo 'Building'
|
||||||
|
|
||||||
|
OutputPath='./bin/v2rayN'
|
||||||
|
|
||||||
|
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o "${OutputPath}/osx-x64"
|
||||||
|
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-arm64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o "${OutputPath}/osx-arm64"
|
||||||
|
|
||||||
|
rm -rf "$OutputPath/osx-x64/*.pdb"
|
||||||
|
rm -rf "$OutputPath/osx-arm64/*.pdb"
|
||||||
|
|
||||||
|
echo 'Build done'
|
||||||
|
|
||||||
|
ls $OutputPath
|
||||||
|
7z a v2rayN-osx.zip $OutputPath
|
||||||
|
exit 0
|
||||||
@@ -2,37 +2,57 @@ param (
|
|||||||
[Parameter()]
|
[Parameter()]
|
||||||
[ValidateNotNullOrEmpty()]
|
[ValidateNotNullOrEmpty()]
|
||||||
[string]
|
[string]
|
||||||
$OutputPath = '.\bin\v2rayN'
|
$OutputPath = './bin/v2rayN'
|
||||||
)
|
)
|
||||||
|
|
||||||
Write-Host 'Building'
|
Write-Host 'Building'
|
||||||
|
|
||||||
dotnet publish `
|
dotnet publish `
|
||||||
.\v2rayN\v2rayN.csproj `
|
./v2rayN/v2rayN.csproj `
|
||||||
-c Release `
|
-c Release `
|
||||||
-r win-x64 `
|
-r win-x64 `
|
||||||
--self-contained false `
|
--self-contained false `
|
||||||
-p:PublishReadyToRun=false `
|
-p:PublishReadyToRun=false `
|
||||||
-p:PublishSingleFile=true `
|
-p:PublishSingleFile=true `
|
||||||
-o "$OutputPath\win-x64"
|
-o "$OutputPath/win-x64"
|
||||||
|
|
||||||
dotnet publish `
|
dotnet publish `
|
||||||
.\v2rayN.Desktop\v2rayN.Desktop.csproj `
|
./v2rayN/v2rayN.csproj `
|
||||||
|
-c Release `
|
||||||
|
-r win-arm64 `
|
||||||
|
--self-contained false `
|
||||||
|
-p:PublishReadyToRun=false `
|
||||||
|
-p:PublishSingleFile=true `
|
||||||
|
-o "$OutputPath/win-arm64"
|
||||||
|
|
||||||
|
dotnet publish `
|
||||||
|
./v2rayN.Desktop/v2rayN.Desktop.csproj `
|
||||||
-c Release `
|
-c Release `
|
||||||
-r linux-x64 `
|
-r linux-x64 `
|
||||||
--self-contained true `
|
--self-contained true `
|
||||||
-p:PublishReadyToRun=false `
|
-p:PublishReadyToRun=false `
|
||||||
-p:PublishSingleFile=true `
|
-p:PublishSingleFile=true `
|
||||||
-o "$OutputPath\linux-x64"
|
-o "$OutputPath/linux-x64"
|
||||||
|
|
||||||
|
dotnet publish `
|
||||||
|
./v2rayN.Desktop/v2rayN.Desktop.csproj `
|
||||||
|
-c Release `
|
||||||
|
-r linux-arm64 `
|
||||||
|
--self-contained true `
|
||||||
|
-p:PublishReadyToRun=false `
|
||||||
|
-p:PublishSingleFile=true `
|
||||||
|
-o "$OutputPath/linux-arm64"
|
||||||
|
|
||||||
|
|
||||||
if ( -Not $? ) {
|
if ( -Not $? ) {
|
||||||
exit $lastExitCode
|
exit $lastExitCode
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( Test-Path -Path .\bin\v2rayN ) {
|
if ( Test-Path -Path ./bin/v2rayN ) {
|
||||||
rm -Force "$OutputPath\win-x64\*.pdb"
|
rm -Force "$OutputPath/win-x64/*.pdb"
|
||||||
rm -Force "$OutputPath\linux-x64\*.pdb"
|
rm -Force "$OutputPath/win-arm64/*.pdb"
|
||||||
|
rm -Force "$OutputPath/linux-x64/*.pdb"
|
||||||
|
rm -Force "$OutputPath/linux-arm64/*.pdb"
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Host 'Build done'
|
Write-Host 'Build done'
|
||||||
|
|||||||
@@ -379,6 +379,7 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
|
x:Name="tbAutoRun"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
|||||||
@@ -169,6 +169,13 @@ namespace v2rayN.Desktop.Views
|
|||||||
{
|
{
|
||||||
tabSystemproxy.IsVisible = false;
|
tabSystemproxy.IsVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Utils.IsOSX())
|
||||||
|
{
|
||||||
|
tbAutoRun.IsVisible = false;
|
||||||
|
togAutoRun.IsVisible = false;
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||||
@@ -202,7 +209,7 @@ namespace v2rayN.Desktop.Views
|
|||||||
{
|
{
|
||||||
return lstFonts;
|
return lstFonts;
|
||||||
}
|
}
|
||||||
else if (Utils.IsLinux())
|
else if (Utils.IsLinux() || Utils.IsOSX())
|
||||||
{
|
{
|
||||||
var result = await Utils.GetLinuxFontFamily("zh");
|
var result = await Utils.GetLinuxFontFamily("zh");
|
||||||
if (result.IsNullOrEmpty())
|
if (result.IsNullOrEmpty())
|
||||||
|
|||||||
@@ -20,12 +20,12 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Avalonia" Version="11.2.1" />
|
<PackageReference Include="Avalonia" Version="11.2.2" />
|
||||||
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.2.1" />
|
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.2.2" />
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="11.2.1" />
|
<PackageReference Include="Avalonia.Desktop" Version="11.2.2" />
|
||||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.1" />
|
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.2" />
|
||||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.1" />
|
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.2" />
|
||||||
<PackageReference Include="Avalonia.ReactiveUI" Version="11.2.1" />
|
<PackageReference Include="Avalonia.ReactiveUI" Version="11.2.2" />
|
||||||
<PackageReference Include="DialogHost.Avalonia" Version="0.8.1" />
|
<PackageReference Include="DialogHost.Avalonia" Version="0.8.1" />
|
||||||
<PackageReference Include="MessageBox.Avalonia" Version="3.2.0" />
|
<PackageReference Include="MessageBox.Avalonia" Version="3.2.0" />
|
||||||
<PackageReference Include="Semi.Avalonia" Version="11.2.1" />
|
<PackageReference Include="Semi.Avalonia" Version="11.2.1" />
|
||||||
|
|||||||
Reference in New Issue
Block a user