Merge pull request #304 from Parabot/development

[RELEASE] Release of V2.8
This commit is contained in:
Jeroen Ketelaar
2019-05-08 15:11:57 -05:00
committed by GitHub
32 changed files with 593 additions and 131 deletions
+1 -1
View File
@@ -34,7 +34,7 @@ env:
- secure: UG+b1tEgc8xv9x4r//2OAIK1RrYv6n209KTTFMMwcnAa7DI8HaP8nljRa5/VhDhuKHdlVrYH/tI90v7UVBs0GDVNwK5V17Io0fMm3FUGZekSthTCqqno5wAGa9r6a6mMLtSaSmIFeIKi0+0d2ZwplRuhj/dtEYjjBBj+kK8g4nE=
- secure: St/fecUDInFBCRriYqgp2F8PU9/SooorgxD9Mrs+b0EsC7AbtSsQXvdIv2Lp6xzdQ0VSXPcLIhULPOYrmBKnGQ/NjXTIZXxnroyQxxnI6xyEWIZwiHRY/bKRJDRbQTxD9NL32szKiDSwnw7pu6llF4D64UqQvziq4Gm6VohU75M=
- secure: bD15GVZWowiknbfLavh8CxSh0GsnF5kT4kZ6ggCuUDGyj0mzqf7dNRnchQIKkCG0WRYyTrFN4pEiygeywWsipEeAVv9Xhx3cuUZmzeQaR5KCWabSwJ8gK6jZd1YhcWmM9vrdPHobZr65MP0y/8mu/Fovgky9dY7KDf4G3SebNrM=
- PARABOT_VERSION=2.7
- PARABOT_VERSION=2.8
cache:
directories:
+1 -1
View File
@@ -3,7 +3,7 @@
# Parabot
Parabot V2.7
Parabot V2.8
#### Links
+2 -2
View File
@@ -6,7 +6,7 @@
<groupId>org.parabot</groupId>
<artifactId>client</artifactId>
<version>2.7</version>
<version>2.8</version>
<packaging>jar</packaging>
@@ -73,7 +73,7 @@
<dependency>
<groupId>org.parabot</groupId>
<artifactId>internal-api</artifactId>
<version>1.52.1</version>
<version>1.53.1</version>
</dependency>
</dependencies>
+15
View File
@@ -1,6 +1,7 @@
package org.parabot;
import org.parabot.api.translations.TranslationHelper;
import org.parabot.core.Context;
import org.parabot.core.Core;
import org.parabot.core.Directories;
import org.parabot.core.forum.AccountManager;
@@ -9,6 +10,7 @@ import org.parabot.core.network.proxy.ProxySocket;
import org.parabot.core.network.proxy.ProxyType;
import org.parabot.core.ui.BotUI;
import org.parabot.core.ui.ServerSelector;
import org.parabot.core.ui.utils.UILog;
import javax.swing.*;
import java.io.File;
@@ -27,6 +29,16 @@ public final class Landing {
public static void main(String... args) throws IOException {
if (Context.getJavaVersion() >= 9) {
UILog.log("Parabot", "Parabot doesn't support Java 9+ currently. Please downgrade to Java 8 to ensure Parabot is working correctly.");
System.exit(0);
}
if (!System.getProperty("os.arch").contains("64")) {
UILog.log("Parabot", "You are not running a 64-bit version of Java, this might cause the client to lag or crash unexpectedly.\r\n" +
"It's recommended to upgrade to a 64-bit version.");
}
parseArgs(args);
Directories.validate();
@@ -139,6 +151,9 @@ public final class Landing {
case "-uuid":
Core.setQuickLaunchByUuid(Integer.parseInt(args[++i]));
break;
default:
System.err.println(String.format("Unknown argument given: %s", arg.toLowerCase()));
break;
}
}
}
@@ -11,17 +11,21 @@ public class Configuration extends org.parabot.api.Configuration {
public static final String LOGIN_SERVER = "http://bdn.parabot.org/api/v2/users/login";
public static final String GET_SCRIPTS = "http://bdn.parabot.org/api/get.php?action=scripts_scripts&server=";
public static final String GET_SCRIPT = "http://bdn.parabot.org/api/get.php?action=scripts_script&id=";
public static final String GET_SERVER_PROVIDER_TYPE = "http://v3.bdn.parabot.org/api/bot/server/type?server=%s";
public static final String GET_SERVER_PROVIDERS = "http://bdn.parabot.org/api/get.php?action=server_providers";
public static final String GET_SERVER_PROVIDER = "http://v3.bdn.parabot.org/api/bot/download/provider?nightly=%s&server=%s";
public static final String SERVER_PROVIDER_INFO = "http://v3.bdn.parabot.org/api/bot/list/%s?latest=true";
public static final String GET_SERVER_PROVIDER_INFO = "http://bdn.parabot.org/api/get.php?action=server_information&name=";
public static final String GET_SERVER_SETTINGS = "http://bdn.parabot.org/api/get.php?action=get_settings";
public static final String GET_BOT_VERSION = "http://bdn.parabot.org/api/v2/bot/version";
public static final String API_DOWNLOAD_BOT = "http://v3.bdn.parabot.org/api/bot/download/client";
public static final String DOWNLOAD_BOT = "http://bdn.parabot.org/versions/";
public static final String REGISTRATION_PAGE = "https://www.parabot.org/community/register/";
public static final String GET_RANDOMS = "http://v3.bdn.parabot.org/api/bot/download/randoms";
public static final String DATA_API = "http://bdn.parabot.org/api/v2/data/";
public static final String ITEM_API = DATA_API + "items/";
public static final Version BOT_VERSION = ProjectProperties.getProjectVersion();
public static final Version BOT_VERSION = ProjectProperties.getProjectVersion();
public static final String COMMUNITY_PAGE = "https://www.parabot.org/community/";
public static final String REGISTRATION_PAGE = COMMUNITY_PAGE + "register/";
}
@@ -70,6 +70,13 @@ public class Context {
this.defaultErr = System.err;
}
public static double getJavaVersion() {
String version = System.getProperty("java.version");
int pos = version.indexOf('.');
pos = version.indexOf('.', pos + 1);
return Double.parseDouble(version.substring(0, pos));
}
/**
* Returns the instance of this class, based on a given ServerProvider
*
@@ -1,24 +1,29 @@
package org.parabot.core.asm.hooks;
import org.parabot.core.forum.AccountManager;
import org.parabot.core.parsers.hooks.HookParser;
import org.parabot.core.parsers.hooks.JSONHookParser;
import org.parabot.core.parsers.hooks.XMLHookParser;
import org.parabot.environment.api.utils.WebUtil;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
public class HookFile {
public static final int TYPE_XML = 0;
public static final int TYPE_XML = 0;
public static final int TYPE_JSON = 1;
private URL url;
private int type;
private boolean isLocal;
public HookFile(File file, int type) throws MalformedURLException {
this(file.toURI().toURL(), type);
this.isLocal = true;
}
public HookFile(URL url, int type) {
@@ -26,17 +31,22 @@ public class HookFile {
this.url = url;
}
private void setType(int type) {
if (type < 0 || type > 1) {
throw new IllegalArgumentException("This type does not exist");
}
this.type = type;
}
public InputStream getInputStream() {
return WebUtil.getInputStream(url);
}
public InputStream getInputStream(AccountManager manager) {
if (isLocal) {
return this.getInputStream();
} else {
try {
return WebUtil.getConnection(url, "apikey=" + manager.getAccount().getApi()).getInputStream();
} catch (IOException e) {
return null;
}
}
}
public HookParser getParser() {
switch (type) {
case TYPE_XML:
@@ -47,4 +57,11 @@ public class HookFile {
return null;
}
private void setType(int type) {
if (type < 0 || type > 1) {
throw new IllegalArgumentException("This type does not exist");
}
this.type = type;
}
}
@@ -7,6 +7,7 @@ import org.parabot.environment.scripts.Script;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
@@ -58,6 +59,15 @@ public class ClassRedirect {
return Class.forName(name);
}
public static URL getResource(Class<?> c, String path) {
if(validStack() || validRequest(c)) {
return c.getResource(path);
}
System.err.println(c.getName() + "#getResource(" + path + ") Blocked.");
throw RedirectClassAdapter.createSecurityException();
}
public static ClassLoader getClassLoader(Class<?> c) {
System.err.println(c.getName() + "#getClassLoader()" + " Blocked.");
throw RedirectClassAdapter.createSecurityException();
@@ -31,7 +31,7 @@ public class RuntimeRedirect {
if (s.contains("ping")) {
System.out.println("Faked attempted command: " + s);
try {
return r.exec("ping 127.0.0.1");
return r.exec("ping 8.8.8.8");
} catch (IOException e) {
throw RedirectClassAdapter.createSecurityException();
}
@@ -61,4 +61,12 @@ public class ThreadRedirect {
public static void setUncaughtExceptionHandler(Thread t, Thread.UncaughtExceptionHandler handler) {
t.setUncaughtExceptionHandler(handler);
}
public static boolean isInterrupted(Thread thread) {
return thread.isInterrupted();
}
public static long getId(Thread thread) {
return thread.getId();
}
}
@@ -49,4 +49,19 @@ public class Callback implements Injectable {
this.invokeMethod, this.desc, this.args, this.conditional);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Injectable type: Callback");
if(method != null) {
sb.append(", intercepts method: ").append(method.name);
}
sb.append(", calls class: ").append(invokeClass)
.append(", calls method: ").append(invokeMethod);
return sb.toString();
}
}
@@ -38,7 +38,7 @@ public class Getter implements Injectable {
this.fieldLocation = ASMUtils.getClass(fieldLocation);
this.fieldNode = ASMUtils.getField(ASMUtils.getClass(fieldLocation), fieldNode, fieldDesc);
this.methodName = methodName;
this.returnDesc = returnDesc == null ? this.fieldNode.desc : returnDesc;
this.returnDesc = (returnDesc == null && this.fieldNode != null) ? this.fieldNode.desc : returnDesc;
this.staticMethod = staticMethod;
this.multiplier = multiplier;
Core.verbose(methodName + "[" + fieldLocation + "." + fieldNode + "]");
@@ -77,4 +77,21 @@ public class Getter implements Injectable {
return new AddGetterAdapter(into, fieldLocation, fieldNode, methodName, returnDesc, staticMethod, multiplier);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Injectable type: Getter");
if(fieldLocation.interfaces.size() > 0) {
sb.append(", accessor type: ").append(fieldLocation.interfaces.get(0).toString().replace('/', '.'));
}
if(fieldNode != null) {
sb.append(", field: ").append(fieldNode.name);
}
sb.append(", method name: ").append(methodName);
return sb.toString();
}
}
@@ -79,4 +79,8 @@ public class Invoker implements Injectable {
this.argsDesc, this.returnDesc, this.methodName, this.isInterface, this.instanceCast, this.argsCheckCastDesc);
}
@Override
public String toString() {
return String.format("Injectable type: Invoker, accessor: %s, method name: %s, invokes method: %s", methodLocation.name, methodName, mName);
}
}
@@ -25,7 +25,7 @@ public class Setter implements Injectable {
this.into = ASMUtils.getClass(into);
this.field = ASMUtils.getField(this.fieldLocation, fieldName, fieldDesc);
this.name = methodName;
this.desc = (desc == null) ? this.field.desc : desc;
this.desc = (desc == null && this.field != null) ? this.field.desc : desc;
this.methodStatic = methodStatic;
}
@@ -52,4 +52,21 @@ public class Setter implements Injectable {
return new AddSetterAdapter(fieldLocation, into, field, name, desc, methodStatic);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Injectable type: Setter");
if(fieldLocation.interfaces.size() > 0) {
sb.append(", accessor type: ").append(fieldLocation.interfaces.get(0).toString().replace('/', '.'));
}
if(field != null) {
sb.append(", field: ").append(field.name);
}
sb.append(", method name: ").append(name);
return sb.toString();
}
}
@@ -166,6 +166,7 @@ public class ServerProviderInfo {
/**
* Gets the URL to download the Randoms JAR from.
*
* @return The provided URL in the server config JSON (denoted by 'randoms:') or, fallback to the default BDN URL.
*/
public URL getRandoms() {
@@ -182,4 +183,19 @@ public class ServerProviderInfo {
// Will never return null, unless the BDN URL is changed. It shouldn't be.
return null;
}
/**
* Gets the current provider version
*
* @return provider version
*/
public String getProviderVersion() {
String providerType = WebUtil.getJsonValue(String.format(Configuration.GET_SERVER_PROVIDER_TYPE , properties.getProperty("name")), "type");
if(providerType != null) {
String providerInfo = String.format(Configuration.SERVER_PROVIDER_INFO, providerType);
return WebUtil.getJsonValue(providerInfo, "version");
}
return null;
}
}
@@ -4,6 +4,7 @@ import org.json.simple.JSONObject;
import org.parabot.core.Configuration;
import org.parabot.core.Context;
import org.parabot.core.Core;
import org.parabot.core.parsers.hooks.HookParser;
import org.parabot.core.parsers.scripts.BDNScripts;
import org.parabot.core.parsers.servers.PublicServers;
import org.parabot.core.ui.components.VerboseLoader;
@@ -48,6 +49,7 @@ public final class AccountManager {
accessors.add(PublicServers.MANAGER_FETCHER);
accessors.add(PublicServerExecuter.MANAGER_FETCHER);
accessors.add(PBPreferences.MANAGER_FETCHER);
accessors.add(HookParser.MANAGER_FETCHER);
for (final AccountManagerAccess accessor : accessors) {
accessor.setManager(instance);
@@ -1,5 +1,6 @@
package org.parabot.core.network.proxy;
import org.parabot.core.Core;
import org.parabot.core.ui.utils.UILog;
import javax.swing.*;
@@ -44,7 +45,7 @@ public class ProxySocket extends Socket {
socket.close();
value++;
} catch (Exception e) {
Core.verbose("Error closing proxy connection: " + e.getMessage());
}
}
return value;
@@ -3,25 +3,39 @@ package org.parabot.core.parsers.hooks;
import org.parabot.core.asm.hooks.HookFile;
import org.parabot.core.asm.interfaces.Injectable;
import org.parabot.core.asm.wrappers.*;
import org.parabot.core.forum.AccountManager;
import org.parabot.core.forum.AccountManagerAccess;
import org.parabot.environment.api.utils.PBPreferences;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Parses an XML files which injects the hooks and other bytecode manipulation
* Parses a structured format file which injects the hooks and other bytecode manipulation
* methods
*
* @author Everel
* @author Everel, JKetelaar
*/
public abstract class HookParser {
protected static AccountManager manager;
public static final AccountManagerAccess MANAGER_FETCHER = new AccountManagerAccess() {
@Override
public final void setManager(AccountManager manager) {
HookParser.manager = manager;
}
};
public HookParser(HookFile hookFile) {
}
public abstract Interface[] getInterfaces();
public abstract Map<String, String> getInterfaceMap();
public abstract Super[] getSupers();
public abstract Getter[] getGetters();
@@ -12,7 +12,10 @@ import java.util.HashMap;
import java.util.Map;
/**
* @author Dane
* Parses a JSON file which injects the hooks and other bytecode manipulation
* methods
*
* @author Dane, JKetelaar
*/
public class JSONHookParser extends HookParser {
private JSONObject root;
@@ -71,6 +74,11 @@ public class JSONHookParser extends HookParser {
return null;
}
@Override
public Map<String, String> getInterfaceMap() {
return this.interfaces;
}
@Override
public Super[] getSupers() {
JSONArray a = (JSONArray) root.get("supers");
@@ -13,22 +13,29 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* Parses an XML file which injects the hooks and other bytecode manipulation
* methods
*
* @author JKetelaar
*/
public class XMLHookParser extends HookParser {
private Document doc;
private Document doc;
private HashMap<String, String> interfaceMap;
private HashMap<String, String> constants;
private boolean parsedInterfaces;
private boolean parsedInterfaces;
public XMLHookParser(HookFile hookFile) {
super(hookFile);
interfaceMap = new HashMap<String, String>();
constants = new HashMap<String, String>();
interfaceMap = new HashMap<>();
constants = new HashMap<>();
try {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
doc = dBuilder.parse(hookFile.getInputStream());
doc = dBuilder.parse(hookFile.getInputStream(manager));
doc.getDocumentElement().normalize();
if (!doc.getDocumentElement().getNodeName().equals("injector")) {
throw new RuntimeException("Incorrect hook file.");
@@ -38,48 +45,6 @@ public class XMLHookParser extends HookParser {
}
}
private static String resolveDesc(String returnDesc) {
String array = "";
if (returnDesc != null && returnDesc.contains("%s")) {
StringBuilder str = new StringBuilder();
if (returnDesc.startsWith("[")) {
for (int i = 0; i < returnDesc.length(); i++) {
if (returnDesc.charAt(i) == '[') {
array += '[';
}
}
returnDesc = returnDesc.replaceAll("\\[", "");
}
str.append(array)
.append('L')
.append(String.format(returnDesc,
AddInterfaceAdapter.getAccessorPackage()))
.append(";");
returnDesc = str.toString();
}
return returnDesc;
}
private static final boolean isSet(String tag, Element element) {
return element.getElementsByTagName(tag).getLength() > 0;
}
private static final String getValue(String tag, Element element) {
if (element.getElementsByTagName(tag).item(0) == null) {
throw new NullPointerException("MISSING HOOK TAG: The '" + tag + "' xml tag is missing from one of the hooks of type: " + element.getParentNode().getNodeName());
}
NodeList nodes = element.getElementsByTagName(tag).item(0)
.getChildNodes();
if (nodes.getLength() == 0 || nodes.item(0) == null) {
if (Core.inVerboseMode()) {
System.err.println("WARNING: Invalid Hook " + tag + " subnode. Tag is missing or empty?");
}
return "";
}
Node node = (Node) nodes.item(0);
return node.getNodeValue();
}
@Override
public Interface[] getInterfaces() {
parsedInterfaces = true;
@@ -98,8 +63,8 @@ public class XMLHookParser extends HookParser {
if (node.getNodeType() != Node.ELEMENT_NODE) {
return null;
}
final Element interfaceRoot = (Element) node;
final NodeList interfaces = interfaceRoot.getElementsByTagName("add");
final Element interfaceRoot = (Element) node;
final NodeList interfaces = interfaceRoot.getElementsByTagName("add");
if (interfaces.getLength() == 0) {
return null;
}
@@ -109,9 +74,9 @@ public class XMLHookParser extends HookParser {
if (n.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
final Element addInterface = (Element) n;
final String className = getValue("classname", addInterface);
final String interfaceClass = getValue("interface", addInterface);
final Element addInterface = (Element) n;
final String className = getValue("classname", addInterface);
final String interfaceClass = getValue("interface", addInterface);
interfaceMap.put(interfaceClass, className);
final Interface inf = new Interface(className, interfaceClass);
interfaceList.add(inf);
@@ -119,6 +84,11 @@ public class XMLHookParser extends HookParser {
return interfaceList.toArray(new Interface[interfaceList.size()]);
}
@Override
public Map<String, String> getInterfaceMap() {
return this.interfaceMap;
}
@Override
public Super[] getSupers() {
final NodeList interfaceRootList = doc.getElementsByTagName("supers");
@@ -135,8 +105,8 @@ public class XMLHookParser extends HookParser {
if (node.getNodeType() != Node.ELEMENT_NODE) {
return null;
}
final Element superRoot = (Element) node;
final NodeList supers = superRoot.getElementsByTagName("add");
final Element superRoot = (Element) node;
final NodeList supers = superRoot.getElementsByTagName("add");
if (supers.getLength() == 0) {
return null;
}
@@ -146,10 +116,10 @@ public class XMLHookParser extends HookParser {
if (n.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
final Element addSuper = (Element) n;
final String className = getValue("classname", addSuper);
final String superClass = getValue("super", addSuper);
final Super sup = new Super(className, superClass);
final Element addSuper = (Element) n;
final String className = getValue("classname", addSuper);
final String superClass = getValue("super", addSuper);
final Super sup = new Super(className, superClass);
superList.add(sup);
}
return superList.toArray(new Super[superList.size()]);
@@ -171,8 +141,8 @@ public class XMLHookParser extends HookParser {
if (node.getNodeType() != Node.ELEMENT_NODE) {
return null;
}
final Element getterRoot = (Element) node;
final NodeList getters = getterRoot.getElementsByTagName("add");
final Element getterRoot = (Element) node;
final NodeList getters = getterRoot.getElementsByTagName("add");
if (getters.getLength() == 0) {
return null;
}
@@ -196,9 +166,9 @@ public class XMLHookParser extends HookParser {
"accessor", addGetter));
final String into = isSet("into", addGetter) ? getValue("into",
addGetter) : className;
final long multiplier = isSet("multiplier", addGetter) ? Long.parseLong(getValue("multiplier", addGetter)) : 0L;
final String fieldName = getValue("field", addGetter);
final String fieldDesc = isSet("descfield", addGetter) ? getValue("descfield", addGetter) : null;
final long multiplier = isSet("multiplier", addGetter) ? Long.parseLong(getValue("multiplier", addGetter)) : 0L;
final String fieldName = getValue("field", addGetter);
final String fieldDesc = isSet("descfield", addGetter) ? getValue("descfield", addGetter) : null;
final String methodName = getValue("methodname", addGetter);
boolean staticMethod = isSet("methstatic", addGetter) ? (getValue(
"methstatic", addGetter).equals("true")) : false;
@@ -246,8 +216,8 @@ public class XMLHookParser extends HookParser {
if (node.getNodeType() != Node.ELEMENT_NODE) {
return null;
}
final Element setterRoot = (Element) node;
final NodeList setters = setterRoot.getElementsByTagName("add");
final Element setterRoot = (Element) node;
final NodeList setters = setterRoot.getElementsByTagName("add");
if (setters.getLength() == 0) {
return null;
}
@@ -271,8 +241,8 @@ public class XMLHookParser extends HookParser {
"accessor", addSetter));
final String into = isSet("into", addSetter) ? getValue("into",
addSetter) : className;
final String fieldName = getValue("field", addSetter);
final String fieldDesc = isSet("descfield", addSetter) ? getValue("descfield", addSetter) : null;
final String fieldName = getValue("field", addSetter);
final String fieldDesc = isSet("descfield", addSetter) ? getValue("descfield", addSetter) : null;
final String methodName = getValue("methodname", addSetter);
boolean staticMethod = isSet("methstatic", addSetter) ? (getValue(
"methstatic", addSetter).equals("true")) : false;
@@ -319,8 +289,8 @@ public class XMLHookParser extends HookParser {
if (node.getNodeType() != Node.ELEMENT_NODE) {
return null;
}
final Element invokerRoot = (Element) node;
final NodeList invokers = invokerRoot.getElementsByTagName("add");
final Element invokerRoot = (Element) node;
final NodeList invokers = invokerRoot.getElementsByTagName("add");
if (invokers.getLength() == 0) {
return null;
}
@@ -344,15 +314,15 @@ public class XMLHookParser extends HookParser {
"accessor", addInvoker));
final String into = isSet("into", addInvoker) ? getValue("into",
addInvoker) : className;
final String methodName = getValue("methodname", addInvoker);
final String methodName = getValue("methodname", addInvoker);
final String invMethodName = getValue("invokemethod", addInvoker);
final String argsDesc = getValue("argsdesc", addInvoker);
final String argsDesc = getValue("argsdesc", addInvoker);
String returnDesc = isSet("desc", addInvoker) ? resolveDesc(getValue(
"desc", addInvoker)) : null;
final boolean isInterface = isSet("interface", addInvoker) ? Boolean.parseBoolean(getValue("interface", addInvoker)) : false;
final String instanceCast = isSet("instancecast", addInvoker) ? getValue("instancecast", addInvoker) : null;
final String checkCastArgsDesc = isSet("castargs", addInvoker) ? getValue("castargs", addInvoker) : null;
final boolean isInterface = isSet("interface", addInvoker) ? Boolean.parseBoolean(getValue("interface", addInvoker)) : false;
final String instanceCast = isSet("instancecast", addInvoker) ? getValue("instancecast", addInvoker) : null;
final String checkCastArgsDesc = isSet("castargs", addInvoker) ? getValue("castargs", addInvoker) : null;
final Invoker invoker = new Invoker(into, className, invMethodName,
argsDesc, returnDesc, methodName, isInterface, instanceCast, checkCastArgsDesc);
@@ -381,7 +351,7 @@ public class XMLHookParser extends HookParser {
if (node.getNodeType() != Node.ELEMENT_NODE) {
return null;
}
final Element constantRoot = (Element) node;
final Element constantRoot = (Element) node;
final NodeList constantsList = constantRoot.getElementsByTagName("add");
if (constantsList.getLength() == 0) {
// return empty hashmap
@@ -393,8 +363,8 @@ public class XMLHookParser extends HookParser {
continue;
}
final Element addConstant = (Element) n;
final String key = getValue("key", addConstant);
final String value = getValue("value", addConstant);
final String key = getValue("key", addConstant);
final String value = getValue("value", addConstant);
constants.put(key, value);
}
return constants;
@@ -416,8 +386,8 @@ public class XMLHookParser extends HookParser {
if (node.getNodeType() != Node.ELEMENT_NODE) {
return null;
}
final Element callbackRoot = (Element) node;
final NodeList callbacks = callbackRoot.getElementsByTagName("add");
final Element callbackRoot = (Element) node;
final NodeList callbacks = callbackRoot.getElementsByTagName("add");
if (callbacks.getLength() == 0) {
return null;
}
@@ -441,12 +411,12 @@ public class XMLHookParser extends HookParser {
"classname", addCallback) : interfaceMap.get(getValue(
"accessor", addCallback));
final String methodName = getValue("methodname", addCallback);
final String callClass = getValue("callclass", addCallback);
final String callMethod = getValue("callmethod", addCallback);
final String callDesc = getValue("calldesc", addCallback);
final String callArgs = getValue("callargs", addCallback);
final String desc = getValue("desc", addCallback);
final String methodName = getValue("methodname", addCallback);
final String callClass = getValue("callclass", addCallback);
final String callMethod = getValue("callmethod", addCallback);
final String callDesc = getValue("calldesc", addCallback);
final String callArgs = getValue("callargs", addCallback);
final String desc = getValue("desc", addCallback);
final boolean conditional = isSet("conditional", addCallback);
final Callback callback = new Callback(className, methodName, desc,
@@ -456,4 +426,46 @@ public class XMLHookParser extends HookParser {
return callbackList.toArray(new Callback[callbackList.size()]);
}
private static String resolveDesc(String returnDesc) {
String array = "";
if (returnDesc != null && returnDesc.contains("%s")) {
StringBuilder str = new StringBuilder();
if (returnDesc.startsWith("[")) {
for (int i = 0; i < returnDesc.length(); i++) {
if (returnDesc.charAt(i) == '[') {
array += '[';
}
}
returnDesc = returnDesc.replaceAll("\\[", "");
}
str.append(array)
.append('L')
.append(String.format(returnDesc,
AddInterfaceAdapter.getAccessorPackage()))
.append(";");
returnDesc = str.toString();
}
return returnDesc;
}
private static final boolean isSet(String tag, Element element) {
return element.getElementsByTagName(tag).getLength() > 0;
}
private static final String getValue(String tag, Element element) {
if (element.getElementsByTagName(tag).item(0) == null) {
throw new NullPointerException("MISSING HOOK TAG: The '" + tag + "' xml tag is missing from one of the hooks of type: " + element.getParentNode().getNodeName());
}
NodeList nodes = element.getElementsByTagName(tag).item(0)
.getChildNodes();
if (nodes.getLength() == 0 || nodes.item(0) == null) {
if (Core.inVerboseMode()) {
System.err.println("WARNING: Invalid Hook " + tag + " subnode. Tag is missing or empty?");
}
return "";
}
Node node = (Node) nodes.item(0);
return node.getNodeValue();
}
}
+1 -2
View File
@@ -1,6 +1,5 @@
package org.parabot.core.ui;
import javafx.application.Application;
import org.parabot.core.Configuration;
import org.parabot.core.Context;
import org.parabot.core.Directories;
@@ -248,7 +247,7 @@ public class BotUI extends JFrame implements ActionListener, ComponentListener,
Directories.clearCache();
break;
case "Notifications":
Application.launch(NotificationUI.class);
NotificationUI.create();
break;
default:
System.out.println("Invalid command: " + command);
@@ -1,20 +1,56 @@
package org.parabot.core.ui.components.notifications;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import org.parabot.core.Configuration;
import org.parabot.api.Configuration;
import org.parabot.api.output.Verboser;
import org.parabot.api.ui.JavaFxUtil;
public class NotificationUI extends Application {
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
/**
* A JavaFX Panel embedded into a Swing JFrame - handles notification settings
*
* @author Shadowrs
*/
public class NotificationUI extends JavaFxUtil {
final NotificationUI n;
private NotificationUI() throws URISyntaxException, MalformedURLException {
super(Configuration.class.getClass().getResource("/storage/ui/notifications.fxml").toURI().toURL(), NotificationUIController.class);
this.n = this;
}
public static void create() {
try {
new NotificationUI();
} catch (URISyntaxException | MalformedURLException e) {
e.printStackTrace();
}
}
@Override
public void start(Stage stage) throws Exception {
//noinspection RedundantCast
BorderPane root = (BorderPane) FXMLLoader.load(this.getClass().getResource("/storage/ui/notifications.fxml"));
stage.setTitle(Configuration.BOT_TITLE);
stage.setScene(new Scene(root));
stage.show();
public WindowAdapter getWindowAdapter() {
return new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
Verboser.verbose("NotificationUI closed " + e);
}
@Override
public void windowClosing(WindowEvent e) {
// Anything here. JFrame hides on exit.
Verboser.verbose("NotificationUI closing " + e);
n.getFrame().dispose();
}
};
}
@Override
protected void onLaunched() {
n.getFrame().setTitle("Notifications");
}
}
@@ -30,4 +30,13 @@ public class UILog {
public static int alert(final String title, final String message, int optionType, int messageType) {
return JOptionPane.showConfirmDialog(null, message, title, optionType, messageType);
}
public static int alert(final String title, final String message, Object[] options) {
return alert(title, message, options, JOptionPane.INFORMATION_MESSAGE);
}
public static int alert(final String title, final String message, Object[] options, int messageType) {
return JOptionPane.showOptionDialog(null, message, title,
JOptionPane.YES_NO_CANCEL_OPTION, messageType, null, options, null);
}
}
@@ -33,7 +33,7 @@ public class Environment extends org.parabot.api.io.libraries.Environment {
loadLibrary(lib, true);
}
Core.verbose("Loading server: " + desc.toString() + "...");
Core.verbose("[Environment] Loading server: " + desc.toString() + "...");
ServerParser.SERVER_CACHE.get(desc).run();
}
@@ -1,10 +1,8 @@
package org.parabot.environment.api.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -88,4 +86,29 @@ public class FileUtil {
}
destination.close();
}
/**
* Reads the contents of a text file
*
* @param file file to get contents from
* @return file contents
* @throws IOException when anything goes wrong
*/
public static String getFileContents(File file) throws IOException {
return new String(Files.readAllBytes(file.toPath()));
}
/**
* Writes a string to a file overwriting the existing contents if present
*
* @param file file to write to
* @param contents contents to write to given file
* @throws IOException when anything goes wrong
*/
public static void writeFileContents(File file, String contents) throws IOException {
BufferedWriter writer = new BufferedWriter(new FileWriter(file.getAbsolutePath()));
writer.write(contents);
writer.close();
}
}
@@ -0,0 +1,118 @@
package org.parabot.environment.api.utils;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.parabot.core.Directories;
import java.io.File;
import java.util.HashMap;
/**
* Manages preferences in a local file in JSON format in the Parabot settings folder
*
* @author AlexanderBielen
*/
public class PBLocalPreferences {
private static JSONParser parser = new JSONParser();
private File settingsFile;
public PBLocalPreferences(String fileName) {
settingsFile = new File(Directories.getSettingsPath() + "/" + secureFileName(fileName));
}
/**
* Gets all settings inside the file
*
* @return JSONObject or null if anything went wrong
*/
public JSONObject getSettings() {
try {
String stringContents = FileUtil.getFileContents(settingsFile);
return (JSONObject) parser.parse(stringContents);
} catch(Exception ex) {
return null;
}
}
/**
* Convert a HashMap to json and writes it to the file
*
* @param settings HashMap<String, String>
* @param append If true, append to existing settings in file
*/
public void writeSettings(HashMap<String, String> settings, boolean append) {
JSONObject existingSettings;
if(append && (existingSettings = getSettings()) != null) {
existingSettings.putAll(settings);
settings = existingSettings;
}
try {
if (!settingsFile.exists()) {
settingsFile.createNewFile();
}
FileUtil.writeFileContents(settingsFile, new JSONObject(settings).toJSONString());
} catch (Exception ignore) {
ignore.printStackTrace();
}
}
/**
* Adds a setting, or overwrites it if it exists
*
* @param key key of the setting
* @param value value of the setting
*/
public void addSetting(String key, String value) {
HashMap<String, String> pair = new HashMap<>();
pair.put(key, value);
writeSettings(pair, true);
}
/**
* Fetches a setting
*
* @param key key to get the value for
* @return value that belongs to given key or null if non-existent
*/
public String getSetting(String key) {
if(getSettings() == null) {
return null;
}
return getSettings().get(key).toString();
}
/**
* Adjusts an existing setting
*
* @param key key to adjust the value for
* @param value value for the key
*/
public void adjustSetting(String key, String value) {
addSetting(key, value);
}
/**
* Removes a setting
*
* @param key key to remove
*/
public void removeSetting(String key) {
JSONObject json = getSettings();
json.remove(key);
writeSettings(json, false);
}
/**
* Replaces all double dots to make sure the link does not leave the settings folder
*
* @param filePath path to secure
* @return secured string
*/
private static String secureFileName(String filePath) {
return filePath.replace("..", "");
}
}
@@ -53,6 +53,30 @@ public final class Time {
return true;
}
/**
* Sleeps until SleepCondition is valid, but with a minimum timeout.
*
* @param conn the condition.
* @param timeout the time in milliseconds before it stops sleeping.
* @param minimumTimeout the minimum time to sleep.
*
* @return whether it ran successfully without timing out.
*/
public static boolean sleep(SleepCondition conn, int timeout, int minimumTimeout) {
long start = System.currentTimeMillis();
if(!sleep(conn, timeout)) {
return false;
}
long t;
if((t = System.currentTimeMillis() - start) < minimumTimeout) {
Time.sleep((int)(minimumTimeout - t));
}
return true;
}
/**
* Gets current time in milliseconds
*
@@ -105,7 +105,18 @@ public class Timer {
* @return hourly gains
*/
public int getPerHour(final int gained) {
return (int) ((gained) * 3600000D / (System.currentTimeMillis() - start));
return getPerHour(gained, 0);
}
/**
* Calculates hourly gains based on given variable, with variable start amount
*
* @param gained total gained amount
* @param startAmount start amount
* @return hourly gains
*/
public int getPerHour(final int gained, final int startAmount) {
return (int) (((gained - startAmount) * 3600000D) / (System.currentTimeMillis() - start));
}
/**
@@ -1,5 +1,7 @@
package org.parabot.environment.api.utils;
import org.json.simple.JSONObject;
/**
* A WebUtil class fetches data from an URL
*
@@ -7,4 +9,27 @@ package org.parabot.environment.api.utils;
*/
public class WebUtil extends org.parabot.api.io.WebUtil {
/**
* Fetches a single value from a JSON string at the given url
*
* @param url url to get the JSON string from
* @param key key to search for in the JSON string
* @return value that belongs to given key
*/
public static String getJsonValue(String url, String key) {
try {
String response = WebUtil.getContents(url);
if(response.length() > 0) {
JSONObject jsonObject = (JSONObject) WebUtil.getJsonParser().parse(response);
if (jsonObject.get(key) != null) {
return jsonObject.get(key).toString();
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
}
@@ -1,10 +1,12 @@
package org.parabot.environment.servers;
import org.objectweb.asm.Opcodes;
import org.parabot.core.Configuration;
import org.parabot.core.Context;
import org.parabot.core.asm.hooks.HookFile;
import org.parabot.core.asm.interfaces.Injectable;
import org.parabot.core.parsers.hooks.HookParser;
import org.parabot.core.ui.utils.UILog;
import org.parabot.environment.input.Keyboard;
import org.parabot.environment.input.Mouse;
import org.parabot.environment.scripts.Script;
@@ -13,6 +15,8 @@ import javax.swing.*;
import java.applet.Applet;
import java.applet.AppletStub;
import java.awt.*;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
/**
@@ -21,6 +25,7 @@ import java.net.URL;
* @author Everel
*/
public abstract class ServerProvider implements Opcodes {
private boolean crashed = false;
/**
* Get the game/applet dimensions
@@ -74,12 +79,36 @@ public abstract class ServerProvider implements Opcodes {
HookParser parser = hookFile.getParser();
Injectable[] injectables = parser.getInjectables();
if (injectables == null) {
return;
}
for (Injectable inj : injectables) {
inj.inject();
int index = 0;
try {
for (Injectable inj : injectables) {
inj.inject();
index++;
}
} catch (NullPointerException ex) {
if(!crashed) {
Injectable inj = injectables[index];
int resp = UILog.alert("Outdated client", "This server currently has outdated hooks, please report it to a member of the Parabot staff.\r\n\r\n" +
"Broken hook:\r\n"+inj, new Object[]{"Close", "Report here..."}, JOptionPane.ERROR_MESSAGE);
if(resp == 1) {
URI uri = URI.create(Configuration.COMMUNITY_PAGE + "forum/135-reports/");
try {
Desktop.getDesktop().browse(uri);
} catch (IOException ignore) {}
}
}
crashed = true;
throw ex;
}
Context.getInstance().setHookParser(parser);
}
@@ -11,6 +11,7 @@ import org.parabot.core.forum.AccountManager;
import org.parabot.core.forum.AccountManagerAccess;
import org.parabot.core.ui.components.VerboseLoader;
import org.parabot.core.ui.utils.UILog;
import org.parabot.environment.api.utils.PBLocalPreferences;
import org.parabot.environment.api.utils.WebUtil;
import org.parabot.environment.servers.ServerProvider;
import org.parabot.environment.servers.loader.ServerLoader;
@@ -37,6 +38,9 @@ public class PublicServerExecuter extends ServerExecuter {
};
private String serverName;
private PBLocalPreferences settings;
private final String cacheVersionKey = "cachedProviderVersion";
public PublicServerExecuter(final String serverName) {
this.serverName = serverName;
}
@@ -53,6 +57,24 @@ public class PublicServerExecuter extends ServerExecuter {
Core.verbose("Downloading: " + jarUrl + " ...");
String providerVersion = serverProviderInfo.getProviderVersion();
if(providerVersion == null) {
providerVersion = "error";
}
settings = new PBLocalPreferences(serverProviderInfo.getClientCRC32()+".json");
if(settings.getSetting(cacheVersionKey) != null) {
Core.verbose(String.format("Latest provider version: %s, local provider version: %s", settings.getSetting(cacheVersionKey), providerVersion));
if(!settings.getSetting(cacheVersionKey).equals(providerVersion)) {
Core.verbose("Local provider outdated, clearing cache.");
Directories.clearCache();
}
} else {
Core.verbose("No local provider version in settings, adding to settings file");
}
settings.addSetting(cacheVersionKey, providerVersion);
if (destination.exists()) {
Core.verbose("Found cached server provider [CRC32: " + serverProviderInfo.getCRC32() + "]");
} else {
@@ -4,8 +4,7 @@
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="231.0"
prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="org.parabot.core.ui.components.notifications.NotificationUIController">
prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1">
<bottom>
<Button mnemonicParsing="false" text="Save" BorderPane.alignment="CENTER" onAction="#save">
<BorderPane.margin>