diff --git a/Authentication/MicrosoftAuthentication.cs b/Authentication/MicrosoftAuthentication.cs index 945d28b..d7bf125 100644 --- a/Authentication/MicrosoftAuthentication.cs +++ b/Authentication/MicrosoftAuthentication.cs @@ -104,6 +104,31 @@ public async ValueTask GetTokenResponse(RetrieveDeviceCode dev ClientId = deviceCodeInfo.ClientId }; } + else + { + // 先判断是否正在等待中,直接使用 Contains,避免额外解析开销 + if (!tokenJson.Contains("authorization_pending")) + { + try + { + var errorData = tokenJson.ToJsonEntry(); + switch (errorData.Error) + { + case "authorization_declined": + throw new Exception("用户拒绝了授权"); + case "bad_verification_code": + throw new Exception("提交的 device_code 无效"); + case "expired_token": + throw new TimeoutException("登录已超时,请重试"); // 避免轮询时正好过期导致抓不到异常 + // 实际上还有其他的错误类型,但按理说不会出现,比如 slow_down + } + } + catch (Exception e) + { + throw new Exception("轮询获取 Token 错误:" + e.Message); + } + } + } await Task.Delay(pollingInterval); } diff --git a/Models/Authentication/GetTokenErrorResponse.cs b/Models/Authentication/GetTokenErrorResponse.cs new file mode 100644 index 0000000..d552a33 --- /dev/null +++ b/Models/Authentication/GetTokenErrorResponse.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace StarLight_Core.Models.Authentication; + +/// +/// 令牌错误信息 +/// +public class GetTokenErrorResponse +{ + /// + /// 验证令牌 + /// + [JsonPropertyName("error")] + public string Error { get; set; } +} \ No newline at end of file diff --git a/Skin/Fetchers/YggdrasilSkinFetcher.cs b/Skin/Fetchers/YggdrasilSkinFetcher.cs new file mode 100644 index 0000000..4fffda8 --- /dev/null +++ b/Skin/Fetchers/YggdrasilSkinFetcher.cs @@ -0,0 +1,44 @@ +using StarLight_Core.Models.Authentication; +using StarLight_Core.Models.Skin; +using StarLight_Core.Utilities; +using System.Security.Cryptography.X509Certificates; +using System.Security.Principal; +using System.Text; + +namespace StarLight_Core.Skin.Fetchers; + +/// +/// 外置皮肤获取器 +/// +public class YggdrasilSkinFetcher +{ + /// + /// 获取外置皮肤 + /// + /// 外置账户 + /// 皮肤图片字节信息 + public static async Task GetYggdrasilSkinAsync(YggdrasilAccount account) + { + return await GetYggdrasilSkinAsync(account.ServerUrl, account.Uuid); + } + + /// + /// 获取外置皮肤 + /// + /// 服务器 Url + /// 外置账户 Uuid + /// + public static async Task GetYggdrasilSkinAsync(string serverUrl, string uuid) + { + var baseUrl = serverUrl.TrimEnd("/"); + var skinJson = await HttpUtil.GetStringAsync($"{baseUrl}/sessionserver/session/minecraft/profile/{uuid}"); + var skinUrl = + Encoding.UTF8.GetString( + Convert.FromBase64String( + skinJson.ToJsonEntry().Properties.First().Value)) + .ToJsonEntry() + .Textures.Skin.Url; + using var httpClient = new HttpClient(); + return await httpClient.GetByteArrayAsync(skinUrl); + } +} \ No newline at end of file