1use reqwest::{Client, Error};
2use serde_json::Value;
3
4const BASE_URL: &str = "https://api.shodan.io";
5
6#[derive(Debug, Clone)]
8pub struct ShodanClient {
9 api_key: String,
10 client: Client,
11}
12
13impl ShodanClient {
14 pub fn new(api_key: String) -> Self {
16 Self {
17 api_key,
18 client: Client::new(),
19 }
20 }
21
22 async fn request(&self, endpoint: &str) -> Result<Value, Error> {
24 let url = format!("{BASE_URL}/{endpoint}?key={}", self.api_key);
25 let response = self.client.get(&url).send().await?;
26 let json = response.json::<Value>().await?;
27 Ok(json)
28 }
29
30 pub async fn host_info(&self, ip_address: &str) -> Result<Value, Error> {
32 let endpoint = format!("shodan/host/{}", ip_address);
33 self.request(&endpoint).await
34 }
35
36 pub async fn search(&self, query: &str) -> Result<Value, Error> {
38 let endpoint = format!("shodan/host/search?query={}", query);
39 self.request(&endpoint).await
40 }
41
42 pub async fn honeyscore(&self, ip_address: &str) -> Result<Value, Error> {
44 let endpoint = format!("labs/honeyscore/{}", ip_address);
45 self.request(&endpoint).await
46 }
47}
48
49pub async fn get_host_info(api_key: &str, ip_address: &str) -> Result<Value, Error> {
51 ShodanClient::new(api_key.to_string())
52 .host_info(ip_address)
53 .await
54}
55
56pub async fn search_shodan(api_key: &str, query: &str) -> Result<Value, Error> {
58 ShodanClient::new(api_key.to_string())
59 .search(query)
60 .await
61}
62
63pub async fn get_honeyscore(api_key: &str, ip_address: &str) -> Result<Value, Error> {
65 ShodanClient::new(api_key.to_string())
66 .honeyscore(ip_address)
67 .await
68}