From 9c8b2a19c64b2b1add86945f7c4ad1baeefadb83 Mon Sep 17 00:00:00 2001 From: Soda5601 <62250232+Soda5601@users.noreply.github.com> Date: Sat, 4 Mar 2023 20:13:28 +0800 Subject: [PATCH] Yggdrasil Login (#229) --- README.md | 2 + .../mixin/MinecraftClientAccessor.java | 54 ++++++ .../mixin/PlayerSkinProviderAccessor.java | 13 ++ .../rejects/mixin/meteor/AccountMixin.java | 16 ++ .../rejects/mixin/meteor/AccountsMixin.java | 23 +++ .../mixin/meteor/AccountsScreenMixin.java | 32 ++++ .../rejects/mixin/meteor/WAccountMixin.java | 21 +++ .../rejects/utils/accounts/AccountUtils.java | 45 +++++ .../AddCustomYggdrasilAccountScreen.java | 46 +++++ .../accounts/CustomYggdrasilAccount.java | 80 ++++++++ .../utils/accounts/CustomYggdrasilLogin.java | 176 ++++++++++++++++++ .../meteor-rejects-meteor.mixins.json | 14 +- src/main/resources/meteor-rejects.mixins.json | 2 + 13 files changed, 519 insertions(+), 5 deletions(-) create mode 100644 src/main/java/anticope/rejects/mixin/MinecraftClientAccessor.java create mode 100644 src/main/java/anticope/rejects/mixin/PlayerSkinProviderAccessor.java create mode 100644 src/main/java/anticope/rejects/mixin/meteor/AccountMixin.java create mode 100644 src/main/java/anticope/rejects/mixin/meteor/AccountsMixin.java create mode 100644 src/main/java/anticope/rejects/mixin/meteor/AccountsScreenMixin.java create mode 100644 src/main/java/anticope/rejects/mixin/meteor/WAccountMixin.java create mode 100644 src/main/java/anticope/rejects/utils/accounts/AccountUtils.java create mode 100644 src/main/java/anticope/rejects/utils/accounts/AddCustomYggdrasilAccountScreen.java create mode 100644 src/main/java/anticope/rejects/utils/accounts/CustomYggdrasilAccount.java create mode 100644 src/main/java/anticope/rejects/utils/accounts/CustomYggdrasilLogin.java diff --git a/README.md b/README.md index 59d6e90e..f5eda310 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,8 @@ - `Random Teleport, Hit Chance, Random Delay` (Removed from Meteor in [8722e](https://github.com/MeteorDevelopment/meteor-client/commit/8722ef565afa02ca4b6d9710a20fc9fcfd97bf05)) - AimAssist - `Fov filter` +- Alts + - `Yggdrasil Login` ## Commands - `.center` diff --git a/src/main/java/anticope/rejects/mixin/MinecraftClientAccessor.java b/src/main/java/anticope/rejects/mixin/MinecraftClientAccessor.java new file mode 100644 index 00000000..5e7d71f7 --- /dev/null +++ b/src/main/java/anticope/rejects/mixin/MinecraftClientAccessor.java @@ -0,0 +1,54 @@ +package anticope.rejects.mixin; + +import com.mojang.authlib.minecraft.MinecraftSessionService; +import com.mojang.authlib.minecraft.UserApiService; +import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.SocialInteractionsManager; +import net.minecraft.client.report.AbuseReportContext; +import net.minecraft.client.texture.PlayerSkinProvider; +import net.minecraft.client.util.ProfileKeys; +import net.minecraft.client.util.Session; +import net.minecraft.network.encryption.SignatureVerifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(MinecraftClient.class) +public interface MinecraftClientAccessor { + @Mutable + @Accessor("session") + void setSession(Session session); + + @Mutable + @Accessor("sessionService") + void setSessionService(MinecraftSessionService sessionService); + + @Mutable + @Accessor("authenticationService") + void setAuthenticationService(YggdrasilAuthenticationService authenticationService); + + @Mutable + @Accessor("servicesSignatureVerifier") + void setServicesSignatureVerifier(SignatureVerifier servicesSignatureVerifier); + + @Mutable + @Accessor("skinProvider") + void setSkinProvider(PlayerSkinProvider skinProvider); + + @Mutable + @Accessor("socialInteractionsManager") + void setSocialInteractionsManager(SocialInteractionsManager socialInteractionsManager); + + @Mutable + @Accessor("userApiService") + void setUserApiService(UserApiService userApiService); + + @Mutable + @Accessor("abuseReportContext") + void setAbuseReportContext(AbuseReportContext abuseReportContext); + + @Mutable + @Accessor("profileKeys") + void setProfileKeys(ProfileKeys profileKeys); +} \ No newline at end of file diff --git a/src/main/java/anticope/rejects/mixin/PlayerSkinProviderAccessor.java b/src/main/java/anticope/rejects/mixin/PlayerSkinProviderAccessor.java new file mode 100644 index 00000000..0bd1f795 --- /dev/null +++ b/src/main/java/anticope/rejects/mixin/PlayerSkinProviderAccessor.java @@ -0,0 +1,13 @@ +package anticope.rejects.mixin; + +import net.minecraft.client.texture.PlayerSkinProvider; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.io.File; + +@Mixin(PlayerSkinProvider.class) +public interface PlayerSkinProviderAccessor { + @Accessor("skinCacheDir") + File getSkinCacheDir(); +} diff --git a/src/main/java/anticope/rejects/mixin/meteor/AccountMixin.java b/src/main/java/anticope/rejects/mixin/meteor/AccountMixin.java new file mode 100644 index 00000000..f5d718c6 --- /dev/null +++ b/src/main/java/anticope/rejects/mixin/meteor/AccountMixin.java @@ -0,0 +1,16 @@ +package anticope.rejects.mixin.meteor; + +import anticope.rejects.utils.accounts.CustomYggdrasilAccount; +import meteordevelopment.meteorclient.systems.accounts.Account; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; + +@Mixin(value = Account.class, remap = false) +public class AccountMixin { + @ModifyArg(method = "toTag", at = @At(value = "INVOKE", target = "Lnet/minecraft/nbt/NbtCompound;putString(Ljava/lang/String;Ljava/lang/String;)V", ordinal = 0), index = 1) + private String putString(String key) { + if ((Object) this instanceof CustomYggdrasilAccount) return "Yggdrasil"; + return key; + } +} diff --git a/src/main/java/anticope/rejects/mixin/meteor/AccountsMixin.java b/src/main/java/anticope/rejects/mixin/meteor/AccountsMixin.java new file mode 100644 index 00000000..4398cd63 --- /dev/null +++ b/src/main/java/anticope/rejects/mixin/meteor/AccountsMixin.java @@ -0,0 +1,23 @@ +package anticope.rejects.mixin.meteor; + +import anticope.rejects.utils.accounts.CustomYggdrasilAccount; +import meteordevelopment.meteorclient.systems.accounts.Account; +import meteordevelopment.meteorclient.systems.accounts.Accounts; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +@Mixin(value = Accounts.class, remap = false) +public class AccountsMixin { + @Inject(method = "lambda$fromTag$0", at = @At(value = "INVOKE", target = "Lnet/minecraft/nbt/NbtCompound;getString(Ljava/lang/String;)Ljava/lang/String;"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true) + private static void onFromTag(NbtElement tag1, CallbackInfoReturnable> cir, NbtCompound t) { + if (t.getString("type").equals("Yggdrasil")) { + Account account = new CustomYggdrasilAccount(null, null, null).fromTag(t); + if (account.fetchInfo()) cir.setReturnValue(account); + } + } +} diff --git a/src/main/java/anticope/rejects/mixin/meteor/AccountsScreenMixin.java b/src/main/java/anticope/rejects/mixin/meteor/AccountsScreenMixin.java new file mode 100644 index 00000000..832dedcf --- /dev/null +++ b/src/main/java/anticope/rejects/mixin/meteor/AccountsScreenMixin.java @@ -0,0 +1,32 @@ +package anticope.rejects.mixin.meteor; + +import anticope.rejects.utils.accounts.AddCustomYggdrasilAccountScreen; +import meteordevelopment.meteorclient.gui.GuiTheme; +import meteordevelopment.meteorclient.gui.WindowScreen; +import meteordevelopment.meteorclient.gui.screens.AccountsScreen; +import meteordevelopment.meteorclient.gui.widgets.WWidget; +import meteordevelopment.meteorclient.gui.widgets.containers.WContainer; +import meteordevelopment.meteorclient.gui.widgets.containers.WHorizontalList; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +@Mixin(value = AccountsScreen.class, remap = false) +public abstract class AccountsScreenMixin extends WindowScreen { + public AccountsScreenMixin(GuiTheme theme, WWidget icon, String title) { + super(theme, icon, title); + } + + @Shadow + protected abstract void addButton(WContainer c, String text, Runnable action); + + @Inject(method = "initWidgets", at = @At(value = "INVOKE", target = "Lmeteordevelopment/meteorclient/gui/screens/AccountsScreen;addButton(Lmeteordevelopment/meteorclient/gui/widgets/containers/WContainer;Ljava/lang/String;Ljava/lang/Runnable;)V", ordinal = 0), locals = LocalCapture.CAPTURE_FAILHARD) + private void afterAddCrackedButton(CallbackInfo info, WHorizontalList l) { + addButton(l, "Yggdrasil", () -> mc.setScreen(new AddCustomYggdrasilAccountScreen(theme, (AccountsScreen) (Object) this))); + } +} diff --git a/src/main/java/anticope/rejects/mixin/meteor/WAccountMixin.java b/src/main/java/anticope/rejects/mixin/meteor/WAccountMixin.java new file mode 100644 index 00000000..84bd53d2 --- /dev/null +++ b/src/main/java/anticope/rejects/mixin/meteor/WAccountMixin.java @@ -0,0 +1,21 @@ +package anticope.rejects.mixin.meteor; + +import anticope.rejects.utils.accounts.CustomYggdrasilAccount; +import meteordevelopment.meteorclient.gui.widgets.WAccount; +import meteordevelopment.meteorclient.systems.accounts.Account; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; + +@Mixin(value = WAccount.class, remap = false) +public class WAccountMixin { + @Shadow @Final private Account account; + + @ModifyArg(method = "init", at = @At(value = "INVOKE", target = "Lmeteordevelopment/meteorclient/gui/GuiTheme;label(Ljava/lang/String;)Lmeteordevelopment/meteorclient/gui/widgets/WLabel;",ordinal = 1)) + private String accountName(String text) { + if (account instanceof CustomYggdrasilAccount) return "(Yggdrasil)"; + return text; + } +} diff --git a/src/main/java/anticope/rejects/utils/accounts/AccountUtils.java b/src/main/java/anticope/rejects/utils/accounts/AccountUtils.java new file mode 100644 index 00000000..288a0ce4 --- /dev/null +++ b/src/main/java/anticope/rejects/utils/accounts/AccountUtils.java @@ -0,0 +1,45 @@ +package anticope.rejects.utils.accounts; + +import anticope.rejects.mixin.MinecraftClientAccessor; +import anticope.rejects.mixin.PlayerSkinProviderAccessor; +import com.mojang.authlib.exceptions.AuthenticationException; +import com.mojang.authlib.minecraft.MinecraftSessionService; +import com.mojang.authlib.minecraft.UserApiService; +import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; +import net.minecraft.client.network.SocialInteractionsManager; +import net.minecraft.client.report.AbuseReportContext; +import net.minecraft.client.report.ReporterEnvironment; +import net.minecraft.client.texture.PlayerSkinProvider; +import net.minecraft.client.util.ProfileKeys; +import net.minecraft.client.util.Session; +import net.minecraft.network.encryption.SignatureVerifier; + +import java.io.File; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +public class AccountUtils { + public static MinecraftSessionService applyLoginEnvironment(YggdrasilAuthenticationService authService, MinecraftSessionService sessService, Session session) { + File skinDir = ((PlayerSkinProviderAccessor) mc.getSkinProvider()).getSkinCacheDir(); + ((MinecraftClientAccessor) mc).setSession(session); + ((MinecraftClientAccessor) mc).setAuthenticationService(authService); + ((MinecraftClientAccessor) mc).setSessionService(sessService); + ((MinecraftClientAccessor) mc).setServicesSignatureVerifier(SignatureVerifier.create(authService.getServicesKey())); + ((MinecraftClientAccessor) mc).setSkinProvider(new PlayerSkinProvider(mc.getTextureManager(), skinDir, sessService)); + UserApiService apiService = createUserApiService(authService, session); + ((MinecraftClientAccessor) mc).setUserApiService(apiService); + ((MinecraftClientAccessor) mc).setSocialInteractionsManager(new SocialInteractionsManager(mc, apiService)); + ((MinecraftClientAccessor) mc).setProfileKeys(ProfileKeys.create(apiService, session, mc.runDirectory.toPath())); + ((MinecraftClientAccessor) mc).setAbuseReportContext(AbuseReportContext.create(ReporterEnvironment.ofIntegratedServer(), apiService)); + return sessService; + } + + public static UserApiService createUserApiService(YggdrasilAuthenticationService authService, Session session) { + try { + return authService.createUserApiService(session.getAccessToken()); + } catch (AuthenticationException e) { + return UserApiService.OFFLINE; + } + } +} + diff --git a/src/main/java/anticope/rejects/utils/accounts/AddCustomYggdrasilAccountScreen.java b/src/main/java/anticope/rejects/utils/accounts/AddCustomYggdrasilAccountScreen.java new file mode 100644 index 00000000..42c9ec9d --- /dev/null +++ b/src/main/java/anticope/rejects/utils/accounts/AddCustomYggdrasilAccountScreen.java @@ -0,0 +1,46 @@ +package anticope.rejects.utils.accounts; + +import meteordevelopment.meteorclient.gui.GuiTheme; +import meteordevelopment.meteorclient.gui.screens.AccountsScreen; +import meteordevelopment.meteorclient.gui.screens.AddAccountScreen; +import meteordevelopment.meteorclient.gui.widgets.containers.WTable; +import meteordevelopment.meteorclient.gui.widgets.input.WTextBox; +import meteordevelopment.meteorclient.systems.accounts.Accounts; + +public class AddCustomYggdrasilAccountScreen extends AddAccountScreen { + public AddCustomYggdrasilAccountScreen(GuiTheme theme, AccountsScreen parent) { + super(theme, "Add Yggdrasil Account", parent); + } + + @Override + public void initWidgets() { + WTable t = add(theme.table()).widget(); + + // Email + t.add(theme.label("Username / Email: ")); + WTextBox username = t.add(theme.textBox("")).minWidth(400).expandX().widget(); + username.setFocused(true); + t.row(); + + // Password + t.add(theme.label("Password: ")); + WTextBox password = t.add(theme.textBox("")).minWidth(400).expandX().widget(); + t.row(); + + // Password + t.add(theme.label("Server: ")); + WTextBox server = t.add(theme.textBox("")).minWidth(400).expandX().widget(); + t.row(); + + // Add + add = t.add(theme.button("Add")).expandX().widget(); + add.action = () -> { + CustomYggdrasilAccount account = new CustomYggdrasilAccount(username.get(), password.get(), server.get()); + if (!username.get().isEmpty() && !password.get().isEmpty() && !Accounts.get().exists(account)) { + AccountsScreen.addAccount(this, parent, account); + } + }; + + enterAction = add.action; + } +} \ No newline at end of file diff --git a/src/main/java/anticope/rejects/utils/accounts/CustomYggdrasilAccount.java b/src/main/java/anticope/rejects/utils/accounts/CustomYggdrasilAccount.java new file mode 100644 index 00000000..0f4b9a3d --- /dev/null +++ b/src/main/java/anticope/rejects/utils/accounts/CustomYggdrasilAccount.java @@ -0,0 +1,80 @@ +package anticope.rejects.utils.accounts; + +import com.mojang.authlib.exceptions.AuthenticationException; +import meteordevelopment.meteorclient.MeteorClient; +import meteordevelopment.meteorclient.mixin.MinecraftClientAccessor; +import meteordevelopment.meteorclient.systems.accounts.Account; +import meteordevelopment.meteorclient.systems.accounts.AccountType; +import meteordevelopment.meteorclient.utils.misc.NbtException; +import net.minecraft.client.util.Session; +import net.minecraft.nbt.NbtCompound; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +public class CustomYggdrasilAccount extends Account { + private String password, server; + + public CustomYggdrasilAccount(String name, String password, String server) { + super(AccountType.Cracked, name); + this.password = password; + this.server = server; + } + + @Override + public boolean fetchInfo() { + try { + Session session = CustomYggdrasilLogin.login(name, password, server); + + cache.username = session.getUsername(); + cache.uuid = session.getUuid(); + + return true; + } catch (AuthenticationException e) { + return false; + } + } + + @Override + public boolean login() { + try { + Session session = CustomYggdrasilLogin.login(name, password, server); + CustomYggdrasilLogin.LocalYggdrasilAuthenticationService service = new CustomYggdrasilLogin.LocalYggdrasilAuthenticationService(((MinecraftClientAccessor) mc).getProxy(), server); + CustomYggdrasilLogin.applyYggdrasilAccount(service, session); + cache.username = session.getUsername(); + cache.loadHead(); + return true; + } catch (AuthenticationException e) { + if (e.getMessage().contains("Invalid username or password") || e.getMessage().contains("account migrated")) + MeteorClient.LOG.error("Wrong password."); + else MeteorClient.LOG.error("Failed to contact the authentication server."); + return false; + } + } + + @Override + public NbtCompound toTag() { + NbtCompound tag = super.toTag(); + + tag.putString("password", password); + tag.putString("server", server); + + return tag; + } + + @Override + public CustomYggdrasilAccount fromTag(NbtCompound tag) { + super.fromTag(tag); + if (!tag.contains("password")) throw new NbtException(); + + password = tag.getString("password"); + server = tag.getString("server"); + + return this; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof CustomYggdrasilAccount)) return false; + return ((CustomYggdrasilAccount) o).name.equals(this.name); + } +} diff --git a/src/main/java/anticope/rejects/utils/accounts/CustomYggdrasilLogin.java b/src/main/java/anticope/rejects/utils/accounts/CustomYggdrasilLogin.java new file mode 100644 index 00000000..bb6e2874 --- /dev/null +++ b/src/main/java/anticope/rejects/utils/accounts/CustomYggdrasilLogin.java @@ -0,0 +1,176 @@ +// Credit to https://github.com/IAFEnvoy/AccountSwitcher + +package anticope.rejects.utils.accounts; + +import com.google.common.collect.Iterables; +import com.google.gson.*; +import com.mojang.authlib.Environment; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.exceptions.AuthenticationException; +import com.mojang.authlib.minecraft.InsecureTextureException; +import com.mojang.authlib.minecraft.MinecraftProfileTexture; +import com.mojang.authlib.minecraft.MinecraftSessionService; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; +import com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService; +import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload; +import com.mojang.util.UUIDTypeAdapter; +import meteordevelopment.meteorclient.utils.network.Http; +import net.minecraft.client.util.Session; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.net.Proxy; +import java.nio.charset.StandardCharsets; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; +import java.util.*; + +public class CustomYggdrasilLogin { + public static Session login(String name, String password, String server) throws AuthenticationException { + try { + String url = server + "/authserver/authenticate"; + JsonObject agent = new JsonObject(); + agent.addProperty("name", "Minecraft"); + agent.addProperty("version", 1); + + JsonObject root = new JsonObject(); + root.add("agent", agent); + root.addProperty("username", name); + root.addProperty("password", password); + + String data = Http.post(url).bodyJson(root).sendString(); + JsonObject json = JsonParser.parseString(data).getAsJsonObject(); + if (json.has("error")) { + throw new AuthenticationException(json.get("errorMessage").getAsString()); + } + String token = json.get("accessToken").getAsString(); + String uuid = json.get("selectedProfile").getAsJsonObject().get("id").getAsString(); + String username = json.get("selectedProfile").getAsJsonObject().get("name").getAsString(); + return new Session(username, uuid, token, Optional.empty(), Optional.empty(), Session.AccountType.MOJANG); + } catch (Exception e) { + throw new AuthenticationException(e); + } + } + + public static void applyYggdrasilAccount(LocalYggdrasilAuthenticationService authService, Session session) { + MinecraftSessionService service = new LocalYggdrasilMinecraftSessionService(authService, authService.server); + AccountUtils.applyLoginEnvironment(authService, service, session); + } + + public static class LocalYggdrasilApi implements Environment { + private final String url; + + public LocalYggdrasilApi(String serverUrl) { + this.url = serverUrl; + } + + @Override + public String getAuthHost() { + return url + "/authserver"; + } + + @Override + public String getAccountsHost() { + return url + "/api"; + } + + @Override + public String getSessionHost() { + return url + "/sessionserver"; + } + + @Override + public String getServicesHost() { + return url + "/minecraftservices"; + } + + @Override + public String getName() { + return "Custom-Yggdrasil"; + } + + @Override + public String asString() { + return new StringJoiner(", ", "", "") + .add("authHost='" + getAuthHost() + "'") + .add("accountsHost='" + getAccountsHost() + "'") + .add("sessionHost='" + getSessionHost() + "'") + .add("servicesHost='" + getServicesHost() + "'") + .add("name='" + getName() + "'") + .toString(); + } + } + + public static class LocalYggdrasilMinecraftSessionService extends YggdrasilMinecraftSessionService { + private static final Logger LOGGER = LogManager.getLogger(); + private final PublicKey publicKey; + private final Gson gson = new GsonBuilder().registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).create(); + + public LocalYggdrasilMinecraftSessionService(YggdrasilAuthenticationService service, String serverUrl) { + super(service, new LocalYggdrasilApi(serverUrl)); + String data = Http.get(serverUrl).sendString(); + JsonObject json = JsonParser.parseString(data).getAsJsonObject(); + this.publicKey = getPublicKey(json.get("signaturePublickey").getAsString()); + } + + private static PublicKey getPublicKey(String key) { + key = key.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", ""); + try { + byte[] byteKey = Base64.getDecoder().decode(key.replace("\n", "")); + X509EncodedKeySpec spec = new X509EncodedKeySpec(byteKey); + KeyFactory factory = KeyFactory.getInstance("RSA"); + return factory.generatePublic(spec); + } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public Map getTextures(final GameProfile profile, final boolean requireSecure) { + final Property textureProperty = Iterables.getFirst(profile.getProperties().get("textures"), null); + + if (textureProperty == null) + return new HashMap<>(); + + if (requireSecure) { + if (!textureProperty.hasSignature()) { + LOGGER.error("Signature is missing from textures payload"); + throw new InsecureTextureException("Signature is missing from textures payload"); + } + if (!textureProperty.isSignatureValid(publicKey)) { + LOGGER.error("Textures payload has been tampered with (signature invalid)"); + throw new InsecureTextureException("Textures payload has been tampered with (signature invalid)"); + } + } + + final MinecraftTexturesPayload result; + try { + final String json = new String(org.apache.commons.codec.binary.Base64.decodeBase64(textureProperty.getValue()), StandardCharsets.UTF_8); + result = gson.fromJson(json, MinecraftTexturesPayload.class); + } catch (final JsonParseException e) { + LOGGER.error("Could not decode textures payload", e); + return new HashMap<>(); + } + + if (result == null || result.getTextures() == null) + return new HashMap<>(); + + return result.getTextures(); + } + } + + public static class LocalYggdrasilAuthenticationService extends YggdrasilAuthenticationService { + public final String server; + + public LocalYggdrasilAuthenticationService(Proxy proxy, String server) { + super(proxy, new LocalYggdrasilApi(server)); + this.server = server; + } + } + +} diff --git a/src/main/resources/meteor-rejects-meteor.mixins.json b/src/main/resources/meteor-rejects-meteor.mixins.json index 6cb2bd7c..714b5436 100644 --- a/src/main/resources/meteor-rejects-meteor.mixins.json +++ b/src/main/resources/meteor-rejects-meteor.mixins.json @@ -3,18 +3,22 @@ "package": "anticope.rejects.mixin.meteor", "compatibilityLevel": "JAVA_16", "client": [ + "AccountMixin", + "AccountsMixin", + "AccountsScreenMixin", "ConfigTabMixin", + "DefaultSettingsWidgetFactoryMixin", + "FontUtilsMixin", "GuiRendererAccessor", "HttpMixin", "ModuleMixin", "ModulesMixin", - "FontUtilsMixin", - "DefaultSettingsWidgetFactoryMixin", - "modules.FlightMixin", - "modules.NoRenderAccessor", + "WAccountMixin", + "modules.AimAssistMixin", "modules.AutoSignMixin", + "modules.FlightMixin", "modules.InventoryTweaksMixin", "modules.KillAuraMixin", - "modules.AimAssistMixin" + "modules.NoRenderAccessor" ] } diff --git a/src/main/resources/meteor-rejects.mixins.json b/src/main/resources/meteor-rejects.mixins.json index b681774e..9f489c3d 100644 --- a/src/main/resources/meteor-rejects.mixins.json +++ b/src/main/resources/meteor-rejects.mixins.json @@ -12,9 +12,11 @@ "GameRendererMixin", "LivingEntityMixin", "LivingEntityRendererMixin", + "MinecraftClientAccessor", "MultiplayerScreenAccessor", "MultiplayerScreenMixin", "PlayerMoveC2SPacketAccessor", + "PlayerSkinProviderAccessor", "ServerListAccessor", "StructureVoidBlockMixin", "TexturedRenderLayersMixin",