From b7a5b484b5236d0795319ef37915907b54f07e06 Mon Sep 17 00:00:00 2001 From: Burning_TNT <88144530+burningtnt@users.noreply.github.com> Date: Sat, 20 Jul 2024 01:56:13 +0800 Subject: [PATCH] =?UTF-8?q?[=E9=87=8D=E8=A6=81]=20=E5=AE=9E=E7=8E=B0=20#30?= =?UTF-8?q?95=20=E5=BE=AE=E8=BD=AF=E7=99=BB=E5=BD=95=E7=95=8C=E9=9D=A2?= =?UTF-8?q?=E5=AF=B9=20XBox=20400=20=E9=94=99=E8=AF=AF=E7=BB=99=E4=BA=88?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=20(#3121)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix #3095 * Fix * Update I18N_zh_CN.properties --------- Co-authored-by: Glavo --- .../org/jackhuang/hmcl/setting/Accounts.java | 11 ++++-- .../resources/assets/lang/I18N.properties | 1 + .../resources/assets/lang/I18N_zh.properties | 1 + .../assets/lang/I18N_zh_CN.properties | 11 +++--- .../hmcl/auth/microsoft/MicrosoftService.java | 39 ++++++++++++------- .../jackhuang/hmcl/util/io/HttpRequest.java | 11 ++++-- .../hmcl/util/io/ResponseCodeException.java | 7 ++++ 7 files changed, 57 insertions(+), 24 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Accounts.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Accounts.java index c96b56cfa..6223c6da8 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Accounts.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Accounts.java @@ -54,17 +54,19 @@ import static org.jackhuang.hmcl.setting.ConfigHolder.config; import static org.jackhuang.hmcl.ui.FXUtils.onInvalidating; import static org.jackhuang.hmcl.util.Lang.immutableListOf; import static org.jackhuang.hmcl.util.Lang.mapOf; -import static org.jackhuang.hmcl.util.logging.Logger.LOG; import static org.jackhuang.hmcl.util.Pair.pair; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; +import static org.jackhuang.hmcl.util.logging.Logger.LOG; /** * @author huangyuhui */ public final class Accounts { - private Accounts() {} + private Accounts() { + } private static final AuthlibInjectorArtifactProvider AUTHLIB_INJECTOR_DOWNLOADER = createAuthlibInjectorArtifactProvider(); + private static void triggerAuthlibInjectorUpdateCheck() { if (AUTHLIB_INJECTOR_DOWNLOADER instanceof AuthlibInjectorDownloader) { Schedulers.io().execute(() -> { @@ -87,6 +89,7 @@ public final class Accounts { // ==== login type / account factory mapping ==== private static final Map> type2factory = new HashMap<>(); private static final Map, String> factory2type = new HashMap<>(); + static { type2factory.put("offline", FACTORY_OFFLINE); type2factory.put("authlibInjector", FACTORY_AUTHLIB_INJECTOR); @@ -130,7 +133,7 @@ public final class Accounts { private static final String GLOBAL_PREFIX = "$GLOBAL:"; private static final ObservableList> globalAccountStorages = FXCollections.observableArrayList(); - private static final ObservableList accounts = observableArrayList(account -> new Observable[] { account }); + private static final ObservableList accounts = observableArrayList(account -> new Observable[]{account}); private static final ObjectProperty selectedAccount = new SimpleObjectProperty<>(Accounts.class, "selectedAccount"); /** @@ -465,6 +468,8 @@ public final class Accounts { } else { return i18n("account.methods.microsoft.error.unknown", errorCode); } + } else if (exception instanceof MicrosoftService.XBox400Exception) { + return i18n("account.methods.microsoft.error.wrong_verify_method"); } else if (exception instanceof MicrosoftService.NoMinecraftJavaEditionProfileException) { return i18n("account.methods.microsoft.error.no_character"); } else if (exception instanceof MicrosoftService.NoXuiException) { diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 77ed7f419..cbafeefbb 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -107,6 +107,7 @@ account.methods.microsoft.error.country_unavailable=Xbox Live is not available i account.methods.microsoft.error.missing_xbox_account=Your Microsoft account does not have a linked Xbox account yet. Please create one before continuing. account.methods.microsoft.error.no_character=Your account does not own the Minecraft Java Edition.\nThe game profile may not have been created,\nplease click the link above to create it. account.methods.microsoft.error.unknown=Failed to log in, error: %d. +account.methods.microsoft.error.wrong_verify_method=Please log in using your account & password on the Microsoft account login page. Please do not use a verification code to log in. account.methods.microsoft.logging_in=Logging in... account.methods.microsoft.hint=Please click on the "login" button, and copy the code shown here later to finish the login process in the opened browser window.\n\ \n\ diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 0063a9cb9..2cdb8948d 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -106,6 +106,7 @@ account.methods.microsoft.error.country_unavailable=你所在的國家或地區 account.methods.microsoft.error.missing_xbox_account=你的微軟帳號尚未關聯 XBox 帳號,你必須先創建 XBox 帳號,才能登入遊戲。 account.methods.microsoft.error.no_character=該帳戶未包含 Minecraft Java 版購買記錄\n可能未創建遊戲檔案,請點擊上方鏈接創建 account.methods.microsoft.error.unknown=登入失敗,錯誤碼:%d +account.methods.microsoft.error.wrong_verify_method=請在 Microsoft 帳號登陸頁面使用帳號 + 密碼登入。請不要使用驗證碼登入。 account.methods.microsoft.logging_in=登入中... account.methods.microsoft.makegameidsettings=創建檔案/編輯檔案名稱 account.methods.microsoft.hint=你需要按照以下步驟添加賬戶:\n\ diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index ee0fca1ee..ac4cb2e15 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -101,12 +101,13 @@ account.methods.microsoft=微软账户 account.methods.microsoft.birth=如何修改账户出生日期 account.methods.microsoft.close_page=已完成微软账户授权,接下来启动器还需要完成剩余登录步骤。你已经可以关闭本页面了。 account.methods.microsoft.deauthorize=解除账户授权 -account.methods.microsoft.error.add_family=由于你未满 18 岁,你的账户必须被加入到家庭中才能登录游戏。你也可以点击上方【账户设置页】更改你的账户的出生日期,使年龄满 18 岁以上以继续登录。\n你可以点击右上角帮助按钮进行求助。 -account.methods.microsoft.error.add_family_probably=请检查你的账户设置,如果年龄未满 18 岁,你的账户必须被加入到家庭中才能登录游戏。你也可以点击上方链接更改你的账户的出生日期,使年龄满 18 岁以上以继续登录。\n你可以点击右上角帮助按钮进行求助。 +account.methods.microsoft.error.add_family=请点击上方【账户设置页】更改你的账户的出生日期,使年龄满 18 岁以上。或将账户加入到家庭中。\n你可以点击右上角帮助按钮进行求助。 +account.methods.microsoft.error.add_family_probably=请点击上方【账户设置页】更改你的账户的出生日期,使年龄满 18 岁以上。或将账户加入到家庭中。\n你可以点击右上角帮助按钮进行求助。 account.methods.microsoft.error.country_unavailable=你所在的国家或地区不受 XBox Live 的支持。 -account.methods.microsoft.error.missing_xbox_account=你的微软账户尚未关联 XBox 账户,你必须先创建 XBox 账户,才能登录游戏。\n你可以点击右上角帮助按钮进行求助。 -account.methods.microsoft.error.no_character=该账户未包含 Minecraft Java 版购买记录\n若已购买,则可能未创建游戏档案,请点击上方链接创建。\n若确定该账户完成了上述步骤,请先在 Minecraft 官网(minecraft.net)登录一次账户,然后再在启动器登录。\n你可以点击右上角帮助按钮进行求助。 -account.methods.microsoft.error.unknown=登录失败,错误码:%d +account.methods.microsoft.error.missing_xbox_account=请点击上方【创建档案】关联 XBox 账户。\n你可以点击右上角帮助按钮进行求助。 +account.methods.microsoft.error.no_character=请确认你购买了 Minecraft: Java 版。若已购买,该账户未包含 Minecraft Java 版购买记录\n请点击【创建档案】创建游戏档案。\n你可以点击右上角帮助按钮进行求助。 +account.methods.microsoft.error.unknown=未知问题。错误码:%d。\n你可以点击右上角帮助按钮进行求助。 +account.methods.microsoft.error.wrong_verify_method=请在 Microsoft 账户登陆页面使用账户 + 密码登录。请不要使用验证码登录。\n你可以点击右上角帮助按钮进行求助。 account.methods.microsoft.logging_in=登录中…… account.methods.microsoft.makegameidsettings=创建档案/编辑档案名称 account.methods.microsoft.hint=你需要按照以下步骤添加账户:\n\ diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/microsoft/MicrosoftService.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/microsoft/MicrosoftService.java index 79e4a32d1..ae3bc1b8c 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/microsoft/MicrosoftService.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/microsoft/MicrosoftService.java @@ -21,8 +21,10 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; import com.google.gson.annotations.SerializedName; -import org.jackhuang.hmcl.auth.*; +import org.jackhuang.hmcl.auth.AuthenticationException; import org.jackhuang.hmcl.auth.OAuth; +import org.jackhuang.hmcl.auth.ServerDisconnectException; +import org.jackhuang.hmcl.auth.ServerResponseMalformedException; import org.jackhuang.hmcl.auth.yggdrasil.CompleteGameProfile; import org.jackhuang.hmcl.auth.yggdrasil.RemoteAuthenticationException; import org.jackhuang.hmcl.auth.yggdrasil.Texture; @@ -44,8 +46,8 @@ import static java.net.HttpURLConnection.HTTP_NOT_FOUND; import static java.util.Objects.requireNonNull; import static org.jackhuang.hmcl.util.Lang.mapOf; import static org.jackhuang.hmcl.util.Lang.threadPool; -import static org.jackhuang.hmcl.util.logging.Logger.LOG; import static org.jackhuang.hmcl.util.Pair.pair; +import static org.jackhuang.hmcl.util.logging.Logger.LOG; public class MicrosoftService { private static final String SCOPE = "XboxLive.signin offline_access"; @@ -123,17 +125,25 @@ public class MicrosoftService { String uhs = getUhs(xboxResponse, null); - // Authenticate Minecraft with XSTS - XBoxLiveAuthenticationResponse minecraftXstsResponse = HttpRequest - .POST("https://xsts.auth.xboxlive.com/xsts/authorize") - .json(mapOf( - pair("Properties", - mapOf(pair("SandboxId", "RETAIL"), - pair("UserTokens", Collections.singletonList(xboxResponse.token)))), - pair("RelyingParty", "rp://api.minecraftservices.com/"), pair("TokenType", "JWT"))) - .ignoreHttpErrorCode(401) - .retry(5) - .getJson(XBoxLiveAuthenticationResponse.class); + XBoxLiveAuthenticationResponse minecraftXstsResponse; + try { + minecraftXstsResponse = HttpRequest + .POST("https://xsts.auth.xboxlive.com/xsts/authorize") + .json(mapOf( + pair("Properties", + mapOf(pair("SandboxId", "RETAIL"), + pair("UserTokens", Collections.singletonList(xboxResponse.token)))), + pair("RelyingParty", "rp://api.minecraftservices.com/"), pair("TokenType", "JWT"))) + .ignoreHttpErrorCode(401) + .retry(5) + .getJson(XBoxLiveAuthenticationResponse.class); + } catch (ResponseCodeException e) { + if (e.getResponseCode() == 400) { + throw new XBox400Exception(); + } + + throw e; + } getUhs(minecraftXstsResponse, uhs); @@ -290,6 +300,9 @@ public class MicrosoftService { public static final long ADD_FAMILY = 2148916238L; } + public static class XBox400Exception extends AuthenticationException { + } + public static class NoMinecraftJavaEditionProfileException extends AuthenticationException { } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/HttpRequest.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/HttpRequest.java index c8dbc8792..29dd6d504 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/HttpRequest.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/HttpRequest.java @@ -187,13 +187,18 @@ public abstract class HttpRequest { os.write(bytes); } + URL url = new URL(this.url); + if (responseCodeTester != null) { - responseCodeTester.accept(new URL(url), con.getResponseCode()); + responseCodeTester.accept(url, con.getResponseCode()); } else { if (con.getResponseCode() / 100 != 2) { if (!ignoreHttpCode && !toleratedHttpCodes.contains(con.getResponseCode())) { - String data = NetworkUtils.readData(con); - throw new ResponseCodeException(new URL(url), con.getResponseCode(), data); + try { + throw new ResponseCodeException(url, con.getResponseCode(), NetworkUtils.readData(con)); + } catch (IOException e) { + throw new ResponseCodeException(url, con.getResponseCode(), e); + } } } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/ResponseCodeException.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/ResponseCodeException.java index 19d4d9a3f..b38649764 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/ResponseCodeException.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/ResponseCodeException.java @@ -33,6 +33,13 @@ public final class ResponseCodeException extends IOException { this.data = null; } + public ResponseCodeException(URL url, int responseCode, Throwable cause) { + super("Unable to request url " + url + ", response code: " + responseCode, cause); + this.url = url; + this.responseCode = responseCode; + this.data = null; + } + public ResponseCodeException(URL url, int responseCode, String data) { super("Unable to request url " + url + ", response code: " + responseCode + ", data: " + data); this.url = url;