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}