use std::{net::SocketAddr, path::PathBuf};
use clap::Args;
use onomancy_core::time::UnixSeconds;
use onomancy_dnssec::{
certificate::Certificate,
validator::{Validator, WalkError},
};
use onomancy_hickory::provider::FetchChainError;
use onomancy_keyhive::authority::KeyhiveAuthority;
use onomancy_publish::ceremony::refresh::Refresh as RefreshCeremony;
use crate::{now_ms, plan_io};
#[derive(Debug, Args)]
pub(crate) struct Refresh {
#[arg(long)]
cert: PathBuf,
#[arg(long)]
resolver: Option<SocketAddr>,
#[arg(long, default_value = ".")]
out_dir: PathBuf,
}
impl Refresh {
pub(crate) fn run(&self) -> Result<(), RefreshError> {
let certificate = Certificate::decode(&std::fs::read(&self.cert)?)?;
let provider = crate::provider(self.resolver);
let chain = crate::block_on(provider.fetch_chain(certificate.hostname()))??;
let proof = Validator::iana().validate_detailed(certificate.hostname(), &chain)?;
let plan = RefreshCeremony {
certificate,
chain,
records: proof.records,
}
.plan(UnixSeconds::from(now_ms() / 1000), &KeyhiveAuthority)?;
crate::block_on(plan_io::execute(&plan, &self.out_dir))??;
Ok(())
}
}
#[derive(Debug, thiserror::Error)]
pub(crate) enum RefreshError {
#[error(transparent)]
Ceremony(#[from] onomancy_publish::ceremony::CeremonyError),
#[error("certificate: {0}")]
Certificate(#[from] onomancy_dnssec::certificate::DecodeCertificateError),
#[error(transparent)]
Fetch(#[from] FetchChainError),
#[error(transparent)]
Io(#[from] std::io::Error),
#[error("live chain invalid: {0}")]
Walk(#[from] WalkError),
}