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",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "endian-type"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "enum-as-inner"
|
name = "enum-as-inner"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
@ -470,6 +476,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
"tempdir",
|
"tempdir",
|
||||||
|
"trust-dns-client",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1514,6 +1521,15 @@ dependencies = [
|
|||||||
"windows-sys 0.45.0",
|
"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]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "7.1.3"
|
version = "7.1.3"
|
||||||
@ -1639,6 +1655,16 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"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]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
@ -2236,6 +2262,26 @@ dependencies = [
|
|||||||
"once_cell",
|
"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]]
|
[[package]]
|
||||||
name = "trust-dns-proto"
|
name = "trust-dns-proto"
|
||||||
version = "0.22.0"
|
version = "0.22.0"
|
||||||
|
@ -18,3 +18,4 @@ gix = { version = "0.44.1", features = [
|
|||||||
tempdir = "0.3.7"
|
tempdir = "0.3.7"
|
||||||
serde = { version = "1.0.162", features = [ "derive" ]}
|
serde = { version = "1.0.162", features = [ "derive" ]}
|
||||||
serde_json = "1.0.96"
|
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 origin;
|
||||||
|
pub mod domain;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use std::error::Error;
|
|
||||||
|
|
||||||
use serde_json;
|
|
||||||
|
|
||||||
use super::Descr;
|
use super::Descr;
|
||||||
|
use serde_json;
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Limits {}
|
pub struct Limits {}
|
||||||
@ -61,8 +59,6 @@ pub mod git {
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::{fs, io};
|
use std::{fs, io};
|
||||||
|
|
||||||
use gix::progress::Discard;
|
|
||||||
|
|
||||||
pub struct Store<'a> {
|
pub struct Store<'a> {
|
||||||
dir_path: &'a Path,
|
dir_path: &'a Path,
|
||||||
}
|
}
|
||||||
@ -88,8 +84,10 @@ pub mod git {
|
|||||||
|
|
||||||
impl<'a> super::Store for Store<'a> {
|
impl<'a> super::Store for Store<'a> {
|
||||||
fn sync(&self, descr: &Descr, _limits: Limits) -> Result<(), SyncError> {
|
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);
|
let repo_path = &self.repo_path(descr);
|
||||||
|
|
||||||
// if the path doesn't exist then use the gix clone feature to clone it into the
|
// 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;
|
let Descr::Git { url, branch_name } = descr;
|
||||||
|
|
||||||
use gix::clone::Error as gixCloneErr;
|
|
||||||
|
|
||||||
let (repo, _) = gix::prepare_clone_bare(url.clone(), repo_path)
|
let (repo, _) = gix::prepare_clone_bare(url.clone(), repo_path)
|
||||||
.map_err(|e| match e {
|
.map_err(|e| match e {
|
||||||
gixCloneErr::Init(gix::init::Error::InvalidBranchName { .. }) => {
|
gixCloneErr::Init(gix::init::Error::InvalidBranchName { .. }) => {
|
||||||
@ -214,7 +210,6 @@ pub mod git {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::super::Store;
|
use super::super::Store;
|
||||||
use super::Descr;
|
use super::Descr;
|
||||||
|
|
||||||
use tempdir::TempDir;
|
use tempdir::TempDir;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
Reference in New Issue
Block a user