Minimize configuration interface API
This commit is contained in:
parent
375a151851
commit
62645eec96
|
@ -12,7 +12,6 @@ celes = "2.1"
|
|||
chrono = "0.4"
|
||||
quick-xml = { version = "0.22", features = [ "serialize" ] }
|
||||
rustls = "0.20"
|
||||
rustls-pemfile = "0.2"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tokio = { version = "1.0", features = [ "full" ] }
|
||||
tokio-rustls = "0.23"
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
//!
|
||||
//! ```no_run
|
||||
//! use std::collections::HashMap;
|
||||
//! use std::net::ToSocketAddrs;
|
||||
//!
|
||||
//! use epp_client::config::{EppClientConfig, RegistryConfig};
|
||||
//! use epp_client::EppClient;
|
||||
//! use epp_client::domain::check::DomainCheck;
|
||||
//! use epp_client::common::NoExtension;
|
||||
|
@ -13,20 +13,10 @@
|
|||
//! #[tokio::main]
|
||||
//! async fn main() {
|
||||
//!
|
||||
//! // Create a config
|
||||
//! let mut registry: HashMap<String, RegistryConfig> = HashMap::new();
|
||||
//! registry.insert(
|
||||
//! "registry_name".to_owned(),
|
||||
//! RegistryConfig {
|
||||
//! host: "example.com".to_owned(),
|
||||
//! port: 700,
|
||||
//! tls_files: None,
|
||||
//! },
|
||||
//! );
|
||||
//! let config = EppClientConfig { registry };
|
||||
//!
|
||||
//! // Create an instance of EppClient, passing the config and the registry you want to connect to
|
||||
//! let mut client = match EppClient::new(&config, "registry_name").await {
|
||||
//! // Create an instance of EppClient
|
||||
//! let host = "example.com";
|
||||
//! let addr = (host, 7000).to_socket_addrs().unwrap().next().unwrap();
|
||||
//! let mut client = match EppClient::new("registry_name".to_string(), addr, host, None).await {
|
||||
//! Ok(client) => client,
|
||||
//! Err(e) => panic!("Failed to create EppClient: {}", e)
|
||||
//! };
|
||||
|
@ -44,9 +34,9 @@
|
|||
//! ```
|
||||
|
||||
use std::error::Error;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use crate::common::NoExtension;
|
||||
use crate::config::EppClientConfig;
|
||||
use crate::common::{Certificate, NoExtension, PrivateKey};
|
||||
use crate::connection::EppConnection;
|
||||
use crate::error;
|
||||
use crate::hello::{Greeting, GreetingDocument, HelloDocument};
|
||||
|
@ -65,16 +55,13 @@ impl EppClient {
|
|||
/// Creates a new EppClient object and does an EPP Login to a given registry to become ready
|
||||
/// for subsequent transactions on this client instance
|
||||
pub async fn new(
|
||||
config: &EppClientConfig,
|
||||
registry: &str,
|
||||
) -> Result<EppClient, Box<dyn Error>> {
|
||||
let registry_creds = match config.registry(registry) {
|
||||
Some(creds) => creds,
|
||||
None => return Err(format!("missing credentials for {}", registry).into()),
|
||||
};
|
||||
|
||||
Ok(EppClient {
|
||||
connection: EppConnection::connect(registry.to_string(), registry_creds).await?,
|
||||
registry: String,
|
||||
addr: SocketAddr,
|
||||
hostname: &str,
|
||||
identity: Option<(Vec<Certificate>, PrivateKey)>,
|
||||
) -> Result<Self, Box<dyn Error>> {
|
||||
Ok(Self {
|
||||
connection: EppConnection::connect(registry, addr, hostname, identity).await?,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -358,3 +358,13 @@ impl PostalInfo {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This type contains a single DER-encoded X.509 certificate.
|
||||
///
|
||||
/// The rustls-pemfile crate can be used to parse a PEM file.
|
||||
pub struct Certificate(pub Vec<u8>);
|
||||
|
||||
/// This type contains a DER-encoded ASN.1 private key in PKCS#8 or PKCS#1 format.
|
||||
///
|
||||
/// The rustls-pemfile crate can be used to parse a PEM file in these formats.
|
||||
pub struct PrivateKey(pub Vec<u8>);
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
//! Config
|
||||
//!
|
||||
//! This module contains the connection configuration for the EPP client.
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use std::collections::HashMap;
|
||||
//!
|
||||
//! use epp_client::config::{EppClientConfig, RegistryConfig};
|
||||
//!
|
||||
//! // Create a config
|
||||
//! let mut registry: HashMap<String, RegistryConfig> = HashMap::new();
|
||||
//! registry.insert(
|
||||
//! "registry_name".to_owned(),
|
||||
//! RegistryConfig {
|
||||
//! host: "example.com".to_owned(),
|
||||
//! port: 700,
|
||||
//! tls_files: None,
|
||||
//! },
|
||||
//! );
|
||||
//! let config = EppClientConfig { registry };
|
||||
//!
|
||||
//! // Get configuration for the relevant registry section
|
||||
//! let registry = config.registry("verisign").unwrap();
|
||||
//! ```
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Paths to the client certificate and client key PEM files
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct EppClientTlsFiles {
|
||||
pub cert_chain: PathBuf,
|
||||
pub key: PathBuf,
|
||||
}
|
||||
|
||||
/// Config that stores settings for multiple registries
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct EppClientConfig {
|
||||
pub registry: HashMap<String, RegistryConfig>,
|
||||
}
|
||||
|
||||
impl EppClientConfig {
|
||||
/// Returns the config for a particular registry
|
||||
pub fn registry(&self, registry: &str) -> Option<&RegistryConfig> {
|
||||
self.registry.get(registry)
|
||||
}
|
||||
}
|
||||
|
||||
/// Connection details to connect to and authenticate with a registry
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct RegistryConfig {
|
||||
pub host: String,
|
||||
pub port: u16,
|
||||
pub tls_files: Option<EppClientTlsFiles>,
|
||||
}
|
|
@ -1,20 +1,17 @@
|
|||
//! Manages registry connections and reading/writing to them
|
||||
|
||||
use std::convert::TryInto;
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, Seek, SeekFrom};
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::{error::Error, io as stdio, net::ToSocketAddrs};
|
||||
use std::{error::Error, io as stdio};
|
||||
use std::{io, str, u32};
|
||||
|
||||
use rustls::{Certificate, PrivateKey};
|
||||
use rustls::{OwnedTrustAnchor, RootCertStore};
|
||||
use rustls_pemfile;
|
||||
use tokio::{io::AsyncReadExt, io::AsyncWriteExt, net::TcpStream};
|
||||
use tokio_rustls::{client::TlsStream, rustls::ClientConfig, TlsConnector};
|
||||
use tracing::{debug, info, warn};
|
||||
use tracing::{debug, info};
|
||||
|
||||
use crate::config::RegistryConfig;
|
||||
use crate::common::{Certificate, PrivateKey};
|
||||
use crate::error;
|
||||
|
||||
/// EPP Connection struct with some metadata for the connection
|
||||
|
@ -28,9 +25,11 @@ impl EppConnection {
|
|||
/// Create an EppConnection instance with the stream to the registry
|
||||
pub(crate) async fn connect(
|
||||
registry: String,
|
||||
config: &RegistryConfig,
|
||||
addr: SocketAddr,
|
||||
hostname: &str,
|
||||
identity: Option<(Vec<Certificate>, PrivateKey)>,
|
||||
) -> Result<EppConnection, Box<dyn Error>> {
|
||||
let mut stream = epp_connect(config).await?;
|
||||
let mut stream = epp_connect(addr, hostname, identity).await?;
|
||||
|
||||
let mut buf = vec![0u8; 4096];
|
||||
stream.read(&mut buf).await?;
|
||||
|
@ -121,17 +120,11 @@ impl EppConnection {
|
|||
/// Establishes a TLS connection to a registry and returns a ConnectionStream instance containing the
|
||||
/// socket stream to read/write to the connection
|
||||
async fn epp_connect(
|
||||
registry_creds: &RegistryConfig,
|
||||
addr: SocketAddr,
|
||||
hostname: &str,
|
||||
identity: Option<(Vec<Certificate>, PrivateKey)>,
|
||||
) -> Result<TlsStream<TcpStream>, error::Error> {
|
||||
info!(
|
||||
"Connecting: EPP Server: {} Port: {}",
|
||||
registry_creds.host, registry_creds.port
|
||||
);
|
||||
|
||||
let addr = (registry_creds.host.as_str(), registry_creds.port)
|
||||
.to_socket_addrs()?
|
||||
.next()
|
||||
.ok_or(stdio::ErrorKind::NotFound)?;
|
||||
info!("Connecting to server: {:?}", addr,);
|
||||
|
||||
let mut roots = RootCertStore::empty();
|
||||
roots.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| {
|
||||
|
@ -146,41 +139,15 @@ async fn epp_connect(
|
|||
.with_safe_defaults()
|
||||
.with_root_certificates(roots);
|
||||
|
||||
let config = match ®istry_creds.tls_files {
|
||||
Some(files) => {
|
||||
let (certs_file, key_file) = (&files.cert_chain, &files.key);
|
||||
let certs = rustls_pemfile::certs(&mut BufReader::new(File::open(certs_file)?))?
|
||||
let config = match identity {
|
||||
Some((certs, key)) => {
|
||||
let certs = certs
|
||||
.into_iter()
|
||||
.map(Certificate)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut key;
|
||||
let mut r = BufReader::new(File::open(key_file).unwrap());
|
||||
let mut rsa_keys = rustls_pemfile::rsa_private_keys(&mut r).unwrap();
|
||||
if rsa_keys.len() > 1 {
|
||||
warn!("Multiple RSA keys found in PEM file {:?}", key_file);
|
||||
}
|
||||
key = rsa_keys.pop();
|
||||
|
||||
if key.is_none() {
|
||||
r.seek(SeekFrom::Start(0))?;
|
||||
let mut pkcs8_keys = rustls_pemfile::pkcs8_private_keys(&mut r).unwrap();
|
||||
if pkcs8_keys.len() > 1 {
|
||||
warn!("Multiple PKCS8 keys found in PEM file {:?}", key_file);
|
||||
}
|
||||
key = pkcs8_keys.pop();
|
||||
}
|
||||
|
||||
match key {
|
||||
Some(key) => builder
|
||||
.with_single_cert(certs, PrivateKey(key))
|
||||
.map_err(|e| error::Error::Other(e.to_string()))?,
|
||||
None => {
|
||||
return Err(error::Error::Other(
|
||||
"No private key found in PEM file".to_owned(),
|
||||
))
|
||||
}
|
||||
}
|
||||
.map(|cert| rustls::Certificate(cert.0))
|
||||
.collect();
|
||||
builder
|
||||
.with_single_cert(certs, rustls::PrivateKey(key.0))
|
||||
.map_err(|e| error::Error::Other(e.to_string()))?
|
||||
}
|
||||
None => builder.with_no_client_auth(),
|
||||
};
|
||||
|
@ -188,10 +155,10 @@ async fn epp_connect(
|
|||
let connector = TlsConnector::from(Arc::new(config));
|
||||
let stream = TcpStream::connect(&addr).await?;
|
||||
|
||||
let domain = registry_creds.host.as_str().try_into().map_err(|_| {
|
||||
let domain = hostname.try_into().map_err(|_| {
|
||||
stdio::Error::new(
|
||||
stdio::ErrorKind::InvalidInput,
|
||||
format!("Invalid domain: {}", registry_creds.host),
|
||||
format!("Invalid domain: {}", hostname),
|
||||
)
|
||||
})?;
|
||||
|
||||
|
|
21
src/lib.rs
21
src/lib.rs
|
@ -40,8 +40,8 @@
|
|||
//!
|
||||
//! ```no_run
|
||||
//! use std::collections::HashMap;
|
||||
//! use std::net::ToSocketAddrs;
|
||||
//!
|
||||
//! use epp_client::config::{EppClientConfig, RegistryConfig};
|
||||
//! use epp_client::EppClient;
|
||||
//! use epp_client::domain::check::DomainCheck;
|
||||
//! use epp_client::common::NoExtension;
|
||||
|
@ -51,20 +51,10 @@
|
|||
//! #[tokio::main]
|
||||
//! async fn main() {
|
||||
//!
|
||||
//! // Create a config
|
||||
//! let mut registry: HashMap<String, RegistryConfig> = HashMap::new();
|
||||
//! registry.insert(
|
||||
//! "registry_name".to_owned(),
|
||||
//! RegistryConfig {
|
||||
//! host: "example.com".to_owned(),
|
||||
//! port: 700,
|
||||
//! tls_files: None,
|
||||
//! },
|
||||
//! );
|
||||
//! let config = EppClientConfig { registry };
|
||||
//!
|
||||
//! // Create an instance of EppClient, passing the config and the registry you want to connect to
|
||||
//! let mut client = match EppClient::new(&config, "registry_name").await {
|
||||
//! // Create an instance of EppClient
|
||||
//! let host = "example.com";
|
||||
//! let addr = (host, 7000).to_socket_addrs().unwrap().next().unwrap();
|
||||
//! let mut client = match EppClient::new("registry_name".to_string(), addr, host, None).await {
|
||||
//! Ok(client) => client,
|
||||
//! Err(e) => panic!("Failed to create EppClient: {}", e)
|
||||
//! };
|
||||
|
@ -99,7 +89,6 @@
|
|||
|
||||
pub mod client;
|
||||
pub mod common;
|
||||
pub mod config;
|
||||
pub mod connection;
|
||||
pub mod error;
|
||||
pub mod hello;
|
||||
|
|
Loading…
Reference in New Issue