Skip to main content

htb_cli/models/
vpn.rs

1use serde::{Deserialize, Serialize};
2
3use crate::output::Tabular;
4
5#[derive(Debug, Deserialize)]
6pub struct ConnectionsResponse {
7    pub data: Vec<Connection>,
8}
9
10#[derive(Debug, Deserialize, Serialize)]
11pub struct Connection {
12    #[serde(rename = "type")]
13    pub connection_type: String,
14    #[serde(default)]
15    pub location_type_friendly: Option<String>,
16    #[serde(default)]
17    pub assigned_server: Option<AssignedServer>,
18}
19
20#[derive(Debug, Deserialize, Serialize)]
21pub struct AssignedServer {
22    pub id: u32,
23    pub friendly_name: String,
24    #[serde(default)]
25    pub current_clients: u32,
26    #[serde(default)]
27    pub location: Option<String>,
28}
29
30#[derive(Debug, Deserialize, Serialize)]
31pub struct VpnSwitchResponse {
32    #[serde(default)]
33    pub status: bool,
34    #[serde(default)]
35    pub message: Option<String>,
36    #[serde(default)]
37    pub data: Option<AssignedServer>,
38}
39
40impl Tabular for Connection {
41    fn headers() -> Vec<&'static str> {
42        vec!["Type", "Location", "Server", "Clients"]
43    }
44
45    fn row(&self) -> Vec<String> {
46        let (server, clients) = match &self.assigned_server {
47            Some(s) => (s.friendly_name.clone(), s.current_clients.to_string()),
48            None => ("-".into(), "-".into()),
49        };
50        vec![
51            self.connection_type.clone(),
52            self.location_type_friendly.clone().unwrap_or_default(),
53            server,
54            clients,
55        ]
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn deserialize_connections() {
65        let json = include_str!("../../tests/fixtures/v5-connections.json");
66        let result: ConnectionsResponse = serde_json::from_str(json).unwrap();
67        assert!(!result.data.is_empty());
68        let labs = result.data.iter().find(|c| c.connection_type == "labs");
69        assert!(labs.is_some());
70        assert!(labs.unwrap().assigned_server.is_some());
71    }
72
73    #[test]
74    fn deserialize_connection_status_empty() {
75        let json = include_str!("../../tests/fixtures/connection-status.json");
76        let result: Vec<serde_json::Value> = serde_json::from_str(json).unwrap();
77        assert!(result.is_empty());
78    }
79}