From 0be84a25853edde65a1470be535bb3c12122ac09 Mon Sep 17 00:00:00 2001 From: DismissedLight <1686188646@qq.com> Date: Mon, 14 Nov 2022 16:37:17 +0800 Subject: [PATCH] support PROD salt for #207 --- .../Snap.Hutao/Core/Convert/Md5Convert.cs | 5 ++ .../Snap.Hutao/Core/CoreEnvironment.cs | 28 +------ .../Snap.Hutao/Web/Hoyolab/ApiEndpoints.cs | 35 ++++++++- .../Web/Hoyolab/App/Account/AccountClient.cs | 77 +++++++++++++++++++ .../Web/Hoyolab/App/Account/LtokenWrapper.cs | 26 +++++++ .../Web/Hoyolab/Passport/PassportClient.cs | 2 +- ...ountInfo.cs => ActionTicketAccountInfo.cs} | 2 +- .../Takumi/Auth/ActionTicketWrapper.cs | 2 +- .../Hoyolab/Takumi/Binding/BindingClient.cs | 17 ++++ .../Hoyolab/Takumi/Binding/BindingClient2.cs | 6 +- .../Hoyolab/Takumi/Binding/GenAuthKeyData.cs | 2 + .../Web/Response/KnownReturnCode.cs | 5 ++ 12 files changed, 173 insertions(+), 34 deletions(-) create mode 100644 src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/Account/AccountClient.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/Account/LtokenWrapper.cs rename src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/{AccountInfo.cs => ActionTicketAccountInfo.cs} (98%) diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Convert/Md5Convert.cs b/src/Snap.Hutao/Snap.Hutao/Core/Convert/Md5Convert.cs index f52ee927..001b5802 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Convert/Md5Convert.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Convert/Md5Convert.cs @@ -22,3 +22,8 @@ internal abstract class Md5Convert return System.Convert.ToHexString(hash); } } + +internal class RSAConvert +{ + +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/CoreEnvironment.cs b/src/Snap.Hutao/Snap.Hutao/Core/CoreEnvironment.cs index 6f4ed18c..da63244c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/CoreEnvironment.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/CoreEnvironment.cs @@ -16,33 +16,6 @@ namespace Snap.Hutao.Core; /// internal static class CoreEnvironment { - // 计算过程:https://github.com/UIGF-org/Hoyolab.Salt - - /// - /// 动态密钥1的K2盐 - /// - public const string DynamicSecretK2Salt = "fdv0fY9My9eA7MR0NpjGP9RjueFvjUSQ"; - - /// - /// 动态密钥1的LK2盐 - /// - public const string DynamicSecretLK2Salt = "jEpJb9rRARU2rXDA9qYbZ3selxkuct9a"; - - /// - /// 动态密钥2的X4盐 - /// - public const string DynamicSecretX4Salt = "xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs"; - - /// - /// 动态密钥2的X6盐 - /// - public const string DynamicSecretX6Salt = "t0qEgfub6cvueAPgR5m9aQWWVciEer7v"; - - /// - /// LoginApi的盐 - /// - public const string DynamicSecretPRODSalt = "JwYDpKvLj6MrMqqYU6jTKF17KNO2PXoS"; - /// /// 米游社请求UA /// @@ -55,6 +28,7 @@ internal static class CoreEnvironment /// /// 动态密钥 + /// https://github.com/UIGF-org/Hoyolab.Salt /// public static readonly ImmutableDictionary DynamicSecrets = new Dictionary() { diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/ApiEndpoints.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/ApiEndpoints.cs index d4aba5ca..a39a503c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/ApiEndpoints.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/ApiEndpoints.cs @@ -129,10 +129,15 @@ internal static class ApiEndpoints /// public const string UserGameRolesByCookie = $"{ApiTaKumiBindingApi}/getUserGameRolesByCookie?game_biz=hk4e_cn"; + /// + /// 用户游戏角色 + /// + public const string UserGameRolesByStoken = $"{ApiTaKumiBindingApi}/getUserGameRolesByStoken"; + /// /// AuthKey /// - public const string GenAuthKey = $"{ApiTaKumiBindingApi}/genAuthKey"; + public const string BindingGenAuthKey = $"{ApiTaKumiBindingApi}/genAuthKey"; #endregion #region Auth @@ -179,7 +184,7 @@ internal static class ApiEndpoints // https://sdk-static.mihoyo.com/hk4e_cn/mdk/launcher/api/content?key=eYd89JmJ&language=zh-cn&launcher_id=18 #endregion - #region ma-cn-session + #region LoginApi /// /// 获取 CookieToken @@ -192,8 +197,30 @@ internal static class ApiEndpoints public const string AccountVerifyLtoken = $"{PassportApiV4}/account/ma-cn-session/web/verifyLtoken"; #endregion + #region WebAccountApi + + /// + /// 通过通行证Cookie登录 + /// + /// 通行证Cookie登录 + public static string AccountLoginByCookie() + { + return $"{WebApiAccountApi}/login_by_cookie?t={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}"; + } + #endregion + #region App + /// + /// 另一个AuthKey + /// + public const string AppAccountGenAuthKey = $"{AppAuthApi}/genAuthKey"; + + /// + /// 通过 Stoken 获取 Ltoken + /// + public const string AppAccountGetLTokenBySToken = $"{AppAuthApi}/getLTokenBySToken"; + /// /// 小组件数据 /// @@ -209,6 +236,7 @@ internal static class ApiEndpoints private const string ApiTakumiRecordApi = $"{ApiTakumiRecord}/game_record/app/genshin/api"; private const string App = "https://app.mihoyo.com"; + private const string AppAuthApi = $"{App}/account/auth/api"; private const string AppCardApi = $"{App}/game_record/app/card/api"; private const string BbsApi = "https://bbs-api.mihoyo.com"; @@ -224,5 +252,8 @@ internal static class ApiEndpoints private const string SdkStatic = "https://sdk-static.mihoyo.com"; private const string SdkStaticLauncherApi = $"{SdkStatic}/hk4e_cn/mdk/launcher/api"; + private const string WebApiAccount = "https://webapi.account.mihoyo.com"; + private const string WebApiAccountApi = $"{WebApiAccount}/Api"; + private const string AnnouncementQuery = "game=hk4e&game_biz=hk4e_cn&lang=zh-cn&bundle_id=hk4e_cn&platform=pc®ion=cn_gf01&level=55&uid=100000000"; } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/Account/AccountClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/Account/AccountClient.cs new file mode 100644 index 00000000..cada6339 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/Account/AccountClient.cs @@ -0,0 +1,77 @@ +using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient; +using Snap.Hutao.Model.Entity; +using Snap.Hutao.Web.Hoyolab.Annotation; +using Snap.Hutao.Web.Hoyolab.DynamicSecret; +using Snap.Hutao.Web.Hoyolab.Takumi.Binding; +using Snap.Hutao.Web.Response; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace Snap.Hutao.Web.Hoyolab.App.Account; + +/// +/// 账户客户端 +/// +[HttpClient(HttpClientConfigration.XRpc)] +internal class AccountClient +{ + private readonly HttpClient httpClient; + private readonly JsonSerializerOptions options; + private readonly ILogger logger; + + /// + /// 构造一个新的账户客户端 + /// + /// http客户端 + /// 选项 + /// 日志器 + public AccountClient(HttpClient httpClient, JsonSerializerOptions options, ILogger logger) + { + this.httpClient = httpClient; + this.options = options; + this.logger = logger; + } + + /// + /// 异步生成祈愿验证密钥 + /// 需要stoken + /// + /// 用户 + /// 提交数据 + /// 取消令牌 + /// 用户角色信息 + [ApiInformation(Cookie = CookieType.Stoken, Salt = SaltType.K2)] + public async Task GenerateAuthenticationKeyAsync(User user, GenAuthKeyData data, CancellationToken token = default) + { + Response? resp = await httpClient + .SetUser(user, CookieType.Stoken) + .SetReferer("https://app.mihoyo.com") + .UsingDynamicSecret1(SaltType.K2) + .TryCatchPostAsJsonAsync>(ApiEndpoints.AppAccountGenAuthKey, data, options, logger, token) + .ConfigureAwait(false); + + return resp?.Data; + } + + /// + /// 异步获取 Ltoken + /// + /// 用户 + /// 取消令牌 + /// Ltoken + [ApiInformation(Cookie = CookieType.Stoken, Salt = SaltType.PROD)] + public async Task GetLTokenBySTokenAsync(User user, CancellationToken token) + { + Response? resp = await httpClient + .SetUser(user, CookieType.Stoken) + .UsingDynamicSecret2(SaltType.PROD, options, ApiEndpoints.AppAccountGetLTokenBySToken) + .TryCatchGetFromJsonAsync>(token) + .ConfigureAwait(false); + + return resp?.Data?.Ltoken; + } +} diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/Account/LtokenWrapper.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/Account/LtokenWrapper.cs new file mode 100644 index 00000000..7706f37f --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/Account/LtokenWrapper.cs @@ -0,0 +1,26 @@ +using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient; +using Snap.Hutao.Model.Entity; +using Snap.Hutao.Web.Hoyolab.Annotation; +using Snap.Hutao.Web.Hoyolab.DynamicSecret; +using Snap.Hutao.Web.Hoyolab.Takumi.Binding; +using Snap.Hutao.Web.Response; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace Snap.Hutao.Web.Hoyolab.App.Account; + +/// +/// Ltoken 包装器 +/// +public class LtokenWrapper +{ + /// + /// Ltoken + /// + [JsonPropertyName("ltoken")] + public string Ltoken { get; set; } = default!; +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient.cs index e0930f32..bdfc225d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient.cs @@ -39,7 +39,7 @@ internal class PassportClient /// 用户 /// 取消令牌 /// 验证信息 - [ApiInformation(Cookie = CookieType.Ltoken)] + [ApiInformation(Cookie = CookieType.All)] public async Task VerifyLtokenAsync(User user, CancellationToken token) { Response? response = await httpClient diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/AccountInfo.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/ActionTicketAccountInfo.cs similarity index 98% rename from src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/AccountInfo.cs rename to src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/ActionTicketAccountInfo.cs index 44757483..e76f8940 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/AccountInfo.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/ActionTicketAccountInfo.cs @@ -12,7 +12,7 @@ namespace Snap.Hutao.Web.Hoyolab.Takumi.Auth; /// 账户信息 /// [SuppressMessage("", "SA1600")] -public class AccountInfo +public class ActionTicketAccountInfo { [JsonPropertyName("is_realname")] public bool IsRealname { get; set; } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/ActionTicketWrapper.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/ActionTicketWrapper.cs index 5492510e..9ac5e9b6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/ActionTicketWrapper.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/ActionTicketWrapper.cs @@ -29,5 +29,5 @@ public class ActionTicketWrapper /// 账户信息 /// [JsonPropertyName("account_info")] - public AccountInfo AccountInfo { get; set; } = default!; + public ActionTicketAccountInfo AccountInfo { get; set; } = default!; } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient.cs index 10fb4a13..b526b3c0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient.cs @@ -69,4 +69,21 @@ internal class BindingClient return EnumerableExtension.EmptyIfNull(resp?.Data?.List); } + + /// + /// 获取用户角色信息 + /// + /// 用户 + /// 取消令牌 + /// 用户角色信息 + [ApiInformation(Cookie = CookieType.Stoken)] + public async Task> GetUserGameRolesByStokenAsync(User user, CancellationToken token = default) + { + Response>? resp = await httpClient + .SetUser(user, CookieType.Stoken) + .TryCatchGetFromJsonAsync>>(ApiEndpoints.UserGameRolesByStoken, options, logger, token) + .ConfigureAwait(false); + + return EnumerableExtension.EmptyIfNull(resp?.Data?.List); + } } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient2.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient2.cs index 3d81b1a5..4852d08c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient2.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient2.cs @@ -3,6 +3,7 @@ using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient; using Snap.Hutao.Model.Entity; +using Snap.Hutao.Web.Hoyolab.Annotation; using Snap.Hutao.Web.Hoyolab.DynamicSecret; using Snap.Hutao.Web.Response; using System.Net.Http; @@ -40,13 +41,14 @@ internal class BindingClient2 /// 提交数据 /// 取消令牌 /// 用户角色信息 + [ApiInformation(Cookie = CookieType.Stoken, Salt = SaltType.K2)] public async Task GenerateAuthenticationKeyAsync(User user, GenAuthKeyData data, CancellationToken token = default) { Response? resp = await httpClient .SetUser(user, CookieType.Stoken) .SetReferer("https://app.mihoyo.com") - .UsingDynamicSecret1(SaltType.LK2) - .TryCatchPostAsJsonAsync>(ApiEndpoints.GenAuthKey, data, options, logger, token) + .UsingDynamicSecret1(SaltType.K2) + .TryCatchPostAsJsonAsync>(ApiEndpoints.BindingGenAuthKey, data, options, logger, token) .ConfigureAwait(false); return resp?.Data; diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/GenAuthKeyData.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/GenAuthKeyData.cs index 4de9c2ef..9f7f42c1 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/GenAuthKeyData.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/GenAuthKeyData.cs @@ -5,6 +5,8 @@ namespace Snap.Hutao.Web.Hoyolab.Takumi.Binding; /// /// 验证密钥提交数据 +/// im_css? +/// {"auth_appid":"im_ccs","game_biz":"bbs_cn","game_uid":0,"region":""} /// public sealed class GenAuthKeyData { diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Response/KnownReturnCode.cs b/src/Snap.Hutao/Snap.Hutao/Web/Response/KnownReturnCode.cs index 3e72c6ed..d8fa9116 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Response/KnownReturnCode.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Response/KnownReturnCode.cs @@ -43,6 +43,11 @@ public enum KnownReturnCode : int /// RET_NEED_AIGIS = -3101, + /// + /// 登录信息已失效,请重新登录 + /// + LoginDataOutdated = -262, + /// /// 访问过于频繁 ///