Skip to main content

htb_cli/api/
machines.rs

1use serde_json::json;
2
3use crate::error::HtbError;
4use crate::models::machine::{
5    ActiveVmInfo, ActiveVmResponse, Machine, MachineProfileResponse, TodoListResponse,
6};
7use crate::models::{ActionResponse, Paginated};
8
9use super::HtbClient;
10
11pub struct MachineApi<'a>(pub(crate) &'a HtbClient);
12
13impl MachineApi<'_> {
14    pub async fn list(&self, page: u32, per_page: u32) -> Result<Paginated<Machine>, HtbError> {
15        self.0
16            .get(&format!("/api/v5/machines?per_page={per_page}&page={page}"))
17            .await
18    }
19
20    pub async fn profile(&self, name_or_id: &str) -> Result<Machine, HtbError> {
21        let encoded = super::encode_path(name_or_id);
22        let resp: MachineProfileResponse = self
23            .0
24            .get(&format!("/api/v4/machine/profile/{encoded}"))
25            .await?;
26        Ok(resp.info)
27    }
28
29    pub async fn start(&self, machine_id: u64) -> Result<ActionResponse, HtbError> {
30        self.0
31            .post("/api/v4/vm/spawn", &json!({"machine_id": machine_id}))
32            .await
33    }
34
35    pub async fn stop(&self, machine_id: u64) -> Result<ActionResponse, HtbError> {
36        self.0
37            .post("/api/v4/vm/terminate", &json!({"machine_id": machine_id}))
38            .await
39    }
40
41    pub async fn reset(&self, machine_id: u64) -> Result<ActionResponse, HtbError> {
42        self.0
43            .post("/api/v4/vm/reset", &json!({"machine_id": machine_id}))
44            .await
45    }
46
47    pub async fn submit_flag(
48        &self,
49        machine_id: u64,
50        flag: &str,
51        difficulty: u32,
52    ) -> Result<ActionResponse, HtbError> {
53        self.0
54            .post(
55                "/api/v4/machine/own",
56                &json!({"flag": flag, "id": machine_id, "difficulty": difficulty}),
57            )
58            .await
59    }
60
61    pub async fn extend(&self, machine_id: u64) -> Result<ActionResponse, HtbError> {
62        self.0
63            .post("/api/v4/vm/extend", &json!({"machine_id": machine_id}))
64            .await
65    }
66
67    pub async fn active(&self) -> Result<Option<ActiveVmInfo>, HtbError> {
68        let resp: ActiveVmResponse = self.0.get("/api/v5/virtual_machine/active").await?;
69        Ok(resp.info)
70    }
71
72    pub async fn todo_list(&self) -> Result<Vec<Machine>, HtbError> {
73        let resp: TodoListResponse = self.0.get("/api/v4/machine/todo").await?;
74        Ok(resp.info)
75    }
76
77    pub async fn todo_toggle(&self, machine_id: u64) -> Result<ActionResponse, HtbError> {
78        self.0
79            .post(
80                &format!("/api/v4/machine/todo/update/{machine_id}"),
81                &json!({}),
82            )
83            .await
84    }
85}