some more refactoring

Dieser Commit ist enthalten in:
Sebastian Tobie 2025-06-23 19:41:22 +02:00
Ursprung d982920cf2
Commit 8b9bf2a77d
15 geänderte Dateien mit 325 neuen und 139 gelöschten Zeilen

11
Cargo.lock generiert
Datei anzeigen

@ -1543,6 +1543,7 @@ dependencies = [
"schemars",
"serde",
"serde_json",
"systemd-journal-logger",
"tokio",
"tokio-stream",
"toml",
@ -2016,6 +2017,16 @@ dependencies = [
"syn",
]
[[package]]
name = "systemd-journal-logger"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7266304d24ca5a4b230545fc558c80e18bd3e1d2eb1be149b6bcd04398d3e79c"
dependencies = [
"log",
"rustix",
]
[[package]]
name = "tempfile"
version = "3.20.0"

Datei anzeigen

@ -68,6 +68,10 @@ default-features = false
features = ["std"]
version = "1.0.140"
[dependencies.systemd-journal-logger]
default-features = false
version = "2.2.2"
[dependencies.tokio]
default-features = false
features = ["rt", "sync", "time", "net", "macros"]
@ -91,6 +95,7 @@ unstable = ["capabilities"]
edition = "2024"
name = "racme"
resolver = "3"
rust-version = "1.87"
version = "0.1.0"
[patch.crates-io.acme2-eab]

Datei anzeigen

@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "GeneralConfig",
"title": "General",
"type": "object",
"properties": {
"accounts_path": {

Datei anzeigen

@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "SiteConfig",
"title": "Site",
"type": "object",
"properties": {
"ca": {

Datei anzeigen

@ -1,9 +1,15 @@
//! Acme client that supports multiple CAs and configs for sites that can be seperate from the mainconfig
#![allow(clippy::clone_on_copy)]
#![allow(clippy::identity_op)]
#![allow(refining_impl_trait)]
#![allow(clippy::collapsible_if)]
#![allow(clippy::identity_op)]
#![allow(dead_code)]
#![allow(refining_impl_trait)]
#![deny(clippy::format_push_string)]
#![deny(clippy::macro_use_imports)]
#![deny(clippy::module_name_repetitions)]
#![deny(clippy::single_component_path_imports)]
#![deny(clippy::unnecessary_debug_formatting)]
#![deny(clippy::unnecessary_self_imports)]
pub(crate) mod consts;
pub(crate) mod macros;
@ -17,8 +23,8 @@ use crate::{
prelude::*,
types::{
config::{
GeneralConfig,
SiteConfig,
General,
Site,
},
dns::Manager,
structs::{
@ -28,20 +34,15 @@ use crate::{
SubCommand,
},
},
utils::check_permissions,
utils::{
check_permissions,
logging,
},
};
use acme2_eab::Directory;
use clap::Parser;
use env_logger::init as log_init;
use libsystemd::daemon;
use log::*;
use openssl::{
self,
pkey::{
PKey,
Private,
},
};
use reqwest::{
Client,
tls::Version,
@ -52,9 +53,12 @@ use schemars::{
generate::SchemaSettings,
};
use serde::Serialize;
use serde_json::ser::{
Formatter,
PrettyFormatter,
use serde_json::{
Serializer,
ser::{
Formatter,
PrettyFormatter,
},
};
use std::{
collections::{
@ -75,10 +79,8 @@ use tokio::{
create_dir_all,
read_dir,
},
io::{
AsyncReadExt,
AsyncWriteExt,
},
io::AsyncWriteExt as _,
runtime::Builder,
sync::Mutex,
};
use tokio_stream::{
@ -99,21 +101,6 @@ fn default_client() -> Result<Client, Error> {
.map_err(Error::from_display)
}
async fn load_privkey(path: PathBuf) -> Result<PKey<Private>, Error> {
let mut file = match FILE_MODE.open(path).await {
Ok(file) => file,
Err(error) => return Error::err(format!("Failed to open Private Key: {error}")),
};
let mut data = String::new();
if let Err(error) = file.read_to_string(&mut data).await {
return Error::err(format!("Failed to read data for the key: {error}"));
}
match PKey::private_key_from_pem(data.as_bytes()) {
Ok(key) => Ok(key),
Err(error) => Error::err(format!("Failed to parse pem data: {error}")),
}
}
async fn racme(flags: Arguments) -> Result<(), Error> {
let client = default_client()?;
let mut dns_manager = Manager::new(client.clone());
@ -125,7 +112,7 @@ async fn racme(flags: Arguments) -> Result<(), Error> {
return Error::err(format!("error reading the config: {error}"));
},
};
GeneralConfig::from_file(file).await
General::from_file(file).await
};
for (zone, builder) in mainconfig.dns.iter() {
dns_manager.add_builder(zone.clone(), builder.clone()).await;
@ -149,7 +136,7 @@ async fn racme(flags: Arguments) -> Result<(), Error> {
continue;
},
};
let mut site = SiteConfig::from_file(file).await;
let mut site = Site::from_file(file).await;
site.name = filename.file_stem().unwrap().to_string_lossy().to_string();
siteconfigs.push(site);
}
@ -204,7 +191,7 @@ async fn racme(flags: Arguments) -> Result<(), Error> {
fn serialize_with_formatter<T: Serialize, F: Formatter>(value: &T, formatter: F) -> Result<String, Error> {
let mut store = Vec::with_capacity(2 ^ 10);
let mut serializer = serde_json::ser::Serializer::with_formatter(&mut store, formatter);
let mut serializer = Serializer::with_formatter(&mut store, formatter);
match value.serialize(&mut serializer) {
Ok(_) => {},
Err(error) => return Error::err(format!("Failed to Serialize the schema: {error}")),
@ -218,7 +205,7 @@ async fn schema_generator() -> Result<(), Error> {
let mut schema_settings = SchemaSettings::default();
schema_settings.meta_schema = Some(DRAFT07.into());
let mut generator = SchemaGenerator::new(schema_settings);
let general_schema = serialize_with_formatter(&generator.root_schema_for::<GeneralConfig>(), formatter.clone())?;
let general_schema = serialize_with_formatter(&generator.root_schema_for::<General>(), formatter.clone())?;
match FILE_MODE_WRITE.clone().create_new(false).open("schema-general.json").await {
Ok(mut file) => {
match file.write(general_schema.as_bytes()).await {
@ -229,7 +216,7 @@ async fn schema_generator() -> Result<(), Error> {
Err(error) => return Err(Error::from_display(error)),
};
let site_schema = serialize_with_formatter(&generator.root_schema_for::<SiteConfig>(), formatter.clone())?;
let site_schema = serialize_with_formatter(&generator.root_schema_for::<Site>(), formatter.clone())?;
match FILE_MODE_WRITE.clone().create_new(false).open("schema-site.json").await {
Ok(mut file) => {
match file.write(site_schema.as_bytes()).await {
@ -243,7 +230,7 @@ async fn schema_generator() -> Result<(), Error> {
}
fn main() {
log_init();
logging();
let args = Arguments::parse();
if args.subcommands.is_none() && !check_permissions() {
error!(
@ -251,7 +238,7 @@ fn main() {
);
exit(4)
}
let runtime = match tokio::runtime::Builder::new_current_thread().enable_all().build() {
let runtime = match Builder::new_current_thread().enable_all().build() {
Ok(runtime) => runtime,
Err(error) => {
error!("Could not initialize Tokio runtime: {error}");

Datei anzeigen

@ -5,7 +5,10 @@ use std::{
},
fs::Permissions,
os::{
fd::AsFd,
fd::{
AsFd as _,
AsRawFd as _,
},
unix::fs::{
PermissionsExt as _,
fchown,
@ -25,14 +28,17 @@ use crate::{
MODE_SECRETS,
WAIT_TIME,
},
load_privkey,
prelude::*,
types::{
self,
config::CA,
cryptography::Algorithm,
cryptography::{
Algorithm,
Strength,
},
dns::Manager,
structs::{
Certificate,
Error,
ProcessorArgs,
San,
@ -57,9 +63,14 @@ use acme2_eab::{
OrderBuilder,
OrderStatus,
};
use libc::fchmod;
use log::*;
use openssl::{
hash::MessageDigest,
pkey::{
PKey,
Private,
},
stack::Stack,
x509::{
X509,
@ -74,6 +85,7 @@ use openssl::{
},
},
};
use pem::parse as pem_parse;
use reqwest::Client;
use tokio::{
fs::{
@ -86,7 +98,10 @@ use tokio::{
},
join,
};
use zbus_systemd::systemd1;
use zbus_systemd::{
systemd1,
zbus::Connection,
};
fn gen_stack(args: &ProcessorArgs, context: X509v3Context) -> Stack<X509Extension> {
let mut stack = Stack::new().unwrap();
@ -109,7 +124,7 @@ fn gen_stack(args: &ProcessorArgs, context: X509v3Context) -> Stack<X509Extensio
}
pub async fn accounts(
name: &String,
name: &str,
ca: &CA,
directories: &mut HashMap<String, Arc<Directory>>,
accounts: &mut HashMap<String, Arc<Account>>,
@ -125,7 +140,12 @@ pub async fn accounts(
dir
},
Err(error) => {
error!("Failed to initialize directory for ca {name}: {error}");
match error {
acme2_eab::Error::Server(server_error) => error!("Failed to get the directory(Server Error): {server_error}"),
acme2_eab::Error::Transport(error) => error!("Failed to connect to the CA(Transport error): {error}"),
acme2_eab::Error::Other(error) => error!("unexpected error(other): {error}"),
x => error!("Unexpected Error: {x}"),
}
return;
},
}
@ -141,14 +161,14 @@ pub async fn accounts(
debug!("No Email address given")
},
}
let accountkey = accountpath.join("file.pem").with_file_name(name.clone());
let accountkey = accountpath.join("file.pem").with_file_name(name);
let mut accountkeyfile = None;
if accountkey.exists() {
if let Ok(key) = load_privkey(accountkey).await {
ac.private_key(key);
}
} else {
info!("creating new key for the account {}", name.clone());
info!("creating new key for the account {}", name.to_owned());
accountkeyfile = match FILE_MODE_OVERWRITE.clone().mode(MODE_SECRETS).open(accountkey).await {
Ok(file) => Some(file),
Err(error) => {
@ -193,7 +213,7 @@ pub async fn accounts(
}
let account = match ac.build().await {
Ok(account) => {
accounts.insert(name.clone(), Arc::clone(&account));
accounts.insert(name.to_owned(), Arc::clone(&account));
account
},
Err(error) => {
@ -209,6 +229,120 @@ pub async fn accounts(
}
}
async fn load_privkey(path: PathBuf) -> Result<PKey<Private>, Error> {
let mut file = match FILE_MODE.open(path).await {
Ok(file) => file,
Err(error) => return Error::err(format!("Failed to open Private Key: {error}")),
};
let mut data = String::with_capacity(file.metadata().await.map(|metadata| metadata.len()).unwrap_or_default() as usize);
if let Err(error) = file.read_to_string(&mut data).await {
return Error::err(format!("Failed to read data for the key: {error}"));
}
match PKey::private_key_from_pem(data.as_bytes()) {
Ok(key) => Ok(key),
Err(error) => Error::err(format!("Failed to parse pem data: {error}")),
}
}
async fn load_or_create_privkey(
path: PathBuf,
owner: Option<u32>,
group: Option<u32>,
mode: Option<u32>,
algorithm: Algorithm,
strength: Strength,
) -> types::Result<(PKey<Private>, bool)> {
let mut key_changed = false;
let privkey;
if path.exists() {
match load_privkey(path.clone()).await {
Ok(key) => {
if !key.matches(algorithm, strength) {
info!("Regenerating Key: Parameters changed");
privkey = gen_key(algorithm, strength)?;
key_changed = true;
} else {
privkey = key;
}
},
Err(error) => {
error!("Failed to load key: {error}");
key_changed = true;
privkey = gen_key(algorithm, strength)?;
},
}
} else {
key_changed = true;
privkey = gen_key(algorithm, strength)?;
}
if key_changed {
let mut keyfile = match FILE_MODE_OVERWRITE.clone().open(path.clone()).await {
Ok(file) => file,
Err(error) => return Error::err(format!("Failed to write key: {error}")),
};
if let Err(error) = fchown(keyfile.as_fd(), owner, group) {
error!("Failed to change owner of the private key: {error}")
}
if let Some(mode) = mode {
match unsafe { fchmod(keyfile.as_raw_fd(), mode) } {
0 => {},
libc::EROFS => error!("Not enough Permissions to change the mode of the private key"),
libc::EINVAL => error!("Invalid Mode for the private key"),
libc::EINTR => warn!("chmod was interrupted by an signal"),
err => error!("unkown return code from fchmod: {err}"),
}
}
let pkey = match privkey.private_key_to_pem_pkcs8() {
Ok(pkey) => pkey,
Err(error) => return Err(Error::from_display(error)),
};
if let Err(error) = keyfile.write_all(pkey.as_slice()).await {
return Err(Error::from_display(error));
}
}
Ok((privkey, key_changed))
}
async fn load_public_key(path: PathBuf) -> types::Result<Certificate> {
let mut file = match FILE_MODE.open(path).await {
Ok(file) => file,
Err(error) => return Err(Error::from_display(error)),
};
let mut data = String::with_capacity(file.metadata().await.map(|metadata| metadata.len()).unwrap_or_default() as usize);
if let Err(error) = file.read_to_string(&mut data).await {
return Error::err(format!("Failed to read the public key: {error}"));
}
let pem = match pem_parse(data.as_bytes()) {
Ok(pem) => pem,
Err(error) => return Error::err(format!("Failed to parse PEM file: {error}")),
};
let cert = match X509::from_der(pem.contents()) {
Ok(cert) => cert,
Err(error) => {
return Error::err(format!(
"Failed to parse the certificate:\n- {}",
error
.errors()
.iter()
.map(|err| err.to_string())
.reduce(|mut errorlist, item| {
errorlist.push_str("\n- ");
errorlist.push_str(item.as_str());
errorlist
})
.unwrap_or_default()
));
},
};
Ok(Certificate {
account_id: pem.headers().get("account_id").map(|d| d.to_string()),
cert,
})
}
pub async fn site(args: ProcessorArgs<'_>) {
let mut cert_renew = false;
@ -222,62 +356,43 @@ pub async fn site(args: ProcessorArgs<'_>) {
cert_renew = true;
}
let (uid, gid) = get_uid_gid(args.owner(), args.group());
let mut private_key;
// Private key block
{
let private_key_file = directory.join("privkey.pem");
let mut write_pkey = false;
if !private_key_file.exists() {
cert_renew = true;
write_pkey = true;
private_key = match_error!(gen_key(args.algorithm(), args.strength())=>Err(error)->"Aborting processing the site due to problem with the certificate generation: {error}");
} else if let Ok(key) = load_privkey(private_key_file.clone()).await {
private_key = key;
if !private_key.matches(args.algorithm(), args.strength()) {
info!("Algorithm for the private key has changed, updating the key");
cert_renew = true;
write_pkey = true;
private_key = match_error!(gen_key(args.algorithm(), args.strength())=>Err(error)->"Aborting processing the site due to problem with the certificate generation: {error}");
}
} else {
error!("Failed to parse the private key. Renewing the private key.");
write_pkey = true;
cert_renew = true;
private_key = match_error!(gen_key(args.algorithm(), args.strength())=>Err(error)->"Aborting processing the site due to problem with the certificate generation: {error}");
}
if write_pkey {
let pkey = private_key.private_key_to_pem_pkcs8().unwrap();
let mut file = match_error!(FILE_MODE_OVERWRITE.clone().mode(MODE_PRIVATE).open(private_key_file.clone()).await=>Err(error)->"Failed to write new private key: {error}");
#[cfg(feature = "capabilities")]
if let Err(error) = fchown(file.as_fd(), uid, gid) {
error!("Failed to change owner of the new privatekey: {error}");
return;
}
match_error!(file.write_all(&pkey).await=>Err(error)->"Failed to write new private key: {error}");
}
}
let private_key = match load_or_create_privkey(directory.join("privkey.pem"), uid, gid, Some(MODE_SECRETS), args.algorithm(), args.strength()).await {
Ok((key, changes)) => {
cert_renew |= changes;
key
},
Err(error) => {
error!("Failed to load or to create the key: {error}");
return;
},
};
let pubkey_filename = directory.join("pubkey.pem");
if pubkey_filename.exists() {
let mut file = match_error!(FILE_MODE.open(pubkey_filename.clone()).await=>Err(error)->"Failed to open publickey. Aborting processing: {error}");
let mut data = String::new();
if let Err(error) = file.read_to_string(&mut data).await {
cert_renew = true;
error!("Failed to read public key: {error}")
} else {
let pubkey = match X509::from_pem(data.as_bytes()) {
Ok(key) => key,
Err(_) => todo!(),
};
if !pubkey.days_left(args.refresh_time()) {
let exists = pubkey_filename.exists();
let publickey = load_public_key(pubkey_filename.clone()).await;
if exists {
if let Ok(pubkey) = publickey.clone() {
if let Some(account) = pubkey.account_id {
if account != args.account().id {
info!("Account changed");
cert_renew = true;
}
}
if !pubkey.cert.days_left(args.refresh_time()) {
info!("Certificate is running out of time");
cert_renew = true
} else if !pubkey.match_san(args.san()) {
info!("Subject Alternative Names differ from Certifcate");
}
if !pubkey.cert.match_san(args.san()) {
info!("Subject Alternative Names differ from Certificate");
cert_renew = true;
};
}
} else {
}
if !exists || publickey.is_err() {
cert_renew = true;
if let Err(error) = publickey {
error!("Failed to parse the public key: {error}")
}
}
if !cert_renew {
info!("Site {} doesn't need an update for the certificate.", args.name());
@ -450,7 +565,7 @@ pub async fn auth(auth: Authorization, challenge_dir: Option<PathBuf>, manager:
}
pub async fn services(restart_services: HashSet<String>, reload_services: HashSet<String>) {
let conn = match_error!(zbus_systemd::zbus::Connection::system().await=>Err(error)-> "Failed to connect with the systemd manager: {error}");
let conn = match_error!(Connection::system().await=>Err(error)-> "Failed to connect with the systemd manager: {error}");
let systemd_manager = systemd1::ManagerProxy::new(&conn).await.unwrap();

Datei anzeigen

@ -1,14 +1,19 @@
use crate::{
prelude::*,
types::{
self,
VString,
cryptography::{
Algorithm,
Strength,
},
dns::DnsBuilder,
dns::Builder,
structs::Error,
},
utils::schema::{
email_transform,
uri_transform,
},
};
use macro_rules_attribute::macro_rules_derive;
@ -26,27 +31,27 @@ use std::{
#[macro_rules_derive(DefDer)]
#[derive(Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct GeneralConfig {
#[serde(default = "GeneralConfig::default_accounts")]
pub struct General {
#[serde(default = "General::default_accounts")]
pub accounts_path: String,
#[serde(default = "GeneralConfig::default_sites")]
#[serde(default = "General::default_sites")]
pub sites_path: String,
#[serde(default = "GeneralConfig::default_challenge")]
#[serde(default = "General::default_challenge")]
pub http_challenge_path: Option<String>,
/// This contains the domains(Keys) and the DNS-Servers(values) that are responsible for it.
#[serde(default = "GeneralConfig::default_dns")]
pub dns: HashMap<String, DnsBuilder>,
#[serde(default = "GeneralConfig::default_certificates")]
#[serde(default = "General::default_dns")]
pub dns: HashMap<String, Builder>,
#[serde(default = "General::default_certificates")]
pub certificates_path: String,
/// The Key of this table describe an nickname for an CA.
/// Letsencrypt Prod and Staging are builtin configured, so they doesn't have to be configured.
#[serde(default = "GeneralConfig::default_cas")]
#[serde(default = "General::default_cas")]
pub ca: HashMap<String, CA>,
}
impl GeneralConfig {
impl General {
#[inline]
pub(super) fn default_accounts() -> String {
"accounts".into()
@ -63,7 +68,7 @@ impl GeneralConfig {
}
#[inline]
pub(super) fn default_dns() -> HashMap<String, DnsBuilder> {
pub(super) fn default_dns() -> HashMap<String, Builder> {
HashMap::new()
}
@ -90,7 +95,7 @@ pub struct Eab {
}
impl Eab {
pub fn key(&self) -> super::Result<PKey<Private>> {
pub fn key(&self) -> types::Result<PKey<Private>> {
let decoded = &match_error!(data_encoding::BASE64URL_NOPAD.decode(self.key.as_bytes())=>Err(error)-> "Failed to decode the HMAC key for the eab_key: {error}", Error::err("Failed to decode eab_key"));
PKey::hmac(decoded).map_err(|error| Error::new(format!("Failed to parse the private key: {error}")))
}
@ -101,11 +106,11 @@ impl Eab {
#[serde(deny_unknown_fields)]
pub struct CA {
/// Url for the directory
#[schemars(transform=crate::utils::schema::uri_transform)]
#[schemars(transform=uri_transform)]
pub directory: String,
/// Email addresses for the CA to contact the user
#[schemars(transform=crate::utils::schema::email_transform)]
#[schemars(transform=email_transform)]
pub email_addresses: Option<VString>,
#[serde(flatten, default)]
@ -130,7 +135,7 @@ impl CA {
#[macro_rules_derive(DefDer)]
#[derive(Deserialize, Default, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct SiteConfig {
pub struct Site {
/// The Configured Certificate Authority
pub ca: String,
@ -143,7 +148,7 @@ pub struct SiteConfig {
/// EmailAdresses that this Certificate is valid for
#[serde(default)]
#[schemars(transform=crate::utils::schema::email_transform)]
#[schemars(transform=email_transform)]
pub emails: VString,
/// The systemd services are reloaded

Datei anzeigen

@ -5,6 +5,7 @@ use serde::Deserialize;
use crate::{
macros::DefDer,
types::{
self,
dns::Dns,
structs::DnsToken,
traits::DnsHandler,
@ -26,7 +27,7 @@ impl DNSUpdateClientOptions {
pub struct DnsUpdateHandler {}
impl DnsHandler for DnsUpdateHandler {
async fn set_record(&self, _domain: String, _content: String) -> crate::types::Result<DnsToken> {
async fn set_record(&self, _domain: String, _content: String) -> types::Result<DnsToken> {
Ok(DnsToken::new_dns_update())
}
}

Datei anzeigen

@ -4,6 +4,7 @@ pub(super) mod pdns;
use crate::{
macros::DefDer,
types::{
self,
dns::{
dnsupdate::{
DNSUpdateClientOptions,
@ -75,7 +76,7 @@ impl Manager {
}
}
pub async fn add_builder(&mut self, zone: String, builder: DnsBuilder) {
pub async fn add_builder(&mut self, zone: String, builder: Builder) {
let mut fixed_zone = zone.clone();
if !fixed_zone.ends_with('.') {
fixed_zone.push('.');
@ -83,9 +84,9 @@ impl Manager {
self.0.lock().await.servers.insert(
fixed_zone,
match builder {
DnsBuilder::PowerDNS(pdns_client_options) => pdns_client_options.build(zone, self.1.clone()),
DnsBuilder::DNSUpdate(dnsupdate_client_options) => dnsupdate_client_options.build(zone),
DnsBuilder::None => Dns::None,
Builder::PowerDNS(pdns_client_options) => pdns_client_options.build(zone, self.1.clone()),
Builder::DNSUpdate(dnsupdate_client_options) => dnsupdate_client_options.build(zone),
Builder::None => Dns::None,
},
);
}
@ -103,7 +104,7 @@ struct InnerManager {
#[derive(Deserialize, Default, JsonSchema)]
#[serde(deny_unknown_fields)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum DnsBuilder {
pub enum Builder {
PowerDNS(PdnsClientOptions),
DNSUpdate(DNSUpdateClientOptions),
#[default]
@ -118,7 +119,7 @@ pub enum Dns {
}
impl Dns {
pub async fn set_record(&self, domain: String, content: String) -> crate::types::Result<DnsToken> {
pub async fn set_record(&self, domain: String, content: String) -> types::Result<DnsToken> {
match self {
Dns::PowerDNS(pdns_handler) => pdns_handler.set_record(domain, content).await,
Dns::DNSUpdate(dns_update_handler) => dns_update_handler.set_record(domain, content).await,

Datei anzeigen

@ -21,6 +21,7 @@ use serde::{
use crate::{
macros::DefDer,
types::{
self,
dns::Dns,
structs::{
DnsToken,
@ -83,7 +84,7 @@ fn fix_url(baseurl: Url, path: String) -> Result<Url, ()> {
impl DnsHandler for PdnsHandler {
async fn set_record(&self, mut domain: String, content: String) -> crate::types::Result<DnsToken> {
async fn set_record(&self, mut domain: String, content: String) -> types::Result<DnsToken> {
trace!("Original URL: {}", self.server);
let baseurl = match reqwest::Url::parse(&self.server) {
Ok(url) => {

Datei anzeigen

@ -1,5 +1,9 @@
use std::{
fmt::Display,
fmt::{
Display,
Formatter,
Result as fmtResult,
},
net::IpAddr,
};
@ -7,7 +11,7 @@ use acme2_eab::Identifier;
use openssl::x509::GeneralName;
use crate::types::{
config::GeneralConfig,
config::General,
dns::pdns::PdnsError,
structs::{
Error,
@ -16,7 +20,7 @@ use crate::types::{
};
impl Default for GeneralConfig {
impl Default for General {
#[inline]
fn default() -> Self {
Self {
@ -78,14 +82,14 @@ impl From<San> for Identifier {
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, f: &mut Formatter<'_>) -> fmtResult {
f.write_str(&self.message)
}
}
impl Display for PdnsError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, f: &mut Formatter<'_>) -> fmtResult {
f.write_str(&self.error)?;
if !self.errors.is_empty() {
f.write_str("(")?;

Datei anzeigen

@ -1,7 +1,9 @@
use std::collections::HashSet;
use std::{
collections::HashSet,
result::Result as stdResult,
};
use tokio::sync::Mutex;
pub mod config;
pub mod cryptography;
pub mod dns;
@ -9,10 +11,11 @@ mod foreign_impl;
pub mod structs;
pub mod traits;
/// Alias for Vec\<String\>
pub type VString = Vec<String>;
/// Alias for an Safe Hashset
pub type SafeSet<T> = Mutex<HashSet<T>>;
pub type Result<T> = std::result::Result<T, structs::Error>;
pub type Result<T> = stdResult<T, structs::Error>;

Datei anzeigen

@ -16,6 +16,7 @@ use clap::{
};
use derive_new::new;
use macro_rules_attribute::macro_rules_derive;
use openssl::x509::X509;
use reqwest::{
Client,
RequestBuilder,
@ -26,7 +27,7 @@ use crate::{
prelude::*,
types::{
SafeSet,
config::SiteConfig,
config::Site,
cryptography::{
Algorithm,
Strength,
@ -58,7 +59,7 @@ pub enum SubCommand {
#[allow(clippy::too_many_arguments)]
#[derive(new)]
pub struct ProcessorArgs<'a> {
site: SiteConfig,
site: Site,
account: Arc<Account>,
reload_services: &'a SafeSet<String>,
restart_services: &'a SafeSet<String>,
@ -190,3 +191,9 @@ impl DnsToken {
}
}
}
#[macro_rules_derive(DefDer)]
pub struct Certificate {
pub cert: X509,
pub account_id: Option<String>,
}

Datei anzeigen

@ -33,6 +33,7 @@ use openssl::{
x509::X509,
};
use serde::de::DeserializeOwned;
use std::fmt::Debug as fmtDebug;
use tokio::{
fs::File,
io::AsyncReadExt,
@ -122,6 +123,6 @@ impl MatchX509 for X509 {
}
}
pub trait DnsHandler: std::fmt::Debug + Send {
pub trait DnsHandler: fmtDebug + Send {
async fn set_record(&self, domain: String, content: String) -> types::Result<DnsToken>;
}

Datei anzeigen

@ -1,4 +1,10 @@
use std::ffi::CString;
use std::{
env::{
self,
VarError,
},
ffi::CString,
};
use crate::{
consts::{
@ -38,6 +44,7 @@ use openssl::{
X509NameBuilder,
},
};
use systemd_journal_logger::JournalLog;
#[cfg(feature = "capabilities")]
const CAPABILITY_SET: CapSet = CapSet::Permitted;
@ -249,3 +256,41 @@ pub mod schema {
type_transform(schema, "uri");
}
}
pub(crate) fn logging() {
let level = match env::var("RUST_LOG") {
Ok(levelname) => levelname.to_uppercase(),
Err(error) => {
match error {
VarError::NotPresent => {},
VarError::NotUnicode(text) => println!("Invalid Log Level {}", text.display()),
};
"INFO".to_string()
},
};
let journal = JournalLog::new().map(|logger| logger.with_extra_fields(vec![("PKG_VERSION", env!("CARGO_PKG_VERSION"))]));
match journal {
Ok(logger) => {
match logger.install() {
Ok(()) => {
log::set_max_level(match level.as_str() {
"OFF" => LevelFilter::Off,
"TRACE" => LevelFilter::Trace,
"DEBUG" => LevelFilter::Debug,
"WARN" => LevelFilter::Warn,
"ERROR" => LevelFilter::Error,
_ => LevelFilter::Info,
});
},
Err(error) => {
env_logger::init();
warn!("Failed to initialize the Journal Logger: {error}")
},
}
},
Err(error) => {
env_logger::init();
warn!("Failed to initialize the Journal Logger: {error}")
},
}
}