From ea0b002af1e99da401296da54261dae8aa477b33 Mon Sep 17 00:00:00 2001 From: litoral05 Date: Tue, 5 May 2026 11:54:05 +0100 Subject: [PATCH] Parse OpenVPN clients into structured response --- .../openvpn/OpenVpnClientResponse.java | 13 +++++ .../openvpn/openvpn/OpenVpnController.java | 5 +- .../openvpn/openvpn/OpenVpnService.java | 49 +++++++++++++++++-- 3 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/litoralregas/openvpn/openvpn/OpenVpnClientResponse.java diff --git a/src/main/java/com/litoralregas/openvpn/openvpn/OpenVpnClientResponse.java b/src/main/java/com/litoralregas/openvpn/openvpn/OpenVpnClientResponse.java new file mode 100644 index 0000000..203c7e4 --- /dev/null +++ b/src/main/java/com/litoralregas/openvpn/openvpn/OpenVpnClientResponse.java @@ -0,0 +1,13 @@ +package com.litoralregas.openvpn.openvpn; + +public record OpenVpnClientResponse( + String clientName, + String vpnIp, + String vpnNetmask, + String lanSubnet, + String lanNetmask, + boolean serverRoute, + boolean bundle, + boolean folder +) { +} \ No newline at end of file diff --git a/src/main/java/com/litoralregas/openvpn/openvpn/OpenVpnController.java b/src/main/java/com/litoralregas/openvpn/openvpn/OpenVpnController.java index 418aa2a..e6fc2f8 100644 --- a/src/main/java/com/litoralregas/openvpn/openvpn/OpenVpnController.java +++ b/src/main/java/com/litoralregas/openvpn/openvpn/OpenVpnController.java @@ -1,8 +1,9 @@ package com.litoralregas.openvpn.openvpn; -import com.litoralregas.openvpn.ssh.SshCommandResult; import org.springframework.web.bind.annotation.*; +import java.util.List; + @RestController @RequestMapping("/api/openvpn") public class OpenVpnController { @@ -14,7 +15,7 @@ public class OpenVpnController { } @GetMapping("/clients") - public SshCommandResult getClients() { + public List getClients() { return service.listClients(); } } \ No newline at end of file diff --git a/src/main/java/com/litoralregas/openvpn/openvpn/OpenVpnService.java b/src/main/java/com/litoralregas/openvpn/openvpn/OpenVpnService.java index 9de848c..9b8e666 100644 --- a/src/main/java/com/litoralregas/openvpn/openvpn/OpenVpnService.java +++ b/src/main/java/com/litoralregas/openvpn/openvpn/OpenVpnService.java @@ -1,9 +1,11 @@ package com.litoralregas.openvpn.openvpn; -import com.litoralregas.openvpn.ssh.SshCommandResult; import com.litoralregas.openvpn.ssh.SshService; import org.springframework.stereotype.Service; +import java.util.ArrayList; +import java.util.List; + @Service public class OpenVpnService { @@ -15,9 +17,50 @@ public class OpenVpnService { this.sshService = sshService; } - public SshCommandResult listClients() { - return sshService.executeOnConfiguredVps( + public List listClients() { + var result = sshService.executeOnConfiguredVps( TOOLS_PATH + "/list-clients.sh" ); + + if (result.exitCode() != 0) { + throw new IllegalStateException(result.stderr()); + } + + return parseClients(result.stdout()); + } + + private List parseClients(String stdout) { + List clients = new ArrayList<>(); + + String[] blocks = stdout.split("\\n\\n"); + + for (String block : blocks) { + if (!block.contains("Client:")) { + continue; + } + + clients.add(new OpenVpnClientResponse( + extractValue(block, "Client:"), + extractValue(block, "VPN IP:"), + extractValue(block, "VPN netmask:"), + extractValue(block, "LAN subnet:"), + extractValue(block, "LAN netmask:"), + "yes".equalsIgnoreCase(extractValue(block, "Server route:")), + "yes".equalsIgnoreCase(extractValue(block, "Bundle:")), + "yes".equalsIgnoreCase(extractValue(block, "Folder:")) + )); + } + + return clients; + } + + private String extractValue(String block, String label) { + for (String line : block.split("\\n")) { + if (line.trim().startsWith(label)) { + return line.substring(line.indexOf(":") + 1).trim(); + } + } + + return null; } } \ No newline at end of file