150 lines
6.5 KiB
Java
150 lines
6.5 KiB
Java
package io.gitlab.jfronny.inceptum.launcher.api.account;
|
|
|
|
import io.gitlab.jfronny.commons.http.server.JLHTTPServer;
|
|
import io.gitlab.jfronny.commons.http.server.util.VirtualHost;
|
|
import io.gitlab.jfronny.inceptum.common.Utils;
|
|
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
|
|
import io.gitlab.jfronny.inceptum.launcher.model.microsoft.Entitlements;
|
|
import io.gitlab.jfronny.inceptum.launcher.model.microsoft.Profile;
|
|
import io.gitlab.jfronny.inceptum.launcher.model.microsoft.response.*;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
import java.io.Closeable;
|
|
import java.io.IOException;
|
|
import java.net.URLDecoder;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.Objects;
|
|
|
|
public class MicrosoftAuthServer implements Closeable {
|
|
private static final JLHTTPServer server = new JLHTTPServer(MicrosoftAuthAPI.MICROSOFT_LOGIN_REDIRECT_PORT);
|
|
private static final VirtualHost host = server.getVirtualHost(null);
|
|
|
|
private final MicrosoftAccount previous;
|
|
|
|
public MicrosoftAuthServer(@Nullable MicrosoftAccount previous) {
|
|
this.previous = previous;
|
|
}
|
|
|
|
public void start() throws IOException {
|
|
host.addContext("/", (req, res) -> {
|
|
if (req.getParams().containsKey("error")) {
|
|
res.getHeaders().add("Content-Type", "text/plain");
|
|
res.send(500, "Error logging in. Check console for more information");
|
|
Utils.LOGGER.error("Error logging into Microsoft account: " + URLDecoder
|
|
.decode(req.getParams().get("error_description"), StandardCharsets.UTF_8));
|
|
close();
|
|
return 0;
|
|
}
|
|
|
|
if (!req.getParams().containsKey("code")) {
|
|
res.getHeaders().add("Content-Type", "text/plain");
|
|
res.send(400, "Code is missing");
|
|
close();
|
|
return 0;
|
|
}
|
|
|
|
try {
|
|
acquireAccessToken(req.getParams().get("code"));
|
|
} catch (Exception e) {
|
|
Utils.LOGGER.error("Error acquiring accessToken", e);
|
|
res.getHeaders().add("Content-Type", "text/html");
|
|
res.send(500, "Error logging in. Check console for more information");
|
|
close();
|
|
return 0;
|
|
}
|
|
|
|
res.getHeaders().add("Content-Type", "text/plain");
|
|
// #. {0} is the name of the launcher
|
|
res.send(200, "Login complete. You can now close this window and go back to the Launcher");
|
|
close();
|
|
return 0;
|
|
}, "GET");
|
|
|
|
server.start();
|
|
}
|
|
|
|
private void addAccount(OauthTokenResponse oauthTokenResponse, XboxLiveAuthResponse xstsAuthResponse, LoginResponse loginResponse, Profile profile) {
|
|
if (this.previous != null || AccountManager.isAccountByName(loginResponse.username())) {
|
|
MicrosoftAccount account = (MicrosoftAccount) AccountManager.getAccountByName(loginResponse.username());
|
|
|
|
if (account == null) {
|
|
return;
|
|
}
|
|
|
|
// if forced to relogin, then make sure they logged into correct account
|
|
if (this.previous != null && !Objects.equals(account.accountId, this.previous.accountId)) {
|
|
LauncherEnv.showError("Logged into incorrect account. Please login again on the Accounts tab", "Incorrect account");
|
|
return;
|
|
}
|
|
|
|
account.update(oauthTokenResponse, xstsAuthResponse, loginResponse, profile);
|
|
AccountManager.saveAccounts();
|
|
} else {
|
|
MicrosoftAccount account = new MicrosoftAccount(oauthTokenResponse, xstsAuthResponse, loginResponse, profile);
|
|
AccountManager.addAccount(account);
|
|
}
|
|
}
|
|
|
|
private void acquireAccessToken(String authcode) throws Exception {
|
|
OauthTokenResponse oauthTokenResponse = MicrosoftAuthAPI.tradeCodeForAccessToken(authcode);
|
|
|
|
acquireXBLToken(oauthTokenResponse);
|
|
}
|
|
|
|
private void acquireXBLToken(OauthTokenResponse oauthTokenResponse) throws Exception {
|
|
XboxLiveAuthResponse xblAuthResponse = MicrosoftAuthAPI.getXBLToken(oauthTokenResponse.accessToken());
|
|
|
|
acquireXsts(oauthTokenResponse, xblAuthResponse.token());
|
|
}
|
|
|
|
private void acquireXsts(OauthTokenResponse oauthTokenResponse, String xblToken) throws Exception {
|
|
XboxLiveAuthResponse xstsAuthResponse = MicrosoftAuthAPI.getXstsToken(xblToken);
|
|
|
|
if (xstsAuthResponse != null) {
|
|
acquireMinecraftToken(oauthTokenResponse, xstsAuthResponse);
|
|
}
|
|
}
|
|
|
|
private void acquireMinecraftToken(OauthTokenResponse oauthTokenResponse, XboxLiveAuthResponse xstsAuthResponse) throws Exception {
|
|
LoginResponse loginResponse = MicrosoftAuthAPI.loginToMinecraft("XBL3.0 x=" + xstsAuthResponse.displayClaims().xui().get(0).uhs() + ";" + xstsAuthResponse.token());
|
|
|
|
if (loginResponse == null) {
|
|
throw new Exception("Failed to login to Minecraft");
|
|
}
|
|
|
|
Entitlements entitlements = MicrosoftAuthAPI.getEntitlements(loginResponse.accessToken());
|
|
|
|
if (!(entitlements.items().stream().anyMatch(i -> i.name().equalsIgnoreCase("product_minecraft"))
|
|
&& entitlements.items().stream().anyMatch(i -> i.name().equalsIgnoreCase("game_minecraft")))) {
|
|
LauncherEnv.showError("This account doesn't have a valid purchase of Minecraft.\nPlease make sure you've bought the Java edition of Minecraft and then try again.", "Doesn't own Minecraft");
|
|
throw new Exception("Account does not own Minecraft");
|
|
}
|
|
|
|
Profile profile = null;
|
|
|
|
try {
|
|
profile = MicrosoftAuthAPI.getMcProfile(loginResponse.accessToken());
|
|
} catch (Exception e) {
|
|
LauncherEnv.showError("""
|
|
No Minecraft profiles were found for this account. Have you purchased Minecraft?
|
|
Please make sure you've bought the Java edition of Minecraft and then try again.
|
|
If you're an Xbox Game Pass subscriber, make sure to login and play through the Minecraft
|
|
Launcher once in order to create your Minecraft profile, then try logging in again.""",
|
|
"Minecraft Profile Not Found");
|
|
throw new Exception("Minecraft Profile not found", e);
|
|
}
|
|
|
|
if (profile == null) {
|
|
throw new Exception("Failed to get Minecraft profile");
|
|
}
|
|
|
|
// add the account
|
|
addAccount(oauthTokenResponse, xstsAuthResponse, loginResponse, profile);
|
|
}
|
|
|
|
@Override
|
|
public void close() {
|
|
server.stop();
|
|
}
|
|
}
|