mirror of
https://github.com/2dust/v2rayN.git
synced 2025-10-26 18:24:43 +00:00
Compare commits
7 commits
1d54f88e79
...
5c4f1ea38f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c4f1ea38f | ||
|
|
18ac76e683 | ||
|
|
3e1e23a524 | ||
|
|
534c7ab444 | ||
|
|
18ccabd193 | ||
|
|
942335db61 | ||
|
|
12b46e7c43 |
25 changed files with 216 additions and 24 deletions
|
|
@ -1,7 +1,7 @@
|
|||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>7.14.11</Version>
|
||||
<Version>7.14.12</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@
|
|||
<PackageVersion Include="ReactiveUI" Version="20.4.1" />
|
||||
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
|
||||
<PackageVersion Include="ReactiveUI.WPF" Version="20.4.1" />
|
||||
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.9" />
|
||||
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.9" />
|
||||
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.10" />
|
||||
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.10" />
|
||||
<PackageVersion Include="Splat.NLog" Version="16.2.1" />
|
||||
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
||||
<PackageVersion Include="TaskScheduler" Version="2.12.2" />
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using QRCoder;
|
||||
using QRCoder.Exceptions;
|
||||
using SkiaSharp;
|
||||
using ZXing.SkiaSharp;
|
||||
|
||||
|
|
@ -8,10 +9,45 @@ public class QRCodeUtils
|
|||
{
|
||||
public static byte[]? GenQRCode(string? url)
|
||||
{
|
||||
if (url.IsNullOrEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
using QRCodeGenerator qrGenerator = new();
|
||||
using var qrCodeData = qrGenerator.CreateQrCode(url ?? string.Empty, QRCodeGenerator.ECCLevel.Q);
|
||||
using PngByteQRCode qrCode = new(qrCodeData);
|
||||
return qrCode.GetGraphic(20);
|
||||
DataTooLongException? lastDtle = null;
|
||||
|
||||
var levels = new[]
|
||||
{
|
||||
QRCodeGenerator.ECCLevel.H,
|
||||
QRCodeGenerator.ECCLevel.Q,
|
||||
QRCodeGenerator.ECCLevel.M,
|
||||
QRCodeGenerator.ECCLevel.L
|
||||
};
|
||||
foreach (var level in levels)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var qrCodeData = qrGenerator.CreateQrCode(url, level);
|
||||
using PngByteQRCode qrCode = new(qrCodeData);
|
||||
return qrCode.GetGraphic(20);
|
||||
}
|
||||
catch (DataTooLongException ex)
|
||||
{
|
||||
lastDtle = ex;
|
||||
continue;
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastDtle != null)
|
||||
{
|
||||
throw lastDtle;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string? ParseBarcode(string? fileName)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System.Runtime.InteropServices;
|
|||
using System.Security.Cryptography;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using CliWrap;
|
||||
using CliWrap.Buffered;
|
||||
|
||||
|
|
@ -357,6 +358,14 @@ public class Utils
|
|||
return userHostsMap;
|
||||
}
|
||||
|
||||
public static List<string> ParseCertSha256ToList(string certSha256Content)
|
||||
{
|
||||
return String2List(certSha256Content)
|
||||
.Select(s => s.Replace(":", "").Replace(" ", ""))
|
||||
.Where(s => s.Length == 64 && Regex.IsMatch(s, @"\A\b[0-9a-fA-F]+\b\Z"))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
#endregion 转换函数
|
||||
|
||||
#region 数据检查
|
||||
|
|
|
|||
|
|
@ -253,6 +253,7 @@ public static class ConfigHandler
|
|||
item.ShortId = profileItem.ShortId;
|
||||
item.SpiderX = profileItem.SpiderX;
|
||||
item.Mldsa65Verify = profileItem.Mldsa65Verify;
|
||||
item.CertSha256 = profileItem.CertSha256;
|
||||
item.Extra = profileItem.Extra;
|
||||
item.MuxEnabled = profileItem.MuxEnabled;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ public class ProfileItem : ReactiveObject
|
|||
public string ShortId { get; set; }
|
||||
public string SpiderX { get; set; }
|
||||
public string Mldsa65Verify { get; set; }
|
||||
public string CertSha256 { get; set; }
|
||||
public string Extra { get; set; }
|
||||
public bool? MuxEnabled { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,6 +182,7 @@ public class Tls4Sbox
|
|||
public bool? fragment { get; set; }
|
||||
public string? fragment_fallback_delay { get; set; }
|
||||
public bool? record_fragment { get; set; }
|
||||
public List<string>? certificate_sha256 { get; set; }
|
||||
}
|
||||
|
||||
public class Multiplex4Sbox
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ public class TlsSettings4Ray
|
|||
public string? shortId { get; set; }
|
||||
public string? spiderX { get; set; }
|
||||
public string? mldsa65Verify { get; set; }
|
||||
public List<string>? pinnedPeerCertificateSha256 { get; set; }
|
||||
}
|
||||
|
||||
public class TcpSettings4Ray
|
||||
|
|
|
|||
18
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
18
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
|
|
@ -2364,6 +2364,24 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Server Certificate Fingerprint (SHA-256) 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbCertSha256 {
|
||||
get {
|
||||
return ResourceManager.GetString("TbCertSha256", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Hex SHA-256, comma-separated for certificate chain 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbCertSha256Tips {
|
||||
get {
|
||||
return ResourceManager.GetString("TbCertSha256Tips", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Clear system proxy 的本地化字符串。
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1515,4 +1515,10 @@
|
|||
<data name="TbFakeIPTips" xml:space="preserve">
|
||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
||||
</data>
|
||||
<data name="TbCertSha256" xml:space="preserve">
|
||||
<value>Server Certificate Fingerprint (SHA-256)</value>
|
||||
</data>
|
||||
<data name="TbCertSha256Tips" xml:space="preserve">
|
||||
<value>Hex SHA-256, comma-separated for certificate chain</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1515,4 +1515,10 @@
|
|||
<data name="TbFakeIPTips" xml:space="preserve">
|
||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
||||
</data>
|
||||
<data name="TbCertSha256" xml:space="preserve">
|
||||
<value>Server Certificate Fingerprint (SHA-256)</value>
|
||||
</data>
|
||||
<data name="TbCertSha256Tips" xml:space="preserve">
|
||||
<value>Hex SHA-256, comma-separated for certificate chain</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1515,4 +1515,10 @@
|
|||
<data name="TbFakeIPTips" xml:space="preserve">
|
||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
||||
</data>
|
||||
<data name="TbCertSha256" xml:space="preserve">
|
||||
<value>Server Certificate Fingerprint (SHA-256)</value>
|
||||
</data>
|
||||
<data name="TbCertSha256Tips" xml:space="preserve">
|
||||
<value>Hex SHA-256, comma-separated for certificate chain</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1515,4 +1515,10 @@
|
|||
<data name="TbFakeIPTips" xml:space="preserve">
|
||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
||||
</data>
|
||||
<data name="TbCertSha256" xml:space="preserve">
|
||||
<value>Server Certificate Fingerprint (SHA-256)</value>
|
||||
</data>
|
||||
<data name="TbCertSha256Tips" xml:space="preserve">
|
||||
<value>Hex SHA-256, comma-separated for certificate chain</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1512,4 +1512,10 @@
|
|||
<data name="TbFakeIPTips" xml:space="preserve">
|
||||
<value>默认全局生效,内置 FakeIP 过滤,仅在 sing-box 中生效</value>
|
||||
</data>
|
||||
<data name="TbCertSha256" xml:space="preserve">
|
||||
<value>服务器证书指纹 (SHA-256)</value>
|
||||
</data>
|
||||
<data name="TbCertSha256Tips" xml:space="preserve">
|
||||
<value>十六进制 SHA-256,证书链用逗号分隔</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1512,4 +1512,10 @@
|
|||
<data name="TbFakeIPTips" xml:space="preserve">
|
||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
||||
</data>
|
||||
<data name="TbCertSha256" xml:space="preserve">
|
||||
<value>Server Certificate Fingerprint (SHA-256)</value>
|
||||
</data>
|
||||
<data name="TbCertSha256Tips" xml:space="preserve">
|
||||
<value>Hex SHA-256, comma-separated for certificate chain</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -251,6 +251,20 @@ public partial class CoreConfigSingboxService
|
|||
fingerprint = node.Fingerprint.IsNullOrEmpty() ? _config.CoreBasicItem.DefFingerprint : node.Fingerprint
|
||||
};
|
||||
}
|
||||
if (node.CertSha256.IsNotEmpty())
|
||||
{
|
||||
// hex to raw to base64
|
||||
var certSha256List = Utils.ParseCertSha256ToList(node.CertSha256)
|
||||
.Select(s => Convert.ToBase64String(
|
||||
Enumerable.Range(0, 32)
|
||||
.Select(i => Convert.ToByte(s.Substring(i * 2, 2), 16))
|
||||
.ToArray()))
|
||||
.ToList();
|
||||
if (certSha256List.Count > 0)
|
||||
{
|
||||
tls.certificate_sha256 = certSha256List;
|
||||
}
|
||||
}
|
||||
if (node.StreamSecurity == Global.StreamSecurityReality)
|
||||
{
|
||||
tls.reality = new Reality4Sbox()
|
||||
|
|
|
|||
|
|
@ -277,6 +277,14 @@ public partial class CoreConfigV2rayService
|
|||
{
|
||||
tlsSettings.serverName = Utils.String2List(host)?.First();
|
||||
}
|
||||
if (node.CertSha256.IsNotEmpty())
|
||||
{
|
||||
var certSha256List = Utils.ParseCertSha256ToList(node.CertSha256);
|
||||
if (certSha256List.Count > 0)
|
||||
{
|
||||
tlsSettings.pinnedPeerCertificateSha256 = certSha256List;
|
||||
}
|
||||
}
|
||||
streamSettings.tlsSettings = tlsSettings;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -709,9 +709,9 @@
|
|||
<Grid
|
||||
x:Name="gridTlsMore"
|
||||
Grid.Row="7"
|
||||
ColumnDefinitions="180,Auto"
|
||||
ColumnDefinitions="180,Auto,Auto"
|
||||
IsVisible="False"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
|
|
@ -765,6 +765,26 @@
|
|||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbCertSha256}" />
|
||||
<TextBox
|
||||
x:Name="txtCertSha256"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbCertSha256Tips}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridRealityMore"
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
|||
this.Bind(ViewModel, vm => vm.SelectedSource.AllowInsecure, v => v.cmbAllowInsecure.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Fingerprint, v => v.cmbFingerprint.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Alpn, v => v.cmbAlpn.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.CertSha256, v => v.txtCertSha256.Text).DisposeWith(disposables);
|
||||
//reality
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI2.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Fingerprint, v => v.cmbFingerprint2.SelectedValue).DisposeWith(disposables);
|
||||
|
|
|
|||
|
|
@ -4,19 +4,25 @@
|
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
d:DesignHeight="480"
|
||||
d:DesignWidth="400"
|
||||
xmlns:sys="clr-namespace:System;assembly=netstandard"
|
||||
d:DesignHeight="600"
|
||||
d:DesignWidth="600"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<sys:Double x:Key="QrcodeWidth">500</sys:Double>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid Margin="32" RowDefinitions="Auto,Auto">
|
||||
<Image
|
||||
Name="imgQrcode"
|
||||
Width="300"
|
||||
Height="300" />
|
||||
Width="{StaticResource QrcodeWidth}"
|
||||
Height="{StaticResource QrcodeWidth}" />
|
||||
|
||||
<TextBox
|
||||
x:Name="txtContent"
|
||||
Grid.Row="1"
|
||||
Width="300"
|
||||
Width="{StaticResource QrcodeWidth}"
|
||||
MaxHeight="100"
|
||||
Margin="{StaticResource MarginTb8}"
|
||||
VerticalAlignment="Center"
|
||||
|
|
|
|||
|
|
@ -23,8 +23,16 @@ public partial class QrcodeView : UserControl
|
|||
|
||||
private Bitmap? GetQRCode(string? url)
|
||||
{
|
||||
var bytes = QRCodeUtils.GenQRCode(url);
|
||||
return ByteToBitmap(bytes);
|
||||
try
|
||||
{
|
||||
var bytes = QRCodeUtils.GenQRCode(url);
|
||||
return ByteToBitmap(bytes);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("GetQRCode", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Bitmap? ByteToBitmap(byte[]? bytes)
|
||||
|
|
|
|||
|
|
@ -20,8 +20,9 @@ public class QRCodeUtils
|
|||
var qrCodeImage = ServiceLib.Common.QRCodeUtils.GenQRCode(strContent);
|
||||
return qrCodeImage is null ? null : ByteToImage(qrCodeImage);
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("GetQRCode", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -928,10 +928,12 @@
|
|||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
|
|
@ -995,6 +997,29 @@
|
|||
Width="200"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbCertSha256}" />
|
||||
<TextBox
|
||||
x:Name="txtCertSha256"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbCertSha256Tips}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridRealityMore"
|
||||
|
|
|
|||
|
|
@ -183,6 +183,7 @@ public partial class AddServerWindow
|
|||
this.Bind(ViewModel, vm => vm.SelectedSource.AllowInsecure, v => v.cmbAllowInsecure.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Fingerprint, v => v.cmbFingerprint.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Alpn, v => v.cmbAlpn.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.CertSha256, v => v.txtCertSha256.Text).DisposeWith(disposables);
|
||||
//reality
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI2.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Fingerprint, v => v.cmbFingerprint2.Text).DisposeWith(disposables);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<UserControl
|
||||
<UserControl
|
||||
x:Class="v2rayN.Views.QrcodeView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
|
|
@ -6,28 +6,33 @@
|
|||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="300"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
d:DesignHeight="600"
|
||||
d:DesignWidth="600"
|
||||
Style="{StaticResource ViewGlobal}"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<sys:Double x:Key="QrcodeWidth">500</sys:Double>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid Margin="32">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="60" />
|
||||
<RowDefinition Height="80" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Image
|
||||
x:Name="imgQrcode"
|
||||
Grid.Row="0"
|
||||
Width="300"
|
||||
Height="300"
|
||||
Width="{StaticResource QrcodeWidth}"
|
||||
Height="{StaticResource QrcodeWidth}"
|
||||
Stretch="UniformToFill" />
|
||||
|
||||
<TextBox
|
||||
x:Name="txtContent"
|
||||
Grid.Row="1"
|
||||
Width="300"
|
||||
Width="{StaticResource QrcodeWidth}"
|
||||
Margin="0,8"
|
||||
VerticalAlignment="Center"
|
||||
IsReadOnly="True"
|
||||
|
|
@ -46,4 +51,4 @@
|
|||
IsDefault="True"
|
||||
Style="{StaticResource DefButton}" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
|
|
|
|||
Loading…
Reference in a new issue