diff --git a/src/cloudflare.rs b/src/cloudflare.rs new file mode 100644 index 0000000..0d87f3a --- /dev/null +++ b/src/cloudflare.rs @@ -0,0 +1 @@ +const API_BASE: &str = "https://api.cloudflare.com/client/v4"; \ No newline at end of file diff --git a/src/cloudflare/mod.rs b/src/cloudflare/mod.rs deleted file mode 100644 index 96fa37f..0000000 --- a/src/cloudflare/mod.rs +++ /dev/null @@ -1,269 +0,0 @@ -use reqwest::{ - blocking::{Client, Response}, - Url, -}; -use reqwest::{ - header::{HeaderMap, HeaderValue}, - Error, -}; -use serde_derive::{Deserialize, Serialize}; -use std::{collections::HashMap, string::String}; -use strum_macros::{Display, IntoStaticStr}; - -const API_BASE: &str = "https://api.cloudflare.com/client/v4/"; - -#[derive(Serialize, Deserialize)] -struct CloudflareDnsZone { - result: Vec, - success: bool, -} - -#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Copy, Display, IntoStaticStr)] -pub enum CloudflareDnsType { - #[strum(serialize = "A")] - A = 4, - #[strum(serialize = "AAAA")] - AAAA = 6, - CAA, - CERT, - CNAME, - DNSKEY, - DS, - HTTPS, - LOC, - MX, - NAPTR, - NS, - PTR, - SMIMEA, - SRV, - SSHFP, - SVCB, - TLSA, - TXT, - URI -} - -#[derive(Serialize, Deserialize)] -pub struct CloudflareDnsEntry { - id: String, - pub zone_id: String, - pub name: String, - pub r#type: CloudflareDnsType, - content: String, - proxied: bool, -} - -impl CloudflareDnsEntry { - pub fn is_equal(&self, other_entry: &String) -> bool { - return if &self.name == other_entry { - true - } else { - false - }; - } - - pub fn is_ip_new(&self, other_entry: &String) -> bool { - return if &self.content == other_entry { - false - } else { - true - }; - } -} - -pub(crate) struct Instance { - api_key: String, - pub dns_entries: Vec, - dns_email: String, -} - -impl Instance { - pub fn new(key: &String) -> Instance { - Instance { - api_key: key.clone(), - dns_entries: Vec::new(), - dns_email: "".to_string(), - } - } - - /// Loads all DNS entires in a Zone as a [`CloudflareDnsEntry`] Vector - /// - /// * `email` : E-Mail Address associated with the Zone, required for [`generate_headers()`] - /// * `zone_id` : Zone to be used for the Request - /// * `return` : Returns true if a recoverable Error was encountered, true otherwise - pub fn load_entries(&mut self, email: &String, zone_id: &String) -> Result<(), Error> { - self.dns_email = email.clone(); - let endpoint = format!("{}zones/{}/dns_records", API_BASE, zone_id); - - match self.get(&endpoint) { - Ok(response) => { - if response.status().is_success() { - let entries = match response.json::() { - Ok(data) => data, - Err(e) => { - panic!("{:#?}", e) - } - }; - - for entry in entries.result { - self.dns_entries.append(&mut vec![entry]); - } - - return Ok(()); - } - else { - println!("Server returned Status Code: {}", response.status()); - return Err(response.error_for_status().err().unwrap()); - } - } - Err(e) => return Err(e), - } - } - - /// Shorthand for Cloudflare API Requests - /// - /// Automatically appends Auth Headers and parses the URL - /// - /// * `url` : URL for the request, will be parsed to [`Url`] - fn get(&self, url: &str) -> Result { - let url_parsed = match Url::parse(url) { - Ok(url) => url, - Err(e) => panic!("{:#?}", e), // If this call fails the API changed - }; // Continuing without a code update is not possible - - let result = Client::new() - .get(url_parsed) - .headers(self.generate_headers()) - .send(); - - return result; - } - - /// Shorthand for Cloudflare API Requests - /// - /// Automatically appends Auth Headers and parses the URL - /// - /// * `url` : URL for the request, will be parsed to [`Url`] - /// * `data` : PUT request body - fn put(&self, url: &str, data: &HashMap<&str, &str>) -> Result { - let url_parsed = match Url::parse(url) { - Ok(url) => url, - Err(e) => panic!("{:#?}", e), // If this call fails the API changed - }; // Continuing without a code update is not possible - - let result = match Client::new() - .put(url_parsed) - .headers(self.generate_headers()) - .json(data) - .send() - { - Ok(res) => Ok(res), - Err(e) => Err(e), - }; - - return result; - } - - /// Shorthand for Cloudflare API Requests - /// - /// Automatically appends Auth Headers and parses the URL - /// - /// * `url` : URL for the request, will be parsed to [`Url`] - /// * `data` : POST request body - fn post(&self, url: &str, data: &HashMap<&str, &str>) -> Result { - let url_parsed = match Url::parse(url) { - Ok(url) => url, - Err(e) => panic!("{:#?}", e), // If this call fails the API changed - }; // Continuing without a code update is not possible - - let result = match Client::new() - .post(url_parsed) - .headers(self.generate_headers()) - .json(data) - .send() - { - Ok(res) => Ok(res), - Err(e) => Err(e), - }; - - return result; - } - - /// Updates the given DNS entry with the given IP - /// - /// * `entry` : DNS entry to update - /// * `new_ip` : IP used to Update the DNS entry, can be IPv4 or IPv6 - /// * `return1` : Returns success of the API call, extracted from the HTTP Response body - pub fn update_entry(&self, entry: &CloudflareDnsEntry, new_ip: &String) -> Result { - let endpoint = format!( - "{}zones/{}/dns_records/{}", - API_BASE, entry.zone_id, entry.id - ); - - let mut json_body = HashMap::new(); - json_body.insert("type", entry.r#type.clone().into()); - json_body.insert("name", entry.name.as_ref()); - json_body.insert("content", new_ip); - json_body.insert("ttl", "1"); - - match self.put(&endpoint, &json_body) { - Ok(response) => { - let data = response - .json::() - .expect("Response should always be valid JSON"); - - let success = data["success"] - .as_bool() - .expect("JSON should always include success bool"); - return Ok(success); - } - Err(e) => return Err(e), - } - } - - pub fn create_entry( - &self, - zone_id: &String, - r#type: &str, - name: &str, - ip: &String, - ) -> Result { - let endpoint = format!("{}zones/{}/dns_records", API_BASE, zone_id); - - let mut json_body = HashMap::new(); - json_body.insert("type", r#type); - json_body.insert("name", name); - json_body.insert("content", ip); - json_body.insert("ttl", "1"); - - match self.post(&endpoint, &json_body) { - Ok(response) => { - let data = response - .json::() - .expect("Response should always be valid JSON"); - - let success = data["success"] - .as_bool() - .expect("JSON should always include success bool"); - - return Ok(success); - } - Err(e) => return Err(e), - } - } - - /// Generate Cloudflare API v4 Auth Headers - fn generate_headers(&self) -> HeaderMap { - let mut headers = HeaderMap::new(); - headers.insert( - "X-Auth-Key", - HeaderValue::from_str(self.api_key.as_ref()).unwrap(), - ); - headers.insert( - "X-Auth-Email", - HeaderValue::from_str(self.dns_email.as_ref()).unwrap(), - ); - headers - } -}