initial implementation of domain::Checker
This commit is contained in:
parent
71dcc94e29
commit
2d57353244
46
Cargo.lock
generated
46
Cargo.lock
generated
@ -326,6 +326,12 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "endian-type"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
|
||||
|
||||
[[package]]
|
||||
name = "enum-as-inner"
|
||||
version = "0.5.1"
|
||||
@ -470,6 +476,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"tempdir",
|
||||
"trust-dns-client",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1514,6 +1521,15 @@ dependencies = [
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nibble_vec"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
@ -1639,6 +1655,16 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "radix_trie"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd"
|
||||
dependencies = [
|
||||
"endian-type",
|
||||
"nibble_vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.4.6"
|
||||
@ -2236,6 +2262,26 @@ dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trust-dns-client"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c408c32e6a9dbb38037cece35740f2cf23c875d8ca134d33631cec83f74d3fe"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"data-encoding",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"lazy_static",
|
||||
"radix_trie",
|
||||
"rand 0.8.5",
|
||||
"thiserror",
|
||||
"time",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"trust-dns-proto",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trust-dns-proto"
|
||||
version = "0.22.0"
|
||||
|
@ -18,3 +18,4 @@ gix = { version = "0.44.1", features = [
|
||||
tempdir = "0.3.7"
|
||||
serde = { version = "1.0.162", features = [ "derive" ]}
|
||||
serde_json = "1.0.96"
|
||||
trust-dns-client = "0.22.0"
|
||||
|
1
src/domain.rs
Normal file
1
src/domain.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod checker;
|
105
src/domain/checker.rs
Normal file
105
src/domain/checker.rs
Normal file
@ -0,0 +1,105 @@
|
||||
use std::error::Error;
|
||||
use std::str::FromStr;
|
||||
|
||||
use trust_dns_client::client::{Client, SyncClient};
|
||||
use trust_dns_client::rr::{DNSClass, Name, RData, RecordType};
|
||||
use trust_dns_client::udp::UdpClientConnection;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum NewDNSCheckerError {
|
||||
InvalidResolverAddress,
|
||||
InvalidTargetCNAME,
|
||||
Unexpected(Box<dyn Error>),
|
||||
}
|
||||
|
||||
impl<E: Error + 'static> From<E> for NewDNSCheckerError {
|
||||
fn from(e: E) -> NewDNSCheckerError {
|
||||
NewDNSCheckerError::Unexpected(Box::from(e))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CheckDomainError {
|
||||
InvalidDomainName,
|
||||
TargetCNAMENotSet,
|
||||
ChallengeTokenNotSet,
|
||||
Unexpected(Box<dyn Error>),
|
||||
}
|
||||
|
||||
impl<E: Error + 'static> From<E> for CheckDomainError {
|
||||
fn from(e: E) -> CheckDomainError {
|
||||
CheckDomainError::Unexpected(Box::from(e))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Checker {
|
||||
fn check_domain(&self, domain: &str, challenge_token: &str) -> Result<(), CheckDomainError>;
|
||||
}
|
||||
|
||||
pub struct DNSChecker {
|
||||
target_cname: Name,
|
||||
client: SyncClient<UdpClientConnection>,
|
||||
}
|
||||
|
||||
impl DNSChecker {
|
||||
pub fn new(target_cname: &str, resolver_addr: &str) -> Result<DNSChecker, NewDNSCheckerError> {
|
||||
let target_cname =
|
||||
Name::from_str(target_cname).map_err(|_| NewDNSCheckerError::InvalidTargetCNAME)?;
|
||||
|
||||
let resolver_addr = resolver_addr
|
||||
.parse()
|
||||
.map_err(|_| NewDNSCheckerError::InvalidResolverAddress)?;
|
||||
|
||||
let conn = UdpClientConnection::new(resolver_addr)?;
|
||||
let client = SyncClient::new(conn);
|
||||
|
||||
Ok(DNSChecker {
|
||||
target_cname,
|
||||
client,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Checker for DNSChecker {
|
||||
fn check_domain(&self, domain: &str, challenge_token: &str) -> Result<(), CheckDomainError> {
|
||||
let mut fqdn = Name::from_str(domain).map_err(|_| CheckDomainError::InvalidDomainName)?;
|
||||
fqdn.set_fqdn(true);
|
||||
|
||||
// check that the CNAME is installed correctly on the domain
|
||||
{
|
||||
let response = self.client.query(&fqdn, DNSClass::IN, RecordType::CNAME)?;
|
||||
|
||||
let records = response.answers();
|
||||
|
||||
if records.len() != 1 {
|
||||
return Err(CheckDomainError::TargetCNAMENotSet);
|
||||
}
|
||||
|
||||
// if the single record isn't a CNAME, or it's not the target CNAME, then return
|
||||
// TargetCNAMENotSet
|
||||
match records[0].data() {
|
||||
Some(RData::CNAME(remote_cname)) if remote_cname == &self.target_cname => (),
|
||||
_ => return Err(CheckDomainError::TargetCNAMENotSet),
|
||||
}
|
||||
}
|
||||
|
||||
// check that the TXT record with the challenge token is correctly installed on the domain
|
||||
{
|
||||
let fqdn = Name::from_str("_gateway")?.append_domain(&fqdn)?;
|
||||
let response = self.client.query(&fqdn, DNSClass::IN, RecordType::TXT)?;
|
||||
|
||||
let records = response.answers();
|
||||
|
||||
if !records.iter().any(|record| -> bool {
|
||||
match record.data() {
|
||||
Some(RData::TXT(txt)) => txt.to_string().contains(challenge_token),
|
||||
_ => false,
|
||||
}
|
||||
}) {
|
||||
return Err(CheckDomainError::ChallengeTokenNotSet);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1 +1,2 @@
|
||||
pub mod origin;
|
||||
pub mod domain;
|
||||
|
@ -1,8 +1,6 @@
|
||||
use std::error::Error;
|
||||
|
||||
use serde_json;
|
||||
|
||||
use super::Descr;
|
||||
use serde_json;
|
||||
use std::error::Error;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Limits {}
|
||||
@ -61,8 +59,6 @@ pub mod git {
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{fs, io};
|
||||
|
||||
use gix::progress::Discard;
|
||||
|
||||
pub struct Store<'a> {
|
||||
dir_path: &'a Path,
|
||||
}
|
||||
@ -88,8 +84,10 @@ pub mod git {
|
||||
|
||||
impl<'a> super::Store for Store<'a> {
|
||||
fn sync(&self, descr: &Descr, _limits: Limits) -> Result<(), SyncError> {
|
||||
let should_interrupt = &core::sync::atomic::AtomicBool::new(false);
|
||||
use gix::clone::Error as gixCloneErr;
|
||||
use gix::progress::Discard;
|
||||
|
||||
let should_interrupt = &core::sync::atomic::AtomicBool::new(false);
|
||||
let repo_path = &self.repo_path(descr);
|
||||
|
||||
// if the path doesn't exist then use the gix clone feature to clone it into the
|
||||
@ -99,8 +97,6 @@ pub mod git {
|
||||
|
||||
let Descr::Git { url, branch_name } = descr;
|
||||
|
||||
use gix::clone::Error as gixCloneErr;
|
||||
|
||||
let (repo, _) = gix::prepare_clone_bare(url.clone(), repo_path)
|
||||
.map_err(|e| match e {
|
||||
gixCloneErr::Init(gix::init::Error::InvalidBranchName { .. }) => {
|
||||
@ -214,7 +210,6 @@ pub mod git {
|
||||
mod tests {
|
||||
use super::super::Store;
|
||||
use super::Descr;
|
||||
|
||||
use tempdir::TempDir;
|
||||
|
||||
#[test]
|
||||
|
Loading…
Reference in New Issue
Block a user