robloxapi_s/
https.rs

1use crate::{errors::ApiError, errors::RobloxApiErrorResponse, ApiResult, Client};
2use reqwest::{header, Method, RequestBuilder, Response};
3use serde::de::{self, DeserializeOwned};
4
5#[derive(Debug, Clone)]
6pub struct Https {
7    pub client: reqwest::Client,
8}
9
10impl Default for Https {
11    fn default() -> Self {
12        Self::new()
13    }
14}
15
16impl Client {
17    /// # setCookie
18    /// Set the cookie for the client; This function is needed to execute specific API requests such as `.create_developer_product()`
19    ///
20    /// # Example
21    /// ```
22    ///
23    /// let COOKIE: &str = "_|WARNING:-DO-NOT-SHARE-THIS.--Sharing-this-will-allow-someone-to-log-in-as-you-and-to-steal-your-ROBUX-and-items.|_8B1028";
24    ///
25    /// #[tokio::main]
26    /// async fn main() {
27    ///     let mut client = robloxapi::Client();
28    ///     client.set_cookie(COOKIE).await;
29    /// }
30    ///
31    /// ```
32    pub async fn set_cookie(&mut self, cookie: &str) -> &mut Self {
33        let mut headers = header::HeaderMap::new();
34
35        headers.insert(
36            header::COOKIE,
37            header::HeaderValue::from_str(&(".ROBLOSECURITY=".to_owned() + cookie)).unwrap(),
38        );
39        headers.insert(
40            header::CONTENT_LENGTH,
41            header::HeaderValue::from_static("0"),
42        );
43
44        // Add the x-csrf-token to the headers
45        headers.insert(
46            header::HeaderName::from_static("x-csrf-token"),
47            header::HeaderValue::from(
48                reqwest::Client::new()
49                    .post("https://auth.roblox.com/v2/logout")
50                    .header("content-length", "0")
51                    .send()
52                    .await
53                    .expect("Failed to get X-CSRF-TOKEN")
54                    .headers()
55                    .get("x-csrf-token")
56                    .unwrap_or(&header::HeaderValue::from_static("")),
57            ),
58        );
59
60        // Create a new session with the cookie and token
61        self.session.client = reqwest::Client::builder()
62            .cookie_store(true)
63            .user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.152 Safari/537.36")
64            .default_headers(headers)
65            .build()
66            .expect("Failed to build new client from headers");
67
68        // Validate Cookie before continuing
69        self.session.validate_cookie().await;
70
71        self
72    }
73}
74
75impl Https {
76    /// Create a new client instance
77    pub fn new() -> Self {
78        Self {
79            client: reqwest::Client::builder()
80                .cookie_store(true)
81                .build()
82                .unwrap(),
83        }
84    }
85
86    async fn de_to_result<T>(req: Response) -> ApiResult<T>
87    where
88        T: DeserializeOwned,
89    {
90        let status_code = req.status();
91        let data = req.bytes().await?;
92
93        if let Ok(error) = serde_json::from_slice::<RobloxApiErrorResponse>(&data) {
94            if !error.is_empty() {
95                return Err(ApiError::Roblox {
96                    status_code,
97                    reason: error.reason().unwrap_or_else(|| "Unknown error".to_owned()),
98                });
99            }
100        }
101        Ok(serde_json::from_slice::<T>(&data)?)
102    }
103
104    // Send a get_request. Automatically handles the x-csrf token regeneration
105    pub async fn request<T>(&mut self, method: Method, request_url: &str) -> ApiResult<T>
106    where
107        T: de::DeserializeOwned,
108    {
109        //println!("{}", request_url);
110        let response = self
111            .client
112            .request(method.clone(), request_url)
113            .send()
114            .await
115            .expect("Request failed");
116
117        return Https::de_to_result::<T>(response).await;
118    }
119
120    pub async fn post(&mut self, request_url: &str) -> RequestBuilder {
121        self.client.post(request_url)
122    }
123
124    // Validate the cookie
125    async fn validate_cookie(&mut self) {
126        let req = self
127            .client
128            .request(Method::GET, "https://www.roblox.com/mobileapi/userinfo")
129            .send()
130            .await
131            .expect("Failed to get user info");
132
133        let _: serde_json::Value = req.json().await.expect("Failed to validate cookie");
134    }
135}