Skip to content
This repository was archived by the owner on Aug 30, 2025. It is now read-only.

Commit 5894c7f

Browse files
committed
feat(JsonParse):换用 Record 表示 Json 类、自定义 Converter 、
1 parent 2ab09d0 commit 5894c7f

File tree

12 files changed

+484
-90
lines changed

12 files changed

+484
-90
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using SuikaiLauncher.Core.Account.JsonModel;
2+
using SuikaiLauncher.Core.Base;
3+
using SuikaiLauncher.Core.Override;
4+
using System.Runtime.CompilerServices;
5+
6+
7+
namespace SuikaiLauncher.Core.Account.Modules
8+
{
9+
public class Microsoft
10+
{
11+
public static Action<Dictionary<string, string>>? Callback;
12+
public static string?ClientId;
13+
public async static Task GetDeviceCode()
14+
{
15+
using(MemoryStream ReqData = new($"client_id={ClientId}&scope=XboxLive.Signin%20offline_access".GetBytes()))
16+
{
17+
HttpResponseMessage? Resp = (await HttpRequestBuilder
18+
.Create("https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode", HttpMethod.Post)
19+
.WithRequestData(ReqData)
20+
.SetHeader("Content-Type", "application/x-www-form-urlencoded")
21+
.SetHeader("Accept","application/json")
22+
.SetHeader("User-Agent",HttpRequestBuilder.UserAgent)
23+
.UseProxy()
24+
.Invoke()).GetResponse();
25+
OAuthDeviceCode DeviceCode = Json.Deserialize<OAuthDeviceCode>(await FileIO.ReadAsString(Resp));
26+
if (Callback is not null) Callback(new Dictionary<string, string>()
27+
{
28+
["user_code"] = DeviceCode.UserCode,
29+
["verification_uri"] = DeviceCode.Verification,
30+
["verification_uri_complete"] = DeviceCode.VerificationComplete ?? string.Empty
31+
});
32+
33+
}
34+
35+
return;
36+
}
37+
public async static Task ValidateUserAuthorizeResult(OAuthDeviceCode DeviceCode)
38+
{
39+
using (MemoryStream ReqData = new("device_code=&client_id=&".GetBytes()))
40+
{
41+
HttpResponseMessage? Resp = (await HttpRequestBuilder
42+
.Create("https://login.microsoftonline.com/consumers/oauth2/v2.0/token", HttpMethod.Post)
43+
.WithRequestData(ReqData)
44+
.SetHeader("Content-Type", "application/x-www-form-urlencoded")
45+
.SetHeader("Accept", "application/json")
46+
.SetHeader("User-Agent", HttpRequestBuilder.UserAgent)
47+
.Invoke()).GetResponse(false);
48+
}
49+
}
50+
}
51+
}

