Fixed and added more health support plus network endpoint
This commit is contained in:
@@ -31,10 +31,15 @@ public class ApiKeyAuthFilter extends OncePerRequestFilter {
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(
|
||||
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
FilterChain filterChain
|
||||
) throws ServletException, IOException {
|
||||
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
String providedApiKey = request.getHeader(API_KEY_HEADER);
|
||||
String expectedApiKey = securityProperties.getApiKey();
|
||||
|
||||
@@ -1,14 +1,26 @@
|
||||
package com.litoralregas.vpnorchestrator.config;
|
||||
|
||||
import com.litoralregas.vpnorchestrator.auth.ApiKeyAuthFilter;
|
||||
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties({
|
||||
AppSecurityProperties.class,
|
||||
@@ -18,28 +30,95 @@ public class SecurityConfig {
|
||||
|
||||
private final AppSecurityProperties securityProperties;
|
||||
|
||||
public SecurityConfig(AppSecurityProperties securityProperties) {
|
||||
public SecurityConfig(
|
||||
AppSecurityProperties securityProperties
|
||||
) {
|
||||
this.securityProperties = securityProperties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
ApiKeyAuthFilter apiKeyAuthFilter = new ApiKeyAuthFilter(securityProperties);
|
||||
public SecurityFilterChain securityFilterChain(
|
||||
HttpSecurity http
|
||||
) throws Exception {
|
||||
|
||||
ApiKeyAuthFilter apiKeyAuthFilter =
|
||||
new ApiKeyAuthFilter(securityProperties);
|
||||
|
||||
return http
|
||||
.csrf(csrf -> csrf.disable())
|
||||
.cors(cors -> cors.disable())
|
||||
|
||||
.cors(cors -> {
|
||||
})
|
||||
|
||||
.formLogin(form -> form.disable())
|
||||
|
||||
.httpBasic(basic -> basic.disable())
|
||||
|
||||
.logout(logout -> logout.disable())
|
||||
.sessionManagement(session -> session
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||
|
||||
.sessionManagement(session ->
|
||||
session.sessionCreationPolicy(
|
||||
SessionCreationPolicy.STATELESS
|
||||
)
|
||||
)
|
||||
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.requestMatchers("/actuator/health").permitAll()
|
||||
.requestMatchers(
|
||||
"/actuator/health"
|
||||
).permitAll()
|
||||
|
||||
.requestMatchers(
|
||||
HttpMethod.OPTIONS,
|
||||
"/**"
|
||||
).permitAll()
|
||||
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.addFilterBefore(apiKeyAuthFilter, UsernamePasswordAuthenticationFilter.class)
|
||||
|
||||
.addFilterBefore(
|
||||
apiKeyAuthFilter,
|
||||
UsernamePasswordAuthenticationFilter.class
|
||||
)
|
||||
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CorsConfigurationSource corsConfigurationSource() {
|
||||
|
||||
CorsConfiguration configuration =
|
||||
new CorsConfiguration();
|
||||
|
||||
configuration.setAllowedOrigins(
|
||||
List.of(
|
||||
"http://localhost:1420"
|
||||
)
|
||||
);
|
||||
|
||||
configuration.setAllowedMethods(
|
||||
List.of(
|
||||
"GET",
|
||||
"POST",
|
||||
"PUT",
|
||||
"DELETE",
|
||||
"OPTIONS"
|
||||
)
|
||||
);
|
||||
|
||||
configuration.setAllowedHeaders(
|
||||
List.of("*")
|
||||
);
|
||||
|
||||
configuration.setAllowCredentials(true);
|
||||
|
||||
UrlBasedCorsConfigurationSource source =
|
||||
new UrlBasedCorsConfigurationSource();
|
||||
|
||||
source.registerCorsConfiguration(
|
||||
"/**",
|
||||
configuration
|
||||
);
|
||||
|
||||
return source;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.litoralregas.vpnorchestrator.vps;
|
||||
|
||||
import com.litoralregas.vpnorchestrator.vps.dto.NetworkTrafficResponse;
|
||||
import com.litoralregas.vpnorchestrator.vps.dto.VpsHealthResponse;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -26,4 +27,9 @@ public class VpsController {
|
||||
public String rollbackLastBackup() {
|
||||
return wireGuardService.restoreLastWireGuardBackup();
|
||||
}
|
||||
|
||||
@GetMapping("/network-traffic")
|
||||
public NetworkTrafficResponse getNetworkTraffic() {
|
||||
return wireGuardService.getNetworkTraffic();
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.litoralregas.vpnorchestrator.vps;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.litoralregas.vpnorchestrator.vps.dto.NetworkTrafficResponse;
|
||||
import com.litoralregas.vpnorchestrator.vps.dto.VpsHealthResponse;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -76,19 +77,57 @@ public class WireGuardService {
|
||||
}
|
||||
|
||||
public VpsHealthResponse getVpsHealth() {
|
||||
|
||||
SshCommandResult result = sshService.executeOnConfiguredVps(
|
||||
"sudo /usr/local/sbin/lr-vps-health"
|
||||
);
|
||||
|
||||
if (result.exitCode() != 0) {
|
||||
throw new SshCommandException(
|
||||
"Failed to query VPS health: " + result.stderr()
|
||||
"Failed to query VPS health: "
|
||||
+ result.stderr()
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
return objectMapper.readValue(result.stdout(), VpsHealthResponse.class);
|
||||
|
||||
VpsHealthResponse base =
|
||||
objectMapper.readValue(
|
||||
result.stdout(),
|
||||
VpsHealthResponse.class
|
||||
);
|
||||
|
||||
Set<String> usedIps =
|
||||
findUsedVpnIps();
|
||||
|
||||
return new VpsHealthResponse(
|
||||
|
||||
base.wireGuardInterface(),
|
||||
base.wireGuardRunning(),
|
||||
base.wireGuardPeerCount(),
|
||||
base.wireGuardConfigExists(),
|
||||
|
||||
base.udp2rawService(),
|
||||
base.udp2rawActive(),
|
||||
|
||||
base.latestWireGuardBackup(),
|
||||
|
||||
base.systemUptime(),
|
||||
|
||||
base.diskUsagePercent(),
|
||||
base.memoryUsagePercent(),
|
||||
|
||||
base.loadAverage(),
|
||||
base.publicIp(),
|
||||
|
||||
true,
|
||||
usedIps.size(),
|
||||
65534,
|
||||
java.time.Instant.now().toString()
|
||||
);
|
||||
|
||||
} catch (JsonProcessingException e) {
|
||||
|
||||
throw new IllegalStateException(
|
||||
"Invalid VPS health JSON returned by script",
|
||||
e
|
||||
@@ -123,4 +162,34 @@ public class WireGuardService {
|
||||
|
||||
return result.stdout();
|
||||
}
|
||||
|
||||
public NetworkTrafficResponse getNetworkTraffic() {
|
||||
|
||||
SshCommandResult result =
|
||||
sshService.executeOnConfiguredVps(
|
||||
"sudo /usr/local/sbin/lr-vps-network-traffic"
|
||||
);
|
||||
|
||||
if (result.exitCode() != 0) {
|
||||
throw new SshCommandException(
|
||||
"Failed to query network traffic: "
|
||||
+ result.stderr()
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
return objectMapper.readValue(
|
||||
result.stdout(),
|
||||
NetworkTrafficResponse.class
|
||||
);
|
||||
|
||||
} catch (JsonProcessingException e) {
|
||||
|
||||
throw new IllegalStateException(
|
||||
"Invalid network traffic JSON returned by script",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.litoralregas.vpnorchestrator.vps.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public record NetworkTrafficResponse(
|
||||
|
||||
@JsonProperty("interface")
|
||||
String interfaceName,
|
||||
|
||||
int sampleSeconds,
|
||||
long rxBytesPerSecond,
|
||||
long txBytesPerSecond,
|
||||
double downloadMbps,
|
||||
double uploadMbps,
|
||||
String updatedAt
|
||||
) {
|
||||
}
|
||||
@@ -1,17 +1,28 @@
|
||||
package com.litoralregas.vpnorchestrator.vps.dto;
|
||||
|
||||
public record VpsHealthResponse(
|
||||
|
||||
String wireGuardInterface,
|
||||
boolean wireGuardRunning,
|
||||
int wireGuardPeerCount,
|
||||
boolean wireGuardConfigExists,
|
||||
|
||||
String udp2rawService,
|
||||
boolean udp2rawActive,
|
||||
|
||||
String latestWireGuardBackup,
|
||||
|
||||
String systemUptime,
|
||||
|
||||
int diskUsagePercent,
|
||||
int memoryUsagePercent,
|
||||
|
||||
String loadAverage,
|
||||
String publicIp
|
||||
String publicIp,
|
||||
|
||||
boolean backend,
|
||||
int ipPoolUsed,
|
||||
int ipPoolTotal,
|
||||
String updatedAt
|
||||
) {
|
||||
}
|
||||
Reference in New Issue
Block a user