diff --git a/src/Snap.Hutao/.editorconfig b/src/Snap.Hutao/.editorconfig
index fe0e366b11..a5fa13df09 100644
--- a/src/Snap.Hutao/.editorconfig
+++ b/src/Snap.Hutao/.editorconfig
@@ -102,8 +102,8 @@ dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
-dotnet_diagnostic.SA1629.severity = silent
-dotnet_diagnostic.SA1642.severity = silent
+dotnet_diagnostic.SA1629.severity = none
+dotnet_diagnostic.SA1642.severity = none
dotnet_diagnostic.IDE0060.severity = none
diff --git a/src/Snap.Hutao/SettingsUI/SettingsUI.csproj b/src/Snap.Hutao/SettingsUI/SettingsUI.csproj
index 630184f023..680dff53b0 100644
--- a/src/Snap.Hutao/SettingsUI/SettingsUI.csproj
+++ b/src/Snap.Hutao/SettingsUI/SettingsUI.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/CoreEnvironment.cs b/src/Snap.Hutao/Snap.Hutao/Core/CoreEnvironment.cs
index 1de5db2e8e..de168e725f 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/CoreEnvironment.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/CoreEnvironment.cs
@@ -5,11 +5,7 @@
using Snap.Hutao.Core.Convert;
using Snap.Hutao.Core.Json;
using Snap.Hutao.Extension;
-using Snap.Hutao.Web.Hoyolab.DynamicSecret;
-using System.Collections.Immutable;
-using System.Text.Encodings.Web;
using System.Text.Json.Serialization.Metadata;
-using System.Text.Unicode;
using Windows.ApplicationModel;
namespace Snap.Hutao.Core;
diff --git a/src/Snap.Hutao/Snap.Hutao/Migrations/20221118095755_SplitStoken.Designer.cs b/src/Snap.Hutao/Snap.Hutao/Migrations/20221118095755_SplitStoken.Designer.cs
new file mode 100644
index 0000000000..d4edeb9e79
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Migrations/20221118095755_SplitStoken.Designer.cs
@@ -0,0 +1,286 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Snap.Hutao.Context.Database;
+
+#nullable disable
+
+namespace Snap.Hutao.Migrations
+{
+ [DbContext(typeof(AppDbContext))]
+ [Migration("20221118095755_SplitStoken")]
+ partial class SplitStoken
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder.HasAnnotation("ProductVersion", "7.0.0");
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
+ {
+ b.Property("InnerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("ArchiveId")
+ .HasColumnType("TEXT");
+
+ b.Property("Current")
+ .HasColumnType("INTEGER");
+
+ b.Property("Id")
+ .HasColumnType("INTEGER");
+
+ b.Property("Status")
+ .HasColumnType("INTEGER");
+
+ b.Property("Time")
+ .HasColumnType("TEXT");
+
+ b.HasKey("InnerId");
+
+ b.HasIndex("ArchiveId");
+
+ b.ToTable("achievements");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.AchievementArchive", b =>
+ {
+ b.Property("InnerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("IsSelected")
+ .HasColumnType("INTEGER");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("InnerId");
+
+ b.ToTable("achievement_archives");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.AvatarInfo", b =>
+ {
+ b.Property("InnerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("Info")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Uid")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("InnerId");
+
+ b.ToTable("avatar_infos");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
+ {
+ b.Property("InnerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("DailyNote")
+ .HasColumnType("TEXT");
+
+ b.Property("DailyTaskNotify")
+ .HasColumnType("INTEGER");
+
+ b.Property("DailyTaskNotifySuppressed")
+ .HasColumnType("INTEGER");
+
+ b.Property("ExpeditionNotify")
+ .HasColumnType("INTEGER");
+
+ b.Property("ExpeditionNotifySuppressed")
+ .HasColumnType("INTEGER");
+
+ b.Property("HomeCoinNotifySuppressed")
+ .HasColumnType("INTEGER");
+
+ b.Property("HomeCoinNotifyThreshold")
+ .HasColumnType("INTEGER");
+
+ b.Property("ResinNotifySuppressed")
+ .HasColumnType("INTEGER");
+
+ b.Property("ResinNotifyThreshold")
+ .HasColumnType("INTEGER");
+
+ b.Property("ShowInHomeWidget")
+ .HasColumnType("INTEGER");
+
+ b.Property("TransformerNotify")
+ .HasColumnType("INTEGER");
+
+ b.Property("TransformerNotifySuppressed")
+ .HasColumnType("INTEGER");
+
+ b.Property("Uid")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("UserId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("InnerId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("daily_notes");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b =>
+ {
+ b.Property("InnerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("IsSelected")
+ .HasColumnType("INTEGER");
+
+ b.Property("Uid")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("InnerId");
+
+ b.ToTable("gacha_archives");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
+ {
+ b.Property("InnerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("ArchiveId")
+ .HasColumnType("TEXT");
+
+ b.Property("GachaType")
+ .HasColumnType("INTEGER");
+
+ b.Property("Id")
+ .HasColumnType("INTEGER");
+
+ b.Property("ItemId")
+ .HasColumnType("INTEGER");
+
+ b.Property("QueryType")
+ .HasColumnType("INTEGER");
+
+ b.Property("Time")
+ .HasColumnType("TEXT");
+
+ b.HasKey("InnerId");
+
+ b.HasIndex("ArchiveId");
+
+ b.ToTable("gacha_items");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.GameAccount", b =>
+ {
+ b.Property("InnerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("AttachUid")
+ .HasColumnType("TEXT");
+
+ b.Property("MihoyoSDK")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Type")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("InnerId");
+
+ b.ToTable("game_accounts");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.SettingEntry", b =>
+ {
+ b.Property("Key")
+ .HasColumnType("TEXT");
+
+ b.Property("Value")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Key");
+
+ b.ToTable("settings");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.User", b =>
+ {
+ b.Property("InnerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("Cookie")
+ .HasColumnType("TEXT");
+
+ b.Property("IsSelected")
+ .HasColumnType("INTEGER");
+
+ b.Property("Stoken")
+ .HasColumnType("TEXT");
+
+ b.HasKey("InnerId");
+
+ b.ToTable("users");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
+ {
+ b.HasOne("Snap.Hutao.Model.Entity.AchievementArchive", "Archive")
+ .WithMany()
+ .HasForeignKey("ArchiveId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Archive");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
+ {
+ b.HasOne("Snap.Hutao.Model.Entity.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
+ {
+ b.HasOne("Snap.Hutao.Model.Entity.GachaArchive", "Archive")
+ .WithMany()
+ .HasForeignKey("ArchiveId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Archive");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/Migrations/20221118095755_SplitStoken.cs b/src/Snap.Hutao/Snap.Hutao/Migrations/20221118095755_SplitStoken.cs
new file mode 100644
index 0000000000..5b9dfb99d7
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Migrations/20221118095755_SplitStoken.cs
@@ -0,0 +1,29 @@
+//
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Snap.Hutao.Migrations
+{
+ ///
+ public partial class SplitStoken : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "Stoken",
+ table: "users",
+ type: "TEXT",
+ nullable: true);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "Stoken",
+ table: "users");
+ }
+ }
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/Migrations/20221118124745_AddAidMid.Designer.cs b/src/Snap.Hutao/Snap.Hutao/Migrations/20221118124745_AddAidMid.Designer.cs
new file mode 100644
index 0000000000..706b58d816
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Migrations/20221118124745_AddAidMid.Designer.cs
@@ -0,0 +1,292 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Snap.Hutao.Context.Database;
+
+#nullable disable
+
+namespace Snap.Hutao.Migrations
+{
+ [DbContext(typeof(AppDbContext))]
+ [Migration("20221118124745_AddAidMid")]
+ partial class AddAidMid
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder.HasAnnotation("ProductVersion", "7.0.0");
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
+ {
+ b.Property("InnerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("ArchiveId")
+ .HasColumnType("TEXT");
+
+ b.Property("Current")
+ .HasColumnType("INTEGER");
+
+ b.Property("Id")
+ .HasColumnType("INTEGER");
+
+ b.Property("Status")
+ .HasColumnType("INTEGER");
+
+ b.Property("Time")
+ .HasColumnType("TEXT");
+
+ b.HasKey("InnerId");
+
+ b.HasIndex("ArchiveId");
+
+ b.ToTable("achievements");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.AchievementArchive", b =>
+ {
+ b.Property("InnerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("IsSelected")
+ .HasColumnType("INTEGER");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("InnerId");
+
+ b.ToTable("achievement_archives");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.AvatarInfo", b =>
+ {
+ b.Property("InnerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("Info")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Uid")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("InnerId");
+
+ b.ToTable("avatar_infos");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
+ {
+ b.Property("InnerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("DailyNote")
+ .HasColumnType("TEXT");
+
+ b.Property("DailyTaskNotify")
+ .HasColumnType("INTEGER");
+
+ b.Property("DailyTaskNotifySuppressed")
+ .HasColumnType("INTEGER");
+
+ b.Property("ExpeditionNotify")
+ .HasColumnType("INTEGER");
+
+ b.Property("ExpeditionNotifySuppressed")
+ .HasColumnType("INTEGER");
+
+ b.Property("HomeCoinNotifySuppressed")
+ .HasColumnType("INTEGER");
+
+ b.Property("HomeCoinNotifyThreshold")
+ .HasColumnType("INTEGER");
+
+ b.Property("ResinNotifySuppressed")
+ .HasColumnType("INTEGER");
+
+ b.Property("ResinNotifyThreshold")
+ .HasColumnType("INTEGER");
+
+ b.Property("ShowInHomeWidget")
+ .HasColumnType("INTEGER");
+
+ b.Property("TransformerNotify")
+ .HasColumnType("INTEGER");
+
+ b.Property("TransformerNotifySuppressed")
+ .HasColumnType("INTEGER");
+
+ b.Property("Uid")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("UserId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("InnerId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("daily_notes");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b =>
+ {
+ b.Property("InnerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("IsSelected")
+ .HasColumnType("INTEGER");
+
+ b.Property("Uid")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("InnerId");
+
+ b.ToTable("gacha_archives");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
+ {
+ b.Property("InnerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("ArchiveId")
+ .HasColumnType("TEXT");
+
+ b.Property("GachaType")
+ .HasColumnType("INTEGER");
+
+ b.Property("Id")
+ .HasColumnType("INTEGER");
+
+ b.Property("ItemId")
+ .HasColumnType("INTEGER");
+
+ b.Property("QueryType")
+ .HasColumnType("INTEGER");
+
+ b.Property("Time")
+ .HasColumnType("TEXT");
+
+ b.HasKey("InnerId");
+
+ b.HasIndex("ArchiveId");
+
+ b.ToTable("gacha_items");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.GameAccount", b =>
+ {
+ b.Property("InnerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("AttachUid")
+ .HasColumnType("TEXT");
+
+ b.Property("MihoyoSDK")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Type")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("InnerId");
+
+ b.ToTable("game_accounts");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.SettingEntry", b =>
+ {
+ b.Property("Key")
+ .HasColumnType("TEXT");
+
+ b.Property("Value")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Key");
+
+ b.ToTable("settings");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.User", b =>
+ {
+ b.Property("InnerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property("Aid")
+ .HasColumnType("TEXT");
+
+ b.Property("Cookie")
+ .HasColumnType("TEXT");
+
+ b.Property("IsSelected")
+ .HasColumnType("INTEGER");
+
+ b.Property("Mid")
+ .HasColumnType("TEXT");
+
+ b.Property("Stoken")
+ .HasColumnType("TEXT");
+
+ b.HasKey("InnerId");
+
+ b.ToTable("users");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
+ {
+ b.HasOne("Snap.Hutao.Model.Entity.AchievementArchive", "Archive")
+ .WithMany()
+ .HasForeignKey("ArchiveId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Archive");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
+ {
+ b.HasOne("Snap.Hutao.Model.Entity.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
+ {
+ b.HasOne("Snap.Hutao.Model.Entity.GachaArchive", "Archive")
+ .WithMany()
+ .HasForeignKey("ArchiveId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Archive");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/Migrations/20221118124745_AddAidMid.cs b/src/Snap.Hutao/Snap.Hutao/Migrations/20221118124745_AddAidMid.cs
new file mode 100644
index 0000000000..25e4501637
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Migrations/20221118124745_AddAidMid.cs
@@ -0,0 +1,39 @@
+//
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Snap.Hutao.Migrations
+{
+ ///
+ public partial class AddAidMid : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "Aid",
+ table: "users",
+ type: "TEXT",
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "Mid",
+ table: "users",
+ type: "TEXT",
+ nullable: true);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "Aid",
+ table: "users");
+
+ migrationBuilder.DropColumn(
+ name: "Mid",
+ table: "users");
+ }
+ }
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/Migrations/AppDbContextModelSnapshot.cs b/src/Snap.Hutao/Snap.Hutao/Migrations/AppDbContextModelSnapshot.cs
index 1f24f21b80..94f9b86482 100644
--- a/src/Snap.Hutao/Snap.Hutao/Migrations/AppDbContextModelSnapshot.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Migrations/AppDbContextModelSnapshot.cs
@@ -15,7 +15,7 @@ partial class AppDbContextModelSnapshot : ModelSnapshot
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
- modelBuilder.HasAnnotation("ProductVersion", "6.0.10");
+ modelBuilder.HasAnnotation("ProductVersion", "7.0.0");
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
{
@@ -231,12 +231,21 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
+ b.Property("Aid")
+ .HasColumnType("TEXT");
+
b.Property("Cookie")
.HasColumnType("TEXT");
b.Property("IsSelected")
.HasColumnType("INTEGER");
+ b.Property("Mid")
+ .HasColumnType("TEXT");
+
+ b.Property("Stoken")
+ .HasColumnType("TEXT");
+
b.HasKey("InnerId");
b.ToTable("users");
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/User/User.cs b/src/Snap.Hutao/Snap.Hutao/Model/Binding/User/User.cs
index 35f8a4a44c..6d6bd8c1aa 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Binding/User/User.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Binding/User/User.cs
@@ -5,6 +5,7 @@
using Snap.Hutao.Extension;
using Snap.Hutao.Web.Hoyolab;
using Snap.Hutao.Web.Hoyolab.Bbs.User;
+using Snap.Hutao.Web.Hoyolab.Passport;
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
using EntityUser = Snap.Hutao.Model.Entity.User;
@@ -57,21 +58,28 @@ public bool IsSelected
///
public Cookie? Cookie
+ {
+ get => inner.Cookie;
+ set => inner.Cookie = value;
+ }
+
+ ///
+ public Cookie? Stoken
{
get => inner.Cookie;
set
{
- inner.Cookie = value;
- OnPropertyChanged(nameof(HasSToken));
+ inner.Stoken = value;
+ OnPropertyChanged(nameof(HasStoken));
}
}
///
/// 是否拥有 SToken
///
- public bool HasSToken
+ public bool HasStoken
{
- get => inner.Cookie!.ContainsSToken();
+ get => inner.Stoken != null;
}
///
@@ -88,14 +96,12 @@ public bool HasSToken
/// 从数据库恢复用户
///
/// 数据库实体
- /// 用户客户端
- /// 角色客户端
/// 取消令牌
/// 用户是否初始化完成,若Cookie失效会返回
- internal static async Task ResumeAsync(EntityUser inner, UserClient userClient, BindingClient userGameRoleClient, CancellationToken token = default)
+ internal static async Task ResumeAsync(EntityUser inner, CancellationToken token = default)
{
User user = new(inner);
- bool successful = await user.InitializeCoreAsync(userClient, userGameRoleClient, token).ConfigureAwait(false);
+ bool successful = await user.InitializeCoreAsync(token).ConfigureAwait(false);
return successful ? user : null;
}
@@ -103,40 +109,54 @@ public bool HasSToken
/// 创建并初始化用户
///
/// cookie
- /// 用户客户端
- /// 角色客户端
/// 取消令牌
/// 用户是否初始化完成,若Cookie失效会返回
- internal static async Task CreateAsync(Cookie cookie, UserClient userClient, BindingClient userGameRoleClient, CancellationToken token = default)
+ internal static async Task CreateAsync(Cookie cookie, CancellationToken token = default)
{
- User user = new(EntityUser.Create(cookie));
- bool successful = await user.InitializeCoreAsync(userClient, userGameRoleClient, token).ConfigureAwait(false);
- return successful ? user : null;
+ EntityUser entity = EntityUser.Create(cookie);
+
+ UserInformation? userInfo = await Ioc.Default
+ .GetRequiredService()
+ .VerifyLtokenAsync(cookie, CancellationToken.None)
+ .ConfigureAwait(false);
+
+ entity.Aid = userInfo?.Aid;
+ entity.Mid = userInfo?.Mid;
+
+ if (entity.Aid == null && entity.Mid == null)
+ {
+ return null;
+ }
+ else
+ {
+ User user = new(entity);
+ bool initialized = await user.InitializeCoreAsync(token).ConfigureAwait(false);
+ return initialized ? user : null;
+ }
}
///
/// 更新SToken
///
- /// uid
- /// cookie
- internal void UpdateSToken(string uid, Cookie cookie)
+ /// cookie
+ internal void UpdateSToken(Cookie stoken)
{
- Cookie!.InsertSToken(uid, cookie);
- OnPropertyChanged(nameof(HasSToken));
+ Stoken = stoken;
+ OnPropertyChanged(nameof(HasStoken));
}
- private async Task InitializeCoreAsync(UserClient userClient, BindingClient userGameRoleClient, CancellationToken token = default)
+ private async Task InitializeCoreAsync(CancellationToken token = default)
{
if (isInitialized)
{
return true;
}
- UserInfo = await userClient
+ UserInfo = await Ioc.Default.GetRequiredService()
.GetUserFullInfoAsync(Entity, token)
.ConfigureAwait(false);
- UserGameRoles = await userGameRoleClient
+ UserGameRoles = await Ioc.Default.GetRequiredService()
.GetUserGameRolesByCookieAsync(Entity, token)
.ConfigureAwait(false);
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/Configuration/UserConfiguration.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/Configuration/UserConfiguration.cs
index 69964c1e33..3897b510bf 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/Configuration/UserConfiguration.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/Configuration/UserConfiguration.cs
@@ -18,7 +18,13 @@ public void Configure(EntityTypeBuilder builder)
builder.Property(e => e.Cookie)
.HasColumnType("TEXT")
.HasConversion(
- e => e == null ? string.Empty : e.ToString(),
+ e => e!.ToString(),
+ e => Cookie.Parse(e));
+
+ builder.Property(e => e.Stoken)
+ .HasColumnType("TEXT")
+ .HasConversion(
+ e => e!.ToString(),
e => Cookie.Parse(e));
}
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/User.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/User.cs
index 1712bfda37..80d10dae1a 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/User.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/User.cs
@@ -21,16 +21,31 @@ public class User : ISelectable
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid InnerId { get; set; }
+ ///
+ /// 米游社账号 Id
+ ///
+ public string? Aid { get; set; }
+
+ ///
+ /// 米哈游 Id
+ ///
+ public string? Mid { get; set; }
+
///
/// 是否被选中
///
public bool IsSelected { get; set; }
///
- /// 用户的Cookie
+ /// 用户的 Cookie
///
public Cookie? Cookie { get; set; }
+ ///
+ /// 用户的 Stoken V2
+ ///
+ public Cookie? Stoken { get; set; }
+
///
/// 创建一个新的用户
///
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Primitive/AvatarId.cs b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/AvatarId.cs
index 80feeedc86..afa1e91791 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Primitive/AvatarId.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/AvatarId.cs
@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using Snap.Hutao.Model.Primitive.Converter;
-using Windows.ApplicationModel.Chat;
namespace Snap.Hutao.Model.Primitive;
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UrlProvider/GachaLogUrlStokenProvider.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UrlProvider/GachaLogUrlStokenProvider.cs
index 152e52949b..7efc1f633b 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UrlProvider/GachaLogUrlStokenProvider.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UrlProvider/GachaLogUrlStokenProvider.cs
@@ -37,7 +37,7 @@ public async Task> GetQueryAsync()
Model.Binding.User.User? user = userService.Current;
if (user != null && user.SelectedUserGameRole != null)
{
- if (user.Cookie!.ContainsSToken())
+ if (user.HasStoken)
{
PlayerUid uid = (PlayerUid)user.SelectedUserGameRole;
GenAuthKeyData data = GenAuthKeyData.CreateForWebViewGacha(uid);
@@ -54,7 +54,7 @@ public async Task> GetQueryAsync()
}
else
{
- return new(false, "当前用户的Cookie不包含 Stoken");
+ return new(false, "当前用户的 Cookie 不包含 Stoken");
}
}
else
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/UserHelper.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/UserHelper.cs
index f8bfac3aa5..a0c334e36e 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/User/UserHelper.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/User/UserHelper.cs
@@ -1,6 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
+using Snap.Hutao.Web.Hoyolab;
using System.Collections.ObjectModel;
using BindingUser = Snap.Hutao.Model.Binding.User.User;
@@ -15,13 +16,12 @@ internal static class UserHelper
/// 尝试获取用户
///
/// 待查找的用户集合
- /// uid
+ /// 米哈游Id
/// 用户
/// 是否存在用户
- public static bool TryGetUserByUid(ObservableCollection users, string uid, [NotNullWhen(true)] out BindingUser? user)
+ public static bool TryGetUser(ObservableCollection users, string mid, [NotNullWhen(true)] out BindingUser? user)
{
- user = users.SingleOrDefault(u => u.UserInfo!.Uid == uid);
-
+ user = users.SingleOrDefault(u => u.Entity.Mid == mid);
return user != null;
}
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs
index 2d9d78495f..9b8b09c819 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs
@@ -114,13 +114,11 @@ public async Task> GetUserCollectionAsync()
using (IServiceScope scope = scopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
- UserClient userClient = scope.ServiceProvider.GetRequiredService();
- BindingClient bindingClient = scope.ServiceProvider.GetRequiredService();
foreach (Model.Entity.User entity in appDbContext.Users)
{
BindingUser? initialized = await BindingUser
- .ResumeAsync(entity, userClient, bindingClient)
+ .ResumeAsync(entity)
.ConfigureAwait(false);
if (initialized != null)
@@ -177,51 +175,44 @@ public async Task> GetUserCollectionAsync()
///
public async Task> ProcessInputCookieAsync(Cookie cookie)
{
- cookie.Trim();
Must.NotNull(userCollection!);
- // 检查 uid 是否存在
- if (cookie.TryGetUid(out string? uid))
+ string? mid = await cookie.GetMidAsync().ConfigureAwait(false);
+
+ if (mid == null)
{
- // 检查 login ticket 是否存在
- // 若存在则尝试升级至 stoken
- await cookie.TryAddMultiTokenAsync(uid).ConfigureAwait(false);
+ return new(UserOptionResult.Invalid, "输入的Cookie无法获取用户信息");
+ }
- // 检查 uid 对应用户是否存在
- if (UserHelper.TryGetUserByUid(userCollection, uid, out BindingUser? userWithSameUid))
+ // 检查 mid 对应用户是否存在
+ if (UserHelper.TryGetUser(userCollection, mid, out BindingUser? user))
+ {
+ using (IServiceScope scope = scopeFactory.CreateScope())
{
- using (IServiceScope scope = scopeFactory.CreateScope())
- {
- AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
- // 检查 stoken 是否存在
- if (cookie.ContainsSToken())
- {
- // insert stoken
- await ThreadHelper.SwitchToMainThreadAsync();
- userWithSameUid.UpdateSToken(uid, cookie);
- appDbContext.Users.UpdateAndSave(userWithSameUid.Entity);
+ // 检查 stoken 是否存在
+ if (user.HasStoken)
+ {
+ // update stoken
+ await ThreadHelper.SwitchToMainThreadAsync();
+ user.UpdateSToken(cookie);
+ appDbContext.Users.UpdateAndSave(user.Entity);
- return new(UserOptionResult.Upgraded, uid);
- }
+ return new(UserOptionResult.Upgraded, mid);
+ }
- if (cookie.ContainsLTokenAndCookieToken())
- {
- await ThreadHelper.SwitchToMainThreadAsync();
- userWithSameUid.Cookie = cookie;
- appDbContext.Users.UpdateAndSave(userWithSameUid.Entity);
+ await ThreadHelper.SwitchToMainThreadAsync();
+ user.Cookie = cookie;
+ appDbContext.Users.UpdateAndSave(user.Entity);
- return new(UserOptionResult.Updated, uid);
- }
- }
- }
- else if (cookie.ContainsLTokenAndCookieToken())
- {
- return await TryCreateUserAndAddAsync(cookie).ConfigureAwait(false);
+ return new(UserOptionResult.Updated, mid);
}
}
-
- return new(UserOptionResult.Incomplete, null!);
+ else
+ {
+ return await TryCreateUserAndAddAsync(cookie).ConfigureAwait(false);
+ }
}
private async Task> TryCreateUserAndAddAsync(Cookie cookie)
@@ -229,10 +220,8 @@ private async Task> TryCreateUserAndAddAsy
using (IServiceScope scope = scopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
- UserClient userClient = scope.ServiceProvider.GetRequiredService();
- BindingClient bindingClient = scope.ServiceProvider.GetRequiredService();
- BindingUser? newUser = await BindingUser.CreateAsync(cookie, userClient, bindingClient).ConfigureAwait(false);
+ BindingUser? newUser = await BindingUser.CreateAsync(cookie).ConfigureAwait(false);
if (newUser != null)
{
// Sync cache
@@ -256,7 +245,7 @@ private async Task> TryCreateUserAndAddAsy
}
else
{
- return new(UserOptionResult.Invalid, null!);
+ return new(UserOptionResult.Invalid, "输入的Cookie无法获取用户信息");
}
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml b/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml
index bd5aebfa7c..fdb656f58e 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml
@@ -127,7 +127,7 @@
@@ -210,7 +210,7 @@
-
+
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/UserViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/UserViewModel.cs
index 8a0cbfc77d..61b4594f33 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/UserViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/UserViewModel.cs
@@ -142,7 +142,7 @@ private async Task AddUserAsync()
private async Task LoginMihoyoBBS2Async()
{
MainWindow mainWindow = Ioc.Default.GetRequiredService();
- await new LoginMihoyoBBSDialog(mainWindow).GetInputAccountPasswordAsync();
+ await new LoginMihoyoBBSDialog(mainWindow).GetInputAccountPasswordAsync().ConfigureAwait(false);
}
private void LoginMihoyoBBS()
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Bbs/User/UserClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Bbs/User/UserClient.cs
index 798f2990a1..894792569b 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Bbs/User/UserClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Bbs/User/UserClient.cs
@@ -3,7 +3,6 @@
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
using Snap.Hutao.Web.Hoyolab.Annotation;
-using Snap.Hutao.Web.Hoyolab.DynamicSecret;
using Snap.Hutao.Web.Response;
using System.Net.Http;
@@ -43,7 +42,7 @@ public UserClient(HttpClient httpClient, JsonSerializerOptions options, ILogger<
{
Response? resp = await httpClient
.SetUser(user, CookieType.Cookie)
- //.SetReferer(ApiEndpoints.BbsReferer)
+ .SetReferer(ApiEndpoints.BbsReferer)
.TryCatchGetFromJsonAsync>(ApiEndpoints.UserFullInfo, options, logger, token)
.ConfigureAwait(false);
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.Constant.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.Constant.cs
index 29438b661e..d512cf1908 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.Constant.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.Constant.cs
@@ -10,19 +10,7 @@ namespace Snap.Hutao.Web.Hoyolab;
[SuppressMessage("", "SA1600")]
public partial class Cookie
{
- public const string ACCOUNT_ID = "account_id";
- public const string COOKIE_TOKEN = "cookie_token";
-
- public const string E_HK4E_TOKEN = "e_hk4e_token";
-
- public const string LOGIN_TICKET = "login_ticket";
- public const string LOGIN_UID = "login_uid";
-
- public const string LTOKEN = "ltoken";
- public const string LTUID = "ltuid";
-
public const string MID = "mid";
-
public const string STOKEN = "stoken";
public const string STUID = "stuid";
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.cs
index ea6107c078..6d79fd35a2 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.cs
@@ -3,6 +3,7 @@
using Microsoft.Web.WebView2.Core;
using Snap.Hutao.Extension;
+using Snap.Hutao.Web.Hoyolab.Passport;
using Snap.Hutao.Web.Hoyolab.Takumi.Auth;
namespace Snap.Hutao.Web.Hoyolab;
@@ -65,152 +66,52 @@ public static Cookie FromCoreWebView2Cookies(IReadOnlyList w
}
///
- /// 存在 LoginTicket
+ /// 此 Cookie 是 SToken
///
/// 是否存在
- public bool ContainsLoginTicket()
+ public bool IsStoken()
{
- return inner.ContainsKey(LOGIN_TICKET);
- }
-
- ///
- /// 存在 LToken 与 CookieToken
- ///
- /// 是否存在
- public bool ContainsLTokenAndCookieToken()
- {
- return inner.ContainsKey(LTOKEN) && inner.ContainsKey(COOKIE_TOKEN);
- }
-
- ///
- /// 存在 SToken
- ///
- /// 是否存在
- public bool ContainsSToken()
- {
- return inner.ContainsKey(STOKEN);
- }
-
- ///
- /// 插入 Stoken
- ///
- /// stuid
- /// cookie
- public void InsertSToken(string stuid, Cookie cookie)
- {
- inner[STUID] = stuid;
- inner[STOKEN] = cookie.inner[STOKEN];
- }
+ int stokenFlag = 0;
- ///
- /// 移除无效的键
- ///
- public void Trim()
- {
- foreach (string key in inner.Keys.ToList())
+ foreach (string key in inner.Keys)
{
- if (key == ACCOUNT_ID
- || key == COOKIE_TOKEN
- || key == LOGIN_UID
- || key == LOGIN_TICKET
- || key == LTUID
- || key == LTOKEN
- || key == STUID
- || key == STOKEN)
+ if (key is MID or STOKEN or STUID)
{
- continue;
- }
- else
- {
- inner.Remove(key);
+ stokenFlag++;
}
}
- }
- ///
- public bool TryGetValue(string key, [NotNullWhen(true)] out string? value)
- {
- return inner.TryGetValue(key, out value);
+ return stokenFlag == 3;
}
- public bool TryGetLoginTicket([NotNullWhen(true)] out string? loginTicket)
- {
- return inner.TryGetValue(LOGIN_TICKET, out loginTicket);
- }
-
- public bool TryGetUid([NotNullWhen(true)] out string? uid)
+ ///
+ /// 异步获取 Mid
+ ///
+ /// mid
+ public async Task GetMidAsync()
{
- Dictionary uidCounter = new();
-
- foreach ((string key, string value) in inner)
- {
- if (key is ACCOUNT_ID or LOGIN_UID or LTUID or STUID)
- {
- uidCounter.Increase(key);
- }
- }
-
- if (uidCounter.Count > 0)
+ string? mid;
+ if (IsStoken())
{
- // fix #88 自带页面登录米游社,提示登录失败
- string key = uidCounter.MaxBy(kvp => kvp.Value).Key;
- uid = inner[key];
- return true;
+ mid = inner[MID];
}
else
{
- uid = null;
- return false;
- }
- }
-
- ///
- /// 异步尝试添加MultiToken
- ///
- /// uid
- /// 任务
- public async Task TryAddMultiTokenAsync(string uid)
- {
- if (TryGetLoginTicket(out string? loginTicket))
- {
- // get multitoken
- Dictionary multiToken = await Ioc.Default
- .GetRequiredService()
- .GetMultiTokenByLoginTicketAsync(loginTicket, uid, default)
+ UserInformation? userInfo = await Ioc.Default
+ .GetRequiredService()
+ .VerifyLtokenAsync(this, CancellationToken.None)
.ConfigureAwait(false);
- if (multiToken.Count >= 2)
- {
- inner[STUID] = uid;
- inner[STOKEN] = multiToken[STOKEN];
- inner[LTUID] = uid;
- inner[LTOKEN] = multiToken[LTOKEN];
-
- inner.Remove(LOGIN_TICKET);
- inner.Remove(LOGIN_UID);
- }
+ mid = userInfo?.Mid;
}
+
+ return mid;
}
- ///
- /// 根据类型输出对应的Cookie
- ///
- /// 类型
- /// Cookie对应的字符串表示
- public string ToString(CookieType type)
+ ///
+ public bool TryGetValue(string key, [NotNullWhen(true)] out string? value)
{
- IEnumerable> results;
-
- results = type switch
- {
- CookieType.None => Enumerable.Empty>(),
- CookieType.Cookie => inner.Where(kvp => kvp.Key is E_HK4E_TOKEN or LTUID or LTOKEN or ACCOUNT_ID or COOKIE_TOKEN),
- CookieType.Stoken => inner.Where(kvp => kvp.Key is STUID or STOKEN or MID),
- CookieType.All => inner,
- _ => throw Must.NeverHappen(type.ToString()),
- };
-
- return string.Join(';', results.Select(kvp => $"{kvp.Key}={kvp.Value}"));
+ return inner.TryGetValue(key, out value);
}
///
@@ -219,6 +120,6 @@ public string ToString(CookieType type)
/// Cookie的字符串表示
public override string ToString()
{
- return ToString(CookieType.All);
+ return string.Join(';', inner.Select(kvp => $"{kvp.Key}={kvp.Value}"));
}
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/DynamicSecretProvider.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/DynamicSecretProvider.cs
deleted file mode 100644
index ba42f8faf1..0000000000
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/DynamicSecretProvider.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) DGP Studio. All rights reserved.
-// Licensed under the MIT license.
-
-using Snap.Hutao.Core.Convert;
-using System.Text;
-
-namespace Snap.Hutao.Web.Hoyolab.DynamicSecret;
-
-///
-/// 为MiHoYo接口请求器 提供动态密钥
-///
-internal abstract class DynamicSecretProvider : Md5Convert
-{
- private const string RandomRange = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
-
- ///
- /// 创建动态密钥
- ///
- /// SALT 类型
- /// 密钥
- public static string Create(SaltType saltType)
- {
- Verify.Operation(saltType is SaltType.K2 or SaltType.LK2, "SALT 值无效");
-
- // unix timestamp
- long t = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
-
- string r = GetRandomString();
-
- string salt = Core.CoreEnvironment.DynamicSecrets[saltType];
- string check = ToHexString($"salt={salt}&t={t}&r={r}").ToLowerInvariant();
-
- return $"{t},{r},{check}";
- }
-
- private static string GetRandomString()
- {
- StringBuilder sb = new(6);
-
- for (int i = 0; i < 6; i++)
- {
- int pos = Random.Shared.Next(0, RandomRange.Length);
- sb.Append(RandomRange[pos]);
- }
-
- return sb.ToString();
- }
-}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/DynamicSecretProvider2.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/DynamicSecretProvider2.cs
deleted file mode 100644
index fbd423cb72..0000000000
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/DynamicSecretProvider2.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) DGP Studio. All rights reserved.
-// Licensed under the MIT license.
-
-using Snap.Hutao.Core.Convert;
-
-namespace Snap.Hutao.Web.Hoyolab.DynamicSecret;
-
-///
-/// 为MiHoYo接口请求器 提供2代动态密钥
-///
-internal abstract class DynamicSecretProvider2 : Md5Convert
-{
- ///
- /// 创建动态密钥
- ///
- /// SALT 类型
- /// json格式化器
- /// 查询url
- /// 请求体
- /// 密钥
- public static string Create(SaltType saltType, JsonSerializerOptions options, string queryUrl, object? postBody = null)
- {
- Verify.Operation(saltType is SaltType.X6 or SaltType.X4 or SaltType.PROD, "SALT 值无效");
-
- // unix timestamp
- long t = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
-
- // random
- int r = GetRandom();
-
- // body
- string b = postBody is null ? GetDefaultBody(saltType) : JsonSerializer.Serialize(postBody, options);
-
- // query
- string[] queries = queryUrl.Split('?', 2);
- string q = queries.Length == 2 ? string.Join('&', queries[1].Split('&').OrderBy(x => x)) : string.Empty;
-
- // check
- string salt = Core.CoreEnvironment.DynamicSecrets[saltType];
- string check = ToHexString($"salt={salt}&t={t}&r={r}&b={b}&q={q}").ToLowerInvariant();
-
- return $"{t},{r},{check}";
- }
-
- private static string GetDefaultBody(SaltType saltType)
- {
- return saltType switch
- {
- SaltType.X4 or SaltType.X6 => string.Empty,
- SaltType.PROD => "{}",
- _ => throw Must.NeverHappen(((int)saltType).ToString()),
- };
- }
-
- private static int GetRandom()
- {
- // 原汁原味
- // v16 = time(0LL);
- // srand(v16);
- // v17 = (int)((double)rand() / 2147483650.0 * 100000.0 + 100000.0) % 1000000;
- // if (v17 >= 100001)
- // v18 = v17;
- // else
- // v18 = v17 + 542367;
- int rand = Random.Shared.Next(100000, 200000);
- return rand == 100000 ? 642367 : rand;
- }
-}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/HttpClientDynamicSecretExtensions.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/HttpClientDynamicSecretExtensions.cs
index 43206f39b5..e6d2281564 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/HttpClientDynamicSecretExtensions.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/HttpClientDynamicSecretExtensions.cs
@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
-using Snap.Hutao.Web.Hoyolab.DynamicSecret.Http;
using Snap.Hutao.Web.Request;
using System.Net.Http;
@@ -25,47 +24,4 @@ public static HttpClient UseDynamicSecret(this HttpClient client, DynamicSecretV
client.DefaultRequestHeaders.Set("DS-Option", $"{version}|{salt}|{includeChars}");
return client;
}
-
- ///
- /// 使用一代动态密钥执行 GET/POST 操作
- ///
- /// 请求器
- /// SALT 类型
- /// 响应
- [Obsolete]
- public static HttpClient UsingDynamicSecret1(this HttpClient httpClient, SaltType type)
- {
- httpClient.DefaultRequestHeaders.Set("DS", DynamicSecretProvider.Create(type));
- return httpClient;
- }
-
- ///
- /// 使用二代动态密钥执行 GET/POST 操作
- ///
- /// 请求器
- /// SALT 类型
- /// 选项
- /// 地址
- /// 响应
- [Obsolete]
- public static IDynamicSecretHttpClient UsingDynamicSecret2(this HttpClient httpClient, SaltType type, JsonSerializerOptions options, string url)
- {
- return new DynamicSecretHttpClient(httpClient, type, options, url);
- }
-
- ///
- /// 使用二代动态密钥执行 GET/POST 操作
- ///
- /// 请求数据的类型
- /// 请求器
- /// SALT 类型
- /// 选项
- /// 地址
- /// post数据
- /// 响应
- public static IDynamicSecretHttpClient UsingDynamicSecret2(this HttpClient httpClient, SaltType type, JsonSerializerOptions options, string url, TValue data)
- where TValue : class
- {
- return new DynamicSecretHttpClient(httpClient, type, options, url, data);
- }
-}
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HttpClientExtensions.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HttpClientExtensions.cs
index ab8a8ec763..b9cb7345ad 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HttpClientExtensions.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HttpClientExtensions.cs
@@ -2,8 +2,6 @@
// Licensed under the MIT license.
using Snap.Hutao.Core.Logging;
-using Snap.Hutao.Model.Binding.User;
-using Snap.Hutao.Web.Hoyolab.DynamicSecret;
using Snap.Hutao.Web.Request;
using System.Net.Http;
using System.Net.Http.Json;
@@ -62,7 +60,7 @@ internal static class HttpClientExtensions
}
///
- /// 设置用户的Cookie
+ /// 设置用户的 Cookie
///
/// http客户端
/// 实体用户
@@ -70,7 +68,25 @@ internal static class HttpClientExtensions
/// 客户端
internal static HttpClient SetUser(this HttpClient httpClient, Model.Entity.User user, CookieType cookie)
{
- httpClient.DefaultRequestHeaders.Set("Cookie", user.Cookie!.ToString(cookie));
+ if (cookie == CookieType.Stoken)
+ {
+ return httpClient.SetRawCookie(user.Stoken!);
+ }
+ else
+ {
+ return httpClient.SetRawCookie(user.Cookie!);
+ }
+ }
+
+ ///
+ /// 设置 Cookie
+ ///
+ /// http客户端
+ /// Cookie
+ /// 客户端
+ internal static HttpClient SetRawCookie(this HttpClient httpClient, Cookie cookie)
+ {
+ httpClient.DefaultRequestHeaders.Set("Cookie", cookie.ToString());
return httpClient;
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/Link.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/Link.cs
index bf321f307f..7c83723692 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/Link.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/Link.cs
@@ -1,10 +1,6 @@
// 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;
-
namespace Snap.Hutao.Web.Hoyolab.Passport;
///
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 c02c3d7ff3..094158d5eb 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient.cs
@@ -4,7 +4,6 @@
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;
@@ -36,18 +35,18 @@ public PassportClient(HttpClient httpClient, JsonSerializerOptions options, ILog
///
/// 异步验证Ltoken
///
- /// 用户
+ /// 待校验的 Cookie
/// 取消令牌
/// 验证信息
[ApiInformation(Cookie = CookieType.Cookie)]
- public async Task VerifyLtokenAsync(User user, CancellationToken token)
+ public async Task VerifyLtokenAsync(Cookie cookie, CancellationToken token)
{
- Response? response = await httpClient
- .SetUser(user, CookieType.All)
- .TryCatchPostAsJsonAsync>(ApiEndpoints.AccountVerifyLtoken, new(), options, logger, token)
+ Response? response = await httpClient
+ .SetRawCookie(cookie)
+ .TryCatchPostAsJsonAsync>(ApiEndpoints.AccountVerifyLtoken, new(), options, logger, token)
.ConfigureAwait(false);
- return response?.Data;
+ return response?.Data?.UserInfo;
}
private class Timestamp
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 73d205c43f..102cf69387 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient2.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient2.cs
@@ -50,8 +50,8 @@ public PassportClient2(HttpClient httpClient, JsonSerializerOptions options, ILo
};
Response? resp = await httpClient
- .UsingDynamicSecret2(SaltType.PROD, options, ApiEndpoints.AccountLoginByPassword, data)
- .TryCatchPostAsJsonAsync>(logger, token)
+ .UseDynamicSecret(DynamicSecretVersion.Gen2, SaltType.PROD, true)
+ .TryCatchPostAsJsonAsync, Response>(ApiEndpoints.AccountLoginByPassword, data, options, logger, token)
.ConfigureAwait(false);
return resp?.Data;
@@ -68,8 +68,8 @@ public PassportClient2(HttpClient httpClient, JsonSerializerOptions options, ILo
{
Response? resp = await httpClient
.SetUser(user, CookieType.Stoken)
- .UsingDynamicSecret2(SaltType.PROD, options, ApiEndpoints.AccountCookieAccountInfoBySToken)
- .TryCatchGetFromJsonAsync>(logger, token)
+ .UseDynamicSecret(DynamicSecretVersion.Gen2, SaltType.PROD, true)
+ .TryCatchGetFromJsonAsync>(ApiEndpoints.AccountCookieAccountInfoBySToken, options, logger, token)
.ConfigureAwait(false);
return resp?.Data;
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/UserInfoWrapper.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/UserInfoWrapper.cs
new file mode 100644
index 0000000000..080580b291
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/UserInfoWrapper.cs
@@ -0,0 +1,16 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Web.Hoyolab.Passport;
+
+///
+/// 用户信息包装器
+///
+public class UserInfoWrapper
+{
+ ///
+ /// 用户信息
+ ///
+ [JsonPropertyName("user_info")]
+ public UserInformation UserInfo { get; set; } = default!;
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/UserInformation.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/UserInformation.cs
index ce3872a8e8..8004171b39 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/UserInformation.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/UserInformation.cs
@@ -1,10 +1,6 @@
// 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;
-
namespace Snap.Hutao.Web.Hoyolab.Passport;
///
@@ -101,4 +97,4 @@ public class UserInformation
///
[JsonPropertyName("links")]
public List Links { get; set; } = default!;
-}
\ No newline at end of file
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/ActionTicketAccountInfo.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/ActionTicketAccountInfo.cs
index e76f894077..1664b55a08 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/ActionTicketAccountInfo.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/ActionTicketAccountInfo.cs
@@ -1,11 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
-using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
-using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
-using Snap.Hutao.Web.Response;
-using System.Net.Http;
-
namespace Snap.Hutao.Web.Hoyolab.Takumi.Auth;
///
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 9ac5e9b612..72760f0adc 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
@@ -1,11 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
-using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
-using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
-using Snap.Hutao.Web.Response;
-using System.Net.Http;
-
namespace Snap.Hutao.Web.Hoyolab.Takumi.Auth;
///
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/AuthClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/AuthClient.cs
index e8548cd276..8cce8e7599 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/AuthClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/AuthClient.cs
@@ -41,47 +41,20 @@ public AuthClient(HttpClient httpClient, JsonSerializerOptions options, ILogger<
/// 操作
/// 用户
/// 操作凭证
- [ApiInformation(Cookie = CookieType.Stoken, Salt = DynamicSecret.SaltType.K2)]
+ [ApiInformation(Cookie = CookieType.Stoken, Salt = SaltType.K2)]
public async Task GetActionTicketByStokenAsync(string action, User user)
{
- if (user.Cookie!.TryGetValue(Cookie.STOKEN, out string? stoken))
+ if (user.Stoken != null)
{
- if (user.Cookie.TryGetUid(out string? uid))
- {
- Response? resp = await httpClient
- .UseDynamicSecret(DynamicSecretVersion.Gen1, SaltType.K2, true)
- .TryCatchGetFromJsonAsync>(ApiEndpoints.AuthActionTicket(action, stoken, uid), options, logger)
- .ConfigureAwait(false);
+ user.Stoken.TryGetValue(Cookie.STOKEN, out string? token);
+ Response? resp = await httpClient
+ .UseDynamicSecret(DynamicSecretVersion.Gen1, SaltType.K2, true)
+ .TryCatchGetFromJsonAsync>(ApiEndpoints.AuthActionTicket(action, token!, user.Aid!), options, logger)
+ .ConfigureAwait(false);
- return resp?.Data?.Ticket;
- }
+ return resp?.Data?.Ticket;
}
return null;
}
-
- ///
- /// 获取 MultiToken
- ///
- /// 登录票证
- /// uid
- /// 取消令牌
- /// 包含token的字典
- [Obsolete]
- public async Task> GetMultiTokenByLoginTicketAsync(string loginTicket, string loginUid, CancellationToken token)
- {
- Response>? resp = await httpClient
- .TryCatchGetFromJsonAsync>>(ApiEndpoints.AuthMultiToken(loginTicket, loginUid), options, logger, token)
- .ConfigureAwait(false);
-
- if (resp?.Data != null)
- {
- Dictionary dict = resp.Data.List.ToDictionary(n => n.Name, n => n.Token);
- Must.Argument(dict.ContainsKey(Cookie.LTOKEN), "MultiToken 应该包含 ltoken");
- Must.Argument(dict.ContainsKey(Cookie.STOKEN), "MultiToken 应该包含 stoken");
- return dict;
- }
-
- return new();
- }
}
\ No newline at end of file
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 858e2f2d9e..df1ead7689 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
@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
+using Snap.Hutao.Extension;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Web.Hoyolab.Annotation;
using Snap.Hutao.Web.Hoyolab.DynamicSecret;
@@ -64,11 +65,11 @@ public async Task> GetUserGameRolesByStokenAsync(User user, C
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.BindingGenAuthKey, data, options, logger, token)
- .ConfigureAwait(false);
+ .SetUser(user, CookieType.Stoken)
+ .SetReferer("https://app.mihoyo.com")
+ .UseDynamicSecret(DynamicSecretVersion.Gen1, SaltType.K2, true)
+ .TryCatchPostAsJsonAsync>(ApiEndpoints.BindingGenAuthKey, data, options, logger, token)
+ .ConfigureAwait(false);
return resp?.Data;
}
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 9a40e2d93f..b0f2148fdf 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
@@ -6,7 +6,6 @@
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Web.Hoyolab.Annotation;
using Snap.Hutao.Web.Hoyolab.DynamicSecret;
-using Snap.Hutao.Web.Hoyolab.DynamicSecret.Http;
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Widget;
using Snap.Hutao.Web.Response;
@@ -129,8 +128,8 @@ public async Task> GetCharactersAsync(User user, PlayerUid uid,
Response? resp = await httpClient
.SetUser(user, CookieType.Cookie)
- .UsingDynamicSecret2(SaltType.X4, options, ApiEndpoints.GameRecordCharacter, data)
- .TryCatchPostAsJsonAsync>(logger, token)
+ .UseDynamicSecret(DynamicSecretVersion.Gen2, SaltType.X4, false)
+ .TryCatchPostAsJsonAsync>(ApiEndpoints.GameRecordCharacter, data, options, logger, token)
.ConfigureAwait(false);
return EnumerableExtension.EmptyIfNull(resp?.Data?.Avatars);
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HomaClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HomaClient.cs
index faf9349a34..f78e73a81f 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HomaClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HomaClient.cs
@@ -177,13 +177,8 @@ public async Task GetPlayerRecordAsync(User user, CancellationToke
{
Must.NotNull(user.SelectedUserGameRole!);
- PlayerInfo? playerInfo = await gameRecordClient
- .GetPlayerInfoAsync(user.Entity, user.SelectedUserGameRole, token)
- .ConfigureAwait(false);
- Must.NotNull(playerInfo!);
-
List characters = await gameRecordClient
- .GetCharactersAsync(user.Entity, user.SelectedUserGameRole, playerInfo, token)
+ .GetCharactersAsync(user.Entity, user.SelectedUserGameRole, token)
.ConfigureAwait(false);
SpiralAbyss? spiralAbyssInfo = await gameRecordClient