diff --git a/src/api/tls.rs b/src/api/tls.rs index fd33c3f..2cbf638 100644 --- a/src/api/tls.rs +++ b/src/api/tls.rs @@ -105,24 +105,47 @@ impl Acceptor { #[cfg(test)] mod tests { - use rustls::{ClientConfig, NoClientAuth, ServerConfig}; + use futures_util::{future, stream, StreamExt}; + use rustls::{ + Certificate, ClientConfig, RootCertStore, ServerCertVerified, ServerCertVerifier, TLSError, + }; use std::sync::Arc; use tokio_rustls::webpki::DNSNameRef; - use tokio_rustls::{TlsAcceptor, TlsConnector}; + use tokio_rustls::TlsConnector; + + use super::wrap; + use crate::facade::TestFacade; async fn _test() { let (client, server) = tokio::io::duplex(64); + let server = stream::once(future::ready(Ok(future::ready(Ok(server))))); + let mut acceptor = wrap(server, TestFacade::default()); let server_future = tokio::spawn(async move { - let server_config = ServerConfig::new(NoClientAuth::new()); - let acceptor = TlsAcceptor::from(Arc::new(server_config)); - - acceptor.accept(server).await.unwrap(); + acceptor.next().await.unwrap().unwrap().await.unwrap(); }); + struct TestVerifier; + impl ServerCertVerifier for TestVerifier { + fn verify_server_cert( + &self, + _roots: &RootCertStore, + presented_certs: &[Certificate], + _dns_name: DNSNameRef<'_>, + _ocsp_response: &[u8], + ) -> Result { + println!("{:?}", presented_certs); + Ok(ServerCertVerified::assertion()) + } + } + let client_future = tokio::spawn(async move { - let client_config = Arc::new(ClientConfig::new()); - let connector = TlsConnector::from(client_config); + let mut client_config = ClientConfig::new(); + client_config + .dangerous() + .set_certificate_verifier(Arc::new(TestVerifier {})); + + let connector = TlsConnector::from(Arc::new(client_config)); let domain = DNSNameRef::try_from_ascii_str("google.com").unwrap(); connector.connect(domain, client).await.unwrap(); diff --git a/src/facade/cert.rs b/src/facade/cert.rs index 170a9ab..ecb2145 100644 --- a/src/facade/cert.rs +++ b/src/facade/cert.rs @@ -1,12 +1,13 @@ use anyhow::Result; use async_trait::async_trait; use sqlx::FromRow; -use sqlx::{Executor, Postgres}; +use sqlx::{Database, Executor, Postgres}; use tracing::info; use uuid::Uuid; -use super::domain::{create_domain, Domain}; -use super::PostgresFacade; +use super::domain::{Domain, DomainFacadeInternal}; +use super::DatabaseFacade; +use crate::facade::TestFacade; use crate::util::{now, to_i64, HOUR}; #[derive(sqlx::Type, Debug, PartialEq, Clone)] @@ -56,71 +57,97 @@ pub trait CertFacade { async fn stop_cert(&self, memory_cert: &mut Cert) -> Result<(), sqlx::Error>; } -async fn first_cert<'a, E: Executor<'a, Database = Postgres>>( - executor: E, -) -> Result, sqlx::Error> { - sqlx::query_as("SELECT * FROM cert LIMIT 1") - .fetch_optional(executor) - .await +#[async_trait] +trait CertFacadeInternal { + async fn first_cert<'a, E: Executor<'a, Database = DB>>( + &self, + executor: E, + ) -> Result, sqlx::Error>; + + async fn update_cert<'a, E: Executor<'a, Database = DB>>( + &self, + executor: E, + cert: &Cert, + ) -> Result<(), sqlx::Error>; + + async fn create_cert<'a, E: Executor<'a, Database = DB>>( + &self, + executor: E, + cert: &Cert, + ) -> Result<(), sqlx::Error>; } -async fn update_cert<'a, E: Executor<'a, Database = Postgres>>( - executor: E, - cert: &Cert, -) -> Result<(), sqlx::Error> { - sqlx::query("UPDATE cert SET update = $1, state = $2, cert = $3, private = $4, domain_id = $5 WHERE id = $6") - .bind(&cert.update) - .bind(&cert.state) - .bind(&cert.cert) - .bind(&cert.private) - .bind(&cert.domain) - .bind(&cert.id) - .execute(executor) - .await?; - - Ok(()) -} +#[async_trait] +impl CertFacadeInternal for DatabaseFacade { + async fn first_cert<'a, E: Executor<'a, Database = Postgres>>( + &self, + executor: E, + ) -> Result, sqlx::Error> { + sqlx::query_as("SELECT * FROM cert LIMIT 1") + .fetch_optional(executor) + .await + } + + async fn update_cert<'a, E: Executor<'a, Database = Postgres>>( + &self, + executor: E, + cert: &Cert, + ) -> Result<(), sqlx::Error> { + sqlx::query("UPDATE cert SET update = $1, state = $2, cert = $3, private = $4, domain_id = $5 WHERE id = $6") + .bind(&cert.update) + .bind(&cert.state) + .bind(&cert.cert) + .bind(&cert.private) + .bind(&cert.domain) + .bind(&cert.id) + .execute(executor) + .await?; + + Ok(()) + } -async fn create_cert<'a, E: Executor<'a, Database = Postgres>>( - executor: E, - cert: &Cert, -) -> Result<(), sqlx::Error> { - sqlx::query("INSERT INTO cert (id, update, state, cert, private, domain_id) VALUES ($1, $2, $3, $4, $5, $6)") - .bind(&cert.id) - .bind(&cert.update) - .bind(&cert.state) - .bind(&cert.cert) - .bind(&cert.private) - .bind(&cert.domain) - .execute(executor) - .await?; - - Ok(()) + async fn create_cert<'a, E: Executor<'a, Database = Postgres>>( + &self, + executor: E, + cert: &Cert, + ) -> Result<(), sqlx::Error> { + sqlx::query("INSERT INTO cert (id, update, state, cert, private, domain_id) VALUES ($1, $2, $3, $4, $5, $6)") + .bind(&cert.id) + .bind(&cert.update) + .bind(&cert.state) + .bind(&cert.cert) + .bind(&cert.private) + .bind(&cert.domain) + .execute(executor) + .await?; + + Ok(()) + } } #[async_trait] -impl CertFacade for PostgresFacade { +impl CertFacade for DatabaseFacade { async fn first_cert(&self) -> Result, sqlx::Error> { - first_cert(&self.pool).await + CertFacadeInternal::first_cert(self, &self.pool).await } async fn update_cert(&self, cert: &Cert) -> Result<(), sqlx::Error> { - update_cert(&self.pool, cert).await + CertFacadeInternal::update_cert(self, &self.pool, cert).await } async fn create_cert(&self, cert: &Cert) -> Result<(), sqlx::Error> { - create_cert(&self.pool, cert).await + CertFacadeInternal::create_cert(self, &self.pool, cert).await } async fn start_cert(&self) -> Result> { let mut transaction = self.pool.begin().await?; - let cert = first_cert(&mut transaction).await?; + let cert = CertFacadeInternal::first_cert(self, &mut transaction).await?; let cert = match cert { Some(mut cert) if cert.state == State::Ok => { cert.state = State::Updating; - update_cert(&mut transaction, &cert).await?; + CertFacadeInternal::update_cert(self, &mut transaction, &cert).await?; Some(cert) } Some(mut cert) => { @@ -130,7 +157,7 @@ impl CertFacade for PostgresFacade { if cert.update < one_hour_ago { cert.update = now; cert.state = State::Updating; - update_cert(&mut transaction, &cert).await?; + CertFacadeInternal::update_cert(self, &mut transaction, &cert).await?; Some(cert) } else { info!("job still in progress"); @@ -141,8 +168,8 @@ impl CertFacade for PostgresFacade { let domain = Domain::new()?; let cert = Cert::new(&domain); - create_domain(&mut transaction, &domain).await?; - create_cert(&mut transaction, &cert).await?; + DomainFacadeInternal::create_domain(self, &mut transaction, &domain).await?; + CertFacadeInternal::create_cert(self, &mut transaction, &cert).await?; Some(cert) } }; @@ -155,10 +182,10 @@ impl CertFacade for PostgresFacade { async fn stop_cert(&self, memory_cert: &mut Cert) -> Result<(), sqlx::Error> { let mut transaction = self.pool.begin().await?; - match first_cert(&mut transaction).await? { + match CertFacadeInternal::first_cert(self, &mut transaction).await? { Some(cert) if cert.state == State::Updating && cert.update == memory_cert.update => { memory_cert.state = State::Ok; - update_cert(&self.pool, &memory_cert).await?; + CertFacadeInternal::update_cert(self, &self.pool, &memory_cert).await?; } _ => {} } @@ -167,3 +194,32 @@ impl CertFacade for PostgresFacade { Ok(()) } } + +#[async_trait] +impl CertFacade for TestFacade { + async fn first_cert(&self) -> Result, sqlx::Error> { + let certs = self.certs.lock(); + Ok(certs.values().next().map(Clone::clone)) + } + + async fn update_cert(&self, cert: &Cert) -> Result<(), sqlx::Error> { + let mut certs = self.certs.lock(); + *certs.get_mut(&cert.id).unwrap() = cert.clone(); + + Ok(()) + } + + async fn create_cert(&self, cert: &Cert) -> Result<(), sqlx::Error> { + self.certs.lock().insert(cert.id.clone(), cert.clone()); + + Ok(()) + } + + async fn start_cert(&self) -> Result> { + unimplemented!() + } + + async fn stop_cert(&self, _memory_cert: &mut Cert) -> Result<(), sqlx::Error> { + unimplemented!() + } +} diff --git a/src/facade/domain.rs b/src/facade/domain.rs index 6187669..1101b31 100644 --- a/src/facade/domain.rs +++ b/src/facade/domain.rs @@ -2,9 +2,9 @@ use anyhow::{Error, Result}; use async_trait::async_trait; use core::convert::TryFrom; use serde::{Deserialize, Serialize}; -use sqlx::{Executor, Postgres}; +use sqlx::{Database, Executor, Postgres}; -use super::PostgresFacade; +use super::DatabaseFacade; use crate::util::uuid; #[derive(Debug, Serialize, Clone)] @@ -66,23 +66,36 @@ pub trait DomainFacade { async fn update_domain(&self, domain: &Domain) -> Result<(), sqlx::Error>; } -pub(super) async fn create_domain<'a, E: Executor<'a, Database = Postgres>>( - executor: E, - domain: &Domain, -) -> Result<(), sqlx::Error> { - sqlx::query("INSERT INTO domain (id, username, password, txt) VALUES ($1, $2, $3, $4)") - .bind(&domain.id) - .bind(&domain.username) - .bind(&domain.password) - .bind(&domain.txt) - .execute(executor) - .await?; - - Ok(()) +#[async_trait] +pub(super) trait DomainFacadeInternal { + async fn create_domain<'a, E: Executor<'a, Database = DB>>( + &self, + executor: E, + domain: &Domain, + ) -> Result<(), sqlx::Error>; +} + +#[async_trait] +impl DomainFacadeInternal for DatabaseFacade { + async fn create_domain<'a, E: Executor<'a, Database = Postgres>>( + &self, + executor: E, + domain: &Domain, + ) -> Result<(), sqlx::Error> { + sqlx::query("INSERT INTO domain (id, username, password, txt) VALUES ($1, $2, $3, $4)") + .bind(&domain.id) + .bind(&domain.username) + .bind(&domain.password) + .bind(&domain.txt) + .execute(executor) + .await?; + + Ok(()) + } } #[async_trait] -impl DomainFacade for PostgresFacade { +impl DomainFacade for DatabaseFacade { async fn find_domain_by_id(&self, id: &str) -> Result, sqlx::Error> { sqlx::query_as("SELECT * FROM domain WHERE id = $1 LIMIT 1") .bind(id) @@ -91,7 +104,7 @@ impl DomainFacade for PostgresFacade { } async fn create_domain(&self, domain: &Domain) -> Result<(), sqlx::Error> { - create_domain(&self.pool, domain).await + DomainFacadeInternal::create_domain(self, &self.pool, domain).await } async fn update_domain(&self, domain: &Domain) -> Result<(), sqlx::Error> { diff --git a/src/facade/mod.rs b/src/facade/mod.rs index d649195..67d16b3 100644 --- a/src/facade/mod.rs +++ b/src/facade/mod.rs @@ -1,4 +1,7 @@ -use sqlx::PgPool; +use parking_lot::Mutex; +use sqlx::{Database, PgPool, Pool, Postgres}; +use std::collections::HashMap; +use std::sync::Arc; mod cert; mod domain; @@ -6,13 +9,27 @@ mod domain; pub use cert::{Cert, CertFacade, State}; pub use domain::{Domain, DomainDTO, DomainFacade}; -#[derive(Debug, Clone)] -pub(super) struct PostgresFacade { - pool: PgPool, +#[derive(Debug)] +pub(super) struct DatabaseFacade { + pool: Pool, } -impl From for PostgresFacade { +impl Clone for DatabaseFacade { + fn clone(&self) -> Self { + DatabaseFacade { + pool: self.pool.clone(), + } + } +} + +impl From for DatabaseFacade { fn from(pool: PgPool) -> Self { - PostgresFacade { pool } + DatabaseFacade { pool } } } + +#[derive(Default, Clone)] +pub(super) struct TestFacade { + certs: Arc>>, + //domains: Mutex>, +} diff --git a/src/main.rs b/src/main.rs index 0aa69af..f10b644 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ use tokio::runtime::Runtime; use tokio::signal::ctrl_c; use tracing::{debug, error, info, Instrument}; -use crate::facade::PostgresFacade; +use crate::facade::DatabaseFacade; use acme::DatabasePersist; use cert::CertManager; use dns::{DatabaseAuthority, DNS}; @@ -48,7 +48,7 @@ fn run() -> Result<()> { debug!("Running in runtime"); let pool = setup_database(&config.general.db).await?; - let facade = PostgresFacade::from(pool.clone()); + let facade = DatabaseFacade::from(pool.clone()); let authority = DatabaseAuthority::new(facade.clone(), &config.general.name, config.records); let dns = DNS::new(&config.general.dns, authority);