migamake-api-cloudflare 0.2.0

A library to work with Cloudflare apis
Documentation
//! Defines various type of DNS record structs to be used with
//! [Create DNS record](crate::Cloudflare::create_dns_record)

#![allow(clippy::new_without_default)]

use crate::parameters::DnsRecordType;
use serde::Serialize;
use std::net::{Ipv4Addr, Ipv6Addr};
use validator::{Validate, ValidationError};

fn is_ipv4(content: &str) -> Result<(), ValidationError> {
    let result = content.parse::<Ipv4Addr>();

    match result {
        Ok(_v) => Ok(()),
        Err(_e) => Err(ValidationError::new("IPv4")),
    }
}

fn is_ipv6(content: &str) -> Result<(), ValidationError> {
    let result = content.parse::<Ipv6Addr>();

    match result {
        Ok(_v) => Ok(()),
        Err(_e) => Err(ValidationError::new("IPv6")),
    }
}

fn is_valid_spf(content: &str) -> Result<(), ValidationError> {
    if content.starts_with("v=spf1") {
        return Ok(());
    }
    Err(ValidationError::new("SPF"))
}

#[cfg(test)]
mod tests {

    use crate::dns::*;
    use crate::parameters::DnsRecordType;

    #[test]
    fn should_have_a_type() {
        let ipv4_record = ARecord::new();
        assert_eq!(ipv4_record.record_type, DnsRecordType::A)
    }
    #[test]
    fn should_have_aaaa_type() {
        let ipv6_record = AAAARecord::new();
        assert_eq!(ipv6_record.record_type, DnsRecordType::AAAA)
    }

    #[test]
    #[should_panic]
    fn should_panic_for_bad_spf_content() {
        let mut spf = SPFRecord::new();
        spf.content = "start wrong".into();
        spf.validate().unwrap();
    }
}
/// To create A record
///
/// The record that holds the IP address of a domain
#[derive(Debug, Validate, Serialize)]
pub struct ARecord {
    #[serde(rename(serialize = "type"))]
    record_type: DnsRecordType,
    #[validate(length(min = 1, max = 255))]
    pub name: String,
    #[validate(custom(
        function = "is_ipv4",
        message = "The provided content is not a valid IPv4 address"
    ))]
    pub content: String,
    pub ttl: u32,
}

impl ARecord {
    pub fn new() -> ARecord {
        ARecord {
            record_type: DnsRecordType::A,
            name: "".into(),
            content: "".into(),
            ttl: 1,
        }
    }
}
/// To create a AAAA Record
///
/// The record that holds the IP address of a domain in IPv6 format
#[derive(Debug, Validate, Serialize)]
pub struct AAAARecord {
    #[serde(rename(serialize = "type"))]
    record_type: DnsRecordType,
    #[validate(length(max = 255))]
    pub name: String,
    #[validate(custom(
        function = "is_ipv6",
        message = "The provided content is not a valid IPv6 address"
    ))]
    pub content: String,
    pub ttl: u32,
}

impl AAAARecord {
    pub fn new() -> AAAARecord {
        AAAARecord {
            record_type: DnsRecordType::AAAA,
            name: "".into(),
            content: "".into(),
            ttl: 1,
        }
    }
}

/// To create a CNAME Record
///
/// Forwards one domain or subdomain to another domain, does NOT provide an IP address
#[derive(Debug, Validate, Serialize)]
pub struct CNAMERecord {
    #[serde(rename(serialize = "type"))]
    pub record_type: DnsRecordType,
    #[validate(length(max = 255))]
    pub name: String,
    #[validate(length(max = 255))]
    pub content: String,
    pub ttl: u32,
}

impl CNAMERecord {
    pub fn new() -> CNAMERecord {
        CNAMERecord {
            record_type: DnsRecordType::CNAME,
            name: "".into(),
            content: "".into(),
            ttl: 1,
        }
    }
}
/// To create a TXT Record
///
/// Lets an admin store text notes in the record.
#[derive(Debug, Validate, Serialize)]
pub struct TXTRecord {
    #[serde(rename(serialize = "type"))]
    record_type: DnsRecordType,
    #[validate(length(max = 255))]
    pub name: String,
    #[validate(length(max = 255))]
    pub content: String,
    pub ttl: u32,
}

