diff --git a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocHttpClientConfiguration.cs b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocHttpClientConfiguration.cs index 2a20113f..1d091b32 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocHttpClientConfiguration.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocHttpClientConfiguration.cs @@ -46,7 +46,7 @@ internal static partial class IocHttpClientConfiguration client.DefaultRequestHeaders.Accept.ParseAdd(ApplicationJson); client.DefaultRequestHeaders.Add("x-rpc-app_version", SaltConstants.CNVersion); client.DefaultRequestHeaders.Add("x-rpc-client_type", "5"); - client.DefaultRequestHeaders.Add("x-rpc-device_id", HoyolabOptions.DeviceId); + client.DefaultRequestHeaders.Add("x-rpc-device_id", HoyolabOptions.DeviceId36); } /// @@ -62,7 +62,7 @@ internal static partial class IocHttpClientConfiguration client.DefaultRequestHeaders.Add("x-rpc-app_id", "bll8iq97cem8"); client.DefaultRequestHeaders.Add("x-rpc-app_version", SaltConstants.CNVersion); client.DefaultRequestHeaders.Add("x-rpc-client_type", "2"); - client.DefaultRequestHeaders.Add("x-rpc-device_id", HoyolabOptions.DeviceId); + client.DefaultRequestHeaders.Add("x-rpc-device_id", HoyolabOptions.DeviceId36); client.DefaultRequestHeaders.Add("x-rpc-device_name", string.Empty); client.DefaultRequestHeaders.Add("x-rpc-game_biz", "bbs_cn"); client.DefaultRequestHeaders.Add("x-rpc-sdk_version", "2.16.0"); @@ -81,7 +81,7 @@ internal static partial class IocHttpClientConfiguration client.DefaultRequestHeaders.Add("x-rpc-app_version", SaltConstants.OSVersion); client.DefaultRequestHeaders.Add("x-rpc-client_type", "5"); client.DefaultRequestHeaders.Add("x-rpc-language", "zh-cn"); - client.DefaultRequestHeaders.Add("x-rpc-device_id", HoyolabOptions.DeviceId); + client.DefaultRequestHeaders.Add("x-rpc-device_id", HoyolabOptions.DeviceId36); } /// diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Random.cs b/src/Snap.Hutao/Snap.Hutao/Core/Random.cs index f1427404..74afc366 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Random.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Random.cs @@ -19,9 +19,4 @@ internal static class Random { return new(System.Random.Shared.GetItems("0123456789abcdefghijklmnopqrstuvwxyz".AsSpan(), length)); } - - public static string GetLetterAndNumberString(int length) - { - return new(System.Random.Shared.GetItems("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".AsSpan(), length)); - } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Uuid.cs b/src/Snap.Hutao/Snap.Hutao/Core/Uuid.cs new file mode 100644 index 00000000..b0d74b4f --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Core/Uuid.cs @@ -0,0 +1,61 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using System.Runtime.CompilerServices; +using System.Security.Cryptography; +using System.Text; + +namespace Snap.Hutao.Core; + +internal static class Uuid +{ + public static Guid NewV5(string name, Guid namespaceId) + { + Span namespaceBuffer = stackalloc byte[16]; + Verify.Operation(namespaceId.TryWriteBytes(namespaceBuffer), "Failed to copy namespace guid bytes"); + Span nameBytes = Encoding.UTF8.GetBytes(name); + + if (BitConverter.IsLittleEndian) + { + ReverseEndianness(namespaceBuffer); + } + + Span data = stackalloc byte[namespaceBuffer.Length + nameBytes.Length]; + namespaceBuffer.CopyTo(data); + nameBytes.CopyTo(data[namespaceBuffer.Length..]); + + Span temp = stackalloc byte[20]; + Verify.Operation(SHA1.TryHashData(data, temp, out _), "Failed to compute SHA1 hash of UUID"); + + Span hash = temp[..16]; + + if (BitConverter.IsLittleEndian) + { + ReverseEndianness(hash); + } + + hash[8] &= 0x3F; + hash[8] |= 0x80; + + int versionIndex = BitConverter.IsLittleEndian ? 7 : 6; + + hash[versionIndex] &= 0x0F; + hash[versionIndex] |= 0x50; + + return new(hash); + } + + private static void ReverseEndianness(in Span guidByte) + { + ExchangeBytes(guidByte, 0, 3); + ExchangeBytes(guidByte, 1, 2); + ExchangeBytes(guidByte, 4, 5); + ExchangeBytes(guidByte, 6, 7); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void ExchangeBytes(in Span guid, int left, int right) + { + (guid[right], guid[left]) = (guid[left], guid[right]); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/UserFingerprintService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/UserFingerprintService.cs index 864346e5..a8a1f59e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/User/UserFingerprintService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/UserFingerprintService.cs @@ -74,7 +74,7 @@ internal sealed partial class UserFingerprintService : IUserFingerprintService SeedTime = $"{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}", ExtFields = JsonSerializer.Serialize(extendProperties), AppName = "bbs_cn", - BbsDeviceId = HoyolabOptions.DeviceId, + BbsDeviceId = HoyolabOptions.DeviceId36, DeviceFp = string.IsNullOrEmpty(user.Fingerprint) ? Core.Random.GetLowerHexString(13) : user.Fingerprint, }; diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/UserQRCodeDialog.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Dialog/UserQRCodeDialog.xaml.cs index a9f55887..dcbaa0fc 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Dialog/UserQRCodeDialog.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/UserQRCodeDialog.xaml.cs @@ -6,6 +6,7 @@ using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media; using Microsoft.UI.Xaml.Media.Imaging; using Snap.Hutao.Factory.QrCode; +using Snap.Hutao.Web.Hoyolab.Hk4e.Sdk.Combo; using Snap.Hutao.Web.Hoyolab.Passport; using Snap.Hutao.Web.Response; using System.Collections.Specialized; @@ -18,7 +19,7 @@ namespace Snap.Hutao.View.Dialog; internal sealed partial class UserQRCodeDialog : ContentDialog, IDisposable { private readonly ITaskContext taskContext; - private readonly PassportClient2 passportClient2; + private readonly PandaClient pandaClient; private readonly IQRCodeFactory qrCodeFactory; private readonly CancellationTokenSource userManualCancellationTokenSource = new(); @@ -29,7 +30,7 @@ internal sealed partial class UserQRCodeDialog : ContentDialog, IDisposable InitializeComponent(); taskContext = serviceProvider.GetRequiredService(); - passportClient2 = serviceProvider.GetRequiredService(); + pandaClient = serviceProvider.GetRequiredService(); qrCodeFactory = serviceProvider.GetRequiredService(); } @@ -100,7 +101,7 @@ internal sealed partial class UserQRCodeDialog : ContentDialog, IDisposable private async ValueTask FetchQRCodeAndSetImageAsync(CancellationToken token) { - Response fetchResponse = await passportClient2.QRCodeFetchAsync(token).ConfigureAwait(false); + Response fetchResponse = await pandaClient.QRCodeFetchAsync(token).ConfigureAwait(false); if (!fetchResponse.IsOk()) { return string.Empty; @@ -136,7 +137,7 @@ internal sealed partial class UserQRCodeDialog : ContentDialog, IDisposable { while (await timer.WaitForNextTickAsync(token).ConfigureAwait(false)) { - Response query = await passportClient2.QRCodeQueryAsync(ticket, token).ConfigureAwait(false); + Response query = await pandaClient.QRCodeQueryAsync(ticket, token).ConfigureAwait(false); if (query is { ReturnCode: 0, Data: { Stat: "Confirmed", Payload.Proto: "Account" } }) { diff --git a/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml b/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml index bff2ca0b..eb88a523 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml @@ -158,7 +158,7 @@ Width="{StaticResource LargeAppBarButtonWidth}" MaxWidth="{StaticResource LargeAppBarButtonWidth}" Margin="2,-4" - Command="{Binding LoginByQrCodeCommand}" + Command="{Binding LoginByQRCodeCommand}" Icon="{shcm:FontIcon Glyph={StaticResource FontIconContentQrCode}}" Label="{shcm:ResourceString Name=ViewUserCookieOperationLoginQRCodeAction}"/> ? users; @@ -177,26 +175,29 @@ internal sealed partial class UserViewModel : ObservableObject } } - [Command("LoginByQrCodeCommand")] - private async Task LoginByQrCode() + [Command("LoginByQRCodeCommand")] + private async Task LoginByQRCode() { - // ContentDialog must be created by main thread. - await taskContext.SwitchToMainThreadAsync(); - UserQRCodeDialog dialog = await contentDialogFactory.CreateInstanceAsync().ConfigureAwait(false); - ValueResult result = await dialog.GetUidGameTokenAsync().ConfigureAwait(false); + (bool isOk, UidGameToken? token) = await dialog.GetUidGameTokenAsync().ConfigureAwait(false); - if (result.TryGetValue(out UidGameToken account)) + if (!isOk) { - Response gameTokenResp = await sessionAppClient.PostSTokenByGameTokenAsync(account).ConfigureAwait(false); + return; + } - if (gameTokenResp.IsOk()) - { - Cookie stokenV2 = Cookie.FromLoginResult(gameTokenResp.Data); - (UserOptionResult optionResult, string uid) = await userService.ProcessInputCookieAsync(stokenV2, false).ConfigureAwait(false); + Response sTokenResponse = await serviceProvider + .GetRequiredService() + .GetSTokenByGameTokenAsync(token) + .ConfigureAwait(false); - await HandleUserOptionResultAsync(optionResult, uid).ConfigureAwait(false); - } + if (sTokenResponse.IsOk()) + { + Cookie stokenV2 = Cookie.FromLoginResult(sTokenResponse.Data); + + (UserOptionResult optionResult, string uid) = await userService.ProcessInputCookieAsync(stokenV2, false).ConfigureAwait(false); + + await HandleUserOptionResultAsync(optionResult, uid).ConfigureAwait(false); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSBridge.cs b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSBridge.cs index d9992754..3466901d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSBridge.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSBridge.cs @@ -233,7 +233,7 @@ internal class MiHoYoJSBridge // Skip x-rpc-lifecycle_id { "x-rpc-app_id", "bll8iq97cem8" }, { "x-rpc-client_type", "5" }, - { "x-rpc-device_id", HoyolabOptions.DeviceId }, + { "x-rpc-device_id", HoyolabOptions.DeviceId36 }, { "x-rpc-app_version", userAndUid.IsOversea ? SaltConstants.OSVersion : SaltConstants.CNVersion }, { "x-rpc-sdk_version", "2.16.0" }, }; diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultOptions.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Sdk/Combo/GameLoginRequest.cs similarity index 55% rename from src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultOptions.cs rename to src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Sdk/Combo/GameLoginRequest.cs index d5f17cd6..479d4218 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultOptions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Sdk/Combo/GameLoginRequest.cs @@ -1,13 +1,10 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -namespace Snap.Hutao.Web.Hoyolab.Passport; +namespace Snap.Hutao.Web.Hoyolab.Hk4e.Sdk.Combo; -/// -/// 扫码登录结果请求配置 -/// [HighQuality] -internal sealed class GameLoginResultOptions +internal sealed class GameLoginRequest { [JsonPropertyName("app_id")] public int AppId { get; set; } @@ -16,11 +13,11 @@ internal sealed class GameLoginResultOptions public string Device { get; set; } = default!; [JsonPropertyName("ticket")] - public string Ticket { get; set; } = default!; + public string? Ticket { get; set; } - public static GameLoginResultOptions Create(int appId, string device, string ticket) + public static GameLoginRequest Create(int appId, string device, string? ticket = null) { - return new GameLoginResultOptions + return new() { AppId = appId, Device = device, diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResult.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Sdk/Combo/GameLoginResult.cs similarity index 81% rename from src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResult.cs rename to src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Sdk/Combo/GameLoginResult.cs index bd52a99c..92e6456e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResult.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Sdk/Combo/GameLoginResult.cs @@ -1,9 +1,7 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Snap.Hutao.Web.Hoyolab.Hk4e.QrCode; - -namespace Snap.Hutao.Web.Hoyolab.Passport; +namespace Snap.Hutao.Web.Hoyolab.Hk4e.Sdk.Combo; /// /// 扫码登录结果 diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultPayload.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Sdk/Combo/GameLoginResultPayload.cs similarity index 79% rename from src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultPayload.cs rename to src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Sdk/Combo/GameLoginResultPayload.cs index 8d7cd653..80580331 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultPayload.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Sdk/Combo/GameLoginResultPayload.cs @@ -1,11 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -namespace Snap.Hutao.Web.Hoyolab.Hk4e.QrCode; +namespace Snap.Hutao.Web.Hoyolab.Hk4e.Sdk.Combo; -/// -/// 扫码登录结果Payload -/// [HighQuality] internal sealed partial class GameLoginResultPayload { diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Sdk/Combo/PandaClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Sdk/Combo/PandaClient.cs new file mode 100644 index 00000000..90ec1cfc --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Sdk/Combo/PandaClient.cs @@ -0,0 +1,49 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient; +using Snap.Hutao.Web.Request.Builder; +using Snap.Hutao.Web.Request.Builder.Abstraction; +using Snap.Hutao.Web.Response; +using System.Net.Http; + +namespace Snap.Hutao.Web.Hoyolab.Hk4e.Sdk.Combo; + +[ConstructorGenerated(ResolveHttpClient = true)] +[HttpClient(HttpClientConfiguration.XRpc2)] +internal sealed partial class PandaClient +{ + private readonly IHttpRequestMessageBuilderFactory httpRequestMessageBuilderFactory; + private readonly ILogger logger; + private readonly HttpClient httpClient; + + public async ValueTask> QRCodeFetchAsync(CancellationToken token = default) + { + GameLoginRequest options = GameLoginRequest.Create(4, HoyolabOptions.DeviceId40); + + HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() + .SetRequestUri(ApiEndpoints.QrCodeFetch) + .PostJson(options); + + Response? resp = await builder + .TryCatchSendAsync>(httpClient, logger, token) + .ConfigureAwait(false); + + return Response.Response.DefaultIfNull(resp); + } + + public async ValueTask> QRCodeQueryAsync(string ticket, CancellationToken token = default) + { + GameLoginRequest options = GameLoginRequest.Create(4, HoyolabOptions.DeviceId40, ticket); + + HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() + .SetRequestUri(ApiEndpoints.QrCodeQuery) + .PostJson(options); + + Response? resp = await builder + .TryCatchSendAsync>(httpClient, logger, token) + .ConfigureAwait(false); + + return Response.Response.DefaultIfNull(resp); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/UrlWrapper.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Sdk/Combo/UrlWrapper.cs similarity index 80% rename from src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/UrlWrapper.cs rename to src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Sdk/Combo/UrlWrapper.cs index bda18383..9a962e6a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/UrlWrapper.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Sdk/Combo/UrlWrapper.cs @@ -1,7 +1,7 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -namespace Snap.Hutao.Web.Hoyolab.Passport; +namespace Snap.Hutao.Web.Hoyolab.Hk4e.Sdk.Combo; internal sealed class UrlWrapper { diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HoyolabOptions.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HoyolabOptions.cs index 4610b2c9..ad3dff78 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HoyolabOptions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HoyolabOptions.cs @@ -1,16 +1,16 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Microsoft.Extensions.Options; using Snap.Hutao.Web.Hoyolab.DataSigning; using System.Collections.Frozen; +using System.Security.Cryptography; namespace Snap.Hutao.Web.Hoyolab; /// /// 米游社选项 /// -internal sealed class HoyolabOptions : IOptions +internal static class HoyolabOptions { /// /// 米游社请求UA @@ -35,12 +35,12 @@ internal sealed class HoyolabOptions : IOptions /// /// 米游社设备Id /// - public static string DeviceId { get; } = Guid.NewGuid().ToString(); + public static string DeviceId36 { get; } = Guid.NewGuid().ToString(); /// /// 扫码登录设备Id /// - public static string Device { get; } = Core.Random.GetLetterAndNumberString(64); + public static string DeviceId40 { get; } = GenerateDeviceId40(); /// /// 盐 @@ -61,6 +61,16 @@ internal sealed class HoyolabOptions : IOptions [SaltType.OSX6] = "okr4obncj8bw5a65hbnn5oo6ixjc3l9w", }.ToFrozenDictionary(); - /// - public HoyolabOptions Value { get => this; } + [SuppressMessage("", "CA1308")] + private static string GenerateDeviceId40() + { + Guid uuid = Core.Uuid.NewV5(DeviceId36, new("9450ea74-be9c-35c0-9568-f97407856768")); + + Span uuidSpan = stackalloc byte[16]; + Span hash = stackalloc byte[20]; + + Verify.Operation(uuid.TryWriteBytes(uuidSpan), "Failed to write UUID bytes"); + Verify.Operation(SHA1.TryHashData(uuidSpan, hash, out _), "Failed to write SHA1 hash"); + return Convert.ToHexString(hash).ToLowerInvariant(); + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Account/GameTokenWrapper.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/AccountIdGameToken.cs similarity index 62% rename from src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Account/GameTokenWrapper.cs rename to src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/AccountIdGameToken.cs index 1b62d7cb..0c76cc52 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Account/GameTokenWrapper.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/AccountIdGameToken.cs @@ -1,12 +1,12 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -namespace Snap.Hutao.Web.Hoyolab.Takumi.Account; +namespace Snap.Hutao.Web.Hoyolab.Passport; -internal sealed class GameTokenWrapper +internal sealed class AccountIdGameToken { [JsonPropertyName("account_id")] - public int Stuid { get; set; } = default!; + public int AccountId { get; set; } = default!; [JsonPropertyName("game_token")] public string GameToken { get; set; } = default!; diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginRequestOptions.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginRequestOptions.cs deleted file mode 100644 index fb3b77a4..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginRequestOptions.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -namespace Snap.Hutao.Web.Hoyolab.Passport; - -/// -/// 扫码登录请求配置 -/// -[HighQuality] -internal sealed class GameLoginRequestOptions -{ - [JsonPropertyName("app_id")] - public int AppId { get; set; } - - [JsonPropertyName("device")] - public string Device { get; set; } = default!; - - public static GameLoginRequestOptions Create(int appId, string device) - { - return new GameLoginRequestOptions - { - AppId = appId, - Device = device, - }; - } -} diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient2.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient2.cs index 8516723b..be1ad870 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient2.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient2.cs @@ -5,9 +5,11 @@ using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient; using Snap.Hutao.Model.Entity; using Snap.Hutao.Web.Hoyolab.Annotation; using Snap.Hutao.Web.Hoyolab.DataSigning; +using Snap.Hutao.Web.Hoyolab.Hk4e.Sdk.Combo; using Snap.Hutao.Web.Request.Builder; using Snap.Hutao.Web.Request.Builder.Abstraction; using Snap.Hutao.Web.Response; +using System.Globalization; using System.Net.Http; namespace Snap.Hutao.Web.Hoyolab.Passport; @@ -68,42 +70,20 @@ internal sealed partial class PassportClient2 return Response.Response.DefaultIfNull(resp); } - /// - /// 异步获取扫码链接 - /// - /// 取消令牌 - /// 二维码原始链接 - public async ValueTask> QRCodeFetchAsync(CancellationToken token = default) + public async ValueTask> GetSTokenByGameTokenAsync(UidGameToken account, CancellationToken token = default) { - GameLoginRequestOptions options = GameLoginRequestOptions.Create(4, HoyolabOptions.Device); + AccountIdGameToken data = new() + { + AccountId = int.Parse(account.Uid, CultureInfo.InvariantCulture), + GameToken = account.GameToken, + }; HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() - .SetRequestUri(ApiEndpoints.QrCodeFetch) - .PostJson(options); + .SetRequestUri(ApiEndpoints.AccountGetSTokenByGameToken) + .PostJson(data); - Response? resp = await builder - .TryCatchSendAsync>(httpClient, logger, token) - .ConfigureAwait(false); - - return Response.Response.DefaultIfNull(resp); - } - - /// - /// 异步获取扫码状态 - /// - /// 扫码链接中的ticket - /// 取消令牌 - /// 扫码结果 - public async ValueTask> QRCodeQueryAsync(string ticket, CancellationToken token = default) - { - GameLoginResultOptions options = GameLoginResultOptions.Create(4, HoyolabOptions.Device, ticket); - - HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() - .SetRequestUri(ApiEndpoints.QrCodeQuery) - .PostJson(options); - - Response? resp = await builder - .TryCatchSendAsync>(httpClient, logger, token) + Response? resp = await builder + .TryCatchSendAsync>(httpClient, logger, token) .ConfigureAwait(false); return Response.Response.DefaultIfNull(resp); diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Account/SessionAppClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Account/SessionAppClient.cs deleted file mode 100644 index 57f1c63d..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Account/SessionAppClient.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient; -using Snap.Hutao.Web.Hoyolab.Passport; -using Snap.Hutao.Web.Request.Builder; -using Snap.Hutao.Web.Request.Builder.Abstraction; -using Snap.Hutao.Web.Response; -using System.Globalization; -using System.Net.Http; - -namespace Snap.Hutao.Web.Hoyolab.Takumi.Account; - -[HighQuality] -[ConstructorGenerated(ResolveHttpClient = true)] -[HttpClient(HttpClientConfiguration.XRpc2)] -internal sealed partial class SessionAppClient -{ - private readonly IHttpRequestMessageBuilderFactory httpRequestMessageBuilderFactory; - private readonly ILogger logger; - private readonly HttpClient httpClient; - - /// - /// 通过 GameToken 获取 SToken (V2) - /// - /// 扫码获得的账户信息 - /// 取消令牌 - /// 登录结果 - public async ValueTask> PostSTokenByGameTokenAsync(UidGameToken account, CancellationToken token = default) - { - GameTokenWrapper wrapper = new() - { - Stuid = int.Parse(account.Uid, CultureInfo.CurrentCulture), - GameToken = account.GameToken, - }; - - HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create() - .SetRequestUri(ApiEndpoints.AccountGetSTokenByGameToken) - .PostJson(wrapper); - - Response? resp = await builder - .TryCatchSendAsync>(httpClient, logger, token) - .ConfigureAwait(false); - - return Response.Response.DefaultIfNull(resp); - } -}