package info.mineshafter;
import info.mineshafter.hacks.URLHandlerFactory;
import info.mineshafter.util.JarPatcher;
import info.mineshafter.util.Resources;
import info.mineshafter.util.Streams;
import java.awt.Desktop;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.WindowConstants;
public class Bootstrap extends JFrame {
public static Thread mainThread;
private static final long serialVersionUID = 1;
private static int bootstrapVersion = 4;
private static int mineshafterBootstrapVersion = 14;
public Bootstrap() {
super("Minecraft Launcher");
setSize(854, 480);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
mainThread = Thread.currentThread();
bypassTls();
float v = Util.getCurrentBootstrapVersion();
System.out.println("Current proxy version: " + mineshafterBootstrapVersion);
System.out.println("Gotten proxy version: " + v);
if (mineshafterBootstrapVersion < v) {
JOptionPane.showMessageDialog(null, "A new version of Mineshafter is available at https://mineshafter.info/\nGo get it.", "Update Available", JOptionPane.PLAIN_MESSAGE);
try {
Desktop.getDesktop().browse(new URI("https://mineshafter.info/"));
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
Bootstrap frame = new Bootstrap();
File workDir = Util.getWorkingDirectory();
File launcherJar = new File(workDir, "launcher.jar");
File packedLauncherJar = new File(workDir, "launcher.pack.lzma");
File patchedLauncherJar = new File(workDir, "launcher_mcpatched.jar");
File starterJar = new File(workDir, "ms-starter.jar");
if (!workDir.isDirectory()) workDir.mkdir();
ensureLatestLauncherExists(packedLauncherJar, launcherJar);
ensurePatchedLauncherExists(launcherJar, patchedLauncherJar);
ensureGameStarterExists(starterJar);
startLauncher(workDir, frame, patchedLauncherJar);
}
private static void bypassTls() {
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
} };
SSLContext sc;
try {
sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
}
private static void ensureLatestLauncherExists(File packedLauncherJar, File launcherJar) {
File newerPackedLauncherJar = new File(packedLauncherJar.getParentFile(), "launcher.pack.lzma.new");
File packed200LauncherJar = new File(packedLauncherJar.getParentFile(), "launcher.pack");
String md5 = null;
if (packedLauncherJar.exists()) md5 = Util.getMd5(packedLauncherJar);
Util.grabLauncher(md5, newerPackedLauncherJar);
if (newerPackedLauncherJar.isFile()) {
packedLauncherJar.delete();
newerPackedLauncherJar.renameTo(packedLauncherJar);
}
Util.unpackLZMA(packedLauncherJar, packed200LauncherJar);
Util.unpack200(packed200LauncherJar, launcherJar);
packed200LauncherJar.delete();
}
private static void ensurePatchedLauncherExists(File launcherJar, File patchedLauncherJar) {
if (launcherJar.exists() && patchedLauncherJar.exists()) patchedLauncherJar.delete();
JarPatcher patcher = new JarPatcher(launcherJar);
for (String name : patcher.getEntries()) { // Get rid of all that metadata
if (name.startsWith("META-INF/")) {
if (name.contains("MANIFEST.MF")) {
//Remove MANIFEST.MF signatures
//Also this file contains Implementation-Version parameter which is loaded by the launcher as the launcher version
byte[] manifestData = patcher.getEntry(name);
String manifestString = new String(manifestData);
String rippedData = manifestString.substring(0, manifestString.indexOf("Name"));
patcher.setEntry(name, rippedData.getBytes());
} else if (!name.contains("log4j-provider.properties")) {
//Ignore this file. It is needed for Console Tab and logging related.
patcher.removeEntry(name);
}
}
}
patcher.setEntry("net/minecraft/launcher/game/MinecraftGameRunner.class", Resources.loadByteArray("resources/MinecraftGameRunner.class"));
patcher.setEntry("net/minecraft/launcher/game/MinecraftGameRunner$1.class", Resources.loadByteArray("resources/MinecraftGameRunner$1.class"));
//patcher.setEntry("info/mineshafter/mod/JarPatcher.class", Resources.loadByteArray("info/mineshafter/mod/JarPatcher.class"));
//patcher.setEntry("info/mineshafter/util/Streams.class", Resources.loadByteArray("info/mineshafter/util/Streams.class"));
//patcher.setEntry("info/mineshafter/util/Resources.class", Resources.loadByteArray("info/mineshafter/util/Resources.class"));
patcher.write(patchedLauncherJar);
}
private static void ensureGameStarterExists(File starterJar) {
// Basically just copy this launcher into another file
File thisJarFile = new File(Bootstrap.class.getProtectionDomain().getCodeSource().getLocation().getPath());
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(thisJarFile);
if (starterJar.exists()) { // Only delete once we know we can make a new one
starterJar.delete();
}
out = new FileOutputStream(starterJar);
Streams.pipeStreams(in, out);
Streams.close(in);
Streams.close(out);
} catch (FileNotFoundException e) {
System.out.println("This jar file not found: Unable to create ms-starter.jar");
return;
}
}
private static void startLauncher(File workDir, JFrame frame, File patchedLauncherJar) {
System.setErr(System.out);
System.setProperty("java.net.preferIPv4Stack", "true");
URL.setURLStreamHandlerFactory(new URLHandlerFactory());
try {
@SuppressWarnings("resource")
Class<?> launcher = new URLClassLoader(new URL[] { patchedLauncherJar.toURI().toURL() }).loadClass("net.minecraft.launcher.Launcher");
Constructor<?> ctor = launcher.getConstructor(new Class[] { JFrame.class, File.class, Proxy.class, PasswordAuthentication.class, java.lang.String[].class, Integer.class });
ctor.newInstance(new Object[] { frame, workDir, Proxy.NO_PROXY, null, new String[] {}, bootstrapVersion });
} catch (Exception e) {
System.out.println("Error while starting launcher:");
e.printStackTrace();
}
}
}