impl TXTRecord {
    pub fn new() -> TXTRecord {
        TXTRecord {
            record_type: DnsRecordType::TXT,
            name: "".into(),
            content: "".into(),
            ttl: 1,
        }
    }
}
/// To create a MX Record
///
/// Directs mail to an email server.
#[derive(Debug, Validate, Serialize)]
pub struct MXRecord {
    #[serde(rename(serialize = "type"))]
    pub record_type: DnsRecordType,
    #[validate(length(max = 255))]
    pub name: String,
    pub content: String,
    pub ttl: u32,
    #[validate(range(min = 0, max = 65535))]
    pub priority: u32,
}

impl MXRecord {
    pub fn new() -> MXRecord {
        MXRecord {
            record_type: DnsRecordType::MX,
            name: "".into(),
            content: "".into(),
            ttl: 1,
            priority: 0,
        }
    }
}

/// To create a NS Record
///
/// Stores the name server for a DNS entry.
#[derive(Debug, Validate, Serialize)]
pub struct NSRecord {
    #[serde(rename(serialize = "type"))]
    pub record_type: DnsRecordType,
    #[validate(length(max = 255))]
    pub name: String,
    pub content: String,
    pub ttl: u32,
}

impl NSRecord {
    pub fn new() -> NSRecord {
        NSRecord {
            record_type: DnsRecordType::NS,
            name: "".into(),
            content: "".into(),
            ttl: 1,
        }
    }
}
/// To create a SRV Record
///
/// Specifies a port for specific services.
#[derive(Debug, Validate, Serialize)]
pub struct SRVRecord {
    #[serde(rename(serialize = "type"))]
    pub record_type: DnsRecordType,
    #[validate(length(max = 255))]
    pub name: String,
    pub content: String,
    pub ttl: u32,
}

impl SRVRecord {
    pub fn new() -> SRVRecord {
        SRVRecord {
            record_type: DnsRecordType::SRV,
            name: "".into(),
            content: "".into(),
            ttl: 1,
        }
    }
}
/// To create a CAA Record
///
/// This is the ‘certification authority authorization’ record
#[derive(Debug, Validate, Serialize)]
pub struct CAARecord {
    #[serde(rename(serialize = "type"))]
    pub record_type: DnsRecordType,
    #[validate(length(max = 255))]
    pub name: String,
    pub ttl: u32,
    data: CAAData,
}
/// Fields required for [CAARecord struct](CAARecord)
#[derive(Debug, Validate, Serialize)]
pub(crate) struct CAAData {
    flags: u8,
    tag: String,
    value: String,
}

impl CAARecord {
    pub fn new(ca_authority: String) -> CAARecord {
        let data = CAAData {
            flags: 0,
            tag: "issue".into(),
            value: ca_authority,
        };
        CAARecord {
            record_type: DnsRecordType::CAA,
            name: "".into(),
            ttl: 1,
            data,
        }
    }
}
/// To create a PTR Record
///
/// Provides a domain name in reverse-lookups.
#[derive(Debug, Validate, Serialize)]
pub struct PTRRecord {
    #[serde(rename(serialize = "type"))]
    pub record_type: DnsRecordType,
    #[validate(length(max = 255))]
    pub name: String,
    pub content: String,
    pub ttl: u32,
}

impl PTRRecord {
    pub fn new() -> PTRRecord {
        PTRRecord {
            record_type: DnsRecordType::PTR,
            name: "".into(),
            content: "".into(),
            ttl: 1,
        }
    }
}
/// To create a SPF Record
///
/// used to indicate to mail exchanges which hosts are authorized to send mail for a domain
#[derive(Debug, Validate, Serialize)]
pub struct SPFRecord {
    #[serde(rename(serialize = "type"))]
    pub record_type: DnsRecordType,
    #[validate(length(max = 255))]
    pub name: String,
    #[validate(custom(
        function = "is_valid_spf",
        message = "The provided content should start with v=spf1"
    ))]
    pub content: String,
    pub ttl: u32,
}

impl SPFRecord {
    pub fn new() -> SPFRecord {
        SPFRecord {
            record_type: DnsRecordType::SPF,
            name: "".into(),
            content: "".into(),
            ttl: 1,
        }
    }
}