mirror of
https://github.com/sirjonasxx/G-Earth.git
synced 2024-11-26 10:20:51 +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;
|
||||
|
||||
import gearth.misc.ConfirmationDialog;
|
||||
import gearth.protocol.connection.proxy.nitro.NitroConstants;
|
||||
import gearth.protocol.connection.proxy.nitro.os.NitroOsFunctions;
|
||||
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.impl.DefaultHttpProxyServer;
|
||||
import org.littleshoot.proxy.mitm.Authority;
|
||||
import org.littleshoot.proxy.mitm.CertificateSniffingMitmManager;
|
||||
import org.littleshoot.proxy.mitm.RootCertificateException;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class NitroHttpProxy {
|
||||
|
||||
private static final String ADMIN_WARNING_KEY = "admin_warning_dialog";
|
||||
|
||||
private final Authority authority;
|
||||
private final NitroOsFunctions osFunctions;
|
||||
private final NitroHttpProxyServerCallback serverCallback;
|
||||
@ -24,6 +34,43 @@ public class NitroHttpProxy {
|
||||
}
|
||||
|
||||
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"));
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@ import java.io.File;
|
||||
|
||||
public interface NitroOsFunctions {
|
||||
|
||||
boolean isRootCertificateTrusted(File certificate);
|
||||
|
||||
boolean installRootCertificate(File certificate);
|
||||
|
||||
boolean registerSystemProxy(String host, int port);
|
||||
|
@ -1,15 +1,56 @@
|
||||
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 java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
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
|
||||
public boolean installRootCertificate(File certificate) {
|
||||
// TODO: Prompt registration
|
||||
System.out.println(certificate.toString());
|
||||
final String certificatePath = certificate.getAbsolutePath();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -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