Skip to main content

epp_client/
domain.rs

1use std::borrow::Cow;
2use std::net::IpAddr;
3use std::str::FromStr;
4
5use serde::{Deserialize, Serialize};
6
7use crate::common::{serialize_host_addrs_option, HostAddr, StringValue};
8use crate::Error;
9
10pub mod check;
11pub use check::DomainCheck;
12
13pub mod create;
14pub use create::DomainCreate;
15
16pub mod delete;
17pub use delete::DomainDelete;
18
19pub mod info;
20pub use info::DomainInfo;
21
22pub mod renew;
23pub use renew::DomainRenew;
24
25pub mod transfer;
26pub use transfer::DomainTransfer;
27
28pub mod update;
29pub use update::DomainUpdate;
30
31pub const XMLNS: &str = "urn:ietf:params:xml:ns:domain-1.0";
32
33/// The <hostAttr> type for domain transactions
34#[derive(Serialize, Deserialize, Debug)]
35pub struct HostAttr<'a> {
36    /// The &lt;hostName&gt; tag
37    #[serde(rename = "domain:hostName", alias = "hostName")]
38    pub name: StringValue<'a>,
39    /// The &lt;hostAddr&gt; tags
40    #[serde(
41        rename = "domain:hostAddr",
42        alias = "hostAddr",
43        serialize_with = "serialize_host_addrs_option",
44        deserialize_with = "deserialize_host_addrs_option"
45    )]
46    pub addresses: Option<Vec<IpAddr>>,
47}
48
49fn deserialize_host_addrs_option<'de, D>(de: D) -> Result<Option<Vec<IpAddr>>, D::Error>
50where
51    D: serde::de::Deserializer<'de>,
52{
53    let addrs = Option::<Vec<HostAddr<'static>>>::deserialize(de)?;
54    let addrs = match addrs {
55        Some(addrs) => addrs,
56        None => return Ok(None),
57    };
58
59    let result = addrs
60        .into_iter()
61        .map(|addr| IpAddr::from_str(&addr.address))
62        .collect::<Result<_, _>>();
63
64    match result {
65        Ok(addrs) => Ok(Some(addrs)),
66        Err(e) => Err(serde::de::Error::custom(format!("{}", e))),
67    }
68}
69
70/// The list of &lt;hostAttr&gt; types for domain transactions. Typically under an &lt;ns&gt; tag
71#[derive(Serialize, Debug)]
72pub struct HostAttrList<'a> {
73    /// The list of &lt;hostAttr&gt; tags
74    #[serde(rename = "domain:hostAttr", alias = "hostAttr")]
75    pub hosts: &'a [HostAttr<'a>],
76}
77
78/// The list of &lt;hostObj&gt; types for domain transactions. Typically under an &lt;ns&gt; tag
79#[derive(Serialize, Debug)]
80pub struct HostObjList<'a> {
81    /// The list of &lt;hostObj&gt; tags
82    #[serde(rename = "domain:hostObj", alias = "hostObj")]
83    pub hosts: &'a [StringValue<'a>],
84}
85
86/// Enum that can accept one type which corresponds to either the &lt;hostObj&gt; or &lt;hostAttr&gt;
87/// list of tags
88#[derive(Serialize, Debug)]
89#[serde(untagged)]
90pub enum HostList<'a> {
91    HostObjList(HostObjList<'a>),
92    HostAttrList(HostAttrList<'a>),
93}
94
95/// The &lt;contact&gt; type on domain creation and update requests
96#[derive(Serialize, Deserialize, Debug)]
97pub struct DomainContact<'a> {
98    /// The contact id
99    #[serde(rename = "$value")]
100    pub id: Cow<'a, str>,
101    /// The contact type attr (usually admin, billing, or tech in most registries)
102    #[serde(rename = "type")]
103    pub contact_type: Cow<'a, str>,
104}
105
106/// The &lt;period&gt; type for registration, renewal or transfer on domain transactions
107#[derive(Clone, Copy, Debug, Serialize)]
108pub struct Period {
109    /// The interval (usually 'y' indicating years)
110    unit: char,
111    /// The length of the registration, renewal or transfer period (usually in years)
112    #[serde(rename = "$value")]
113    length: u8,
114}
115
116impl Period {
117    pub fn years(length: u8) -> Result<Self, Error> {
118        Self::new(length, 'y')
119    }
120
121    pub fn months(length: u8) -> Result<Self, Error> {
122        Self::new(length, 'm')
123    }
124
125    fn new(length: u8, unit: char) -> Result<Self, Error> {
126        match length {
127            1..=99 => Ok(Period { length, unit }),
128            0 | 100.. => Err(Error::Other(
129                "Period length must be greater than 0 and less than 100".into(),
130            )),
131        }
132    }
133}
134
135pub const ONE_YEAR: Period = Period {
136    unit: 'y',
137    length: 1,
138};
139
140pub const TWO_YEARS: Period = Period {
141    unit: 'y',
142    length: 2,
143};
144
145pub const THREE_YEARS: Period = Period {
146    unit: 'y',
147    length: 3,
148};
149
150pub const ONE_MONTH: Period = Period {
151    unit: 'm',
152    length: 1,
153};
154
155pub const SIX_MONTHS: Period = Period {
156    unit: 'm',
157    length: 6,
158};
159
160/// The &lt;authInfo&gt; tag for domain and contact transactions
161#[derive(Serialize, Deserialize, Debug, Clone)]
162pub struct DomainAuthInfo<'a> {
163    /// The &lt;pw&gt; tag under &lt;authInfo&gt;
164    #[serde(rename = "domain:pw", alias = "pw")]
165    pub password: StringValue<'a>,
166}
167
168impl<'a> DomainAuthInfo<'a> {
169    /// Creates a DomainAuthInfo instance with the given password
170    pub fn new(password: &'a str) -> Self {
171        Self {
172            password: password.into(),
173        }
174    }
175}