diff --git a/G-Earth-UI/src/main/java/gearth/extensions/Extension.java b/G-Earth-UI/src/main/java/gearth/extensions/Extension.java index b4dc3e0..b613fd5 100644 --- a/G-Earth-UI/src/main/java/gearth/extensions/Extension.java +++ b/G-Earth-UI/src/main/java/gearth/extensions/Extension.java @@ -30,6 +30,7 @@ public abstract class Extension { private boolean isCorrupted = false; private static final String[] PORT_FLAG = {"--port", "-p"}; private static final String[] FILE_FLAG = {"--filename", "-f"}; + private static final String[] COOKIE_FLAG = {"--auth-token", "-c"}; // don't add a cookie or filename when debugging private OutputStream out = null; private final Map> incomingMessageListeners = new HashMap<>(); @@ -81,6 +82,7 @@ public abstract class Extension { int port = Integer.parseInt(getArgument(args, PORT_FLAG)); String file = getArgument(args, FILE_FLAG); + String cookie = getArgument(args, COOKIE_FLAG); Socket gEarthExtensionServer = null; try { @@ -123,6 +125,7 @@ public abstract class Extension { .appendBoolean(isOnClickMethodUsed()) .appendBoolean(file != null) .appendString(file == null ? "": file) + .appendString(cookie == null ? "" : cookie) .appendBoolean(CANLEAVE) .appendBoolean(CANDELETE); writeToStream(response.toBytes()); diff --git a/G-Earth-UI/src/main/java/gearth/misc/ConfirmationDialog.java b/G-Earth-UI/src/main/java/gearth/misc/ConfirmationDialog.java index 3f9e7c6..1287a4b 100644 --- a/G-Earth-UI/src/main/java/gearth/misc/ConfirmationDialog.java +++ b/G-Earth-UI/src/main/java/gearth/misc/ConfirmationDialog.java @@ -7,14 +7,17 @@ import javafx.scene.control.ButtonType; import javafx.scene.control.CheckBox; import javafx.scene.control.DialogPane; +import java.util.HashSet; +import java.util.Set; + /** * Created by Jonas on 27/09/18. */ public class ConfirmationDialog { - public static boolean showDialog = true; + private static Set ignoreDialogs = new HashSet<>(); - public static Alert createAlertWithOptOut(Alert.AlertType type, String title, String headerText, + public static Alert createAlertWithOptOut(Alert.AlertType type, String dialogKey, String title, String headerText, String message, String optOutMessage, /*Callback optOutAction,*/ ButtonType... buttonTypes) { Alert alert = new Alert(type); @@ -29,7 +32,11 @@ public class ConfirmationDialog { protected Node createDetailsButton() { CheckBox optOut = new CheckBox(); optOut.setText(optOutMessage); - optOut.setOnAction(event -> showDialog = !optOut.isSelected()); + optOut.setOnAction(event -> { + if (optOut.isSelected()) { + ignoreDialogs.add(dialogKey); + } + }); return optOut; } }); @@ -46,5 +53,8 @@ public class ConfirmationDialog { return alert; } + public static boolean showDialog(String dialogKey) { + return !ignoreDialogs.contains(dialogKey); + } } diff --git a/G-Earth-UI/src/main/java/gearth/ui/extensions/ExtensionItemContainer.java b/G-Earth-UI/src/main/java/gearth/ui/extensions/ExtensionItemContainer.java index f1dd7da..92193f1 100644 --- a/G-Earth-UI/src/main/java/gearth/ui/extensions/ExtensionItemContainer.java +++ b/G-Earth-UI/src/main/java/gearth/ui/extensions/ExtensionItemContainer.java @@ -101,12 +101,14 @@ public class ExtensionItemContainer extends GridPane { Tooltip.install(deleteButton, uninstall); deleteButton.show(); GridPane this2 = this; + + final String uninstallKey = "uninstallExtension"; deleteButton.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> { boolean delet_dis = true; - if (ConfirmationDialog.showDialog) { - Alert alert = ConfirmationDialog.createAlertWithOptOut(Alert.AlertType.CONFIRMATION, - "Confirmation Dialog", null, + if (ConfirmationDialog.showDialog(uninstallKey)) { + Alert alert = ConfirmationDialog.createAlertWithOptOut(Alert.AlertType.CONFIRMATION, uninstallKey + ,"Confirmation Dialog", null, "Are you sure want to uninstall this extension?", "Do not ask again", ButtonType.YES, ButtonType.NO ); diff --git a/G-Earth-UI/src/main/java/gearth/ui/extensions/GEarthExtension.java b/G-Earth-UI/src/main/java/gearth/ui/extensions/GEarthExtension.java index fc22af9..1d0d7a8 100644 --- a/G-Earth-UI/src/main/java/gearth/ui/extensions/GEarthExtension.java +++ b/G-Earth-UI/src/main/java/gearth/ui/extensions/GEarthExtension.java @@ -6,6 +6,7 @@ import gearth.protocol.HPacket; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; +import gearth.ui.extensions.authentication.Authenticator; import java.net.Socket; import java.util.ArrayList; import java.util.List; @@ -26,6 +27,7 @@ public class GEarthExtension { private boolean isInstalledExtension; // <- extension is in the extensions directory private String fileName; + private String cookie; private Socket connection; @@ -60,7 +62,14 @@ public class GEarthExtension { connection, onDisconnectedCallback ); - callback.act(gEarthExtension); + + if (Authenticator.evaluate(gEarthExtension)) { + callback.act(gEarthExtension); + } + else { + gEarthExtension.closeConnection(); //you shall not pass... + } + break; } } @@ -79,6 +88,7 @@ public class GEarthExtension { this.isInstalledExtension = extensionInfo.readBoolean(); this.fileName = extensionInfo.readString(); + this.cookie = extensionInfo.readString(); this.leaveButtonVisible = extensionInfo.readBoolean(); this.deleteButtonVisible = extensionInfo.readBoolean(); @@ -151,6 +161,9 @@ public class GEarthExtension { public String getFileName() { return fileName; } + public String getCookie() { + return cookie; + } public boolean isDeleteButtonVisible() { return deleteButtonVisible; } diff --git a/G-Earth-UI/src/main/java/gearth/ui/extensions/authentication/Authenticator.java b/G-Earth-UI/src/main/java/gearth/ui/extensions/authentication/Authenticator.java new file mode 100644 index 0000000..d0fc38b --- /dev/null +++ b/G-Earth-UI/src/main/java/gearth/ui/extensions/authentication/Authenticator.java @@ -0,0 +1,101 @@ +package gearth.ui.extensions.authentication; + +import gearth.extensions.Extension; +import gearth.misc.ConfirmationDialog; +import gearth.ui.extensions.GEarthExtension; +import gearth.ui.extensions.executer.ExtensionRunner; +import gearth.ui.extensions.executer.ExtensionRunnerFactory; +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; + +/** + * Created by Jonas on 16/10/18. + */ +public class Authenticator { + + private static Map cookies = new HashMap<>(); + + public static String generateCookieForExtension(String filename) { + String cookie = getRandomCookie(); + cookies.put(filename, cookie); + + return cookie; + } + + public static boolean evaluate(GEarthExtension extension) { + if (extension.isInstalledExtension()) { + return claimSession(extension.getFileName(), extension.getCookie()); + } + else { + return askForPermission(extension); + } + } + + /** + * authenticator: authenticate an extension and remove the cookie + * @param filename + * @param cookie + * @return if the extension is authenticated + */ + private static boolean claimSession(String filename, String cookie) { + if (cookies.containsKey(filename) && cookies.get(filename).equals(cookie)) { + cookies.remove(filename); + return true; + } + return false; + } + + private static volatile boolean rememberOption = false; + //for not-installed extensions, popup a dialog + private static boolean askForPermission(GEarthExtension extension) { + boolean[] allowConnection = {true}; + + final String connectExtensionKey = "allow_extension_connection"; + + if (ConfirmationDialog.showDialog(connectExtensionKey)) { + boolean[] done = {false}; + Platform.runLater(() -> { + Alert alert = ConfirmationDialog.createAlertWithOptOut(Alert.AlertType.WARNING, connectExtensionKey + ,"Confirmation Dialog", null, + "Extension \""+extension.getTitle()+"\" tries to connect but isn't known to G-Earth, accept this connection?", "Remember my choice", + ButtonType.YES, ButtonType.NO + ); + + if (!(alert.showAndWait().filter(t -> t == ButtonType.YES).isPresent())) { + allowConnection[0] = false; + } + done[0] = true; + if (!ConfirmationDialog.showDialog(connectExtensionKey)) { + rememberOption = allowConnection[0]; + } + }); + + while (!done[0]) { + try { + Thread.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + return allowConnection[0]; + } + + return rememberOption; + } + + private static String getRandomCookie() { + StringBuilder builder = new StringBuilder(); + Random r = new Random(); + for (int i = 0; i < 40; i++) { + builder.append(r.nextInt(40)); + } + + return builder.toString(); + } +} diff --git a/G-Earth-UI/src/main/java/gearth/ui/extensions/executer/ExecutionInfo.java b/G-Earth-UI/src/main/java/gearth/ui/extensions/executer/ExecutionInfo.java index 9d0f241..43db6b1 100644 --- a/G-Earth-UI/src/main/java/gearth/ui/extensions/executer/ExecutionInfo.java +++ b/G-Earth-UI/src/main/java/gearth/ui/extensions/executer/ExecutionInfo.java @@ -25,7 +25,7 @@ public class ExecutionInfo { for(String type : extensionTypeToExecutionCommand.keySet()) { extensionTypeToExecutionCommand.put( type, - extensionTypeToExecutionCommand.get(type) + " -p {port} -f {filename}" + extensionTypeToExecutionCommand.get(type) + " -p {port} -f {filename} -c {cookie}" ); } diff --git a/G-Earth-UI/src/main/java/gearth/ui/extensions/executer/NormalExtensionRunner.java b/G-Earth-UI/src/main/java/gearth/ui/extensions/executer/NormalExtensionRunner.java index 4a5e91f..918991f 100644 --- a/G-Earth-UI/src/main/java/gearth/ui/extensions/executer/NormalExtensionRunner.java +++ b/G-Earth-UI/src/main/java/gearth/ui/extensions/executer/NormalExtensionRunner.java @@ -1,6 +1,7 @@ package gearth.ui.extensions.executer; import gearth.Main; +import gearth.ui.extensions.authentication.Authenticator; import java.io.File; import java.io.IOException; @@ -70,11 +71,13 @@ public class NormalExtensionRunner implements ExtensionRunner { public void tryRunExtension(String path, int port) { try { + String filename = Paths.get(path).getFileName().toString(); Runtime.getRuntime().exec( ExecutionInfo.getExecutionCommand(getFileExtension(path)) .replace("{path}", path) .replace("{port}", port+"") - .replace("{filename}", Paths.get(path).getFileName().toString()) + .replace("{filename}", filename) + .replace("{cookie}", Authenticator.generateCookieForExtension(filename)) ); } catch (IOException e) { e.printStackTrace(); @@ -119,7 +122,7 @@ public class NormalExtensionRunner implements ExtensionRunner { private String getRandomString() { StringBuilder builder = new StringBuilder(); Random r = new Random(); - for (int i = 0; i < 10; i++) { + for (int i = 0; i < 12; i++) { builder.append(r.nextInt(10)); }