interactsh_rs/client/
registered.rs1use base64::engine::general_purpose;
2use base64::Engine as _;
3use secrecy::{ExposeSecret, Secret};
4use smallvec::SmallVec;
5use snafu::ResultExt;
6
7use super::errors::{
8 client_poll_error,
9 client_registration_error,
10 ClientPollError,
11 ClientRegistrationError,
12};
13use super::http_utils::{self, Client, DeregisterData, HttpRequest, PollResponse};
14use crate::crypto::aes;
15use crate::crypto::rsa::RSAPrivKey;
16use crate::interaction_log::LogEntry;
17
18#[derive(Debug, Clone)]
21pub struct RegisteredClient {
22 pub(crate) rsa_key: RSAPrivKey,
23 pub(crate) server: String,
24 pub(crate) sub_domain: String,
25 pub(crate) correlation_id: String,
26 pub(crate) auth_token: Option<Secret<String>>,
27 pub(crate) secret_key: Secret<String>,
28 pub(crate) reqwest_client: reqwest::Client,
29 pub(crate) parse_logs: bool,
30}
31
32impl RegisteredClient {
33 #[deprecated(
34 since = "0.2.0",
35 note = "Renaming for accuracy. Use get_interaction_fqdn() instead."
36 )]
37 pub fn get_interaction_url(&self) -> String {
42 self.get_interaction_fqdn()
43 }
44
45 pub fn get_interaction_fqdn(&self) -> String {
48 format!("{}.{}", self.sub_domain, self.server)
49 }
50
51 pub async fn deregister(self) -> Result<(), ClientRegistrationError<RegisteredClient>> {
57 let post_data = DeregisterData {
58 correlation_id: self.correlation_id.clone(),
59 secret_key: self.secret_key.expose_secret().clone(),
60 };
61
62 self.do_registration_request(post_data)
63 .await
64 .context(client_registration_error::ClientRegistration { client: self })?;
65
66 Ok(())
67 }
68
69 pub async fn poll(&self) -> Result<Option<Vec<LogEntry>>, ClientPollError> {
71 let poll_url = format!("https://{}/poll", self.server);
72
73 let mut query_params = SmallVec::<[(String, String); 2]>::new();
74 query_params.push(("id".into(), self.correlation_id.clone()));
75 query_params.push(("secret".into(), self.secret_key.expose_secret().clone()));
76
77 let request_info = HttpRequest::new_get_request(poll_url, query_params);
78
79 let get_response = http_utils::make_http_request(
80 &self.reqwest_client,
81 self.auth_token.as_ref(),
82 request_info,
83 )
84 .await
85 .context(client_poll_error::PollFailure)?;
86
87 let status = &get_response.status();
88
89 if !status.is_success() {
90 let server_msg = get_response
91 .text()
92 .await
93 .unwrap_or_else(|_| "Unknown error".to_string());
94 let status_code = status.as_u16();
95 let error = client_poll_error::PollErrorStatus {
96 server_msg,
97 status_code,
98 };
99
100 return error.fail();
101 }
102
103 let response_body = get_response
104 .json::<PollResponse>()
105 .await
106 .context(client_poll_error::ResponseJsonParseFailed)?;
107
108 let response_body_data = match response_body.data_list {
109 Some(data) => {
110 if data.is_empty() {
111 return Ok(None);
112 } else {
113 data
114 }
115 }
116 None => return Ok(None),
117 };
118 let aes_key_decoded = general_purpose::STANDARD
119 .decode(&response_body.aes_key)
120 .context(client_poll_error::Base64DecodeFailed)?;
121
122 let mut results = Vec::new();
123 for data in response_body_data.iter() {
124 let data_decoded = general_purpose::STANDARD
125 .decode(data)
126 .context(client_poll_error::Base64DecodeFailed)?;
127 let decrypted_data = self.decrypt_data(&aes_key_decoded, &data_decoded)?;
128
129 let log_entry = if self.parse_logs {
130 LogEntry::try_parse_log(decrypted_data.as_str())
131 } else {
132 LogEntry::return_raw_log(decrypted_data.as_str())
133 };
134
135 results.push(log_entry);
136 }
137
138 Ok(Some(results))
139 }
140
141 fn decrypt_data(
142 &self,
143 aes_key: &[u8],
144 encrypted_data: &[u8],
145 ) -> Result<String, ClientPollError> {
146 let aes_plain_key = self
147 .rsa_key
148 .decrypt_data(aes_key)
149 .context(client_poll_error::AesKeyDecryptFailed)?;
150
151 let decrypted_data = aes::decrypt_data(&aes_plain_key, encrypted_data)
152 .context(client_poll_error::DataDecryptFailed)?;
153
154 let decrypted_string = String::from_utf8_lossy(&decrypted_data);
155
156 Ok(decrypted_string.into())
157 }
158}
159
160impl Client for RegisteredClient {
161 fn get_registration_url(&self) -> String {
162 format!("https://{}/deregister", &self.server)
163 }
164
165 fn get_reqwest_client(&self) -> &reqwest::Client {
166 &self.reqwest_client
167 }
168
169 fn get_auth_token(&self) -> Option<&Secret<String>> {
170 self.auth_token.as_ref()
171 }
172}