mirror of
https://github.com/sirjonasxx/G-Earth.git
synced 2024-11-26 18:30:52 +01:00
authentication for extensions as suggested by LittleJ
This commit is contained in:
parent
df87eb339d
commit
aaf3878878
@ -30,6 +30,7 @@ public abstract class Extension {
|
|||||||
private boolean isCorrupted = false;
|
private boolean isCorrupted = false;
|
||||||
private static final String[] PORT_FLAG = {"--port", "-p"};
|
private static final String[] PORT_FLAG = {"--port", "-p"};
|
||||||
private static final String[] FILE_FLAG = {"--filename", "-f"};
|
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 OutputStream out = null;
|
||||||
private final Map<Integer, List<MessageListener>> incomingMessageListeners = new HashMap<>();
|
private final Map<Integer, List<MessageListener>> incomingMessageListeners = new HashMap<>();
|
||||||
@ -81,6 +82,7 @@ public abstract class Extension {
|
|||||||
|
|
||||||
int port = Integer.parseInt(getArgument(args, PORT_FLAG));
|
int port = Integer.parseInt(getArgument(args, PORT_FLAG));
|
||||||
String file = getArgument(args, FILE_FLAG);
|
String file = getArgument(args, FILE_FLAG);
|
||||||
|
String cookie = getArgument(args, COOKIE_FLAG);
|
||||||
|
|
||||||
Socket gEarthExtensionServer = null;
|
Socket gEarthExtensionServer = null;
|
||||||
try {
|
try {
|
||||||
@ -123,6 +125,7 @@ public abstract class Extension {
|
|||||||
.appendBoolean(isOnClickMethodUsed())
|
.appendBoolean(isOnClickMethodUsed())
|
||||||
.appendBoolean(file != null)
|
.appendBoolean(file != null)
|
||||||
.appendString(file == null ? "": file)
|
.appendString(file == null ? "": file)
|
||||||
|
.appendString(cookie == null ? "" : cookie)
|
||||||
.appendBoolean(CANLEAVE)
|
.appendBoolean(CANLEAVE)
|
||||||
.appendBoolean(CANDELETE);
|
.appendBoolean(CANDELETE);
|
||||||
writeToStream(response.toBytes());
|
writeToStream(response.toBytes());
|
||||||
|
@ -7,14 +7,17 @@ import javafx.scene.control.ButtonType;
|
|||||||
import javafx.scene.control.CheckBox;
|
import javafx.scene.control.CheckBox;
|
||||||
import javafx.scene.control.DialogPane;
|
import javafx.scene.control.DialogPane;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Jonas on 27/09/18.
|
* Created by Jonas on 27/09/18.
|
||||||
*/
|
*/
|
||||||
public class ConfirmationDialog {
|
public class ConfirmationDialog {
|
||||||
|
|
||||||
public static boolean showDialog = true;
|
private static Set<String> 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<Boolean, Void> optOutAction,*/
|
String message, String optOutMessage, /*Callback<Boolean, Void> optOutAction,*/
|
||||||
ButtonType... buttonTypes) {
|
ButtonType... buttonTypes) {
|
||||||
Alert alert = new Alert(type);
|
Alert alert = new Alert(type);
|
||||||
@ -29,7 +32,11 @@ public class ConfirmationDialog {
|
|||||||
protected Node createDetailsButton() {
|
protected Node createDetailsButton() {
|
||||||
CheckBox optOut = new CheckBox();
|
CheckBox optOut = new CheckBox();
|
||||||
optOut.setText(optOutMessage);
|
optOut.setText(optOutMessage);
|
||||||
optOut.setOnAction(event -> showDialog = !optOut.isSelected());
|
optOut.setOnAction(event -> {
|
||||||
|
if (optOut.isSelected()) {
|
||||||
|
ignoreDialogs.add(dialogKey);
|
||||||
|
}
|
||||||
|
});
|
||||||
return optOut;
|
return optOut;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -46,5 +53,8 @@ public class ConfirmationDialog {
|
|||||||
return alert;
|
return alert;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean showDialog(String dialogKey) {
|
||||||
|
return !ignoreDialogs.contains(dialogKey);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -101,12 +101,14 @@ public class ExtensionItemContainer extends GridPane {
|
|||||||
Tooltip.install(deleteButton, uninstall);
|
Tooltip.install(deleteButton, uninstall);
|
||||||
deleteButton.show();
|
deleteButton.show();
|
||||||
GridPane this2 = this;
|
GridPane this2 = this;
|
||||||
|
|
||||||
|
final String uninstallKey = "uninstallExtension";
|
||||||
deleteButton.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
|
deleteButton.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
|
||||||
boolean delet_dis = true;
|
boolean delet_dis = true;
|
||||||
|
|
||||||
if (ConfirmationDialog.showDialog) {
|
if (ConfirmationDialog.showDialog(uninstallKey)) {
|
||||||
Alert alert = ConfirmationDialog.createAlertWithOptOut(Alert.AlertType.CONFIRMATION,
|
Alert alert = ConfirmationDialog.createAlertWithOptOut(Alert.AlertType.CONFIRMATION, uninstallKey
|
||||||
"Confirmation Dialog", null,
|
,"Confirmation Dialog", null,
|
||||||
"Are you sure want to uninstall this extension?", "Do not ask again",
|
"Are you sure want to uninstall this extension?", "Do not ask again",
|
||||||
ButtonType.YES, ButtonType.NO
|
ButtonType.YES, ButtonType.NO
|
||||||
);
|
);
|
||||||
|
@ -6,6 +6,7 @@ import gearth.protocol.HPacket;
|
|||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import gearth.ui.extensions.authentication.Authenticator;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -26,6 +27,7 @@ public class GEarthExtension {
|
|||||||
|
|
||||||
private boolean isInstalledExtension; // <- extension is in the extensions directory
|
private boolean isInstalledExtension; // <- extension is in the extensions directory
|
||||||
private String fileName;
|
private String fileName;
|
||||||
|
private String cookie;
|
||||||
|
|
||||||
private Socket connection;
|
private Socket connection;
|
||||||
|
|
||||||
@ -60,7 +62,14 @@ public class GEarthExtension {
|
|||||||
connection,
|
connection,
|
||||||
onDisconnectedCallback
|
onDisconnectedCallback
|
||||||
);
|
);
|
||||||
callback.act(gEarthExtension);
|
|
||||||
|
if (Authenticator.evaluate(gEarthExtension)) {
|
||||||
|
callback.act(gEarthExtension);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gEarthExtension.closeConnection(); //you shall not pass...
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,6 +88,7 @@ public class GEarthExtension {
|
|||||||
|
|
||||||
this.isInstalledExtension = extensionInfo.readBoolean();
|
this.isInstalledExtension = extensionInfo.readBoolean();
|
||||||
this.fileName = extensionInfo.readString();
|
this.fileName = extensionInfo.readString();
|
||||||
|
this.cookie = extensionInfo.readString();
|
||||||
|
|
||||||
this.leaveButtonVisible = extensionInfo.readBoolean();
|
this.leaveButtonVisible = extensionInfo.readBoolean();
|
||||||
this.deleteButtonVisible = extensionInfo.readBoolean();
|
this.deleteButtonVisible = extensionInfo.readBoolean();
|
||||||
@ -151,6 +161,9 @@ public class GEarthExtension {
|
|||||||
public String getFileName() {
|
public String getFileName() {
|
||||||
return fileName;
|
return fileName;
|
||||||
}
|
}
|
||||||
|
public String getCookie() {
|
||||||
|
return cookie;
|
||||||
|
}
|
||||||
public boolean isDeleteButtonVisible() {
|
public boolean isDeleteButtonVisible() {
|
||||||
return deleteButtonVisible;
|
return deleteButtonVisible;
|
||||||
}
|
}
|
||||||
|
@ -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<String, String> 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();
|
||||||
|
}
|
||||||
|
}
|
@ -25,7 +25,7 @@ public class ExecutionInfo {
|
|||||||
for(String type : extensionTypeToExecutionCommand.keySet()) {
|
for(String type : extensionTypeToExecutionCommand.keySet()) {
|
||||||
extensionTypeToExecutionCommand.put(
|
extensionTypeToExecutionCommand.put(
|
||||||
type,
|
type,
|
||||||
extensionTypeToExecutionCommand.get(type) + " -p {port} -f {filename}"
|
extensionTypeToExecutionCommand.get(type) + " -p {port} -f {filename} -c {cookie}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package gearth.ui.extensions.executer;
|
package gearth.ui.extensions.executer;
|
||||||
|
|
||||||
import gearth.Main;
|
import gearth.Main;
|
||||||
|
import gearth.ui.extensions.authentication.Authenticator;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -70,11 +71,13 @@ public class NormalExtensionRunner implements ExtensionRunner {
|
|||||||
|
|
||||||
public void tryRunExtension(String path, int port) {
|
public void tryRunExtension(String path, int port) {
|
||||||
try {
|
try {
|
||||||
|
String filename = Paths.get(path).getFileName().toString();
|
||||||
Runtime.getRuntime().exec(
|
Runtime.getRuntime().exec(
|
||||||
ExecutionInfo.getExecutionCommand(getFileExtension(path))
|
ExecutionInfo.getExecutionCommand(getFileExtension(path))
|
||||||
.replace("{path}", path)
|
.replace("{path}", path)
|
||||||
.replace("{port}", port+"")
|
.replace("{port}", port+"")
|
||||||
.replace("{filename}", Paths.get(path).getFileName().toString())
|
.replace("{filename}", filename)
|
||||||
|
.replace("{cookie}", Authenticator.generateCookieForExtension(filename))
|
||||||
);
|
);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -119,7 +122,7 @@ public class NormalExtensionRunner implements ExtensionRunner {
|
|||||||
private String getRandomString() {
|
private String getRandomString() {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
Random r = new Random();
|
Random r = new Random();
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 12; i++) {
|
||||||
builder.append(r.nextInt(10));
|
builder.append(r.nextInt(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user