support PROD salt for #207

This commit is contained in:
DismissedLight
2022-11-14 16:37:17 +08:00
parent e29e12c9fe
commit 0be84a2585
12 changed files with 173 additions and 34 deletions

View File

@@ -22,3 +22,8 @@ internal abstract class Md5Convert
return System.Convert.ToHexString(hash);
}
}
internal class RSAConvert
{
}

View File

@@ -16,33 +16,6 @@ namespace Snap.Hutao.Core;
/// </summary>
internal static class CoreEnvironment
{
// 计算过程https://github.com/UIGF-org/Hoyolab.Salt
/// <summary>
/// 动态密钥1的K2盐
/// </summary>
public const string DynamicSecretK2Salt = "fdv0fY9My9eA7MR0NpjGP9RjueFvjUSQ";
/// <summary>
/// 动态密钥1的LK2盐
/// </summary>
public const string DynamicSecretLK2Salt = "jEpJb9rRARU2rXDA9qYbZ3selxkuct9a";
/// <summary>
/// 动态密钥2的X4盐
/// </summary>
public const string DynamicSecretX4Salt = "xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs";
/// <summary>
/// 动态密钥2的X6盐
/// </summary>
public const string DynamicSecretX6Salt = "t0qEgfub6cvueAPgR5m9aQWWVciEer7v";
/// <summary>
/// LoginApi的盐
/// </summary>
public const string DynamicSecretPRODSalt = "JwYDpKvLj6MrMqqYU6jTKF17KNO2PXoS";
/// <summary>
/// 米游社请求UA
/// </summary>
@@ -55,6 +28,7 @@ internal static class CoreEnvironment
/// <summary>
/// 动态密钥
/// https://github.com/UIGF-org/Hoyolab.Salt
/// </summary>
public static readonly ImmutableDictionary<SaltType, string> DynamicSecrets = new Dictionary<SaltType, string>()
{

View File

@@ -129,10 +129,15 @@ internal static class ApiEndpoints
/// </summary>
public const string UserGameRolesByCookie = $"{ApiTaKumiBindingApi}/getUserGameRolesByCookie?game_biz=hk4e_cn";
/// <summary>
/// 用户游戏角色
/// </summary>
public const string UserGameRolesByStoken = $"{ApiTaKumiBindingApi}/getUserGameRolesByStoken";
/// <summary>
/// AuthKey
/// </summary>
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
/// <summary>
/// 获取 CookieToken
@@ -192,8 +197,30 @@ internal static class ApiEndpoints
public const string AccountVerifyLtoken = $"{PassportApiV4}/account/ma-cn-session/web/verifyLtoken";
#endregion
#region WebAccountApi
/// <summary>
/// 通过通行证Cookie登录
/// </summary>
/// <returns>通行证Cookie登录</returns>
public static string AccountLoginByCookie()
{
return $"{WebApiAccountApi}/login_by_cookie?t={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}";
}
#endregion
#region App
/// <summary>
/// 另一个AuthKey
/// </summary>
public const string AppAccountGenAuthKey = $"{AppAuthApi}/genAuthKey";
/// <summary>
/// 通过 Stoken 获取 Ltoken
/// </summary>
public const string AppAccountGetLTokenBySToken = $"{AppAuthApi}/getLTokenBySToken";
/// <summary>
/// 小组件数据
/// </summary>
@@ -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&region=cn_gf01&level=55&uid=100000000";
}

View File

@@ -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;
/// <summary>
/// 账户客户端
/// </summary>
[HttpClient(HttpClientConfigration.XRpc)]
internal class AccountClient
{
private readonly HttpClient httpClient;
private readonly JsonSerializerOptions options;
private readonly ILogger<AccountClient> logger;
/// <summary>
/// 构造一个新的账户客户端
/// </summary>
/// <param name="httpClient">http客户端</param>
/// <param name="options">选项</param>
/// <param name="logger">日志器</param>
public AccountClient(HttpClient httpClient, JsonSerializerOptions options, ILogger<AccountClient> logger)
{
this.httpClient = httpClient;
this.options = options;
this.logger = logger;
}
/// <summary>
/// 异步生成祈愿验证密钥
/// 需要stoken
/// </summary>
/// <param name="user">用户</param>
/// <param name="data">提交数据</param>
/// <param name="token">取消令牌</param>
/// <returns>用户角色信息</returns>
[ApiInformation(Cookie = CookieType.Stoken, Salt = SaltType.K2)]
public async Task<GameAuthKey?> GenerateAuthenticationKeyAsync(User user, GenAuthKeyData data, CancellationToken token = default)
{
Response<GameAuthKey>? resp = await httpClient
.SetUser(user, CookieType.Stoken)
.SetReferer("https://app.mihoyo.com")
.UsingDynamicSecret1(SaltType.K2)
.TryCatchPostAsJsonAsync<GenAuthKeyData, Response<GameAuthKey>>(ApiEndpoints.AppAccountGenAuthKey, data, options, logger, token)
.ConfigureAwait(false);
return resp?.Data;
}
/// <summary>
/// 异步获取 Ltoken
/// </summary>
/// <param name="user">用户</param>
/// <param name="token">取消令牌</param>
/// <returns>Ltoken</returns>
[ApiInformation(Cookie = CookieType.Stoken, Salt = SaltType.PROD)]
public async Task<string?> GetLTokenBySTokenAsync(User user, CancellationToken token)
{
Response<LtokenWrapper>? resp = await httpClient
.SetUser(user, CookieType.Stoken)
.UsingDynamicSecret2(SaltType.PROD, options, ApiEndpoints.AppAccountGetLTokenBySToken)
.TryCatchGetFromJsonAsync<Response<LtokenWrapper>>(token)
.ConfigureAwait(false);
return resp?.Data?.Ltoken;
}
}

View File

@@ -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;
/// <summary>
/// Ltoken 包装器
/// </summary>
public class LtokenWrapper
{
/// <summary>
/// Ltoken
/// </summary>
[JsonPropertyName("ltoken")]
public string Ltoken { get; set; } = default!;
}

View File

@@ -39,7 +39,7 @@ internal class PassportClient
/// <param name="user">用户</param>
/// <param name="token">取消令牌</param>
/// <returns>验证信息</returns>
[ApiInformation(Cookie = CookieType.Ltoken)]
[ApiInformation(Cookie = CookieType.All)]
public async Task<VerifyInformation?> VerifyLtokenAsync(User user, CancellationToken token)
{
Response<VerifyInformation>? response = await httpClient

View File

@@ -12,7 +12,7 @@ namespace Snap.Hutao.Web.Hoyolab.Takumi.Auth;
/// 账户信息
/// </summary>
[SuppressMessage("", "SA1600")]
public class AccountInfo
public class ActionTicketAccountInfo
{
[JsonPropertyName("is_realname")]
public bool IsRealname { get; set; }

View File

@@ -29,5 +29,5 @@ public class ActionTicketWrapper
/// 账户信息
/// </summary>
[JsonPropertyName("account_info")]
public AccountInfo AccountInfo { get; set; } = default!;
public ActionTicketAccountInfo AccountInfo { get; set; } = default!;
}

View File

@@ -69,4 +69,21 @@ internal class BindingClient
return EnumerableExtension.EmptyIfNull(resp?.Data?.List);
}
/// <summary>
/// 获取用户角色信息
/// </summary>
/// <param name="user">用户</param>
/// <param name="token">取消令牌</param>
/// <returns>用户角色信息</returns>
[ApiInformation(Cookie = CookieType.Stoken)]
public async Task<List<UserGameRole>> GetUserGameRolesByStokenAsync(User user, CancellationToken token = default)
{
Response<ListWrapper<UserGameRole>>? resp = await httpClient
.SetUser(user, CookieType.Stoken)
.TryCatchGetFromJsonAsync<Response<ListWrapper<UserGameRole>>>(ApiEndpoints.UserGameRolesByStoken, options, logger, token)
.ConfigureAwait(false);
return EnumerableExtension.EmptyIfNull(resp?.Data?.List);
}
}

