From 3977f9ca619fd1b32c2cec403a52bbeeab6fd364 Mon Sep 17 00:00:00 2001 From: Lucas Date: Sat, 22 Jun 2019 02:46:39 +0200 Subject: [PATCH] Make injected-client maven dependency --- injected-client/pom.xml | 16 +- runelite-client/pom.xml | 18 +- .../net/runelite/client/rs/ClientLoader.java | 232 +++--------------- .../client/util/bootstrap/Artifact.java | 9 - .../client/util/bootstrap/Bootstrap.java | 56 ++--- 5 files changed, 66 insertions(+), 265 deletions(-) delete mode 100644 runelite-client/src/main/java/net/runelite/client/util/bootstrap/Artifact.java diff --git a/injected-client/pom.xml b/injected-client/pom.xml index 77cc2e42e8..474adda69b 100644 --- a/injected-client/pom.xml +++ b/injected-client/pom.xml @@ -37,23 +37,11 @@ - net.runelite - client + net.runelite.rs + rs-client ${project.version} true - - net.runelite.rs - runescape-api - ${project.version} - false - - - net.runelite - runelite-api - ${project.version} - false - net.runelite.rs vanilla diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml index 5e690979e2..70c5c83000 100644 --- a/runelite-client/pom.xml +++ b/runelite-client/pom.xml @@ -209,11 +209,12 @@ net.runelite.rs runescape-api ${project.version} + runtime - net.runelit - client-patch - 1.5.26.2 + net.runelite + injected-client + ${project.version} runtime @@ -334,8 +335,8 @@ - - net.runelite:api + + net.runelite:* ** @@ -346,13 +347,6 @@ ** - - - net.runelit:client-patch - - ** - - net.runelite.pushingpixels:* diff --git a/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java b/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java index c13c821178..058336e738 100644 --- a/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java +++ b/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java @@ -26,55 +26,27 @@ */ package net.runelite.client.rs; -import net.runelite.api.Client; +import java.net.URLClassLoader; import java.applet.Applet; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; -import java.net.HttpURLConnection; import java.net.URL; -import java.net.URLConnection; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.jar.Attributes; -import java.util.jar.JarEntry; -import java.util.jar.JarInputStream; -import java.util.jar.Manifest; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import lombok.extern.slf4j.Slf4j; -import static net.runelite.client.RuneLite.RUNELITE_DIR; -import static net.runelite.client.rs.ClientUpdateCheckMode.AUTO; -import static net.runelite.client.rs.ClientUpdateCheckMode.CUSTOM; -import static net.runelite.client.rs.ClientUpdateCheckMode.VANILLA; -import net.runelite.http.api.RuneLiteAPI; -import okhttp3.Request; -import okhttp3.Response; @Slf4j @Singleton public class ClientLoader { - private static final File LOCAL_INJECTED_CLIENT = new File("./injected-client/target/injected-client-" + RuneLiteAPI.getVersion() + ".jar"); - private static final File INJECTED_CLIENT = new File(RUNELITE_DIR + "/injected-client.jar"); private final ClientConfigLoader clientConfigLoader; private ClientUpdateCheckMode updateCheckMode; public static boolean useLocalInjected = false; @Inject private ClientLoader( - @Named("updateCheckMode") final ClientUpdateCheckMode updateCheckMode, - final ClientConfigLoader clientConfigLoader) + @Named("updateCheckMode") final ClientUpdateCheckMode updateCheckMode, + final ClientConfigLoader clientConfigLoader) { this.updateCheckMode = updateCheckMode; this.clientConfigLoader = clientConfigLoader; @@ -84,126 +56,27 @@ public class ClientLoader { try { - Manifest manifest = new Manifest(); - manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); - RSConfig config = clientConfigLoader.fetch(); + final RSConfig config = clientConfigLoader.fetch(); - Map zipFile = new HashMap<>(); - - if (updateCheckMode == VANILLA) + switch (updateCheckMode) { - Certificate[] jagexCertificateChain = getJagexCertificateChain(); - String codebase = config.getCodeBase(); - String initialJar = config.getInitialJar(); - URL url = new URL(codebase + initialJar); - Request request = new Request.Builder() - .url(url) - .build(); - - try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute()) - { - JarInputStream jis; - - jis = new JarInputStream(response.body().byteStream()); - byte[] tmp = new byte[4096]; - ByteArrayOutputStream buffer = new ByteArrayOutputStream(756 * 1024); - for (; ; ) - { - JarEntry metadata = jis.getNextJarEntry(); - if (metadata == null) - { - break; - } - - buffer.reset(); - for (; ; ) - { - int n = jis.read(tmp); - if (n <= -1) - { - break; - } - buffer.write(tmp, 0, n); - } - - if (!Arrays.equals(metadata.getCertificates(), jagexCertificateChain)) - { - if (metadata.getName().startsWith("META-INF/")) - { - // META-INF/JAGEXLTD.SF and META-INF/JAGEXLTD.RSA are not signed, but we don't need - // anything in META-INF anyway. - continue; - } - else - { - throw new VerificationException("Unable to verify jar entry: " + metadata.getName()); - } - } - - zipFile.put(metadata.getName(), buffer.toByteArray()); - } - } + case AUTO: + case CUSTOM: + return loadRLPlus(config); + default: + case VANILLA: + return loadVanilla(config); + case NONE: + return null; } - else if (updateCheckMode == CUSTOM || useLocalInjected) - { - log.info("Loading injected client from {}", LOCAL_INJECTED_CLIENT.getAbsolutePath()); - loadJar(zipFile, LOCAL_INJECTED_CLIENT); - } - else if (updateCheckMode == AUTO) - { - URL url = new URL("https://raw.githubusercontent.com/runelite-extended/maven-repo/master/live/injected-client.jar"); - ReadableByteChannel readableByteChannel = Channels.newChannel(url.openStream()); - INJECTED_CLIENT.mkdirs(); - - if (!INJECTED_CLIENT.exists() || getFileSize(INJECTED_CLIENT.toURI().toURL()) != getFileSize(url)) - { - log.info("{} injected client", INJECTED_CLIENT.exists() ? "Updating" : "Initializing"); - INJECTED_CLIENT.delete(); - INJECTED_CLIENT.createNewFile(); - updateInjectedClient(readableByteChannel); - } - - log.info("Loading injected client from {}", INJECTED_CLIENT.getAbsolutePath()); - loadJar(zipFile, INJECTED_CLIENT); - } - - String initialClass = config.getInitialClass(); - - ClassLoader rsClassLoader = new ClassLoader(ClientLoader.class.getClassLoader()) - { - @Override - protected Class findClass(String name) throws ClassNotFoundException - { - String path = name.replace('.', '/').concat(".class"); - byte[] data = zipFile.get(path); - if (data == null) - { - throw new ClassNotFoundException(name); - } - - return defineClass(name, data, 0, data.length); - } - }; - - Class clientClass = rsClassLoader.loadClass(initialClass); - - Applet rs = (Applet) clientClass.newInstance(); - rs.setStub(new RSAppletStub(config)); - - if (rs instanceof Client) - { - log.info("client-patch 420 blaze it RL pricks"); - } - - return rs; } - catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException | SecurityException | VerificationException | CertificateException e) + catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e) { if (e instanceof ClassNotFoundException) { log.error("Unable to load client - class not found. This means you" - + " are not running RuneLite with Maven as the client patch" - + " is not in your classpath."); + + " are not running RuneLite with Maven as the injected client" + + " is not in your classpath."); } log.error("Error loading RS!", e); @@ -211,66 +84,31 @@ public class ClientLoader } } - private static int getFileSize(URL url) throws IOException + private static Applet loadRLPlus(final RSConfig config) throws ClassNotFoundException, InstantiationException, IllegalAccessException { - URLConnection conn = null; - try - { - conn = url.openConnection(); - if (conn instanceof HttpURLConnection) - { - ((HttpURLConnection) conn).setRequestMethod("HEAD"); - } - conn.getInputStream(); - return conn.getContentLength(); - } - finally - { - if (conn instanceof HttpURLConnection) - { - ((HttpURLConnection) conn).disconnect(); - } - } + // the injected client is a runtime scoped dependency + final Class clientClass = ClientLoader.class.getClassLoader().loadClass(config.getInitialClass()); + return loadFromClass(config, clientClass); } - private void updateInjectedClient(ReadableByteChannel readableByteChannel) throws IOException + private static Applet loadVanilla(final RSConfig config) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException { - FileOutputStream fileOutputStream = new FileOutputStream(INJECTED_CLIENT); - fileOutputStream.getChannel() - .transferFrom(readableByteChannel, 0, Integer.MAX_VALUE); + final String codebase = config.getCodeBase(); + final String initialJar = config.getInitialJar(); + final String initialClass = config.getInitialClass(); + final URL url = new URL(codebase + initialJar); + + // Must set parent classloader to null, or it will pull from + // this class's classloader first + final URLClassLoader classloader = new URLClassLoader(new URL[]{url}, null); + final Class clientClass = classloader.loadClass(initialClass); + return loadFromClass(config, clientClass); } - private static Certificate[] getJagexCertificateChain() throws CertificateException + private static Applet loadFromClass(final RSConfig config, final Class clientClass) throws IllegalAccessException, InstantiationException { - CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); - Collection certificates = certificateFactory.generateCertificates(ClientLoader.class.getResourceAsStream("jagex.crt")); - return certificates.toArray(new Certificate[0]); - } - - private static void loadJar(Map toMap, File fromFile) throws IOException - { - JarInputStream fis = new JarInputStream(new FileInputStream(fromFile)); - byte[] tmp = new byte[4096]; - ByteArrayOutputStream buffer = new ByteArrayOutputStream(756 * 1024); - for (; ; ) - { - JarEntry metadata = fis.getNextJarEntry(); - if (metadata == null) - { - break; - } - - buffer.reset(); - for (; ; ) - { - int n = fis.read(tmp); - if (n <= -1) - { - break; - } - buffer.write(tmp, 0, n); - } - toMap.put(metadata.getName(), buffer.toByteArray()); - } + final Applet rs = (Applet) clientClass.newInstance(); + rs.setStub(new RSAppletStub(config)); + return rs; } } diff --git a/runelite-client/src/main/java/net/runelite/client/util/bootstrap/Artifact.java b/runelite-client/src/main/java/net/runelite/client/util/bootstrap/Artifact.java deleted file mode 100644 index 466dfbcf11..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/util/bootstrap/Artifact.java +++ /dev/null @@ -1,9 +0,0 @@ -package net.runelite.client.util.bootstrap; - -public class Artifact -{ - String hash; - String name; - String path; - String size; -} diff --git a/runelite-client/src/main/java/net/runelite/client/util/bootstrap/Bootstrap.java b/runelite-client/src/main/java/net/runelite/client/util/bootstrap/Bootstrap.java index 6892d31f75..e86f2c8a02 100644 --- a/runelite-client/src/main/java/net/runelite/client/util/bootstrap/Bootstrap.java +++ b/runelite-client/src/main/java/net/runelite/client/util/bootstrap/Bootstrap.java @@ -14,9 +14,16 @@ import net.runelite.http.api.RuneLiteAPI; public class Bootstrap { + class Artifact + { + String hash; + String name; + String path; + String size; + } String buildCommit = "c554ab2400dc04a619b36695da2107648c9c87b3"; - Artifact[] artifacts = getArtifacts(); + private Artifact[] artifacts = getArtifacts(); Client client = new Client(); String[] clientJvm9Arguments = new String[]{ "-XX:+DisableAttachMechanism", @@ -46,54 +53,32 @@ public class Bootstrap "-XX:+UseParNewGC", "-Djna.nosys=true"}; - public Bootstrap() + Bootstrap() { } public static String getChecksumObject(Serializable object) throws IOException, NoSuchAlgorithmException { - ByteArrayOutputStream baos = null; - ObjectOutputStream oos = null; - try + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos)) { - baos = new ByteArrayOutputStream(); - oos = new ObjectOutputStream(baos); oos.writeObject(object); MessageDigest md = MessageDigest.getInstance("MD5"); byte[] thedigest = md.digest(baos.toByteArray()); return DatatypeConverter.printHexBinary(thedigest); } - finally - { - oos.close(); - baos.close(); - } } - private static String getChecksumFile(String filepath) throws IOException + private static String getChecksumFile(String filepath) throws IOException, NoSuchAlgorithmException { System.out.println("Generating Hash for " + filepath); - MessageDigest md = null; - try - { - md = MessageDigest.getInstance("SHA-256"); - } - catch (Exception e) - { - e.printStackTrace(); - } + MessageDigest md = MessageDigest.getInstance("SHA-256"); + try (DigestInputStream dis = new DigestInputStream(new FileInputStream(filepath), md)) { - while (dis.read() != -1) - { - //empty loop to clear the data - } + //empty loop to clear the data + while (dis.read() != -1); md = dis.getMessageDigest(); } - catch (Exception e) - { - e.printStackTrace(); - } return bytesToHex(md.digest()); @@ -111,11 +96,11 @@ public class Bootstrap } - public Artifact[] getArtifacts() + private Artifact[] getArtifacts() { try { - artifacts = new Artifact[42]; + artifacts = new Artifact[43]; //Static artifacts artifacts[0] = new Artifact(); @@ -330,8 +315,13 @@ public class Bootstrap artifacts[37].hash = getChecksumFile("./http-api/target/" + artifacts[37].name); artifacts[37].path = "https://raw.githubusercontent.com/runelite-extended/maven-repo/master/live/" + artifacts[37].name; artifacts[37].size = Long.toString(getFileSize("./http-api/target/" + artifacts[37].name)); + artifacts[42] = new Artifact(); + artifacts[42].name = "injected-client-" + RuneLiteAPI.getVersion() + ".jar"; + artifacts[42].hash = getChecksumFile("./injected-client/target/" + artifacts[42].name); + artifacts[42].path = "https://raw.githubusercontent.com/runelite-extended/maven-repo/master/live/" + artifacts[42].name; + artifacts[42].size = Long.toString(getFileSize("./injected-client/target/" + artifacts[42].name)); } - catch (IOException e) + catch (IOException | NoSuchAlgorithmException e) { e.printStackTrace(); }