1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
extern crate hyper;
extern crate hyper_native_tls;

pub mod shodan {

    use hyper::client::{Client, Response};
    use hyper_native_tls::NativeTlsClient;
    use hyper::net::HttpsConnector;
    use std::io::Read;
    use hyper::Ok as hyper_ok;

    // BaseUrl is the basis for all of our api requests.
    const BASE_URL: &'static str = "https://api.shodan.io";

    #[derive(Debug)]
    pub struct ShodanClient {
        api_key: &'static str,
    }

    impl ShodanClient {
        fn create_http_client(&self) -> Client {
            let ssl = NativeTlsClient::new().unwrap();
            let connector = HttpsConnector::new(ssl);
            let client = Client::with_connector(connector);

            client
        }
        fn request(&self, api_method: &str, url: String) -> Response {
            let client = self.create_http_client();

            let response = match api_method {
                "GET" => {
                    client.get(&*url)
                        .send()
                        .unwrap()
                }
                _ => panic!("Invalid HTTP Verb."),
            };

            response
        }

        fn form_response(&self, mut response: Response) -> Result<String, String> {

            let mut body = String::new();

            if response.status == hyper_ok {
                response.read_to_string(&mut body).unwrap();

                return Ok(body);
            }

            response.read_to_string(&mut body).unwrap();

            Err(body)
        }
        pub fn new(api_key: &'static str) -> ShodanClient {
            ShodanClient { api_key: api_key }
        }

        pub fn host_info(&self, ip_address: &str) -> Result<String, String> {
            let formatted_url = format!("{}/shodan/host/{}?key={}",
                                        BASE_URL,
                                        ip_address,
                                        self.api_key);

            let response = self.request("GET", formatted_url);
            self.form_response(response)
        }

        pub fn search(&self, query: &str) -> Result<String, String> {
            let formatted_url = format!("{}/shodan/host/search?key={}&query={}",
                                        BASE_URL,
                                        self.api_key,
                                        query);

            let response = self.request("GET", formatted_url);
            self.form_response(response)
        }

        pub fn search_with_facets(&self, query: &str, facets: &str) -> Result<String, String> {
            let formatted_url = format!("{}/shodan/host/search?key={}&query={}&facets={}",
                                        BASE_URL,
                                        self.api_key,
                                        query,
                                        facets);

            let response = self.request("GET", formatted_url);
            self.form_response(response)
        }

        pub fn honeyscore(&self, ip_address: &str) -> Result<String, String> {
            let formatted_url = format!("{}/labs/honeyscore/{}?key={}",
                                        BASE_URL,
                                        ip_address,
                                        self.api_key);

            let response = self.request("GET", formatted_url);
            self.form_response(response)
        }
    }
}