diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AddAccountPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AddAccountPane.java index 9b33c1e66..fb860f81a 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AddAccountPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AddAccountPane.java @@ -37,6 +37,7 @@ import javafx.scene.layout.*; import org.jackhuang.hmcl.auth.*; import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorDownloadException; import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer; +import org.jackhuang.hmcl.auth.microsoft.MicrosoftService; import org.jackhuang.hmcl.auth.yggdrasil.GameProfile; import org.jackhuang.hmcl.auth.yggdrasil.RemoteAuthenticationException; import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilService; @@ -385,6 +386,15 @@ public class AddAccountPane extends StackPane { return i18n("account.failed.character_deleted"); } else if (exception instanceof InvalidSkinException) { return i18n("account.skin.invalid_skin"); + } else if (exception instanceof MicrosoftService.XboxAuthorizationException) { + long errorCode = ((MicrosoftService.XboxAuthorizationException) exception).getErrorCode(); + if (errorCode == MicrosoftService.XboxAuthorizationException.ADD_FAMILY) { + return i18n("account.methods.microsoft.error.add_family"); + } else if (errorCode == MicrosoftService.XboxAuthorizationException.MISSING_XBOX_ACCOUNT) { + return i18n("account.methods.microsoft.error.missing_xbox_account"); + } else { + return i18n("account.methods.microsoft.error.unknown", errorCode); + } } else if (exception.getClass() == AuthenticationException.class) { return exception.getLocalizedMessage(); } else { diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index b4d5070e6..a4dea9cd1 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -66,6 +66,9 @@ account.methods=Login Type account.methods.authlib_injector=authlib-injector account.methods.microsoft=Microsoft Account account.methods.microsoft.close_page=Microsoft account authorization has been finished. There are some remaining logging-in steps to be finished later. You can close this page right now. +account.methods.microsoft.error.add_family=Since you are not yet 18 years old, an adult must add you to a family in order for you to play Minecraft. +account.methods.microsoft.error.missing_xbox_account=Your Microsoft account is not connected to an Xbox account. Please create one before continuing. +account.methods.microsoft.error.unknown=Failed to log in. Microsoft respond with error code %d. account.methods.microsoft.logging_in=Logging in... account.methods.microsoft.manual=You should finish authorization in the newly opened browser window. If the browser window failed to show, you can click here to copy the URL, and manually open it in your browser. account.methods.microsoft.waiting_browser=Waiting for authorization in opened browser window... 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 b4481edea..55c8ec27f 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -67,6 +67,9 @@ account.methods=登录方式 account.methods.authlib_injector=外置登录 (authlib-injector) account.methods.microsoft=微软登录 account.methods.microsoft.close_page=已完成微软账号授权,接下来启动器还需要完成剩余登录步骤。你已经可以关闭本页面了。 +account.methods.microsoft.error.add_family=由于你未满 18 岁,你的账号必须被加入到家庭中才能登录游戏。 +account.methods.microsoft.error.missing_xbox_account=你的微软账号尚未关联 XBox 账号,你必须先创建 XBox 账号,才能登录游戏。 +account.methods.microsoft.error.unknown=登录失败,错误码:%d account.methods.microsoft.logging_in=登录中... account.methods.microsoft.manual=您需要在新打开的浏览器窗口中完成登录。若页面未能打开,您可以点击此处复制链接,并手动在浏览器中打开网页。 account.methods.microsoft.waiting_browser=等待在新打开的浏览器窗口中完成登录... 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 c8408f48e..39cf204a7 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 @@ -138,6 +138,11 @@ public class MicrosoftService { pair("RpsTicket", "d=" + liveAccessToken))), pair("RelyingParty", "http://auth.xboxlive.com"), pair("TokenType", "JWT"))) .accept("application/json").getJson(XBoxLiveAuthenticationResponse.class); + + if (xboxResponse.errorCode != 0) { + throw new XboxAuthorizationException(xboxResponse.errorCode); + } + String uhs = (String) xboxResponse.displayClaims.xui.get(0).get("uhs"); // Authenticate Minecraft with XSTS @@ -149,6 +154,11 @@ public class MicrosoftService { pair("UserTokens", Collections.singletonList(xboxResponse.token)))), pair("RelyingParty", "rp://api.minecraftservices.com/"), pair("TokenType", "JWT"))) .getJson(XBoxLiveAuthenticationResponse.class); + + if (xboxResponse.errorCode != 0) { + throw new XboxAuthorizationException(xboxResponse.errorCode); + } + String minecraftXstsUhs = (String) minecraftXstsResponse.displayClaims.xui.get(0).get("uhs"); if (!Objects.equals(uhs, minecraftXstsUhs)) { throw new ServerResponseMalformedException("uhs mismatched"); @@ -163,6 +173,11 @@ public class MicrosoftService { pair("UserTokens", Collections.singletonList(xboxResponse.token)))), pair("RelyingParty", "http://xboxlive.com"), pair("TokenType", "JWT"))) .getJson(XBoxLiveAuthenticationResponse.class); + + if (xboxXstsResponse.errorCode != 0) { + throw new XboxAuthorizationException(xboxXstsResponse.errorCode); + } + String xboxXstsUhs = (String) xboxXstsResponse.displayClaims.xui.get(0).get("uhs"); if (!Objects.equals(uhs, xboxXstsUhs)) { throw new ServerResponseMalformedException("uhs mismatched"); @@ -260,6 +275,21 @@ public class MicrosoftService { return JsonUtils.fromNonNullJson(result, MinecraftProfileResponse.class); } + public static class XboxAuthorizationException extends AuthenticationException { + private final long errorCode; + + public XboxAuthorizationException(long errorCode) { + this.errorCode = errorCode; + } + + public long getErrorCode() { + return errorCode; + } + + public static final long MISSING_XBOX_ACCOUNT = 2148916233L; + public static final long ADD_FAMILY = 2148916238L; + } + /** * Error response: {"error":"invalid_grant","error_description":"The provided * value for the 'redirect_uri' is not valid. The value must exactly match the @@ -304,6 +334,17 @@ public class MicrosoftService { List> xui; } + private static class MicrosoftErrorResponse { + @SerializedName("XErr") + long errorCode; + + @SerializedName("Message") + String message; + + @SerializedName("Redirect") + String redirectUrl; + } + /** * * Success Response: { "IssueInstant":"2020-12-07T19:52:08.4463796Z", @@ -316,7 +357,7 @@ public class MicrosoftService { * XErr Candidates: 2148916233 = missing XBox account 2148916238 = child account * not linked to a family */ - private static class XBoxLiveAuthenticationResponse { + private static class XBoxLiveAuthenticationResponse extends MicrosoftErrorResponse { @SerializedName("IssueInstant") String issueInstant;