Add Finalmask support

This commit is contained in:
DHR60 2026-02-19 01:14:29 +08:00
parent b5800f7dfc
commit b1b7fdb1f5
17 changed files with 137 additions and 14 deletions

View file

@ -254,6 +254,7 @@ public static class ConfigHandler
item.CertSha = profileItem.CertSha;
item.EchConfigList = profileItem.EchConfigList;
item.EchForceQuery = profileItem.EchForceQuery;
item.Finalmask = profileItem.Finalmask;
item.ProtoExtra = profileItem.ProtoExtra;
}
@ -1122,6 +1123,7 @@ public static class ConfigHandler
&& AreEqual(o.Fingerprint, n.Fingerprint)
&& AreEqual(o.PublicKey, n.PublicKey)
&& AreEqual(o.ShortId, n.ShortId)
&& AreEqual(o.Finalmask, n.Finalmask)
&& (!remarks || o.Remarks == n.Remarks);
static bool AreEqual(string? a, string? b)

View file

@ -73,6 +73,19 @@ public class BaseFmt
{
dicQuery.Add("pcs", Utils.UrlEncode(item.CertSha));
}
if (item.Finalmask.IsNotEmpty())
{
var node = JsonUtils.ParseJson(item.Finalmask);
var finalmask = node != null
? JsonUtils.Serialize(node, new JsonSerializerOptions
{
WriteIndented = false,
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
})
: item.Finalmask;
dicQuery.Add("fm", Utils.UrlEncode(finalmask));
}
dicQuery.Add("type", item.Network.IsNotEmpty() ? item.Network : nameof(ETransport.tcp));
@ -214,6 +227,24 @@ public class BaseFmt
item.EchConfigList = GetQueryDecoded(query, "ech");
item.CertSha = GetQueryDecoded(query, "pcs");
var finalmaskDecoded = GetQueryDecoded(query, "fm");
if (finalmaskDecoded.IsNotEmpty())
{
var node = JsonUtils.ParseJson(finalmaskDecoded);
item.Finalmask = node != null
? JsonUtils.Serialize(node, new JsonSerializerOptions
{
WriteIndented = true,
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
})
: finalmaskDecoded;
}
else
{
item.Finalmask = string.Empty;
}
if (_allowInsecureArray.Any(k => GetQueryDecoded(query, k) == "1"))
{
item.AllowInsecure = Global.AllowInsecure.First();

View file

@ -178,6 +178,7 @@ public class ProfileItem
public string CertSha { get; set; }
public string EchConfigList { get; set; }
public string EchForceQuery { get; set; }
public string Finalmask { get; set; }
public string ProtoExtra { get; set; }

View file

@ -341,7 +341,7 @@ public class StreamSettings4Ray
public HysteriaSettings4Ray? hysteriaSettings { get; set; }
public FinalMask4Ray? finalmask { get; set; }
public Finalmask4Ray? finalmask { get; set; }
public Sockopt4Ray? sockopt { get; set; }
}
@ -476,7 +476,7 @@ public class HysteriaUdpHop4Ray
public string? interval { get; set; }
}
public class FinalMask4Ray
public class Finalmask4Ray
{
public List<Mask4Ray>? tcp { get; set; }
public List<Mask4Ray>? udp { get; set; }
@ -485,7 +485,7 @@ public class FinalMask4Ray
public class Mask4Ray
{
public string type { get; set; }
public MaskSettings4Ray? settings { get; set; }
public object? settings { get; set; }
}
public class MaskSettings4Ray

View file

@ -2916,6 +2916,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Finalmask 的本地化字符串。
/// </summary>
public static string TbFinalmask {
get {
return ResourceManager.GetString("TbFinalmask", resourceCulture);
}
}
/// <summary>
/// 查找类似 Fingerprint 的本地化字符串。
/// </summary>

View file

@ -1671,4 +1671,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="menuServerListPreview" xml:space="preserve">
<value>Configuration item preview</value>
</data>
<data name="TbFinalmask" xml:space="preserve">
<value>Finalmask</value>
</data>
</root>

View file

@ -1668,4 +1668,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="menuServerListPreview" xml:space="preserve">
<value>Configuration item preview</value>
</data>
<data name="TbFinalmask" xml:space="preserve">
<value>Finalmask</value>
</data>
</root>

View file

@ -1671,4 +1671,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="menuServerListPreview" xml:space="preserve">
<value>Configuration item preview</value>
</data>
<data name="TbFinalmask" xml:space="preserve">
<value>Finalmask</value>
</data>
</root>

View file

@ -1671,4 +1671,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="menuServerListPreview" xml:space="preserve">
<value>Configuration item preview</value>
</data>
<data name="TbFinalmask" xml:space="preserve">
<value>Finalmask</value>
</data>
</root>

View file

@ -1671,4 +1671,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="menuServerListPreview" xml:space="preserve">
<value>Configuration item preview</value>
</data>
<data name="TbFinalmask" xml:space="preserve">
<value>Finalmask</value>
</data>
</root>

View file

@ -1668,4 +1668,7 @@
<data name="menuServerListPreview" xml:space="preserve">
<value>子配置项预览</value>
</data>
<data name="TbFinalmask" xml:space="preserve">
<value>Finalmask</value>
</data>
</root>

View file

@ -1668,4 +1668,7 @@
<data name="menuServerListPreview" xml:space="preserve">
<value>Configuration item preview</value>
</data>
<data name="TbFinalmask" xml:space="preserve">
<value>Finalmask</value>
</data>
</root>

View file

@ -275,14 +275,7 @@ public partial class CoreConfigV2rayService
var useragent = "";
if (!_config.CoreBasicItem.DefUserAgent.IsNullOrEmpty())
{
try
{
useragent = Global.UserAgentTexts[_config.CoreBasicItem.DefUserAgent];
}
catch (KeyNotFoundException)
{
useragent = _config.CoreBasicItem.DefUserAgent;
}
useragent = Global.UserAgentTexts.GetValueOrDefault(_config.CoreBasicItem.DefUserAgent, _config.CoreBasicItem.DefUserAgent);
}
//if tls
@ -587,6 +580,11 @@ public partial class CoreConfigV2rayService
}
break;
}
if (!node.Finalmask.IsNullOrEmpty())
{
streamSettings.finalmask = JsonUtils.Deserialize<Finalmask4Ray>(node.Finalmask);
}
}
catch (Exception ex)
{

View file

@ -32,7 +32,7 @@
IsCancel="True" />
</StackPanel>
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Grid RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<Grid RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<Grid
Grid.Row="0"
@ -407,7 +407,7 @@
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbPorts7Tips}" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
@ -420,7 +420,7 @@
Grid.Column="1"
Width="400"
Margin="{StaticResource Margin4}" />
<TextBlock
Grid.Row="5"
Grid.Column="0"
@ -997,6 +997,27 @@
HorizontalAlignment="Left" />
</Grid>
<Separator Grid.Row="8" Margin="{StaticResource MarginTb8}" />
<Grid
x:Name="gridFinalmask"
Grid.Row="9"
ColumnDefinitions="300,Auto">
<TextBlock
Grid.Row="0"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbFinalmask}" />
<TextBox
x:Name="txtFinalmask"
Grid.Row="0"
Grid.Column="1"
Width="400"
Margin="{StaticResource Margin4}"
AcceptsReturn="True"
Classes="TextArea"
TextWrapping="NoWrap" />
</Grid>
<Separator Grid.Row="10" Margin="{StaticResource MarginTb8}" />
</Grid>
</ScrollViewer>
</DockPanel>