SuikaiLauncher.Core.Account/Modules/MinecraftYggdrasil.cs

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,43 +6,49 @@
66
namespace SuikaiLauncher.Core.Account{
77
public class MinecraftYggdrasil{
88
internal async Task<Tuple<bool,string>> YggdrasilAuthorize(string XSTSToken,string UserHash){
9-
JsonObject ReqData = new() {
10-
["JsonProperty"] = $"XBL3.0 x={XSTSToken};{UserHash}"
11-
};
12-
HttpResponseMessage Response = await Network.NetworkRequest(
13-
"https://api.minecraftservices.com/authentication/login_with_xbox",
14-
new Dictionary<string, string>() { ["Content-Type"] = "application/json"},
15-
ReqData.ToJsonString(),
16-
method:"POST"
17-
);
18-
if(Response.IsSuccessStatusCode){
19-
string UserAuthResult = await FileIO.ReadAsString(Response);
20-
if(!UserAuthResult.IsNullOrWhiteSpaceF()){
21-
MinecraftOfficialYggdrasil JsonData = Json.GetJson<MinecraftOfficialYggdrasil>(UserAuthResult);
22-
return Tuple.Create(true,JsonData.accessToken);
23-
9+
MinecraftRPLogin AuthData = new() { identityToken = $"XBL3.0 x={XSTSToken};{UserHash}" };
10+
string LoginData = Json.Serialize<MinecraftRPLogin>(AuthData);
11+
using (MemoryStream ReqData = new(LoginData.GetBytes()))
12+
{
13+
HttpResponseMessage Response = (await HttpRequestBuilder
14+
.Create("https://api.minecraftservices.com/authentication/login_with_xbox", HttpMethod.Post)
15+
.WithRequestData(ReqData)
16+
.SetHeader("Content-Type", "application/json")
17+
.SetHeader("Accept", "application/json")
18+
.SetHeader("UserAgent", HttpRequestBuilder.UserAgent)
19+
.UseProxy()
20+
.Invoke()).GetResponse();
21+
22+
23+
string UserAuthResult = await FileIO.ReadAsString(Response!);
24+
if (!UserAuthResult.IsNullOrWhiteSpaceF())
25+
{
26+
MinecraftOfficialYggdrasil JsonData = Json.Deserialize<MinecraftOfficialYggdrasil>(UserAuthResult);
27+
return Tuple.Create(true, JsonData.accessToken);
2428
}
2529
}
26-
return Tuple.Create(false,string.Empty);
27-
}
30+
return Tuple.Create(false, string.Empty);
31+
}
2832
internal async static Task<bool> ValidateOwnership(string AccessToken){
29-
HttpResponseMessage Response = await Network.NetworkRequest(
30-
"https://api.minecraftservices.com/entitlements/mcstore",
31-
new Dictionary<string, string>(){
32-
["Authorization"] = AccessToken
33-
}
34-
) ;
35-
Ownership UserAuthResult = Json.GetJson<Ownership>(await FileIO.ReadAsString(Response));
33+
HttpResponseMessage Response = (await HttpRequestBuilder
34+
.Create("https://api.minecraftservices.com/entitlements/mcstore", HttpMethod.Get)
35+
.SetHeader("Authorization", AccessToken)
36+
.SetHeader("User-Agent", HttpRequestBuilder.UserAgent)
37+
.UseProxy()
38+
.Invoke()).GetResponse();
39+
Ownership UserAuthResult = Json.Deserialize<Ownership>(await FileIO.ReadAsString(Response));
3640
return !(UserAuthResult.items.Count <= 0);
3741
}
3842
internal async static Task<MinecraftUserProfile?> GetMinecraftProfile(string AccessToken){
3943
try{
40-
HttpResponseMessage Response = await Network.NetworkRequest(
41-
"https://api.minecraftservices.com/minecraft/profile",
42-
new Dictionary<string, string>() {
43-
["Authorization"] = AccessToken
44-
});
45-
MinecraftUserProfile PlayerProfile = Json.GetJson<MinecraftUserProfile>(await FileIO.ReadAsString(Response));
44+
HttpResponseMessage Response = (await HttpRequestBuilder
45+
.Create("https://api.minecraftservices.com/minecraft/profile", HttpMethod.Get)
46+
.SetHeader("Authorization", AccessToken)
47+
.SetHeader("User-Agent", HttpRequestBuilder.UserAgent)
48+
.UseProxy()
49+
.Invoke()).GetResponse();
50+
51+
MinecraftUserProfile PlayerProfile = Json.Deserialize<MinecraftUserProfile>(await FileIO.ReadAsString(Response));
4652
return PlayerProfile;
4753
}catch (Exception ex){
4854
Logger.Log(ex,"[Account] 获取档案信息失败");

SuikaiLauncher.Core.Account/Modules/Model.cs

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,48 +3,64 @@
33

44
namespace SuikaiLauncher.Core.Account.JsonModel
55
{
6-
public class YggdrasilUserAuth
6+
public record OAuthDeviceCode
7+
{
8+
[JsonPropertyName("user_code")]
9+
public required string UserCode;
10+
[JsonPropertyName("device_code")]
11+
public required string DeviceCode;
12+
public required int interval;
13+
[JsonPropertyName("verification_uri")]
14+
public required string Verification;
15+
[JsonPropertyName("verification_uri_complete")]
16+
public string? VerificationComplete;
17+
}
18+
public class MinecraftRPLogin
19+
{
20+
public required string identityToken;
21+
}
22+
public record YggdrasilUserAuth
723
{
824
public required string accessToken;
925
public string? clientToken;
1026
public List<Profile?>? availableProfiles;
1127
public Profile? selectedProfile;
1228
}
13-
public class YggdrasilAuthError
29+
public record YggdrasilAuthError
1430
{
1531
public dynamic? errorMessage;
1632
public dynamic? Message;
1733
}
18-
public class Profile
34+
public record Profile
1935
{
2036
public required string name;
2137
public required string id;
2238
public required List<PlayerProperties> Properties;
2339
}
24-
public class PlayerProperties
40+
public record PlayerProperties
2541
{
2642
public required string name;
2743
public required string value;
2844

2945

3046
public string? signature;
3147
}
32-
public class XboxLiveAuth
48+
public record XboxLiveAuth
3349
{
3450
public required string IssueInstant;
3551
public required string NotAfter;
3652
public required string Token;
3753
public required DisplayClaims DisplayClaims;
3854
}
39-
public class DisplayClaims
55+
public record DisplayClaims
4056
{
4157
public required List<Xui> xui;
4258
}
43-
public class Xui
59+
public record Xui
4460
{
4561
public required string uhs;
4662
}
47-
public class MinecraftOfficialYggdrasil
63+
public record MinecraftOfficialYggdrasil
4864
{
4965
public required string username;
5066
public List<dynamic>? roles;
@@ -55,45 +71,57 @@ public class MinecraftOfficialYggdrasil
5571
[JsonPropertyName("expires_in")]
5672
public required long ExpiredIn;
5773
}
58-
public class Ownership
74+
public record Ownership
5975
{
6076
public required List<dynamic?> items;
6177
public required string signature;
6278
public required string keyId;
6379
}
64-
public class MinecraftUserProfile
80+
public record MinecraftUserProfile
6581
{
6682
public required string id;
6783
public required string name;
6884
public required List<MinecraftProfileSkin> skins;
6985
public required List<MinecraftProfileSkin> capes;
7086
}
71-
public class MinecraftProfileSkin
87+
public record MinecraftProfileSkin
7288
{
7389
public required string id;
7490
public required string state;
7591
public string? variant;
7692
public required string url;
7793
public required string alias;
7894
}
79-
public class Texture
95+
public record Texture
8096
{
8197
public required long timestamp;
8298
public required string profileId;
8399
public required string profileName;
84100
public required Textures textures;
85101
}
86-
public class Textures {
102+
public record Textures {
87103
[JsonPropertyName("skin")]
88104
public Skin? Skin;
89105
[JsonPropertyName("cape")]
90106
public Skin? Cape;
91107
}
92-
public class Skin {
108+
public record Skin {
93109
public required string url;
94110
public Metadata? metadata;
95111
}
96-
public class Metadata {
112+
public record Metadata {
97113
public required string model;
98114
}
115+
public class YggdrasilLogin
116+
{
117+
public required string username;
118+
public required string password;
119+
public bool requestUser = true;
120+
public Agent agent = new();
121+
}
122+
public record Agent
123+
{
124+
public string name = "minecraft";
125+
public int version = 1;
126+
}
99127
}

SuikaiLauncher.Core.Account/Modules/Yggdrasil.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public async static Task<string> GetAPILocation(string YggdrasilAPIAddress,Login
6565
);
6666
var UserAuthData = await FileIO.ReadAsString(UserAuthResult);
6767
if (!UserAuthResult.IsSuccessStatusCode){
68-
YggdrasilAuthError Result = Json.GetJson<YggdrasilAuthError>(UserAuthData);
68+
YggdrasilAuthError Result = Json.Deserialize<YggdrasilAuthError>(UserAuthData);
6969
Logger.Log($"[Account] 第三方登录失败:远程服务器返回错误:{UserAuthResult.StatusCode}");
7070
List<string> ErrorReason = new ();
7171
try
Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
1+
using System.Net;
2+
13
namespace SuikaiLauncher.Core.Account.Yggdrasil{
2-
public class Yggdrasil{
3-
4+
public class YggdrasilServer{
5+
private static HttpListener Server = new();
6+
public static async Task StartHttpServer()
7+
{
8+
if (Server.IsListening) return;
9+
Server.Prefixes.Add("http://127.0.0.1:29997");
10+
Server.Start();
11+
12+
}
13+
public static async Task RouteRequest(HttpListenerContext Context)
14+
{
15+
string? RequestPath = Context.Request.Url?.AbsolutePath;
16+
if (RequestPath is null) RequestPath = "/";
17+
while (RequestPath.Contains("//"))
18+
{
19+
RequestPath = RequestPath.Replace("//", "/");
20+
}
21+
switch (RequestPath)
22+
{
23+
case "/":
24+
25+
break;
26+
}
27+
}
428
}
529
}

SuikaiLauncher.Core.Account/SuikaiLauncher.Core.Account.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@
1111
</ItemGroup>
1212

1313
</Project>
14+
15+

0 commit comments

Comments
 (0)