From 75ed512e4a76b388c07d454c0fef1acd7a3c0604 Mon Sep 17 00:00:00 2001 From: qhy040404 Date: Fri, 26 Jan 2024 22:08:38 +0800 Subject: [PATCH 1/5] add current proxy to feedback page --- .../IO/Http/DynamicProxy/DynamicHttpProxy.cs | 42 ++++++++++++++----- .../Resource/Localization/SH.en.resx | 38 ++++++++++------- .../Snap.Hutao/Resource/Localization/SH.resx | 6 +++ .../Snap.Hutao/View/Page/FeedbackPage.xaml | 1 + .../ViewModel/Feedback/FeedbackViewModel.cs | 4 ++ 5 files changed, 64 insertions(+), 27 deletions(-) diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/DynamicProxy/DynamicHttpProxy.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/DynamicProxy/DynamicHttpProxy.cs index 3cee1312..aa786c8e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/DynamicProxy/DynamicHttpProxy.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/DynamicProxy/DynamicHttpProxy.cs @@ -1,6 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using CommunityToolkit.Mvvm.ComponentModel; +using Snap.Hutao.Web; using Snap.Hutao.Win32.Registry; using System.Net; using System.Reflection; @@ -8,7 +10,7 @@ using System.Reflection; namespace Snap.Hutao.Core.IO.Http.DynamicProxy; [Injection(InjectAs.Singleton)] -internal sealed partial class DynamicHttpProxy : IWebProxy, IDisposable +internal sealed partial class DynamicHttpProxy : ObservableObject, IWebProxy, IDisposable { private const string ProxySettingPath = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections"; @@ -33,7 +35,7 @@ internal sealed partial class DynamicHttpProxy : IWebProxy, IDisposable { UpdateProxy(); - watcher = new(ProxySettingPath, UpdateProxy); + watcher = new(ProxySettingPath, OnProxyChanged); watcher.Start(); } @@ -44,6 +46,17 @@ internal sealed partial class DynamicHttpProxy : IWebProxy, IDisposable set => InnerProxy.Credentials = value; } + public string CurrentProxy + { + get + { + Uri? proxyUri = GetProxy(HutaoEndpoints.Website(string.Empty).ToUri()); + return proxyUri is null + ? SH.ViewPageFeedbackCurrentProxyNoProxyDescription + : proxyUri.AbsoluteUri; + } + } + private IWebProxy InnerProxy { get => innerProxy; @@ -61,15 +74,6 @@ internal sealed partial class DynamicHttpProxy : IWebProxy, IDisposable } } - [MemberNotNull(nameof(innerProxy))] - public void UpdateProxy() - { - IWebProxy? proxy = ConstructSystemProxyMethod.Invoke(default, default) as IWebProxy; - ArgumentNullException.ThrowIfNull(proxy); - - InnerProxy = proxy; - } - public Uri? GetProxy(Uri destination) { return InnerProxy.GetProxy(destination); @@ -85,4 +89,20 @@ internal sealed partial class DynamicHttpProxy : IWebProxy, IDisposable (innerProxy as IDisposable)?.Dispose(); watcher.Dispose(); } + + public void OnProxyChanged() + { + UpdateProxy(); + + Ioc.Default.GetRequiredService().InvokeOnMainThread(() => OnPropertyChanged(nameof(CurrentProxy))); + } + + [MemberNotNull(nameof(innerProxy))] + private void UpdateProxy() + { + IWebProxy? proxy = ConstructSystemProxyMethod.Invoke(default, default) as IWebProxy; + ArgumentNullException.ThrowIfNull(proxy); + + InnerProxy = proxy; + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.en.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.en.resx index 321a9291..b0753047 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.en.resx +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.en.resx @@ -60,45 +60,45 @@ : and then encoded with base64 encoding. --> - + - + - - - - + + + + - - + + - - + + - - - - + + + + - + - + @@ -1862,6 +1862,12 @@ Useful Links + + Current Proxy + + + No Proxy + Keep in touch with us diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx index b801ff1a..7ad45dfa 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx @@ -1862,6 +1862,12 @@ 常用链接 + + 当前代理 + + + 无代理 + 与我们密切联系 diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/FeedbackPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/FeedbackPage.xaml index 05d6783a..2a499ddb 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/FeedbackPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/FeedbackPage.xaml @@ -55,6 +55,7 @@ Header="{shcm:ResourceString Name=ViewPageSettingDeviceIdHeader}" IsClickEnabled="True"/> + diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Feedback/FeedbackViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Feedback/FeedbackViewModel.cs index aa5b5b65..38df7dd0 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Feedback/FeedbackViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Feedback/FeedbackViewModel.cs @@ -3,6 +3,7 @@ using Snap.Hutao.Core; using Snap.Hutao.Core.IO.DataTransfer; +using Snap.Hutao.Core.IO.Http.DynamicProxy; using Snap.Hutao.Service; using Snap.Hutao.Service.Notification; using Snap.Hutao.Web.Hutao; @@ -20,6 +21,7 @@ internal sealed partial class FeedbackViewModel : Abstraction.ViewModel private readonly HutaoInfrastructureClient hutaoInfrastructureClient; private readonly HutaoDocumentationClient hutaoDocumentationClient; private readonly IClipboardProvider clipboardProvider; + private readonly DynamicHttpProxy dynamicHttpProxy; private readonly IInfoBarService infoBarService; private readonly CultureOptions cultureOptions; private readonly RuntimeOptions runtimeOptions; @@ -31,6 +33,8 @@ internal sealed partial class FeedbackViewModel : Abstraction.ViewModel public RuntimeOptions RuntimeOptions { get => runtimeOptions; } + public DynamicHttpProxy DynamicHttpProxy { get => dynamicHttpProxy; } + public string? SearchText { get => searchText; set => SetProperty(ref searchText, value); } public List? SearchResults { get => searchResults; set => SetProperty(ref searchResults, value); } From fb1fe3e40fc6ac63bdf99c1e707bddac84bbb861 Mon Sep 17 00:00:00 2001 From: qhy040404 Date: Sat, 27 Jan 2024 00:38:41 +0800 Subject: [PATCH 2/5] add loopback status --- .../Snap.Hutao/Control/Theme/Uri.xaml | 1 + .../Core/IO/Http/Loopback/LoopbackManager.cs | 79 ++++++++++++++++ .../Snap.Hutao/Resource/Localization/SH.resx | 12 +++ .../Snap.Hutao/View/Page/FeedbackPage.xaml | 89 +++++++++++-------- .../ViewModel/Feedback/FeedbackViewModel.cs | 20 +++++ src/Snap.Hutao/Snap.Hutao/Win32/AdvApi32.cs | 4 + 6 files changed, 170 insertions(+), 35 deletions(-) create mode 100644 src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Loopback/LoopbackManager.cs diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Theme/Uri.xaml b/src/Snap.Hutao/Snap.Hutao/Control/Theme/Uri.xaml index a73bbbae..d6789e48 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Theme/Uri.xaml +++ b/src/Snap.Hutao/Snap.Hutao/Control/Theme/Uri.xaml @@ -4,6 +4,7 @@ https://hut.ao https://hut.ao/features/mhy-account-switch.html https://translate.hut.ao + https://hut.ao/zh/advanced/FAQ.html#%E5%A6%82%E4%BD%95%E9%80%9A%E8%BF%87%E7%BD%91%E7%BB%9C%E4%BB%A3%E7%90%86%E4%BD%BF%E7%94%A8%E8%83%A1%E6%A1%83%E5%B7%A5%E5%85%B7%E7%AE%B1 https://github.com/HolographicHat/GetToken/releases/latest diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Loopback/LoopbackManager.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Loopback/LoopbackManager.cs new file mode 100644 index 00000000..6a109dc2 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Loopback/LoopbackManager.cs @@ -0,0 +1,79 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using CommunityToolkit.Mvvm.ComponentModel; +using Snap.Hutao.Win32.Foundation; +using Snap.Hutao.Win32.NetworkManagement.WindowsFirewall; +using Snap.Hutao.Win32.Security; +using static Snap.Hutao.Win32.AdvApi32; +using static Snap.Hutao.Win32.ApiMsWinNetIsolation; + +namespace Snap.Hutao.Core.IO.Http.Loopback; + +[Injection(InjectAs.Singleton)] +internal sealed unsafe class LoopbackManager : ObservableObject, IDisposable +{ + private readonly INET_FIREWALL_APP_CONTAINER* pContainers; + private readonly INET_FIREWALL_APP_CONTAINER* pHutaoContainer; + + private readonly RuntimeOptions runtimeOptions; + private readonly ITaskContext taskContext; + + + public LoopbackManager(IServiceProvider serviceProvider) + { + runtimeOptions = serviceProvider.GetRequiredService(); + taskContext = serviceProvider.GetRequiredService(); + + NetworkIsolationEnumAppContainers(NETISO_FLAG.NETISO_FLAG_MAX, out uint acCount, out pContainers); + for (uint i = 0; i < acCount; i++) + { + INET_FIREWALL_APP_CONTAINER* pContainer = pContainers + i; + if (new string(pContainer->appContainerName) == runtimeOptions.FamilyName) + { + pHutaoContainer = pContainer; + break; + } + } + + NetworkIsolationGetAppContainerConfig(out uint accCount, out SID_AND_ATTRIBUTES* pSids); + for (uint i = 0; i < accCount; i++) + { + if (EqualSid(new PSID { Value = pHutaoContainer->appContainerSid }, (pSids + i)->Sid)) + { + IsLoopbackEnabled = true; + break; + } + } + } + + public bool IsLoopbackEnabled { get; private set; } + + public void EnableLoopback() + { + List sids = []; + + NetworkIsolationGetAppContainerConfig(out uint accCount, out SID_AND_ATTRIBUTES* pSids); + for (uint i = 0; i < accCount; i++) + { + sids.Add(*(pSids + i)); + } + + sids.Add(new SID_AND_ATTRIBUTES + { + Sid = new PSID { Value = pHutaoContainer->appContainerSid }, + Attributes = 0, + }); + + NetworkIsolationSetAppContainerConfig(sids.ToArray()); + + IsLoopbackEnabled = true; + + taskContext.InvokeOnMainThread(() => OnPropertyChanged(nameof(IsLoopbackEnabled))); + } + + public void Dispose() + { + _ = NetworkIsolationFreeAppContainers(pContainers); + } +} diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx index 7ad45dfa..10abdd1b 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx @@ -1187,6 +1187,12 @@ 实时便笺 Webhook Url + + 解除限制后需要使用其他工具恢复限制 + + + 是否解除 Loopback 限制 + 导入祈愿记录 @@ -1868,6 +1874,12 @@ 无代理 + + 已启用 + + + 解除 Loopback 限制 + 与我们密切联系 diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/FeedbackPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/FeedbackPage.xaml index 2a499ddb..943f8172 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/FeedbackPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/FeedbackPage.xaml @@ -3,7 +3,8 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:clw="using:CommunityToolkit.Labs.WinUI" - xmlns:cwc="using:CommunityToolkit.WinUI.Controls" + xmlns:cwcont="using:CommunityToolkit.WinUI.Controls" + xmlns:cwconv="using:CommunityToolkit.WinUI.Converters" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mxi="using:Microsoft.Xaml.Interactivity" @@ -28,6 +29,15 @@ + + + + + + + + + @@ -41,153 +51,162 @@ - - - + - - - - - + + + + + + + + + + - - - + - - - - + + - - - + - - + - - - + + - - - - - - - - - - - + + diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Feedback/FeedbackViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Feedback/FeedbackViewModel.cs index 38df7dd0..7a7bd53a 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Feedback/FeedbackViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Feedback/FeedbackViewModel.cs @@ -1,9 +1,12 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Microsoft.UI.Xaml.Controls; using Snap.Hutao.Core; using Snap.Hutao.Core.IO.DataTransfer; using Snap.Hutao.Core.IO.Http.DynamicProxy; +using Snap.Hutao.Core.IO.Http.Loopback; +using Snap.Hutao.Factory.ContentDialog; using Snap.Hutao.Service; using Snap.Hutao.Service.Notification; using Snap.Hutao.Web.Hutao; @@ -20,8 +23,10 @@ internal sealed partial class FeedbackViewModel : Abstraction.ViewModel { private readonly HutaoInfrastructureClient hutaoInfrastructureClient; private readonly HutaoDocumentationClient hutaoDocumentationClient; + private readonly IContentDialogFactory contentDialogFactory; private readonly IClipboardProvider clipboardProvider; private readonly DynamicHttpProxy dynamicHttpProxy; + private readonly LoopbackManager loopbackManager; private readonly IInfoBarService infoBarService; private readonly CultureOptions cultureOptions; private readonly RuntimeOptions runtimeOptions; @@ -35,6 +40,8 @@ internal sealed partial class FeedbackViewModel : Abstraction.ViewModel public DynamicHttpProxy DynamicHttpProxy { get => dynamicHttpProxy; } + public LoopbackManager LoopbackManager { get => loopbackManager; } + public string? SearchText { get => searchText; set => SetProperty(ref searchText, value); } public List? SearchResults { get => searchResults; set => SetProperty(ref searchResults, value); } @@ -113,4 +120,17 @@ internal sealed partial class FeedbackViewModel : Abstraction.ViewModel infoBarService.Error(ex); } } + + [Command("EnableLoopbackCommand")] + private async Task EnableLoopbackAsync() + { + ContentDialogResult result = await contentDialogFactory + .CreateForConfirmCancelAsync(SH.ViewDialogFeedbackEnableLoopbackTitle, SH.ViewDialogFeedbackEnableLoopbackContent) + .ConfigureAwait(false); + + if (result is ContentDialogResult.Primary) + { + LoopbackManager.EnableLoopback(); + } + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Win32/AdvApi32.cs b/src/Snap.Hutao/Snap.Hutao/Win32/AdvApi32.cs index de928361..5958a9dc 100644 --- a/src/Snap.Hutao/Snap.Hutao/Win32/AdvApi32.cs +++ b/src/Snap.Hutao/Snap.Hutao/Win32/AdvApi32.cs @@ -13,6 +13,10 @@ namespace Snap.Hutao.Win32; [SuppressMessage("", "SYSLIB1054")] internal static class AdvApi32 { + [DllImport("ADVAPI32.dll", ExactSpelling = true)] + [SupportedOSPlatform("windows5.0")] + public static extern BOOL EqualSid(PSID pSid1, PSID pSid2); + [DllImport("ADVAPI32.dll", ExactSpelling = true)] [SupportedOSPlatform("windows5.0")] public static extern WIN32_ERROR RegCloseKey(HKEY hKey); From c2e9f3a9267b5a66b6dc47acd948cad6e321b275 Mon Sep 17 00:00:00 2001 From: qhy040404 Date: Sat, 27 Jan 2024 00:47:09 +0800 Subject: [PATCH 3/5] verify set --- .../Snap.Hutao/Core/IO/Http/Loopback/LoopbackManager.cs | 4 +--- src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx | 2 +- src/Snap.Hutao/Snap.Hutao/Win32/ApiMsWinNetIsolation.cs | 1 - src/Snap.Hutao/Snap.Hutao/Win32/UI/Shell/Common/SHITEMID.cs | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Loopback/LoopbackManager.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Loopback/LoopbackManager.cs index 6a109dc2..a8242cab 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Loopback/LoopbackManager.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Loopback/LoopbackManager.cs @@ -65,9 +65,7 @@ internal sealed unsafe class LoopbackManager : ObservableObject, IDisposable Attributes = 0, }); - NetworkIsolationSetAppContainerConfig(sids.ToArray()); - - IsLoopbackEnabled = true; + IsLoopbackEnabled = NetworkIsolationSetAppContainerConfig(sids.ToArray()) is 0U; taskContext.InvokeOnMainThread(() => OnPropertyChanged(nameof(IsLoopbackEnabled))); } diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx index 10abdd1b..c2094ee5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx @@ -1875,7 +1875,7 @@ 无代理 - 已启用 + 已解除 解除 Loopback 限制 diff --git a/src/Snap.Hutao/Snap.Hutao/Win32/ApiMsWinNetIsolation.cs b/src/Snap.Hutao/Snap.Hutao/Win32/ApiMsWinNetIsolation.cs index a4259ab2..b28db068 100644 --- a/src/Snap.Hutao/Snap.Hutao/Win32/ApiMsWinNetIsolation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Win32/ApiMsWinNetIsolation.cs @@ -1,7 +1,6 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Snap.Hutao.Win32.Foundation; using Snap.Hutao.Win32.NetworkManagement.WindowsFirewall; using Snap.Hutao.Win32.Security; using System.Diagnostics; diff --git a/src/Snap.Hutao/Snap.Hutao/Win32/UI/Shell/Common/SHITEMID.cs b/src/Snap.Hutao/Snap.Hutao/Win32/UI/Shell/Common/SHITEMID.cs index 9c13d012..0efd13a6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Win32/UI/Shell/Common/SHITEMID.cs +++ b/src/Snap.Hutao/Snap.Hutao/Win32/UI/Shell/Common/SHITEMID.cs @@ -1,8 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using System.Runtime.InteropServices; using Snap.Hutao.Win32.Foundation; +using System.Runtime.InteropServices; namespace Snap.Hutao.Win32.UI.Shell.Common; From c4f3eb68e8969e5e263a8624e64e794b47289155 Mon Sep 17 00:00:00 2001 From: qhy040404 Date: Sat, 27 Jan 2024 09:19:18 +0800 Subject: [PATCH 4/5] code style --- .../Core/IO/Http/Loopback/LoopbackManager.cs | 1 - .../Resource/Localization/SH.en.resx | 88 +++++++++---------- 2 files changed, 44 insertions(+), 45 deletions(-) diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Loopback/LoopbackManager.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Loopback/LoopbackManager.cs index a8242cab..e80c9d7f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Loopback/LoopbackManager.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Loopback/LoopbackManager.cs @@ -19,7 +19,6 @@ internal sealed unsafe class LoopbackManager : ObservableObject, IDisposable private readonly RuntimeOptions runtimeOptions; private readonly ITaskContext taskContext; - public LoopbackManager(IServiceProvider serviceProvider) { runtimeOptions = serviceProvider.GetRequiredService(); diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.en.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.en.resx index b0753047..744206bf 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.en.resx +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.en.resx @@ -1,17 +1,17 @@  - - + - + - - - - + + + + - - + + - - + + - - - - + + + + - + - + @@ -3014,4 +3014,4 @@ Monitor ID - \ No newline at end of file + From 196bbb54c3f1118fccc5a538bd0e9e266099a302 Mon Sep 17 00:00:00 2001 From: DismissedLight <1686188646@qq.com> Date: Sat, 27 Jan 2024 13:01:56 +0800 Subject: [PATCH 5/5] code style --- .../IO/Http/DynamicProxy/DynamicHttpProxy.cs | 65 +++++++++-------- .../Core/IO/Http/Loopback/LoopbackManager.cs | 73 +++++++++++-------- .../ViewModel/Feedback/FeedbackViewModel.cs | 1 + src/Snap.Hutao/Snap.Hutao/Win32/AdvApi32.cs | 4 +- .../Snap.Hutao/Win32/ApiMsWinNetIsolation.cs | 21 ++++-- .../Win32/Foundation/FlexibleArray.cs | 6 +- .../Snap.Hutao/Win32/Foundation/PSID.cs | 4 + 7 files changed, 98 insertions(+), 76 deletions(-) diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/DynamicProxy/DynamicHttpProxy.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/DynamicProxy/DynamicHttpProxy.cs index aa786c8e..73a854c9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/DynamicProxy/DynamicHttpProxy.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/DynamicProxy/DynamicHttpProxy.cs @@ -1,4 +1,4 @@ -// Copyright (c) DGP Studio. All rights reserved. +// Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. using CommunityToolkit.Mvvm.ComponentModel; @@ -14,50 +14,34 @@ internal sealed partial class DynamicHttpProxy : ObservableObject, IWebProxy, ID { private const string ProxySettingPath = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections"; - private static readonly MethodInfo ConstructSystemProxyMethod; + private static readonly Lazy LazyConstructSystemProxyMethod = new(GetConstructSystemProxyMethod); + private readonly IServiceProvider serviceProvider; private readonly RegistryWatcher watcher; private IWebProxy innerProxy = default!; - [SuppressMessage("", "CA1810")] - static DynamicHttpProxy() + public DynamicHttpProxy(IServiceProvider serviceProvider) { - Type? systemProxyInfoType = typeof(System.Net.Http.SocketsHttpHandler).Assembly.GetType("System.Net.Http.SystemProxyInfo"); - ArgumentNullException.ThrowIfNull(systemProxyInfoType); + this.serviceProvider = serviceProvider; + UpdateInnerProxy(); - MethodInfo? constructSystemProxyMethod = systemProxyInfoType.GetMethod("ConstructSystemProxy", BindingFlags.Static | BindingFlags.Public); - ArgumentNullException.ThrowIfNull(constructSystemProxyMethod); - ConstructSystemProxyMethod = constructSystemProxyMethod; - } - - public DynamicHttpProxy() - { - UpdateProxy(); - - watcher = new(ProxySettingPath, OnProxyChanged); + watcher = new(ProxySettingPath, OnSystemProxySettingsChanged); watcher.Start(); } - /// - public ICredentials? Credentials - { - get => InnerProxy.Credentials; - set => InnerProxy.Credentials = value; - } - - public string CurrentProxy + public string CurrentProxyUri { get { - Uri? proxyUri = GetProxy(HutaoEndpoints.Website(string.Empty).ToUri()); + Uri? proxyUri = GetProxy("https://hut.ao".ToUri()); return proxyUri is null ? SH.ViewPageFeedbackCurrentProxyNoProxyDescription : proxyUri.AbsoluteUri; } } - private IWebProxy InnerProxy + public IWebProxy InnerProxy { get => innerProxy; @@ -74,6 +58,12 @@ internal sealed partial class DynamicHttpProxy : ObservableObject, IWebProxy, ID } } + public ICredentials? Credentials + { + get => InnerProxy.Credentials; + set => InnerProxy.Credentials = value; + } + public Uri? GetProxy(Uri destination) { return InnerProxy.GetProxy(destination); @@ -90,17 +80,30 @@ internal sealed partial class DynamicHttpProxy : ObservableObject, IWebProxy, ID watcher.Dispose(); } - public void OnProxyChanged() + public void OnSystemProxySettingsChanged() { - UpdateProxy(); + UpdateInnerProxy(); - Ioc.Default.GetRequiredService().InvokeOnMainThread(() => OnPropertyChanged(nameof(CurrentProxy))); + // TaskContext can't be injected directly since there are some recursive dependencies. + ITaskContext taskContext = serviceProvider.GetRequiredService(); + taskContext.BeginInvokeOnMainThread(() => OnPropertyChanged(nameof(CurrentProxyUri))); + } + + private static MethodInfo GetConstructSystemProxyMethod() + { + Type? systemProxyInfoType = typeof(System.Net.Http.SocketsHttpHandler).Assembly.GetType("System.Net.Http.SystemProxyInfo"); + ArgumentNullException.ThrowIfNull(systemProxyInfoType); + + MethodInfo? constructSystemProxyMethod = systemProxyInfoType.GetMethod("ConstructSystemProxy", BindingFlags.Static | BindingFlags.Public); + ArgumentNullException.ThrowIfNull(constructSystemProxyMethod); + + return constructSystemProxyMethod; } [MemberNotNull(nameof(innerProxy))] - private void UpdateProxy() + private void UpdateInnerProxy() { - IWebProxy? proxy = ConstructSystemProxyMethod.Invoke(default, default) as IWebProxy; + IWebProxy? proxy = LazyConstructSystemProxyMethod.Value.Invoke(default, default) as IWebProxy; ArgumentNullException.ThrowIfNull(proxy); InnerProxy = proxy; diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Loopback/LoopbackManager.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Loopback/LoopbackManager.cs index e80c9d7f..607349aa 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Loopback/LoopbackManager.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Loopback/LoopbackManager.cs @@ -5,72 +5,81 @@ using CommunityToolkit.Mvvm.ComponentModel; using Snap.Hutao.Win32.Foundation; using Snap.Hutao.Win32.NetworkManagement.WindowsFirewall; using Snap.Hutao.Win32.Security; +using System.Runtime.InteropServices; using static Snap.Hutao.Win32.AdvApi32; using static Snap.Hutao.Win32.ApiMsWinNetIsolation; +using static Snap.Hutao.Win32.Macros; namespace Snap.Hutao.Core.IO.Http.Loopback; [Injection(InjectAs.Singleton)] -internal sealed unsafe class LoopbackManager : ObservableObject, IDisposable +internal sealed unsafe class LoopbackManager : ObservableObject { - private readonly INET_FIREWALL_APP_CONTAINER* pContainers; - private readonly INET_FIREWALL_APP_CONTAINER* pHutaoContainer; - private readonly RuntimeOptions runtimeOptions; private readonly ITaskContext taskContext; + private readonly SID hutaoContainerSID; + private bool isLoopbackEnabled; + public LoopbackManager(IServiceProvider serviceProvider) { runtimeOptions = serviceProvider.GetRequiredService(); taskContext = serviceProvider.GetRequiredService(); - NetworkIsolationEnumAppContainers(NETISO_FLAG.NETISO_FLAG_MAX, out uint acCount, out pContainers); - for (uint i = 0; i < acCount; i++) + INET_FIREWALL_APP_CONTAINER* pContainers = default; + try { - INET_FIREWALL_APP_CONTAINER* pContainer = pContainers + i; - if (new string(pContainer->appContainerName) == runtimeOptions.FamilyName) + WIN32_ERROR error = NetworkIsolationEnumAppContainers(NETISO_FLAG.NETISO_FLAG_MAX, out uint acCount, out pContainers); + Marshal.ThrowExceptionForHR(HRESULT_FROM_WIN32(error)); + for (uint i = 0; i < acCount; i++) { - pHutaoContainer = pContainer; - break; + INET_FIREWALL_APP_CONTAINER* pContainer = pContainers + i; + ReadOnlySpan appContainerName = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(pContainer->appContainerName); + if (appContainerName.Equals(runtimeOptions.FamilyName)) + { + hutaoContainerSID = *pContainer->appContainerSid; + break; + } } } - - NetworkIsolationGetAppContainerConfig(out uint accCount, out SID_AND_ATTRIBUTES* pSids); - for (uint i = 0; i < accCount; i++) + finally { - if (EqualSid(new PSID { Value = pHutaoContainer->appContainerSid }, (pSids + i)->Sid)) + uint retVal = NetworkIsolationFreeAppContainers(pContainers); + Marshal.ThrowExceptionForHR(HRESULT_FROM_WIN32(*(WIN32_ERROR*)&retVal)); + } + + WIN32_ERROR error2 = NetworkIsolationGetAppContainerConfig(out uint accCount, out SID_AND_ATTRIBUTES* pSids); + Marshal.ThrowExceptionForHR(HRESULT_FROM_WIN32(error2)); + fixed (SID* phutaoContainerSID = &hutaoContainerSID) + { + for (uint i = 0; i < accCount; i++) { - IsLoopbackEnabled = true; - break; + if (EqualSid(phutaoContainerSID, (pSids + i)->Sid)) + { + IsLoopbackEnabled = true; + break; + } } } } - public bool IsLoopbackEnabled { get; private set; } + public bool IsLoopbackEnabled { get => isLoopbackEnabled; private set => SetProperty(ref isLoopbackEnabled, value); } public void EnableLoopback() { - List sids = []; - NetworkIsolationGetAppContainerConfig(out uint accCount, out SID_AND_ATTRIBUTES* pSids); + List sids = new((int)(accCount + 1)); for (uint i = 0; i < accCount; i++) { sids.Add(*(pSids + i)); } - sids.Add(new SID_AND_ATTRIBUTES + fixed (SID* phutaoContainerSID = &hutaoContainerSID) { - Sid = new PSID { Value = pHutaoContainer->appContainerSid }, - Attributes = 0, - }); - - IsLoopbackEnabled = NetworkIsolationSetAppContainerConfig(sids.ToArray()) is 0U; - - taskContext.InvokeOnMainThread(() => OnPropertyChanged(nameof(IsLoopbackEnabled))); - } - - public void Dispose() - { - _ = NetworkIsolationFreeAppContainers(pContainers); + SID_AND_ATTRIBUTES sidAndAttributes = default; + sidAndAttributes.Sid = phutaoContainerSID; + sids.Add(sidAndAttributes); + IsLoopbackEnabled = NetworkIsolationSetAppContainerConfig(CollectionsMarshal.AsSpan(sids)) is WIN32_ERROR.ERROR_SUCCESS; + } } } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Feedback/FeedbackViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Feedback/FeedbackViewModel.cs index 7a7bd53a..e80b8edb 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Feedback/FeedbackViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Feedback/FeedbackViewModel.cs @@ -130,6 +130,7 @@ internal sealed partial class FeedbackViewModel : Abstraction.ViewModel if (result is ContentDialogResult.Primary) { + await taskContext.SwitchToMainThreadAsync(); LoopbackManager.EnableLoopback(); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Win32/AdvApi32.cs b/src/Snap.Hutao/Snap.Hutao/Win32/AdvApi32.cs index 5958a9dc..d95aa0e4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Win32/AdvApi32.cs +++ b/src/Snap.Hutao/Snap.Hutao/Win32/AdvApi32.cs @@ -13,8 +13,8 @@ namespace Snap.Hutao.Win32; [SuppressMessage("", "SYSLIB1054")] internal static class AdvApi32 { - [DllImport("ADVAPI32.dll", ExactSpelling = true)] - [SupportedOSPlatform("windows5.0")] + [DllImport("ADVAPI32.dll", ExactSpelling = true, SetLastError = true)] + [SupportedOSPlatform("windows5.1.2600")] public static extern BOOL EqualSid(PSID pSid1, PSID pSid2); [DllImport("ADVAPI32.dll", ExactSpelling = true)] diff --git a/src/Snap.Hutao/Snap.Hutao/Win32/ApiMsWinNetIsolation.cs b/src/Snap.Hutao/Snap.Hutao/Win32/ApiMsWinNetIsolation.cs index b28db068..29fffef3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Win32/ApiMsWinNetIsolation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Win32/ApiMsWinNetIsolation.cs @@ -1,6 +1,7 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Win32.Foundation; using Snap.Hutao.Win32.NetworkManagement.WindowsFirewall; using Snap.Hutao.Win32.Security; using System.Diagnostics; @@ -19,13 +20,14 @@ internal static class ApiMsWinNetIsolation public static unsafe extern uint NetworkIsolationEnumAppContainers(uint Flags, uint* pdwNumPublicAppCs, INET_FIREWALL_APP_CONTAINER** ppPublicAppCs); [DebuggerStepThrough] - public static unsafe uint NetworkIsolationEnumAppContainers(NETISO_FLAG Flags, out uint dwNumPublicAppCs, out INET_FIREWALL_APP_CONTAINER* pPublicAppCs) + public static unsafe WIN32_ERROR NetworkIsolationEnumAppContainers(NETISO_FLAG Flags, out uint dwNumPublicAppCs, out INET_FIREWALL_APP_CONTAINER* pPublicAppCs) { fixed (uint* pdwNumPublicAppCs = &dwNumPublicAppCs) { fixed (INET_FIREWALL_APP_CONTAINER** ppPublicAppCs = &pPublicAppCs) { - return NetworkIsolationEnumAppContainers((uint)Flags, pdwNumPublicAppCs, ppPublicAppCs); + uint retVal = NetworkIsolationEnumAppContainers((uint)Flags, pdwNumPublicAppCs, ppPublicAppCs); + return *(WIN32_ERROR*)&retVal; } } } @@ -35,11 +37,12 @@ internal static class ApiMsWinNetIsolation public static unsafe extern uint NetworkIsolationFreeAppContainers(INET_FIREWALL_APP_CONTAINER* pPublicAppCs); [DebuggerStepThrough] - public static unsafe uint NetworkIsolationFreeAppContainers(ref readonly INET_FIREWALL_APP_CONTAINER publicAppCs) + public static unsafe WIN32_ERROR NetworkIsolationFreeAppContainers(ref readonly INET_FIREWALL_APP_CONTAINER publicAppCs) { fixed (INET_FIREWALL_APP_CONTAINER* pPublicAppCs = &publicAppCs) { - return NetworkIsolationFreeAppContainers(pPublicAppCs); + uint retVal = NetworkIsolationFreeAppContainers(pPublicAppCs); + return *(WIN32_ERROR*)&retVal; } } @@ -48,13 +51,14 @@ internal static class ApiMsWinNetIsolation public static unsafe extern uint NetworkIsolationGetAppContainerConfig(uint* pdwNumPublicAppCs, SID_AND_ATTRIBUTES** appContainerSids); [DebuggerStepThrough] - public static unsafe uint NetworkIsolationGetAppContainerConfig(out uint dwNumPublicAppCs, out SID_AND_ATTRIBUTES* appContainerSids) + public static unsafe WIN32_ERROR NetworkIsolationGetAppContainerConfig(out uint dwNumPublicAppCs, out SID_AND_ATTRIBUTES* appContainerSids) { fixed (uint* pdwNumPublicAppCs = &dwNumPublicAppCs) { fixed (SID_AND_ATTRIBUTES** pAppContainerSids = &appContainerSids) { - return NetworkIsolationGetAppContainerConfig(pdwNumPublicAppCs, pAppContainerSids); + uint retVal = NetworkIsolationGetAppContainerConfig(pdwNumPublicAppCs, pAppContainerSids); + return *(WIN32_ERROR*)&retVal; } } } @@ -64,11 +68,12 @@ internal static class ApiMsWinNetIsolation public static unsafe extern uint NetworkIsolationSetAppContainerConfig(uint dwNumPublicAppCs, SID_AND_ATTRIBUTES* appContainerSids); [DebuggerStepThrough] - public static unsafe uint NetworkIsolationSetAppContainerConfig(ReadOnlySpan appContainerSids) + public static unsafe WIN32_ERROR NetworkIsolationSetAppContainerConfig(ReadOnlySpan appContainerSids) { fixed (SID_AND_ATTRIBUTES* pAppContainerSids = appContainerSids) { - return NetworkIsolationSetAppContainerConfig((uint)appContainerSids.Length, pAppContainerSids); + uint retVal = NetworkIsolationSetAppContainerConfig((uint)appContainerSids.Length, pAppContainerSids); + return *(WIN32_ERROR*)&retVal; } } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Win32/Foundation/FlexibleArray.cs b/src/Snap.Hutao/Snap.Hutao/Win32/Foundation/FlexibleArray.cs index e4a4ba5e..97e163ec 100644 --- a/src/Snap.Hutao/Snap.Hutao/Win32/Foundation/FlexibleArray.cs +++ b/src/Snap.Hutao/Snap.Hutao/Win32/Foundation/FlexibleArray.cs @@ -3,8 +3,8 @@ namespace Snap.Hutao.Win32.Foundation; -internal unsafe struct FlexibleArray - where T : unmanaged +internal unsafe struct FlexibleArray + where TElement : unmanaged { - public T* Reference; + public TElement* Reference; } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Win32/Foundation/PSID.cs b/src/Snap.Hutao/Snap.Hutao/Win32/Foundation/PSID.cs index 8978cf35..f039093d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Win32/Foundation/PSID.cs +++ b/src/Snap.Hutao/Snap.Hutao/Win32/Foundation/PSID.cs @@ -1,9 +1,13 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Win32.Security; + namespace Snap.Hutao.Win32.Foundation; internal struct PSID { public unsafe void* Value; + + public static unsafe implicit operator PSID(SID* value) => *(PSID*)&value; } \ No newline at end of file