View file

@ -78,6 +78,7 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
cmbCoreType.IsEnabled = false;
cmbFingerprint.IsEnabled = false;
cmbFingerprint.SelectedValue = string.Empty;
gridFinalmask.IsVisible = false;
cmbHeaderType8.ItemsSource = Global.TuicCongestionControls;
break;
@ -95,6 +96,7 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
gridAnytls.IsVisible = true;
lstStreamSecurity.Add(Global.StreamSecurityReality);
cmbCoreType.IsEnabled = false;
gridFinalmask.IsVisible = false;
break;
}
cmbStreamSecurity.ItemsSource = lstStreamSecurity;
@ -194,6 +196,8 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
this.Bind(ViewModel, vm => vm.SelectedSource.SpiderX, v => v.txtSpiderX.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Mldsa65Verify, v => v.txtMldsa65Verify.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Finalmask, v => v.txtFinalmask.Text).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.FetchCertCmd, v => v.btnFetchCert).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.FetchCertChainCmd, v => v.btnFetchCertChain).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);

View file

@ -60,6 +60,8 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
@ -1267,6 +1269,36 @@
Grid.Row="8"
Margin="0,2"
Style="{DynamicResource MaterialDesignSeparator}" />
<Grid x:Name="gridFinalmask" Grid.Row="9">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbFinalmask}" />
<TextBox
x:Name="txtFinalmask"
Grid.Row="0"
Grid.Column="1"
Width="400"
Margin="{StaticResource Margin4}"
AcceptsReturn="True"
HorizontalScrollBarVisibility="Auto"
MaxLines="8"
MinLines="4"
Style="{StaticResource MyOutlinedTextBox}"
TextWrapping="NoWrap"
VerticalScrollBarVisibility="Auto" />
</Grid>
<Separator
Grid.Row="10"
Margin="0,2"
Style="{DynamicResource MaterialDesignSeparator}" />
</Grid>
</ScrollViewer>
</DockPanel>

View file

@ -73,6 +73,7 @@ public partial class AddServerWindow
cmbCoreType.IsEnabled = false;
cmbFingerprint.IsEnabled = false;
cmbFingerprint.Text = string.Empty;
gridFinalmask.Visibility = Visibility.Collapsed;
cmbHeaderType8.ItemsSource = Global.TuicCongestionControls;
break;
@ -90,6 +91,7 @@ public partial class AddServerWindow
gridAnytls.Visibility = Visibility.Visible;
cmbCoreType.IsEnabled = false;
lstStreamSecurity.Add(Global.StreamSecurityReality);
gridFinalmask.Visibility = Visibility.Collapsed;
break;
}
cmbStreamSecurity.ItemsSource = lstStreamSecurity;
@ -190,6 +192,8 @@ public partial class AddServerWindow
this.Bind(ViewModel, vm => vm.SelectedSource.SpiderX, v => v.txtSpiderX.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Mldsa65Verify, v => v.txtMldsa65Verify.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Finalmask, v => v.txtFinalmask.Text).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.FetchCertCmd, v => v.btnFetchCert).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.FetchCertChainCmd, v => v.btnFetchCertChain).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);