package net.minecraft.launcher.authentication.yggdrasil;
import com.google.gson.Gson;
import com.google.gson.JsonParseException;
import net.minecraft.hopper.Util;
import net.minecraft.launcher.Launcher;
import net.minecraft.launcher.authentication.BaseAuthenticationService;
import net.minecraft.launcher.authentication.GameProfile;
import net.minecraft.launcher.authentication.exceptions.AuthenticationException;
import net.minecraft.launcher.authentication.exceptions.InvalidCredentialsException;
import net.minecraft.launcher.authentication.exceptions.UserMigratedException;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.Map;
public class YggdrasilAuthenticationService extends BaseAuthenticationService {
private static final String BASE_URL = "https://authserver.mojang.com/";
private static final URL ROUTE_AUTHENTICATE = Util.constantURL("https://authserver.mojang.com/authenticate");
private static final URL ROUTE_REFRESH = Util.constantURL("https://authserver.mojang.com/refresh");
private static final URL ROUTE_VALIDATE = Util.constantURL("https://authserver.mojang.com/validate");
private static final URL ROUTE_INVALIDATE = Util.constantURL("https://authserver.mojang.com/invalidate");
private static final URL ROUTE_SIGNOUT = Util.constantURL("https://authserver.mojang.com/signout");
private static final String STORAGE_KEY_ACCESS_TOKEN = "accessToken";
private final Gson gson = new Gson();
private final Agent agent = Agent.MINECRAFT;
private GameProfile[] profiles;
private String accessToken;
private boolean isOnline;
public boolean canLogIn() {
return (!canPlayOnline()) && (StringUtils.isNotBlank(getUsername())) && ((StringUtils.isNotBlank(getPassword())) || (StringUtils.isNotBlank(getAccessToken())));
}
public void logIn() throws AuthenticationException {
if (StringUtils.isBlank(getUsername())) {
throw new InvalidCredentialsException("Invalid username");
}
if (StringUtils.isNotBlank(getAccessToken()))
logInWithToken();
else if (StringUtils.isNotBlank(getPassword()))
logInWithPassword();
else
throw new InvalidCredentialsException("Invalid password");
}
protected void logInWithPassword() throws AuthenticationException {
if (StringUtils.isBlank(getUsername())) {
throw new InvalidCredentialsException("Invalid username");
}
if (StringUtils.isBlank(getPassword())) {
throw new InvalidCredentialsException("Invalid password");
}
Launcher.getInstance().println("Logging in with username & password");
AuthenticationRequest request = new AuthenticationRequest(this, getPassword());
AuthenticationResponse response = (AuthenticationResponse) makeRequest(ROUTE_AUTHENTICATE, request, AuthenticationResponse.class);
if (!response.getClientToken().equals(getClientToken())) {
throw new AuthenticationException("Server requested we change our client token. Don't know how to handle this!");
}
this.accessToken = response.getAccessToken();
this.profiles = response.getAvailableProfiles();
setSelectedProfile(response.getSelectedProfile());
fireAuthenticationChangedEvent();
}
protected void logInWithToken() throws AuthenticationException {
if (StringUtils.isBlank(getUsername())) {
throw new InvalidCredentialsException("Invalid username");
}
if (StringUtils.isBlank(getAccessToken())) {
throw new InvalidCredentialsException("Invalid access token");
}
Launcher.getInstance().println("Logging in with access token");
RefreshRequest request = new RefreshRequest(this);
RefreshResponse response = (RefreshResponse) makeRequest(ROUTE_REFRESH, request, RefreshResponse.class);
if (!response.getClientToken().equals(getClientToken())) {
throw new AuthenticationException("Server requested we change our client token. Don't know how to handle this!");
}
this.accessToken = response.getAccessToken();
this.profiles = response.getAvailableProfiles();
setSelectedProfile(response.getSelectedProfile());
fireAuthenticationChangedEvent();
}
protected <T extends Response> T makeRequest(URL url, Object input, Class<T> classOfT) throws AuthenticationException {
try {
String jsonResult = Util.performPost(url, this.gson.toJson(input), Launcher.getInstance().getProxy(), "application/json", true);
Response result = (Response) this.gson.fromJson(jsonResult, classOfT);
if (result == null) return null;
if (StringUtils.isNotBlank(result.getError())) {
if ("UserMigratedException".equals(result.getCause()))
throw new UserMigratedException(result.getErrorMessage());
if (result.getError().equals("ForbiddenOperationException")) {
throw new InvalidCredentialsException(result.getErrorMessage());
}
throw new AuthenticationException(result.getErrorMessage());
}
this.isOnline = true;
return (T) result;
} catch (IOException e) {
throw new AuthenticationException("Cannot contact authentication server", e);
} catch (IllegalStateException e) {
throw new AuthenticationException("Cannot contact authentication server", e);
} catch (JsonParseException e) {
throw new AuthenticationException("Cannot contact authentication server", e);
}
}
public void logOut() {
super.logOut();
this.accessToken = null;
this.profiles = null;
this.isOnline = false;
}
public GameProfile[] getAvailableProfiles() {
return this.profiles;
}
public boolean isLoggedIn() {
return StringUtils.isNotBlank(this.accessToken);
}
public boolean canPlayOnline() {
return (isLoggedIn()) && (getSelectedProfile() != null) && (this.isOnline);
}
public void selectGameProfile(GameProfile profile) throws AuthenticationException {
if (!isLoggedIn()) {
throw new AuthenticationException("Cannot change game profile whilst not logged in");
}
if (getSelectedProfile() != null) {
throw new AuthenticationException("Cannot change game profile. You must log out and back in.");
}
if ((profile == null) || (!ArrayUtils.contains(this.profiles, profile))) {
throw new IllegalArgumentException("Invalid profile '" + profile + "'");
}
RefreshRequest request = new RefreshRequest(this, profile);
RefreshResponse response = (RefreshResponse) makeRequest(ROUTE_REFRESH, request, RefreshResponse.class);
if (!response.getClientToken().equals(getClientToken())) {
throw new AuthenticationException("Server requested we change our client token. Don't know how to handle this!");
}
this.accessToken = response.getAccessToken();
setSelectedProfile(response.getSelectedProfile());
fireAuthenticationChangedEvent();
}
public void loadFromStorage(Map<String, String> credentials) {
super.loadFromStorage(credentials);
this.accessToken = ((String) credentials.get("accessToken"));
}
public Map<String, String> saveForStorage() {
Map result = super.saveForStorage();
if (!shouldRememberMe()) return result;
if (StringUtils.isNotBlank(getAccessToken())) {
result.put("accessToken", getAccessToken());
}
return result;
}
public String getSessionToken() {
if ((isLoggedIn()) && (getSelectedProfile() != null) && (canPlayOnline())) {
return String.format("token:%s:%s", new Object[]{getAccessToken(), getSelectedProfile().getId()});
}
return null;
}
public String getAccessToken() {
return this.accessToken;
}
public String getClientToken() {
return Launcher.getInstance().getClientToken().toString();
}
public Agent getAgent() {
return this.agent;
}
public String toString() {
return "YggdrasilAuthenticationService{agent=" + this.agent + ", profiles=" + Arrays.toString(this.profiles) + ", selectedProfile=" + getSelectedProfile() + ", sessionToken='" + getSessionToken() + '\'' + ", username='" + getUsername() + '\'' + ", isLoggedIn=" + isLoggedIn() + ", canPlayOnline=" + canPlayOnline() + ", accessToken='" + this.accessToken + '\'' + ", clientToken='" + getClientToken() + '\'' + '}';
}
}