mirror of
https://github.com/sirjonasxx/G-Earth.git
synced 2024-11-30 04:00:50 +01:00
Prompt root certificate installation
This commit is contained in:
parent
322cb05ceb
commit
09105e956b
31
G-Earth/src/main/java/gearth/misc/RuntimeUtil.java
Normal file
31
G-Earth/src/main/java/gearth/misc/RuntimeUtil.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package gearth.misc;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
public final class RuntimeUtil {
|
||||||
|
|
||||||
|
public static String getCommandOutput(String[] command) throws IOException {
|
||||||
|
try {
|
||||||
|
final Runtime rt = Runtime.getRuntime();
|
||||||
|
final Process proc = rt.exec(command);
|
||||||
|
|
||||||
|
final BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
|
||||||
|
final StringBuilder result = new StringBuilder();
|
||||||
|
|
||||||
|
String line;
|
||||||
|
|
||||||
|
while ((line = stdInput.readLine()) != null) {
|
||||||
|
result.append(line);
|
||||||
|
result.append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,16 +1,26 @@
|
|||||||
package gearth.protocol.connection.proxy.nitro.http;
|
package gearth.protocol.connection.proxy.nitro.http;
|
||||||
|
|
||||||
|
import gearth.misc.ConfirmationDialog;
|
||||||
import gearth.protocol.connection.proxy.nitro.NitroConstants;
|
import gearth.protocol.connection.proxy.nitro.NitroConstants;
|
||||||
import gearth.protocol.connection.proxy.nitro.os.NitroOsFunctions;
|
import gearth.protocol.connection.proxy.nitro.os.NitroOsFunctions;
|
||||||
import gearth.protocol.connection.proxy.nitro.os.NitroOsFunctionsFactory;
|
import gearth.protocol.connection.proxy.nitro.os.NitroOsFunctionsFactory;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.scene.control.Alert;
|
||||||
|
import javafx.scene.control.ButtonType;
|
||||||
import org.littleshoot.proxy.HttpProxyServer;
|
import org.littleshoot.proxy.HttpProxyServer;
|
||||||
import org.littleshoot.proxy.impl.DefaultHttpProxyServer;
|
import org.littleshoot.proxy.impl.DefaultHttpProxyServer;
|
||||||
import org.littleshoot.proxy.mitm.Authority;
|
import org.littleshoot.proxy.mitm.Authority;
|
||||||
import org.littleshoot.proxy.mitm.CertificateSniffingMitmManager;
|
import org.littleshoot.proxy.mitm.CertificateSniffingMitmManager;
|
||||||
import org.littleshoot.proxy.mitm.RootCertificateException;
|
import org.littleshoot.proxy.mitm.RootCertificateException;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
public class NitroHttpProxy {
|
public class NitroHttpProxy {
|
||||||
|
|
||||||
|
private static final String ADMIN_WARNING_KEY = "admin_warning_dialog";
|
||||||
|
|
||||||
private final Authority authority;
|
private final Authority authority;
|
||||||
private final NitroOsFunctions osFunctions;
|
private final NitroOsFunctions osFunctions;
|
||||||
private final NitroHttpProxyServerCallback serverCallback;
|
private final NitroHttpProxyServerCallback serverCallback;
|
||||||
@ -24,6 +34,43 @@ public class NitroHttpProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean initializeCertificate() {
|
private boolean initializeCertificate() {
|
||||||
|
final File certificate = this.authority.aliasFile(".pem");
|
||||||
|
|
||||||
|
// All good if certificate is already trusted.
|
||||||
|
if (this.osFunctions.isRootCertificateTrusted(certificate)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let the user know about admin permissions.
|
||||||
|
final Semaphore waitForDialog = new Semaphore(0);
|
||||||
|
final AtomicBoolean shouldInstall = new AtomicBoolean();
|
||||||
|
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
Alert alert = ConfirmationDialog.createAlertWithOptOut(Alert.AlertType.WARNING, ADMIN_WARNING_KEY,
|
||||||
|
"Root certificate installation", null,
|
||||||
|
"G-Earth detected that you do not have the root certificate authority installed. " +
|
||||||
|
"This is required for Nitro to work, do you want to continue? " +
|
||||||
|
"G-Earth will ask you for Administrator permission if you do so.", "Remember my choice",
|
||||||
|
ButtonType.YES, ButtonType.NO
|
||||||
|
);
|
||||||
|
|
||||||
|
shouldInstall.set(!(alert.showAndWait().filter(t -> t == ButtonType.YES).isPresent()));
|
||||||
|
waitForDialog.release();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait for dialog choice.
|
||||||
|
try {
|
||||||
|
waitForDialog.acquire();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// User opted out.
|
||||||
|
if (!shouldInstall.get()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return this.osFunctions.installRootCertificate(this.authority.aliasFile(".pem"));
|
return this.osFunctions.installRootCertificate(this.authority.aliasFile(".pem"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ import java.io.File;
|
|||||||
|
|
||||||
public interface NitroOsFunctions {
|
public interface NitroOsFunctions {
|
||||||
|
|
||||||
|
boolean isRootCertificateTrusted(File certificate);
|
||||||
|
|
||||||
boolean installRootCertificate(File certificate);
|
boolean installRootCertificate(File certificate);
|
||||||
|
|
||||||
boolean registerSystemProxy(String host, int port);
|
boolean registerSystemProxy(String host, int port);
|
||||||
|
@ -1,15 +1,56 @@
|
|||||||
package gearth.protocol.connection.proxy.nitro.os.windows;
|
package gearth.protocol.connection.proxy.nitro.os.windows;
|
||||||
|
|
||||||
|
import com.sun.jna.platform.win32.Kernel32;
|
||||||
|
import com.sun.jna.platform.win32.WinBase;
|
||||||
|
import com.sun.jna.platform.win32.WinDef;
|
||||||
|
import com.sun.jna.ptr.IntByReference;
|
||||||
|
import gearth.misc.RuntimeUtil;
|
||||||
import gearth.protocol.connection.proxy.nitro.os.NitroOsFunctions;
|
import gearth.protocol.connection.proxy.nitro.os.NitroOsFunctions;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
public class NitroWindows implements NitroOsFunctions {
|
public class NitroWindows implements NitroOsFunctions {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the certificate is trusted by the local machine.
|
||||||
|
* @param certificate Absolute path to the certificate.
|
||||||
|
* @return true if trusted
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isRootCertificateTrusted(File certificate) {
|
||||||
|
try {
|
||||||
|
final String output = RuntimeUtil.getCommandOutput(new String[] {"cmd", "/c", " certutil.exe -f -verify " + certificate.getAbsolutePath()});
|
||||||
|
|
||||||
|
return !output.contains("CERT_TRUST_IS_UNTRUSTED_ROOT") &&
|
||||||
|
output.contains("dwInfoStatus=10c dwErrorStatus=0");
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean installRootCertificate(File certificate) {
|
public boolean installRootCertificate(File certificate) {
|
||||||
// TODO: Prompt registration
|
final String certificatePath = certificate.getAbsolutePath();
|
||||||
System.out.println(certificate.toString());
|
|
||||||
|
// Prompt UAC elevation.
|
||||||
|
WinDef.HINSTANCE result = NitroWindowsShell32.INSTANCE.ShellExecuteA(null, "runas", "cmd.exe", "/S /C \"certutil -addstore root " + certificatePath + "\"", null, 1);
|
||||||
|
|
||||||
|
// Wait for exit.
|
||||||
|
Kernel32.INSTANCE.WaitForSingleObject(result, WinBase.INFINITE);
|
||||||
|
|
||||||
|
// Exit code for certutil.
|
||||||
|
final IntByReference statusRef = new IntByReference(-1);
|
||||||
|
Kernel32.INSTANCE.GetExitCodeProcess(result, statusRef);
|
||||||
|
|
||||||
|
// Check if process exited without errors
|
||||||
|
if (statusRef.getValue() != -1) {
|
||||||
|
System.out.printf("Certutil command exited with exit code %s%n", statusRef.getValue());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
package gearth.protocol.connection.proxy.nitro.os.windows;
|
||||||
|
|
||||||
|
import com.sun.jna.Native;
|
||||||
|
import com.sun.jna.platform.win32.ShellAPI;
|
||||||
|
import com.sun.jna.platform.win32.WinDef;
|
||||||
|
import com.sun.jna.win32.StdCallLibrary;
|
||||||
|
|
||||||
|
public interface NitroWindowsShell32 extends ShellAPI, StdCallLibrary {
|
||||||
|
NitroWindowsShell32 INSTANCE = Native.loadLibrary("shell32", NitroWindowsShell32.class);
|
||||||
|
|
||||||
|
WinDef.HINSTANCE ShellExecuteA(WinDef.HWND hwnd,
|
||||||
|
String lpOperation,
|
||||||
|
String lpFile,
|
||||||
|
String lpParameters,
|
||||||
|
String lpDirectory,
|
||||||
|
int nShowCmd);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user