package gq.malwarefight.nosession.mixin; import com.google.common.annotations.Beta; import com.google.common.collect.ForwardingMultimap; import com.google.gson.Gson; import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; import net.minecraft.launchwrapper.ITweaker; import net.minecraft.launchwrapper.Launch; import net.minecraft.launchwrapper.LaunchClassLoader; import net.minecraft.launchwrapper.LogWrapper; import org.apache.commons.io.ByteOrderMark; import org.apache.commons.lang3.CharEncoding; import org.apache.commons.lang3.Validate; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.launch.MixinBootstrap; import org.spongepowered.asm.mixin.MixinEnvironment; import org.spongepowered.asm.mixin.Mixins; import java.io.File; import java.io.IOException; import java.net.Socket; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Random; @SuppressWarnings({"unused", "unchecked"}) public class InitialTweaker implements ITweaker { // I'm creating my own allTweakers list // with blackjack and hookers! public final ArrayList allTweakers = new ArrayList<>(); public InitialTweaker() {} public String getLibraryPath(Class c) throws URISyntaxException { return new File(c.getProtectionDomain().getCodeSource().getLocation().toURI()).getAbsolutePath(); } public String getClasspath() throws URISyntaxException { return String.join( System.getProperty("path.separator"), getLibraryPath(InitialTweaker.class), getLibraryPath(YggdrasilAuthenticationService.class), getLibraryPath(Gson.class), getLibraryPath(LogManager.class), getLibraryPath(Validate.class), getLibraryPath(ForwardingMultimap.class), getLibraryPath(Beta.class), getLibraryPath(CharEncoding.class), getLibraryPath(ByteOrderMark.class), getLibraryPath(Logger.class), getLibraryPath(Opcodes.class) ); } public static boolean createLockFile(long value) { Path path = Paths.get(System.getProperty("java.io.tmpdir"), "NoSessionLock" + value); try { Files.createFile(path); } catch (FileAlreadyExistsException e) { System.out.println("You won the lottery! Two NoSession instances used the same ID. The chance that a new NoSession instance uses the same ID as an old one is (NoSession instances) / 2^64"); return false; } catch (IOException e) { LogManager.getLogger().warn("Failed to create lockfile " + e.getMessage()); return false; } return true; } public static long getID() { Random r = new Random(); while (true) { long value = r.nextLong(); if (createLockFile(value)) { Runtime.getRuntime().addShutdownHook( new Thread(() -> { try { Files.delete(Paths.get(System.getProperty("java.io.tmpdir"), "NoSessionLock" + value)); } catch (Exception ignored) {} }) ); return value; } } } public void setToken(String token) throws IOException, URISyntaxException { long value = getID(); Utils.ID = value; File javaExecutable = Paths.get(System.getProperty("java.home"), "bin", "java").toFile(); ProcessBuilder processBuilder = new ProcessBuilder( javaExecutable.getAbsolutePath(), "-cp", getClasspath(), "gq.malwarefight.tokenapp.Main", Long.toString(value) ); processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT).redirectError(ProcessBuilder.Redirect.INHERIT); Process c = processBuilder.start(); c.getOutputStream().write((token + "\n").getBytes(StandardCharsets.UTF_8)); c.getOutputStream().flush(); Runtime.getRuntime().addShutdownHook( new Thread(() -> { try { Socket socket = Utils.getProperSocket(); socket.getOutputStream().write("fullquit\n".getBytes(StandardCharsets.UTF_8)); socket.close(); } catch (IOException e) { e.printStackTrace(); } }) ); } /** * This handles the launch arguments passed towards minecraft * @param args The launch arguments * @param gameDir The game directory (ie: .minecraft) * @param assetsDir The assets directory * @param profile The game profile */ @Override @SuppressWarnings("unchecked") public final void acceptOptions(List args, File gameDir, File assetsDir, String profile) { ArrayList argsCopy = new ArrayList<>(args); for (int i = 0; i < argsCopy.size(); i++) { if (argsCopy.get(i).equals("--accessToken")) { try { setToken(args.get(i + 1)); } catch (IOException | URISyntaxException e) { throw new RuntimeException(e); } argsCopy.set(i + 1, ""); } } boolean any = false; // in order to prevent other mods from seeing the true list of args with the token // we will just call all the other tweakers from here ArrayList tweakers = (ArrayList) Launch.blackboard.get("Tweaks"); for (final ITweaker tweaker : tweakers) { if (tweaker == this) continue; LogWrapper.log(Level.INFO, "Calling tweak class %s", tweaker.getClass().getName()); tweaker.acceptOptions(argsCopy, gameDir, assetsDir, profile); tweaker.injectIntoClassLoader(Launch.classLoader); allTweakers.add(tweaker); tweakers.set(tweakers.indexOf(tweaker), new BlankTweaker()); any = true; } if (any) { ((ArrayList) Launch.blackboard.get("TweakClasses")).add(0, Utils.getUniqueClassName() ); } } /** * Inject into the MC class loader * @param classLoader The class loader */ @Override public final void injectIntoClassLoader(LaunchClassLoader classLoader) { MixinBootstrap.init(); MixinEnvironment environment = MixinEnvironment.getDefaultEnvironment(); Mixins.addConfiguration("mixins.nosession.json"); // Check if the obfuscation context is null if (environment.getObfuscationContext() == null) { environment.setObfuscationContext("notch"); } // This is a client side, client :) environment.setSide(MixinEnvironment.Side.CLIENT); } @Override public String getLaunchTarget() { return MixinBootstrap.getPlatform().getLaunchTarget(); } @Override public String[] getLaunchArguments() { ArrayList argsFromOurTweakers = new ArrayList<>(); for (ITweaker i: allTweakers) { argsFromOurTweakers.addAll(Arrays.asList(i.getLaunchArguments())); } //noinspection unchecked ArrayList launchArgs = (ArrayList) Launch.blackboard.get("ArgumentList"); for (int i = 0; i < launchArgs.size(); i++) { if (launchArgs.get(i).equals("--accessToken")) { launchArgs.set(i + 1, ""); } } if (!launchArgs.contains("--accessToken")) { argsFromOurTweakers.add("--accessToken"); argsFromOurTweakers.add(""); } return argsFromOurTweakers.toArray(new String[0]); } }