139 lines
3.5 KiB
Rust
139 lines
3.5 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use rust_util::util_file;
|
|
use rust_util::XResult;
|
|
use std::fs;
|
|
use std::fs::File;
|
|
use std::io::Read;
|
|
use acme_lib::DirectoryUrl;
|
|
|
|
const CERT_NAME: &str = "cert.pem";
|
|
const KEY_NAME: &str = "key.pem";
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub enum AcmeAlgo {
|
|
Ec256,
|
|
Ec384,
|
|
Rsa(u32),
|
|
}
|
|
|
|
impl Default for AcmeAlgo {
|
|
fn default() -> Self {
|
|
Self::Ec384
|
|
}
|
|
}
|
|
|
|
impl AcmeAlgo {
|
|
pub fn parse_or_default(s: &str) -> AcmeAlgo {
|
|
Self::parse(s).unwrap_or_else(|_| Default::default())
|
|
}
|
|
|
|
pub fn parse(s: &str) -> XResult<AcmeAlgo> {
|
|
match s {
|
|
"ec256" => Ok(AcmeAlgo::Ec256),
|
|
"ec384" => Ok(AcmeAlgo::Ec384),
|
|
"rsa2048" => Ok(AcmeAlgo::Rsa(2048)),
|
|
"rsa3072" => Ok(AcmeAlgo::Rsa(3072)),
|
|
"rsa4096" => Ok(AcmeAlgo::Rsa(4096)),
|
|
_ => simple_error!("Unknown algo: {}", s),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub enum AcmeMode {
|
|
Prod,
|
|
Test,
|
|
}
|
|
|
|
impl Default for AcmeMode {
|
|
fn default() -> Self {
|
|
Self::Prod
|
|
}
|
|
}
|
|
|
|
impl AcmeMode {
|
|
pub fn parse_or_default(s: &str) -> AcmeMode {
|
|
Self::parse(s).unwrap_or_else(|_| Default::default())
|
|
}
|
|
|
|
pub fn parse(s: &str) -> XResult<AcmeMode> {
|
|
match s {
|
|
"prod" => Ok(AcmeMode::Prod),
|
|
"test" => Ok(AcmeMode::Test),
|
|
_ => simple_error!("Unknown mode: {}", s),
|
|
}
|
|
}
|
|
|
|
pub fn directory_url(&self) -> DirectoryUrl {
|
|
match self {
|
|
AcmeMode::Prod => DirectoryUrl::LetsEncrypt,
|
|
AcmeMode::Test => DirectoryUrl::LetsEncryptStaging,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct AcmeConfig {
|
|
pub email: String,
|
|
pub dir: String,
|
|
pub auth_timeout: Option<u64>,
|
|
pub csr_timeout: Option<u64>,
|
|
pub concurrent: Option<u32>, // ?
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CertConfigItem {
|
|
pub path: String,
|
|
pub algo: Option<String>,
|
|
pub dns_names: Option<Vec<String>>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CertConfig {
|
|
pub cert_items: Vec<CertConfigItem>,
|
|
}
|
|
|
|
impl AcmeConfig {
|
|
pub fn get_auth_timeout(&self) -> u64 {
|
|
self.auth_timeout.unwrap_or(5_000)
|
|
}
|
|
|
|
pub fn get_csr_timeout(&self) -> u64 {
|
|
self.csr_timeout.unwrap_or(5_000)
|
|
}
|
|
|
|
pub fn get_concurrent(&self) -> u32 {
|
|
self.concurrent.unwrap_or(0)
|
|
}
|
|
}
|
|
|
|
impl CertConfigItem {
|
|
pub fn fill_dns_names(&mut self) -> XResult<()> {
|
|
// TODO
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
pub fn load_acme_config(file: Option<&str>, load_default: bool) -> XResult<AcmeConfig> {
|
|
if let Some(file) = file {
|
|
let s = opt_result!(util_file::read_file_content(file), "Read file: {}, failed: {}", file);
|
|
return Ok(opt_result!(deser_hjson::from_str(&s), "Parse acme config file: {}, failed: {}", file));
|
|
}
|
|
|
|
if load_default {
|
|
let default_config = util_file::read_config(None, &[
|
|
"~/acme_config.json".to_string(),
|
|
"/etc/acme_config.json".to_string(),
|
|
]);
|
|
if let Some(default_config) = default_config {
|
|
let s = opt_result!(fs::read_to_string(default_config.clone()), "Read file: {:?}, failed: {}", default_config);
|
|
return Ok(opt_result!(deser_hjson::from_str(&s), "Parse acme config file: {:?}, failed: {}", default_config));
|
|
}
|
|
}
|
|
|
|
simple_error!("Acme config file not found!")
|
|
}
|