diff --git a/src/Snap.Hutao/Snap.Hutao/App.xaml b/src/Snap.Hutao/Snap.Hutao/App.xaml
index 98d24da7..3d8f03c0 100644
--- a/src/Snap.Hutao/Snap.Hutao/App.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/App.xaml
@@ -4,6 +4,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cwcont="using:CommunityToolkit.WinUI.Controls"
xmlns:cwconv="using:CommunityToolkit.WinUI.Converters"
+ xmlns:cwm="using:CommunityToolkit.WinUI.Media"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
xmlns:shci="using:Snap.Hutao.Control.Image"
xmlns:shmmc="using:Snap.Hutao.Model.Metadata.Converter"
@@ -28,6 +29,7 @@
+
@@ -301,6 +303,11 @@
+
+
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
index e448229e..66e5dcf9 100644
--- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
@@ -7080,6 +7080,15 @@ namespace Snap.Hutao.Resource.Localization {
}
}
+ ///
+ /// 查找类似 验证失败,请手动验证或前往「米游社-我的角色」页面查看 的本地化字符串。
+ ///
+ internal static string WebIndexOrSpiralAbyssVerificationFailed {
+ get {
+ return ResourceManager.GetString("WebIndexOrSpiralAbyssVerificationFailed", resourceCulture);
+ }
+ }
+
///
/// 查找类似 状态:{0} | 信息:{1} 的本地化字符串。
///
diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
index b7136696..cec38669 100644
--- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
+++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
@@ -2513,6 +2513,9 @@
武器活动祈愿
+
+ 验证失败,请手动验证或前往「米游社-我的角色」页面查看
+
状态:{0} | 信息:{1}
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Control/WebViewer.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Control/WebViewer.xaml.cs
index 890a581f..19e2425c 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Control/WebViewer.xaml.cs
+++ b/src/Snap.Hutao/Snap.Hutao/View/Control/WebViewer.xaml.cs
@@ -77,7 +77,12 @@ internal partial class WebViewer : UserControl, IRecipient
// TODO: replace with .NET 8 UnsafeAccessor
try
{
- CoreWebView2 coreWebView2 = WebView.CoreWebView2;
+ CoreWebView2? coreWebView2 = WebView?.CoreWebView2;
+
+ if (coreWebView2 is null)
+ {
+ return;
+ }
if (SourceProvider is not null)
{
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementPage.xaml
index aa3dc1d6..91203b71 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementPage.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementPage.xaml
@@ -178,7 +178,7 @@
-
+
@@ -188,7 +188,7 @@
-
+
@@ -21,22 +22,43 @@
Padding="0,0,0,0"
Spacing="4">
-
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
? resp = await httpClient
-
- // .SetUser(user, CookieType.SToken)
.SetReferer(ApiEndpoints.BbsReferer)
-
- // .UseDynamicSecret(DynamicSecretVersion.Gen1, SaltType.K2, true)
.TryCatchGetFromJsonAsync>(ApiEndpoints.UserFullInfoQuery(user.Aid), options, logger, token)
.ConfigureAwait(false);
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/GameRecordClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/GameRecordClient.cs
index 8c295996..94398052 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/GameRecordClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/GameRecordClient.cs
@@ -78,6 +78,24 @@ internal sealed partial class GameRecordClient : IGameRecordClient
.TryCatchGetFromJsonAsync>(ApiEndpoints.GameRecordIndex(userAndUid.Uid), options, logger, token)
.ConfigureAwait(false);
+ // We have a verification procedure to handle
+ if (resp?.ReturnCode == (int)KnownReturnCode.CODE1034)
+ {
+ // Replace message
+ resp.Message = SH.WebIndexOrSpiralAbyssVerificationFailed;
+ IGeetestCardVerifier verifier = serviceProvider.GetRequiredService();
+
+ if (await verifier.TryValidateXrpcChallengeAsync(userAndUid.User, token).ConfigureAwait(false) is { } challenge)
+ {
+ resp = await httpClient
+ .SetUser(userAndUid.User, CookieType.Cookie)
+ .SetXrpcChallenge(challenge)
+ .UseDynamicSecret(DynamicSecretVersion.Gen2, SaltType.X4, false)
+ .TryCatchGetFromJsonAsync>(ApiEndpoints.GameRecordIndex(userAndUid.Uid), options, logger, token)
+ .ConfigureAwait(false);
+ }
+ }
+
return Response.Response.DefaultIfNull(resp);
}
@@ -97,6 +115,24 @@ internal sealed partial class GameRecordClient : IGameRecordClient
.TryCatchGetFromJsonAsync>(ApiEndpoints.GameRecordSpiralAbyss(schedule, userAndUid.Uid), options, logger, token)
.ConfigureAwait(false);
+ // We have a verification procedure to handle
+ if (resp?.ReturnCode == (int)KnownReturnCode.CODE1034)
+ {
+ // Replace message
+ resp.Message = SH.WebIndexOrSpiralAbyssVerificationFailed;
+ IGeetestCardVerifier verifier = serviceProvider.GetRequiredService();
+
+ if (await verifier.TryValidateXrpcChallengeAsync(userAndUid.User, token).ConfigureAwait(false) is { } challenge)
+ {
+ resp = await httpClient
+ .SetUser(userAndUid.User, CookieType.Cookie)
+ .SetXrpcChallenge(challenge)
+ .UseDynamicSecret(DynamicSecretVersion.Gen2, SaltType.X4, false)
+ .TryCatchGetFromJsonAsync>(ApiEndpoints.GameRecordSpiralAbyss(schedule, userAndUid.Uid), options, logger, token)
+ .ConfigureAwait(false);
+ }
+ }
+
return Response.Response.DefaultIfNull(resp);
}
@@ -136,6 +172,24 @@ internal sealed partial class GameRecordClient : IGameRecordClient
.TryCatchPostAsJsonAsync>(ApiEndpoints.GameRecordCharacter, data, options, logger, token)
.ConfigureAwait(false);
+ // We have a verification procedure to handle
+ if (resp?.ReturnCode == (int)KnownReturnCode.CODE1034)
+ {
+ // Replace message
+ resp.Message = SH.WebIndexOrSpiralAbyssVerificationFailed;
+ IGeetestCardVerifier verifier = serviceProvider.GetRequiredService();
+
+ if (await verifier.TryValidateXrpcChallengeAsync(userAndUid.User, token).ConfigureAwait(false) is { } challenge)
+ {
+ resp = await httpClient
+ .SetUser(userAndUid.User, CookieType.Cookie)
+ .SetXrpcChallenge(challenge)
+ .UseDynamicSecret(DynamicSecretVersion.Gen2, SaltType.X4, false)
+ .TryCatchPostAsJsonAsync>(ApiEndpoints.GameRecordCharacter, data, options, logger, token)
+ .ConfigureAwait(false);
+ }
+ }
+
return Response.Response.DefaultIfNull(resp);
}
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/HttpClientExtension.cs b/src/Snap.Hutao/Snap.Hutao/Web/HttpClientExtension.cs
index bb29921a..a4e82d85 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/HttpClientExtension.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/HttpClientExtension.cs
@@ -16,13 +16,12 @@ internal static class HttpClientExtension
{
private const string RequestErrorMessage = "请求异常已忽略";
- ///
- internal static async ValueTask TryCatchGetFromJsonAsync(this HttpClient httpClient, string requestUri, JsonSerializerOptions options, ILogger logger, CancellationToken token = default)
- where T : class
+ internal static async ValueTask TryCatchGetFromJsonAsync(this HttpClient httpClient, string requestUri, JsonSerializerOptions options, ILogger logger, CancellationToken token = default)
+ where TResult : class
{
try
{
- return await httpClient.GetFromJsonAsync(requestUri, options, token).ConfigureAwait(false);
+ return await httpClient.GetFromJsonAsync(requestUri, options, token).ConfigureAwait(false);
}
catch (HttpRequestException ex)
{
@@ -46,7 +45,6 @@ internal static class HttpClientExtension
}
}
- ///
internal static async ValueTask TryCatchPostAsJsonAsync(this HttpClient httpClient, string requestUri, TValue value, JsonSerializerOptions options, ILogger logger, CancellationToken token = default)
where TResult : class
{
@@ -77,7 +75,6 @@ internal static class HttpClientExtension
}
}
- ///
internal static async ValueTask TryCatchPostAsJsonAsync(this HttpClient httpClient, string requestUri, TValue value, CancellationToken token = default)
where TResult : class
{