added serialization tests

This commit is contained in:
Ritesh Chitlangi 2021-07-25 03:10:40 +08:00
parent f9fd4080b9
commit c310e6f7b4
43 changed files with 1090 additions and 60 deletions

2
.gitignore vendored
View File

@ -1,4 +1,6 @@
/target
**/target
**/certs
/config
/epp-client/misc
Cargo.lock

View File

@ -15,8 +15,11 @@ bytes = "1"
chrono = "0.4"
confy = "0.4"
futures = "0.3"
log = "0.4"
lazy_static = "1.4"
quick-xml = { version = "0.22", features = [ "serialize" ] }
rustls = "0.19"
rustls-pemfile = "0.2"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.0", features = [ "full" ] }
tokio-rustls = "0.22"
@ -25,3 +28,4 @@ webpki-roots = "0.21"
[dev-dependencies]
tokio-test = "*"
regex = "1.5"

View File

@ -52,7 +52,7 @@ async fn update_contact(client: &mut EppClient) {
let mut contact_update = EppContactUpdate::new("eppdev-contact-1", gen_client_tr_id("eppdev").unwrap().as_str());
let contact_info_res_data = contact_info_response.data.res_data.unwrap();
contact_update.set_info("newemail@eppdev.net", contact_info_res_data.info_data.postal_info, contact_info_res_data.info_data.voice, contact_info_res_data.info_data.auth_info.password.to_string().as_str());
contact_update.set_info("newemail@eppdev.net", contact_info_res_data.info_data.postal_info, contact_info_res_data.info_data.voice, "eppdev-387323");
let add_statuses = vec![ContactStatus { status: "clientTransferProhibited".to_string() }];
contact_update.remove_statuses(add_statuses);
@ -284,7 +284,7 @@ async fn hello(client: &mut EppClient) {
#[tokio::main]
async fn main() {
let mut client = match EppClient::new("hexonet").await {
let mut client = match EppClient::new("verisign").await {
Ok(client) => {
println!("{:?}", client.greeting());
client
@ -296,7 +296,7 @@ async fn main() {
// hello(&mut client).await;
// check_domains(&mut client).await;
let response = check_domains(&mut client).await;
// check_contacts(&mut client).await;

View File

@ -1,8 +1,11 @@
use confy;
use lazy_static::lazy_static;
use rustls::{Certificate, PrivateKey};
use rustls_pemfile;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::default;
use std::{fs, io};
lazy_static! {
pub static ref CONFIG: EppClientConfig = match confy::load("epp-client") {
@ -11,6 +14,12 @@ lazy_static! {
};
}
#[derive(Serialize, Deserialize, Debug)]
pub struct EppClientTlsFiles {
cert_chain: String,
key: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct EppClientConnection {
host: String,
@ -18,17 +27,32 @@ pub struct EppClientConnection {
username: String,
password: String,
ext_uris: Option<Vec<String>>,
tls_files: Option<EppClientTlsFiles>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct EppClientConfig {
pub servers: HashMap<String, EppClientConnection>,
pub registry: HashMap<String, EppClientConnection>,
}
impl default::Default for EppClientConfig {
fn default() -> Self {
let servers: HashMap<String, EppClientConnection> = HashMap::new();
Self { servers: servers }
let mut registries: HashMap<String, EppClientConnection> = HashMap::new();
let registrar = EppClientConnection {
host: "epphost".to_string(),
port: 700,
username: "username".to_string(),
password: "password".to_string(),
ext_uris: Some(vec![]),
tls_files: Some(EppClientTlsFiles {
cert_chain: "/path/to/certificate/chain/pemfile".to_string(),
key: "/path/to/private/key/pemfile".to_string(),
}),
};
registries.insert("hexonet".to_string(), registrar);
Self {
registry: registries,
}
}
}
@ -42,10 +66,46 @@ impl EppClientConnection {
pub fn ext_uris(&self) -> Option<&Vec<String>> {
self.ext_uris.as_ref()
}
pub fn tls_files(&self) -> Option<(Vec<Certificate>, PrivateKey)> {
let certificates = self.client_certificate();
let key = self.key();
if certificates == None || key == None {
None
} else {
Some((certificates.unwrap(), key.unwrap()))
}
}
fn client_certificate(&self) -> Option<Vec<Certificate>> {
match &self.tls_files {
Some(tls) => Some(
rustls_pemfile::certs(&mut io::BufReader::new(
fs::File::open(tls.cert_chain.to_string()).unwrap(),
))
.unwrap()
.iter()
.map(|v| Certificate(v.clone()))
.collect(),
),
None => None,
}
}
fn key(&self) -> Option<PrivateKey> {
match &self.tls_files {
Some(tls) => Some(rustls::PrivateKey(
rustls_pemfile::rsa_private_keys(&mut io::BufReader::new(
fs::File::open(tls.key.to_string()).unwrap(),
))
.unwrap()[0]
.clone(),
)),
None => None,
}
}
}
impl EppClientConfig {
pub fn registry(&self, registry: &str) -> Option<&EppClientConnection> {
self.servers.get(registry)
self.registry.get(registry)
}
}

View File

@ -100,25 +100,22 @@ impl EppClient {
let response = self.connection.transact(&hello_xml).await?;
println!("hello response: {}", response);
Ok(EppGreeting::deserialize(&response)?)
}
pub async fn transact<T: EppXml + Debug, E: EppXml + Debug>(&mut self, request: &T) -> Result<E::Output, error::Error> {
let epp_xml = request.serialize()?;
println!("Request:\r\n{}", epp_xml);
debug!("request: {}", epp_xml);
let response = self.connection.transact(&epp_xml).await?;
println!("Response:\r\n{}", response);
debug!("response: {}", response);
let status = EppCommandResponseStatus::deserialize(&response)?;
if status.data.result.code < 2000 {
let response = E::deserialize(&response)?;
println!("Response:\r\n{:?}", response);
Ok(response)
} else {
let epp_error = EppCommandResponseError::deserialize(&response)?;
@ -134,15 +131,15 @@ impl EppClient {
return String::from(&self.connection.greeting)
}
pub fn greeting(&self) -> Result<EppGreeting, Box<dyn Error>> {
Ok(EppGreeting::deserialize(&self.connection.greeting)?)
pub fn greeting(&self) -> Result<EppGreeting, error::Error> {
EppGreeting::deserialize(&self.connection.greeting)
}
pub async fn logout(&mut self) {
pub async fn logout(&mut self) -> Result<EppCommandResponse, error::Error> {
let client_tr_id = generate_client_tr_id(&self.credentials.0).unwrap();
let epp_logout = EppLogout::new(client_tr_id.as_str());
self.transact::<_, EppCommandResponse>(&epp_logout).await;
self.transact::<_, EppCommandResponse>(&epp_logout).await
}
}

View File

@ -39,7 +39,7 @@ impl EppConnection {
async fn write(&mut self, buf: &Vec<u8>) -> Result<(), Box<dyn Error>> {
let wrote = self.stream.writer.write(buf).await?;
println!("Wrote {} bytes", wrote);
debug!("Wrote {} bytes", wrote);
Ok(())
}
@ -66,7 +66,7 @@ impl EppConnection {
let buf_size :usize = u32::from_be_bytes(buf).try_into()?;
let message_size = buf_size - 4;
println!("Message buffer size: {}", message_size);
debug!("Message buffer size: {}", message_size);
let mut buf = BytesMut::with_capacity(4096);
let mut read_buf = vec![0u8; 4096];
@ -75,11 +75,11 @@ impl EppConnection {
loop {
let read = self.stream.reader.read(&mut read_buf).await?;
println!("Read: {} bytes", read);
debug!("Read: {} bytes", read);
buf.extend_from_slice(&read_buf[0..read]);
read_size = read_size + read;
println!("Total read: {} bytes", read_size);
debug!("Total read: {} bytes", read_size);
if read == 0 {
panic!("Unexpected eof")
@ -108,7 +108,7 @@ impl EppConnection {
}
async fn close(&mut self) -> Result<(), Box<dyn Error>> {
println!("Closing ...");
debug!("Closing {} connection", self.registry);
self.stream.writer.shutdown().await?;
Ok(())
@ -124,7 +124,7 @@ impl Drop for EppConnection {
pub async fn epp_connect(registry_creds: &EppClientConnection) -> Result<ConnectionStream, error::Error> {
let (host, port) = registry_creds.connection_details();
println!("{}: {}", host, port);
debug!("Server: {}\r\nPort: {}", host, port);
let addr = (host.as_str(), port)
.to_socket_addrs()?
@ -137,6 +137,12 @@ pub async fn epp_connect(registry_creds: &EppClientConnection) -> Result<Connect
.root_store
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
if let Some(tls) = registry_creds.tls_files() {
if let Err(e) = config.set_single_client_cert(tls.0, tls.1) {
return Err(format!("Failed to set client TLS credentials: {}", e).into())
}
}
let connector = TlsConnector::from(Arc::new(config));
let stream = TcpStream::connect(&addr).await?;

View File

@ -1,6 +1,5 @@
pub mod command;
pub mod object;
pub mod quick_xml;
pub mod request;
pub mod response;
pub mod xml;

View File

@ -13,12 +13,12 @@ pub type EppContactUpdate = EppObject<Command<ContactUpdate>>;
#[derive(Serialize, Deserialize, Debug)]
pub struct ContactChangeInfo {
#[serde(rename = "postalInfo")]
postal_info: PostalInfo,
voice: Phone,
postal_info: Option<PostalInfo>,
voice: Option<Phone>,
fax: Option<Phone>,
email: StringValue,
email: Option<StringValue>,
#[serde(rename = "authInfo")]
auth_info: AuthInfo,
auth_info: Option<AuthInfo>,
}
#[derive(Serialize, Deserialize, Debug)]
@ -69,10 +69,10 @@ impl EppContactUpdate {
auth_password: &str,
) {
self.data.command.contact.change_info = Some(ContactChangeInfo {
email: email.to_string_value(),
postal_info: postal_info,
voice: voice,
auth_info: AuthInfo::new(auth_password),
email: Some(email.to_string_value()),
postal_info: Some(postal_info),
voice: Some(voice),
auth_info: Some(AuthInfo::new(auth_password)),
fax: None,
});
}
@ -99,11 +99,11 @@ impl EppContactUpdate {
match contact_info.data.res_data {
Some(res_data) => {
self.data.command.contact.change_info = Some(ContactChangeInfo {
email: res_data.info_data.email.clone(),
postal_info: res_data.info_data.postal_info.clone(),
voice: res_data.info_data.voice.clone(),
email: Some(res_data.info_data.email.clone()),
postal_info: Some(res_data.info_data.postal_info.clone()),
voice: Some(res_data.info_data.voice.clone()),
fax: res_data.info_data.fax.clone(),
auth_info: res_data.info_data.auth_info.clone(),
auth_info: None,
});
Ok(())
}

View File

@ -11,9 +11,9 @@ pub type EppDomainUpdateWithHostAttr = EppObject<Command<DomainUpdate<HostAttrLi
#[derive(Serialize, Deserialize, Debug)]
pub struct DomainChangeInfo {
registrant: StringValue,
pub registrant: Option<StringValue>,
#[serde(rename = "authInfo")]
auth_info: AuthInfo,
pub auth_info: Option<AuthInfo>,
}
#[derive(Serialize, Deserialize, Debug)]

View File

@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
pub type EppMessageAck = EppObject<Command<MessageAck>>;
#[derive(Serialize, Deserialize, Debug, ElementName)]
#[element_name(name = "ack")]
#[element_name(name = "poll")]
pub struct MessageAck {
op: String,
#[serde(rename = "msgID")]

View File

@ -31,7 +31,7 @@ pub struct ContactInfoData {
#[serde(rename = "trDate")]
pub transferred_at: Option<StringValue>,
#[serde(rename = "authInfo")]
pub auth_info: AuthInfo,
pub auth_info: Option<AuthInfo>,
}
#[derive(Serialize, Deserialize, Debug)]

View File

@ -15,7 +15,8 @@ pub struct DomainCheck {
#[derive(Serialize, Deserialize, Debug)]
pub struct DomainCheckDataItem {
pub name: DomainCheck,
#[serde(rename = "name")]
pub domain: DomainCheck,
pub reason: Option<StringValue>,
}

View File

@ -1,3 +1,5 @@
pub mod quick_xml;
use std::{error::Error, fmt::Debug};
use crate::error;

View File

@ -1,3 +1,90 @@
//! EPP Client Library for the Extensible Provisioning Protocol (EPP).
//!
//! ## Description
//!
//! epp-client is a client library for Internet domain registration and management for domain registrars.
//!
//! It supports the following basic Domain, Contact and Host management calls, with plans to add more calls
//! and other EPP extensions in the future, and to eventually be RFC compliant with the EPP protocol.
//!
//! - Domain Check
//! - Domain Create
//! - Domain Info
//! - Domain Update
//! - Domain Delete
//! - Domain Renew
//! - Domain Transfer
//!
//! - Contact Check
//! - Contact Create
//! - Contact Info
//! - Contact Update
//! - Contact Delete
//!
//! - Host Check
//! - Host Create
//! - Host Info
//! - Host Update
//! - Host Delete
//!
//! ## Prerequisites
//!
//! To use the library, you must have an `epp-client/epp-client.toml` config file with the relevant registry
//! credentials in your default user configuration directory on your OS. For Linux, this is the `XDG user directory`,
//! usually located at `$HOME/.config` or defined by the `XDG_CONFIG_HOME` environment variable.
//!
//! An example config looks like this:
//!
//! ```toml
//! [registry.verisign]
//! host = 'epp.verisign-grs.com'
//! port = 700
//! username = 'username'
//! password = 'password'
//! # service extensions
//! ext_uris = []
//!
//! [registry.hexonet.tls_files]
//! # the full client certificate chain in PEM format
//! cert_chain = '/path/to/certificate/chain/pemfile'
//! # the RSA private key for your certificate
//! key = '/path/to/private/key/pemfile'
//! ```
//!
//! ## Operation
//!
//! Once the config is set correctly, you can create a mut variable of type [`EppClient`] to transact
//! with the domain registry
//!
//! ```rust
//! use epp_client::EppClient;
//! use epp_client::epp::{EppDomainCheck, EppDomainCheckResponse};
//!
//! #[tokio::main]
//! async fn main() {
//! // Create an instance of EppClient, specifying the name of the registry as in
//! // the config file
//! let mut client = match EppClient::new("verisign").await {
//! Ok(client) => client,
//! Err(e) => panic!("Failed to create EppClient: {}", e)
//! };
//!
//! // Make a domain check call, which returns an object of type EppDomainCheckResponse
//! // that contains the result of the call
//! let domain_check = EppDomainCheck::new(vec!["eppdev.com", "eppdev.net"], "client-trid-12345");
//!
//! let response = client.transact::<_, EppDomainCheckResponse>(&domain_check).await.unwrap();
//!
//! // print the availability results
//! response.data.res_data.unwrap().check_data.domain_list
//! .iter()
//! .for_each(|chk| println!("Domain: {}, Available: {}", chk.domain.name, chk.domain.available));
//! }
//! ```
#[macro_use]
extern crate log;
pub mod config;
pub mod connection;
pub mod epp;
@ -7,30 +94,484 @@ pub use connection::client::EppClient;
#[cfg(test)]
mod tests {
use super::config;
use super::connection::client::EppClient;
use std::{fs::File, io::Read, error::Error};
use regex::Regex;
#[test]
fn config() {
let servers = &config::CONFIG.servers;
const RESOURCES_DIR: &str = "./test/resources";
()
fn get_xml(path: &str) -> Result<String, Box<dyn Error>> {
let ws_regex = Regex::new(r"[\s]{2,}")?;
let mut f = File::open(format!("{}/{}", RESOURCES_DIR, path))?;
let mut buf = String::new();
f.read_to_string(&mut buf)?;
if buf.len() > 0 {
let mat = Regex::new(r"\?>").unwrap().find(&buf.as_str()).unwrap();
let start = mat.end();
buf = format!("{}\r\n{}", &buf[..start], ws_regex.replace_all(&buf[start..], ""));
}
Ok(buf)
}
macro_rules! aw {
($e:expr) => {
tokio_test::block_on($e)
};
}
mod se {
mod request {
use chrono::NaiveDate;
use crate::tests::get_xml;
use crate::epp::object::StringValueTrait;
use crate::epp::object::data::{
Phone, Address, PostalInfo, ContactStatus, DomainContact, HostAttr, HostAddr,
DomainStatus, AuthInfo, Host, HostStatus
};
use crate::epp::request::{EppHello, EppLogin, EppLogout};
use crate::epp::xml::EppXml;
use crate::epp::*;
#[test]
fn connect() {
let mut client = match aw!(EppClient::new("hexonet")) {
Ok(client) => {
println!("{}", client.xml_greeting());
client
},
Err(e) => panic!("Error: {}", e)
};
const CLTRID: &str = "cltrid:1626454866";
#[test]
fn hello() {
let xml = get_xml("request/hello.xml").unwrap();
let object = EppHello::new();
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn login() {
let ext_uris = Some(vec![
"http://schema.ispapi.net/epp/xml/keyvalue-1.0".to_string()
]);
let xml = get_xml("request/login.xml").unwrap();
let object = EppLogin::new("username", "password", &ext_uris, CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn logout() {
let xml = get_xml("request/logout.xml").unwrap();
let object = EppLogout::new(CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn contact_check() {
let xml = get_xml("request/contact/check.xml").unwrap();
let object = EppContactCheck::new(vec!["eppdev-contact-1", "eppdev-contact-2"], CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn contact_create() {
let xml = get_xml("request/contact/create.xml").unwrap();
let street = vec!["58", "Orchid Road"];
let address = Address::new(street, "Paris", "Paris", "392374", "FR");
let postal_info = PostalInfo::new("int", "John Doe", "Acme Widgets", address);
let mut voice = Phone::new("+33.47237942");
voice.set_extension("123");
let mut fax = Phone::new("+33.86698799");
fax.set_extension("677");
let mut object = EppContactCreate::new("eppdev-contact-3", "contact@eppdev.net", postal_info, voice, "eppdev-387323", CLTRID);
object.set_fax(fax);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn contact_info() {
let xml = get_xml("request/contact/info.xml").unwrap();
let object = EppContactInfo::new("eppdev-contact-3", "eppdev-387323", CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn contact_update() {
let xml = get_xml("request/contact/update.xml").unwrap();
let mut object = EppContactUpdate::new("eppdev-contact-3", CLTRID);
let street = vec!["58", "Orchid Road"];
let address = Address::new(street, "Paris", "Paris", "392374", "FR");
let postal_info = PostalInfo::new("loc", "John Doe", "Acme Widgets", address);
let voice = Phone::new("+33.47237942");
object.set_info("newemail@eppdev.net", postal_info, voice, "eppdev-387323");
let add_statuses = vec![ContactStatus { status: "clientTransferProhibited".to_string() }];
object.add_statuses(add_statuses);
let remove_statuses = vec![ContactStatus { status: "clientDeleteProhibited".to_string() }];
object.remove_statuses(remove_statuses);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn contact_delete() {
let xml = get_xml("request/contact/delete.xml").unwrap();
let object = EppContactDelete::new("eppdev-contact-3", CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn domain_check() {
let xml = get_xml("request/domain/check.xml").unwrap();
let object = EppDomainCheck::new(vec!["eppdev.com", "eppdev.net"], CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn domain_create() {
let xml = get_xml("request/domain/create.xml").unwrap();
let contacts = vec![
DomainContact {
contact_type: "admin".to_string(),
id: "eppdev-contact-3".to_string()
},
DomainContact {
contact_type: "tech".to_string(),
id: "eppdev-contact-3".to_string()
},
DomainContact {
contact_type: "billing".to_string(),
id: "eppdev-contact-3".to_string()
}
];
let object = EppDomainCreate::new("eppdev-1.com", 1, "eppdev-contact-3", "epP4uthd#v", contacts, CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn domain_create_with_host_obj() {
let xml = get_xml("request/domain/create_with_host_obj.xml").unwrap();
let contacts = vec![
DomainContact {
contact_type: "admin".to_string(),
id: "eppdev-contact-3".to_string()
},
DomainContact {
contact_type: "tech".to_string(),
id: "eppdev-contact-3".to_string()
},
DomainContact {
contact_type: "billing".to_string(),
id: "eppdev-contact-3".to_string()
}
];
let object = EppDomainCreate::new_with_ns("eppdev-1.com", 1, vec!["ns1.test.com", "ns2.test.com"], "eppdev-contact-3", "epP4uthd#v", contacts, CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn domain_create_with_host_attr() {
let xml = get_xml("request/domain/create_with_host_attr.xml").unwrap();
let contacts = vec![
DomainContact {
contact_type: "admin".to_string(),
id: "eppdev-contact-3".to_string()
},
DomainContact {
contact_type: "tech".to_string(),
id: "eppdev-contact-3".to_string()
},
DomainContact {
contact_type: "billing".to_string(),
id: "eppdev-contact-3".to_string()
}
];
let host_attr = vec![
HostAttr {
name: "ns1.eppdev-1.com".to_string_value(),
addresses: None,
},
HostAttr {
name: "ns2.eppdev-1.com".to_string_value(),
addresses: Some(vec![
HostAddr::new_v4("177.232.12.58"),
HostAddr::new_v6("2404:6800:4001:801::200e"),
])
}
];
let object = EppDomainCreate::new_with_host_attr("eppdev-2.com", 1, host_attr, "eppdev-contact-3", "epP4uthd#v", contacts, CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn domain_info() {
let xml = get_xml("request/domain/info.xml").unwrap();
let object = EppDomainInfo::new("eppdev.com", CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn domain_update() {
let xml = get_xml("request/domain/update.xml").unwrap();
let mut object = EppDomainUpdate::new("eppdev.com", CLTRID);
let add = DomainAddRemove {
ns: None,
contacts: None,
statuses: Some(vec![
DomainStatus {
status: "clientDeleteProhibited".to_string()
}
])
};
let remove = DomainAddRemove {
ns: None,
contacts: Some(vec![
DomainContact {
contact_type: "billing".to_string(),
id: "eppdev-contact-2".to_string()
}
]),
statuses: None,
};
let change_info = DomainChangeInfo {
registrant: None,
auth_info: Some(AuthInfo::new("epP5uthd#v")),
};
object.add(add);
object.remove(remove);
object.info(change_info);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn domain_delete() {
let xml = get_xml("request/domain/delete.xml").unwrap();
let object = EppDomainDelete::new("eppdev.com", CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn domain_renew() {
let xml = get_xml("request/domain/renew.xml").unwrap();
let exp_date = NaiveDate::from_ymd(2022, 7, 23);
let object = EppDomainRenew::new("eppdev.com", exp_date, 1, CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn domain_transfer_request() {
let xml = get_xml("request/domain/transfer_request.xml").unwrap();
let object = EppDomainTransferRequest::request("testing.com", 1, "epP4uthd#v", CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn domain_transfer_approve() {
let xml = get_xml("request/domain/transfer_approve.xml").unwrap();
let object = EppDomainTransferApprove::approve("testing.com", CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn domain_transfer_reject() {
let xml = get_xml("request/domain/transfer_reject.xml").unwrap();
let object = EppDomainTransferReject::reject("testing.com", CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn domain_transfer_cancel() {
let xml = get_xml("request/domain/transfer_cancel.xml").unwrap();
let object = EppDomainTransferCancel::cancel("testing.com", CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn domain_transfer_query() {
let xml = get_xml("request/domain/transfer_query.xml").unwrap();
let object = EppDomainTransferQuery::query("testing.com", "epP4uthd#v", CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn host_check() {
let xml = get_xml("request/host/check.xml").unwrap();
let object = EppHostCheck::new(vec!["ns1.eppdev-1.com", "host1.eppdev-1.com"], CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn host_create() {
let xml = get_xml("request/host/create.xml").unwrap();
let host = Host {
name: "host1.eppdev-1.com".to_string_value(),
addresses: Some(vec![
HostAddr::new("v4", "29.245.122.14"),
HostAddr::new("v6", "2404:6800:4001:801::200e"),
])
};
let object = EppHostCreate::new(host, CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn host_info() {
let xml = get_xml("request/host/info.xml").unwrap();
let object = EppHostInfo::new("ns1.eppdev-1.com", CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn host_update() {
let xml = get_xml("request/host/update.xml").unwrap();
let addr = vec![
HostAddr::new("v6", "2404:6800:4001:801::200e"),
];
let add = HostAddRemove {
addresses: Some(addr),
statuses: None,
};
let remove = HostAddRemove {
addresses: None,
statuses: Some(vec![
HostStatus {
status: "clientDeleteProhibited".to_string()
}
]),
};
let mut object = EppHostUpdate::new("host1.eppdev-1.com", CLTRID);
object.add(add);
object.remove(remove);
object.info(HostChangeInfo { name: "host2.eppdev-1.com".to_string_value() });
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn host_delete() {
let xml = get_xml("request/host/delete.xml").unwrap();
let object = EppHostDelete::new("ns1.eppdev-1.com", CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn message_poll() {
let xml = get_xml("request/message/poll.xml").unwrap();
let object = EppMessagePoll::new(CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn message_ack() {
let xml = get_xml("request/message/ack.xml").unwrap();
let object = EppMessageAck::new(12345, CLTRID);
let serialized = object.serialize().unwrap();
assert_eq!(xml, serialized);
}
}
}
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<check>
<check xmlns="urn:ietf:params:xml:ns:contact-1.0">
<id>eppdev-contact-1</id>
<id>eppdev-contact-2</id>
</check>
</check>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<create>
<create xmlns="urn:ietf:params:xml:ns:contact-1.0">
<id>eppdev-contact-3</id>
<postalInfo type="int">
<name>John Doe</name>
<org>Acme Widgets</org>
<addr>
<street>58</street>
<street>Orchid Road</street>
<city>Paris</city>
<sp>Paris</sp>
<pc>392374</pc>
<cc>FR</cc>
</addr>
</postalInfo>
<voice x="123">+33.47237942</voice>
<fax x="677">+33.86698799</fax>
<email>contact@eppdev.net</email>
<authInfo>
<pw>eppdev-387323</pw>
</authInfo>
</create>
</create>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<delete>
<delete xmlns="urn:ietf:params:xml:ns:contact-1.0">
<id>eppdev-contact-3</id>
</delete>
</delete>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<info>
<info xmlns="urn:ietf:params:xml:ns:contact-1.0">
<id>eppdev-contact-3</id>
<authInfo>
<pw>eppdev-387323</pw>
</authInfo>
</info>
</info>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<update>
<update xmlns="urn:ietf:params:xml:ns:contact-1.0">
<id>eppdev-contact-3</id>
<add>
<status s="clientTransferProhibited"/>
</add>
<rem>
<status s="clientDeleteProhibited"/>
</rem>
<chg>
<postalInfo type="loc">
<name>John Doe</name>
<org>Acme Widgets</org>
<addr>
<street>58</street>
<street>Orchid Road</street>
<city>Paris</city>
<sp>Paris</sp>
<pc>392374</pc>
<cc>FR</cc>
</addr>
</postalInfo>
<voice>+33.47237942</voice>
<email>newemail@eppdev.net</email>
<authInfo>
<pw>eppdev-387323</pw>
</authInfo>
</chg>
</update>
</update>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<check>
<check xmlns="urn:ietf:params:xml:ns:domain-1.0">
<name>eppdev.com</name>
<name>eppdev.net</name>
</check>
</check>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<create>
<create xmlns="urn:ietf:params:xml:ns:domain-1.0">
<name>eppdev-1.com</name>
<period unit="y">1</period>
<registrant>eppdev-contact-3</registrant>
<contact type="admin">eppdev-contact-3</contact>
<contact type="tech">eppdev-contact-3</contact>
<contact type="billing">eppdev-contact-3</contact>
<authInfo>
<pw>epP4uthd#v</pw>
</authInfo>
</create>
</create>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<create>
<create xmlns="urn:ietf:params:xml:ns:domain-1.0">
<name>eppdev-2.com</name>
<period unit="y">1</period>
<ns>
<hostAttr>
<hostName>ns1.eppdev-1.com</hostName>
</hostAttr>
<hostAttr>
<hostName>ns2.eppdev-1.com</hostName>
<hostAddr ip="v4">177.232.12.58</hostAddr>
<hostAddr ip="v6">2404:6800:4001:801::200e</hostAddr>
</hostAttr>
</ns>
<registrant>eppdev-contact-3</registrant>
<contact type="admin">eppdev-contact-3</contact>
<contact type="tech">eppdev-contact-3</contact>
<contact type="billing">eppdev-contact-3</contact>
<authInfo>
<pw>epP4uthd#v</pw>
</authInfo>
</create>
</create>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<create>
<create xmlns="urn:ietf:params:xml:ns:domain-1.0">
<name>eppdev-1.com</name>
<period unit="y">1</period>
<ns>
<hostObj>ns1.test.com</hostObj>
<hostObj>ns2.test.com</hostObj>
</ns>
<registrant>eppdev-contact-3</registrant>
<contact type="admin">eppdev-contact-3</contact>
<contact type="tech">eppdev-contact-3</contact>
<contact type="billing">eppdev-contact-3</contact>
<authInfo>
<pw>epP4uthd#v</pw>
</authInfo>
</create>
</create>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<delete>
<delete xmlns="urn:ietf:params:xml:ns:domain-1.0">
<name>eppdev.com</name>
</delete>
</delete>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<info>
<info xmlns="urn:ietf:params:xml:ns:domain-1.0">
<name hosts="all">eppdev.com</name>
</info>
</info>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<renew>
<renew xmlns="urn:ietf:params:xml:ns:domain-1.0">
<name>eppdev.com</name>
<curExpDate>2022-07-23</curExpDate>
<period unit="y">1</period>
</renew>
</renew>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<transfer op="approve">
<transfer xmlns="urn:ietf:params:xml:ns:domain-1.0">
<name>testing.com</name>
</transfer>
</transfer>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<transfer op="cancel">
<transfer xmlns="urn:ietf:params:xml:ns:domain-1.0">
<name>testing.com</name>
</transfer>
</transfer>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<transfer op="query">
<transfer xmlns="urn:ietf:params:xml:ns:domain-1.0">
<name>testing.com</name>
<authInfo>
<pw>epP4uthd#v</pw>
</authInfo>
</transfer>
</transfer>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<transfer op="reject">
<transfer xmlns="urn:ietf:params:xml:ns:domain-1.0">
<name>testing.com</name>
</transfer>
</transfer>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<transfer op="request">
<transfer xmlns="urn:ietf:params:xml:ns:domain-1.0">
<name>testing.com</name>
<period unit="y">1</period>
<authInfo>
<pw>epP4uthd#v</pw>
</authInfo>
</transfer>
</transfer>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<update>
<update xmlns="urn:ietf:params:xml:ns:domain-1.0">
<name>eppdev.com</name>
<add>
<status s="clientDeleteProhibited"/>
</add>
<rem>
<contact type="billing">eppdev-contact-2</contact>
</rem>
<chg>
<authInfo>
<pw>epP5uthd#v</pw>
</authInfo>
</chg>
</update>
</update>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<hello/>
</epp>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<check>
<check xmlns="urn:ietf:params:xml:ns:host-1.0">
<name>ns1.eppdev-1.com</name>
<name>host1.eppdev-1.com</name>
</check>
</check>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<create>
<create xmlns="urn:ietf:params:xml:ns:host-1.0">
<name>host1.eppdev-1.com</name>
<addr ip="v4">29.245.122.14</addr>
<addr ip="v6">2404:6800:4001:801::200e</addr>
</create>
</create>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<delete>
<delete xmlns="urn:ietf:params:xml:ns:host-1.0">
<name>ns1.eppdev-1.com</name>
</delete>
</delete>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<info>
<info xmlns="urn:ietf:params:xml:ns:host-1.0">
<name>ns1.eppdev-1.com</name>
</info>
</info>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<update>
<update xmlns="urn:ietf:params:xml:ns:host-1.0">
<name>host1.eppdev-1.com</name>
<add>
<addr ip="v6">2404:6800:4001:801::200e</addr>
</add>
<rem>
<status s="clientDeleteProhibited"/>
</rem>
<chg>
<name>host2.eppdev-1.com</name>
</chg>
</update>
</update>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<login>
<clID>username</clID>
<pw>password</pw>
<options>
<version>1.0</version>
<lang>en</lang>
</options>
<svcs>
<objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
<objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
<objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
<svcExtension>
<extURI>http://schema.ispapi.net/epp/xml/keyvalue-1.0</extURI>
</svcExtension>
</svcs>
</login>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<logout/>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<poll op="ack" msgID="12345"/>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<poll op="req"/>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>