From 893cf379017ac33e586112fcb9cb2d82000cd25d Mon Sep 17 00:00:00 2001 From: ZeoNight Date: Wed, 18 May 2022 23:02:54 +0300 Subject: [PATCH] haha altening go brr --- build.gradle | 1 - lib/xauthlib-1.0.0.jar | Bin 57132 -> 0 bytes .../java/me/x150/authlib/AccountUtils.java | 48 +++ .../exception/AuthFailureException.java | 12 + .../authlib/login/altening/AlteningAuth.java | 63 ++++ .../microsoft/MicrosoftAuthenticator.java | 297 ++++++++++++++++++ .../login/microsoft/MicrosoftToken.java | 26 ++ .../login/microsoft/XboxLiveToken.java | 26 ++ .../authlib/login/microsoft/XboxToken.java | 10 + .../login/mojang/MinecraftAuthenticator.java | 179 +++++++++++ .../authlib/login/mojang/MinecraftToken.java | 26 ++ .../mojang/profile/MinecraftProfile.java | 32 ++ .../mojang/profile/MinecraftProfileCape.java | 12 + .../mojang/profile/MinecraftProfileSkin.java | 27 ++ .../me/x150/authlib/struct/AuthToken.java | 6 + .../me/x150/authlib/struct/Authenticator.java | 15 + .../me/x150/authlib/struct/OnlineTexture.java | 38 +++ .../feature/gui/screen/AltManagerScreen.java | 15 +- .../mixin/IMinecraftClientAccessor.java | 4 + 19 files changed, 831 insertions(+), 6 deletions(-) delete mode 100644 lib/xauthlib-1.0.0.jar create mode 100644 src/main/java/me/x150/authlib/AccountUtils.java create mode 100644 src/main/java/me/x150/authlib/exception/AuthFailureException.java create mode 100644 src/main/java/me/x150/authlib/login/altening/AlteningAuth.java create mode 100644 src/main/java/me/x150/authlib/login/microsoft/MicrosoftAuthenticator.java create mode 100644 src/main/java/me/x150/authlib/login/microsoft/MicrosoftToken.java create mode 100644 src/main/java/me/x150/authlib/login/microsoft/XboxLiveToken.java create mode 100644 src/main/java/me/x150/authlib/login/microsoft/XboxToken.java create mode 100644 src/main/java/me/x150/authlib/login/mojang/MinecraftAuthenticator.java create mode 100644 src/main/java/me/x150/authlib/login/mojang/MinecraftToken.java create mode 100644 src/main/java/me/x150/authlib/login/mojang/profile/MinecraftProfile.java create mode 100644 src/main/java/me/x150/authlib/login/mojang/profile/MinecraftProfileCape.java create mode 100644 src/main/java/me/x150/authlib/login/mojang/profile/MinecraftProfileSkin.java create mode 100644 src/main/java/me/x150/authlib/struct/AuthToken.java create mode 100644 src/main/java/me/x150/authlib/struct/Authenticator.java create mode 100644 src/main/java/me/x150/authlib/struct/OnlineTexture.java diff --git a/build.gradle b/build.gradle index 6811fde..7fdcd88 100644 --- a/build.gradle +++ b/build.gradle @@ -56,7 +56,6 @@ dependencies { impl("meteordevelopment:discord-ipc:1.1") - impl(name: "xauthlib-1.0.0") impl 'org.java-websocket:Java-WebSocket:1.5.3' configurations.impl.dependencies.each { diff --git a/lib/xauthlib-1.0.0.jar b/lib/xauthlib-1.0.0.jar deleted file mode 100644 index 7b410f3c12f7f63883563730e3778f43e66ca4a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57132 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

^+ST!^UZkQ|jx46bBnN_fE($cl3 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 O+|LMZeRrfAc=vy@-vBWH diff --git a/src/main/java/me/x150/authlib/AccountUtils.java b/src/main/java/me/x150/authlib/AccountUtils.java new file mode 100644 index 0000000..e6c2ec3 --- /dev/null +++ b/src/main/java/me/x150/authlib/AccountUtils.java @@ -0,0 +1,48 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client/). + * Copyright (c) 2021 Meteor Development. + */ + +package me.x150.authlib; + +import com.google.gson.Gson; +import com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService; + +import java.lang.reflect.Field; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Base64; + +public class AccountUtils { + public static void setBaseUrl(YggdrasilMinecraftSessionService service, String url) { + try { + Field field = service.getClass().getDeclaredField("baseUrl"); + field.setAccessible(true); + field.set(service, url); + } catch (IllegalAccessException | NoSuchFieldException e) { + e.printStackTrace(); + } + } + + public static void setJoinUrl(YggdrasilMinecraftSessionService service, String url) { + try { + Field field = service.getClass().getDeclaredField("joinUrl"); + field.setAccessible(true); + field.set(service, new URL(url)); + } catch (IllegalAccessException | NoSuchFieldException | MalformedURLException e) { + e.printStackTrace(); + } + } + + public static void setCheckUrl(YggdrasilMinecraftSessionService service, String url) { + try { + Field field = service.getClass().getDeclaredField("checkUrl"); + field.setAccessible(true); + field.set(service, new URL(url)); + } catch (IllegalAccessException | NoSuchFieldException | MalformedURLException e) { + e.printStackTrace(); + } + } + + +} diff --git a/src/main/java/me/x150/authlib/exception/AuthFailureException.java b/src/main/java/me/x150/authlib/exception/AuthFailureException.java new file mode 100644 index 0000000..909ea1a --- /dev/null +++ b/src/main/java/me/x150/authlib/exception/AuthFailureException.java @@ -0,0 +1,12 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// + +package me.x150.authlib.exception; + +public class AuthFailureException extends RuntimeException { + public AuthFailureException(String message) { + super(message); + } +} diff --git a/src/main/java/me/x150/authlib/login/altening/AlteningAuth.java b/src/main/java/me/x150/authlib/login/altening/AlteningAuth.java new file mode 100644 index 0000000..a042acb --- /dev/null +++ b/src/main/java/me/x150/authlib/login/altening/AlteningAuth.java @@ -0,0 +1,63 @@ +package me.x150.authlib.login.altening; + +import com.mojang.authlib.Agent; +import com.mojang.authlib.Environment; +import com.mojang.authlib.exceptions.AuthenticationException; +import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; +import com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService; +import com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication; +import me.x150.authlib.AccountUtils; +import me.x150.authlib.login.mojang.MinecraftToken; +import net.minecraft.client.util.Session; +import net.shadow.client.ShadowMain; +import net.shadow.client.mixin.IMinecraftClientAccessor; + +import java.util.Optional; + +public class AlteningAuth { + private static final String AUTH = "http://authserver.thealtening.com"; + private static final String ACCOUNT = "https://api.mojang.com"; + private static final String SESSION = "http://sessionserver.thealtening.com"; + private static final String SERVICES = "https://api.minecraftservices.com"; + String username; + String uuid; + String token; + private YggdrasilUserAuthentication getAuth() { + YggdrasilUserAuthentication yggdrasilUserAuthentication = (YggdrasilUserAuthentication)new YggdrasilAuthenticationService(((IMinecraftClientAccessor) ShadowMain.client).getProxy(), "", Environment.create((String)"http://authserver.thealtening.com", (String)"https://api.mojang.com", (String)"http://sessionserver.thealtening.com", (String)"https://api.minecraftservices.com", (String)"The Altening")).createUserAuthentication(Agent.MINECRAFT); + yggdrasilUserAuthentication.setUsername(token); + yggdrasilUserAuthentication.setPassword("(REAL)"); + return yggdrasilUserAuthentication; + } + public AlteningAuth(String token) { + this.token = token; + } + public boolean fetchInfo() { + YggdrasilUserAuthentication yggdrasilUserAuthentication = this.getAuth(); + try { + yggdrasilUserAuthentication.logIn(); + this.username = yggdrasilUserAuthentication.getSelectedProfile().getName(); + this.uuid = yggdrasilUserAuthentication.getSelectedProfile().getId().toString(); + return true; + } + catch (AuthenticationException authenticationException) { + return false; + } + } + public MinecraftToken login() { + fetchInfo(); + YggdrasilMinecraftSessionService yggdrasilMinecraftSessionService = (YggdrasilMinecraftSessionService) ShadowMain.client.getSessionService(); + AccountUtils.setBaseUrl(yggdrasilMinecraftSessionService, SESSION + "/session/minecraft/"); + AccountUtils.setJoinUrl(yggdrasilMinecraftSessionService, SESSION + "/session/minecraft/join"); + AccountUtils.setCheckUrl(yggdrasilMinecraftSessionService, SESSION + "/session/minecraft/hasJoined"); + YggdrasilUserAuthentication yggdrasilUserAuthentication = this.getAuth(); + try { + yggdrasilUserAuthentication.logIn(); + ((IMinecraftClientAccessor) ShadowMain.client).setSession(new Session(yggdrasilUserAuthentication.getSelectedProfile().getName(), yggdrasilUserAuthentication.getSelectedProfile().getId().toString(), yggdrasilUserAuthentication.getAuthenticatedToken(), Optional.empty(), Optional.empty(), Session.AccountType.MOJANG)); + this.username = yggdrasilUserAuthentication.getSelectedProfile().getName(); + return new MinecraftToken(yggdrasilUserAuthentication.getAuthenticatedToken(),username); + } + catch (AuthenticationException authenticationException) { + return null; + } + } +} diff --git a/src/main/java/me/x150/authlib/login/microsoft/MicrosoftAuthenticator.java b/src/main/java/me/x150/authlib/login/microsoft/MicrosoftAuthenticator.java new file mode 100644 index 0000000..227fc09 --- /dev/null +++ b/src/main/java/me/x150/authlib/login/microsoft/MicrosoftAuthenticator.java @@ -0,0 +1,297 @@ + + +package me.x150.authlib.login.microsoft; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.StringJoiner; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import me.x150.authlib.exception.AuthFailureException; +import me.x150.authlib.struct.Authenticator; + +public class MicrosoftAuthenticator extends Authenticator { + protected final String clientId = "00000000402b5328"; + protected final String scopeUrl = "service::user.auth.xboxlive.com::MBI_SSL"; + protected String loginUrl; + protected String loginCookie; + protected String loginPPFT; + + public MicrosoftAuthenticator() { + } + + public XboxToken login(String email, String password) { + MicrosoftToken microsoftToken = this.generateTokenPair(this.generateLoginCode(email, password)); + XboxLiveToken xboxLiveToken = this.generateXboxTokenPair(microsoftToken); + return this.generateXboxTokenPair(xboxLiveToken); + } + + private String generateLoginCode(String email, String password) { + try { + URL url = new URL("https://login.live.com/oauth20_authorize.srf?redirect_uri=https://login.live.com/oauth20_desktop.srf&scope=service::user.auth.xboxlive.com::MBI_SSL&display=touch&response_type=code&locale=en&client_id=00000000402b5328"); + HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection(); + InputStream inputStream = httpURLConnection.getResponseCode() == 200 ? httpURLConnection.getInputStream() : httpURLConnection.getErrorStream(); + this.loginCookie = httpURLConnection.getHeaderField("set-cookie"); + String responseData = (String)(new BufferedReader(new InputStreamReader(inputStream))).lines().collect(Collectors.joining()); + Matcher bodyMatcher = Pattern.compile("sFTTag:[ ]?'.*value=\"(.*)\"/>'").matcher(responseData); + if (bodyMatcher.find()) { + this.loginPPFT = bodyMatcher.group(1); + bodyMatcher = Pattern.compile("urlPost:[ ]?'(.+?(?='))").matcher(responseData); + if (!bodyMatcher.find()) { + throw new AuthFailureException("Authentication error. Could not find 'LOGIN-URL' tag from response!"); + } else { + this.loginUrl = bodyMatcher.group(1); + if (this.loginCookie != null && this.loginPPFT != null && this.loginUrl != null) { + return this.sendCodeData(email, password); + } else { + throw new AuthFailureException("Authentication error. Error in authentication process!"); + } + } + } else { + throw new AuthFailureException("Authentication error. Could not find 'LOGIN-PFTT' tag from response!"); + } + } catch (IOException var8) { + throw new AuthFailureException(String.format("Authentication error. Request could not be made! Cause: '%s'", var8.getMessage())); + } + } + + private String sendCodeData(String email, String password) { + Map requestData = new HashMap(); + requestData.put("login", email); + requestData.put("loginfmt", email); + requestData.put("passwd", password); + requestData.put("PPFT", this.loginPPFT); + String postData = this.encodeURL((Map)requestData); + + String authToken; + try { + byte[] data = postData.getBytes(StandardCharsets.UTF_8); + HttpURLConnection connection = (HttpURLConnection)(new URL(this.loginUrl)).openConnection(); + connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"); + connection.setRequestProperty("Content-Length", String.valueOf(data.length)); + connection.setRequestProperty("Cookie", this.loginCookie); + connection.setDoInput(true); + connection.setDoOutput(true); + OutputStream outputStream = connection.getOutputStream(); + + try { + outputStream.write(data); + } catch (Throwable var12) { + if (outputStream != null) { + try { + outputStream.close(); + } catch (Throwable var11) { + var12.addSuppressed(var11); + } + } + + throw var12; + } + + if (outputStream != null) { + outputStream.close(); + } + + if (connection.getResponseCode() != 200 || connection.getURL().toString().equals(this.loginUrl)) { + throw new AuthFailureException("Authentication error. Username or password is not valid."); + } + + Pattern pattern = Pattern.compile("[?|&]code=([\\w.-]+)"); + Matcher tokenMatcher = pattern.matcher(URLDecoder.decode(connection.getURL().toString(), StandardCharsets.UTF_8.name())); + if (!tokenMatcher.find()) { + throw new AuthFailureException("Authentication error. Could not handle data from response."); + } + + authToken = tokenMatcher.group(1); + } catch (IOException var13) { + throw new AuthFailureException(String.format("Authentication error. Request could not be made! Cause: '%s'", var13.getMessage())); + } + + this.loginUrl = null; + this.loginCookie = null; + this.loginPPFT = null; + return authToken; + } + + private void sendXboxRequest(HttpURLConnection httpURLConnection, JsonObject request, JsonObject properties) throws IOException { + request.add("Properties", properties); + String requestBody = request.toString(); + httpURLConnection.setFixedLengthStreamingMode(requestBody.length()); + httpURLConnection.setRequestProperty("Content-Type", "application/json"); + httpURLConnection.setRequestProperty("Accept", "application/json"); + httpURLConnection.connect(); + OutputStream outputStream = httpURLConnection.getOutputStream(); + + try { + outputStream.write(requestBody.getBytes(StandardCharsets.US_ASCII)); + } catch (Throwable var9) { + if (outputStream != null) { + try { + outputStream.close(); + } catch (Throwable var8) { + var9.addSuppressed(var8); + } + } + + throw var9; + } + + if (outputStream != null) { + outputStream.close(); + } + + } + + private MicrosoftToken generateTokenPair(String authToken) { + try { + Map arguments = new HashMap(); + arguments.put("client_id", "00000000402b5328"); + arguments.put("code", authToken); + arguments.put("grant_type", "authorization_code"); + arguments.put("redirect_uri", "https://login.live.com/oauth20_desktop.srf"); + arguments.put("scope", "service::user.auth.xboxlive.com::MBI_SSL"); + StringJoiner argumentBuilder = new StringJoiner("&"); + Iterator var4 = arguments.entrySet().iterator(); + + while(var4.hasNext()) { + Map.Entry entry = (Map.Entry)var4.next(); + argumentBuilder.add(this.encodeURL((String)entry.getKey()) + "=" + this.encodeURL((String)entry.getValue())); + } + + byte[] data = argumentBuilder.toString().getBytes(StandardCharsets.UTF_8); + URL url = new URL("https://login.live.com/oauth20_token.srf"); + URLConnection urlConnection = url.openConnection(); + HttpURLConnection httpURLConnection = (HttpURLConnection)urlConnection; + httpURLConnection.setRequestMethod("POST"); + httpURLConnection.setDoOutput(true); + httpURLConnection.setFixedLengthStreamingMode(data.length); + httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + httpURLConnection.connect(); + OutputStream outputStream = httpURLConnection.getOutputStream(); + + try { + outputStream.write(data); + } catch (Throwable var12) { + if (outputStream != null) { + try { + outputStream.close(); + } catch (Throwable var11) { + var12.addSuppressed(var11); + } + } + + throw var12; + } + + if (outputStream != null) { + outputStream.close(); + } + + JsonObject jsonObject = this.parseResponseData(httpURLConnection); + return new MicrosoftToken(jsonObject.get("access_token").getAsString(), jsonObject.get("refresh_token").getAsString()); + } catch (IOException var13) { + throw new AuthFailureException(String.format("Authentication error. Request could not be made! Cause: '%s'", var13.getMessage())); + } + } + + public XboxLiveToken generateXboxTokenPair(MicrosoftToken microsoftToken) { + try { + URL url = new URL("https://user.auth.xboxlive.com/user/authenticate"); + URLConnection urlConnection = url.openConnection(); + HttpURLConnection httpURLConnection = (HttpURLConnection)urlConnection; + httpURLConnection.setDoOutput(true); + JsonObject request = new JsonObject(); + request.addProperty("RelyingParty", "http://auth.xboxlive.com"); + request.addProperty("TokenType", "JWT"); + JsonObject properties = new JsonObject(); + properties.addProperty("AuthMethod", "RPS"); + properties.addProperty("SiteName", "user.auth.xboxlive.com"); + properties.addProperty("RpsTicket", microsoftToken.getToken()); + this.sendXboxRequest(httpURLConnection, request, properties); + JsonObject jsonObject = this.parseResponseData(httpURLConnection); + String uhs = ((JsonObject)jsonObject.getAsJsonObject("DisplayClaims").getAsJsonArray("xui").get(0)).get("uhs").getAsString(); + return new XboxLiveToken(jsonObject.get("Token").getAsString(), uhs); + } catch (IOException var9) { + throw new AuthFailureException(String.format("Authentication error. Request could not be made! Cause: '%s'", var9.getMessage())); + } + } + + public XboxToken generateXboxTokenPair(XboxLiveToken xboxLiveToken) { + try { + URL url = new URL("https://xsts.auth.xboxlive.com/xsts/authorize"); + URLConnection urlConnection = url.openConnection(); + HttpURLConnection httpURLConnection = (HttpURLConnection)urlConnection; + httpURLConnection.setRequestMethod("POST"); + httpURLConnection.setDoOutput(true); + JsonObject request = new JsonObject(); + request.addProperty("RelyingParty", "rp://api.minecraftservices.com/"); + request.addProperty("TokenType", "JWT"); + JsonObject properties = new JsonObject(); + properties.addProperty("SandboxId", "RETAIL"); + JsonArray userTokens = new JsonArray(); + userTokens.add(xboxLiveToken.getToken()); + properties.add("UserTokens", userTokens); + this.sendXboxRequest(httpURLConnection, request, properties); + if (httpURLConnection.getResponseCode() == 401) { + throw new AuthFailureException("No xbox account was found!"); + } else { + JsonObject jsonObject = this.parseResponseData(httpURLConnection); + String uhs = ((JsonObject)jsonObject.getAsJsonObject("DisplayClaims").getAsJsonArray("xui").get(0)).get("uhs").getAsString(); + return new XboxToken(jsonObject.get("Token").getAsString(), uhs); + } + } catch (IOException var10) { + throw new AuthFailureException(String.format("Authentication error. Request could not be made! Cause: '%s'", var10.getMessage())); + } + } + + public JsonObject parseResponseData(HttpURLConnection httpURLConnection) throws IOException { + BufferedReader bufferedReader; + if (httpURLConnection.getResponseCode() != 200) { + bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getErrorStream())); + } else { + bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream())); + } + + String lines = (String)bufferedReader.lines().collect(Collectors.joining()); + JsonObject jsonObject = (new JsonParser()).parse(lines).getAsJsonObject(); + if (jsonObject.has("error")) { + throw new AuthFailureException(jsonObject.get("error") + ": " + jsonObject.get("error_description")); + } else { + return jsonObject; + } + } + + private String encodeURL(String url) { + return URLEncoder.encode(url, StandardCharsets.UTF_8); + } + + private String encodeURL(Map map) { + StringBuilder sb = new StringBuilder(); + + Map.Entry entry; + for(Iterator var3 = map.entrySet().iterator(); var3.hasNext(); sb.append(String.format("%s=%s", this.encodeURL((String)entry.getKey()), this.encodeURL((String)entry.getValue())))) { + entry = (Map.Entry)var3.next(); + if (sb.length() > 0) { + sb.append("&"); + } + } + + return sb.toString(); + } +} diff --git a/src/main/java/me/x150/authlib/login/microsoft/MicrosoftToken.java b/src/main/java/me/x150/authlib/login/microsoft/MicrosoftToken.java new file mode 100644 index 0000000..d023025 --- /dev/null +++ b/src/main/java/me/x150/authlib/login/microsoft/MicrosoftToken.java @@ -0,0 +1,26 @@ + + +package me.x150.authlib.login.microsoft; + +import me.x150.authlib.struct.AuthToken; + +public class MicrosoftToken extends AuthToken { + protected String token; + protected String refreshToken; + + public MicrosoftToken() { + } + + public MicrosoftToken(String token, String refreshToken) { + this.token = token; + this.refreshToken = refreshToken; + } + + public String getToken() { + return this.token; + } + + public String getRefreshToken() { + return this.refreshToken; + } +} diff --git a/src/main/java/me/x150/authlib/login/microsoft/XboxLiveToken.java b/src/main/java/me/x150/authlib/login/microsoft/XboxLiveToken.java new file mode 100644 index 0000000..6510f4e --- /dev/null +++ b/src/main/java/me/x150/authlib/login/microsoft/XboxLiveToken.java @@ -0,0 +1,26 @@ + + +package me.x150.authlib.login.microsoft; + +import me.x150.authlib.struct.AuthToken; + +public class XboxLiveToken extends AuthToken { + protected String token; + protected String uhs; + + public XboxLiveToken() { + } + + public XboxLiveToken(String token, String uhs) { + this.token = token; + this.uhs = uhs; + } + + public String getToken() { + return this.token; + } + + public String getUhs() { + return this.uhs; + } +} diff --git a/src/main/java/me/x150/authlib/login/microsoft/XboxToken.java b/src/main/java/me/x150/authlib/login/microsoft/XboxToken.java new file mode 100644 index 0000000..30d51bd --- /dev/null +++ b/src/main/java/me/x150/authlib/login/microsoft/XboxToken.java @@ -0,0 +1,10 @@ +package me.x150.authlib.login.microsoft; + +public class XboxToken extends XboxLiveToken { + public XboxToken() { + } + + public XboxToken(String token, String uhs) { + super(token, uhs); + } +} diff --git a/src/main/java/me/x150/authlib/login/mojang/MinecraftAuthenticator.java b/src/main/java/me/x150/authlib/login/mojang/MinecraftAuthenticator.java new file mode 100644 index 0000000..ce00f1d --- /dev/null +++ b/src/main/java/me/x150/authlib/login/mojang/MinecraftAuthenticator.java @@ -0,0 +1,179 @@ +package me.x150.authlib.login.mojang; + +import com.google.gson.JsonObject; +import com.google.gson.reflect.TypeToken; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; +import me.x150.authlib.exception.AuthFailureException; +import me.x150.authlib.login.altening.AlteningAuth; +import me.x150.authlib.login.microsoft.MicrosoftAuthenticator; +import me.x150.authlib.login.microsoft.XboxToken; +import me.x150.authlib.login.mojang.MinecraftToken; +import me.x150.authlib.login.mojang.profile.MinecraftProfile; +import me.x150.authlib.login.mojang.profile.MinecraftProfileCape; +import me.x150.authlib.login.mojang.profile.MinecraftProfileSkin; +import me.x150.authlib.struct.Authenticator; + +public class MinecraftAuthenticator extends Authenticator { + protected final MicrosoftAuthenticator microsoftAuthenticator = new MicrosoftAuthenticator(); + + public MinecraftAuthenticator() { + } + + public MinecraftToken login(String email, String password) { + try { + URL url = new URL("https://authserver.mojang.com/authenticate"); + URLConnection urlConnection = url.openConnection(); + HttpURLConnection httpURLConnection = (HttpURLConnection)urlConnection; + httpURLConnection.setRequestMethod("POST"); + httpURLConnection.setDoOutput(true); + JsonObject request = new JsonObject(); + JsonObject agent = new JsonObject(); + agent.addProperty("name", "Minecraft"); + agent.addProperty("version", "1"); + request.add("agent", agent); + request.addProperty("username", email); + request.addProperty("password", password); + request.addProperty("requestUser", false); + String requestBody = request.toString(); + httpURLConnection.setFixedLengthStreamingMode(requestBody.length()); + httpURLConnection.setRequestProperty("Content-Type", "application/json"); + httpURLConnection.setRequestProperty("Host", "authserver.mojang.com"); + httpURLConnection.connect(); + OutputStream outputStream = httpURLConnection.getOutputStream(); + + try { + outputStream.write(requestBody.getBytes(StandardCharsets.US_ASCII)); + } catch (Throwable var13) { + if (outputStream != null) { + try { + outputStream.close(); + } catch (Throwable var12) { + var13.addSuppressed(var12); + } + } + + throw var13; + } + + if (outputStream != null) { + outputStream.close(); + } + + JsonObject jsonObject = this.parseResponseData(httpURLConnection); + return new MinecraftToken(jsonObject.get("accessToken").getAsString(), ((JsonObject)jsonObject.get("selectedProfile")).get("name").getAsString()); + } catch (IOException var14) { + throw new AuthFailureException(String.format("Authentication error. Request could not be made! Cause: '%s'", var14.getMessage())); + } + } + + public MinecraftToken loginWithMicrosoft(String email, String password) { + XboxToken xboxToken = this.microsoftAuthenticator.login(email, password); + + try { + URL url = new URL("https://api.minecraftservices.com/authentication/login_with_xbox"); + URLConnection urlConnection = url.openConnection(); + HttpURLConnection httpURLConnection = (HttpURLConnection)urlConnection; + httpURLConnection.setRequestMethod("POST"); + httpURLConnection.setDoOutput(true); + JsonObject request = new JsonObject(); + request.addProperty("identityToken", "XBL3.0 x=" + xboxToken.getUhs() + ";" + xboxToken.getToken()); + String requestBody = request.toString(); + httpURLConnection.setFixedLengthStreamingMode(requestBody.length()); + httpURLConnection.setRequestProperty("Content-Type", "application/json"); + httpURLConnection.setRequestProperty("Host", "api.minecraftservices.com"); + httpURLConnection.connect(); + OutputStream outputStream = httpURLConnection.getOutputStream(); + + try { + outputStream.write(requestBody.getBytes(StandardCharsets.US_ASCII)); + } catch (Throwable var13) { + if (outputStream != null) { + try { + outputStream.close(); + } catch (Throwable var12) { + var13.addSuppressed(var12); + } + } + + throw var13; + } + + if (outputStream != null) { + outputStream.close(); + } + + JsonObject jsonObject = this.microsoftAuthenticator.parseResponseData(httpURLConnection); + return new MinecraftToken(jsonObject.get("access_token").getAsString(), jsonObject.get("username").getAsString()); + } catch (IOException var14) { + throw new AuthFailureException(String.format("Authentication error. Request could not be made! Cause: '%s'", var14.getMessage())); + } + } + public MinecraftToken loginWithAltening(String token) { + AlteningAuth alteningAuth = new AlteningAuth(token); + return alteningAuth.login(); + } + + public MinecraftProfile getGameProfile(MinecraftToken minecraftToken) { + try { + URL url = new URL("https://api.minecraftservices.com/minecraft/profile"); + URLConnection urlConnection = url.openConnection(); + HttpURLConnection httpURLConnection = (HttpURLConnection)urlConnection; + httpURLConnection.setRequestMethod("GET"); + httpURLConnection.setRequestProperty("Authorization", "Bearer " + minecraftToken.getAccessToken()); + httpURLConnection.setRequestProperty("Host", "api.minecraftservices.com"); + httpURLConnection.connect(); + JsonObject jsonObject = this.parseResponseData(httpURLConnection); + UUID uuid = this.generateUUID(jsonObject.get("id").getAsString()); + String name = jsonObject.get("name").getAsString(); + + return new MinecraftProfile(uuid, name); + } catch (IOException var10) { + throw new AuthFailureException(String.format("Authentication error. Request could not be made! Cause: '%s'", var10.getMessage())); + } + } + + public JsonObject parseResponseData(HttpURLConnection httpURLConnection) throws IOException { + BufferedReader bufferedReader; + if (httpURLConnection.getResponseCode() != 200) { + bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getErrorStream())); + } else { + bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream())); + } + + String lines = (String)bufferedReader.lines().collect(Collectors.joining()); + JsonObject jsonObject = (JsonObject)this.gson.fromJson(lines, JsonObject.class); + if (jsonObject.has("error")) { + throw new AuthFailureException(String.format("Could not find profile!. Error: '%s'", jsonObject.get("errorMessage").getAsString())); + } else { + return jsonObject; + } + } + + public UUID generateUUID(String trimmedUUID) throws IllegalArgumentException { + if (trimmedUUID == null) { + throw new IllegalArgumentException(); + } else { + StringBuilder builder = new StringBuilder(trimmedUUID.trim()); + + try { + builder.insert(20, "-"); + builder.insert(16, "-"); + builder.insert(12, "-"); + builder.insert(8, "-"); + return UUID.fromString(builder.toString()); + } catch (StringIndexOutOfBoundsException var4) { + return null; + } + } + } +} diff --git a/src/main/java/me/x150/authlib/login/mojang/MinecraftToken.java b/src/main/java/me/x150/authlib/login/mojang/MinecraftToken.java new file mode 100644 index 0000000..45a933b --- /dev/null +++ b/src/main/java/me/x150/authlib/login/mojang/MinecraftToken.java @@ -0,0 +1,26 @@ +package me.x150.authlib.login.mojang; + +public class MinecraftToken { + private String accessToken; + private String username; + + public MinecraftToken() { + } + + public MinecraftToken(String accessToken, String username) { + this.accessToken = accessToken; + this.username = username; + } + + public String getAccessToken() { + return this.accessToken; + } + + public String getUsername() { + return this.username; + } + + public String toString() { + return "MinecraftToken{accessToken='" + this.accessToken + '\'' + ", username='" + this.username + '\'' + '}'; + } +} diff --git a/src/main/java/me/x150/authlib/login/mojang/profile/MinecraftProfile.java b/src/main/java/me/x150/authlib/login/mojang/profile/MinecraftProfile.java new file mode 100644 index 0000000..09e2a5d --- /dev/null +++ b/src/main/java/me/x150/authlib/login/mojang/profile/MinecraftProfile.java @@ -0,0 +1,32 @@ +package me.x150.authlib.login.mojang.profile; + +import java.util.List; +import java.util.UUID; + +public class MinecraftProfile { + private UUID uuid; + private String username; + + public MinecraftProfile() { + } + + public MinecraftProfile(UUID uuid, String username) { + this.uuid = uuid; + this.username = username; + + } + + public UUID getUuid() { + return this.uuid; + } + + public String getUsername() { + return this.username; + } + + + + public String toString() { + return "MinecraftProfile{uuid=" + this.uuid + ", username='" + this.username + '\'' + '}'; + } +} diff --git a/src/main/java/me/x150/authlib/login/mojang/profile/MinecraftProfileCape.java b/src/main/java/me/x150/authlib/login/mojang/profile/MinecraftProfileCape.java new file mode 100644 index 0000000..b85cbaf --- /dev/null +++ b/src/main/java/me/x150/authlib/login/mojang/profile/MinecraftProfileCape.java @@ -0,0 +1,12 @@ +package me.x150.authlib.login.mojang.profile; + +import me.x150.authlib.struct.OnlineTexture; + +public class MinecraftProfileCape extends OnlineTexture { + public MinecraftProfileCape() { + } + + public MinecraftProfileCape(String id, String state, String url, String alias) { + super(id, state, url, alias); + } +} diff --git a/src/main/java/me/x150/authlib/login/mojang/profile/MinecraftProfileSkin.java b/src/main/java/me/x150/authlib/login/mojang/profile/MinecraftProfileSkin.java new file mode 100644 index 0000000..9bada9b --- /dev/null +++ b/src/main/java/me/x150/authlib/login/mojang/profile/MinecraftProfileSkin.java @@ -0,0 +1,27 @@ +package me.x150.authlib.login.mojang.profile; + +import me.x150.authlib.struct.OnlineTexture; + +public class MinecraftProfileSkin extends OnlineTexture { + private String variant; + + public MinecraftProfileSkin() { + } + + public MinecraftProfileSkin(String variant) { + this.variant = variant; + } + + public MinecraftProfileSkin(String id, String state, String url, String alias, String variant) { + super(id, state, url, alias); + this.variant = variant; + } + + public String getVariant() { + return this.variant; + } + + public String toString() { + return "MinecraftSkin{id='" + this.getId() + '\'' + ", state='" + this.getState() + '\'' + ", url='" + this.getUrl() + '\'' + ", alias='" + this.getAlias() + '\'' + "variant='" + this.variant + '\'' + '}'; + } +} diff --git a/src/main/java/me/x150/authlib/struct/AuthToken.java b/src/main/java/me/x150/authlib/struct/AuthToken.java new file mode 100644 index 0000000..302c482 --- /dev/null +++ b/src/main/java/me/x150/authlib/struct/AuthToken.java @@ -0,0 +1,6 @@ +package me.x150.authlib.struct; + +public abstract class AuthToken { + public AuthToken() { + } +} diff --git a/src/main/java/me/x150/authlib/struct/Authenticator.java b/src/main/java/me/x150/authlib/struct/Authenticator.java new file mode 100644 index 0000000..55a661f --- /dev/null +++ b/src/main/java/me/x150/authlib/struct/Authenticator.java @@ -0,0 +1,15 @@ +package me.x150.authlib.struct; + +import com.google.gson.Gson; +import java.net.http.HttpClient; +import java.time.Duration; + +public abstract class Authenticator { + protected final Gson gson = new Gson(); + protected final HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10L)).build(); + + public Authenticator() { + } + + public abstract T login(String var1, String var2); +} diff --git a/src/main/java/me/x150/authlib/struct/OnlineTexture.java b/src/main/java/me/x150/authlib/struct/OnlineTexture.java new file mode 100644 index 0000000..1c5f474 --- /dev/null +++ b/src/main/java/me/x150/authlib/struct/OnlineTexture.java @@ -0,0 +1,38 @@ +package me.x150.authlib.struct; + +public abstract class OnlineTexture { + private String id; + private String state; + private String url; + private String alias; + + public OnlineTexture() { + } + + public OnlineTexture(String id, String state, String url, String alias) { + this.id = id; + this.state = state; + this.url = url; + this.alias = alias; + } + + public String getId() { + return this.id; + } + + public String getState() { + return this.state; + } + + public String getUrl() { + return this.url; + } + + public String getAlias() { + return this.alias; + } + + public String toString() { + return "TextureVariable{id='" + this.id + '\'' + ", state='" + this.state + '\'' + ", url='" + this.url + '\'' + ", alias='" + this.alias + '\'' + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/net/shadow/client/feature/gui/screen/AltManagerScreen.java b/src/main/java/net/shadow/client/feature/gui/screen/AltManagerScreen.java index ee16b02..200061b 100644 --- a/src/main/java/net/shadow/client/feature/gui/screen/AltManagerScreen.java +++ b/src/main/java/net/shadow/client/feature/gui/screen/AltManagerScreen.java @@ -233,10 +233,12 @@ public class AltManagerScreen extends ClientScreen implements FastTickable { new Thread(() -> { this.selectedAlt.login(); isLoggingIn.set(false); - if (!this.selectedAlt.storage.valid) { + // TODO: Actually fix this error instead of janky bypass + if (!this.selectedAlt.storage.valid && this.selectedAlt.storage.type != AddScreenOverlay.AccountType.ALTENING) { HudNotification.create("Failed to log in", 5000, HudNotification.Type.ERROR); return; } + if(this.selectedAlt.storage.type == AddScreenOverlay.AccountType.ALTENING) return; Session newSession = new Session(selectedAlt.storage.cachedName, selectedAlt.storage.cachedUuid.toString(), selectedAlt.storage.accessToken, Optional.empty(), Optional.empty(), Session.AccountType.MOJANG); ((IMinecraftClientAccessor) ShadowMain.client).setSession(newSession); HudNotification.create("Logged into account " + newSession.getUsername(), 5000, HudNotification.Type.INFO); @@ -337,7 +339,7 @@ public class AltManagerScreen extends ClientScreen implements FastTickable { RenderSystem.defaultBlendFunc(); String mail; - if (this.selectedAlt.storage.type != AddScreenOverlay.AccountType.CRACKED) { + if (this.selectedAlt.storage.type != AddScreenOverlay.AccountType.CRACKED || this.selectedAlt.storage.type != AddScreenOverlay.AccountType.ALTENING) { mail = this.selectedAlt.storage.email; String[] mailPart = mail.split("@"); String domain = mailPart[mailPart.length - 1]; @@ -671,7 +673,7 @@ public class AltManagerScreen extends ClientScreen implements FastTickable { protected void init() { RoundButton exit = new net.shadow.client.feature.gui.widget.RoundButton(net.shadow.client.feature.gui.widget.RoundButton.STANDARD, width - 20 - 5, 5, 20, 20, "X", () -> Objects.requireNonNull(client).setScreen(parent)); buttons.add(exit); - email = new RoundTextFieldWidget(width / 2d - (widgetWid - padding * 2) / 2d, height / 2d - widgetHei / 2d + padding, widgetWid - padding * 2, 20, "E-Mail or username"); + email = new RoundTextFieldWidget(width / 2d - (widgetWid - padding * 2) / 2d, height / 2d - widgetHei / 2d + padding, widgetWid - padding * 2, 20, "E-Mail or username or Token"); passwd = new RoundTextFieldWidget(width / 2d - (widgetWid - padding * 2) / 2d, height / 2d - widgetHei / 2d + padding * 2 + 20, widgetWid - padding * 2, 20, "Password"); type = new net.shadow.client.feature.gui.widget.RoundButton(net.shadow.client.feature.gui.widget.RoundButton.STANDARD, 0, 0, widgetWid / 2d - padding * 1.5, 20, "Type: " + AccountType.values()[accountTypeI].s, this::cycle); add = new net.shadow.client.feature.gui.widget.RoundButton(net.shadow.client.feature.gui.widget.RoundButton.STANDARD, 0, 0, widgetWid / 2d - padding * 1.5, 20, "Add", this::add); @@ -687,7 +689,7 @@ public class AltManagerScreen extends ClientScreen implements FastTickable { } boolean isAddApplicable() { - if (AccountType.values()[accountTypeI] == AccountType.CRACKED && !email.getText().isEmpty()) { + if (AccountType.values()[accountTypeI] == AccountType.CRACKED ||AccountType.values()[accountTypeI] == AccountType.ALTENING && !email.getText().isEmpty()) { return true; } else { return !email.getText().isEmpty() && !passwd.getText().isEmpty(); @@ -776,7 +778,7 @@ public class AltManagerScreen extends ClientScreen implements FastTickable { } enum AccountType { - MOJANG("Mojang"), MICROSOFT("Microsoft"), CRACKED("Cracked"); + MOJANG("Mojang"), MICROSOFT("Microsoft"), CRACKED("Cracked"), ALTENING("The Altening"); final String s; @@ -828,6 +830,7 @@ public class AltManagerScreen extends ClientScreen implements FastTickable { case MOJANG -> auth.login(storage.email, storage.password); case MICROSOFT -> auth.loginWithMicrosoft(storage.email, storage.password); case CRACKED -> null; + case ALTENING -> auth.loginWithAltening(storage.email); }; if (token == null && storage.password.equals("")) { storage.valid = true; @@ -840,9 +843,11 @@ public class AltManagerScreen extends ClientScreen implements FastTickable { throw new NullPointerException(); } storage.accessToken = token.getAccessToken(); + MinecraftProfile profile = auth.getGameProfile(token); storage.cachedName = profile.getUsername(); storage.cachedUuid = profile.getUuid(); + downloadTexture(); storage.valid = true; } catch (Exception ignored) { diff --git a/src/main/java/net/shadow/client/mixin/IMinecraftClientAccessor.java b/src/main/java/net/shadow/client/mixin/IMinecraftClientAccessor.java index fe1f74a..02638aa 100644 --- a/src/main/java/net/shadow/client/mixin/IMinecraftClientAccessor.java +++ b/src/main/java/net/shadow/client/mixin/IMinecraftClientAccessor.java @@ -11,6 +11,8 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mutable; import org.spongepowered.asm.mixin.gen.Accessor; +import java.net.Proxy; + @Mixin(MinecraftClient.class) public interface IMinecraftClientAccessor { @@ -20,4 +22,6 @@ public interface IMinecraftClientAccessor { @Accessor("renderTickCounter") RenderTickCounter getRenderTickCounter(); + @Accessor("networkProxy") + Proxy getProxy(); }