mirror of
https://github.com/sirjonasxx/G-Earth.git
synced 2025-01-18 16:26:26 +01:00
Merge branch 'webviewLogger' into anime-edition
This commit is contained in:
commit
3e1acde242
@ -13,7 +13,7 @@
|
||||
<parent>
|
||||
<groupId>G-Earth</groupId>
|
||||
<artifactId>G-Earth-Parent</artifactId>
|
||||
<version>1.1</version>
|
||||
<version>1.3</version>
|
||||
<relativePath>../../</relativePath>
|
||||
</parent>
|
||||
|
||||
@ -106,7 +106,7 @@
|
||||
<dependency>
|
||||
<groupId>G-Earth</groupId>
|
||||
<artifactId>G-Earth</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.3</version>
|
||||
<!--<scope>provided</scope>-->
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
@ -13,7 +13,7 @@
|
||||
<parent>
|
||||
<groupId>G-Earth</groupId>
|
||||
<artifactId>G-Earth-Parent</artifactId>
|
||||
<version>1.1</version>
|
||||
<version>1.3</version>
|
||||
<relativePath>../../</relativePath>
|
||||
</parent>
|
||||
|
||||
@ -106,7 +106,7 @@
|
||||
<dependency>
|
||||
<groupId>G-Earth</groupId>
|
||||
<artifactId>G-Earth</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.3</version>
|
||||
<!--<scope>provided</scope>-->
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
@ -8,22 +8,21 @@
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<version>1.1</version>
|
||||
<version>1.3</version>
|
||||
|
||||
<properties>
|
||||
<javafx.version>1.8</javafx.version>
|
||||
<jettyVersion>9.4.35.v20201120</jettyVersion>
|
||||
</properties>
|
||||
|
||||
<parent>
|
||||
<groupId>G-Earth</groupId>
|
||||
<artifactId>G-Earth-Parent</artifactId>
|
||||
<version>1.1</version>
|
||||
<version>1.3</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
|
||||
<!-- this builds a non-standalone JAR file -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
@ -36,7 +35,7 @@
|
||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||
<addClasspath>true</addClasspath>
|
||||
<classpathPrefix>lib/</classpathPrefix>
|
||||
<mainClass>gearth.J11Main</mainClass>
|
||||
<mainClass>gearth.Main</mainClass>
|
||||
<useUniqueVersions>false</useUniqueVersions>
|
||||
</manifest>
|
||||
</archive>
|
||||
@ -58,7 +57,7 @@
|
||||
<outputDirectory>${project.build.directory}/bin</outputDirectory>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>gearth.J11Main</mainClass>
|
||||
<mainClass>gearth.Main</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
@ -86,6 +85,11 @@
|
||||
<copy file="target/bin/G-Earth.jar" todir="../Build/Windows_32bit/"/>
|
||||
<copy file="target/bin/G-Earth.jar" todir="../Build/Windows_64bit/"/>
|
||||
|
||||
<copy file="src/main/resources/build/messages.json" todir="../Build/Mac/"/>
|
||||
<copy file="src/main/resources/build/messages.json" todir="../Build/Linux/"/>
|
||||
<copy file="src/main/resources/build/messages.json" todir="../Build/Windows_32bit/"/>
|
||||
<copy file="src/main/resources/build/messages.json" todir="../Build/Windows_64bit/"/>
|
||||
|
||||
<copy todir="../Build/Mac/">
|
||||
<fileset dir="src/main/resources/build/mac" includes="**/*" />
|
||||
</copy>
|
||||
@ -123,6 +127,7 @@
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.openjfx</groupId>-->
|
||||
@ -152,13 +157,51 @@
|
||||
<dependency>
|
||||
<groupId>com.github.tulskiy</groupId>
|
||||
<artifactId>jkeymaster</artifactId>
|
||||
<version>1.2</version>
|
||||
<version>1.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-jdk14</artifactId>
|
||||
<version>2.0.0-alpha0</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.apache.maven/maven-artifact -->
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-artifact</artifactId>
|
||||
<version>3.6.3</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.websocket</groupId>
|
||||
<artifactId>javax.websocket-api</artifactId>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${jettyVersion}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>javax-websocket-server-impl</artifactId>
|
||||
<version>${jettyVersion}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-http</artifactId>
|
||||
<version>${jettyVersion}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>G-Earth</groupId>
|
||||
<artifactId>G-Wasm</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
|
@ -1,7 +0,0 @@
|
||||
package gearth;
|
||||
|
||||
public class J11Main {
|
||||
public static void main(String[] args) {
|
||||
Main.main(args);
|
||||
}
|
||||
}
|
@ -1,54 +1,53 @@
|
||||
package gearth;
|
||||
|
||||
import gearth.misc.AdminValidator;
|
||||
import gearth.ui.GEarthController;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.Hyperlink;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.layout.FlowPane;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.web.WebView;
|
||||
import javafx.stage.Stage;
|
||||
import gearth.ui.GEarthController;
|
||||
import org.json.JSONObject;
|
||||
import org.jsoup.Jsoup;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
// run as root issue Invalid MIT-MAGIC-COOKIE-1 key fix: https://stackoverflow.com/questions/48139447/invalid-mit-magic-cookie-1-key
|
||||
|
||||
public class Main extends Application {
|
||||
|
||||
public static Application main;
|
||||
public static String version = "1.1";
|
||||
public static String version = "1.3";
|
||||
private static String gitApi = "https://api.github.com/repos/sirjonasxx/G-Earth/releases/latest";
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception{
|
||||
main = this;
|
||||
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/gearth/ui/G-Earth.fxml"));
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("ui/G-Earth.fxml"));
|
||||
Parent root = loader.load();
|
||||
GEarthController companion = loader.getController();
|
||||
companion.setStage(primaryStage);
|
||||
|
||||
primaryStage.getIcons().add(new Image(getClass().getResourceAsStream("/gearth/G-EarthLogoSmaller.png")));
|
||||
primaryStage.getIcons().add(new Image(getClass().getResourceAsStream("G-EarthLogoSmaller.png")));
|
||||
|
||||
// TODO fix
|
||||
primaryStage.setResizable(false);
|
||||
// primaryStage.setResizable(true);
|
||||
// primaryStage.onShownProperty().addListener(e -> {
|
||||
// Platform.runLater(() -> primaryStage.setResizable(false));
|
||||
// });
|
||||
|
||||
//primaryStage.initStyle(StageStyle.UNDECORATED);
|
||||
primaryStage.setTitle("G-Earth " + version);
|
||||
primaryStage.setScene(new Scene(root, 650, 295));
|
||||
primaryStage.show();
|
||||
primaryStage.getScene().getStylesheets().add(getClass().getResource("/gearth/ui/bootstrap3.css").toExternalForm());
|
||||
primaryStage.getScene().getStylesheets().add(getClass().getResource("ui/bootstrap3.css").toExternalForm());
|
||||
|
||||
primaryStage.setOnCloseRequest( event -> {
|
||||
companion.exit();
|
||||
@ -58,21 +57,17 @@ public class Main extends Application {
|
||||
System.exit(0);
|
||||
});
|
||||
|
||||
new Thread(() -> {
|
||||
if (!AdminValidator.isAdmin()) {
|
||||
Platform.runLater(() -> {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR, "G-Earth needs admin privileges in order to work properly, please restart G-Earth with admin permissions unless you know what you're doing", ButtonType.OK);
|
||||
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
|
||||
alert.setResizable(false);
|
||||
// alert.setResizable(true);
|
||||
// alert.onShownProperty().addListener(e -> {
|
||||
// Platform.runLater(() -> alert.setResizable(false));
|
||||
// });
|
||||
alert.show();
|
||||
});
|
||||
|
||||
}
|
||||
}).start();
|
||||
// new Thread(() -> {
|
||||
// if (!AdminValidator.isAdmin()) {
|
||||
// Platform.runLater(() -> {
|
||||
// Alert alert = new Alert(Alert.AlertType.ERROR, "G-Earth needs admin privileges in order to work properly, please restart G-Earth with admin permissions unless you know what you're doing", ButtonType.OK);
|
||||
// alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
|
||||
// alert.setResizable(false);
|
||||
// alert.show();
|
||||
// });
|
||||
//
|
||||
// }
|
||||
// }).start();
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
@ -83,7 +78,7 @@ public class Main extends Application {
|
||||
if (!gitv.equals(version)) {
|
||||
Platform.runLater(() -> {
|
||||
String body = (String)object.get("body");
|
||||
boolean isForcedUpdate = body.contains("<F>");
|
||||
boolean isForcedUpdate = body.contains("(!)");
|
||||
|
||||
Alert alert = new Alert(isForcedUpdate ? Alert.AlertType.ERROR : Alert.AlertType.INFORMATION, "G-Earth is outdated!", ButtonType.OK);
|
||||
|
||||
@ -103,11 +98,6 @@ public class Main extends Application {
|
||||
webView.setPrefSize(500, 200);
|
||||
|
||||
alert.setResizable(false);
|
||||
// alert.setResizable(true);
|
||||
// alert.onShownProperty().addListener(e -> {
|
||||
// Platform.runLater(() -> alert.setResizable(false));
|
||||
// });
|
||||
|
||||
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
|
||||
alert.getDialogPane().setContent(fp);
|
||||
if (isForcedUpdate) {
|
||||
|
@ -298,7 +298,13 @@ public abstract class Extension implements IExtension {
|
||||
public boolean requestFlags(FlagsCheckListener flagRequestCallback) {
|
||||
if (this.flagRequestCallback != null) return false;
|
||||
this.flagRequestCallback = flagRequestCallback;
|
||||
return true;
|
||||
try {
|
||||
writeToStream(new HPacket(NetworkExtensionInfo.INCOMING_MESSAGES_IDS.REQUESTFLAGS).toBytes());
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -11,7 +11,7 @@ import gearth.protocol.HPacket;
|
||||
public abstract class ExtensionForm implements IExtension {
|
||||
|
||||
volatile Extension extension;
|
||||
volatile Stage primaryStage;
|
||||
protected volatile Stage primaryStage;
|
||||
|
||||
protected static void runExtensionForm(String[] args, Class<? extends ExtensionForm> extension) {
|
||||
ExtensionFormLauncher launcher = new ExtensionFormLauncher();
|
||||
|
@ -6,6 +6,7 @@ import gearth.misc.harble_api.HarbleAPI;
|
||||
import gearth.protocol.HMessage;
|
||||
import gearth.protocol.HPacket;
|
||||
|
||||
import java.io.File;
|
||||
import java.security.InvalidParameterException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -30,7 +31,7 @@ public class HashSupport {
|
||||
|
||||
extension.onConnect((host, port, hotelversion, cachePath) -> {
|
||||
// synchronized (lock) {
|
||||
harbleAPI = new HarbleAPI(hotelversion, cachePath);
|
||||
harbleAPI = new HarbleAPI(new File(cachePath));
|
||||
// }
|
||||
});
|
||||
|
||||
|
@ -4,14 +4,14 @@ import gearth.protocol.HPacket;
|
||||
|
||||
public class HEntityUpdate {
|
||||
private int index;
|
||||
private boolean isController;
|
||||
private boolean isController = false;
|
||||
|
||||
private HPoint tile;
|
||||
private HPoint movingTo;
|
||||
private HPoint movingTo = null;
|
||||
|
||||
private HSign sign;
|
||||
private HStance stance;
|
||||
private HAction action;
|
||||
private HSign sign = null;
|
||||
private HStance stance = null;
|
||||
private HAction action = null;
|
||||
private HDirection headFacing;
|
||||
private HDirection bodyFacing;
|
||||
|
||||
|
@ -71,7 +71,6 @@ public class HarbleAPI {
|
||||
|
||||
private boolean success = false;
|
||||
private String fullPath = null;
|
||||
private String revision = null;
|
||||
|
||||
/**
|
||||
* cache file must be generated first within G-Earth, inb4 20 extensions requesting it at the same time
|
||||
@ -92,22 +91,18 @@ public class HarbleAPI {
|
||||
if (Cacher.cacheFileExists(possibleCachedMessagesPath)) {
|
||||
JSONObject object = Cacher.getCacheContents(possibleCachedMessagesPath);
|
||||
success = true;
|
||||
revision = hotelversion;
|
||||
fullPath = Cacher.getCacheDir() + File.separator + possibleCachedMessagesPath;
|
||||
parse(object);
|
||||
}
|
||||
}
|
||||
|
||||
public HarbleAPI(String hotelversion, String path_to_file) {
|
||||
|
||||
File f = new File(path_to_file);
|
||||
public HarbleAPI(File f) {
|
||||
if (f.exists() && !f.isDirectory()) {
|
||||
try {
|
||||
String contents = String.join("\n", Files.readAllLines(f.toPath()));
|
||||
JSONObject object = new JSONObject(contents);
|
||||
success = true;
|
||||
revision = hotelversion;
|
||||
fullPath = path_to_file;
|
||||
fullPath = f.getAbsolutePath();
|
||||
parse(object);
|
||||
|
||||
} catch (IOException e) {
|
||||
@ -118,15 +113,16 @@ public class HarbleAPI {
|
||||
|
||||
private void addMessage(HMessage.Direction direction, JSONObject object) {
|
||||
String name;
|
||||
try {
|
||||
name = object.getString("Name");
|
||||
} catch (Exception e) {
|
||||
name = null;
|
||||
}
|
||||
String hash = object.getString("Hash");
|
||||
Integer headerId = object.getInt("Id");
|
||||
String structure;
|
||||
String hash;
|
||||
try { name = object.getString("Name"); }
|
||||
catch (Exception e) { name = null; }
|
||||
try { hash = object.getString("Hash"); }
|
||||
catch (Exception e) { hash = null; }
|
||||
|
||||
|
||||
int headerId = object.getInt("Id");
|
||||
|
||||
String structure;
|
||||
try {
|
||||
structure = object.getString("Structure");
|
||||
} catch (Exception e) {
|
||||
@ -218,10 +214,6 @@ public class HarbleAPI {
|
||||
return nameToMessage.get(name);
|
||||
}
|
||||
|
||||
public String getRevision() {
|
||||
return revision;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
if (success) {
|
||||
return fullPath;
|
||||
|
@ -1,11 +1,14 @@
|
||||
package gearth.misc.harble_api;
|
||||
|
||||
import gearth.Main;
|
||||
import gearth.misc.Cacher;
|
||||
import gearth.protocol.HMessage;
|
||||
import org.jsoup.Connection;
|
||||
import org.jsoup.Jsoup;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 10/11/2018.
|
||||
@ -36,6 +39,20 @@ public class HarbleAPIFetcher {
|
||||
public static HarbleAPI HARBLEAPI = null;
|
||||
|
||||
public synchronized static void fetch(String hotelversion) {
|
||||
// if unity
|
||||
if (!(hotelversion.toLowerCase().contains("production") || hotelversion.toLowerCase().contains("release"))) {
|
||||
try {
|
||||
HARBLEAPI = new HarbleAPI(
|
||||
new File(new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI())
|
||||
.getParentFile(), "messages.json"
|
||||
)
|
||||
);
|
||||
} catch (URISyntaxException e) {
|
||||
HARBLEAPI = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
String cacheName = CACHE_PREFIX + hotelversion;
|
||||
|
||||
if (Cacher.cacheFileExists(cacheName)) {
|
||||
|
@ -39,12 +39,18 @@ public class PacketStringUtils {
|
||||
packet = replaceAll(packet, "\\{i:(-?[0-9]+)}",
|
||||
m -> toString(ByteBuffer.allocate(4).putInt(Integer.parseInt(m.group(1))).array()));
|
||||
|
||||
packet = replaceAll(packet, "\\{l:(-?[0-9]+)}",
|
||||
m -> toString(ByteBuffer.allocate(8).putLong(Integer.parseInt(m.group(1))).array()));
|
||||
|
||||
packet = replaceAll(packet, "\\{d:(-?[0-9]*\\.[0-9]*)}",
|
||||
m -> toString(ByteBuffer.allocate(8).putDouble(Double.parseDouble(m.group(1))).array()));
|
||||
|
||||
packet = replaceAll(packet, "\\{u:([0-9]+)}",
|
||||
m -> "[" + (Integer.parseInt(m.group(1))/256) + "][" + (Integer.parseInt(m.group(1)) % 256) + "]");
|
||||
|
||||
packet = replaceAll(packet, "\\{h:([0-9]+)}",
|
||||
m -> "[" + (Integer.parseInt(m.group(1))/256) + "][" + (Integer.parseInt(m.group(1)) % 256) + "]");
|
||||
|
||||
packet = replaceAll(packet, "\\{b:([Ff]alse|[Tt]rue)}",
|
||||
m -> m.group(1).toLowerCase().equals("true") ? "[1]" : "[0]");
|
||||
|
||||
@ -174,7 +180,7 @@ public class PacketStringUtils {
|
||||
packet.resetReadIndex();
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("{l}{u:").append(packet.headerId()).append("}");
|
||||
builder.append("{l}{h:").append(packet.headerId()).append("}");
|
||||
|
||||
buildExpressionFromGivenStructure(packet, struct, 0, builder);
|
||||
packet.setReadIndex(oldReadIndex);
|
||||
@ -196,7 +202,7 @@ public class PacketStringUtils {
|
||||
}
|
||||
else if (c == 'i') builder.append("{i:").append(prevInt = p.readInteger()).append('}');
|
||||
else if (c == 's') builder.append("{s:\"").append(
|
||||
new String(p.readString().getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8)
|
||||
p.readString(StandardCharsets.UTF_8)
|
||||
.replace("\\", "\\\\") // \ -> \\
|
||||
.replace("\"", "\\\"") // " -> \"
|
||||
.replace("\r", "\\r") // CR -> \r
|
||||
@ -204,6 +210,8 @@ public class PacketStringUtils {
|
||||
else if (c == 'd') builder.append("{d:").append(p.readDouble()).append('}');
|
||||
else if (c == 'b') builder.append("{b:").append(p.readByte()).append('}');
|
||||
else if (c == 'B') builder.append("{b:").append(p.readBoolean()).append('}');
|
||||
else if (c == 'l') builder.append("{l:").append(p.readLong()).append('}');
|
||||
else if (c == 'u') builder.append("{u:").append(p.readShort()).append('}');
|
||||
else return;
|
||||
}
|
||||
}
|
||||
@ -232,16 +240,16 @@ public class PacketStringUtils {
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws InvalidPacketException {
|
||||
HPacket p1 = fromString("{l}{u:1129}{s:\"\\\\\\\\\"}{i:0}{i:0}");
|
||||
HPacket p1 = fromString("{l}{h:1129}{s:\"\\\\\\\\\"}{i:0}{i:0}");
|
||||
System.out.println(p1.toExpression());
|
||||
HPacket p1_2 = fromString(p1.toExpression());
|
||||
System.out.println(p1_2.toExpression());
|
||||
|
||||
HPacket p2 = fromString("{l}{u:4564}{i:3}{i:0}{s:\"hi\"}{i:0}{i:1}{s:\"how\"}{i:3}{b:1}{b:2}{b:3}{i:2}{s:\"r u\"}{i:1}{b:120}{i:2}{b:true}");
|
||||
HPacket p2 = fromString("{l}{h:4564}{i:3}{i:0}{s:\"hi\"}{i:0}{i:1}{s:\"how\"}{i:3}{b:1}{b:2}{b:3}{i:2}{s:\"r u\"}{i:1}{b:120}{i:2}{b:true}");
|
||||
System.out.println(p2);
|
||||
|
||||
System.out.println(structureEquals(
|
||||
new HPacket("{l}{u:5}{s:\"asdas\"}"),
|
||||
new HPacket("{l}{h:5}{s:\"asdas\"}"),
|
||||
"s"
|
||||
));
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ import java.util.List;
|
||||
|
||||
public class StructurePredictor {
|
||||
|
||||
HPacket packet;
|
||||
String structure; // null if not found/ didnt try to find
|
||||
private HPacket packet;
|
||||
private String structure; // null if not found/ didnt try to find
|
||||
|
||||
public StructurePredictor(HPacket packet) {
|
||||
this.packet = packet;
|
||||
@ -44,17 +44,12 @@ public class StructurePredictor {
|
||||
while (index < packet.getBytesLength()) {
|
||||
double currentLogScore = dynamic[index - 6].logScore;
|
||||
for (TypeChecker typeChecker : typeCheckers) {
|
||||
if (typeChecker.canRead(index)) {
|
||||
double score = typeChecker.score(index);
|
||||
double newScore = currentLogScore + Math.log(score);
|
||||
int nextIndex = typeChecker.nextIndex(index) - 6;
|
||||
if (dynamic[nextIndex] == null || newScore > dynamic[nextIndex].logScore) {
|
||||
dynamic[nextIndex] = new SubStructure(
|
||||
index - 6,
|
||||
typeChecker.getStructCode(),
|
||||
newScore
|
||||
);
|
||||
}
|
||||
if (!typeChecker.canRead(index)) continue;
|
||||
|
||||
double newScore = currentLogScore + Math.log(typeChecker.score(index));
|
||||
int nextIndex = typeChecker.nextIndex(index) - 6;
|
||||
if (dynamic[nextIndex] == null || newScore > dynamic[nextIndex].logScore) {
|
||||
dynamic[nextIndex] = new SubStructure(index - 6, typeChecker.getStructCode(), newScore);
|
||||
}
|
||||
}
|
||||
index++;
|
||||
@ -80,39 +75,4 @@ public class StructurePredictor {
|
||||
public String getStructure() {
|
||||
return structure;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
HPacket[] packets = new HPacket[] {
|
||||
new HPacket("{l}{u:500}{i:20}"),
|
||||
new HPacket(4002, "test"),
|
||||
new HPacket(4002, "test", 0, true),
|
||||
new HPacket(4002, "test", "testtsd", 54452, true, false),
|
||||
new HPacket(4002, "test", 46564554, "testtsd", 54452, true, false),
|
||||
new HPacket(4002, "test", 0, 46564554, "testtsd", 54452, true, false),
|
||||
new HPacket(4002, -1, "test", 0, 46564554, "testtsd", -1, 54452, true, false),
|
||||
new HPacket(4002, -1, "test", 0, 46564554, "testtsd", -1, 54452, false, true, ""),
|
||||
new HPacket(4002, -1, "test", 0, 46564554, "testtsd", -1, 54452, false, true, ""),
|
||||
new HPacket(4002, -1, "test", 0, 46564554, "testtsd", -1, 54452, false, true, 0),
|
||||
new HPacket(4002, -1, (byte) 5, "test", 0, 46564554, "testtsd", -1, 54452, false, true, 0),
|
||||
new HPacket(4002, "", 20, 0),
|
||||
new HPacket(4002, 1),
|
||||
new HPacket(4002, 0, 0),
|
||||
new HPacket(4002, 0, 0, 42, false),
|
||||
new HPacket(4002, 0, ""),
|
||||
new HPacket("[0][0][0]F[0] [0][0][0] [0][0][0][5][0]\u0013ACH_FriendListSize5[0][0][0]U[0][0][0] [0][0][0][0][0][0][0][0][0][0][0]Z[0][0][6]social[0][0][0][0][0][13][0][0][0][2]"),
|
||||
new HPacket("[0][0][0]?[0] [0][0][0][4][0][0][0][4][0][10]ACH_Login4[0][0][0]\u000F[0][0][0]\u001C[0][0][0][0][0][0][0][0][0][0][0][2][0][0][8]identity[0][0][0][0][0]\u0014[0][0][0][0]"),
|
||||
new HPacket("[0][0][0][6]\u000Ew[0][0][0][0]"),
|
||||
new HPacket("[0][0][0]'[3] [0][5]Login[0][6]socket[0]\u000Eclient.auth_ok[0][0][0][0][0][0]"),
|
||||
new HPacket(4002, false, ""),
|
||||
new HPacket("{l}{u:145}[0][0][0]ÿÿÿÿ[0]"),
|
||||
// new HPacket("[0][0][1]p[13]1[0][0][0][12][0][10]MOUSE_ZOOM[0][0][1][0]\u0015HABBO_CLUB_OFFER_BETA[0][0][1][0]\u000EUSE_GUIDE_TOOL[0]&requirement.unfulfilled.helper_level_4[0][0]\u000FBUILDER_AT_WORK[0](requirement.unfulfilled.group_membership[0][0]\u000FCALL_ON_HELPERS[0][0][1][0]\u001FNAVIGATOR_ROOM_THUMBNAIL_CAMERA[0][0][1][0][7]CITIZEN[0][0][1][0]\u0012JUDGE_CHAT_REVIEWS[0]&requirement.unfulfilled.helper_level_6[0][0][5]TRADE[0][0][1][0][6]CAMERA[0][0][1][0]\u0014VOTE_IN_COMPETITIONS[0][0][1][0]\u0018NAVIGATOR_PHASE_TWO_2014[0][0][1]")
|
||||
|
||||
};
|
||||
|
||||
for (HPacket packet : packets) {
|
||||
StructurePredictor structurePredictor = new StructurePredictor(packet);
|
||||
System.out.println(structurePredictor.getStructure());
|
||||
System.out.println(structurePredictor.getExpression());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package gearth.misc.packetrepresentation.prediction.checkers;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
import gearth.services.Constants;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@ -33,7 +34,7 @@ public class IntegerChecker extends TypeChecker<Integer> {
|
||||
}
|
||||
|
||||
// 4 bytes that read [0][2]xy could be a string
|
||||
if (ushortTest >= 2 && ushortTest <= 6 && StringChecker.canReadString(hPacket, index)) {
|
||||
if (ushortTest == 2 && StringChecker.canReadString(hPacket, index)) {
|
||||
return (1 - StringChecker.scoreString(hPacket.readString(index)));
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,45 @@
|
||||
package gearth.misc.packetrepresentation.prediction.checkers;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
||||
public class LongChecker extends TypeChecker<Long> {
|
||||
|
||||
private IntegerChecker integerChecker;
|
||||
|
||||
protected LongChecker(HPacket hPacket) {
|
||||
super("l", hPacket);
|
||||
integerChecker = new IntegerChecker(hPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRead(int index) {
|
||||
return index >= 6 && !(index + 8 > hPacket.getBytesLength());
|
||||
}
|
||||
|
||||
@Override
|
||||
public double score(int index) {
|
||||
int split1 = hPacket.readInteger(index);
|
||||
int split2 = hPacket.readInteger(index + 4);
|
||||
|
||||
int zeros = 0;
|
||||
for (int i = index + 4; i < index + 8; i++) {
|
||||
zeros += hPacket.readByte(i) == 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
if (split2 > 256 * 256 * 3 && split1 == 0 && zeros < 2) {
|
||||
return integerChecker.score(index) * integerChecker.score(index + 4) + 0.0000000001;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
Long get(int index) {
|
||||
return hPacket.readLong(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
int nextIndexSafe(int index) {
|
||||
return index + 8;
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package gearth.misc.packetrepresentation.prediction.checkers;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
||||
public class ShortChecker extends TypeChecker {
|
||||
|
||||
private BooleanChecker booleanChecker;
|
||||
private ByteChecker byteChecker;
|
||||
|
||||
protected ShortChecker(HPacket hPacket) {
|
||||
super("u", hPacket);
|
||||
booleanChecker = new BooleanChecker(hPacket);
|
||||
byteChecker = new ByteChecker(hPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRead(int index) {
|
||||
return index >= 6 && !(index + 2 > hPacket.getBytesLength());
|
||||
}
|
||||
|
||||
@Override
|
||||
public double score(int index) {
|
||||
short val = hPacket.readShort(index);
|
||||
|
||||
if (index == 6 && val == 0 && hPacket.length() == nextIndexSafe(index)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (val <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (val < 1000) {
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
double leftMinScore;
|
||||
double rightMinScore;
|
||||
if (booleanChecker.canRead(index)) leftMinScore = booleanChecker.score(index);
|
||||
else leftMinScore = byteChecker.score(index);
|
||||
if (booleanChecker.canRead(index+1)) rightMinScore = booleanChecker.score(index+1);
|
||||
else rightMinScore = byteChecker.score(index+1);
|
||||
|
||||
return leftMinScore * rightMinScore + 0.00000001;
|
||||
}
|
||||
|
||||
@Override
|
||||
Object get(int index) {
|
||||
return hPacket.readShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
int nextIndexSafe(int index) {
|
||||
return index + 2;
|
||||
}
|
||||
}
|
@ -2,18 +2,27 @@ package gearth.misc.packetrepresentation.prediction.checkers;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static gearth.services.Constants.UNITY_PACKETS;
|
||||
|
||||
public class TypeCheckerProducer {
|
||||
|
||||
public static List<TypeChecker> getValidators(HPacket packet) {
|
||||
return Arrays.asList(
|
||||
List<TypeChecker> typeCheckers = new ArrayList<>(Arrays.asList(
|
||||
new BooleanChecker(packet),
|
||||
new ByteChecker(packet),
|
||||
new IntegerChecker(packet),
|
||||
new StringChecker(packet)
|
||||
);
|
||||
new StringChecker(packet)));
|
||||
|
||||
if (UNITY_PACKETS) {
|
||||
typeCheckers.add(new LongChecker(packet));
|
||||
typeCheckers.add(new ShortChecker(packet));
|
||||
}
|
||||
|
||||
return typeCheckers;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,9 +4,10 @@ import gearth.misc.listenerpattern.Observable;
|
||||
import gearth.protocol.connection.HProxy;
|
||||
import gearth.protocol.connection.HState;
|
||||
import gearth.protocol.connection.proxy.ProxyProvider;
|
||||
import gearth.protocol.connection.proxy.flash.FlashProxyProvider;
|
||||
import gearth.protocol.connection.proxy.ProxyProviderFactory;
|
||||
import gearth.protocol.connection.proxy.unix.LinuxRawIpProxyProvider;
|
||||
import gearth.protocol.connection.proxy.windows.WindowsRawIpProxyProvider;
|
||||
import gearth.protocol.connection.proxy.flash.unix.LinuxRawIpFlashProxyProvider;
|
||||
import gearth.protocol.connection.proxy.unity.UnityProxyProvider;
|
||||
import gearth.services.extensionhandler.ExtensionHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -60,6 +61,12 @@ public class HConnection {
|
||||
startMITM();
|
||||
}
|
||||
|
||||
public void startUnity() {
|
||||
HConnection selff = this;
|
||||
proxyProvider = new UnityProxyProvider(proxy -> selff.proxy = proxy, selff::setState, this);
|
||||
startMITM();
|
||||
}
|
||||
|
||||
private void startMITM() {
|
||||
try {
|
||||
if (proxyProvider != null) {
|
||||
@ -166,7 +173,7 @@ public class HConnection {
|
||||
}
|
||||
|
||||
public boolean isRawIpMode() {
|
||||
return proxyProvider != null && proxyProvider instanceof LinuxRawIpProxyProvider;
|
||||
return proxyProvider != null && proxyProvider instanceof LinuxRawIpFlashProxyProvider;
|
||||
// WindowsRawIpProxyProvider extends LinuxRawIpProxyProvider
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ import gearth.misc.packetrepresentation.PacketStringUtils;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidParameterException;
|
||||
import java.util.Arrays;
|
||||
@ -36,7 +37,7 @@ public class HPacket implements StringifyAble {
|
||||
}
|
||||
public HPacket(int header) {
|
||||
packetInBytes = new byte[]{0,0,0,2,0,0};
|
||||
replaceUShort(4, header);
|
||||
replaceShort(4, (short)header);
|
||||
isEdited = false;
|
||||
}
|
||||
public HPacket(int header, byte[] bytes) {
|
||||
@ -126,7 +127,7 @@ public class HPacket implements StringifyAble {
|
||||
}
|
||||
|
||||
public int headerId() {
|
||||
return readUshort(4);
|
||||
return readShort(4);
|
||||
}
|
||||
|
||||
public int readInteger(){
|
||||
@ -180,34 +181,49 @@ public class HPacket implements StringifyAble {
|
||||
return java.nio.ByteBuffer.wrap(btarray).getLong();
|
||||
}
|
||||
|
||||
public String readString() {
|
||||
String r = readString(readIndex);
|
||||
readIndex += (2 + r.length());
|
||||
|
||||
public String readString(Charset charset) {
|
||||
String r = readString(readIndex, charset);
|
||||
readIndex += (2 + readUshort(readIndex));
|
||||
return r;
|
||||
}
|
||||
public String readString(int index) {
|
||||
public String readString(int index, Charset charset) {
|
||||
int length = readUshort(index);
|
||||
index+=2;
|
||||
|
||||
return readString(index, length);
|
||||
return readString(index, length, charset);
|
||||
}
|
||||
|
||||
private String readString(int index, int length) {
|
||||
public String readString() {
|
||||
return readString(StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
public String readString(int index) {
|
||||
return readString(index, StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
|
||||
private String readString(int index, int length, Charset charset) {
|
||||
byte[] x = new byte[length];
|
||||
for (int i = 0; i < x.length; i++) { x[i] = readByte(index); index++; }
|
||||
return new String(x, StandardCharsets.ISO_8859_1);
|
||||
return new String(x, charset);
|
||||
}
|
||||
|
||||
public String readLongString() {
|
||||
String r = readLongString(readIndex);
|
||||
readIndex += (4 + r.length());
|
||||
|
||||
public String readLongString(Charset charset) {
|
||||
String r = readLongString(readIndex, charset);
|
||||
readIndex += (4 + readInteger(readIndex));
|
||||
return r;
|
||||
}
|
||||
public String readLongString(int index) {
|
||||
public String readLongString(int index, Charset charset) {
|
||||
int length = readInteger(index);
|
||||
index += 4;
|
||||
|
||||
return readString(index, length);
|
||||
return readString(index, length, charset);
|
||||
}
|
||||
|
||||
public String readLongString() {
|
||||
return readLongString(StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
public String readLongString(int index) {
|
||||
return readLongString(index, StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
|
||||
public boolean readBoolean() {
|
||||
@ -231,6 +247,14 @@ public class HPacket implements StringifyAble {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public HPacket replaceLong(int index, long l) {
|
||||
isEdited = true;
|
||||
ByteBuffer b = ByteBuffer.allocate(8).putLong(l);
|
||||
for (int j = 0; j < 8; j++) {
|
||||
packetInBytes[index + j] = b.array()[j];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public HPacket replaceDouble(int index, double d) {
|
||||
isEdited = true;
|
||||
ByteBuffer b = ByteBuffer.allocate(8).putDouble(d);
|
||||
@ -267,10 +291,11 @@ public class HPacket implements StringifyAble {
|
||||
packetInBytes[index + 1] = b.array()[1];
|
||||
return this;
|
||||
}
|
||||
public HPacket replaceString(int index, String s) {
|
||||
|
||||
public HPacket replaceString(int index, String s, Charset charset) {
|
||||
isEdited = true;
|
||||
byte[] sbytes = s.getBytes(StandardCharsets.ISO_8859_1);
|
||||
int mover = s.length() - readUshort(index);
|
||||
byte[] sbytes = s.getBytes(charset);
|
||||
int mover = sbytes.length - readUshort(index);
|
||||
|
||||
if (mover != 0) {
|
||||
byte[] newPacket = Arrays.copyOf(packetInBytes, packetInBytes.length + mover);
|
||||
@ -283,7 +308,7 @@ public class HPacket implements StringifyAble {
|
||||
}
|
||||
}
|
||||
else {
|
||||
int i = index + 2 + s.length();
|
||||
int i = index + 2 + sbytes.length;
|
||||
while (i < newPacket.length) {
|
||||
newPacket[i] = packetInBytes[i - mover];
|
||||
i++;
|
||||
@ -294,13 +319,17 @@ public class HPacket implements StringifyAble {
|
||||
fixLength();
|
||||
}
|
||||
|
||||
replaceUShort(index, s.length());
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
replaceUShort(index, sbytes.length);
|
||||
for (int i = 0; i < sbytes.length; i++) {
|
||||
packetInBytes[index + 2 + i] = sbytes[i];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public HPacket replaceString(int index, String s) {
|
||||
return replaceString(index, s, StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
|
||||
private boolean canReadString(int index) {
|
||||
if (index < packetInBytes.length - 1) {
|
||||
int l = readUshort(index);
|
||||
@ -394,6 +423,16 @@ public class HPacket implements StringifyAble {
|
||||
fixLength();
|
||||
return this;
|
||||
}
|
||||
public HPacket appendLong(long l) {
|
||||
isEdited = true;
|
||||
packetInBytes = Arrays.copyOf(packetInBytes, packetInBytes.length + 8);
|
||||
ByteBuffer byteBuffer = ByteBuffer.allocate(8).putLong(l);
|
||||
for (int j = 0; j < 8; j++) {
|
||||
packetInBytes[packetInBytes.length - 8 + j] = byteBuffer.array()[j];
|
||||
}
|
||||
fixLength();
|
||||
return this;
|
||||
}
|
||||
public HPacket appendDouble(double d) {
|
||||
isEdited = true;
|
||||
packetInBytes = Arrays.copyOf(packetInBytes, packetInBytes.length + 8);
|
||||
@ -445,18 +484,27 @@ public class HPacket implements StringifyAble {
|
||||
fixLength();
|
||||
return this;
|
||||
}
|
||||
public HPacket appendString(String s, Charset charset) {
|
||||
isEdited = true;
|
||||
appendUShort(s.getBytes(charset).length);
|
||||
appendBytes(s.getBytes(charset));
|
||||
return this;
|
||||
}
|
||||
public HPacket appendString(String s) {
|
||||
return appendString(s, StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
|
||||
public HPacket appendLongString(String s, Charset charset) {
|
||||
isEdited = true;
|
||||
appendUShort(s.length());
|
||||
appendBytes(s.getBytes(StandardCharsets.ISO_8859_1));
|
||||
appendInt(s.getBytes(charset).length);
|
||||
appendBytes(s.getBytes(charset));
|
||||
return this;
|
||||
}
|
||||
|
||||
public HPacket appendLongString(String s) {
|
||||
isEdited = true;
|
||||
appendInt(s.length());
|
||||
appendBytes(s.getBytes(StandardCharsets.ISO_8859_1));
|
||||
return this;
|
||||
return appendLongString(s, StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
|
||||
public HPacket appendObject(Object o) throws InvalidParameterException {
|
||||
isEdited = true;
|
||||
|
||||
@ -472,6 +520,9 @@ public class HPacket implements StringifyAble {
|
||||
else if (o instanceof Boolean) {
|
||||
appendBoolean((Boolean) o);
|
||||
}
|
||||
else if (o instanceof Long) {
|
||||
appendLong((Long) o);
|
||||
}
|
||||
else {
|
||||
throw new InvalidParameterException();
|
||||
}
|
||||
@ -479,20 +530,6 @@ public class HPacket implements StringifyAble {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public HPacket removeFrom(int index) {
|
||||
return removeRange(index, packetInBytes.length - index);
|
||||
}
|
||||
public HPacket removeRange(int index, int length) {
|
||||
isEdited = true;
|
||||
for (int i = index; i < packetInBytes.length - length; i++) {
|
||||
packetInBytes[i] = packetInBytes[i + length];
|
||||
}
|
||||
packetInBytes = Arrays.copyOf(packetInBytes, packetInBytes.length - length);
|
||||
fixLength();
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isReplaced() {
|
||||
return isEdited;
|
||||
}
|
||||
@ -507,25 +544,44 @@ public class HPacket implements StringifyAble {
|
||||
isEdited = edited;
|
||||
}
|
||||
|
||||
public String toExpression(HMessage.Direction direction) {
|
||||
if (isCorrupted()) return "";
|
||||
|
||||
private String getHarbleStructure(HMessage.Direction direction) {
|
||||
HarbleAPI.HarbleMessage msg;
|
||||
if (HarbleAPIFetcher.HARBLEAPI != null &&
|
||||
((msg = HarbleAPIFetcher.HARBLEAPI.getHarbleMessageFromHeaderId(direction, headerId())) != null)) {
|
||||
if (msg.getStructure() != null) {
|
||||
return PacketStringUtils.toExpressionFromGivenStructure(this, msg.getStructure());
|
||||
if (msg.getStructure() != null && structureEquals(msg.getStructure())) {
|
||||
return msg.getStructure();
|
||||
}
|
||||
}
|
||||
return toExpression();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toExpression(HMessage.Direction direction) {
|
||||
if (isCorrupted()) return "";
|
||||
|
||||
String structure = getHarbleStructure(direction);
|
||||
if (structure != null) {
|
||||
return PacketStringUtils.toExpressionFromGivenStructure(this, structure);
|
||||
}
|
||||
|
||||
return PacketStringUtils.predictedExpression(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns "" if not found or not sure enough
|
||||
* dont hate on the coding quality in this function, its pretty effective.
|
||||
*/
|
||||
public String toExpression() {
|
||||
if (isCorrupted()) return "";
|
||||
|
||||
String structure1 = getHarbleStructure(HMessage.Direction.TOCLIENT);
|
||||
String structure2 = getHarbleStructure(HMessage.Direction.TOSERVER);
|
||||
if (structure1 != null && structure2 == null) {
|
||||
return PacketStringUtils.toExpressionFromGivenStructure(this, structure1);
|
||||
}
|
||||
else if (structure1 == null && structure2 != null) {
|
||||
return PacketStringUtils.toExpressionFromGivenStructure(this, structure2);
|
||||
}
|
||||
|
||||
return PacketStringUtils.predictedExpression(this);
|
||||
}
|
||||
|
||||
@ -551,7 +607,7 @@ public class HPacket implements StringifyAble {
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
HPacket packet = new HPacket("{l}{u:4564}{i:3}{i:0}{s:\"hi\"}{i:0}{i:1}{s:\"how\"}{i:3}{b:1}{b:2}{b:3}{i:2}{s:\"r u\"}{i:1}{b:120}{i:2}{b:true}{d:1.4}");
|
||||
HPacket packet = new HPacket("{l}{h:4564}{i:3}{i:0}{s:\"hi\"}{i:0}{i:1}{s:\"how\"}{i:3}{b:1}{b:2}{b:3}{i:2}{s:\"r u\"}{i:1}{b:120}{i:2}{b:true}{d:1.4}");
|
||||
|
||||
String str = PacketStringUtils.toExpressionFromGivenStructure(packet, "i(isi(b))iBd");
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
package gearth.protocol.connection;
|
||||
|
||||
public enum HClient {
|
||||
UNITY,
|
||||
FLASH
|
||||
}
|
@ -1,11 +1,13 @@
|
||||
package gearth.protocol.connection;
|
||||
|
||||
import gearth.protocol.packethandler.IncomingPacketHandler;
|
||||
import gearth.protocol.packethandler.OutgoingPacketHandler;
|
||||
import gearth.protocol.packethandler.PacketHandler;
|
||||
|
||||
import java.net.ServerSocket;
|
||||
|
||||
public class HProxy {
|
||||
|
||||
private final HClient hClient;
|
||||
|
||||
private volatile String input_domain; //string representation of the domain to intercept
|
||||
private volatile String actual_domain; //dns resolved domain (ignoring hosts file)
|
||||
private volatile int actual_port; //port of the server
|
||||
@ -15,13 +17,14 @@ public class HProxy {
|
||||
|
||||
private volatile ServerSocket proxy_server = null; //listener for the client
|
||||
|
||||
private volatile IncomingPacketHandler inHandler = null; //connection with client (only initialized when verified habbo connection)
|
||||
private volatile OutgoingPacketHandler outHandler = null; //connection with server (only initialized when verified habbo connection)
|
||||
private volatile PacketHandler inHandler = null; //connection with client (only initialized when verified habbo connection)
|
||||
private volatile PacketHandler outHandler = null; //connection with server (only initialized when verified habbo connection)
|
||||
|
||||
private volatile String hotelVersion = "";
|
||||
private volatile AsyncPacketSender asyncPacketSender = null;
|
||||
|
||||
public HProxy(String input_domain, String actual_domain, int actual_port, int intercept_port, String intercept_host) {
|
||||
public HProxy(HClient hClient, String input_domain, String actual_domain, int actual_port, int intercept_port, String intercept_host) {
|
||||
this.hClient = hClient;
|
||||
this.input_domain = input_domain;
|
||||
this.actual_domain = actual_domain;
|
||||
this.actual_port = actual_port;
|
||||
@ -33,7 +36,7 @@ public class HProxy {
|
||||
this.proxy_server = socket;
|
||||
}
|
||||
|
||||
public void verifyProxy(IncomingPacketHandler incomingHandler, OutgoingPacketHandler outgoingHandler, String hotelVersion) {
|
||||
public void verifyProxy(PacketHandler incomingHandler, PacketHandler outgoingHandler, String hotelVersion) {
|
||||
this.inHandler = incomingHandler;
|
||||
this.outHandler = outgoingHandler;
|
||||
this.hotelVersion = hotelVersion;
|
||||
@ -64,11 +67,11 @@ public class HProxy {
|
||||
return intercept_host;
|
||||
}
|
||||
|
||||
public IncomingPacketHandler getInHandler() {
|
||||
public PacketHandler getInHandler() {
|
||||
return inHandler;
|
||||
}
|
||||
|
||||
public OutgoingPacketHandler getOutHandler() {
|
||||
public PacketHandler getOutHandler() {
|
||||
return outHandler;
|
||||
}
|
||||
|
||||
@ -79,4 +82,8 @@ public class HProxy {
|
||||
public AsyncPacketSender getAsyncPacketSender() {
|
||||
return asyncPacketSender;
|
||||
}
|
||||
|
||||
public HClient gethClient() {
|
||||
return hClient;
|
||||
}
|
||||
}
|
||||
|
@ -1,129 +1,10 @@
|
||||
package gearth.protocol.connection.proxy;
|
||||
|
||||
import gearth.protocol.HConnection;
|
||||
import gearth.protocol.connection.HProxy;
|
||||
import gearth.protocol.connection.HProxySetter;
|
||||
import gearth.protocol.connection.HState;
|
||||
import gearth.protocol.connection.HStateSetter;
|
||||
import gearth.protocol.memory.Rc4Obtainer;
|
||||
import gearth.protocol.packethandler.IncomingPacketHandler;
|
||||
import gearth.protocol.packethandler.OutgoingPacketHandler;
|
||||
import gearth.protocol.packethandler.PacketHandler;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
public abstract class ProxyProvider {
|
||||
public interface ProxyProvider {
|
||||
|
||||
protected final HProxySetter proxySetter;
|
||||
protected final HStateSetter stateSetter;
|
||||
protected final HConnection hConnection;
|
||||
|
||||
private Semaphore abortSemaphore = null;
|
||||
|
||||
public ProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection){
|
||||
this.proxySetter = proxySetter;
|
||||
this.stateSetter = stateSetter;
|
||||
this.hConnection = hConnection;
|
||||
}
|
||||
|
||||
protected void startProxyThread(Socket client, Socket server, HProxy proxy) throws IOException, InterruptedException {
|
||||
final boolean[] datastream = new boolean[1];
|
||||
server.setTcpNoDelay(true);
|
||||
client.setTcpNoDelay(true);
|
||||
|
||||
client.setSoTimeout(0);
|
||||
server.setSoTimeout(0);
|
||||
|
||||
if (HConnection.DEBUG) System.out.println(server.getLocalAddress().getHostAddress() + ": " + server.getLocalPort());
|
||||
Rc4Obtainer rc4Obtainer = new Rc4Obtainer(hConnection);
|
||||
|
||||
OutgoingPacketHandler outgoingHandler = new OutgoingPacketHandler(server.getOutputStream(), hConnection.getTrafficObservables(), hConnection.getExtensionHandler());
|
||||
IncomingPacketHandler incomingHandler = new IncomingPacketHandler(client.getOutputStream(), hConnection.getTrafficObservables(), outgoingHandler, hConnection.getExtensionHandler());
|
||||
rc4Obtainer.setPacketHandlers(outgoingHandler, incomingHandler);
|
||||
|
||||
Semaphore abort = new Semaphore(0);
|
||||
|
||||
outgoingHandler.addOnDatastreamConfirmedListener(hotelVersion -> {
|
||||
incomingHandler.setAsDataStream();
|
||||
proxy.verifyProxy(incomingHandler, outgoingHandler, hotelVersion);
|
||||
proxySetter.setProxy(proxy);
|
||||
datastream[0] = true;
|
||||
abortSemaphore = abort;
|
||||
onConnect();
|
||||
});
|
||||
|
||||
handleInputStream(client, outgoingHandler, abort);
|
||||
handleInputStream(server, incomingHandler, abort);
|
||||
|
||||
// abort can be acquired as soon as one of the sockets is closed
|
||||
abort.acquire();
|
||||
try {
|
||||
if (!server.isClosed()) server.close();
|
||||
if (!client.isClosed()) client.close();
|
||||
if (HConnection.DEBUG) System.out.println("STOP");
|
||||
if (datastream[0]) {
|
||||
onConnectEnd();
|
||||
};
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleInputStream(Socket socket, PacketHandler packetHandler, Semaphore abort) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
int readLength;
|
||||
byte[] buffer = new byte[10000];
|
||||
while (!socket.isClosed() &&
|
||||
(hConnection.getState() == HState.WAITING_FOR_CLIENT || hConnection.getState() == HState.CONNECTED) &&
|
||||
(readLength = socket.getInputStream().read(buffer)) != -1) {
|
||||
packetHandler.act(Arrays.copyOf(buffer, readLength));
|
||||
}
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
// System.err.println(packetHandler instanceof IncomingPacketHandler ? "incoming" : "outgoing");
|
||||
// ignore.printStackTrace();
|
||||
} finally {
|
||||
abort.release();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
|
||||
public abstract void start() throws IOException;
|
||||
public void abort() {
|
||||
if (abortSemaphore != null) {
|
||||
abortSemaphore.release();
|
||||
}
|
||||
else {
|
||||
stateSetter.setState(HState.NOT_CONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onConnect() {
|
||||
stateSetter.setState(HState.CONNECTED);
|
||||
}
|
||||
protected void onConnectEnd() {
|
||||
proxySetter.setProxy(null);
|
||||
abortSemaphore = null;
|
||||
stateSetter.setState(HState.NOT_CONNECTED);
|
||||
}
|
||||
|
||||
protected void showInvalidConnectionError() {
|
||||
Platform.runLater(() -> {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR, "You entered invalid connection information, G-Earth could not connect", ButtonType.OK);
|
||||
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
|
||||
alert.setResizable(false);
|
||||
alert.show();
|
||||
});
|
||||
}
|
||||
void start() throws IOException;
|
||||
void abort();
|
||||
|
||||
}
|
||||
|
@ -5,8 +5,10 @@ import gearth.misc.OSValidator;
|
||||
import gearth.protocol.HConnection;
|
||||
import gearth.protocol.connection.HProxySetter;
|
||||
import gearth.protocol.connection.HStateSetter;
|
||||
import gearth.protocol.connection.proxy.unix.LinuxRawIpProxyProvider;
|
||||
import gearth.protocol.connection.proxy.windows.WindowsRawIpProxyProvider;
|
||||
import gearth.protocol.connection.proxy.flash.NormalFlashProxyProvider;
|
||||
import gearth.protocol.connection.proxy.flash.FlashProxyProvider;
|
||||
import gearth.protocol.connection.proxy.flash.unix.LinuxRawIpFlashProxyProvider;
|
||||
import gearth.protocol.connection.proxy.flash.windows.WindowsRawIpFlashProxyProvider;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonType;
|
||||
@ -67,7 +69,7 @@ public class ProxyProviderFactory {
|
||||
|
||||
// checks if host is a raw IP instead of a domain
|
||||
// TODO support ipv6 (not only here, also in IPmapper)
|
||||
static boolean hostIsIpAddress(String host){
|
||||
public static boolean hostIsIpAddress(String host){
|
||||
for (char c : host.toCharArray()) {
|
||||
if (c != '.' && (c < '0' || c > '9')) {
|
||||
return false;
|
||||
@ -79,7 +81,6 @@ public class ProxyProviderFactory {
|
||||
public ProxyProvider provide() {
|
||||
return provide(autoDetectHosts);
|
||||
}
|
||||
|
||||
public ProxyProvider provide(String domain, int port) {
|
||||
List<Object> additionalCachedHotels = Cacher.getList(HOTELS_CACHE_KEY);
|
||||
if (additionalCachedHotels == null) {
|
||||
@ -92,12 +93,12 @@ public class ProxyProviderFactory {
|
||||
|
||||
if (hostIsIpAddress(domain)) {
|
||||
if (OSValidator.isWindows()) {
|
||||
if (WindowsRawIpProxyProvider.isNoneConnected(domain) &&
|
||||
if (WindowsRawIpFlashProxyProvider.isNoneConnected(domain) &&
|
||||
(!socksConfig.useSocks() || socksConfig.onlyUseIfNeeded()) ) {
|
||||
return new WindowsRawIpProxyProvider(proxySetter, stateSetter, hConnection, domain, port, false);
|
||||
return new WindowsRawIpFlashProxyProvider(proxySetter, stateSetter, hConnection, domain, port, false);
|
||||
}
|
||||
else if (socksConfig.useSocks()) {
|
||||
return new WindowsRawIpProxyProvider(proxySetter, stateSetter, hConnection, domain, port, true);
|
||||
return new WindowsRawIpFlashProxyProvider(proxySetter, stateSetter, hConnection, domain, port, true);
|
||||
}
|
||||
|
||||
Platform.runLater(() -> {
|
||||
@ -112,7 +113,7 @@ public class ProxyProviderFactory {
|
||||
return null;
|
||||
}
|
||||
else if (OSValidator.isUnix() || OSValidator.isMac()) {
|
||||
return new LinuxRawIpProxyProvider(proxySetter, stateSetter, hConnection, domain, port, socksConfig.useSocks() && !socksConfig.onlyUseIfNeeded());
|
||||
return new LinuxRawIpFlashProxyProvider(proxySetter, stateSetter, hConnection, domain, port, socksConfig.useSocks() && !socksConfig.onlyUseIfNeeded());
|
||||
}
|
||||
return null;
|
||||
|
||||
@ -123,9 +124,8 @@ public class ProxyProviderFactory {
|
||||
return provide(potentialHost);
|
||||
}
|
||||
}
|
||||
|
||||
private ProxyProvider provide(List<String> potentialHosts) {
|
||||
return new NormalProxyProvider(proxySetter, stateSetter, hConnection, potentialHosts, socksConfig.useSocks() && !socksConfig.onlyUseIfNeeded());
|
||||
return new NormalFlashProxyProvider(proxySetter, stateSetter, hConnection, potentialHosts, socksConfig.useSocks() && !socksConfig.onlyUseIfNeeded());
|
||||
}
|
||||
|
||||
public static void setSocksConfig(SocksConfiguration configuration) {
|
||||
|
@ -0,0 +1,130 @@
|
||||
package gearth.protocol.connection.proxy.flash;
|
||||
|
||||
import gearth.protocol.HConnection;
|
||||
import gearth.protocol.connection.HProxy;
|
||||
import gearth.protocol.connection.HProxySetter;
|
||||
import gearth.protocol.connection.HState;
|
||||
import gearth.protocol.connection.HStateSetter;
|
||||
import gearth.protocol.connection.proxy.ProxyProvider;
|
||||
import gearth.protocol.memory.Rc4Obtainer;
|
||||
import gearth.protocol.packethandler.flash.IncomingFlashPacketHandler;
|
||||
import gearth.protocol.packethandler.flash.OutgoingFlashPacketHandler;
|
||||
import gearth.protocol.packethandler.flash.FlashPacketHandler;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
public abstract class FlashProxyProvider implements ProxyProvider {
|
||||
|
||||
protected final HProxySetter proxySetter;
|
||||
protected final HStateSetter stateSetter;
|
||||
protected final HConnection hConnection;
|
||||
|
||||
private Semaphore abortSemaphore = null;
|
||||
|
||||
public FlashProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection){
|
||||
this.proxySetter = proxySetter;
|
||||
this.stateSetter = stateSetter;
|
||||
this.hConnection = hConnection;
|
||||
}
|
||||
|
||||
protected void startProxyThread(Socket client, Socket server, HProxy proxy) throws IOException, InterruptedException {
|
||||
final boolean[] datastream = new boolean[1];
|
||||
server.setTcpNoDelay(true);
|
||||
client.setTcpNoDelay(true);
|
||||
|
||||
client.setSoTimeout(0);
|
||||
server.setSoTimeout(0);
|
||||
|
||||
if (HConnection.DEBUG) System.out.println(server.getLocalAddress().getHostAddress() + ": " + server.getLocalPort());
|
||||
Rc4Obtainer rc4Obtainer = new Rc4Obtainer(hConnection);
|
||||
|
||||
OutgoingFlashPacketHandler outgoingHandler = new OutgoingFlashPacketHandler(server.getOutputStream(), hConnection.getTrafficObservables(), hConnection.getExtensionHandler());
|
||||
IncomingFlashPacketHandler incomingHandler = new IncomingFlashPacketHandler(client.getOutputStream(), hConnection.getTrafficObservables(), outgoingHandler, hConnection.getExtensionHandler());
|
||||
rc4Obtainer.setFlashPacketHandlers(outgoingHandler, incomingHandler);
|
||||
|
||||
Semaphore abort = new Semaphore(0);
|
||||
|
||||
outgoingHandler.addOnDatastreamConfirmedListener(hotelVersion -> {
|
||||
incomingHandler.setAsDataStream();
|
||||
proxy.verifyProxy(incomingHandler, outgoingHandler, hotelVersion);
|
||||
proxySetter.setProxy(proxy);
|
||||
datastream[0] = true;
|
||||
abortSemaphore = abort;
|
||||
onConnect();
|
||||
});
|
||||
|
||||
handleInputStream(client, outgoingHandler, abort);
|
||||
handleInputStream(server, incomingHandler, abort);
|
||||
|
||||
// abort can be acquired as soon as one of the sockets is closed
|
||||
abort.acquire();
|
||||
try {
|
||||
if (!server.isClosed()) server.close();
|
||||
if (!client.isClosed()) client.close();
|
||||
if (HConnection.DEBUG) System.out.println("STOP");
|
||||
if (datastream[0]) {
|
||||
onConnectEnd();
|
||||
};
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleInputStream(Socket socket, FlashPacketHandler flashPacketHandler, Semaphore abort) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
int readLength;
|
||||
byte[] buffer = new byte[10000];
|
||||
while (!socket.isClosed() &&
|
||||
(hConnection.getState() == HState.WAITING_FOR_CLIENT || hConnection.getState() == HState.CONNECTED) &&
|
||||
(readLength = socket.getInputStream().read(buffer)) != -1) {
|
||||
flashPacketHandler.act(Arrays.copyOf(buffer, readLength));
|
||||
}
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
// System.err.println(packetHandler instanceof IncomingPacketHandler ? "incoming" : "outgoing");
|
||||
// ignore.printStackTrace();
|
||||
} finally {
|
||||
abort.release();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
|
||||
public abstract void start() throws IOException;
|
||||
public void abort() {
|
||||
if (abortSemaphore != null) {
|
||||
abortSemaphore.release();
|
||||
}
|
||||
else {
|
||||
stateSetter.setState(HState.NOT_CONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onConnect() {
|
||||
stateSetter.setState(HState.CONNECTED);
|
||||
}
|
||||
protected void onConnectEnd() {
|
||||
proxySetter.setProxy(null);
|
||||
abortSemaphore = null;
|
||||
stateSetter.setState(HState.NOT_CONNECTED);
|
||||
}
|
||||
|
||||
protected void showInvalidConnectionError() {
|
||||
Platform.runLater(() -> {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR, "You entered invalid connection information, G-Earth could not connect", ButtonType.OK);
|
||||
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
|
||||
alert.setResizable(false);
|
||||
alert.show();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -1,21 +1,19 @@
|
||||
package gearth.protocol.connection.proxy;
|
||||
package gearth.protocol.connection.proxy.flash;
|
||||
|
||||
import gearth.misc.Cacher;
|
||||
import gearth.protocol.HConnection;
|
||||
import gearth.protocol.connection.HProxy;
|
||||
import gearth.protocol.connection.HProxySetter;
|
||||
import gearth.protocol.connection.HState;
|
||||
import gearth.protocol.connection.HStateSetter;
|
||||
import gearth.protocol.connection.*;
|
||||
import gearth.protocol.connection.proxy.ProxyProviderFactory;
|
||||
import gearth.protocol.connection.proxy.SocksConfiguration;
|
||||
import gearth.protocol.hostreplacer.hostsfile.HostReplacer;
|
||||
import gearth.protocol.hostreplacer.hostsfile.HostReplacerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class NormalProxyProvider extends ProxyProvider {
|
||||
public class NormalFlashProxyProvider extends FlashProxyProvider {
|
||||
|
||||
private List<String> potentialHosts;
|
||||
|
||||
@ -29,7 +27,7 @@ public class NormalProxyProvider extends ProxyProvider {
|
||||
private boolean useSocks;
|
||||
|
||||
|
||||
public NormalProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, List<String> potentialHosts, boolean useSocks) {
|
||||
public NormalFlashProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, List<String> potentialHosts, boolean useSocks) {
|
||||
super(proxySetter, stateSetter, hConnection);
|
||||
this.potentialHosts = potentialHosts;
|
||||
this.useSocks = useSocks;
|
||||
@ -72,7 +70,7 @@ public class NormalProxyProvider extends ProxyProvider {
|
||||
|
||||
int intercept_port = port;
|
||||
String intercept_host = "127.0." + (c / 254) + "." + (1 + c % 254);
|
||||
potentialProxies.add(new HProxy(input_dom, actual_dom, port, intercept_port, intercept_host));
|
||||
potentialProxies.add(new HProxy(HClient.FLASH, input_dom, actual_dom, port, intercept_port, intercept_host));
|
||||
c++;
|
||||
}
|
||||
}
|
@ -1,26 +1,19 @@
|
||||
package gearth.protocol.connection.proxy.unix;
|
||||
package gearth.protocol.connection.proxy.flash.unix;
|
||||
|
||||
import gearth.protocol.HConnection;
|
||||
import gearth.protocol.connection.HProxy;
|
||||
import gearth.protocol.connection.HProxySetter;
|
||||
import gearth.protocol.connection.HState;
|
||||
import gearth.protocol.connection.HStateSetter;
|
||||
import gearth.protocol.connection.proxy.ProxyProvider;
|
||||
import gearth.protocol.connection.*;
|
||||
import gearth.protocol.connection.proxy.flash.FlashProxyProvider;
|
||||
import gearth.protocol.connection.proxy.ProxyProviderFactory;
|
||||
import gearth.protocol.connection.proxy.SocksConfiguration;
|
||||
import gearth.protocol.hostreplacer.ipmapping.IpMapper;
|
||||
import gearth.protocol.hostreplacer.ipmapping.IpMapperFactory;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
public class LinuxRawIpProxyProvider extends ProxyProvider {
|
||||
public class LinuxRawIpFlashProxyProvider extends FlashProxyProvider {
|
||||
|
||||
private volatile String input_host;
|
||||
private volatile int input_port;
|
||||
@ -30,7 +23,7 @@ public class LinuxRawIpProxyProvider extends ProxyProvider {
|
||||
|
||||
private boolean useSocks;
|
||||
|
||||
public LinuxRawIpProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, String input_host, int input_port, boolean useSocks) {
|
||||
public LinuxRawIpFlashProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, String input_host, int input_port, boolean useSocks) {
|
||||
super(proxySetter, stateSetter, hConnection);
|
||||
this.input_host = input_host;
|
||||
this.input_port = input_port;
|
||||
@ -50,7 +43,7 @@ public class LinuxRawIpProxyProvider extends ProxyProvider {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
stateSetter.setState(HState.PREPARING);
|
||||
proxy = new HProxy(input_host, input_host, input_port, input_port, "0.0.0.0");
|
||||
proxy = new HProxy(HClient.FLASH, input_host, input_host, input_port, input_port, "0.0.0.0");
|
||||
|
||||
maybeRemoveMapping();
|
||||
|
@ -1,35 +1,23 @@
|
||||
package gearth.protocol.connection.proxy.windows;
|
||||
package gearth.protocol.connection.proxy.flash.windows;
|
||||
|
||||
import gearth.misc.Cacher;
|
||||
import gearth.protocol.HConnection;
|
||||
import gearth.protocol.connection.HProxy;
|
||||
import gearth.protocol.connection.HProxySetter;
|
||||
import gearth.protocol.connection.HState;
|
||||
import gearth.protocol.connection.HStateSetter;
|
||||
import gearth.protocol.connection.proxy.ProxyProvider;
|
||||
import gearth.protocol.connection.proxy.unix.LinuxRawIpProxyProvider;
|
||||
import gearth.protocol.hostreplacer.ipmapping.IpMapper;
|
||||
import gearth.protocol.hostreplacer.ipmapping.IpMapperFactory;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.layout.Region;
|
||||
import gearth.protocol.connection.proxy.flash.unix.LinuxRawIpFlashProxyProvider;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.net.*;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.UUID;
|
||||
|
||||
// windows raw ip proxy provider extends the Linux one with the exception that it does not want to close
|
||||
// the IP redirect on connect
|
||||
public class WindowsRawIpProxyProvider extends LinuxRawIpProxyProvider {
|
||||
public class WindowsRawIpFlashProxyProvider extends LinuxRawIpFlashProxyProvider {
|
||||
|
||||
private boolean hasMapped = false;
|
||||
|
||||
public WindowsRawIpProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, String input_host, int input_port, boolean useSocks) {
|
||||
public WindowsRawIpFlashProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, String input_host, int input_port, boolean useSocks) {
|
||||
super(proxySetter, stateSetter, hConnection, input_host, input_port, useSocks);
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
package gearth.protocol.connection.proxy.unity;
|
||||
|
||||
import javafx.beans.InvalidationListener;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.JsrParamIdText;
|
||||
|
||||
import javax.websocket.OnOpen;
|
||||
import javax.websocket.Session;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import java.io.IOException;
|
||||
|
||||
// tells which port the packethandler is running on
|
||||
// server gets closed afterwards
|
||||
@ServerEndpoint(value = "/portrequest")
|
||||
public class PortRequester {
|
||||
|
||||
private final int packetHandlerPort;
|
||||
|
||||
public PortRequester(int port) {
|
||||
this.packetHandlerPort = port;
|
||||
}
|
||||
|
||||
@OnOpen
|
||||
public void onOpen(Session session) throws IOException {
|
||||
session.getBasicRemote().sendText("port " + packetHandlerPort);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package gearth.protocol.connection.proxy.unity;
|
||||
|
||||
import javax.websocket.server.ServerEndpointConfig;
|
||||
|
||||
public class PortRequesterConfig extends ServerEndpointConfig.Configurator {
|
||||
|
||||
private final int packetHandlerPort;
|
||||
|
||||
public PortRequesterConfig(int packetHandlerPort) {
|
||||
this.packetHandlerPort = packetHandlerPort;
|
||||
}
|
||||
|
||||
public <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException {
|
||||
return (T)new PortRequester(packetHandlerPort);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
package gearth.protocol.connection.proxy.unity;
|
||||
|
||||
import gearth.protocol.HConnection;
|
||||
import gearth.protocol.HMessage;
|
||||
import gearth.protocol.HPacket;
|
||||
import gearth.protocol.connection.*;
|
||||
import gearth.protocol.connection.proxy.ProxyProvider;
|
||||
import gearth.protocol.packethandler.unity.UnityPacketHandler;
|
||||
|
||||
import javax.websocket.*;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
@ServerEndpoint(value = "/packethandler")
|
||||
public class UnityCommunicator {
|
||||
|
||||
private final HProxySetter proxySetter;
|
||||
private final HStateSetter stateSetter;
|
||||
private final HConnection hConnection;
|
||||
private final ProxyProvider proxyProvider;
|
||||
|
||||
private HProxy hProxy = null;
|
||||
private String allowedSession = null;
|
||||
private String revision = null;
|
||||
|
||||
public UnityCommunicator(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, ProxyProvider proxyProvider) {
|
||||
this.proxySetter = proxySetter;
|
||||
this.stateSetter = stateSetter;
|
||||
this.hConnection = hConnection;
|
||||
this.proxyProvider = proxyProvider;
|
||||
}
|
||||
|
||||
|
||||
@OnOpen
|
||||
public void onOpen(Session session) throws IOException {
|
||||
session.setMaxBinaryMessageBufferSize(1024 * 1024 * 10);
|
||||
}
|
||||
|
||||
@OnMessage
|
||||
public void onMessage(byte[] b, Session session) throws IOException {
|
||||
if (allowedSession != null && !session.getId().equals(allowedSession)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (revision == null) {
|
||||
revision = new String(b, StandardCharsets.ISO_8859_1);
|
||||
allowedSession = session.getId();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
byte[] packet = Arrays.copyOfRange(b, 1, b.length);
|
||||
|
||||
if (hProxy == null && b[0] == 1) {
|
||||
HPacket maybe = new HPacket(packet);
|
||||
if (maybe.getBytesLength() > 6 && maybe.headerId() == 4000) {
|
||||
hProxy = new HProxy(HClient.UNITY, "", "", -1, -1, "");
|
||||
hProxy.verifyProxy(
|
||||
new UnityPacketHandler(hConnection.getExtensionHandler(), hConnection.getTrafficObservables(), session, HMessage.Direction.TOCLIENT),
|
||||
new UnityPacketHandler(hConnection.getExtensionHandler(), hConnection.getTrafficObservables(), session, HMessage.Direction.TOSERVER),
|
||||
revision
|
||||
);
|
||||
proxySetter.setProxy(hProxy);
|
||||
stateSetter.setState(HState.CONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (hProxy != null && b[0] == 0) {
|
||||
hProxy.getInHandler().act(packet);
|
||||
}
|
||||
else if (hProxy != null && b[0] == 1) {
|
||||
hProxy.getOutHandler().act(packet);
|
||||
}
|
||||
else {
|
||||
proxyProvider.abort();
|
||||
}
|
||||
}
|
||||
|
||||
@OnClose
|
||||
public void onClose(Session session) throws IOException {
|
||||
proxyProvider.abort();
|
||||
}
|
||||
|
||||
@OnError
|
||||
public void onError(Session session, Throwable throwable) {
|
||||
proxyProvider.abort();
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package gearth.protocol.connection.proxy.unity;
|
||||
|
||||
import gearth.protocol.HConnection;
|
||||
import gearth.protocol.connection.HProxySetter;
|
||||
import gearth.protocol.connection.HStateSetter;
|
||||
import gearth.protocol.connection.proxy.ProxyProvider;
|
||||
|
||||
import javax.websocket.server.ServerEndpointConfig;
|
||||
|
||||
public class UnityCommunicatorConfig extends ServerEndpointConfig.Configurator {
|
||||
private final HProxySetter proxySetter;
|
||||
private final HStateSetter stateSetter;
|
||||
private final HConnection hConnection;
|
||||
private final ProxyProvider proxyProvider;
|
||||
|
||||
public UnityCommunicatorConfig(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, ProxyProvider proxyProvider) {
|
||||
this.proxySetter = proxySetter;
|
||||
this.stateSetter = stateSetter;
|
||||
this.hConnection = hConnection;
|
||||
this.proxyProvider = proxyProvider;
|
||||
}
|
||||
|
||||
|
||||
public <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException {
|
||||
return (T)new UnityCommunicator(proxySetter, stateSetter, hConnection, proxyProvider);
|
||||
}
|
||||
}
|
@ -0,0 +1,168 @@
|
||||
package gearth.protocol.connection.proxy.unity;
|
||||
|
||||
import gearth.protocol.HConnection;
|
||||
import gearth.protocol.StateChangeListener;
|
||||
import gearth.protocol.connection.HProxySetter;
|
||||
import gearth.protocol.connection.HState;
|
||||
import gearth.protocol.connection.HStateSetter;
|
||||
import gearth.protocol.connection.proxy.ProxyProvider;
|
||||
import gearth.services.unity_tools.GUnityFileServer;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.HandlerList;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
|
||||
|
||||
import javax.websocket.server.ServerContainer;
|
||||
import javax.websocket.server.ServerEndpointConfig;
|
||||
import java.io.IOException;
|
||||
|
||||
import static gearth.services.unity_tools.GUnityFileServer.FILESERVER_PORT;
|
||||
|
||||
public class UnityProxyProvider implements ProxyProvider {
|
||||
|
||||
private final HProxySetter proxySetter;
|
||||
private final HStateSetter stateSetter;
|
||||
private final HConnection hConnection;
|
||||
|
||||
private Server packetHandlerServer = null;
|
||||
|
||||
public UnityProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection) {
|
||||
this.proxySetter = proxySetter;
|
||||
this.stateSetter = stateSetter;
|
||||
this.hConnection = hConnection;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void start() throws IOException {
|
||||
// https://happyhyppo.ro/2016/03/21/minimal-websockets-communication-with-javajetty-and-angularjs/
|
||||
|
||||
try {
|
||||
int port = 9040;
|
||||
boolean fail = true;
|
||||
while (fail && port < 9100) {
|
||||
try {
|
||||
packetHandlerServer = new Server(port);
|
||||
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
context.setContextPath("/ws");
|
||||
|
||||
HandlerList handlers = new HandlerList();
|
||||
handlers.setHandlers(new Handler[] { context });
|
||||
|
||||
ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);
|
||||
wscontainer.addEndpoint(ServerEndpointConfig.Builder
|
||||
.create(UnityCommunicator.class, "/packethandler") // the endpoint url
|
||||
.configurator(new UnityCommunicatorConfig(proxySetter, stateSetter, hConnection, this))
|
||||
.build());
|
||||
packetHandlerServer.setHandler(handlers);
|
||||
packetHandlerServer.start();
|
||||
fail = false;
|
||||
}
|
||||
catch (Exception e) {
|
||||
port++;
|
||||
}
|
||||
}
|
||||
|
||||
if (fail) {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
|
||||
startPortRequestServer(port);
|
||||
startUnityFileServer();
|
||||
stateSetter.setState(HState.WAITING_FOR_CLIENT);
|
||||
|
||||
} catch (Exception e) {
|
||||
stateSetter.setState(HState.NOT_CONNECTED);
|
||||
try {
|
||||
packetHandlerServer.stop();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void abort() {
|
||||
if (packetHandlerServer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Server abortThis = packetHandlerServer;
|
||||
stateSetter.setState(HState.ABORTING);
|
||||
new Thread(() -> {
|
||||
try {
|
||||
abortThis.stop();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
stateSetter.setState(HState.NOT_CONNECTED);
|
||||
}
|
||||
}).start();
|
||||
packetHandlerServer = null;
|
||||
}
|
||||
|
||||
private void startUnityFileServer() throws Exception {
|
||||
Server server = new Server(FILESERVER_PORT);
|
||||
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
context.setContextPath("/");
|
||||
|
||||
context.addServlet(new ServletHolder(new GUnityFileServer()), "/*");
|
||||
|
||||
HandlerList handlers = new HandlerList();
|
||||
handlers.setHandlers(new Handler[] { context });
|
||||
server.setHandler(handlers);
|
||||
|
||||
server.start();
|
||||
StateChangeListener fileServerCloser = new StateChangeListener() {
|
||||
@Override
|
||||
public void stateChanged(HState oldState, HState newState) {
|
||||
if (oldState == HState.WAITING_FOR_CLIENT || newState == HState.NOT_CONNECTED) {
|
||||
hConnection.getStateObservable().removeListener(this);
|
||||
try {
|
||||
server.stop();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
hConnection.getStateObservable().addListener(fileServerCloser);
|
||||
}
|
||||
|
||||
private void startPortRequestServer(int packetHandlerPort) throws Exception {
|
||||
Server portRequestServer = new Server(9039);
|
||||
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
context.setContextPath("/ws");
|
||||
|
||||
HandlerList handlers = new HandlerList();
|
||||
handlers.setHandlers(new Handler[] { context });
|
||||
portRequestServer.setHandler(handlers);
|
||||
|
||||
ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);
|
||||
wscontainer.addEndpoint(ServerEndpointConfig.Builder
|
||||
.create(PortRequester.class, "/portrequest") // the endpoint url
|
||||
.configurator(new PortRequesterConfig(packetHandlerPort))
|
||||
.build());
|
||||
|
||||
portRequestServer.start();
|
||||
|
||||
StateChangeListener portRequesterCloser = new StateChangeListener() {
|
||||
@Override
|
||||
public void stateChanged(HState oldState, HState newState) {
|
||||
if (oldState == HState.WAITING_FOR_CLIENT || newState == HState.NOT_CONNECTED) {
|
||||
hConnection.getStateObservable().removeListener(this);
|
||||
try {
|
||||
portRequestServer.stop();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
hConnection.getStateObservable().addListener(portRequesterCloser);
|
||||
}
|
||||
}
|
@ -7,7 +7,9 @@ import gearth.protocol.HPacket;
|
||||
import gearth.protocol.crypto.RC4;
|
||||
import gearth.protocol.memory.habboclient.HabboClient;
|
||||
import gearth.protocol.memory.habboclient.HabboClientFactory;
|
||||
import gearth.protocol.packethandler.*;
|
||||
import gearth.protocol.packethandler.flash.BufferChangeListener;
|
||||
import gearth.protocol.packethandler.flash.FlashPacketHandler;
|
||||
import gearth.protocol.packethandler.PayloadBuffer;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonType;
|
||||
@ -25,17 +27,17 @@ public class Rc4Obtainer {
|
||||
public static final boolean DEBUG = false;
|
||||
|
||||
private HabboClient client;
|
||||
private List<PacketHandler> packetHandlers;
|
||||
private List<FlashPacketHandler> flashPacketHandlers;
|
||||
|
||||
public Rc4Obtainer(HConnection hConnection) {
|
||||
client = HabboClientFactory.get(hConnection);
|
||||
}
|
||||
|
||||
|
||||
public void setPacketHandlers(PacketHandler... packetHandlers) {
|
||||
this.packetHandlers = Arrays.asList(packetHandlers);
|
||||
public void setFlashPacketHandlers(FlashPacketHandler... flashPacketHandlers) {
|
||||
this.flashPacketHandlers = Arrays.asList(flashPacketHandlers);
|
||||
|
||||
for (PacketHandler handler : packetHandlers) {
|
||||
for (FlashPacketHandler handler : flashPacketHandlers) {
|
||||
BufferChangeListener bufferChangeListener = new BufferChangeListener() {
|
||||
@Override
|
||||
public void act() {
|
||||
@ -53,10 +55,10 @@ public class Rc4Obtainer {
|
||||
|
||||
|
||||
|
||||
private void onSendFirstEncryptedMessage(PacketHandler packetHandler) {
|
||||
private void onSendFirstEncryptedMessage(FlashPacketHandler flashPacketHandler) {
|
||||
if (!HConnection.DECRYPTPACKETS) return;
|
||||
|
||||
packetHandlers.forEach(PacketHandler::block);
|
||||
flashPacketHandlers.forEach(FlashPacketHandler::block);
|
||||
|
||||
new Thread(() -> {
|
||||
|
||||
@ -67,8 +69,8 @@ public class Rc4Obtainer {
|
||||
int i = 0;
|
||||
while (!worked && i < 4) {
|
||||
worked = (i % 2 == 0) ?
|
||||
onSendFirstEncryptedMessage(packetHandler, client.getRC4cached()) :
|
||||
onSendFirstEncryptedMessage(packetHandler, client.getRC4possibilities());
|
||||
onSendFirstEncryptedMessage(flashPacketHandler, client.getRC4cached()) :
|
||||
onSendFirstEncryptedMessage(flashPacketHandler, client.getRC4possibilities());
|
||||
i++;
|
||||
}
|
||||
|
||||
@ -107,16 +109,16 @@ public class Rc4Obtainer {
|
||||
System.out.println("Cracked RC4 in " + (endTime - startTime) + "ms");
|
||||
}
|
||||
|
||||
packetHandlers.forEach(PacketHandler::unblock);
|
||||
flashPacketHandlers.forEach(FlashPacketHandler::unblock);
|
||||
}).start();
|
||||
}
|
||||
|
||||
private boolean onSendFirstEncryptedMessage(PacketHandler packetHandler, List<byte[]> potentialRC4tables) {
|
||||
private boolean onSendFirstEncryptedMessage(FlashPacketHandler flashPacketHandler, List<byte[]> potentialRC4tables) {
|
||||
for (byte[] possible : potentialRC4tables) {
|
||||
|
||||
byte[] encBuffer = new byte[packetHandler.getEncryptedBuffer().size()];
|
||||
byte[] encBuffer = new byte[flashPacketHandler.getEncryptedBuffer().size()];
|
||||
for (int i = 0; i < encBuffer.length; i++) {
|
||||
encBuffer[i] = packetHandler.getEncryptedBuffer().get(i);
|
||||
encBuffer[i] = flashPacketHandler.getEncryptedBuffer().get(i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
@ -124,7 +126,7 @@ public class Rc4Obtainer {
|
||||
byte[] keycpy = Arrays.copyOf(possible, possible.length);
|
||||
RC4 rc4Tryout = new RC4(keycpy, i, j);
|
||||
|
||||
if (packetHandler.getMessageSide() == HMessage.Direction.TOSERVER) rc4Tryout.undoRc4(encBuffer);
|
||||
if (flashPacketHandler.getMessageSide() == HMessage.Direction.TOSERVER) rc4Tryout.undoRc4(encBuffer);
|
||||
if (rc4Tryout.couldBeFresh()) {
|
||||
byte[] encDataCopy = Arrays.copyOf(encBuffer, encBuffer.length);
|
||||
RC4 rc4TryCopy = rc4Tryout.deepCopy();
|
||||
@ -135,7 +137,7 @@ public class Rc4Obtainer {
|
||||
HPacket[] checker = payloadBuffer.pushAndReceive(decoded);
|
||||
|
||||
if (payloadBuffer.peak().length == 0) {
|
||||
packetHandler.setRc4(rc4Tryout);
|
||||
flashPacketHandler.setRc4(rc4Tryout);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,12 @@
|
||||
package gearth.protocol.packethandler;
|
||||
|
||||
public class ByteArrayUtils {
|
||||
|
||||
public static byte[] combineByteArrays(byte[] arr1, byte[] arr2) {
|
||||
byte[] combined = new byte[arr1.length + arr2.length];
|
||||
System.arraycopy(arr1,0,combined,0 ,arr1.length);
|
||||
System.arraycopy(arr2,0,combined,arr1.length,arr2.length);
|
||||
return combined;
|
||||
}
|
||||
|
||||
}
|
@ -1,125 +1,32 @@
|
||||
package gearth.protocol.packethandler;
|
||||
|
||||
import gearth.misc.listenerpattern.Observable;
|
||||
import gearth.protocol.HConnection;
|
||||
import gearth.protocol.HMessage;
|
||||
import gearth.protocol.HPacket;
|
||||
import gearth.protocol.TrafficListener;
|
||||
import gearth.protocol.crypto.RC4;
|
||||
import gearth.services.extensionhandler.ExtensionHandler;
|
||||
import gearth.services.extensionhandler.OnHMessageHandled;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class PacketHandler {
|
||||
|
||||
protected static final boolean DEBUG = false;
|
||||
protected final ExtensionHandler extensionHandler;
|
||||
private final Object[] trafficObservables; //get notified on packet send
|
||||
protected final PayloadBuffer payloadBuffer;
|
||||
protected volatile int currentIndex = 0;
|
||||
protected final Object sendLock = new Object();
|
||||
|
||||
private volatile PayloadBuffer payloadBuffer = new PayloadBuffer();
|
||||
private volatile OutputStream out;
|
||||
private volatile ExtensionHandler extensionHandler;
|
||||
private volatile Object[] trafficObservables; //get notified on packet send
|
||||
private volatile boolean isTempBlocked = false;
|
||||
volatile boolean isDataStream = false;
|
||||
private volatile int currentIndex = 0;
|
||||
|
||||
private final Object manipulationLock = new Object();
|
||||
private final Object sendLock = new Object();
|
||||
|
||||
private RC4 decryptcipher = null;
|
||||
private RC4 encryptcipher = null;
|
||||
|
||||
private volatile List<Byte> tempEncryptedBuffer = new ArrayList<>();
|
||||
volatile boolean isEncryptedStream = false;
|
||||
|
||||
|
||||
PacketHandler(OutputStream outputStream, Object[] trafficObservables, ExtensionHandler extensionHandler) {
|
||||
this.trafficObservables = trafficObservables;
|
||||
protected PacketHandler(ExtensionHandler extensionHandler, Object[] trafficObservables) {
|
||||
this.extensionHandler = extensionHandler;
|
||||
out = outputStream;
|
||||
}
|
||||
|
||||
public boolean isDataStream() {return isDataStream;}
|
||||
public void setAsDataStream() {
|
||||
isDataStream = true;
|
||||
}
|
||||
|
||||
public boolean isEncryptedStream() {
|
||||
return isEncryptedStream;
|
||||
}
|
||||
|
||||
public void act(byte[] buffer) throws IOException {
|
||||
if (!isDataStream) {
|
||||
out.write(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
bufferChangeObservable.fireEvent();
|
||||
|
||||
if (!isEncryptedStream) {
|
||||
payloadBuffer.push(buffer);
|
||||
}
|
||||
else if (!HConnection.DECRYPTPACKETS) {
|
||||
synchronized (sendLock) {
|
||||
out.write(buffer);
|
||||
}
|
||||
}
|
||||
else if (decryptcipher == null) {
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
tempEncryptedBuffer.add(buffer[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
byte[] tm = decryptcipher.rc4(buffer);
|
||||
if (DEBUG) {
|
||||
printForDebugging(tm);
|
||||
}
|
||||
payloadBuffer.push(tm);
|
||||
}
|
||||
|
||||
if (!isTempBlocked) {
|
||||
flush();
|
||||
}
|
||||
this.trafficObservables = trafficObservables;
|
||||
this.payloadBuffer = new PayloadBuffer();
|
||||
}
|
||||
|
||||
|
||||
public void setRc4(RC4 rc4) {
|
||||
this.decryptcipher = rc4.deepCopy();
|
||||
this.encryptcipher = rc4.deepCopy();
|
||||
public abstract void sendToStream(byte[] buffer);
|
||||
|
||||
byte[] encrbuffer = new byte[tempEncryptedBuffer.size()];
|
||||
for (int i = 0; i < tempEncryptedBuffer.size(); i++) {
|
||||
encrbuffer[i] = tempEncryptedBuffer.get(i);
|
||||
}
|
||||
public abstract void act(byte[] buffer) throws IOException;
|
||||
|
||||
try {
|
||||
act(encrbuffer);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
tempEncryptedBuffer = null;
|
||||
}
|
||||
|
||||
public void block() {
|
||||
isTempBlocked = true;
|
||||
}
|
||||
public void unblock() {
|
||||
try {
|
||||
flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
isTempBlocked = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* LISTENERS CAN EDIT THE MESSAGE BEFORE BEING SENT
|
||||
* @param message
|
||||
*/
|
||||
private void notifyListeners(int i, HMessage message) {
|
||||
protected void notifyListeners(int i, HMessage message) {
|
||||
((Observable<TrafficListener>) trafficObservables[i]).fireEvent(trafficListener -> {
|
||||
message.getPacket().resetReadIndex();
|
||||
trafficListener.onCapture(message);
|
||||
@ -127,72 +34,4 @@ public abstract class PacketHandler {
|
||||
message.getPacket().resetReadIndex();
|
||||
}
|
||||
|
||||
public void sendToStream(byte[] buffer) {
|
||||
synchronized (sendLock) {
|
||||
try {
|
||||
out.write(
|
||||
(!isEncryptedStream)
|
||||
? buffer
|
||||
: encryptcipher.rc4(buffer)
|
||||
);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void flush() throws IOException {
|
||||
synchronized (manipulationLock) {
|
||||
HPacket[] hpackets = payloadBuffer.receive();
|
||||
|
||||
for (HPacket hpacket : hpackets){
|
||||
HMessage hMessage = new HMessage(hpacket, getMessageSide(), currentIndex);
|
||||
boolean isencrypted = isEncryptedStream;
|
||||
|
||||
OnHMessageHandled afterExtensionIntercept = hMessage1 -> {
|
||||
if (isDataStream) {
|
||||
notifyListeners(2, hMessage1);
|
||||
}
|
||||
|
||||
if (!hMessage1.isBlocked()) {
|
||||
synchronized (sendLock) {
|
||||
out.write(
|
||||
(!isencrypted)
|
||||
? hMessage1.getPacket().toBytes()
|
||||
: encryptcipher.rc4(hMessage1.getPacket().toBytes())
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (isDataStream) {
|
||||
notifyListeners(0, hMessage);
|
||||
notifyListeners(1, hMessage);
|
||||
extensionHandler.handle(hMessage, afterExtensionIntercept);
|
||||
}
|
||||
else {
|
||||
afterExtensionIntercept.finished(hMessage);
|
||||
}
|
||||
|
||||
currentIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract HMessage.Direction getMessageSide();
|
||||
|
||||
public List<Byte> getEncryptedBuffer() {
|
||||
return tempEncryptedBuffer;
|
||||
}
|
||||
|
||||
protected abstract void printForDebugging(byte[] bytes);
|
||||
|
||||
private Observable<BufferChangeListener> bufferChangeObservable = new Observable<>(BufferChangeListener::act);
|
||||
public Observable<BufferChangeListener> getBufferChangeObservable() {
|
||||
return bufferChangeObservable;
|
||||
}
|
||||
|
||||
public int getCurrentIndex() {
|
||||
return currentIndex;
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ public class PayloadBuffer {
|
||||
return receive();
|
||||
}
|
||||
public void push(byte[] tcpData) {
|
||||
buffer = buffer.length == 0 ? tcpData.clone() : combineByteArrays(buffer, tcpData);
|
||||
buffer = buffer.length == 0 ? tcpData.clone() : ByteArrayUtils.combineByteArrays(buffer, tcpData);
|
||||
}
|
||||
public HPacket[] receive() {
|
||||
if (buffer.length < 6) return new HPacket[0];
|
||||
@ -30,14 +30,6 @@ public class PayloadBuffer {
|
||||
}
|
||||
|
||||
|
||||
private byte[] combineByteArrays(byte[] arr1, byte[] arr2) {
|
||||
byte[] combined = new byte[arr1.length + arr2.length];
|
||||
System.arraycopy(arr1,0,combined,0 ,arr1.length);
|
||||
System.arraycopy(arr2,0,combined,arr1.length,arr2.length);
|
||||
return combined;
|
||||
}
|
||||
|
||||
|
||||
public byte[] peak() {
|
||||
return buffer;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package gearth.protocol.packethandler;
|
||||
package gearth.protocol.packethandler.flash;
|
||||
|
||||
|
||||
public interface BufferChangeListener {
|
@ -0,0 +1,182 @@
|
||||
package gearth.protocol.packethandler.flash;
|
||||
|
||||
import gearth.misc.listenerpattern.Observable;
|
||||
import gearth.protocol.HConnection;
|
||||
import gearth.protocol.HMessage;
|
||||
import gearth.protocol.HPacket;
|
||||
import gearth.protocol.TrafficListener;
|
||||
import gearth.protocol.crypto.RC4;
|
||||
import gearth.protocol.packethandler.PacketHandler;
|
||||
import gearth.protocol.packethandler.PayloadBuffer;
|
||||
import gearth.services.extensionhandler.ExtensionHandler;
|
||||
import gearth.services.extensionhandler.OnHMessageHandled;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class FlashPacketHandler extends PacketHandler {
|
||||
|
||||
protected static final boolean DEBUG = false;
|
||||
|
||||
private volatile OutputStream out;
|
||||
private volatile boolean isTempBlocked = false;
|
||||
volatile boolean isDataStream = false;
|
||||
|
||||
private final Object manipulationLock = new Object();
|
||||
|
||||
private RC4 decryptcipher = null;
|
||||
private RC4 encryptcipher = null;
|
||||
|
||||
private volatile List<Byte> tempEncryptedBuffer = new ArrayList<>();
|
||||
volatile boolean isEncryptedStream = false;
|
||||
|
||||
|
||||
FlashPacketHandler(OutputStream outputStream, Object[] trafficObservables, ExtensionHandler extensionHandler) {
|
||||
super(extensionHandler, trafficObservables);
|
||||
out = outputStream;
|
||||
}
|
||||
|
||||
public boolean isDataStream() {return isDataStream;}
|
||||
public void setAsDataStream() {
|
||||
isDataStream = true;
|
||||
}
|
||||
|
||||
public boolean isEncryptedStream() {
|
||||
return isEncryptedStream;
|
||||
}
|
||||
|
||||
public void act(byte[] buffer) throws IOException {
|
||||
if (!isDataStream) {
|
||||
out.write(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
bufferChangeObservable.fireEvent();
|
||||
|
||||
if (!isEncryptedStream) {
|
||||
payloadBuffer.push(buffer);
|
||||
}
|
||||
else if (!HConnection.DECRYPTPACKETS) {
|
||||
synchronized (sendLock) {
|
||||
out.write(buffer);
|
||||
}
|
||||
}
|
||||
else if (decryptcipher == null) {
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
tempEncryptedBuffer.add(buffer[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
byte[] tm = decryptcipher.rc4(buffer);
|
||||
if (DEBUG) {
|
||||
printForDebugging(tm);
|
||||
}
|
||||
payloadBuffer.push(tm);
|
||||
}
|
||||
|
||||
if (!isTempBlocked) {
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setRc4(RC4 rc4) {
|
||||
this.decryptcipher = rc4.deepCopy();
|
||||
this.encryptcipher = rc4.deepCopy();
|
||||
|
||||
byte[] encrbuffer = new byte[tempEncryptedBuffer.size()];
|
||||
for (int i = 0; i < tempEncryptedBuffer.size(); i++) {
|
||||
encrbuffer[i] = tempEncryptedBuffer.get(i);
|
||||
}
|
||||
|
||||
try {
|
||||
act(encrbuffer);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
tempEncryptedBuffer = null;
|
||||
}
|
||||
|
||||
public void block() {
|
||||
isTempBlocked = true;
|
||||
}
|
||||
public void unblock() {
|
||||
try {
|
||||
flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
isTempBlocked = false;
|
||||
}
|
||||
|
||||
public void sendToStream(byte[] buffer) {
|
||||
synchronized (sendLock) {
|
||||
try {
|
||||
out.write(
|
||||
(!isEncryptedStream)
|
||||
? buffer
|
||||
: encryptcipher.rc4(buffer)
|
||||
);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void flush() throws IOException {
|
||||
synchronized (manipulationLock) {
|
||||
HPacket[] hpackets = payloadBuffer.receive();
|
||||
|
||||
for (HPacket hpacket : hpackets){
|
||||
HMessage hMessage = new HMessage(hpacket, getMessageSide(), currentIndex);
|
||||
boolean isencrypted = isEncryptedStream;
|
||||
|
||||
OnHMessageHandled afterExtensionIntercept = hMessage1 -> {
|
||||
if (isDataStream) {
|
||||
notifyListeners(2, hMessage1);
|
||||
}
|
||||
|
||||
if (!hMessage1.isBlocked()) {
|
||||
synchronized (sendLock) {
|
||||
out.write(
|
||||
(!isencrypted)
|
||||
? hMessage1.getPacket().toBytes()
|
||||
: encryptcipher.rc4(hMessage1.getPacket().toBytes())
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (isDataStream) {
|
||||
notifyListeners(0, hMessage);
|
||||
notifyListeners(1, hMessage);
|
||||
extensionHandler.handle(hMessage, afterExtensionIntercept);
|
||||
}
|
||||
else {
|
||||
afterExtensionIntercept.finished(hMessage);
|
||||
}
|
||||
|
||||
currentIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract HMessage.Direction getMessageSide();
|
||||
|
||||
public List<Byte> getEncryptedBuffer() {
|
||||
return tempEncryptedBuffer;
|
||||
}
|
||||
|
||||
protected abstract void printForDebugging(byte[] bytes);
|
||||
|
||||
private Observable<BufferChangeListener> bufferChangeObservable = new Observable<>(BufferChangeListener::act);
|
||||
public Observable<BufferChangeListener> getBufferChangeObservable() {
|
||||
return bufferChangeObservable;
|
||||
}
|
||||
|
||||
public int getCurrentIndex() {
|
||||
return currentIndex;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package gearth.protocol.packethandler;
|
||||
package gearth.protocol.packethandler.flash;
|
||||
|
||||
import gearth.misc.listenerpattern.Observable;
|
||||
import gearth.protocol.HMessage;
|
||||
@ -6,13 +6,11 @@ import gearth.protocol.HPacket;
|
||||
import gearth.protocol.TrafficListener;
|
||||
import gearth.services.extensionhandler.ExtensionHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
|
||||
public class IncomingPacketHandler extends PacketHandler {
|
||||
public class IncomingFlashPacketHandler extends FlashPacketHandler {
|
||||
|
||||
public IncomingPacketHandler(OutputStream outputStream, Object[] trafficObservables, OutgoingPacketHandler outgoingHandler, ExtensionHandler extensionHandler) {
|
||||
public IncomingFlashPacketHandler(OutputStream outputStream, Object[] trafficObservables, OutgoingFlashPacketHandler outgoingHandler, ExtensionHandler extensionHandler) {
|
||||
super(outputStream, trafficObservables, extensionHandler);
|
||||
|
||||
TrafficListener listener = new TrafficListener() {
|
@ -1,4 +1,4 @@
|
||||
package gearth.protocol.packethandler;
|
||||
package gearth.protocol.packethandler.flash;
|
||||
|
||||
public interface OnDatastreamConfirmedListener {
|
||||
|
@ -1,4 +1,4 @@
|
||||
package gearth.protocol.packethandler;
|
||||
package gearth.protocol.packethandler.flash;
|
||||
|
||||
import gearth.misc.listenerpattern.Observable;
|
||||
import gearth.protocol.HMessage;
|
||||
@ -7,13 +7,10 @@ import gearth.services.extensionhandler.ExtensionHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class OutgoingPacketHandler extends PacketHandler {
|
||||
public class OutgoingFlashPacketHandler extends FlashPacketHandler {
|
||||
|
||||
public OutgoingPacketHandler(OutputStream outputStream, Object[] trafficObservables, ExtensionHandler extensionHandler) {
|
||||
public OutgoingFlashPacketHandler(OutputStream outputStream, Object[] trafficObservables, ExtensionHandler extensionHandler) {
|
||||
super(outputStream, trafficObservables, extensionHandler);
|
||||
}
|
||||
|
@ -0,0 +1,52 @@
|
||||
package gearth.protocol.packethandler.unity;
|
||||
|
||||
import gearth.protocol.HMessage;
|
||||
import gearth.protocol.HPacket;
|
||||
import gearth.protocol.packethandler.ByteArrayUtils;
|
||||
import gearth.protocol.packethandler.PacketHandler;
|
||||
import gearth.protocol.packethandler.PayloadBuffer;
|
||||
import gearth.services.extensionhandler.ExtensionHandler;
|
||||
import gearth.services.extensionhandler.OnHMessageHandled;
|
||||
|
||||
import javax.websocket.Session;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class UnityPacketHandler extends PacketHandler {
|
||||
|
||||
private final Session session;
|
||||
private final HMessage.Direction direction;
|
||||
|
||||
public UnityPacketHandler(ExtensionHandler extensionHandler, Object[] trafficObservables, Session session, HMessage.Direction direction) {
|
||||
super(extensionHandler, trafficObservables);
|
||||
this.session = session;
|
||||
this.direction = direction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToStream(byte[] buffer) {
|
||||
byte[] prefix = new byte[]{(direction == HMessage.Direction.TOCLIENT ? ((byte)0) : ((byte)1))};
|
||||
byte[] combined = ByteArrayUtils.combineByteArrays(prefix, buffer);
|
||||
|
||||
session.getAsyncRemote().sendBinary(ByteBuffer.wrap(combined));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void act(byte[] buffer) throws IOException {
|
||||
HMessage hMessage = new HMessage(new HPacket(buffer), direction, currentIndex);
|
||||
|
||||
OnHMessageHandled afterExtensionIntercept = hMessage1 -> {
|
||||
notifyListeners(2, hMessage1);
|
||||
|
||||
if (!hMessage1.isBlocked()) {
|
||||
sendToStream(hMessage1.getPacket().toBytes());
|
||||
}
|
||||
};
|
||||
|
||||
notifyListeners(0, hMessage);
|
||||
notifyListeners(1, hMessage);
|
||||
extensionHandler.handle(hMessage, afterExtensionIntercept);
|
||||
|
||||
currentIndex++;
|
||||
}
|
||||
}
|
7
G-Earth/src/main/java/gearth/services/Constants.java
Normal file
7
G-Earth/src/main/java/gearth/services/Constants.java
Normal file
@ -0,0 +1,7 @@
|
||||
package gearth.services;
|
||||
|
||||
public class Constants {
|
||||
|
||||
public static volatile boolean UNITY_PACKETS = false;
|
||||
|
||||
}
|
@ -212,6 +212,27 @@ public class ExtensionHandler {
|
||||
protected void manipulatedPacket(HMessage hMessage) {
|
||||
onExtensionRespond(extension, hMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void packetToStringRequest(HPacket packet) {
|
||||
String s = "";
|
||||
String expression = "";
|
||||
try {
|
||||
s = packet.toString();
|
||||
if (packet.length() < 3000) {
|
||||
expression = packet.toExpression();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
extension.packetToStringResponse(s, expression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stringToPacketRequest(String string) {
|
||||
HPacket packet = new HPacket(string);
|
||||
extension.stringToPacketResponse(packet);
|
||||
}
|
||||
};
|
||||
|
||||
extension.getExtensionObservable().addListener(listener);
|
||||
|
@ -12,4 +12,7 @@ public abstract class ExtensionListener {
|
||||
protected void log(String text) {}
|
||||
protected void hasClosed() {}
|
||||
|
||||
protected void packetToStringRequest(HPacket packet) {}
|
||||
protected void stringToPacketRequest(String string) {}
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import gearth.services.extensionhandler.extensions.listeners.OmRemoveClickListen
|
||||
import gearth.services.extensionhandler.extensions.listeners.OnClickListener;
|
||||
import gearth.services.extensionhandler.extensions.listeners.OnDeleteListener;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public abstract class GEarthExtension {
|
||||
|
||||
|
||||
@ -40,6 +42,8 @@ public abstract class GEarthExtension {
|
||||
public abstract void connectionEnd();
|
||||
public abstract void init();
|
||||
public abstract void close();
|
||||
public abstract void packetToStringResponse(String string, String expression);
|
||||
public abstract void stringToPacketResponse(HPacket packet);
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
|
||||
@ -78,6 +82,19 @@ public abstract class GEarthExtension {
|
||||
protected void hasClosed() {
|
||||
extensionObservable.fireEvent(ExtensionListener::hasClosed);
|
||||
}
|
||||
|
||||
protected void packetToStringRequest(HPacket packet) {
|
||||
int orgIndex = packet.getReadIndex();
|
||||
extensionObservable.fireEvent(listener -> {
|
||||
packet.setReadIndex(6);
|
||||
listener.packetToStringRequest(packet);
|
||||
});
|
||||
packet.setReadIndex(orgIndex);
|
||||
}
|
||||
protected void stringToPacketRequest(String string) {
|
||||
extensionObservable.fireEvent(l -> l.stringToPacketRequest(string));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
|
@ -8,6 +8,7 @@ import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 21/06/18.
|
||||
@ -88,6 +89,14 @@ public class NetworkExtension extends GEarthExtension {
|
||||
else if (message.headerId() == NetworkExtensionInfo.INCOMING_MESSAGES_IDS.EXTENSIONCONSOLELOG) {
|
||||
log(message.readString());
|
||||
}
|
||||
else if (message.headerId() == NetworkExtensionInfo.INCOMING_MESSAGES_IDS.PACKETTOSTRING_REQUEST) {
|
||||
HPacket p = new HPacket(new byte[0]);
|
||||
p.constructFromString(message.readLongString());
|
||||
packetToStringRequest(p);
|
||||
}
|
||||
else if (message.headerId() == NetworkExtensionInfo.INCOMING_MESSAGES_IDS.STRINGTOPACKET_REQUEST) {
|
||||
stringToPacketRequest(message.readLongString(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -211,4 +220,19 @@ public class NetworkExtension extends GEarthExtension {
|
||||
connection.close();
|
||||
} catch (IOException ignored) { }
|
||||
}
|
||||
|
||||
@Override
|
||||
public void packetToStringResponse(String string, String expression) {
|
||||
HPacket packet = new HPacket(NetworkExtensionInfo.OUTGOING_MESSAGES_IDS.PACKETTOSTRING_RESPONSE);
|
||||
packet.appendLongString(string);
|
||||
packet.appendLongString(expression, StandardCharsets.UTF_8);
|
||||
sendMessage(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stringToPacketResponse(HPacket packetFromString) {
|
||||
HPacket packet = new HPacket(NetworkExtensionInfo.OUTGOING_MESSAGES_IDS.STRINGTOPACKET_RESPONSE);
|
||||
packet.appendLongString(packetFromString.stringify());
|
||||
sendMessage(packet);
|
||||
}
|
||||
}
|
@ -87,6 +87,9 @@ public class NetworkExtensionInfo {
|
||||
public static final int CONNECTIONSTART = 5;
|
||||
public static final int CONNECTIONEND = 6;
|
||||
public static final int INIT = 7;
|
||||
|
||||
public static final int PACKETTOSTRING_RESPONSE = 20;
|
||||
public static final int STRINGTOPACKET_RESPONSE = 21;
|
||||
}
|
||||
|
||||
|
||||
@ -95,6 +98,10 @@ public class NetworkExtensionInfo {
|
||||
public static final int MANIPULATEDPACKET = 2;
|
||||
public static final int REQUESTFLAGS = 3;
|
||||
public static final int SENDMESSAGE = 4;
|
||||
|
||||
public static final int PACKETTOSTRING_REQUEST = 20;
|
||||
public static final int STRINGTOPACKET_REQUEST = 21;
|
||||
|
||||
public static final int EXTENSIONCONSOLELOG = 98;
|
||||
}
|
||||
|
||||
|
@ -6,9 +6,7 @@ import javafx.application.Platform;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonType;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 16/10/18.
|
||||
@ -16,15 +14,24 @@ import java.util.Random;
|
||||
public class Authenticator {
|
||||
|
||||
private static Map<String, String> cookies = new HashMap<>();
|
||||
private static Set<String> perma_cookies = new HashSet<>();
|
||||
|
||||
public static String generateCookieForExtension(String filename) {
|
||||
String cookie = getRandomCookie();
|
||||
cookies.put(filename, cookie);
|
||||
|
||||
return cookie;
|
||||
}
|
||||
public static String generatePermanentCookie() {
|
||||
String cookie = getRandomCookie();
|
||||
perma_cookies.add(cookie);
|
||||
return cookie;
|
||||
}
|
||||
|
||||
public static boolean evaluate(NetworkExtension extension) {
|
||||
if (extension.getCookie() != null && perma_cookies.contains(extension.getCookie())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (extension.isInstalledExtension()) {
|
||||
return claimSession(extension.getFileName(), extension.getCookie());
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package gearth.services.extensionhandler.extensions.implementations.simple;
|
||||
|
||||
import gearth.protocol.HMessage;
|
||||
import gearth.protocol.HPacket;
|
||||
import gearth.services.extensionhandler.extensions.GEarthExtension;
|
||||
|
||||
public class ExampleExtension extends GEarthExtension {
|
||||
@ -105,4 +106,18 @@ public class ExampleExtension extends GEarthExtension {
|
||||
// finish up and call "hasClosed()"
|
||||
hasClosed();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// ignore these
|
||||
@Override
|
||||
public void packetToStringResponse(String string, String expression) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stringToPacketResponse(HPacket packet) {
|
||||
|
||||
}
|
||||
}
|
||||
|
205
G-Earth/src/main/java/gearth/services/gpython/GPythonShell.java
Normal file
205
G-Earth/src/main/java/gearth/services/gpython/GPythonShell.java
Normal file
@ -0,0 +1,205 @@
|
||||
package gearth.services.gpython;
|
||||
|
||||
import gearth.Main;
|
||||
import gearth.ui.extra.ExtraController;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.Hyperlink;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.FlowPane;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class GPythonShell {
|
||||
|
||||
private final String extensionName;
|
||||
private final int port;
|
||||
private final String cookie;
|
||||
|
||||
public GPythonShell(String extensionName, int port, String cookie) {
|
||||
this.extensionName = extensionName;
|
||||
this.port = port;
|
||||
this.cookie = cookie;
|
||||
}
|
||||
|
||||
public void launch(OnQtConsoleLaunch onLaunch) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
// launch the jupyter console
|
||||
ProcessBuilder gConsoleBuilder = new ProcessBuilder("python", "-m", "jupyter", "console", "--simple-prompt");
|
||||
Process gConsole = gConsoleBuilder.start();
|
||||
|
||||
InputStreamReader in = new InputStreamReader(gConsole.getInputStream());
|
||||
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(gConsole.getOutputStream()));
|
||||
|
||||
readUntilExpectInput(in);
|
||||
|
||||
// obtain jupyter kernel name
|
||||
List<String> sysargs = enterCommandAndAwait(out, in, "import sys; sys.argv");
|
||||
String kernelName = extractKernelName(sysargs);
|
||||
|
||||
InputStream initScriptResource = getClass().getResourceAsStream("init_script.py");
|
||||
List<String> initScript = new BufferedReader(new InputStreamReader(initScriptResource,
|
||||
StandardCharsets.UTF_8)).lines().collect(Collectors.toList());
|
||||
|
||||
for (String line : initScript) {
|
||||
line = line.replace("$G_PYTHON_SHELL_TITLE$", extensionName)
|
||||
.replace("$G_EARTH_PORT$", "" + port)
|
||||
.replace("$COOKIE$", cookie);
|
||||
enterCommandAndAwait(out, in, line);
|
||||
}
|
||||
|
||||
ProcessBuilder qtConsoleBuilder = new ProcessBuilder("python", "-m", "jupyter", "qtconsole",
|
||||
"--ConsoleWidget.include_other_output", "True",
|
||||
"--ConsoleWidget.gui_completion", "'droplist'",
|
||||
// "--ConsoleWidget.other_output_prefix", "'[G-Earth]'",
|
||||
// "--JupyterWidget.in_prompt", "'>>>: '",
|
||||
// "--JupyterWidget.out_prompt", "''",
|
||||
"--KernelManager.autorestart", "False",
|
||||
"--JupyterConsoleApp.confirm_exit", "False",
|
||||
"--JupyterConsoleApp.existing", kernelName);
|
||||
Process qtConsole = qtConsoleBuilder.start();
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
qtConsole.waitFor();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
enterCommandAndAwait(out, in, "ext.stop()");
|
||||
enterCommand(out, "exit()");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}).start();
|
||||
|
||||
onLaunch.launched(false);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
showError();
|
||||
onLaunch.launched(true);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private List<String> readUntilExpectInput(InputStreamReader in) throws IOException {
|
||||
List<String> readings = new ArrayList<>();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
int c;
|
||||
while ((c = in.read()) != -1) {
|
||||
char character = (char)c;
|
||||
if (character == '\n') {
|
||||
String reading = builder.toString();
|
||||
if (reading.endsWith("\r")) {
|
||||
reading = reading.substring(0, reading.length() - 1);
|
||||
}
|
||||
if (reading.matches("Out\\[[0-9+]]: .*")) {
|
||||
reading = reading.replaceAll("^Out\\[[0-9+]]: ", "");
|
||||
if (reading.equals("")) {
|
||||
builder = new StringBuilder();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
readings.add(reading);
|
||||
builder = new StringBuilder();
|
||||
}
|
||||
else {
|
||||
builder.append(character);
|
||||
|
||||
if (builder.toString().matches("In \\[[0-9]+]: ") && !in.ready()) {
|
||||
return readings;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private void enterCommand(BufferedWriter out, String command) throws IOException {
|
||||
out.write(command);
|
||||
out.newLine();
|
||||
out.flush();
|
||||
}
|
||||
private List<String> enterCommandAndAwait(BufferedWriter out, InputStreamReader in, String command) throws IOException {
|
||||
enterCommand(out, command);
|
||||
return readUntilExpectInput(in);
|
||||
}
|
||||
|
||||
private String extractKernelName(List<String> inputArgs) {
|
||||
// null if not found
|
||||
|
||||
String joined = String.join("", inputArgs);
|
||||
String paramsFull = joined.replaceAll("^[^\\[]*\\[", "").replaceAll("][^]]*$", "");
|
||||
List<String> params = new ArrayList<>();
|
||||
|
||||
boolean backslashed = false;
|
||||
int beginParameterIndex = -1;
|
||||
for (int i = 0; i < paramsFull.length(); i++) {
|
||||
char c = paramsFull.charAt(i);
|
||||
if (c == '\'' && !backslashed) {
|
||||
if (beginParameterIndex == -1) {
|
||||
beginParameterIndex = i + 1;
|
||||
}
|
||||
else {
|
||||
params.add(paramsFull.substring(beginParameterIndex, i));
|
||||
beginParameterIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
backslashed = c == '\\' && !backslashed;
|
||||
}
|
||||
|
||||
for (int i = 0; i < params.size() - 1; i++) {
|
||||
if (params.get(i).equals("-f")) {
|
||||
return "'" + params.get(i+1) + "'";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void showError() {
|
||||
Platform.runLater(() -> {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR, "G-Python error", ButtonType.OK);
|
||||
alert.setTitle("G-Python error");
|
||||
|
||||
FlowPane fp = new FlowPane();
|
||||
Label lbl = new Label("Something went wrong launching the G-Python shell," +
|
||||
System.lineSeparator() + "are you sure you followed the installation guide correctly?" +
|
||||
System.lineSeparator() + System.lineSeparator() + "More information here:");
|
||||
Hyperlink link = new Hyperlink(ExtraController.INFO_URL_GPYTHON);
|
||||
fp.getChildren().addAll(lbl, link);
|
||||
link.setOnAction(event -> {
|
||||
Main.main.getHostServices().showDocument(link.getText());
|
||||
event.consume();
|
||||
});
|
||||
|
||||
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
|
||||
alert.getDialogPane().setContent(fp);
|
||||
alert.show();
|
||||
});
|
||||
}
|
||||
|
||||
public String getExtensionName() {
|
||||
return extensionName;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
GPythonShell shell = new GPythonShell("test", 9092, "cookie");
|
||||
shell.launch((b) -> {
|
||||
System.out.println("launched");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
package gearth.services.gpython;
|
||||
|
||||
import org.apache.maven.artifact.versioning.ComparableVersion;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GPythonVersionUtils {
|
||||
|
||||
private static final String MIN_GPYTHON_VERSION = "0.1";
|
||||
private static final String MIN_PYTHON_VERSION = "3.2";
|
||||
|
||||
// returns null if python not installed
|
||||
public static String pythonVersion() {
|
||||
List<String> commandOutput = executeCommand("python", "--version");
|
||||
if (commandOutput.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
String maybeVersion = commandOutput.get(0);
|
||||
if (!maybeVersion.contains("Python")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return maybeVersion.split(" ")[1];
|
||||
}
|
||||
|
||||
public static boolean validInstallation() {
|
||||
// validates if user has all dependencies installed
|
||||
String pythonVersion = pythonVersion();
|
||||
if (pythonVersion == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ComparableVersion version = new ComparableVersion(pythonVersion);
|
||||
if (version.compareTo(new ComparableVersion(MIN_PYTHON_VERSION)) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<String> allPackages = executeCommand("python", "-m", "pip", "list");
|
||||
allPackages = allPackages.subList(2, allPackages.size());
|
||||
|
||||
String qtconsole = getPackageVersion(allPackages, "qtconsole");
|
||||
String pyqt5 = getPackageVersion(allPackages, "pyqt5");
|
||||
String jupyterConsole = getPackageVersion(allPackages, "jupyter-console");
|
||||
String gPython = getPackageVersion(allPackages, "g-python");
|
||||
|
||||
if (qtconsole == null || pyqt5 == null || jupyterConsole == null || gPython == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ComparableVersion gVersion = new ComparableVersion(gPython);
|
||||
return gVersion.compareTo(new ComparableVersion(MIN_GPYTHON_VERSION)) >= 0;
|
||||
}
|
||||
|
||||
// null if not found
|
||||
private static String getPackageVersion(List<String> allPackages, String pkg) {
|
||||
pkg = pkg.toLowerCase();
|
||||
|
||||
for (String maybePkg : allPackages) {
|
||||
String[] split = maybePkg.split(" +");
|
||||
if (split[0].toLowerCase().equals(pkg)) {
|
||||
return split[1];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static List<String> executeCommand(String... command) {
|
||||
List<String> output = new ArrayList<>();
|
||||
|
||||
try {
|
||||
ProcessBuilder processBuilder = new ProcessBuilder(command);
|
||||
Process process = processBuilder.start();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
output.add(line);
|
||||
}
|
||||
|
||||
process.waitFor();
|
||||
|
||||
} catch (IOException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
// public static void main(String[] args) {
|
||||
// System.out.println(validInstallation());
|
||||
// }
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package gearth.services.gpython;
|
||||
|
||||
public interface OnQtConsoleLaunch {
|
||||
|
||||
void launched(boolean failed);
|
||||
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
package gearth.services.unity_tools;
|
||||
|
||||
import gearth.Main;
|
||||
import gearth.misc.Cacher;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Random;
|
||||
|
||||
public class GUnityFileServer extends HttpServlet
|
||||
{
|
||||
|
||||
public final static int FILESERVER_PORT = 9089;
|
||||
|
||||
@Override
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
try {
|
||||
response.addHeader("Access-Control-Allow-Origin", "*");
|
||||
String path = request.getPathInfo();
|
||||
|
||||
if (path.equals("/ping")) {
|
||||
response.setStatus(200);
|
||||
return;
|
||||
}
|
||||
|
||||
String url = request.getParameter("blabla");
|
||||
if (url == null || url.isEmpty()) {
|
||||
response.setStatus(404);
|
||||
return;
|
||||
}
|
||||
|
||||
response.addHeader("ETag", createETag());
|
||||
|
||||
String revision = url.split("/")[4];
|
||||
|
||||
if (path.equals("/prod")) getProd(revision, response);
|
||||
else if (path.equals("/data")) getData(revision, response);
|
||||
else if (path.equals("/wasm/code")) getWasmCode(revision, response);
|
||||
else if (path.equals("/wasm/framework")) getWasmFramework(revision, response);
|
||||
else if (path.equals("/unityloader")) getUnityLoader(revision, response);
|
||||
else if (path.equals("/version")) getVersion(revision, response, url);
|
||||
else if (path.equals("/logo")) getLogo(response);
|
||||
else {
|
||||
response.setStatus(404);
|
||||
}
|
||||
|
||||
response.setStatus(200);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
response.setStatus(500);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static String getRandomHexString(int numchars){
|
||||
Random r = new Random();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
while(sb.length() < numchars){
|
||||
sb.append(Integer.toHexString(r.nextInt()));
|
||||
}
|
||||
return sb.toString().substring(0, numchars);
|
||||
}
|
||||
|
||||
private String createETag() {
|
||||
return "W/\"" + getRandomHexString(6) + "-" + getRandomHexString(13) + "\"";
|
||||
}
|
||||
|
||||
private String getDir(String revision) {
|
||||
return Cacher.getCacheDir() + File.separator + "UNITY-" + revision + File.separator;
|
||||
}
|
||||
|
||||
|
||||
private void fileResponse(String file, HttpServletResponse response, String contentType) throws IOException {
|
||||
ServletOutputStream out = response.getOutputStream();
|
||||
InputStream in = new FileInputStream(file);
|
||||
// response.setContentType(contentType);
|
||||
|
||||
byte[] bytes = new byte[4096];
|
||||
int bytesRead;
|
||||
|
||||
while ((bytesRead = in.read(bytes)) != -1) {
|
||||
out.write(bytes, 0, bytesRead);
|
||||
}
|
||||
|
||||
in.close();
|
||||
out.close();
|
||||
}
|
||||
|
||||
|
||||
private void getProd(String revision, HttpServletResponse response) throws IOException {
|
||||
UnityWebModifyer unitywebModifyer = new UnityWebModifyer(revision, getDir(revision));
|
||||
unitywebModifyer.modifyAllFiles();
|
||||
|
||||
fileResponse(getDir(revision) + UnityWebModifyer.UNITY_PROD, response, "application/json");
|
||||
}
|
||||
|
||||
private void getData(String revision, HttpServletResponse response) throws IOException {
|
||||
// application/vnd.unity
|
||||
fileResponse(getDir(revision) + UnityWebModifyer.UNITY_DATA, response, "application/vnd.unity");
|
||||
}
|
||||
|
||||
private void getWasmCode(String revision, HttpServletResponse response) throws IOException {
|
||||
fileResponse(getDir(revision) + UnityWebModifyer.UNITY_CODE, response, "application/vnd.unity");
|
||||
}
|
||||
|
||||
private void getWasmFramework(String revision, HttpServletResponse response) throws IOException {
|
||||
fileResponse(getDir(revision) + UnityWebModifyer.UNITY_FRAMEWORK, response, "application/vnd.unity");
|
||||
}
|
||||
|
||||
private void getUnityLoader(String revision, HttpServletResponse response) throws IOException {
|
||||
UnityWebModifyer unitywebModifyer = new UnityWebModifyer(revision, getDir(revision));
|
||||
unitywebModifyer.modifyAllFiles();
|
||||
|
||||
fileResponse(getDir(revision) + UnityWebModifyer.UNITY_LOADER, response, "text/javascript");
|
||||
}
|
||||
|
||||
private void getVersion(String revision, HttpServletResponse response, String url) throws IOException {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(new URL(url).openStream()));
|
||||
|
||||
String version = in.readLine();
|
||||
String realVersion = version.split(" ")[0];
|
||||
|
||||
response.getOutputStream().print(realVersion + " - G-Earth by sirjonasxx");
|
||||
response.getOutputStream().close();
|
||||
}
|
||||
|
||||
private void getLogo(HttpServletResponse response) throws IOException {
|
||||
OutputStream out = response.getOutputStream();
|
||||
InputStream in = Main.class.getResourceAsStream("G-EarthLogo.png");
|
||||
|
||||
byte[] bytes = new byte[4096];
|
||||
int bytesRead;
|
||||
|
||||
while ((bytesRead = in.read(bytes)) != -1) {
|
||||
out.write(bytes, 0, bytesRead);
|
||||
}
|
||||
|
||||
in.close();
|
||||
out.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,176 @@
|
||||
package gearth.services.unity_tools;
|
||||
|
||||
import wasm.disassembly.InvalidOpCodeException;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class UnityWebModifyer {
|
||||
|
||||
public final static String UNITY_PROD = "habbo2020-global-prod.json";
|
||||
public final static String UNITY_DATA = "habbo2020-global-prod.data.unityweb";
|
||||
public final static String UNITY_CODE = "habbo2020-global-prod.wasm.code.unityweb";
|
||||
public final static String UNITY_FRAMEWORK = "habbo2020-global-prod.wasm.framework.unityweb";
|
||||
public final static String UNITY_LOADER = "UnityLoader.js";
|
||||
|
||||
private final static String UNITYFILES_URL = "https://images.habbo.com/habbo-webgl-clients/{revision}/WebGL/habbo2020-global-prod/Build/";
|
||||
|
||||
private final String revision;
|
||||
private final File saveFolder;
|
||||
private final String currentUrl;
|
||||
|
||||
|
||||
public UnityWebModifyer(String revision, String saveFolder) {
|
||||
this.revision = revision;
|
||||
this.currentUrl = UNITYFILES_URL.replace("{revision}", revision);
|
||||
this.saveFolder = new File(saveFolder);
|
||||
}
|
||||
|
||||
public boolean modifyAllFiles() {
|
||||
if (saveFolder.exists()) {
|
||||
return true;
|
||||
}
|
||||
saveFolder.mkdirs();
|
||||
|
||||
try {
|
||||
modifyProdFile();
|
||||
modifyDataFile();
|
||||
modifyCodeFile();
|
||||
modifyFrameworkFile();
|
||||
modifyUnityLoader();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
saveFolder.delete();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// return urls for: data, code & framework file
|
||||
private void modifyProdFile() throws IOException {
|
||||
String prodUrl = currentUrl + UNITY_PROD;
|
||||
|
||||
URLConnection connection = new URL(prodUrl).openConnection();
|
||||
InputStream is = connection.getInputStream();
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
|
||||
|
||||
FileWriter fileWriter = new FileWriter(new File(saveFolder, UNITY_PROD));
|
||||
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
|
||||
|
||||
String line;
|
||||
while ((line = in.readLine()) != null) {
|
||||
bufferedWriter.write(line);
|
||||
bufferedWriter.newLine();
|
||||
}
|
||||
|
||||
bufferedWriter.close();
|
||||
in.close();
|
||||
}
|
||||
|
||||
private void downloadToFile(URL url, File file) throws IOException {
|
||||
BufferedInputStream in = new BufferedInputStream(url.openStream());
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(file);
|
||||
byte[] dataBuffer = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
|
||||
fileOutputStream.write(dataBuffer, 0, bytesRead);
|
||||
}
|
||||
fileOutputStream.close();
|
||||
in.close();
|
||||
}
|
||||
|
||||
private void modifyDataFile() throws IOException {
|
||||
File dataFile = new File(saveFolder, UNITY_DATA);
|
||||
URL dataUrl = new URL(currentUrl + UNITY_DATA);
|
||||
downloadToFile(dataUrl, dataFile);
|
||||
}
|
||||
|
||||
private void modifyCodeFile() throws IOException, InvalidOpCodeException {
|
||||
File codeFile = new File(saveFolder, UNITY_CODE);
|
||||
URL codeUrl = new URL(currentUrl + UNITY_CODE);
|
||||
downloadToFile(codeUrl, codeFile);
|
||||
|
||||
new WasmCodePatcher(codeFile.getAbsolutePath()).patch();
|
||||
}
|
||||
|
||||
|
||||
private String insertFrameworkCode(String fileContents, int index, String codeName) throws IOException {
|
||||
BufferedReader code = new BufferedReader(new InputStreamReader(UnityWebModifyer.class.getResourceAsStream(codeName), StandardCharsets.UTF_8));
|
||||
|
||||
String firstPart = fileContents.substring(0, index);
|
||||
String lastPart = fileContents.substring(index);
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.append(firstPart);
|
||||
|
||||
stringBuilder.append("\n");
|
||||
String line;
|
||||
while ((line = code.readLine()) != null) {
|
||||
stringBuilder.append(line);
|
||||
stringBuilder.append("\n");
|
||||
}
|
||||
|
||||
stringBuilder.append(lastPart);
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
private void modifyFrameworkFile() throws IOException {
|
||||
File frameworkFile = new File(saveFolder, UNITY_FRAMEWORK);
|
||||
URL frameworkUrl = new URL(currentUrl + UNITY_FRAMEWORK);
|
||||
downloadToFile(frameworkUrl, frameworkFile);
|
||||
|
||||
|
||||
byte[] encoded = Files.readAllBytes(Paths.get(frameworkFile.getAbsolutePath()));
|
||||
String contents = new String(encoded, StandardCharsets.UTF_8);
|
||||
|
||||
contents = insertFrameworkCode(contents, 0, "js_code/unity_code.js");
|
||||
|
||||
String exportSearch = "Module.asmLibraryArg,buffer);Module[\"asm\"]=asm;";
|
||||
int exportIndex = contents.indexOf(exportSearch) + exportSearch.length();
|
||||
contents = insertFrameworkCode(contents, exportIndex, "js_code/unity_exports.js");
|
||||
|
||||
String importSearch = "if(!env[\"tableBase\"]){env[\"tableBase\"]=0}";
|
||||
int importIndex = contents.indexOf(importSearch) + importSearch.length();
|
||||
contents = insertFrameworkCode(contents, importIndex, "js_code/unity_imports.js");
|
||||
|
||||
contents = contents
|
||||
.replace("var _free", "_free")
|
||||
.replace("var _malloc", "_malloc")
|
||||
.replace("{{RevisionName}}", revision);
|
||||
|
||||
BufferedWriter writer = new BufferedWriter(new FileWriter(frameworkFile));
|
||||
writer.write(contents);
|
||||
writer.close();
|
||||
}
|
||||
|
||||
private void modifyUnityLoader() throws IOException {
|
||||
File loaderFile = new File(saveFolder, UNITY_LOADER);
|
||||
URL loaderUrl = new URL(currentUrl + UNITY_LOADER);
|
||||
downloadToFile(loaderUrl, loaderFile);
|
||||
|
||||
byte[] encoded = Files.readAllBytes(Paths.get(loaderFile.getAbsolutePath()));
|
||||
String contents = new String(encoded, StandardCharsets.UTF_8);
|
||||
|
||||
contents = contents.replace("o.result.responseHeaders[e]==a.getResponseHeader(e)", "false");
|
||||
contents = contents.replace("i.responseHeaders[e]=o.getResponseHeader(e)",
|
||||
"const genRanHex = size => [...Array(size)].map(() => Math.floor(Math.random() * 16).toString(16)).join('');\n" +
|
||||
" if (e === \"ETag\") {\n" +
|
||||
" i.responseHeaders[e] = \"W/\\\"\" + genRanHex(6) + \"-\" + genRanHex(13) + \"\\\"\"\n" +
|
||||
" }\n" +
|
||||
" else {\n" +
|
||||
" i.responseHeaders[e] = o.getResponseHeader(e)\n" +
|
||||
" }");
|
||||
|
||||
BufferedWriter writer = new BufferedWriter(new FileWriter(loaderFile));
|
||||
writer.write(contents);
|
||||
writer.close();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package gearth.services.unity_tools;
|
||||
|
||||
import gearth.services.unity_tools.codepatcher.IncomingPacketPatcher;
|
||||
import gearth.services.unity_tools.codepatcher.OutgoingPacketPatcher;
|
||||
import gearth.services.unity_tools.codepatcher.ReturnBytePatcher;
|
||||
import gearth.services.unity_tools.codepatcher.SetKeyPatcher;
|
||||
import wasm.disassembly.InvalidOpCodeException;
|
||||
import wasm.disassembly.modules.Module;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class WasmCodePatcher {
|
||||
|
||||
private String file;
|
||||
|
||||
public WasmCodePatcher(String file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public void patch() throws IOException, InvalidOpCodeException {
|
||||
Module module = new Module(file, Arrays.asList(
|
||||
new SetKeyPatcher(),
|
||||
new ReturnBytePatcher(),
|
||||
new OutgoingPacketPatcher(),
|
||||
new IncomingPacketPatcher()
|
||||
));
|
||||
module.assembleToFile(file);
|
||||
}
|
||||
}
|
@ -0,0 +1,225 @@
|
||||
//package gearth.services.unity_tools;
|
||||
//
|
||||
//import wasm.disassembly.InvalidOpCodeException;
|
||||
//import wasm.disassembly.instructions.Expression;
|
||||
//import wasm.disassembly.instructions.Instr;
|
||||
//import wasm.disassembly.instructions.InstrType;
|
||||
//import wasm.disassembly.instructions.control.CallInstr;
|
||||
//import wasm.disassembly.instructions.variable.LocalVariableInstr;
|
||||
//import wasm.disassembly.modules.Module;
|
||||
//import wasm.disassembly.modules.indices.FuncIdx;
|
||||
//import wasm.disassembly.modules.indices.LocalIdx;
|
||||
//import wasm.disassembly.modules.indices.TypeIdx;
|
||||
//import wasm.disassembly.modules.sections.code.Func;
|
||||
//import wasm.disassembly.modules.sections.export.Export;
|
||||
//import wasm.disassembly.modules.sections.export.ExportDesc;
|
||||
//import wasm.disassembly.modules.sections.imprt.Import;
|
||||
//import wasm.disassembly.modules.sections.imprt.ImportDesc;
|
||||
//import wasm.disassembly.types.FuncType;
|
||||
//import wasm.disassembly.types.ResultType;
|
||||
//import wasm.disassembly.types.ValType;
|
||||
//import wasm.misc.Function;
|
||||
//
|
||||
//import java.io.*;
|
||||
//import java.util.*;
|
||||
//
|
||||
//public class WasmCodePatcherOld {
|
||||
//
|
||||
// private String file;
|
||||
//
|
||||
// public WasmCodePatcherOld(String file) {
|
||||
// this.file = file;
|
||||
// }
|
||||
//
|
||||
// public void patch() throws IOException, InvalidOpCodeException {
|
||||
// Module module = new Module(file);
|
||||
//
|
||||
// FuncIdx returnByteId = findReturnByteFunc(module);
|
||||
// FuncIdx setkey = findSetKeyFunc(module);
|
||||
// FuncIdx outgoingIdx = findOutFunc(module);
|
||||
// FuncIdx incomingIdx = findInFunc(module);
|
||||
//
|
||||
// hook(module, setkey, "g_chacha_setkey");
|
||||
// copyEmptyHook(module, returnByteId, "_gearth_returnbyte_copy", "g_chacha_returnbyte");
|
||||
// copyEmptyHook(module, outgoingIdx, "_gearth_outgoing_copy", "g_outgoing_packet");
|
||||
// copyEmptyHook(module, incomingIdx, "_gearth_incoming_copy", "g_incoming_packet");
|
||||
//
|
||||
// module.assembleToFile(file);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// private FuncIdx findOutFunc(Module module) {
|
||||
// TypeIdx expectedTypeIdx = module.getTypeSection().getTypeIdxForFuncType(new FuncType(
|
||||
// new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32)),
|
||||
// new ResultType(Collections.emptyList())
|
||||
// ));
|
||||
//
|
||||
// outerloop:
|
||||
// for (int i = 0; i < module.getCodeSection().getCodesEntries().size(); i++) {
|
||||
// FuncIdx currentIdx = new FuncIdx(i + module.getImportSection().getTotalFuncImports(), module);
|
||||
//
|
||||
// Func func = module.getCodeSection().getByIdx(currentIdx);
|
||||
// if (func.getLocalss().size() != 0) continue;
|
||||
// if (!module.getFunctionSection().getByIdx(currentIdx).equals(expectedTypeIdx)) continue;
|
||||
//
|
||||
// List<Instr> expression = func.getExpression().getInstructions();
|
||||
//
|
||||
// if (expression.size() != 6) continue;
|
||||
//
|
||||
// if (expression.get(0).getInstrType() != InstrType.LOCAL_GET) continue;
|
||||
// if (expression.get(1).getInstrType() != InstrType.LOCAL_GET) continue;
|
||||
// if (expression.get(2).getInstrType() != InstrType.LOCAL_GET) continue;
|
||||
// if (expression.get(3).getInstrType() != InstrType.I32_LOAD) continue;
|
||||
// if (expression.get(4).getInstrType() != InstrType.I32_CONST) continue;
|
||||
// if (expression.get(5).getInstrType() != InstrType.CALL) continue;
|
||||
//
|
||||
// return currentIdx;
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
// private FuncIdx findSetKeyFunc(Module module) {
|
||||
// FuncType expectedType = new FuncType(
|
||||
// new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32, ValType.I32)),
|
||||
// new ResultType(Collections.emptyList())
|
||||
// );
|
||||
//
|
||||
// List<InstrType> expectedExpr = Arrays.asList(InstrType.I32_CONST, InstrType.I32_LOAD8_S,
|
||||
// InstrType.I32_EQZ, InstrType.IF, InstrType.BLOCK, InstrType.LOCAL_GET, InstrType.I32_CONST,
|
||||
// InstrType.LOCAL_GET, InstrType.I32_LOAD, InstrType.I32_CONST, InstrType.I32_CONST, InstrType.I32_CONST,
|
||||
// InstrType.CALL);
|
||||
//
|
||||
// outerloop:
|
||||
// for (int i = 0; i < module.getCodeSection().getCodesEntries().size(); i++) {
|
||||
// FuncIdx funcIdx = new FuncIdx(i + module.getImportSection().getTotalFuncImports(), module);
|
||||
//
|
||||
// Function function = new Function(module, funcIdx);
|
||||
// if (!function.getFuncType().equals(expectedType)) continue;
|
||||
// if (!(function.getLocalsFloored().size() == 1 && function.getLocalsFloored().get(0) == ValType.I32)) continue;
|
||||
// if (function.getCode().getInstructions().size() != expectedExpr.size()) continue;
|
||||
//
|
||||
// for (int j = 0; j < function.getCode().getInstructions().size(); j++) {
|
||||
// Instr instr = function.getCode().getInstructions().get(j);
|
||||
// if (instr.getInstrType() != expectedExpr.get(j)) continue outerloop;
|
||||
// }
|
||||
//
|
||||
// return funcIdx;
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
// private FuncIdx findReturnByteFunc(Module module) {
|
||||
// FuncType expectedType = new FuncType(
|
||||
// new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32)),
|
||||
// new ResultType(Collections.singletonList(ValType.I32))
|
||||
// );
|
||||
//
|
||||
// outerloop:
|
||||
// for (int i = 0; i < module.getCodeSection().getCodesEntries().size(); i++) {
|
||||
// FuncIdx funcIdx = new FuncIdx(i + module.getImportSection().getTotalFuncImports(), module);
|
||||
//
|
||||
// Function function = new Function(module, funcIdx);
|
||||
// if (!function.getFuncType().equals(expectedType)) continue;
|
||||
// if (function.getLocalsFloored().size() != 0) continue;
|
||||
// if (function.getCode().getInstructions().size() != 30) continue;
|
||||
//
|
||||
// List<Instr> expr = function.getCode().getInstructions();
|
||||
// if (expr.get(expr.size() - 1).getInstrType() != InstrType.I32_XOR) continue;
|
||||
//
|
||||
// return funcIdx;
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
// private FuncIdx findInFunc(Module module) {
|
||||
// FuncType expectedType = new FuncType(
|
||||
// new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32, ValType.I32, ValType.I32)),
|
||||
// new ResultType(Collections.emptyList())
|
||||
// );
|
||||
//
|
||||
// List<InstrType> expectedExpr = Arrays.asList(InstrType.I32_CONST, InstrType.I32_LOAD8_S,
|
||||
// InstrType.I32_EQZ, InstrType.IF, InstrType.LOCAL_GET, InstrType.I32_LOAD, InstrType.LOCAL_TEE,
|
||||
// InstrType.IF);
|
||||
//
|
||||
// outerloop:
|
||||
// for (int i = 0; i < module.getCodeSection().getCodesEntries().size(); i++) {
|
||||
// FuncIdx funcIdx = new FuncIdx(i + module.getImportSection().getTotalFuncImports(), module);
|
||||
//
|
||||
// Function function = new Function(module, funcIdx);
|
||||
// if (!function.getFuncType().equals(expectedType)) continue;
|
||||
// if (!(function.getLocalsFloored().size() == 1 && function.getLocalsFloored().get(0) == ValType.I32)) continue;
|
||||
// if (function.getCode().getInstructions().size() != expectedExpr.size()) continue;
|
||||
//
|
||||
// for (int j = 0; j < function.getCode().getInstructions().size(); j++) {
|
||||
// Instr instr = function.getCode().getInstructions().get(j);
|
||||
// if (instr.getInstrType() != expectedExpr.get(j)) continue outerloop;
|
||||
// }
|
||||
//
|
||||
// return funcIdx;
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// private void copyEmptyHook(Module module, FuncIdx orgFuncIdx, String exportName, String hookname) throws InvalidOpCodeException, IOException {
|
||||
// // copies the method, empties the first one
|
||||
// // export the copy
|
||||
// // hooks to the emptied one
|
||||
//
|
||||
// Func func = module.getCodeSection().getByIdx(orgFuncIdx);
|
||||
// FuncType funcType = module.getTypeSection().getByFuncIdx(orgFuncIdx);
|
||||
//
|
||||
// // copy the function
|
||||
// Function copy = new Function(funcType, func.getLocalss(), func.getExpression());
|
||||
// FuncIdx copyIdx = copy.addToModule(module);
|
||||
//
|
||||
// module.getExportSection().getExports().add(new Export(exportName, new ExportDesc(copyIdx)));
|
||||
//
|
||||
//
|
||||
// // clear & hook original function, let it return whatever JS returns
|
||||
// Import imp = new Import(
|
||||
// "env",
|
||||
// hookname,
|
||||
// new ImportDesc(module.getTypeSection().getTypeIdxForFuncType(new FuncType(
|
||||
// funcType.getParameterType(),
|
||||
// funcType.getResultType()
|
||||
// )))
|
||||
// );
|
||||
// FuncIdx hookIdx = module.getImportSection().importFunction(imp);
|
||||
//
|
||||
// CallInstr call = new CallInstr(hookIdx);
|
||||
// List<Instr> newInstrs = new ArrayList<>();
|
||||
// for (int i = 0; i < funcType.getParameterType().typeList().size(); i++) {
|
||||
// newInstrs.add(new LocalVariableInstr(InstrType.LOCAL_GET, new LocalIdx(i)));
|
||||
// }
|
||||
// newInstrs.add(call);
|
||||
// func.setExpression(new Expression(newInstrs));
|
||||
//
|
||||
// }
|
||||
//
|
||||
// private void hook(Module module, FuncIdx funcIdx, String jsFunctionName) throws InvalidOpCodeException, IOException {
|
||||
// FuncType funcType = module.getTypeSection().getByFuncIdx(funcIdx);
|
||||
//
|
||||
// Import imp = new Import(
|
||||
// "env",
|
||||
// jsFunctionName,
|
||||
// new ImportDesc(module.getTypeSection().getTypeIdxForFuncType(new FuncType(
|
||||
// funcType.getParameterType(),
|
||||
// new ResultType(Collections.emptyList())
|
||||
// )))
|
||||
// );
|
||||
// FuncIdx hookIdx = module.getImportSection().importFunction(imp);
|
||||
//
|
||||
// CallInstr call = new CallInstr(hookIdx);
|
||||
//
|
||||
// Func root = module.getCodeSection().getByIdx(funcIdx);
|
||||
// List<Instr> newInstrs = new ArrayList<>();
|
||||
// for (int i = 0; i < funcType.getParameterType().typeList().size(); i++) {
|
||||
// newInstrs.add(new LocalVariableInstr(InstrType.LOCAL_GET, new LocalIdx(i)));
|
||||
// }
|
||||
// newInstrs.add(call);
|
||||
// newInstrs.addAll(root.getExpression().getInstructions());
|
||||
// root.getExpression().setInstructions(newInstrs);
|
||||
// }
|
||||
//
|
||||
//}
|
@ -0,0 +1,60 @@
|
||||
package gearth.services.unity_tools.codepatcher;
|
||||
|
||||
import wasm.disassembly.instructions.Instr;
|
||||
import wasm.disassembly.instructions.InstrType;
|
||||
import wasm.disassembly.modules.sections.code.Func;
|
||||
import wasm.disassembly.modules.sections.code.Locals;
|
||||
import wasm.disassembly.types.FuncType;
|
||||
import wasm.disassembly.types.ResultType;
|
||||
import wasm.disassembly.types.ValType;
|
||||
import wasm.misc.CodeCompare;
|
||||
import wasm.misc.StreamReplacement;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class IncomingPacketPatcher implements StreamReplacement {
|
||||
@Override
|
||||
public FuncType getFuncType() {
|
||||
return new FuncType(new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32, ValType.I32, ValType.I32)),
|
||||
new ResultType(Collections.emptyList())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplacementType getReplacementType() {
|
||||
return ReplacementType.HOOKCOPYEXPORT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImportName() {
|
||||
return "g_incoming_packet";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportName() {
|
||||
return "_gearth_incoming_copy";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeCompare getCodeCompare() {
|
||||
return code -> {
|
||||
if (!(code.getLocalss().equals(Collections.singletonList(new Locals(1, ValType.I32)))))
|
||||
return false;
|
||||
|
||||
List<InstrType> expectedExpr = Arrays.asList(InstrType.I32_CONST, InstrType.I32_LOAD8_S,
|
||||
InstrType.I32_EQZ, InstrType.IF, InstrType.LOCAL_GET, InstrType.I32_LOAD, InstrType.LOCAL_TEE,
|
||||
InstrType.IF);
|
||||
|
||||
if (code.getExpression().getInstructions().size() != expectedExpr.size()) return false;
|
||||
|
||||
for (int j = 0; j < code.getExpression().getInstructions().size(); j++) {
|
||||
Instr instr = code.getExpression().getInstructions().get(j);
|
||||
if (instr.getInstrType() != expectedExpr.get(j)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package gearth.services.unity_tools.codepatcher;
|
||||
|
||||
import wasm.disassembly.instructions.Instr;
|
||||
import wasm.disassembly.instructions.InstrType;
|
||||
import wasm.disassembly.modules.sections.code.Func;
|
||||
import wasm.disassembly.types.FuncType;
|
||||
import wasm.disassembly.types.ResultType;
|
||||
import wasm.disassembly.types.ValType;
|
||||
import wasm.misc.CodeCompare;
|
||||
import wasm.misc.StreamReplacement;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class OutgoingPacketPatcher implements StreamReplacement {
|
||||
@Override
|
||||
public FuncType getFuncType() {
|
||||
return new FuncType(new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32)),
|
||||
new ResultType(Collections.emptyList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplacementType getReplacementType() {
|
||||
return ReplacementType.HOOKCOPYEXPORT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImportName() {
|
||||
return "g_outgoing_packet";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportName() {
|
||||
return "_gearth_outgoing_copy";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeCompare getCodeCompare() {
|
||||
return code -> {
|
||||
if (code.getLocalss().size() != 0) return false;
|
||||
List<Instr> expression = code.getExpression().getInstructions();
|
||||
if (expression.get(0).getInstrType() != InstrType.LOCAL_GET) return false;
|
||||
if (expression.get(1).getInstrType() != InstrType.LOCAL_GET) return false;
|
||||
if (expression.get(2).getInstrType() != InstrType.LOCAL_GET) return false;
|
||||
if (expression.get(3).getInstrType() != InstrType.I32_LOAD) return false;
|
||||
if (expression.get(4).getInstrType() != InstrType.I32_CONST) return false;
|
||||
if (expression.get(5).getInstrType() != InstrType.CALL) return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package gearth.services.unity_tools.codepatcher;
|
||||
|
||||
import wasm.disassembly.instructions.Instr;
|
||||
import wasm.disassembly.instructions.InstrType;
|
||||
import wasm.disassembly.modules.sections.code.Func;
|
||||
import wasm.disassembly.types.FuncType;
|
||||
import wasm.disassembly.types.ResultType;
|
||||
import wasm.disassembly.types.ValType;
|
||||
import wasm.misc.CodeCompare;
|
||||
import wasm.misc.StreamReplacement;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ReturnBytePatcher implements StreamReplacement {
|
||||
@Override
|
||||
public FuncType getFuncType() {
|
||||
return new FuncType(new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32)),
|
||||
new ResultType(Collections.singletonList(ValType.I32)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplacementType getReplacementType() {
|
||||
return ReplacementType.HOOKCOPYEXPORT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImportName() {
|
||||
return "g_chacha_returnbyte";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportName() {
|
||||
return "_gearth_returnbyte_copy";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeCompare getCodeCompare() {
|
||||
return code -> {
|
||||
if (code.getLocalss().size() != 0) return false;
|
||||
if (code.getExpression().getInstructions().size() != 30) return false;
|
||||
List<Instr> expr = code.getExpression().getInstructions();
|
||||
if (expr.get(expr.size() - 1).getInstrType() != InstrType.I32_XOR) return false;
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package gearth.services.unity_tools.codepatcher;
|
||||
|
||||
import wasm.disassembly.instructions.Instr;
|
||||
import wasm.disassembly.instructions.InstrType;
|
||||
import wasm.disassembly.modules.sections.code.Func;
|
||||
import wasm.disassembly.modules.sections.code.Locals;
|
||||
import wasm.disassembly.types.FuncType;
|
||||
import wasm.disassembly.types.ResultType;
|
||||
import wasm.disassembly.types.ValType;
|
||||
import wasm.misc.CodeCompare;
|
||||
import wasm.misc.StreamReplacement;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class SetKeyPatcher implements StreamReplacement {
|
||||
|
||||
@Override
|
||||
public FuncType getFuncType() {
|
||||
return new FuncType(new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32, ValType.I32)),
|
||||
new ResultType(Collections.emptyList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplacementType getReplacementType() {
|
||||
return ReplacementType.HOOK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImportName() {
|
||||
return "g_chacha_setkey";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeCompare getCodeCompare() {
|
||||
return code -> {
|
||||
if (!(code.getLocalss().equals(Collections.singletonList(new Locals(1, ValType.I32)))))
|
||||
return false;
|
||||
List<InstrType> expectedExpr = Arrays.asList(InstrType.I32_CONST, InstrType.I32_LOAD8_S,
|
||||
InstrType.I32_EQZ, InstrType.IF, InstrType.BLOCK, InstrType.LOCAL_GET, InstrType.I32_CONST,
|
||||
InstrType.LOCAL_GET, InstrType.I32_LOAD, InstrType.I32_CONST, InstrType.I32_CONST, InstrType.I32_CONST,
|
||||
InstrType.CALL);
|
||||
|
||||
if (code.getExpression().getInstructions().size() != expectedExpr.size()) return false;
|
||||
|
||||
for (int j = 0; j < code.getExpression().getInstructions().size(); j++) {
|
||||
Instr instr = code.getExpression().getInstructions().get(j);
|
||||
if (instr.getInstrType() != expectedExpr.get(j)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
package gearth.ui;
|
||||
|
||||
import gearth.ui.logger.loggerdisplays.PacketLoggerFactory;
|
||||
import javafx.event.Event;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.layout.Pane;
|
||||
@ -44,52 +46,35 @@ public class GEarthController {
|
||||
|
||||
public void initialize() {
|
||||
tabs = new ArrayList<>();
|
||||
// must be ordered correctly
|
||||
tabs.add(connectionController);
|
||||
tabs.add(injectionController);
|
||||
tabs.add(loggerController);
|
||||
tabs.add(toolsController);
|
||||
tabs.add(schedulerController);
|
||||
tabs.add(extensionsController);
|
||||
tabs.add(extraController);
|
||||
tabs.add(infoController);
|
||||
tabs.add(extensionsController);
|
||||
|
||||
synchronized (this) {
|
||||
trySetController();
|
||||
}
|
||||
|
||||
List<Tab> uiTabs = tabBar.getTabs();
|
||||
for (int i = 0; i < uiTabs.size(); i++) {
|
||||
Tab tab = uiTabs.get(i);
|
||||
int[] ii = {i};
|
||||
|
||||
tab.setOnSelectionChanged(event -> {
|
||||
if (tab.isSelected()) {
|
||||
tabs.get(ii[0]).onTabOpened();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (PacketLoggerFactory.usesUIlogger()) {
|
||||
tabBar.getTabs().remove(tab_Logger);
|
||||
}
|
||||
|
||||
//custom header bar
|
||||
// final Point[] startpos = {null};
|
||||
// final Double[] xx = {0.0};
|
||||
// final Double[] yy = {0.0};
|
||||
// final Boolean[] isMoving = {false};
|
||||
//
|
||||
// mover.addEventHandler(MouseEvent.MOUSE_PRESSED,
|
||||
// event -> {
|
||||
// startpos[0] = MouseInfo.getPointerInfo().getLocation();
|
||||
// xx[0] = stage.getX();
|
||||
// yy[0] = stage.getY();
|
||||
// isMoving[0] = true;
|
||||
// });
|
||||
//
|
||||
// mover.addEventHandler(MouseEvent.MOUSE_RELEASED,
|
||||
// event -> {
|
||||
// isMoving[0] = false;
|
||||
// });
|
||||
//
|
||||
//
|
||||
// mover.setOnMouseDragged(event -> {
|
||||
// if (isMoving[0]) {
|
||||
// Point now = MouseInfo.getPointerInfo().getLocation();
|
||||
// double diffX = now.getX() - startpos[0].getX();
|
||||
// double diffY = now.getY() - startpos[0].getY();
|
||||
// stage.setX(xx[0] + diffX);
|
||||
// stage.setY(yy[0] + diffY);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
public void setStage(Stage stage) {
|
||||
@ -122,5 +107,4 @@ public class GEarthController {
|
||||
tabs.forEach(SubForm::exit);
|
||||
hConnection.abort();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,6 +28,10 @@ public class SubForm {
|
||||
|
||||
}
|
||||
|
||||
protected void onTabOpened() {
|
||||
|
||||
}
|
||||
|
||||
protected HConnection getHConnection() {
|
||||
return parentController.getHConnection();
|
||||
}
|
||||
|
@ -18,8 +18,8 @@ public class BoxButton extends StackPane {
|
||||
|
||||
//paths zijn relatief aan deze classpath
|
||||
public BoxButton(String imageName, String imageOnHoverName) {
|
||||
this.image = new Image(getClass().getResourceAsStream("/gearth/ui/buttons/files/" + imageName));
|
||||
this.imageOnHover = new Image(getClass().getResourceAsStream("/gearth/ui/buttons/files/" + imageOnHoverName));
|
||||
this.image = new Image(getClass().getResourceAsStream("files/" + imageName));
|
||||
this.imageOnHover = new Image(getClass().getResourceAsStream("files/" + imageOnHoverName));
|
||||
this.imageView = new ImageView();
|
||||
|
||||
setCursor(Cursor.DEFAULT);
|
||||
|
@ -33,10 +33,10 @@ public class PauseResumeButton extends StackPane{
|
||||
public PauseResumeButton(boolean isPaused) {
|
||||
this.isPaused[0] = isPaused;
|
||||
|
||||
this.imagePause = new Image(getClass().getResourceAsStream("/gearth/ui/buttons/files/ButtonPause.png"));
|
||||
this.imagePauseOnHover = new Image(getClass().getResourceAsStream("/gearth/ui/buttons/files/ButtonPauseHover.png"));
|
||||
this.imageResume = new Image(getClass().getResourceAsStream("/gearth/ui/buttons/files/ButtonResume.png"));
|
||||
this.imageResumeOnHover = new Image(getClass().getResourceAsStream("/gearth/ui/buttons/files/ButtonResumeHover.png"));
|
||||
this.imagePause = new Image(getClass().getResourceAsStream("files/ButtonPause.png"));
|
||||
this.imagePauseOnHover = new Image(getClass().getResourceAsStream("files/ButtonPauseHover.png"));
|
||||
this.imageResume = new Image(getClass().getResourceAsStream("files/ButtonResume.png"));
|
||||
this.imageResumeOnHover = new Image(getClass().getResourceAsStream("files/ButtonResumeHover.png"));
|
||||
this.imageView = new ImageView();
|
||||
|
||||
setCursor(Cursor.DEFAULT);
|
||||
|
@ -98,7 +98,9 @@ public class ConnectionController extends SubForm {
|
||||
txtfield_hotelversion.setText(getHConnection().getHotelVersion());
|
||||
|
||||
btnConnect.setDisable(getHConnection().getState() == HState.PREPARING || getHConnection().getState() == HState.ABORTING);
|
||||
if (!cbx_autodetect.isSelected() && !btnConnect.isDisable()) {
|
||||
|
||||
|
||||
if (!cbx_autodetect.isSelected() && !btnConnect.isDisable() && useFlash()) {
|
||||
try {
|
||||
int i = Integer.parseInt(inpPort.getEditor().getText());
|
||||
btnConnect.setDisable(i < 0 || i >= 256 * 256);
|
||||
@ -110,6 +112,13 @@ public class ConnectionController extends SubForm {
|
||||
|
||||
inpHost.setDisable(getHConnection().getState() != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
|
||||
inpPort.setDisable(getHConnection().getState() != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
|
||||
|
||||
cbx_autodetect.setDisable(!useFlash());
|
||||
outHost.setDisable(!useFlash());
|
||||
outPort.setDisable(!useFlash());
|
||||
|
||||
inpHost.setDisable(!useFlash() || getHConnection().getState() != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
|
||||
inpPort.setDisable(!useFlash() || getHConnection().getState() != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
|
||||
}
|
||||
|
||||
public void onParentSet(){
|
||||
@ -134,14 +143,15 @@ public class ConnectionController extends SubForm {
|
||||
|
||||
if (newState == HState.CONNECTED) {
|
||||
lblState.setText("Connected");
|
||||
outHost.setText(getHConnection().getDomain());
|
||||
outPort.setText(getHConnection().getServerPort()+"");
|
||||
}
|
||||
if (newState == HState.WAITING_FOR_CLIENT) {
|
||||
lblState.setText("Waiting for connection");
|
||||
}
|
||||
|
||||
if (newState == HState.CONNECTED) {
|
||||
if (newState == HState.CONNECTED && useFlash()) {
|
||||
outHost.setText(getHConnection().getDomain());
|
||||
outPort.setText(getHConnection().getServerPort()+"");
|
||||
|
||||
JSONObject connectionSettings = new JSONObject();
|
||||
connectionSettings.put(AUTODETECT_CACHE, cbx_autodetect.isSelected());
|
||||
connectionSettings.put(HOST_CACHE, inpHost.getEditor().getText());
|
||||
@ -158,12 +168,19 @@ public class ConnectionController extends SubForm {
|
||||
|
||||
btnConnect.setDisable(true);
|
||||
new Thread(() -> {
|
||||
if (cbx_autodetect.isSelected()) {
|
||||
getHConnection().start();
|
||||
if (useFlash()) {
|
||||
if (cbx_autodetect.isSelected()) {
|
||||
getHConnection().start();
|
||||
}
|
||||
else {
|
||||
getHConnection().start(inpHost.getEditor().getText(), Integer.parseInt(inpPort.getEditor().getText()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
getHConnection().start(inpHost.getEditor().getText(), Integer.parseInt(inpPort.getEditor().getText()));
|
||||
getHConnection().startUnity();
|
||||
}
|
||||
|
||||
|
||||
if (HConnection.DEBUG) System.out.println("connecting");
|
||||
}).start();
|
||||
|
||||
@ -179,4 +196,11 @@ public class ConnectionController extends SubForm {
|
||||
getHConnection().abort();
|
||||
}
|
||||
|
||||
public void changeClientMode() {
|
||||
updateInputUI();
|
||||
}
|
||||
|
||||
private boolean useFlash() {
|
||||
return parentController.extraController.rd_flash.isSelected();
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,31 @@
|
||||
package gearth.ui.extensions;
|
||||
|
||||
import gearth.Main;
|
||||
import gearth.services.extensionhandler.ExtensionConnectedListener;
|
||||
import gearth.services.extensionhandler.ExtensionHandler;
|
||||
import gearth.services.extensionhandler.extensions.ExtensionListener;
|
||||
import gearth.services.extensionhandler.extensions.GEarthExtension;
|
||||
import gearth.services.extensionhandler.extensions.implementations.network.NetworkExtensionsProducer;
|
||||
import gearth.services.extensionhandler.extensions.implementations.network.authentication.Authenticator;
|
||||
import gearth.services.extensionhandler.extensions.implementations.network.executer.ExecutionInfo;
|
||||
import gearth.services.extensionhandler.extensions.implementations.network.executer.ExtensionRunner;
|
||||
import gearth.services.extensionhandler.extensions.implementations.network.executer.ExtensionRunnerFactory;
|
||||
import gearth.services.gpython.GPythonShell;
|
||||
import gearth.services.gpython.OnQtConsoleLaunch;
|
||||
import gearth.ui.SubForm;
|
||||
import gearth.ui.extensions.logger.ExtensionLogger;
|
||||
import gearth.ui.extra.ExtraController;
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.FlowPane;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.FileChooser;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 06/04/18.
|
||||
@ -29,12 +35,12 @@ public class ExtensionsController extends SubForm {
|
||||
|
||||
|
||||
public Button btn_install;
|
||||
public Button btn_remove;
|
||||
public TextField ext_port;
|
||||
public VBox extensioncontainer;
|
||||
public GridPane header_ext;
|
||||
public ScrollPane scroller;
|
||||
public Button btn_viewExtensionConsole;
|
||||
public Button btn_gpython;
|
||||
|
||||
private ExtensionRunner extensionRunner = null;
|
||||
private ExtensionHandler extensionHandler;
|
||||
@ -98,6 +104,33 @@ public class ExtensionsController extends SubForm {
|
||||
else {
|
||||
extensionLogger.hide();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTabOpened() {
|
||||
updateGPythonStatus();
|
||||
}
|
||||
|
||||
public void updateGPythonStatus() {
|
||||
if (!pythonShellLaunching) {
|
||||
btn_gpython.setDisable(!parentController.extraController.useGPython());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private volatile int gpytonShellCounter = 1;
|
||||
private volatile boolean pythonShellLaunching = false;
|
||||
public void gpythonBtnClicked(ActionEvent actionEvent) {
|
||||
pythonShellLaunching = true;
|
||||
Platform.runLater(() -> btn_gpython.setDisable(true));
|
||||
GPythonShell shell = new GPythonShell(
|
||||
"Scripting shell " + gpytonShellCounter++,
|
||||
networkExtensionsProducer.getPort(),
|
||||
Authenticator.generatePermanentCookie()
|
||||
);
|
||||
shell.launch((b) -> {
|
||||
pythonShellLaunching = false;
|
||||
Platform.runLater(this::updateGPythonStatus);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,22 @@
|
||||
package gearth.ui.extra;
|
||||
|
||||
import gearth.Main;
|
||||
import gearth.misc.Cacher;
|
||||
import gearth.misc.packetrepresentation.prediction.checkers.TypeCheckerProducer;
|
||||
import gearth.protocol.HConnection;
|
||||
import gearth.protocol.connection.HState;
|
||||
import gearth.protocol.connection.proxy.ProxyProviderFactory;
|
||||
import gearth.protocol.connection.proxy.SocksConfiguration;
|
||||
import gearth.services.Constants;
|
||||
import gearth.services.gpython.GPythonVersionUtils;
|
||||
import gearth.ui.SubForm;
|
||||
import gearth.ui.info.InfoController;
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.FlowPane;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Region;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
@ -16,12 +24,17 @@ import org.json.JSONObject;
|
||||
*/
|
||||
public class ExtraController extends SubForm implements SocksConfiguration {
|
||||
|
||||
public static final String INFO_URL_GPYTHON = "https://github.com/sirjonasxx/G-Earth/wiki/G-Python-qtConsole";
|
||||
|
||||
public static final String NOTEPAD_CACHE_KEY = "notepad_text";
|
||||
public static final String SOCKS_CACHE_KEY = "socks_config";
|
||||
public static final String GPYTHON_CACHE_KEY = "use_gpython";
|
||||
|
||||
public static final String USE_UNITY_CLIENT_CACHE_KEY = "use_unity";
|
||||
|
||||
public static final String SOCKS_IP = "ip";
|
||||
public static final String SOCKS_PORT = "port";
|
||||
public static final String IGNORE_ONCE = "ignore_once";
|
||||
// public static final String IGNORE_ONCE = "ignore_once";
|
||||
|
||||
|
||||
public TextArea txtarea_notepad;
|
||||
@ -29,20 +42,32 @@ public class ExtraController extends SubForm implements SocksConfiguration {
|
||||
public CheckBox cbx_alwaysOnTop;
|
||||
public Hyperlink url_troubleshooting;
|
||||
|
||||
//TODO add setup link to g-earth wiki
|
||||
public CheckBox cbx_gpython;
|
||||
|
||||
public CheckBox cbx_advanced;
|
||||
public GridPane grd_advanced;
|
||||
|
||||
public CheckBox cbx_disableDecryption;
|
||||
public CheckBox cbx_debug;
|
||||
|
||||
|
||||
public CheckBox cbx_useSocks;
|
||||
public GridPane grd_socksInfo;
|
||||
public TextField txt_socksPort;
|
||||
public TextField txt_socksIp;
|
||||
public CheckBox cbx_socksUseIfNeeded;
|
||||
|
||||
|
||||
public ToggleGroup tgl_clientMode;
|
||||
public RadioButton rd_unity;
|
||||
public RadioButton rd_flash;
|
||||
public GridPane grd_clientSelection;
|
||||
|
||||
public void initialize() {
|
||||
Constants.UNITY_PACKETS = rd_unity.isSelected();
|
||||
tgl_clientMode.selectedToggleProperty().addListener(observable -> {
|
||||
if (parentController != null) parentController.connectionController.changeClientMode();
|
||||
Constants.UNITY_PACKETS = rd_unity.isSelected();
|
||||
});
|
||||
|
||||
url_troubleshooting.setTooltip(new Tooltip("https://github.com/sirjonasxx/G-Earth/wiki/Troubleshooting"));
|
||||
InfoController.activateHyperlink(url_troubleshooting);
|
||||
@ -56,7 +81,16 @@ public class ExtraController extends SubForm implements SocksConfiguration {
|
||||
JSONObject socksInitValue = Cacher.getCacheContents().getJSONObject(SOCKS_CACHE_KEY);
|
||||
txt_socksIp.setText(socksInitValue.getString(SOCKS_IP));
|
||||
txt_socksPort.setText(socksInitValue.getString(SOCKS_PORT));
|
||||
cbx_socksUseIfNeeded.setSelected(socksInitValue.getBoolean(IGNORE_ONCE));
|
||||
// cbx_socksUseIfNeeded.setSelected(socksInitValue.getBoolean(IGNORE_ONCE));
|
||||
}
|
||||
|
||||
if (Cacher.getCacheContents().has(GPYTHON_CACHE_KEY)) {
|
||||
cbx_gpython.setSelected(Cacher.getCacheContents().getBoolean(GPYTHON_CACHE_KEY));
|
||||
}
|
||||
|
||||
if (Cacher.getCacheContents().has(USE_UNITY_CLIENT_CACHE_KEY)) {
|
||||
rd_unity.setSelected(Cacher.getCacheContents().getBoolean(USE_UNITY_CLIENT_CACHE_KEY));
|
||||
rd_flash.setSelected(!Cacher.getCacheContents().getBoolean(USE_UNITY_CLIENT_CACHE_KEY));
|
||||
}
|
||||
|
||||
cbx_debug.selectedProperty().addListener(observable -> HConnection.DEBUG = cbx_debug.isSelected());
|
||||
@ -85,6 +119,8 @@ public class ExtraController extends SubForm implements SocksConfiguration {
|
||||
@Override
|
||||
protected void onExit() {
|
||||
Cacher.put(NOTEPAD_CACHE_KEY, txtarea_notepad.getText());
|
||||
Cacher.put(GPYTHON_CACHE_KEY, cbx_gpython.isSelected());
|
||||
Cacher.put(USE_UNITY_CLIENT_CACHE_KEY, rd_unity.isSelected());
|
||||
saveSocksConfig();
|
||||
}
|
||||
|
||||
@ -92,11 +128,13 @@ public class ExtraController extends SubForm implements SocksConfiguration {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put(SOCKS_IP, txt_socksIp.getText());
|
||||
jsonObject.put(SOCKS_PORT, txt_socksPort.getText());
|
||||
jsonObject.put(IGNORE_ONCE, cbx_socksUseIfNeeded.isSelected());
|
||||
// jsonObject.put(IGNORE_ONCE, cbx_socksUseIfNeeded.isSelected());
|
||||
Cacher.put(SOCKS_CACHE_KEY, jsonObject);
|
||||
}
|
||||
|
||||
private void updateAdvancedUI() {
|
||||
grd_clientSelection.setDisable(getHConnection().getState() != HState.NOT_CONNECTED);
|
||||
|
||||
if (!cbx_advanced.isSelected()) {
|
||||
cbx_debug.setSelected(false);
|
||||
cbx_useSocks.setSelected(false);
|
||||
@ -127,6 +165,54 @@ public class ExtraController extends SubForm implements SocksConfiguration {
|
||||
|
||||
@Override
|
||||
public boolean onlyUseIfNeeded() {
|
||||
return cbx_socksUseIfNeeded.isSelected();
|
||||
// return cbx_socksUseIfNeeded.isSelected();
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean useGPython() {
|
||||
return cbx_gpython.isSelected();
|
||||
}
|
||||
|
||||
public void gpythonCbxClick(ActionEvent actionEvent) {
|
||||
if (cbx_gpython.isSelected()) {
|
||||
new Thread(() -> {
|
||||
Platform.runLater(() -> {
|
||||
cbx_gpython.setSelected(false);
|
||||
cbx_gpython.setDisable(true);
|
||||
});
|
||||
if (!GPythonVersionUtils.validInstallation()) {
|
||||
Platform.runLater(() -> {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR, "G-Python installation", ButtonType.OK);
|
||||
alert.setTitle("G-Python installation");
|
||||
|
||||
FlowPane fp = new FlowPane();
|
||||
Label lbl = new Label("Before using G-Python, install the right packages using pip!" +
|
||||
System.lineSeparator() + System.lineSeparator() + "More information here:");
|
||||
Hyperlink link = new Hyperlink(INFO_URL_GPYTHON);
|
||||
fp.getChildren().addAll( lbl, link);
|
||||
link.setOnAction(event -> {
|
||||
Main.main.getHostServices().showDocument(link.getText());
|
||||
event.consume();
|
||||
});
|
||||
|
||||
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
|
||||
alert.getDialogPane().setContent(fp);
|
||||
alert.show();
|
||||
|
||||
cbx_gpython.setDisable(false);
|
||||
});
|
||||
}
|
||||
else {
|
||||
Platform.runLater(() -> {
|
||||
cbx_gpython.setSelected(true);
|
||||
cbx_gpython.setDisable(false);
|
||||
parentController.extensionsController.updateGPythonStatus();
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -2,27 +2,27 @@ package gearth.ui.info;
|
||||
|
||||
import gearth.Main;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.Hyperlink;
|
||||
import javafx.scene.control.*;
|
||||
import gearth.ui.SubForm;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.FlowPane;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.web.WebView;
|
||||
|
||||
/**
|
||||
* Created by Jonas on 06/04/18.
|
||||
*/
|
||||
public class InfoController extends SubForm {
|
||||
public ImageView img_logo;
|
||||
public Hyperlink link_sng;
|
||||
public Hyperlink link_ase;
|
||||
public Hyperlink link_darkbox;
|
||||
public Hyperlink link_d_harble;
|
||||
public Hyperlink link_g_gearth;
|
||||
public Hyperlink link_g_tanji;
|
||||
public Hyperlink link_d_bonnie;
|
||||
public Label version;
|
||||
public Hyperlink link_d_gearth;
|
||||
|
||||
// this is a TEMPORARY info tab
|
||||
public Label version;
|
||||
|
||||
public static void activateHyperlink(Hyperlink link) {
|
||||
link.setOnAction((ActionEvent event) -> {
|
||||
@ -38,16 +38,36 @@ public class InfoController extends SubForm {
|
||||
|
||||
img_logo.setImage(new Image("/gearth/G-EarthLogo.png"));
|
||||
|
||||
link_sng.setTooltip(new Tooltip("https://www.sngforum.info"));
|
||||
link_ase.setTooltip(new Tooltip("https://allseeingeye.to"));
|
||||
link_darkbox.setTooltip(new Tooltip("https://darkbox.nl"));
|
||||
link_d_harble.setTooltip(new Tooltip("https://discord.gg/CzRuHvW"));
|
||||
link_d_gearth.setTooltip(new Tooltip("https://discord.gg/AVkcF8y"));
|
||||
link_g_gearth.setTooltip(new Tooltip("https://github.com/sirjonasxx/G-Earth"));
|
||||
link_g_tanji.setTooltip(new Tooltip("https://github.com/ArachisH/Tanji"));
|
||||
link_d_harble.setTooltip(new Tooltip("https://discord.gg/CzRuHvW"));
|
||||
|
||||
activateHyperlink(link_ase);
|
||||
activateHyperlink(link_darkbox);
|
||||
activateHyperlink(link_d_harble);
|
||||
activateHyperlink(link_d_gearth);
|
||||
activateHyperlink(link_g_gearth);
|
||||
activateHyperlink(link_g_tanji);
|
||||
activateHyperlink(link_sng);
|
||||
activateHyperlink(link_darkbox);
|
||||
}
|
||||
|
||||
public void donate(ActionEvent actionEvent) {
|
||||
String pubkey = "1GEarthEV9Ua3RcixsKTcuc1PPZd9hqri3";
|
||||
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION, "Donate Bitcoins", ButtonType.OK);
|
||||
alert.setHeaderText("Donate Bitcoins");
|
||||
|
||||
WebView webView = new WebView();
|
||||
webView.getEngine().loadContent("<html>Bitcoin public address:<br><br>" +
|
||||
"<textarea>" + pubkey +"</textarea>" +
|
||||
"</html>");
|
||||
webView.setPrefSize(200, 100);
|
||||
|
||||
alert.setResizable(false);
|
||||
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
|
||||
alert.getDialogPane().setContent(webView);
|
||||
alert.show();
|
||||
}
|
||||
}
|
||||
|
@ -136,8 +136,8 @@ public class InjectionController extends SubForm {
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
HPacket[] packets = parsePackets("{l}{u:3}{i:967585}{i:9589}{s:\"furni_inscriptionfuckfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss\"}{s:\"sirjonasxx-II\"}{s:\"\"}{i:188}{i:0}{i:0}{b:false}");
|
||||
System.out.println(new HPacket("{l}{u:2550}{s:\"ClientPerf\"\"ormance\\\"}\"}{s:\"23\"}{s:\"fps\"}{s:\"Avatars: 1, Objects: 0\"}{i:76970180}").toExpression());
|
||||
HPacket[] packets = parsePackets("{l}{h:3}{i:967585}{i:9589}{s:\"furni_inscriptionfuckfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss\"}{s:\"sirjonasxx-II\"}{s:\"\"}{i:188}{i:0}{i:0}{b:false}");
|
||||
System.out.println(new HPacket("{l}{h:2550}{s:\"ClientPerf\"\"ormance\\\"}\"}{s:\"23\"}{s:\"fps\"}{s:\"Avatars: 1, Objects: 0\"}{i:76970180}").toExpression());
|
||||
|
||||
System.out.println("hi");
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ public class UiLoggerController implements Initializable {
|
||||
|
||||
String expr = packet.toExpression(isIncoming ? HMessage.Direction.TOCLIENT : HMessage.Direction.TOSERVER);
|
||||
|
||||
lblHarbleAPI.setText("HarbleAPI: " + (HarbleAPIFetcher.HARBLEAPI == null ? "False" : "True"));
|
||||
lblHarbleAPI.setText("Messages: " + (HarbleAPIFetcher.HARBLEAPI == null ? "False" : "True"));
|
||||
if ((viewMessageName || viewMessageHash) && HarbleAPIFetcher.HARBLEAPI != null) {
|
||||
HarbleAPI api = HarbleAPIFetcher.HARBLEAPI;
|
||||
HarbleAPI.HarbleMessage message = api.getHarbleMessageFromHeaderId(
|
||||
@ -124,7 +124,7 @@ public class UiLoggerController implements Initializable {
|
||||
.append(packet.headerId())
|
||||
.append(spanWithClass("]", isIncoming ? "incoming" : "outgoing"))
|
||||
.append(isIncoming ? " <- " : " -> ")
|
||||
.append(skiphugepackets && packet.length() > 8000 ?
|
||||
.append(skiphugepackets && packet.length() > 4000 ?
|
||||
divWithClass("<packet skipped>", "skipped") :
|
||||
divWithClass(packet.toString(), isIncoming ? "incoming" : "outgoing"));
|
||||
|
||||
|
1109
G-Earth/src/main/resources/build/messages.json
Normal file
1109
G-Earth/src/main/resources/build/messages.json
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
@ -0,0 +1,42 @@
|
||||
from time import sleep
|
||||
|
||||
from g_python.gextension import Extension
|
||||
from g_python.hmessage import Direction, HMessage
|
||||
from g_python.hpacket import HPacket
|
||||
from g_python import hparsers
|
||||
from g_python import htools
|
||||
|
||||
extension_info = {"title": "$G_PYTHON_SHELL_TITLE$", "description": "G-Python scripting console", "version": "1.0", "author": ""}
|
||||
|
||||
ext = Extension(extension_info, ["--port", "$G_EARTH_PORT$", "--auth-token", "$COOKIE$"], {"can_leave": False})
|
||||
ext.start()
|
||||
|
||||
|
||||
def is_closed(): return ext.is_closed()
|
||||
|
||||
|
||||
def send_to_client(packet): return ext.send_to_client(packet)
|
||||
|
||||
|
||||
def send_to_server(packet): return ext.send_to_server(packet)
|
||||
|
||||
|
||||
def on_event(event_name: str, func): return ext.on_event(event_name, func)
|
||||
|
||||
|
||||
def intercept(direction: Direction, callback, id=-1): return ext.intercept(direction, callback, id)
|
||||
|
||||
|
||||
def start(): return ext.start()
|
||||
|
||||
|
||||
def stop(): return ext.stop()
|
||||
|
||||
|
||||
def write_to_console(text, color='black', mention_title=True): return ext.write_to_console(text, color, mention_title)
|
||||
|
||||
|
||||
def request_flags(): return ext.request_flags()
|
||||
|
||||
|
||||
HPacket.default_extension = ext
|
@ -0,0 +1,214 @@
|
||||
let gearth_isconnected = false;
|
||||
|
||||
let revision = "{{RevisionName}}";
|
||||
let g_ws;
|
||||
|
||||
|
||||
let chachas = [];
|
||||
let chachaClass = -1;
|
||||
|
||||
let out_send_param1 = -1;
|
||||
let out_send_param3 = -1;
|
||||
let out_packet_objid = new Uint8Array(4);
|
||||
|
||||
let in_recv_param1 = -1;
|
||||
let in_packet_prefix = new Uint8Array(16);
|
||||
|
||||
let _gearth_returnbyte_copy;
|
||||
let _gearth_outgoing_copy;
|
||||
let _gearth_incoming_copy;
|
||||
|
||||
let _malloc;
|
||||
let _free;
|
||||
|
||||
|
||||
var packetBuff = {"out": [], "in": []};
|
||||
|
||||
function readLittleEndian(arr) {
|
||||
return arr[0] + arr[1] * 256 + arr[2] * 65536 + arr[3] * 16777216;
|
||||
}
|
||||
|
||||
function readBigEndian(arr) {
|
||||
return arr[3] + arr[2] * 256 + arr[1] * 65536 + arr[0] * 16777216;
|
||||
}
|
||||
|
||||
function writeLittleEndian(n) {
|
||||
let arr = new Uint8Array(4);
|
||||
for (let i = 0; i < 4; i++) {
|
||||
let rest = n % 256;
|
||||
arr[i] = rest;
|
||||
n -= rest;
|
||||
n /= 256;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
function writeBigEndian(n) {
|
||||
let arr = new Uint8Array(4);
|
||||
for (let i = 0; i < 4; i++) {
|
||||
let rest = n % 256;
|
||||
arr[3 - i] = rest;
|
||||
n -= rest;
|
||||
n /= 256;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function packetToString(packet) {
|
||||
let chars = [];
|
||||
let textDecode = new TextDecoder('latin1');
|
||||
for (let i = 0; i < packet.length; i++) {
|
||||
let byte = packet[i];
|
||||
if (byte < 32 || (byte > 127 && byte < 160) || byte === 93 || byte === 91 || byte === 125 || byte === 127) {
|
||||
chars.push("["+byte+"]");
|
||||
}
|
||||
else {
|
||||
chars.push(textDecode.decode(packet.slice(i, i+1)));
|
||||
}
|
||||
}
|
||||
|
||||
return chars.join("");
|
||||
}
|
||||
|
||||
function printPacket(type, packet) {
|
||||
packet = new Uint8Array(packet);
|
||||
if (packet.length > 2000) {
|
||||
console.log("[" + type + " capture]" + " -> skipped");
|
||||
}
|
||||
else {
|
||||
console.log("[" + type + " capture]" + " -> " + packetToString(packet));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let _g_packet_split = 600;
|
||||
|
||||
function inject_out(packet) {
|
||||
|
||||
if (chachas.length > 1) {
|
||||
packet[5] = _gearth_returnbyte_copy(chachas[0], packet[5], chachaClass);
|
||||
packet[4] = _gearth_returnbyte_copy(chachas[0], packet[4], chachaClass);
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
while (i < packet.length) {
|
||||
let inject_amount = Math.min(_g_packet_split, packet.length - i);
|
||||
|
||||
let packet_location = _malloc(inject_amount + 16);
|
||||
unityInstance.Module.HEAPU8.set(out_packet_objid, packet_location);
|
||||
unityInstance.Module.HEAPU8.fill(0, packet_location + 4, packet_location + 12);
|
||||
unityInstance.Module.HEAPU8.set(writeLittleEndian(inject_amount), packet_location + 12);
|
||||
unityInstance.Module.HEAPU8.set(packet.slice(i, i + inject_amount), packet_location + 16);
|
||||
|
||||
_gearth_outgoing_copy(out_send_param1, packet_location, out_send_param3);
|
||||
_free(packet_location);
|
||||
|
||||
i += inject_amount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function handle_out(packet) {
|
||||
if (gearth_isconnected) {
|
||||
let g_message = new Uint8Array(packet.length + 1);
|
||||
g_message[0] = 1; // toserver
|
||||
g_message.set(new Uint8Array(packet), 1);
|
||||
g_ws.send(g_message);
|
||||
}
|
||||
else {
|
||||
inject_out(packet);
|
||||
}
|
||||
}
|
||||
|
||||
function inject_in(packet) {
|
||||
let i = 0;
|
||||
while (i < packet.length) {
|
||||
let inject_amount = Math.min(_g_packet_split, packet.length - i);
|
||||
|
||||
let packet_location = _malloc(inject_amount + 16);
|
||||
unityInstance.Module.HEAPU8.set(in_packet_prefix, packet_location);
|
||||
unityInstance.Module.HEAPU8.set(packet.slice(i, i + inject_amount), packet_location + 16);
|
||||
|
||||
_gearth_incoming_copy(in_recv_param1, packet_location, 0, inject_amount, 0);
|
||||
_free(packet_location);
|
||||
|
||||
i += inject_amount;
|
||||
}
|
||||
}
|
||||
|
||||
function handle_in(packet) {
|
||||
if (gearth_isconnected) {
|
||||
let g_message = new Uint8Array(packet.length + 1);
|
||||
g_message[0] = 0; // toclient
|
||||
g_message.set(new Uint8Array(packet), 1);
|
||||
g_ws.send(g_message);
|
||||
}
|
||||
else {
|
||||
inject_in(packet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function collect_packets(type) {
|
||||
let finishedPackets = [];
|
||||
|
||||
while (packetBuff[type].length >= 6 && readBigEndian(packetBuff[type].slice(0, 4)) + 4 <= packetBuff[type].length) {
|
||||
let packetLength = readBigEndian(packetBuff[type].slice(0, 4)) + 4;
|
||||
let packet = packetBuff[type].slice(0, packetLength);
|
||||
finishedPackets.push(packet);
|
||||
packetBuff[type] = packetBuff[type].slice(packetLength);
|
||||
}
|
||||
|
||||
return finishedPackets;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
let onOpen = function() {
|
||||
g_ws.send(new TextEncoder('latin1').encode(revision));
|
||||
gearth_isconnected = true;
|
||||
};
|
||||
|
||||
let onClose = function() {
|
||||
gearth_isconnected = false;
|
||||
};
|
||||
|
||||
let onMessage = function(message) {
|
||||
let buffer = new Uint8Array(message.data);
|
||||
|
||||
if (buffer[0] === 0) {
|
||||
inject_in([].slice.call(buffer.slice(1)));
|
||||
}
|
||||
else if (buffer[0] === 1) {
|
||||
inject_out([].slice.call(buffer.slice(1)));
|
||||
}
|
||||
else {
|
||||
gearth_isconnected = false;
|
||||
g_ws.close();
|
||||
}
|
||||
};
|
||||
|
||||
let onError = function(event) {
|
||||
gearth_isconnected = false;
|
||||
};
|
||||
|
||||
let portRequester = new WebSocket("ws://localhost:9039/ws/portrequest");
|
||||
portRequester.onmessage = function(message) {
|
||||
let port = message.data.split(" ")[1];
|
||||
|
||||
let _g_packet_url = "ws://localhost:" + port + "/ws/packethandler";
|
||||
g_ws = new WebSocket(_g_packet_url);
|
||||
g_ws.binaryType = "arraybuffer";
|
||||
|
||||
g_ws.onopen = onOpen;
|
||||
g_ws.onclose = onClose;
|
||||
g_ws.onmessage = onMessage;
|
||||
g_ws.onerror = onError;
|
||||
|
||||
portRequester.close();
|
||||
};
|
||||
|
@ -0,0 +1,11 @@
|
||||
_gearth_returnbyte_copy = Module["_gearth_returnbyte_copy"] = (function() {
|
||||
return Module["asm"]["_gearth_returnbyte_copy"].apply(null, arguments)
|
||||
});
|
||||
|
||||
_gearth_outgoing_copy = Module["_gearth_outgoing_copy"] = (function() {
|
||||
return Module["asm"]["_gearth_outgoing_copy"].apply(null, arguments)
|
||||
});
|
||||
|
||||
_gearth_incoming_copy = Module["_gearth_incoming_copy"] = (function() {
|
||||
return Module["asm"]["_gearth_incoming_copy"].apply(null, arguments)
|
||||
});
|
@ -0,0 +1,49 @@
|
||||
function g_outgoing_packet(param1, param2, param3) {
|
||||
out_send_param1 = param1;
|
||||
out_send_param3 = param3;
|
||||
out_packet_objid = unityInstance.Module.HEAPU8.slice(param2, param2 + 4);
|
||||
|
||||
let length = readLittleEndian(unityInstance.Module.HEAPU8.subarray(param2 + 12, param2 + 12 + 4));
|
||||
let array = [].slice.call(unityInstance.Module.HEAPU8.subarray(param2 + 12 + 4, param2 + 12 + 4 + length));
|
||||
|
||||
packetBuff["out"] = packetBuff["out"].concat(array);
|
||||
|
||||
for (let packet of collect_packets("out")) {
|
||||
handle_out(packet);
|
||||
}
|
||||
}
|
||||
|
||||
function g_incoming_packet(param1, param2, param3, param4, param5) {
|
||||
in_recv_param1 = param1;
|
||||
in_packet_prefix = unityInstance.Module.HEAPU8.slice(param2, param2 + 16);
|
||||
|
||||
let buffer = unityInstance.Module.HEAPU8.slice(param2 + 16, param2 + 16 + param4);
|
||||
packetBuff["in"] = packetBuff["in"].concat([].slice.call(buffer));
|
||||
|
||||
let packets = collect_packets("in");
|
||||
for (let packet of packets) {
|
||||
if (chachas.length > 1) {
|
||||
packet[5] = _gearth_returnbyte_copy(chachas[1], packet[5], chachaClass);
|
||||
packet[4] = _gearth_returnbyte_copy(chachas[1], packet[4], chachaClass);
|
||||
}
|
||||
handle_in(packet);
|
||||
}
|
||||
}
|
||||
|
||||
function g_chacha_setkey(param1, param2, param3, param4) {
|
||||
if (chachas.length === 2) {
|
||||
chachas = [];
|
||||
}
|
||||
|
||||
chachas.push(param1);
|
||||
}
|
||||
|
||||
function g_chacha_returnbyte(param1, param2, param3) {
|
||||
chachaClass = param3;
|
||||
return param2;
|
||||
}
|
||||
|
||||
env["g_outgoing_packet"] = g_outgoing_packet;
|
||||
env["g_incoming_packet"] = g_incoming_packet;
|
||||
env["g_chacha_setkey"] = g_chacha_setkey;
|
||||
env["g_chacha_returnbyte"] = g_chacha_returnbyte;
|
@ -11,7 +11,7 @@
|
||||
fx:controller="gearth.ui.GEarthController">
|
||||
<Pane fx:id="mover" maxHeight="0.0" minHeight="0.0" prefWidth="200.0"/>
|
||||
<TabPane fx:id="tabBar" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity"
|
||||
minWidth="-Infinity" prefHeight="295.0" prefWidth="565.0" tabClosingPolicy="UNAVAILABLE">
|
||||
minWidth="-Infinity" prefHeight="295.0" prefWidth="650.0" tabClosingPolicy="UNAVAILABLE">
|
||||
<Tab text="Connection">
|
||||
<fx:include fx:id="connection" source="connection/Connection.fxml"/>
|
||||
</Tab>
|
||||
|
@ -11,7 +11,7 @@
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
|
||||
<GridPane alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="262.0" prefWidth="565.0" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.connection.ConnectionController">
|
||||
<GridPane alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.connection.ConnectionController">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
|
||||
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="262.0" prefWidth="565.0" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.extensions.ExtensionsController">
|
||||
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.extensions.ExtensionsController">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="10.0" prefWidth="277.0" />
|
||||
</columnConstraints>
|
||||
@ -19,11 +19,11 @@
|
||||
<VBox fx:id="extensioncontainer" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
|
||||
<GridPane fx:id="header_ext" gridLinesVisible="true">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="163.0" minWidth="10.0" percentWidth="22.0" prefWidth="57.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="190.0" minWidth="10.0" percentWidth="34.0" prefWidth="189.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="118.0" minWidth="10.0" percentWidth="18.0" prefWidth="66.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="100.0" minWidth="10.0" percentWidth="13.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="100.0" minWidth="10.0" percentWidth="11.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="22.0" prefWidth="132.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="34.0" prefWidth="204.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="18.0" prefWidth="108.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="13.0" prefWidth="78.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="11.0" prefWidth="66.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
@ -52,14 +52,16 @@
|
||||
<GridPane hgap="7.0">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="49.0" minWidth="49.0" prefWidth="49.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="101.0" minWidth="101.0" prefWidth="101.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="90.0" minWidth="90.0" prefWidth="90.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="0.0" prefWidth="247.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="140.0" minWidth="140.0" prefWidth="140.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="140.0" minWidth="140.0" prefWidth="140.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="130.0" minWidth="130.0" prefWidth="130.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="130.0" minWidth="130.0" prefWidth="130.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="130.0" minWidth="130.0" prefWidth="130.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<Button fx:id="btn_gpython" disable="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#gpythonBtnClicked" text="G-Python shell" GridPane.columnIndex="3" />
|
||||
<TextField fx:id="ext_port" editable="false" prefHeight="26.0" prefWidth="157.0" GridPane.columnIndex="1">
|
||||
<GridPane.margin>
|
||||
<Insets left="-7.0" />
|
||||
@ -70,8 +72,8 @@
|
||||
<Insets left="3.0" />
|
||||
</GridPane.margin>
|
||||
</Label>
|
||||
<Button fx:id="btn_install" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#installBtnClicked" text="Install" GridPane.columnIndex="4" />
|
||||
<Button fx:id="btn_viewExtensionConsole" layoutX="401.0" layoutY="10.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#extConsoleBtnClicked" text="View logs" GridPane.columnIndex="3" />
|
||||
<Button fx:id="btn_install" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#installBtnClicked" text="Install" GridPane.columnIndex="5" />
|
||||
<Button fx:id="btn_viewExtensionConsole" layoutX="401.0" layoutY="10.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#extConsoleBtnClicked" text="View logs" GridPane.columnIndex="4" />
|
||||
</GridPane>
|
||||
</GridPane>
|
||||
</GridPane>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<?import javafx.geometry.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
|
||||
<BorderPane fx:id="borderPane" prefHeight="230.0" prefWidth="394.0" style="-fx-background-color: white;" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.extensions.logger.ExtensionLoggerController">
|
||||
<BorderPane fx:id="borderPane" prefHeight="230.0" prefWidth="394.0" style="-fx-background-color: white;" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.extensions.logger.ExtensionLoggerController">
|
||||
<padding>
|
||||
<Insets bottom="1.0" left="5.0" right="1.0" top="5.0" />
|
||||
</padding>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
|
||||
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="262.0" prefWidth="565.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.extra.ExtraController">
|
||||
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.extra.ExtraController">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="331.0" minWidth="10.0" prefWidth="318.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="390.0" minWidth="10.0" prefWidth="247.0" />
|
||||
@ -26,38 +26,39 @@
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints maxHeight="125.0" minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="235.0" minHeight="10.0" prefHeight="232.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="7.0" minHeight="7.0" prefHeight="7.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="34.0" minHeight="34.0" prefHeight="34.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="28.0" minHeight="28.0" prefHeight="28.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="10.0" prefHeight="232.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<GridPane fx:id="grd_advanced" disable="true" style="-fx-border-color: #888888; -fx-border-radius: 5px;" GridPane.rowIndex="1">
|
||||
<GridPane fx:id="grd_advanced" disable="true" prefHeight="161.0" prefWidth="299.0" style="-fx-border-color: #888888; -fx-border-radius: 5px;" GridPane.rowIndex="4">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="119.0" minHeight="58.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="119.0" minHeight="6.0" prefHeight="15.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="28.0" minHeight="28.0" prefHeight="28.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="28.0" minHeight="28.0" prefHeight="28.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="28.0" minHeight="28.0" prefHeight="28.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<GridPane.margin>
|
||||
<Insets bottom="12.0" left="10.0" right="10.0" />
|
||||
<Insets bottom="5.0" left="10.0" right="10.0" top="6.0" />
|
||||
</GridPane.margin>
|
||||
<padding>
|
||||
<Insets bottom="4.0" left="7.0" top="7.0" />
|
||||
<Insets left="7.0" top="3.0" />
|
||||
</padding>
|
||||
<children>
|
||||
<CheckBox fx:id="cbx_useSocks" mnemonicParsing="false" text="Use SOCKS proxy" />
|
||||
<CheckBox fx:id="cbx_disableDecryption" mnemonicParsing="false" text="Disable decryption" GridPane.rowIndex="3" />
|
||||
<CheckBox fx:id="cbx_debug" mnemonicParsing="false" text="Debug to stdout" GridPane.rowIndex="4" />
|
||||
<CheckBox fx:id="cbx_disableDecryption" mnemonicParsing="false" text="Disable decryption" GridPane.rowIndex="2" />
|
||||
<CheckBox fx:id="cbx_debug" mnemonicParsing="false" text="Debug to stdout" GridPane.rowIndex="3" />
|
||||
<GridPane fx:id="grd_socksInfo" disable="true" prefHeight="54.0" prefWidth="81.0" GridPane.rowIndex="1">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<GridPane.margin>
|
||||
<Insets />
|
||||
@ -66,7 +67,6 @@
|
||||
<Insets left="5.0" />
|
||||
</padding>
|
||||
<children>
|
||||
<CheckBox fx:id="cbx_socksUseIfNeeded" mnemonicParsing="false" selected="true" text="Only use if needed" GridPane.rowIndex="1" />
|
||||
<GridPane prefHeight="119.0" prefWidth="259.0">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="159.0" minWidth="10.0" prefWidth="68.0" />
|
||||
@ -104,12 +104,50 @@
|
||||
</GridPane>
|
||||
</children>
|
||||
</GridPane>
|
||||
<CheckBox fx:id="cbx_advanced" mnemonicParsing="false" text="Advanced" textFill="#000000ba">
|
||||
<CheckBox fx:id="cbx_advanced" mnemonicParsing="false" text="Advanced" textFill="#000000ba" GridPane.rowIndex="3">
|
||||
<GridPane.margin>
|
||||
<Insets left="10.0" top="2.0" />
|
||||
</GridPane.margin>
|
||||
<padding>
|
||||
<Insets top="2.0" />
|
||||
</padding>
|
||||
</CheckBox>
|
||||
<CheckBox fx:id="cbx_gpython" mnemonicParsing="false" onAction="#gpythonCbxClick" text="Enable G-Python scripting" textFill="#000000ba" GridPane.rowIndex="2">
|
||||
<GridPane.margin>
|
||||
<Insets left="10.0" top="2.0" />
|
||||
</GridPane.margin>
|
||||
</CheckBox>
|
||||
<GridPane fx:id="grd_clientSelection" prefHeight="26.0" prefWidth="286.0" style="-fx-border-color: #888888; -fx-border-radius: 5px;" GridPane.rowIndex="1">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="149.0" minWidth="10.0" prefWidth="38.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="81.0" minWidth="69.0" prefWidth="75.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="83.0" minWidth="66.0" prefWidth="72.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="82.0" minWidth="61.0" prefWidth="65.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="242.0" minWidth="10.0" prefWidth="47.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="20.0" prefHeight="34.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<RadioButton fx:id="rd_unity" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" selected="true" text="Unity" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" GridPane.vgrow="ALWAYS">
|
||||
<toggleGroup>
|
||||
<ToggleGroup fx:id="tgl_clientMode" />
|
||||
</toggleGroup>
|
||||
</RadioButton>
|
||||
<RadioButton fx:id="rd_flash" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="Flash" toggleGroup="$tgl_clientMode" GridPane.columnIndex="2" />
|
||||
<RadioButton disable="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="Anime" GridPane.columnIndex="3" />
|
||||
</children>
|
||||
<GridPane.margin>
|
||||
<Insets left="10.0" right="10.0" />
|
||||
</GridPane.margin>
|
||||
<padding>
|
||||
<Insets bottom="8.0" top="8.0" />
|
||||
</padding>
|
||||
</GridPane>
|
||||
</children>
|
||||
<GridPane.margin>
|
||||
<Insets />
|
||||
</GridPane.margin>
|
||||
</GridPane>
|
||||
</children>
|
||||
</GridPane>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.text.*?>
|
||||
|
||||
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="262.0" prefWidth="595.0" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.info.InfoController">
|
||||
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.info.InfoController">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="10.0" prefWidth="332.0" />
|
||||
</columnConstraints>
|
||||
@ -20,61 +20,63 @@
|
||||
<Font size="18.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label layoutX="260.0" layoutY="50.0" text="Habbo packet manipulator for Linux, Windows & Mac" textFill="#000000b2">
|
||||
<Label layoutX="260.0" layoutY="57.0" text="Habbo packet manipulator for Linux, Windows & Mac" textFill="#000000b2">
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label layoutX="260.0" layoutY="87.0" text="Made by:" textFill="#000000b2">
|
||||
<Label layoutX="260.0" layoutY="94.0" text="Made by:" textFill="#000000b2">
|
||||
<font>
|
||||
<Font name="System Bold" size="14.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label layoutX="260.0" layoutY="107.0" text="sirjonasxx" textFill="#000000b2">
|
||||
<Label layoutX="260.0" layoutY="114.0" text="sirjonasxx" textFill="#000000b2">
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label layoutX="363.0" layoutY="87.0" text="Contributors:" textFill="#000000b2">
|
||||
<Label layoutX="363.0" layoutY="94.0" text="Contributors:" textFill="#000000b2">
|
||||
<font>
|
||||
<Font name="System Bold" size="14.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label layoutX="363.0" layoutY="107.0" text="XePeleato" textFill="#000000b2">
|
||||
<Label layoutX="363.0" layoutY="114.0" text="XePeleato" textFill="#000000b2">
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label layoutX="363.0" layoutY="127.0" text="Scott Stamp" textFill="#000000b2">
|
||||
<Label layoutX="363.0" layoutY="134.0" text="Scott Stamp" textFill="#000000b2">
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label layoutX="363.0" layoutY="147.0" text="LittleJ" textFill="#000000b2">
|
||||
<Label layoutX="363.0" layoutY="154.0" text="LittleJ" textFill="#000000b2">
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label layoutX="363.0" layoutY="167.0" text="ArachisH" textFill="#000000b2">
|
||||
<Label layoutX="363.0" layoutY="174.0" text="ArachisH" textFill="#000000b2">
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label layoutX="363.0" layoutY="187.0" text="BurakDev" textFill="#000000b2">
|
||||
<Label layoutX="363.0" layoutY="194.0" text="BurakDev" textFill="#000000b2">
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label layoutX="487.0" layoutY="87.0" text="Links:" textFill="#000000b2">
|
||||
<Label layoutX="491.0" layoutY="94.0" text="Links:" textFill="#000000b2">
|
||||
<font>
|
||||
<Font name="System Bold" size="14.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Hyperlink fx:id="link_sng" layoutX="487.0" layoutY="107.0" text="SNG Forum" />
|
||||
<Hyperlink fx:id="link_darkbox" layoutX="487.0" layoutY="127.0" text="Darkbox" />
|
||||
<Hyperlink fx:id="link_d_harble" layoutX="487.0" layoutY="187.0" text="Discord - Harble" />
|
||||
<Hyperlink fx:id="link_g_gearth" layoutX="487.0" layoutY="147.0" text="Github - G-Earth" />
|
||||
<Hyperlink fx:id="link_g_tanji" layoutX="487.0" layoutY="167.0" text="Github - Tanji" />
|
||||
<Hyperlink fx:id="link_ase" layoutX="487.0" layoutY="114.0" text="AllSeeingEye" />
|
||||
<Hyperlink fx:id="link_darkbox" layoutX="487.0" layoutY="134.0" text="Darkbox" />
|
||||
<Hyperlink fx:id="link_d_gearth" layoutX="487.0" layoutY="194.0" text="Discord - G-Earth" />
|
||||
<Hyperlink fx:id="link_d_harble" layoutX="487.0" layoutY="214.0" text="Discord - Harble" />
|
||||
<Hyperlink fx:id="link_g_gearth" layoutX="487.0" layoutY="154.0" text="Github - G-Earth" />
|
||||
<Hyperlink fx:id="link_g_tanji" layoutX="487.0" layoutY="174.0" text="Github - Tanji" />
|
||||
<Button layoutX="537.0" layoutY="14.0" mnemonicParsing="false" onAction="#donate" prefHeight="20.0" prefWidth="100.0" text="Donate BTC" />
|
||||
<!--<Hyperlink fx:id="link_d_bonnie" layoutX="400.0" layoutY="221.0" text="Discord - BonnieScripting (pt/br)" />-->
|
||||
</children>
|
||||
</AnchorPane>
|
||||
|
@ -10,7 +10,7 @@
|
||||
<?import javafx.scene.text.Text?>
|
||||
|
||||
<?import javafx.scene.text.TextFlow?>
|
||||
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="262.0" prefWidth="565.0"
|
||||
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0"
|
||||
xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="gearth.ui.injection.InjectionController">
|
||||
<columnConstraints>
|
||||
|
@ -12,7 +12,7 @@
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.text.TextFlow?>
|
||||
|
||||
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="262.0" prefWidth="565.0"
|
||||
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0"
|
||||
xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="gearth.ui.logger.LoggerController">
|
||||
<columnConstraints>
|
||||
|
@ -75,7 +75,7 @@
|
||||
<Insets right="10.0" />
|
||||
</FlowPane.margin>
|
||||
</Label>
|
||||
<Label fx:id="lblHarbleAPI" layoutX="283.0" layoutY="11.0" style="-fx-text-fill: black !important" text="HarbleAPI: False">
|
||||
<Label fx:id="lblHarbleAPI" layoutX="283.0" layoutY="11.0" style="-fx-text-fill: black !important" text="Messages: False">
|
||||
<FlowPane.margin>
|
||||
<Insets right="10.0" />
|
||||
</FlowPane.margin>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
|
||||
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="262.0" prefWidth="595.0" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.scheduler.SchedulerController">
|
||||
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.scheduler.SchedulerController">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="10.0" prefWidth="277.0" />
|
||||
</columnConstraints>
|
||||
|
@ -10,7 +10,7 @@
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
|
||||
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="262.0" prefWidth="565.0"
|
||||
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0"
|
||||
xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="gearth.ui.tools.ToolsController">
|
||||
<rowConstraints>
|
||||
|
19
README.md
19
README.md
@ -3,25 +3,25 @@ Habbo packet logger & manipulator for Windows, Linux and Mac.
|
||||
|
||||
- Requires Java 8
|
||||
|
||||
FOR TROUBLESHOOTING, GO TO https://github.com/sirjonasxx/G-Earth/wiki/Troubleshooting
|
||||
[CLICK HERE FOR TROUBLESHOOTING](https://github.com/sirjonasxx/G-Earth/wiki/Troubleshooting)
|
||||
|
||||
Join the G-Earth Discord server: https://discord.gg/AVkcF8y
|
||||
Join the G-Earth [Discord server](https://discord.gg/AVkcF8y)
|
||||
|
||||
# Windows execution
|
||||
Double click G-Earth.exe, which will be delivered in the release. Note that executing G-Earth requires admin privileges.
|
||||
|
||||
# Linux execution
|
||||
Execution command (temporary, verified in Ubuntu):
|
||||
Execution command:
|
||||
> $ sudo java -jar G-Earth.jar
|
||||
|
||||
Additionally, you can add the -t flag to log the packets in your terminal instead of opening a new window for it.
|
||||
|
||||
# Mac execution
|
||||
https://github.com/sirjonasxx/G-Earth/wiki/macOs-Installation-guide
|
||||
[MacOs Installation guide](https://github.com/sirjonasxx/G-Earth/wiki/macOs-Installation-guide)
|
||||
|
||||
# Features
|
||||
* Log outgoing and incoming packets
|
||||
* Injection, both sides
|
||||
* Injection, both directions
|
||||
* Blocking & replacing packets functionality
|
||||
* Packet expressions
|
||||
* Encoding/decoding
|
||||
@ -29,10 +29,13 @@ https://github.com/sirjonasxx/G-Earth/wiki/macOs-Installation-guide
|
||||
* Retro support - enter game host & port manually (only the first time)
|
||||
* Advanced scheduler
|
||||
* Advanced extension support
|
||||
* Python scripting on the fly
|
||||
* SOCKS proxy
|
||||
* 2 included extensions on-release
|
||||
|
||||
Interested in creating an extension?
|
||||
* If you're not experienced with Java but have written extensions before in C#, you could have a look at https://github.com/ArachisH/Geode
|
||||
* If you are experienced with Java, read this wiki page carefully: https://github.com/sirjonasxx/G-Earth/wiki/Extensions
|
||||
* If you're not experienced with Java but have written extensions before in C#, you could have a look at [Geode](https://github.com/ArachisH/Geode).
|
||||
* If you are experienced with Java, read this [wiki page](https://github.com/sirjonasxx/G-Earth/wiki/Extensions) carefully.
|
||||
* The easiest way to create extensions is using [G-Python](https://github.com/sirjonasxx/G-Python). (can also be done inside G-Earth with a [live scripting console](https://github.com/sirjonasxx/G-Earth/wiki/G-Python-qtConsole))
|
||||
|
||||
For the memorysearcher that extracts the RC4 table, go to https://github.com/sirjonasxx/G-Mem
|
||||
For the memorysearcher that extracts the RC4 table, go to [G-Mem](https://github.com/sirjonasxx/G-Mem).
|
||||
|
Loading…
Reference in New Issue
Block a user