View File

@@ -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
/// <param name="data">提交数据</param>
/// <param name="token">取消令牌</param>
/// <returns>用户角色信息</returns>
[ApiInformation(Cookie = CookieType.Stoken, Salt = SaltType.K2)]
public async Task<GameAuthKey?> GenerateAuthenticationKeyAsync(User user, GenAuthKeyData data, CancellationToken token = default)
{
Response<GameAuthKey>? resp = await httpClient
.SetUser(user, CookieType.Stoken)
.SetReferer("https://app.mihoyo.com")
.UsingDynamicSecret1(SaltType.LK2)
.TryCatchPostAsJsonAsync<GenAuthKeyData, Response<GameAuthKey>>(ApiEndpoints.GenAuthKey, data, options, logger, token)
.UsingDynamicSecret1(SaltType.K2)
.TryCatchPostAsJsonAsync<GenAuthKeyData, Response<GameAuthKey>>(ApiEndpoints.BindingGenAuthKey, data, options, logger, token)
.ConfigureAwait(false);
return resp?.Data;

View File

@@ -5,6 +5,8 @@ namespace Snap.Hutao.Web.Hoyolab.Takumi.Binding;
/// <summary>
/// 验证密钥提交数据
/// im_css?
/// {"auth_appid":"im_ccs","game_biz":"bbs_cn","game_uid":0,"region":""}
/// </summary>
public sealed class GenAuthKeyData
{

View File

@@ -43,6 +43,11 @@ public enum KnownReturnCode : int
/// </summary>
RET_NEED_AIGIS = -3101,
/// <summary>
/// 登录信息已失效,请重新登录
/// </summary>
LoginDataOutdated = -262,
/// <summary>
/// 访问过于频繁
/// </summary>