Worky
This commit is contained in:
@@ -1,33 +1,28 @@
|
||||
package tech.nevets.tvpn;
|
||||
|
||||
import com.formdev.flatlaf.FlatDarkLaf;
|
||||
import tech.nevets.tvpn.ui.UIManager;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) throws IOException, InterruptedException {
|
||||
public static void main(String[] args) {
|
||||
|
||||
try {
|
||||
UIManager.setLookAndFeel(new FlatDarkLaf());
|
||||
javax.swing.UIManager.setLookAndFeel(new FlatDarkLaf());
|
||||
} catch (UnsupportedLookAndFeelException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (args.length == 0) {
|
||||
System.out.println("No args");
|
||||
System.exit(0);
|
||||
}
|
||||
File f = new File(Utils.APP_DIR + "/temp/");
|
||||
f.delete();
|
||||
f.mkdirs();
|
||||
|
||||
switch (args[0]) {
|
||||
case "load" -> WireGuardHandler.loadTunnel(Path.of("C:\\Users\\steven.v\\Desktop\\test.conf"));
|
||||
case "delete" -> WireGuardHandler.deleteTunnel("test");
|
||||
case "start" -> WireGuardHandler.startTunnel("test");
|
||||
case "stop" -> WireGuardHandler.stopTunnel("test");
|
||||
case "--help", "-h" -> {
|
||||
System.out.println("Options:\n - load\n - delete\n - start\n - stop");
|
||||
return;
|
||||
}
|
||||
}
|
||||
UIManager uim = new UIManager();
|
||||
uim.startUIFrame();
|
||||
uim.startLoginFrame();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Created by JFormDesigner on Tue Oct 08 20:59:17 EDT 2024
|
||||
*/
|
||||
|
||||
package tech.nevets.tvpn;
|
||||
|
||||
import javax.swing.*;
|
||||
import net.miginfocom.swing.*;
|
||||
|
||||
/**
|
||||
* @author steven
|
||||
*/
|
||||
public class UI extends JPanel {
|
||||
public UI() {
|
||||
initComponents();
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents @formatter:off
|
||||
|
||||
//======== this ========
|
||||
setLayout(new MigLayout(
|
||||
"hidemode 3",
|
||||
// columns
|
||||
"[fill]" +
|
||||
"[fill]",
|
||||
// rows
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]"));
|
||||
// JFormDesigner - End of component initialization //GEN-END:initComponents @formatter:on
|
||||
}
|
||||
|
||||
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables @formatter:off
|
||||
// JFormDesigner - End of variables declaration //GEN-END:variables @formatter:on
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
JFDML JFormDesigner: "8.2.4.0.393" Java: "17.0.9" encoding: "UTF-8"
|
||||
|
||||
new FormModel {
|
||||
contentType: "form/swing"
|
||||
root: new FormRoot {
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "hidemode 3"
|
||||
"$columnConstraints": "[fill][fill]"
|
||||
"$rowConstraints": "[][][]"
|
||||
} ) {
|
||||
name: "this"
|
||||
}, new FormLayoutConstraints( null ) {
|
||||
"location": new java.awt.Point( 0, 0 )
|
||||
"size": new java.awt.Dimension( 400, 300 )
|
||||
} )
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,57 @@
|
||||
package tech.nevets.tvpn;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.Map;
|
||||
|
||||
public class Utils {
|
||||
public static final File APP_DIR = new File("./tvpn/");
|
||||
public static final String WG_CONF_DIR = "C:\\Program Files\\WireGuard\\Data\\Configurations\\";
|
||||
public static final String API_ENDPOINT_BASE = "http://tvpn.lan/";
|
||||
|
||||
static {
|
||||
if (!APP_DIR.exists()) APP_DIR.mkdirs();
|
||||
}
|
||||
|
||||
public static String get(URI url, Map<String, String> headers) {
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
HttpRequest.Builder reqBuilder = HttpRequest.newBuilder()
|
||||
.GET()
|
||||
.uri(url);
|
||||
for (Map.Entry<String, String> header : headers.entrySet()) {
|
||||
reqBuilder.header(header.getKey(), header.getValue());
|
||||
}
|
||||
HttpRequest req = reqBuilder.build();
|
||||
HttpResponse<String> res;
|
||||
try {
|
||||
res = client.send(req, HttpResponse.BodyHandlers.ofString());
|
||||
return res.body();
|
||||
} catch (IOException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static String post(URI url, Map<String, String> headers, HttpRequest.BodyPublisher bodyPub) {
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
HttpRequest.Builder reqBuilder = HttpRequest.newBuilder()
|
||||
.POST(bodyPub)
|
||||
.uri(url);
|
||||
for (Map.Entry<String, String> header : headers.entrySet()) {
|
||||
reqBuilder.header(header.getKey(), header.getValue());
|
||||
}
|
||||
HttpRequest req = reqBuilder.build();
|
||||
HttpResponse<String> res;
|
||||
try {
|
||||
res = client.send(req, HttpResponse.BodyHandlers.ofString());
|
||||
return res.body();
|
||||
} catch (IOException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
package tech.nevets.tvpn;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static tech.nevets.tvpn.Utils.*;
|
||||
|
||||
public class WireGuardHandler {
|
||||
|
||||
public static void loadTunnel(Path tunnelConfig) throws IOException {
|
||||
Files.copy(tunnelConfig, Path.of(WG_CONF_DIR + tunnelConfig.getFileName().toString()));
|
||||
}
|
||||
|
||||
public static void deleteTunnel(String tunnelName) throws IOException {
|
||||
File f = new File(WG_CONF_DIR + tunnelName + ".conf.dpapi");
|
||||
f.delete();
|
||||
}
|
||||
|
||||
public static void startTunnel(String tunnelName) throws IOException, InterruptedException {
|
||||
Process proc = new ProcessBuilder()
|
||||
.directory(APP_DIR)
|
||||
.command("cmd", "/C", "wireguard.exe", "/installtunnelservice", WG_CONF_DIR + tunnelName + ".conf.dpapi")
|
||||
.inheritIO()
|
||||
.start();
|
||||
System.out.println("Start Tunnel: " + proc.waitFor());
|
||||
}
|
||||
|
||||
public static void stopTunnel(String tunnelName) throws IOException, InterruptedException {
|
||||
Process proc = new ProcessBuilder()
|
||||
.directory(APP_DIR)
|
||||
.command("cmd", "/C", "wireguard.exe", "/uninstalltunnelservice", tunnelName)
|
||||
.inheritIO()
|
||||
.start();
|
||||
System.out.println("Stop Tunnel: " + proc.waitFor());
|
||||
|
||||
}
|
||||
}
|
||||
72
src/main/java/tech/nevets/tvpn/auth/AuthManager.java
Normal file
72
src/main/java/tech/nevets/tvpn/auth/AuthManager.java
Normal file
@@ -0,0 +1,72 @@
|
||||
package tech.nevets.tvpn.auth;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import tech.nevets.tvpn.Utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class AuthManager {
|
||||
|
||||
public static UserToken serverAuth() {
|
||||
CompletableFuture<String> cf = new CompletableFuture<>();
|
||||
AuthServer as = new AuthServer(cf);
|
||||
// TODO create new thread to handle login so the app doesn't hang while logging in
|
||||
String response = cf.join();
|
||||
String[] resSplit = response.split(":");
|
||||
if (resSplit.length != 2) return new UserToken(false, "", 0, "Error");
|
||||
UserToken userToken = new UserToken(true, resSplit[0], Long.parseLong(resSplit[1]), "");
|
||||
|
||||
try {
|
||||
if (userToken.getToken().isEmpty()) return userToken;
|
||||
Files.writeString(Path.of(Utils.APP_DIR + "/token.txt"), userToken.getToken());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return userToken;
|
||||
}
|
||||
|
||||
public static UserToken httpAuth(String username, String password) {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Content-Type", "application/json");
|
||||
String body = "{" +
|
||||
"\"username\":\"" + username + "\"," +
|
||||
"\"password\":\"" + password + "\"" +
|
||||
"}";
|
||||
String res = Utils.post(URI.create(Utils.API_ENDPOINT_BASE + "api/auth.php"), headers, HttpRequest.BodyPublishers.ofString(body));
|
||||
JsonObject resObj = new Gson().fromJson(res, JsonObject.class);
|
||||
UserToken token = new UserToken(resObj.get("isAuthenticated").getAsBoolean(), resObj.get("token").getAsString(), resObj.get("expires").getAsLong(), resObj.get("message").getAsString());
|
||||
|
||||
try {
|
||||
if (token.getToken().isEmpty()) return token;
|
||||
Files.writeString(Path.of(Utils.APP_DIR + "/token.txt"), token.getToken());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
public static UserToken checkAuth() {
|
||||
try {
|
||||
String token = Files.readString(Path.of(Utils.APP_DIR + "/token.txt"));
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Authorization", "Bearer " + token);
|
||||
String res = Utils.get(URI.create(Utils.API_ENDPOINT_BASE + "api/auth.php"), headers);
|
||||
JsonObject resObj = new Gson().fromJson(res, JsonObject.class);
|
||||
return new UserToken(resObj.get("isAuthenticated").getAsBoolean(), resObj.get("token").getAsString(), resObj.get("expires").getAsLong(), resObj.get("message").getAsString());
|
||||
} catch (IOException e) {
|
||||
System.out.println("No token file found");
|
||||
return new UserToken(false, "", 0, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
76
src/main/java/tech/nevets/tvpn/auth/AuthServer.java
Normal file
76
src/main/java/tech/nevets/tvpn/auth/AuthServer.java
Normal file
@@ -0,0 +1,76 @@
|
||||
package tech.nevets.tvpn.auth;
|
||||
|
||||
import com.sun.net.httpserver.Headers;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class AuthServer {
|
||||
private HttpServer server;
|
||||
|
||||
public AuthServer(CompletableFuture<String> cf) {
|
||||
try {
|
||||
server = HttpServer.create(new InetSocketAddress(InetAddress.getLoopbackAddress(), 8342), 0);
|
||||
server.createContext("/", new AuthHandler(cf));
|
||||
server.setExecutor(null);
|
||||
server.start();
|
||||
|
||||
System.out.println("Server is running on port 8342");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
server.stop(0);
|
||||
}
|
||||
|
||||
// define a custom HttpHandler
|
||||
static class AuthHandler implements HttpHandler {
|
||||
private CompletableFuture<String> cf;
|
||||
|
||||
public AuthHandler(CompletableFuture<String> cf) {
|
||||
this.cf = cf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) throws IOException {
|
||||
// handle the request
|
||||
Headers headers = exchange.getRequestHeaders();
|
||||
List<String> strHeaders = headers.get("Token");
|
||||
String response;
|
||||
int status;
|
||||
String token = "";
|
||||
if (exchange.getRequestMethod().equals("POST")) {
|
||||
if (strHeaders == null || strHeaders.isEmpty()) {
|
||||
response = "Error, not token found.";
|
||||
status = 412;
|
||||
} else {
|
||||
response = "Successfully authenticated, you can now return to the app!";
|
||||
status = 200;
|
||||
token = strHeaders.getFirst();
|
||||
}
|
||||
} else {
|
||||
response = "Invalid Request Method";
|
||||
status = 405;
|
||||
}
|
||||
exchange.sendResponseHeaders(status, response.length());
|
||||
OutputStream os = exchange.getResponseBody();
|
||||
|
||||
os.write(response.getBytes());
|
||||
os.flush();
|
||||
os.close();
|
||||
|
||||
if (status == 200) {
|
||||
cf.complete(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
49
src/main/java/tech/nevets/tvpn/auth/Session.java
Normal file
49
src/main/java/tech/nevets/tvpn/auth/Session.java
Normal file
@@ -0,0 +1,49 @@
|
||||
package tech.nevets.tvpn.auth;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import tech.nevets.tvpn.Utils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class Session {
|
||||
private final UserToken token;
|
||||
|
||||
public static Session loadSession() {
|
||||
File f = new File(Utils.APP_DIR + "/session.json");
|
||||
if (f.exists() && f.isFile()) {
|
||||
Gson g = new Gson();
|
||||
try {
|
||||
BufferedReader br = Files.newBufferedReader(Path.of(Utils.APP_DIR + "/session.json"));
|
||||
return g.fromJson(br, Session.class);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Session(UserToken token) {
|
||||
this.token = token;
|
||||
saveSession();
|
||||
}
|
||||
|
||||
public UserToken getToken() {
|
||||
return this.token;
|
||||
}
|
||||
|
||||
public void invalidateSession() {
|
||||
this.token.invalidate();
|
||||
}
|
||||
|
||||
public void saveSession() {
|
||||
try {
|
||||
Files.writeString(Path.of(Utils.APP_DIR + "/session.json"), new Gson().toJson(token));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
69
src/main/java/tech/nevets/tvpn/auth/UserToken.java
Normal file
69
src/main/java/tech/nevets/tvpn/auth/UserToken.java
Normal file
@@ -0,0 +1,69 @@
|
||||
package tech.nevets.tvpn.auth;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import tech.nevets.tvpn.Utils;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static tech.nevets.tvpn.Utils.API_ENDPOINT_BASE;
|
||||
|
||||
public class UserToken {
|
||||
|
||||
private boolean isAuthenticated;
|
||||
private final String token;
|
||||
private final long expires;
|
||||
private final String message;
|
||||
|
||||
private String username;
|
||||
private String email;
|
||||
|
||||
public UserToken(boolean isAuthenticated, String token, long expires, String message) {
|
||||
this.isAuthenticated = isAuthenticated;
|
||||
this.token = token;
|
||||
this.expires = expires;
|
||||
this.message = message;
|
||||
|
||||
getUserInfo(token);
|
||||
}
|
||||
|
||||
private void getUserInfo(String userToken) {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Authorization", "Bearer " + userToken);
|
||||
String response = Utils.get(URI.create(API_ENDPOINT_BASE + "api/user-info.php"), headers);
|
||||
JsonObject resObj = new Gson().fromJson(response, JsonObject.class);
|
||||
|
||||
this.username = resObj.get("username").getAsString();
|
||||
this.email = resObj.get("email").getAsString();
|
||||
}
|
||||
|
||||
public boolean isAuthenticated() {
|
||||
return this.isAuthenticated;
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
this.isAuthenticated = false;
|
||||
}
|
||||
|
||||
public void checkExpiry() {
|
||||
if (System.currentTimeMillis() > expires) isAuthenticated = false;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return this.token;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return this.message;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return this.email;
|
||||
}
|
||||
}
|
||||
161
src/main/java/tech/nevets/tvpn/ui/LoginPanel.java
Normal file
161
src/main/java/tech/nevets/tvpn/ui/LoginPanel.java
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Created by JFormDesigner on Wed Oct 09 08:18:13 EDT 2024
|
||||
*/
|
||||
|
||||
package tech.nevets.tvpn.ui;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import javax.swing.*;
|
||||
import net.miginfocom.swing.*;
|
||||
import tech.nevets.tvpn.auth.AuthManager;
|
||||
import tech.nevets.tvpn.auth.UserToken;
|
||||
|
||||
/**
|
||||
* @author steven
|
||||
*/
|
||||
public class LoginPanel extends JPanel {
|
||||
private final UIManager uim;
|
||||
|
||||
public LoginPanel(UIManager uim) {
|
||||
this.uim = uim;
|
||||
|
||||
SwingWorker<UserToken, Void> worker = new SwingWorker<>() {
|
||||
@Override
|
||||
protected UserToken doInBackground() throws Exception {
|
||||
statusLabel.setText("Attempting login with stored token...");
|
||||
return AuthManager.checkAuth();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
try {
|
||||
UserToken token = get();
|
||||
|
||||
// Update the UI on the Event Dispatch Thread
|
||||
if (token.isAuthenticated()) {
|
||||
uim.getUIPanel().updateUserInfo(token.getUsername(), token.getEmail());
|
||||
uim.disposeLoginFrame();
|
||||
} else {
|
||||
statusLabel.setText("Unable to authenticate with stored token, please login");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
statusLabel.setText("An error occurred during login.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
initComponents();
|
||||
worker.execute();
|
||||
}
|
||||
|
||||
private void loginBtn(ActionEvent e) {
|
||||
// Immediately update the statusLabel on the UI thread
|
||||
this.statusLabel.setText("Logging in...");
|
||||
|
||||
// Use SwingWorker to handle the authentication process in the background
|
||||
SwingWorker<UserToken, Void> worker = new SwingWorker<>() {
|
||||
|
||||
@Override
|
||||
protected UserToken doInBackground() {
|
||||
// This is done in the background thread, so the UI won't be blocked
|
||||
return AuthManager.httpAuth(usernameField.getText(), new String(passwordField.getPassword()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
try {
|
||||
// Get the result of doInBackground
|
||||
UserToken token = get();
|
||||
|
||||
// Update the UI on the Event Dispatch Thread
|
||||
if (!token.isAuthenticated()) {
|
||||
statusLabel.setText(token.getMessage());
|
||||
passwordField.setText("");
|
||||
return;
|
||||
}
|
||||
|
||||
uim.getUIPanel().updateUserInfo(token.getUsername(), token.getEmail());
|
||||
uim.disposeLoginFrame();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
statusLabel.setText("An error occurred during login.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Start the background task
|
||||
worker.execute();
|
||||
}
|
||||
|
||||
|
||||
private void enterKeyTyped(KeyEvent e) {
|
||||
if (e.getKeyChar() == KeyEvent.VK_ENTER) {
|
||||
loginBtn(new ActionEvent(e.getSource(), e.getID(), "Login"));
|
||||
}
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents @formatter:off
|
||||
usernameLabel = new JLabel();
|
||||
usernameField = new JTextField();
|
||||
passwordLabel = new JLabel();
|
||||
passwordField = new JPasswordField();
|
||||
loginBtn = new JButton();
|
||||
statusLabel = new JLabel();
|
||||
|
||||
//======== this ========
|
||||
setLayout(new MigLayout(
|
||||
"hidemode 3",
|
||||
// columns
|
||||
"[fill]" +
|
||||
"[grow,fill]",
|
||||
// rows
|
||||
"[grow]" +
|
||||
"[shrink 0,top]" +
|
||||
"[shrink 0]" +
|
||||
"[grow,top]" +
|
||||
"[]"));
|
||||
|
||||
//---- usernameLabel ----
|
||||
usernameLabel.setText("Username");
|
||||
add(usernameLabel, "cell 0 1");
|
||||
|
||||
//---- usernameField ----
|
||||
usernameField.setMaximumSize(new Dimension(300, 2147483647));
|
||||
add(usernameField, "cell 1 1,growx");
|
||||
|
||||
//---- passwordLabel ----
|
||||
passwordLabel.setText("Password");
|
||||
add(passwordLabel, "cell 0 2");
|
||||
|
||||
//---- passwordField ----
|
||||
passwordField.setMaximumSize(new Dimension(300, 2147483647));
|
||||
passwordField.addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e) {
|
||||
enterKeyTyped(e);
|
||||
}
|
||||
});
|
||||
add(passwordField, "cell 1 2,growx");
|
||||
|
||||
//---- loginBtn ----
|
||||
loginBtn.setText("Login");
|
||||
loginBtn.setMaximumSize(new Dimension(200, 22));
|
||||
loginBtn.setMinimumSize(new Dimension(100, 22));
|
||||
loginBtn.addActionListener(e -> loginBtn(e));
|
||||
add(loginBtn, "cell 0 3 2 1,alignx center,growx 0");
|
||||
add(statusLabel, "cell 0 4 2 1");
|
||||
// JFormDesigner - End of component initialization //GEN-END:initComponents @formatter:on
|
||||
}
|
||||
|
||||
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables @formatter:off
|
||||
private JLabel usernameLabel;
|
||||
private JTextField usernameField;
|
||||
private JLabel passwordLabel;
|
||||
private JPasswordField passwordField;
|
||||
private JButton loginBtn;
|
||||
private JLabel statusLabel;
|
||||
// JFormDesigner - End of variables declaration //GEN-END:variables @formatter:on
|
||||
}
|
||||
56
src/main/java/tech/nevets/tvpn/ui/LoginPanel.jfd
Normal file
56
src/main/java/tech/nevets/tvpn/ui/LoginPanel.jfd
Normal file
@@ -0,0 +1,56 @@
|
||||
JFDML JFormDesigner: "8.2.4.0.393" Java: "17.0.9" encoding: "UTF-8"
|
||||
|
||||
new FormModel {
|
||||
contentType: "form/swing"
|
||||
root: new FormRoot {
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "hidemode 3"
|
||||
"$columnConstraints": "[fill][grow,fill]"
|
||||
"$rowConstraints": "[grow][shrink 0,top][shrink 0][grow,top][]"
|
||||
} ) {
|
||||
name: "this"
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "usernameLabel"
|
||||
"text": "Username"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JTextField" ) {
|
||||
name: "usernameField"
|
||||
"maximumSize": new java.awt.Dimension( 300, 2147483647 )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 1,growx"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "passwordLabel"
|
||||
"text": "Password"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 2"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JPasswordField" ) {
|
||||
name: "passwordField"
|
||||
"maximumSize": new java.awt.Dimension( 300, 2147483647 )
|
||||
addEvent( new FormEvent( "java.awt.event.KeyListener", "keyTyped", "enterKeyTyped", true ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 2,growx"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JButton" ) {
|
||||
name: "loginBtn"
|
||||
"text": "Login"
|
||||
"maximumSize": new java.awt.Dimension( 200, 22 )
|
||||
"minimumSize": new java.awt.Dimension( 100, 22 )
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "loginBtn", true ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 3 2 1,alignx center,growx 0"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "statusLabel"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 4 2 1"
|
||||
} )
|
||||
}, new FormLayoutConstraints( null ) {
|
||||
"location": new java.awt.Point( 0, 0 )
|
||||
"size": new java.awt.Dimension( 400, 300 )
|
||||
} )
|
||||
}
|
||||
}
|
||||
239
src/main/java/tech/nevets/tvpn/ui/UI.java
Normal file
239
src/main/java/tech/nevets/tvpn/ui/UI.java
Normal file
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Created by JFormDesigner on Tue Oct 08 20:59:17 EDT 2024
|
||||
*/
|
||||
|
||||
package tech.nevets.tvpn.ui;
|
||||
|
||||
import java.awt.event.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
|
||||
import net.miginfocom.swing.*;
|
||||
import tech.nevets.tvpn.Utils;
|
||||
import tech.nevets.tvpn.wg.WireGuardHandler;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author steven
|
||||
*/
|
||||
public class UI extends JPanel {
|
||||
private final UIManager uim;
|
||||
|
||||
public UI(UIManager uim) {
|
||||
initComponents();
|
||||
createTunnelsUI(WireGuardHandler.getTunnelConfigs());
|
||||
this.uim = uim;
|
||||
updateActiveTunnels();
|
||||
}
|
||||
|
||||
public void createTunnelsUI(List<String> tunnels) {
|
||||
// Clear the list model first in case we're refreshing
|
||||
listModel.clear();
|
||||
|
||||
// Add each tunnel string to the list model, which updates the JList
|
||||
for (String s : tunnels) {
|
||||
listModel.addElement("◦ " + s.substring(0, s.length() - 11));
|
||||
}
|
||||
}
|
||||
|
||||
private void updateActiveTunnels() {
|
||||
String tunnelName;
|
||||
if (WireGuardHandler.isActiveTunnel()) {
|
||||
tunnelName = WireGuardHandler.getActiveTunnels().getFirst();
|
||||
} else {
|
||||
tunnelName = "";
|
||||
}
|
||||
for (int i = 0; i < listModel.size(); i++) {
|
||||
String s = listModel.get(i).replace("◦", "").replace("•", "").trim();
|
||||
String newStr;
|
||||
if (s.equals(tunnelName)) {
|
||||
newStr = "• " + s;
|
||||
} else {
|
||||
newStr = "◦ " + s;
|
||||
}
|
||||
listModel.set(i, newStr);
|
||||
}
|
||||
tunnelList.updateUI();
|
||||
}
|
||||
|
||||
private String getSelectedTunnel() {
|
||||
return tunnelList.getSelectedValue().replace("•", "").replace("◦", "").trim();
|
||||
}
|
||||
|
||||
private void loadTunnel(String tunnelName) {
|
||||
List<String> tunnels = WireGuardHandler.getActiveTunnels();
|
||||
if (tunnels.size() > 1) { //TODO implement this logic
|
||||
System.out.println("Too many tunnels active, logic not implemented yet.");
|
||||
return;
|
||||
}
|
||||
if (WireGuardHandler.isActiveTunnel()) {
|
||||
String tunnel = tunnels.getFirst();
|
||||
WireGuardHandler.stopTunnel(tunnel);
|
||||
}
|
||||
WireGuardHandler.startTunnel(tunnelName);
|
||||
updateActiveTunnels();
|
||||
}
|
||||
|
||||
public void updateUserInfo(String username, String email) {
|
||||
userLabel.setText(username);
|
||||
emailLabel.setText(email);
|
||||
}
|
||||
|
||||
private void loadBtn(ActionEvent e) {
|
||||
loadTunnel(getSelectedTunnel());
|
||||
}
|
||||
|
||||
private void showConfigBtn(ActionEvent e) {
|
||||
List<String> activeTunnels = WireGuardHandler.getActiveTunnels();
|
||||
if (activeTunnels.size() > 1) { //TODO implement this logic
|
||||
System.out.println("Too many tunnels active, logic not implemented yet.");
|
||||
return;
|
||||
}
|
||||
String originalTunnel = activeTunnels.getFirst();
|
||||
if (originalTunnel.equals(getSelectedTunnel())) {
|
||||
try {
|
||||
String tunnelConfig = Files.readString(Path.of(Utils.APP_DIR + "/" + getSelectedTunnel() + ".conf"));
|
||||
configArea.setText(tunnelConfig);
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return;
|
||||
}
|
||||
loadTunnel(getSelectedTunnel());
|
||||
WireGuardHandler.getActiveConfig(getSelectedTunnel());
|
||||
try {
|
||||
String tunnelConfig = Files.readString(Path.of(Utils.APP_DIR + "/" + getSelectedTunnel() + ".conf"));
|
||||
configArea.setText(tunnelConfig);
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
loadTunnel(originalTunnel);
|
||||
}
|
||||
|
||||
private void stopTunnelBtn(ActionEvent e) {
|
||||
List<String> tunnels = WireGuardHandler.getActiveTunnels();
|
||||
for (String tunnel : tunnels) {
|
||||
WireGuardHandler.stopTunnel(tunnel);
|
||||
}
|
||||
updateActiveTunnels();
|
||||
}
|
||||
|
||||
private void importBtn(ActionEvent e) {
|
||||
JFileChooser fileChooser = new JFileChooser(System.getenv("HOME"));
|
||||
fileChooser.setFileFilter(new FileNameExtensionFilter("WireGuard Config", "conf"));
|
||||
fileChooser.showOpenDialog(null);
|
||||
File f = fileChooser.getSelectedFile();
|
||||
if (f == null) return;
|
||||
try {
|
||||
WireGuardHandler.loadTunnel(Path.of(f.getAbsolutePath()));
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
listModel.addElement("◦ " + f.getName().replace(".conf", ""));
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents @formatter:off
|
||||
tunnelsLabel = new JLabel();
|
||||
userLabel = new JLabel();
|
||||
tunnelScrollPane = new JScrollPane();
|
||||
listModel = new DefaultListModel<>();
|
||||
tunnelList = new JList<>(listModel);
|
||||
emailLabel = new JLabel();
|
||||
configScrollPane = new JScrollPane();
|
||||
configArea = new JTextArea();
|
||||
showConfigBtn = new JButton();
|
||||
importBtn = new JButton();
|
||||
startTunnelBtn = new JButton();
|
||||
stopTunnelBtn = new JButton();
|
||||
|
||||
//======== this ========
|
||||
setLayout(new MigLayout(
|
||||
"hidemode 3",
|
||||
// columns
|
||||
"[fill]" +
|
||||
"[fill]" +
|
||||
"[grow,fill]" +
|
||||
"[fill]",
|
||||
// rows
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]"));
|
||||
|
||||
//---- tunnelsLabel ----
|
||||
tunnelsLabel.setText("Tunnels");
|
||||
add(tunnelsLabel, "cell 0 0 2 1");
|
||||
|
||||
//---- userLabel ----
|
||||
userLabel.setText("Guest");
|
||||
add(userLabel, "cell 3 0");
|
||||
|
||||
//======== tunnelScrollPane ========
|
||||
{
|
||||
tunnelScrollPane.setViewportView(tunnelList);
|
||||
}
|
||||
add(tunnelScrollPane, "cell 0 1 2 8,growy");
|
||||
|
||||
//---- emailLabel ----
|
||||
emailLabel.setText("guest@tvpn.lan");
|
||||
add(emailLabel, "cell 3 1");
|
||||
|
||||
//======== configScrollPane ========
|
||||
{
|
||||
configScrollPane.setViewportView(configArea);
|
||||
}
|
||||
add(configScrollPane, "cell 2 3 2 6,growy");
|
||||
|
||||
//---- showConfigBtn ----
|
||||
showConfigBtn.setText("Show Config");
|
||||
showConfigBtn.addActionListener(e -> showConfigBtn(e));
|
||||
add(showConfigBtn, "cell 0 9 2 1");
|
||||
|
||||
//---- importBtn ----
|
||||
importBtn.setText("Import Tunnel");
|
||||
importBtn.addActionListener(e -> importBtn(e));
|
||||
add(importBtn, "cell 3 9");
|
||||
|
||||
//---- startTunnelBtn ----
|
||||
startTunnelBtn.setText("Start Tunnel");
|
||||
startTunnelBtn.addActionListener(e -> loadBtn(e));
|
||||
add(startTunnelBtn, "cell 0 10 2 1");
|
||||
|
||||
//---- stopTunnelBtn ----
|
||||
stopTunnelBtn.setText("Stop Tunnel");
|
||||
stopTunnelBtn.addActionListener(e -> stopTunnelBtn(e));
|
||||
add(stopTunnelBtn, "cell 0 11 2 1");
|
||||
// JFormDesigner - End of component initialization //GEN-END:initComponents @formatter:on
|
||||
}
|
||||
|
||||
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables @formatter:off
|
||||
private JLabel tunnelsLabel;
|
||||
private JLabel userLabel;
|
||||
private JScrollPane tunnelScrollPane;
|
||||
private JList<String> tunnelList;
|
||||
private JLabel emailLabel;
|
||||
private JScrollPane configScrollPane;
|
||||
private JTextArea configArea;
|
||||
private JButton showConfigBtn;
|
||||
private JButton importBtn;
|
||||
private JButton startTunnelBtn;
|
||||
private JButton stopTunnelBtn;
|
||||
// JFormDesigner - End of variables declaration //GEN-END:variables @formatter:on
|
||||
|
||||
private DefaultListModel<String> listModel;
|
||||
}
|
||||
84
src/main/java/tech/nevets/tvpn/ui/UI.jfd
Normal file
84
src/main/java/tech/nevets/tvpn/ui/UI.jfd
Normal file
@@ -0,0 +1,84 @@
|
||||
JFDML JFormDesigner: "8.2.4.0.393" Java: "17.0.9" encoding: "UTF-8"
|
||||
|
||||
new FormModel {
|
||||
contentType: "form/swing"
|
||||
root: new FormRoot {
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "hidemode 3"
|
||||
"$columnConstraints": "[fill][fill][grow,fill][fill]"
|
||||
"$rowConstraints": "[][][][][][][][][][][][]"
|
||||
} ) {
|
||||
name: "this"
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "tunnelsLabel"
|
||||
"text": "Tunnels"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 0 2 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "userLabel"
|
||||
"text": "Guest"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 3 0"
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
|
||||
name: "tunnelScrollPane"
|
||||
add( new FormComponent( "javax.swing.JList" ) {
|
||||
name: "tunnelList"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.preCreateCode": "listModel = new DefaultListModel<>();"
|
||||
"JavaCodeGenerator.typeParameters": "String"
|
||||
"JavaCodeGenerator.customCreateCode": "new JList<>(listModel);"
|
||||
}
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 1 2 8,growy"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "emailLabel"
|
||||
"text": "guest@tvpn.lan"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 3 1"
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
|
||||
name: "configScrollPane"
|
||||
add( new FormComponent( "javax.swing.JTextArea" ) {
|
||||
name: "configArea"
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 3 2 6,growy"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JButton" ) {
|
||||
name: "showConfigBtn"
|
||||
"text": "Show Config"
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showConfigBtn", true ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 9 2 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JButton" ) {
|
||||
name: "importBtn"
|
||||
"text": "Import Tunnel"
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "importBtn", true ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 3 9"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JButton" ) {
|
||||
name: "startTunnelBtn"
|
||||
"text": "Start Tunnel"
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "loadBtn", true ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 10 2 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JButton" ) {
|
||||
name: "stopTunnelBtn"
|
||||
"text": "Stop Tunnel"
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "stopTunnelBtn", true ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 11 2 1"
|
||||
} )
|
||||
}, new FormLayoutConstraints( null ) {
|
||||
"location": new java.awt.Point( 0, 0 )
|
||||
"size": new java.awt.Dimension( 400, 300 )
|
||||
} )
|
||||
}
|
||||
}
|
||||
59
src/main/java/tech/nevets/tvpn/ui/UIManager.java
Normal file
59
src/main/java/tech/nevets/tvpn/ui/UIManager.java
Normal file
@@ -0,0 +1,59 @@
|
||||
package tech.nevets.tvpn.ui;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class UIManager {
|
||||
private List<JPanel> panels = new ArrayList<>();
|
||||
private JFrame loginFrame;
|
||||
private JFrame uiFrame;
|
||||
private UI uiPanel;
|
||||
|
||||
|
||||
public void startLoginFrame() {
|
||||
loginFrame = new JFrame();
|
||||
JPanel p = new LoginPanel(this);
|
||||
loginFrame.add(p);
|
||||
panels.add(p);
|
||||
loginFrame.pack();
|
||||
loginFrame.setTitle("Login");
|
||||
loginFrame.setSize(340, 170);
|
||||
loginFrame.setResizable(false);
|
||||
loginFrame.setLocationRelativeTo(null);
|
||||
loginFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
|
||||
loginFrame.setVisible(true);
|
||||
}
|
||||
|
||||
protected void disposeLoginFrame() {
|
||||
loginFrame.dispose();
|
||||
}
|
||||
|
||||
public void startUIFrame() {
|
||||
uiFrame = new JFrame();
|
||||
uiPanel = new UI(this);
|
||||
uiFrame.add(uiPanel);
|
||||
panels.add(uiPanel);
|
||||
uiFrame.pack();
|
||||
uiFrame.setTitle("TVPN");
|
||||
uiFrame.setSize(720, 480);
|
||||
uiFrame.setLocationRelativeTo(null);
|
||||
uiFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
uiFrame.setVisible(true);
|
||||
}
|
||||
|
||||
protected UI getUIPanel() {
|
||||
return uiPanel;
|
||||
}
|
||||
|
||||
public void startFileChooserFrame(JFileChooser fileChooser) {
|
||||
JFrame f = new JFrame();
|
||||
f.add(fileChooser);
|
||||
f.pack();
|
||||
f.setTitle("Choose WireGuard Config File");
|
||||
f.setLocationRelativeTo(null);
|
||||
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
|
||||
f.setVisible(true);
|
||||
}
|
||||
|
||||
}
|
||||
79
src/main/java/tech/nevets/tvpn/wg/WGTesting.java
Normal file
79
src/main/java/tech/nevets/tvpn/wg/WGTesting.java
Normal file
@@ -0,0 +1,79 @@
|
||||
package tech.nevets.tvpn.wg;
|
||||
|
||||
import tech.nevets.tvpn.Utils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class WGTesting {
|
||||
|
||||
public static void main(String[] args) throws IOException, InterruptedException {
|
||||
List<String> configs = listConfigs();
|
||||
//String currentTunnel = getCurrentTunnel();
|
||||
//System.out.println(currentTunnel);
|
||||
//pullTunnelConfig(currentTunnel);
|
||||
//WireGuardHandler.stopTunnel(currentTunnel);
|
||||
Random r = ThreadLocalRandom.current();
|
||||
int index = r.nextInt(configs.size());
|
||||
System.out.println("Index: " + index);
|
||||
System.out.println("Random Tunnel: " + configs.get(index).substring(0, configs.get(index).length() - 11));
|
||||
//WireGuardHandler.startTunnel(configs.get(index).substring(0, configs.get(index).length() - 11));
|
||||
}
|
||||
|
||||
public static String getCurrentTunnel() throws IOException {
|
||||
String[] rSplit = getWGShowLines();
|
||||
for (String s : rSplit) {
|
||||
if (s.toLowerCase().contains("interface")) {
|
||||
return s.split(":")[1].trim();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static List<String> getCurrentTunnels() throws IOException {
|
||||
String[] rSplit = getWGShowLines();
|
||||
List<String> tunnels = new ArrayList<>();
|
||||
for (String s : rSplit) {
|
||||
if (s.toLowerCase().contains("interface")) {
|
||||
tunnels.add(s.split(":")[1].trim());
|
||||
}
|
||||
}
|
||||
return tunnels;
|
||||
}
|
||||
|
||||
public static String[] getWGShowLines() throws IOException {
|
||||
ProcessBuilder pb = new ProcessBuilder();
|
||||
pb.command("cmd", "/C", "wg.exe", "show");
|
||||
Process p = pb.start();
|
||||
String result = new String(p.getInputStream().readAllBytes());
|
||||
return result.split("\n");
|
||||
}
|
||||
|
||||
public static void pullTunnelConfig(String tunnelName) throws IOException {
|
||||
ProcessBuilder pb = new ProcessBuilder();
|
||||
pb.redirectOutput(new File(Utils.APP_DIR + "/" + tunnelName + ".conf"));
|
||||
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
|
||||
pb.command("cmd", "/C", "wg.exe", "showconf", tunnelName);
|
||||
pb.start();
|
||||
}
|
||||
|
||||
public static List<String> listConfigs() throws IOException {
|
||||
List<Path> filePaths = new ArrayList<>();
|
||||
Path path = Path.of(Utils.WG_CONF_DIR);
|
||||
Files.walk(path)
|
||||
.filter(Files::isRegularFile)
|
||||
.forEach(filePaths::add);
|
||||
List<String> fileNames = new ArrayList<>();
|
||||
for(Path p : filePaths) {
|
||||
String fullPath = p.toString();
|
||||
fileNames.add(fullPath.substring(fullPath.lastIndexOf("\\") + 1));
|
||||
}
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
}
|
||||
144
src/main/java/tech/nevets/tvpn/wg/WireGuardHandler.java
Normal file
144
src/main/java/tech/nevets/tvpn/wg/WireGuardHandler.java
Normal file
@@ -0,0 +1,144 @@
|
||||
package tech.nevets.tvpn.wg;
|
||||
|
||||
import tech.nevets.tvpn.Utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static tech.nevets.tvpn.Utils.*;
|
||||
|
||||
public class WireGuardHandler {
|
||||
|
||||
public static void loadTunnel(Path tunnelConfig) throws IOException {
|
||||
Files.copy(tunnelConfig, Path.of(WG_CONF_DIR + tunnelConfig.getFileName().toString()));
|
||||
}
|
||||
|
||||
public static boolean deleteTunnel(String tunnelName) {
|
||||
File f = new File(WG_CONF_DIR + tunnelName + ".conf.dpapi");
|
||||
return f.delete();
|
||||
}
|
||||
|
||||
public static void startTunnel(String tunnelName) {
|
||||
try {
|
||||
Process proc = new ProcessBuilder()
|
||||
.directory(APP_DIR)
|
||||
.command("cmd", "/C", "wireguard.exe", "/installtunnelservice", WG_CONF_DIR + tunnelName + ".conf.dpapi")
|
||||
.inheritIO()
|
||||
.start();
|
||||
System.out.println("Start Tunnel: " + proc.waitFor());
|
||||
if (getWGShow() == null) return;
|
||||
for (float f = 0; getWGShow().isEmpty(); f += 0.5f) {
|
||||
//while (getWGShow().isEmpty()) {
|
||||
if (f >= 12) {
|
||||
System.out.println("Start tunnel timed out");
|
||||
return;
|
||||
}
|
||||
System.out.println("Waiting for wg start... " + f + "s");
|
||||
Thread.sleep(500);
|
||||
}
|
||||
System.out.println("Tunnel Started");
|
||||
} catch (IOException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void stopTunnel(String tunnelName) {
|
||||
try {
|
||||
Process proc = new ProcessBuilder()
|
||||
.directory(APP_DIR)
|
||||
.command("cmd", "/C", "wireguard.exe", "/uninstalltunnelservice", tunnelName)
|
||||
.inheritIO()
|
||||
.start();
|
||||
System.out.println("Stop Tunnel: " + proc.waitFor());
|
||||
if (getWGShow() == null) return;
|
||||
for (float f = 0; !getWGShow().isEmpty(); f += 0.5f) {
|
||||
// while (!getWGShow().isEmpty()) {
|
||||
if (f >= 12) {
|
||||
System.out.println("Stop tunnel timed out");
|
||||
return;
|
||||
}
|
||||
System.out.println("Waiting for wg stop... " + f + "s");
|
||||
Thread.sleep(500);
|
||||
}
|
||||
System.out.println("Tunnel Stopped");
|
||||
} catch (IOException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getTunnelConfigs() {
|
||||
List<Path> filePaths = new ArrayList<>();
|
||||
Path path = Path.of(Utils.WG_CONF_DIR);
|
||||
try (Stream<Path> ps = Files.walk(path)) {
|
||||
ps.filter(Files::isRegularFile)
|
||||
.forEach(filePaths::add);
|
||||
List<String> fileNames = new ArrayList<>();
|
||||
for(Path p : filePaths) {
|
||||
String fullPath = p.toString();
|
||||
fileNames.add(fullPath.substring(fullPath.lastIndexOf("\\") + 1));
|
||||
}
|
||||
return fileNames;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getActiveTunnels() {
|
||||
String[] rSplit = getWGShowLines();
|
||||
List<String> tunnels = new ArrayList<>();
|
||||
for (String s : rSplit) {
|
||||
if (s.toLowerCase().contains("interface")) {
|
||||
tunnels.add(s.split(":")[1].trim());
|
||||
}
|
||||
}
|
||||
return tunnels;
|
||||
}
|
||||
|
||||
private static String getWGShow() {
|
||||
ProcessBuilder pb = new ProcessBuilder();
|
||||
pb.command("cmd", "/C", "wg.exe", "show");
|
||||
try {
|
||||
Process p = pb.start();
|
||||
return new String(p.getInputStream().readAllBytes());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String[] getWGShowLines() {
|
||||
String result = getWGShow();
|
||||
if (result == null) {
|
||||
return new String[]{};
|
||||
}
|
||||
return result.split("\n");
|
||||
}
|
||||
|
||||
public static void getActiveConfig(String tunnelName) {
|
||||
ProcessBuilder pb = new ProcessBuilder();
|
||||
System.out.println("Tunnel Name: " + tunnelName);
|
||||
String outFile = Utils.APP_DIR + "/" + tunnelName + ".conf";
|
||||
System.out.println("Out File: " + outFile);
|
||||
pb.redirectOutput(new File(outFile));
|
||||
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
|
||||
pb.command("cmd", "/C", "wg.exe", "showconf", tunnelName);
|
||||
try {
|
||||
Process p = pb.start();
|
||||
p.waitFor();
|
||||
} catch (IOException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isActiveTunnel() {
|
||||
getActiveTunnels().forEach(System.out::println);
|
||||
|
||||
return !getActiveTunnels().isEmpty();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user