warlocks_cauldron/providers/
internet.rs

1use chrono::Datelike;
2pub use ipaddress::*;
3
4use super::dependencies::*;
5use super::{Datetime, File, Text};
6
7
8#[derive(Debug)]
9pub enum StockType {
10    URL(String),
11    Image(Vec<u8>),
12}
13
14/// Methods collection for generating data related to the internet
15pub struct Internet;
16
17impl Internet {
18    /// Get a random HTTP content type
19    ///
20    /// return example: Content-Type: application/json
21    ///
22    /// # Arguments
23    /// * `mime_type` - MimeType enum
24    pub fn content_type(mime_type: Option<MimeType>) -> String {
25        format!("Content-Type: {}", File::mime_type(mime_type))
26    }
27
28    /// Get a random HTTP status message
29    ///
30    /// return example: 200 OK
31    pub fn http_status_message() -> &'static str {
32        get_random_element(HTTP_STATUS_MSGS.iter())
33    }
34
35    /// Get a random HTTP status message
36    ///
37    /// return example: 200
38    pub fn http_status_code() -> &'static str {
39        get_random_element(HTTP_STATUS_CODES.iter())
40    }
41
42    /// Get a random HTTP status message
43    ///
44    /// return example: POST
45    pub fn http_method() -> &'static str {
46        get_random_element(HTTP_METHODS.iter())
47    }
48
49    /// Generate random port
50    /// 
51    /// return example: 8000
52    ///
53    /// # Arguments
54    /// * `port_range` - PortRange enum
55    pub fn port(port_range: Option<PortRange>) -> u16 {
56        let range = validate_enum(port_range, Some(PortRange::ALL));
57        randint(range.0, range.1)
58    }
59
60    /// Get a random v4 IPAddress struct
61    ///
62    /// return example: IPAddress
63    pub fn ip_v4_object() -> IPAddress {
64        ipv4::from_u32(randint(0, 4294967295), 32).expect("Cant create v4 IPAddress!")
65    }
66
67    /// Get a random v4 IP address
68    ///
69    /// return example: 127.0.0.1
70    pub fn ip_v4() -> String {
71        Self::ip_v4_object().to_s()
72    }
73
74    /// Get a random v4 IP address with port
75    ///
76    /// return example: 127.0.0.1:666
77    ///
78    /// # Arguments
79    /// * `port_range` - PortRange enum
80    pub fn ip_v4_with_port(port_range: Option<PortRange>) -> String {
81        format!("{}:{}", Self::ip_v4(), Self::port(port_range))
82    }
83
84    /// Get a random v6 IPAddress struct
85    ///
86    /// return example: IPAddress
87    pub fn ip_v6_object() -> IPAddress {
88        ipv6::from_int(randbigint(u128::MIN, u128::MAX), 32).expect("Cant create v6 IPAddress!")
89    }
90
91    /// Get a random v6 IP address
92    ///
93    /// return example: 0000:0000:0000:0000:0000:0000:0000:0001
94    pub fn ip_v6() -> String {
95        Self::ip_v6_object().to_s()
96    }
97
98    /// Get a random mac address
99    ///
100    /// return example: 00:16:3e:25:e7:f1
101    pub fn mac() -> String {
102        vec![
103            0x00,
104            0x16,
105            0x3E,
106            randint(0x00, 0x7F),
107            randint(0x00, 0xFF),
108            randint(0x00, 0xFF),
109        ].iter().map(|i| format!("{:02x}", i))
110            .join(":")
111    }
112
113    /// Get a random emoji shortcut code
114    ///
115    /// return example: :smirk:
116    pub fn emoji() -> &'static str {
117        get_random_element(EMOJI.iter())
118    }
119
120    /// Generate random stock image (JPG/JPEG) hosted on Unsplash
121    ///
122    /// return example: StockType::URL("<https://source.unsplash.com/666x666?test>")
123    ///
124    /// # Arguments
125    /// * `width` - Width of the image
126    /// * `height` - Height of the image
127    /// * `keywords` - List of search keywords
128    /// * `to_image` - Return image as vec of u8
129    pub fn stock_image(width: u32, height: u32, keywords: Vec<&str>, to_image: bool) -> StockType {
130        let keywords_str = keywords.join(",");
131        let url = format!("https://source.unsplash.com/{width}x{height}?{keywords_str}");
132
133        match to_image {
134            true => {
135                let r = reqwest::blocking::get(url).expect("Cant fetch images from unsplash!")
136                    .bytes().expect("Cant get output!");
137                
138                StockType::Image(r.to_vec())
139            },
140            false => StockType::URL(url),
141        }
142    }
143
144    /// Generate a list of hashtags
145    ///
146    /// return example: vec!\['#some', '#random', '#things'\]
147    ///
148    /// # Arguments
149    /// * `quantity` - The quantity of hashtags
150    pub fn hashtags(quantity: i32) -> Vec<String> {
151        let locale = Text(&Locale::EN);
152        (0..quantity).map(|_| format!("#{}", locale.word())).collect()
153    }
154
155    /// Generates random top level domain
156    ///
157    /// return example: com
158    ///
159    /// # Arguments
160    /// * `tld_type` - TLDType provide hostname domain
161    pub fn top_level_domain(tld_type: Option<TLDType>) -> &'static str {
162        let tld = validate_enum(tld_type, None);
163        get_random_element(TLD.get(tld).expect("Cant get TLD type!").iter())
164    }
165
166    /// Generates random top level domain | *An allias for .top_level_domain()*
167    ///
168    /// return example: com
169    ///
170    /// # Arguments
171    /// * `tld_type` - TLDType provide hostname domain
172    pub fn tld(tld_type: Option<TLDType>) -> &'static str {
173        Self::top_level_domain(tld_type)
174    }
175
176    /// Get a random user agent
177    ///
178    /// return example: Gecko/20100101 Firefox/15.0.1
179    pub fn user_agent() -> &'static str {
180        get_random_element(USER_AGENTS.iter())
181    }
182
183    /// Get a random user agent
184    ///
185    /// return example: 1.1.1.1
186    pub fn public_dns() -> &'static str {
187        get_random_element(PUBLIC_DNS.iter())
188    }
189
190    /// Generate a random slug of given parts count
191    /// 
192    /// return example: some-slug-here
193    pub fn slug(parts_count: Option<usize>) -> String {
194        let parts = parts_count.unwrap_or_else(|| randint(2, 12));
195
196        if parts > 12 {
197            panic!("Slug's parts count must be <= 12");
198        }
199
200        if parts < 2 {
201            panic!("Slug must contain more than 2 parts");
202        }
203
204        Text(&Locale::EN).words(parts).iter().join("-")
205    }
206
207    /// Generate a random hostname without scheme
208    ///
209    /// return example: sub.domain
210    ///
211    /// # Arguments
212    /// * `tld_type` - TLDType provide hostname domain
213    /// * `subdomains` - vec of subdomains
214    pub fn hostname(tld_type: Option<TLDType>, subdomains: Option<Vec<&str>>) -> String {
215        let tld = Self::top_level_domain(tld_type);
216        let host = get_random_element(USERNAMES.iter());
217
218        let mut url = format!("{host}{tld}");
219
220        if let Some(v) = subdomains {
221            url = format!("{}.{url}", get_random_element(v.iter()));
222        }
223
224        url
225    }
226
227    /// Generate random URL
228    ///
229    /// return example: <https://sub.domain.com:8000/>
230    ///
231    /// # Arguments
232    /// * `scheme` - URLScheme provide url scheme
233    /// * `port_range` - PortRange enum
234    /// * `tld_type` - TLDType provide hostname domain
235    /// * `subdomains` - vec of subdomains
236    pub fn url(scheme: Option<URLScheme>, port_range: Option<PortRange>, tld_type: Option<TLDType>, subdomains: Option<Vec<&str>>) -> String {
237        let hostname = Self::hostname(tld_type, subdomains);
238        let scheme = validate_enum(scheme, None);
239        let mut url = format!("{scheme}://{hostname}");
240
241        if port_range.is_some() {
242            url = format!("{url}:{}", Self::port(port_range));
243        }
244
245        format!("{url}/")
246    }
247
248    /// Generate a random URI
249    ///
250    /// return example: <https://sub.domain.com:8000/2013/6/6/?some-things&test-test>
251    ///
252    /// # Arguments
253    /// * `scheme` - URLScheme for url prefix
254    /// * `port_range` - PortRange enum for port
255    /// * `tld_type` - TLDType provide hostname domain
256    /// * `subdomains` - vec of subdomains
257    /// * `query_params_count` - Query params count
258    pub fn uri(scheme: Option<URLScheme>, port_range: Option<PortRange>, tld_type: Option<TLDType>, subdomains: Option<Vec<&str>>, query_params_count: Option<usize>) -> String {
259        let directory = Datetime::date(2010, chrono::Local::now().year()).format("%Y/%m/%d");
260
261        let mut url = format!("{}{directory}/{}", Self::url(scheme, port_range, tld_type, subdomains), Self::slug(None));
262
263        if query_params_count.is_some() {
264            url = format!("{url}?{}", Self::query_string(query_params_count));
265        }
266
267        url
268    }
269
270    /// Generate arbitrary query string of given length
271    ///
272    /// return example: some-things&test-test
273    ///
274    /// # Arguments
275    /// * `length` - Query params count
276    pub fn query_string(length: Option<usize>) -> String {
277        let formated = Self::query_parameters(length).iter().map(|p| {
278            format!("{}={}", p.0, p.1)
279        }).join("&");
280    
281        urlencoding::encode(&formated).into_owned()
282    }
283
284    /// Generate arbitrary query parameters as a set
285    ///
286    /// return example: vec![('some', 'things'), ('test', 'test')]
287    ///
288    /// # Arguments
289    /// * `length` - Query params count
290    pub fn query_parameters(length: Option<usize>) -> Vec<(&'static str, &'static String)> {
291        let text = &Text(&Locale::RU);
292        let length = length.unwrap_or_else(|| randint(1, 10));
293
294        if length > 32 {
295            panic!("Length should be less than 32!")
296        }
297
298        let mut unique_words: Vec<&'static str> = vec![];
299        while unique_words.len() < length {
300            let word = text.word();
301            if !unique_words.contains(&word) {
302                unique_words.push(word)
303            }
304        }
305
306        unique_words.into_iter().zip(text.words(length)).collect()
307    }
308}