From 7912fa35a67b15c12060a7b5e33cb4ff6a8e8b4e Mon Sep 17 00:00:00 2001 From: sirjonasxx <36828922+sirjonasxx@users.noreply.github.com> Date: Tue, 27 Dec 2022 22:39:32 +0100 Subject: [PATCH] Developer mode and unsafe packet protection (wip) --- .../java/gearth/protocol/HConnection.java | 49 +++++++++++---- .../gearth/protocol/connection/HProxy.java | 10 ++- .../packetsafety/PacketSafetyManager.java | 32 ++++++++++ .../packetsafety/SafePacketsContainer.java | 24 +++++++ .../extensions/ExtensionsController.java | 4 ++ .../ui/subforms/extra/ExtraController.java | 63 +++++++++++++++---- .../ui/subforms/extensions/Extensions.fxml | 4 +- .../gearth/ui/subforms/extra/Extra.fxml | 40 ++++++------ .../ui/translations/messages_de.properties | 10 +++ .../ui/translations/messages_en.properties | 10 +++ .../ui/translations/messages_es.properties | 10 +++ .../ui/translations/messages_fi.properties | 10 +++ .../ui/translations/messages_fr.properties | 10 +++ .../ui/translations/messages_it.properties | 10 +++ .../ui/translations/messages_nl.properties | 10 +++ .../ui/translations/messages_pt.properties | 10 +++ .../ui/translations/messages_tr.properties | 10 +++ 17 files changed, 268 insertions(+), 48 deletions(-) create mode 100644 G-Earth/src/main/java/gearth/protocol/connection/packetsafety/PacketSafetyManager.java create mode 100644 G-Earth/src/main/java/gearth/protocol/connection/packetsafety/SafePacketsContainer.java diff --git a/G-Earth/src/main/java/gearth/protocol/HConnection.java b/G-Earth/src/main/java/gearth/protocol/HConnection.java index 70bd0c4..1a20f9b 100644 --- a/G-Earth/src/main/java/gearth/protocol/HConnection.java +++ b/G-Earth/src/main/java/gearth/protocol/HConnection.java @@ -1,6 +1,8 @@ package gearth.protocol; import gearth.misc.listenerpattern.Observable; +import gearth.protocol.connection.packetsafety.PacketSafetyManager; +import gearth.protocol.connection.packetsafety.SafePacketsContainer; import gearth.protocol.connection.proxy.nitro.NitroProxyProvider; import gearth.services.packet_info.PacketInfoManager; import gearth.protocol.connection.HClient; @@ -30,6 +32,8 @@ public class HConnection { private ProxyProviderFactory proxyProviderFactory; private ProxyProvider proxyProvider = null; + private volatile boolean developerMode = false; + public HConnection() { HConnection selff = this; proxyProviderFactory = new ProxyProviderFactory( @@ -37,6 +41,8 @@ public class HConnection { selff::setState, this ); + + PacketSafetyManager.PACKET_SAFETY_MANAGER.initialize(this); } public HState getState() { @@ -147,30 +153,47 @@ public class HConnection { public boolean sendToClient(HPacket packet) { - HProxy proxy = this.proxy; - if (proxy == null) return false; - - if (!packet.isPacketComplete()) { - PacketInfoManager packetInfoManager = getPacketInfoManager(); - packet.completePacket(packetInfoManager); - - if (!packet.isPacketComplete() || !packet.canSendToClient()) return false; - } - + if (!canSendPacket(HMessage.Direction.TOCLIENT, packet)) return false; return proxy.sendToClient(packet); } + public boolean sendToServer(HPacket packet) { + if (!canSendPacket(HMessage.Direction.TOSERVER, packet)) return false; + return proxy.sendToServer(packet); + } + + private boolean canSendPacket(HMessage.Direction direction, HPacket packet) { + return isPacketSendingAllowed(direction, packet) && (developerMode || isPacketSendingSafe(direction, packet)); + } + + public boolean isPacketSendingAllowed(HMessage.Direction direction, HPacket packet) { HProxy proxy = this.proxy; if (proxy == null) return false; + if (packet.isCorrupted()) return false; + if (!packet.isPacketComplete()) { PacketInfoManager packetInfoManager = getPacketInfoManager(); packet.completePacket(packetInfoManager); - if (!packet.isPacketComplete() || !packet.canSendToServer()) return false; + return packet.isPacketComplete() && + (packet.canSendToClient() || direction != HMessage.Direction.TOCLIENT) && + (packet.canSendToServer() || direction != HMessage.Direction.TOSERVER); } - return proxy.sendToServer(packet); + return true; + } + + public boolean isPacketSendingSafe(HMessage.Direction direction, HPacket packet) { + String hotelVersion = proxy.getHotelVersion(); + if (hotelVersion == null) return false; + + SafePacketsContainer packetsContainer = PacketSafetyManager.PACKET_SAFETY_MANAGER.getPacketContainer(hotelVersion); + return packetsContainer.isPacketSafe(packet.headerId(), direction); + } + + public void setDeveloperMode(boolean developerMode) { + this.developerMode = developerMode; } public String getClientHost() { @@ -205,7 +228,7 @@ public class HConnection { if (proxy == null) { return null; } - return proxy.gethClient(); + return proxy.getHClient(); } public PacketInfoManager getPacketInfoManager() { diff --git a/G-Earth/src/main/java/gearth/protocol/connection/HProxy.java b/G-Earth/src/main/java/gearth/protocol/connection/HProxy.java index e3bb228..57d6d62 100644 --- a/G-Earth/src/main/java/gearth/protocol/connection/HProxy.java +++ b/G-Earth/src/main/java/gearth/protocol/connection/HProxy.java @@ -1,6 +1,9 @@ package gearth.protocol.connection; import gearth.protocol.HPacket; +import gearth.protocol.connection.packetsafety.PacketSafetyManager; +import gearth.protocol.connection.packetsafety.SafePacketsContainer; +import gearth.services.packet_info.PacketInfo; import gearth.services.packet_info.PacketInfoManager; import gearth.protocol.packethandler.PacketHandler; @@ -45,6 +48,11 @@ public class HProxy { this.hotelVersion = hotelVersion; this.clientIdentifier = clientIdentifier; this.packetInfoManager = PacketInfoManager.fromHotelVersion(hotelVersion, hClient); + + SafePacketsContainer packetsContainer = PacketSafetyManager.PACKET_SAFETY_MANAGER.getPacketContainer(hotelVersion); + for (PacketInfo packetInfo : packetInfoManager.getPacketInfoList()) { + packetsContainer.validateSafePacket(packetInfo.getHeaderId(), packetInfo.getDestination()); + } } public boolean sendToServer(HPacket packet) { @@ -101,7 +109,7 @@ public class HProxy { return hotelVersion; } - public HClient gethClient() { + public HClient getHClient() { return hClient; } diff --git a/G-Earth/src/main/java/gearth/protocol/connection/packetsafety/PacketSafetyManager.java b/G-Earth/src/main/java/gearth/protocol/connection/packetsafety/PacketSafetyManager.java new file mode 100644 index 0000000..76b5c42 --- /dev/null +++ b/G-Earth/src/main/java/gearth/protocol/connection/packetsafety/PacketSafetyManager.java @@ -0,0 +1,32 @@ +package gearth.protocol.connection.packetsafety; + +import gearth.protocol.HConnection; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class PacketSafetyManager { + + public static final PacketSafetyManager PACKET_SAFETY_MANAGER = new PacketSafetyManager(); + + private final Map safePacketContainers = new ConcurrentHashMap<>(); + + private PacketSafetyManager() { + + } + + public void initialize(HConnection connection) { + connection.addTrafficListener(0, message -> { + String hotelVersion = connection.getHotelVersion(); + if (hotelVersion.equals("")) return; + + SafePacketsContainer safePacketsContainer = getPacketContainer(hotelVersion); + safePacketsContainer.validateSafePacket(message.getPacket().headerId(), message.getDestination()); + }); + } + + public SafePacketsContainer getPacketContainer(String hotelVersion) { + return safePacketContainers.computeIfAbsent(hotelVersion, v -> new SafePacketsContainer()); + } + +} diff --git a/G-Earth/src/main/java/gearth/protocol/connection/packetsafety/SafePacketsContainer.java b/G-Earth/src/main/java/gearth/protocol/connection/packetsafety/SafePacketsContainer.java new file mode 100644 index 0000000..ef47977 --- /dev/null +++ b/G-Earth/src/main/java/gearth/protocol/connection/packetsafety/SafePacketsContainer.java @@ -0,0 +1,24 @@ +package gearth.protocol.connection.packetsafety; + +import gearth.protocol.HMessage; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class SafePacketsContainer { + + private final Set safeIncomingIds = Collections.synchronizedSet(new HashSet<>()); + private final Set safeOutgoingIds = Collections.synchronizedSet(new HashSet<>()); + + public void validateSafePacket(int headerId, HMessage.Direction direction) { + Set headerIds = direction == HMessage.Direction.TOCLIENT ? safeIncomingIds : safeOutgoingIds; + headerIds.add(headerId); + } + + public boolean isPacketSafe(int headerId, HMessage.Direction direction) { + Set headerIds = direction == HMessage.Direction.TOCLIENT ? safeIncomingIds : safeOutgoingIds; + return headerIds.contains(headerId); + } + +} diff --git a/G-Earth/src/main/java/gearth/ui/subforms/extensions/ExtensionsController.java b/G-Earth/src/main/java/gearth/ui/subforms/extensions/ExtensionsController.java index b385c50..83da26a 100644 --- a/G-Earth/src/main/java/gearth/ui/subforms/extensions/ExtensionsController.java +++ b/G-Earth/src/main/java/gearth/ui/subforms/extensions/ExtensionsController.java @@ -113,6 +113,10 @@ public class ExtensionsController extends SubForm { } } + public void setLocalInstallingEnabled(boolean enabled) { + btn_install.setDisable(!enabled); + } + private volatile int gpytonShellCounter = 1; private volatile boolean pythonShellLaunching = false; diff --git a/G-Earth/src/main/java/gearth/ui/subforms/extra/ExtraController.java b/G-Earth/src/main/java/gearth/ui/subforms/extra/ExtraController.java index a0ba435..a1c552d 100644 --- a/G-Earth/src/main/java/gearth/ui/subforms/extra/ExtraController.java +++ b/G-Earth/src/main/java/gearth/ui/subforms/extra/ExtraController.java @@ -16,14 +16,13 @@ import gearth.ui.translations.TranslatableString; import javafx.application.Platform; import javafx.event.ActionEvent; import javafx.scene.control.*; -import javafx.scene.image.Image; import javafx.scene.layout.FlowPane; import javafx.scene.layout.GridPane; import javafx.scene.layout.Region; -import javafx.stage.Stage; import org.json.JSONObject; import java.io.IOException; +import java.util.Optional; /** * Created by Jonas on 06/04/18. @@ -33,6 +32,7 @@ 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 DEVELOP_CACHE_KEY = "develop_mode"; public static final String ALWAYS_ADMIN_KEY = "always_admin"; public static final String SOCKS_CACHE_KEY = "socks_config"; public static final String GPYTHON_CACHE_KEY = "use_gpython"; @@ -58,10 +58,10 @@ public class ExtraController extends SubForm implements SocksConfiguration { public CheckBox cbx_useSocks; public GridPane grd_socksInfo; - public TextField txt_socksPort; public TextField txt_socksIp; public CheckBox cbx_admin; - public Label lbl_notepad, lbl_proxyIp, lbl_proxyPort; + public Label lbl_notepad, lbl_proxyIp; + public CheckBox cbx_develop; private AdminService adminService; @@ -76,8 +76,7 @@ public class ExtraController extends SubForm implements SocksConfiguration { if (Cacher.getCacheContents().has(SOCKS_CACHE_KEY)) { JSONObject socksInitValue = Cacher.getCacheContents().getJSONObject(SOCKS_CACHE_KEY); - txt_socksIp.setText(socksInitValue.getString(SOCKS_IP)); - txt_socksPort.setText(socksInitValue.getString(SOCKS_PORT)); + txt_socksIp.setText(socksInitValue.getString(SOCKS_IP) + ":" + socksInitValue.getInt(SOCKS_PORT)); // cbx_socksUseIfNeeded.setSelected(socksInitValue.getBoolean(IGNORE_ONCE)); } @@ -115,6 +114,11 @@ public class ExtraController extends SubForm implements SocksConfiguration { } }); + if (Cacher.getCacheContents().has(DEVELOP_CACHE_KEY)) { + boolean inDevelopMode = Cacher.getCacheContents().getBoolean(DEVELOP_CACHE_KEY); + setDevelopMode(inDevelopMode); + } + updateAdvancedUI(); } @@ -123,13 +127,14 @@ public class ExtraController extends SubForm implements SocksConfiguration { Cacher.put(NOTEPAD_CACHE_KEY, txtarea_notepad.getText()); Cacher.put(GPYTHON_CACHE_KEY, cbx_gpython.isSelected()); Cacher.put(ALWAYS_ADMIN_KEY, cbx_admin.isSelected()); + Cacher.put(DEVELOP_CACHE_KEY, cbx_develop.isSelected()); saveSocksConfig(); } private void saveSocksConfig() { JSONObject jsonObject = new JSONObject(); - jsonObject.put(SOCKS_IP, txt_socksIp.getText()); - jsonObject.put(SOCKS_PORT, txt_socksPort.getText()); + jsonObject.put(SOCKS_IP, getSocksHost()); + jsonObject.put(SOCKS_PORT, getSocksPort()); // jsonObject.put(IGNORE_ONCE, cbx_socksUseIfNeeded.isSelected()); Cacher.put(SOCKS_CACHE_KEY, jsonObject); } @@ -155,12 +160,12 @@ public class ExtraController extends SubForm implements SocksConfiguration { @Override public int getSocksPort() { - return Integer.parseInt(txt_socksPort.getText()); + return Integer.parseInt(txt_socksIp.getText().split(":")[1]); } @Override public String getSocksHost() { - return txt_socksIp.getText(); + return txt_socksIp.getText().split(":")[0]; } @Override @@ -221,9 +226,43 @@ public class ExtraController extends SubForm implements SocksConfiguration { } + public void developCbxClick(ActionEvent actionEvent) { + if (cbx_develop.isSelected()) { + Platform.runLater(() -> { + Alert alert = new Alert(Alert.AlertType.WARNING, LanguageBundle.get("tab.extra.options.developmode.alert.title"), ButtonType.NO, ButtonType.YES); + alert.setTitle(LanguageBundle.get("tab.extra.options.developmode.alert.title")); + + Label lbl = new Label(LanguageBundle.get("tab.extra.options.developmode.alert.content")); + + alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE); + alert.getDialogPane().setContent(lbl); + + try { + Optional result = TitleBarController.create(alert).showAlertAndWait(); + if (!result.isPresent() || result.get() == ButtonType.NO) { + cbx_develop.setSelected(false); + } + else { + setDevelopMode(true); + } + } catch (IOException e) { + e.printStackTrace(); + } + }); + } + else { + setDevelopMode(false); + } + } + + private void setDevelopMode(boolean enabled) { + cbx_develop.setSelected(enabled); + getHConnection().setDeveloperMode(enabled); + parentController.extensionsController.setLocalInstallingEnabled(enabled); + } + public void adminCbxClick(ActionEvent actionEvent) { adminService.setEnabled(cbx_admin.isSelected()); - } private void initLanguageBinding() { @@ -231,10 +270,10 @@ public class ExtraController extends SubForm implements SocksConfiguration { lbl_notepad.textProperty().bind(new TranslatableString("%s:", "tab.extra.notepad")); lbl_proxyIp.textProperty().bind(new TranslatableString("%s:", "tab.extra.options.advanced.proxy.ip")); - lbl_proxyPort.textProperty().bind(new TranslatableString("%s:", "tab.extra.options.advanced.proxy.port")); cbx_alwaysOnTop.textProperty().bind(new TranslatableString("%s", "tab.extra.options.alwaysontop")); + cbx_develop.textProperty().bind(new TranslatableString("%s", "tab.extra.options.developmode")); cbx_admin.textProperty().bind(new TranslatableString("%s", "tab.extra.options.staffpermissions")); cbx_gpython.textProperty().bind(new TranslatableString("%s", "tab.extra.options.pythonscripting")); cbx_advanced.textProperty().bind(new TranslatableString("%s", "tab.extra.options.advanced")); diff --git a/G-Earth/src/main/resources/gearth/ui/subforms/extensions/Extensions.fxml b/G-Earth/src/main/resources/gearth/ui/subforms/extensions/Extensions.fxml index 44a9666..5dd0051 100644 --- a/G-Earth/src/main/resources/gearth/ui/subforms/extensions/Extensions.fxml +++ b/G-Earth/src/main/resources/gearth/ui/subforms/extensions/Extensions.fxml @@ -4,7 +4,7 @@ - + @@ -72,7 +72,7 @@ -