Adds Download endpoint for client bundle
This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
package com.litoralregas.openvpn.openvpn;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public record OpenVpnBundleDownload(
|
||||||
|
String filename,
|
||||||
|
long size,
|
||||||
|
InputStream inputStream
|
||||||
|
) {
|
||||||
|
}
|
||||||
@@ -137,4 +137,13 @@ public class OpenVpnService {
|
|||||||
|
|
||||||
return sshService.executeOnConfiguredVps(command);
|
return sshService.executeOnConfiguredVps(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OpenVpnBundleDownload downloadClientBundle(String clientName) {
|
||||||
|
String filename = clientName + ".tar.gz";
|
||||||
|
|
||||||
|
return sshService.downloadFileFromConfiguredVps(
|
||||||
|
"/var/litoral_regas_openvpn/clients/" + filename,
|
||||||
|
filename
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,10 @@ import com.litoralregas.openvpn.openvpn.IpAllocationService;
|
|||||||
import com.litoralregas.openvpn.openvpn.OpenVpnService;
|
import com.litoralregas.openvpn.openvpn.OpenVpnService;
|
||||||
import com.litoralregas.openvpn.ssh.SshService;
|
import com.litoralregas.openvpn.ssh.SshService;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
|
import org.springframework.core.io.InputStreamResource;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -18,14 +22,12 @@ public class RouterController {
|
|||||||
|
|
||||||
private final RouterService service;
|
private final RouterService service;
|
||||||
private final DeploymentService deploymentService;
|
private final DeploymentService deploymentService;
|
||||||
private final SshService sshService;
|
|
||||||
private final IpAllocationService ipAllocationService;
|
private final IpAllocationService ipAllocationService;
|
||||||
private final OpenVpnService openVpnService;
|
private final OpenVpnService openVpnService;
|
||||||
|
|
||||||
public RouterController(RouterService service, DeploymentService deploymentService, SshService sshService, IpAllocationService ipAllocationService, OpenVpnService openVpnService) {
|
public RouterController(RouterService service, DeploymentService deploymentService, IpAllocationService ipAllocationService, OpenVpnService openVpnService) {
|
||||||
this.service = service;
|
this.service = service;
|
||||||
this.deploymentService = deploymentService;
|
this.deploymentService = deploymentService;
|
||||||
this.sshService = sshService;
|
|
||||||
this.ipAllocationService = ipAllocationService;
|
this.ipAllocationService = ipAllocationService;
|
||||||
this.openVpnService = openVpnService;
|
this.openVpnService = openVpnService;
|
||||||
}
|
}
|
||||||
@@ -45,7 +47,6 @@ public class RouterController {
|
|||||||
return service.findById(id);
|
return service.findById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public void delete(@PathVariable UUID id) {
|
public void delete(@PathVariable UUID id) {
|
||||||
service.delete(id);
|
service.delete(id);
|
||||||
@@ -154,4 +155,28 @@ public class RouterController {
|
|||||||
return DeploymentResponse.from(failed);
|
return DeploymentResponse.from(failed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}/bundle")
|
||||||
|
public ResponseEntity<InputStreamResource> downloadBundle(@PathVariable UUID id) {
|
||||||
|
Router router = service.findById(id);
|
||||||
|
|
||||||
|
if (router.getStatus() != RouterStatus.PROVISIONED) {
|
||||||
|
throw new IllegalStateException("Router is not provisioned yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
var allocation = ipAllocationService.findByRouterId(id);
|
||||||
|
|
||||||
|
var bundle = openVpnService.downloadClientBundle(
|
||||||
|
allocation.getClientName()
|
||||||
|
);
|
||||||
|
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.header(
|
||||||
|
HttpHeaders.CONTENT_DISPOSITION,
|
||||||
|
"attachment; filename=\"" + bundle.filename() + "\""
|
||||||
|
)
|
||||||
|
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
|
.contentLength(bundle.size())
|
||||||
|
.body(new InputStreamResource(bundle.inputStream()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,19 @@
|
|||||||
package com.litoralregas.openvpn.ssh;
|
package com.litoralregas.openvpn.ssh;
|
||||||
|
|
||||||
import com.jcraft.jsch.*;
|
import com.jcraft.jsch.*;
|
||||||
|
import com.litoralregas.openvpn.openvpn.OpenVpnBundleDownload;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.FilterInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class SshService {
|
public class SshService {
|
||||||
private final VpsSshProperties properties;
|
private final VpsSshProperties properties;
|
||||||
|
|
||||||
public SshService(VpsSshProperties properties) {
|
public SshService(VpsSshProperties properties) {
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
}
|
}
|
||||||
@@ -23,6 +28,70 @@ public class SshService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OpenVpnBundleDownload downloadFileFromConfiguredVps(
|
||||||
|
String remotePath,
|
||||||
|
String filename
|
||||||
|
) {
|
||||||
|
return downloadFile(
|
||||||
|
properties.getHost(),
|
||||||
|
properties.getPort(),
|
||||||
|
properties.getUsername(),
|
||||||
|
properties.getPassword(),
|
||||||
|
remotePath,
|
||||||
|
filename
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenVpnBundleDownload downloadFile(
|
||||||
|
String host,
|
||||||
|
int port,
|
||||||
|
String username,
|
||||||
|
String password,
|
||||||
|
String remotePath,
|
||||||
|
String filename
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
JSch jsch = new JSch();
|
||||||
|
|
||||||
|
Session session = jsch.getSession(username, host, port);
|
||||||
|
session.setPassword(password);
|
||||||
|
session.setConfig("StrictHostKeyChecking", "no");
|
||||||
|
session.connect(10_000);
|
||||||
|
|
||||||
|
ChannelSftp channel = (ChannelSftp) session.openChannel("sftp");
|
||||||
|
channel.connect(10_000);
|
||||||
|
|
||||||
|
SftpATTRS attrs = channel.lstat(remotePath);
|
||||||
|
long size = attrs.getSize();
|
||||||
|
|
||||||
|
InputStream inputStream = channel.get(remotePath);
|
||||||
|
|
||||||
|
InputStream wrapped = new FilterInputStream(inputStream) {
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
try {
|
||||||
|
super.close();
|
||||||
|
} finally {
|
||||||
|
channel.disconnect();
|
||||||
|
session.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return new OpenVpnBundleDownload(
|
||||||
|
filename,
|
||||||
|
size,
|
||||||
|
wrapped
|
||||||
|
);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Failed to download file from VPS: " + remotePath,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public SshCommandResult execute(
|
public SshCommandResult execute(
|
||||||
String host,
|
String host,
|
||||||
int port,
|
int port,
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user