mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Merge branch 'DGP-Studio:main' into main
This commit is contained in:
@@ -32,7 +32,7 @@ internal sealed class ExceptionRecorder
|
||||
{
|
||||
#if RELEASE
|
||||
#pragma warning disable VSTHRD002
|
||||
Ioc.Default.GetRequiredService<Web.Hutao.HomaClient2>().UploadLogAsync(e.Exception).GetAwaiter().GetResult();
|
||||
Ioc.Default.GetRequiredService<Web.Hutao.HomaLogUploadClient>().UploadLogAsync(e.Exception).GetAwaiter().GetResult();
|
||||
#pragma warning restore VSTHRD002
|
||||
#endif
|
||||
StringBuilder dataDetailBuilder = new();
|
||||
|
||||
@@ -29,6 +29,16 @@ internal static class SettingKeys
|
||||
/// </summary>
|
||||
public const string DataFolderPath = "DataFolderPath";
|
||||
|
||||
/// <summary>
|
||||
/// 通行证用户名(邮箱)
|
||||
/// </summary>
|
||||
public const string PassportUserName = "PassportUserName";
|
||||
|
||||
/// <summary>
|
||||
/// 通行证密码
|
||||
/// </summary>
|
||||
public const string PassportPassword = "PassportPassword";
|
||||
|
||||
/// <summary>
|
||||
/// 静态资源合约
|
||||
/// 新增合约时 请注意
|
||||
|
||||
@@ -214,7 +214,7 @@ internal sealed class User : ObservableObject
|
||||
return false;
|
||||
}
|
||||
|
||||
if (await TrySetCookieTokenAsync(scope.ServiceProvider, token).ConfigureAwait(false))
|
||||
if (!await TrySetCookieTokenAsync(scope.ServiceProvider, token).ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4281,6 +4281,15 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 胡桃账号 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewPageSettingHutaoPassportHeader {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewPageSettingHutaoPassportHeader", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 在完整阅读原神和胡桃工具箱用户协议后,我选择启用「启动游戏-高级功能」 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -4488,6 +4497,24 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 登录失败,请重新登录 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewServiceHutaoUserLoginFailHint {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewServiceHutaoUserLoginFailHint", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 立即登录或注册 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewServiceHutaoUserLoginOrRegisterHint {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewServiceHutaoUserLoginOrRegisterHint", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 战斗数据 的本地化字符串。
|
||||
/// </summary>
|
||||
|
||||
@@ -1797,4 +1797,13 @@
|
||||
<data name="ViewDialogSettingDeleteUserDataTitle" xml:space="preserve">
|
||||
<value>是否永久删除用户数据</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingHutaoPassportHeader" xml:space="preserve">
|
||||
<value>胡桃账号</value>
|
||||
</data>
|
||||
<data name="ViewServiceHutaoUserLoginFailHint" xml:space="preserve">
|
||||
<value>登录失败,请重新登录</value>
|
||||
</data>
|
||||
<data name="ViewServiceHutaoUserLoginOrRegisterHint" xml:space="preserve">
|
||||
<value>立即登录或注册</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -81,10 +81,11 @@ internal sealed class GameFpsUnlocker : IGameFpsUnlocker
|
||||
try
|
||||
{
|
||||
Marshal.ThrowExceptionForHR(Marshal.GetLastPInvokeError());
|
||||
|
||||
foreach (MODULEENTRY32 entry in StructMarshal.EnumerateModuleEntry32(snapshot))
|
||||
{
|
||||
if (entry.th32ProcessID == processId && entry.szModule.AsNullTerminatedReadOnlySpan().SequenceEqual(moduleName))
|
||||
__CHAR_256* pszModule = &entry.szModule;
|
||||
ReadOnlySpan<byte> szModuleLocal = MemoryMarshal.CreateReadOnlySpanFromNullTerminated((byte*)pszModule);
|
||||
if (entry.th32ProcessID == processId && szModuleLocal.SequenceEqual(moduleName))
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Snap.Hutao.Service.Hutao;
|
||||
[Injection(InjectAs.Scoped, typeof(IHutaoService))]
|
||||
internal sealed class HutaoService : IHutaoService
|
||||
{
|
||||
private readonly HomaClient homaClient;
|
||||
private readonly HomaSpiralAbyssClient homaClient;
|
||||
private readonly IMemoryCache memoryCache;
|
||||
private readonly AppDbContext appDbContext;
|
||||
private readonly JsonSerializerOptions options;
|
||||
@@ -30,7 +30,7 @@ internal sealed class HutaoService : IHutaoService
|
||||
/// <param name="memoryCache">内存缓存</param>
|
||||
/// <param name="appDbContext">数据库上下文</param>
|
||||
/// <param name="options">Json序列化选项</param>
|
||||
public HutaoService(HomaClient homaClient, IMemoryCache memoryCache, AppDbContext appDbContext, JsonSerializerOptions options)
|
||||
public HutaoService(HomaSpiralAbyssClient homaClient, IMemoryCache memoryCache, AppDbContext appDbContext, JsonSerializerOptions options)
|
||||
{
|
||||
this.homaClient = homaClient;
|
||||
this.memoryCache = memoryCache;
|
||||
@@ -103,18 +103,21 @@ internal sealed class HutaoService : IHutaoService
|
||||
}
|
||||
|
||||
Response<T> webResponse = await taskFunc(default).ConfigureAwait(false);
|
||||
T web = webResponse.IsOk() ? webResponse.Data : new();
|
||||
T? data = webResponse.Data;
|
||||
|
||||
try
|
||||
{
|
||||
appDbContext.ObjectCache.AddAndSave(new()
|
||||
if (data != null)
|
||||
{
|
||||
Key = key,
|
||||
appDbContext.ObjectCache.AddAndSave(new()
|
||||
{
|
||||
Key = key,
|
||||
|
||||
// we hold the cache for 4 hours, then just expire it.
|
||||
ExpireTime = DateTimeOffset.Now.AddHours(4),
|
||||
Value = JsonSerializer.Serialize(web, options),
|
||||
});
|
||||
// we hold the cache for 4 hours, then just expire it.
|
||||
ExpireTime = DateTimeOffset.Now.AddHours(4),
|
||||
Value = JsonSerializer.Serialize(data, options),
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Microsoft.EntityFrameworkCore.DbUpdateException)
|
||||
{
|
||||
@@ -122,6 +125,6 @@ internal sealed class HutaoService : IHutaoService
|
||||
// TODO: Not ignore it.
|
||||
}
|
||||
|
||||
return memoryCache.Set(key, web, TimeSpan.FromMinutes(30));
|
||||
return memoryCache.Set(key, data ?? new(), TimeSpan.FromHours(4));
|
||||
}
|
||||
}
|
||||
}
|
||||
77
src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoUserService.cs
Normal file
77
src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoUserService.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Web.Hutao;
|
||||
|
||||
namespace Snap.Hutao.Service.Hutao;
|
||||
|
||||
/// <summary>
|
||||
/// 胡桃用户服务
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Singleton, typeof(IHutaoUserService))]
|
||||
internal sealed class HutaoUserService : IHutaoUserService, IHutaoUserServiceInitialization
|
||||
{
|
||||
private readonly HomaPassportClient passportClient;
|
||||
private readonly TaskCompletionSource initializeCompletionSource = new();
|
||||
|
||||
private bool isInitialized;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的胡桃用户服务
|
||||
/// </summary>
|
||||
/// <param name="passportClient">通行证客户端</param>
|
||||
public HutaoUserService(HomaPassportClient passportClient)
|
||||
{
|
||||
this.passportClient = passportClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户名
|
||||
/// </summary>
|
||||
public string? UserName { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 访问令牌
|
||||
/// </summary>
|
||||
public string? Token { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 异步初始化
|
||||
/// </summary>
|
||||
/// <returns>任务</returns>
|
||||
public async ValueTask<bool> InitializeAsync()
|
||||
{
|
||||
await initializeCompletionSource.Task.ConfigureAwait(false);
|
||||
return isInitialized;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task InitializeInternalAsync(CancellationToken token = default)
|
||||
{
|
||||
string userName = LocalSetting.Get(SettingKeys.PassportUserName, string.Empty);
|
||||
string passport = LocalSetting.Get(SettingKeys.PassportPassword, string.Empty);
|
||||
|
||||
if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(passport))
|
||||
{
|
||||
Web.Response.Response<string> response = await passportClient.LoginAsync(userName, passport, token).ConfigureAwait(false);
|
||||
|
||||
if (response.IsOk())
|
||||
{
|
||||
Token = response.Data;
|
||||
UserName = userName;
|
||||
isInitialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UserName = SH.ViewServiceHutaoUserLoginFailHint;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UserName = SH.ViewServiceHutaoUserLoginOrRegisterHint;
|
||||
}
|
||||
|
||||
initializeCompletionSource.TrySetResult();
|
||||
}
|
||||
}
|
||||
11
src/Snap.Hutao/Snap.Hutao/Service/Hutao/IHutaoUserService.cs
Normal file
11
src/Snap.Hutao/Snap.Hutao/Service/Hutao/IHutaoUserService.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Service.Hutao;
|
||||
|
||||
/// <summary>
|
||||
/// 胡桃用户服务
|
||||
/// </summary>
|
||||
internal interface IHutaoUserService : ICastableService
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Service.Hutao;
|
||||
|
||||
/// <summary>
|
||||
/// 指示该类为用户服务初始化器
|
||||
/// </summary>
|
||||
internal interface IHutaoUserServiceInitialization
|
||||
{
|
||||
/// <summary>
|
||||
/// 异步初始化
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>任务</returns>
|
||||
Task InitializeInternalAsync(CancellationToken token = default);
|
||||
}
|
||||
@@ -244,7 +244,7 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.6.4-alpha" />
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.188-beta">
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.206-beta">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -72,6 +72,10 @@
|
||||
Description="{Binding AppVersion}"
|
||||
Header="{shcm:ResourceString Name=AppName}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}"/>
|
||||
<clw:SettingsCard
|
||||
Description="{Binding AppVersion}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingHutaoPassportHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}"/>
|
||||
<clw:SettingsCard
|
||||
ActionIcon="{shcm:FontIcon Glyph=}"
|
||||
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingCopyDeviceIdAction}"
|
||||
@@ -199,15 +203,9 @@
|
||||
IsOpen="{Binding Options.IsAdvancedLaunchOptionsEnabled}"
|
||||
Message="{shcm:ResourceString Name=ViewPageSettingFeaturesDangerousHint}"
|
||||
Severity="Error"/>
|
||||
<InfoBar
|
||||
IsClosable="False"
|
||||
IsOpen="{Binding IsElevated, Converter={StaticResource BoolNegationConverter}}"
|
||||
Message="{shcm:ResourceString Name=ViewPageLaunchGameElevationHint}"
|
||||
Severity="Warning"/>
|
||||
|
||||
<clw:SettingsCard
|
||||
Background="{StaticResource SystemFillColorCriticalBackgroundBrush}"
|
||||
BorderBrush="{StaticResource SystemFillColorCriticalBrush}"
|
||||
Description="{shcm:ResourceString Name=ViewPageSettingIsAdvancedLaunchOptionsEnabledDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingIsAdvancedLaunchOptionsEnabledHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}">
|
||||
@@ -217,6 +215,7 @@
|
||||
IsOn="{Binding Options.IsAdvancedLaunchOptionsEnabled, Mode=TwoWay}"/>
|
||||
</clw:SettingsCard>
|
||||
<InfoBar
|
||||
Margin="0,4,0,0"
|
||||
IsClosable="False"
|
||||
IsOpen="True"
|
||||
Message="{shcm:ResourceString Name=ViewPageSettingDangerousHint}"
|
||||
|
||||
@@ -50,7 +50,7 @@ internal sealed class AchievementImporter
|
||||
{
|
||||
if (await GetUIAFFromClipboardAsync().ConfigureAwait(false) is UIAF uiaf)
|
||||
{
|
||||
return await ImportAsync(achievementService.CurrentArchive!, uiaf).ConfigureAwait(false);
|
||||
return await TryImportAsync(achievementService.CurrentArchive!, uiaf).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -85,7 +85,7 @@ internal sealed class AchievementImporter
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
return await ImportAsync(achievementService.CurrentArchive, uiaf!).ConfigureAwait(false);
|
||||
return await TryImportAsync(achievementService.CurrentArchive, uiaf!).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -114,7 +114,7 @@ internal sealed class AchievementImporter
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> ImportAsync(EntityAchievementArchive archive, UIAF uiaf)
|
||||
private async Task<bool> TryImportAsync(EntityAchievementArchive archive, UIAF uiaf)
|
||||
{
|
||||
if (uiaf.IsCurrentVersionSupported())
|
||||
{
|
||||
|
||||
@@ -176,7 +176,7 @@ internal sealed class SpiralAbyssRecordViewModel : Abstraction.ViewModel, IRecip
|
||||
|
||||
private async Task UploadSpiralAbyssRecordAsync()
|
||||
{
|
||||
HomaClient homaClient = serviceProvider.GetRequiredService<HomaClient>();
|
||||
HomaSpiralAbyssClient homaClient = serviceProvider.GetRequiredService<HomaSpiralAbyssClient>();
|
||||
IInfoBarService infoBarService = serviceProvider.GetRequiredService<IInfoBarService>();
|
||||
|
||||
if (UserAndUid.TryFromUser(userService.Current, out UserAndUid? userAndUid))
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Snap.Hutao.Web.Hutao;
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[HttpClient(HttpClientConfigration.Default)]
|
||||
internal sealed class HomaClient2
|
||||
internal sealed class HomaLogUploadClient
|
||||
{
|
||||
private readonly HttpClient httpClient;
|
||||
|
||||
@@ -21,7 +21,7 @@ internal sealed class HomaClient2
|
||||
/// 构造一个新的胡桃日志客户端
|
||||
/// </summary>
|
||||
/// <param name="httpClient">Http客户端</param>
|
||||
public HomaClient2(HttpClient httpClient)
|
||||
public HomaLogUploadClient(HttpClient httpClient)
|
||||
{
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
@@ -50,4 +50,4 @@ internal sealed class HomaClient2
|
||||
Info = exception.ToString(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
147
src/Snap.Hutao/Snap.Hutao/Web/Hutao/HomaPassportClient.cs
Normal file
147
src/Snap.Hutao/Snap.Hutao/Web/Hutao/HomaPassportClient.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||
using Snap.Hutao.Web.Response;
|
||||
using System.Net.Http;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Snap.Hutao.Web.Hutao;
|
||||
|
||||
/// <summary>
|
||||
/// 胡桃通行证客户端
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[HttpClient(HttpClientConfigration.Default)]
|
||||
internal sealed class HomaPassportClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 通行证请求公钥
|
||||
/// </summary>
|
||||
public const string PublicKey = """
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5W2SEyZSlP2zBI1Sn8Gd
|
||||
TwbZoXlUGNKyoVrY8SVYu9GMefdGZCrUQNkCG/Np8pWPmSSEFGd5oeug/oIMtCZQ
|
||||
NOn0drlR+pul/XZ1KQhKmj/arWjN1XNok2qXF7uxhqD0JyNT/Fxy6QvzqIpBsM9S
|
||||
7ajm8/BOGlPG1SInDPaqTdTRTT30AuN+IhWEEFwT3Ctv1SmDupHs2Oan5qM7Y3uw
|
||||
b6K1rbnk5YokiV2FzHajGUymmSKXqtG1USZzwPqImpYb4Z0M/StPFWdsKqexBqMM
|
||||
mkXckI5O98GdlszEmQ0Ejv5Fx9fR2rXRwM76S4iZTfabYpiMbb4bM42mHMauupj6
|
||||
9QIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
""";
|
||||
|
||||
private readonly HttpClient httpClient;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的胡桃通行证客户端
|
||||
/// </summary>
|
||||
/// <param name="httpClient">Http客户端</param>
|
||||
public HomaPassportClient(HttpClient httpClient)
|
||||
{
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取验证码
|
||||
/// </summary>
|
||||
/// <param name="email">邮箱</param>
|
||||
/// <param name="isResetPassword">是否重置账号密码</param>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>响应</returns>
|
||||
public async Task<Response.Response> VerifyAsync(string email, bool isResetPassword, CancellationToken token = default)
|
||||
{
|
||||
Dictionary<string, object> data = new()
|
||||
{
|
||||
["UserName"] = Encrypt(email),
|
||||
["IsResetPassword"] = isResetPassword,
|
||||
};
|
||||
|
||||
Response.Response? resp = await httpClient
|
||||
.TryCatchPostAsJsonAsync<Dictionary<string, object>, Response.Response>(HutaoEndpoints.PassportVerify, data, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return Response.Response.DefaultIfNull(resp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步注册
|
||||
/// </summary>
|
||||
/// <param name="email">邮箱</param>
|
||||
/// <param name="password">密码</param>
|
||||
/// <param name="verifyCode">验证码</param>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>响应,包含登录令牌</returns>
|
||||
public async Task<Response<string>> RegisterAsync(string email, string password, string verifyCode, CancellationToken token = default)
|
||||
{
|
||||
Dictionary<string, string> data = new()
|
||||
{
|
||||
["UserName"] = Encrypt(email),
|
||||
["Password"] = Encrypt(password),
|
||||
["VerifyCode"] = Encrypt(verifyCode),
|
||||
};
|
||||
|
||||
Response<string>? resp = await httpClient
|
||||
.TryCatchPostAsJsonAsync<Dictionary<string, string>, Response<string>>(HutaoEndpoints.PassportRegister, data, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return Response.Response.DefaultIfNull(resp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步重置密码
|
||||
/// </summary>
|
||||
/// <param name="email">邮箱</param>
|
||||
/// <param name="password">密码</param>
|
||||
/// <param name="verifyCode">验证码</param>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>响应,包含登录令牌</returns>
|
||||
public async Task<Response<string>> ResetPasswordAsync(string email, string password, string verifyCode, CancellationToken token = default)
|
||||
{
|
||||
Dictionary<string, string> data = new()
|
||||
{
|
||||
["UserName"] = Encrypt(email),
|
||||
["Password"] = Encrypt(password),
|
||||
["VerifyCode"] = Encrypt(verifyCode),
|
||||
};
|
||||
|
||||
Response<string>? resp = await httpClient
|
||||
.TryCatchPostAsJsonAsync<Dictionary<string, string>, Response<string>>(HutaoEndpoints.PassportResetPassword, data, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return Response.Response.DefaultIfNull(resp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步登录
|
||||
/// </summary>
|
||||
/// <param name="email">邮箱</param>
|
||||
/// <param name="password">密码</param>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>响应,包含登录令牌</returns>
|
||||
public async Task<Response<string>> LoginAsync(string email, string password, CancellationToken token = default)
|
||||
{
|
||||
Dictionary<string, string> data = new()
|
||||
{
|
||||
["UserName"] = Encrypt(email),
|
||||
["Password"] = Encrypt(password),
|
||||
};
|
||||
|
||||
Response<string>? resp = await httpClient
|
||||
.TryCatchPostAsJsonAsync<Dictionary<string, string>, Response<string>>(HutaoEndpoints.PassportLogin, data, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return Response.Response.DefaultIfNull(resp);
|
||||
}
|
||||
|
||||
private static string Encrypt(string text)
|
||||
{
|
||||
byte[] plaintextBytes = Encoding.UTF8.GetBytes(text);
|
||||
using (RSACryptoServiceProvider rsa = new(2048))
|
||||
{
|
||||
rsa.ImportFromPem(PublicKey);
|
||||
byte[] encryptedBytes = rsa.Encrypt(plaintextBytes, true);
|
||||
return Convert.ToBase64String(encryptedBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,12 +19,12 @@ namespace Snap.Hutao.Web.Hutao;
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[HttpClient(HttpClientConfigration.Default)]
|
||||
internal sealed class HomaClient
|
||||
internal sealed class HomaSpiralAbyssClient
|
||||
{
|
||||
private readonly HttpClient httpClient;
|
||||
private readonly GameRecordClient gameRecordClient;
|
||||
private readonly JsonSerializerOptions options;
|
||||
private readonly ILogger<HomaClient> logger;
|
||||
private readonly ILogger<HomaSpiralAbyssClient> logger;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的胡桃API客户端
|
||||
@@ -33,7 +33,7 @@ internal sealed class HomaClient
|
||||
/// <param name="gameRecordClient">游戏记录客户端</param>
|
||||
/// <param name="options">json序列化选项</param>
|
||||
/// <param name="logger">日志器</param>
|
||||
public HomaClient(HttpClient httpClient, GameRecordClient gameRecordClient, JsonSerializerOptions options, ILogger<HomaClient> logger)
|
||||
public HomaSpiralAbyssClient(HttpClient httpClient, GameRecordClient gameRecordClient, JsonSerializerOptions options, ILogger<HomaSpiralAbyssClient> logger)
|
||||
{
|
||||
this.httpClient = httpClient;
|
||||
this.gameRecordClient = gameRecordClient;
|
||||
@@ -16,6 +16,29 @@ internal static class HutaoEndpoints
|
||||
/// </summary>
|
||||
public const string StaticHutao = "static.hut.ao";
|
||||
|
||||
#region Passport
|
||||
|
||||
/// <summary>
|
||||
/// 获取注册验证码
|
||||
/// </summary>
|
||||
public const string PassportVerify = $"{HomaSnapGenshinApi}/Passport/Verify";
|
||||
|
||||
/// <summary>
|
||||
/// 注册账号
|
||||
/// </summary>
|
||||
public const string PassportRegister = $"{HomaSnapGenshinApi}/Passport/Register";
|
||||
|
||||
/// <summary>
|
||||
/// 重设密码
|
||||
/// </summary>
|
||||
public const string PassportResetPassword = $"{HomaSnapGenshinApi}/Passport/ResetPassword";
|
||||
|
||||
/// <summary>
|
||||
/// 登录
|
||||
/// </summary>
|
||||
public const string PassportLogin = $"{HomaSnapGenshinApi}/Passport/Login";
|
||||
#endregion
|
||||
|
||||
#region HutaoAPI
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -40,6 +40,12 @@ internal class Response
|
||||
[JsonPropertyName("message")]
|
||||
public string Message { get; set; } = default!;
|
||||
|
||||
public static Response DefaultIfNull(Response? response, [CallerMemberName] string callerName = default!)
|
||||
{
|
||||
// 0x26F19335 is a magic number that hashed from "Snap.Hutao"
|
||||
return response ?? new(0x26F19335, $"[{callerName}] 中的请求异常");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回本体或带有消息提示的默认值
|
||||
/// </summary>
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Win32.Foundation;
|
||||
|
||||
namespace Snap.Hutao.Win32;
|
||||
|
||||
/// <summary>
|
||||
/// 内存拓展 for <see cref="Memory{T}"/> and <see cref="Span{T}"/>
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal static class MemoryExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 将 __CHAR_256 转换到 字符串
|
||||
/// </summary>
|
||||
/// <param name="char256">目标字符数组</param>
|
||||
/// <returns>结果字符串</returns>
|
||||
public static unsafe ReadOnlySpan<byte> AsNullTerminatedReadOnlySpan(this in __CHAR_256 char256)
|
||||
{
|
||||
fixed (CHAR* pszChar = &char256._0)
|
||||
{
|
||||
return MemoryMarshal.CreateReadOnlySpanFromNullTerminated((byte*)pszChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user